The preferred mechanism for programmatically interacting with VI3 is the SDK, not the commands available in the ESX COS (such as the suite of commands prefixed with "esxcfg" found in /usr/sbin). The SDK is very powerful, and its power can be harnessed with another equally powerful tool, .NET. In this article, I will describe the beginning steps you must take as you start down the path toward leveraging the VI3 SDK with .NET using C#.
The first step to leverage the VI3 SDK with .NET is to understand the VI3 SDK. This text is but one part in a series of articles that will explain how to use a complex piece of software, and this article should not be thought of as the golden standard for reference material on the subject. This text is meant to be a companion to VMware's own documentation, such as the "VMware Infrastructure Getting Started Guide," "VMware Infrastructure Programming Guide," and the "VMware Infrastructure SDK Reference Guide." This documentation is available as part of the VMware VI3 SDK or individually (with the exception of the Reference Guide).
In this article, I will discuss the two of the SDK's concepts that one must understand to write even the most basic code, and I will attempt to relate new concepts to familiar ones in order to make them easier to understand. The first section will discuss the SDK's two object types, managed objects and data objects. The second section will cover the VI3 hierarchy and structure.
Managed objects and data objects
A note: The VI3 SDK reference material uses the terminology "managed objects" and "data objects" when it should actually refer to them as "managed classes" and "data classes." Because the VI3 SDK reference material does not distinguish between classes and objects instantiated from those classes, I will not either except where I explicitly note otherwise.
The SDK will appear a little unusual to most traditional .NET developers. When we think of SDKs, we are used to an assembly that exposes a series of instantiable classes and methods that provide their own help contexts with the joyous technology called Intellisense. The VI3 SDK is, however, exposed via another technology familiar to .NET developers, Web services. As most .NET developers know, .NET makes working with Web services wonderfully easy by generating client-side code based on the Web Services Description Language (WSDL) file. Yet even if client-side code exists for a type exposed via a Web service, that type must be serializable in order for its data to be passed from the server to the client. Serialization is the process by which an object is converted into a persistable format (such as a string) so that it can be saved to disk or transmitted across the network. Type serialization is, in fact, one of the three characteristics that define the differences between the SDK's two primary object types, managed objects and data objects.
A managed object has two defining characteristics. First, a managed object does not exist in the VI3 SDK WSDL schema. The implication of this is that the .NET wsdl.exe tool does not generate class definitions for managed objects. That brings me to the second characteristic of managed objects. Managed objects are not serializable and therefore are not passed from the server to the client, meaning that managed objects are not accessed from the client directly but rather through managed object references (MOREF). Understanding this concept is very important, because it defines the location and the signatures of most of the useful SDK methods. Most SDK methods are not defined on many managed objects but are in fact defined on a single central managed object and expect a MOREF as their first parameter.
This type of method signature may seem unusual to .NET developers, because we are used to the traditional object oriented design of a class defining its methods rather than some central class defining several methods from a combination of different classes (if you have any experience programming in Objective C for Mac OS X you should feel right at home).
If this is all too confusing, let me explain it another way. Imagine we have two classes named EsxServer and VirtualMachine. These two classes contain useful methods such as EsxServer.Shutdown, EsxServer.StartMaintenance, VirtualMachine.StartVMotion and VirtualMachine.Suspend. Make sense so far? Now, here is the unusual part. Instead of each class defining its own methods, all of the methods are defined on a central class VimService (more on VimService later) and the methods expect as their first parameter a reference to an object of the original class -- a managed object reference. Have I lost you? Take a look at this ManagedObject (Class)/Method relationship comparison between a traditional API and the VI3 SDK:
Standard Class/Method Relationship: class EsxServer method Shutdown method StartMaintenance class VirtualMachine method StartVMotion method Suspend VI3 SDK ManagedObject (Class)/Method Relationship: ManagedObject VimService method ShutdownEsxServer( ManagedObjectReference EsxServer ) method StartMaintenanceEsxServer( ManagedObjectReference EsxServer ) method StartVMotionVirtualMachine( ManagedObjectReference VirtualMachine ) method SuspendVirtualMachine( ManagedObjectReference VirtualMachine )
As you can see, the methods that are traditionally defined on the classes EsxServer and VirtualMachine are instead defined on a managed object called VimService and expect a reference to their respective managed objects.
You may be asking, "What is the VimService managed object and why does it appear to define all of the methods?" VimService is the name that the VI3 SDK gives to the managed object ServiceInstance. The managed object ServiceInstance is the most important managed object in the VI3 SDK. Per the VMware Infrastructure SDK Programming Guide, it is "the central access point for all management data in the VMware Infrastructure SDK." This managed object defines most, if not all (I have not checked all of them so I cannot say for sure), of the SDK's methods. Learn it, like it, love it.
The defining characteristic of a data object is that, unlike a managed object, it is serializable and instantiable in client code. A data object defines useful properties on itself such as the data object HostPortGroupSpec. This object represents a port group defined on a host and lets a client access information such as the name of the port group, the virtual switch to which the port group belongs and the VLAN ID the port group uses.
For more specifics on managed objects and data objects, please refer to page 20 of the "VMware Infrastructure SDK Programming Guide."
The VI3 SDK hierarchy and structure
The VI3 SDK logically organizes the virtual infrastructure into a structured hierarchy. Understanding this hierarchy is the key to being able to access the data within it. As foreboding as this all sounds, the hierarchy is actually quite simple. There are two different, but similar, hierarchies, depending on whether or not the SDK is being accessed via VirtualCenter or directly on an ESX server, as illustrated on page 24 of the "VMware Infrastructure SDK Programming Guide." There should be very few cases where it even matters whether or not a client is accessing the SDK via VirtualCenter or directly on an ESX host. Again, knowledge of the SDK structure is quite important because the only way to access managed objects and data objects is by building and executing search queries against the SDK hierarchy.
The important thing to remember about the VI3 SDK hierarchy is that to get from point A to point D, points B and C somehow have to be traversed as well. There are no shortcuts. It is not necessary to take any action whatsoever on points B and C, but they have to be accounted for when searching for point D from a search base of point A. This may seem odd, but try to look at the VI3 SDK hierarchy as a special type of file system. This file system contains four types of special folders: 1) the root folder - all other folders and files exist beneath this folder, 2) a documents folder - this folder can contain document files, 3) a music folder - this folder can contain music files and 4) a media folder - this folder can contain video or music files and music folders. It would look something like this:
Parent - RootFolder Possible SubFolders - DocumentFolder, MusicFolder, VideoFolder, MediaFolder Possible Files - DocumentFiles, MusicFiles, VideoFiles Parent - DocumentFolder Possible Files - DocumentFiles Parent - MusicFolder Possible Files - MusicFiles Parent - VideoFolder Possible Files - VideoFiles Parent - MediaFolder Possible SubFolders - MusicFolder Possible Files - MusicFiles, VideoFiles
Now imagine if the layout of this file system as it existed on someone's hard drive looked like this:
RootFolder DocumentFolder_1 DocumentFile_1 DocumentFile_2 VideFolder_1 VideoFile_1 MediaFolder_1 MusicFolder_1 MusicFile_1 MusicFile_2 MusicFile_3 VideoFile_2
In this scenario, Point A is the folder "RootFolder." Point D is the music file "MusicFIle_2." Using the same logic as the VI3 SDK, it is not possible to simply search for a file named MusicFile_2 from RootFolder. All possible parent --> child relationships must be defined as part of the search criteria. For this situation the search criteria would read like:
RootFolder --> MusicFolder RootFolder --> MediaFolder RootFolder --> MusicFile MusicFolder --> MusicFile MediaFolder --> MusicFolder MediaFolder --> MusicFile
The actual path to the file is much more straightforward; it is RootFolder --> MediaFolder --> MusicFolder --> MusicFile. In fact, the only parent --> child relationships that must be defined in order to find MusicFile_2 are:
RootFolder --> MediaFolder MediaFolder --> MusicFolder MusicFolder --> MusicFile
This is called building a static path. If the location of the desired object is always known ahead of time, then this is a perfectly valid approach. But many times the location of the object, in this case MusicFile_2, is not known, and all possible parent --> child relationships that could lead to the object must be accounted for in order to ensure finding the object (if it exists at all). For more details on the specifics of searching the VI3 SDK hierarchy, please refer to page 83 of the "VMware Infrastructure SDK Getting Started Guide." I will also be demonstrating a simple, real-world example of searching the VI3 SDK hierarchy in the next article of this series.
I hope that I have been able to shed some light on some of the more complicated portions of the VMware VI3 SDK. Please be sure to take a look at the next article in the series. I will talk about what version of .NET to use, how to generate client-side code and demonstrate a simple, real-world program written in C# that interacts with the VI3 SDK. Until next time!
Andrew Kutz is deeply embedded in the dark, dangerous world of virtualization. Andrew is an avid fan of .NET, open source, Terminal Services, coding and comics. He is a Microsoft Certified Solutions Developer (MCSD) and a SANS/GIAC Certified Windows Security Administrator (GCWN). Andrew graduated from the University of Texas at Austin with a BA in Ancient History and Classical Civilization and currently lives in Austin, Tex., with his wife Mandy and their two puppies, Lucy and CJ.
This was first published in October 2007