Multi-cloud
Aria Automation vRealize Automation Ecosystem

Scaling a vRA 7.3 Environment (Part 3)

Last time we explored the wonderful vra-command tool. Now it’s time to dive into the REST API world of vRA configuration. You may already know the vRA API and probably may have already used it. However, if you open a browser and navigate to https://you-vra-va:5480/config you’ll see a nice UI listing all the available options for meddling with your infrastructure:

When you click on a certain command you can event test it. This will trigger a curl statement on the current VA and will show all the results on the same page:

This is very neat!

And just like with vra-command, you’ve got all the options in the world to scale vRA any way you want.

To make your life easier, I’ve even prepared a PowerShell script that can invoke all these operations. The script is below and can be run by using the following switches:

script-name.ps1 [install-webcert] [install-mgrcert] [install-vracert] [invite-cluster] [install-web] [install-dem] [install-manager]

Before running the script there are a few parameters you need to fill out. You can see all the parameters and their values in the initialization section of the script. Just edit the script to reflect your environment and you’re good to go. If you want to know what parameters each operation requires you can check all the Construct-XXXBody functions. They define the JSON bodies for all the PUT requests that are issued. I’ve tried to make the script as generic as possible so it would be easier for you to modify it every way you want. Just remember to install the management agents on the IaaS server beforehand.

I almost forgot – the install-XXXcert switches are actually working 100% and also do the job of re-configuring IIS and other services for you! Quite unlike vra-command. API’s are wicked!

#####Initialization############
 ###### ############

######Script Parameters#######
 Param(
 [ValidateNotNullOrEmpty()][string]$ConfigOperation
 )

add-type @"
 using System.Net;
 using System.Security.Cryptography.X509Certificates;

public class IgnoreSSLPolicy : ICertificatePolicy {
 public IgnoreSSLPolicy() {}
 public bool CheckValidationResult(
 ServicePoint sPoint, X509Certificate cert,
 WebRequest wRequest, int certProb) {
 return true;
 }
 }
 "@
 [System.Net.ServicePointManager]::CertificatePolicy = new-object IgnoreSSLPolicy

######Initial vRA Parameters
 $accept = "application/json"
 $contentType = "application/json"
 $CertFile = "" #Path to the cert file used for the install-XXXcert commands. The file should be in PEM format and should contain both he private key and the public key chain
 #VA
 $vraURI = "https://" #The URI of the VA appliance you're connecting to. It should look like https://va-fqdn
 $vamiPort = "5480" #most commonly 5480
 $username = "root"
 $password = ""
 $credPair = "$($username):$($password)"
 $encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($credPair)) #convert the credential pair to base64
 $vraLBFQDN = "" #The FQDN of the load balancing endpoint of the VAs, i.e. the vRealize Automation Console
 $defaultTenant = "vsphere.local"
 $vidmAdminUser = "[email protected]" #the administrator for the default tenant
 $VidmAdminPassword = ""
 $VraCertThumbprint = "" #The thumbprint of the certificate used for the load balancing endpoint of the VAs
 $newVA = "" #the FQDN of the appliance you're trying to add
 $newVAUsername = "root" #Username and password of the appliance you're trying to add
 $newVAPassword = ""
 #IaaS General
 $svcUserName = "" #Service Account information for the IaaS. Usually it's the same across all roles, but if it's different you should modify it before each script run
 $svcUserPwd = ""
 #IaaS WEB
 $iaaSWebLBFQDN = "" #The load balancing endpoint of the IaaS Web role
 $webCertThumbprint = "" #the thumbripnt of the certificate used for the load balancing endpoint of the IaaS Web role
 $webUseEncryption = "False"
 $webInstallPath = ""
 $webNode = "" #The web node to add to cluster
 #SQL Server
 $msSQLServer = "" #The SQL Server for the IaaS database
 $sqlDBName = ""
 $useWindowsAuth = "True"
 $sqlUserPwd = ""
 $sqlUserName = ""
 $passhrase = ""
 #IaaS Manager
 $mgrNode = "" #The manager node to add to cluster
 $mgrServiceAddr = "" #The load balancing endpoint of the manager service
 $mgrHTTPSPort = "443"
 $mgrWebSiteName = "Default Web Site"
 $mgrInstallPath = ""
 $mgrUseEncryption = "False"
 $mgrServiceFailoverModeEnabled = "True"
 $mgrServiceCertThumbprint = ""
 #DEM
 $demDescr = ""
 $demName = ""
 $demNode = ""

