Home > vSphere API > Creating Your Own Task and Event in vSphere

Creating Your Own Task and Event in vSphere

September 9th, 2010 Leave a comment Go to comments

vSphere has a powerful extension mechanism that allows you to add new features as integral part of the platform. Many vendors have already leveraged this by providing plug-ins so that users can manage their components seamlessly within same vSphere Client.

You can actually do more than that with the extension. The following sample shows how to create your own task and event with vSphere API. The code should be self explanatory therefore I don’t elaborate much here. Note that you must run the sample with a vCenter server as extensibility is implemented only in vCenter.

Lost VMs or Containers? Too Many Consoles? Too Slow GUI? Time to learn how to "Google" and manage your VMware and clouds in a fast and secure HTML5 App.

When running the code, you can see a new task created and progresses with 10% every second in the “Recent Tasks” pane of vSphere Client. When the task is done, you will also see a new event posted in the “Tasks & Events” tab of the host you associate the task with.

What can you do with this capability? Here are two typical use cases:

  1. Use it in your vSphere Client plug-in so that progress of a chosen operation is visible to all logged in users. In that case, you don’t need to create additional extension;
  2. Use it in your server extension applications such as VMware Site Recovery Manager.

You can also use it in a utility program as this sample, but may be an over use of this feature.

package com.vmware.vim25.mo.samples;

import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.RemoteException;
import java.util.Calendar;

import com.vmware.vim25.Description;
import com.vmware.vim25.Extension;
import com.vmware.vim25.ExtensionEventTypeInfo;
import com.vmware.vim25.ExtensionResourceInfo;
import com.vmware.vim25.ExtensionTaskTypeInfo;
import com.vmware.vim25.KeyValue;
import com.vmware.vim25.TaskInfo;
import com.vmware.vim25.TaskInfoState;
import com.vmware.vim25.mo.ExtensionManager;
import com.vmware.vim25.mo.HostSystem;
import com.vmware.vim25.mo.InventoryNavigator;
import com.vmware.vim25.mo.ManagedEntity;
import com.vmware.vim25.mo.ServiceInstance;
import com.vmware.vim25.mo.Task;
import com.vmware.vim25.mo.TaskManager;

public class CreateCustomTask
{
  final static String EXTENSION_KEY = "DoubleCloud";

  public static void main(String[] args) throws RemoteException, MalformedURLException, InterruptedException
  {
    if (args.length != 3)
    {
      System.out.println("java CreateCustomTask <SdkUrl> <username> <password>");
      System.out.println("java CreateCustomTask https://192.168.8.8/sdk administrator password");
      return;
    }

    ServiceInstance si = new ServiceInstance(new URL(args[0]), args[1], args[2], true);
    ManagedEntity[] mes =  new InventoryNavigator(si.getRootFolder()).searchManagedEntities("HostSystem");
    HostSystem host = (HostSystem) mes[0];

    ExtensionManager em = si.getExtensionManager();
    if(em.findExtension(EXTENSION_KEY)==null)
    {
      em.registerExtension(createExtension());
    }

    //allow a little time for vCenter to persist the extension data
    Thread.sleep(3000);

    TaskManager tm = si.getTaskManager();
    TaskInfo ti = tm.createTask(host, "AcmeBackupTask", "Administrator", true);
    Task task = new Task(si.getServerConnection(), ti.getTask());

    //change the state to running before updating the progress
    task.setTaskState(TaskInfoState.running, null, null);
    for(int i=1; i<=10; i++)
    {
      System.out.println("percentage done: " + i*10);
      task.updateProgress(i*10);
      Thread.sleep(1000);
    }
    task.setTaskState(TaskInfoState.success, null, null);

    //remove extension. you can leave it there and no need to register next time
    em.unregisterExtension(EXTENSION_KEY);
    si.getServerConnection().logout();
  }

