I’ve been spending a lot of time lately thinking about how organizations can provide services can operationalize the principles behind Infrastructure as Code in a way that’s accessible. In my experience, if a tool isn’t easy to use, it won’t be used. This is one of the biggest barriers to organizations (and companies that provide services, like mine) benefiting from IaC. It’s my intention that this script will achieve a high level of usability and will also generate and consume reusable code for future use.
Table of Contents
Recap
Challenge
You want to use Infrastructure as Code principles to deploy your vCenter Server, but you want to ensure that your solution is accessible without code as well.
Solution
Create a script that gathers all relevant information for a VCSA deployment via the the vcsa-deploy and generates the JSON file that the utility consumes, while also allowing for the download of the VCSA ISO from a web server.
Background
In order for this to fit my definition of infrastructure as code, we should be able to define all details of the vCenter in a structured format. Additionally, we should not assume that the vCenter installer is local, and should pull it from an external location if we need it to. While the vcsa-deploy utility can handle the installation of the vCenter, I’ve found most people don’t like it.
With this script, I allow a VI admin to fill out all relevant details of the vCenter in a spreadsheet. The script will then access the spreadsheet directly, and generate the JSON file used by vcsa-deploy. As a bonus, it will call the vcsa-deploy utility and kick off the actual deployment.
Demo
Features
- Validate Password Complexity
- Provide Input via Excel Spreadsheet or JSON file
- Download ISO, extract contents
- Deploy vCenter to either ESXi or vCenter
Requirements
- ImportExcel module
- 7-zip
- URL to a vCenter Server 6.7 Appliance ISO
- Standard vCenter Prerequisites (forward/reverse DNS, space, networking, etc) (link)
Code Review
The code can be located on my github account. As per usual, let’s go through the code.
Lines 1-31
Documentation
Lines 32-58
Define parameters
Lines 66-91
Download and install the ISO
Lines 93-130
Extract the ISO using 7-zip
Lines 133-139
Use import-excel to grab sections of the spreadsheet. There’s a bit of overhead, but my goal here was for the spreadsheet to look good.
Lines 141-152
Validate the password specified meets VMware’s requirements for the VCSA
Lines 154-172
Detect the OS
Lines 176-224
Determine whether we are deploying to a vCenter or an ESXi host and create the respective JSON. This is the only difference between deploying to a vCenter or an ESXi host.
Lines 226-298
Create a hashtable used for to create the rest of parameters common to a the json used by vcsa-deploy.
Lines 300-312
Write the JSON file to disk
Lines 314-333
Begin the install
Lines 335-343
Determine if the install was successful. If it failed, print out the error messages.
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 |
#Github: https://github.com/jonhowe/Virtjunkie.com/tree/master/VCSA-AutoDeploy #Blog Post: http://www.virtjunkie.com/deploy-vcsa-via-powershell/ <# .SYNOPSIS Install the VMware vCenter Server Appliance based on input from a Microsoft Excel File .DESCRIPTION This script will install the VMware vCenter Server Appliance based on input from a Microsoft Excel File. .PARAMETER ForceDownload Switch parameter that will force a (re) download and extract of the ISO .PARAMETER URI This is the URL of the vCenter Installer ISO .PARAMETER Workspace Absolute path to the directory that will be used as a workspace. The vCenter ISO will be downloaded there, and will be extracted there as well. .PARAMETER DeploymentTarget Location that the new VCSA will be deployed to. Valid options are: ESXi, vCenter .PARAMETER ExcelFile Absolute path to the Excel file that contains the parameters required for vCenter to be built .PARAMETER 7z Absolute path path to the 7z binary #> #Requires -modules Microsoft.powershell.archive,importexcel [CmdletBinding()] param ( [switch]$ForceDownload , $URI = "http://jondesktop.home.lan:8123/files/VMware/VSMRepo/dlg_VC67U3B/VMware-VCSA-all-6.7.0-15132721.iso" , [Parameter(Mandatory=$true)] [ValidateScript( { if ( -Not ($_ | Test-Path) ) { throw "File or folder does not exist" } return $true })] $Workspace , [validateset("vCenter", "ESXi")] $deploymentTarget , [ValidateScript( { Test-Path $_ })] [string] $ExcelFile = "/home/jhowe/git/Personal/AutomatedLab/JonAutoLab/HostDetails.xlsx" , [Parameter(Mandatory=$true)] [ValidateScript( { Test-Path $_ })] [string] $7z = '/usr/bin/7z' ) $ErrorActionPreference = 'Stop' #region Download and Extract the ISO $VCSA_Installer_Archive = $workspace + ($uri.Split('/')[-1]) $VCSA_Extracted_Directory = ($VCSA_Installer_Archive.Split(".iso")[0]) $VCSA_CLI_Installer_Path = ($VCSA_Extracted_Directory + "/vcsa-cli-installer/") #Download the VCSA only if it doesn't already exist if ((Test-Path $VCSA_Installer_Archive) -eq $false -or $forcedownload) { $filesize = (Invoke-WebRequest $uri -Method Head).Headers.'Content-Length' [int]$WebServerFileSize = ([convert]::ToInt64($filesize, 10)) / 1024 Write-Output "Downloading VCSA Installer" $wc = New-Object System.Net.WebClient $wc.DownloadFileAsync($uri, $VCSA_Installer_Archive) #The following loop will print the progressof the download every 15 seconds $incomplete = $true while ($incomplete) { $CurrentSize = ((Get-Item $VCSA_Installer_Archive).length) / 1024 if ($CurrentSize -eq $WebServerFileSize) { $incomplete = $false } else { Write-Output "File Download Size is $([math]::round($CurrentSize,0)) / $($WebServerFileSize) ($(($CurrentSize / $WebServerFileSize).ToString("P") )%)" Start-Sleep -Seconds 15 } } } else { Write-Output "VCSA Installer already exists" } #Extract the VCSA only if the directory it should be extracted to doesn't already exist if ((Test-Path ($VCSA_Extracted_Directory)) -eq $false -or $forcedownload) { Write-Output "Unzipping VCSA" #Expand-Archive -LiteralPath $VCSA_Installer_Archive -destinationpath $workspace Write-Output "Extracting the ISO now..." $arguments = "x -bb0 -bd -y -o$($VCSA_Extracted_Directory) $($VCSA_Installer_Archive)" Write-Verbose -Message ($7z + " " + $arguments) $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = $7z $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $arguments $p = New-Object System.Diagnostics.Process $p.StartInfo = $pinfo $p.Start() | Out-Null $p.WaitForExit() $7z_stdout = $p.StandardOutput.ReadToEnd() $7z_stderr = $p.StandardError.ReadToEnd() $7z_stdout | out-file -Path ($workspace + "7z-stdout.txt") $7z_stderr | out-file -Path ($workspace + "7z-stderr.txt") if ($p.ExitCode -ne 0) { Write-Output "There was an error..." Write-Output "Process finished with exit code $($p.ExitCode)" Write-Output "Log data written to: $($workspace)7z-stdout.txt and $($workspace)7z-stderr.txt" $7z_stderr } else { Write-Output "Extraction completed successfully." } } else { Write-Output "VCSA has already been unzipped" } #endregion Download and Extract the ISO #region import excel file into sections and validate input $targettype = Import-Excel $excelfile -WorksheetName vCenter -StartRow 1 -EndRow 2 -StartColumn 1 -EndColumn 1 $targetinfo = Import-Excel $excelfile -WorksheetName vCenter -StartRow 1 -EndRow 2 -StartColumn 2 -EndColumn 8 $applianceinfo = Import-Excel $excelfile -WorksheetName vCenter -StartRow 4 -EndRow 5 -StartColumn 1 -EndColumn 3 $networkinfo = Import-Excel $excelfile -WorksheetName vCenter -StartRow 7 -EndRow 8 -StartColumn 1 -EndColumn 7 $os = Import-Excel $excelfile -WorksheetName vCenter -StartRow 10 -EndRow 11 -StartColumn 1 -EndColumn 3 $sso_ciep = Import-Excel $excelfile -WorksheetName vCenter -StartRow 13 -EndRow 14 -StartColumn 1 -EndColumn 3 #Ensure the password specified has the appropriate complexity based on vCenter's requirements $input = ($os."vCenter Root Password") if (($input -cmatch '[a-z]') ` -and ($input -match '\d') ` -and ($input.length -ge 8) ` -and ($input -match '!|@|#|%|^|&|$')) { Write-Output "Password complexity is sufficient. Continuing." } else { Write-Output "$input does not meet complexity requirements. Password must be at least 8 characters, include one numeric, and one special character." exit } $deploymentTarget = $targettype.'vCenter or ESXi' #endregion import excel file into sections and validate input #region Detect the OS (Windows, Linux, OSX) if ($IsWindows -or $ENV:OS) { $installer_dir = ($VCSA_CLI_Installer_Path + "win32/") $installer = ($installer_dir + "vcsa-deploy.exe") } elseif ($IsLinux) { $installer_dir = ($VCSA_CLI_Installer_Path + "lin64/") $installer = ($installer_dir + "vcsa-deploy") chmod -R +x $workspace } elseif ($IsMacOS) { $installer_dir = ($VCSA_CLI_Installer_Path + "mac/") $installer = ($installer_dir + "vcsa-deploy") } #endregion Detect the OS (Windows, Linux, OSX) #region Create and format the JSON #Detect whether we are deploying to vCenter or ESXi switch ($deploymentTarget) { 'vCenter' { Write-Output "Deploying to vCenter" $target = [ordered] @{ vc = [ordered]@{ __comments = @("'datacenter' must end with a datacenter name, and only with a datacenter name. ", "'target' must end with an ESXi hostname, a cluster name, or a resource pool name. ", "The item 'Resources' must precede the resource pool name. ", "All names are case-sensitive. ", "For details and examples, refer to template help, i.e. vcsa-deploy {install|upgrade|migrate} --template-help") hostname = $targetinfo."Target Host or vCenter" username = $targetinfo."Username" password = $targetinfo."Password" deployment_network = $targetinfo."PortGroup" <# datacenter = @("Folder 1 (parent of Folder 2)", "Folder 2 (parent of Your Datacenter)", "Your Datacenter") #> datacenter = $targetinfo."Datacenter (vCenter Only)" datastore = $targetinfo."Datastore" <# target = @( "Folder A (parent of Folder B)", "Folder B (parent of Your ESXi Host, or Cluster)", "Your ESXi Host, or Cluster") #> target = $targetinfo."Cluster Name (vCenter Only)" } } } 'ESXi' { Write-Output "Deploying to ESXi" $target = [ordered] @{ esxi = [ordered]@{ hostname = $targetinfo."Target Host or vCenter" username = $targetinfo."Username" password = $targetinfo."Password" deployment_network = $targetinfo."PortGroup" datastore = $targetinfo."Datastore" } } } Default { Write-Error "Invalid Deployment Target Specified. Exiting." exit } } <# I'm aware that others have imported the json file provided by the installer... I don't have a great reason that I didn't do that.. maybe I'm just different :-) Either way - we are simply generating a hashtable here, and then writing it to a file. #> $common_properties = @{ appliance = [ordered]@{ __comments = @("You must provide the 'deployment_option' key with a value, which will affect the VCSA's configuration parameters, such as the VCSA's number of vCPUs, the memory size, the storage size, and the maximum numbers of ESXi hosts and VMs which can be managed. For a list of acceptable values, run the supported deployment sizes help, i.e. vcsa-deploy --supported-deployment-sizes") thin_disk_mode = $applianceinfo."Thin Disk?" deployment_option = $applianceinfo."vCenter Size" name = $applianceinfo."VM Name" } network = [ordered]@{ ip_family = $networkinfo."IP v4 or v6" mode = $networkinfo."IP Allocation Mode" ip = $networkinfo."IP Address" dns_servers = @($networkinfo.'DNS Server List').split(",") prefix = ($networkinfo."CIDR Block").tostring() gateway = $networkinfo."Default Gateway" system_name = $networkinfo."vCenter Hostname" } os = [ordered]@{ password = $os."vCenter Root Password" ntp_servers = $os."NTP Servers" ssh_enable = $os."Enable SSH By Default?" } sso = [ordered]@{ password = $sso_ciep."SSO Password" domain_name = $sso_ciep."SSO Domain Name" } } $combined = [ordered]@{ __version = "2.13.0" __comments = "Sample template to deploy a vCenter Server Appliance with an embedded Platform Services Controller on an ESXi host." new_vcsa = $target + $common_properties ceip = [ordered]@{ description = @{ __comments = @("++++VMware Customer Experience Improvement Program (CEIP)++++", "VMware's Customer Experience Improvement Program (CEIP) ", "provides VMware with information that enables VMware to ", "improve its products and services, to fix problems, ", "and to advise you on how best to deploy and use our ", "products. As part of CEIP, VMware collects technical ", "information about your organization's use of VMware ", "products and services on a regular basis in association ", "with your organization's VMware license key(s). This ", "information does not personally identify any individual. ", "", "Additional information regarding the data collected ", "through CEIP and the purposes for which it is used by ", "VMware is set forth in the Trust & Assurance Center at ", "http://www.vmware.com/trustvmware/ceip.html . If you ", "prefer not to participate in VMware's CEIP for this ", "product, you should disable CEIP by setting ", "'ceip_enabled': false. You may join or leave VMware's ", "CEIP for this product at any time. Please confirm your ", "acknowledgement by passing in the parameter ", "--acknowledge-ceip in the command line.", "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++") } settings = @{ #TODO I believe an extra member is needed if this is enabled ceip_enabled = $sso_ciep."Enable CIEP?" } } } $json = $combined | ConvertTo-Json -Depth 99 $fixtrue = $json.replace("`"true`"", "true") $FinalJSON = $fixtrue.replace("`"false`"", "false") #endregion Create and format the JSON #region Write the json file to disk switch ($deploymentTarget) { 'vCenter' { $FinalConfigFile = $workspace + "$(($FinalJSON | convertfrom-json).new_vcsa.vc.hostname).json" } 'ESXi' { $FinalConfigFile = $workspace + "$(($FinalJSON | convertfrom-json).new_vcsa.esxi.hostname).json" } Default { } } $FinalJSON | out-file -FilePath $FinalConfigFile Write-Output ("JSON file written to: " + $FinalConfigFile) #endregion Write the json file to disk #region Start the install Write-Output "Beginning install now.. this will take a few minutes. Please wait." $arguments = "install --accept-eula --no-ssl-certificate-verification --log-dir $($VCSA_CLI_Installer_Path) $($FinalConfigFile)" $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = $installer $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $arguments $p = New-Object System.Diagnostics.Process $p.StartInfo = $pinfo $p.Start() | Out-Null $p.WaitForExit() $stdout = $p.StandardOutput.ReadToEnd() $stderr = $p.StandardError.ReadToEnd() $stdout | out-file -Path ($VCSA_CLI_Installer_Path + "stdout.txt") $stderr | out-file -Path ($VCSA_CLI_Installer_Path + "stderr.txt") #endregion Start the install if ($p.ExitCode -ne 0) { Write-Output "There was an error..." Write-Output "Process finished with exit code $($p.ExitCode)" Write-Output "Log data written to: $($VCSA_CLI_Installer_Path)stdout.txt and $($VCSA_CLI_Installer_Path)stderr.txt" $stderr } else { Write-Output "Install completed successfully." } |
What’s next?
Good question! vSphere 7 is releasing vCenter Server Profiles and Image Cluster Management. Creating tools that can consume these new features will be helpful.
I’m working on template management using Hashicorp’s Packer and will be posting some of my work on that soon. In addition, I have done some work on Hashicorp’s Terraform for deploying lab VMs that I’ll share too. Finally – I’ve got a few skeleton Ansible Playbooks that I’m working on for configuration of the lab VMs, as well as a playbook for doing high level configuration of a bare vCenter. So in short – lots more coming!
Thanks for viewing,
Jon
Interesting. There are few points which I would like to highlight.
1. deploying VCSA using this method where there is no internet to download.
2. Instead internet download, how about specifying alternative intranet locations such as FTP / NAS?
3. The script developed based on linux environment, Windows version would much helpful
Hey @KKrishna, thanks for stopping by.
Re: #3 – You’re spot on.. I did use Linux to develop this, but it doesn’t make a difference. Just specify Windows paths to the 7-zip binary and your excel file and the rest should be fine.
For #1, I actually designed this to run without internet access. An example for how to do this is here: https://www.virtjunkie.com/poor-mans-autodeploy/#Web_Server
For #2, love the idea of pulling via FTP. I’d welcome a PR here: https://github.com/jonhowe/Virtjunkie.com/tree/master/VCSA-AutoDeploy
Thanks for your prompt response.
Unfortunately. I’m new to PS and as well Git. But I liked your approach. For me, I’m looking for script that start from place where ISO already extracted. So of now I’m trying to tailor your script.
Hi – Great script! Nonetheless I’m pondering a bit why you don’t only extract the ova from the ISOvcsa and deploy using “ovf-tool”. Do you have any specific reason you could share?
Good question Cristoph! I typically use ovftool when I deploy vCenter using ansible, but in this case, I wanted to use the tool that VMware provided, vcsa-deploy.