VMware Cloud Community
Czernobog
Expert
Expert

vRA/vRO 7.6 - creating array of all cafe VMs - methods not consistent

Hello,

I've created a small inventory script in vRO, which needs all vRA cafe VMs (type: VCACCAFE:CatalogResource) as input.

Loading all CatalogResources ist not an issue, this is done using an odata query and the results are consistent, that is, each time the method delivers the same amount of objects (assuming no changes are made in vRA).

The weird part begins, when I try to filter out non-VM objects from the array, that is everything, that is not of the virtual machine type: Deployments, Networks and other objects provisioned in vRA, that are of no use in the context of this workflow.

I tried different methods for determining if the CatalogResource object is a virtual machine, but each time the script is run, a different amount of objects is returned and as a result, the output is not consistent and cannot be used - some vRA vms are missing each time but also some are duplicated.

What would be an affective way to return all vRA vms as an array? Is there no method that would return consistent results? The only one I could think of, is to load all vCAC Vm objects first and the find the corresponding catalog resource for each, by name, but that would be slow.

Here's the code snippet I use for testing, input is the array of cafeHosts. WARNING - using it can result in excessive JVM Memory usage:

for (var j=0;j<3;j++){

    System.log("====== iteration " + j);

    var vCACCAFEVMs = [];

    // Query each host for catalog resources; this will include cafe vms AND deployments; using odata query with pagination

        for each (host in cafeHosts){

            var service = host.createCatalogClient().getCatalogConsumerResourceService();

            var query = vCACCAFEOdataQuery.query();

            var i;

            for (i = 1; i < 20; i++){

                var items = service.getResourcesList(new vCACCAFEPageOdataRequest(i, 100, query));

                if (items.length == 0) { System.debug("Breaking query of host " + host.name + " on iteration " + i); break }

                vCACCAFEVMs = vCACCAFEVMs.concat(items);

            }

        }

        System.log("Total Found CatalogResource items: " + vCACCAFEVMs.length);

    /*var result = [];

    for each (vm in vCACCAFEVMs){ result.push(vm.name) }

    System.log(result);*/

    // Filter out non-VMs using .resourceTypeRef values

        var vCACCAFEVMs_v2 = vCACCAFEVMs.slice();

        var i = vCACCAFEVMs_v2.length;

        while(i--){

            if (vCACCAFEVMs_v2[i].resourceTypeRef.getId() != "Infrastructure.Virtual" && vCACCAFEVMs_v2[i].resourceTypeRef.getLabel() != "Virtual Machine") { vCACCAFEVMs_v2.splice(i, 1) }

        }

        System.log("CatalogResource after filtering out non-VMs using .resourceTypeRef value: " + vCACCAFEVMs_v2.length);

    var result = [];

    for each (vm in vCACCAFEVMs_v2){ result.push(vm.name) }

    System.log(result.sort());

    // Filter out non-VMs using cafeVm to vcacVm convert

        var vCACCAFEVMs_v3 = vCACCAFEVMs.slice();

        var i = vCACCAFEVMs_v3.length;

        while(i--){

            var vCACVMs = Server.findAllForType("vCAC:VirtualMachine", "VirtualMachineName eq '" + vCACCAFEVMs_v3[i].name + "'");

            if (vCACVMs[0] == undefined) { vCACCAFEVMs_v3.splice(i, 1) }

        }

        System.log("CatalogResource after filtering out non-VMs using cafeVm to vcacVm convert: " + vCACCAFEVMs_v3.length);

    var result = [];

    for each (vm in vCACCAFEVMs_v3){ result.push(vm.name) }

    System.log(result.sort());

}

Tags (2)
Reply
0 Kudos
5 Replies
GeiAll
Enthusiast
Enthusiast

If I understand you correctly, you want a list over all the VM's who is managed by vRA?

You can use vCACEntityManager for this.

(Example, you can adjust the property input, and the result is a list of properties for a VM.)

 

 

var entitySetName = "VirtualMachines" // Info about each virtual Machine
var host = Server.findAllForType("vCAC:vCACHost")[0];
var locs = [];  
var model = "ManagementModelEntities.svc";  


