Merge "Make sure host in maintenance mode excluded from image upload"

This commit is contained in:
Jenkins 2017-06-28 08:33:07 +00:00 committed by Gerrit Code Review
commit 5b01c09e86
4 changed files with 225 additions and 5 deletions

View File

@ -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]

View File

@ -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))

View File

@ -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))

View File

@ -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}