########### Functions ###########
 ########### ###########

function Invoke-VraConfig
 {
 param(
 [ValidateNotNullOrEmpty()][uri]$configURI="",
 [ValidateNotNullOrEmpty()][hashtable]$reqBody=@{},
 [ValidateNotNullOrEmpty()][hashtable]$reqHeaders=@{},
 [string]$method="GET",
 [ValidateNotNullOrEmpty()][string]$b64Credentials=""
 )

if(!$configUri.IsAbsoluteUri)
 {
 Write-Host "Please, specify a valid API URI."
 return 0
 }

$basicAuthValue = "Basic $b64credentials"
 $reqHeaders.add("Authorization", $basicAuthValue)

$result=$null

if($method -eq "GET")
 {
 $result = try {Invoke-RestMethod -Uri $configURI.OriginalString -Headers $reqHeaders -Method $method } catch {$_.Exception.Response}
 }else
 {
 $result = try {Invoke-RestMethod -Uri $configURI.OriginalString -Headers $reqHeaders -Body (ConvertTo-JSON $reqBody) -Method $method -TimeoutSec 0 } catch {$_.Exception.Response}
 }
 return $result

}

function Get-NodeId
 {
 [OutputType([string])]
 param(
 [ValidateNotNullOrEmpty()][uri]$baseURI="",
 [string]$vamiPort="5480",
 [ValidateNotNullOrEmpty()][string]$b64Credentials="",
 [ValidateNotNullOrEmpty()][string]$nodeHost=""
 )
 $tempURI = ""
 $tempURI = $baseURI.OriginalString + ":" + $vamiPort + "/config/nodes/list?json=true&components=false" #construct the API URL
 $reqBody = @{}

$reqHeaders = @{}
 $reqHeaders.Add("Accept","text/plain")
 Write-Host "Trying to get ID of node $mgrNode by calling $tempURI"
 $nodesList = Invoke-VraConfig -configURI $tempURI -reqHeaders $reqHeaders -method "GET" -b64Credentials $b64Credentials
 if($nodesList -ne 0)
 {
 $nodeId = $nodesList | where {$_.nodeHost -eq "$nodeHost"} | Select nodeId
 return $nodeId.nodeId
 }
 else
 {
 Write-Host "Could not get list of nodes"
 return 0
 }
 }

