Click here to Skip to main content
Click here to Skip to main content

Automating VMWare Tasks in C# with the VIX API

, 13 Feb 2009 MIT
Rate this:
Please Sign up or sign in to vote.
A VMWare C# tasks library.
VMWare

Introduction

I've been playing with VMware lately, both Workstation and VMware Infrastructure (VI). The company has really stepped up with the new SDKs and the level of programmable interfaces, making some excellent implementation decisions that enable developers to drive virtual machines programmatically with an asynchronous, job-based programming model. Unfortunately that turns out to be too complicated for 99.9% of scenarios and most developers want to use a simple object-oriented interface for common VMWare tasks. The VMWareTasks library implements that interface and makes programming against virtual machine a no brainer. This article explains how to use the library and discusses some of its implementation details.

Background

There're two types of VMWare APIs.

  • VMWare Virtual Infrastructure SDK: a set of tools and APIs to manage a VMWare Infrastructure environment. A toolkit has also been released that contains managed wrappers on top of the SOAP interface provided by a VMWare deployment. It's focused on VMWare ESX or VirtualCenter management and is beyond the scope of this article.
  • VMWare VIX API. The VIX API allows developers to write programs and scripts that automate virtual machine operations, as well as the guests within virtual machines. It runs on both Windows and Linux and supports management of VMware Server, Workstation, and Virtual Infrastructure (both ESX and vCenter). Bindings are provided for C, Perl, and COM (Visual Basic, VBscript, C#). In this post, I'll focus on the C# implementation.

Using the Library

In order to use the library or build or run the source code, you must install the following VMWare software.

In your project, add a reference to Vestris.VMWareLib.dll and a namespace reference.

using Vestris.VMWareLib;

You can now connect to a local VMWare Workstation or a remote ESX server and perform VMWare tasks. Here's an example that creates, restores, powers on and removes a snapshot on a VMWare Workstation.

// declare a virtual host
VMWareVirtualHost virtualHost = new VMWareVirtualHost();
// connect to a local (VMWare Workstation) virtual machine
virtualHost.ConnectToVMWareWorkstation();
// open an existing virtual machine
VMWareVirtualMachine virtualMachine = virtualHost.Open("C:\Virtual Machines\xp\xp.vmx");
// power on this virtual machine
virtualMachine.PowerOn();
// login to the virtual machine
virtualMachine.Login("Administrator", "password");
// run notepad
virtualMachine.RunProgramInGuest("notepad.exe", string.Empty);
// create a new snapshot
string name = "New Snapshot";
// take a snapshot at the current state
virtualMachine.Snapshots.CreateSnapshot(name, "test snapshot");
// power off
virtualMachine.PowerOff();
// find the newly created snapshot
VMWareSnapshot snapshot = virtualMachine.Snapshots.GetNamedSnapshot(name);
// revert to the new snapshot
snapshot.RevertToSnapshot();
// delete snapshot
snapshot.RemoveSnapshot();

Implementation

The following sections describe VMWareTasks library implementation details. It's absolutely not necessary to understand those in order to use the library.

Connecting to VMWare in pure VIX API

Connecting synchronously to either a local VMWare Workstation or an ESX server is virtually identical. The ESX server requires a URL to the SOAP SDK (eg. https://esxserver/sdk) and a username and password.

public IHost ConnectToVMWareWorkstation()
{
    return Connect(Constants.VIX_SERVICEPROVIDER_VMWARE_WORKSTATION, 
		string.Empty, 0, string.Empty, string.Empty);
}

public IHost ConnectToVMWareVIServer(string hostName, int hostPort, 
			string username, string password)
{
    return Connect(Constants.VIX_SERVICEPROVIDER_VMWARE_VI_SERVER,  
			hostName, hostPort, username, password);
}

public IHost Connect(int hostType, string hostName, int hostPort, 
			string username, string password)
{
    VixLib vix = new VixLib();
    IJob vmJob = vix.Connect(Constants.VIX_API_VERSION, hostType, 
		hostName, hostPort, username, password, 0, null, null);
    // You need to get the IHost object that represents the host 
    // where your VM is located.
    // Since COM allocates the object you need to use this funky mechanism 
    // to extract the IHosts array.
    object[] properties = { Constants.VIX_PROPERTY_JOB_RESULT_HANDLE };
    // Wait for the operation to complete
    object hosts = VmwareVixInterop.Wait(vmJob, properties);
    object[] hostArray = hosts as object[];
    return (IHost) hostArray[0];
}

You have to declare an array of properties that you want the job to produce, start a VMWare job and examine the results for the host handle. You can see how cumbersome this is! The API was originally designed for C, then extended to COM with a very limited object model: a number of interfaces were declared, but no corresponding COM classes have been implemented. Also, because the job interface is generic, there're no strongly typed results.

We can easily fill this gap in our C# implementation.

Transforming Error Codes into Exceptions

The first task for wrapping any API is to implement error handling. Our managed implementation must translate error codes into managed exceptions. VIX API provides an implementation for the IVixLib interface which contains a couple of helper methods (very C-programmer). We'll be interested in IVixLib.ErrorIndicatesFailure and IVixLib.GetErrorText combined with a new class, VMWareException.

public abstract class VMWareInterop
{
    public static VixLib Instance = new VixLib();

    public static void Check(ulong errCode)
    {
        if (Instance.ErrorIndicatesFailure(errCode))
        {
            throw new VMWareException(errCode);
        }
    }
}  

Aside from the abstract VMWareInterop, our goal is to produce concrete classes that wrap various aspects of VMWare functionality.

Base VMWareVixHandle

VMWare COM API returns interface pointers such as ISnapshot. The objects also implement IVixHandle which gives access to a set of object properties. We will base-class everything on VMWareVixHandle.

public class VMWareVixHandle<T>
{
    protected T _handle = default(T);

    protected IVixHandle _vixhandle
    {
        get
        {
            return (IVixHandle) _handle;
        }
    }

    public VMWareVixHandle()
    {

    }

    public VMWareVixHandle(T handle)
    {
        _handle = handle;
    }

    public object[] GetProperties(object[] properties)
    {
        object result = null;
        VMWareInterop.Check(_vixhandle.GetProperties(properties, ref result));
        return (object[]) result;
    }

    public R GetProperty<R>(int propertyId)
    {
        object[] properties = { propertyId };
        return (R) GetProperties(properties)[0];
    }
}  

Implementing VMWareJob

Since all operations in VMWare are job-based, let's wrap up a job. If we use the COM API directly, we would have to call IVixLib.Wait passing a job handle. In an object-oriented library, this operation belongs inside the job, plus a job is also a VMWareVixHandle.

 public class VMWareJob : VMWareVixHandle<IJob>
 {
     public VMWareJob(IJob job)
         : base(job)
     {

     }

     public void Wait()
     {
         VMWareInterop.Check(_handle.WaitWithoutResults());
     }
 }  

One very common problem in VMWare API implementations that transform an asynchronous job into a synchronous one is to use the blocking wait above. This is a bad design decision since this call may never return. VMWare server may timeout or someone can pull the network cable, leaving your program hanging. I originally wrote a busy wait where all externally visible wait functions were based on the following InternalWait.

private void InternalWait(int timeoutInSeconds)
{
    if (timeoutInSeconds == 0)
    {
        throw new ArgumentOutOfRangeException("timeoutInSeconds");
    }

    // active wait for the job to finish
    bool isComplete = false;
    while (!isComplete && timeoutInSeconds > 0)
    {
        VMWareInterop.Check(_handle.CheckCompletion(out isComplete));
        if (isComplete) break;
        Thread.Sleep(1000);
        timeoutInSeconds--;
    }

    if (timeoutInSeconds == 0)
    {
        throw new TimeoutException();
    }
}

A more elegant implementation combines a callback mechanism provided by VixCOM with every asynchronous API and a blocking wait with a timeout. Wait is now signaled and there's no CPU spin waiting for completion of an asynchronous API call.

public class VMWareJobCallback : ICallback
{
    #region ICallback Members

    private EventWaitHandle _jobCompleted = new EventWaitHandle(
         false, EventResetMode.ManualReset);

    public void OnVixEvent(IJob job, int eventType, IVixHandle moreEventInfo)
    {
        switch (eventType)
        {
            case VixCOM.Constants.VIX_EVENTTYPE_JOB_COMPLETED:
                _jobCompleted.Set();
                break;
        }
    }

    public bool TryWaitForCompletion(int timeoutInMilliseconds)
    {
        return _jobCompleted.WaitOne(timeoutInMilliseconds, false);
    }

    public void WaitForCompletion(int timeoutInMilliseconds)
    {
        if (!TryWaitForCompletion(timeoutInMilliseconds))
        {
            throw new TimeoutException();
        }
    }

    #endregion
}  

This and some generic code in VMWareJob can now be used inside Connect. I have modified VMWareJob to require a VMWareCallback in order to prevent callers from ever having a blocking wait.

VMWareJobCallback callback = new VMWareJobCallback();
VMWareJob job = new VMWareJob(VMWareInterop.Instance.Connect(
    Constants.VIX_API_VERSION, Constants.VIX_SERVICEPROVIDER_VMWARE_SERVER, 
	hostName, hostPort, username, password, 0, null, callback), callback); 

VMWareVirtualHost

With VMWareJob and VMWareException, it's now possible to implement VMWareVirtualHost and connect to it. Note references to default timeouts (a collection of constants) and some facilities in VMWareJob that add strong typing into VMWare job results.

public class VMWareVirtualHost
{
    private IHost _host = null;

    public VMWareVirtualHost()
    {

    }

    public void ConnectToVMWareWorkstation()
    {
        ConnectToVMWareWorkstation(VMWareInterop.Timeouts.ConnectTimeout);
    }

    public void ConnectToVMWareWorkstation(int timeoutInSeconds)
    {
        Connect(Constants.VIX_SERVICEPROVIDER_VMWARE_WORKSTATION,
            string.Empty, 0, string.Empty, string.Empty, timeoutInSeconds);
    }

    private void Connect(int hostType, string hostName, 
	int hostPort, string username, string password, int timeout)
    {
        int serviceProvider = (int)serviceProviderType;
        VMWareJobCallback callback = new VMWareJobCallback();
        VMWareJob job = new VMWareJob(VMWareInterop.Instance.Connect(
            Constants.VIX_API_VERSION, serviceProvider, hostName, hostPort,
            username, password, 0, null, callback), callback);

        _handle = job.Wait
<ihost />(Constants.VIX_PROPERTY_JOB_RESULT_HANDLE, timeout);
        _serviceProviderType = serviceProviderType;
    }
}

VMWareVirtualHost can now implement opening of an actual virtual machine and return an instance of VMWareVirtualMachine.

public VMWareVirtualMachine Open(string fileName, int timeoutInSeconds)
{
    VMWareJobCallback callback = new VMWareJobCallback();
    VMWareJob job = new VMWareJob(_handle.OpenVM(fileName, callback), callback);
    return new VMWareVirtualMachine(job.Wait<ivm2>
    (
        Constants.VIX_PROPERTY_JOB_RESULT_HANDLE,
        timeoutInSeconds));
}

Based on this model, we can code many functions of VMWareVirtualMachine, VMWareSnapshot, etc. The rest is implementation details.

Advanced Implementation Details

Yielding Property Arrays

One of the peculiar VIX COM API constructs is the combination that returns arrays of properties. This is done with two functions: GetNumProperties and GetNthProperties. The first returns the number of property arrays returned by the job and the second fetches a property array at a given index. The first obvious step is to wrap the functions within the job class.

public T GetNthProperties<T>(int index, object[] properties)
{
    object result = null;
    VMWareInterop.Check(_handle.GetNthProperties(index, properties, ref result));
    return (T) result;
}

public int GetNumProperties(int property)
{
    return _handle.GetNumProperties(property);
}

We can now write such properties as RunningVirtualMachines.

public IEnumerable<VMWareVirtualMachine> RunningVirtualMachines
{
    get
    {
        VMWareJobCallback callback = new VMWareJobCallback();
        VMWareJob job = new VMWareJob(_handle.FindItems(
            Constants.VIX_FIND_RUNNING_VMS, null, -1, callback),
            callback);
        object[] properties = { Constants.VIX_PROPERTY_FOUND_ITEM_LOCATION };
        for (int i = 0; i < job.GetNumProperties((int) properties[0]); i++)
        {
            yield return this.Open(
                (string) job.GetNthProperties<object[]>(i, properties)[0]);
        }
    }
}

This is nice, but still not good enough. Let's combine the number of results and the results themselves in a YieldWait method.

public IEnumerable <object[]> YieldWait(object[] properties, int timeoutInSeconds)
{
    Wait(timeoutInSeconds);
    for (int i = 0; i < GetNumProperties((int)properties[0]); i++)
    {
        yield return GetNthProperties<object[]>(i, properties);
    }
}

This results in a nice improvement over the previous implementation.

public IEnumerable<VMWareVirtualMachine> RunningVirtualMachines
{
    get
    {
        VMWareJobCallback callback = new VMWareJobCallback();
        VMWareJob job = new VMWareJob(_handle.FindItems(
            Constants.VIX_FIND_RUNNING_VMS, null, -1, callback),
            callback);
        foreach (object[] runningVirtualMachine in job.YieldWait
		(properties, VMWareInterop.Timeouts.FindItemsTimeout))
        {
            yield return this.Open((string) runningVirtualMachine[0]);
        }
    }
}  

Dates and Times

Date/time in VMWare VIX is expressed in UNIX EPOCH (number of seconds since January 1st, 1970).

DateTime currentDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0).AddSeconds((int) dt);

Source Code and Patches

This project lives on CodePlex at http://www.codeplex.com/vmwaretasks. You can find the latest information about this library at code.dblock.org. You're encouraged to submit patches for added functionality and bug fixes.

History

  • 12/22/2008: Initial article, version 1.0
  • 02/11/2009: Revised "Using VMWareTasks" and described implementation of a blocking job wait
  • 02/12/2009: Moved to CodePlex, version 1.1

License

This article, along with any associated source code and files, is licensed under The MIT License

Share

About the Author

dB.
Team Leader Application Security Inc., www.appsecinc.com
United States United States
Daniel Doubrovkine has been in software engineering for twelve years and is currently development manager at Application Security Inc. in New York City. He has been involved in many software ventures, including Xo3 and Vestris Inc, was a development lead at Microsoft Corp. in Redmond, and director of Engineering at Visible Path Corp. in New York City. Daniel also builds and runs a foodie website, http://www.foodcandy.com.

Comments and Discussions

 
QuestionAutomating VMWare Tacks From Remote Desktop PinmemberNitishSharma17-Feb-13 13:40 
QuestionHow to revert child snap shot in Vmware using C# PinmemberBiju Krishnan8-Jan-13 23:35 
QuestionGet the name of a snapshot Pinmembermarkus133717-Aug-12 1:47 
AnswerRe: Get the name of a snapshot PinmemberdB.17-Aug-12 4:11 
QuestionNeed help on VMWare automations PinmemberV.J. Kumar16-Jul-12 2:08 
AnswerRe: Need help on VMWare automations PinmemberdB.16-Jul-12 3:08 
QuestionCant connect PinmemberChad Z. Hower aka Kudzu15-Jun-12 13:43 
For anyone who has trouble with not being able to connect, here is the solution:
 
http://www.tellingmachine.com/post/Too-much-VMWare-can-cause-Unable-to-connect-to-host-Error-The-specified-version-was-not-found.aspx[^]
 
VMWare apparently is quite sloppy about this. I had two of these txt files and the one in the vmware dir only supported 8.0.0, not 8.0.1.
Chad Z. Hower, a.k.a. Kudzu
"Programming is an art form that fights back"
 
My Technical Stuff:
http://www.KudzuWorld.com
 
My Blogs:
http://www.KudzuWorld.com/blogs/

Questionstrong named or VS 2010 version? PinmemberChad Z. Hower aka Kudzu15-Jun-12 10:57 
AnswerRe: strong named or VS 2010 version? PinmemberdB.15-Jun-12 11:06 
QuestionMulty-Thread functionality PinmemberPaulMinsk9-Feb-12 1:20 
AnswerRe: Multy-Thread functionality PinmemberdB.9-Feb-12 4:09 
GeneralMy vote of 4 PinmemberAsim Javed17-Jan-12 2:01 
GeneralMy vote of 5 PinmemberHari Om Prakash Sharma23-Oct-11 22:40 
QuestionLogin WinXP/Win7 PinmemberMarkuss2125-Aug-11 1:27 
AnswerRe: Login WinXP/Win7 PinmemberdB.25-Aug-11 5:24 
GeneralRunProgramInGuest Pinmembericmonicky22-May-11 19:58 
GeneralRe: RunProgramInGuest PinmemberdB.23-May-11 1:02 
GeneralMy vote of 5 Pinmemberjim lahey13-Apr-11 4:30 
QuestionIs .vmx file only one way to get a virtual machine? Pinmembersurite6-Jul-10 23:57 
AnswerPLEASE POST QUESTIONS ON CODEPLEX PinmemberdB.7-Jul-10 1:08 
Generalunable to connect to VMserver from aspx page Pinmembernkoleilat31-May-10 21:54 
GeneralPLEASE POST QUESTIONS ON CODEPLEX PinmemberdB.1-Jun-10 1:34 
GeneralList Running Virtual Machines Pinmembersdhillon0716-Feb-10 9:44 
GeneralPLEASE POST QUESTIONS ON CODEPLEX PinmemberdB.16-Feb-10 10:16 
GeneralException: A file was not found Pinmemberalbertitomd30-Nov-09 8:37 
GeneralPLEASE POST QUESTIONS ON CODEPLEX PinmemberdB.30-Nov-09 8:41 
QuestionHow Can i get memory an Cpu usage? PinmemberMember 406479825-Sep-09 4:54 
AnswerPLEASE POST QUESTIONS ON CODEPLEX PinmemberdB.25-Sep-09 9:28 
Generalvery good vmae article PinmemberDonsw14-Jun-09 16:17 
GeneralRe: very good vmae article PinmemberdB.11-Aug-09 2:50 
GeneralPLEASE POST QUESTIONS ON CODEPLEX, NOT HERE PinmemberdB.14-Jun-09 5:18 
QuestionHow to swtich between powerup VMs using vix api Pinmemberhamidzaidi10-Jun-09 2:39 
AnswerRe: How to swtich between powerup VMs using vix api PinmemberdB.10-Jun-09 3:45 
GeneralUsing this API to manage multiple task on an ESX server Pinmemberjbc19-Jun-09 5:50 
GeneralRe: Using this API to manage multiple task on an ESX server PinmemberdB.10-Jun-09 3:45 
GeneralPlease supply a code snippet how I can read vm properties PinmemberMember 39992452-Jun-09 22:36 
GeneralRe: Please supply a code snippet how I can read vm properties PinmemberdB.7-Jun-09 3:09 
QuestionHow do I find out if a VM is a linked clone of another VM? PinmemberMember 39992452-Jun-09 22:32 
AnswerRe: How do I find out if a VM is a linked clone of another VM? PinmemberdB.3-Jun-09 2:59 
QuestionException by conect to vmware ESXi 3.5 U4 or vmwarews 3.5.1 please help Pinmembermarc.peter@frsglobal.com4-May-09 1:01 
AnswerRe: Exception by conect to vmware ESXi 3.5 U4 or vmwarews 3.5.1 please help PinmemberdB.4-May-09 3:41 
GeneralRe: Exception by conect to vmware ESXi 3.5 U4 or vmwarews 3.5.1 please help Pinmembermarc.peter@frsglobal.com4-May-09 8:23 
GeneralRe: Exception by conect to vmware ESXi 3.5 U4 or vmwarews 3.5.1 please help PinmemberdB.5-May-09 7:15 
GeneralRe: Exception by conect to vmware ESXi 3.5 U4 or vmwarews 3.5.1 please help Pinmembersupersidor15-Oct-09 6:58 
GeneralVMWareTasks 1.2 has been released PinmemberdB.21-Apr-09 10:47 
Questionenvironment variables? Pinmemberjbc17-Apr-09 1:30 
AnswerRe: environment variables? PinmemberdB.7-Apr-09 4:10 
GeneralRe: environment variables? Pinmemberjbc17-Apr-09 4:20 
GeneralRe: environment variables? PinmemberdB.8-Apr-09 15:41 
GeneralRe: environment variables? Pinmemberjbc19-Apr-09 1:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.141022.2 | Last Updated 13 Feb 2009
Article Copyright 2008 by dB.
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid