In very large environments, the standard (out of the box methods) of retrieving a specific virtual machine object by name in vRealize Orchestrator are not particularly efficient and can take a long time to retrieve a particular object. This is of particular concern when using a vRO action to retrieve an external value in a vRA XaaS form. The default timeout for value retrieval is 30 seconds, and although this can be extended (see https://kb.vmware.com/s/article/2144872), the aim should be to retrieve all values in the fastest time possible as opposed to increasing the timeout to a large value.
So, the challenge was set, design a method of retrieval of any VM object within the vRA timeout.
Out of the box, vRO provides a method of retrieving all virtual machine:
allVMs = VcPlugin.getAllVirtualMachines()
This can be looped through until a specific virtual machine name is found. In small environments this method is absolutely fine as the response time will not be an issue
This can be extended (and made faster) either via including a name:
allVMs = VcPlugin.getAllVirtualMachines(null, vmname)
or by using xpath:
allVMs = VcPlugin.getAllVirtualMachines(null, "xpath:name=\'" + vmname + "\'")
The latter method has issues with case sensitive queries, and using an xpath translation is really slow!
In the environment I was working the former query took many minutes to return data, the latter two took between 45-60 seconds, which was much better, but not quick enough to return the VM object to vRA in less than 30 seconds which was the ultimate goal.
So an alternative solution had to be found…
The aim was to get to a situation whereby the smallest possible number of VMs could be retrieved by vRO, which could then be used to search for the exact VM object. In this way the query made to vCenter is much smaller, resulting in a significantly faster response time. Although this information can itself be queried from vCenter, in environments with more than one vCenter this would still be an iterative process which may result in lengthy delays in returning information.
Fortunately there is a database in many vSphere environments that contains a combined view of the world; vRealize Operations Manager. Each virtual machine object has a number of properties that allow the parent objects of the virtual machine to be readily identified:
vROps also has an API that can be used to retrieve these properties once the internal vROps ID of the object has been determined. The API calls used are:
- https://hostname/suite-api/api/resources?name&resourceKind=virtualmachine – the object identifier is included in the response
- https://hostname/suite-api/api/resource/objectid/properties – the response is queried for the value of the specified property
Unfortunately this only gets us half way. Although we now have the cluster and host that the virtual machine is running on, we need to convert those names into objects that vRO can use.
To speed things up, a cache was created that contains all of the vSphere Clusters in the various vCenter environments. This cache is queried to match the name of the cluster to the cluster object. The cache is updated via a scheduled workflow.
The host object is now retrieved by querying the hosts in the cluster looking for a match for the host retrieved from vROps. This part could be skipped altogether by using a cache containing all ESXi hosts. This was not done in the environment I was working in as the number of hosts would have been very large (> 5000) and the impact of having that many attributes in a configuration element was felt to be excessive.
The final stage is to match the virtual machines of the identified host with the name originally entered. The result is the virtual machine object.
The vRO Package
The package below includes all of the elements needed. Once the package has been imported there is a little bit of configuration that needs to be done:
- Add vROps host(s) as REST endpoints (Library > Configuration > Add a REST host). The name given to the REST host will be the one used in the ‘Get VM by Name via vROps’ workflow that can be used to test the action. Use basic authentication and configure certificate handling as appropriate
- Edit the resource configuration ‘GetVMbyName/vROpsHosts’. Edit the ‘vROpsHosts’ attribute and add each configured vROps host into the array
- Edit the resource configuration ‘GetVMbyName/allVCSDKConnections’. Edit the ‘vcSDKConnections’ attribute and add each vCenter SDK connection as appropriate
- Run the ‘Create Cluster Cache’ workflow and then validate that the ‘GetVMyName/ClusterCache’ resource configuration has all expected clusters
The ‘Get VM by Name via vROps’ workflow can now be run. Enter the name of the virtual machine to search for and the name of the vROps host to use
The output can be viewed either via the log:
Or by viewing the variables. A positive result will include a virtual machine object in the ‘vm’ variable
The test workflow requires a REST host name to be inputted, although this could set via a field on a vRA form, or additional code written to choose the REST host based on some condition.