  private static Extension createExtension()
  {
    Extension extension = new Extension();

    Description desc = new Description();
    desc.setLabel("DoubleCloud");
    desc.setSummary("A sample extension with a new type of task.");

    ExtensionTaskTypeInfo etti = new ExtensionTaskTypeInfo();
    etti.setTaskID("AcmeBackupTask");

    ExtensionEventTypeInfo eeti = new ExtensionEventTypeInfo();
    eeti.setEventID("AcmeBackupEvent");

    KeyValue kv1 = new KeyValue();
    kv1.setKey("AcmeBackupTask.category");
    kv1.setValue("info");

    KeyValue kv2 = new KeyValue();
    kv2.setKey("AcmeBackupTask.label");
    kv2.setValue("Acme backup task");

    KeyValue kv3 = new KeyValue();
    kv3.setKey("AcmeBackupTask.fullFormat");
    kv3.setValue("Acme backup virtual machines on host {hostname}");

    ExtensionResourceInfo eri = new ExtensionResourceInfo();
    eri.setLocale("en");
    eri.setModule("task");
    eri.setData(new KeyValue[] {kv1, kv2, kv3});

    extension.setDescription(desc);
    extension.setKey(EXTENSION_KEY);
    extension.setVersion("1.0.0");
    extension.setLastHeartbeatTime(Calendar.getInstance());
    extension.setCompany("Acme Inc.");
    extension.setTaskList(new ExtensionTaskTypeInfo[] { etti });
    extension.setEventList(new ExtensionEventTypeInfo[] { eeti });
    extension.setResourceList(new ExtensionResourceInfo[] { eri });

    return extension;
  }
}
package com.vmware.vim25.mo.samples;

import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.RemoteException;
import java.util.Calendar;

import com.vmware.vim25.Description;
import com.vmware.vim25.Extension;
import com.vmware.vim25.ExtensionEventTypeInfo;
import com.vmware.vim25.ExtensionResourceInfo;
import com.vmware.vim25.ExtensionTaskTypeInfo;
import com.vmware.vim25.KeyValue;
import com.vmware.vim25.TaskInfo;
import com.vmware.vim25.TaskInfoState;
import com.vmware.vim25.mo.ExtensionManager;
import com.vmware.vim25.mo.HostSystem;
import com.vmware.vim25.mo.InventoryNavigator;
import com.vmware.vim25.mo.ManagedEntity;
import com.vmware.vim25.mo.ServiceInstance;
import com.vmware.vim25.mo.Task;
import com.vmware.vim25.mo.TaskManager;

public class CreateCustomTask
{
final static String EXTENSION_KEY = “DoubleCloud”;

public static void main(String[] args) throws RemoteException, MalformedURLException, InterruptedException
{
if (args.length != 3)
{
System.out.println(“java CreateCustomTask <SdkUrl> <username> <password>”);
System.out.println(“java CreateCustomTask https://192.168.8.8/sdk administrator password”);
return;
}

ServiceInstance si = new ServiceInstance(new URL(args[0]), args[1], args[2], true);
ManagedEntity[] mes =  new InventoryNavigator(si.getRootFolder()).searchManagedEntities(“HostSystem”);
HostSystem host = (HostSystem) mes[0];

ExtensionManager em = si.getExtensionManager();
if(em.findExtension(EXTENSION_KEY)==null)
{
em.registerExtension(createExtension());
}

//allow a little time for vCenter to persist the extension data
Thread.sleep(3000);

TaskManager tm = si.getTaskManager();
TaskInfo ti = tm.createTask(host, “AcmeBackupTask”, “Administrator”, true);
Task task = new Task(si.getServerConnection(), ti.getTask());

//change the state to running before updating the progress
task.setTaskState(TaskInfoState.running, null, null);
for(int i=1; i<=10; i++)
{
System.out.println(“percentage done: ” + i*10);
task.updateProgress(i*10);
Thread.sleep(1000);
}
task.setTaskState(TaskInfoState.success, null, null);

//remove extension. you can leave it there and no need to register next time
em.unregisterExtension(EXTENSION_KEY);
si.getServerConnection().logout();
}

private static Extension createExtension()
{
Extension extension = new Extension();

Description desc = new Description();
desc.setLabel(“DoubleCloud”);
desc.setSummary(“A sample extension with a new type of task.”);

ExtensionTaskTypeInfo etti = new ExtensionTaskTypeInfo();
etti.setTaskID(“AcmeBackupTask”);

ExtensionEventTypeInfo eeti = new ExtensionEventTypeInfo();
eeti.setEventID(“AcmeBackupEvent”);

KeyValue kv1 = new KeyValue();
kv1.setKey(“AcmeBackupTask.category”);
kv1.setValue(“info”);

KeyValue kv2 = new KeyValue();
kv2.setKey(“AcmeBackupTask.label”);
kv2.setValue(“Acme backup task”);

KeyValue kv3 = new KeyValue();
kv3.setKey(“AcmeBackupTask.fullFormat”);
kv3.setValue(“Acme backup virtual machines on host {hostname}”);

ExtensionResourceInfo eri = new ExtensionResourceInfo();
eri.setLocale(“en”);
eri.setModule(“task”);
eri.setData(new KeyValue[] {kv1, kv2, kv3});

extension.setDescription(desc);
extension.setKey(EXTENSION_KEY);
extension.setVersion(“1.0.0”);
extension.setLastHeartbeatTime(Calendar.getInstance());
extension.setCompany(“Acme Inc.”);
extension.setTaskList(new ExtensionTaskTypeInfo[] { etti });
extension.setEventList(new ExtensionEventTypeInfo[] { eeti });
extension.setResourceList(new ExtensionResourceInfo[] { eri });

return extension;
}
}

  1. September 9th, 2010 at 04:56 | #1

    Wow! It’s really awesome feture of vCenter.
    Steve is there any ability to set IP address (ip,netmask, gateway) to concrete ethernet adapater of VM by means of vCenter???

    I’ve tried a lot of things but unfortunatelly still there is no results.

  2. September 11th, 2010 at 00:35 | #2

    Do you mean you want to change the networking setting like IP address by connecting to vCenter server? What API have you tried?

    Steve

  3. Yogesh
    May 3rd, 2011 at 01:43 | #3

    Hi,

    I have used this in our product, but when I call findExtention on ExtensionManager it returns me a extension object with empty ResourceList. Do you know why this must be happening. I wanted to updateExtension due to some reasons and so I added some more events and resoure info list for new event keys and next updateExtension. But it overrides old values and the description in vSphere for old events is seen as XXX.

    Does any one know about this ? Please revert back if any solution / information.

    Regards,
    Yogesh G

  4. Bob Fletcher
    May 23rd, 2011 at 04:51 | #4

    This is the most comprehensive description I could find of how to do this- thanks!

    But there’s always one more question…

    In my case I was wondering how to specify some elements of the formatted message when an event is posted, rather than when the event type is specified in an extension.

    If I leave the formatted message empty in the definition and attempt to set it at creation-time, it is filled in with what looks like an identifier for this property, e.g. “event.com.my.event.blah”

    So, next, I assume that the {} syntax can be used for argument replacement at event-creation time. I assume that the use of {} in the formatted message will correspond to the arguments in the eventTypeSchema.
    However, I find that if I try to specify an XML event type schema using VI Java, the SOAP parser seems to be confused by the unexpected XML, (somewhat like the story of the boy called “Robert Drop Table” in xkcd!).

    The error trace is:
    —-
    Unexpected element tag “EventType” seen

    while parsing serialized value of type string
    at line 1, column 737

    while parsing property “eventTypeSchema” of static type string

    while parsing serialized DataObject of type vim.Extension.EventTypeInfo
    at line 1, column 678

    while parsing property “eventList” of static type ArrayOfExtensionEventTypeInfo

    while parsing serialized DataObject of type vim.Extension
    at line 1, column 377

    while parsing call information for method RegisterExtension
    at line 1, column 285

    while parsing SOAP body
    at line 1, column 271

    while parsing SOAP envelope
    at line 1, column 38

    while parsing HTTP request for method registerExtension
    on object of type vim.ExtensionManager
    at line 1, column 0
    —————————–

    Is there some way of “escaping” the XML, or is there another way of defining arguments for replacement at event creation time?

    Thanks!

  5. Bob Fletcher
    May 23rd, 2011 at 05:09 | #5

    @Bob Fletcher
    And of course, immediately after posting, I had a d’oh moment. Simply turn the of the eventTypeSchema into < and > and it works a treat. Hope this is of use to someone else…

  6. May 23rd, 2011 at 10:21 | #6

    Hi Bob,

    Glad you find it useful. If you want to include XML data in any string using vijava, you want to escape the 5 special characters like & etc.

    -Steve

  7. Bob Fletcher
    May 25th, 2011 at 07:30 | #7

    Great, thanks!

    I’m afraid I have a follow-up question…

    I find that when creating custom tasks as described, I get an error in the “Task” field of the corresponding event listing which looks like: “**NO DESCRIPTION FOR: AcmeBackup Task”.

    Where should this description be defined?

    I assumed the the “.fullFormat” key-value pair defined this, and have also tried using a “.summary” key as suggested elsewhere.

    I’ve also tried setting Task.setTaskDescription at creation time, but this resulted in an invalid request error…

    I’m using vSphere 5.0.0 beta if that’s relevant.

    Thanks!

