Dell SC: Missing volume creation options.

The Dell SC driver is missing options for Data Reduction,
Group QOS and Volume QOS. Added.

Change-Id: I01951e41eea9985471830b5410892be37e13805a
This commit is contained in:
Tom Swanson 2016-12-05 17:16:40 -06:00
parent 94b5afc75f
commit c5368a7394
6 changed files with 1045 additions and 129 deletions

View File

@ -898,6 +898,10 @@ class DellDriverRetryableException(VolumeBackendAPIException):
message = _("Retryable Dell Exception encountered") message = _("Retryable Dell Exception encountered")
class DellDriverUnknownSpec(VolumeDriverException):
message = _("Dell driver failure: %(reason)s")
# Pure Storage # Pure Storage
class PureDriverException(VolumeDriverException): class PureDriverException(VolumeDriverException):
message = _("Pure Storage Cinder driver failure: %(reason)s") message = _("Pure Storage Cinder driver failure: %(reason)s")

View File

@ -568,10 +568,8 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
mock_init): mock_init):
volume = {'id': fake.VOLUME_ID, 'size': 1} volume = {'id': fake.VOLUME_ID, 'size': 1}
self.driver.create_volume(volume) self.driver.create_volume(volume)
mock_create_volume.assert_called_once_with(fake.VOLUME_ID, mock_create_volume.assert_called_once_with(
1, fake.VOLUME_ID, 1, None, None, None, None, None)
None,
None)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi, @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'find_replay_profile', 'find_replay_profile',
@ -591,13 +589,65 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
volume = {'id': fake.VOLUME_ID, 'size': 1, volume = {'id': fake.VOLUME_ID, 'size': 1,
'consistencygroup_id': fake.CONSISTENCY_GROUP_ID} 'consistencygroup_id': fake.CONSISTENCY_GROUP_ID}
self.driver.create_volume(volume) self.driver.create_volume(volume)
mock_create_volume.assert_called_once_with(fake.VOLUME_ID, mock_create_volume.assert_called_once_with(
1, fake.VOLUME_ID, 1, None, None, None, None, None)
None,
None)
self.assertTrue(mock_find_replay_profile.called) self.assertTrue(mock_find_replay_profile.called)
self.assertTrue(mock_update_cg_volumes.called) self.assertTrue(mock_update_cg_volumes.called)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'create_volume',
return_value=VOLUME)
@mock.patch.object(
volume_types,
'get_volume_type_extra_specs',
return_value={'storagetype:volumeqos': 'volumeqos'})
def test_create_volume_volumeqos_profile(self,
mock_extra,
mock_create_volume,
mock_close_connection,
mock_open_connection,
mock_init):
volume = {'id': fake.VOLUME_ID, 'size': 1, 'volume_type_id': 'abc'}
self.driver.create_volume(volume)
mock_create_volume.assert_called_once_with(
fake.VOLUME_ID, 1, None, None, 'volumeqos', None, None)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'create_volume',
return_value=VOLUME)
@mock.patch.object(
volume_types,
'get_volume_type_extra_specs',
return_value={'storagetype:groupqos': 'groupqos'})
def test_create_volume_groupqos_profile(self,
mock_extra,
mock_create_volume,
mock_close_connection,
mock_open_connection,
mock_init):
volume = {'id': fake.VOLUME_ID, 'size': 1, 'volume_type_id': 'abc'}
self.driver.create_volume(volume)
mock_create_volume.assert_called_once_with(
fake.VOLUME_ID, 1, None, None, None, 'groupqos', None)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'create_volume',
return_value=VOLUME)
@mock.patch.object(
volume_types,
'get_volume_type_extra_specs',
return_value={'storagetype:datareductionprofile': 'drprofile'})
def test_create_volume_data_reduction_profile(self,
mock_extra,
mock_create_volume,
mock_close_connection,
mock_open_connection,
mock_init):
volume = {'id': fake.VOLUME_ID, 'size': 1, 'volume_type_id': 'abc'}
self.driver.create_volume(volume)
mock_create_volume.assert_called_once_with(
fake.VOLUME_ID, 1, None, None, None, None, 'drprofile')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi, @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'create_volume', 'create_volume',
return_value=VOLUME) return_value=VOLUME)
@ -613,10 +663,8 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
mock_init): mock_init):
volume = {'id': fake.VOLUME_ID, 'size': 1, 'volume_type_id': 'abc'} volume = {'id': fake.VOLUME_ID, 'size': 1, 'volume_type_id': 'abc'}
self.driver.create_volume(volume) self.driver.create_volume(volume)
mock_create_volume.assert_called_once_with(fake.VOLUME_ID, mock_create_volume.assert_called_once_with(
1, fake.VOLUME_ID, 1, "HighPriority", None, None, None, None)
"HighPriority",
None)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi, @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'create_volume', 'create_volume',
@ -633,10 +681,8 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
mock_init): mock_init):
volume = {'id': fake.VOLUME_ID, 'size': 1, 'volume_type_id': 'abc'} volume = {'id': fake.VOLUME_ID, 'size': 1, 'volume_type_id': 'abc'}
self.driver.create_volume(volume) self.driver.create_volume(volume)
mock_create_volume.assert_called_once_with(fake.VOLUME_ID, mock_create_volume.assert_called_once_with(
1, fake.VOLUME_ID, 1, None, 'Daily', None, None, None)
None,
'Daily')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi, @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'create_volume', 'create_volume',
@ -1492,9 +1538,50 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
snapshot = {'id': fake.SNAPSHOT_ID, 'volume_id': fake.VOLUME_ID, snapshot = {'id': fake.SNAPSHOT_ID, 'volume_id': fake.VOLUME_ID,
'volume_size': 1} 'volume_size': 1}
res = self.driver.create_volume_from_snapshot(volume, snapshot) res = self.driver.create_volume_from_snapshot(volume, snapshot)
mock_create_view_volume.assert_called_once_with(fake.VOLUME_ID, mock_create_view_volume.assert_called_once_with(
'fake', fake.VOLUME_ID, 'fake', None, None, None, None)
None) self.assertTrue(mock_find_replay.called)
self.assertTrue(mock_find_volume.called)
self.assertFalse(mock_find_replay_profile.called)
# This just makes sure that we created
self.assertTrue(mock_create_replications.called)
self.assertEqual(model_update, res)
@mock.patch.object(dell_storagecenter_iscsi.DellStorageCenterISCSIDriver,
'_create_replications')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'find_replay_profile')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'find_volume')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'find_replay')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'create_view_volume')
@mock.patch.object(dell_storagecenter_iscsi.DellStorageCenterISCSIDriver,
'_get_volume_extra_specs')
def test_create_volume_from_snapshot_with_profiles(
self, mock_get_volume_extra_specs, mock_create_view_volume,
mock_find_replay, mock_find_volume, mock_find_replay_profile,
mock_create_replications, mock_close_connection,
mock_open_connection, mock_init):
mock_get_volume_extra_specs.return_value = {
'storagetype:replayprofiles': 'replayprofiles',
'storagetype:volumeqos': 'volumeqos',
'storagetype:groupqos': 'groupqos',
'storagetype:datareductionprofile': 'drprofile'}
mock_create_view_volume.return_value = self.VOLUME
mock_find_replay.return_value = 'fake'
mock_find_volume.return_value = self.VOLUME
model_update = {'something': 'something'}
mock_create_replications.return_value = model_update
volume = {'id': fake.VOLUME_ID, 'size': 1}
snapshot = {'id': fake.SNAPSHOT_ID, 'volume_id': fake.VOLUME_ID,
'volume_size': 1}
res = self.driver.create_volume_from_snapshot(volume, snapshot)
mock_create_view_volume.assert_called_once_with(
fake.VOLUME_ID, 'fake', 'replayprofiles', 'volumeqos', 'groupqos',
'drprofile')
self.assertTrue(mock_find_replay.called) self.assertTrue(mock_find_replay.called)
self.assertTrue(mock_find_volume.called) self.assertTrue(mock_find_volume.called)
self.assertFalse(mock_find_replay_profile.called) self.assertFalse(mock_find_replay_profile.called)
@ -1534,9 +1621,8 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
snapshot = {'id': fake.SNAPSHOT_ID, 'volume_id': fake.VOLUME_ID, snapshot = {'id': fake.SNAPSHOT_ID, 'volume_id': fake.VOLUME_ID,
'volume_size': 1} 'volume_size': 1}
res = self.driver.create_volume_from_snapshot(volume, snapshot) res = self.driver.create_volume_from_snapshot(volume, snapshot)
mock_create_view_volume.assert_called_once_with(fake.VOLUME_ID, mock_create_view_volume.assert_called_once_with(
'fake', fake.VOLUME_ID, 'fake', None, None, None, None)
None)
self.assertTrue(mock_find_replay.called) self.assertTrue(mock_find_replay.called)
self.assertTrue(mock_find_volume.called) self.assertTrue(mock_find_volume.called)
self.assertFalse(mock_find_replay_profile.called) self.assertFalse(mock_find_replay_profile.called)
@ -1578,9 +1664,8 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
snapshot = {'id': fake.SNAPSHOT_ID, 'volume_id': fake.VOLUME_ID, snapshot = {'id': fake.SNAPSHOT_ID, 'volume_id': fake.VOLUME_ID,
'volume_size': 1} 'volume_size': 1}
res = self.driver.create_volume_from_snapshot(volume, snapshot) res = self.driver.create_volume_from_snapshot(volume, snapshot)
mock_create_view_volume.assert_called_once_with(fake.VOLUME_ID, mock_create_view_volume.assert_called_once_with(
'fake', fake.VOLUME_ID, 'fake', None, None, None, None)
None)
self.assertTrue(mock_find_replay.called) self.assertTrue(mock_find_replay.called)
self.assertTrue(mock_find_volume.called) self.assertTrue(mock_find_volume.called)
self.assertTrue(mock_find_replay_profile.called) self.assertTrue(mock_find_replay_profile.called)
@ -1700,9 +1785,37 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
src_vref = {'id': fake.VOLUME2_ID, 'size': 1} src_vref = {'id': fake.VOLUME2_ID, 'size': 1}
ret = self.driver.create_cloned_volume(volume, src_vref) ret = self.driver.create_cloned_volume(volume, src_vref)
mock_create_cloned_volume.assert_called_once_with( mock_create_cloned_volume.assert_called_once_with(
fake.VOLUME_ID, fake.VOLUME_ID, self.VOLUME, None, None, None, None)
self.VOLUME, self.assertTrue(mock_find_volume.called)
None) self.assertEqual({'provider_id': provider_id}, ret)
@mock.patch.object(dell_storagecenter_iscsi.DellStorageCenterISCSIDriver,
'_create_replications')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'find_volume')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'create_cloned_volume')
@mock.patch.object(dell_storagecenter_iscsi.DellStorageCenterISCSIDriver,
'_get_volume_extra_specs')
def test_create_cloned_volume_with_profiles(
self, mock_get_volume_extra_specs, mock_create_cloned_volume,
mock_find_volume, mock_create_replications, mock_close_connection,
mock_open_connection, mock_init):
mock_get_volume_extra_specs.return_value = {
'storagetype:replayprofiles': 'replayprofiles',
'storagetype:volumeqos': 'volumeqos',
'storagetype:groupqos': 'groupqos',
'storagetype:datareductionprofile': 'drprofile'}
mock_find_volume.return_value = self.VOLUME
mock_create_cloned_volume.return_value = self.VOLUME
mock_create_replications.return_value = {}
provider_id = self.VOLUME[u'instanceId']
volume = {'id': fake.VOLUME_ID, 'size': 1}
src_vref = {'id': fake.VOLUME2_ID, 'size': 1}
ret = self.driver.create_cloned_volume(volume, src_vref)
mock_create_cloned_volume.assert_called_once_with(
fake.VOLUME_ID, self.VOLUME, 'replayprofiles', 'volumeqos',
'groupqos', 'drprofile')
self.assertTrue(mock_find_volume.called) self.assertTrue(mock_find_volume.called)
self.assertEqual({'provider_id': provider_id}, ret) self.assertEqual({'provider_id': provider_id}, ret)
@ -1731,9 +1844,7 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
src_vref = {'id': fake.VOLUME2_ID, 'size': 1} src_vref = {'id': fake.VOLUME2_ID, 'size': 1}
ret = self.driver.create_cloned_volume(volume, src_vref) ret = self.driver.create_cloned_volume(volume, src_vref)
mock_create_cloned_volume.assert_called_once_with( mock_create_cloned_volume.assert_called_once_with(
fake.VOLUME_ID, fake.VOLUME_ID, self.VOLUME, None, None, None, None)
self.VOLUME,
None)
self.assertTrue(mock_find_volume.called) self.assertTrue(mock_find_volume.called)
self.assertEqual({'provider_id': provider_id}, ret) self.assertEqual({'provider_id': provider_id}, ret)
self.assertTrue(mock_expand_volume.called) self.assertTrue(mock_expand_volume.called)
@ -1847,9 +1958,7 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
src_vref = {'id': fake.VOLUME2_ID, 'size': 1} src_vref = {'id': fake.VOLUME2_ID, 'size': 1}
self.driver.create_cloned_volume(volume, src_vref) self.driver.create_cloned_volume(volume, src_vref)
mock_create_cloned_volume.assert_called_once_with( mock_create_cloned_volume.assert_called_once_with(
fake.VOLUME_ID, fake.VOLUME_ID, self.VOLUME, None, None, None, None)
self.VOLUME,
None)
self.assertTrue(mock_find_volume.called) self.assertTrue(mock_find_volume.called)
self.assertTrue(mock_find_replay_profile.called) self.assertTrue(mock_find_replay_profile.called)
self.assertTrue(mock_update_cg_volumes.called) self.assertTrue(mock_update_cg_volumes.called)

