Advertisement
Guest User

Cluster PowerCLI

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