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’

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

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

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.

The key things to note in the below yaml are:
- 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
- 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.

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.

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.

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.

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.