  8. Frank Yang
    June 2nd, 2011 at 11:16 | #8

    @Yogesh
    Your obervation is correct. The resource list is always Unset in MOB and you won’t find it in returned extension object either. It is by design according to VMware. On the same token, updating resource list is actually creating a new one. So you will have to include previously defined events, in addition to new ones, in your call. BTW, the resources are stored in files not database: C:\Program Files\VMware\Infrastructure\VirtualCenter Server\extensions. However I will still use Web Service calls to alter these files to be safe.

  9. Frank Yang
    June 2nd, 2011 at 12:54 | #9

    @Bob Fletcher
    You have noticed the column head reads “Task”. So the key is “.label”, whose value shows up in othe two places as you may already see, and you should see “Acme backup event” after running Steve’s sample. I have tried my other apps with 5.0 and nothing is broken yet. So I doubt the version is the cause. It behaves as expected in both my C# and Java codes. I did observe this once while migrating my codes from C# to Java. Somehow it disappeared after I restarted my Java dev environment for a different reason.

  10. Prithvee
    December 6th, 2011 at 06:33 | #10

    This is about task notification. How can we post event which is not task?

  11. QuanT
    January 31st, 2012 at 21:13 | #11

    In my server extension, I define my event with ExtensionEventTypeInfo(), and in there I define the eventTypeSchema property with an XML that contains 1 argument (snip) chassisstring.
    I also register a message resource for use with this event type, which contains the .fullformat string as “Show {chassis} info”.

    Question: when I post an event, how should I pass in a value for this argument so that it replaces the {chassis} argument when displayed?

    To post an event of the above type, I first create an ExtendedEvent object and do a PostEvent(), but can’t find a way to get the event .fullformat string to show the {chassis} value. I played with the ExtendedEvent.data as well as ExtendedEvent.dynamicProperty but none worked.

  12. angelo
    February 3rd, 2012 at 08:33 | #12

    Hi I have successfully registered a task and can update its using task.setTaskState(state, null, null), where state is either TaskInfoState.error or TaskInfoState.success. The problem I am having is setting the status message when I have an error. The documentation suggests

    LocalizedMethodFault msg = new LocalizedMethodFault();
    msg.localizedMessage = “My error message”;
    msg.fault = null;
    vmTask.setTaskState(TaskInfoState.error, null, msg);

    But if I do this I get an exception thrown com.vmware.vim25.InvalidRequest
    This is driving me nuts. Does anyone have any idea? Should the localizedMessage be a key value lookup into a message catalogue somewhere?

  13. QuanT
    February 10th, 2012 at 13:12 | #13

    @QuanT
    The answer is to use EventEx instead of ExtendedEvent

  14. deepak
    May 10th, 2012 at 14:24 | #14

    @angelo

    Hi angelo, I’m hitting the same issue. were you able to fix it?

  15. syed
    May 14th, 2012 at 10:05 | #15

    Hi

    We are working on a vCenter plugin which has a number of custom tasks/events associated with it. We have successfully managed to achieve this using your example.

    The problem: Tasks/Events can be registered easily but when we unregister the plugin and then register it again with some new messages for Tasks/Events the old messages are shown instead of the new ones. I have noticed that on registration it creates .vmsg files in the following location:

    “C:\Program Files\VMware\Infrastructure\VirtualCenter Server\extensions\PLUGIN-KEY\locale\en\”

    Apparently these files also contain the updated strings each time the plugin is updated and registered with new strings. Inspecting the tasks from the mob somehow shows the old strings. When the tasks are run they still show those old strings that were supposed to have been updated. This is annoying.

    It appears as if the only way to update those messages is to reinstall the vcenter and then register the extension. Even in that case the strings can only be updated once unless the vCenter is reinstalled. Can someone please give an explanation for this behavior of plugin or point out what could have gone wrong?

  16. May 14th, 2012 at 18:23 | #16

    Good question. I haven’t gone that far to delete anything. What if you delete the .vmsf file after the unregistration? Please make sure to back it up though.
    Steve

  17. syed
    May 15th, 2012 at 03:49 | #17

    It appears as if that file has no effect on the string/messages shown inside the mob. So even when the plugin is registered and the file is deleted, the custom tasks continue to show the same old messages. If I delete these files after unregistering, they are created again when the plugin is registered but still this has no effect on the messages shown inside the mob.

    Can you please explain why those old messages continue to appear even after I re-register the plugin with the new ones? I have a feeling that there is some sort of key-value cache or database that does not get updated if we try to input a message having a key already present in that database.

