Pages

Showing posts with label Powershell. Show all posts
Showing posts with label Powershell. Show all posts

Friday, September 30, 2022

VRA ABX Action to set Deployment Lease

 Running vRealize Automation (VRA), I wanted to create a new catalog item in Service Broker that would basically self-destruct after a certain time. My intent is to allow our Windows engineers to quickly spin up a new machine in AWS with a lease applied to it. 

I could find a catalog template setting that allowed me to configure this, so I found that I could do this via a REST call to the VRA. So I decided to work on creating an extensibility action using Powershell. 

Note, once a lease is set, I don't think it's possible to remove the lease. 

Pre-requisites:

  • Extensibility Actions on Prem integration server configured.
  • VRA refresh token defined. This will be used in step 0.
  • BlueprintID of a catalog template that will apply the lease to. We'll need this for step 2. The blueprint id can be captured easily from the URL when viewing it in the design menu. Copy everything after the %2F, for example (the bolded portion): 

    https://www.mgmt.cloud.vmware.com/automation-ui/#/blueprint-ui;ash=%2Fblueprint%2Fedit%2F123456-7890123456-123456789
Step 0: setup Action Constant
  1. Inside VRA - Extensibility menu, select Actions on the sidebar. 
  2. Select Action Constants and add a + New Action Constant
  3. Enter the name of "refreshToken" and paste the refresh token string into the value field and select toggle to enable the Encrypt the action contact value
  4. Click SAVE.

Step 1: create the action 

  1. Extensibility menu, Actions on sidebar and click + New Action
  2. Define the new action Name "SetDeploymentLease" and select the VRA Project that this will run against then click Next.
  3. On the top, change the dropdown from PYTHON to POWERSHELL. 
  4. Copy the pastebin code below and paste it into the body of the action.
  5. Under Default Inputs, add two more input fields (for a total of 3). These fields will be used during the run-time of the action. 

    1. Default - LeasePeriod - Positive integer for the number of days to define the lease.
    2. Default - deploymentId - can be anything, this will be sent to the action from the subscription event defined in step 2. I copied the deployment id off an existing 'test' deployment directly from the URL. (like prerequisites, it's everything after the %2F). 
    3. Action Constant - refreshToken - this will pull the value from Step 0.
  6. SAVE the action
Step 2: create a subscription - The subscription will trigger after the blueprint is run.
  1. Extensibility menu, Subscriptions option on sidebar and click + NEW SUBSCRIPTION
  2. Give subscription name. 
  3. For Event Topic select "Deployment Resource Completed"
  4. Enable the Condition and enter a (case matters) single value of: 
    event.data.blueprintId == "value from pre-requisites"
  5. Action/Workflow: select the new action you created in Step 1.
  6. Projects: Select the project you specified in step 1, item 2.
  7. SAVE



Testing: 
  1. Option: If valid values are entered in step 1 part 5, the test button on the Action will run. 


  2. Option: Deploy a new machine using the catalog item defined in the prerequisites. Within a minute after the deployment completes the build, the lease should be applied via the subscription. 





Thursday, July 30, 2020

VRA API Programming Lessons Learned

I've been working for so long inside the closed environment of Exchange powershell, that when a co-worker suggested programming against a REST API, I sort of cringed in fear. Here was a brand new programming method that I had no concept of where to start. Luckily, VMWare vRealize Automation (reference) has a full-featured API that you can easily write PowerShell commands against to both pull information from or push configurations up to. The documentation is well rounded with examples (written in CURL format) that can be easily translated to Powershell. 

Our friend on this journey will be invoke-restMethod. (msdn link) (yes, I have started writing my commands in camel case). This command has a few basic components:
  1. headers - a variable that contains the credentials that you'll need to access this URI
  2. uri - the URL to the aspect that you are looking to read from/post to. 
  3. method - GET information, POST information PATCH update information etc. 
  4. body - the information you'd like to post up to this interface. Usually empty when doing a GET.
Headers = Authorization - This differs per the API. VMWare requests that a 'refresh' token is generated in the UI, then exchanged for a bearer token. The bearer token can then be used for up to 30 minutes on API calls. AWS needs an Access key and Secret key encoded in a basic credential (i.e. 'get-credential') object. 

URI - This is the basic URL to reach this object type. From my experience, this URL follows a basic format. 

    API URL / object

For example, to query all of the VRA Cloud Accounts (reference) in my environment, the URI would be 

$myURL = "https://api.mgmt.cloud.vmware.com" + "/iaas/api/cloud-accounts"

Method - Are actions telling invoke-restMethod what is to be performed at the URL. 90% of the time I used only GET to query and POST to create. PATCH can be used to update an existing entry. (see the msdn link for more info)

Note: Powershell on a GET method will return an object that you can extract information from. Unfortunately, I was never able to read modify and post the same object back to a site. I ended up reading it, then creating a new body and posting that. 

$Results = Invoke-RestMethod -Uri $myURL -Method get -ContentType "application/json" -UseBasicParsing -headers $headers 
 
$results | convertto-json

(if the query is successful, the results should look like this)

whereas, you can manipulate the object:

$results.content.name 

and get "my-name"


Body - This was the largest part of the learning curve. The body variable is looking for a JSON formatted variable. For example, peek at the cloud-accounts POST method. The completed body JSON should look like something like this:

Sample Cloud-Account Body from code.vmware.com

In Powershell, you can attempt to create this two different ways. Simply, it can be a giant text string that you format to contain all of the properties and values. Seems easy enough, but will be rather hard to support later on.  The second option you can create a PowerShell hash table and convert it to JSON using the (obviously named) convertTo-JSON command. Once we identify come clues, I feel you'll agree, the hash table to JSON method is much easier.

Observation one: Items are enclosed in curly brackets. These enclose a concept or object. This will be replaced with a hash. "@{ }"
Observation two: There are a few items enclosed in square brackets as well. These are actually arrays of results. Often when there is a one-to-many relationship. @( ) 
Observation three: Backslashes "\" surround almost all variable values. Ignore them. 
Observation four: concepts are separated by commas. Replace these with a semi-colon. 
Observation five: the colon is used to separate a key with its value. "name": "string". replace colons with an equals sign.
Observation six: variable names are in 'camelCase' sensitive (only uppercase the first letter of the following words). This is EXTREMELY important when doing REST calls in JSON. You can build the prettiest JSON in the world, but if your variable names are not perfectly matching the case shown in the documentation, the rest call will fail. regionIds -ne RegionIDs. Going from PowerShell to JSON was a shock because of this! 


This next example includes a multi-value array for the tags:

The hardest part of the process is making sure that the hash tables and arrays are closed correctly. 

Here's a snippet of what I use to create new AWS Cloud Accounts in VRA. I pass a number of variables to this JSON, but I think you can guess how they correlate to your AWS account. 

$CloudRegionArray = @("us-west-2") # we only put stuff here.
$NewCloudAccount = @{"accessKeyId"=$strCloudAccountAccessKey;"secretAccessKey"=$strCloudAccountSecretKey;"createDefaultZones"="true";"name"=$strCloudAccountName;"regionIds"=$CloudRegionArray;"tag"=@(@{"key"="ca";"value"=$($strCloudAccountName+"-aws")})}  | convertto-json

Invoke-RestMethod -uri "https://api.mgmt.cloud.vmware.com/iaas/api/cloud-accounts-aws" -Method POST -ContentType "application/json" -headers $headers -Body $NewCloudAccount