function Get-PublicKey
 {
 [OutputType([string])]
 param (
 [ValidateNotNullOrEmpty()][Uri]$Uri
 )

if (-Not ($uri.Scheme -eq "https"))
 {
 Write-Error "You can only get keys for https addresses"
 return 0
 }

try
 {
 $request = [System.Net.HttpWebRequest]::Create($uri)

#Make the request but ignore (dispose it) the response, since we only care about the service point
 $request.GetResponse().Dispose()
 }
 catch [System.Net.WebException]
 {
 if ($_.Exception.Status -eq [System.Net.WebExceptionStatus]::TrustFailure)
 {
 #We ignore trust failures, since we only want the certificate, and the service point is still populated at this point
 }
 else
 {
 #Let other exceptions of type WebException be handled here
 Write-Host $_.Exception.Message
 return 0
 }
 }
 catch [Exception]
 {
 #and the rest here
 Write-Host $_.Exception.Message
 return 0
 }

#The ServicePoint object should now contain the Certificate for the site.
 $servicePoint = $request.ServicePoint
 $cert = $servicePoint.Certificate.GetRawCertData()
 $keyB64 = [System.Convert]::ToBase64String($cert)
 return $keyB64
 }
 #region Cluster Join
 #Invite another VA
 function Construct-VABody
 {
 $body = @{}
 $body.Add("VaUser", $newVAUsername)
 $body.Add("VaPassword", $newVAPassword)
 $body.Add("VaHost", "$secondVA")
 return $body
 }
 function Invite-Cluster
 {
 param(
 [ValidateNotNullOrEmpty()][hashtable]$body = @{},
 [ValidateNotNullOrEmpty()][string]$vaNode,
 [ValidateNotNullOrEmpty()][uri]$baseURI="",
 [string]$vamiPort="5480",
 [ValidateNotNullOrEmpty()][string]$b64Credentials=""
 )

$vaNodeId = Get-NodeId -baseURI $baseUri.OriginalString -vamiPort $vamiPort -b64Credentials $encodedCreds -nodeHost $baseURI.Host
 if(!$vaNodeID)
 {
 Write-Host "Cannot find ID for node $baseURI.Host"
 }
 else
 {
 Write-Host "ID of node $baseURI is $vaNodeId"
 $URL = "/config/execute/command/cluster-invite/node/$vaNodeId" #Execute command on first VA
 try
 {
 $publicKey = Get-PublicKey -Uri ("https://$vaNode" + ":5480")
 if ($publicKey -ne 0)
 {
 $publicKey = "-----BEGIN CERTIFICATE-----`n"+$publicKey
 $publicKey = $publicKey + "`n-----END CERTIFICATE-----"
 $body.Add("VamiCertificate", "$publicKey")
 }
 else
 {
 Write-Host "Cannot get certificate of the VA to add"
 return 0
 }
 }
 catch [Exception]
 {
 Write-Host "There was an error while extracting the public key from the new VA"
 return $_.Exception.Message
 }
 $headers = $null
 $headers = @{}
 $headers.Add("Content-Type", "application/json")
 $headers.Add("Accept", "text/html")

$reqUri = $baseURI.OriginalString + ":" + $vamiPort + $URL
 Write-Host "Trying to call Invite-Cluster on $vaNode by calling $reqUri"
 Invoke-VraConfig -configURI "$reqURI" -reqbody $body -reqheaders $headers -method PUT -b64Credentials $b64Credentials
 }
 }

#endregion

