From e331287cdd1300878bfb9bbb3630889370e5fa72 Mon Sep 17 00:00:00 2001 From: Gary Kotton Date: Tue, 9 Jul 2013 23:55:32 -0700 Subject: [PATCH] Use RetrievePropertiesEx instead of RetrieveProperties Fixes bug 1183654 The fix also adds a configuration variable enabling the user to configure the maximum amount of objects that can be retrieved by the aforementioned function. When using RetrievePropertiesEx the server may allocate resources in case additional calls are made. These are addressed by reading the extra resources using ContinueRetrievePropertiesEx (if necessary) or CancelRetrievePropertiesEx (when the necessary result has been found). DocImpact Change-Id: I894d9698461b0ce22b01211fd196f6c32899a8fd --- etc/nova/nova.conf.sample | 14 ++ nova/tests/virt/vmwareapi/test_vmwareapi.py | 6 +- .../virt/vmwareapi/test_vmwareapi_vm_util.py | 33 +++-- nova/virt/vmwareapi/error_util.py | 4 +- nova/virt/vmwareapi/fake.py | 45 ++++-- nova/virt/vmwareapi/host.py | 9 +- nova/virt/vmwareapi/vim_util.py | 55 +++++++- nova/virt/vmwareapi/vm_util.py | 129 +++++++++++++----- nova/virt/vmwareapi/vmops.py | 114 +++++++++------- 9 files changed, 288 insertions(+), 121 deletions(-) diff --git a/etc/nova/nova.conf.sample b/etc/nova/nova.conf.sample index 9a760cf3a63e..50f36d5f7d7a 100644 --- a/etc/nova/nova.conf.sample +++ b/etc/nova/nova.conf.sample @@ -3118,6 +3118,20 @@ #wsdl_location= +# +# Options defined in nova.virt.vmwareapi.vim_util +# + +# The maximum number of ObjectContent data objects that should +# be returned in a single result. A positive value will cause +# the operation to suspend the retrieval when the count of +# objects reaches the specified maximum. The server may still +# limit the count to something less than the configured value. +# Any remaining objects may be retrieved with additional +# requests. (integer value) +#maximum_objects=100 + + # # Options defined in nova.virt.vmwareapi.vmops # diff --git a/nova/tests/virt/vmwareapi/test_vmwareapi.py b/nova/tests/virt/vmwareapi/test_vmwareapi.py index af3f83536f4b..1ee1b64168d0 100644 --- a/nova/tests/virt/vmwareapi/test_vmwareapi.py +++ b/nova/tests/virt/vmwareapi/test_vmwareapi.py @@ -175,7 +175,7 @@ class VMwareAPIVMTestCase(test.TestCase): # Get record for VM vms = vmwareapi_fake._get_objects("VirtualMachine") - vm = vms[0] + vm = vms.objects[0] # Check that m1.large above turned into the right thing. mem_kib = long(self.type_data['memory_mb']) << 10 @@ -521,10 +521,10 @@ class VMwareAPIVMTestCase(test.TestCase): def fake_get_vm_ref_from_name(session, vm_name): self.assertEquals(self.vm_name, vm_name) - return vmwareapi_fake._get_objects("VirtualMachine")[0] + return vmwareapi_fake._get_objects("VirtualMachine").objects[0] def fake_get_vm_ref_from_uuid(session, vm_uuid): - return vmwareapi_fake._get_objects("VirtualMachine")[0] + return vmwareapi_fake._get_objects("VirtualMachine").objects[0] def fake_call_method(*args, **kwargs): pass diff --git a/nova/tests/virt/vmwareapi/test_vmwareapi_vm_util.py b/nova/tests/virt/vmwareapi/test_vmwareapi_vm_util.py index 0456dfecec75..df08ea28d644 100644 --- a/nova/tests/virt/vmwareapi/test_vmwareapi_vm_util.py +++ b/nova/tests/virt/vmwareapi/test_vmwareapi_vm_util.py @@ -42,8 +42,10 @@ class VMwareVMUtilTestCase(test.TestCase): fake.reset() def test_get_datastore_ref_and_name(self): + fake_objects = fake.FakeRetrieveResult() + fake_objects.add_object(fake.Datastore()) result = vm_util.get_datastore_ref_and_name( - fake_session([fake.Datastore()])) + fake_session(fake_objects)) self.assertEquals(result[1], "fake-ds") self.assertEquals(result[2], 1024 * 1024 * 1024 * 1024) @@ -66,9 +68,10 @@ class VMwareVMUtilTestCase(test.TestCase): fake_host_id = fake_host_sys.obj.value fake_host_name = "ha-host" - + fake_objects = fake.FakeRetrieveResult() + fake_objects.add_object(fake_host_sys) ref = vm_util.get_host_ref_from_id( - fake_session([fake_host_sys]), fake_host_id, ['name']) + fake_session(fake_objects), fake_host_id, ['name']) self.assertIsInstance(ref, fake.HostSystem) self.assertEqual(fake_host_id, ref.obj.value) @@ -84,9 +87,11 @@ class VMwareVMUtilTestCase(test.TestCase): "vm-123", "VirtualMachine")) fake_vm.propSet.append( fake.Property('name', 'vm-123')) + fake_objects = fake.FakeRetrieveResult() + fake_objects.add_object(fake_vm) vm_ref = vm_util.get_vm_ref_from_name( - fake_session([fake_vm]), 'vm-123') + fake_session(fake_objects), 'vm-123') self.assertIsNotNone(vm_ref) @@ -98,8 +103,12 @@ class VMwareVMUtilTestCase(test.TestCase): 'host-123', 'HostSystem')) ])] + fake_objects = fake.FakeRetrieveResult() + for results in fake_results: + fake_objects.add_object(results) + host_id = vm_util.get_host_id_from_vm_ref( - fake_session(fake_results), vm_ref) + fake_session(fake_objects), vm_ref) self.assertEqual('host-123', host_id) @@ -109,6 +118,7 @@ class VMwareVMUtilTestCase(test.TestCase): DynamicProperty = namedtuple('Property', ['name', 'val']) MoRef = namedtuple('Val', ['value']) + good_objects = fake.FakeRetrieveResult() results_good = [ ObjectContent(propSet=[ DynamicProperty(name='name', val=MoRef(value='vm-123'))]), @@ -121,7 +131,10 @@ class VMwareVMUtilTestCase(test.TestCase): ObjectContent(propSet=[ DynamicProperty( name='something', val=MoRef(value='thing'))]), ] + for result in results_good: + good_objects.add_object(result) + bad_objects = fake.FakeRetrieveResult() results_bad = [ ObjectContent(propSet=[ DynamicProperty(name='name', val=MoRef(value='vm-123'))]), @@ -131,22 +144,24 @@ class VMwareVMUtilTestCase(test.TestCase): ObjectContent(propSet=[ DynamicProperty( name='something', val=MoRef(value='thing'))]), ] + for result in results_bad: + bad_objects.add_object(result) prop = vm_util.property_from_property_set( - 'runtime.host', results_good) + 'runtime.host', good_objects) self.assertIsNotNone(prop) value = prop.val.value self.assertEqual('host-123', value) prop2 = vm_util.property_from_property_set( - 'runtime.host', results_bad) + 'runtime.host', bad_objects) self.assertIsNone(prop2) - prop3 = vm_util.property_from_property_set('foo', results_good) + prop3 = vm_util.property_from_property_set('foo', good_objects) self.assertIsNotNone(prop3) val3 = prop3.val.value self.assertEqual('bar1', val3) - prop4 = vm_util.property_from_property_set('foo', results_bad) + prop4 = vm_util.property_from_property_set('foo', bad_objects) self.assertIsNotNone(prop4) self.assertEqual('bar1', prop4.val) diff --git a/nova/virt/vmwareapi/error_util.py b/nova/virt/vmwareapi/error_util.py index 9527c51d1509..47655cd221ce 100644 --- a/nova/virt/vmwareapi/error_util.py +++ b/nova/virt/vmwareapi/error_util.py @@ -67,7 +67,7 @@ class FaultCheckers(object): @staticmethod def retrieveproperties_fault_checker(resp_obj): """ - Checks the RetrieveProperties response for errors. Certain faults + Checks the RetrievePropertiesEx response for errors. Certain faults are sent as part of the SOAP body as property of missingSet. For example NotAuthenticated fault. """ @@ -91,5 +91,5 @@ class FaultCheckers(object): if fault_list: exc_msg_list = ', '.join(fault_list) raise VimFaultException(fault_list, Exception(_("Error(s) %s " - "occurred in the call to RetrieveProperties") % + "occurred in the call to RetrievePropertiesEx") % exc_msg_list)) diff --git a/nova/virt/vmwareapi/fake.py b/nova/virt/vmwareapi/fake.py index 21d50fb78460..98172e0da597 100644 --- a/nova/virt/vmwareapi/fake.py +++ b/nova/virt/vmwareapi/fake.py @@ -77,12 +77,22 @@ def _create_object(table, table_obj): def _get_objects(obj_type): """Get objects of the type.""" - lst_objs = [] + lst_objs = FakeRetrieveResult() for key in _db_content[obj_type]: - lst_objs.append(_db_content[obj_type][key]) + lst_objs.add_object(_db_content[obj_type][key]) return lst_objs +class FakeRetrieveResult(object): + """Object to retrieve a ObjectContent list.""" + + def __init__(self): + self.objects = [] + + def add_object(self, object): + self.objects.append(object) + + class Property(object): """Property Object base class.""" @@ -317,16 +327,19 @@ class ClusterComputeResource(ManagedObject): super(ClusterComputeResource, self).__init__("ClusterComputeResource", value="domain-test") r_pool = DataObject() - r_pool.ManagedObjectReference = [_get_objects("ResourcePool")[0].obj] + obj = _get_objects("ResourcePool").objects[0].obj + r_pool.ManagedObjectReference = [obj] self.set("resourcePool", r_pool) host_sys = DataObject() - host_sys.ManagedObjectReference = [_get_objects("HostSystem")[0].obj] + obj = _get_objects("HostSystem").objects[0].obj + host_sys.ManagedObjectReference = [obj] self.set("host", host_sys) self.set("name", "test_cluster") datastore = DataObject() - datastore.ManagedObjectReference = [_get_objects("Datastore")[0].obj] + obj = _get_objects("Datastore").objects[0].obj + datastore.ManagedObjectReference = [obj] self.set("datastore", datastore) @@ -773,6 +786,14 @@ class FakeVim(object): task_mdo = create_task(method, "success") return task_mdo.obj + def _retrieve_properties_continue(self, method, *args, **kwargs): + """Continues the retrieve.""" + return FakeRetrieveResult() + + def _retrieve_properties_cancel(self, method, *args, **kwargs): + """Cancels the retrieve.""" + return None + def _retrieve_properties(self, method, *args, **kwargs): """Retrieves properties based on the type.""" spec_set = kwargs.get("specSet")[0] @@ -781,7 +802,7 @@ class FakeVim(object): if not isinstance(properties, list): properties = properties.split() objs = spec_set.objectSet - lst_ret_objs = [] + lst_ret_objs = FakeRetrieveResult() for obj in objs: try: obj_ref = obj.obj @@ -797,14 +818,14 @@ class FakeVim(object): temp_mdo = ManagedObject(mdo.objName, mdo.obj) for prop in properties: temp_mdo.set(prop, mdo.get(prop)) - lst_ret_objs.append(temp_mdo) + lst_ret_objs.add_object(temp_mdo) else: if obj_ref in _db_content[type]: mdo = _db_content[type][obj_ref] temp_mdo = ManagedObject(mdo.objName, obj_ref) for prop in properties: temp_mdo.set(prop, mdo.get(prop)) - lst_ret_objs.append(temp_mdo) + lst_ret_objs.add_object(temp_mdo) except Exception as exc: LOG.exception(exc) continue @@ -872,9 +893,15 @@ class FakeVim(object): elif attr_name == "MakeDirectory": return lambda *args, **kwargs: self._make_dir(attr_name, *args, **kwargs) - elif attr_name == "RetrieveProperties": + elif attr_name == "RetrievePropertiesEx": return lambda *args, **kwargs: self._retrieve_properties( attr_name, *args, **kwargs) + elif attr_name == "ContinueRetrievePropertiesEx": + return lambda *args, **kwargs: self._retrieve_properties_continue( + attr_name, *args, **kwargs) + elif attr_name == "CancelRetrievePropertiesEx": + return lambda *args, **kwargs: self._retrieve_properties_cancel( + attr_name, *args, **kwargs) elif attr_name == "AcquireCloneTicket": return lambda *args, **kwargs: self._just_return() elif attr_name == "AddPortGroup": diff --git a/nova/virt/vmwareapi/host.py b/nova/virt/vmwareapi/host.py index 4bba8f9f0d0b..3521ead4694b 100644 --- a/nova/virt/vmwareapi/host.py +++ b/nova/virt/vmwareapi/host.py @@ -35,8 +35,7 @@ class Host(object): def host_power_action(self, host, action): """Reboots or shuts down the host.""" - host_mor = self._session._call_method(vim_util, "get_objects", - "HostSystem")[0].obj + host_mor = vm_util.get_host_ref(self._session) LOG.debug(_("%(action)s %(host)s"), {'action': action, 'host': host}) if action == "reboot": host_task = self._session._call_method( @@ -59,8 +58,7 @@ class Host(object): """Start/Stop host maintenance window. On start, it triggers guest VMs evacuation. """ - host_mor = self._session._call_method(vim_util, "get_objects", - "HostSystem")[0].obj + host_mor = vm_util.get_host_ref(self._session) LOG.debug(_("Set maintenance mod on %(host)s to %(mode)s"), {'host': host, 'mode': mode}) if mode: @@ -103,8 +101,7 @@ class HostState(object): def update_status(self): """Update the current state of the host. """ - host_mor = self._session._call_method(vim_util, "get_objects", - "HostSystem")[0].obj + host_mor = vm_util.get_host_ref(self._session) summary = self._session._call_method(vim_util, "get_dynamic_property", host_mor, diff --git a/nova/virt/vmwareapi/vim_util.py b/nova/virt/vmwareapi/vim_util.py index e131e007d77f..885b19999db4 100644 --- a/nova/virt/vmwareapi/vim_util.py +++ b/nova/virt/vmwareapi/vim_util.py @@ -19,6 +19,22 @@ The VMware API utility module. """ +from oslo.config import cfg + + +vmware_opts = cfg.IntOpt('maximum_objects', default=100, + help='The maximum number of ObjectContent data ' + 'objects that should be returned in a single ' + 'result. A positive value will cause the ' + 'operation to suspend the retrieval when the ' + 'count of objects reaches the specified ' + 'maximum. The server may still limit the count ' + 'to something less than the configured value. ' + 'Any remaining objects may be retrieved with ' + 'additional requests.') +CONF = cfg.CONF +CONF.register_opt(vmware_opts, 'vmware') + def build_selection_spec(client_factory, name): """Builds the selection spec.""" @@ -143,15 +159,20 @@ def get_object_properties(vim, collector, mobj, type, properties): object_spec.skip = False property_filter_spec.propSet = [property_spec] property_filter_spec.objectSet = [object_spec] - return vim.RetrieveProperties(usecoll, specSet=[property_filter_spec]) + options = client_factory.create('ns0:RetrieveOptions') + options.maxObjects = CONF.vmware.maximum_objects + return vim.RetrievePropertiesEx(usecoll, specSet=[property_filter_spec], + options=options) def get_dynamic_property(vim, mobj, type, property_name): """Gets a particular property of the Managed Object.""" obj_content = get_object_properties(vim, None, mobj, type, [property_name]) + if hasattr(obj_content, 'token'): + vim.CancelRetrievePropertiesEx(token=obj_content.token) property_value = None - if obj_content: - dynamic_property = obj_content[0].propSet + if obj_content.objects: + dynamic_property = obj_content.objects[0].propSet if dynamic_property: property_value = dynamic_property[0].val return property_value @@ -172,8 +193,25 @@ def get_objects(vim, type, properties_to_collect=None, all=False): property_filter_spec = build_property_filter_spec(client_factory, [property_spec], [object_spec]) - return vim.RetrieveProperties(vim.get_service_content().propertyCollector, - specSet=[property_filter_spec]) + options = client_factory.create('ns0:RetrieveOptions') + options.maxObjects = CONF.vmware.maximum_objects + return vim.RetrievePropertiesEx( + vim.get_service_content().propertyCollector, + specSet=[property_filter_spec], options=options) + + +def cancel_retrieve(vim, token): + """Cancels the retrieve operation.""" + return vim.CancelRetrievePropertiesEx( + vim.get_service_content().propertyCollector, + token=token) + + +def continue_to_get_objects(vim, token): + """Continues to get the list of objects of the type specified.""" + return vim.ContinueRetrievePropertiesEx( + vim.get_service_content().propertyCollector, + token=token) def get_prop_spec(client_factory, spec_type, properties): @@ -217,5 +255,8 @@ def get_properties_for_a_collection_of_objects(vim, type, lst_obj_specs.append(get_obj_spec(client_factory, obj)) prop_filter_spec = get_prop_filter_spec(client_factory, lst_obj_specs, [prop_spec]) - return vim.RetrieveProperties(vim.get_service_content().propertyCollector, - specSet=[prop_filter_spec]) + options = client_factory.create('ns0:RetrieveOptions') + options.maxObjects = CONF.vmware.maximum_objects + return vim.RetrievePropertiesEx( + vim.get_service_content().propertyCollector, + specSet=[prop_filter_spec], options=options) diff --git a/nova/virt/vmwareapi/vm_util.py b/nova/virt/vmwareapi/vm_util.py index 3996189d9293..d9e40f1f62f0 100644 --- a/nova/virt/vmwareapi/vm_util.py +++ b/nova/virt/vmwareapi/vm_util.py @@ -498,23 +498,64 @@ def search_datastore_spec(client_factory, file_name): return search_spec +def _get_token(results): + """Get the token from the property results.""" + return getattr(results, 'token', None) + + +def _get_reference_for_value(results, value): + for object in results.objects: + if object.obj.value == value: + return object + + +def _get_object_for_value(results, value): + for object in results.objects: + if object.propSet[0].val == value: + return object.obj + + +def _get_object_from_results(session, results, value, func): + while results: + token = _get_token(results) + object = func(results, value) + if object: + if token: + session._call_method(vim_util, + "cancel_retrieve", + token) + return object + + if token: + results = session._call_method(vim_util, + "continue_to_get_objects", + token) + else: + return None + + +def _cancel_retrieve_if_necessary(session, results): + token = _get_token(results) + if token: + results = session._call_method(vim_util, + "cancel_retrieve", + token) + + def get_vm_ref_from_name(session, vm_name): """Get reference to the VM with the name specified.""" vms = session._call_method(vim_util, "get_objects", "VirtualMachine", ["name"]) - for vm in vms: - if vm.propSet[0].val == vm_name: - return vm.obj - return None + return _get_object_from_results(session, vms, vm_name, + _get_object_for_value) def get_vm_ref_from_uuid(session, instance_uuid): """Get reference to the VM with the uuid specified.""" vms = session._call_method(vim_util, "get_objects", "VirtualMachine", ["name"]) - for vm in vms: - if vm.propSet[0].val == instance_uuid: - return vm.obj + return _get_object_from_results(session, vms, instance_uuid, + _get_object_for_value) def get_vm_ref(session, instance): @@ -536,10 +577,8 @@ def get_host_ref_from_id(session, host_id, property_list=None): host_refs = session._call_method( vim_util, "get_objects", "HostSystem", property_list) - - for ref in host_refs: - if ref.obj.value == host_id: - return ref + return _get_object_from_results(session, host_refs, host_id, + _get_reference_for_value) def get_host_id_from_vm_ref(session, vm_ref): @@ -600,7 +639,7 @@ def property_from_property_set(property_name, property_set): :return: the value of the property. ''' - for prop in property_set: + for prop in property_set.objects: p = _property_from_propSet(prop.propSet, property_name) if p is not None: return p @@ -643,17 +682,17 @@ def get_cluster_ref_from_name(session, cluster_name): """Get reference to the cluster with the name specified.""" cls = session._call_method(vim_util, "get_objects", "ClusterComputeResource", ["name"]) - for cluster in cls: - if cluster.propSet[0].val == cluster_name: - return cluster.obj - return None + return _get_object_from_results(session, cls, cluster_name, + _get_object_for_value) def get_host_ref(session, cluster=None): """Get reference to a host within the cluster specified.""" if cluster is None: - host_mor = session._call_method(vim_util, "get_objects", - "HostSystem")[0].obj + results = session._call_method(vim_util, "get_objects", + "HostSystem") + _cancel_retrieve_if_necessary(session, results) + host_mor = results.objects[0].obj else: host_ret = session._call_method(vim_util, "get_dynamic_property", cluster, "ClusterComputeResource", @@ -667,6 +706,26 @@ def get_host_ref(session, cluster=None): return host_mor +def _get_datastore_ref_and_name(data_stores): + for elem in data_stores.objects: + ds_name = None + ds_type = None + ds_cap = None + ds_free = None + for prop in elem.propSet: + if prop.name == "summary.type": + ds_type = prop.val + elif prop.name == "summary.name": + ds_name = prop.val + elif prop.name == "summary.capacity": + ds_cap = prop.val + elif prop.name == "summary.freeSpace": + ds_free = prop.val + # Local storage identifier + if ds_type == "VMFS" or ds_type == "NFS": + return elem.obj, ds_name, ds_cap, ds_free + + def get_datastore_ref_and_name(session, cluster=None, host=None): """Get the datastore list and choose the first local storage.""" if cluster is None and host is None: @@ -693,22 +752,20 @@ def get_datastore_ref_and_name(session, cluster=None, host=None): "Datastore", data_store_mors, ["summary.type", "summary.name", "summary.capacity", "summary.freeSpace"]) - for elem in data_stores: - ds_name = None - ds_type = None - ds_cap = None - ds_free = None - for prop in elem.propSet: - if prop.name == "summary.type": - ds_type = prop.val - elif prop.name == "summary.name": - ds_name = prop.val - elif prop.name == "summary.capacity": - ds_cap = prop.val - elif prop.name == "summary.freeSpace": - ds_free = prop.val - # Local storage identifier - if ds_type == "VMFS" or ds_type == "NFS": - return elem.obj, ds_name, ds_cap, ds_free - raise exception.DatastoreNotFound() + while data_stores: + token = _get_token(data_stores) + results = _get_datastore_ref_and_name(data_stores) + if results: + if token: + session._call_method(vim_util, + "cancel_retrieve", + token) + return results + if token: + data_stores = session._call_method(vim_util, + "continue_to_get_objects", + token) + else: + raise exception.DatastoreNotFound() + raise exception.DatastoreNotFound() diff --git a/nova/virt/vmwareapi/vmops.py b/nova/virt/vmwareapi/vmops.py index d7e37a4fbc68..4ba9cbd80f4e 100644 --- a/nova/virt/vmwareapi/vmops.py +++ b/nova/virt/vmwareapi/vmops.py @@ -94,17 +94,27 @@ class VMwareVMOps(object): "VirtualMachine", ["name", "runtime.connectionState"]) lst_vm_names = [] - for vm in vms: - vm_name = None - conn_state = None - for prop in vm.propSet: - if prop.name == "name": - vm_name = prop.val - elif prop.name == "runtime.connectionState": - conn_state = prop.val - # Ignoring the orphaned or inaccessible VMs - if conn_state not in ["orphaned", "inaccessible"]: - lst_vm_names.append(vm_name) + + while vms: + token = vm_util._get_token(vms) + for vm in vms.objects: + vm_name = None + conn_state = None + for prop in vm.propSet: + if prop.name == "name": + vm_name = prop.val + elif prop.name == "runtime.connectionState": + conn_state = prop.val + # Ignoring the orphaned or inaccessible VMs + if conn_state not in ["orphaned", "inaccessible"]: + lst_vm_names.append(vm_name) + if token: + vms = self._session._call_method(vim_util, + "continue_to_get_objects", + token) + else: + break + LOG.debug(_("Got total of %s instances") % str(len(lst_vm_names))) return lst_vm_names @@ -579,6 +589,22 @@ class VMwareVMOps(object): _clean_temp_data() + def _get_values_from_object_properties(self, props, query): + while props: + token = vm_util._get_token(props) + for elem in props.objects: + for prop in elem.propSet: + for key in query.keys(): + if prop.name == key: + query[key] = prop.val + break + if token: + props = self._session._call_method(vim_util, + "continue_to_get_objects", + token) + else: + break + def reboot(self, instance, network_info): """Reboot a VM instance.""" vm_ref = vm_util.get_vm_ref(self._session, instance) @@ -589,17 +615,13 @@ class VMwareVMOps(object): props = self._session._call_method(vim_util, "get_object_properties", None, vm_ref, "VirtualMachine", lst_properties) - pwr_state = None - tools_status = None - tools_running_status = False - for elem in props: - for prop in elem.propSet: - if prop.name == "runtime.powerState": - pwr_state = prop.val - elif prop.name == "summary.guest.toolsStatus": - tools_status = prop.val - elif prop.name == "summary.guest.toolsRunningStatus": - tools_running_status = prop.val + query = {'runtime.powerState': None, + 'summary.guest.toolsStatus': None, + 'summary.guest.toolsRunningStatus': False} + self._get_values_from_object_properties(props, query) + pwr_state = query['runtime.powerState'] + tools_status = query['summary.guest.toolsStatus'] + tools_running_status = query['summary.guest.toolsRunningStatus'] # Raise an exception if the VM is not powered On. if pwr_state not in ["poweredOn"]: @@ -659,14 +681,11 @@ class VMwareVMOps(object): props = self._session._call_method(vim_util, "get_object_properties", None, vm_ref, "VirtualMachine", lst_properties) - pwr_state = None - for elem in props: - vm_config_pathname = None - for prop in elem.propSet: - if prop.name == "runtime.powerState": - pwr_state = prop.val - elif prop.name == "config.files.vmPathName": - vm_config_pathname = prop.val + query = {'runtime.powerState': None, + 'config.files.vmPathName': None} + self._get_values_from_object_properties(props, query) + pwr_state = query['runtime.powerState'] + vm_config_pathname = query['config.files.vmPathName'] if vm_config_pathname: _ds_path = vm_util.split_datastore_path(vm_config_pathname) datastore_name, vmx_file_path = _ds_path @@ -1039,23 +1058,15 @@ class VMwareVMOps(object): vm_props = self._session._call_method(vim_util, "get_object_properties", None, vm_ref, "VirtualMachine", lst_properties) - max_mem = None - pwr_state = None - num_cpu = None - for elem in vm_props: - for prop in elem.propSet: - if prop.name == "summary.config.numCpu": - num_cpu = int(prop.val) - elif prop.name == "summary.config.memorySizeMB": - # In MB, but we want in KB - max_mem = int(prop.val) * 1024 - elif prop.name == "runtime.powerState": - pwr_state = VMWARE_POWER_STATES[prop.val] - - return {'state': pwr_state, + query = {'summary.config.numCpu': None, + 'summary.config.memorySizeMB': None, + 'runtime.powerState': None} + self._get_values_from_object_properties(vm_props, query) + max_mem = int(query['summary.config.memorySizeMB']) * 1024 + return {'state': VMWARE_POWER_STATES[query['runtime.powerState']], 'max_mem': max_mem, 'mem': max_mem, - 'num_cpu': num_cpu, + 'num_cpu': int(query['summary.config.numCpu']), 'cpu_time': 0} def get_diagnostics(self, instance): @@ -1190,12 +1201,14 @@ class VMwareVMOps(object): """Get the datacenter name and the reference.""" dc_obj = self._session._call_method(vim_util, "get_objects", "Datacenter", ["name"]) - return dc_obj[0].obj, dc_obj[0].propSet[0].val + vm_util._cancel_retrieve_if_necessary(self._session, dc_obj) + return dc_obj.objects[0].obj, dc_obj.objects[0].propSet[0].val def _get_host_ref_from_name(self, host_name): """Get reference to the host with the name specified.""" host_objs = self._session._call_method(vim_util, "get_objects", "HostSystem", ["name"]) + vm_util._cancel_retrieve_if_necessary(self._session, host_objs) for host in host_objs: if host.propSet[0].val == host_name: return host.obj @@ -1205,16 +1218,19 @@ class VMwareVMOps(object): """Get the Vm folder ref from the datacenter.""" dc_objs = self._session._call_method(vim_util, "get_objects", "Datacenter", ["vmFolder"]) + vm_util._cancel_retrieve_if_necessary(self._session, dc_objs) # There is only one default datacenter in a standalone ESX host - vm_folder_ref = dc_objs[0].propSet[0].val + vm_folder_ref = dc_objs.objects[0].propSet[0].val return vm_folder_ref def _get_res_pool_ref(self): # Get the resource pool. Taking the first resource pool coming our # way. Assuming that is the default resource pool. if self._cluster is None: - res_pool_ref = self._session._call_method(vim_util, "get_objects", - "ResourcePool")[0].obj + results = self._session._call_method(vim_util, "get_objects", + "ResourcePool") + vm_util._cancel_retrieve_if_necessary(self._session, results) + res_pool_ref = results.objects[0].obj else: res_pool_ref = self._session._call_method(vim_util, "get_dynamic_property",