nikhilxp64
Enthusiast
Enthusiast

Problems with recursive traversal of inventory (C# and web services)

Jump to solution

To start off, let me say my goal was to write a piece of code that would pick up the HostSystem ManagedObjectReference(MOR) when given the MOR to the root-folder of an ESXi system.

However I am unable to get this to work with recursion at all. I could just manually each and every path to follow (no recursion) but given that I need to work with the web-services SDK a lot more, I really want to get this working.

I usually get exceptions like "unlabelled traversal spec" or "invalid type". Usually the invalid type is caused by a mistake in the capitalization of letters in the TraversalSpec.type property. But why does it tell me I have an "unlabelled traversal spec" when I took care of specifying the names in each TraversalSpec.

Can anyone provide an example on how to set up a PropertyFilterSpec to traverse from the root folder to HostSystem using recursive calls via SelectionSpec?

Below is some of my code relating to the traversal of the inventory. It's a mess right now and not exactly set up for recursive calls as I kept trying different things to get it to work.

Help greatly appreciated.

               ObjectSpec objSpec = new ObjectSpec();
            PropertySpec pSpec = new PropertySpec();
            PropertyFilterSpec pFilterSpec = new PropertyFilterSpec();

            SelectionSpec sSpec = new SelectionSpec();
            sSpec.name = "travelFolder";

            SelectionSpec sSpec2 = new SelectionSpec();
            sSpec.name = "travelDCtoFolder";

            TraversalSpec travelDCtoFolder = new TraversalSpec();
            travelDCtoFolder.name = "travelDCtoFolder";
            travelDCtoFolder.skip = false;
            travelDCtoFolder.type = "Datacenter";
            travelDCtoFolder.path = "hostFolder";
            travelDCtoFolder.selectSet = new SelectionSpec[] { new SelectionSpec() };
            travelDCtoFolder.selectSet[0].name = "travelFolder";

            TraversalSpec travelCRtoHF = new TraversalSpec();
            travelDCtoFolder.name = "travelCRtoHF";
            travelDCtoFolder.skip = false;
            travelDCtoFolder.type = "ComputeResource";
            travelDCtoFolder.path = "host";

            TraversalSpec travelFolder = new TraversalSpec();
            travelFolder.name = "travelFolder";
            travelFolder.type = "Folder";
            travelFolder.path = "childEntity";
            travelFolder.skip = false;
            travelFolder.selectSet = new SelectionSpec[] { };

            objSpec.obj = hostMOR;
            objSpec.skip = false;
            objSpec.selectSet = new SelectionSpec[] { travelFolder, travelDCtoFolder, travelFolder, travelCRtoHF };

            pSpec.type = "ManagedEntity";
            pSpec.pathSet = new string[] { "name" };

            pFilterSpec.objectSet = new ObjectSpec[] { objSpec };
            pFilterSpec.propSet = new PropertySpec[] { pSpec };

1 Solution

Accepted Solutions
BenN
Enthusiast
Enthusiast

Here's an example, it's in VI Java but should point the way:

        TraversalSpec findHosts = new TraversalSpec();
        findHosts.setType("ComputeResource");
        findHosts.setPath("host");
       
        SelectionSpec recurseFolders = new SelectionSpec();
        recurseFolders.setName("FolderParent");
       
        TraversalSpec findClusters = new TraversalSpec();
        findClusters.setType("Datacenter");
        findClusters.setPath("hostFolder");
        findClusters.setSelectSet(new SelectionSpec[] {recurseFolders} );
       

        TraversalSpec findFolders = new TraversalSpec();

        findFolders.setName("FolderParent");
        findFolders.setType("Folder");
        findFolders.setPath("childEntity");
        findFolders.setSkip(Boolean.FALSE);
        findFolders.setSelectSet(new SelectionSpec[] { recurseFolders, findClusters, findHosts });

        ObjectSpec searchFromRoot = new ObjectSpec();
        searchFromRoot.setObj(si.getRootFolder().getMOR());
        searchFromRoot.setSelectSet(new SelectionSpec[] { findFolders });

        PropertySpec reportHostName = new PropertySpec();
        reportHostName.setType("HostSystem");
        reportHostName.setPathSet(new String[] { "name" });

        PropertyFilterSpec pfSpec = new PropertyFilterSpec();
        pfSpec.setObjectSet(new ObjectSpec[] { searchFromRoot });
        pfSpec.setPropSet(new PropertySpec[] { reportHostName });

        PropertyCollector pc = si.getPropertyCollector();
        ObjectContent[] ocs = pc.retrieveProperties(new PropertyFilterSpec[] { pfSpec });

        if (ocs != null) {
            for (ObjectContent oc : ocs) {
                ManagedObjectReference dc = oc.getObj();
                DynamicProperty[] props = oc.getPropSet();
                if (props != null && props.length == 1) {
                    String name = (String) props[0].getVal();
                    System.out.println("Found " + dc.getType() + " name is '" + name + "'");
                }
            }
        }

This is a bit old, so I'm not sure I can explain it any more, but here goes.

FIrst, the ObjectSpec specifies the root folder as the starting point, with the "findFolders" TraversalSpec saying what to search from there.

Second, findFolders specifies that for a found Folder, select the objects in its childEntity list.

If the selected child object of a Folder is another Folder, the "recurseFolders" SelectionSpec will point back at "findFolders" to search the child.

If the selected child object of a Folder is a DataCenter, "findClusters" will select its "hostFolder" object, and again use "recurseFolders" to search that Folder.

If the selected child object of a Folder is a ComputeResource, it will select the objects in its "host" list and search no further.

View solution in original post

5 Replies
BenN
Enthusiast
Enthusiast

Here's an example, it's in VI Java but should point the way:

        TraversalSpec findHosts = new TraversalSpec();
        findHosts.setType("ComputeResource");
        findHosts.setPath("host");
       
        SelectionSpec recurseFolders = new SelectionSpec();
        recurseFolders.setName("FolderParent");
       
        TraversalSpec findClusters = new TraversalSpec();
        findClusters.setType("Datacenter");
        findClusters.setPath("hostFolder");
        findClusters.setSelectSet(new SelectionSpec[] {recurseFolders} );
       

        TraversalSpec findFolders = new TraversalSpec();

        findFolders.setName("FolderParent");
        findFolders.setType("Folder");
        findFolders.setPath("childEntity");
        findFolders.setSkip(Boolean.FALSE);
        findFolders.setSelectSet(new SelectionSpec[] { recurseFolders, findClusters, findHosts });

        ObjectSpec searchFromRoot = new ObjectSpec();
        searchFromRoot.setObj(si.getRootFolder().getMOR());
        searchFromRoot.setSelectSet(new SelectionSpec[] { findFolders });

        PropertySpec reportHostName = new PropertySpec();
        reportHostName.setType("HostSystem");
        reportHostName.setPathSet(new String[] { "name" });

        PropertyFilterSpec pfSpec = new PropertyFilterSpec();
        pfSpec.setObjectSet(new ObjectSpec[] { searchFromRoot });
        pfSpec.setPropSet(new PropertySpec[] { reportHostName });

        PropertyCollector pc = si.getPropertyCollector();
        ObjectContent[] ocs = pc.retrieveProperties(new PropertyFilterSpec[] { pfSpec });

        if (ocs != null) {
            for (ObjectContent oc : ocs) {
                ManagedObjectReference dc = oc.getObj();
                DynamicProperty[] props = oc.getPropSet();
                if (props != null && props.length == 1) {
                    String name = (String) props[0].getVal();
                    System.out.println("Found " + dc.getType() + " name is '" + name + "'");
                }
            }
        }

This is a bit old, so I'm not sure I can explain it any more, but here goes.

FIrst, the ObjectSpec specifies the root folder as the starting point, with the "findFolders" TraversalSpec saying what to search from there.

Second, findFolders specifies that for a found Folder, select the objects in its childEntity list.

If the selected child object of a Folder is another Folder, the "recurseFolders" SelectionSpec will point back at "findFolders" to search the child.

If the selected child object of a Folder is a DataCenter, "findClusters" will select its "hostFolder" object, and again use "recurseFolders" to search that Folder.

If the selected child object of a Folder is a ComputeResource, it will select the objects in its "host" list and search no further.

nikhilxp64
Enthusiast
Enthusiast

Thanks for taking the time to reply BenN! Heart

I think I got the logic behind it all. The example was very useful. I got the same thing working in C# now and I including it below in case there's someone out there who's using C# like me and is confused about recursive traversal :smileygrin:

            SelectionSpec recurseFolders = new SelectionSpec();
            recurseFolders.name = "travelFolder";

            TraversalSpec findHosts = new TraversalSpec();
            findHosts.type = "ComputeResource";
            findHosts.path = "host";

            TraversalSpec DcToHf = new TraversalSpec();
            DcToHf.type = "Datacenter";
            DcToHf.path = "hostFolder";
            DcToHf.selectSet = new SelectionSpec[] { recurseFolders };

            TraversalSpec travelFolders = new TraversalSpec();
            travelFolders.name = "travelFolder";
            travelFolders.type = "Folder";
            travelFolders.path = "childEntity";
            travelFolders.skip = false;
            travelFolders.selectSet = new SelectionSpec[] { recurseFolders, DcToHf, findHosts };

            ObjectSpec objSpec = new ObjectSpec();
            objSpec.obj = _serviceContent.rootFolder;
            objSpec.selectSet = new SelectionSpec[] { travelFolders };

            PropertySpec propSpec = new PropertySpec();
            propSpec.type = "HostSystem";
            propSpec.pathSet = new string[] { "name" };

            PropertyFilterSpec pfilter = new PropertyFilterSpec();
            pfilter.objectSet = new ObjectSpec[] { objSpec };
            pfilter.propSet = new PropertySpec[] { propSpec };

            try
            {
                ManagedObjectReference propertyCollector = _serviceContent.propertyCollector;
                ObjectContent[] objs = _vimService.RetrieveProperties(propertyCollector, new PropertyFilterSpec[] { pfilter });
                if (objs != null)
                {
                    foreach (ObjectContent obj in objs)
                    {
                        ManagedObjectReference mor = obj.obj;
                        DynamicProperty[] dprops = obj.propSet;
                        if (dprops != null)
                        {
                            Debug.WriteLine("Found " + mor.type + ", name is " + dprops[0].val);
                        }
                    }
                }
            }
            catch (Exception ex)
            {

                Debug.WriteLine(ex);
            }

Also I just wanted to confirm that if there are multiple host system instances (in the case of a vCenter Server for instance), this property filter would pick them all up correct?

0 Kudos
nikhilxp64
Enthusiast
Enthusiast

Also another question comes to mind. For the sake of this discussion let's assume we have more than one Datacenter reference under the root folder. So the inventory looks something like so:

                              root-folder

                            /                \

         Datacenter1                   Datacenter2

              |                                     |

         hostFolder1                    hostFolder2

              |                                            |

         ComputeResource1              ComputeResource2

              |                                             |

         hostSystem1                       hostSystem2

Would this code be able to travel down both the branches of the inventory from the root folder and pick up the name of hostSystem1 as well as hostSystem2?

Or does it only follow a single path using the first instance of Datacenter is picks up? :smileyconfused:

0 Kudos
BenN
Enthusiast
Enthusiast

It will go down both trees. The folder traversal spec selects a Folders childEntity member, which is a list, and each object in that list is matched against the other selection specs.

If you were only interested in a single Datacenter, you'd use that Datacenter MOREF in the object spec instead of the root folder MOREF.

You'd probably have to re-arrange the traversal specs so the datacenter one pointed directly at the folder one, instead of by name, since the recursion is now starting below the datacenter instead of from the root.

nikhilxp64
Enthusiast
Enthusiast

Thanks for sorting that out for me.

0 Kudos