vSphere CreateContainerView/RetrievePropertiesEx is only returning 100 Objects

1.5k Views Asked by At

I am using nodejs and the node code is fairly simple (using some of folktale here, but a task is similar to a promise):

const connect = (vcenter) => {
    return new Task( (reject, resolve) => {
        const Vsphere = require('vsphere');
        const vc = new Vsphere.Client(vcenter, 'me', 'myPass', false);

        vc.once('ready', () => resolve(vc));
        vc.once('error', reject);
    })
}
const getVirtualMachines = (vc) => {
    return new Task( (reject, resolve) => {
        const rootFolder = vc.serviceContent.rootFolder;
        const vms =  vc.getMORefsInContainerByType( rootFolder, 'VirtualMachine');
        vms.once('result', resolve)
        vms.once('error', reject)
    })
}

connect(vcenterIp).
    chain(getVirtualMachines).
    // SNIP (this isn't significant)
    fork(e2,f2)

and results in sending these requests

CreateContainerView
{
   "_this": {
      "attributes": {
         "type": "ViewManager"
      },
      "$value": "ViewManager"
   },
   "container": {
      "attributes": {
         "type": "Folder"
      },
      "$value": "group-d1"
   },
   "type": "VirtualMachine",
   "recursive": true
}



RetrievePropertiesEx
{
   "_this": {
      "attributes": {
         "type": "PropertyCollector"
      },
      "$value": "propertyCollector"
   },
   "specSet": [
      {
         "attributes": {
            "xsi:type": "PropertyFilterSpec"
         },
         "propSet": [
            {
               "attributes": {
                  "xsi:type": "PropertySpec"
               },
               "type": "VirtualMachine",
               "all": true
            }
         ],
         "objectSet": [
            {
               "attributes": {
                  "xsi:type": "ObjectSpec"
               },
               "obj": {
                  "attributes": {
                     "type": "ContainerView"
                  },
                  "$value": "session[520e031b-3c15-9c1d-408a-45ab98bde1dc]52dfe626-a128-c94f-8c4c-df52a68d97c0"
               },
               "skip": true,
               "selectSet": [
                  {
                     "attributes": {
                        "xsi:type": "TraversalSpec"
                     },
                     "type": "ContainerView",
                     "path": "view",
                     "skip": false
                  }
               ]
            }
         ]
      }
   ],
   "options": {}
}

Which returns

{ returnval: 
   { token: '0',
     objects: 
      [ [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object] ] } }

The problem i am seeing is that the API is only returning 100 items, while there are more than 100VMs in my environment.

I really want the query to return all of my VMs


update 1:

To invoke a single property collection operation, call the RetrievePropertiesEx method. The example application passes the populated PropertyFilterSpec and an empty options structure to the method. The default for the RetrieveOptions.maxObjects specifies that no maximum for the number of objects that can be returned is set. The PropertyCollector can impose a maximum. If the number of collected objects is greater than the maximum, the PropertyCollector returns a token value in the RetrieveResult data object and this token is used to retrieve the remaining properties using the ContinueRetrievePropertiesEx API method

https://pubs.vmware.com/vsphere-50/index.jsp?topic=%2Fcom.vmware.wssdk.pg.doc_50%2FPG_Ch5_PropertyCollector.7.5.html


update 2

OK looking at the returned results vSPehere is returning me a token code. and the node-vsphere library isn't to retrieve all of the results. I need to figure out a way to get all the results in one step.

2

There are 2 best solutions below

2
On BEST ANSWER

I need to follow up with this request

ContinueRetrievePropertiesEx
{
   "_this": {
      "attributes": {
         "type": "PropertyCollector"
      },
      "$value": "propertyCollector"
   },
   "token": "0"
}

HEre is how I accomplished this with the library:

const connect = (vcenter) => {
    return new Task( (reject, resolve) => {
        const Vsphere = require('vsphere');
        const vc = new Vsphere.Client(vcenter, 'xyz\\tbrown', 'ijhi', false);

        vc.once('ready', () => resolve(vc));
        vc.once('error', reject);
    })
}

const getVirtualMachines = (vc) => {
    return new Task( (reject, resolve) => {
        const rootFolder = vc.serviceContent.rootFolder;
        const vms =  vc.getMORefsInContainerByType( rootFolder, 'VirtualMachine');
        vms.once('result', (initial) =>{
            if(initial.returnval.token == undefined) {
                resolve(initial)
                return
            }else {
                const thisReceiveAll = receiveAll(reject, resolve)
                thisReceiveAll(vc, initial)
            }
        })
        vms.once('error', reject)
    })
}

const receiveAll = (reject, resolve) => (vc, initial) => {
    const executeContinueReceive = function executeContinueReceive(previous) {
        const args = {
            _this: {"attributes":{"type":"PropertyCollector"},"$value":"propertyCollector"},
            token: previous.returnval.token
        }
        vc.vc.runCommand('ContinueRetrievePropertiesEx', args).once('result', function(current){
            const previousObjects = previous.returnval.objects
            const currentObjects = current.returnval.objects
            const allObjects = previousObjects.concat(currentObjects)

            current.returnval.objects = allObjects
            if(current.returnval.token == undefined) {
                resolve(current);
                return
            }
            return executeContinueReceive(current)

        }).once('error', reject);
    }
    executeContinueReceive(initial)
}

Essentially when I retreive the intial result set, and check for a token. If the token is there I enter a recursive "receiveAll" function which calls runCommand('ContinueRetrievePropertiesEx', args) and appends its results. Again checking the token at the end, and either returning the result OR make another recursive call... perhaps this should move back into the library

0
On

You can simply use RetrieveProperties and you will not need to do any kind of traversing.