Merge "Dell SC: Add support for driver retype"

This commit is contained in:
Jenkins 2015-07-24 03:17:32 +00:00 committed by Gerrit Code Review
commit 92d9c96551
6 changed files with 279 additions and 4 deletions

View File

@ -12,14 +12,14 @@
# License for the specific language governing permissions and limitations
# under the License.
import uuid
import mock
import uuid
from cinder import context
from cinder import exception
from cinder import test
from cinder.volume.drivers.dell import dell_storagecenter_api
from cinder.volume.drivers.dell import dell_storagecenter_common
from cinder.volume.drivers.dell import dell_storagecenter_iscsi
from cinder.volume import volume_types
@ -1636,6 +1636,37 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
volume,
existing_ref)
def test_retype_not_extra_specs(self,
mock_close_connection,
mock_open_connection,
mock_init):
res = self.driver.retype(
None, None, None, {'extra_specs': None}, None)
self.assertFalse(res)
def test_retype_not_storage_profile(self,
mock_close_connection,
mock_open_connection,
mock_init):
res = self.driver.retype(
None, None, None, {'extra_specs': {'something': 'else'}}, None)
self.assertFalse(res)
def test_retype_malformed(self,
mock_close_connection,
mock_open_connection,
mock_init):
LOG = self.mock_object(dell_storagecenter_common, "LOG")
res = self.driver.retype(
None, None, None,
{'extra_specs': {
'storagetype:storageprofile': ['something',
'not',
'right']}},
None)
self.assertFalse(res)
self.assertEqual(1, LOG.warning.call_count)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'find_volume',
return_value=VOLUME)
@ -1667,3 +1698,26 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
self.driver.unmanage(volume)
mock_find_volume.assert_called_once_with(volume['id'])
self.assertFalse(mock_unmanage.called)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'update_storage_profile')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'find_volume',
return_value=VOLUME)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'find_sc',
return_value=12345)
def test_retype(self,
mock_find_sc,
mock_find_volume,
mock_update_storage_profile,
mock_close_connection,
mock_open_connection,
mock_init):
res = self.driver.retype(
None, {'id': 'volid'}, None,
{'extra_specs': {'storagetype:storageprofile': ['A', 'B']}},
None)
mock_update_storage_profile.ssert_called_once_with(
self.VOLUME, 'B')
self.assertTrue(res)

View File

@ -4009,6 +4009,113 @@ class DellSCSanAPITestCase(test.TestCase):
self.assertFalse(mock_delete.called)
self.assertIsNone(res, 'Expected None')
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_json',
return_value={'test': 'test'})
@mock.patch.object(dell_storagecenter_api.HttpClient,
'get',
return_value=RESPONSE_200)
def test_get_user_preferences(self,
mock_get,
mock_get_json,
mock_close_connection,
mock_open_connection,
mock_init):
# Not really testing anything other than the ability to mock, but
# including for completeness.
res = self.scapi._get_user_preferences()
self.assertEqual({'test': 'test'}, res)
@mock.patch.object(dell_storagecenter_api.HttpClient,
'get',
return_value=RESPONSE_400)
def test_get_user_preferences_failure(self,
mock_get,
mock_close_connection,
mock_open_connection,
mock_init):
LOG = self.mock_object(dell_storagecenter_api, "LOG")
res = self.scapi._get_user_preferences()
self.assertEqual({}, res)
self.assertTrue(LOG.error.call_count > 0)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_user_preferences',
return_value=None)
def test_update_storage_profile_noprefs(self,
mock_prefs,
mock_close_connection,
mock_open_connection,
mock_init):
res = self.scapi.update_storage_profile(None, None)
self.assertFalse(res)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_user_preferences',
return_value={'allowStorageProfileSelection': False})
def test_update_storage_profile_not_allowed(self,
mock_prefs,
mock_close_connection,
mock_open_connection,
mock_init):
LOG = self.mock_object(dell_storagecenter_api, "LOG")
res = self.scapi.update_storage_profile(None, None)
self.assertFalse(res)
self.assertEqual(1, LOG.error.call_count)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_storage_profile',
return_value=None)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_user_preferences',
return_value={'allowStorageProfileSelection': True})
def test_update_storage_profile_prefs_not_found(self,
mock_profile,
mock_prefs,
mock_close_connection,
mock_open_connection,
mock_init):
LOG = self.mock_object(dell_storagecenter_api, "LOG")
res = self.scapi.update_storage_profile(None, 'Fake')
self.assertFalse(res)
self.assertEqual(1, LOG.error.call_count)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_user_preferences',
return_value={'allowStorageProfileSelection': True,
'storageProfile': None})
def test_update_storage_profile_default_not_found(self,
mock_prefs,
mock_close_connection,
mock_open_connection,
mock_init):
LOG = self.mock_object(dell_storagecenter_api, "LOG")
res = self.scapi.update_storage_profile(None, None)
self.assertFalse(res)
self.assertEqual(1, LOG.error.call_count)
@mock.patch.object(
dell_storagecenter_api.StorageCenterApi,
'_get_user_preferences',
return_value={'allowStorageProfileSelection': True,
'storageProfile': {'name': 'Fake',
'instanceId': 'fakeId'}})
@mock.patch.object(dell_storagecenter_api.HttpClient,
'post',
return_value=RESPONSE_200)
def test_update_storage_profile(self,
mock_post,
mock_prefs,
mock_close_connection,
mock_open_connection,
mock_init):
LOG = self.mock_object(dell_storagecenter_api, "LOG")
fake_scvolume = {'name': 'name', 'instanceId': 'id'}
res = self.scapi.update_storage_profile(fake_scvolume, None)
self.assertTrue(res)
self.assertTrue('fakeId' in repr(mock_post.call_args_list[0]))
self.assertEqual(1, LOG.info.call_count)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_json',
return_value=[RPLAY_PROFILE])

