Unattended Deployment and Configuration of OVA

Share this:

Good Sys Admin is the lazy Sys Admin. Step by step IT automation is making its way in our daily activities and I like to use it as much as possible. Saving time and reducing human errors are obvious advantages, but I also like to watch how the magic happens. One press of “Enter” and everything will be done for you – not a single click of the mouse. In the spirit of IT automation, I want to share my solution for unattended deployment and configuration using an example of Runecast Analyzer. This solution can be customized for any other product that provides API for doing so.

Runecast Analyzer version 1.5.6.0 introduces a big increase in the number of available REST API endpoints. An overview can be found at Runecast API Boost article, here I’ll focus on the technical implementation.
Let’s jump to the code:

#Get-Module -Name VMware* -ListAvailable | Import-Module #Importing PowerCLI modules in case it was initated from directly from PowerShell, uncomment if needed
#Variables - Step1#
$vCenter = 'myvCenter.my.domain' #vCenter Server where to deploy Runecast
$username = 'administrator@vsphere.local' #vCenter username
$password = 'VMware1!' #Password for the provided username
$cluster= 'My-VSAN-Cluster' #Cluster where to deploy Runecast
$datastore = 'vsanDatastore' #Datastore name
$ovaPath = 'C:\Runecast\1.5.6.0\RCapp_OVF10.ova' #Path to the OVA
$rcHostname = 'rc-cli' #Hostname for Runecast Analyzer
$rcVMname = 'Runecast Analyzer' #VM name
$rcFQDN = '' #Leave blank if you don't have valid DNS record
$rcDeployOption = 'small' #accepted values: small, medium, large
$rcIPprotocol = 'IPv4'
$rcNetwork = 'VM Network' #Network name
$rcGateway = '10.1.0.1'
$rcDNS = '10.1.0.2' #Comma separated if multiple, leave blank if DHCP desired
$rcIP = '10.1.0.3' #Leave blank if DHCP desired
$rcNetMask = '255.255.0.0' #Leave blank if DHCP desired
$rcUser = 'rcuser' #The default local user of Runecast Analyzer
$rcPassword = 'Runecast!' #Passowrd for the Runecast user
$vcToAdd = 'myvCenter.my.domain' #vCenter to add to Runecast after deployment
$vcPort = 443
$vcUser = 'administrator@vsphere.local'
$vcPassword = 'VMware1!'

#Do not edit beyond here

#Accept self signed certificates
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

#Deploying Runecast Analyzer - Step 2#
Write-Host "Connecting to $vCenter..." -foregroundcolor "yellow"
Connect-VIServer -server $vCenter -User $username -Password $password

$vmHost = Get-Cluster -Name $cluster | Get-VMHost | Where-Object {$_.ConnectionState -eq "Connected"} | Get-Random
$portGroup = Get-VirtualPortGroup -Host $vmHost -Name $rcNetwork
$targetDatastore = Get-Datastore -Name $datastore

$ovaConfig = Get-OvfConfiguration -Ovf $ovaPath
$ovaConfig.Common.vami.hostname.value = $rcHostname
$ovaConfig.DeploymentOption.Value = $rcDeployOption
$ovaConfig.IpAssignment.IpProtocol.Value = $rcIPprotocol
$ovaConfig.NetworkMapping.Network_1.Value = $portGroup
$ovaConfig.vami.Runecast_analyzer.gateway.Value = $rcGateway
$ovaConfig.vami.Runecast_analyzer.DNS.Value = $rcDNS
$ovaConfig.vami.Runecast_analyzer.ip0.Value = $rcIP
$ovaConfig.vami.Runecast_analyzer.netmask0.Value = $rcNetMask

Write-Host "Deploying Runecast Analyzer..." -foregroundcolor "yellow"
$RC = Import-VApp -Source $ovaPath -OvfConfiguration $ovaConfig -Name $rcVMname -VMHost $vmHost -Datastore $targetDatastore -DiskStorageFormat "Thin"

Write-Host "Starting $rcVMname" -foregroundcolor "yellow"
Start-VM -VM $RC | Out-Null

Write-Host "Disconnecting from $vCenter..." -foregroundcolor "yellow"
Disconnect-VIServer -Confirm:$false

#Waiting Runecast Analyzer to load - Step 3#
if ($rcFQDN -eq '') {
	$baseUrl = "https://$rcIP/rc2"
} else {
	$BaseUrl = "https://$rcFQDN/rc2"
}
$numTries = 60 # 5 minutes timeout
do {
	Write-Host "Waiting for Runecast Analyzer to load..." -foregroundcolor "yellow"
	Start-Sleep -s 5
	$numTries--
	try { $queryRC = Invoke-WebRequest -Uri $baseUrl } catch { Write-Host "Not ready" }
} until ($queryRC.StatusCode -eq '200' -Or $numTries -lt 1)

if ($numTries -eq 0) {
	Write-Host "Timeout reached. Giving up..."
	exit
} else { Write-Host "Runecast Analyzer is up" }

