Using the vRA Plugin for vRO – Enabling Actions in custom forms which call the vRA API

I haven’t done a blog for a while due to an overload of work, but I’m getting back on the horse!

Earlier this year VMware released a new vRA plugin for vRO – https://blogs.vmware.com/management/2021/03/vro-vra-plugin.html. Typically a vRO plugin provides out of the box workflows and actions which enable standard functions to be called in third party products.

This blog covers the installation and configuration of this plugin, but moreover, how to use it effectively within custom forms to pre-fill data within custom forms in the service broker.

Use case for this demo: I have a project within vRA which has a number of custom properties configured. Custom properties on projects are a great way of pushing common information to deployments within a project. The only downside is that you are unable to allocate these custom properties to cloud template variables for use during the provisioning cycle.unless you use extensibility i.e a vRO workflow.

In this example, my vRA project has a custom property of customer_id and a value of fin (finance). I need this value to populate a security group constraint within my cloud template but it cant be called with any of the default template inputs. To work around this problem I will extract this information during the request phase in the custom form and pass it through to the template as an input variable. Make sense!? It will.

I will say it now for anyone well versed with vRA…I know there are a few ways to skin this cat, and this is only one way. I am choosing to do it this way as I like the fact that an element of processing is done pre-request, reducing the amount of extensibility runs required through the deployment phase, which adds time to the deployment cycle as a whole.

Plugin Installation

Connect to the vRO control centre, found at https://vra-fqdn/vco-controlcenter and click ‘Manage Plugins’

vRO – Manage Plugins

Once in the plugin inventory, click browse, find your downloaded vRA plugin file and upload it. Then vRO will automatically reboot to complete the installation

Upload vRA plugin to vRO

Once the appliance has rebooted, go into the inventory to verify the plugin is installed. In my setup I am running vRO as an embedded appliance on the vRA appliance so it has automatically connected to the host also

Plugin installed and connected to vRA

I mentioned earlier in the blog that many plugins come with lots of workflows and actions that can be utilized. The vRA plugin does not. It comes with next to nothing of use except for some example API calls using the rest client within vRO.

At this stage you may ask why bother with the plugin, which would be a valid question. The answer is that if you created a normal rest host / operation, credentials would need to be passed in some form. You may have to call credentials from a secrets management system or hold them as securestrings in a constants file. These are reasonable solutions but where possible, I would rather not hold credentials in multiple systems and with the vRA plugin, no credentials need to be plumbed in to allow API calls to be executed.

Cloud Template / NSX-T Configuration

I have a basic cloud template, comprising of a vSphere machine, vSphere network and an existing NSX-T security group which I wish to assign the VM against.

Cloud Template blueprint

The key things to note in the below yaml are:

  1. An input has been created for customer_id. This is a placeholder which the custom form will fill in rather than it being manual user input
  2. This input value is passed through to complete the security tag constraint.
formatVersion: 1
inputs:
  customer_id:
    type: string
resources:
  Cloud_SecurityGroup_1:
    type: Cloud.SecurityGroup
    properties:
      constraints:
        - tag: '${input.customer_id + ":customer_id}'
        # In NSX-T land, this maps to tag:scope
      securityGroupType: existing
  Cloud_vSphere_Machine_1:
    type: Cloud.vSphere.Machine
    properties:
      minionId: '${self.resourceName}'
      image: base-centos7
      cpuCount: 2
      totalMemoryMB: 2048
      networks:
        - network: '${resource.Cloud_vSphere_Network_1.id}'
          assignment: static
          securityGroups:
            - '${resource.Cloud_SecurityGroup_1.id}'
  Cloud_vSphere_Network_1:
    type: Cloud.vSphere.Network
    properties:
      networkType: existing
      name: PG_172-16-10-0
      networkCidr: null

For reference – in NSX-T I have a finance group configured with a tag of customer_id and a scope of fin. No compute member criteria is configured as constraints match on tags.

NSX-T finance group configuration

As it stands, upon requesting this template the customer_id input must be manually entered. This is what we are going to auto-populate with a vRO action.

Manual entry of customer_id

vRO Configuration

External data sources within custom forms use vRO actions. To auto-populate customer_id, the action we create will need to call the vRA project API and pull back the custom property of interest (customer_id) and return the value.

Step 1 – Create a constants file

Create a constants file in vRO and map the VRA:Host data type which has been created by the vRA plugin. The action will then call this constants file and use the variable to execute the REST call.

In this example, the constants file created is called tgConstants and the mapped variable is called vra_host.

vRO Action Code

Below is the full action code. Annotations within the code break down the relevant parts.

@@inputs - projectId :: string
@@outputs - string

if (projectId == "") {
	return ("")
} else {
  	// Find the constants file path
	var category = Server.getConfigurationElementCategoryWithPath("Library/TG")
	if (category == null) {
	    throw "Configuration element category '" + categoryPath + "' not found or empty!";
	}
	// Declare the constants file
	var elementName = "tgConstants"
    // Declare the variable name within the constants file
	var attributeName_vra_host = "vra_host"

	var elements = category.configurationElements;
	var result = [];
	// Iterate the elements within the constants file and if it matches the name, grab the value i.e VRA:HOST
	for (i = 0; i < elements.length; i++) {
	    if (elements[i].name == elementName) {
	        var vra_host = elements[i].getAttributeWithKey(attributeName_vra_host).value;
	    } else {
	        throw "Attribute '" + attributeName + "' not found!";
	    }
	
	}
	// Declare the API URL we wish to query
	var url = "/iaas/api/projects/" + projectId
	//Setup Request and headers to grab projects
    var restClient = vra_host.createRestClient();
	var request = restClient.createRequest("GET",url, null);
    // LOOK - NO AUTH HEADER NEEDED!!!!
	request.setHeader("accept", "application/json");
	var response = {
	    statusCode: 0,
	    contentAsString: ""
	};
    
	// Run the HTTP Get request and extract the custom property and return it
	var count = 3
	var sleepMs = 10000
	while (count > 0) {
	    --count; 3;
	    try {
	        response = restClient.execute(request);
	        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) {
                System.log(content)
	            return(content.customProperties.customer_id)
	            count = 0
	        }
	    }
	    else { System.sleep(sleepMs) }
	}
}

Map the input to the action

Within the service broker – customize the form and configure the customer_id field to call the vRO action. Map the action input to the project field (project ID). Enable the custom form.

Nb. In this example I have also made the field read-only to prove the action populates the field.

Configure external data source

Moving back to the catalog > request you can now see the customer_id field is now populated via the action! In a production environment you should configure this field as hidden because a customer does not need to see the output.

The field will now be passed to the security group input to inform the constraint, as described earlier.

Auto populated customer_id field

Hopefully this demo gives someone some new ideas on how best to customize their vRA environment and the value of the vRA plugin for vRO.

Leave a Reply