vRA8 External Inputs and Input Property Groups

Share on:

Hiccups and possible solutions using dynamic input dropdowns

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