View File

@ -2097,6 +2097,84 @@ class DellSCSanAPITestCase(test.TestCase):
mock_find_volume_folder.assert_called_once_with(True) mock_find_volume_folder.assert_called_once_with(True)
self.assertEqual(self.VOLUME, res, 'Unexpected ScVolume') self.assertEqual(self.VOLUME, res, 'Unexpected ScVolume')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_json')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_volume_folder')
@mock.patch.object(dell_storagecenter_api.HttpClient,
'post')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_qos_profile')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_data_reduction_profile')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_storage_profile')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_replay_profiles')
def test_create_volume_with_profiles(self,
mock_find_replay_profiles,
mock_find_storage_profile,
mock_find_data_reduction_profile,
mock_find_qos_profile,
mock_post,
mock_find_volume_folder,
mock_get_json,
mock_close_connection,
mock_open_connection,
mock_init):
mock_find_replay_profiles.return_value = (['12345.4'], [])
mock_get_json.return_value = self.VOLUME
mock_find_volume_folder.return_value = {'instanceId': '12345.200'}
mock_post.return_value = self.RESPONSE_201
mock_find_storage_profile.return_value = {'instanceId': '12345.0'}
mock_find_data_reduction_profile.return_value = {'instanceId':
'12345.1'}
mock_find_qos_profile.side_effect = [{'instanceId': '12345.2'},
{'instanceId': '12345.3'}]
res = self.scapi.create_volume(self.volume_name, 1, 'storage_profile',
'replay_profile_string', 'volume_qos',
'group_qos', 'datareductionprofile')
expected_payload = {'Name': self.volume_name,
'Notes': 'Created by Dell Cinder Driver',
'Size': '1 GB',
'StorageCenter': 12345,
'VolumeFolder': '12345.200',
'StorageProfile': '12345.0',
'VolumeQosProfile': '12345.2',
'GroupQosProfile': '12345.3',
'DataReductionProfile': '12345.1',
'ReplayProfileList': ['12345.4']}
mock_find_volume_folder.assert_called_once_with(True)
mock_post.assert_called_once_with('StorageCenter/ScVolume',
expected_payload, True)
self.assertEqual(self.VOLUME, res)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_volume_folder')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_qos_profile')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_storage_profile')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_replay_profiles')
def test_create_volume_profile_not_found(self,
mock_find_replay_profiles,
mock_find_storage_profile,
mock_find_qos_profile,
mock_find_volume_folder,
mock_close_connection,
mock_open_connection,
mock_init):
mock_find_replay_profiles.return_value = (['12345.4'], [])
mock_find_volume_folder.return_value = self.FLDR
mock_find_storage_profile.return_value = [{'instanceId': '12345.0'}]
# Failure is on the volumeqosprofile.
mock_find_qos_profile.return_value = None
self.assertRaises(exception.VolumeBackendAPIException,
self.scapi.create_volume, self.volume_name, 1,
'storage_profile', 'replay_profile_string',
'volume_qos', 'group_qos', 'datareductionprofile')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi, @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_storage_profile', '_find_storage_profile',
return_value=None) return_value=None)
@ -4351,9 +4429,7 @@ class DellSCSanAPITestCase(test.TestCase):
mock_init): mock_init):
vol_name = u'Test_create_vol' vol_name = u'Test_create_vol'
res = self.scapi.create_view_volume( res = self.scapi.create_view_volume(
vol_name, vol_name, self.TST_RPLAY, None, None, None, None)
self.TST_RPLAY,
None)
self.assertTrue(mock_post.called) self.assertTrue(mock_post.called)
mock_find_volume_folder.assert_called_once_with(True) mock_find_volume_folder.assert_called_once_with(True)
self.assertTrue(mock_first_result.called) self.assertTrue(mock_first_result.called)
@ -4378,9 +4454,7 @@ class DellSCSanAPITestCase(test.TestCase):
# Test case where volume folder does not exist and must be created # Test case where volume folder does not exist and must be created
vol_name = u'Test_create_vol' vol_name = u'Test_create_vol'
res = self.scapi.create_view_volume( res = self.scapi.create_view_volume(
vol_name, vol_name, self.TST_RPLAY, None, None, None, None)
self.TST_RPLAY,
None)
self.assertTrue(mock_post.called) self.assertTrue(mock_post.called)
mock_find_volume_folder.assert_called_once_with(True) mock_find_volume_folder.assert_called_once_with(True)
self.assertTrue(mock_first_result.called) self.assertTrue(mock_first_result.called)
@ -4405,9 +4479,7 @@ class DellSCSanAPITestCase(test.TestCase):
# Test case where volume folder does not exist and cannot be created # Test case where volume folder does not exist and cannot be created
vol_name = u'Test_create_vol' vol_name = u'Test_create_vol'
res = self.scapi.create_view_volume( res = self.scapi.create_view_volume(
vol_name, vol_name, self.TST_RPLAY, None, None, None, None)
self.TST_RPLAY,
None)
self.assertTrue(mock_post.called) self.assertTrue(mock_post.called)
mock_find_volume_folder.assert_called_once_with(True) mock_find_volume_folder.assert_called_once_with(True)
self.assertTrue(mock_first_result.called) self.assertTrue(mock_first_result.called)
@ -4428,13 +4500,148 @@ class DellSCSanAPITestCase(test.TestCase):
# Test case where view volume create fails # Test case where view volume create fails
vol_name = u'Test_create_vol' vol_name = u'Test_create_vol'
res = self.scapi.create_view_volume( res = self.scapi.create_view_volume(
vol_name, vol_name, self.TST_RPLAY, None, None, None, None)
self.TST_RPLAY,
None)
self.assertTrue(mock_post.called) self.assertTrue(mock_post.called)
mock_find_volume_folder.assert_called_once_with(True) mock_find_volume_folder.assert_called_once_with(True)
self.assertIsNone(res, 'Expected None') self.assertIsNone(res, 'Expected None')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_first_result')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_volume_folder')
@mock.patch.object(dell_storagecenter_api.HttpClient,
'post')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_qos_profile')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_replay_profiles')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'update_datareduction_profile')
def test_create_view_volume_with_profiles(
self, mock_update_datareduction_profile, mock_find_replay_profiles,
mock_find_qos_profile, mock_post, mock_find_volume_folder,
mock_first_result, mock_close_connection, mock_open_connection,
mock_init):
mock_find_replay_profiles.return_value = (['12345.4'], [])
mock_first_result.return_value = {'name': 'name'}
mock_post.return_value = self.RESPONSE_200
mock_find_volume_folder.return_value = {'instanceId': '12345.200'}
mock_find_qos_profile.side_effect = [{'instanceId': '12345.2'},
{'instanceId': '12345.3'}]
screplay = {'instanceId': '12345.100.1'}
res = self.scapi.create_view_volume(
'name', screplay, 'replay_profile_string', 'volume_qos',
'group_qos', 'datareductionprofile')
expected_payload = {'Name': 'name',
'Notes': 'Created by Dell Cinder Driver',
'VolumeFolder': '12345.200',
'ReplayProfileList': ['12345.4'],
'VolumeQosProfile': '12345.2',
'GroupQosProfile': '12345.3'}
mock_find_volume_folder.assert_called_once_with(True)
mock_post.assert_called_once_with(
'StorageCenter/ScReplay/12345.100.1/CreateView', expected_payload,
True)
mock_update_datareduction_profile.assert_called_once_with(
{'name': 'name'}, 'datareductionprofile')
self.assertEqual({'name': 'name'}, res)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_first_result')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_volume_folder')
@mock.patch.object(dell_storagecenter_api.HttpClient,
'post')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_qos_profile')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_replay_profiles')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'update_datareduction_profile')
def test_create_view_volume_with_profiles_no_dr(
self, mock_update_datareduction_profile, mock_find_replay_profiles,
mock_find_qos_profile, mock_post, mock_find_volume_folder,
mock_first_result, mock_close_connection, mock_open_connection,
mock_init):
mock_find_replay_profiles.return_value = (['12345.4'], [])
mock_first_result.return_value = {'name': 'name'}
mock_post.return_value = self.RESPONSE_200
mock_find_volume_folder.return_value = {'instanceId': '12345.200'}
mock_find_qos_profile.side_effect = [{'instanceId': '12345.2'},
{'instanceId': '12345.3'}]
screplay = {'instanceId': '12345.100.1'}
res = self.scapi.create_view_volume('name', screplay,
'replay_profile_string',
'volume_qos',
'group_qos',
None)
expected_payload = {'Name': 'name',
'Notes': 'Created by Dell Cinder Driver',
'VolumeFolder': '12345.200',
'ReplayProfileList': ['12345.4'],
'VolumeQosProfile': '12345.2',
'GroupQosProfile': '12345.3'}
mock_find_volume_folder.assert_called_once_with(True)
mock_post.assert_called_once_with(
'StorageCenter/ScReplay/12345.100.1/CreateView', expected_payload,
True)
mock_update_datareduction_profile.assert_not_called()
self.assertEqual({'name': 'name'}, res)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_first_result')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_volume_folder')
@mock.patch.object(dell_storagecenter_api.HttpClient,
'post')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_qos_profile')
def test_create_view_volume_with_profiles_no_replayprofiles(
self, mock_find_qos_profile, mock_post, mock_find_volume_folder,
mock_first_result, mock_close_connection, mock_open_connection,
mock_init):
mock_first_result.return_value = {'name': 'name'}
mock_post.return_value = self.RESPONSE_200
mock_find_volume_folder.return_value = {'instanceId': '12345.200'}
mock_find_qos_profile.side_effect = [{'instanceId': '12345.2'},
{'instanceId': '12345.3'}]
screplay = {'instanceId': '12345.100.1'}
res = self.scapi.create_view_volume('name', screplay,
None,
'volume_qos',
'group_qos',
None)
expected_payload = {'Name': 'name',
'Notes': 'Created by Dell Cinder Driver',
'VolumeFolder': '12345.200',
'VolumeQosProfile': '12345.2',
'GroupQosProfile': '12345.3'}
mock_find_volume_folder.assert_called_once_with(True)
mock_post.assert_called_once_with(
'StorageCenter/ScReplay/12345.100.1/CreateView', expected_payload,
True)
self.assertEqual({'name': 'name'}, res)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_volume_folder')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_qos_profile')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_replay_profiles')
def test_create_view_volume_with_profiles_not_found(
self, mock_find_replay_profiles, mock_find_qos_profile,
mock_find_volume_folder, mock_close_connection,
mock_open_connection, mock_init):
mock_find_replay_profiles.return_value = (['12345.4'], [])
mock_find_volume_folder.return_value = {'instanceId': '12345.200'}
# Our qos profile isn't found.
mock_find_qos_profile.return_value = None
screplay = {'instanceId': '12345.100.1'}
self.assertRaises(exception.VolumeBackendAPIException,
self.scapi.create_view_volume,
'name', screplay, 'replay_profile_string',
'volume_qos', 'group_qos', 'datareductionprofile')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi, @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'create_view_volume', 'create_view_volume',
return_value=VOLUME) return_value=VOLUME)
@ -4449,16 +4656,14 @@ class DellSCSanAPITestCase(test.TestCase):
mock_init): mock_init):
vol_name = u'Test_create_clone_vol' vol_name = u'Test_create_clone_vol'
res = self.scapi.create_cloned_volume( res = self.scapi.create_cloned_volume(
vol_name, vol_name, self.VOLUME, ['Daily'],
self.VOLUME, 'volume_qos', 'group_qos', 'dr_profile')
['Daily'])
mock_create_replay.assert_called_once_with(self.VOLUME, mock_create_replay.assert_called_once_with(self.VOLUME,
'Cinder Clone Replay', 'Cinder Clone Replay',
60) 60)
mock_create_view_volume.assert_called_once_with( mock_create_view_volume.assert_called_once_with(
vol_name, vol_name, self.RPLAY, ['Daily'],
self.RPLAY, 'volume_qos', 'group_qos', 'dr_profile')
['Daily'])
self.assertEqual(self.VOLUME, res, 'Unexpected ScVolume') self.assertEqual(self.VOLUME, res, 'Unexpected ScVolume')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi, @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
@ -4477,9 +4682,7 @@ class DellSCSanAPITestCase(test.TestCase):
vol_name = u'Test_create_clone_vol' vol_name = u'Test_create_clone_vol'
mock_create_replay.return_value = None mock_create_replay.return_value = None
res = self.scapi.create_cloned_volume( res = self.scapi.create_cloned_volume(
vol_name, vol_name, self.VOLUME, ['Daily'], None, None, None)
self.VOLUME,
['Daily'])
mock_create_replay.assert_called_once_with(self.VOLUME, mock_create_replay.assert_called_once_with(self.VOLUME,
'Cinder Clone Replay', 'Cinder Clone Replay',
60) 60)
@ -4488,13 +4691,11 @@ class DellSCSanAPITestCase(test.TestCase):
# Again buy let create_view_volume fail. # Again buy let create_view_volume fail.
mock_create_replay.return_value = self.RPLAY mock_create_replay.return_value = self.RPLAY
res = self.scapi.create_cloned_volume( res = self.scapi.create_cloned_volume(
vol_name, vol_name, self.VOLUME, ['Daily'],
self.VOLUME, 'volume_qos', 'group_qos', 'dr_profile')
['Daily'])
mock_create_view_volume.assert_called_once_with( mock_create_view_volume.assert_called_once_with(
vol_name, vol_name, self.RPLAY, ['Daily'],
self.RPLAY, 'volume_qos', 'group_qos', 'dr_profile')
['Daily'])
self.assertIsNone(res) self.assertIsNone(res)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi, @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
@ -7107,6 +7308,441 @@ class DellSCSanAPITestCase(test.TestCase):
True) True)
self.assertFalse(ret) self.assertFalse(ret)
@mock.patch.object(dell_storagecenter_api.HttpClient,
'post')
def test_swap_roles_live_volume(self,
mock_post,
mock_close_connection,
mock_open_connection,
mock_init):
mock_post.return_value = self.RESPONSE_200
lv = {'instanceId': '12345.0'}
ret = self.scapi.swap_roles_live_volume(lv)
self.assertTrue(ret)
@mock.patch.object(dell_storagecenter_api.HttpClient,
'post')
def test_swap_roles_live_volume_fail(self,
mock_post,
mock_close_connection,
mock_open_connection,
mock_init):
mock_post.return_value = self.RESPONSE_400
lv = {'instanceId': '12345.0'}
ret = self.scapi.swap_roles_live_volume(lv)
self.assertFalse(ret)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_json')
@mock.patch.object(dell_storagecenter_api.HttpClient,
'post')
def test__find_qos_profile(self,
mock_post,
mock_get_json,
mock_close_connection,
mock_open_connection,
mock_init):
mock_post.return_value = self.RESPONSE_200
mock_get_json.return_value = [{'instanceId': '12345.0'}]
expected_payload = {'filter': {'filterType': 'AND', 'filters': [
{'filterType': 'Equals', 'attributeName': 'ScSerialNumber',
'attributeValue': 12345},
{'filterType': 'Equals', 'attributeName': 'Name',
'attributeValue': 'Default'},
{'filterType': 'Equals', 'attributeName': 'profileType',
'attributeValue': 'VolumeQosProfile'}]}}
ret = self.scapi._find_qos_profile('Default', False)
self.assertEqual({'instanceId': '12345.0'}, ret)
mock_post.assert_called_once_with('StorageCenter/ScQosProfile/GetList',
expected_payload)
def test__find_qos_no_qosprofile(self,
mock_close_connection,
mock_open_connection,
mock_init):
ret = self.scapi._find_qos_profile('', False)
self.assertIsNone(ret)
@mock.patch.object(dell_storagecenter_api.HttpClient,
'post')
def test__find_qos_error(self,
mock_post,
mock_close_connection,
mock_open_connection,
mock_init):
mock_post.return_value = self.RESPONSE_400
ret = self.scapi._find_qos_profile('Default', False)
self.assertIsNone(ret)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_json')
@mock.patch.object(dell_storagecenter_api.HttpClient,
'post')
def test__find_qos_profile_empty_list(self,
mock_post,
mock_get_json,
mock_close_connection,
mock_open_connection,
mock_init):
mock_post.return_value = self.RESPONSE_200
mock_get_json.return_value = []
ret = self.scapi._find_qos_profile('Default', False)
self.assertIsNone(ret)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_json')
@mock.patch.object(dell_storagecenter_api.HttpClient,
'post')
def test__find_qos_profile_group(self,
mock_post,
mock_get_json,
mock_close_connection,
mock_open_connection,
mock_init):
mock_post.return_value = self.RESPONSE_200
mock_get_json.return_value = [{'instanceId': '12345.0'}]
expected_payload = {'filter': {'filterType': 'AND', 'filters': [
{'filterType': 'Equals', 'attributeName': 'ScSerialNumber',
'attributeValue': 12345},
{'filterType': 'Equals', 'attributeName': 'Name',
'attributeValue': 'Default'},
{'filterType': 'Equals', 'attributeName': 'profileType',
'attributeValue': 'GroupQosProfile'}]}}
ret = self.scapi._find_qos_profile('Default', True)
self.assertEqual({'instanceId': '12345.0'}, ret)
mock_post.assert_called_once_with('StorageCenter/ScQosProfile/GetList',
expected_payload)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_json')
@mock.patch.object(dell_storagecenter_api.HttpClient,
'post')
def test__find_datareduction_profile(self,
mock_post,
mock_get_json,
mock_close_connection,
mock_open_connection,
mock_init):
mock_post.return_value = self.RESPONSE_200
mock_get_json.return_value = [{'instanceId': '12345.0'}]
expected_payload = {'filter': {'filterType': 'AND', 'filters': [
{'filterType': 'Equals', 'attributeName': 'ScSerialNumber',
'attributeValue': 12345},
{'filterType': 'Equals', 'attributeName': 'instanceName',
'attributeValue': 'Compression'}]}}
ret = self.scapi._find_data_reduction_profile('Compression')
self.assertEqual({'instanceId': '12345.0'}, ret)
mock_post.assert_called_once_with(
'StorageCenter/ScDataReductionProfile/GetList', expected_payload)
def test__find_datareduction_profile_no_drprofile(self,
mock_close_connection,
mock_open_connection,
mock_init):
ret = self.scapi._find_data_reduction_profile('')
self.assertIsNone(ret)
@mock.patch.object(dell_storagecenter_api.HttpClient,
'post')
def test__find_datareduction_profile_error(self,
mock_post,
mock_close_connection,
mock_open_connection,
mock_init):
mock_post.return_value = self.RESPONSE_400
ret = self.scapi._find_data_reduction_profile('Compression')
self.assertIsNone(ret)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_json')
@mock.patch.object(dell_storagecenter_api.HttpClient,
'post')
def test__find_datareduction_profile_empty_list(self,
mock_post,
mock_get_json,
mock_close_connection,
mock_open_connection,
mock_init):
mock_post.return_value = self.RESPONSE_200
mock_get_json.return_value = []
ret = self.scapi._find_data_reduction_profile('Compression')
self.assertIsNone(ret)
def test__check_add_profile_payload(self,
mock_close_connection,
mock_open_connection,
mock_init):
payload = {}
profile = {'instanceId': '12345.0'}
self.scapi._check_add_profile_payload(payload, profile,
'Profile1', 'GroupQosProfile')
self.assertEqual({'GroupQosProfile': '12345.0'}, payload)
def test__check_add_profile_payload_no_name(self,
mock_close_connection,
mock_open_connection,
mock_init):
payload = {}
profile = {'instanceId': '12345.0'}
self.scapi._check_add_profile_payload(payload, profile,
None, 'GroupQosProfile')
self.assertEqual({}, payload)
def test__check_add_profile_payload_no_profile(self,
mock_close_connection,
mock_open_connection,
mock_init):
payload = {}
profile = None
self.assertRaises(exception.VolumeBackendAPIException,
self.scapi._check_add_profile_payload,
payload, profile, 'Profile1',
'VolumeQosProfile')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_user_preferences')
@mock.patch.object(dell_storagecenter_api.HttpClient,
'put')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_data_reduction_profile')
def test_update_datareduction_profile(
self, mock_find_datareduction_profile, mock_put, mock_prefs,
mock_close_connection, mock_open_connection, mock_init):
# Test we get and set our default
mock_find_datareduction_profile.return_value = {}
mock_prefs.return_value = {
'allowDataReductionSelection': True,
'dataReductionProfile': {'name': 'Default',
'instanceId': '12345.0'}}
scvolume = {'name': fake.VOLUME_ID, 'instanceId': '12345.101'}
mock_put.return_value = self.RESPONSE_200
expected = {'dataReductionProfile': '12345.0'}
res = self.scapi.update_datareduction_profile(scvolume, None)
self.assertTrue(res)
mock_put.assert_called_once_with(
'StorageCenter/ScVolumeConfiguration/12345.101', expected, True)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_user_preferences')
@mock.patch.object(dell_storagecenter_api.HttpClient,
'put')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_data_reduction_profile')
def test_update_datareduction_profile_error(
self, mock_find_datareduction_profile, mock_put, mock_prefs,
mock_close_connection, mock_open_connection, mock_init):
# Test we get and set our default
mock_find_datareduction_profile.return_value = {}
mock_prefs.return_value = {
'allowDataReductionSelection': True,
'dataReductionProfile': {'name': 'Default',
'instanceId': '12345.0'}}
scvolume = {'name': fake.VOLUME_ID, 'instanceId': '12345.101'}
mock_put.return_value = self.RESPONSE_400
expected = {'dataReductionProfile': '12345.0'}
res = self.scapi.update_datareduction_profile(scvolume, None)
self.assertFalse(res)
mock_put.assert_called_once_with(
'StorageCenter/ScVolumeConfiguration/12345.101', expected, True)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_user_preferences')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_data_reduction_profile')
def test_update_datareduction_profile_not_found(
self, mock_find_datareduction_profile, mock_prefs,
mock_close_connection, mock_open_connection,
mock_init):
mock_find_datareduction_profile.return_value = None
mock_prefs.return_value = {'allowDataReductionSelection': True}
scvolume = {'name': fake.VOLUME_ID, 'instanceId': '12345.101'}
res = self.scapi.update_datareduction_profile(scvolume, 'Profile')
self.assertFalse(res)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_user_preferences')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_data_reduction_profile')
def test_update_datareduction_profile_not_allowed(
self, mock_find_datareduction_profile, mock_prefs,
mock_close_connection, mock_open_connection,
mock_init):
mock_find_datareduction_profile.return_value = None
mock_prefs.return_value = {'allowDataReductionSelection': False}
scvolume = {'name': fake.VOLUME_ID, 'instanceId': '12345.101'}
res = self.scapi.update_datareduction_profile(scvolume, None)
self.assertFalse(res)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_user_preferences')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_data_reduction_profile')
def test_update_datareduction_profile_prefs_not_found(
self, mock_find_datareduction_profile, mock_prefs,
mock_close_connection, mock_open_connection,
mock_init):
mock_find_datareduction_profile.return_value = None
mock_prefs.return_value = None
scvolume = {'name': fake.VOLUME_ID, 'instanceId': '12345.101'}
res = self.scapi.update_datareduction_profile(scvolume, None)
self.assertFalse(res)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_user_preferences')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_data_reduction_profile')
def test_update_datareduction_profile_default_not_found(
self, mock_find_datareduction_profile, mock_prefs,
mock_close_connection, mock_open_connection,
mock_init):
mock_find_datareduction_profile.return_value = None
mock_prefs.return_value = {'allowDataReductionSelection': True}
scvolume = {'name': fake.VOLUME_ID, 'instanceId': '12345.101'}
res = self.scapi.update_datareduction_profile(scvolume, None)
self.assertFalse(res)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_user_preferences')
@mock.patch.object(dell_storagecenter_api.HttpClient,
'put',
return_value=RESPONSE_200)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_data_reduction_profile')
def test_update_datareduction_profile_default(
self, mock_find_datareduction_profile, mock_put, mock_prefs,
mock_close_connection, mock_open_connection, mock_init):
# Test we get and set our default
mock_find_datareduction_profile.return_value = None
mock_prefs.return_value = {
'allowDataReductionSelection': True,
'dataReductionProfile': {'name': 'Default',
'instanceId': '12345.0'}}
scvolume = {'name': fake.VOLUME_ID, 'instanceId': '12345.101'}
res = self.scapi.update_datareduction_profile(scvolume, None)
self.assertTrue(res)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_user_preferences')
@mock.patch.object(dell_storagecenter_api.HttpClient,
'put')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_qos_profile')
def test_update_qos_profile(
self, mock_find_qos_profile, mock_put, mock_prefs,
mock_close_connection, mock_open_connection, mock_init):
# Test we get and set our default
mock_find_qos_profile.return_value = {}
mock_prefs.return_value = {
'allowQosProfileSelection': True,
'volumeQosProfile': {'name': 'Default',
'instanceId': '12345.0'}}
scvolume = {'name': fake.VOLUME_ID, 'instanceId': '12345.101'}
mock_put.return_value = self.RESPONSE_200
expected = {'volumeQosProfile': '12345.0'}
res = self.scapi.update_qos_profile(scvolume, None)
self.assertTrue(res)
mock_put.assert_called_once_with(
'StorageCenter/ScVolumeConfiguration/12345.101', expected, True)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_user_preferences')
@mock.patch.object(dell_storagecenter_api.HttpClient,
'put')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_data_reduction_profile')
def test_update_qos_profile_error(
self, mock_find_qos_profile, mock_put, mock_prefs,
mock_close_connection, mock_open_connection, mock_init):
# Test we get and set our default
mock_find_qos_profile.return_value = {}
mock_prefs.return_value = {
'allowQosProfileSelection': True,
'volumeQosProfile': {'name': 'Default',
'instanceId': '12345.0'}}
scvolume = {'name': fake.VOLUME_ID, 'instanceId': '12345.101'}
mock_put.return_value = self.RESPONSE_400
expected = {'volumeQosProfile': '12345.0'}
res = self.scapi.update_qos_profile(scvolume, None)
self.assertFalse(res)
mock_put.assert_called_once_with(
'StorageCenter/ScVolumeConfiguration/12345.101', expected, True)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_user_preferences')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_qos_profile')
def test_update_qos_profile_not_found(
self, mock_find_qos_profile, mock_prefs,
mock_close_connection, mock_open_connection,
mock_init):
mock_find_qos_profile.return_value = None
mock_prefs.return_value = {'allowQosProfileSelection': True}
scvolume = {'name': fake.VOLUME_ID, 'instanceId': '12345.101'}
res = self.scapi.update_qos_profile(scvolume, 'Profile')
self.assertFalse(res)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_user_preferences')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_qos_profile')
def test_update_qos_profile_not_allowed(
self, mock_find_qos_profile, mock_prefs,
mock_close_connection, mock_open_connection,
mock_init):
mock_find_qos_profile.return_value = None
mock_prefs.return_value = {'allowQosProfileSelection': False}
scvolume = {'name': fake.VOLUME_ID, 'instanceId': '12345.101'}
res = self.scapi.update_qos_profile(scvolume, None)
self.assertFalse(res)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_user_preferences')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_qos_profile')
def test_update_qos_profile_prefs_not_found(
self, mock_find_qos_profile, mock_prefs,
mock_close_connection, mock_open_connection,
mock_init):
mock_find_qos_profile.return_value = None
mock_prefs.return_value = None
scvolume = {'name': fake.VOLUME_ID, 'instanceId': '12345.101'}
res = self.scapi.update_qos_profile(scvolume, None)
self.assertFalse(res)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_user_preferences')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_qos_profile')
def test_update_qos_profile_default_not_found(
self, mock_find_qos_profile, mock_prefs,
mock_close_connection, mock_open_connection,
mock_init):
mock_find_qos_profile.return_value = None
mock_prefs.return_value = {'allowQosProfileSelection': True}
scvolume = {'name': fake.VOLUME_ID, 'instanceId': '12345.101'}
res = self.scapi.update_qos_profile(scvolume, None)
self.assertFalse(res)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_user_preferences')
@mock.patch.object(dell_storagecenter_api.HttpClient,
'put')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_qos_profile')
def test_update_qos_profile_default(
self, mock_find_qos_profile, mock_put, mock_prefs,
mock_close_connection, mock_open_connection, mock_init):
# Test we get and set our default
mock_find_qos_profile.return_value = None
mock_prefs.return_value = {
'allowQosProfileSelection': True,
'volumeQosProfile': {'name': 'Default',
'instanceId': '12345.0'}}
mock_put.return_value = self.RESPONSE_200
scvolume = {'name': fake.VOLUME_ID, 'instanceId': '12345.101'}
res = self.scapi.update_qos_profile(scvolume, None)
self.assertTrue(res)
class DellSCSanAPIConnectionTestCase(test.TestCase): class DellSCSanAPIConnectionTestCase(test.TestCase):

