Merge "Make sure host in maintenance mode excluded from image upload"
This commit is contained in:
commit
5b01c09e86
|
@ -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]
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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}
|
||||
|
|
Loading…
Reference in New Issue