  18. May 15th, 2012 at 22:23 | #18

    If that is the case, I think the information is also stored inside database, therefore recreated if the file is missing. You may want to open a SR with VMware support on this.

    Steve

  19. syed
    May 16th, 2012 at 04:18 | #19

    Hi Steve

    Thanks for your response. I have noticed that the information is cached somewhere and is not updated when a plugin is registered. If the vCenter services are restarted then everything is read again (probably from the text files) and the information in custom tasks or any other custom strings gets updated.

  20. angelo
    June 18th, 2012 at 04:00 | #20

    Deepak, no I never worked it out and worked around it, haven’t had time to return to it. I would appreciate an example if you managed to find out how to do it.
    QuanT, do you have an example of using EventEx to generate meaningful messages.

  21. Tejaswi
    December 24th, 2012 at 05:25 | #21

    how to create VM with the help pf Vsphere API?

  22. December 26th, 2012 at 12:47 | #22

    check out the source code of the API package – there is a sample showing how to create a new VM there.
    Steve

  23. kim
    February 5th, 2013 at 04:24 | #23

    how to get vm lists from 1 cluster using vi java?
    i m getting all the vms’s list ,but it does not display from which cluster they are belongs to…
    need ur help

  24. AJ
    February 26th, 2013 at 19:30 | #24

    @angelo

    Since vSphere 5.1 forces to specify “fault’ along for setTaskState with TaskInfostate.ERROR, I’m also running into same issue. Were you able to fix it?

  25. John
    June 23rd, 2014 at 16:45 | #25

    So I am able to do this fine, but I am having some trouble when it comes to updating the task with an ERROR state. All works fine when I update the task to a success state, but when I update the task with an error state I must be doing it wrong because the recent tasks pane breaks and I see this message (from the recent tasks pane):
    “faultCode:Server.Processing faultString:’An error error occurred while serializing server response(s). ‘faultDetail:’null’ ”

    I see someone here is having a similar problem: https://communities.vmware.com/message/2047506

    Except they are getting an invalid argument error.

    Can you provide an example of how to correctly set an error state on a task. I think that this would really complete this post.

  26. Nikolas
    February 4th, 2015 at 04:52 | #26

    Hi Steve,

    I’m trying to create a task in a specific Virtual Machine, to advert the VM User that the VM is “busy”, and unable to manage snapshots. Is it possible?

    I’ve also tried unabling doing snapshots, but I didn’t succes. Do you know what should I do?

    Thanks!

  27. February 4th, 2015 at 10:18 | #27

    Hi Nikolas,

    Are you trying to do something within the guest OS running on the VM and therefore want to disable snapshot function of the VM in vSphere Client?

    Steve

  28. Nikolas
    February 4th, 2015 at 11:06 | #28

    Hi Steve,

    Yes, something like that. I’m trying to copy the VM disks with a little program I’m developing. First of all, I do a snapshot in order to “liberate” the disks. Therefore I would like to disable snapshot function of the VM in vSphere Client during the operation.

    Thank you for your attention and I look forward to your comment!

    Nikolas

  29. February 4th, 2015 at 21:49 | #29

    Even if your vm is busy, the snapshot can still go forward. What is your concern?

    Steve

  30. Nikolas
    February 5th, 2015 at 03:21 | #30

    My main problem is that I can’t disable the snapshot function of the VM in vSphere Client while the copy is beeing made. And the second concern would be to show the VM user the progress bar of the copy.

    Thanks a lot!

    Nikolas

  31. February 6th, 2015 at 12:27 | #31

    There is a private API for you to do this, but not exposed. You can ask VMware for help.

  32. abhilasha
    February 20th, 2015 at 01:26 | #32

    @angelo

    Since vSphere 5.1 forces to specify “fault’ along for setTaskState with TaskInfostate.ERROR,
    I’m also running into same issue. It gives me InvalidMessageFault .Were you able to fix it?

    can you please provide the example to set the Task state to error.

  33. ZC
    October 7th, 2015 at 04:17 | #33

    Hi Steve,
    How would this example change for The vSphere Web Client 6.0 and it’s change in localization handling?

    The client still displays the task name as “AcmeBackupTask.label”, even though there is a translation key defined for it.

    KeyValue kv2 = new KeyValue();
    kv2.setKey(“AcmeBackupTask.label”);
    kv2.setValue(“Acme backup task”);

    Thanks!

  1. No trackbacks yet.