CloudAutoCraft
Enthusiast
Enthusiast

Sorting properties returned via custom action

Jump to solution

Greetings,

I have custom vRO actions that are bound to vRA 7.2 properties.  The actions are working properly and returning values into vRA.  However, vRA is not displaying the properties in a sorted fashion.  I even go so far as to sort the properties in vRO before I return them to vRA, but it seems that vRA is rejecting / not caring about the order in which vRO returns them, and it displays them (in the Catalog Request) however it sees fit. 

Has anyone had any luck in getting properties to sort alphabetically when returned via a vRO action?  See screenshot below for an example.  This is showing a list of networks that is valid for a user-selected Reservation (via a ReservationPolicy).  The action that provided this list is a derivative of the OOTB action {com.vmware.vra.networks}\getApplicableNetworks.

Unsorted Network Selection.png

I'm having the same challenges for ReservationPolicyId. 

Any help / advice would be appreciated.  Thanks!

2 Solutions

Accepted Solutions
craigso
Enthusiast
Enthusiast

This was on my list of things to get answered while at VMworld this year. While networking with other developers and I found someone that ran across this same limitation and he was kind enough to share some sample code. I took that code and wrote the example (shown below).

While there is no way to sort a list of properties themselves, there is a bit of a workaround which will result in a sorted list.

TLDR;

Create an array of properties, return that to vRA.

pastedImage_0.png

function addToArray(prop){

     System.log("Adding: " + prop.get("value"));

     array.push(prop);

}

var array = [];

for(var i = 0 ; i < 2 ; i++ ) {

     var property = new Properties();

     property.put('label','label'+i);

     property.put('value','value'+i);

     addToArray(property);

}

for each (item in array){

     System.log("item: " + item.get("label"));

     System.log("item: " + item.get("value"));

}

return array;

pastedImage_1.png

View solution in original post

nmshadey
Enthusiast
Enthusiast

The problem with the original answer is that the example is setting up the array of properties in the correct order. However, if the data you are working with is provided unordered then you will need to further sort this data.

I came up with a solution to this, whilst not exactly the most efficient path, executes in about a second with every use case I have had so far.

The idea is to take the original array of properties and build an array of labels. Sort this label array and then reconstruct the array of properties in the correct order:

function sortProps(propertiesArray) {
    var sortedLabels = [];
    var sortedProps = [];

    sortedLabels = propertiesArray.map(function(x){return x.get("label")});
    sortedLabels.sort();
 
    for each (var label in sortedLabels) {
        for each (var prop in propertiesArray) {
            var propLabel = prop.get("label");
            if (propLabel === label) {
                var property = new Properties();
                property.put('label', label);
                property.put('value',prop.get('value'));
                sortedProps.push(property);
                break;
            }
        }
    }
    return sortedProps;
}

View solution in original post

15 Replies
SeanKohler
Expert
Expert

Hmmm...

Via external action (vRO action)... I am seeing the exact positional order in an array go back to the property.  Sooo... not sure.  Can you set up a similar small test and draw comparisons to your sorting methods in your VLAN list?

sorted1.jpg

sorted2.jpg

-----------------------------

sorted3.jpg

sorted4.jpg

0 Kudos
CloudAutoCraft
Enthusiast
Enthusiast

Thanks for the reply, SeanKohler

I was able to recreate the simple sort like you did, and the behavior was the same as what you shared (property values were displayed in the order that vRO returned them to vRA).  However, it seems that the behavior is different when dealing with properties that are linked to vRA constructs such as Reservation Policies and Network Profiles.  If you don't mind tumbling a bit further down the rabbit hole with me....

vRO 7.x comes with an OOTB script action called "getApplicableReservationPolicies" (located in the [com.vmware.vra.reservations] module).  I have copied the OOTB action into one that I can tweak on my own.  The first 17 lines of the script remain unchanged.  I also did not touch the function defined at the end of the script.  Here's what I changed.

