vSphere Cluster Host-VM rule affinity with PowerCLI
A colleague wanted a script that could make a Host-VM affinity rule so that certain VM´s that resided on one storage at one site would run on the hosts on that site, the cluster spanns over two sites so the VM´s can run at both sites but one datastore is primary at the first site and the other at the second site. So He wanted to get the VM´s that have their storage on datastoreLocation1 to be in an host-vm affinity rule “Should Run” on the hosts that is in that site. In this community post I found most of the code, I made som adjustments but mostly the cred goes to @lucd22 and GotMoo.
Here you can see the screendump from the cluster settings
Here is the powerCLI that has been run
One thing here was also that this VMgroup should be updated once a day if there was new VM´s that needed to be included. So this lines should be run in a scheduled task, this will make the DRSVMGroup VMLocationDC1 to be updated with the VM´s currently located at that datastore:
$VM = get-datastore delad02 | get-vm Update-DrsVMGroup -cluster vmw* -VMs $VM -groupVMName VMLocationDC1
Here are the PowerCLI functions for doing this. As you can see I have an switch parameter for -MustRun, that will create the rule as a Must Run on these hosts.
function New-DRSGroupRule{ <# .SYNOPSIS Create a new DRSGroupRule for VMs to reside on some hosts in a cluster .DESCRIPTION Use this function to create vms in a group and hosts in a group and a host-vm affinity .PARAMETER MustRun A switch that will create the rule with Must Run on these host, if not set it will create the rule with should run. .NOTES Author: Niklas Akerlund / RTS (most of the code came from http://communities.vmware.com/message/1667279 @LucD22 and GotMoo) Date: 2012-06-28 #> param ( [Parameter(Position=0,Mandatory=$true,HelpMessage="A Cluster", ValueFromPipeline=$True)] $cluster, $VMHosts, $VMs, [string]$Name, [switch]$MustRun ) $cluster = Get-Cluster $cluster $spec = New-Object VMware.Vim.ClusterConfigSpecEx $groupVM = New-Object VMware.Vim.ClusterGroupSpec $groupVM.operation = "add" $groupVM.Info = New-Object VMware.Vim.ClusterVmGroup $groupVM.Info.Name = "VM$Name" Get-VM $VMs | %{ $groupVM.Info.VM += $_.Extensiondata.MoRef } $spec.GroupSpec += $groupVM $groupESX = New-Object VMware.Vim.ClusterGroupSpec $groupESX.operation = "add" $groupESX.Info = New-Object VMware.Vim.ClusterHostGroup $groupESX.Info.Name = "Host$Name" Get-VMHost $VMHosts | %{ $groupESX.Info.Host += $_.Extensiondata.MoRef } $spec.GroupSpec += $groupESX $rule = New-Object VMware.Vim.ClusterRuleSpec $rule.operation = "add" $rule.info = New-Object VMware.Vim.ClusterVmHostRuleInfo $rule.info.enabled = $true $rule.info.name = $Name if($MustRun){ $rule.info.mandatory = $true }else{ $rule.info.mandatory = $false } $rule.info.vmGroupName = "VM$Name" $rule.info.affineHostGroupName = "Host$Name" $spec.RulesSpec += $rule $cluster.ExtensionData.ReconfigureComputeResource($spec,$true) } function Update-DrsVMGroup { <# .SYNOPSIS Update DRS VM group with a new collection of VM´s .DESCRIPTION Use this function to update the ClusterVMgroup with VMs that are sent in by parameters .PARAMETER xyz .NOTES Author: Niklas Akerlund / RTS (most of the code came from http://communities.vmware.com/message/1667279 @LucD22 and GotMoo) Date: 2012-06-28 #> param ( $cluster, $VMs, $groupVMName) $cluster = Get-Cluster $cluster $spec = New-Object VMware.Vim.ClusterConfigSpecEx $groupVM = New-Object VMware.Vim.ClusterGroupSpec #Operation edit will replace the contents of the GroupVMName with the new contents seleced below. $groupVM.operation = "edit" $groupVM.Info = New-Object VMware.Vim.ClusterVmGroup $groupVM.Info.Name = $groupVMName Get-VM $VMs | %{ $groupVM.Info.VM += $_.Extensiondata.MoRef } $spec.GroupSpec += $groupVM #Apply the settings to the cluster $cluster.ExtensionData.ReconfigureComputeResource($spec,$true) }
When I get the time I might add some more functionality to also remove rules and groups.