Search code examples
node.jssoapvspherenode-vsphere

vSphere CreateContainerView/RetrievePropertiesEx is only returning 100 Objects


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.


Solution

  • 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