Advertisement
Guest User

cluster vmware

a guest
Apr 17th, 2018
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.60 KB | None | 0 0
  1. <#
  2. Script name: ha-vcenter-deploy.ps1
  3. Created on: 30/06/2017
  4. Author: Sam McGeown, @sammcgeown
  5. 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/
  6. Dependencies: None known
  7. #>
  8. param(
  9. [Parameter(Mandatory=$true)] [String]$configFile,
  10. [switch]$deployActive,
  11. [switch]$licenseVCSA,
  12. [switch]$addSecondaryNic,
  13. [switch]$prepareVCHA,
  14. [switch]$clonePassiveVM,
  15. [switch]$cloneWitnessVM,
  16. [switch]$configureVCHA,
  17. [switch]$resizeWitness,
  18. [switch]$createDRSRule
  19. )
  20.  
  21. if($psboundparameters.count -eq 1) {
  22. # Only the configFile is passed, set all steps to true
  23. $deployActive = $true
  24. $licenseVCSA = $true
  25. $addSecondaryNic = $true
  26. $prepareVCHA = $true
  27. $clonePassiveVM = $true
  28. $cloneWitnessVM = $true
  29. $configureVCHA = $true
  30. $resizeWitness = $true
  31. $createDRSRule = $true
  32. }
  33.  
  34. # Import the PowerCLI and DNS modules
  35. Get-Module -ListAvailable VMware*,DnsServer | Import-Module
  36. if ( !(Get-Module -Name VMware.VimAutomation.Core -ErrorAction SilentlyContinue) ) {
  37. throw "PowerCLI must be installed"
  38. }
  39. # Written by Sam McGeown @sammcgeown - www.definit.co.uk
  40. # Hat tips and thanks go to...
  41. # William Lam http://www.virtuallyghetto.com/2016/11/vghetto-automated-vsphere-lab-deployment-for-vsphere-6-0u2-vsphere-6-5.html
  42. # http://www.virtuallyghetto.com/2017/01/exploring-new-vcsa-vami-api-wpowercli-part-1.html
  43.  
  44. # Get the folder location
  45. $ScriptLocation = Split-Path -Parent $PSCommandPath
  46.  
  47. # Import the JSON Config File
  48. $podConfig = (get-content $($configFile) -Raw) | ConvertFrom-Json
  49.  
  50. # Path to VCSA Install Sources
  51. $VCSAInstaller = "$($podConfig.sources.VCSAInstaller)"
  52.  
  53. # Log File
  54. $verboseLogFile = $podConfig.general.log
  55.  
  56. $StartTime = Get-Date
  57.  
  58. Function Write-Log {
  59. param(
  60. [Parameter(Mandatory=$true)]
  61. [String]$message,
  62. [switch]$Warning,
  63. [switch]$Info
  64. )
  65. $timeStamp = Get-Date -Format "dd-MM-yyyy hh:mm:ss"
  66. Write-Host -NoNewline -ForegroundColor White "[$timestamp]"
  67. if($Warning){
  68. Write-Host -ForegroundColor Yellow " WARNING: $message"
  69. } elseif($Info) {
  70. Write-Host -ForegroundColor White " $message"
  71. }else {
  72. Write-Host -ForegroundColor Green " $message"
  73. }
  74. $logMessage = "[$timeStamp] $message" | Out-File -Append -LiteralPath $verboseLogFile
  75. }
  76.  
  77. function Get-VCSAConnection {
  78. param(
  79. [string]$vcsaName,
  80. [string]$vcsaUser,
  81. [string]$vcsaPassword
  82. )
  83. $existingConnection = $global:DefaultVIServers | where-object -Property Name -eq -Value $vcsaName
  84. if($existingConnection -ne $null) {
  85. return $existingConnection;
  86. } else {
  87. $connection = Connect-VIServer -Server $vcsaName -User $vcsaUser -Password $vcsaPassword -WarningAction SilentlyContinue;
  88. if($connection -ne $null) {
  89. return $connection;
  90. } else {
  91. throw "Unable to connect to $($vcsaName)..."
  92. }
  93. }
  94. }
  95.  
  96. function Close-VCSAConnection {
  97. param(
  98. [string]$vcsaName
  99. )
  100. if($vcsaName.Length -le 0) {
  101. if($Global:DefaultVIServers -ne $null) {
  102. Disconnect-VIServer -Server $Global:DefaultVIServers -Confirm:$false -ErrorAction SilentlyContinue
  103. }
  104. } else {
  105. $existingConnection = $global:DefaultVIServers | where-object -Property Name -eq -Value $vcsaName
  106. if($existingConnection -ne $null) {
  107. Disconnect-VIServer -Server $existingConnection -Confirm:$false;
  108. } else {
  109. Write-Warning -Message "Could not find an existing connection named $($vcsaName)"
  110. }
  111. }
  112. }
  113.  
  114. function Get-PodFolder {
  115. param(
  116. $vcsaConnection,
  117. [string]$folderPath
  118. )
  119. $folderArray = $folderPath.split("/")
  120. $parentFolder = Get-Folder -Server $vcsaConnection -Name vm
  121. foreach($folder in $folderArray) {
  122. $folderExists = Get-Folder -Server $vcsaConnection | Where-Object -Property Name -eq -Value $folder
  123. if($folderExists -ne $null) {
  124. $parentFolder = $folderExists
  125. } else {
  126. $parentFolder = New-Folder -Name $folder -Location $parentFolder
  127. }
  128. }
  129. return $parentFolder
  130. }
  131.  
  132.  
  133. Close-VCSAConnection
  134.  
  135. if($deployActive) {
  136. Write-Log "#### Deploying Active VCSA ####"
  137. $pVCSA = Get-VCSAConnection -vcsaName $podConfig.target.server -vcsaUser $podConfig.target.user -vcsaPassword $podConfig.target.password
  138. $pCluster = Get-Cluster -Name $podConfig.target.cluster -Server $pVCSA
  139. $pDatastore = Get-Datastore -Name $podConfig.target.datastore -Server $pVCSA
  140. $pPortGroup = Get-VDPortgroup -Name $podConfig.target.portgroup -Server $pVCSA
  141. $pFolder = Get-PodFolder -vcsaConnection $pVCSA -folderPath $podConfig.target.folder
  142.  
  143. Write-Log "Disabling DRS on $($podConfig.target.cluster)"
  144. $pCluster | Set-Cluster -DrsEnabled:$true -DrsAutomationLevel:PartiallyAutomated -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile
  145.  
  146.  
  147. Write-Log "Creating DNS Record"
  148. Add-DnsServerResourceRecordA -Name $podConfig.active.name -ZoneName $podConfig.target.network.domain -AllowUpdateAny -IPv4Address $podConfig.active.ip -ComputerName "192.168.1.20" -CreatePtr -ErrorAction SilentlyContinue
  149.  
  150. Write-Log "Deploying VCSA"
  151. $config = (Get-Content -Raw "$($VCSAInstaller)\vcsa-cli-installer\templates\install\embedded_vCSA_on_VC.json") | convertfrom-json
  152. $config.'new.vcsa'.vc.hostname = $podConfig.target.server
  153. $config.'new.vcsa'.vc.username = $podConfig.target.user
  154. $config.'new.vcsa'.vc.password = $podConfig.target.password
  155. $config.'new.vcsa'.vc.datacenter = @($podConfig.target.datacenter)
  156. $config.'new.vcsa'.vc.datastore = $podConfig.target.datastore
  157. $config.'new.vcsa'.vc.target = @($podConfig.target.cluster)
  158. $config.'new.vcsa'.vc.'deployment.network' = $podConfig.target.portgroup
  159. $config.'new.vcsa'.os.'ssh.enable' = $podConfig.general.ssh
  160. $config.'new.vcsa'.os.password = $podConfig.active.rootPassword
  161. $config.'new.vcsa'.appliance.'thin.disk.mode' = $true
  162. $config.'new.vcsa'.appliance.'deployment.option' = $podConfig.active.deploymentSize
  163. $config.'new.vcsa'.appliance.name = $podConfig.active.name
  164. $config.'new.vcsa'.network.'system.name' = $podConfig.active.hostname
  165. $config.'new.vcsa'.network.'ip.family' = "ipv4"
  166. $config.'new.vcsa'.network.mode = "static"
  167. $config.'new.vcsa'.network.ip = $podConfig.active.ip
  168. $config.'new.vcsa'.network.'dns.servers'[0] = $podConfig.target.network.dns
  169. $config.'new.vcsa'.network.prefix = $podConfig.target.network.prefix
  170. $config.'new.vcsa'.network.gateway = $podConfig.target.network.gateway
  171. $config.'new.vcsa'.sso.password = $podConfig.active.sso.password
  172. $config.'new.vcsa'.sso.'domain-name' = $podConfig.active.sso.domain
  173. $config.'new.vcsa'.sso.'site-name' = $podConfig.active.sso.site
  174.  
  175. Write-Log "Creating VCSA JSON Configuration file for deployment"
  176.  
  177. $config | ConvertTo-Json | Set-Content -Path "$($ENV:Temp)\active.json"
  178. if((Get-VM | Where-Object -Property Name -eq -Value $podConfig.active.name) -eq $null) {
  179. Write-Log "Deploying OVF, this may take a while..."
  180. 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
  181. $vcsaDeployOutput | Out-File -Append -LiteralPath $verboseLogFile
  182. Write-Log "Moving $($podConfig.active.name) to $($podConfig.target.folder)"
  183. if((Get-VM | where {$_.name -eq $podConfig.active.name}) -eq $null) {
  184. throw "Could not find VCSA VM. The script was unable to find the deployed VCSA"
  185. }
  186. Get-VM -Name $podConfig.active.name | Move-VM -Destination $pFolder | Out-File -Append -LiteralPath $verboseLogFile
  187. } else {
  188. Write-Log "VCSA exists, skipping" -Warning
  189. }
  190. Close-VCSAConnection
  191. }
  192.  
  193.  
  194. if($licenseVCSA) {
  195. Write-Log "#### Configuring VCSA ####"
  196. Write-Log "Getting connection to the new VCSA"
  197. $nVCSA = Get-VCSAConnection -vcsaName $podConfig.active.ip -vcsaUser "administrator@$($podConfig.active.sso.domain)" -vcsaPassword $podConfig.active.sso.password
  198.  
  199. Write-Log "Installing vCenter License"
  200. $serviceInstance = Get-View ServiceInstance -Server $nVCSA
  201. $licenseManagerRef=$serviceInstance.Content.LicenseManager
  202. $licenseManager=Get-View $licenseManagerRef
  203. $licenseManager.AddLicense($podConfig.license.vcenter,$null) | Out-File -Append -LiteralPath $verboseLogFile
  204. $licenseAssignmentManager = Get-View $licenseManager.LicenseAssignmentManager
  205. Write-Log "Assigning vCenter Server License"
  206. try {
  207. $licenseAssignmentManager.UpdateAssignedLicense($nVCSA.InstanceUuid, $podConfig.license.vcenter, $null) | Out-File -Append -LiteralPath $verboseLogFile
  208. }
  209. catch {
  210. $ErrorMessage = $_.Exception.Message
  211. Write-Log $ErrorMessage -Warning
  212. }
  213. Close-VCSAConnection -vcsaName $podConfig.active.ip
  214. }
  215.  
  216. if($addSecondaryNic) {
  217. Write-Log "#### Adding HA Network Adapter ####"
  218. $pVCSA = Get-VCSAConnection -vcsaName $podConfig.target.server -vcsaUser $podConfig.target.user -vcsaPassword $podConfig.target.password
  219.  
  220. if((Get-VM -Server $pVCSA -Name $podConfig.active.name | Get-NetworkAdapter).count -le 1) {
  221. Write-Log "Adding HA interface"
  222. 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
  223. }
  224. Close-VCSAConnection
  225.  
  226. $nVCSA = Get-VCSAConnection -vcsaName $podConfig.active.ip -vcsaUser "administrator@$($podConfig.active.sso.domain)" -vcsaPassword $podConfig.active.sso.password
  227.  
  228. Write-Log "Configuring HA interface"
  229. $CisServer = Connect-CisServer -Server $podConfig.active.ip -User "administrator@$($podConfig.active.sso.domain)" -Password $podConfig.active.sso.password
  230.  
  231. $ipv4API = (Get-CisService -Name 'com.vmware.appliance.techpreview.networking.ipv4')
  232. $specList = $ipv4API.Help.set.config.CreateExample()
  233. $createSpec = [pscustomobject] @{
  234. address = $podConfig.active."ha-ip";
  235. default_gateway = "";
  236. interface_name = "nic1";
  237. mode = "is_static";
  238. prefix = "29";
  239. }
  240. $specList += $createSpec
  241. $ipv4API.set($specList)
  242. Close-VCSAConnection
  243. }
  244.  
  245. if($prepareVCHA) {
  246. Write-Log "#### Preparing vCenter HA mode ####"
  247.  
  248. $nVCSA = Get-VCSAConnection -vcsaName $podConfig.active.ip -vcsaUser "administrator@$($podConfig.active.sso.domain)" -vcsaPassword $podConfig.active.sso.password
  249.  
  250. Write-Log "Preparing vCenter HA"
  251. $ClusterConfig = Get-View failoverClusterConfigurator
  252.  
  253. $PassiveIpSpec = New-Object VMware.Vim.CustomizationFixedIp
  254. $PassiveIpSpec.IpAddress = $podConfig.cluster."passive-ip"
  255.  
  256. $PassiveNetwork = New-object VMware.Vim.CustomizationIPSettings
  257. $PassiveNetwork.Ip = $PassiveIpSpec
  258. $PassiveNetwork.SubnetMask = $podConfig.cluster."ha-mask"
  259.  
  260. $PassiveNetworkSpec = New-Object Vmware.Vim.PassiveNodeNetworkSpec
  261. $PassiveNetworkSpec.IpSettings = $PassiveNetwork
  262.  
  263. $WitnessIpSpec = New-Object VMware.Vim.CustomizationFixedIp
  264. $WitnessIpSpec.IpAddress = $podConfig.cluster."witness-ip"
  265.  
  266. $WitnessNetwork = New-object VMware.Vim.CustomizationIPSettings
  267. $WitnessNetwork.Ip = $WitnessIpSpec
  268. $WitnessNetwork.SubnetMask = $podConfig.cluster."ha-mask"
  269.  
  270. $WitnessNetworkSpec = New-Object VMware.Vim.NodeNetworkSpec
  271. $WitnessNetworkSpec.IpSettings = $WitnessNetwork
  272.  
  273. $ClusterNetworkSpec = New-Object VMware.Vim.VchaClusterNetworkSpec
  274. $ClusterNetworkSpec.WitnessNetworkSpec = $WitnessNetworkSpec
  275. $ClusterNetworkSpec.PassiveNetworkSpec = $PassiveNetworkSpec
  276.  
  277. $PrepareTask = $ClusterConfig.prepareVcha_task($ClusterNetworkSpec)
  278.  
  279. Close-VCSAConnection
  280. }
  281.  
  282. if($clonePassiveVM) {
  283. Write-Log "#### Cloning VCSA for Passive Node ####"
  284.  
  285. $pVCSA = Get-VCSAConnection -vcsaName $podConfig.target.server -vcsaUser $podConfig.target.user -vcsaPassword $podConfig.target.password
  286. $pVMHost = Get-Random (Get-VMhost -Location $podConfig.target.cluster)
  287. $pFolder = Get-PodFolder -vcsaConnection $pVCSA -folderPath $podConfig.target.folder
  288.  
  289. $activeVM = Get-VM -Name $podConfig.active.name
  290. $CloneSpecName = "vCHA_ClonePassive"
  291.  
  292. Write-Log "Creating customization spec"
  293. # Clean up any old spec
  294. Get-OSCustomizationSpec -Name $CloneSpecName -ErrorAction SilentlyContinue | Remove-OSCustomizationSpec -Confirm:$false -ErrorAction SilentlyContinue | Out-File -Append -LiteralPath $verboseLogFile
  295. 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
  296. 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
  297. 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
  298.  
  299. Write-Log "Cloning Active VCSA to Passive VCSA"
  300. $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
  301.  
  302. # Ensure the network adapters are connected
  303. $passiveVM | Get-NetworkAdapter | Set-NetworkAdapter -Connected:$true -Confirm:$false
  304.  
  305. Write-Log "Waiting for VMware Tools"
  306. $passiveVM | Wait-Tools
  307.  
  308. Close-VCSAConnection
  309. }
  310.  
  311. if($cloneWitnessVM) {
  312. Write-Log "#### Cloning VCSA for Witness Node ####"
  313.  
  314. $pVCSA = Get-VCSAConnection -vcsaName $podConfig.target.server -vcsaUser $podConfig.target.user -vcsaPassword $podConfig.target.password
  315. $pVMHost = Get-Random (Get-VMhost -Location $podConfig.target.cluster)
  316. $pFolder = Get-PodFolder -vcsaConnection $pVCSA -folderPath $podConfig.target.folder
  317.  
  318. $activeVM = Get-VM -Name $podConfig.active.name
  319. $CloneSpecName = "vCHA_CloneWitness"
  320.  
  321. Write-Log "Creating customization spec"
  322. # Clean up any old spec
  323. Get-OSCustomizationSpec -Name $CloneSpecName -ErrorAction SilentlyContinue | Remove-OSCustomizationSpec -Confirm:$false -ErrorAction SilentlyContinue | Out-File -Append -LiteralPath $verboseLogFile
  324. 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
  325. 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
  326.  
  327. Write-Log "Cloning Active VCSA to Witness VCSA"
  328. $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
  329.  
  330. # Ensure the network adapters are connected
  331. $witnessVM | Get-NetworkAdapter | Set-NetworkAdapter -Connected:$true -Confirm:$false
  332.  
  333. Write-Log "Waiting for VMware Tools"
  334. $witnessVM | Wait-Tools
  335.  
  336. Close-VCSAConnection
  337. }
  338.  
  339. if($configureVCHA) {
  340. Write-Log "#### Configuring vCenter HA mode ####"
  341.  
  342. $nVCSA = Get-VCSAConnection -vcsaName $podConfig.active.ip -vcsaUser "administrator@$($podConfig.active.sso.domain)" -vcsaPassword $podConfig.active.sso.password
  343.  
  344. $ClusterConfig = Get-View failoverClusterConfigurator
  345. $ClusterConfigSpec = New-Object VMware.Vim.VchaClusterConfigSpec
  346. $ClusterConfigSpec.PassiveIp = $podConfig.cluster."passive-ip"
  347. $ClusterConfigSpec.WitnessIp = $podConfig.cluster."witness-ip"
  348. $ConfigureTask = $ClusterConfig.configureVcha_task($ClusterConfigSpec)
  349. Write-Log "Waiting for cluster configuration task"
  350. Start-Sleep -Seconds 30
  351.  
  352. Close-VCSAConnection -vcsaName $podConfig.active.ip
  353. }
  354.  
  355. if($resizeWitness) {
  356. Write-Log "#### Resizing Witness Node ####"
  357. $pVCSA = Get-VCSAConnection -vcsaName $podConfig.target.server -vcsaUser $podConfig.target.user -vcsaPassword $podConfig.target.password
  358.  
  359. $witnessVM = Get-VM -Name $podConfig.cluster."witness-name"
  360. Write-Log "Waiting for Witness node to shut down"
  361. $witnessVM | Stop-VMGuest -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile
  362. do {
  363. Start-Sleep -Seconds 3
  364. $witnessVM = Get-VM -Name $podConfig.cluster."witness-name"
  365. } until($witnessVM.PowerState -eq "Poweredoff")
  366. Write-Log "Setting CPU and Memory"
  367. $witnessVM | Set-VM -MemoryGB 1 -NumCpu 1 -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile
  368. Write-Log "Starting Witness VM"
  369. $witnessVM | Start-VM | Out-File -Append -LiteralPath $verboseLogFile
  370. Close-VCSAConnection
  371. }
  372.  
  373. if($createDRSRule) {
  374. Write-Log "#### Creating DRS Rule ####"
  375. $pVCSA = Get-VCSAConnection -vcsaName $podConfig.target.server -vcsaUser $podConfig.target.user -vcsaPassword $podConfig.target.password
  376. $pCluster = Get-Cluster $podConfig.target.cluster
  377. $vCHA = Get-VM -Name $podConfig.active.name,$podConfig.cluster."passive-name",$podConfig.cluster."witness-name"
  378. New-DRSRule -Name "vCenter HA" -Cluster $pCluster -VM $vCHA -KeepTogether $false | Out-File -Append -LiteralPath $verboseLogFile
  379. Write-Log "Enabling DRS on $($podConfig.target.cluster)"
  380. $pCluster | Set-Cluster -DrsEnabled:$true -DrsAutomationLevel:FullyAutomated -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile
  381. Close-VCSAConnection
  382. }
  383.  
  384.  
  385. $EndTime = Get-Date
  386. $duration = [math]::Round((New-TimeSpan -Start $StartTime -End $EndTime).TotalMinutes,2)
  387.  
  388. Write-Log "Pod Deployment Completed in $($duration) minutes"
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement