summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZhongcheng Lao <zlao@vmware.com>2017-05-16 11:52:02 +0800
committerZhongcheng Lao <zlao@vmware.com>2017-05-24 04:21:46 -0700
commit37f72b0db622e32bcebd86ee516a134dbd2eef9c (patch)
treeb1fc6033a422a3d2630c1786ab6a4ab86ae6560b
parent37c3d53d5b9e16f6624f784a20d006f43b194d04 (diff)
downloadoslo-vmware-37f72b0db622e32bcebd86ee516a134dbd2eef9c.tar.gz
Make sure host in maintenance mode excluded from image upload
Currently when selecting host for image upload, hosts in maintenance mode will also be included. This commit adds a check for available hosts to make sure these hosts excluded from the list. Change-Id: I46e4a879245e4f9258178738da9920b34b65a187
-rw-r--r--oslo_vmware/objects/datastore.py17
-rw-r--r--oslo_vmware/tests/objects/test_datastore.py43
-rw-r--r--oslo_vmware/tests/test_vim_util.py102
-rw-r--r--oslo_vmware/vim_util.py68
4 files changed, 225 insertions, 5 deletions
diff --git a/oslo_vmware/objects/datastore.py b/oslo_vmware/objects/datastore.py
index cd89d4f..a0fca70 100644
--- a/oslo_vmware/objects/datastore.py
+++ b/oslo_vmware/objects/datastore.py
@@ -142,7 +142,19 @@ class Datastore(object):
for host_mount in host_mounts.DatastoreHostMount:
if self.is_datastore_mount_usable(host_mount.mountInfo):
hosts.append(host_mount.key)
- return hosts
+ connectables = []
+ if hosts:
+ host_runtimes = session.invoke_api(
+ vim_util,
+ 'get_properties_for_a_collection_of_objects',
+ session.vim, 'HostSystem', hosts, ['runtime'])
+ for host_object in host_runtimes.objects:
+ host_props = vim_util.propset_dict(host_object.propSet)
+ host_runtime = host_props.get('runtime')
+ if hasattr(host_runtime, 'inMaintenanceMode') and (
+ not host_runtime.inMaintenanceMode):
+ connectables.append(host_object.obj)
+ return connectables
@staticmethod
def is_datastore_mount_usable(mount_info):
@@ -162,6 +174,9 @@ class Datastore(object):
@staticmethod
def choose_host(hosts):
+ if not hosts:
+ return None
+
i = random.SystemRandom().randrange(0, len(hosts))
return hosts[i]
diff --git a/oslo_vmware/tests/objects/test_datastore.py b/oslo_vmware/tests/objects/test_datastore.py
index 28bfacf..9ee23bb 100644
--- a/oslo_vmware/tests/objects/test_datastore.py
+++ b/oslo_vmware/tests/objects/test_datastore.py
@@ -95,7 +95,8 @@ class DatastoreTestCase(base.TestCase):
session.vim,
ds.ref, 'summary')
- def test_get_connected_hosts(self):
+ def _test_get_connected_hosts(self, in_maintenance_mode,
+ m1_accessible=True):
session = mock.Mock()
ds_ref = vim_util.get_moref('ds-0', 'Datastore')
ds = datastore.Datastore(ds_ref, 'ds-name')
@@ -103,7 +104,7 @@ class DatastoreTestCase(base.TestCase):
ds.get_summary.return_value.accessible = False
self.assertEqual([], ds.get_connected_hosts(session))
ds.get_summary.return_value.accessible = True
- m1 = HostMount("m1", MountInfo('readWrite', True, True))
+ m1 = HostMount("m1", MountInfo('readWrite', True, m1_accessible))
m2 = HostMount("m2", MountInfo('read', True, True))
m3 = HostMount("m3", MountInfo('readWrite', False, True))
m4 = HostMount("m4", MountInfo('readWrite', True, False))
@@ -111,12 +112,46 @@ class DatastoreTestCase(base.TestCase):
class Prop(object):
DatastoreHostMount = [m1, m2, m3, m4]
- session.invoke_api = mock.Mock()
- session.invoke_api.return_value = Prop()
+
+ class HostRuntime(object):
+ inMaintenanceMode = in_maintenance_mode
+
+ class HostProp(object):
+ name = 'runtime'
+ val = HostRuntime()
+
+ class Object(object):
+ obj = "m1"
+ propSet = [HostProp()]
+
+ class Runtime(object):
+ objects = [Object()]
+
+ session.invoke_api = mock.Mock(side_effect=[Prop(), Runtime()])
hosts = ds.get_connected_hosts(session)
+ calls = [mock.call(vim_util, 'get_object_property',
+ session.vim, ds_ref, 'host')]
+ if m1_accessible:
+ calls.append(
+ mock.call(vim_util,
+ 'get_properties_for_a_collection_of_objects',
+ session.vim, 'HostSystem', ["m1"], ['runtime']))
+ self.assertEqual(calls, session.invoke_api.mock_calls)
+ return hosts
+
+ def test_get_connected_hosts(self):
+ hosts = self._test_get_connected_hosts(False)
self.assertEqual(1, len(hosts))
self.assertEqual("m1", hosts.pop())
+ def test_get_connected_hosts_in_maintenance(self):
+ hosts = self._test_get_connected_hosts(True)
+ self.assertEqual(0, len(hosts))
+
+ def test_get_connected_hosts_ho_hosts(self):
+ hosts = self._test_get_connected_hosts(False, False)
+ self.assertEqual(0, len(hosts))
+
def test_is_datastore_mount_usable(self):
m = MountInfo('readWrite', True, True)
self.assertTrue(datastore.Datastore.is_datastore_mount_usable(m))
diff --git a/oslo_vmware/tests/test_vim_util.py b/oslo_vmware/tests/test_vim_util.py
index 8e43c95..1b7d4fd 100644
--- a/oslo_vmware/tests/test_vim_util.py
+++ b/oslo_vmware/tests/test_vim_util.py
@@ -430,3 +430,105 @@ class VimUtilTest(base.TestCase):
entity = mock.Mock()
inv_path = vim_util.get_inventory_path(session.vim, entity, 100)
self.assertEqual('dc-1', inv_path)
+
+ def test_get_prop_spec(self):
+ client_factory = mock.Mock()
+ prop_spec = vim_util.get_prop_spec(
+ client_factory, "VirtualMachine", ["test_path"])
+ self.assertEqual(["test_path"], prop_spec.pathSet)
+ self.assertEqual("VirtualMachine", prop_spec.type)
+
+ def test_get_obj_spec(self):
+ client_factory = mock.Mock()
+ mock_obj = mock.Mock()
+ obj_spec = vim_util.get_obj_spec(
+ client_factory, mock_obj, select_set=["abc"])
+ self.assertEqual(mock_obj, obj_spec.obj)
+ self.assertFalse(obj_spec.skip)
+ self.assertEqual(["abc"], obj_spec.selectSet)
+
+ def test_get_prop_filter_spec(self):
+ client_factory = mock.Mock()
+ mock_obj = mock.Mock()
+ filter_spec = vim_util.get_prop_filter_spec(
+ client_factory, [mock_obj], ["test_prop"])
+ self.assertEqual([mock_obj], filter_spec.objectSet)
+ self.assertEqual(["test_prop"], filter_spec.propSet)
+
+ @mock.patch('oslo_vmware.vim_util.get_prop_spec')
+ @mock.patch('oslo_vmware.vim_util.get_obj_spec')
+ @mock.patch('oslo_vmware.vim_util.get_prop_filter_spec')
+ def _test_get_properties_for_a_collection_of_objects(
+ self, objs, max_objects,
+ mock_get_prop_filter_spec,
+ mock_get_obj_spec,
+ mock_get_prop_spec):
+ vim = mock.Mock()
+ if len(objs) == 0:
+ self.assertEqual(
+ [], vim_util.get_properties_for_a_collection_of_objects(
+ vim, 'VirtualMachine', [], {}))
+ return
+
+ mock_prop_spec = mock.Mock()
+ mock_get_prop_spec.return_value = mock_prop_spec
+
+ mock_get_obj_spec.side_effect = [mock.Mock()
+ for obj in objs]
+ get_obj_spec_calls = [mock.call(vim.client.factory, obj)
+ for obj in objs]
+
+ mock_prop_spec = mock.Mock()
+ mock_get_prop_spec.return_value = mock_prop_spec
+
+ mock_prop_filter_spec = mock.Mock()
+ mock_get_prop_filter_spec.return_value = mock_prop_filter_spec
+ mock_options = mock.Mock()
+ vim.client.factory.create.return_value = mock_options
+
+ mock_return_value = mock.Mock()
+ vim.RetrievePropertiesEx.return_value = mock_return_value
+ res = vim_util.get_properties_for_a_collection_of_objects(
+ vim, 'VirtualMachine', objs, ['runtime'], max_objects)
+ self.assertEqual(mock_return_value, res)
+
+ mock_get_prop_spec.assert_called_once_with(vim.client.factory,
+ 'VirtualMachine',
+ ['runtime'])
+ self.assertEqual(get_obj_spec_calls, mock_get_obj_spec.mock_calls)
+ vim.client.factory.create.assert_called_once_with(
+ 'ns0:RetrieveOptions')
+ self.assertEqual(max_objects if max_objects else len(objs),
+ mock_options.maxObjects)
+ vim.RetrievePropertiesEx.assert_called_once_with(
+ vim.service_content.propertyCollector,
+ specSet=[mock_prop_filter_spec],
+ options=mock_options)
+
+ def test_get_properties_for_a_collection_of_objects(
+ self):
+ objects = ["m1", "m2"]
+ self._test_get_properties_for_a_collection_of_objects(objects, None)
+
+ def test_get_properties_for_a_collection_of_objects_max_objects_1(
+ self):
+ objects = ["m1", "m2"]
+ self._test_get_properties_for_a_collection_of_objects(objects, 1)
+
+ def test_get_properties_for_a_collection_of_objects_no_objects(
+ self):
+ self._test_get_properties_for_a_collection_of_objects([], None)
+
+ def test_propset_dict(self):
+ self.assertEqual({}, vim_util.propset_dict(None))
+
+ mock_propset = []
+ for i in range(2):
+ mock_obj = mock.Mock()
+ mock_obj.name = "test_name_%d" % i
+ mock_obj.val = "test_val_%d" % i
+ mock_propset.append(mock_obj)
+
+ self.assertEqual({"test_name_0": "test_val_0",
+ "test_name_1": "test_val_1"},
+ vim_util.propset_dict(mock_propset))
diff --git a/oslo_vmware/vim_util.py b/oslo_vmware/vim_util.py
index 9332ae2..6269016 100644
--- a/oslo_vmware/vim_util.py
+++ b/oslo_vmware/vim_util.py
@@ -553,3 +553,71 @@ def get_http_service_request_spec(client_factory, method, uri):
http_service_request_spec.method = method
http_service_request_spec.url = uri
return http_service_request_spec
+
+
+def get_prop_spec(client_factory, spec_type, properties):
+ """Builds the Property Spec Object."""
+ prop_spec = client_factory.create('ns0:PropertySpec')
+ prop_spec.type = spec_type
+ prop_spec.pathSet = properties
+ return prop_spec
+
+
+def get_obj_spec(client_factory, obj, select_set=None):
+ """Builds the Object Spec object."""
+ obj_spec = client_factory.create('ns0:ObjectSpec')
+ obj_spec.obj = obj
+ obj_spec.skip = False
+ if select_set is not None:
+ obj_spec.selectSet = select_set
+ return obj_spec
+
+
+def get_prop_filter_spec(client_factory, obj_spec, prop_spec):
+ """Builds the Property Filter Spec Object."""
+ prop_filter_spec = client_factory.create('ns0:PropertyFilterSpec')
+ prop_filter_spec.propSet = prop_spec
+ prop_filter_spec.objectSet = obj_spec
+ return prop_filter_spec
+
+
+def get_properties_for_a_collection_of_objects(vim, type_,
+ obj_list, properties,
+ max_objects=None):
+ """Gets the list of properties for the collection of
+ objects of the type specified.
+ """
+ client_factory = vim.client.factory
+ if len(obj_list) == 0:
+ return []
+ prop_spec = get_prop_spec(client_factory, type_, properties)
+ lst_obj_specs = []
+ for obj in obj_list:
+ lst_obj_specs.append(get_obj_spec(client_factory, obj))
+ prop_filter_spec = get_prop_filter_spec(client_factory,
+ lst_obj_specs, [prop_spec])
+ options = client_factory.create('ns0:RetrieveOptions')
+ options.maxObjects = max_objects if max_objects else len(obj_list)
+ return vim.RetrievePropertiesEx(
+ vim.service_content.propertyCollector,
+ specSet=[prop_filter_spec], options=options)
+
+
+def propset_dict(propset):
+ """Turn a propset list into a dictionary
+
+ PropSet is an optional attribute on ObjectContent objects
+ that are returned by the VMware API.
+
+ You can read more about these at:
+ | http://pubs.vmware.com/vsphere-51/index.jsp
+ | #com.vmware.wssdk.apiref.doc/
+ | vmodl.query.PropertyCollector.ObjectContent.html
+
+ :param propset: a property "set" from ObjectContent
+ :return: dictionary representing property set
+ """
+ if propset is None:
+ return {}
+
+ return {prop.name: prop.val for prop in propset}