VMware's code (lines 18-22) :

var reservationPolicyProperties = new Properties();

for each(var reservationPolicy in reservationPolicies) {

  reservationPolicyProperties.put(reservationPolicy.getId(),reservationPolicy.getName());

}

return reservationPolicyProperties;

My code (replaces the above, inserted above the function defintion):

var reservationPolicyProperties = new Properties();

var resPolNames = new Array();

//capture an array of the Reservation Policy names

for each(var reservationPolicy in reservationPolicies) {

  resPolNames.push(reservationPolicy.getName());

}

resPolNames.sort();

//sort the array of Reservation Policy names

//step thru the sorted Reservation Policy names; insert them into Properties object in alphabetical order (by name, assuming the sort worked)

for each (name in resPolNames) {

  for each(var reservationPolicy in reservationPolicies) {

  var retrievedName = reservationPolicy.getName();

  if (name == retrievedName) {

  reservationPolicyProperties.put(reservationPolicy.getId(),reservationPolicy.getName());

  }

  }

}

//write the results to log; note that keys is never sorted, so presumably, we are stepping through reservationPolicyProperties in the order they are returned to vRA.

var keys = new Array();

keys = reservationPolicyProperties.keys;

for each (var key in keys) {

  System.log("Key: " + key + "| Value: " + reservationPolicyProperties.get(key));

}

return reservationPolicyProperties;

The output in vRO scripting.log (generated by the loop in lines 21-25 of my snippet) shows that the sorting/property insertions I performed above (lines 03-16) seems to have worked the way I wanted (the properties object appears to be sorted by Names of the Reservation Policies, highlighted with red text):

2017-02-22 17:38:28.827-0600 INFO  {cafe-IDGbGg2xvA@vsphere.local:} [SCRIPTING_LOG] Key: e611971f-c42c-4307-98b0-4785833eb3c0| Value: BN-CRP-HYBRID-01C - EUC Team

2017-02-22 17:38:28.828-0600 INFO  {cafe-IDGbGg2xvA@vsphere.local:} [SCRIPTING_LOG] Key: 1c558a75-1ad7-40a6-ba49-97d20d857247| Value: LB-CRP-GEN-01C - Cloud Team

2017-02-22 17:38:28.829-0600 INFO  {cafe-IDGbGg2xvA@vsphere.local:} [SCRIPTING_LOG] Key: 275ec551-7bd6-4841-9361-b648543d73da| Value: LB-CRP-GEN-01C - Enterprise Operations

2017-02-22 17:38:28.830-0600 INFO  {cafe-IDGbGg2xvA@vsphere.local:} [SCRIPTING_LOG] Key: 8a342a96-cb1b-4ab9-a6c3-133c1711e651| Value: LB-CRP-GEN-01C - SQL DBA Team

2017-02-22 17:38:28.831-0600 INFO  {cafe-IDGbGg2xvA@vsphere.local:} [SCRIPTING_LOG] Key: 9005d4d2-635b-4e56-a663-c05d3d3fde8f| Value: Nutanix_Lab - Cloud Team

2017-02-22 17:38:28.832-0600 INFO  {cafe-IDGbGg2xvA@vsphere.local:} [SCRIPTING_LOG] Key: 8395c8a7-6a82-413b-b61d-aceb728c0cce| Value: Nutanix_Lab - Enterprise Operations

2017-02-22 17:38:28.833-0600 INFO  {cafe-IDGbGg2xvA@vsphere.local:} [SCRIPTING_LOG] Key: 20d089b9-5ccc-41dc-beef-1d2c5b1dd877| Value: RASC_Lab

What vRA displays however, is in a different order:

My Script ResultsVMware Script Results (in vRA Catalog)
MyScriptResults.pngVMwareScriptResults.png

