I am using VMWare VSphere WS SDK in Python using the suds client. I want to wait for any changes to VMs. I am specifically interested in VMs of a particular cluster. Is there a way in the propertyfilterspec to say that? I tried setting the managed object reference of the cluster in the ObjectSpec with no avail. Is there anything I am missing?
Concerned piece of code is :
object_spec = client_factory.create('ns0:ObjectSpec')
object_spec.obj = clu_mor
object_spec.skip = False
object_spec.selectSet = build_recursive_traversal_spec(client_factory)
def build_selection_spec(client_factory, name):
"""Builds the selection spec."""
sel_spec = client_factory.create('ns0:SelectionSpec')
sel_spec.name = name
return sel_spec
def build_traversal_spec(client_factory, name, spec_type, path, skip,
select_set):
"""Builds the traversal spec object."""
traversal_spec = client_factory.create('ns0:TraversalSpec')
traversal_spec.name = name
traversal_spec.type = spec_type
traversal_spec.path = path
traversal_spec.skip = skip
traversal_spec.selectSet = select_set
return traversal_spec
def build_recursive_traversal_spec(client_factory):
"""
Builds the Recursive Traversal Spec to traverse the object managed
object hierarchy.
"""
visit_folders_select_spec = build_selection_spec(client_factory,
"visitFolders")
# For getting to hostFolder from datacenter
dc_to_hf = build_traversal_spec(client_factory, "dc_to_hf", "Datacenter",
"hostFolder", False,
[visit_folders_select_spec])
# For getting to vmFolder from datacenter
dc_to_vmf = build_traversal_spec(client_factory, "dc_to_vmf", "Datacenter",
"vmFolder", False,
[visit_folders_select_spec])
# For getting Host System to virtual machine
h_to_vm = build_traversal_spec(client_factory, "h_to_vm", "HostSystem",
"vm", False,
[visit_folders_select_spec])
# For getting to networkfolder from datacenter
dc_to_nwf = build_traversal_spec(client_factory, "dc_to_nwf", "Datacenter",
"networkFolder", False,
[visit_folders_select_spec])
# For getting to Host System from Compute Resource
cr_to_h = build_traversal_spec(client_factory, "cr_to_h",
"ComputeResource", "host", False, [])
# For getting to datastore from Compute Resource
cr_to_ds = build_traversal_spec(client_factory, "cr_to_ds",
"ComputeResource", "datastore", False, [])
rp_to_rp_select_spec = build_selection_spec(client_factory, "rp_to_rp")
rp_to_vm_select_spec = build_selection_spec(client_factory, "rp_to_vm")
# For getting to resource pool from Compute Resource
cr_to_rp = build_traversal_spec(client_factory, "cr_to_rp",
"ComputeResource", "resourcePool", False,
[rp_to_rp_select_spec, rp_to_vm_select_spec])
# For getting to child res pool from the parent res pool
rp_to_rp = build_traversal_spec(client_factory, "rp_to_rp", "ResourcePool",
"resourcePool", False,
[rp_to_rp_select_spec, rp_to_vm_select_spec])
# For getting to Virtual Machine from the Resource Pool
rp_to_vm = build_traversal_spec(client_factory, "rp_to_vm", "ResourcePool",
"vm", False,
[rp_to_rp_select_spec, rp_to_vm_select_spec])
# Get the assorted traversal spec which takes care of the objects to
# be searched for from the root folder
traversal_spec = build_traversal_spec(client_factory, "visitFolders",
"Folder", "childEntity", False,
[visit_folders_select_spec, dc_to_hf,
dc_to_vmf, dc_to_nwf, cr_to_ds, cr_to_h, cr_to_rp,
rp_to_rp, h_to_vm, rp_to_vm])
return traversal_spec
@stumpr Only a propertycollector gives you a update of changes rite? Can I use ContainerView to wait for updates from any VM under a cluster?
@BenN Thanks for your reply. I figured it out some days back. In case some one else stumbles on this, below is the python code which I wrote for creating the traversal spec:
def build_recursive_traversal_spec(client_factory):
#Recurse through all ResourcePools
rp_to_rp = client_factory.create('ns0:TraversalSpec')
rp_to_rp.name = 'rpToRp'
rp_to_rp.type = 'ResourcePool'
rp_to_rp.path = 'resourcePool'
rp_to_rp.skip = False
rp_to_vm = client_factory.create('ns0:TraversalSpec')
rp_to_vm.name = 'rpToVm'
rp_to_vm.type = 'ResourcePool'
rp_to_vm.path = 'vm'
rp_to_vm.skip = False
spec_array_resource_pool = [client_factory.create('ns0:SelectionSpec'),
client_factory.create('ns0:SelectionSpec')]
spec_array_resource_pool[0].name = 'rpToRp'
spec_array_resource_pool[1].name = 'rpToVm'
rp_to_rp.selectSet = spec_array_resource_pool
#Traversal through resource pool branch
cr_to_rp = client_factory.create('ns0:TraversalSpec')
cr_to_rp.name = 'crToRp'
cr_to_rp.type = 'ComputeResource'
cr_to_rp.path = 'resourcePool'
cr_to_rp.skip = False
spec_array_computer_resource = [client_factory.create('ns0:SelectionSpec'),
client_factory.create('ns0:SelectionSpec')]
spec_array_computer_resource[0].name = 'rpToRp'
spec_array_computer_resource[1].name = 'rpToVm'
cr_to_rp.selectSet = spec_array_computer_resource
#Traversal through host branch
cr_to_h = client_factory.create('ns0:TraversalSpec')
cr_to_h.name = 'crToH'
cr_to_h.type = 'ComputeResource'
cr_to_h.path = 'host'
cr_to_h.skip = False
#Traversal through hostFolder branch
dc_to_hf = client_factory.create('ns0:TraversalSpec')
dc_to_hf.name = 'dcToHf'
dc_to_hf.type = 'Datacenter'
dc_to_hf.path = 'hostFolder'
dc_to_hf.skip = False
spec_array_datacenter_host = [client_factory.create('ns0:SelectionSpec')]
spec_array_datacenter_host[0].name = 'visitFolders'
dc_to_hf.selectSet = spec_array_datacenter_host
#Traversal through vmFolder branch
dc_to_vmf = client_factory.create('ns0:TraversalSpec')
dc_to_vmf.name = 'dcToVmf'
dc_to_vmf.type = 'Datacenter'
dc_to_vmf.path = 'vmFolder'
dc_to_vmf.skip = False
spec_array_datacenter_vm = [client_factory.create('ns0:SelectionSpec')]
spec_array_datacenter_vm[0].name = 'visitFolders'
dc_to_vmf.selectSet = spec_array_datacenter_vm
#Traversal through datastore branch
dc_to_ds = client_factory.create('ns0:TraversalSpec')
dc_to_ds.name = 'dcToDs'
dc_to_ds.type = 'Datacenter'
dc_to_ds.path = 'datastore'
dc_to_ds.skip = False
spec_array_datacenter_ds = [client_factory.create('ns0:SelectionSpec')]
spec_array_datacenter_ds[0].name = 'visitFolders'
dc_to_ds.selectSet = spec_array_datacenter_ds
#Recurse through all hosts
h_to_vm = client_factory.create('ns0:TraversalSpec')
h_to_vm.name = 'hToVm'
h_to_vm.type = 'HostSystem'
h_to_vm.path = 'vm'
h_to_vm.skip = False
spec_array_host_vm = [client_factory.create('ns0:SelectionSpec')]
spec_array_host_vm[0].name = 'visitFolders'
h_to_vm.selectSet = spec_array_host_vm
#Recurse through all datastores
ds_to_vm = client_factory.create('ns0:TraversalSpec')
ds_to_vm.name = 'dsToVm'
ds_to_vm.type = 'Datastore'
ds_to_vm.path = 'vm'
ds_to_vm.skip = False
spec_array_datastore_vm = [client_factory.create('ns0:SelectionSpec')]
spec_array_datastore_vm[0].name = 'visitFolders'
ds_to_vm.selectSet = spec_array_datastore_vm
#Recurse through the folders
visit_folders = client_factory.create('ns0:TraversalSpec')
visit_folders.name = 'visitFolders'
visit_folders.type = 'Folder'
visit_folders.path = 'childEntity'
visit_folders.skip = False
spec_array_visit_folders = [client_factory.create('ns0:SelectionSpec'),
client_factory.create('ns0:SelectionSpec'),
client_factory.create('ns0:SelectionSpec'),
client_factory.create('ns0:SelectionSpec'),
client_factory.create('ns0:SelectionSpec'),
client_factory.create('ns0:SelectionSpec'),
client_factory.create('ns0:SelectionSpec'),
client_factory.create('ns0:SelectionSpec'),
client_factory.create('ns0:SelectionSpec')]
spec_array_visit_folders[0].name = 'visitFolders'
spec_array_visit_folders[1].name = 'dcToHf'
spec_array_visit_folders[2].name = 'dcToVmf'
spec_array_visit_folders[3].name = 'crToH'
spec_array_visit_folders[4].name = 'crToRp'
spec_array_visit_folders[5].name = 'dcToDs'
spec_array_visit_folders[6].name = 'hToVm'
spec_array_visit_folders[7].name = 'dsToVm'
spec_array_visit_folders[8].name = 'rpToVm'
visit_folders.selectSet = spec_array_visit_folders
#Add all of them here
spec_array = [visit_folders, dc_to_vmf, dc_to_ds, dc_to_hf, cr_to_h,
cr_to_rp, rp_to_rp, h_to_vm, ds_to_vm, rp_to_vm]
return spec_array
I'd use a ContainerView object, setting the root to the Cluster entity. You won't need your traversal specs in that case, just your property list.
I think there is an example of using Views in the SDK.
@stumpr Only a propertycollector gives you a update of changes rite? Can I use ContainerView to wait for updates from any VM under a cluster?
@BenN Thanks for your reply. I figured it out some days back. In case some one else stumbles on this, below is the python code which I wrote for creating the traversal spec:
def build_recursive_traversal_spec(client_factory):
#Recurse through all ResourcePools
rp_to_rp = client_factory.create('ns0:TraversalSpec')
rp_to_rp.name = 'rpToRp'
rp_to_rp.type = 'ResourcePool'
rp_to_rp.path = 'resourcePool'
rp_to_rp.skip = False
rp_to_vm = client_factory.create('ns0:TraversalSpec')
rp_to_vm.name = 'rpToVm'
rp_to_vm.type = 'ResourcePool'
rp_to_vm.path = 'vm'
rp_to_vm.skip = False
spec_array_resource_pool = [client_factory.create('ns0:SelectionSpec'),
client_factory.create('ns0:SelectionSpec')]
spec_array_resource_pool[0].name = 'rpToRp'
spec_array_resource_pool[1].name = 'rpToVm'
rp_to_rp.selectSet = spec_array_resource_pool
#Traversal through resource pool branch
cr_to_rp = client_factory.create('ns0:TraversalSpec')
cr_to_rp.name = 'crToRp'
cr_to_rp.type = 'ComputeResource'
cr_to_rp.path = 'resourcePool'
cr_to_rp.skip = False
spec_array_computer_resource = [client_factory.create('ns0:SelectionSpec'),
client_factory.create('ns0:SelectionSpec')]
spec_array_computer_resource[0].name = 'rpToRp'
spec_array_computer_resource[1].name = 'rpToVm'
cr_to_rp.selectSet = spec_array_computer_resource
#Traversal through host branch
cr_to_h = client_factory.create('ns0:TraversalSpec')
cr_to_h.name = 'crToH'
cr_to_h.type = 'ComputeResource'
cr_to_h.path = 'host'
cr_to_h.skip = False
#Traversal through hostFolder branch
dc_to_hf = client_factory.create('ns0:TraversalSpec')
dc_to_hf.name = 'dcToHf'
dc_to_hf.type = 'Datacenter'
dc_to_hf.path = 'hostFolder'
dc_to_hf.skip = False
spec_array_datacenter_host = [client_factory.create('ns0:SelectionSpec')]
spec_array_datacenter_host[0].name = 'visitFolders'
dc_to_hf.selectSet = spec_array_datacenter_host
#Traversal through vmFolder branch
dc_to_vmf = client_factory.create('ns0:TraversalSpec')
dc_to_vmf.name = 'dcToVmf'
dc_to_vmf.type = 'Datacenter'
dc_to_vmf.path = 'vmFolder'
dc_to_vmf.skip = False
spec_array_datacenter_vm = [client_factory.create('ns0:SelectionSpec')]
spec_array_datacenter_vm[0].name = 'visitFolders'
dc_to_vmf.selectSet = spec_array_datacenter_vm
#Traversal through datastore branch
dc_to_ds = client_factory.create('ns0:TraversalSpec')
dc_to_ds.name = 'dcToDs'
dc_to_ds.type = 'Datacenter'
dc_to_ds.path = 'datastore'
dc_to_ds.skip = False
spec_array_datacenter_ds = [client_factory.create('ns0:SelectionSpec')]
spec_array_datacenter_ds[0].name = 'visitFolders'
dc_to_ds.selectSet = spec_array_datacenter_ds
#Recurse through all hosts
h_to_vm = client_factory.create('ns0:TraversalSpec')
h_to_vm.name = 'hToVm'
h_to_vm.type = 'HostSystem'
h_to_vm.path = 'vm'
h_to_vm.skip = False
spec_array_host_vm = [client_factory.create('ns0:SelectionSpec')]
spec_array_host_vm[0].name = 'visitFolders'
h_to_vm.selectSet = spec_array_host_vm
#Recurse through all datastores
ds_to_vm = client_factory.create('ns0:TraversalSpec')
ds_to_vm.name = 'dsToVm'
ds_to_vm.type = 'Datastore'
ds_to_vm.path = 'vm'
ds_to_vm.skip = False
spec_array_datastore_vm = [client_factory.create('ns0:SelectionSpec')]
spec_array_datastore_vm[0].name = 'visitFolders'
ds_to_vm.selectSet = spec_array_datastore_vm
#Recurse through the folders
visit_folders = client_factory.create('ns0:TraversalSpec')
visit_folders.name = 'visitFolders'
visit_folders.type = 'Folder'
visit_folders.path = 'childEntity'
visit_folders.skip = False
spec_array_visit_folders = [client_factory.create('ns0:SelectionSpec'),
client_factory.create('ns0:SelectionSpec'),
client_factory.create('ns0:SelectionSpec'),
client_factory.create('ns0:SelectionSpec'),
client_factory.create('ns0:SelectionSpec'),
client_factory.create('ns0:SelectionSpec'),
client_factory.create('ns0:SelectionSpec'),
client_factory.create('ns0:SelectionSpec'),
client_factory.create('ns0:SelectionSpec')]
spec_array_visit_folders[0].name = 'visitFolders'
spec_array_visit_folders[1].name = 'dcToHf'
spec_array_visit_folders[2].name = 'dcToVmf'
spec_array_visit_folders[3].name = 'crToH'
spec_array_visit_folders[4].name = 'crToRp'
spec_array_visit_folders[5].name = 'dcToDs'
spec_array_visit_folders[6].name = 'hToVm'
spec_array_visit_folders[7].name = 'dsToVm'
spec_array_visit_folders[8].name = 'rpToVm'
visit_folders.selectSet = spec_array_visit_folders
#Add all of them here
spec_array = [visit_folders, dc_to_vmf, dc_to_ds, dc_to_hf, cr_to_h,
cr_to_rp, rp_to_rp, h_to_vm, ds_to_vm, rp_to_vm]
return spec_array
Perl example, but shouldn't be too hard to convert. Not sure which Python kit your using and if they exposed all the SDK objects.
#!/usr/bin/perl
use strict;
use warnings;
use VMware::VIRuntime;
my %opts = (
clustername => {
type => "=s",
variable => "CLUSTERNAME",
help => "Name of cluster entity",
required => 1,
}
);
Opts::add_options(%opts);
Opts::parse();
Opts::validate();
Util::connect();
my ($cluster_name, $cluster_view, $view_manager, $container_view, $moref, $version,
$property_collector, $property_spec, $filter_spec, $traversal_spec, $update_set,
$object_spec, $filter );
$cluster_name = Opts::get_option('clustername');
$cluster_view = Vim::find_entity_view(view_type => 'ClusterComputeResource',
filter => { 'name' => $cluster_name },
properties => [ 'name' ] );
die "Failed to find cluster '$cluster_name' in inventory" unless $cluster_name;
# View Manager
$view_manager = Vim::get_view( mo_ref => Vim::get_service_content->viewManager );
die "Failed to retrieve View Manager" unless $view_manager;
# Create Container View
$moref = $view_manager->CreateContainerView(
container => $cluster_view, # Container starting point in inventory tree
recursive => 1, # Recurse through folders, resource pools, etc.
type => [ 'VirtualMachine' ], # Add additional entity types if required
);
$container_view = Vim::get_view( mo_ref => $moref );
# Get default session property collector
$property_collector = Vim::get_view( mo_ref => Vim::get_service_content->propertyCollector );
die "Failed to retrieve session Property Collector" unless $property_collector;
# What vm properties do you want to monitor? Guessing 'all', though that may be too much
# noise depending on your needs.
# PropertySpec - VirtualMachines
$property_spec = new PropertySpec(all => 1, type => 'VirtualMachine');
# TraversalSpec is the ContainerView, which already has captured a set of VMs. For the
# type, use the moref type of the container_view (here, moref->{type} or use
# $container_view->{mo_ref}->{type}
$traversal_spec = new TraversalSpec(type => $moref->{'type'},
path => 'view' );
# ObjectSpec
$object_spec = new ObjectSpec(obj => $container_view,
selectSet => [ $traversal_spec ],
skip => 1 );
# Create a PropertyFilterSpec. In this case, will make your selectSet the view container
# traversal spec.
$filter_spec = new PropertyFilterSpec(
objectSet => [ $object_spec ],
propSet => [ $property_spec ],
reportMissingObjectsInResults => 1 );
# Now create a filter. Depending on your logic, you'll want partialUpdates = 1 or 0.
# For now, will assume 1, which means you will get a full VM update vs partial when any
# vm property is modified.
$filter = $property_collector->CreateFilter(spec => $filter_spec, partialUpdates => 0);
# Loop, waiting for changes
print "Entering update wait loop...\n";
$version = ''; # Initial version should be empty string
while (1) {
$update_set = $property_collector->WaitForUpdatesEx(version => $version);
if (defined $update_set) {
print "Updates found!\n";
# Here you would iterate the filterSet and objectSet lists, getting the obj (moref)
# and update changeSet + kind.
$version = $update_set->{version}; # Get new version string
}
}
Util::disconnect();
BEGIN {
$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0;
}
Sample run:
perl clustervms.pl --clustername=DC0_C0 --username=administrator@vlab --password=VMware1! --server=172.16.254.71
Entering update wait loop...
Updates found!
Updates found!
Updates found!
Updates found!
Updates found!
Updates found!
Updates found!
I'm using a VCSIM setup, which does some random activity to generate changes. I didn't delve into the loops to parse the UpdateSet data, but I've done so before. Requires some logic to evaluate the changes in detail. But if you just want to know a VM changed (but not what), you can just get the obj moref from the updateSet.