View File

@ -1000,8 +1000,17 @@ class StorageCenterApi(object):
return False return False
return True return True
def _check_add_profile_payload(self, payload, profile, name, type):
if name:
if profile is None:
msg = _('Profile %s not found.') % name
raise exception.VolumeBackendAPIException(data=msg)
else:
payload[type] = self._get_id(profile)
def create_volume(self, name, size, storage_profile=None, def create_volume(self, name, size, storage_profile=None,
replay_profile_string=None): replay_profile_string=None, volume_qos=None,
group_qos=None, datareductionprofile=None):
"""Creates a new volume on the Storage Center. """Creates a new volume on the Storage Center.
It will create it in a folder called self.vfname. If self.vfname It will create it in a folder called self.vfname. If self.vfname
@ -1014,15 +1023,22 @@ class StorageCenterApi(object):
:param storage_profile: Optional storage profile to set for the volume. :param storage_profile: Optional storage profile to set for the volume.
:param replay_profile_string: Optional replay profile to set for :param replay_profile_string: Optional replay profile to set for
the volume. the volume.
:param volume_qos: Volume QOS profile name.
:param group_qos: Group QOS profile name.
:param datareductionprofile: Data reduction profile name
:returns: Dell Volume object or None. :returns: Dell Volume object or None.
""" """
LOG.debug('create_volume: %(name)s %(ssn)s %(folder)s %(profile)s', LOG.debug('create_volume: %(name)s %(ssn)s %(folder)s %(profile)s '
'%(vqos)r %(gqos)r %(dup)r',
{'name': name, {'name': name,
'ssn': self.ssn, 'ssn': self.ssn,
'folder': self.vfname, 'folder': self.vfname,
'profile': storage_profile, 'profile': storage_profile,
'replay': replay_profile_string 'replay': replay_profile_string,
}) 'vqos': volume_qos,
'gqos': group_qos,
'dup': datareductionprofile})
# Find our folder # Find our folder
folder = self._find_volume_folder(True) folder = self._find_volume_folder(True)
@ -1031,12 +1047,6 @@ class StorageCenterApi(object):
if folder is None: if folder is None:
LOG.warning(_LW('Unable to create folder %s'), self.vfname) LOG.warning(_LW('Unable to create folder %s'), self.vfname)
# See if we need a storage profile
profile = self._find_storage_profile(storage_profile)
if storage_profile and profile is None:
msg = _('Storage Profile %s not found.') % storage_profile
raise exception.VolumeBackendAPIException(data=msg)
# Find our replay_profiles. # Find our replay_profiles.
addids, removeids = self._find_replay_profiles(replay_profile_string) addids, removeids = self._find_replay_profiles(replay_profile_string)
@ -1051,11 +1061,27 @@ class StorageCenterApi(object):
payload['StorageCenter'] = self.ssn payload['StorageCenter'] = self.ssn
if folder is not None: if folder is not None:
payload['VolumeFolder'] = self._get_id(folder) payload['VolumeFolder'] = self._get_id(folder)
if profile: # Add our storage profile.
payload['StorageProfile'] = self._get_id(profile) self._check_add_profile_payload(
payload, self._find_storage_profile(storage_profile),
storage_profile, 'StorageProfile')
# Add our Volume QOS Profile.
self._check_add_profile_payload(
payload, self._find_qos_profile(volume_qos), volume_qos,
'VolumeQosProfile')
# Add our Group QOS Profile.
self._check_add_profile_payload(
payload, self._find_qos_profile(group_qos, True), group_qos,
'GroupQosProfile')
# Add our Data Reduction Proflie.
self._check_add_profile_payload(
payload, self._find_data_reduction_profile(datareductionprofile),
datareductionprofile, 'DataReductionProfile')
# This is a new volume so there is nothing to remove. # This is a new volume so there is nothing to remove.
if addids: if addids:
payload['ReplayProfileList'] = addids payload['ReplayProfileList'] = addids
r = self.client.post('StorageCenter/ScVolume', payload, True) r = self.client.post('StorageCenter/ScVolume', payload, True)
if self._check_result(r): if self._check_result(r):
# Our volume should be in the return. # Our volume should be in the return.
@ -2063,12 +2089,16 @@ class StorageCenterApi(object):
# If we couldn't find it we call that a success. # If we couldn't find it we call that a success.
return ret return ret
def create_view_volume(self, volname, screplay, replay_profile_string): def create_view_volume(self, volname, screplay, replay_profile_string,
volume_qos, group_qos, dr_profile):
"""Creates a new volume named volname from the screplay. """Creates a new volume named volname from the screplay.
:param volname: Name of new volume. This is the cinder volume ID. :param volname: Name of new volume. This is the cinder volume ID.
:param screplay: Dell replay object from which to make a new volume. :param screplay: Dell replay object from which to make a new volume.
:param replay_profile_string: Profiles to be applied to the volume :param replay_profile_string: Profiles to be applied to the volume
:param volume_qos: Volume QOS Profile to use.
:param group_qos: Group QOS Profile to use.
:param dr_profile: Data reduction profile to use.
:returns: Dell volume object or None. :returns: Dell volume object or None.
""" """
folder = self._find_volume_folder(True) folder = self._find_volume_folder(True)
@ -2084,19 +2114,34 @@ class StorageCenterApi(object):
payload['VolumeFolder'] = self._get_id(folder) payload['VolumeFolder'] = self._get_id(folder)
if addids: if addids:
payload['ReplayProfileList'] = addids payload['ReplayProfileList'] = addids
# Add our Volume QOS Profile.
self._check_add_profile_payload(
payload, self._find_qos_profile(volume_qos), volume_qos,
'VolumeQosProfile')
# Add our Group QOS Profile.
self._check_add_profile_payload(
payload, self._find_qos_profile(group_qos, True), group_qos,
'GroupQosProfile')
r = self.client.post('StorageCenter/ScReplay/%s/CreateView' r = self.client.post('StorageCenter/ScReplay/%s/CreateView'
% self._get_id(screplay), payload, True) % self._get_id(screplay), payload, True)
volume = None volume = None
if self._check_result(r): if self._check_result(r):
volume = self._first_result(r) volume = self._first_result(r)
# If we have a dr_profile to apply we should do so now.
if dr_profile and not self.update_datareduction_profile(volume,
dr_profile):
LOG.error(_LE('Unable to apply %s to volume.'), dr_profile)
volume = None
if volume is None: if volume is None:
LOG.error(_LE('Unable to create volume %s from replay'), LOG.error(_LE('Unable to create volume %s from replay'),
volname) volname)
return volume return volume
def create_cloned_volume(self, volumename, scvolume, replay_profile_list): def create_cloned_volume(self, volumename, scvolume, replay_profile_list,
volume_qos, group_qos, dr_profile):
"""Creates a volume named volumename from a copy of scvolume. """Creates a volume named volumename from a copy of scvolume.
This is done by creating a replay and then a view volume from This is done by creating a replay and then a view volume from
@ -2108,12 +2153,16 @@ class StorageCenterApi(object):
:param volumename: Name of new volume. This is the cinder volume ID. :param volumename: Name of new volume. This is the cinder volume ID.
:param scvolume: Dell volume object. :param scvolume: Dell volume object.
:param replay_profile_list: List of snapshot profiles. :param replay_profile_list: List of snapshot profiles.
:param volume_qos: Volume QOS Profile to use.
:param group_qos: Group QOS Profile to use.
:param dr_profile: Data reduction profile to use.
:returns: The new volume's Dell volume object. :returns: The new volume's Dell volume object.
""" """
replay = self.create_replay(scvolume, 'Cinder Clone Replay', 60) replay = self.create_replay(scvolume, 'Cinder Clone Replay', 60)
if replay is not None: if replay is not None:
return self.create_view_volume(volumename, replay, return self.create_view_volume(volumename, replay,
replay_profile_list) replay_profile_list, volume_qos,
group_qos, dr_profile)
LOG.error(_LE('Error: unable to snap replay')) LOG.error(_LE('Error: unable to snap replay'))
return None return None
@ -2162,6 +2211,48 @@ class StorageCenterApi(object):
'name': name}) 'name': name})
return False return False
def _update_profile(self, scvolume, profile, profilename,
profiletype, restname, allowprefname,
continuewithoutdefault=False):
prefs = self._get_user_preferences()
if not prefs:
return False
if not prefs.get(allowprefname):
LOG.error(_LE('User does not have permission to change '
'%s selection.'), profiletype)
return False
if profilename:
if not profile:
LOG.error(_LE('%(ptype)s %(pname)s was not found.'),
{'ptype': profiletype,
'pname': profilename})
return False
else:
# Going from specific profile to the user default
profile = prefs.get(restname)
if not profile and not continuewithoutdefault:
LOG.error(_LE('Default %s was not found.'), profiletype)
return False
LOG.info(_LI('Switching volume %(vol)s to profile %(prof)s.'),
{'vol': scvolume['name'],
'prof': profile.get('name')})
payload = {}
payload[restname] = self._get_id(profile) if profile else None
r = self.client.put('StorageCenter/ScVolumeConfiguration/%s'
% self._get_id(scvolume), payload, True)
if self._check_result(r):
return True
LOG.error(_LE('Error changing %(ptype)s for volume '
'%(original)s to %(name)s'),
{'ptype': profiletype,
'original': scvolume['name'],
'name': profilename})
return False
def update_storage_profile(self, scvolume, storage_profile): def update_storage_profile(self, scvolume, storage_profile):
"""Update a volume's Storage Profile. """Update a volume's Storage Profile.
@ -2173,43 +2264,45 @@ class StorageCenterApi(object):
:param storage_profile: The requested Storage Profile name. :param storage_profile: The requested Storage Profile name.
:returns: True if successful, False otherwise. :returns: True if successful, False otherwise.
""" """
prefs = self._get_user_preferences()
if not prefs:
return False
if not prefs.get('allowStorageProfileSelection'):
LOG.error(_LE('User does not have permission to change '
'Storage Profile selection.'))
return False
profile = self._find_storage_profile(storage_profile) profile = self._find_storage_profile(storage_profile)
if storage_profile: return self._update_profile(scvolume, profile, storage_profile,
if not profile: 'Storage Profile', 'storageProfile',
LOG.error(_LE('Storage Profile %s was not found.'), 'allowStorageProfileSelection')
storage_profile)
return False
else:
# Going from specific profile to the user default
profile = prefs.get('storageProfile')
if not profile:
LOG.error(_LE('Default Storage Profile was not found.'))
return False
LOG.info(_LI('Switching volume %(vol)s to profile %(prof)s.'), def update_datareduction_profile(self, scvolume, dr_profile):
{'vol': scvolume['name'], """Update a volume's Data Reduction Profile
'prof': profile.get('name')})
payload = {}
payload['StorageProfile'] = self._get_id(profile)
r = self.client.put('StorageCenter/ScVolumeConfiguration/%s'
% self._get_id(scvolume), payload, True)
if self._check_result(r):
return True
LOG.error(_LE('Error changing Storage Profile for volume ' Changes the volume setting to use a different data reduction profile.
'%(original)s to %(name)s'), If dr_profile is None, will reset to the default profile for the
{'original': scvolume['name'], cinder user account.
'name': storage_profile})
return False :param scvolume: The Storage Center volume to be updated.
:param dr_profile: The requested data reduction profile name.
:returns: True if successful, False otherwise.
"""
profile = self._find_data_reduction_profile(dr_profile)
return self._update_profile(scvolume, profile, dr_profile,
'Data Reduction Profile',
'dataReductionProfile',
'allowDataReductionSelection')
def update_qos_profile(self, scvolume, qosprofile, grouptype=False):
"""Update a volume's QOS profile
Changes the volume setting to use a different QOS Profile.
:param scvolume: The Storage Center volume to be updated.
:param qosprofile: The requested QOS profile name.
:param grouptype: Is this a group QOS profile?
:returns: True if successful, False otherwise.
"""
profiletype = 'groupQosProfile' if grouptype else 'volumeQosProfile'
profile = self._find_qos_profile(qosprofile, grouptype)
return self._update_profile(scvolume, profile, qosprofile,
'Qos Profile', profiletype,
'allowQosProfileSelection',
grouptype)
def _get_user_preferences(self): def _get_user_preferences(self):
"""Gets the preferences and defaults for this user. """Gets the preferences and defaults for this user.
@ -3277,3 +3370,33 @@ class StorageCenterApi(object):
if self._check_result(r): if self._check_result(r):
return True return True
return False return False
def _find_qos_profile(self, qosprofile, grouptype=False):
if qosprofile:
pf = self._get_payload_filter()
pf.append('ScSerialNumber', self.ssn)
pf.append('Name', qosprofile)
if grouptype:
pf.append('profileType', 'GroupQosProfile')
else:
pf.append('profileType', 'VolumeQosProfile')
r = self.client.post('StorageCenter/ScQosProfile/GetList',
pf.payload)
if self._check_result(r):
qosprofiles = self._get_json(r)
if len(qosprofiles):
return qosprofiles[0]
return None
def _find_data_reduction_profile(self, drprofile):
if drprofile:
pf = self._get_payload_filter()
pf.append('ScSerialNumber', self.ssn)
pf.append('instanceName', drprofile)
r = self.client.post(
'StorageCenter/ScDataReductionProfile/GetList', pf.payload)
if self._check_result(r):
drps = self._get_json(r)
if len(drps):
return drps[0]
return None

View File

@ -287,21 +287,21 @@ class DellCommonDriver(driver.ConsistencyGroupVD, driver.ManageableVD,
# Look for our volume # Look for our volume
volume_size = volume.get('size') volume_size = volume.get('size')
# See if we have any extra specs.
specs = self._get_volume_extra_specs(volume)
storage_profile = specs.get('storagetype:storageprofile')
replay_profile_string = specs.get('storagetype:replayprofiles')
LOG.debug('Creating volume %(name)s of size %(size)s', LOG.debug('Creating volume %(name)s of size %(size)s',
{'name': volume_name, {'name': volume_name,
'size': volume_size}) 'size': volume_size})
scvolume = None scvolume = None
with self._client.open_connection() as api: with self._client.open_connection() as api:
try: try:
scvolume = api.create_volume(volume_name, # Get our extra specs.
volume_size, specs = self._get_volume_extra_specs(volume)
storage_profile, scvolume = api.create_volume(
replay_profile_string) volume_name, volume_size,
specs.get('storagetype:storageprofile'),
specs.get('storagetype:replayprofiles'),
specs.get('storagetype:volumeqos'),
specs.get('storagetype:groupqos'),
specs.get('storagetype:datareductionprofile'))
if scvolume is None: if scvolume is None:
raise exception.VolumeBackendAPIException( raise exception.VolumeBackendAPIException(
message=_('Unable to create volume %s') % message=_('Unable to create volume %s') %
@ -494,10 +494,12 @@ class DellCommonDriver(driver.ConsistencyGroupVD, driver.ManageableVD,
if replay is not None: if replay is not None:
# See if we have any extra specs. # See if we have any extra specs.
specs = self._get_volume_extra_specs(volume) specs = self._get_volume_extra_specs(volume)
replay_profile_string = specs.get(
'storagetype:replayprofiles')
scvolume = api.create_view_volume( scvolume = api.create_view_volume(
volume_name, replay, replay_profile_string) volume_name, replay,
specs.get('storagetype:replayprofiles'),
specs.get('storagetype:volumeqos'),
specs.get('storagetype:groupqos'),
specs.get('storagetype:datareductionprofile'))
# Extend Volume # Extend Volume
if scvolume and (volume['size'] > if scvolume and (volume['size'] >
@ -555,13 +557,15 @@ class DellCommonDriver(driver.ConsistencyGroupVD, driver.ManageableVD,
try: try:
srcvol = api.find_volume(src_volume_name, src_provider_id) srcvol = api.find_volume(src_volume_name, src_provider_id)
if srcvol is not None: if srcvol is not None:
# See if we have any extra specs. # Get our specs.
specs = self._get_volume_extra_specs(volume) specs = self._get_volume_extra_specs(volume)
replay_profile_string = specs.get(
'storagetype:replayprofiles')
# Create our volume # Create our volume
scvolume = api.create_cloned_volume( scvolume = api.create_cloned_volume(
volume_name, srcvol, replay_profile_string) volume_name, srcvol,
specs.get('storagetype:replayprofiles'),
specs.get('storagetype:volumeqos'),
specs.get('storagetype:groupqos'),
specs.get('storagetype:datareductionprofile'))
# Extend Volume # Extend Volume
if scvolume and volume['size'] > src_vref['size']: if scvolume and volume['size'] > src_vref['size']:
@ -1094,6 +1098,40 @@ class DellCommonDriver(driver.ConsistencyGroupVD, driver.ManageableVD,
LOG.error(_LE('Failed to update replay profiles')) LOG.error(_LE('Failed to update replay profiles'))
return False return False
# Volume QOS profiles.
current, requested = (
self._get_retype_spec(diff, volume_name,
'Volume QOS Profile',
'storagetype:volumeqos'))
if current != requested:
if not api.update_qos_profile(scvolume, requested):
LOG.error(_LE('Failed to update volume '
'qos profile'))
# Group QOS profiles.
current, requested = (
self._get_retype_spec(diff, volume_name,
'Group QOS Profile',
'storagetype:groupqos'))
if current != requested:
if not api.update_qos_profile(scvolume, requested,
True):
LOG.error(_LE('Failed to update group '
'qos profile'))
return False
# Data reduction profiles.
current, requested = (
self._get_retype_spec(
diff, volume_name, 'Data Reduction Profile',
'storagetype:datareductionprofile'))
if current != requested:
if not api.update_datareduction_profile(scvolume,
requested):
LOG.error(_LE('Failed to update data reduction '
'profile'))
return False
# Replication_enabled. # Replication_enabled.
current, requested = ( current, requested = (
self._get_retype_spec(diff, self._get_retype_spec(diff,
@ -1124,8 +1162,6 @@ class DellCommonDriver(driver.ConsistencyGroupVD, driver.ManageableVD,
'replication:activereplay setting')) 'replication:activereplay setting'))
return False return False
# TODO(tswanson): replaytype once it actually works.
except exception.VolumeBackendAPIException: except exception.VolumeBackendAPIException:
# We do nothing with this. We simply return failure. # We do nothing with this. We simply return failure.
return False return False
@ -1187,7 +1223,7 @@ class DellCommonDriver(driver.ConsistencyGroupVD, driver.ManageableVD,
return qosnode return qosnode
def _parse_extraspecs(self, volume): def _parse_extraspecs(self, volume):
# Digest our extra specs. # Digest our extra specs for replication.
extraspecs = {} extraspecs = {}
specs = self._get_volume_extra_specs(volume) specs = self._get_volume_extra_specs(volume)
if specs.get('replication_type') == '<in> sync': if specs.get('replication_type') == '<in> sync':

View File

@ -0,0 +1,8 @@
---
features:
- Dell SC - Compression and Dedupe support
added for Storage Centers that support the
options.
- Dell SC - Volume and Group QOS support
added for Storage Centers that support and
have enabled the option.