It's interesting that there is a slight variation on the display order (in the vRA Catalog Request) between my script and VMware's script.  I had been guessing that vRA was sorting the list based on some other property behind the scenes, but the fact that there are differences here lead me to believe otherwise now.  To that end, I looked at the dbo.HostReservationPolicy table in the IaaS SQL server, and based on the properties in that table (and in the associated dbo.HostReservation table), I'm not seeing any solid correlation between properties and how they are sorted/displayed in the property dropdown on a catalog request.  They aren't sorted by name, id, lastmodified (from the HostReservationPolicy table), nor by any other property that I can see in the affiliated HostReservation table.

Here's the HostReservationPolicy table:

idlastmodifiednamedescription
8A342A96-CB1B-4AB9-A6C3-133C1711E6512016-12-22 14:06:48.207LB-CRP-GEN-01C - SQL DBA Team
20D089B9-5CCC-41DC-BEEF-1D2C5B1DD8772016-12-07 07:24:24.553RASC_Lab
E611971F-C42C-4307-98B0-4785833EB3C02017-01-16 12:48:57.540BN-CRP-HYBRID-01C - EUC Team
416D171D-9597-4178-AC71-680336B692562017-01-18 15:56:27.877BN-CRP-HYBRID-01C - Cloud Team
1C558A75-1AD7-40A6-BA49-97D20D8572472016-12-07 07:24:55.357LB-CRP-GEN-01C - Cloud Team
8395C8A7-6A82-413B-B61D-ACEB728C0CCE2016-12-07 07:24:34.990Nutanix_Lab - Enterprise Operations
275EC551-7BD6-4841-9361-B648543D73DA2016-12-07 07:24:48.720LB-CRP-GEN-01C - Enterprise Operations
9005D4D2-635B-4E56-A663-C05D3D3FDE8F2016-12-07 07:24:42.267Nutanix_Lab - Cloud Team
B9111C09-071D-42B7-99C1-EE019ED6FC982016-12-20 09:19:26.173LB-CRP-GEN-01C EUC Team

If you're still with me and thinking "Dude, this isn't that bad, just deal with it," please recognize that this is a simple example from my Dev environment that I'm using for demonstration purposes. In my prod environment, my end users will have to select the right Reservation Policy out of roughly 100.  Without sorting, I guarantee there will be more user errors, and I really prefer to head those off wherever possible (don't you?!).  I have a similar problem with my Network Selection property (which is also driven by an action that VMware provides OOTB and I copied/tweaked to my requirements), but worst case there is they have to pick the right network out of about 40 choices.  One saving grace in both cases is that they can start typing the name in, and it will auto-filter down based on what they type.  Still, sorting isn't new, and I'm hoping that one of you fine folks can help me figure this out so I can help my end users ward off issues.  Besides, I'd really like a deeper understanding of what's in play here.

If I can't get help here, I may submit this as a feature enhancement request to the vRA product team.

Thanks in advance for any help you cats can offer here!

GrantOrchardVMware‌‌, stvkpln, and jadelzein -- you seem to know a thing or two about this; tagging you in hopes you can offer insight?

0 Kudos
SeanKohler
Expert
Expert

>>"Dude, this isn't that bad, just deal with it,"

With you and not thinking this.  Sorting is important in all cases.

Let me look into it further.

0 Kudos
SeanKohler
Expert
Expert

So a couple of observations...

1. You are using property (an Object() extension) in a somewhat unique way by specifying the key as a the ID and the value as the name. (maybe this is common, but I was unaware)  Normally an "instance" of a property would have a key for ID and a key for Name with the values being the value for that instance.

2. The "simple" method we tested was using an ARRAY.  By position Array[0] is the first item in a vRA drop-down.  By contrast... you are returning a single property with a collection of all items as keys.  Properties are un-ordered lists referenced through keys. I don't think it is a function of vRA or otherwise that keys maintain position within a property.  I understand that you want the behavior found in the plugin setup of the property which is maintaining order... but the handoff to vRA (a new instance of a property) doesn't appear to hold the order as you have demonstrated.  I don't know that I would expect it to:  property keys are unordered lists (I wouldn't care if "age" was before or after "name" in memory if I was calling the value by key).