#Configuration - Step 4#
$credentials = $username + ':' + $password
$bytes = [System.Text.Encoding]::UTF8.GetBytes($credentials)
$encryptedCredentials = [System.Convert]::ToBase64String($bytes)
$headers = @{"Authorization"="Basic $encryptedCredentials";"Content-Type"="application/json";"Accept"="application/json"}
$url = $BaseUrl+"/api/v1/users/local/$rcUser/tokens"

$body = '{
	"description": "Auto config",
    "password" : "'+$rcPassword+'"

}'
Write-Host "Requesting access token..." -foregroundcolor "yellow"
$getToken = Invoke-WebRequest -Uri $url -Method Post -Body $body -Headers $headers

if ($getToken -ne $null) {
    if ($getToken.StatusCode -eq '200') {
		$jsonContent = $getToken.Content | ConvertFrom-Json
		$token = $jsonContent.token
		Write-Host "Token received"
    }
} else { Write-Host 'Request not successful' }

$headers = @{"Authorization"=$token;"Content-Type"="application/json";"Accept"="application/json"}
$url = $baseUrl+"/api/v1/vcenters"
$body = '{
  "address": "'+$vcToAdd+'",
  "password": "'+$vcPassword+'",
  "port": '+$vcPort+',
  "username": "'+$vcUser+'"
}'
Write-Host "Adding $vcToAdd..." -foregroundcolor "yellow"
$addVC = Invoke-WebRequest -Uri $url -Method Put -Body $body -Headers $headers
if ($addVC -ne $null) {
    if ($addVC.StatusCode -eq '200') {
		$jsonContent = $addVC.Content | ConvertFrom-Json
		$vc = $jsonContent.address
		$vcId = $jsonContent.uid
		Write-Host "vCenter Server $vc added successfully"
    }
} else { Write-Host 'Request not successful' }

$url = $baseUrl+"/api/v1/scan/$vcId"
$body = ''
Write-Host "Triggering scan against $vc..." -foregroundcolor "yellow"
$scanVC = Invoke-WebRequest -Uri $url -Method Post -Headers $headers
if ($scanVC -ne $null) {
    if ($scanVC.StatusCode -eq '202') {
		Write-Host "Scan triggered successfully"
    }
} else { Write-Host 'Request not successful' }

 

I’ll split and review the script in 4 parts, which you may reuse in other scenarios. Each step is marked in the code as comment, i.e #Variables – Step1#

  1. Variables
    Here are defined the variables used during deployment and configuration. Make sure to adjust them for your environment.
  2. Deploying Runecast Analyzer
    This section prepares the configuration for the appliance. Get-OvfConfiguration cmdlet will provide you with the structure of expected parameters needed for the deployment. Since we already have defined each value in the previous block, it’s easy to do the assignments here. The final step is to pass the OVA configuration along with the path to the OVA, name of the VM that will be deployed, host and datastore.
  3. Waiting for Runecast Analyzer to load
    In order to continue with the configuration, the Runecast application needs time to load. It usually takes just a couple of minutes after starting the VM. My check for running application is simply doing GET request to the main page. If we have response – Runecast Analyzer is up and running, if not – wait for 5 second and try again. In order to avoid infinite loop in case of some issue, there is a timeout set to 60 iterations (meaning roughly 5 minutes; 60 iterations with 5 seconds wait interval = 300 seconds = 5 minutes + some time spent executing the request and waiting for response).
  4. Configuration
    Once Runecast Analyzer is up the configuration can start. Each REST request against Runecast Analyzer needs to be authenticated with access token. Access token can be generated from Settings -> API Access tokens -> Generate API access token. That’s good, but I promise no clicking! Yes, there is another way introduced in the new set of endpoints: POST request to /api/v1/users/local/{username}/tokens providing description of the token (optional) and password of the account for which the token is requested. In response we get API access token which we can use in all other requests.
    Next in line is PUT request to add a vCenter Server and POST request to trigger a scan against the vCenter that was just added.
    Examples and “Try it out” option for each REST endpoint can be found in the swagger interface at Runecast Analyzer under Settings -> API Access tokens -> Runecast API

All of that put together and executed results in the following:

Now, when I log in to Runecast Analyzer web interface, my vCenter Server is added and the results of analysis are already there waiting for me:

In less than 5 minutes you have proactive monitoring solution deployed and configured. Enjoy!

The following two tabs change content below.

Ivaylo Ivanov

Ivaylo has 5 years of professional IT experience. Most of it in server administration area, network and virtualization technologies. From 2014 he specializes in VMware products family. He holds VCIX6-DCV and VCP7-CMA certifications. vExpert 2016/2017

Latest posts by Ivaylo Ivanov (see all)

About Ivaylo Ivanov

Ivaylo has 5 years of professional IT experience. Most of it in server administration area, network and virtualization technologies. From 2014 he specializes in VMware products family. He holds VCIX6-DCV and VCP7-CMA certifications. vExpert 2016/2017
Bookmark the permalink.

One Comment

  1. Pingback: Runecast Analyzer VMware Best Practices new REST API Integration - Virtualization Howto

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.