Geaux Virtual

Helping virtualize the datacenter…

Archive for the ‘Scripting’ Category

Follow up on ESXCLI with PowerCLI

with 3 comments

In a previous post here, Applying Patches to ESXi 5 with the help of PowerCLI, I showed how simple it was to call ESXCLI that is part of vCLI through a PowerCLI script, but did you know that ESXCLI is also part of PowerCLI?

ESXCLI is actually part of the VMware API for an ESXi host. Note: While the API for vSphere 4 also had ESXCLI included, it is much more robust with vSphere 5. Most if not all of the commands I show will only work against vSphere 5. PowerCLI has a cmdlet called Get-EsxCli that can be used when connected directly to an ESXi host.

First, connect to an ESXi host through PowerCLI.


Next, lets run the Get-EsxCli cmdlet.

$esxcli = Get-EsxCli

Now we have our ESXCLI object. Now what can we do with it? Well basically anything that you would do with ESXCLI through vCLI or local to the ESXi host. So let’s say our host is running on a Cisco UCS system, and we wanted to verify the enic driver version loaded on the host. We could issue the following command to view the driver version.


Now, to follow-up on the previous post, we could use the $esxcli object obtained through PowerCLI to issue the commands to view the vibs on the host and apply vibs to the host in the same manor that we were calling ESXCLI before. If we wanted to see all the VIBs installed on a host, we can issue the following command to give us the name, vendor, and version of all VIBs installed on the host in formatted table output.

$ | ft Name,Vendor,Version

Let’s look at the example from the previous blog post. Here we set the patch name and location of the patch on the datastore that the host could access.

$patch = "" #patch file we want to apply
$datastore = "datastore1" #datastore where we want to store the patch
$remoteLocation = "/vmfs/volumes/" + $datastore + "/" + $patch #remote location of patch

Now once the patch is on the datastore, which I covered in the previous post, you could install it with the command


Here is another tip as well for PowerShell and PowerCLI. If you are unsure of the arguments that a function takes, such as the command above, you can run


and the command will output some useful data about the method. One particular useful output is Value. This tells you what the expected value type will be given the proper inputs. For the above command, you can see the output as follows:

Hopefully this proves useful to someone.


Written by jguidroz

March 12, 2012 at 9:12 am

Posted in Scripting, VMware

Working with Sinatra and Cloud Foundry

with 2 comments

The other night I had idea pop in my head, that honestly, I was quite surprised hadn’t thought about before. I then set about working through the design of what would be needed to pull this idea off (sorry, the idea is under strict NDA that requires many pints of Guinness to even be able to sign).

Recently, I have started to move most of my work to Ruby, even working on another side project in Ruby that this project will be able to utilize. This project is a web based application, so with that, I needed a web/application server plus a platform to run it on. Now I have done my share of setting up Linux boxes with the required software before, but this time I wanted to see if the open source Cloud Foundry bits (VCAP) would prove useful in what I was looking to do. For the web/application server, I decided to go with Sinatra and Thin.


This was not my first time setting up a VCAP server or deploying apps to one. For some reason, I decided to stand up yet another VCAP VM on my laptop instead of using an existing instance :/. Of course in this process, I ran into issues, such as corrupted vmc profiles and a rvm installation issue in the soon to be deprecated default install process. Using the experimental Chef based installation, I had no issues getting a VCAP VM up and running. One interesting point to note when using the default or Chef based installation off of github, the default domain is When you ping, this resolves to :). So how do you access the VM via DNS? Well you set up an SSH tunnel from your workstation to the VCAP VM (also explained in the installation instructions).

In order to deploy applications to your VCAP VM, you need to install VMC to your workstation. This is as simple as running gem install vmc. If you want the latest beta, add –pre behind that command like so gem install vmc --pre. With your SSH tunnel setup and VMC installed, now you can follow the “Trying your setup” section on the VCAP github page (VCAP).


Now with VCAP up and running, I focused on getting Sinatra and Thin working. Sinatra is actually quite simple, actually. First install the Sinatra gem:

