A few months ago a client asked me to create an NSX application load-balancer programmatically, and then make it available to their vRealize Automation consumers in through the self-service catalog. In building-block fashion, they requested that this wasn’t a composite blueprint, but rather through XaaS. While the former would definitely take less time, the latter was not that difficult either once I got started.
From the outset, I knew I would be building this using the NSX REST API, as I’ve had more success with that than with the NSX plugin for vRO. The first step would be to create an NSX Edge appliance, and then in a follow-up workflow apply the load-balancer settings.
The biggest challenge I faced was that once I’d collated the necessary information (datastore, network portgroup etc), how do I insert it into the XML body for the API call?
The solution was to store the XML as a resource element. In the XML where the values would normally be placed, I inserted the name of the attributes which would then later be populated.
The XML template looks like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<edge> | |
<name>{attXmlConfigName}</name> | |
<appliances> | |
<applianceSize>compact</applianceSize> | |
<appliance> | |
<resourcePoolId>{attXmlConfigResourcePoolId}</resourcePoolId> | |
<datastoreId>{attXmlConfigDatastoreId}</datastoreId> | |
</appliance> | |
</appliances> | |
<vnics> | |
<vnic> | |
<index>0</index> | |
<name>{attXmlConfigNicName}</name> | |
<type>uplink</type> | |
<portgroupId>{attXmlConfigPortgroupId}</portgroupId> | |
<addressGroups> | |
<addressGroup> | |
<primaryAddress>{attXmlConfigPrimaryAddress}</primaryAddress> | |
<subnetMask>{attXmlConfigSubnetMask}</subnetMask> | |
</addressGroup> | |
</addressGroups> | |
<mtu>1500</mtu> | |
<isConnected>true</isConnected> | |
</vnic> | |
</vnics> | |
<cliSettings> | |
<userName>{attXmlConfigUserName}</userName> | |
<password>{attXmlConfigPassword}</password> | |
<remoteAccess>false</remoteAccess> | |
</cliSettings> | |
</edge> |
As part of our workflow, we need to populate values for the following attributes:
- attXmlConfigDatastoreId
- attXmlConfigName
- attXmlConfigNicName
- attXmlConfigPortgroupId
- attXmlConfigPrimaryAddress
- attXmlConfigResourcePoolId
- attXmlConfigSubnetMask
The following also need to be supplied, but they will be defined as configuration elements:
- attXmlConfigUserName
- attXmlConfigPassword
With further work, it would be better to extract the last two from an enterprise secret store, such as HashiCorp Vault.
So far our workflow has defined the values, we now need to merge them into the XML:
To do that we will first define a new Properties object, replace our values, and then cycle through the XML inserting the property keys. To do this, use the following code:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var xmlDetail = new Properties(); | |
xmlDetail.put("{attXmlConfigName}",attXmlConfigName); | |
xmlDetail.put("{attXmlConfigResourcePoolId}",attXmlConfigResourcePoolId); | |
xmlDetail.put("{attXmlConfigDatastoreId}",attXmlConfigDatastoreId); | |
xmlDetail.put("{attXmlConfigNicName}",attXmlConfigNicName); | |
xmlDetail.put("{attXmlConfigPortgroupId}",attXmlConfigPortgroupId); | |
xmlDetail.put("{attXmlConfigPrimaryAddress}",attXmlConfigPrimaryAddress); | |
xmlDetail.put("{attXmlConfigSubnetMask}",attXmlConfigSubnetMask); | |
xmlDetail.put("{attXmlConfigUserName}",attXmlConfigUserName); | |
xmlDetail.put("{attXmlConfigPassword}",attXmlConfigPassword); | |
//Replace placeholders in XML file with correct values | |
var attBody = attXmlConfigEsgBody.getContentAsMimeAttachment().content; | |
for each (var key in xmlDetail.keys) { | |
attBody = attBody.replace(key, xmlDetail.get(key)); | |
} |
Now that we have a complete XML body, we can submit this as a REST API request to provision our NSX Edge. If you’re looking for an excellent example on how to do this, I suggest you take a look at Gavin Stephens blog at https://www.simplygeek.co.uk/2019/05/16/vrealize-orchestrator-http-rest-client.