#region Scale Manager
 function Construct-MgrBody
 {
 [OutputType([hashtable])]
 $body = @{}
 $body.Add("VraAddress",$vraLBFQDN)
 $body.Add("ManagerServiceStartAutomatically","True")
 $body.Add("ManagerServiceCertificate",$mgrServiceCertThumbprint)
 $body.Add("ManagerServiceFailoverModeEnabled",$mgrServiceFailoverModeEnabled)
 $body.Add("IaaSWebAddress",$iaaSWebLBFQDN)
 $body.Add("ServiceUser",$svcUserName)
 $body.Add("ServiceUserPassword",$svcUserPwd)
 #$body.Add("UseExistingDatabase","true")
 $body.Add("SqlServer",$msSQLServer)
 $body.Add("DatabaseName",$sqlDBName)
 #$body.Add("HttpsPort",$mgrHTTPSPort)
 $body.Add("WebsiteName",$mgrWebSiteName)
 $body.Add("UseWindowsAuthentication",$useWindowsAuth)
 if($useWindowsAuth -ne "True")
 {
 $body.Add("SqlUserPassword",$sqlUserPwd)
 $body.Add("SqlUser",$sqlUserName)
 }
 if($mgrInstallPath.Length -gt 3)
 {
 $body.Add("InstallationPath",$mgrInstallPath)
 }
 $body.Add("SecurityPassphrase", $passhrase)
 $body.Add("UseEncryption", $mgrUseEncryption)
 return $body
 }
 function Install-Manager
 {
 param(
 [ValidateNotNullOrEmpty()][hashtable]$body=@{},
 [ValidateNotNullOrEmpty()][string]$mgrNode="",
 [ValidateNotNullOrEmpty()][uri]$baseURI="",
 [string]$vamiPort="5480",
 [ValidateNotNullOrEmpty()][string]$b64Credentials="",
 [string]$validationmode = "True"
 )

$mgrNodeId = Get-NodeId -baseURI $baseURI.OriginalString -vamiPort $vamiPort -b64Credentials $encodedCreds -nodeHost $mgrNode

if(!$mgrNodeId)
 {
 return "No node could be found with the name of $mgrNode. Maybe you should install the Management Agent?"
 }
 else
 {
 Write-Host "ID of node $mgrNode is $mgrNodeId"
 $headers = $null
 $headers = @{}
 $headers.Add("Content-Type", "application/json")
 $headers.Add("Accept", "text/html")

$body.Add("ValidationMode",$validationmode)

$URL = "/config/execute/command/install-manager-service/node/$mgrNodeId"
 $reqUri = $baseURI.OriginalString + ":" + $vamiPort + $URL
 Write-Host "Trying to call Install-Manager on $mgrNode by calling $reqUri"
 Invoke-VraConfig -configURI "$reqURI" -reqbody $body -reqheaders $headers -method PUT -b64Credentials $b64Credentials
 }
 }
 #endregion
 #region Install DEM
 function Construct-DEMBody
 {
 [OutputType([hashtable])]
 $body = @{}

$body.Add("ServiceUser",$svcUserName)
 $body.Add("ServiceUserPassword",$svcUserPwd)
 $body.Add("ManagerServiceAddress",$mgrServiceAddr)
 $body.Add("DemDescription", $demDescr)
 $body.Add("DemName",$demName)
 $body.Add("IaaSWebAddress",$iaaSWebLBFQDN)
 $body.Add("WebUserName",$svcUserName)
 $body.Add("WebUserPassword",$svcUserPwd)
 $body.Add("VraWebCertificateThumbprint",$VraCertThumbprint)
 $body.Add("VraAddress",$vraLBFQDN)
 $body.Add("HttpsPort",$mgrHTTPSPort)
 if($mgrInstallPath.Length -gt 3)
 {
 $body.Add("InstallationPath",$mgrInstallPath)
 }
 return $body
 }
 function Install-DEM
 {
 param(
 [ValidateNotNullOrEmpty()][hashtable]$body = @{},
 [ValidateNotNullOrEmpty()][string]$demNode,
 [ValidateNotNullOrEmpty()][string]$demRole,
 [ValidateNotNullOrEmpty()][uri]$baseURI="",
 [string]$vamiPort="5480",
 [ValidateNotNullOrEmpty()][string]$b64Credentials="",
 [string]$validationmode = "True"
 )

$demNodeId = Get-NodeId -baseURI $baseUri.OriginalString -vamiPort $vamiPort -b64Credentials $encodedCreds -nodeHost $demNode
 if(!$demNodeId)
 {
 return "No node could be found with the name of $demNode. Maybe you should install the Management Agent?"
 }
 else
 {
 Write-Host "ID of node $demNode is $demNodeId"
 $headers = $null
 $headers = @{}
 $headers.Add("Content-Type", "application/json")
 $headers.Add("Accept", "text/html")

if($demRole -eq "Worker" -or $demRole -eq "Orchestrator")
 {
 $body.Add("DemRole",$demRole)
 }
 else
 {
 return "Please, specify a valid DEM role: Worker or Orchestrator"
 }

$body.Add("ValidationMode",$validationmode)

$URL = "/config/execute/command/install-dem/node/$mgrNodeId"
 $reqUri = $baseURI.OriginalString + ":" + $vamiPort + $URL
 Write-Host "Trying to call Install-DEM on $demNode by calling $reqUri"
 Invoke-VraConfig -configURI "$reqURI" -reqbody $body -reqheaders $headers -method PUT -b64Credentials $b64Credentials
 }
 }
 #endregion

