From: Tom Swanson Date: Thu, 7 May 2015 21:39:26 +0000 (-0500) Subject: Dell: Added support for update_migrated_volume X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=fc09713f2c8102d4b04c8df57fc401a34525d79e;p=openstack-build%2Fcinder-build.git Dell: Added support for update_migrated_volume Added support for updated_migrated_volume to common driver. Added rename_volume to dell_storagecenter_api to support it. Added tests to test_dellsc.py and test_dellapi.py. The only thing we do in this rename the newly migrated volume destination volume on the Dell Storage center to be the same as the original volume ID. Since we identify the volumes by volume ID this prevents them from being lost. Change-Id: I531e24853cf5db8b7c34d91460d3abe786a652de Closes-bug: 1452919 --- diff --git a/cinder/tests/unit/test_dellsc.py b/cinder/tests/unit/test_dellsc.py index 19c60bb43..3a9b4f2ab 100644 --- a/cinder/tests/unit/test_dellsc.py +++ b/cinder/tests/unit/test_dellsc.py @@ -1025,3 +1025,78 @@ class DellSCSanISCSIDriverTestCase(test.TestCase): stats = self.driver.get_volume_stats(False) self.assertEqual(stats['storage_protocol'], 'iSCSI') assert mock_get_storage_usage.called is False + + @mock.patch.object(dell_storagecenter_api.StorageCenterApi, + 'find_sc', + return_value=12345) + @mock.patch.object(dell_storagecenter_api.StorageCenterApi, + 'find_volume', + return_value=VOLUME) + @mock.patch.object(dell_storagecenter_api.StorageCenterApi, + 'rename_volume', + return_value=True) + def test_update_migrated_volume(self, + mock_rename_volume, + mock_find_volume, + mock_find_sc, + mock_close_connection, + mock_open_connection, + mock_init): + volume = {'id': 111} + backend_volume = {'id': 112} + model_update = {'_name_id': None} + rt = self.driver.update_migrated_volume(None, volume, backend_volume) + mock_rename_volume.assert_called_once_with(self.VOLUME, + volume['id']) + self.assertEqual(model_update, rt) + + @mock.patch.object(dell_storagecenter_api.StorageCenterApi, + 'find_sc', + return_value=12345) + @mock.patch.object(dell_storagecenter_api.StorageCenterApi, + 'find_volume', + return_value=VOLUME) + @mock.patch.object(dell_storagecenter_api.StorageCenterApi, + 'rename_volume', + return_value=False) + def test_update_migrated_volume_rename_fail(self, + mock_rename_volume, + mock_find_volume, + mock_find_sc, + mock_close_connection, + mock_open_connection, + mock_init): + volume = {'id': 111} + backend_volume = {'id': 112} + rt = self.driver.update_migrated_volume(None, volume, backend_volume) + mock_rename_volume.assert_called_once_with(self.VOLUME, + volume['id']) + self.assertEqual(None, rt) + + def test_update_migrated_volume_no_volume_id(self, + mock_close_connection, + mock_open_connection, + mock_init): + volume = {'id': None} + backend_volume = {'id': 112} + rt = self.driver.update_migrated_volume(None, volume, backend_volume) + self.assertEqual(None, rt) + + @mock.patch.object(dell_storagecenter_api.StorageCenterApi, + 'find_sc', + return_value=12345) + @mock.patch.object(dell_storagecenter_api.StorageCenterApi, + 'find_volume', + return_value=None) + def test_update_migrated_volume_no_backend_id(self, + mock_find_volume, + mock_find_sc, + mock_close_connection, + mock_open_connection, + mock_init): + volume = {'id': 111} + backend_volume = {'id': None} + rt = self.driver.update_migrated_volume(None, volume, backend_volume) + mock_find_sc.assert_called_once_with(12345) + mock_find_volume.assert_called_once_with(12345, None) + self.assertEqual(None, rt) diff --git a/cinder/tests/unit/test_dellscapi.py b/cinder/tests/unit/test_dellscapi.py index 215828a53..6fe432613 100644 --- a/cinder/tests/unit/test_dellscapi.py +++ b/cinder/tests/unit/test_dellscapi.py @@ -3588,6 +3588,30 @@ class DellSCSanAPITestCase(test.TestCase): self.assertTrue(mock_post.called) self.assertIsNone(res, 'Expected None') + @mock.patch.object(dell_storagecenter_api.HttpClient, + 'post', + return_value=RESPONSE_200) + def test_rename_volume(self, + mock_post, + mock_close_connection, + mock_open_connection, + mock_init): + res = self.scapi.rename_volume(self.VOLUME, 'newname') + self.assertTrue(mock_post.called) + self.assertTrue(res) + + @mock.patch.object(dell_storagecenter_api.HttpClient, + 'post', + return_value=RESPONSE_204) + def test_rename_volume_failure(self, + mock_post, + mock_close_connection, + mock_open_connection, + mock_init): + res = self.scapi.rename_volume(self.VOLUME, 'newname') + self.assertTrue(mock_post.called) + self.assertFalse(res) + @mock.patch.object(dell_storagecenter_api.HttpClient, 'delete', return_value=RESPONSE_200) diff --git a/cinder/volume/drivers/dell/dell_storagecenter_api.py b/cinder/volume/drivers/dell/dell_storagecenter_api.py index 9cdb273be..9ed896243 100644 --- a/cinder/volume/drivers/dell/dell_storagecenter_api.py +++ b/cinder/volume/drivers/dell/dell_storagecenter_api.py @@ -1163,6 +1163,21 @@ class StorageCenterApi(object): 's': vol['configuredSize']}) return vol + def rename_volume(self, scvolume, name): + payload = {} + payload['Name'] = name + r = self.client.post('StorageCenter/ScVolume/%s/Modify' + % self._get_id(scvolume), + payload) + if r.status_code != 200: + LOG.error(_LE('Error renaming volume %(o)s to %(n)s: %(c)d %(r)s'), + {'o': scvolume['name'], + 'n': name, + 'c': r.status_code, + 'r': r.reason}) + return False + return True + def _delete_server(self, scserver): '''_delete_server diff --git a/cinder/volume/drivers/dell/dell_storagecenter_common.py b/cinder/volume/drivers/dell/dell_storagecenter_common.py index 47511ab7b..207f1840d 100644 --- a/cinder/volume/drivers/dell/dell_storagecenter_common.py +++ b/cinder/volume/drivers/dell/dell_storagecenter_common.py @@ -348,3 +348,33 @@ class DellCommonDriver(san.SanDriver): LOG.debug('Total cap %(t)s Free cap %(f)s', {'t': totalcapacitygb, 'f': freespacegb}) + + def update_migrated_volume(self, ctxt, volume, new_volume): + """Return model update for migrated volume. + + :param volume: The original volume that was migrated to this backend + :param new_volume: The migration volume object that was created on + this backend as part of the migration process + :return model_update to update DB with any needed changes + """ + # We use id as our volume name so we need to rename the backend + # volume to the original volume name. + original_volume_name = volume.get('id') + current_name = new_volume.get('id') + LOG.debug('update_migrated_volume: %(c)s to %(o)s', + {'c': current_name, + 'o': original_volume_name}) + if original_volume_name: + with self._client.open_connection() as api: + ssn = api.find_sc(self.configuration.dell_sc_ssn) + if ssn is not None: + scvolume = api.find_volume(ssn, + current_name) + if scvolume: + if api.rename_volume(scvolume, original_volume_name): + model_update = {'_name_id': None} + return model_update + # The world was horrible to us so we should error and leave. + LOG.error(_LE('Unabled to rename the logical volume for volume: %s'), + original_volume_name) + return None