I have long advocated using string and array/string representation in presentation with object lookup in workflow. I understand that there can be issue with name lookups that are not paired with ID, but string representations can also be anything we want.

I would be curious at this point what would happen within the vRA display if you returned something like this....

[0] Property1 - key: e611971f-c42c-4307-98b0-4785833eb3c0 | value: BN-CRP-HYBRID-01C - EUC Team

[1] Property2 - key: 1c558a75-1ad7-40a6-ba49-97d20d857247 | value: LB-CRP-GEN-01C - Cloud Team

If such a thing worked... You gain the value of the array positional awareness represented and the selection would be a property return with a key/value pair that you are expecting to be able to leverage in workflow.

I will think on this more.

0 Kudos
SeanKohler
Expert
Expert

Bleh... don't bother trying the last test.  It returns, I believe, the right properties in the right position... but it would take key/value expansion that doesn't exist for a single property instance in an array. (If that makes sense)

sorted5.jpg

sorted6.jpg

0 Kudos
SeanKohler
Expert
Expert

Could you explain a little more detail behind how you are populating the list in vRA?

e.g.  Is this a custom property dropdown in IaaS Blueprint running an external action in vRO, another IaaS property display method, or something else in a XaaS Blueprint?

0 Kudos
CloudAutoCraft
Enthusiast
Enthusiast

Sorry I kinda went dark yesterday.  Appreciate the responses. 

In Reply #4 you observed using property in a unique way.  I agree, and this threw me for a bit of a loop, but I didn't want to alter the structure of the data returned to vRA from what VMware provided OOTB.  Thus, I'm 100% piggybacking on what VMware provided in their OOTB script action.  I used the same call that VMware made to create the data being returned to vRA ( reservationPolicyProperties.put(reservationPolicy.getId(),reservationPolicy.getName()); ); I just wrapped my own logic around their statement in an attempt to sort it presentably for my end users. 

To answer your query in Reply #6:

This is a custom property dropdown in an IaaS Blueprint.  Its name is the reserved/special property "ReservationPolicyID"  (more info here:  vRealize Automation 7.2 Information Center)

Here is the property definition.  I blacked out the name of our module where the script action resides to preserve anonymity and avoid IP/Legal concerns, but any one of you (with vRA/vRO 7.x and an ounce of ambition) should be able to wire this up with VMware's OOTB action (located in the com.vmware.vra.reservations module) and observe the same behavior. 

ReservationPolicyID_prop_def.png

To catch up to exactly where I'm at, you would copy that action into one of your own, and replace the code like I described in Reply #2 on this thread.  Then update your property definition to point to your newly created action, apply the property to a blueprint, and fire up a catalog request against said blueprint.

0 Kudos
SeanKohler
Expert
Expert

Ah ha... so yeah, one of the Reserved properties that doesn't behave like any other type in the product.  I duplicated your issue.

It is a string type that accepts a property type return to populate the field.  (try that with anything else, and you get a type mismatch)

So I only see two options.

1. Put in your feature request for alpha-sorted property return to the handling of that Reserved property. Wait for a long time.

2. Return a sorted string array of Reservation Policies (names) using a resource action field NOT named "ReservationPolicyID" (name it Cluster Selection), and then set a hidden "ReservationPolicyID" field with the ID property value based on a lookup from the first field.

So use two fields.  A field where you have your sorted list and a field where the selected item in the first field is used.

I will build a quick example.

0 Kudos
SeanKohler
Expert
Expert

Well... unfortunately I wasn't paying attention (haven't needed to yet) with the IaaS external calls.  Unlike the ASD side of things, you cannot make an external call for a textbox... only for dropdown list.

