diff --git a/nova/tests/virt/vmwareapi/test_ds_util.py b/nova/tests/virt/vmwareapi/test_ds_util.py index 06fd2420220d..2b957e1c5fe0 100644 --- a/nova/tests/virt/vmwareapi/test_ds_util.py +++ b/nova/tests/virt/vmwareapi/test_ds_util.py @@ -13,9 +13,12 @@ # under the License. import contextlib +import re import mock +from nova import exception +from nova.openstack.common.gettextutils import _ from nova.openstack.common import units from nova import test from nova.tests.virt.vmwareapi import fake @@ -157,6 +160,100 @@ class DsUtilTestCase(test.NoDBTestCase): 'fake-browser', 'fake-path', 'fake-file') self.assertFalse(file_exists) + def test_get_datastore(self): + fake_objects = fake.FakeRetrieveResult() + fake_objects.add_object(fake.Datastore()) + result = ds_util.get_datastore( + fake.FakeObjectRetrievalSession(fake_objects)) + + self.assertEqual("fake-ds", result.name) + self.assertEqual(units.Ti, result.capacity) + self.assertEqual(500 * units.Gi, result.freespace) + + def test_get_datastore_with_regex(self): + # Test with a regex that matches with a datastore + datastore_valid_regex = re.compile("^openstack.*\d$") + fake_objects = fake.FakeRetrieveResult() + fake_objects.add_object(fake.Datastore("openstack-ds0")) + fake_objects.add_object(fake.Datastore("fake-ds0")) + fake_objects.add_object(fake.Datastore("fake-ds1")) + result = ds_util.get_datastore( + fake.FakeObjectRetrievalSession(fake_objects), None, None, + datastore_valid_regex) + self.assertEqual("openstack-ds0", result.name) + + def test_get_datastore_with_token(self): + regex = re.compile("^ds.*\d$") + fake0 = fake.FakeRetrieveResult() + fake0.add_object(fake.Datastore("ds0", 10 * units.Gi, 5 * units.Gi)) + fake0.add_object(fake.Datastore("foo", 10 * units.Gi, 9 * units.Gi)) + setattr(fake0, 'token', 'token-0') + fake1 = fake.FakeRetrieveResult() + fake1.add_object(fake.Datastore("ds2", 10 * units.Gi, 8 * units.Gi)) + fake1.add_object(fake.Datastore("ds3", 10 * units.Gi, 1 * units.Gi)) + result = ds_util.get_datastore( + fake.FakeObjectRetrievalSession(fake0, fake1), None, None, regex) + self.assertEqual("ds2", result.name) + + def test_get_datastore_with_list(self): + # Test with a regex containing whitelist of datastores + datastore_valid_regex = re.compile("(openstack-ds0|openstack-ds2)") + fake_objects = fake.FakeRetrieveResult() + fake_objects.add_object(fake.Datastore("openstack-ds0")) + fake_objects.add_object(fake.Datastore("openstack-ds1")) + fake_objects.add_object(fake.Datastore("openstack-ds2")) + result = ds_util.get_datastore( + fake.FakeObjectRetrievalSession(fake_objects), None, None, + datastore_valid_regex) + self.assertNotEqual("openstack-ds1", result.name) + + def test_get_datastore_with_regex_error(self): + # Test with a regex that has no match + # Checks if code raises DatastoreNotFound with a specific message + datastore_invalid_regex = re.compile("unknown-ds") + exp_message = (_("Datastore regex %s did not match any datastores") + % datastore_invalid_regex.pattern) + fake_objects = fake.FakeRetrieveResult() + fake_objects.add_object(fake.Datastore("fake-ds0")) + fake_objects.add_object(fake.Datastore("fake-ds1")) + # assertRaisesRegExp would have been a good choice instead of + # try/catch block, but it's available only from Py 2.7. + try: + ds_util.get_datastore( + fake.FakeObjectRetrievalSession(fake_objects), None, None, + datastore_invalid_regex) + except exception.DatastoreNotFound as e: + self.assertEqual(exp_message, e.args[0]) + else: + self.fail("DatastoreNotFound Exception was not raised with " + "message: %s" % exp_message) + + def test_get_datastore_without_datastore(self): + + self.assertRaises(exception.DatastoreNotFound, + ds_util.get_datastore, + fake.FakeObjectRetrievalSession(None), host="fake-host") + + self.assertRaises(exception.DatastoreNotFound, + ds_util.get_datastore, + fake.FakeObjectRetrievalSession(None), cluster="fake-cluster") + + def test_get_datastore_no_host_in_cluster(self): + self.assertRaises(exception.DatastoreNotFound, + ds_util.get_datastore, + fake.FakeObjectRetrievalSession(""), 'fake_cluster') + + def test_get_datastore_inaccessible_ds(self): + data_store = fake.Datastore() + data_store.set("summary.accessible", False) + + fake_objects = fake.FakeRetrieveResult() + fake_objects.add_object(data_store) + + self.assertRaises(exception.DatastoreNotFound, + ds_util.get_datastore, + fake.FakeObjectRetrievalSession(fake_objects)) + class DatastoreTestCase(test.NoDBTestCase): def test_ds(self): diff --git a/nova/tests/virt/vmwareapi/test_vm_util_datastore_selection.py b/nova/tests/virt/vmwareapi/test_ds_util_datastore_selection.py similarity index 92% rename from nova/tests/virt/vmwareapi/test_vm_util_datastore_selection.py rename to nova/tests/virt/vmwareapi/test_ds_util_datastore_selection.py index b988b57486a5..c34e76f4c276 100644 --- a/nova/tests/virt/vmwareapi/test_vm_util_datastore_selection.py +++ b/nova/tests/virt/vmwareapi/test_ds_util_datastore_selection.py @@ -17,7 +17,6 @@ import re from nova.openstack.common import units from nova import test from nova.virt.vmwareapi import ds_util -from nova.virt.vmwareapi import vm_util ResultSet = collections.namedtuple('ResultSet', ['objects']) ResultSetToken = collections.namedtuple('ResultSet', ['objects', 'token']) @@ -26,10 +25,10 @@ DynamicProperty = collections.namedtuple('Property', ['name', 'val']) MoRef = collections.namedtuple('ManagedObjectReference', ['value']) -class VMwareVMUtilDatastoreSelectionTestCase(test.NoDBTestCase): +class VMwareDSUtilDatastoreSelectionTestCase(test.NoDBTestCase): def setUp(self): - super(VMwareVMUtilDatastoreSelectionTestCase, self).setUp() + super(VMwareDSUtilDatastoreSelectionTestCase, self).setUp() self.data = [ ['VMFS', 'os-some-name', True, 987654321, 12346789], ['NFS', 'another-name', True, 9876543210, 123467890], @@ -63,7 +62,7 @@ class VMwareVMUtilDatastoreSelectionTestCase(test.NoDBTestCase): datastores = self.build_result_set(self.data) best_match = ds_util.Datastore(ref='fake_ref', name='ds', capacity=0, freespace=0) - rec = vm_util._select_datastore(datastores, best_match) + rec = ds_util._select_datastore(datastores, best_match) self.assertIsNotNone(rec.ref, "could not find datastore!") self.assertEqual('ds-001', rec.ref.value, @@ -77,7 +76,7 @@ class VMwareVMUtilDatastoreSelectionTestCase(test.NoDBTestCase): best_match = ds_util.Datastore(ref='fake_ref', name='ds', capacity=0, freespace=0) - rec = vm_util._select_datastore(datastores, best_match) + rec = ds_util._select_datastore(datastores, best_match) self.assertEqual(rec, best_match) @@ -87,7 +86,7 @@ class VMwareVMUtilDatastoreSelectionTestCase(test.NoDBTestCase): best_match = ds_util.Datastore(ref='fake_ref', name='ds', capacity=0, freespace=0) - rec = vm_util._select_datastore(datastores, + rec = ds_util._select_datastore(datastores, best_match, datastore_regex) @@ -108,7 +107,7 @@ class VMwareVMUtilDatastoreSelectionTestCase(test.NoDBTestCase): best_match = ds_util.Datastore(ref='fake_ref', name='ds', capacity=0, freespace=0) - rec = vm_util._select_datastore(datastores, + rec = ds_util._select_datastore(datastores, best_match, datastore_regex) @@ -135,7 +134,7 @@ class VMwareVMUtilDatastoreSelectionTestCase(test.NoDBTestCase): best_match = ds_util.Datastore(ref='fake_ref', name='ds', capacity=0, freespace=0) - rec = vm_util._select_datastore(datastores, best_match) + rec = ds_util._select_datastore(datastores, best_match) self.assertEqual(rec, best_match, "no matches were expected") def test_filter_datastores_best_match(self): @@ -153,7 +152,7 @@ class VMwareVMUtilDatastoreSelectionTestCase(test.NoDBTestCase): # the current best match is better than all candidates best_match = ds_util.Datastore(ref='ds-100', name='best-ds-good', capacity=20 * units.Gi, freespace=19 * units.Gi) - rec = vm_util._select_datastore(datastores, + rec = ds_util._select_datastore(datastores, best_match, datastore_regex) self.assertEqual(rec, best_match, "did not match datastore properly") diff --git a/nova/tests/virt/vmwareapi/test_vm_util.py b/nova/tests/virt/vmwareapi/test_vm_util.py index d6d7285fae18..0e7f30f1e284 100644 --- a/nova/tests/virt/vmwareapi/test_vm_util.py +++ b/nova/tests/virt/vmwareapi/test_vm_util.py @@ -22,8 +22,6 @@ import mock from nova import exception from nova.network import model as network_model -from nova.openstack.common.gettextutils import _ -from nova.openstack.common import units from nova.openstack.common import uuidutils from nova import test from nova.tests.virt.vmwareapi import fake @@ -47,28 +45,6 @@ class VMwareVMUtilTestCase(test.NoDBTestCase): super(VMwareVMUtilTestCase, self).tearDown() fake.reset() - def test_get_datastore(self): - fake_objects = fake.FakeRetrieveResult() - fake_objects.add_object(fake.Datastore()) - result = vm_util.get_datastore( - fake.FakeObjectRetrievalSession(fake_objects)) - - self.assertEqual("fake-ds", result.name) - self.assertEqual(units.Ti, result.capacity) - self.assertEqual(500 * units.Gi, result.freespace) - - def test_get_datastore_with_regex(self): - # Test with a regex that matches with a datastore - datastore_valid_regex = re.compile("^openstack.*\d$") - fake_objects = fake.FakeRetrieveResult() - fake_objects.add_object(fake.Datastore("openstack-ds0")) - fake_objects.add_object(fake.Datastore("fake-ds0")) - fake_objects.add_object(fake.Datastore("fake-ds1")) - result = vm_util.get_datastore( - fake.FakeObjectRetrievalSession(fake_objects), - None, None, datastore_valid_regex) - self.assertEqual("openstack-ds0", result.name) - def _test_get_stats_from_cluster(self, connection_state="connected", maintenance_mode=False): ManagedObjectRefs = [fake.ManagedObjectReference("host1", @@ -148,62 +124,6 @@ class VMwareVMUtilTestCase(test.NoDBTestCase): def test_get_stats_from_cluster_hosts_connected_and_maintenance(self): self._test_get_stats_from_cluster(maintenance_mode=True) - def test_get_datastore_with_token(self): - regex = re.compile("^ds.*\d$") - fake0 = fake.FakeRetrieveResult() - fake0.add_object(fake.Datastore("ds0", 10 * units.Gi, 5 * units.Gi)) - fake0.add_object(fake.Datastore("foo", 10 * units.Gi, 9 * units.Gi)) - setattr(fake0, 'token', 'token-0') - fake1 = fake.FakeRetrieveResult() - fake1.add_object(fake.Datastore("ds2", 10 * units.Gi, 8 * units.Gi)) - fake1.add_object(fake.Datastore("ds3", 10 * units.Gi, 1 * units.Gi)) - result = vm_util.get_datastore( - fake.FakeObjectRetrievalSession(fake0, fake1), None, None, regex) - self.assertEqual("ds2", result.name) - - def test_get_datastore_with_list(self): - # Test with a regex containing whitelist of datastores - datastore_valid_regex = re.compile("(openstack-ds0|openstack-ds2)") - fake_objects = fake.FakeRetrieveResult() - fake_objects.add_object(fake.Datastore("openstack-ds0")) - fake_objects.add_object(fake.Datastore("openstack-ds1")) - fake_objects.add_object(fake.Datastore("openstack-ds2")) - result = vm_util.get_datastore( - fake.FakeObjectRetrievalSession(fake_objects), - None, None, datastore_valid_regex) - self.assertNotEqual("openstack-ds1", result.name) - - def test_get_datastore_with_regex_error(self): - # Test with a regex that has no match - # Checks if code raises DatastoreNotFound with a specific message - datastore_invalid_regex = re.compile("unknown-ds") - exp_message = (_("Datastore regex %s did not match any datastores") - % datastore_invalid_regex.pattern) - fake_objects = fake.FakeRetrieveResult() - fake_objects.add_object(fake.Datastore("fake-ds0")) - fake_objects.add_object(fake.Datastore("fake-ds1")) - # assertRaisesRegExp would have been a good choice instead of - # try/catch block, but it's available only from Py 2.7. - try: - vm_util.get_datastore( - fake.FakeObjectRetrievalSession(fake_objects), None, None, - datastore_invalid_regex) - except exception.DatastoreNotFound as e: - self.assertEqual(exp_message, e.args[0]) - else: - self.fail("DatastoreNotFound Exception was not raised with " - "message: %s" % exp_message) - - def test_get_datastore_without_datastore(self): - - self.assertRaises(exception.DatastoreNotFound, - vm_util.get_datastore, - fake.FakeObjectRetrievalSession(None), host="fake-host") - - self.assertRaises(exception.DatastoreNotFound, - vm_util.get_datastore, - fake.FakeObjectRetrievalSession(None), cluster="fake-cluster") - def test_get_host_ref_from_id(self): fake_host_name = "ha-host" fake_host_sys = fake.HostSystem(fake_host_name) @@ -226,11 +146,6 @@ class VMwareVMUtilTestCase(test.NoDBTestCase): vm_util.get_host_ref, fake.FakeObjectRetrievalSession(""), 'fake_cluster') - def test_get_datastore_no_host_in_cluster(self): - self.assertRaises(exception.DatastoreNotFound, - vm_util.get_datastore, - fake.FakeObjectRetrievalSession(""), 'fake_cluster') - @mock.patch.object(vm_util, '_get_vm_ref_from_vm_uuid', return_value=None) def test_get_host_name_for_vm(self, _get_ref_from_uuid): @@ -305,17 +220,6 @@ class VMwareVMUtilTestCase(test.NoDBTestCase): self.assertIsNotNone(prop4) self.assertEqual('bar1', prop4.val) - def test_get_datastore_inaccessible_ds(self): - data_store = fake.Datastore() - data_store.set("summary.accessible", False) - - fake_objects = fake.FakeRetrieveResult() - fake_objects.add_object(data_store) - - self.assertRaises(exception.DatastoreNotFound, - vm_util.get_datastore, - fake.FakeObjectRetrievalSession(fake_objects)) - def test_get_resize_spec(self): fake_instance = {'id': 7, 'name': 'fake!', 'uuid': 'bda5fb9e-b347-40e8-8256-42397848cb00', diff --git a/nova/tests/virt/vmwareapi/test_vmops.py b/nova/tests/virt/vmwareapi/test_vmops.py index 6d1b221f204c..a093bff658cf 100644 --- a/nova/tests/virt/vmwareapi/test_vmops.py +++ b/nova/tests/virt/vmwareapi/test_vmops.py @@ -569,7 +569,7 @@ class VMwareVMOpsTestCase(test.NoDBTestCase): recorded_methods = [c[1][1] for c in mock_call_method.mock_calls] self.assertEqual(expected_methods, recorded_methods) - @mock.patch('nova.virt.vmwareapi.vm_util.get_datastore') + @mock.patch('nova.virt.vmwareapi.ds_util.get_datastore') @mock.patch( 'nova.virt.vmwareapi.vmops.VMwareVCVMOps.get_datacenter_ref_and_name') @mock.patch('nova.virt.vmwareapi.vm_util.get_mo_id_from_instance', diff --git a/nova/virt/vmwareapi/ds_util.py b/nova/virt/vmwareapi/ds_util.py index ad3fa1eda785..cc76b9a70020 100644 --- a/nova/virt/vmwareapi/ds_util.py +++ b/nova/virt/vmwareapi/ds_util.py @@ -17,9 +17,12 @@ Datastore utility functions """ import posixpath +from nova import exception from nova.openstack.common.gettextutils import _ from nova.openstack.common import log as logging from nova.virt.vmwareapi import error_util +from nova.virt.vmwareapi import vim_util +from nova.virt.vmwareapi import vm_util LOG = logging.getLogger(__name__) @@ -158,6 +161,152 @@ def build_datastore_path(datastore_name, path): return str(DatastorePath(datastore_name, path)) +# NOTE(mdbooth): this convenience function is temporarily duplicated in +# vm_util. The correct fix is to handle paginated results as they are returned +# from the relevant vim_util function. However, vim_util is currently +# effectively deprecated as we migrate to oslo.vmware. This duplication will be +# removed when we fix it properly in oslo.vmware. +def _get_token(results): + """Get the token from the property results.""" + return getattr(results, 'token', None) + + +def _select_datastore(data_stores, best_match, datastore_regex=None): + """Find the most preferable datastore in a given RetrieveResult object. + + :param data_stores: a RetrieveResult object from vSphere API call + :param best_match: the current best match for datastore + :param datastore_regex: an optional regular expression to match names + :return: datastore_ref, datastore_name, capacity, freespace + """ + + # data_stores is actually a RetrieveResult object from vSphere API call + for obj_content in data_stores.objects: + # the propset attribute "need not be set" by returning API + if not hasattr(obj_content, 'propSet'): + continue + + propdict = vm_util.propset_dict(obj_content.propSet) + # Local storage identifier vSphere doesn't support CIFS or + # vfat for datastores, therefore filtered + ds_type = propdict['summary.type'] + ds_name = propdict['summary.name'] + if ((ds_type == 'VMFS' or ds_type == 'NFS') and + propdict.get('summary.accessible')): + if datastore_regex is None or datastore_regex.match(ds_name): + new_ds = Datastore( + ref=obj_content.obj, + name=ds_name, + capacity=propdict['summary.capacity'], + freespace=propdict['summary.freeSpace']) + # favor datastores with more free space + if (best_match is None or + new_ds.freespace > best_match.freespace): + best_match = new_ds + + return best_match + + +def get_datastore(session, cluster=None, host=None, datastore_regex=None): + """Get the datastore list and choose the most preferable one.""" + if cluster is None and host is None: + data_stores = session._call_method(vim_util, "get_objects", + "Datastore", ["summary.type", "summary.name", + "summary.capacity", "summary.freeSpace", + "summary.accessible"]) + else: + if cluster is not None: + datastore_ret = session._call_method( + vim_util, + "get_dynamic_property", cluster, + "ClusterComputeResource", "datastore") + else: + datastore_ret = session._call_method( + vim_util, + "get_dynamic_property", host, + "HostSystem", "datastore") + + if not datastore_ret: + raise exception.DatastoreNotFound() + data_store_mors = datastore_ret.ManagedObjectReference + data_stores = session._call_method(vim_util, + "get_properties_for_a_collection_of_objects", + "Datastore", data_store_mors, + ["summary.type", "summary.name", + "summary.capacity", "summary.freeSpace", + "summary.accessible"]) + best_match = None + while data_stores: + best_match = _select_datastore(data_stores, best_match, + datastore_regex) + token = _get_token(data_stores) + if not token: + break + data_stores = session._call_method(vim_util, + "continue_to_get_objects", + token) + if best_match: + return best_match + if datastore_regex: + raise exception.DatastoreNotFound( + _("Datastore regex %s did not match any datastores") + % datastore_regex.pattern) + else: + raise exception.DatastoreNotFound() + + +def _get_allowed_datastores(data_stores, datastore_regex, allowed_types): + allowed = [] + for obj_content in data_stores.objects: + # the propset attribute "need not be set" by returning API + if not hasattr(obj_content, 'propSet'): + continue + + propdict = vm_util.propset_dict(obj_content.propSet) + # Local storage identifier vSphere doesn't support CIFS or + # vfat for datastores, therefore filtered + ds_type = propdict['summary.type'] + ds_name = propdict['summary.name'] + if (propdict['summary.accessible'] and ds_type in allowed_types): + if datastore_regex is None or datastore_regex.match(ds_name): + allowed.append({'ref': obj_content.obj, 'name': ds_name}) + + return allowed + + +def get_available_datastores(session, cluster=None, datastore_regex=None): + """Get the datastore list and choose the first local storage.""" + if cluster: + mobj = cluster + resource_type = "ClusterComputeResource" + else: + mobj = vm_util.get_host_ref(session) + resource_type = "HostSystem" + ds = session._call_method(vim_util, "get_dynamic_property", mobj, + resource_type, "datastore") + if not ds: + return [] + data_store_mors = ds.ManagedObjectReference + # NOTE(garyk): use utility method to retrieve remote objects + data_stores = session._call_method(vim_util, + "get_properties_for_a_collection_of_objects", + "Datastore", data_store_mors, + ["summary.type", "summary.name", "summary.accessible"]) + + allowed = [] + while data_stores: + allowed.extend(_get_allowed_datastores(data_stores, datastore_regex, + ['VMFS', 'NFS'])) + token = _get_token(data_stores) + if not token: + break + + data_stores = session._call_method(vim_util, + "continue_to_get_objects", + token) + return allowed + + def file_delete(session, datastore_path, dc_ref): LOG.debug("Deleting the datastore file %s", datastore_path) vim = session._get_vim() diff --git a/nova/virt/vmwareapi/host.py b/nova/virt/vmwareapi/host.py index b1be80803c7f..ba9a01de759e 100644 --- a/nova/virt/vmwareapi/host.py +++ b/nova/virt/vmwareapi/host.py @@ -21,6 +21,7 @@ from nova import exception from nova.openstack.common import log as logging from nova.openstack.common import units from nova import utils +from nova.virt.vmwareapi import ds_util from nova.virt.vmwareapi import vim_util from nova.virt.vmwareapi import vm_util @@ -80,7 +81,7 @@ class Host(object): def _get_ds_capacity_and_freespace(session, cluster=None): try: - ds = vm_util.get_datastore(session, cluster) + ds = ds_util.get_datastore(session, cluster) return ds.capacity, ds.freespace except exception.DatastoreNotFound: return 0, 0 diff --git a/nova/virt/vmwareapi/vm_util.py b/nova/virt/vmwareapi/vm_util.py index cbeea889e54b..f6e3e7adf2c7 100644 --- a/nova/virt/vmwareapi/vm_util.py +++ b/nova/virt/vmwareapi/vm_util.py @@ -30,7 +30,6 @@ from nova.openstack.common import log as logging from nova.openstack.common import units from nova import utils from nova.virt.vmwareapi import constants -from nova.virt.vmwareapi import ds_util from nova.virt.vmwareapi import error_util from nova.virt.vmwareapi import vim_util @@ -689,6 +688,11 @@ def _get_allocated_vnc_ports(session): return vnc_ports +# NOTE(mdbooth): this convenience function is temporarily duplicated in +# ds_util. The correct fix is to handle paginated results as they are returned +# from the relevant vim_util function. However, vim_util is currently +# effectively deprecated as we migrate to oslo.vmware. This duplication will be +# removed when we fix it properly in oslo.vmware. def _get_token(results): """Get the token from the property results.""" return getattr(results, 'token', None) @@ -1011,142 +1015,6 @@ def propset_dict(propset): return dict([(prop.name, prop.val) for prop in propset]) -def _select_datastore(data_stores, best_match, datastore_regex=None): - """Find the most preferable datastore in a given RetrieveResult object. - - :param data_stores: a RetrieveResult object from vSphere API call - :param best_match: the current best match for datastore - :param datastore_regex: an optional regular expression to match names - :return: datastore_ref, datastore_name, capacity, freespace - """ - - # data_stores is actually a RetrieveResult object from vSphere API call - for obj_content in data_stores.objects: - # the propset attribute "need not be set" by returning API - if not hasattr(obj_content, 'propSet'): - continue - - propdict = propset_dict(obj_content.propSet) - # Local storage identifier vSphere doesn't support CIFS or - # vfat for datastores, therefore filtered - ds_type = propdict['summary.type'] - ds_name = propdict['summary.name'] - if ((ds_type == 'VMFS' or ds_type == 'NFS') and - propdict.get('summary.accessible')): - if datastore_regex is None or datastore_regex.match(ds_name): - new_ds = ds_util.Datastore( - ref=obj_content.obj, - name=ds_name, - capacity=propdict['summary.capacity'], - freespace=propdict['summary.freeSpace']) - # favor datastores with more free space - if (best_match is None or - new_ds.freespace > best_match.freespace): - best_match = new_ds - - return best_match - - -def get_datastore(session, cluster=None, host=None, datastore_regex=None): - """Get the datastore list and choose the most preferable one.""" - if cluster is None and host is None: - data_stores = session._call_method(vim_util, "get_objects", - "Datastore", ["summary.type", "summary.name", - "summary.capacity", "summary.freeSpace", - "summary.accessible"]) - else: - if cluster is not None: - datastore_ret = session._call_method( - vim_util, - "get_dynamic_property", cluster, - "ClusterComputeResource", "datastore") - else: - datastore_ret = session._call_method( - vim_util, - "get_dynamic_property", host, - "HostSystem", "datastore") - - if not datastore_ret: - raise exception.DatastoreNotFound() - data_store_mors = datastore_ret.ManagedObjectReference - data_stores = session._call_method(vim_util, - "get_properties_for_a_collection_of_objects", - "Datastore", data_store_mors, - ["summary.type", "summary.name", - "summary.capacity", "summary.freeSpace", - "summary.accessible"]) - best_match = None - while data_stores: - best_match = _select_datastore(data_stores, best_match, - datastore_regex) - token = _get_token(data_stores) - if not token: - break - data_stores = session._call_method(vim_util, - "continue_to_get_objects", - token) - if best_match: - return best_match - if datastore_regex: - raise exception.DatastoreNotFound( - _("Datastore regex %s did not match any datastores") - % datastore_regex.pattern) - else: - raise exception.DatastoreNotFound() - - -def _get_allowed_datastores(data_stores, datastore_regex, allowed_types): - allowed = [] - for obj_content in data_stores.objects: - # the propset attribute "need not be set" by returning API - if not hasattr(obj_content, 'propSet'): - continue - - propdict = propset_dict(obj_content.propSet) - # Local storage identifier vSphere doesn't support CIFS or - # vfat for datastores, therefore filtered - ds_type = propdict['summary.type'] - ds_name = propdict['summary.name'] - if (propdict['summary.accessible'] and ds_type in allowed_types): - if datastore_regex is None or datastore_regex.match(ds_name): - allowed.append({'ref': obj_content.obj, 'name': ds_name}) - - return allowed - - -def get_available_datastores(session, cluster=None, datastore_regex=None): - """Get the datastore list and choose the first local storage.""" - if cluster: - mobj = cluster - resource_type = "ClusterComputeResource" - else: - mobj = get_host_ref(session) - resource_type = "HostSystem" - ds = session._call_method(vim_util, "get_dynamic_property", mobj, - resource_type, "datastore") - if not ds: - return [] - data_store_mors = ds.ManagedObjectReference - # NOTE(garyk): use utility method to retrieve remote objects - data_stores = session._call_method(vim_util, - "get_properties_for_a_collection_of_objects", - "Datastore", data_store_mors, - ["summary.type", "summary.name", "summary.accessible"]) - - allowed = [] - while data_stores: - allowed.extend(_get_allowed_datastores(data_stores, datastore_regex, - ['VMFS', 'NFS'])) - token = _get_token(data_stores) - if not token: - break - - data_stores = session._call_method(vim_util, - "continue_to_get_objects", - token) - return allowed - - def get_vmdk_backed_disk_uuid(hardware_devices, volume_uuid): if hardware_devices.__class__.__name__ == "ArrayOfVirtualDevice": hardware_devices = hardware_devices.VirtualDevice diff --git a/nova/virt/vmwareapi/vmops.py b/nova/virt/vmwareapi/vmops.py index 50057315dc92..9d7093c7a4df 100644 --- a/nova/virt/vmwareapi/vmops.py +++ b/nova/virt/vmwareapi/vmops.py @@ -195,7 +195,7 @@ class VMwareVMOps(object): (file_type, is_iso) = self._get_disk_format(image_meta) client_factory = self._session._get_vim().client.factory - datastore = vm_util.get_datastore( + datastore = ds_util.get_datastore( self._session, self._cluster, datastore_regex=self._datastore_regex) dc_info = self.get_datacenter_ref_and_name(datastore.ref) @@ -1156,7 +1156,7 @@ class VMwareVMOps(object): step=2, total_steps=RESIZE_TOTAL_STEPS) - ds_ref = vm_util.get_datastore( + ds_ref = ds_util.get_datastore( self._session, self._cluster, host_ref, datastore_regex=self._datastore_regex).ref dc_info = self.get_datacenter_ref_and_name(ds_ref) @@ -1470,7 +1470,7 @@ class VMwareVMOps(object): LOG.debug("Image aging disabled. Aging will not be done.") return - datastores = vm_util.get_available_datastores(self._session, + datastores = ds_util.get_available_datastores(self._session, self._cluster, self._datastore_regex) datastores_info = []