I have been doing a lot of lab testing lately and using vCloud Director is a great way to be able to run side by side tests (sometimes destructive!) against multiple environments without requiring multiple physical clusters. I wanted to emulate a Dell EMC VxRail appliance so I created a 4 node nested vSAN cluster with a vCenter appliance & external PSC running on the cluster, to use as a vCD template. When creating vCD templates it is preferable to power down the environment before adding to the vCD catalog. When it comes to powering down this environment, because the vCenter & PSC are running on the cluster, there is a chicken and egg scenario as you need to power down in this order:
- vCenter
- PSC
- Put ESXi hosts in maintenance mode (vSAN aware operation)
- Power down ESXi hosts
The inverse applies when powering up the environment. So rather than connect to multiple different interfaces to execute the power down or power up operations I put together the following Menu based PowerCli script with the following Options
These options will call the following functions
Option 1. Shutdown vSAN Cluster & PSC/vCenter
- ConnectViServer $vCenterFQDN $vCenterUser $vCenterPassword
- Generic function to connect to a VIServer (ESXi or vCenter). Just pass the hostname, user & password. This instance connects to vCenter as we need to perform a DRS operation.
- ChangeDRSLevel $PartiallyAutomated
- The ChangeDRSLevel function takes an argument for the level to set it to. In this case it sets it to partially Automated to stop DRS from moving VMs around.
- MoveVMs
- This function will move the VMs defined in $VMList to the host defined in $VMHost. This ensures that we know where the VMs are when we come to power the cluster back up
- ConnectViServer $VMHost $VMHostUser $VMHostPassword
- Generic function to connect to a VIServer (ESXi or vCenter). Just pass the hostname, user & password. This instance connects to the host defined in the $VMHost variable
- ShutdownVM
- This function will gracefully shutdown the VMs in the order defined in $VMList. In this case it will shutdown the vCenter first & then the PSC. This list can be expanded to include other VMs or could be refactored to use a CSV for a large list of VMs
- EnterMaintenanceMode
- This function will put all hosts defined in $VMHosts into maintenance mode. As this is a vSAN cluster it passes the NoAction flag to prevent any data moment or rebuild
- ShutdownESXiHosts
- This function will shutdown all hosts in the cluster
Option 2. Startup vSAN Cluster & PSC/vCenter
- ExitMaintenanceMode
- This function will exit all hosts from maintenance mode
- ConnectViServer $VMHost $VMHostUser $VMHostPassword
- Generic function to connect to a VIServer (ESXi or vCenter). Just pass the hostname, user & password. This instance connects to the host defined in the $VMHost variable
- StartVMs
- This function will startup the VMs in the reverse order defined in $VMList. In this case it will startup the PSC first & then the vCenter.
- PollvCenter
- This function will Poll vCenter until it is up and available
- ConnectViServer $vCenterFQDN $vCenterUser $vCenterPassword
- Generic function to connect to a VIServer (ESXi or vCenter). Just pass the hostname, user & password. This instance connects to vCenter as we need to perform a DRS operation
- ChangeDRSLevel $FullyAutomated
- The ChangeDRSLevel function takes an argument for the level to set it to. In this case it sets it to Fully Automated as we are done with the maintenance.
The script is posted to Github here and is also posted below. This was written and tested against vSphere 6. I will update it in the coming weeks for vSphere 6.5 and hopefully leverage some of the new APIs
# Script to shutdown & startup a vSAN cluster when vCenter/PSC are running on the cluster # Created by Brian O'Connell | Dell EMC # Provided with zero warranty! Please test before using in anger! # @LifeOfBrianOC # https://lifeofbrianoc.com/ ## User Variables ## $vCenterFQDN = "vcs01.domain.local" $vCenterUser = "VC_Admin@domain.local" $vCenterPassword = "Password123!" $Cluster = "MARVIN-Virtual-SAN-Cluster" $VMList = @("VCS01", "PSC01") $VMHosts = @("esxi04.domain.local", "esxi05.domain.local", "esxi06.domain.local", "esxi07.domain.local") $VMHost = "esxi04.domain.local" $VMHostUser = "root" $VMHostPassword = "Password123!" ### DO NOT MODIFY ANYTHING BELOW THIS LINE ### # Add Required PowerCli Modules Get-Module -ListAvailable VM* | Import-Module # Function to Connect to VI Host (vCenter or ESXi). Pass host, username & password to the function Function ConnectVIServer ($VIHost, $User, $Password) { Write-Host " " Write-Host "Connecting to $VIHost..." -Foregroundcolor yellow Connect-VIServer $VIHost -User $User -Password $Password | Out-Null Write-Host "Connected to $VIHost..." -Foregroundcolor Green Write-Host "------------------------------------------------" -Foregroundcolor Green } # Define DRS Levels to stop Vms from moving away from the defined host $PartiallyAutomated = "PartiallyAutomated" $FullyAutomated = "FullyAutomated" # Function to Change DRS Automation level Function ChangeDRSLevel ($Level) { Write-Host " " Write-Host "Changing cluster DRS Automation Level to Partially Automated" -Foregroundcolor yellow Get-Cluster $cluster | Set-Cluster -DrsAutomation $Level -confirm:$false | Out-Null Write-Host "------------------------------------------------" -Foregroundcolor yellow } # Function to Move the Vms to a defined host so they can be easily found when starting back up Function MoveVMs { Foreach ($VM in $VMList) { # Power down VM Write-Host " " Write-Host "Moving $VM to $VMHost" -Foregroundcolor yellow Get-VM $VM | Move-VM -Destination $VMHost -Confirm:$false | Out-Null Write-Host "------------------------------------------------" -Foregroundcolor yellow } Disconnect-VIServer $vCenterFQDN -confirm:$false | Out-Null } # Function to Shutdown VMs Function ShutdownVM { Foreach ($VM in $VMList) { # Power down VM Write-Host " " Write-Host "Shutting down $VM" -Foregroundcolor yellow Shutdown-VMGuest $VM -Confirm:$false | Out-Null Write-Host "------------------------------------------------" -Foregroundcolor yellow Write-Host " " Write-Host "Waiting for $VM to be Shutdown" -Foregroundcolor yellow # Check VM powerstate and wait until it is powered off before proceeding with the next VM do { sleep 15 $powerState = (get-vm $VM).PowerState } while ($powerState -eq "PoweredOn") Write-Host " " Write-Host "$VM Shutdown.." -Foregroundcolor green Write-Host "------------------------------------------------" -Foregroundcolor yellow } } # Function to put all ESXi hosts into maintenance mode with the No Action flag for vSAN data rebuilds Function EnterMaintenanceMode { Foreach ($VMHost in $VMHosts) { Connect-VIServer $VMHost -User root -Password $VMHostPassword | Out-Null # Put Host into Maintenance Mode Write-Host " " Write-Host "Putting $VMHost into Maintenance Mode" -Foregroundcolor yellow Get-View -ViewType HostSystem -Filter @{"Name" = $VMHost }|?{!$_.Runtime.InMaintenanceMode}|%{$_.EnterMaintenanceMode(0, $false, (new-object VMware.Vim.HostMaintenanceSpec -Property @{vsanMode=(new-object VMware.Vim.VsanHostDecommissionMode -Property @{objectAction=[VMware.Vim.VsanHostDecommissionModeObjectAction]::NoAction})}))} Disconnect-VIServer $VMHost -confirm:$false | Out-Null Write-Host "------------------------------------------------" -Foregroundcolor yellow Write-Host " " Write-Host "$VMHost in maintenance mode.." -Foregroundcolor green Write-Host "------------------------------------------------" -Foregroundcolor yellow } } # Function to Exit hosts from maintenance mode Function ExitMaintenanceMode { Foreach ($VMHost in $VMHosts) { Connect-VIServer $VMHost -User root -Password $VMHostPassword | Out-Null # Exit Maintenance Mode Write-Host " " Write-Host "Exiting Maintenance Mode for $VMHost" -Foregroundcolor yellow Set-VMHost $VMHost -State "Connected" | Out-Null Disconnect-VIServer $VMHost -confirm:$false | Out-Null Write-Host "------------------------------------------------" -Foregroundcolor yellow Write-Host " " Write-Host "$VMHost out of maintenance mode.." -Foregroundcolor green Write-Host "------------------------------------------------" -Foregroundcolor yellow } Write-Host "Waiting for vSAN Cluster to be Online" -Foregroundcolor yellow Sleep 60 } # Function to shutdown hosts Function ShutdownESXiHosts { Foreach ($VMHost in $VMHosts) { # Exit Maintenance Mode Write-Host " " Write-Host "Shutting down ESXi Hosts" -Foregroundcolor yellow Connect-VIServer -Server $VMHost -User root -Password $VMHostPassword | %{ Get-VMHost -Server $_ | %{ $_.ExtensionData.ShutdownHost_Task($TRUE) | Out-Null } } Write-Host "------------------------------------------------" -Foregroundcolor yellow Write-Host " " Write-Host "ESXi host $VMHost shutdown.." -Foregroundcolor green Write-Host "------------------------------------------------" -Foregroundcolor yellow } Write-Host "------------------------------------------------" -Foregroundcolor yellow Write-Host " " Write-Host "All ESXi Hosts shutdown.." -Foregroundcolor green Write-Host "------------------------------------------------" -Foregroundcolor yellow } # Function to Start VMs in the reverse order they were powered down Function StartVMs { # Reverse the VM list to start in reverse order [array]::Reverse($VMList) Foreach ($VM in $VMList) { # Power on VM Write-Host " " Write-Host "Powering on $VM" -Foregroundcolor yellow Start-VM $VM -Confirm:$false | Out-Null Write-Host "------------------------------------------------" -Foregroundcolor yellow Write-Host " " Write-Host "Waiting for $VM to be Powered On" -Foregroundcolor yellow # Check VM powerstate and wait until it is powered on before proceeding with the next VM do { sleep 15 $powerState = (get-vm $VM).PowerState } while ($VM -eq "PoweredOff") Write-Host " " Write-Host "$VM Powered On..proceeding with next VM" -Foregroundcolor green Write-Host "------------------------------------------------" -Foregroundcolor yellow } } # Function to Poll the status of vCenter after starting up the VM Function PollvCenter { do { try { Write-Host " " Write-Host "Polling vCenter $vCenterFQDN Availability...." -ForegroundColor Yellow Write-Host "------------------------------------------------" -Foregroundcolor yellow # Create Web Request [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} $HTTP_Request = [System.Net.WebRequest]::Create("https://$($vCenterFQDN):9443") # Get a response $HTTP_Response = $HTTP_Request.GetResponse() # Get the HTTP code $HTTP_Status = [int]$HTTP_Response.StatusCode If ($HTTP_Status -eq 200) { Write-Host " " Write-Host "vCenter $vCenterFQDN is Available!" -ForegroundColor Green Write-Host "------------------------------------------------" -Foregroundcolor Green # Close HTTP request $HTTP_Response.Close() } } catch { Write-Host " " Write-Host "vCenter $vCenterFQDN Not Available Yet...Retrying Poll..." -ForegroundColor Cyan Write-Host "------------------------------------------------" -Foregroundcolor Cyan } } While ($HTTP_Status -ne 200) } # Function to display the main menu Function Menu { Clear-Host Do { Clear-Host Write-Host -Object 'Please choose an option' Write-Host -Object '**********************' Write-Host -Object 'vCenter & vSAN Maintenance Options' -Foregroundcolor Yellow Write-Host -Object '**********************' Write-Host -Object '1. Shutdown vSAN Cluster & PSC/vCenter ' Write-Host -Object '' Write-Host -Object '2. Startup vSAN Cluster & PSC/vCenter ' Write-Host -Object '' Write-Host -Object 'Q. Exit' Write-Host -Object $errout $Menu = Read-Host -Prompt '(Enter 1 - 2 or Q to quit)' switch ($Menu) { 1 { ConnectVIServer $vCenterFQDN $vCenterUser $vCenterPassword ChangeDRSLevel $PartiallyAutomated MoveVMs ConnectVIServer $VMHost $VMHostUser $VMHostPassword ShutdownVM EnterMaintenanceMode ShutdownESXiHosts } 2 { ExitMaintenanceMode ConnectVIServer $VMHost $VMHostUser $VMHostPassword StartVMs PollvCenter ConnectVIServer $vCenterFQDN $vCenterUser $vCenterPassword ChangeDRSLevel $FullyAutomated } Q { Exit } default { $errout = 'Invalid option please try again........Try 1-2 or Q only' } } } until ($Menu -eq 'q') } # Launch The Menu Menu
Hello, thanks for this… I am working with a number of your colleagues on an errant VXrail system. Hoping we get the performance on it up to scratch eventually, its been hard work.
Regarding your script, I am trying to adapt it to shut down my home lab vsan in the case of a power outage. My UPS gives me about 25 minutes run time, but if its an extended outage and I am not here I want to shut down gracefully. I think I can probably use the functions in this to get the job done, so thank you. If you have any advice on this, I’d also appreciate that.
Hi, me again… didn’t realize you are in Cork, have a very good friend lives in Cork and works for Apple, nice city. Anyway, going through your script I don’t think it checks to make sure that there are no objects syncing before shutting down. I have shutdown my vsan several time and not checked that there were no objects resyncing and it has never been a problem. I became familiar with the resyncing process from working on our VXRail system – engineering identified that we have 4 bad SSDs (its a hybrid system) and we are currently replacing them. Its taking around 2 days to resync the data after replacing each one… can’t understand why it takes that long as adding the objects up it’s less than 1TB of data. Anyway, we are half way through. Back to your script – do you know if there is a way to check if any objects are syncing before shutting down? and would there be a way to stop that safely? As I would be shutting down due to power failure, I don’t have much choice but to shut down – but just wondered if you have given that any thought.
Cheers
Bill
Hey Bill..thanks for the comments and glad you’re finding the script useful. To be honest the script is a little rough and ready and was created for my use case of quickly and easily starting up and shutting down my nested vSAN lab. It should be easy enough to adapt it for your use case though. If you would like to give me some additional information on your setup i’ll see if i can help (time permitting obviously!). I hadnt looked at re-sync status but i will take a look when i get some free time. I do plan to revisit the script for vSphere 6.5 to leverage the new APIs. Will post that when i get around to completing it. Cheers Brian