summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVipin Balachandran <vbala@vmware.com>2014-02-19 11:43:50 +0530
committerDavanum Srinivas <dims@linux.vnet.ibm.com>2014-02-20 07:39:08 -0500
commitf1b8a91961a8601d5356b76d2ad93a56f4fbb93a (patch)
treea21088c2a5387e8f324d5f0fb9cd20ad07ee3abb
parentd1a383c25ba4e0c1dd31fd12c04bc3a875045b79 (diff)
downloadoslo-vmware-f1b8a91961a8601d5356b76d2ad93a56f4fbb93a.tar.gz
Move utility methods in VMware drivers to OSLO
There is lot of common code between VMware drivers for nova and cinder; for e.g., session management and VIM API invocation code. The new VMware driver for glance and the telemetry agent for vSphere are also planning to use this common code. This change moves the utility methods for inventory traversal spec creation, managed object property retrieval etc. defined in various drivers into OSLO. Change-Id: Ibdd80188ffb0936468545ceec86b67162a111fff Implements: blueprint vmware-api
-rw-r--r--oslo/vmware/exceptions.py68
-rw-r--r--oslo/vmware/vim_util.py367
-rw-r--r--requirements.txt2
-rw-r--r--tests/test_vim_util.py290
-rw-r--r--tox.ini3
5 files changed, 730 insertions, 0 deletions
diff --git a/oslo/vmware/exceptions.py b/oslo/vmware/exceptions.py
new file mode 100644
index 0000000..e72dac4
--- /dev/null
+++ b/oslo/vmware/exceptions.py
@@ -0,0 +1,68 @@
+# Copyright (c) 2014 VMware, Inc.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""
+Exception definitions.
+"""
+
+NOT_AUTHENTICATED_FAULT = "NotAuthenticated"
+
+
+class VimException(Exception):
+ """The base exception class for all exceptions this library raises."""
+
+ def __init__(self, message, cause=None):
+ self.msg = message
+ self.cause = cause
+
+ def __str__(self):
+ descr = self.msg
+ if self.cause:
+ descr += '\nCause: ' + str(self.cause)
+ return descr
+
+
+class VimSessionOverLoadException(VimException):
+ """Thrown when there is an API call overload at the VMware server."""
+ pass
+
+
+class VimConnectionException(VimException):
+ """Thrown when there is a connection problem."""
+ pass
+
+
+class VimAttributeException(VimException):
+ """Thrown when a particular attribute cannot be found."""
+ pass
+
+
+class VimFaultException(VimException):
+ """Exception thrown when there are faults during VIM API calls."""
+
+ def __init__(self, fault_list, message, cause=None):
+ super(VimFaultException, self).__init__(message, cause)
+ self.fault_list = fault_list
+
+ def __str__(self):
+ descr = VimException.__str__(self)
+ if self.fault_list:
+ descr += '\nFaults: ' + str(self.fault_list)
+ return descr
+
+
+class ImageTransferException(VimException):
+ """Thrown when there is an error during image transfer."""
+ pass
diff --git a/oslo/vmware/vim_util.py b/oslo/vmware/vim_util.py
new file mode 100644
index 0000000..c9b022b
--- /dev/null
+++ b/oslo/vmware/vim_util.py
@@ -0,0 +1,367 @@
+# Copyright (c) 2014 VMware, Inc.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""
+The VMware API utility module.
+"""
+
+import suds
+
+
+def get_moref(value, type_):
+ """Get managed object reference.
+
+ :param value: value of the managed object
+ :param type_: type of the managed object
+ :returns: managed object reference with given value and type
+ """
+ moref = suds.sudsobject.Property(value)
+ moref._type = type_
+ return moref
+
+
+def build_selection_spec(client_factory, name):
+ """Builds the selection spec.
+
+ :param client_factory: factory to get API input specs
+ :param name: name for the selection spec
+ :returns: selection spec
+ """
+ sel_spec = client_factory.create('ns0:SelectionSpec')
+ sel_spec.name = name
+ return sel_spec
+
+
+def build_traversal_spec(client_factory, name, type_, path, skip, select_set):
+ """Builds the traversal spec.
+
+ :param client_factory: factory to get API input specs
+ :param name: name for the traversal spec
+ :param type_: type of the managed object
+ :param path: property path of the managed object
+ :param skip: whether or not to filter the object identified by param path
+ :param select_set: set of selection specs specifying additional objects
+ to filter
+ :returns: traversal spec
+ """
+ traversal_spec = client_factory.create('ns0:TraversalSpec')
+ traversal_spec.name = name
+ traversal_spec.type = 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 recursive traversal spec to traverse managed object hierarchy.
+
+ :param client_factory: factory to get API input specs
+ :returns: recursive traversal spec
+ """
+ visit_folders_select_spec = build_selection_spec(client_factory,
+ 'visitFolders')
+ # Next hop from Datacenter
+ dc_to_hf = build_traversal_spec(client_factory,
+ 'dc_to_hf',
+ 'Datacenter',
+ 'hostFolder',
+ False,
+ [visit_folders_select_spec])
+ dc_to_vmf = build_traversal_spec(client_factory,
+ 'dc_to_vmf',
+ 'Datacenter',
+ 'vmFolder',
+ False,
+ [visit_folders_select_spec])
+
+ # Next hop from HostSystem
+ h_to_vm = build_traversal_spec(client_factory,
+ 'h_to_vm',
+ 'HostSystem',
+ 'vm',
+ False,
+ [visit_folders_select_spec])
+
+ # Next hop from ComputeResource
+ cr_to_h = build_traversal_spec(client_factory,
+ 'cr_to_h',
+ 'ComputeResource',
+ 'host',
+ False,
+ [])
+ 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')
+
+ cr_to_rp = build_traversal_spec(client_factory,
+ 'cr_to_rp',
+ 'ComputeResource',
+ 'resourcePool',
+ False,
+ [rp_to_rp_select_spec,
+ rp_to_vm_select_spec])
+
+ # Next hop from ClusterComputeResource
+ ccr_to_h = build_traversal_spec(client_factory,
+ 'ccr_to_h',
+ 'ClusterComputeResource',
+ 'host',
+ False,
+ [])
+ ccr_to_ds = build_traversal_spec(client_factory,
+ 'ccr_to_ds',
+ 'ClusterComputeResource',
+ 'datastore',
+ False,
+ [])
+ ccr_to_rp = build_traversal_spec(client_factory,
+ 'ccr_to_rp',
+ 'ClusterComputeResource',
+ 'resourcePool',
+ False,
+ [rp_to_rp_select_spec,
+ rp_to_vm_select_spec])
+ # Next hop from ResourcePool
+ rp_to_rp = build_traversal_spec(client_factory,
+ 'rp_to_rp',
+ 'ResourcePool',
+ 'resourcePool',
+ False,
+ [rp_to_rp_select_spec,
+ rp_to_vm_select_spec])
+ 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 rootFolder
+ traversal_spec = build_traversal_spec(client_factory,
+ 'visitFolders',
+ 'Folder',
+ 'childEntity',
+ False,
+ [visit_folders_select_spec,
+ h_to_vm,
+ dc_to_hf,
+ dc_to_vmf,
+ cr_to_ds,
+ cr_to_h,
+ cr_to_rp,
+ ccr_to_h,
+ ccr_to_ds,
+ ccr_to_rp,
+ rp_to_rp,
+ rp_to_vm])
+ return traversal_spec
+
+
+def build_property_spec(client_factory, type_='VirtualMachine',
+ properties_to_collect=None, all_properties=False):
+ """Builds the property spec.
+
+ :param client_factory: factory to get API input specs
+ :param type_: type of the managed object
+ :param properties_to_collect: names of the managed object properties to be
+ collected while traversal filtering
+ :param all_properties: whether all properties of the managed object need
+ to be collected
+ :returns: property spec
+ """
+ if not properties_to_collect:
+ properties_to_collect = ['name']
+
+ property_spec = client_factory.create('ns0:PropertySpec')
+ property_spec.all = all_properties
+ property_spec.pathSet = properties_to_collect
+ property_spec.type = type_
+ return property_spec
+
+
+def build_object_spec(client_factory, root_folder, traversal_specs):
+ """Builds the object spec.
+
+ :param client_factory: factory to get API input specs
+ :param root_folder: root folder reference; the starting point of traversal
+ :param traversal_specs: filter specs required for traversal
+ :returns: object spec
+ """
+ object_spec = client_factory.create('ns0:ObjectSpec')
+ object_spec.obj = root_folder
+ object_spec.skip = False
+ object_spec.selectSet = traversal_specs
+ return object_spec
+
+
+def build_property_filter_spec(client_factory, property_specs, object_specs):
+ """Builds the property filter spec.
+
+ :param client_factory: factory to get API input specs
+ :param property_specs: property specs to be collected for filtered objects
+ :param object_specs: object specs to identify objects to be filtered
+ :returns: property filter spec
+ """
+ property_filter_spec = client_factory.create('ns0:PropertyFilterSpec')
+ property_filter_spec.propSet = property_specs
+ property_filter_spec.objectSet = object_specs
+ return property_filter_spec
+
+
+def get_objects(vim, type_, max_objects, properties_to_collect=None,
+ all_properties=False):
+ """Get all managed object references of the given type.
+
+ It is the caller's responsibility to continue or cancel retrieval.
+
+ :param vim: Vim object
+ :param type_: type of the managed object
+ :param max_objects: maximum number of objects that should be returned in
+ a single call
+ :param properties_to_collect: names of the managed object properties to be
+ collected
+ :param all_properties: whether all properties of the managed object need to
+ be collected
+ :returns: all managed object references of the given type
+ :raises: VimException, VimFaultException, VimAttributeException,
+ VimSessionOverLoadException, VimConnectionException
+ """
+ if not properties_to_collect:
+ properties_to_collect = ['name']
+
+ client_factory = vim.client.factory
+ recur_trav_spec = build_recursive_traversal_spec(client_factory)
+ object_spec = build_object_spec(client_factory,
+ vim.service_content.rootFolder,
+ [recur_trav_spec])
+ property_spec = build_property_spec(
+ client_factory,
+ type_=type_,
+ properties_to_collect=properties_to_collect,
+ all_properties=all_properties)
+ property_filter_spec = build_property_filter_spec(client_factory,
+ [property_spec],
+ [object_spec])
+ options = client_factory.create('ns0:RetrieveOptions')
+ options.maxObjects = max_objects
+ return vim.RetrievePropertiesEx(vim.service_content.propertyCollector,
+ specSet=[property_filter_spec],
+ options=options)
+
+
+def get_object_properties(vim, moref, properties_to_collect):
+ """Get properties of the given managed object.
+
+ :param vim: Vim object
+ :param moref: managed object reference
+ :param properties_to_collect: names of the managed object properties to be
+ collected
+ :returns: properties of the given managed object
+ :raises: VimException, VimFaultException, VimAttributeException,
+ VimSessionOverLoadException, VimConnectionException
+ """
+ if moref is None:
+ return None
+
+ client_factory = vim.client.factory
+ all_properties = (properties_to_collect is None or
+ len(properties_to_collect) == 0)
+ property_spec = build_property_spec(
+ client_factory,
+ type_=moref._type,
+ properties_to_collect=properties_to_collect,
+ all_properties=all_properties)
+ object_spec = build_object_spec(client_factory, moref, [])
+ property_filter_spec = build_property_filter_spec(client_factory,
+ [property_spec],
+ [object_spec])
+
+ options = client_factory.create('ns0:RetrieveOptions')
+ options.maxObjects = 1
+ retrieve_result = vim.RetrievePropertiesEx(
+ vim.service_content.propertyCollector,
+ specSet=[property_filter_spec],
+ options=options)
+ cancel_retrieval(vim, retrieve_result)
+ return retrieve_result.objects
+
+
+def _get_token(retrieve_result):
+ """Get token from result to obtain next set of results.
+
+ :retrieve_result: Result of RetrievePropertiesEx API call
+ :returns: token to obtain next set of results; None if no more results.
+ """
+ return getattr(retrieve_result, 'token', None)
+
+
+def cancel_retrieval(vim, retrieve_result):
+ """Cancels the retrieve operation if necessary.
+
+ :param vim: Vim object
+ :param retrieve_result: result of RetrievePropertiesEx API call
+ :raises: VimException, VimFaultException, VimAttributeException,
+ VimSessionOverLoadException, VimConnectionException
+ """
+ token = _get_token(retrieve_result)
+ if token:
+ collector = vim.service_content.propertyCollector
+ vim.CancelRetrievePropertiesEx(collector, token=token)
+
+
+def continue_retrieval(vim, retrieve_result):
+ """Continue retrieving results, if available.
+
+ :param vim: Vim object
+ :param retrieve_result: result of RetrievePropertiesEx API call
+ :raises: VimException, VimFaultException, VimAttributeException,
+ VimSessionOverLoadException, VimConnectionException
+ """
+ token = _get_token(retrieve_result)
+ if token:
+ collector = vim.service_content.propertyCollector
+ return vim.ContinueRetrievePropertiesEx(collector, token=token)
+
+
+def get_object_property(vim, moref, property_name):
+ """Get property of the given managed object.
+
+ :param vim: Vim object
+ :param moref: managed object reference
+ :param property_name: name of the property to be retrieved
+ :returns: property of the given managed object
+ :raises: VimException, VimFaultException, VimAttributeException,
+ VimSessionOverLoadException, VimConnectionException
+ """
+ props = get_object_properties(vim, moref, [property_name])
+ prop_val = None
+ if props:
+ prop = None
+ if hasattr(props[0], 'propSet'):
+ # propSet will be set only if the server provides value
+ # for the field
+ prop = props[0].propSet
+ if prop:
+ prop_val = prop[0].val
+ return prop_val
diff --git a/requirements.txt b/requirements.txt
index c7af94c..576fd57 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -13,3 +13,5 @@ Babel>=1.3
# for the routing notifier
PyYAML>=3.1.0
+
+suds>=0.4
diff --git a/tests/test_vim_util.py b/tests/test_vim_util.py
new file mode 100644
index 0000000..d077d7c
--- /dev/null
+++ b/tests/test_vim_util.py
@@ -0,0 +1,290 @@
+# Copyright (c) 2014 VMware, Inc.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""
+Unit tests for VMware API utility module.
+"""
+
+import mock
+
+from oslo.vmware import vim_util
+from tests import base
+
+
+class VimUtilTest(base.TestCase):
+ """Test class for utility methods in vim_util."""
+
+ def test_get_moref(self):
+ moref = vim_util.get_moref("vm-0", "VirtualMachine")
+ self.assertEqual("vm-0", moref.value)
+ self.assertEqual("VirtualMachine", moref._type)
+
+ def test_build_selection_spec(self):
+ client_factory = mock.Mock()
+ sel_spec = vim_util.build_selection_spec(client_factory, "test")
+ self.assertEqual("test", sel_spec.name)
+
+ def test_build_traversal_spec(self):
+ client_factory = mock.Mock()
+ sel_spec = mock.Mock()
+ traversal_spec = vim_util.build_traversal_spec(client_factory,
+ 'dc_to_hf',
+ 'Datacenter',
+ 'hostFolder', False,
+ [sel_spec])
+ self.assertEqual("dc_to_hf", traversal_spec.name)
+ self.assertEqual("hostFolder", traversal_spec.path)
+ self.assertEqual([sel_spec], traversal_spec.selectSet)
+ self.assertFalse(traversal_spec.skip)
+ self.assertEqual("Datacenter", traversal_spec.type)
+
+ @mock.patch.object(vim_util, 'build_selection_spec')
+ def test_build_recursive_traversal_spec(self, build_selection_spec_mock):
+ sel_spec = mock.Mock()
+ rp_to_rp_sel_spec = mock.Mock()
+ rp_to_vm_sel_spec = mock.Mock()
+
+ def build_sel_spec_side_effect(client_factory, name):
+ if name == 'visitFolders':
+ return sel_spec
+ elif name == 'rp_to_rp':
+ return rp_to_rp_sel_spec
+ elif name == 'rp_to_vm':
+ return rp_to_vm_sel_spec
+ else:
+ return None
+
+ build_selection_spec_mock.side_effect = build_sel_spec_side_effect
+ traversal_spec_dict = {'dc_to_hf': {'type': 'Datacenter',
+ 'path': 'hostFolder',
+ 'skip': False,
+ 'selectSet': [sel_spec]},
+ 'dc_to_vmf': {'type': 'Datacenter',
+ 'path': 'vmFolder',
+ 'skip': False,
+ 'selectSet': [sel_spec]},
+ 'h_to_vm': {'type': 'HostSystem',
+ 'path': 'vm',
+ 'skip': False,
+ 'selectSet': [sel_spec]},
+ 'cr_to_h': {'type': 'ComputeResource',
+ 'path': 'host',
+ 'skip': False,
+ 'selectSet': []},
+ 'cr_to_ds': {'type': 'ComputeResource',
+ 'path': 'datastore',
+ 'skip': False,
+ 'selectSet': []},
+ 'cr_to_rp': {'type': 'ComputeResource',
+ 'path': 'resourcePool',
+ 'skip': False,
+ 'selectSet': [rp_to_rp_sel_spec,
+ rp_to_vm_sel_spec]},
+ 'cr_to_rp': {'type': 'ComputeResource',
+ 'path': 'resourcePool',
+ 'skip': False,
+ 'selectSet': [rp_to_rp_sel_spec,
+ rp_to_vm_sel_spec]},
+ 'ccr_to_h': {'type': 'ClusterComputeResource',
+ 'path': 'host',
+ 'skip': False,
+ 'selectSet': []},
+ 'ccr_to_ds': {'type': 'ClusterComputeResource',
+ 'path': 'datastore',
+ 'skip': False,
+ 'selectSet': []},
+ 'ccr_to_rp': {'type': 'ClusterComputeResource',
+ 'path': 'resourcePool',
+ 'skip': False,
+ 'selectSet': [rp_to_rp_sel_spec,
+ rp_to_vm_sel_spec]},
+ 'rp_to_rp': {'type': 'ResourcePool',
+ 'path': 'resourcePool',
+ 'skip': False,
+ 'selectSet': [rp_to_rp_sel_spec,
+ rp_to_vm_sel_spec]},
+ 'rp_to_vm': {'type': 'ResourcePool',
+ 'path': 'vm',
+ 'skip': False,
+ 'selectSet': [rp_to_rp_sel_spec,
+ rp_to_vm_sel_spec]},
+ }
+
+ client_factory = mock.Mock()
+ client_factory.create.side_effect = lambda ns: mock.Mock()
+ trav_spec = vim_util.build_recursive_traversal_spec(client_factory)
+ self.assertEqual("visitFolders", trav_spec.name)
+ self.assertEqual("childEntity", trav_spec.path)
+ self.assertFalse(trav_spec.skip)
+ self.assertEqual("Folder", trav_spec.type)
+
+ self.assertEqual(len(traversal_spec_dict) + 1,
+ len(trav_spec.selectSet))
+ for spec in trav_spec.selectSet:
+ if spec.name not in traversal_spec_dict:
+ self.assertEqual(sel_spec, spec)
+ else:
+ exp_spec = traversal_spec_dict[spec.name]
+ self.assertEqual(exp_spec['type'], spec.type)
+ self.assertEqual(exp_spec['path'], spec.path)
+ self.assertEqual(exp_spec['skip'], spec.skip)
+ self.assertEqual(exp_spec['selectSet'], spec.selectSet)
+
+ def test_build_property_spec(self):
+ client_factory = mock.Mock()
+ prop_spec = vim_util.build_property_spec(client_factory)
+ self.assertFalse(prop_spec.all)
+ self.assertEqual(["name"], prop_spec.pathSet)
+ self.assertEqual("VirtualMachine", prop_spec.type)
+
+ def test_build_object_spec(self):
+ client_factory = mock.Mock()
+ root_folder = mock.Mock()
+ specs = [mock.Mock()]
+ obj_spec = vim_util.build_object_spec(client_factory,
+ root_folder, specs)
+ self.assertEqual(root_folder, obj_spec.obj)
+ self.assertEqual(specs, obj_spec.selectSet)
+ self.assertFalse(obj_spec.skip)
+
+ def test_build_property_filter_spec(self):
+ client_factory = mock.Mock()
+ prop_specs = [mock.Mock()]
+ obj_specs = [mock.Mock()]
+ filter_spec = vim_util.build_property_filter_spec(client_factory,
+ prop_specs,
+ obj_specs)
+ self.assertEqual(obj_specs, filter_spec.objectSet)
+ self.assertEqual(prop_specs, filter_spec.propSet)
+
+ @mock.patch(
+ 'oslo.vmware.vim_util.build_recursive_traversal_spec')
+ def test_get_objects(self, build_recursive_traversal_spec):
+ vim = mock.Mock()
+ trav_spec = mock.Mock()
+ build_recursive_traversal_spec.return_value = trav_spec
+ max_objects = 10
+ _type = "VirtualMachine"
+
+ def vim_RetrievePropertiesEx_side_effect(pc, specSet, options):
+ self.assertTrue(pc is vim.service_content.propertyCollector)
+ self.assertEqual(max_objects, options.maxObjects)
+
+ self.assertEqual(1, len(specSet))
+ property_filter_spec = specSet[0]
+
+ propSet = property_filter_spec.propSet
+ self.assertEqual(1, len(propSet))
+ prop_spec = propSet[0]
+ self.assertFalse(prop_spec.all)
+ self.assertEqual(["name"], prop_spec.pathSet)
+ self.assertEqual(_type, prop_spec.type)
+
+ objSet = property_filter_spec.objectSet
+ self.assertEqual(1, len(objSet))
+ obj_spec = objSet[0]
+ self.assertTrue(obj_spec.obj is vim.service_content.rootFolder)
+ self.assertEqual([trav_spec], obj_spec.selectSet)
+ self.assertFalse(obj_spec.skip)
+
+ vim.RetrievePropertiesEx.side_effect = \
+ vim_RetrievePropertiesEx_side_effect
+ vim_util.get_objects(vim, _type, max_objects)
+ self.assertEqual(1, vim.RetrievePropertiesEx.call_count)
+
+ def test_get_object_properties_with_empty_moref(self):
+ vim = mock.Mock()
+ ret = vim_util.get_object_properties(vim, None, None)
+ self.assertEqual(None, ret)
+
+ @mock.patch('oslo.vmware.vim_util.cancel_retrieval')
+ def test_get_object_properties(self, cancel_retrieval):
+ vim = mock.Mock()
+ moref = mock.Mock()
+ moref._type = "VirtualMachine"
+ retrieve_result = mock.Mock()
+
+ def vim_RetrievePropertiesEx_side_effect(pc, specSet, options):
+ self.assertTrue(pc is vim.service_content.propertyCollector)
+ self.assertEqual(1, options.maxObjects)
+
+ self.assertEqual(1, len(specSet))
+ property_filter_spec = specSet[0]
+
+ propSet = property_filter_spec.propSet
+ self.assertEqual(1, len(propSet))
+ prop_spec = propSet[0]
+ self.assertTrue(prop_spec.all)
+ self.assertEqual(['name'], prop_spec.pathSet)
+ self.assertEqual(moref._type, prop_spec.type)
+
+ objSet = property_filter_spec.objectSet
+ self.assertEqual(1, len(objSet))
+ obj_spec = objSet[0]
+ self.assertEqual(moref, obj_spec.obj)
+ self.assertEqual([], obj_spec.selectSet)
+ self.assertFalse(obj_spec.skip)
+
+ return retrieve_result
+
+ vim.RetrievePropertiesEx.side_effect = \
+ vim_RetrievePropertiesEx_side_effect
+
+ res = vim_util.get_object_properties(vim, moref, None)
+ self.assertEqual(1, vim.RetrievePropertiesEx.call_count)
+ self.assertTrue(res is retrieve_result.objects)
+ cancel_retrieval.assert_called_once_with(vim, retrieve_result)
+
+ def test_get_token(self):
+ retrieve_result = object()
+ self.assertFalse(vim_util._get_token(retrieve_result))
+
+ @mock.patch('oslo.vmware.vim_util._get_token')
+ def test_cancel_retrieval(self, get_token):
+ token = mock.Mock()
+ get_token.return_value = token
+ vim = mock.Mock()
+ retrieve_result = mock.Mock()
+ vim_util.cancel_retrieval(vim, retrieve_result)
+ get_token.assert_called_once_with(retrieve_result)
+ vim.CancelRetrievePropertiesEx.assert_called_once_with(
+ vim.service_content.propertyCollector, token=token)
+
+ @mock.patch('oslo.vmware.vim_util._get_token')
+ def test_continue_retrieval(self, get_token):
+ token = mock.Mock()
+ get_token.return_value = token
+ vim = mock.Mock()
+ retrieve_result = mock.Mock()
+ vim_util.continue_retrieval(vim, retrieve_result)
+ get_token.assert_called_once_with(retrieve_result)
+ vim.ContinueRetrievePropertiesEx.assert_called_once_with(
+ vim.service_content.propertyCollector, token=token)
+
+ @mock.patch('oslo.vmware.vim_util.get_object_properties')
+ def test_get_object_property(self, get_object_properties):
+ prop = mock.Mock()
+ prop.val = "ubuntu-12.04"
+ properties = mock.Mock()
+ properties.propSet = [prop]
+ properties_list = [properties]
+ get_object_properties.return_value = properties_list
+ vim = mock.Mock()
+ moref = mock.Mock()
+ property_name = 'name'
+ val = vim_util.get_object_property(vim, moref, property_name)
+ self.assertEqual(prop.val, val)
+ get_object_properties.assert_called_once_with(
+ vim, moref, [property_name])
diff --git a/tox.ini b/tox.ini
index 0fef3bf..54771a9 100644
--- a/tox.ini
+++ b/tox.ini
@@ -22,3 +22,6 @@ commands = {posargs}
show-source = True
exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build,__init__.py
builtins = _
+
+[hacking]
+import_exceptions = oslo.vmware.openstack.common.gettextutils._ \ No newline at end of file