vRealize Automation Ecosystem vRealize Orchestrator

How to use dynamic property definitions in vRA 7.2

Since vRA 7.2. was released we are seeing more and more customers with earlier vRA versions wanting to move to the new version. I was recently involved in a migration of a customer’s production environment from vRA 6.2 to 7.2 (If you haven’t heard of migration, check it out – it’s a totally awesome feature). When the migration ended successfully, the customer started browsing the catalog items and in a patient and polite tone said “I don’t see my property values”, while I could feel he was screaming “Aaaaaaaghhh!” panicking on the inside.

no-values

 

You could safely presume that the idea of a major issue right before an approaching migration deadline increased my heartbeat rate in no time. So, while my first reaction was “Ugh…”, I asked the customer if I could take a look at their 6.2. environment – it seemed they were using relationships as XML files.

category-profile-relation-62

The idea of the current example is simple – a user selects a VM Category from a list during a request, then the drop down list of network profiles gets filtered based on this category, and so does the list of networks. The network profiles bear the same name as the networks so it is easier to choose. In vRA 6 this is achieved by using long, incomprehensible and rather static (I would say boring) XML statements that only specify relationships, and those relationships can only be formed in a 1-to-1 manner. This means that in 6.2 when we choose the VM Category, only the Profile Name drop down list can be filtered, but not the Network Name. The “problem” with 7.2 after migration is that it doesn’t migrate XML code as the property value. Instead, we have to write vRO actions, which, as you may know can do anything, except maybe brewing coffee, last time I checked.

So, after overcoming the first rush of blood to my head and estimating the situation I said to the customer: “Alright, we can fix this”. Seeing a slight smile on the face of the person next to me I started working on a resolution to this problem. Firstly, I had to develop some kind of a database for my vRO actions to play with. I opened the VM Category property definition and manually entered the categories in a static list as the customer wanted them.

vm-category-72

The next problem I had to solve was the mapping between the network profiles and their respective VM Category. I could easily enter that as a static dictionary in my Javascript code in vRO, but I wanted to stick to a basic principle when coding vRO actions – keep as much of the data as possible in vRA and leave the logic to vRO. One solution could be creating another property definition as a static list featuring the relationships, but this meant the customer would have yet another set of properties to manage whenever something in their infrastructure changed, for example a network got removed. I knew that in the customer environment the relationship between VM Category and Network profiles was 1-to-many, so I implemented another approach – I filled the Description of the already migrated Network Profiles with the VM Category names. This way when the customer removes a profile, they would also remove the relationship, and vice-versa.

network-profiles-72

Next, I logged onto the vRO client, went to Design and created a new module from the Actions pane.

vro-newmodule

Then, I created a new Action and named it GetNetProfiles, which, you guessed it, could fetch the profiles based on an input called VM Category. On the Scripting tab of the Edit window I set the return type to be “Array of Strings”, because this is what a drop down list actually represents.

vro-returntype-netpr

Then I added the input parameter and called it VMCategory of type String.

vro-input-netpr

Now, the reader might already be shouting “Show me the code!”, so I will not delay this anymore.

function getNetProfiles(VMCategoryName)
{
  var host = Server.findAllForType("vCAC:vCACHost")[0];
  var netProfilesNamesList = [""];
  var model = "ManagementModelEntities.svc";
  var entitySetName = "StaticIPv4NetworkProfiles";
  var property = new Properties();
  property.put("ProfileDescription", VMCategoryName);
  var netProfiles = vCACEntityManager.readModelEntitiesByCustomFilter(host.id, model, entitySetName, property, null);
  for each (var netProfile in netProfiles)
  {
    netProfilesNamesList.push(netProfile.getProperty("StaticIPv4NetworkProfileName"));
  }
    return netProfilesNamesList;
}
if (VMCategory)
{
  return getNetProfiles(VMCategory);
}
else
{
  return ["Please, select a VM Category"];
}

So, let’s analyse the code. First, it gets a host variable that represents the default IaaS Server, i.e. your Web IaaS Service of a vRA environment. Then, we craft a property variable that will be used to filter only those Network Profiles, that have VM Category as their description. After that, we just call the vCACEntityManager class and read all Entities of Set StaticIPv4NetworkProfiles by using the aforementioned property as a filter. Finally, the names of all Network Profiles which are returned by this query get extracted and poured into an array (remember the return type we set). So, basically we wrap this into a function and call this function in the action execution, while checking if we have a selected VMCategory.

After wrapping up the script code. I created another action, this time calling it GetNetworkName, which again returns an array of String and accepts an input string called NetProfile.

vro-returntype-netname

This action returns the name of the Network Profile as the name of the network in vCenter. Remember in my case I had the Network Profile name be the same as the Network name.

if(NetProfile)
{
 return [NetProfile];
}
else
{
 return ["Please, select a network profile"];
}

Now, you might be wondering how do we attach these actions to a drop down and how do we specify the input properties. Stay with me.

When done with scripting, I navigated back to the vRA 7.2 Automation Console and went straight ahead to editing a Property Definition. I selected the property with a name of VirtualMachine.Network0.ProfileName. I set the type to String and the display name as a Dropdown. The values were set to “External values” and the script action was selected from the list of actions. This list is filtered based on the data type of the property, so don’t freak out if you don’t see all the actions here.

As the Input parameter I entered VMCategory and made sure the value is passed from the VM Category Property Definition I had created earlier.

prop72-profilename

After that, I edited the VirtualMachine.Network0.Name property and selected the GetNetworkName action while setting the ProfileName property as an input parameter.

prop72-netname

I made sure the display order is set correctly, so the request form will show all the properties one under the other.

Next, I headed to the blueprint that needs these properties and made sure that the VM Category is set as a Custom Property and Show in Request is set to Yes, i.e. checked.

blueprint72-vmcatprop

Since the properties for the profiles and networks are network properties we need to check they exist in the network configuration of the blueprint.

blueprint72-netprop

Finally, I was able to request a new VM:

req72-vmcat

req72-netpr

The number of ways this approach can be modified or optimized is infinite – for example, we can use the now recommended NetworkProfileName property which combines the Network Profile and Network Name properties into one or if the profile name differs from the network name we could create another set of a dictionary that maps these two, or you can connect to the company’s service catalog and extract the VM Categories dynamically and so on and so on. I leave it to the reader’s imagination…

More on vRA 7.2.

Comments

8 comments have been added so far

  1. Awesome work Nikolay…
    Thank You for this.

    The instructions required some interpretation, but once we figured it out, it works like a charm.

    Question:
    This works with vRA integrated network profiles, however we are now attempting to use Infoblox IPAM with an Infoblox endpoint and cant manage to get this working with it.

    Any ideas on this would be appreciated.

    1. Hi, Richard
      Sorry, for the late response. . Have you actually tried to do it via the IPAM vRO plugin instead of using the vRA one? Not really sure where the problem is with your setup…

  2. Hi Nikolay;

    Is your Blueprint Build Information (Action) using the “Clone” type? I can honestly state this is not working for me in the manner in which you have described above. When I add a Network Adapter, (and whether I enable the Custom Network Properties or NOT), I get the following “Infrastructure” provisioning ERROR… “No reservation available that has all specified networks: [Network Profile Name]”…. I am UNABLE to get any IP Address allocated during the initial provisioning phase from any IPAM Endpoint source (embedded vRA or external one).

    For info, the Template I am using is Windows 2016. I pre-configured the Template with a Network Adapter (this is our customary way of creating Templates) and then I removed the Network Adapter from the Template just in case there was a conflict with Blueprint Properties.

    Please advise soonest otherwise I’ll defer to another method for selecting Networks via Dropdown method.

    Thanks.. Ron

  3. Hi Nikolay;

    Thx for replying. I honestly have no clue why this is failing.. I am getting the same “Infrastructure” provisioning error… “No reservation available that has all specified networks: [Network Profile Name]”… I thought after reading the Comments Section of the link you pasted that perhaps a space in my Network Profile Names was giving me grief so I removed them but regrettably this had no effect. I also made sure to remove any potential Reservation conflicts to be safe and am experiencing the same failed results.

    I even created a new Property Group and then added the 2 new Property Definitions ( VirtualMachine.Network0.Name and VirtualMachine.Network0.ProfileName) then bound this new Group to the vSphere Machine Properties Tab instead of using the Network Tab of the vSphere Machine and still no luck.

    For your info, the new Action Elements are working as designed.. I am getting the proper dropdown association which is even more confusing..???

    Ironically and for your additional info, I am able to successfully provision VMs with the “static” network dropdown selection as per instructions in the link you sent (http://www.virtualjad.com/2016/06/add-a-network-selection-drop-down-in-vra-7.html) but would much prefer your “dynamic” method herein… 🙁

    Oh well, as I mentioned above, at least I have one way of satisfying the network dropdown selection requirement..

    Thx for your help again..

    1. Hi, Ron
      Unfortunately, I can’t help you much further without having a look at your environment. One option for you is to open a support case with VMware and then mention my name so they contact me.

  4. I have a code it is returning two action result. Actionresult —- Array/string————– Blank
    ActionResult — String ——————- Values

    How can i remove that 1st action result , i do not know from where is it calling . Could you please help .

    if (clusterName == null || tenantName == null) return “”;
    var networkProfiles = [];

    var host = vCACCAFEHostManager.getDefaultHostForTenant(tenantName, true);
    var reservations = vCACCAFEEntitiesFinder.getReservations(host);
    var res;
    for each(reservation in reservations) {
    if (reservation.name == “Res-” + clusterName) res = reservation;
    }
    var data = res.getExtensionData();
    var reservationNetworks = data.get(“reservationNetworks”);

    for each(network in reservationNetworks.getValue()) {
    if (network.getValue().get(“networkProfile”).label.indexOf(‘BUN’) == 0) {
    networkProfiles.push(network.getValue().get(“networkProfile”).label);
    }
    }

    if (networkProfiles.length < 1) return "";
    return networkProfiles[0];

    1. Hi,
      Can you attempt returning only networkProfiles – the drop down box expects an array and in this case you’re returning only string. Just do a return networkProfiles; – if it has only one member then it will return only one member.

Leave a Reply

Your email address will not be published. Required fields are marked *