I have a bunch of one off scripts and modules I’ve written for a VI Migration I performed last week. The task was to migrate a moderate VI farm (15 hosts 100+ vm) from AMD based server to Intel in a ridiculous 20min window. I played with the idea of setting masks in the vmx, but ultimately that itself would require a reboot. In the end I wrote a series of small scripts that handled the whole thing for me. That has become my MO as of late… get a task write a couple quick functions then a small script that uses those functions. I have to get approval from my client to post the scripts (even though there’s nothing in them they were written on their network) so in the mean time I thought I would share how I navigate the VI API, and create new functionality.
We’ll start with something simple; my home lab has a pesky problem. My ESXi hosts always disconnect from vCenter… More of an annoyance really, but still I wanted a quick way to fix it. Where to start, we’ll probably need to get below the VITK, and work with the VI objects directly. To do that we need to start by getting an instance of our target object in this case a VMhost.
Tip 1; Keep it simple, don’t write the total solution take small bites at a problem. As you can see I have two hosts in my farm to avoid complicating things we need only a single instance! Also as you work your way through a problem avoid using variable names like $a. While it may seem faster remember you’ll be copying most of this later into your “script”. Start off right name your variables after the objects they contain. Additionally you really need to run two commands against anything you get from the VI API. You’ll waste a ton of time otherwise, always run the GetType() method, and the Get-Member cmdlet against any objects you get. Be mindful of the methods available and if an instance or a collection was returned!
Here we can see that GetType() has confirmed that we have a single instance of a VMHostImpl object.
Unfortunately VMHostImpl is a pointer to the real object. To get the real Managed Object from the impl use the Get-View cmdlet. Unfortunately, VMHostImpl is an Automation Object, Automation Objects are small light weight objects used to pass key data between cmdlets. Fortunately, VMHostImpl is an Unsynthesized Automation Object, meaning it corresponds to a full Managed Object! So how can we transform VMHostImpl to a full .Net object? Enter the Get-View cmdlet, The Get-View cmdlet will take an Unsynthesized object and return the full Managed Object. This is important because all 300+ methods that enable direct manipulation of vCenter only exist within managed objects. When you need to extend the VI Toolkit (write your own functions) you’ll need a Managed Object.
A fantastic explanation of VMware’s object model is provided in the VI Toolkit Lab Manual: VMworld Euroup 2009: section9
Enough of that let’s get that Managed Object, as always check the type. You should get an object back that is derived from VMware.Vim.ManagedEntity (aka a Managed Object).
Ahh, that is much better just look at all the great stuff… A quick scan reveals that there is a native method that handles reconnecting a disconnected VMHost for us.
TIP 2; When dealing with a new method call the method without any parentheses to retrieve any overloads. An overload is a definition of the methods signature… It’ll tell you what you need where for it to all work!
So whether we perform a reconnect operation asynchronously via the ReconnectHost_Task method or synchronously via the ReconnectHost method… either way we’ll need an instance of a HostConnectSpec. Where does one find such a thing, if there were only a web site that spelled all this out? You will have a love hate relationship with the VI API Developers reference. It doesn’t always translate too well into the .Net representation of the API, but it’s all in there. My Perl counterparts typically will start there and then code, but with PowerShells discoverability I prefer to stay in the console as much as possible. Most of the object in the VI API are derived from DynamicData and are instantiated from VMware.Vim (in a pinch just try that first).
As always, keep your variables simple but descriptive. The developers at VMware probably banged their heads for months naming all this stuff. Where possible Just name your obejcts after the types they represent/contain! This will pay dividends when you start to paste several of these into a larger script. Again check the object for any methods, run it through gettype(), and Get-Member!
So we have our object but what properties need to be set, and with what? At this point if you haven’t already head on over to the VI API Ref. Since we already know our Data Object Type just click the Data Object types on the right side and search for HostConnectSpec. Hit the link and you’ll be brought to the documentation for the HostConnectSpec Data type.
Here you’ll find everything you need to know about this little guy. Every method that uses it, where it extends from and what extends from it. I really do have to take my hat off to VMware here, as an Admin I loathe having to referance developer documentation, but they’ve done a great job. If you read through you’ll discover that the HostConnectSpec is used primarily to Add a host to vCenter. Well since our host is already in vCenter we can skip all that stuff, and go straight to what we do need.
To connect our host all we need is a HostName, and Port number.
TIP 3; At all costs avoid hard coding anything. We could easily just require the user to enter this information. Or we could just set defaults and provide an override for say the port, but in reality either of those would be poor code! Fact, It’s in VIC so all this data is in the SDK somewhere… FIND IT!
For some odd reason I prefer stumbling through an object looking for the desired data. While this isn’t the most efficient method it will enlighten you exactly how much data is in there! For time sake though just go back to the VI API REF, and click the All Properties link at the top of the page. Scroll all the way down until you find PORT. You’ll notice that next to each property it shows what object contains that property. It just so happens the one we need is right there on the top. Port(HostConfigSummary) -> Click it.
Now we need to find this object, and it’s reference to us in the API. We need to make a map of how to get to it programmatically. To do this just walk back along the “Property of” links on the top of the page until you find something familiar. Sometimes it’s necessary to walk all the way to the root managed object reference, and it can be a pain, but it works! HostConfigSummary is a Property of HostListSummmary and host list summary is a Property of HostSystem! Now just walk it back using the HostSystem Object we got earlier.
As you can see the property names don’t match what we found in the SDK Documentation, but the Object Types do so just shift your eye to the left and look for the type you need!
Putting it all together; we should now have everything we need to programmatically correct my disconnected host, but still always prove it in the console before you go, and start writing a script/function.
Task: Fix my host
- Get an instance of our VMHost
- Get the Managed Object from that instance
- Create a new HostConnectSpec using the values already present in vCenter
- Call the ReConnectHost method with our new HostConnectSpec
So there you have it now that you have the logic to accomplish a given task writing a Function or Script is really just adding documentation! I would also recommend creating this stuff in pares i.e. if we create a script to reconnect a given host we should also write one to disconnect a host. As I did with my example here:
In action with PoshCode:
So that’s a rough overview how I use the VI Toolkit to automate vCenter. As always feel free to call me out if you spot a mistake!
Update: Well it took Carter –lt 10min to call me out on this one… Yes I Could have used Set-VMHost –state, but I was cherry picking the SDK 😀