gem install sinatra

and here is a simple web application

require 'sinatra'
get '/' do
  "Hello World"

And that’s it. When you run ruby app.rb (or whatever you named the file), Sinatra fires up webrick and starts serving your page. See? Simple.

So lets move on. Now there are two ways to run Sinatra apps. The first is classic mode, as shown above. The second is in modular mode in a file called server.rb, shown below:

require 'sinatra/base'

class Server < Sinatra::Base
  get '/' do
    "Hello World"

Each mode of Sinatra application is also started differently. With the classic mode, you can start it with! However, in modular mode, Rack is used to start the server, and here in comes the fun of getting Sinatra/Thin working on Cloud Foundry VCAP VM. Classic mode works quite well on the VCAP VM, but modular mode requires a little bit more configuration.

First, you want to create a file in the root of your application. The location is key. By default, Rack looks for in the root of your application directory. There is a :config setting that can be changed, but for some reason when I set this key with a different location, the default port Thin starts on changed from 9292 to 8080. I have not figured out why this is occurring as nothing in my changed the Thin port; however, this will cause it to start on port 8080 in VCAP and not be accessible. The file needs to look like the following:

require 'sinatra'

set :run, false #This disables Sinatra trying to start Thin and let's Rack start Thin

require File.dirname(__FILE__) + "/path/to/server/file"

#The following is key. Sinatra Modular apps could
#be started with just run Server, but when deployed to
#VCAP, you need to map the application #to a location.
#In this instance, I want my server application
#to be mapped to the default path.
map '/' do
  run Server

Ok, now that our is configured (and of course more configurations could be added to it), we need to configure our main application file. For this, we need to use Rack to start our server. Lets say this file is called app.rb

require File.dirname(__FILE__) + "/path/to/server/file"
require 'rack'
require 'sinatra' #required for VCAP to detect this is a Sinatra Application
require 'thin'

server =

Now before we push our application to our VCAP VM, we need to create a Gemfile that looks like the following:

source ""

gem 'sinatra'
gem 'thin'

You may wonder why Rack is not listed. Sinatra is dependent on Rack and will install the Rack gems when its installed. With the Gemfile created, we can run bundle package && bundle install to package up all the gems required by our application. If you require any more gems for your application, you will want to run bundle package && bundle install before you update your application.

With done, we need to push our application. We start this process with the command:

vmc push --runtime ruby19

If you are still using Ruby 1.8.7, do not add the –runtime ruby19. There is one more key step when pushing the application. VMC will ask for the “Application Deployment URL”. The default url it will show will be [APPLICATION NAME][SSH TUNNEL PORT]. You will receive an error if you keep the default. You will want to remove the [SSH TUNNEL PORT] from the url, so it looks like [APPLICATION NAME]

With that, you should see VMC staging and starting your application on your VCAP VM. When started, you can access via web browser or curl at [APPLICATION NAME][SSH TUNNEL PORT].

It took me a while to get this working, but now that is, it is working great. The next step will be to see if Sinatra-Synchrony will work as well. I do not believe my application will require this, but it is more for an academic purpose at this point.

Written by jguidroz

February 14, 2012 at 7:34 pm

Posted in Random, Scripting

leave a comment »

Over the past year, I dropped the ball on this blog. It’s been a busy time, but I’ll try over the next year to make a few more posts. So what has been going on? Here are a few of the items keeping me busy:

  • Received the results on the VCAP-DCA; did not pass. The equipment I was using was also moved, so I did not get the opportunity to prepare and take it again.
  • Made a couple of trips to Ireland and spent about a month in England.
  • Moved back to Louisiana.
  • Dabbled in PowerShell, PHP, Python, Scala, Ruby
  • Changed managers about two or three times.
  • Passed the VCP 5

So what’s in store in the coming year? Well hopefully a lot of cool projects. There are a few topics I want to blog about and hopefully post some useful tools. I’m looking to move everything I do to Ruby, though there may still be some internal PowerShell scripts for some items.

This is my short update. Hopefully everyone had a good year.

Written by jguidroz

December 26, 2011 at 6:48 pm

Posted in Random, Scripting, VMware

Applying patches to ESXi 5 with the help of PowerCLI

with 2 comments

So today, Chris Colitti posted a blog article about patching ESXi 5 without VUM. If you haven’t read it, I suggest you click this link and read his post.

After reading this post, I was surprised to find out that esxcli did not support pushing patch or extension files remotely. Prior to ESXi 5, you could use vihostupdate via the vCLI to install the patch or extension zip files to a host. With vSphere 5, vihostupdate has been deprecated. The esxcli command supports installing a patch or extension from a remote depot url (VUM for instance) or from a local file path on the server, as Chris pointed out. Another option would be to host the actual vib files on an http or ftp server and use the -v option with esxcli to point to the remote location of these files. However, this is not the point of this blog post. This blog post will talk about using PowerShell and PowerCLI to assist esxcli in installing patches remotely. I will not provide a whole script, but just some useful commands.

First, to make things easier, we’ll set a couple of variables.
$esxcli = "C:\Program Files\VMware\VMware vSphere CLI\bin\esxcli.exe" #location of esxcli
$server = "" #server we want to patch
$patch = "" #patch file we want to apply
$patchLocation = "C:\" #local path to patch"
$datastore = "datastore1" #datastore where we want to store the patch
$remoteLocation = "/vmfs/volumes/" + $datastore + "/" + $patch #remote location of patch

Now, we want to mount a datastore to our workstation. First we need to connect to the ESXi host before doing anything.

Connect-VIServer $server
New-PSDrive -name "mounteddatastore" -Root \ -PSProvider VimDatastore -Datastore (Get-Datastore $datastore)

After we mount our datastore, we can then copy the patch to the datastore.

Copy-Datastoreitem $patchLocation + $patch -Destination mounteddatastore:

Once our file is copied, we can then execute esxcli to install our patch

& $esxcli --server $server software vib install -d $remoteLocation

This will execute esxcli on your workstation to install the patch we just uploaded to the datastore. Once the patch is installed, we can remove the patch and disconnect the datastore from the workstation.

del mounteddatastore:$patch
Remove-PSDrive -name "mounteddatastore" -PSProvider VimDatastore

So with this little bit of knowledge, you could write a PS script to copy the patch to a datastore (preferably shared across hosts), and then call esxcli to install the patch on the required hosts.

Update: A new blog post is up detailing using the Get-EsxCli cmdlet in PowerCLI. This can be located here.

Written by jguidroz

December 2, 2011 at 4:16 pm

Posted in Scripting, VMware

Setting time on ESXi hosts through PowerCLI

with one comment

So you go and build your new ESXi hosts, set NTP, but notice your time is still off. Did you know you can set your ESXi host time through PowerCLI?

After connecting to a host, you can set the time with the following commands. Always make sure you use UTC time when setting the time on your host as ESXi does not use timezones.

$t = Get-Date
$dst = Get-VMHost | %{ Get-View $_.ExtensionData.ConfigManager.DateTimeSystem }
$dst.UpdateDateTime((Get-Date($t.ToUniversalTime()) -format u))

And there you go. Now your ESXi hosts will have the same time as the machine you ran your script on, so just make sure that machine has the correct time.

And on why I have not blogged in a while, well that is another blog post.

Written by jguidroz

November 29, 2011 at 4:19 pm

Posted in Scripting, VMware

Using PHP5 SOAP with vSphere API

with 3 comments

I will more blog later detailing better usage of PHP with vSphere API.  This post is focused on how to use PHP5 Soap Client methods to interact with the vSphere API.

The vSphere API is SOAP based.  First step is to download the WSDL from vCenter or the ESX(i) host.  So how do we do this with PHP5?

First, we need a SOAP Client.

