In the first post in this series I covered the basics of establishing an authenticated session with the Zerto API and connecting to the vCenter server. You need to configure the script examples covered in this first post in order to follow the instructions in this blog post, you can find this here:
In the Zerto GUI its very simple to deploy a Virtual Replication Appliance (VRA), you simply click New VRA, specify the information required and click Install. Then with no-impact, no downtime or maintenance mode the VRA is deployed to the ESXi host in minutes:
This process is so simple that anybody can do it in just a few clicks, but performing this process on each ESXi host can become challenging in a larger environment when you have 50, 200 or even 2000 ESXi hosts! To address this challenge you can automate this process using the API if you are running Zerto Virtual Replication (ZVR) 4.0 U2 onwards. My examples are all using ZVR 4.5 which removes the need to specify a root password as VRAs are deployed using a VIB.
To get started run the authentication and web session examples from the first post. Then we need to configure the following variables:
$LogDataDir = "C:\ZVRAPIBulkVRAScript\" $ESXiHostCSV = "C:\ZVRAPIBulkVRAScript\VRADeploymentESXiHosts.csv" $ZertoServer = "192.168.0.31" $ZertoPort = "9669" $ZertoUser = "administrator@lab.local" $ZertoPassword = "Password123" $vCenterServer = "192.168.0.81" $vCenterUser = "administrator@lab.local" $vCenterPassword = "Password123"
Now we need to create the VRADeploymentESXiHosts .csv containing all the hosts and VRA settings to use for VRA deployment. Ensure that the names of ESXi hosts, datastores and port groups are all 100% correct otherwise this will fail. VRA Groups should be configured per physical datacenter and so will usually match your vCenter name. Here is an example to deploy 2 VRAs in my DC1 vCenter:
We then need to get the Zerto Site Identifier and import the CSV of the VRAs to install:
# Get SiteIdentifier for getting Network Identifier later in the script $SiteInfoURL = $BaseURL+"localsite" $SiteInfoCMD = Invoke-RestMethod -Uri $SiteInfoURL -TimeoutSec 100 -Headers $zertSessionHeader -ContentType "application/JSON" $SiteIdentifier = $SiteInfoCMD | Select SiteIdentifier -ExpandProperty SiteIdentifier $VRAInstallURL = $BaseURL+"vras" # Importing the CSV of ESXi hosts to deploy VRA to $ESXiHostCSVImport = Import-Csv $ESXiHostCSV
All reasonably simple so far, but now comes the tricky part! We have to run the operation on each ESXi host in the CSV and do the following:
- Get the Zerto Identifiers (not vCenter) for the Port Group, ESXi Host and Datastore names specified
- Construct the JSON request for installing the VRA using the settings defined
- POST the JSON request to the ZVM to start the installation process
- Wait 90 seconds then start the same process for the next ESXi host in the environment
And to save you the hassle of figuring this out yourself here is the full script start to finish:
########################################################################### # Start of the script - Description, Requirements & Legal Disclaimer ########################################################################### # Written by: Joshua Stenhouse joshua@zerto.com +44 7834 344 838 ################################################ # Description: # This script automates the deployment of VRAs for the hosts in the specified CSV file using PowerCLI and the Zerto API to complete the process. ################################################ # Requirements: # - ZVM ServerName, Username and password with permission to access the API of the ZVM # - vCenter ServerName, Username and password to establish as session using PowerCLI to the vCenter # - ESXi root user and password for deploying the VRA # - Network access to the ZVM and vCenter, use the target site ZVM for storage info to be populated # - Access permission to write in and create (or create it manually and ensure the user has permission to write within)the directory specified for logging # - VMware PowerCLI, any version, installed on the host running the script # - Run PowerShell as administrator with command "Set-ExecutionPolcity unrestricted" ################################################ # Legal Disclaimer: # This script is written by Joshua Stenhouse is not supported under any Zerto support program or service. # All scripts are provided AS IS without warranty of any kind. # The author and Zerto further disclaims all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. # The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. # In no event shall Zerto, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or documentation, even if the author or Zerto has been advised of the possibility of such damages. ################################################ # Configure the variables below ################################################ $LogDataDir = "C:\ZVRAPIBulkVRAScript\" $ESXiHostCSV = "C:\ZVRAPIBulkVRAScript\VRADeploymentESXiHosts.csv" $ZertoServer = "192.168.0.31" $ZertoPort = "9669" $ZertoUser = "administrator@lab.local" $ZertoPassword = "Password123" $SecondsBetweenVRADeployments = "120" ################################################################################ # Nothing to configure below this line - Starting the main function ################################################################################ ################################################ # Setting log directory for engine and current month ################################################ $CurrentMonth = get-date -format MM.yy $CurrentTime = get-date -format hh.mm.ss $CurrentLogDataDir = $LogDataDir + $CurrentMonth $CurrentLogDataFile = $LogDataDir + $CurrentMonth + "\BulkVPGCreationLog-" + $CurrentTime + ".txt" # Testing path exists to engine logging, if not creating it $ExportDataDirTestPath = test-path $CurrentLogDataDir if ($ExportDataDirTestPath -eq $False) { New-Item -ItemType Directory -Force -Path $CurrentLogDataDir } start-transcript -path $CurrentLogDataFile -NoClobber ################################################ # Setting Cert Policy - required for successful auth with the Zerto API ################################################ add-type @" using System.Net; using System.Security.Cryptography.X509Certificates; public class TrustAllCertsPolicy : ICertificatePolicy { public bool CheckValidationResult( ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) { return true; } } "@ [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy ################################################ # Building Zerto API string and invoking API ################################################ $baseURL = "https://" + $ZertoServer + ":"+$ZertoPort+"/v1/" # Authenticating with Zerto APIs $xZertoSessionURI = $baseURL + "session/add" $authInfo = ("{0}:{1}" -f $ZertoUser,$ZertoPassword) $authInfo = [System.Text.Encoding]::UTF8.GetBytes($authInfo) $authInfo = [System.Convert]::ToBase64String($authInfo) $headers = @{Authorization=("Basic {0}" -f $authInfo)} $sessionBody = '{"AuthenticationMethod": "1"}' $contentType = "application/json" $xZertoSessionResponse = Invoke-WebRequest -Uri $xZertoSessionURI -Headers $headers -Method POST -Body $sessionBody -ContentType $contentType #Extracting x-zerto-session from the response, and adding it to the actual API $xZertoSession = $xZertoSessionResponse.headers.get_item("x-zerto-session") $zertoSessionHeader = @{"x-zerto-session"=$xZertoSession} # Get SiteIdentifier for getting Network Identifier later in the script $SiteInfoURL = $BaseURL+"localsite" $SiteInfoCMD = Invoke-RestMethod -Uri $SiteInfoURL -TimeoutSec 100 -Headers $zertoSessionHeader -ContentType "application/JSON" $SiteIdentifier = $SiteInfoCMD | Select SiteIdentifier -ExpandProperty SiteIdentifier $VRAInstallURL = $BaseURL+"vras" ################################################ # Importing the CSV of ESXi hosts to deploy VRA to ################################################ $ESXiHostCSVImport = Import-Csv $ESXiHostCSV ################################################ # Starting Install Process for each ESXi host specified in the CSV ################################################ foreach ($ESXiHost in $ESXiHostCSVImport) { # Setting Current variables for ease of use throughout script $VRAESXiHostName = $ESXiHost.ESXiHostName $VRADatastoreName = $ESXiHost.DatastoreName $VRAPortGroupName = $ESXiHost.PortGroupName $VRAGroupName = $ESXiHost.VRAGroupName $VRAMemoryInGB = $ESXiHost.MemoryInGB $VRADefaultGateway = $ESXiHost.DefaultGateway $VRASubnetMask = $ESXiHost.SubnetMask $VRAIPAddress = $ESXiHost.VRAIPAddress # Get NetworkIdentifier for API $APINetworkURL = $BaseURL+"virtualizationsites/$SiteIdentifier/networks" $APINetworkCMD = Invoke-RestMethod -Uri $APINetworkURL -TimeoutSec 100 -Headers $zertoSessionHeader -ContentType $ContentType $NetworkIdentifier = $APINetworkCMD | Where-Object {$_.VirtualizationNetworkName -eq $VRAPortGroupName} | Select -ExpandProperty NetworkIdentifier # Get HostIdentifier for API $APIHostURL = $BaseURL+"virtualizationsites/$SiteIdentifier/hosts" $APIHostCMD = Invoke-RestMethod -Uri $APIHostURL -TimeoutSec 100 -Headers $zertoSessionHeader -ContentType $ContentType $VRAESXiHostID = $APIHostCMD | Where-Object {$_.VirtualizationHostName -eq $VRAESXiHostName} | Select -ExpandProperty HostIdentifier # Get DatastoreIdentifier for API $APIDatastoreURL = $BaseURL+"virtualizationsites/$SiteIdentifier/datastores" $APIDatastoreCMD = Invoke-RestMethod -Uri $APIDatastoreURL -TimeoutSec 100 -Headers $zertoSessionHeader -ContentType $ContentType $VRADatastoreID = $APIDatastoreCMD | Where-Object {$_.DatastoreName -eq $VRADatastoreName} | Select -ExpandProperty DatastoreIdentifier # Creating JSON Body for API settings $JSON = "{ ""DatastoreIdentifier"": ""$VRADatastoreID"", ""GroupName"": ""$VRAGroupName"", ""HostIdentifier"": ""$VRAESXiHostID"", ""HostRootPassword"":null, ""MemoryInGb"": ""$VRAMemoryInGB"", ""NetworkIdentifier"": ""$NetworkIdentifier"", ""UsePublicKeyInsteadOfCredentials"":true, ""VraNetworkDataApi"": { ""DefaultGateway"": ""$VRADefaultGateway"", ""SubnetMask"": ""$VRASubnetMask"", ""VraIPAddress"": ""$VRAIPAddress"", ""VraIPConfigurationTypeApi"": ""Static"" } }" write-host "Executing $JSON" # Now trying API install cmd Try { Invoke-RestMethod -Method Post -Uri $VRAInstallURL -Body $JSON -ContentType $ContentType -Headers $zertoSessionHeader } Catch { Write-Host $_.Exception.ToString() $error[0] | Format-List -Force } # Waiting xx seconds before deploying the next VRA write-host "Waiting $SecondsBetweenVRADeployments seconds before deploying the next VRA" sleep $SecondsBetweenVRADeployments # End of per Host operations below } # End of per Host operations above ################################################ # Stopping logging ################################################ Stop-Transcript
And that’s it! Now you can deploy any number of VRAs automatically with the simplicity of editing a CSV and the benefits of speed and accuracy. For a pre-built version of this script and CSV you can download them as a zip file from the following link:
I hope you found this blog post useful and questions or comments let me know. Happy scripting,
Joshua