Introduction
In this article I shall demonstrate the new XenServer PowerShell snap-in, using the simple example of "chained" VM starts: waiting for one VM to finish booting before starting the next.
The new SnapIn is available at http://community.citrix.com/cdn/xs/sdks.
In this example, we are using the XenServer Tools to detect when booting is complete: once they advertise the VM's IP address, we assume that the VM is ready. Of course, you may want to make this more sophisticated, for example waiting for a domain controller to start before moving on. I'll leave this to your imagination!
In the first screenshot, I've got XenCenter 5.0 talking to a XenServer 5.0 pool, XS-PS started afresh, and the script that runs this example, Start-VM.Wait.ps1. The PowerShell install is out-of-the-box, though I've already set the ExecutionPolicy to RemoteSigned.
Namespaces and Initialize-XenServer:Aliases
Firstly, a quick word about how we handle namespaces in XS-PS.
A lot of the Xen-API's names are very generic; a cmdlet called "Create-Message" could clash with any number of things. With this in mind, XenServer's cmdlets are named within a XenServer namespace, something like this:
Create-XenServer:VM Destroy-XenServer:VM Get-XenServer:VM Get-XenServer:VM.NameLabel Set-XenServer:VM.NameLabel Invoke-XenServer:VM.Start
This is great for people who want to use XS-PS in a mixed environment, but it's obviously a bit verbose for quick scripting, so we've added the ability to alias these full names to something shorter. In Start-VM.Wait's process block, you can see the following call:
Initialize-XenServer:Aliases Start
This introduces a full set of aliases, so that we can now use names such as
Create-VM Destroy-VM Get-VM Get-VM.NameLabel Set-VM.NameLabel Start-VM
These aliases are scoped within this script, so they won't pollute the user's environment. If you want, you can pass it a -Scope parameter, and have them put into an outer or global scope instead.
Initialize-XenServer:Aliases actually supports three styles of alias, so you can choose the style that best suits your environment, or you can stick with the full names if you prefer.
PS C:\Users\Ewan Mellor> Initialize-XenServer:Aliases Invoke-Xen = Get-Xen:VM / Invoke-Xen:VM.Start Invoke = Get-VM / Invoke-VM.Start Start = Get-VM / Start-VM
Start-VM.Wait
Start-VM.Wait takes its VMs from the pipeline. It then processes them one at a time, like this:
- If the VM record represents the control domain, or a template, then silently skip it.
- If the VM is unstartable (because it's already running, say), then log the fact, and skip it.
- Otherwise, call Start-VM. This will block until the VM boot process begins.
- Next, wait for up to five minutes for the VM to boot. We wait for the VM.guest_metrics field to be populated, and for an entry to appear in VM_guest_metrics.networks. Once there's an entry here, we know that the XenServer Tools are ready, and the VM has an IP address configured (from DHCP, for example).
- If polling this field fails after 5 minutes, then warn, and just move on to the next VM.
function Start-VM.Wait
{
begin
{
$timeout = 5 * 60 * 1000
Initialize-XenServer:Aliases Start
}
process
{
if ($_.is_a_template -or $_.is_control_domain)
{
return
}
if ($_.allowed_operations -notcontains "start")
{
Write-Warning("{0} cannot be started" -f $_.name_label)
return
}
Write-Verbose("Starting {0}..." -f $_.name_label)
Start-VM $_
for ($count = 0; $count -le $timeout / 500; $count += 1)
{
$metrics = Get-VM.GuestMetrics $_
if ($metrics -ne $null -and $metrics.networks.Count -gt 0)
{
Write-Verbose("VM {0} started" -f $_.name_label)
return
}
Start-Sleep -m 500
}
Write-Warning("Timeout starting {0}" -f $_.name_label)
}
}
Using it
Using this script is now very simple:
- Dot-source the script, to load the function.
- Set $VerbosePreference to "Continue", just for this demo.
- Connect to your master server.
- Choose the VM's that you want to start (in the example, all those tagged as "Production").
- Pipe those VM's into Start-VM.Wait.
- Watch the magic!
- Log out from your server afterwards.
PS> . .\Start-VM.Wait.ps1 PS> $VerbosePreference = "Continue" PS> Connect-XenServer -url https://<servername> PS> Get-XenServer:VM -Tags Production | Start-VM.Wait ... PS> Disconnect-XenServer
This is a simple example, and no doubt you would want to tweak it to match your deployment, but I hope that it's enough of an example for you to get started.
Comments (7)
Oct 13, 2008
John Crawford says:
Ewan I currently have a .cmd script (I am a glutton for punishment) that reads ...Ewan
I currently have a .cmd script (I am a glutton for punishment) that reads a list of VMs from a file, and for each of those VMs:-
1. Run a few checks (e.g. is there a Template/Snapshot with a similar name to the VM)
2. Close the VM
3. Destroy the VM
It then re-reads the file and for each of the VMs:-
1. Recreate the VM from the similarly named Template/Snapshot
2. Start the VM
3. Wait for a period of time before starting the next VM
What I would like to do now is to re-implement my .cmd script as a PowerShell script, and your Start-VM.Wait example looks like a useful starting point. I particularly like the idea of driving the script with Tag information from XenServer.
However, something that gets lost with your approach is the order in which the VMs should be started. Currently my file contains a list of VMs with the router VM in position 1, followed by the AD domain controller VM, and then other servers and workstation VMs, whereas the Tag approach would present them in some other order.
I was thinking that "Custom Fields" be a way of controlling this? If I were to create a "Custom Field" called StartOrder then I might be able sort my VMs on that. Unfortunately, I don't seem to be clever enough to extract/use "Custom Field/StartOrder" in the Get-XenServer:VM line. Can you suggest how I could do this, or am I barking up the wrong end of the stick?
John (PowerShell novice)
Oct 13, 2008
Ewan Mellor says:
Good question John! XenCenter stores the custom field values in the VM.other_co...Good question John!
XenCenter stores the custom field values in the VM.other_config dictionary, using the key XenCenter.CustomFields.Name_of_field.
You can certainly sort on these values with PowerShell – here's an example, using "Sort Order" as the custom field's column header:
Jan 26, 2009
Anonymous says:
Where does one get the ps-snapin from? is this on the install cd?Where does one get the ps-snapin from? is this on the install cd?
Jan 26, 2009
Ewan Mellor says:
It's available at http://community.citrix.com/cdn/xs/sdks; I've updated the text...It's available at http://community.citrix.com/cdn/xs/sdks; I've updated the text above to reflect this. This is now the homepage for all the XenServer SDKs, so check back later for updates.
Mar 15, 2009
Anonymous says:
PowerShell integration into the IT world was meant to make our job simple. ...PowerShell integration into the IT world was meant to make our job simple. Now, we know how powerful this .NET scripting technology is, then we seen people getting away from the simple Verb-Noun concept. Maybe not knowing is not the right direction.
Why creating a pssnapin with cmdlets such as:
Create-XenServer:VM
Get-XenServer:VM
Get-XenServer:VM.NameLabel
Set-XenServer:VM.NameLabel
Invoke-XenServer:VM.StartÂ
Instead of using Verb-Noun -Parameter
Create-XenServer -VM
Destroy-XenServer -VM
Get-XenServer -VM -Namelabel
Invoke-XenServer -VM -StartÂ
You are getting out of the standard PowerShell structure and add complexity to it. It has to be kept simple enough or people are going to get intimidated by it.
Mar 15, 2009
Maximo Trinidad says:
PowerShell integration into the IT world was meant to make our job simple. ...PowerShell integration into the IT world was meant to make our job simple. Now, we know how powerful this .NET scripting technology is, then we seen people getting away from the simple Verb-Noun concept. Maybe not knowing is not the right direction.
Why creating a pssnapin with cmdlets such as:
Create-XenServer:VM
Get-XenServer:VM
Get-XenServer:VM.NameLabel
Set-XenServer:VM.NameLabel
Invoke-XenServer:VM.Start
Instead of using Verb-Noun -Parameter
Create-XenServer -VM
Destroy-XenServer -VM
Get-XenServer -VM -Namelabel
Invoke-XenServer -VM -Start
You are getting out of the standard PowerShell structure and add complexity to it. It has to be kept simple enough or people are going to get intimidated by it.
Mar 16, 2009
Ewan Mellor says:
Take a look at the Initialize-XenServer:Aliases section. If you use that, you c...Take a look at the Initialize-XenServer:Aliases section. If you use that, you can have names like
Create-VM
Destroy-VM
Get-VM
Start-VM
The long names (with XenServer: ) are really only intended for people who have to deal with multiple hypervisors (VMware's names would clash with ours, for example).
Add Comment