$connection = new SoapClient(“https://<hostname or ip/sdk/vimService.wsdl”, array(“trace” => 1, “location”=>”https://<hostname or ip>/sdk/”);

From this code snippet, we created a new SoapClient, $connection, set the location of the wsdl, set trace to 1 for debugging purposes, and set the location that we will send requests to.  Next we need to create a SOAP message to send to the server.

$soapmsg[“_this”] = new SoapVar(“ServiceInstance”, XSD_STRING, “ServiceInstance”);

Basically every call to vSphere API will require a “_this” key.  Most calls will require more information.  From this code snippet, we are creating an array with a “_this” key and setting a SoapVar with data of “ServiceInstance” and type of “ServiceInstance”.  Now, we are going to retrieve the Service Instance.

$result = $connection->RetrieveServiceContent($soapmsg);

And what do we get?  Definitely not the result we were expecting.  With trace enabled, we can actually view the SOAP request that was made to the server.


What is the problem with the SOAP request?  Well, PHP5 SOAP function sets the type of the SOAP message as “xsi:type”.  The vSphere API expects a type of just “type”.  How do we fix this?  We must create our own class that extends SoapClient and overrides the __doRequest method.  Here, we can strip “xsi:” out of the request and send the vSphere API the request it is expecting.

class mySoapClient extends SoapClient {

     function __doRequest($request, $location, $action, $version) {

          $request = str_replace(“xsi:”, “”, $request);

          return parent::__doRequest($request, $location, $action, $version);



After altering the request, we can now successfully retrieve the Service Instance from the vSphere API.

Written by jguidroz

October 7, 2010 at 7:22 am

Posted in Scripting, VMware

Working with UCS and vCenter: IPMI Settings

with 5 comments

In my last blog post, Working with Cisco UCS XML API, I went through the steps needed to login and logout of UCS Manager using PHP and PowerShell.  Today, I decided to write the first PowerShell script I needed which would automatically update the IPMI settings on the ESX hosts with the settings from UCS Manager.  In writing this script, I did come across this post from Mike Laverick on using PowerShell to enable DPM settings

Now, this script is important for two reasons.  The first reason is that to configure IPMI on ESX hosts, you need both IP address and the MAC address of the CIMC controller from the UCS blades.  When having to do this for multiple ESX hosts, a script is very handy.  Now the second reason is more important.  Currently in UCS, the CIMC IP is tied to the actual blade and not the service profile.  This means if a service profile is associated with a new blade, the ESX host IPMI information is now pointing to the old blade.  Not good!

With that said, here is the first version of this script as a PowerShell script.  (This will also come as a PHP script and possibly other languages in the near future.)  In order to run this script, you will need PowerCLI installed.  You will also need IP and credentials for vCenter and UCS, as well as the IPMI user and password.  This script has only been tested against UCS 1.3.1 and vSphere 4.1.  I will be testing this shortly against vSphere 4.0.  This is also a v0.1 script, so there is no error checking (who needs it right?).  That will be coming in a future version.


I provide this script for academic purposes only.  Use at your own risk.  I am not responsible for any damages it may cause.


So what does the script do?  The script first logs into vCenter and UCS Manager.  It then grabs the UUID from each ESX host.  Once done, it will pass this UUID to UCS to find the corresponding blade and return the CIMC IP and MAC for that blade.  The script will then write these settings to the IPMI of the ESX host.  Finally, it will log out of the UCS and vCenter.

# UCS_VMware_IMPI.ps1 v0.01  By: Justin Guidroz
# This script will connect to UCS Manager, collect IPMI information
# for the provisioned blades, and update the appropriate IPMI
# information on the ESX hosts.  The script can also be run to
# update the IPMI information if a service profile is moved to a
# different blade.
Add-PSSnapin VMware.VimAutomation.Core

### Needed variables
$ucsUrl = “”
$ucsUser = “”
$ucsPassword = “”
$vCenterUrl = “”
$vCenterUser = “”
$vCenterPassword = “”
$ipmiUser = “”
$ipmiPassword = “”

### Function ucs_post
### Required variables: $url = UCS Url $data = XML to send to UCS
### Returns: XML response from UCS
function ucs_post($url,$data) {
$request = [System.Net.HttpWebRequest] [System.Net.HttpWebRequest]::Create(“http://&#8221; + $url +”/nuova”)
$request.Method = “POST”
$request.ContentType = “text/xml”
$sendData = new-object System.IO.StreamWriter($request.GetRequestStream())
$response = $request.GetResponse()
$sr = new-object System.IO.StreamReader($response.GetResponseStream())
$xml = [xml] $sr.ReadToEnd()
return $xml

### Function ucs_login
### Required variables: $inName = UCS username $inPassword = UCS password $url = UCS url
### Returns: Cookie after login
### Todo: Error Checking
function ucs_login($inName, $inPassword, $url) {
$aaaLogin = “<aaaLogin inName='” + $inName + “‘ inPassword='” + $inPassword + “‘ />”
$xml = ucs_post $url $aaaLogin
$outCookie = $xml.aaaLogin.outCookie
return $outCookie

### Function ucs_logout
### Required variables: $url = UCS url $inCookie = Cookie for session to logout
### Returns: Status of logout
### Todo: Error Checking
function ucs_logout($url, $inCookie) {
$aaaLogout = “<aaaLogout inCookie='” + $inCookie + “‘ />”
$xml = ucs_post $url $aaaLogout
$outStatus = $xml.aaaLogout.outStatus
return $outStatus

### Function get_esx_hosts
### Required variables: $vCenter = $vCenter server object
### Returns: ESX hosts in vCenter
### ToDo: Error checking. More logic
function get_esx_hosts($vCenter) {
$esxhosts = @()
$VMHosts = Get-VMhost -server $vCenter
foreach ($h in $VMHosts) {
$esxhost = “” | Select-Object Name, Uuid, IpmiIp, IpmiMac
$esxhost.Name = $
$v = Get-VMHost -Name $h | Get-View
$esxhost.Uuid = $v.Summary.Hardware.Uuid
$esxhosts += $esxhost
return $esxhosts

### Function get_blade_dn
### Required variables: $uuid = ESX UUID $url = UCS url $cookie = UCS cookie for session
### Returns: DN of physical blade
### Todo: Error Checking
function get_blade_dn($uuid, $url, $cookie) {
$computeBlade = “<configResolveClass cookie='” + $cookie + “‘ inHierarchical=’false’ classId=’computeBlade’><inFilter><eq class=’computeBlade’ property=’uuid’ value='” + $uuid + “‘ /></inFilter> </configResolveClass>”
$bladeXml = ucs_post $url $computeBlade
return $bladeXml.configResolveClass.outConfigs.computeBlade.dn

### Function get_blade_ipmi
### Required variables: $dn = DN of physical blade $url = UCS url $cookie = UCS cookie for session
### Returns: Management Interface XML response from UCS
### Todo: Error Checking
function get_blade_ipmi($dn, $url, $cookie) {
$mgmtIf = “<configResolveClass cookie='” + $cookie + “‘ inHierarchical=’false’ classId=’mgmtIf’><inFilter><eq class=’mgmtIf’ property=’dn’ value='” + $dn + “/mgmt/if-1′ /></inFilter> </configResolveClass>”
$mgmtIfXml = ucs_post $url $mgmtIf
return $mgmtIfXml

### Function get_host_ipmi
### Required variables: $esxhost = ESX Host object $url = UCS url $cookie = UCS cookie for session
### Returns: Updated ESX host object
### Todo: Error checking
function get_host_ipmi($esxhost, $url, $cookie) {
$bladeDn = get_blade_dn $esxhost.Uuid $url $cookie
$mgmtIfXml = get_blade_ipmi $bladeDn $url $cookie
$esxhost.IpmiIp = $mgmtIfXml.configResolveClass.outConfigs.mgmtIf.extIp
$esxhost.IpmiMac = $mgmtIfXml.configResolveClass.outConfigs.mgmtIf.mac
return $esxhost

### Function set_host_ipmi
### Required variables: $esxhost = ESX host object $vCenter = vCenter Server Object
### Returns: nothing (should be changed)
### Todo: Error checking
function set_host_ipmi($esxhost, $vCenter) {
$v = Get-VMHost -server $vCenter -Name $esxhost.Name | % {Get-View $_.Id}
$ipmi = New-Object Vmware.Vim.HostIpmiInfo
$ipmi.BmcIpAddress = $esxhost.IpmiIp
$ipmi.BmcMacAddress = $esxhost.IpmiMac
$ipmi.Login = $ipmiUser
$ipmi.Password = $ipmiPassword

### Where the fun begins
### Lets log in to vCenter and UCS
$vCenter = Connect-VIServer -server $vCenterUrl -user $vCenterUser -password $vCenterPassword
$cookie = ucs_login $ucsUser $ucsPassword $ucsUrl

### Grabbing ESX hosts from vCenter
Write-Host “Getting ESX Hosts from vCenter”
$esxhosts = get_esx_hosts $vCenter

### Get the IPMI settings from UCS and update ESX hosts with information
Write-Host “Getting IPMI Settings from UCS and configuring ESX”
foreach ($h in $esxhosts) {
$h = get_host_ipmi $h $ucsUrl $cookie
set_host_ipmi $h $vCenter

### Fun as ended, time to log out.
Write-Host “Logging out of UCS”
$outStatus = ucs_logout $ucsUrl $cookie
Write-Host $outStatus
Write-Host “Logging out of vCenter”
Disconnect-VIServer -server $server -confirm:$false

And here is the PowerShell file.  UCS_VMware_IPMI.ps1.doc The .doc will need to be deleted from the end of the file (only way I could get the file uploaded).

Looks like I need to figure out a way to make code display on my blog. Another day.

Written by jguidroz

September 20, 2010 at 6:37 pm

Posted in Scripting, UCS, VMware

Working with the Cisco UCS XML API

with 3 comments

Working with Cisco UCS systems on a daily basis, I decided to take some time this weekend to learn more about the XML API.  Honestly, it is a thing of beauty and simplicity.  Working with the Cisco UCS XML API is as simple as sending an HTTP POST with an XML document to the UCS Manager and getting the response.  That’s it.  Isn’t that great?

Seeing as I have a couple of projects that will benefit from interacting with UCS systems, I decided to write a script in PHP to login and logout of a UCS for starters.  Then Rob Markovic asked, “Why not PowerShell?”.  So I wrote the same script in PowerShell as well.  I do need to give credit to Steve Chambers for this post: Access UCS API with Ruby.  This was beneficial as I was reading the XML API documentation and starting to work on my scripts.


I am not an expert in PHP or PowerShell.  I am providing this information for academic purposes only to show how easy it is to work with the UCS XML API.  I am also not responsible for any damage this may cause your systems.


One thing you’ll notice with the Cisco UCS XML API is that the only methods that require a username and password to be passed is the aaaLogin and aaaRefresh methods.  All other methods require a cookie to be passed, which is only obtained by logging in or refreshing your session to the UCS Manager.

Let’s start with what’s needed for PHP to work with the Cisco XML API.  I downloaded and installed HTTP_Request2 from PEAR to make the HTTP call easier.

require_once HTTP/Request2.php;

Now we need to set the url of our server and the XML parameters for logging into the UCS system.

$url = “http://server ip or dns/nuova”;

$aaaLogin = “<aaaLogin inName=’username’ inPassword=’password’ />”;

With the url and XML set, we can now create our HTTP request for logging in.


$request->setHeader(“Content-type: text/xml”);


After the request is created, we can send the data to the UCS Manager and get our response.

$response = $request->send();

To make it easier to work with the response, we are going to create SimpleXMLElement from the response.

$xml = new SimpleXMLElement($response->getBody());

Now to get our cookie from the XML response, we just need to do the following:

$outCookie = $xml->attributes()->outCookie

With the cookie now obtained, we are free to call other UCS XML API methods for interacting with the system.  To logout, we need to create the logout xml and issue an HTTP POST with this data.  (I will not repeat the code for issuing the HTTP POST).  Here is the XML for logging out of the system.

$aaaLogout = “<aaaLogout inCookie=’cookie for session’ />”;

To verify status of logout, you look at the outStatus attribute from the XML response.

$outStatus = $xml->attributes()->outStatus;

Here is how to do the same with PowerShell.

$url = “http://server ip or dns/nuova”

$aaaLogin = “<aaaLogin inName=’username’ inPassword=’password’ />

$request = [System.Net.HttpWebRequest] [System.Net.HttpWebRequest]::Create($url)

$request.Method = “POST”

$request.ContentType = “text/xml”

$sendData = new-object System.IO.StreamWriter($request.GetRequestStream())



$response = $request.GetResponse()

$sr = new-object System.IO.StreamReader($response.GetReponseStream())

$xml = [xml] $sr.ReadToEnd()

$outCookie = $xml.aaaLogin.outCookie

To logout with PowerShell, we create the aaaLogout XML with the cookie we just obtained and issue another HTTP Request (code not repeated).

$aaaLogout =”<aaaLogout inCookie=’cookie for session’ />”

And to get the status of the logout.

$outstatus = $xml->aaaLogout->outStatus

There you have it.  PHP and PowerShell example code for logging into and out of Cisco UCS Manager.  You can find the programmer’s guide here:  Cisco UCS Manager XML API Programmer’s Guide.  I would also suggest checking out these Cisco blog posts on the Cisco UCS Manager XML API by John McDonough: UCS XML API “Hello World”, UCS XML API “curl and xml”, and UCS XML API Query Methods.

Written by jguidroz

September 19, 2010 at 2:36 pm

Posted in Scripting, UCS

Automating ESXi 4.1 continuation

with 4 comments

William Lam has posted a great article on tips and tricks of automating ESXi 4.1 here.  Go read his post first.

Seriously, go read his post first.

Ok, you’re back?

I wanted to add to his post with some issues and fixes I’ve run across with moving from ESX to ESXi automation.

With ESX 4.0, at the beginning of the ks.cfg file, you would specify an install line.  Nothing else was needed as the url location of the install bits was passed in the PXE config line.  No more.  For ESX(i) 4.1, you must specify the url for the install location in the ks.cfg file.

Beginning with ESX(i) 4.1, ip append 2 in the PXE config boot line no longer works.  What does this do exactly?  This told the ESX(i) to use the same nic it booted from for downloading the install bits.  If this was not specified, ESX(i) would try to use the first nic it detected, vmnic0.  With ESX(i) 4.1, you must specify ksdevice=vmnic(x) if you are booting and installing from a different nic than vmnic0.  I’m not sure why this behavior changed between 4.0 and 4.1.

William did mention vim-cmd.  In ESX, the command is actually vmware-vim-cmd.  For ESXi, be sure to update these commands to vim-cmd.

For disk setup, I have two lines in my ks.cfg file: clearpart –onfirstdisk –overwritevmfs and autopart –onfirstdisk –overwritevmfs.  I did notice this will create the datastore name on each ESXi host as datastore.  I need to investigate if this can be changed at this part, or add a line in the script to update that name.

In my working with scripting ESXi installations, I’ve found it much easier to have everything run after firstboot then trying to run the configurations before firstboot.

Plenty of advanced configurations (SNMP, Active Directory, adding to vCenter) can be handled through the scripted install, but involve writing a python script to handle.  For some, it will be easier using the supplied commands in the vMA or writing PowerShell scripts.

Outside of these differences, scripted ESXi installs are awesome.

Written by jguidroz

September 11, 2010 at 12:07 pm

Posted in Scripting, VMware

Automatically add ESX(i) to vCenter from ESX(i)

with 3 comments

I have to say, I love my job.  Since starting at the end of May, I have had the opportunity to work with some great people and tackle tasks that I have been wanting to complete yet never had the time to do at previous employers.  Specifically, I am talking about automating ESX(i) deployments.  I have performed many scripted installs before (in fact I had not done a full load of ESX for over 3 years and only recently did so because CNA drivers were not in the ISO), but now I am in the situation where build after build must be exactly the same no matter who is performing the builds.  With that, our team started looking at the ESX Deployment Appliance (great appliance BTW), but I quickly noticed some lacking features which I quickly added to fit our current needs.  (Keep your eyes out for announcement in the near future on a collaboration myself and @lynxbat will put together regarding a deployment appliance).

With the work I’ve been doing lately, I asked myself the question: why couldn’t an ESX(i) host add itself to vCenter?  The easiest answer to this question is that VMware has not written a program or script to perform this task.  But is their a technical reason why this would not be possible?

In order to perform any type of action on vCenter, API access is required.  There are two ways to access the vCenter APIs: MOB and Web Services API.  The MOB, or Managed Object Browser, is a web site that allows retrieving and setting values for vCenter.  Traversing the MOB is not easy and requires frequent trips to the vSphere API documentation for assistance.  The Web Services API is a web service that can be used to retrieve and set values via a SOAP client.  VMware even provides SDKs for Java and Perl.

Do we have an SDK available on ESX(i)? No.  This means we must see if we can access the MOB or Web Services API from ESX(i) by writing a script that does not rely on an SDK.  Looking through an ESXi host, I noticed python was on the host.  Why is python on the host?  The MOB is written in python.  There is no SOAP client libs loaded for python on ESX(i)(if there are, please post a comment), and this solution should not require loading of additional libraries to ESX(i).  With that I set out and wrote a script that will connect an ESX(i) host to vCenter.


Use at your own risk.  I provide this script as an academic example of how to do this.  I am not responsible if it does havoc on your environment.  This script has only been tested with vSphere 4.1 ESXi and vCenter.  ESX 4.1, ESX 4.0, and vCenter 4.0  have not been tested.


First we must import the libraries we need.

import re,os,urllib,urllib2

Next, let’s set some variables that will be needed.  This is where it starts to get interesting.  <CLUSTER> below needs to be replaced with the cluster the host will be added to. For this exercise, this is a static assignment. This name will be in the form of domain-c21 or something similar and can be found in the MOB.

url = "https://vcenteraddress/mob/?moid=<CLUSTER>&method=addHost"
username = "vcenterusername"
password = "vcenterpassword"

This section configures the authentication for when we connect to the MOB.

passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
authhandler = urllib2.HTTPBasicAuthHandler(passman)
opener = urllib2.build_opener(authhandler)

This next section computes the SHA1 hash for the host and strips out all unnecessary characters.  As you can tell, my regex skills are a bit rusty, and this probably could be cleaned up.

cmd = "openssl x509 -sha1 -in /etc/vmware/ssl/rui.crt -noout -fingerprint"
tmp = os.popen(cmd)
tmp_sha1 = tmp.readline()
s1 = re.split('=',tmp_sha1)
s2 = s1[1]
s3 = re.split('\n', s2)
sha1 = s3[0]

This next section creates the ConnectHostSpec information that needs to be passed to the addHost method.

xml = """<spec xsi:type="HostConnectSpec">
xml = xml.replace("%s",sha1)

Once the ConnectHostSpec is created, we can now encode the parameters that must be sent with the POST to the addHost method.  As you can see, besides the ConnectHostSpec, we must also pass values for asConnected, resoursePool, and license.  Only spec and asConnected require a value.  After the values are encoded, a request can be created and the data sent to the URL.

params = {'spec':xml,'asConnected':'1','resourcePool':'','license':''}
e_params = urllib.urlencode(params)
req = urllib2.Request(url,e_params)
page = urllib2.urlopen(req).read()

And that’s it. This small script will take the parameters needed to add an ESX(i) host to vCenter through the MOB and complete this task from the host itself.  I am currently testing integrating this script with scripted installs.  Stay tuned as I am already getting more ideas for this script.

Written by jguidroz

July 25, 2010 at 3:57 pm

Posted in Scripting, VMware