Tag Based Affinity Rules

vROPS has a feature called Business Intent, which allows us to control the placement of virtual machines through the use of vSphere tags. Business intent allows us to control the placement of machines on a cluster basis or a host basis, allowing you to optimize the performance and placement of vms in accordance with licensing constraints, performance requirements, replication standards, etc. One downside of this feature is that vROPS does not currently allow you to control both cluster and host based placement at the same time. Today I'll present a way that allows you to leverage cluster based business intent, with a secondary method of controlling host placement within the target clusters.

OVERVIEW

There are two modes for vROPS Business Intent: Cluster Based and Host Based. Cluster based business intent causes vROPS to look at vSphere tags applied to clusters and compares them to tags applied to virtual machines. vROPS will then identify violations of these rules and allow you to remediate them manually, on a schedule or automatically. You are able to build intent rules consuming multiple vSphere tag catagories and tags. Here's an example of what it looks like when configured with an intent violation highlight.

Intent Violation

Today, we will be focusing on how to leverage host based intent. We will cover cluster based intent and the potential options for mixing the two in a future post. When using host based intent, vROPS will control placement of VMs within clusters using affinity rules, vROPS is currently only able to consume a single vSphere tag category, and each object can only have a single tag within that category. This can make it a bit limiting, as you are unable to create a scenario of declaring that host A can run windows and MSSQL servers, and host B can run windows servers such as the following scenario

Can't Do this

If you do try to assign multiple tags to an object - you'll get a big NOPE from vROPS when you try to configure the rules!

NOPE

Depening on your requirements you can perform via an approach that is less explicit in the way you declare your desired placement intentions. You can read more about that here.

If that method does not meet your needs, and you don't feel like waiting for a feature request to fix this, you can utilize a script (provided below) to configure host base affinity rules using multiple tags and categories. Be warned, the script provided below doesn't check if your tagged rules would create an affinity/anti-affinity conflict and cause DRS issues.

Yeah!

This method has the downside of pulling the management of the business intent out of vROPS hands from a host base intent perspective, but it allows you to configure cluster based business intent to understand where violations are occuring. We will cover in a future post how you can blend this script with cluster based business intent.

Before using this script, besure to vet it and perform proper testing.

  1param (
  2[Parameter(Mandatory=$true)][string[]]$vcenterlist,
  3[Parameter(Mandatory=$true)][string]$vCUsername,
  4[Parameter(Mandatory=$true)][string]$vcPassword,
  5[Parameter(Mandatory=$true)][string[]]$tagcategories
  6)
  7#$cred = Get-Credential
  8#$vcenterlist = "lab-comp01-vcenter.int.sentania.net"
  9#$tagcategories = "businessIntent"
 10
 11###CYCLE THROUGH EACH vCENTER
 12foreach ($vcenter in $vcenterlist)
 13{
 14  $vCConn = Connect-VIServer -Server $vcenter -User $vCUsername -Password $vcPassword
 15  Write-host "Processing DRS Rules via tags for: $vcenter..."
 16
 17  ####CYCLE THROUGH EACH TAG CATEGORY
 18  foreach ($tagCategory in $tagcategories)
 19  {
 20    Write-host "Processing tag category: $tagcategory..."
 21    $tagcategoryObj = Get-TagCategory -Name $tagCategory -server $vCConn
 22    $tagcategoryObj
 23
 24    ####cycle through each tag in the category
 25    $tags = get-tag -Category $tagcategoryObj
 26    foreach ($tag in $tags)
 27    {
 28       Write-host "Processing tag: $tag" -ForegroundColor Yellow
 29        ###cycle through each cluster for every tag
 30       $clusters = get-cluster -Server $vCConn
 31       foreach ($cluster in $clusters)
 32       {
 33            Write-host "Processing Cluster: $cluster..."
 34            
 35
 36            #get all hosts that have this tag
 37            $vmhosts = $cluster | get-vmhost -Tag $tag
 38            $vms = $cluster | get-vm -Tag $tag
 39            $vmgroupName = "$cluster.affinitygroup.vm."+ $tag.category +"." + $tag.name
 40            $hostgroupName = "$cluster.affinitygroup.host."+ $tag.category +"." + $tag.name
 41            $rulename = "$cluster.affinityRule."+ $tag.category +"." + $tag.name
 42            if (($vms.count -gt 0) -and ($vmhosts.count -gt 0))
 43            {
 44                ###add hosts to host group
 45                if (($hostgroup = Get-DrsClusterGroup -name $hostgroupName -ea SilentlyContinue))
 46                {
 47                    Write-host -ForegroundColor Green "Host Group Exists, updating if required..."
 48                    ###EVALUTE GROUP FOR REMOVED MEMBERS
 49                    $currentHostMembers = $hostgroupName.member
 50                    foreach ( $thishost in $currentHostMembers)
 51                    {
 52                        $hostMembersToRemove = @()
 53                        if ($vmhosts -notcontains $thishost) 
 54                        {
 55                            
 56                            $hostMembersToRemove += $thishost
 57                        }
 58                    }
 59                    if ($hostMembersToRemove.length -gt 0)
 60                    {
 61                        Write-host -ForegroundColor Red "Hosts have been removed from the group, updating...."   
 62                        $hostGroup = Set-DrsClusterGroup -DrsClusterGroup $vmgroupName -VMHost $hostMembersToRemove -Remove
 63                    }
 64                    ###EVALUTE GROUP FOR MISSING MEMBERS
 65                    $currentHostMembers = $hostgroup.member
 66                    foreach ( $thishost in $vmhosts)
 67                    {
 68                        $hostMembersToAdd = @()
 69                        if ($currentHostMembers -notcontains $thishost) 
 70                        {
 71                            
 72                            $hostMembersToAdd += $thishost
 73                        }
 74                    }
 75                    if ($hostMembersToAdd.Length -gt 0)
 76                    {
 77                        Write-host -ForegroundColor Red "Hosts are missing from the group, updating...." 
 78                        $hostGroup = set-DrsClusterGroup -DrsClusterGroup $hostgroup -VMHost $hostMembersToAdd -Add -Confirm:$false
 79                    }
 80                    else
 81                    {
 82                        Write-host -ForegroundColor Green "Host group membership is up to date"
 83                    }
 84                }
 85                else
 86                {
 87                    Write-host -ForegroundColor DarkYellow "Host Group does not exist, creating..."
 88                    $hostGroup = New-DrsClusterGroup -Name $hostgroupName -VMHost $vmhosts -Cluster $cluster -Confirm:$false
 89                }
 90                    
 91                if (($vmGroup = Get-DrsClusterGroup -name $vmgroupName  -ea SilentlyContinue))
 92                {
 93                    Write-host -ForegroundColor Green "VM Group Exists, updating if required..."
 94                    ####EVALUATE FOR REMOVED MEMBERS 
 95                    $currentVMMembers = $vmGroup.member
 96                    foreach ( $vm in $currentVMMembers)
 97                    {
 98                        $vmMembersToRemove = @()
 99                        if ($vms -notcontains $vm) 
100                        {
101                            $vmMembersToRemove += $vm
102                        }
103                    }
104                    if ($vmMembersToRemove.Length -gt 0)
105                    {
106                        $vmGroup = Set-DrsClusterGroup -DrsClusterGroup $vmgroupName -vm $vmMembersToRemove -Remove -Confirm:$false
107                    }
108                    ####EVALUATE FOR MISSING MEMBERS 
109                    $currentVMMembers = $vmGroup.member
110                    foreach ( $vm in $vms)
111                    {
112                        $vmMembersToAdd = @()
113                        if ($currentVMMembers -notcontains $vm) 
114                        {
115                            $vmMembersToAdd += $vm
116                        }
117                    }
118                    if ($vmMembersToAdd.Length -gt 0)
119                    {
120                        $vmGroup = Set-DrsClusterGroup -DrsClusterGroup $vmgroupName -vm $vmMembersToRemove -Add -Confirm:$false
121                    }
122                    else
123                    {
124                        Write-host -ForegroundColor Green "VM group membership is up to date"
125                    }
126
127                }
128                else
129                {
130                    Write-host -ForegroundColor DarkYellow "VM Group does not exist, creating..."
131                    $vmGroup = new-DrsClusterGroup -Name $vmgroupName -VM $vms -Cluster $cluster -Confirm:$false
132                }
133                
134                if (($vmhostRule = Get-DrsVMHostRule -Name $rulename -Cluster $clusters -ea SilentlyContinue))
135                {
136                    Write-Host -ForegroundColor DarkGray "VM Host rule exists - group updates will automatically cascade..."
137                }
138                else
139                {                   
140                    Write-Host -ForegroundColor DarkGray "VM Host RUle does not exist, updating"    
141                    $vmhostrule = New-DrsVMHostRule -Name $rulename -Enabled $true -VMGroup $vmGroup -VMHostGroup $hostGroup -Cluster $cluster -Type ShouldRunOn -Confirm:$false
142                }
143            }
144            else 
145            {
146                ###REMOVE GROUPS NO LONGER TAGGED 
147                Write-host "REMOVING UNUSED RULE and GROUPS....."
148                if ($vmGroup = Get-DrsClusterGroup -name $vmgroupName -Cluster $cluster -ErrorAction SilentlyContinue)
149                {
150                    Write-host "REMOVING RULE: $vmgroup"
151                    Write-host ""
152                    Remove-DrsClusterGroup -DrsClusterGroup $vmGroup -Confirm:$false
153                }
154                if ($hostGroup = Get-DrsClusterGroup -name $hostgroupName -Cluster $cluster -ErrorAction SilentlyContinue)
155                {
156                    Write-host "REMOVING RULE: $hostgroup"
157                    Write-host ""
158                    Remove-DrsClusterGroup -DrsClusterGroup $hostgroup -Confirm:$false
159                }
160                if ($drsVMHostRule = Get-DrsVMHostRule -name $rulename -Cluster $cluster -ErrorAction SilentlyContinue)
161                {
162                    Write-host "REMOVING RULE: $drsvmhostrule"
163                    Write-host ""
164                    Remove-DrsVMHostRule -RunAsync $drsVMHostRule -Confirm:$false
165                }
166
167            }
168        }
169    }
170  }
171
172  Disconnect-VIServer -Server $vCConn -Confirm:$false
173 }