#region Scale Web
 function Construct-IaaSWebBody
 {
 [OutputType([hashtable])]
 $body = @{}
 $body.Add("ServiceUser",$svcUserName)
 $body.Add("ServiceUserPassword",$svcUserPwd)
 $body.Add("IaaSWebAddress",$iaaSWebLBFQDN)
 $body.Add("HttpsPort",$mgrHTTPSPort)
 $body.Add("WebCertificate",$webCertThumbprint)

$body.Add("VraAddress",$vraLBFQDN)
 $body.Add("VraWebCertificateThumbprint",$VraCertThumbprint)
 $body.Add("DefaultTenant",$defaultTenant)
 $body.Add("VidmAdminUser",$vidmAdminUser)
 $body.Add("VidmAdminPassword",$VidmAdminPassword)
 $body.Add("SqlServer",$msSQLServer)
 $body.Add("DatabaseName",$sqlDBName)
 $body.Add("UseEncryption", $webUseEncryption)
 $body.Add("UseWindowsAuthentication",$useWindowsAuth)
 if($useWindowsAuth -ne "True")
 {
 $body.Add("SqlUser",$sqlUserName)
 $body.Add("SqlUserPassword",$sqlUserPwd)
 }
 $body.Add("UseExistingDatabase","true")
 $body.Add("SecurityPassphrase", $passhrase)
 if($webInstallPath.Length -gt 3)
 {
 $body.Add("InstallationPath",$webInstallPath)
 }

return $body
 }

function Install-Web
 {
 param(
 [ValidateNotNullOrEmpty()][hashtable]$body = @{},
 [ValidateNotNullOrEmpty()][string]$webNode,
 [ValidateNotNullOrEmpty()][uri]$baseURI="",
 [string]$vamiPort="5480",
 [ValidateNotNullOrEmpty()][string]$b64Credentials="",
 [string]$validationmode = "True"
 )
 $webNodeId = Get-NodeId -baseURI $baseURI.OriginalString -vamiPort $vamiPort -b64Credentials $encodedCreds -nodeHost $webNode
 if(!$webNodeId)
 {
 return "No node could be found with the name of $webNode. Maybe you should install the Management Agent?"
 }
 else
 {
 Write-Host "ID of node $webNode is $webNodeId"
 $headers = $null
 $headers = @{}
 $headers.Add("Content-Type", "application/json")
 $headers.Add("Accept", "text/html")

$body.Add("ValidationMode",$validationmode)

$URL = "/config/execute/command/install-web/node/$webNodeId"
 $reqUri = $baseURI.OriginalString + ":" + $vamiPort + $URL
 Write-Host "Trying to call Install-Web on $webNode by calling $reqUri"
 Invoke-VraConfig -configURI "$reqURI" -reqbody $body -reqheaders $headers -method PUT -b64Credentials $b64Credentials
 }
 }
 #endregion

