Deploying vRA Blueprints from PowerShell

The PowervRA module is a great set of PowerShell cmdlets for managing a VMware vRealize Automation (vRA) environment, but I wanted to learn a bit more about the REST API available from vRA and also had a requirement - to script a deployment from an existing vRA blueprint ('Cloud Template') which had no PowervRA cmdlet. So I set about writing my own script in PowerShell to do this and have documented this and the steps required in this post.

The steps in this process are:

  • Gather the parameters and inputs for the deployment
  • Authenticate to the vRA API and obtain a refresh token
  • Use the obtained refresh token to obtain an access token
  • Find the Project Id and Blueprint Id that we want to deploy from the API
  • Request the deployment and check the request is submitted successfully

I also wanted to provide some basic error checking so that if the specified vRA Project or Blueprint could not be found the script provided meaningful feedback.

Gather the parameters and inputs for the deployment

In the first code block, I simply configure variables for the environment - including prompting for the password which will be used to authenticate to vRA:

1# Target vRealize Automation System
2$vrauri = 'https://<vRealize Automation URL e.g. https://myvraserver.mydomain.local>'
3$user = '<user name to authenticate to vRA>'
4$pass = (Get-Credential -UserName $user).GetNetworkCredential().password
5$header = @{'Content-Type'='application/json'}

The next block defines the parameters for the blueprint that will be deployed, including which vRA Project will be the deployment target, which blueprint will be used and the input parameters required for deploying this instance. The blueprint I'm using is a 3-tier application that I've been working on to provide a more realistic demonstration of vRA capabilities. Obviously these parameters will vary depending on the environment and template being deployed

 1# Blueprint Deploy Parameters:
 2$environment        = 'Production'
 3$blueprintName      = '3-Tier App'
 4$deploymentName     = 'MyDeployment'
 5$description        = 'Deploying a vRA blueprint from code'
 6$appliancepassword  = 'MySecretPassword'
 7$department         = 'it'
 8$db_flavor          = 'medium'
 9$app_flavor         = 'small'
10$web_flavor         = 'small'

Authenticate to the vRA API and obtain a refresh token

Next we need to POST the authentication data to the /csp/gateway/am/api/login?access_token URL to obtain a refresh token:

 1try {   # Get an API refresh token
 2    $refres = Invoke-RestMethod -Method Post `
 3        -Uri "$vrauri/csp/gateway/am/api/login?access_token" `
 4        -Headers $header `
 5        -Body (@{'username'=$user;'password'=$pass} |
 6        ConvertTo-Json)
 7} catch { 
 8    Write-Host -ForegroundColor Red ("Error status: $_.Exception.Response.StatusCode.value__")
 9    Exit
10}

I've included some basic error handling here so that if an error occurs (e.g. an incorrect user name or password is provided) this is caught and the script gracefully exits. ConvertTo-Json is used to ensure our parameters are correctly provided to the API.

Use the obtained refresh token to obtain an access token

Once we have our refresh token, we can call the /iaas/api/login URL to obtain the bearer token which will be used to authenticate all our subsequent API requests.

1try {   # Get an API access token
2    $access_token = Invoke-RestMethod -Method Post `
3        -Uri "$vrauri/iaas/api/login" `
4        -Headers $header `
5        -Body (@{'refreshToken'=$refres.refresh_token} | ConvertTo-Json)
6} catch { 
7    Write-Host -ForegroundColor Red ("Error status: $_.Exception.Response.StatusCode.value__")
8    Exit 
9}

Find the Project Id and Blueprint Id that we want to deploy from the API

If everything has gone ok up to this point, we now have a token (in $access_token.token) which can be used to authenticate our next requests. In order to be able to request deployment of our blueprint we need to provide both the Project Id and Blueprint Id to the API. As I didn't want to have to keep looking up and coding these Id's into scripts I've used 2 calls to search and match these by name ($environment is the 'friendly' Project name and $blueprintName is the 'friendly' blueprint name in this example). Since both API calls use the same headers, we can set up a single $header variable and use it for both calls containing our authorization token.

 1# Get the projectid for the deployment environment
 2$header = @{'Authorization'='Bearer ' + $access_token.token;'Content-Type'='*/*'}
 3$projects = (Invoke-RestMethod -Method Get `
 4    -Uri "$vrauri/project-service/api/projects" `
 5    -Headers $header).content
 6$projectid = ($projects | Where-Object { $_.name -eq $environment }).id
 7if (!$projectid) { 
 8    Write-Host -ForegroundColor Red "Environment $environment could not be located, exiting."
 9    Exit 
10}
11
12# Get the blueprintid for requested blueprint
13$blueprints = (Invoke-RestMethod -Method Get `
14    -Uri "$vrauri/blueprint/api/blueprints" `
15    -Headers $header).content
16$blueprintid = ($blueprints | Where-Object {$_.name -eq $blueprintName}).id
17if (!$blueprintid) { 
18    Write-Host -ForegroundColor Red "Blueprint $blueprintName could not be located, existing."
19    Exit
20}

Request the deployment and check the request is submitted successfully

