vRA8 External Inputs and Input Property Groups
Hiccups and possible solutions using dynamic input dropdowns
Table of Contents
Introduction
vRA 8.4.2 added support to use vRO actions for dynamic external values to define properties in property groups, and 8.5.1 added support to define Cloud Templates with dynamic vRO inputs.
In my previous post I've discussed dynamic dropdowns with Custom Forms, now let's take a look on how we can adapt the approach to Cloud Templates and Property Groups. Although the support of Property Groups were introduced earlier, I'll start with the latter.
Cloud Templates with dynamic vRO selection inputs
We can use vRO actions to define the default value and a selection list with possible values to select from.
If the list action returns an Array of String, the dropdown just works fine: the user selected label will be passed to the input variable as value.
For a different label of the values passed within Custom Forms, we could use two return types: Properties and Array of Properties. The main difference was that Properties represent a hashmap that is unsorted, while the Array is always sorted. The latter is useful if we want to display a long list and some ordering is needed for the user to locate the desired item quickly. This has been presented in the previous blog entry already.
A (very) simple Cloud Template
Our sample Cloud Template has only a single input: a string. The provided name is the owner of the VM provisioned, and we assign the tag owner:username to the VM:
1formatVersion: 1
2inputs:
3 owner:
4 type: string
5resources:
6 photon:
7 type: Cloud.vSphere.Machine
8 properties:
9 image: photon
10 cpuCount: 1
11 totalMemoryMB: 1024
12 folderName: vra8
13 tags:
14 - key: owner
15 value: '${input.owner}'
To make the input value dynamic, we have to create a vRO action with a return value. The Cloud Assembly template example documentation describes only the (single) Properties option, let's take a look at both approaches to provide enumerated input selections.
vRO action returning Properties
For demonstration purposes we'll use the JSONPlaceholder service to get some sample data. For key we use the username field, and for value (label) the name field. The name of the action is getUsersUnsorted.
1var restHost = RESTHostManager.createTransientHostFrom(
2 RESTHostManager.createHost("dynamicRequest"));
3restHost.url = "http://jsonplaceholder.typicode.com";
4var request = restHost.createRequest("GET", "/users");
5var response = request.execute();
6var content = JSON.parse(response.contentAsString);
7
8users = new Properties();
9content.forEach(
10 function (user) {
11 users.put(user.username, user.name);
12 }
13);
14
15return users;
In Cloud Assembly, select in Cloud Template editor the Inputs tab, and click on the input named owner. Now within More Options we can assign the action by selecting External source and choosing getUsersUnsorted:
The Cloud Template code will include the action now highlighted:
1formatVersion: 1
2inputs:
3 owner:
4 type: string
5 $dynamicEnum: /data/vro-actions/com.vra.dropdown/getUsersUnsorted
6resources:
7 photon:
8 type: Cloud.vSphere.Machine
9 properties:
10 image: photon
11 cpuCount: 1
12 totalMemoryMB: 1024
13 folderName: vra8
14 tags:
15 - key: owner
16 value: '${input.owner}'
Let's try out our dropdown in Service Broker:
This list appears, but unsorted. The tag is assigned correctly:
vRO action returning Array of Properties
Now we return an ordered list to make our dropdown prettier. The name of the action is getUsersSorted.
1var restHost = RESTHostManager.createTransientHostFrom(
2 RESTHostManager.createHost("dynamicRequest"));
3restHost.url = "http://jsonplaceholder.typicode.com";
4var request = restHost.createRequest("GET", "/users");
5var response = request.execute();
6var content = JSON.parse(response.contentAsString);
7
8users = [];
9content.forEach(
10 function (user) {
11 users.push(new Properties({value: user.username, label: user.name}));
12 }
13);
14
15users.sort(
16 function (a, b) {
17 return a.label > b.label ? 1 : (a.label < b.label ? -1 : 0);
18 }
19);
20
21return users;
In the Cloud Template Inputs tab choose getUsersSorted as External source, or modify the template code:
1formatVersion: 1
2inputs:
3 owner:
4 type: string
5 $dynamicEnum: /data/vro-actions/com.vra.dropdown/getUsersSorted
6...
We can quicly test the result in Cloud Assembly too (without releasing the new version to Service Broker), with the Test button:
Looks good so far, the names are sorted alphabetically. But after submitting the test value, the following error message displayed:
Value 'Delphine' is not in list of valid values ["label", "value", "label", "value", "label", "value", "label", "value", "label", "value", "label", "value", "label", "value", "label", "value", "label", "value", "label", "value"]
Altough we've selected an item from the dropdown, it is not accepted as a valid input! The same happens in Service Broker. Looks like the validation logic cannot use our second action, despite the fact it was correctly displayed.
Workaround
Let's revert our changes to the Cloud Template by selecting the getUsersUnsorted again as External source. This will fix the validation issue, and we can levereage Custom Forms to improve the user experience by sorting the dropdown.
After creating the default Custom Form, we can see the Value options are copied from the Cloud Template:
By re-selecting the action getUsersSorted in the Custom Form, we can override the action providing an unsorted list. After enabling the Custom Form on the catalog item, the user list is sorted and the chosen value is accepted:
vRO actions in an Input Property Group
I found the same limitation applies to properties within an Input Property Group: altough actions returing Array of Properties can be selected as external source of values, and the labels are displayed correctly on the form, the selected value cannot be submitted.
So we create the Property Group with the owner property and external values action getUsersUnsorted returning a (single) Properties object. The user interface is very similar to the Cloud Template Input definition form. Let's define one more property in the group:
A Cloud Template with Input Property Group
We remove the owner input from the Cloud Template and assign the Input Property Group:
The resulting Cloud Template (the referenced Property Group and properties are hightlighted):
1formatVersion: 1
2inputs:
3 photonpg:
4 type: object
5 $ref: /ref/property-groups/photonInputs
6resources:
7 photon:
8 type: Cloud.vSphere.Machine
9 properties:
10 image: photon
11 cpuCount: 1
12 totalMemoryMB: 1024
13 folderName: vra8
14 tags:
15 - key: owner
16 value: '${input.photonpg.owner}'
17 - key: department
18 value: '${input.photonpg.department}'
Adjusting the Custom Form
Let's delete the previous Custom Request Form to start from scratch. By customizing the custom form again, the Schema Elements (our Input Property Group) is added to the canvas. If we click on the Property Group, on the Values tab we can see the individual property names and labels, but we cannot override the input selection options:
As a workaround we export the form as YAML and edit it manually. Within the schema section we replace the default action (copied from the Cloud Template) with the action getUsersSorted:
1 photonpg:
2 label: Photonpg
3 type:
4 dataType: complex
5 fields:
6 - label: owner
7 type:
8 dataType: string
9 isMultiple: false
10 valueList:
11 id: com.vra.dropdown/getUsersSorted
12 type: scriptAction
13 parameters: []
14 id: owner
15 - label: department
16 type:
17 dataType: string
18 isMultiple: false
19 valueList:
20 - value: acc
21 label: Accounting
22 - value: dev
23 label: Developers
24 id: department
25 isMultiple: false
Our form with the nice, ordered list:
and the deployment inputs are accepted:
Bonus: Reordering the Property Group list
The GUI does not provide a way to reorder the inputs within an Input Property Group on the Custom Form. You could delete and re-add the fields but the action assignments are lost then. However, we can export the Custom Form as YAML and manually reorder the display order of the properties. Just cut'n'paste them in YAML schema section:
1 photonpg:
2 label: Photonpg
3 type:
4 dataType: complex
5 fields:
6 - label: department
7 type:
8 dataType: string
9 isMultiple: false
10 valueList:
11 - value: acc
12 label: Accounting
13 - value: dev
14 label: Developers
15 id: department
16 - label: owner
17 type:
18 dataType: string
19 isMultiple: false
20 valueList:
21 id: com.vra.dropdown/getUsersSorted
22 type: scriptAction
23 parameters: []
24 id: owner
After importing the modified file, the inputs are displayed in the rearranged order:
Conclusion
You may ask why to bother with the dynamic actions on the Cloud Template Inputs (either directly or via Property Groups), why not just use them on the Custom Forms as before? The answer is validation: in case the user submits a request via REST API (where Custom Form is not in use), vRA can still check if the input valid.
1curl -s -k -H 'Content-Type: application/json' -H "Authorization: Bearer $access_token" \
2'https://vra8.corp.local/catalog/api/items/3dd31701-d9c1-3f3d-8656-0d87acb6258e/request' \
3-d '{"deploymentName":"test5","inputs":{"photonpg":{"department":"dev","owner":"NoSuchUser"}},"projectId":"22a712bc-5c9e-4784-a55c-0b3719134190","bulkRequestCount":1,"reason":null}' | jq .
vRA will refuse the request by validating the inputs against the vRO actions:
1{
2 "message": "Validation failed with: $.inputs.photonpg.owner: Value 'NoSuchUser' is not in list of valid values [\"Bret\", \"Moriah.Stanton\", \"Kamren\", \"Elwyn.Skiles\", \"Karianne\", \"Leopoldo_Corkery\", \"Delphine\", \"Maxime_Nienow\", \"Samantha\", \"Antonette\"]",
3 "statusCode": 400,
4 "errorCode": 24002
5}
You can download the com.vra.dropdown package containing the sample actions from GitHub: https://github.com/kuklis/vro8-packages