#region Install Iaas Certificate
 function Install-Cert
 {
 param(
 [ValidateNotNullOrEmpty()][string]$cert="",
 [string]$component="iaas-web",
 [ValidateNotNullOrEmpty()][uri]$baseURI="",
 [string]$vamiPort="5480",
 [ValidateNotNullOrEmpty()][string]$b64Credentials=""
 )

$URL = "/config/ssl/import-certificates"
 if($cert.Length -lt 4)
 {
 Write-Host "Please, specify a valid path to the certificate file. Certificate should be in PEM format"
 }
 else
 {
 if(Test-Path $cert)
 {

#$cert = $webCertFile
 if((Get-Item $cert) -is [System.IO.DirectoryInfo])
 {
 return "Path is only a folder. Please, specify a file"
 }

try
 {
 $prvKeyLineBegin = (Select-String -Path $cert -Pattern "BEGIN RSA PRIVATE KEY").LineNumber
 $prvKeyLineEnd = (Select-String -Path $cert -Pattern "END RSA PRIVATE KEY").LineNumber
 if($prvKeyLineBegin -lt 1 -or $prvKeyLineEnd -lt 1)
 {
 return "Cannot find the Private Key section of the certificate. Aborting..."
 }
 else
 {
 $prvKey =""
 $prvKey = (get-content $cert -Encoding ASCII)[($prvKeyLineBegin-1)..($prvKeyLineEnd-1)] | out-string
 $pblKey =""
 $pblKey = get-content $cert -Encoding ASCII | select -skip $prvKeyLineEnd |out-string
 }

}catch [Exception]
 {
 Write-Host "There was an error while reading the file."
 return $_.Exception.Message
 }
 try
 {
 $headers = $null

$headers = @{}
 $headers.Add("Content-Type", "application/json")
 $headers.Add("Accept", "text/html")

$certInfo = @{}
 $certInfo.add("PrivateKeyData", "$prvKey")
 $certInfo.add("CertificateData", "$pblKey")

$body = @{}
 if($component -eq "iaas-web")
 {
 $certInfo.add("CertificateFriendlyName", "Cert API")
 $body.Add("iaas-web", $certInfo)
 }
 if($component -eq "iaas-ms")
 {
 $certInfo.add("CertificateFriendlyName", "Cert API")
 $body.Add("iaas-ms", $certInfo)
 }
 if($component -eq "vra")
 {
 $body.Add("vra", $certInfo)
 }

$reqUri = $baseURI.OriginalString + ":" + $vamiPort + $URL

Invoke-VraConfig -configURI "$reqURI" -reqbody $body -reqheaders $headers -method PUT -b64Credentials $b64Credentials
 }
 catch
 {
 Write-Host "There was an error while invoking the command."
 return $_.Exception.Message
 }
 }else
 {
 Write-Host "File $cert not found."
 }
 }
 }
 #endregion

############ Execution ###########
 ############ ###########
 switch ($ConfigOperation.ToLower())
 {
 "install-webcert" {install-iaascert -cert $certFile -component "iaas-web" -baseURI $vraURI -b64Credentials $encodedCreds}
 "install-mgrcert" {install-iaascert -cert $certFile -component "iaas-ms" -baseURI $vraURI -b64Credentials $encodedCreds}
 "install-vracert" {install-iaascert -cert $certFile -component "vra" -baseURI $vraURI -b64Credentials $encodedCreds}
 "invite-cluster" {$vaBody = Construct-VABody; Invite-Cluster -body $vaBody -vaNode $newVa -baseURI $vraURI -b64Credentials $encodedCreds}
 "install-web" {$webBody = Construct-IaaSWebBody; install-web -body $webBody -webNode $webNode -baseURI $vraURI -b64Credentials $encodedCreds -validationmode "fALSE"}
 "install-demo" {$demBody = Construct-DEMBody; install-dem -body $demBody -demNode $demNode -demRole "Orchestrator" -baseURI $vraURI -b64Credentials $encodedCreds -validationmode "False"}
 "install-demw" {$demBody = Construct-DEMBody; install-dem -body $demBody -demNode $demNode -demRole "Worker" -baseURI $vraURI -b64Credentials $encodedCreds -validationmode "False"}
 "install-manager" {$mgrBody = Construct-MgrBody; Install-Manager -body $mgrBody -mgrNode $mgrNode -baseURI $vraURI -b64Credentials $encodedCreds -validationmode "False"}
 default {Write-Host "Please, specify a valid switch. Script syntax is:`n scale-vra.ps1 [install-webcert] [install-mgrcert] [install-vracert] [invite-cluster] [install-web] [install-dem] [install-manager]" }
 }

Upgrade to vRA 7.3 now!