View File

@ -1538,6 +1538,78 @@ class StorageCenterApi(object):
return False
return True
def update_storage_profile(self, scvolume, storage_profile):
"""Update a volume's Storage Profile.
Changes the volume setting to use a different Storage Profile. If
storage_profile is None, will reset to the default profile for the
cinder user account.
:param scvolume: The Storage Center volume to be updated.
:param storage_profile: The requested Storage Profile name.
: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)
if storage_profile:
if not profile:
LOG.error(_LE('Storage Profile %s was not found.'),
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.'),
{'vol': scvolume['name'],
'prof': profile.get('name')})
payload = {}
payload['StorageProfile'] = self._get_id(profile)
r = self.client.post('StorageCenter/ScVolumeConfiguration'
'/%s/Modify'
% self._get_id(scvolume),
payload)
if r.status_code != 200:
LOG.error(_LE('Error changing Storage Profile for volume '
'%(original)s to %(name)s: %(code)d %(reason)s '
'%(text)s'),
{'original': scvolume['name'],
'name': storage_profile,
'code': r.status_code,
'reason': r.reason,
'text': r.text})
return False
return True
def _get_user_preferences(self):
"""Gets the preferences and defaults for this user.
There are a set of preferences and defaults for each user on the
Storage Center. This retrieves all settings for the current account
used by Cinder.
"""
r = self.client.get('StorageCenter/StorageCenter/%s/UserPreferences' %
self.ssn)
if r.status_code != 200:
LOG.error(_LE('Error getting user preferences: '
'%(code)d %(reason)s %(text)s'),
{'code': r.status_code,
'reason': r.reason,
'text': r.text})
return {}
return self._get_json(r)
def _delete_server(self, scserver):
'''Deletes scserver from the backend.

View File

@ -636,3 +636,43 @@ class DellCommonDriver(driver.ConsistencyGroupVD, driver.ManageableVD,
scvolume = api.find_volume(volume['id'])
if scvolume:
api.unmanage(scvolume)
def retype(self, ctxt, volume, new_type, diff, host):
"""Convert the volume to be of the new type.
Returns a boolean indicating whether the retype occurred.
:param ctxt: Context
:param volume: A dictionary describing the volume to migrate
:param new_type: A dictionary describing the volume type to convert to
:param diff: A dictionary with the difference between the two types
:param host: A dictionary describing the host to migrate to, where
host['host'] is its name, and host['capabilities'] is a
dictionary of its reported capabilities (Not Used).
"""
# We currently only support retyping for the Storage Profile extra spec
if diff['extra_specs']:
storage_profiles = diff['extra_specs'].get(
'storagetype:storageprofile')
if storage_profiles:
if len(storage_profiles) != 2:
LOG.warning(_LW('Unable to retype Storage Profile, '
'expected to receive current and '
'requested storagetype:storageprofile '
'values. Value received: %s'),
storage_profiles)
return False
requested = storage_profiles[1]
volume_name = volume.get('id')
LOG.debug('Retyping volume %(vol)s to use storage '
'profile %(profile)s',
{'vol': volume_name,
'profile': requested})
with self._client.open_connection() as api:
if api.find_sc():
scvolume = api.find_volume(volume_name)
return api.update_storage_profile(
scvolume, requested)
return False

View File

@ -41,9 +41,10 @@ class DellStorageCenterFCDriver(dell_storagecenter_common.DellCommonDriver,
2.0.0 - Switched to inheriting functional objects rather than volume
driver.
2.1.0 - Added support for ManageableVD.
2.2.0 - Driver retype support for switching volume's Storage Profile
'''
VERSION = '2.1.0'
VERSION = '2.2.0'
def __init__(self, *args, **kwargs):
super(DellStorageCenterFCDriver, self).__init__(*args, **kwargs)

View File

@ -39,9 +39,10 @@ class DellStorageCenterISCSIDriver(dell_storagecenter_common.DellCommonDriver,
2.0.0 - Switched to inheriting functional objects rather than volume
driver.
2.1.0 - Added support for ManageableVD.
2.2.0 - Driver retype support for switching volume's Storage Profile
'''
VERSION = '2.1.0'
VERSION = '2.2.0'
def __init__(self, *args, **kwargs):
super(DellStorageCenterISCSIDriver, self).__init__(*args, **kwargs)