Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <#
- Script name: ha-vcenter-deploy.ps1
- Created on: 30/06/2017
- Author: Sam McGeown, @sammcgeown
- Description: The purpose of the script is to deploy vCenter in High Availability mode, using the advanced method. See https://www.definit.co.uk/2017/06/powershell-deploying-vcenter-high-availability-in-advanced-mode/
- Dependencies: None known
- #>
- param(
- [Parameter(Mandatory=$true)] [String]$configFile,
- [switch]$deployActive,
- [switch]$licenseVCSA,
- [switch]$addSecondaryNic,
- [switch]$prepareVCHA,
- [switch]$clonePassiveVM,
- [switch]$cloneWitnessVM,
- [switch]$configureVCHA,
- [switch]$resizeWitness,
- [switch]$createDRSRule
- )
- if($psboundparameters.count -eq 1) {
- # Only the configFile is passed, set all steps to true
- $deployActive = $true
- $licenseVCSA = $true
- $addSecondaryNic = $true
- $prepareVCHA = $true
- $clonePassiveVM = $true
- $cloneWitnessVM = $true
- $configureVCHA = $true
- $resizeWitness = $true
- $createDRSRule = $true
- }
- # Import the PowerCLI and DNS modules
- Get-Module -ListAvailable VMware*,DnsServer | Import-Module
- if ( !(Get-Module -Name VMware.VimAutomation.Core -ErrorAction SilentlyContinue) ) {
- throw "PowerCLI must be installed"
- }
- # Written by Sam McGeown @sammcgeown - www.definit.co.uk
- # Hat tips and thanks go to...
- # William Lam http://www.virtuallyghetto.com/2016/11/vghetto-automated-vsphere-lab-deployment-for-vsphere-6-0u2-vsphere-6-5.html
- # http://www.virtuallyghetto.com/2017/01/exploring-new-vcsa-vami-api-wpowercli-part-1.html
- # Get the folder location
- $ScriptLocation = Split-Path -Parent $PSCommandPath
- # Import the JSON Config File
- $podConfig = (get-content $($configFile) -Raw) | ConvertFrom-Json
- # Path to VCSA Install Sources
- $VCSAInstaller = "$($podConfig.sources.VCSAInstaller)"
- # Log File
- $verboseLogFile = $podConfig.general.log
- $StartTime = Get-Date
- Function Write-Log {
- param(
- [Parameter(Mandatory=$true)]
- [String]$message,
- [switch]$Warning,
- [switch]$Info
- )
- $timeStamp = Get-Date -Format "dd-MM-yyyy hh:mm:ss"
- Write-Host -NoNewline -ForegroundColor White "[$timestamp]"
- if($Warning){
- Write-Host -ForegroundColor Yellow " WARNING: $message"
- } elseif($Info) {
- Write-Host -ForegroundColor White " $message"
- }else {
- Write-Host -ForegroundColor Green " $message"
- }
- $logMessage = "[$timeStamp] $message" | Out-File -Append -LiteralPath $verboseLogFile
- }
- function Get-VCSAConnection {
- param(
- [string]$vcsaName,
- [string]$vcsaUser,
- [string]$vcsaPassword
- )
- $existingConnection = $global:DefaultVIServers | where-object -Property Name -eq -Value $vcsaName
- if($existingConnection -ne $null) {
- return $existingConnection;
- } else {
- $connection = Connect-VIServer -Server $vcsaName -User $vcsaUser -Password $vcsaPassword -WarningAction SilentlyContinue;
- if($connection -ne $null) {
- return $connection;
- } else {
- throw "Unable to connect to $($vcsaName)..."
- }
- }
- }
- function Close-VCSAConnection {
- param(
- [string]$vcsaName
- )
- if($vcsaName.Length -le 0) {
- if($Global:DefaultVIServers -ne $null) {
- Disconnect-VIServer -Server $Global:DefaultVIServers -Confirm:$false -ErrorAction SilentlyContinue
- }
- } else {
- $existingConnection = $global:DefaultVIServers | where-object -Property Name -eq -Value $vcsaName
- if($existingConnection -ne $null) {
- Disconnect-VIServer -Server $existingConnection -Confirm:$false;
- } else {
- Write-Warning -Message "Could not find an existing connection named $($vcsaName)"
- }
- }
- }
- function Get-PodFolder {
- param(
- $vcsaConnection,
- [string]$folderPath
- )
- $folderArray = $folderPath.split("/")
- $parentFolder = Get-Folder -Server $vcsaConnection -Name vm
- foreach($folder in $folderArray) {
- $folderExists = Get-Folder -Server $vcsaConnection | Where-Object -Property Name -eq -Value $folder
- if($folderExists -ne $null) {
- $parentFolder = $folderExists
- } else {
- $parentFolder = New-Folder -Name $folder -Location $parentFolder
- }
- }
- return $parentFolder
- }
- Close-VCSAConnection
- if($deployActive) {
- Write-Log "#### Deploying Active VCSA ####"
- $pVCSA = Get-VCSAConnection -vcsaName $podConfig.target.server -vcsaUser $podConfig.target.user -vcsaPassword $podConfig.target.password
- $pCluster = Get-Cluster -Name $podConfig.target.cluster -Server $pVCSA
- $pDatastore = Get-Datastore -Name $podConfig.target.datastore -Server $pVCSA
- $pPortGroup = Get-VDPortgroup -Name $podConfig.target.portgroup -Server $pVCSA
- $pFolder = Get-PodFolder -vcsaConnection $pVCSA -folderPath $podConfig.target.folder
- Write-Log "Disabling DRS on $($podConfig.target.cluster)"
- $pCluster | Set-Cluster -DrsEnabled:$true -DrsAutomationLevel:PartiallyAutomated -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile
- Write-Log "Creating DNS Record"
- Add-DnsServerResourceRecordA -Name $podConfig.active.name -ZoneName $podConfig.target.network.domain -AllowUpdateAny -IPv4Address $podConfig.active.ip -ComputerName "192.168.1.20" -CreatePtr -ErrorAction SilentlyContinue
- Write-Log "Deploying VCSA"
- $config = (Get-Content -Raw "$($VCSAInstaller)\vcsa-cli-installer\templates\install\embedded_vCSA_on_VC.json") | convertfrom-json
- $config.'new.vcsa'.vc.hostname = $podConfig.target.server
- $config.'new.vcsa'.vc.username = $podConfig.target.user
- $config.'new.vcsa'.vc.password = $podConfig.target.password
- $config.'new.vcsa'.vc.datacenter = @($podConfig.target.datacenter)
- $config.'new.vcsa'.vc.datastore = $podConfig.target.datastore
- $config.'new.vcsa'.vc.target = @($podConfig.target.cluster)
- $config.'new.vcsa'.vc.'deployment.network' = $podConfig.target.portgroup
- $config.'new.vcsa'.os.'ssh.enable' = $podConfig.general.ssh
- $config.'new.vcsa'.os.password = $podConfig.active.rootPassword
- $config.'new.vcsa'.appliance.'thin.disk.mode' = $true
- $config.'new.vcsa'.appliance.'deployment.option' = $podConfig.active.deploymentSize
- $config.'new.vcsa'.appliance.name = $podConfig.active.name
- $config.'new.vcsa'.network.'system.name' = $podConfig.active.hostname
- $config.'new.vcsa'.network.'ip.family' = "ipv4"
- $config.'new.vcsa'.network.mode = "static"
- $config.'new.vcsa'.network.ip = $podConfig.active.ip
- $config.'new.vcsa'.network.'dns.servers'[0] = $podConfig.target.network.dns
- $config.'new.vcsa'.network.prefix = $podConfig.target.network.prefix
- $config.'new.vcsa'.network.gateway = $podConfig.target.network.gateway
- $config.'new.vcsa'.sso.password = $podConfig.active.sso.password
- $config.'new.vcsa'.sso.'domain-name' = $podConfig.active.sso.domain
- $config.'new.vcsa'.sso.'site-name' = $podConfig.active.sso.site
- Write-Log "Creating VCSA JSON Configuration file for deployment"
- $config | ConvertTo-Json | Set-Content -Path "$($ENV:Temp)\active.json"
- if((Get-VM | Where-Object -Property Name -eq -Value $podConfig.active.name) -eq $null) {
- Write-Log "Deploying OVF, this may take a while..."
- Invoke-Expression "$($VCSAInstaller)\vcsa-cli-installer\win32\vcsa-deploy.exe install --no-esx-ssl-verify --accept-eula --acknowledge-ceip $($ENV:Temp)\active.json"| Out-File -Append -LiteralPath $verboseLogFile
- $vcsaDeployOutput | Out-File -Append -LiteralPath $verboseLogFile
- Write-Log "Moving $($podConfig.active.name) to $($podConfig.target.folder)"
- if((Get-VM | where {$_.name -eq $podConfig.active.name}) -eq $null) {
- throw "Could not find VCSA VM. The script was unable to find the deployed VCSA"
- }
- Get-VM -Name $podConfig.active.name | Move-VM -Destination $pFolder | Out-File -Append -LiteralPath $verboseLogFile
- } else {
- Write-Log "VCSA exists, skipping" -Warning
- }
- Close-VCSAConnection
- }
- if($licenseVCSA) {
- Write-Log "#### Configuring VCSA ####"
- Write-Log "Getting connection to the new VCSA"
- $nVCSA = Get-VCSAConnection -vcsaName $podConfig.active.ip -vcsaUser "administrator@$($podConfig.active.sso.domain)" -vcsaPassword $podConfig.active.sso.password
- Write-Log "Installing vCenter License"
- $serviceInstance = Get-View ServiceInstance -Server $nVCSA
- $licenseManagerRef=$serviceInstance.Content.LicenseManager
- $licenseManager=Get-View $licenseManagerRef
- $licenseManager.AddLicense($podConfig.license.vcenter,$null) | Out-File -Append -LiteralPath $verboseLogFile
- $licenseAssignmentManager = Get-View $licenseManager.LicenseAssignmentManager
- Write-Log "Assigning vCenter Server License"
- try {
- $licenseAssignmentManager.UpdateAssignedLicense($nVCSA.InstanceUuid, $podConfig.license.vcenter, $null) | Out-File -Append -LiteralPath $verboseLogFile
- }
- catch {
- $ErrorMessage = $_.Exception.Message
- Write-Log $ErrorMessage -Warning
- }
- Close-VCSAConnection -vcsaName $podConfig.active.ip
- }
- if($addSecondaryNic) {
- Write-Log "#### Adding HA Network Adapter ####"
- $pVCSA = Get-VCSAConnection -vcsaName $podConfig.target.server -vcsaUser $podConfig.target.user -vcsaPassword $podConfig.target.password
- if((Get-VM -Server $pVCSA -Name $podConfig.active.name | Get-NetworkAdapter).count -le 1) {
- Write-Log "Adding HA interface"
- Get-VM -Server $pVCSA -Name $podConfig.active.name | New-NetworkAdapter -Portgroup (Get-VDPortgroup -Name $podConfig.target."ha-portgroup") -Type Vmxnet3 -StartConnected | Out-File -Append -LiteralPath $verboseLogFile
- }
- Close-VCSAConnection
- $nVCSA = Get-VCSAConnection -vcsaName $podConfig.active.ip -vcsaUser "administrator@$($podConfig.active.sso.domain)" -vcsaPassword $podConfig.active.sso.password
- Write-Log "Configuring HA interface"
- $CisServer = Connect-CisServer -Server $podConfig.active.ip -User "administrator@$($podConfig.active.sso.domain)" -Password $podConfig.active.sso.password
- $ipv4API = (Get-CisService -Name 'com.vmware.appliance.techpreview.networking.ipv4')
- $specList = $ipv4API.Help.set.config.CreateExample()
- $createSpec = [pscustomobject] @{
- address = $podConfig.active."ha-ip";
- default_gateway = "";
- interface_name = "nic1";
- mode = "is_static";
- prefix = "29";
- }
- $specList += $createSpec
- $ipv4API.set($specList)
- Close-VCSAConnection
- }
- if($prepareVCHA) {
- Write-Log "#### Preparing vCenter HA mode ####"
- $nVCSA = Get-VCSAConnection -vcsaName $podConfig.active.ip -vcsaUser "administrator@$($podConfig.active.sso.domain)" -vcsaPassword $podConfig.active.sso.password
- Write-Log "Preparing vCenter HA"
- $ClusterConfig = Get-View failoverClusterConfigurator
- $PassiveIpSpec = New-Object VMware.Vim.CustomizationFixedIp
- $PassiveIpSpec.IpAddress = $podConfig.cluster."passive-ip"
- $PassiveNetwork = New-object VMware.Vim.CustomizationIPSettings
- $PassiveNetwork.Ip = $PassiveIpSpec
- $PassiveNetwork.SubnetMask = $podConfig.cluster."ha-mask"
- $PassiveNetworkSpec = New-Object Vmware.Vim.PassiveNodeNetworkSpec
- $PassiveNetworkSpec.IpSettings = $PassiveNetwork
- $WitnessIpSpec = New-Object VMware.Vim.CustomizationFixedIp
- $WitnessIpSpec.IpAddress = $podConfig.cluster."witness-ip"
- $WitnessNetwork = New-object VMware.Vim.CustomizationIPSettings
- $WitnessNetwork.Ip = $WitnessIpSpec
- $WitnessNetwork.SubnetMask = $podConfig.cluster."ha-mask"
- $WitnessNetworkSpec = New-Object VMware.Vim.NodeNetworkSpec
- $WitnessNetworkSpec.IpSettings = $WitnessNetwork
- $ClusterNetworkSpec = New-Object VMware.Vim.VchaClusterNetworkSpec
- $ClusterNetworkSpec.WitnessNetworkSpec = $WitnessNetworkSpec
- $ClusterNetworkSpec.PassiveNetworkSpec = $PassiveNetworkSpec
- $PrepareTask = $ClusterConfig.prepareVcha_task($ClusterNetworkSpec)
- Close-VCSAConnection
- }
- if($clonePassiveVM) {
- Write-Log "#### Cloning VCSA for Passive Node ####"
- $pVCSA = Get-VCSAConnection -vcsaName $podConfig.target.server -vcsaUser $podConfig.target.user -vcsaPassword $podConfig.target.password
- $pVMHost = Get-Random (Get-VMhost -Location $podConfig.target.cluster)
- $pFolder = Get-PodFolder -vcsaConnection $pVCSA -folderPath $podConfig.target.folder
- $activeVM = Get-VM -Name $podConfig.active.name
- $CloneSpecName = "vCHA_ClonePassive"
- Write-Log "Creating customization spec"
- # Clean up any old spec
- Get-OSCustomizationSpec -Name $CloneSpecName -ErrorAction SilentlyContinue | Remove-OSCustomizationSpec -Confirm:$false -ErrorAction SilentlyContinue | Out-File -Append -LiteralPath $verboseLogFile
- New-OSCustomizationSpec -Name $CloneSpecName -OSType Linux -Domain $podConfig.target.network.domain -NamingScheme fixed -DnsSuffix $podConfig.target.network.domain -NamingPrefix $podConfig.active.hostname -DnsServer $podConfig.target.network.dns -Type NonPersistent | Out-File -Append -LiteralPath $verboseLogFile
- Get-OSCustomizationNicMapping -OSCustomizationSpec $CloneSpecName | Set-OSCustomizationNicMapping -IpMode UseStaticIP -IpAddress $podConfig.active.ip -SubnetMask $podConfig.target.network.netmask -DefaultGateway $podConfig.target.network.gateway | Out-File -Append -LiteralPath $verboseLogFile
- New-OSCustomizationNicMapping -OSCustomizationSpec $CloneSpecName -IpMode UseStaticIP -IpAddress $podConfig.cluster."passive-ip" -SubnetMask $podConfig.cluster."ha-mask" -DefaultGateway $podConfig.target.network.gateway | Out-File -Append -LiteralPath $verboseLogFile
- Write-Log "Cloning Active VCSA to Passive VCSA"
- $passiveVM = New-VM -Name $podConfig.cluster."passive-name" -VM $activeVM -OSCustomizationSpec $CloneSpecName -VMhost $pVMHost -Server $pVCSA -Location $pFolder | Start-VM | Out-File -Append -LiteralPath $verboseLogFile
- # Ensure the network adapters are connected
- $passiveVM | Get-NetworkAdapter | Set-NetworkAdapter -Connected:$true -Confirm:$false
- Write-Log "Waiting for VMware Tools"
- $passiveVM | Wait-Tools
- Close-VCSAConnection
- }
- if($cloneWitnessVM) {
- Write-Log "#### Cloning VCSA for Witness Node ####"
- $pVCSA = Get-VCSAConnection -vcsaName $podConfig.target.server -vcsaUser $podConfig.target.user -vcsaPassword $podConfig.target.password
- $pVMHost = Get-Random (Get-VMhost -Location $podConfig.target.cluster)
- $pFolder = Get-PodFolder -vcsaConnection $pVCSA -folderPath $podConfig.target.folder
- $activeVM = Get-VM -Name $podConfig.active.name
- $CloneSpecName = "vCHA_CloneWitness"
- Write-Log "Creating customization spec"
- # Clean up any old spec
- Get-OSCustomizationSpec -Name $CloneSpecName -ErrorAction SilentlyContinue | Remove-OSCustomizationSpec -Confirm:$false -ErrorAction SilentlyContinue | Out-File -Append -LiteralPath $verboseLogFile
- New-OSCustomizationSpec -Name $CloneSpecName -OSType Linux -Domain $podConfig.target.network.domain -NamingScheme fixed -DnsSuffix $podConfig.target.network.domain -NamingPrefix $podConfig.active.hostname -DnsServer $podConfig.target.network.dns -Type NonPersistent | Out-File -Append -LiteralPath $verboseLogFile
- New-OSCustomizationNicMapping -OSCustomizationSpec $CloneSpecName -IpMode UseStaticIP -IpAddress $podConfig.cluster."witness-ip" -SubnetMask $podConfig.cluster."ha-mask" -DefaultGateway $podConfig.target.network.gateway | Out-File -Append -LiteralPath $verboseLogFile
- Write-Log "Cloning Active VCSA to Witness VCSA"
- $witnessVM = New-VM -Name $podConfig.cluster."witness-name" -VM $activeVM -OSCustomizationSpec $CloneSpecName -VMhost $pVMHost -Server $pVCSA -Location $pFolder | Start-VM | Out-File -Append -LiteralPath $verboseLogFile
- # Ensure the network adapters are connected
- $witnessVM | Get-NetworkAdapter | Set-NetworkAdapter -Connected:$true -Confirm:$false
- Write-Log "Waiting for VMware Tools"
- $witnessVM | Wait-Tools
- Close-VCSAConnection
- }
- if($configureVCHA) {
- Write-Log "#### Configuring vCenter HA mode ####"
- $nVCSA = Get-VCSAConnection -vcsaName $podConfig.active.ip -vcsaUser "administrator@$($podConfig.active.sso.domain)" -vcsaPassword $podConfig.active.sso.password
- $ClusterConfig = Get-View failoverClusterConfigurator
- $ClusterConfigSpec = New-Object VMware.Vim.VchaClusterConfigSpec
- $ClusterConfigSpec.PassiveIp = $podConfig.cluster."passive-ip"
- $ClusterConfigSpec.WitnessIp = $podConfig.cluster."witness-ip"
- $ConfigureTask = $ClusterConfig.configureVcha_task($ClusterConfigSpec)
- Write-Log "Waiting for cluster configuration task"
- Start-Sleep -Seconds 30
- Close-VCSAConnection -vcsaName $podConfig.active.ip
- }
- if($resizeWitness) {
- Write-Log "#### Resizing Witness Node ####"
- $pVCSA = Get-VCSAConnection -vcsaName $podConfig.target.server -vcsaUser $podConfig.target.user -vcsaPassword $podConfig.target.password
- $witnessVM = Get-VM -Name $podConfig.cluster."witness-name"
- Write-Log "Waiting for Witness node to shut down"
- $witnessVM | Stop-VMGuest -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile
- do {
- Start-Sleep -Seconds 3
- $witnessVM = Get-VM -Name $podConfig.cluster."witness-name"
- } until($witnessVM.PowerState -eq "Poweredoff")
- Write-Log "Setting CPU and Memory"
- $witnessVM | Set-VM -MemoryGB 1 -NumCpu 1 -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile
- Write-Log "Starting Witness VM"
- $witnessVM | Start-VM | Out-File -Append -LiteralPath $verboseLogFile
- Close-VCSAConnection
- }
- if($createDRSRule) {
- Write-Log "#### Creating DRS Rule ####"
- $pVCSA = Get-VCSAConnection -vcsaName $podConfig.target.server -vcsaUser $podConfig.target.user -vcsaPassword $podConfig.target.password
- $pCluster = Get-Cluster $podConfig.target.cluster
- $vCHA = Get-VM -Name $podConfig.active.name,$podConfig.cluster."passive-name",$podConfig.cluster."witness-name"
- New-DRSRule -Name "vCenter HA" -Cluster $pCluster -VM $vCHA -KeepTogether $false | Out-File -Append -LiteralPath $verboseLogFile
- Write-Log "Enabling DRS on $($podConfig.target.cluster)"
- $pCluster | Set-Cluster -DrsEnabled:$true -DrsAutomationLevel:FullyAutomated -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile
- Close-VCSAConnection
- }
- $EndTime = Get-Date
- $duration = [math]::Round((New-TimeSpan -Start $StartTime -End $EndTime).TotalMinutes,2)
- Write-Log "Pod Deployment Completed in $($duration) minutes"
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement