vRA 7.3 环境扩展 (Part 3)

vRA 7.3 环境扩展 (Part 3)

作者 :Nikolay Nikolov

翻译:李崇民

之前我们尝试用精彩的vra-command工具来对vRA环境进行扩展。现在我们要深入研究可对vRA进行配置的REST API。也许你早已熟知vRA API,并已开始使用。当你打开浏览器并浏览https://you-vra-va:5480/config,就会看到一个非常友好的UI界面,里面列出了所有针对基础设施的修改选项。

vp1

当你单击某个命令时,甚至还可以直接对该命令进行测试。这会在当前VA环境中触发一个curl请求,并在同一页面上显示请求的结果。

vp2

这非常简洁!就像使用vra-command一样,可以按照你想要的方式来扩展vRA环境。

为了方便大家,在这里准备了一个Powershell脚本,可以执行所有的配置操作。脚本在文章的最后给出,可以使用的开关项如下:

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

在运行脚本之前,需要给一些参数赋值。在脚本初始化部分可以看到这些参数和它们的值。在根据具体环境来编辑这些参数后,就可以执行脚本完成工作了。如果想要知道每项操作使用了哪些参数,就需要查看具体的Construct-XXXBody函数了。这些函数定义了PUT操作需要的JSON格式与内容。我尽量使这个脚本更加通用,可以很容易的按你想要的方式来修改脚本。运行脚本之前要确保管控代理已经安装在IaaS服务器上。

差点忘了,install-XXXcert选项已经替你完成了对IIS和其它服务的重配置!与vra-command不一样,API的功能更灵活,强大。

#####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 = "Administrator@vsphere.local" #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]" }
 }

—END—