var property = new Properties();  
property.put("IsDeleted",false);
property.put("IsManaged",true);
var VMList = vCACEntityManager.readModelEntitiesByCustomFilter(host.id, model, entitySetName, property, null);  


for each (var Element in VMList)
{
    if (Element instanceof (VCACEntity))
    {
        var Props = Element.getProperties();    // Get All Properties of this Entity
        System.log(Props.VirtualMachineName);
            
    }
}

Reply
0 Kudos
Czernobog
Expert
Expert

I need an array of VCACCAFE:CatalogResource, not vCAC:VirtualMachine, becuase some properties I need are not present on the latter.

I also just tried it with

var items = host.createCatalogClient().getCatalogConsumerResourceService().getResourcesList();

but I only get 20% of the inventory returned Smiley Sad.

Reply
0 Kudos
GeiAll
Enthusiast
Enthusiast

Hi.

Sorry for the misunderstanding.  I only have one CatalogItem myself (one blueprint) and they are all single VMs. All the rest is done using XaaS. 

However you have alot of data here if you follow the links. Including the CatalogRequestID and other references back to the blueprint and so on, maybe there is something here you can use to trace it back. 

This is a script to dump all the data into json format, so it should be quick for you to see if there is anything you can use to trace backwards.

 

var entitySetName = "VirtualMachines" // Info about each virtual Machine
var host = Server.findAllForType("vCAC:vCACHost")[0];
var locs = [];  
var model = "ManagementModelEntities.svc";  

 

function JsonIt(Props)
{
    var Obj = new Object();
    for each (P in Props.keys)
    {
        Obj[P] = Props.get(P);
    }
    return Obj;
}
function JsonItAdd(Obj,Props,Name)
{
    if (Obj[Name] == null)
    {
        // First Entry
        Obj[Name] = new Array();
    }
    var Size = Obj[Name].length;
    Obj[Name][Size] = new Object()
    for each (P in Props.keys)
    {
        Obj[Name][Size][P] = Props.get(P);
    }
    return Obj;
}

var property = new Properties();  
property.put("IsDeleted",false);
property.put("IsManaged",true);
var VMList = vCACEntityManager.readModelEntitiesByCustomFilter(host.id, model, entitySetName, property, null);  


for each (var Element in VMList)
{
    if (Element instanceof (VCACEntity))
    {
        var Props = Element.getProperties();    // Get All Properties of this Entity
        var Links = Element.getLinks(host);
        
        var E = JsonIt(Props)
        for each (L in Links.keys)
        {
            var LinkItems = Links.get(L);
            if (LinkItems)
            {
                for each (LinkItem in LinkItems)
                {
                    var PropLink = LinkItem.getProperties();
                    E = JsonItAdd(E,PropLink,L)
                }    
            }
        }
        System.log(JSON.stringify(E));        
            
    }
}

 
 
 
var entitySetName = "VirtualMachines" // Info about each virtual Machine
var host = Server.findAllForType("vCAC:vCACHost")[0];
var locs = [];  
var model = "ManagementModelEntities.svc";  
 
 
 
function JsonIt(Props)
{
var Obj = new Object();
for each (P in Props.keys)
{
Obj[P] = Props.get(P);
}
return Obj;
}
function JsonItAdd(Obj,Props,Name)
{
if (Obj[Name] == null)
{
// First Entry
Obj[Name] = new Array();
}
var Size = Obj[Name].length;
Obj[Name][Size] = new Object()
for each (P in Props.keys)
{
Obj[Name][Size][P] = Props.get(P);
}
return Obj;
}
 
var property = new Properties();  
property.put("IsDeleted",false);
property.put("IsManaged",true);
var VMList = vCACEntityManager.readModelEntitiesByCustomFilter(host.id, model, entitySetName, property, null);  
 
 
for each (var Element in VMList)
{
if (Element instanceof (VCACEntity))
{
var Props = Element.getProperties(); // Get All Properties of this Entity
var Links = Element.getLinks(host);
 
var E = JsonIt(Props)
for each (L in Links.keys)
{
var LinkItems = Links.get(L);
if (LinkItems)
{
for each (LinkItem in LinkItems)
{
var PropLink = LinkItem.getProperties();
E = JsonItAdd(E,PropLink,L)
}
}
}
System.log(JSON.stringify(E));
 
}
}
Reply
0 Kudos
Czernobog
Expert
Expert

