akaphenom akaphenom - 5 months ago 13
Node.js Question

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.

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, 'frt\\tbrown', 'Vogenbag1', 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