VMware: Storage policy support
vSphere 6.7 added storage policy support for vStorageObject APIs. Adding vSphere storage policy support in vStorageObject driver. Change-Id: I300ecddaac0d882ae32c289d183882c10e3d1aae
This commit is contained in:
parent
85c13f73f2
commit
af54b296e3
@ -65,16 +65,19 @@ class VMwareVStorageObjectDriverTestCase(test.TestCase):
|
|||||||
self._driver = fcd.VMwareVStorageObjectDriver(
|
self._driver = fcd.VMwareVStorageObjectDriver(
|
||||||
configuration=self._config)
|
configuration=self._config)
|
||||||
self._driver._vc_version = self.VC_VERSION
|
self._driver._vc_version = self.VC_VERSION
|
||||||
|
self._driver._storage_policy_enabled = True
|
||||||
self._context = context.get_admin_context()
|
self._context = context.get_admin_context()
|
||||||
|
|
||||||
@mock.patch.object(VMDK_DRIVER, 'do_setup')
|
@mock.patch.object(VMDK_DRIVER, 'do_setup')
|
||||||
@mock.patch.object(FCD_DRIVER, 'volumeops')
|
@mock.patch.object(FCD_DRIVER, 'volumeops')
|
||||||
def test_do_setup(self, vops, vmdk_do_setup):
|
def test_do_setup(self, vops, vmdk_do_setup):
|
||||||
|
self._driver._storage_policy_enabled = False
|
||||||
self._driver.do_setup(self._context)
|
self._driver.do_setup(self._context)
|
||||||
|
|
||||||
vmdk_do_setup.assert_called_once_with(self._context)
|
vmdk_do_setup.assert_called_once_with(self._context)
|
||||||
self.assertFalse(self._driver._storage_policy_enabled)
|
|
||||||
vops.set_vmx_version.assert_called_once_with('vmx-13')
|
vops.set_vmx_version.assert_called_once_with('vmx-13')
|
||||||
self.assertTrue(self._driver._use_fcd_snapshot)
|
self.assertTrue(self._driver._use_fcd_snapshot)
|
||||||
|
self.assertTrue(self._driver._storage_policy_enabled)
|
||||||
|
|
||||||
def test_get_volume_stats(self):
|
def test_get_volume_stats(self):
|
||||||
stats = self._driver.get_volume_stats()
|
stats = self._driver.get_volume_stats()
|
||||||
@ -117,8 +120,12 @@ class VMwareVStorageObjectDriverTestCase(test.TestCase):
|
|||||||
project_id)
|
project_id)
|
||||||
return fake_volume.fake_volume_obj(self._context, **vol)
|
return fake_volume.fake_volume_obj(self._context, **vol)
|
||||||
|
|
||||||
|
@mock.patch.object(FCD_DRIVER, '_get_storage_profile')
|
||||||
@mock.patch.object(FCD_DRIVER, '_select_datastore')
|
@mock.patch.object(FCD_DRIVER, '_select_datastore')
|
||||||
def test_select_ds_fcd(self, select_datastore):
|
def test_select_ds_fcd(self, select_datastore, get_storage_profile):
|
||||||
|
profile = mock.sentinel.profile
|
||||||
|
get_storage_profile.return_value = profile
|
||||||
|
|
||||||
datastore = mock.sentinel.datastore
|
datastore = mock.sentinel.datastore
|
||||||
summary = mock.Mock(datastore=datastore)
|
summary = mock.Mock(datastore=datastore)
|
||||||
select_datastore.return_value = (mock.ANY, mock.ANY, summary)
|
select_datastore.return_value = (mock.ANY, mock.ANY, summary)
|
||||||
@ -126,7 +133,8 @@ class VMwareVStorageObjectDriverTestCase(test.TestCase):
|
|||||||
volume = self._create_volume_obj()
|
volume = self._create_volume_obj()
|
||||||
ret = self._driver._select_ds_fcd(volume)
|
ret = self._driver._select_ds_fcd(volume)
|
||||||
self.assertEqual(datastore, ret)
|
self.assertEqual(datastore, ret)
|
||||||
exp_req = {hub.DatastoreSelector.SIZE_BYTES: volume.size * units.Gi}
|
exp_req = {hub.DatastoreSelector.SIZE_BYTES: volume.size * units.Gi,
|
||||||
|
hub.DatastoreSelector.PROFILE_NAME: profile}
|
||||||
select_datastore.assert_called_once_with(exp_req)
|
select_datastore.assert_called_once_with(exp_req)
|
||||||
|
|
||||||
@mock.patch.object(FCD_DRIVER, '_select_datastore')
|
@mock.patch.object(FCD_DRIVER, '_select_datastore')
|
||||||
@ -177,14 +185,19 @@ class VMwareVStorageObjectDriverTestCase(test.TestCase):
|
|||||||
|
|
||||||
@mock.patch.object(FCD_DRIVER, '_select_ds_fcd')
|
@mock.patch.object(FCD_DRIVER, '_select_ds_fcd')
|
||||||
@mock.patch.object(FCD_DRIVER, '_get_disk_type')
|
@mock.patch.object(FCD_DRIVER, '_get_disk_type')
|
||||||
|
@mock.patch.object(FCD_DRIVER, '_get_storage_profile_id')
|
||||||
@mock.patch.object(FCD_DRIVER, 'volumeops')
|
@mock.patch.object(FCD_DRIVER, 'volumeops')
|
||||||
def test_create_volume(self, vops, get_disk_type, select_ds_fcd):
|
def test_create_volume(self, vops, get_storage_profile_id, get_disk_type,
|
||||||
|
select_ds_fcd):
|
||||||
ds_ref = mock.sentinel.ds_ref
|
ds_ref = mock.sentinel.ds_ref
|
||||||
select_ds_fcd.return_value = ds_ref
|
select_ds_fcd.return_value = ds_ref
|
||||||
|
|
||||||
disk_type = mock.sentinel.disk_type
|
disk_type = mock.sentinel.disk_type
|
||||||
get_disk_type.return_value = disk_type
|
get_disk_type.return_value = disk_type
|
||||||
|
|
||||||
|
profile_id = mock.sentinel.profile_id
|
||||||
|
get_storage_profile_id.return_value = profile_id
|
||||||
|
|
||||||
fcd_loc = mock.Mock()
|
fcd_loc = mock.Mock()
|
||||||
provider_loc = mock.sentinel.provider_loc
|
provider_loc = mock.sentinel.provider_loc
|
||||||
fcd_loc.provider_location.return_value = provider_loc
|
fcd_loc.provider_location.return_value = provider_loc
|
||||||
@ -196,7 +209,8 @@ class VMwareVStorageObjectDriverTestCase(test.TestCase):
|
|||||||
select_ds_fcd.assert_called_once_with(volume)
|
select_ds_fcd.assert_called_once_with(volume)
|
||||||
get_disk_type.assert_called_once_with(volume)
|
get_disk_type.assert_called_once_with(volume)
|
||||||
vops.create_fcd.assert_called_once_with(
|
vops.create_fcd.assert_called_once_with(
|
||||||
volume.name, volume.size * units.Ki, ds_ref, disk_type)
|
volume.name, volume.size * units.Ki, ds_ref, disk_type,
|
||||||
|
profile_id=profile_id)
|
||||||
|
|
||||||
@mock.patch.object(volumeops.FcdLocation, 'from_provider_location')
|
@mock.patch.object(volumeops.FcdLocation, 'from_provider_location')
|
||||||
@mock.patch.object(FCD_DRIVER, 'volumeops')
|
@mock.patch.object(FCD_DRIVER, 'volumeops')
|
||||||
@ -269,10 +283,12 @@ class VMwareVStorageObjectDriverTestCase(test.TestCase):
|
|||||||
'_create_virtual_disk_from_preallocated_image')
|
'_create_virtual_disk_from_preallocated_image')
|
||||||
@mock.patch.object(FCD_DRIVER, 'volumeops')
|
@mock.patch.object(FCD_DRIVER, 'volumeops')
|
||||||
@mock.patch.object(datastore, 'DatastoreURL')
|
@mock.patch.object(datastore, 'DatastoreURL')
|
||||||
|
@mock.patch.object(FCD_DRIVER, '_get_storage_profile_id')
|
||||||
@ddt.data(vmdk.ImageDiskType.PREALLOCATED, vmdk.ImageDiskType.SPARSE,
|
@ddt.data(vmdk.ImageDiskType.PREALLOCATED, vmdk.ImageDiskType.SPARSE,
|
||||||
vmdk.ImageDiskType.STREAM_OPTIMIZED)
|
vmdk.ImageDiskType.STREAM_OPTIMIZED)
|
||||||
def test_copy_image_to_volume(self,
|
def test_copy_image_to_volume(self,
|
||||||
disk_type,
|
disk_type,
|
||||||
|
get_storage_profile_id,
|
||||||
datastore_url_cls,
|
datastore_url_cls,
|
||||||
vops,
|
vops,
|
||||||
create_disk_from_preallocated_image,
|
create_disk_from_preallocated_image,
|
||||||
@ -303,6 +319,9 @@ class VMwareVStorageObjectDriverTestCase(test.TestCase):
|
|||||||
ds_url = mock.sentinel.ds_url
|
ds_url = mock.sentinel.ds_url
|
||||||
datastore_url_cls.return_value = ds_url
|
datastore_url_cls.return_value = ds_url
|
||||||
|
|
||||||
|
profile_id = mock.sentinel.profile_id
|
||||||
|
get_storage_profile_id.return_value = profile_id
|
||||||
|
|
||||||
fcd_loc = mock.Mock()
|
fcd_loc = mock.Mock()
|
||||||
provider_location = mock.sentinel.provider_location
|
provider_location = mock.sentinel.provider_location
|
||||||
fcd_loc.provider_location.return_value = provider_location
|
fcd_loc.provider_location.return_value = provider_location
|
||||||
@ -331,6 +350,7 @@ class VMwareVStorageObjectDriverTestCase(test.TestCase):
|
|||||||
str(ds_url),
|
str(ds_url),
|
||||||
volume.name,
|
volume.name,
|
||||||
summary.datastore)
|
summary.datastore)
|
||||||
|
vops.update_fcd_policy.assert_called_once_with(fcd_loc, profile_id)
|
||||||
|
|
||||||
@mock.patch.object(volumeops.FcdLocation, 'from_provider_location')
|
@mock.patch.object(volumeops.FcdLocation, 'from_provider_location')
|
||||||
@mock.patch.object(FCD_DRIVER, 'volumeops')
|
@mock.patch.object(FCD_DRIVER, 'volumeops')
|
||||||
@ -420,7 +440,7 @@ class VMwareVStorageObjectDriverTestCase(test.TestCase):
|
|||||||
self.assertEqual(dest_fcd_loc, ret)
|
self.assertEqual(dest_fcd_loc, ret)
|
||||||
from_provider_loc.assert_called_once_with(provider_loc)
|
from_provider_loc.assert_called_once_with(provider_loc)
|
||||||
vops.clone_fcd.assert_called_once_with(
|
vops.clone_fcd.assert_called_once_with(
|
||||||
name, fcd_loc, dest_ds_ref, disk_type)
|
name, fcd_loc, dest_ds_ref, disk_type, profile_id=None)
|
||||||
|
|
||||||
@mock.patch.object(FCD_DRIVER, '_select_ds_fcd')
|
@mock.patch.object(FCD_DRIVER, '_select_ds_fcd')
|
||||||
@mock.patch.object(FCD_DRIVER, '_clone_fcd')
|
@mock.patch.object(FCD_DRIVER, '_clone_fcd')
|
||||||
@ -519,16 +539,21 @@ class VMwareVStorageObjectDriverTestCase(test.TestCase):
|
|||||||
|
|
||||||
@mock.patch.object(FCD_DRIVER, '_select_ds_fcd')
|
@mock.patch.object(FCD_DRIVER, '_select_ds_fcd')
|
||||||
@mock.patch.object(FCD_DRIVER, '_get_disk_type')
|
@mock.patch.object(FCD_DRIVER, '_get_disk_type')
|
||||||
|
@mock.patch.object(FCD_DRIVER, '_get_storage_profile_id')
|
||||||
@mock.patch.object(FCD_DRIVER, '_clone_fcd')
|
@mock.patch.object(FCD_DRIVER, '_clone_fcd')
|
||||||
@mock.patch.object(FCD_DRIVER, '_extend_if_needed')
|
@mock.patch.object(FCD_DRIVER, '_extend_if_needed')
|
||||||
def test_create_volume_from_fcd(
|
def test_create_volume_from_fcd(
|
||||||
self, extend_if_needed, clone_fcd, get_disk_type, select_ds_fcd):
|
self, extend_if_needed, clone_fcd, get_storage_profile_id,
|
||||||
|
get_disk_type, select_ds_fcd):
|
||||||
ds_ref = mock.sentinel.ds_ref
|
ds_ref = mock.sentinel.ds_ref
|
||||||
select_ds_fcd.return_value = ds_ref
|
select_ds_fcd.return_value = ds_ref
|
||||||
|
|
||||||
disk_type = mock.sentinel.disk_type
|
disk_type = mock.sentinel.disk_type
|
||||||
get_disk_type.return_value = disk_type
|
get_disk_type.return_value = disk_type
|
||||||
|
|
||||||
|
profile_id = mock.sentinel.profile_id
|
||||||
|
get_storage_profile_id.return_value = profile_id
|
||||||
|
|
||||||
cloned_fcd_loc = mock.Mock()
|
cloned_fcd_loc = mock.Mock()
|
||||||
dest_provider_loc = mock.sentinel.dest_provider_loc
|
dest_provider_loc = mock.sentinel.dest_provider_loc
|
||||||
cloned_fcd_loc.provider_location.return_value = dest_provider_loc
|
cloned_fcd_loc.provider_location.return_value = dest_provider_loc
|
||||||
@ -543,17 +568,19 @@ class VMwareVStorageObjectDriverTestCase(test.TestCase):
|
|||||||
select_ds_fcd.test_assert_called_once_with(volume)
|
select_ds_fcd.test_assert_called_once_with(volume)
|
||||||
get_disk_type.test_assert_called_once_with(volume)
|
get_disk_type.test_assert_called_once_with(volume)
|
||||||
clone_fcd.assert_called_once_with(
|
clone_fcd.assert_called_once_with(
|
||||||
provider_loc, volume.name, ds_ref, disk_type=disk_type)
|
provider_loc, volume.name, ds_ref, disk_type=disk_type,
|
||||||
|
profile_id=profile_id)
|
||||||
extend_if_needed.assert_called_once_with(
|
extend_if_needed.assert_called_once_with(
|
||||||
cloned_fcd_loc, cur_size, volume.size)
|
cloned_fcd_loc, cur_size, volume.size)
|
||||||
|
|
||||||
@mock.patch.object(FCD_DRIVER, '_create_volume_from_fcd')
|
@mock.patch.object(FCD_DRIVER, '_create_volume_from_fcd')
|
||||||
@mock.patch.object(volumeops.FcdSnapshotLocation, 'from_provider_location')
|
@mock.patch.object(volumeops.FcdSnapshotLocation, 'from_provider_location')
|
||||||
|
@mock.patch.object(FCD_DRIVER, '_get_storage_profile_id')
|
||||||
@mock.patch.object(FCD_DRIVER, 'volumeops')
|
@mock.patch.object(FCD_DRIVER, 'volumeops')
|
||||||
@mock.patch.object(FCD_DRIVER, '_extend_if_needed')
|
@mock.patch.object(FCD_DRIVER, '_extend_if_needed')
|
||||||
def _test_create_volume_from_snapshot(
|
def _test_create_volume_from_snapshot(
|
||||||
self, extend_if_needed, vops, from_provider_loc,
|
self, extend_if_needed, vops, get_storage_profile_id,
|
||||||
create_volume_from_fcd, use_fcd_snapshot=False):
|
from_provider_loc, create_volume_from_fcd, use_fcd_snapshot=False):
|
||||||
src_volume = self._create_volume_obj(vol_id=self.SRC_VOL_ID)
|
src_volume = self._create_volume_obj(vol_id=self.SRC_VOL_ID)
|
||||||
snapshot = fake_snapshot.fake_snapshot_obj(
|
snapshot = fake_snapshot.fake_snapshot_obj(
|
||||||
self._context, volume=src_volume)
|
self._context, volume=src_volume)
|
||||||
@ -563,6 +590,9 @@ class VMwareVStorageObjectDriverTestCase(test.TestCase):
|
|||||||
fcd_snap_loc = mock.sentinel.fcd_snap_loc
|
fcd_snap_loc = mock.sentinel.fcd_snap_loc
|
||||||
from_provider_loc.return_value = fcd_snap_loc
|
from_provider_loc.return_value = fcd_snap_loc
|
||||||
|
|
||||||
|
profile_id = mock.sentinel.profile_id
|
||||||
|
get_storage_profile_id.return_value = profile_id
|
||||||
|
|
||||||
fcd_loc = mock.Mock()
|
fcd_loc = mock.Mock()
|
||||||
provider_loc = mock.sentinel.provider_loc
|
provider_loc = mock.sentinel.provider_loc
|
||||||
fcd_loc.provider_location.return_value = provider_loc
|
fcd_loc.provider_location.return_value = provider_loc
|
||||||
@ -574,7 +604,7 @@ class VMwareVStorageObjectDriverTestCase(test.TestCase):
|
|||||||
if use_fcd_snapshot:
|
if use_fcd_snapshot:
|
||||||
self.assertEqual({'provider_location': provider_loc}, ret)
|
self.assertEqual({'provider_location': provider_loc}, ret)
|
||||||
vops.create_fcd_from_snapshot.assert_called_once_with(
|
vops.create_fcd_from_snapshot.assert_called_once_with(
|
||||||
fcd_snap_loc, volume.name)
|
fcd_snap_loc, volume.name, profile_id=profile_id)
|
||||||
extend_if_needed.assert_called_once_with(
|
extend_if_needed.assert_called_once_with(
|
||||||
fcd_loc, snapshot.volume_size, volume.size)
|
fcd_loc, snapshot.volume_size, volume.size)
|
||||||
else:
|
else:
|
||||||
|
@ -1925,13 +1925,18 @@ class VolumeOpsTestCase(test.TestCase):
|
|||||||
|
|
||||||
@mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps.'
|
@mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps.'
|
||||||
'_create_fcd_backing_spec')
|
'_create_fcd_backing_spec')
|
||||||
def test_create_fcd(self, create_fcd_backing_spec):
|
@mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps.'
|
||||||
|
'_create_profile_spec')
|
||||||
|
def test_create_fcd(self, create_profile_spec, create_fcd_backing_spec):
|
||||||
spec = mock.Mock()
|
spec = mock.Mock()
|
||||||
self.session.vim.client.factory.create.return_value = spec
|
self.session.vim.client.factory.create.return_value = spec
|
||||||
|
|
||||||
backing_spec = mock.sentinel.backing_spec
|
backing_spec = mock.sentinel.backing_spec
|
||||||
create_fcd_backing_spec.return_value = backing_spec
|
create_fcd_backing_spec.return_value = backing_spec
|
||||||
|
|
||||||
|
profile_spec = mock.sentinel.profile_spec
|
||||||
|
create_profile_spec.return_value = profile_spec
|
||||||
|
|
||||||
task = mock.sentinel.task
|
task = mock.sentinel.task
|
||||||
self.session.invoke_api.return_value = task
|
self.session.invoke_api.return_value = task
|
||||||
|
|
||||||
@ -1945,7 +1950,9 @@ class VolumeOpsTestCase(test.TestCase):
|
|||||||
ds_ref_val = mock.sentinel.ds_ref_val
|
ds_ref_val = mock.sentinel.ds_ref_val
|
||||||
ds_ref = mock.Mock(value=ds_ref_val)
|
ds_ref = mock.Mock(value=ds_ref_val)
|
||||||
disk_type = mock.sentinel.disk_type
|
disk_type = mock.sentinel.disk_type
|
||||||
ret = self.vops.create_fcd(name, size_mb, ds_ref, disk_type)
|
profile_id = mock.sentinel.profile_id
|
||||||
|
ret = self.vops.create_fcd(
|
||||||
|
name, size_mb, ds_ref, disk_type, profile_id=profile_id)
|
||||||
|
|
||||||
self.assertEqual(fcd_id, ret.fcd_id)
|
self.assertEqual(fcd_id, ret.fcd_id)
|
||||||
self.assertEqual(ds_ref_val, ret.ds_ref_val)
|
self.assertEqual(ds_ref_val, ret.ds_ref_val)
|
||||||
@ -1955,6 +1962,9 @@ class VolumeOpsTestCase(test.TestCase):
|
|||||||
self.assertEqual(1024, spec.capacityInMB)
|
self.assertEqual(1024, spec.capacityInMB)
|
||||||
self.assertEqual(name, spec.name)
|
self.assertEqual(name, spec.name)
|
||||||
self.assertEqual(backing_spec, spec.backingSpec)
|
self.assertEqual(backing_spec, spec.backingSpec)
|
||||||
|
self.assertEqual([profile_spec], spec.profile)
|
||||||
|
create_profile_spec.assert_called_once_with(
|
||||||
|
self.session.vim.client.factory, profile_id)
|
||||||
self.session.invoke_api.assert_called_once_with(
|
self.session.invoke_api.assert_called_once_with(
|
||||||
self.session.vim,
|
self.session.vim,
|
||||||
'CreateDisk_Task',
|
'CreateDisk_Task',
|
||||||
@ -1983,13 +1993,18 @@ class VolumeOpsTestCase(test.TestCase):
|
|||||||
|
|
||||||
@mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps.'
|
@mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps.'
|
||||||
'_create_fcd_backing_spec')
|
'_create_fcd_backing_spec')
|
||||||
def test_clone_fcd(self, create_fcd_backing_spec):
|
@mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps.'
|
||||||
|
'_create_profile_spec')
|
||||||
|
def test_clone_fcd(self, create_profile_spec, create_fcd_backing_spec):
|
||||||
spec = mock.Mock()
|
spec = mock.Mock()
|
||||||
self.session.vim.client.factory.create.return_value = spec
|
self.session.vim.client.factory.create.return_value = spec
|
||||||
|
|
||||||
backing_spec = mock.sentinel.backing_spec
|
backing_spec = mock.sentinel.backing_spec
|
||||||
create_fcd_backing_spec.return_value = backing_spec
|
create_fcd_backing_spec.return_value = backing_spec
|
||||||
|
|
||||||
|
profile_spec = mock.sentinel.profile_spec
|
||||||
|
create_profile_spec.return_value = profile_spec
|
||||||
|
|
||||||
task = mock.sentinel.task
|
task = mock.sentinel.task
|
||||||
self.session.invoke_api.return_value = task
|
self.session.invoke_api.return_value = task
|
||||||
|
|
||||||
@ -2008,7 +2023,9 @@ class VolumeOpsTestCase(test.TestCase):
|
|||||||
dest_ds_ref_val = mock.sentinel.dest_ds_ref_val
|
dest_ds_ref_val = mock.sentinel.dest_ds_ref_val
|
||||||
dest_ds_ref = mock.Mock(value=dest_ds_ref_val)
|
dest_ds_ref = mock.Mock(value=dest_ds_ref_val)
|
||||||
disk_type = mock.sentinel.disk_type
|
disk_type = mock.sentinel.disk_type
|
||||||
ret = self.vops.clone_fcd(name, fcd_location, dest_ds_ref, disk_type)
|
profile_id = mock.sentinel.profile_id
|
||||||
|
ret = self.vops.clone_fcd(
|
||||||
|
name, fcd_location, dest_ds_ref, disk_type, profile_id=profile_id)
|
||||||
|
|
||||||
self.assertEqual(fcd_id, ret.fcd_id)
|
self.assertEqual(fcd_id, ret.fcd_id)
|
||||||
self.assertEqual(dest_ds_ref_val, ret.ds_ref_val)
|
self.assertEqual(dest_ds_ref_val, ret.ds_ref_val)
|
||||||
@ -2017,6 +2034,9 @@ class VolumeOpsTestCase(test.TestCase):
|
|||||||
create_fcd_backing_spec.assert_called_once_with(disk_type, dest_ds_ref)
|
create_fcd_backing_spec.assert_called_once_with(disk_type, dest_ds_ref)
|
||||||
self.assertEqual(name, spec.name)
|
self.assertEqual(name, spec.name)
|
||||||
self.assertEqual(backing_spec, spec.backingSpec)
|
self.assertEqual(backing_spec, spec.backingSpec)
|
||||||
|
self.assertEqual([profile_spec], spec.profile)
|
||||||
|
create_profile_spec.assert_called_once_with(
|
||||||
|
self.session.vim.client.factory, profile_id)
|
||||||
self.session.invoke_api.assert_called_once_with(
|
self.session.invoke_api.assert_called_once_with(
|
||||||
self.session.vim,
|
self.session.vim,
|
||||||
'CloneVStorageObject_Task',
|
'CloneVStorageObject_Task',
|
||||||
@ -2172,10 +2192,15 @@ class VolumeOpsTestCase(test.TestCase):
|
|||||||
snapshotId=fcd_snap_id)
|
snapshotId=fcd_snap_id)
|
||||||
self.session.wait_for_task(task)
|
self.session.wait_for_task(task)
|
||||||
|
|
||||||
def test_create_fcd_from_snapshot(self):
|
@mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps.'
|
||||||
|
'_create_profile_spec')
|
||||||
|
def test_create_fcd_from_snapshot(self, create_profile_spec):
|
||||||
task = mock.sentinel.task
|
task = mock.sentinel.task
|
||||||
self.session.invoke_api.return_value = task
|
self.session.invoke_api.return_value = task
|
||||||
|
|
||||||
|
profile_spec = mock.sentinel.profile_spec
|
||||||
|
create_profile_spec.return_value = profile_spec
|
||||||
|
|
||||||
task_info = mock.Mock()
|
task_info = mock.Mock()
|
||||||
fcd_id = mock.sentinel.fcd_id
|
fcd_id = mock.sentinel.fcd_id
|
||||||
task_info.result.config.id.id = fcd_id
|
task_info.result.config.id.id = fcd_id
|
||||||
@ -2192,10 +2217,14 @@ class VolumeOpsTestCase(test.TestCase):
|
|||||||
fcd_snap_loc.id.return_value = fcd_snap_id
|
fcd_snap_loc.id.return_value = fcd_snap_id
|
||||||
|
|
||||||
name = mock.sentinel.name
|
name = mock.sentinel.name
|
||||||
ret = self.vops.create_fcd_from_snapshot(fcd_snap_loc, name)
|
profile_id = mock.sentinel.profile_id
|
||||||
|
ret = self.vops.create_fcd_from_snapshot(
|
||||||
|
fcd_snap_loc, name, profile_id=profile_id)
|
||||||
|
|
||||||
self.assertEqual(fcd_id, ret.fcd_id)
|
self.assertEqual(fcd_id, ret.fcd_id)
|
||||||
self.assertEqual(ds_ref_val, ret.ds_ref_val)
|
self.assertEqual(ds_ref_val, ret.ds_ref_val)
|
||||||
|
create_profile_spec.assert_called_once_with(
|
||||||
|
self.session.vim.client.factory, profile_id)
|
||||||
self.session.invoke_api.assert_called_once_with(
|
self.session.invoke_api.assert_called_once_with(
|
||||||
self.session.vim,
|
self.session.vim,
|
||||||
'CreateDiskFromSnapshot_Task',
|
'CreateDiskFromSnapshot_Task',
|
||||||
@ -2203,9 +2232,48 @@ class VolumeOpsTestCase(test.TestCase):
|
|||||||
id=fcd_id,
|
id=fcd_id,
|
||||||
datastore=ds_ref,
|
datastore=ds_ref,
|
||||||
snapshotId=fcd_snap_id,
|
snapshotId=fcd_snap_id,
|
||||||
name=name)
|
name=name,
|
||||||
|
profile=[profile_spec])
|
||||||
self.session.wait_for_task.assert_called_once_with(task)
|
self.session.wait_for_task.assert_called_once_with(task)
|
||||||
|
|
||||||
|
@mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps.'
|
||||||
|
'_create_profile_spec')
|
||||||
|
@ddt.data(mock.sentinel.profile_id, None)
|
||||||
|
def test_update_fcd_policy(self, profile_id, create_profile_spec):
|
||||||
|
cf = self.session.vim.client.factory
|
||||||
|
if profile_id:
|
||||||
|
profile_spec = mock.sentinel.profile_spec
|
||||||
|
create_profile_spec.return_value = profile_spec
|
||||||
|
else:
|
||||||
|
empty_profile_spec = mock.sentinel.empty_profile_spec
|
||||||
|
cf.create.return_value = empty_profile_spec
|
||||||
|
|
||||||
|
task = mock.sentinel.task
|
||||||
|
self.session.invoke_api.return_value = task
|
||||||
|
|
||||||
|
fcd_location = mock.Mock()
|
||||||
|
fcd_id = mock.sentinel.fcd_id
|
||||||
|
fcd_location.id.return_value = fcd_id
|
||||||
|
ds_ref = mock.Mock()
|
||||||
|
fcd_location.ds_ref.return_value = ds_ref
|
||||||
|
|
||||||
|
self.vops.update_fcd_policy(fcd_location, profile_id)
|
||||||
|
if profile_id:
|
||||||
|
create_profile_spec.assert_called_once_with(cf, profile_id)
|
||||||
|
exp_profile_spec = profile_spec
|
||||||
|
else:
|
||||||
|
cf.create.assert_called_once_with(
|
||||||
|
'ns0:VirtualMachineEmptyProfileSpec')
|
||||||
|
exp_profile_spec = empty_profile_spec
|
||||||
|
self.session.invoke_api.assert_called_once_with(
|
||||||
|
self.session.vim,
|
||||||
|
'UpdateVStorageObjectPolicy_Task',
|
||||||
|
self.session.vim.service_content.vStorageObjectManager,
|
||||||
|
id=fcd_id,
|
||||||
|
datastore=ds_ref,
|
||||||
|
profile=[exp_profile_spec])
|
||||||
|
self.session.wait_for_task(task)
|
||||||
|
|
||||||
|
|
||||||
class VirtualDiskPathTest(test.TestCase):
|
class VirtualDiskPathTest(test.TestCase):
|
||||||
"""Unit tests for VirtualDiskPath."""
|
"""Unit tests for VirtualDiskPath."""
|
||||||
|
@ -44,7 +44,8 @@ class VMwareVStorageObjectDriver(vmdk.VMwareVcVmdkDriver):
|
|||||||
|
|
||||||
# 1.0 - initial version based on vSphere 6.5 vStorageObject APIs
|
# 1.0 - initial version based on vSphere 6.5 vStorageObject APIs
|
||||||
# 1.1 - support for vStorageObject snapshot APIs
|
# 1.1 - support for vStorageObject snapshot APIs
|
||||||
VERSION = '1.1.0'
|
# 1.2 - support for SPBM storage policies
|
||||||
|
VERSION = '1.2.0'
|
||||||
|
|
||||||
# ThirdPartySystems wiki page
|
# ThirdPartySystems wiki page
|
||||||
CI_WIKI_NAME = "VMware_CI"
|
CI_WIKI_NAME = "VMware_CI"
|
||||||
@ -60,10 +61,11 @@ class VMwareVStorageObjectDriver(vmdk.VMwareVcVmdkDriver):
|
|||||||
:param context: The admin context.
|
:param context: The admin context.
|
||||||
"""
|
"""
|
||||||
super(VMwareVStorageObjectDriver, self).do_setup(context)
|
super(VMwareVStorageObjectDriver, self).do_setup(context)
|
||||||
self._storage_policy_enabled = False
|
|
||||||
self.volumeops.set_vmx_version('vmx-13')
|
self.volumeops.set_vmx_version('vmx-13')
|
||||||
self._use_fcd_snapshot = versionutils.is_compatible(
|
vc_67_compatible = versionutils.is_compatible(
|
||||||
'6.7.0', self._vc_version, same_major=False)
|
'6.7.0', self._vc_version, same_major=False)
|
||||||
|
self._use_fcd_snapshot = vc_67_compatible
|
||||||
|
self._storage_policy_enabled = vc_67_compatible
|
||||||
|
|
||||||
def get_volume_stats(self, refresh=False):
|
def get_volume_stats(self, refresh=False):
|
||||||
"""Collects volume backend stats.
|
"""Collects volume backend stats.
|
||||||
@ -80,6 +82,10 @@ class VMwareVStorageObjectDriver(vmdk.VMwareVcVmdkDriver):
|
|||||||
def _select_ds_fcd(self, volume):
|
def _select_ds_fcd(self, volume):
|
||||||
req = {}
|
req = {}
|
||||||
req[hub.DatastoreSelector.SIZE_BYTES] = volume.size * units.Gi
|
req[hub.DatastoreSelector.SIZE_BYTES] = volume.size * units.Gi
|
||||||
|
|
||||||
|
if self._storage_policy_enabled:
|
||||||
|
req[hub.DatastoreSelector.PROFILE_NAME] = (
|
||||||
|
self._get_storage_profile(volume))
|
||||||
(_host_ref, _resource_pool, summary) = self._select_datastore(req)
|
(_host_ref, _resource_pool, summary) = self._select_datastore(req)
|
||||||
return summary.datastore
|
return summary.datastore
|
||||||
|
|
||||||
@ -106,6 +112,12 @@ class VMwareVStorageObjectDriver(vmdk.VMwareVcVmdkDriver):
|
|||||||
VMwareVStorageObjectDriver, self)._get_disk_type(volume)
|
VMwareVStorageObjectDriver, self)._get_disk_type(volume)
|
||||||
return vops.VirtualDiskType.get_virtual_disk_type(extra_spec_disk_type)
|
return vops.VirtualDiskType.get_virtual_disk_type(extra_spec_disk_type)
|
||||||
|
|
||||||
|
def _get_storage_profile_id(self, volume):
|
||||||
|
if self._storage_policy_enabled:
|
||||||
|
return super(
|
||||||
|
VMwareVStorageObjectDriver, self)._get_storage_profile_id(
|
||||||
|
volume)
|
||||||
|
|
||||||
def create_volume(self, volume):
|
def create_volume(self, volume):
|
||||||
"""Create a new volume on the backend.
|
"""Create a new volume on the backend.
|
||||||
|
|
||||||
@ -114,8 +126,10 @@ class VMwareVStorageObjectDriver(vmdk.VMwareVcVmdkDriver):
|
|||||||
"""
|
"""
|
||||||
disk_type = self._get_disk_type(volume)
|
disk_type = self._get_disk_type(volume)
|
||||||
ds_ref = self._select_ds_fcd(volume)
|
ds_ref = self._select_ds_fcd(volume)
|
||||||
|
profile_id = self._get_storage_profile_id(volume)
|
||||||
fcd_loc = self.volumeops.create_fcd(
|
fcd_loc = self.volumeops.create_fcd(
|
||||||
volume.name, volume.size * units.Ki, ds_ref, disk_type)
|
volume.name, volume.size * units.Ki, ds_ref, disk_type,
|
||||||
|
profile_id=profile_id)
|
||||||
return {'provider_location': fcd_loc.provider_location()}
|
return {'provider_location': fcd_loc.provider_location()}
|
||||||
|
|
||||||
def _delete_fcd(self, provider_loc):
|
def _delete_fcd(self, provider_loc):
|
||||||
@ -204,6 +218,11 @@ class VMwareVStorageObjectDriver(vmdk.VMwareVcVmdkDriver):
|
|||||||
|
|
||||||
fcd_loc = self.volumeops.register_disk(
|
fcd_loc = self.volumeops.register_disk(
|
||||||
str(vmdk_url), volume.name, summary.datastore)
|
str(vmdk_url), volume.name, summary.datastore)
|
||||||
|
|
||||||
|
profile_id = self._get_storage_profile_id(volume)
|
||||||
|
if profile_id:
|
||||||
|
self.volumeops.update_fcd_policy(fcd_loc, profile_id)
|
||||||
|
|
||||||
return {'provider_location': fcd_loc.provider_location()}
|
return {'provider_location': fcd_loc.provider_location()}
|
||||||
|
|
||||||
def copy_volume_to_image(self, context, volume, image_service, image_meta):
|
def copy_volume_to_image(self, context, volume, image_service, image_meta):
|
||||||
@ -264,9 +283,11 @@ class VMwareVStorageObjectDriver(vmdk.VMwareVcVmdkDriver):
|
|||||||
self.volumeops.extend_fcd(fcd_loc, new_size * units.Ki)
|
self.volumeops.extend_fcd(fcd_loc, new_size * units.Ki)
|
||||||
|
|
||||||
def _clone_fcd(self, provider_loc, name, dest_ds_ref,
|
def _clone_fcd(self, provider_loc, name, dest_ds_ref,
|
||||||
disk_type=vops.VirtualDiskType.THIN):
|
disk_type=vops.VirtualDiskType.THIN,
|
||||||
|
profile_id=None):
|
||||||
fcd_loc = vops.FcdLocation.from_provider_location(provider_loc)
|
fcd_loc = vops.FcdLocation.from_provider_location(provider_loc)
|
||||||
return self.volumeops.clone_fcd(name, fcd_loc, dest_ds_ref, disk_type)
|
return self.volumeops.clone_fcd(
|
||||||
|
name, fcd_loc, dest_ds_ref, disk_type, profile_id=profile_id)
|
||||||
|
|
||||||
def create_snapshot(self, snapshot):
|
def create_snapshot(self, snapshot):
|
||||||
"""Creates a snapshot.
|
"""Creates a snapshot.
|
||||||
@ -309,8 +330,10 @@ class VMwareVStorageObjectDriver(vmdk.VMwareVcVmdkDriver):
|
|||||||
def _create_volume_from_fcd(self, provider_loc, cur_size, volume):
|
def _create_volume_from_fcd(self, provider_loc, cur_size, volume):
|
||||||
ds_ref = self._select_ds_fcd(volume)
|
ds_ref = self._select_ds_fcd(volume)
|
||||||
disk_type = self._get_disk_type(volume)
|
disk_type = self._get_disk_type(volume)
|
||||||
|
profile_id = self._get_storage_profile_id(volume)
|
||||||
cloned_fcd_loc = self._clone_fcd(
|
cloned_fcd_loc = self._clone_fcd(
|
||||||
provider_loc, volume.name, ds_ref, disk_type=disk_type)
|
provider_loc, volume.name, ds_ref, disk_type=disk_type,
|
||||||
|
profile_id=profile_id)
|
||||||
self._extend_if_needed(cloned_fcd_loc, cur_size, volume.size)
|
self._extend_if_needed(cloned_fcd_loc, cur_size, volume.size)
|
||||||
return {'provider_location': cloned_fcd_loc.provider_location()}
|
return {'provider_location': cloned_fcd_loc.provider_location()}
|
||||||
|
|
||||||
@ -324,8 +347,9 @@ class VMwareVStorageObjectDriver(vmdk.VMwareVcVmdkDriver):
|
|||||||
fcd_snap_loc = vops.FcdSnapshotLocation.from_provider_location(
|
fcd_snap_loc = vops.FcdSnapshotLocation.from_provider_location(
|
||||||
snapshot.provider_location)
|
snapshot.provider_location)
|
||||||
if fcd_snap_loc:
|
if fcd_snap_loc:
|
||||||
|
profile_id = self._get_storage_profile_id(volume)
|
||||||
fcd_loc = self.volumeops.create_fcd_from_snapshot(
|
fcd_loc = self.volumeops.create_fcd_from_snapshot(
|
||||||
fcd_snap_loc, volume.name)
|
fcd_snap_loc, volume.name, profile_id=profile_id)
|
||||||
self._extend_if_needed(fcd_loc, snapshot.volume_size, volume.size)
|
self._extend_if_needed(fcd_loc, snapshot.volume_size, volume.size)
|
||||||
return {'provider_location': fcd_loc.provider_location()}
|
return {'provider_location': fcd_loc.provider_location()}
|
||||||
else:
|
else:
|
||||||
|
@ -1783,12 +1783,22 @@ class VMwareVolumeOps(object):
|
|||||||
backing_spec.datastore = ds_ref
|
backing_spec.datastore = ds_ref
|
||||||
return backing_spec
|
return backing_spec
|
||||||
|
|
||||||
def create_fcd(self, name, size_mb, ds_ref, disk_type):
|
def _create_profile_spec(self, cf, profile_id):
|
||||||
spec = self._session.vim.client.factory.create('ns0:VslmCreateSpec')
|
profile_spec = cf.create('ns0:VirtualMachineDefinedProfileSpec')
|
||||||
|
profile_spec.profileId = profile_id
|
||||||
|
return profile_spec
|
||||||
|
|
||||||
|
def create_fcd(self, name, size_mb, ds_ref, disk_type, profile_id=None):
|
||||||
|
cf = self._session.vim.client.factory
|
||||||
|
spec = cf.create('ns0:VslmCreateSpec')
|
||||||
spec.capacityInMB = size_mb
|
spec.capacityInMB = size_mb
|
||||||
spec.name = name
|
spec.name = name
|
||||||
spec.backingSpec = self._create_fcd_backing_spec(disk_type, ds_ref)
|
spec.backingSpec = self._create_fcd_backing_spec(disk_type, ds_ref)
|
||||||
|
|
||||||
|
if profile_id:
|
||||||
|
profile_spec = self._create_profile_spec(cf, profile_id)
|
||||||
|
spec.profile = [profile_spec]
|
||||||
|
|
||||||
LOG.debug("Creating fcd with spec: %(spec)s on datastore: %(ds_ref)s.",
|
LOG.debug("Creating fcd with spec: %(spec)s on datastore: %(ds_ref)s.",
|
||||||
{'spec': spec, 'ds_ref': ds_ref})
|
{'spec': spec, 'ds_ref': ds_ref})
|
||||||
vstorage_mgr = self._session.vim.service_content.vStorageObjectManager
|
vstorage_mgr = self._session.vim.service_content.vStorageObjectManager
|
||||||
@ -1812,13 +1822,18 @@ class VMwareVolumeOps(object):
|
|||||||
datastore=fcd_location.ds_ref())
|
datastore=fcd_location.ds_ref())
|
||||||
self._session.wait_for_task(task)
|
self._session.wait_for_task(task)
|
||||||
|
|
||||||
def clone_fcd(self, name, fcd_location, dest_ds_ref, disk_type):
|
def clone_fcd(
|
||||||
|
self, name, fcd_location, dest_ds_ref, disk_type, profile_id=None):
|
||||||
cf = self._session.vim.client.factory
|
cf = self._session.vim.client.factory
|
||||||
spec = cf.create('ns0:VslmCloneSpec')
|
spec = cf.create('ns0:VslmCloneSpec')
|
||||||
spec.name = name
|
spec.name = name
|
||||||
spec.backingSpec = self._create_fcd_backing_spec(disk_type,
|
spec.backingSpec = self._create_fcd_backing_spec(disk_type,
|
||||||
dest_ds_ref)
|
dest_ds_ref)
|
||||||
|
|
||||||
|
if profile_id:
|
||||||
|
profile_spec = self._create_profile_spec(cf, profile_id)
|
||||||
|
spec.profile = [profile_spec]
|
||||||
|
|
||||||
LOG.debug("Copying fcd: %(fcd_loc)s to datastore: %(ds_ref)s with "
|
LOG.debug("Copying fcd: %(fcd_loc)s to datastore: %(ds_ref)s with "
|
||||||
"spec: %(spec)s.",
|
"spec: %(spec)s.",
|
||||||
{'fcd_loc': fcd_location,
|
{'fcd_loc': fcd_location,
|
||||||
@ -1921,12 +1936,16 @@ class VMwareVolumeOps(object):
|
|||||||
snapshotId=fcd_snap_loc.id(cf))
|
snapshotId=fcd_snap_loc.id(cf))
|
||||||
self._session.wait_for_task(task)
|
self._session.wait_for_task(task)
|
||||||
|
|
||||||
def create_fcd_from_snapshot(self, fcd_snap_loc, name):
|
def create_fcd_from_snapshot(self, fcd_snap_loc, name, profile_id=None):
|
||||||
LOG.debug("Creating fcd with name: %(name)s from fcd snapshot: "
|
LOG.debug("Creating fcd with name: %(name)s from fcd snapshot: "
|
||||||
"%(snap)s.", {'name': name, 'snap': fcd_snap_loc})
|
"%(snap)s.", {'name': name, 'snap': fcd_snap_loc})
|
||||||
|
|
||||||
vstorage_mgr = self._session.vim.service_content.vStorageObjectManager
|
vstorage_mgr = self._session.vim.service_content.vStorageObjectManager
|
||||||
cf = self._session.vim.client.factory
|
cf = self._session.vim.client.factory
|
||||||
|
if profile_id:
|
||||||
|
profile = [self._create_profile_spec(cf, profile_id)]
|
||||||
|
else:
|
||||||
|
profile = None
|
||||||
task = self._session.invoke_api(
|
task = self._session.invoke_api(
|
||||||
self._session.vim,
|
self._session.vim,
|
||||||
'CreateDiskFromSnapshot_Task',
|
'CreateDiskFromSnapshot_Task',
|
||||||
@ -1934,7 +1953,8 @@ class VMwareVolumeOps(object):
|
|||||||
id=fcd_snap_loc.fcd_loc.id(cf),
|
id=fcd_snap_loc.fcd_loc.id(cf),
|
||||||
datastore=fcd_snap_loc.fcd_loc.ds_ref(),
|
datastore=fcd_snap_loc.fcd_loc.ds_ref(),
|
||||||
snapshotId=fcd_snap_loc.id(cf),
|
snapshotId=fcd_snap_loc.id(cf),
|
||||||
name=name)
|
name=name,
|
||||||
|
profile=profile)
|
||||||
task_info = self._session.wait_for_task(task)
|
task_info = self._session.wait_for_task(task)
|
||||||
fcd_loc = FcdLocation.create(task_info.result.config.id,
|
fcd_loc = FcdLocation.create(task_info.result.config.id,
|
||||||
fcd_snap_loc.fcd_loc.ds_ref())
|
fcd_snap_loc.fcd_loc.ds_ref())
|
||||||
@ -1942,6 +1962,27 @@ class VMwareVolumeOps(object):
|
|||||||
LOG.debug("Created fcd: %s.", fcd_loc)
|
LOG.debug("Created fcd: %s.", fcd_loc)
|
||||||
return fcd_loc
|
return fcd_loc
|
||||||
|
|
||||||
|
def update_fcd_policy(self, fcd_location, profile_id):
|
||||||
|
LOG.debug("Changing fcd: %(fcd_loc)s storage policy to %(policy)s.",
|
||||||
|
{'fcd_loc': fcd_location, 'policy': profile_id})
|
||||||
|
|
||||||
|
vstorage_mgr = self._session.vim.service_content.vStorageObjectManager
|
||||||
|
cf = self._session.vim.client.factory
|
||||||
|
if profile_id is None:
|
||||||
|
profile_spec = cf.create('ns0:VirtualMachineEmptyProfileSpec')
|
||||||
|
else:
|
||||||
|
profile_spec = self._create_profile_spec(cf, profile_id)
|
||||||
|
task = self._session.invoke_api(
|
||||||
|
self._session.vim,
|
||||||
|
'UpdateVStorageObjectPolicy_Task',
|
||||||
|
vstorage_mgr,
|
||||||
|
id=fcd_location.id(cf),
|
||||||
|
datastore=fcd_location.ds_ref(),
|
||||||
|
profile=[profile_spec])
|
||||||
|
self._session.wait_for_task(task)
|
||||||
|
|
||||||
|
LOG.debug("Updated fcd storage policy to %s.", profile_id)
|
||||||
|
|
||||||
|
|
||||||
class FcdLocation(object):
|
class FcdLocation(object):
|
||||||
|
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Added vSphere storage policy support in VMwareVStorageObjectDriver.
|
||||||
|
The storage policies that must be associated with the volumes can
|
||||||
|
be specified using volume type extra-spec key 'vmware:storage_profile'
|
||||||
|
similar to VMware VMDK driver. The vSphere version must be 6.7 or
|
||||||
|
above to use this feature.
|
Loading…
Reference in New Issue
Block a user