If you are working with VMware cloud services such as VMware on AWS (VMC) or vRA Cloud, you will likely hit the point where you need to authenticate into cloud services before enacting the relevant REST API call.
This post quickly covers creating a vRO workflow (which will also work as an action) and a python ABX call. Both the workflow and ABX action return an access token which subsequent calls can utilise.
This post assumes a good working knowledge of vRealize Orchestrator
vRO Worflow
Step 1 – Create REST Host & Operation
a. Create a new REST host with the below parameters
b. Create a new REST Operation against the above host with the below parameters. Note the Content-Type is application/x-www-form-urlencoded, which is a little unexpected as everything these days is application/json. This caught me out for ages and I had to go back and RTFM!
Step 2 – Setup constants file
I like to use vRO constants as a way of holding global variables, configurations and credentials in a secure manner which can be programatically called rather than having multiple inputs on workflows. It also speeds up the transformation from workflow > action when needed.
In this example, I have a tg-test100Constants file with my VMware Cloud API key and the REST:Operation configured as vars cloudApiKey & restLogin respectively.
Step 3 – Create workflow schema
Create a very basic workflow with a single script, no inputs and a single output of accessToken/string. I always add a default error handler to workflows as a centralised error handling mechanism, but here it is probably overkill!
Step 4 – Code
Below is the code within the Obtain Token step.
General Flow.
- Grabs the variables from the constants file, as described above.
- Creates content var, which is the urlencoded payload which is passed in the body of the HTTP request.
- Sets the request header to accept application/json, allowing for simple parsing of the returned data.
- Executes the request to VMware in a while loop, which will try 3 times before failing.
- If statuscode 200 is found, the returned content is parsed as JSON and the relevant access token is obtained and set as the workflow output variable.
var categoryPath = "Library/Testing" var category = Server.getConfigurationElementCategoryWithPath(categoryPath) //die in a fire if non-existent if (category == null) { throw "Configuration element category '" + categoryPath + "' not found or empty!"; } //get _all_ the elements var elementName = "tg-test100Constants" var attributeName_cloudAPIKey = "cloudApiKey" var attributeName_restlogin = "restLogin" var elements = category.configurationElements; var result = []; for (i = 0; i < elements.length; i++) { if (elements[i].name == elementName) { var apikey_attribute = elements[i].getAttributeWithKey(attributeName_cloudAPIKey); var restlogin_attribute = elements[i].getAttributeWithKey(attributeName_restlogin); var refresh_token = apikey_attribute.value var restLogin = restlogin_attribute.value } else { throw "Attribute '" + attributeName + "' not found!"; } } var content = "refresh_token=" + refresh_token param = [""] var request = restLogin.createRequest(param, content); request.setHeader("accept", "application/json"); System.log(request.fullUrl) //System.debug("Executing content: " + content); var response = { statusCode: 0, contentAsString: "" }; var count = 3 var sleepMs = 10000 while (count > 0) { --count; 3; try { response = request.execute();; System.debug("Response status code: " + response.statusCode); System.debug("Response content: " + response.contentAsString); } catch (e) { System.error("REST Execution failed with URL: " + request.fullUrl + " Error Details: " + e); } if (response.statusCode === 200) { var content = JSON.parse(response.contentAsString); if (content !== null) { var accessToken = content.access_token; System.debug("Access Token Obtained") count = 0 } } else { if (count > 0) { System.sleep(sleepMs) } else { errorCode = "Unable to retrieve access token" throw (errorCode) } } }
ABX Action
The equivilant code in ABX is much smaller and simplier.
ABX Dependancy: requests
refresh_token – This is an ABX input with your API key included. I don’t recommend this as its held in clear text using vRA Cloud.
import ldap3 import json import requests import time def handler(context, inputs): #Login to VMware API and obtain access token refresh_token = inputs['refresh_token'] vmware_api_url = 'https://console.cloud.vmware.com/csp/gateway/am/api/auth/api-tokens/authorize' full_url = vmware_api_url session = requests.Session() session.headers.update({"accept" : "application/json"}) response = session.post(full_url, data = {'refresh_token':refresh_token}) if response.status_code == 200: json_response = json.loads(response.content) access_token = json_response['access_token'] else: raise NameError("Error Obtaining API Access Code. Status Code " + response.status_code) #Setup response headers session.headers.update({"content-type" : "application/json"}) basic_auth_header = "Bearer " + access_token session.headers.update({"authorization" : basic_auth_header}) session.headers.update({"csp-auth-token": access_token})
References
Creating an API key: