From 891f2268b72d3047ea6e953cf5fd1a47a4ba9b6b Mon Sep 17 00:00:00 2001 From: Xiaoqin Li Date: Thu, 23 Feb 2017 18:39:18 +0800 Subject: [PATCH] Storwize: correct unreplicated vol status Correct the status of unreplicated vol during failover/failback. 1. The status of unreplicated vol (vol which is not replicated or volume status is not 'available', for example, 'in-use' or 'error') should be changed to 'error' during failover/failback. 2. The status of unreplicated vol should be changed back to previous status after failback/failover. Change-Id: I9828e6ecbe4ec0e207492335088fc1081fa00538 Closes-Bug: 1665189 --- .../volume/drivers/ibm/test_storwize_svc.py | 59 +++++++++++++++---- .../drivers/ibm/storwize_svc/replication.py | 18 +++++- .../ibm/storwize_svc/storwize_svc_common.py | 54 ++++++++--------- 3 files changed, 84 insertions(+), 47 deletions(-) diff --git a/cinder/tests/unit/volume/drivers/ibm/test_storwize_svc.py b/cinder/tests/unit/volume/drivers/ibm/test_storwize_svc.py index cffc14c1d13..ab3d79e0748 100644 --- a/cinder/tests/unit/volume/drivers/ibm/test_storwize_svc.py +++ b/cinder/tests/unit/volume/drivers/ibm/test_storwize_svc.py @@ -5979,7 +5979,6 @@ class StorwizeSVCReplicationTestCase(test.TestCase): def _create_test_volume(self, rep_type): volume = self._generate_vol_info(rep_type) model_update = self.driver.create_volume(volume) - volume['status'] = 'available' return volume, model_update def _get_vdisk_uid(self, vdisk_name): @@ -6630,10 +6629,13 @@ class StorwizeSVCReplicationTestCase(test.TestCase): [self.rep_target]) self.driver.do_setup(self.ctxt) - # Create metro mirror replication. + # Create replication volume. mm_vol, model_update = self._create_test_volume(self.mm_type) self.assertEqual('enabled', model_update['replication_status']) mm_vol['status'] = 'in-use' + gm_vol, model_update = self._create_test_volume(self.gm_type) + self.assertEqual('enabled', model_update['replication_status']) + gm_vol['status'] = 'available' # Create non-replication volume. non_replica_vol1, model_update = self._create_test_volume( @@ -6645,12 +6647,14 @@ class StorwizeSVCReplicationTestCase(test.TestCase): non_replica_vol1['status'] = 'error' non_replica_vol2['status'] = 'available' - volumes = [mm_vol, non_replica_vol1, non_replica_vol2] + volumes = [mm_vol, non_replica_vol1, non_replica_vol2, gm_vol] rep_data0 = json.dumps({'previous_status': mm_vol['status']}) rep_data1 = json.dumps({'previous_status': non_replica_vol1['status']}) rep_data2 = json.dumps({'previous_status': non_replica_vol2['status']}) - failover_expect = [{'updates': {'status': 'error', + failover_expect = [{'updates': {'replication_status': 'failed-over'}, + 'volume_id': gm_vol['id']}, + {'updates': {'status': 'error', 'replication_driver_data': rep_data0}, 'volume_id': mm_vol['id']}, {'updates': {'status': 'error', @@ -6659,15 +6663,6 @@ class StorwizeSVCReplicationTestCase(test.TestCase): {'updates': {'status': 'error', 'replication_driver_data': rep_data2}, 'volume_id': non_replica_vol2['id']}] - failback_expect = [{'updates': {'status': 'in-use', - 'replication_driver_data': ''}, - 'volume_id': mm_vol['id']}, - {'updates': {'status': 'error', - 'replication_driver_data': ''}, - 'volume_id': non_replica_vol1['id']}, - {'updates': {'status': 'available', - 'replication_driver_data': ''}, - 'volume_id': non_replica_vol2['id']}] # Already failback target_id, volume_list = self.driver.failover_host( self.ctxt, volumes, 'default') @@ -6689,6 +6684,20 @@ class StorwizeSVCReplicationTestCase(test.TestCase): {'previous_status': 'error'}) non_replica_vol2['replication_driver_data'] = json.dumps( {'previous_status': 'available'}) + gm_vol['status'] = 'in-use' + rep_data3 = json.dumps({'previous_status': gm_vol['status']}) + failback_expect = [{'updates': {'status': 'in-use', + 'replication_driver_data': ''}, + 'volume_id': mm_vol['id']}, + {'updates': {'status': 'error', + 'replication_driver_data': ''}, + 'volume_id': non_replica_vol1['id']}, + {'updates': {'status': 'available', + 'replication_driver_data': ''}, + 'volume_id': non_replica_vol2['id']}, + {'updates': {'status': 'error', + 'replication_driver_data': rep_data3}, + 'volume_id': gm_vol['id']}] target_id, volume_list = self.driver.failover_host( self.ctxt, volumes, 'default') self.assertEqual('default', target_id) @@ -6735,6 +6744,30 @@ class StorwizeSVCReplicationTestCase(test.TestCase): self.assertIsNotNone(partner_info) self.assertEqual(partner_info['name'], source_system_name) + @mock.patch.object(storwize_svc_common.StorwizeHelpers, + 'get_partnership_info') + @mock.patch.object(storwize_svc_common.StorwizeHelpers, + 'chpartnership') + def test_start_partnership(self, chpartnership, get_partnership_info): + get_partnership_info.side_effect = [ + None, + {'partnership': 'fully_configured', + 'id': '0'}, + {'partnership': 'fully_configured_stopped', + 'id': '0'}] + + rep_mgr = self.driver._get_replica_mgr() + rep_mgr._partnership_start(rep_mgr._master_helpers, + 'storwize-svc-sim') + self.assertFalse(chpartnership.called) + rep_mgr._partnership_start(rep_mgr._master_helpers, + 'storwize-svc-sim') + self.assertFalse(chpartnership.called) + + rep_mgr._partnership_start(rep_mgr._master_helpers, + 'storwize-svc-sim') + chpartnership.assert_called_once_with('0') + @mock.patch.object(storwize_svc_common.StorwizeHelpers, 'start_relationship') def test_sync_replica_volumes_with_aux(self, start_relationship): diff --git a/cinder/volume/drivers/ibm/storwize_svc/replication.py b/cinder/volume/drivers/ibm/storwize_svc/replication.py index 8a00ff49e8e..db0cead036e 100644 --- a/cinder/volume/drivers/ibm/storwize_svc/replication.py +++ b/cinder/volume/drivers/ibm/storwize_svc/replication.py @@ -396,15 +396,25 @@ class StorwizeSVCReplicationManager(object): client.mkfcpartnership(remote_name) else: client.mkippartnership(remote_ip) - partnership_info = client.get_partnership_info(remote_name) - if partnership_info['partnership'] != 'fully_configured': - client.chpartnership(partnership_info['id']) except Exception: msg = (_('Unable to establish the partnership with ' 'the Storwize cluster %s.'), remote_name) LOG.error(msg) raise exception.VolumeDriverException(message=msg) + def _partnership_start(self, client, remote_name): + try: + partnership_info = client.get_partnership_info( + remote_name) + if (partnership_info and + partnership_info['partnership'] != 'fully_configured'): + client.chpartnership(partnership_info['id']) + except Exception: + msg = (_('Unable to start the partnership with ' + 'the Storwize cluster %s.'), remote_name) + LOG.error(msg) + raise exception.VolumeDriverException(message=msg) + def establish_target_partnership(self): local_system_info = self._master_helpers.get_system_info() target_system_info = self.target_helpers.get_system_info() @@ -419,3 +429,5 @@ class StorwizeSVCReplicationManager(object): target_system_name, target_ip) self._partnership_validate_create(self.target_helpers, local_system_name, local_ip) + self._partnership_start(self._master_helpers, target_system_name) + self._partnership_start(self.target_helpers, local_system_name) diff --git a/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py b/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py index 2da247b1414..3f351ddc9db 100644 --- a/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py +++ b/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py @@ -387,7 +387,7 @@ class StorwizeSSH(object): self.run_ssh_assert_no_output(ssh_cmd) def mkvdisk(self, name, size, units, pool, opts, params): - ssh_cmd = ['svctask', 'mkvdisk', '-name', name, '-mdiskgrp', + ssh_cmd = ['svctask', 'mkvdisk', '-name', '"%s"' % name, '-mdiskgrp', '"%s"' % pool, '-iogrp', six.text_type(opts['iogrp']), '-size', size, '-unit', units] + params try: @@ -1247,7 +1247,6 @@ class StorwizeHelpers(object): return params def create_vdisk(self, name, size, units, pool, opts): - name = '"%s"' % name LOG.debug('Enter: create_vdisk: vdisk %s.', name) params = self._get_vdisk_create_params(opts) self.ssh.mkvdisk(name, size, units, pool, opts, params) @@ -2739,7 +2738,7 @@ class StorwizeSVCCommonDriver(san.SanDriver, LOG.error(msg) raise exception.UnableToFailOver(reason=msg) - normal_volumes, rep_volumes = self._classify_volume(ctxt, volumes) + unrep_volumes, rep_volumes = self._classify_volume(ctxt, volumes) # start synchronize from aux volume to master volume self._sync_with_aux(ctxt, rep_volumes) @@ -2749,8 +2748,9 @@ class StorwizeSVCCommonDriver(san.SanDriver, rep_volumes) volumes_update.extend(rep_volumes_update) - normal_volumes_update = self._failback_normal_volumes(normal_volumes) - volumes_update.extend(normal_volumes_update) + unrep_volumes_update = self._failover_unreplicated_volume( + unrep_volumes) + volumes_update.extend(unrep_volumes_update) self._helpers = self._master_backend_helpers self._active_backend_id = None @@ -2806,18 +2806,22 @@ class StorwizeSVCCommonDriver(san.SanDriver, {'volumes_update': volumes_update}) return volumes_update - def _failback_normal_volumes(self, normal_volumes): + def _failover_unreplicated_volume(self, unreplicated_vols): volumes_update = [] - for vol in normal_volumes: - pre_status = 'available' - if ('replication_driver_data' in vol and - vol['replication_driver_data']): - rep_data = json.loads(vol['replication_driver_data']) - pre_status = rep_data['previous_status'] + for vol in unreplicated_vols: + if vol.replication_driver_data: + rep_data = json.loads(vol.replication_driver_data) + update_status = rep_data['previous_status'] + rep_data = '' + else: + update_status = 'error' + rep_data = json.dumps({'previous_status': vol.status}) + volumes_update.append( - {'volume_id': vol['id'], - 'updates': {'status': pre_status, - 'replication_driver_data': ''}}) + {'volume_id': vol.id, + 'updates': {'status': update_status, + 'replication_driver_data': rep_data}}) + return volumes_update def _sync_with_aux(self, ctxt, volumes): @@ -2928,13 +2932,14 @@ class StorwizeSVCCommonDriver(san.SanDriver, LOG.error(msg) raise exception.UnableToFailOver(reason=msg) - normal_volumes, rep_volumes = self._classify_volume(ctxt, volumes) + unrep_volumes, rep_volumes = self._classify_volume(ctxt, volumes) rep_volumes_update = self._failover_replica_volumes(ctxt, rep_volumes) volumes_update.extend(rep_volumes_update) - normal_volumes_update = self._failover_normal_volumes(normal_volumes) - volumes_update.extend(normal_volumes_update) + unrep_volumes_update = self._failover_unreplicated_volume( + unrep_volumes) + volumes_update.extend(unrep_volumes_update) self._helpers = self._aux_backend_helpers self._active_backend_id = self._replica_target['backend_id'] @@ -2993,19 +2998,6 @@ class StorwizeSVCCommonDriver(san.SanDriver, {'volumes_update': volumes_update}) return volumes_update - def _failover_normal_volumes(self, normal_volumes): - volumes_update = [] - for volume in normal_volumes: - # If the volume is not of replicated type, we need to - # force the status into error state so a user knows they - # do not have access to the volume. - rep_data = json.dumps({'previous_status': volume['status']}) - volumes_update.append( - {'volume_id': volume['id'], - 'updates': {'status': 'error', - 'replication_driver_data': rep_data}}) - return volumes_update - def _classify_volume(self, ctxt, volumes): normal_volumes = [] replica_volumes = []