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.
Comments
great work Niklas, will try this immediately. thanks.
Hi Niklas,
I’ve been reviewing the code from your site and VMware communities in order to create a PowerCLI script to update two DRS VM Groups on a stretched cluster nightly. I will be generating the new lists of VMs for the two DRS VM groups based on datastore names.
For example, the following commands below that I found appear to work for me as far as getting the latest lists of VMs for the two groups. I’m just not sure how to incorporate this into the code to update the two DRS groups. Also would like to have it output the latest lists to .csv files and have it email it. And perhaps down the road, add code to have it output to a log file. Any feedback would be appreciated, since I am very new at Powershell/PowerCLI.
Get-Cluster “clustername” | Get-vm | ?{($_.extensiondata.config.datastoreurl | %{$_.name}) -like “datastorex[1-3]_A*”} | Select-Object Name
Get-Cluster “clustername” | Get-vm | ?{($_.extensiondata.config.datastoreurl | %{$_.name}) -like “datastorez[4-6]_B*”} | Select-Object Name
[…] Niklas Åkerlund @vNiklas, wrote a function to manage DRS rules back in 2012, blog post available here, so i decided to use his function for my […]
Hello,
I’m not a PowerShell expert and I need your help.
I want to write a PS Script to compare where the VM actually running (ESX host) -> may be like “Get-VM | select name, VMhost” with the DRS hosts Group (list of ESX hosts) where she should run, if it doesn’t violate the DRS Host Affinity.
I don’t know how to collect the list of ESX Host (in DRS host group) which are associated with the VM DRS Group?
Thanks a lot for your help
Philippe
Your script works great. Thank you!
A question though… I have tried to modify your script from edit to add, but it does not work. Meaning, how can this be modified to append to the existing list instead of recreating each time?
I have numerous datastores and I am generating my VM list from DC1 and DC2 datastores.
[…] found this blog post which references this script created by Niklas Akerlund and tweaked it to my […]
Thats exactly what I was looking for! Works great! Cheers!