Now we have all of the information required, we can build a JSON object containing all our inputs to the deployment process and then make an API POST request to /blueprint/api/blueprint-requests to initiate the actual deployment.

 1# Create 'body' for API deployment request
 2$deploybody = @{
 3    'blueprintId'       =$blueprintid # found from API
 4    'deploymentName'    =$deploymentName
 5    'description'       =$description
 6    'projectId'         =$projectid # found from API
 7    'inputs'=@{
 8        'password'      =$appliancepassword
 9        'department'    =$department
10        'db_flavor'     =$db_flavor
11        'app_flavor'    =$app_flavor
12        'web_flavor'    =$web_flavor
13    }
14}
15$header = @{'Authorization'='Bearer ' + $access_token.token;'Content-Type'='application/json'}
16
17try {   # Deploy the blueprint
18    $res = Invoke-RestMethod -Method Post `
19         -Uri "$vrauri/blueprint/api/blueprint-requests" `
20         -Headers $header `
21         -Body ($deploybody | ConvertTo-Json)
22} catch {
23    Write-Host -ForegroundColor Red ("Error status: $_.Exception.Response.StatusCode.value__")
24    Exit 
25}
26
27if ($res.status -eq 'CREATED' -or $res.status -eq 'STARTED') {
28    Write-Host ("Deployment request successfully submitted, deploymentId is $($res.deploymentId).")
29} else {
30    Write-Host -ForegroundColor Red ("Deployment request failed, returned data shown below.")
31    $res
32}

Summary

Hopefully this post is detailed enough that it will be easy to adjust for your particular blueprints and requirements if needed. I've included the entire script in one block below for easier copying/pasting if you want to try this in your own environment.

As always, comments, feedback and suggestions for improvement are welcome.

Jon

 1# Complete code listing - vRA automation to deploy a blueprint and supply input parameters
 2
 3# Target vRealize Automation System
 4$vrauri = 'https://<vRealize Automation URL e.g. https://myvraserver.mydomain.local>'
 5$user = '<user name to authenticate to vRA>'
 6$pass = (Get-Credential -UserName $user).GetNetworkCredential().password
 7$header = @{'Content-Type'='application/json'}
 8
 9# Blueprint Deploy Parameters:
10$environment        = 'Production'
11$blueprintName      = '3-Tier App'
12$deploymentName     = 'MyDeployment'
13$description        = 'Deploying a vRA blueprint from code'
14$appliancepassword  = 'MySecretPassword'
15$department         = 'it'
16$db_flavor          = 'medium'
17$app_flavor         = 'small'
18$web_flavor         = 'small'
19
20try {   # Get an API refresh token
21    $refres = Invoke-RestMethod -Method Post `
22        -Uri "$vrauri/csp/gateway/am/api/login?access_token" `
23        -Headers $header `
24        -Body (@{'username'=$user;'password'=$pass} |
25        ConvertTo-Json)
26} catch { 
27    Write-Host -ForegroundColor Red ("Error status: $_.Exception.Response.StatusCode.value__")
28     Exit
29}
30
31try {   # Get an API access token
32    $access_token = Invoke-RestMethod -Method Post `
33        -Uri "$vrauri/iaas/api/login" `
34        -Headers $header `
35        -Body (@{'refreshToken'=$refres.refresh_token} | ConvertTo-Json)
36} catch { 
37    Write-Host -ForegroundColor Red ("Error status: $_.Exception.Response.StatusCode.value__")
38    Exit 
39}
40
41# Get the projectid for deployment environment
42$header = @{'Authorization'='Bearer ' + $access_token.token;'Content-Type'='*/*'}
43$projects = (Invoke-RestMethod -Method Get `
44    -Uri "$vrauri/project-service/api/projects" `
45    -Headers $header).content
46$projectid = ($projects | Where-Object { $_.name -eq $environment }).id
47if (!$projectid) { 
48    Write-Host -ForegroundColor Red "Environment $environment could not be located, exiting."
49    Exit 
50}
51
52# Get the blueprintid for requested blueprint
53$blueprints = (Invoke-RestMethod -Method Get `
54    -Uri "$vrauri/blueprint/api/blueprints" `
55    -Headers $header).content
56$blueprintid = ($blueprints | Where-Object {$_.name -eq $blueprintName}).id
57if (!$blueprintid) { 
58    Write-Host -ForegroundColor Red "Blueprint $blueprintName could not be located, existing."
59    Exit
60}
61
62# Create 'body' for API deployment request
63$deploybody = @{
64    'blueprintId'       =$blueprintid # found from API
65    'deploymentName'    =$deploymentName
66    'description'       =$description
67    'projectId'         =$projectid # found from API
68    'inputs'=@{
69        'password'      =$appliancepassword
70        'department'    =$department
71        'db_flavor'     =$db_flavor
72        'app_flavor'    =$app_flavor
73        'web_flavor'    =$web_flavor
74    }
75}
76$header = @{'Authorization'='Bearer ' + $access_token.token;'Content-Type'='application/json'}
77
78try {   # Deploy the blueprint
79    $res = Invoke-RestMethod -Method Post `
80         -Uri "$vrauri/blueprint/api/blueprint-requests" `
81         -Headers $header `
82         -Body ($deploybody | ConvertTo-Json)
83} catch {
84    Write-Host -ForegroundColor Red ("Error status: $_.Exception.Response.StatusCode.value__")
85    Exit 
86}
87
88if ($res.status -eq 'CREATED' -or $res.status -eq 'STARTED') {
89    Write-Host ("Deployment request successfully submitted, deploymentId is $($res.deploymentId).")
90} else {
91    Write-Host -ForegroundColor Red ("Deployment request failed, returned data shown below.")
92    $res
93}