Run an Event Broker Subscription after Ansible resource execution.

Introduction

I was working with the customer using vRA Cloud (SaaS version of vRA). Customer was using native ansible integration in the bluprint and wanted to run an EBS subscription after the ansible run.

Use Case

The customer was running a similar bluepint with native ansible open source integration with vRA Cloud.

The customer was running a number of EBS subscriptions and had a very specific use case where one of the subscriptions that locked the VM down must run after the ansible playbooks.

Solution

The tricky bit is the ansible integration will run only after the machine resource has completed. Most of the existing EBS were configured in the “Compute Provision” event topic. However, a closer look at the timings of the ansible run reveals that it runs around the “Deployment Completed” event. After doing some research I decided to use the “Deployment resource completed” event topic for running my post ansible subscription.

Now one of the challenges of running a subscription workflow in “Deployment resource completed” event is the lack of custom properties in this event.

From the screenshots above, it’s clear that there are no custom properties in this event. However, it doesn’t mean we can’t get one!

We will use IaaS API to get the required custom properties with the deployment id.

The customer just wanted the hostname and IP address from the custom properties for his hardening workflow subscription.

To get the required details we can use the below API call from vRO and it provides the detailed information of the deployment.

GET https://{{api_url}}/deployment/api/deployments/{{deployment_id}}?expandResources=true&apiVersion={{api_version}}
Accept: application/json
Content-Type: application/json 
Authorization: Bearer {{bearer}}

I did a quick worklfow in my lab to get a JSON object with the hostnames and IP addresses of the virtual machine resouces using the deployment id.

If you followed my other posts, I always like to write my actions as services and call them from the workflow as objects. Here’s my sample code for the API call.

function deploymentService() {
    //#region VALIDATION 
	this.validateInit = function() {
		if (!restHost) { throw _CustomException("Unable to retrieve rest host!!!"); }
		if (!accessToken) { throw _CustomException("Unable to retrieve bearer token!!!"); }
	}
	
	this.validateDeploymentInputs = function (deploymentID){
		if (!deploymentID) { throw _CustomException("Invalid deployment id!!!"); }
	}
    //#region methods
    this.getDeploymentDetails = function (deploymentID){
		this.validateDeploymentInputs(deploymentID);
        try {
            var request = restHost.createRequest("GET",url+"/"+deploymentID+"/?expandResources=true&apiVersion="+apiVersion);
            request.setHeader("Authorization","Bearer "+accessToken);
            request.setHeader("Content-Type","application/json");
            request.setHeader("Cache-Control","no-cache");
            var requestResponse = request.execute();
            if (requestResponse.statusCode != 200) {
                System.log("Rest operation failed: "+ equestResponse.statusCode);
                throw "ERROR: "+ equestResponse.statusCode
            }
        } catch(e){
            throw ("ERROR: Rest operation failed: "+e);
        }
        var responseContent = requestResponse.contentAsString;
        System.debug(responseContent);
        return responseContent;
    }
    this.getCustomProperties = function (deploymentID){
        try {
            var responseContent = this.getDeploymentDetails(deploymentID);
            responseContent = JSON.parse(responseContent);
            var vmProperties = (responseContent.resources).filter(function(e){
                return e.type == "Cloud.vSphere.Machine";
            });
            var vmDetails = {};
            for each (var vmProperty in vmProperties) {
                vmDetails[vmProperty.properties.name] = {};
                vmDetails[vmProperty.properties.name].name = vmProperty.properties.resourceName;
                vmDetails[vmProperty.properties.name].id = vmProperty.properties.id;
                var networks = vmProperty.properties.networks;
                vmDetails[vmProperty.properties.name].networks = {};
                for (var i = 0;i<networks.length;i++){
                    vmDetails[vmProperty.properties.name].networks[i] = {};
                    vmDetails[vmProperty.properties.name].networks[i].adapterName = networks[i].name;
                    vmDetails[vmProperty.properties.name].networks[i].address = networks[i].address;
                }
            }
            var customProps = JSON.stringify(vmDetails,null,2);
            System.log(customProps);
        } catch(e){
            throw ("ERROR: Custom properties failed to read "+ e)
        }
        return customProps;
    }
    //#region init
	var _CustomException = System.getModule("Cloud").CustomException(arguments.callee.name);
    var accessToken = System.getModule("Cloud").getBearerTokenCloud();
    var restHost = System.getModule("Cloud").getvRAAPIRestHost();
    var apiVersion = "2019-09-12";
    var url = "/deployment/api/deployments";
	this.validateInit();
}
return deploymentService

Getting the deployment id from the input properites is a one liner.

//Get Deployment ID from input properties
var deploymentID = inputProperties.get("deploymentId");

My vRO workflow looks like this:

//Get Deployment ID from input properties
var deploymentID = inputProperties.get("deploymentId");
//Get custom properties with deployment id
var deploymentSVC = System.getModule("Cloud").deploymentService();
var deploymentObj = new deploymentSVC();
var props = deploymentObj.getCustomProperties(deploymentID);

Here’s the output of my workflow that the customer wanted.

{
  "Cloud_vSphere_Machine_1": {
    "name": "fluffyclouds7070",
    "id": "/resources/compute/f21fb5ad-1dfe-4b20-a5fd-f849f0b12134",
    "networks": {
      "0": {
        "adapterName": "Network adapter 1",
        "address": "192.168.20.113"
      }
    }
  }
}

Conclusion

If you are a vRA developer with vRA 7.x experience, vRA Cloud is a different product and some of the features will not match with the older versions. Once you are used to it there is no looking back.

Author: Barjinder Singh

Leave a Reply