6 minute read

There are multiple ways of adding extra storage policies and apply them to multiple virtual machines and plenty of VMware documentation and others to show how to do it.

But to reduce risk and minimize configuration drift, typically scripting/automating is the way to achieve that.

Hence we will try to quickly describe how to leverage some of the VMware PowerCLI cmdlets that can do this job for us.

And the better way of doing is using an example taken from our experience.

Objective

  • We want to setup a series of extra vSAN Storage Policies
  • We want to change the Storage Policy _assigned to all _Management Virtual Machines to one of our new Storage Policies
  • We want a script that can scale to any number of Storage Policies and Virtual Machine Locations

Scenario

  • Implementation is done via VMware Cloud Foundation (VCF)
  • Consolidate Cluster Design
  • Management Virtual Machines are all under specific Resource Pools

Script Structure

  • some structures and variables - that will make our life easier later if we need to scale out the script
  • loops - where we create the storage policies and assign to the virtual machines
  • the entire script

Some structure and variables

  • Some variables with useful info that will be easier to keep on top to edit that go through the code
# Utility variables/constants
# Locations where the vms will be and policy to assign
# - Locations - see notes in the end of the post
$vmLocations = @(
    @{ location = "X-ResourcePool" ; policy = "management" } ;
    @{ location = "Y-ResourcePool" ; policy = "raid5" }
)
# expreg with the name of the VMs that we do not want to change the assigned storage policy
$vmsToExcludeStoragePolicyChanges = "(DoNotChange_VM.*)|(NSX-Controller.*)"
  • Our structure to define the multiple policies
# Policy definition
$vsanPoliciesProperties = @{
    "management" = @{
        "name" = "Management VMs Storage Policy" ;
        "description" = "Used for all management vms" ;
        "rulesets" = @(
            @{
                "name" = "Rule-set 1: VSAN" ;
                "rules" = @(
                    @{ "capability" = "VSAN.hostFailuresToTolerate" ;
                       "value" = 1 } ,
                    @{ "capability" = "VSAN.replicaPreference" ;
                       "value"= "RAID-1 (Mirroring) - Performance" }
                )
            }
        )
    } ;
    "raid5" = @{
        "name" = "VM Storage Policy - RAID5" ;
        "description" = "RAID5" ;
        "rulesets" = @(
            @{
                "name"  = "Rule-set 1: VSAN" ;
                "rules" = @(
                    @{ "capability" = "VSAN.hostFailuresToTolerate" ;
                       "value" = 1 } ,
                    @{ "capability" = "VSAN.replicaPreference";
                       "value"= "RAID-5/6 (Erasure Coding) - Capacity" }
                )
            }
        )
    }
}

# List of VSAN capabilities for reference
#Get-SpbmCapability VSAN*
#Name                                     ValueCollectionType ValueType
#VSAN.cacheReservation                                        System.Int32
#VSAN.checksumDisabled                                        System.Boolean
#VSAN.forceProvisioning                                       System.Boolean
#VSAN.hostFailuresToTolerate                                  System.Int32
#VSAN.iopsLimit                                               System.Int32
#VSAN.proportionalCapacity                                    System.Int32
#VSAN.replicaPreference                                       System.String
#VSAN.stripeWidth                                             System.Int32
  • vsanPoliciesProperties structure seems a bit too much, but the idea is to give the flexibility to add more storage policies if needed with a minimal change

  • Example of adding one extra policy vsanPoliciesProperties

...
    "newPolicy" = @{
        "name" = "VM Storage Policy - New Policy" ;
        "description" = "Im a example of a new storage policy" ;
        "rulesets" = @(
            @{
                "name"  = "Rule-set 1: VSAN" ;
                "rules" = @(
                    @{ "capability" = "VSAN.iopsLimit" ; "value" = 1000 } ,
                    @{ "capability" = "VSAN.stripeWidth" ; "value"= 2 }
                )
            }
        )
    }
....

Loops

  • There are 2 loops
    • First creating the storage policies using the information from the structures described above
    • A second where we will assign the virtual machines in each location in $vmLocations the respective storage policy

Creating Storage Policies

# Setup policies
Write-Host "=> Setup vSAN storage policies <=" -ForegroundColor Green
Foreach($policyName in $vsanPoliciesProperties.Keys) {
    # Get specific properties for the policy to configure
    $policyProperties = $vsanPoliciesProperties.$policyName

    # Get and create rulesets
    $ruleSets = New-Object System.Collections.ArrayList
    Foreach($ruleSet in $policyProperties.rulesets ) {
        # Create array with the rules of each ruleset
        $rules = New-Object System.Collections.ArrayList
        Foreach( $rule in $ruleSet.rules ) {
            $rules += New-SpbmRule `
               -Capability (Get-SpbmCapability -Name $rule.capability) `
               -Value $rule.value
        }
        $ruleSets += New-SpbmRuleSet -Name $ruleSet.name -AllOfRules $rules
    }
    # Create policy
    New-SpbmStoragePolicy -Name $policyProperties.name `
       -Description $policyProperties.description `
       -AnyOfRuleSets $ruleSets
}

Assigning Storage Policies

$clusters = Get-Cluster
Foreach($cluster in $clusters) {
    # Change VSAN storage policy for Management VMs
    Write-Host "=> Setup vSAN storage policies - $($vsanPoliciesProperties.management.name) <=" `
       -ForegroundColor Green
    # For each of the Resource Pools with Management VMs
    Foreach($vmLocation in $vmLocations) {
       # for each resourcePool
       $vms = $cluster | Get-ResourcePool -Name $vmLocation.location | Get-VM | `
          Where-Object { $_.Name -notmatch $vmsToExcludeStoragePolicyChanges}
       if($vms.Count) {
          Write-Host "==> Setup vSAN storage policies - Virtual Machines in $($vmLocation.location) - `
             Policy: $($vsanPoliciesProperties.($vmLocation.policy).name) <==" `
             -ForegroundColor Green
          # Set VMs Storage Policy
          $vms | Set-SpbmEntityConfiguration -SpbmEnabled $true `
            -StoragePolicy (Get-SpbmStoragePolicy `
            -Name ($vsanPoliciesProperties.($vmLocation.policy).name)) | `
            Select-Object Name, StoragePolicy | Format-Table -AutoSize
          # Set VMs All vDisks
          $vms | Get-HardDisk | `
          Set-SpbmEntityConfiguration -SpbmEnabled $true `
            -StoragePolicy (Get-SpbmStoragePolicy `
            -Name ($vsanPoliciesProperties.($vmLocation.policy).name)) | `
            Select-Object @{N="VM Name";E={Get-VM -Id ($_.Id).Split("/")[0]}}, Name, StoragePolicy |`
            Format-Table -AutoSize
        }
    }
}

Last notes

  • Consolidate Cluster Design means that Management Virtual Machines will be assigned under a Management Resource Pool, instead of a Dedicated VMware Cluster
  • Will be easy to adapt the script to allow the use of any type of Location besides Resource Pools (something that could be covered later in another post)
  • Code should have enough comments to be easy to read, however feel free to reach out if needed
  • Post do not cover detailed explanation of VMware PowerCLI cmdlets, since VMware documentation is really good, some of the links