So we can get a sorted order of Reservation Policies, but we cannot set the ReservationPolicyId custom property to a value based on a selection at the form level.

What I think can happen (need to confirm)... is we may be able to hijack the property value for the ID after the request is made. This I don't know too well, but it is worth looking into.

We can get a sorted array of reservation policies (this isn't filtered by anything and would need to be to ultimately be usable--just a quick example--and I am short-cutting the cafeHost requirement through a Configuration Element reader I made)

sorted7.jpg

sorted8.jpg

We can get the ID based on the name (keeping in mind this requires us to not have name duplication--or have a name that appends uniqueness for ID lookup).

sorted9.jpg

0 Kudos
xian_
Expert
Expert

Are there any solutions found to sort a list of Properties in a custom form dropdown yet? Or the only workaround is to return a (sorted) array of strings and map the display name back to the value it represents? Kinda awkward to use...

0 Kudos
daphnissov
Immortal
Immortal

Still no way to sort a list of Properties from vRO into vRA, custom form or not.

craigso
Enthusiast
Enthusiast

This was on my list of things to get answered while at VMworld this year. While networking with other developers and I found someone that ran across this same limitation and he was kind enough to share some sample code. I took that code and wrote the example (shown below).

While there is no way to sort a list of properties themselves, there is a bit of a workaround which will result in a sorted list.

TLDR;

Create an array of properties, return that to vRA.

pastedImage_0.png

function addToArray(prop){

     System.log("Adding: " + prop.get("value"));

     array.push(prop);

}

var array = [];

for(var i = 0 ; i < 2 ; i++ ) {

     var property = new Properties();

     property.put('label','label'+i);

     property.put('value','value'+i);

     addToArray(property);

}

for each (item in array){

     System.log("item: " + item.get("label"));

     System.log("item: " + item.get("value"));

}

return array;

pastedImage_1.png

xian_
Expert
Expert

Wow, worked fine! Your answer should be marked as the "Correct answer".

I thought there should be a solution, as exporting a custom form containing a dropdown with constant values does not change the order of items on the GUI:

        "dropDown_f78e36ea": {

            "label": "DropDown",

            "type": {

                "dataType": "string"

            },

            "valueList": [

                {

                    "value": "1",

                    "label": "label1"

                },

                {

                    "value": "2",

                    "label": "label2"

                }

            ],

            "placeholder": "",

            "constraints": {}

        }

It is an array indeed, just does not say it is an array of Properties...

Thanks.

BrettK1
Enthusiast
Enthusiast

Well, we're a few years further in, wondering if this has gone anywhere?
Turning the properties into an array (of properties) and returning that looked like it had promise, but all the methods I've looked up to sort an array of properties thus far hasn't worked for me.
Basically the same issue - I have a (not as large) vRO populated dropdown list and would like to a) sort it for user ease and/or b) sort it and be able to search it properly (via another vRO action) to return the index of a default I'd like (or [0] if I don't find the default there).

0 Kudos
nmshadey
Enthusiast
Enthusiast

The problem with the original answer is that the example is setting up the array of properties in the correct order. However, if the data you are working with is provided unordered then you will need to further sort this data.

I came up with a solution to this, whilst not exactly the most efficient path, executes in about a second with every use case I have had so far.

The idea is to take the original array of properties and build an array of labels. Sort this label array and then reconstruct the array of properties in the correct order:

function sortProps(propertiesArray) {
    var sortedLabels = [];
    var sortedProps = [];

    sortedLabels = propertiesArray.map(function(x){return x.get("label")});
    sortedLabels.sort();
 
    for each (var label in sortedLabels) {
        for each (var prop in propertiesArray) {
            var propLabel = prop.get("label");
            if (propLabel === label) {
                var property = new Properties();
                property.put('label', label);
                property.put('value',prop.get('value'));
                sortedProps.push(property);
                break;
            }
        }
    }
    return sortedProps;
}