I’ve been doing a lot of work with the Release Candidate of System Center Orchestrator, so it’s always interesting to see what other orchestration products are capable of. I recently read a blog post on Creating Workflow Loops in vCenter Orchestrator and I was struck by just how complicated it is to do relatively simple tasks, with lots of really arcane syntax to work with.
It’s probably worth taking a look at how System Center Orchestrator would accomplish a similar task. First, we start with a new empty runbook. I’m going to use a text file as an input into the runbook, but we could just as easily prompt for user input, or even better store the list of servers to be patched in a change control record in a service desk system (of course it doesn’t have to be the Microsoft service desk, that’s one of the strengths of the Orchestrator platform).
We’re going to build a runbook that looks like this.
First we drag out a standard Read Line activity from the palette on the right from the Text File Management category. Then we’ll grab a Get VM List activity from the VMware vSphere. We can then join the two activities together by hovering over the activity, clicking the arrow that appears and then drag it to the next activity. We’ll repeat the process dragging out a Compare Values activity, and then finally a Take VM Snapshot activity. We’ve now built the structure of our runbook, and we can go about customising the activities.
First we’ll specify the text file to read in. Double click the Read Line activity, and you can enter the properties. I’ve used an ASCII format text file that just contains a list of VM Names, and the 1-END tells the activity to read from the first line to the end of the file.
The Get-VMList activity doesn’t need much customisation, it just needs to be told which vSphere connection to use (defined in the Runbook Designer under Options…VMware vSphere).
The Compare Values activity allows us to compare two text or numeric values – we are going to use this to match our list of VM’s to snapshot from the text file against the list of VM’s returned from vSphere. We’re going to use one of the real key features of Orchestrator, which is the concept of published data. Each activity preceding this one returns data onto the databus, and any activity following can take advantage of the published data. We’re going to use the Line Text returned from the Read Line activity, and the VM Names returned from the Get VM List activity. In the Test area, we right click and choose Subscribe…Published Data. We select from the drop down at the top the Read Line activity, and choose the Line Text option
We then right click in the pattern field and subscribe Published Data again, and choose the Get VM List activity.
We’ll end up with a Compare Values task that looks like this. (By default we do a text comparison, if you want to compare numbers, the general tab allows you to select that.)
We can then customise the Take VM Snapshot activity to customise the behaviour. Again, we’ll use some published data to identify which VM’s to snapshot. Up to now we’ve been working with VM names, but the snapshot activity actually requires a VM Path parameter – not to worry, the VM Path is returned along with the VM Name as part of the Get VM List published data.
The final step in the puzzle is to customise our link so that the snapshot task only runs for VM’s that match the list of VM’s in the text file. To do this, we double click the link object between the Compare Values & Take VM Shapshot activities. This brings up a dialog that allows us to set the conditions when we will execute the next step – by default it will proceed should the task succeed, but success in this case is simply that the task ran. We will change it by clicking the text that says “Compare Values” and select the Comparison result published data. We will then change the criteria to true by clicking the text that says value, and entering true in the popup.
The great thing about this runbook is that it will loop by itself, you don’t need to keep track of the loops (you might still want to maintain the state of the loop so you can restart the runbook should it strike an error) and without any strange syntax we’ve built an easy to understand & debug runbook. The looping was handled automatically as part of the runbook, and we performed a relatively complex text comparison very quickly.
Compare this to the vCenter Orchestrator example, and you’ll see that using System Center Orchestrator you’ll be up and running with your runbooks much faster.
In my last post on this subject I set up the cluster patching framework in Opalis. In this post I’m going to modify the policy initiation phase to use PowerShell & some text manipulation to make it more dynamic.
I’d set this up originally to simply read the cluster nodes from a text file. There are more options available to us though – we could use PowerShell to query the cluster for a list of cluster nodes, or in this case I’m going to use PowerShell to query Virtual Machine Manager to get the list of Hyper-V cluster nodes.
I’ve got a simple PowerShell script which is as follows:
Add-PSSnapin Microsoft.SystemCenter.VirtualMachineManager $cluster=get-vmhostcluster -name "democluster.contoso.com" -vmmserver "vmm.contoso.com" $vmhosts=get-vmhost -vmhostcluster $cluster | select -property Name
Running this script will return me a variable $vmhosts which contains text as follows:
@{Name=clusternode1.contoso.com}
@{Name=clusternode2.contoso.com}
That’s not quite in the format that I want and I could do some further processing in PowerShell to get it right, but I’m lazy, and also want to show off some of the text manipulation features in Opalis.
First thing though, I want to execute this in Opalis. Because I’m using Virtual Machine Manager objects I’ll need to have the VMM 2008 R2 console installed on my Opalis machine.
Once I’ve got it installed I can then modify my policy. I’m going to add a “Run .NET script” object. “Run .NET Script” is pretty powerful and lets us run scripts in C#, JScript, VB.NET or PowerShell. I just drag and drop my object into my policy, and then double click it to open the properties.
My policy looks like this:
When I open the properties, I can simply paste my script in there, and change the language to PowerShell:
Now I need some way to get the output from the script. The great thing about Opalis is that it makes this really easy. I go to the “Published Data” area and tell the policy which variable I want to return as published data. In this case my vmhosts variable is the data I want, so I simply add that in. Now when I need to retrieve the published data from the data bus, vmhosts will appear as available.
As I said before the data that comes out of that script isn’t exactly in the format I want – I only want hostnames, not all the other text so I need some way of stripping that out. Fortunately this is another area that Opalis makes really easy.
In my “Trigger Policy” task I previously set it up to pass the Computer Name parameter through to the next policy. I’m going to continue to do this, but manipulate the text that I pass through.
There is a screen shot below that shows the start of this, but I will expand further. Opalis will treat information in square brackets as data manipulation functions, so I start with that. In this case there is a consistent set of data coming out of the script – there is effectively a header (“@{Name=”) , the data (“clusternodex.contoso.com”) and a footer (“}”. I’m going to use a combination of three functions – the Mid function, the Sum function and the Len function. Mid allows me to retrieve text from the middle of a string, and Len will allow me to get the length of a string. Sum just allows me to add two numbers together.
Because my data is in a consistent format the information I want always starts at the 8th character, and the data I need to retrieve is from that point through to the second last character. The length of text I need to grab is the overall length of the string less 8 characters (the 7 in the header plus the 1 in the footer). For this I use the Sum function to add –8 to the length of the string. I could equally use the Diff function to subtract 8.
I then build my function as:
[Mid('<vmhosts published data>’,8, Sum(Len(‘<vmhosts published data>’),-8))]
I insert my published data by right clicking where I want to insert it and choosing “Subscribe…published data”. I choose the “Run .NET Script” task, and the vmhosts data.
So now when my trigger policy task runs it will pass the ComputerName parameter as clusternodex.contoso.com, having stripped off the header and footer.
If you wanted to simply use the Windows 2008 R2 Failover Cluster PowerShell cmdlet’s to get the cluster nodes you could do this:
Import-Module -Name FailoverClusters Get-ClusterNode -cluster democluster | Format-Table -Property Name –HideTableHeaders
This actually gives nicer output than the VMM Cmdlets but the VMM ones were slightly easier to work with in my case (I can execute them locally on the Opalis server).
Next time we’ll look at some of the pre-patching checks.
Edit: Should have made clear, the Opalis service account needs to have permission in VMM to execute this script. As there is no concept of an "Operator" in VMM the Opalis account will need to be a delegated administrator. To run the standalone Failover Cluster scripts the Opalis account simply needs to have Read-only permissions on the cluster.
One of the things that isn’t made 100% clear in the DPM documentation is what you need to do for Hyper-V VM’s that you are protecting at the Hyper-V host layer. The “Protected Computer Software Requirements” document on Technet tells you that you need to apply certain hotfixes to the Hyper-V host, and you could be forgiven for thinking that was all you needed to do.
However, if you remember that when DPM uses the Hyper-V VSS Writer to take a snapshot of a running VM, it also leverages the in-guest VSS Writers to ensure that the guest itself is consistent inside, so we are able to have application consistent backups.
What’s the implication of this? If there is a hotfix required in the physical world (for instance a file server running Windows Server 2003 requires hotfixes 940349 & 975759) then you should also have that hotfix applied to your protected VM’s, even though you aren’t running a DPM agent in that VM. Essentially treat any machine you are protecting the same according to the “Protected Computer Software Requirements” document, regardless of whether it is physical or virtual, and protected at the host or guest level.
One of the scenarios that we had running at TechEd NZ was a continuous live migration between two hosts which I had set up using Virtual Machine Manager & the Powershell components. Someone asked for it internally, and I thought I’d post it here in case anyone else would find it useful.
This is useful if you want to do any long running tests of live migration, and record the number of migrations you have done.
To set up, create C:\temp\counter.txt and edit it so that it has a single line which has the content 0. It uses this text file to record the number of migrations (it also stores in memory but uses the file in case you have to restart the script for any reason). Edit the script to replace the following fields:
vmmhost.yourdomain.com –> FQDN of your VMM Server
HyperVHost1.yourdomain.com –> FQDN of Hyper-V host 1
HyperVHost2.yourdomain.com –> FQDN of Hyper-V host 2
VMName –> Name of the VM you are going to migrate.
There is also a random delay introduced at the end of the script so the migration is not predictable.
get-vmmserver -computername "vmmhost.yourdomain.com" $vm = get-vm | where { $_.Name -eq "VMName"} $host1 = get-vmhost | where {$_.Name -eq "HyperVHost1.yourdomain.com"} $host2 = get-vmhost | where {$_.Name -eq "HyperVHost2.yourdomain.com"}
Do {
if ($vm.VMhost -eq "HyperVHost1.yourdomain.com") {$desthost=$host2} else {$desthost=$host1}
move-vm -vm $vm -vmhost $desthost -jobvariable movejob if ($movejob.Errorinfo.DetailedCode -eq 0) { $rawmigrations = get-content -Path C:\temp\counter.txt -TotalCount 1 $migrations = [int32] $rawmigrations $migrations++ $migrations set-content -Path C:\temp\counter.txt -value $migrations } $wait=get-random -minimum 60 -maximum 240 start-sleep -seconds $wait
} while ($true)
To enhance this you could also randomise the guest that is being migrated, and if you have more than a two node cluster you could randomise the destination host. If I get bored over the next few weeks I’ll update it so that it does these things.