TMP_DIR = "/vmware-tmp"
CA_FILE = "/etc/ssl/rui-ca-cert.pem"
VMDK_DRIVER = vmdk.VMwareEsxVmdkDriver
+ CLUSTERS = ["cls-1", "cls-2"]
def setUp(self):
super(VMwareEsxVmdkDriverTestCase, self).setUp()
self._config.vmware_tmp_dir = self.TMP_DIR
self._config.vmware_ca_file = self.CA_FILE
self._config.vmware_insecure = False
+ self._config.vmware_cluster_name = self.CLUSTERS
self._db = mock.Mock()
self._driver = vmdk.VMwareEsxVmdkDriver(configuration=self._config,
db=self._db)
- api_retry_count = self._config.vmware_api_retry_count,
+ api_retry_count = self._config.vmware_api_retry_count
task_poll_interval = self._config.vmware_task_poll_interval,
self._session = api.VMwareAPISession(self.IP, self.USERNAME,
self.PASSWORD, api_retry_count,
version = self._driver._get_vc_version()
self.assertEqual(ver.LooseVersion('6.0.1'), version)
+ @mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps')
@mock.patch('cinder.volume.drivers.vmware.vmdk.VMwareVcVmdkDriver.'
'_get_vc_version')
@mock.patch('cinder.volume.drivers.vmware.vmdk.VMwareVcVmdkDriver.'
'session', new_callable=mock.PropertyMock)
- def test_do_setup_with_pbm_disabled(self, session, get_vc_version):
+ def test_do_setup_with_pbm_disabled(self, session, get_vc_version,
+ vops_cls):
session_obj = mock.Mock(name='session')
session.return_value = session_obj
get_vc_version.return_value = ver.LooseVersion('5.0')
+ cluster_refs = mock.Mock()
+ cluster_refs.values.return_value = mock.sentinel.cluster_refs
+ vops = mock.Mock()
+ vops.get_cluster_refs.return_value = cluster_refs
+
+ def vops_side_effect(session, max_objects):
+ vops._session = session
+ vops._max_objects = max_objects
+ return vops
+
+ vops_cls.side_effect = vops_side_effect
+
self._driver.do_setup(mock.ANY)
self.assertFalse(self._driver._storage_policy_enabled)
get_vc_version.assert_called_once_with()
self.assertEqual(session_obj, self._driver.volumeops._session)
self.assertEqual(session_obj, self._driver.ds_sel._session)
+ self.assertEqual(mock.sentinel.cluster_refs, self._driver._clusters)
+ vops.get_cluster_refs.assert_called_once_with(self.CLUSTERS)
@mock.patch('oslo_vmware.pbm.get_pbm_wsdl_location')
@mock.patch('cinder.volume.drivers.vmware.vmdk.VMwareVcVmdkDriver.'
get_pbm_wsdl_location.assert_called_once_with(
six.text_type(vc_version))
+ @mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps')
@mock.patch('oslo_vmware.pbm.get_pbm_wsdl_location')
@mock.patch('cinder.volume.drivers.vmware.vmdk.VMwareVcVmdkDriver.'
'_get_vc_version')
@mock.patch('cinder.volume.drivers.vmware.vmdk.VMwareVcVmdkDriver.'
'session', new_callable=mock.PropertyMock)
- def test_do_setup(self, session, get_vc_version, get_pbm_wsdl_location):
+ def test_do_setup(self, session, get_vc_version, get_pbm_wsdl_location,
+ vops_cls):
session_obj = mock.Mock(name='session')
session.return_value = session_obj
get_vc_version.return_value = vc_version
get_pbm_wsdl_location.return_value = 'file:///pbm.wsdl'
+ cluster_refs = mock.Mock()
+ cluster_refs.values.return_value = mock.sentinel.cluster_refs
+ vops = mock.Mock()
+ vops.get_cluster_refs.return_value = cluster_refs
+
+ def vops_side_effect(session, max_objects):
+ vops._session = session
+ vops._max_objects = max_objects
+ return vops
+
+ vops_cls.side_effect = vops_side_effect
+
self._driver.do_setup(mock.ANY)
self.assertTrue(self._driver._storage_policy_enabled)
six.text_type(vc_version))
self.assertEqual(session_obj, self._driver.volumeops._session)
self.assertEqual(session_obj, self._driver.ds_sel._session)
+ self.assertEqual(mock.sentinel.cluster_refs, self._driver._clusters)
+ vops.get_cluster_refs.assert_called_once_with(self.CLUSTERS)
@mock.patch.object(VMDK_DRIVER, '_extend_volumeops_virtual_disk')
@mock.patch.object(VMDK_DRIVER, '_create_backing')
close.assert_called_once_with(fd)
delete_if_exists.assert_called_once_with(tmp)
+ @mock.patch.object(VMDK_DRIVER, 'volumeops')
+ @mock.patch.object(VMDK_DRIVER, 'ds_sel')
+ def test_select_datastore(self, ds_sel, vops):
+ cls_1 = mock.sentinel.cls_1
+ cls_2 = mock.sentinel.cls_2
+ self._driver._clusters = [cls_1, cls_2]
+
+ host_1 = mock.sentinel.host_1
+ host_2 = mock.sentinel.host_2
+ host_3 = mock.sentinel.host_3
+ vops.get_cluster_hosts.side_effect = [[host_1, host_2], [host_3]]
+
+ best_candidate = mock.sentinel.best_candidate
+ ds_sel.select_datastore.return_value = best_candidate
+
+ req = mock.sentinel.req
+ self.assertEqual(best_candidate, self._driver._select_datastore(req))
+
+ exp_calls = [mock.call(cls_1), mock.call(cls_2)]
+ self.assertEqual(exp_calls, vops.get_cluster_hosts.call_args_list)
+
+ ds_sel.select_datastore.assert_called_once_with(
+ req, hosts=[host_1, host_2, host_3])
+
+ @mock.patch.object(VMDK_DRIVER, 'volumeops')
+ @mock.patch.object(VMDK_DRIVER, 'ds_sel')
+ def test_select_datastore_with_no_best_candidate(self, ds_sel, vops):
+ cls_1 = mock.sentinel.cls_1
+ cls_2 = mock.sentinel.cls_2
+ self._driver._clusters = [cls_1, cls_2]
+
+ host_1 = mock.sentinel.host_1
+ host_2 = mock.sentinel.host_2
+ host_3 = mock.sentinel.host_3
+ vops.get_cluster_hosts.side_effect = [[host_1, host_2], [host_3]]
+
+ ds_sel.select_datastore.return_value = ()
+
+ req = mock.sentinel.req
+ self.assertRaises(vmdk_exceptions.NoValidDatastoreException,
+ self._driver._select_datastore,
+ req)
+
+ exp_calls = [mock.call(cls_1), mock.call(cls_2)]
+ self.assertEqual(exp_calls, vops.get_cluster_hosts.call_args_list)
+
+ ds_sel.select_datastore.assert_called_once_with(
+ req, hosts=[host_1, host_2, host_3])
+
+ @mock.patch.object(VMDK_DRIVER, 'volumeops')
+ @mock.patch.object(VMDK_DRIVER, 'ds_sel')
+ def test_select_datastore_with_single_host(self, ds_sel, vops):
+ cls_1 = mock.sentinel.cls_1
+ cls_2 = mock.sentinel.cls_2
+ self._driver._clusters = [cls_1, cls_2]
+
+ host_1 = mock.sentinel.host_1
+
+ best_candidate = mock.sentinel.best_candidate
+ ds_sel.select_datastore.return_value = best_candidate
+
+ req = mock.sentinel.req
+ self.assertEqual(best_candidate,
+ self._driver._select_datastore(req, host_1))
+
+ ds_sel.select_datastore.assert_called_once_with(req, hosts=[host_1])
+ self.assertFalse(vops.get_cluster_hosts.called)
+
+ @mock.patch.object(VMDK_DRIVER, 'volumeops')
+ @mock.patch.object(VMDK_DRIVER, 'ds_sel')
+ def test_select_datastore_with_empty_clusters(self, ds_sel, vops):
+ self._driver._clusters = None
+
+ best_candidate = mock.sentinel.best_candidate
+ ds_sel.select_datastore.return_value = best_candidate
+
+ req = mock.sentinel.req
+ self.assertEqual(best_candidate, self._driver._select_datastore(req))
+
+ ds_sel.select_datastore.assert_called_once_with(req, hosts=None)
+ self.assertFalse(vops.get_cluster_hosts.called)
+
+ @mock.patch.object(VMDK_DRIVER, 'volumeops')
+ @mock.patch.object(VMDK_DRIVER, 'ds_sel')
+ def test_select_datastore_with_no_valid_host(self, ds_sel, vops):
+ cls_1 = mock.sentinel.cls_1
+ cls_2 = mock.sentinel.cls_2
+ self._driver._clusters = [cls_1, cls_2]
+
+ vops.get_cluster_hosts.side_effect = [[], []]
+
+ req = mock.sentinel.req
+ self.assertRaises(vmdk_exceptions.NoValidHostException,
+ self._driver._select_datastore, req)
+
+ exp_calls = [mock.call(cls_1), mock.call(cls_2)]
+ self.assertEqual(exp_calls, vops.get_cluster_hosts.call_args_list)
+
+ self.assertFalse(ds_sel.called)
+
@mock.patch.object(VMDK_DRIVER, 'volumeops')
@mock.patch.object(VMDK_DRIVER, 'ds_sel')
def test_relocate_backing_nop(self, ds_sel, vops):
eagerZero=False)
self.session.wait_for_task.assert_called_once_with(task)
+ @mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps.'
+ '_get_all_clusters')
+ def test_get_cluster_refs(self, get_all_clusters):
+ cls_1 = mock.sentinel.cls_1
+ cls_2 = mock.sentinel.cls_2
+ clusters = {"cls_1": cls_1, "cls_2": cls_2}
+ get_all_clusters.return_value = clusters
+
+ self.assertEqual({"cls_2": cls_2},
+ self.vops.get_cluster_refs(["cls_2"]))
+
+ @mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps.'
+ '_get_all_clusters')
+ def test_get_cluster_refs_with_invalid_cluster(self, get_all_clusters):
+ cls_1 = mock.sentinel.cls_1
+ cls_2 = mock.sentinel.cls_2
+ clusters = {"cls_1": cls_1, "cls_2": cls_2}
+ get_all_clusters.return_value = clusters
+
+ self.assertRaises(vmdk_exceptions.ClusterNotFoundException,
+ self.vops.get_cluster_refs,
+ ["cls_1", "cls_3"])
+
+ def test_get_cluster_hosts(self):
+ host_1 = mock.sentinel.host_1
+ host_2 = mock.sentinel.host_2
+ hosts = mock.Mock(ManagedObjectReference=[host_1, host_2])
+ self.session.invoke_api.return_value = hosts
+
+ cluster = mock.sentinel.cluster
+ ret = self.vops.get_cluster_hosts(cluster)
+
+ self.assertEqual([host_1, host_2], ret)
+ self.session.invoke_api.assert_called_once_with(vim_util,
+ 'get_object_property',
+ self.session.vim,
+ cluster,
+ 'host')
+
+ def test_get_cluster_hosts_with_no_host(self):
+ self.session.invoke_api.return_value = None
+
+ cluster = mock.sentinel.cluster
+ ret = self.vops.get_cluster_hosts(cluster)
+
+ self.assertEqual([], ret)
+ self.session.invoke_api.assert_called_once_with(vim_util,
+ 'get_object_property',
+ self.session.vim,
+ cluster,
+ 'host')
+
class VirtualDiskPathTest(test.TestCase):
"""Unit tests for VirtualDiskPath."""
'verified. If false, then the default CA truststore is '
'used for verification. This option is ignored if '
'"vmware_ca_file" is set.'),
+ cfg.MultiStrOpt('vmware_cluster_name',
+ default=None,
+ help='Name of a vCenter compute cluster where volumes '
+ 'should be created.'),
]
CONF = cfg.CONF
# directly to ESX
self._storage_policy_enabled = False
self._ds_sel = None
+ self._clusters = None
@property
def session(self):
def _relocate_backing(self, volume, backing, host):
pass
+ def _get_hosts(self, clusters):
+ hosts = []
+ if clusters:
+ for cluster in clusters:
+ hosts.extend(self.volumeops.get_cluster_hosts(cluster))
+ return hosts
+
def _select_datastore(self, req, host=None):
"""Selects datastore satisfying the given requirements.
:return: (host, resource_pool, summary)
"""
+ hosts = None
+ if host:
+ hosts = [host]
+ elif self._clusters:
+ hosts = self._get_hosts(self._clusters)
+ if not hosts:
+ LOG.error(_LE("There are no valid hosts available in "
+ "configured cluster(s): %s."), self._clusters)
+ raise vmdk_exceptions.NoValidHostException()
- hosts = [host] if host else None
best_candidate = self.ds_sel.select_datastore(req, hosts=hosts)
if not best_candidate:
LOG.error(_LE("There is no valid datastore satisfying "
self._volumeops = volumeops.VMwareVolumeOps(self.session, max_objects)
self._ds_sel = hub.DatastoreSelector(self.volumeops, self.session)
+ # Get clusters to be used for backing VM creation.
+ cluster_names = self.configuration.vmware_cluster_name
+ if cluster_names:
+ self._clusters = self.volumeops.get_cluster_refs(
+ cluster_names).values()
+ LOG.info(_LI("Using compute cluster(s): %s."), cluster_names)
+
LOG.info(_LI("Successfully setup driver: %(driver)s for server: "
"%(ip)s."), {'driver': self.__class__.__name__,
'ip': self.configuration.vmware_host_ip})
req[hub.DatastoreSelector.PROFILE_NAME] = backing_profile
# Select datastore satisfying the requirements.
- best_candidate = self.ds_sel.select_datastore(req, hosts=[host])
- if not best_candidate:
- # No candidate datastore to relocate.
- msg = _("There are no datastores matching volume requirements;"
- " can't relocate volume: %s.") % volume['name']
- LOG.error(msg)
- raise vmdk_exceptions.NoValidDatastoreException(msg)
-
- (host, resource_pool, summary) = best_candidate
+ (host, resource_pool, summary) = self._select_datastore(req, host)
dc = self.volumeops.get_dc(resource_pool)
folder = self._get_volume_group_folder(dc)