Thanks for looking into it, but like I said, I need the Cafe objects, not the vCAC ones.

I've had partial success with lowering the page size from 100 to 20, but the output is still inconsistent. I don't really know anymore how to get a better result, is my method wrong or is the software just janky?

Reply
0 Kudos
Czernobog
Expert
Expert

I've finally found a way to get consistent results, although no idea if this will still be reliable in environments with >1000 vms.

First thing I have found out - the api call that returns all resources does not include "Missing" machines, this is why there was a discrepancy in the number of machines returned by the call vs. the number on the "Managed Machines" list.

Another thing is the pagination itself - the lower the page size, the more duplicates would be returned - the total number of objects returned was correct, however about 25% of unique entries were replaced by duplicates of other objects in the array. I understand that offset-based paging is not the optimal method, however the environment is mostly static and I do not know why so many duplicate/missing entries are returned. The optimal page size seems to be 100, it cannot be increased anyway, otherwise the api call would throw an error (Error Msg: Request was denied due to exceeded resource size limit. The maximum number of resources allowed is 100).

The documentation of the API in regards to using filters is also really poor, basically non-existent - the parameter name you have to input for the query has no reliance to a property of the object returned and has to be half guessed.

Also, executing the query results in a generic "System exception." error in about 10% of the cases.

Here's a  simple code snippet to test it out:

// return number of vcac vms (infrastructure vms), for comparison

    var vCacVms = Server.findAllForType("vCAC:VirtualMachine");

    System.log("found total vcac machines: " + vCacVms.length);

    var vCacVmNames = [];

    for each (vcacVm in vCacVms){ vCacVmNames.push(vcacVm.VirtualMachineName) }

    System.log(vCacVmNames.sort());

// optionally iterate a few times, to check result for consistence

for (var j=0;j<1;j++){ // adjust j as needed

    System.log("====== iteration " + j);

    var vCACCAFEVMs = [];

    // Query each host for catalog resources; using odata query with filter and pagination

        for each (host in cafeHosts){

            var service = host.createCatalogClient().getCatalogConsumerResourceService();

            var filter = new Array();

                filter[0] = vCACCAFEFilterParam.equal("resourceType/id", vCACCAFEFilterParam.string("Infrastructure.Virtual"));

            var query = vCACCAFEOdataQuery.query().addFilter(filter);

            var i;

            var maxNumPages = 50; // max number of pages returned

            var maxPageSize = 100; // optimal value = 100, lowering results in returning duplicates

            for (i = 1; i < maxNumPages; i++){

                var items = service.getResourcesList(new vCACCAFEPageOdataRequest(i, maxPageSize, query));

                if (items.length == 0) { System.debug("Breaking query of host " + host.displayName + " on iteration " + i); break }

                vCACCAFEVMs = vCACCAFEVMs.concat(items);

            }

        }

        System.log("Total returned CatalogResource items: " + vCACCAFEVMs.length);

            var result = [];

            for each (vm in vCACCAFEVMs){ result.push(vm.name) }

            System.log(result);

        vCACCAFEVMs = uniq_fast(vCACCAFEVMs);

        System.log("Post dedupe returned CatalogResource items: " + vCACCAFEVMs.length);

            var result = [];

            for each (vm in vCACCAFEVMs){ result.push(vm.name) }

            System.log(result);

}

// source for sort function: https://stackoverflow.com/questions/9229645/remove-duplicate-values-from-js-array

function uniq_fast(a) {

    var seen = {};

    var out = [];

    var len = a.length;

    var j = 0;

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

         var item = a[i];

         if(seen[item] !== 1) {

               seen[item] = 1;

               out[j++] = item;

         }

    }

    return out;

}

Edit:

Today I get 20% of objects returned as duplicates, again!, while not changing anything in the script. I have no idea how this jank works now, and it seems noone in the communities has either:smileycry: