Using CPU Reserve to enforce virtual processor ratio

On Monday I posted a script for configuring virtual machine CPU scheduler settings.  This script got me to thinking about another use for the virtual machine CPU reserve.

You see, it can also be used to ensure that you do not unintentionally start too many virtual machines at once.

If you were to set the CPU reserve on each virtual machine at 20% (or at 20,000 using the underlying API) then it is not possible to start extra virtual machines once you hit a ratio of 5 virtual processors for each physical processor.  This is actually what System Center Virtual Machine Manager does to enforce limits on the system.

Here is a script that will do just that:

 # Function for handling WMI jobs / return values
 Function ProcessResult($result, $successString, $failureString)
 {
    #Return success if the return value is "0"
    if ($result.ReturnValue -eq 0)
       {write-host $successString} 
  
    #If the return value is not "0" or "4096" then the operation failed
    ElseIf ($result.ReturnValue -ne 4096)
       {write-host $failureString " Error value:" $result.ReturnValue}
  
    Else
       {#Get the job object
       $job=[WMI]$result.job
  
       #Provide updates if the jobstate is "3" (starting) or "4" (running)
       while ($job.JobState -eq 3 -or $job.JobState -eq 4)
          {write-host $job.PercentComplete "% complete"
           start-sleep 1
  
           #Refresh the job object
           $job=[WMI]$result.job}
  
        #A jobstate of "7" means success
        if ($job.JobState -eq 7)
           {write-host $successString}
        Else
           {write-host $failureString
           write-host "ErrorCode:" $job.ErrorCode
           write-host "ErrorDescription" $job.ErrorDescription}
        }
 }
  
 # Prompt for the Hyper-V Server to use
 $HyperVServer = Read-Host "Specify the Hyper-V Server to use (enter '.' for the local computer)"
  
 # Prompt for the new CPU reservation
 $NewReservation = Read-Host "Specify the CPU reservation (from 0-100000)"
  
 # Get the management service
 $VMMS = gwmi -namespace root\virtualization Msvm_VirtualSystemManagementService -computername $HyperVServer
  
 # Get all VSSDs for non-snapshots
 $VSSDs = gwmi "MSVM_VirtualSystemSettingData" -namespace "root\virtualization" -computername $HyperVServer | ? {$_.SettingType -eq 3}  
  
 foreach ($VSSD in $VSSDs)
    {
    # Get the related VM
    $VM = $VSSD.getRelated("MSVM_ComputerSystem") | select -first 1
    
    # Get the processor setting data
    $ProcSetting = $VSSD.getRelated("Msvm_ProcessorSettingData") | select -first 1
  
    # Update ProcSetting with the new value
    $ProcSetting.Reservation = $NewReservation
  
    # Apply the changes to the processor setting data back to the virtual machine
    $result = $VMMS.ModifyVirtualSystemResources($VM, $ProcSetting.GetText(1))
   
    # Process the result
    $successMessage = "Updated processor scheduling settings on '" + $VM.ElementName + "'"
    $failureMessage = "Failed to update processor scheduling settings on " + $VM.ElementName + "'"
    ProcessResult $result $successMessage $failureMessage
    }

If you run this script and specify “20000” then you will be able to run at a ratio of 5 virtual processors for each physical processor.  If you run this script and specify “25000” then you will be able to run at a ratio of 4 virtual processors for each physical processor.

Note that this will not apply to any virtual machine snapshots, or to any newly created virtual machines, so it is a little fragile as a solution.

Cheers,
Ben

SetProcReservationOnAll.zip