From: Jason Ni Date: Mon, 25 Aug 2014 05:14:54 +0000 (+0300) Subject: Adds volume replication methods to xiv/ds8k driver interface. X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=3220e7f930f841b3bf822dc906da39db36a194c2;p=openstack-build%2Fcinder-build.git Adds volume replication methods to xiv/ds8k driver interface. Change-Id: I99add7e562d7b5e8f14b186f7c705209af27f6a2 --- diff --git a/cinder/tests/test_ibm_xiv_ds8k.py b/cinder/tests/test_ibm_xiv_ds8k.py index 64bb53d56..ef4baf65f 100644 --- a/cinder/tests/test_ibm_xiv_ds8k.py +++ b/cinder/tests/test_ibm_xiv_ds8k.py @@ -19,6 +19,8 @@ # Avishay Traeger +import copy + import mox from oslo.config import cfg @@ -33,11 +35,19 @@ FAKE = "fake" VOLUME = {'size': 16, 'name': FAKE, 'id': 1} + MANAGED_FAKE = "managed_fake" MANAGED_VOLUME = {'size': 16, 'name': MANAGED_FAKE, 'id': 2} +REPLICA_FAKE = "repicated_fake" +REPLICATED_VOLUME = {'size': 64, + 'name': REPLICA_FAKE, + 'id': 2} + +CONTEXT = {} + CONNECTOR = {'initiator': "iqn.2012-07.org.fake:01:948f189c4695", } CONF = cfg.CONF @@ -130,6 +140,32 @@ class XIVDS8KFakeProxyDriver(object): return (self.volumes[volume['name']].get('attached', None) == connector) + def reenable_replication(self, context, volume): + model_update = {} + if volume['replication_status'] == 'inactive': + model_update['replication_status'] = 'active' + elif volume['replication_status'] == 'invalid_status_val': + raise exception.CinderException() + model_update['replication_extended_status'] = 'some_status' + model_update['replication_driver_data'] = 'some_data' + return model_update + + def get_replication_status(self, context, volume): + if volume['replication_status'] == 'invalid_status_val': + raise exception.CinderException() + return {'replication_status': 'active'} + + def promote_replica(self, context, volume): + if volume['replication_status'] == 'invalid_status_val': + raise exception.CinderException() + return {'replication_status': 'inactive'} + + def create_replica_test_volume(self, volume, src_vref): + if volume['size'] != src_vref['size']: + raise exception.InvalidVolume( + reason="Target and source volumes have different size.") + return + class XIVDS8KVolumeDriverTest(test.TestCase): """Test IBM XIV and DS8K volume driver.""" @@ -317,3 +353,130 @@ class XIVDS8KVolumeDriverTest(test.TestCase): self.driver.manage_existing, VOLUME, existing_ref) + + def test_reenable_replication(self): + """Test that reenable_replication returns successfully. """ + + self.driver.do_setup(None) + # assume the replicated volume is inactive + replicated_volume = copy.deepcopy(REPLICATED_VOLUME) + replicated_volume['replication_status'] = 'inactive' + model_update = self.driver.reenable_replication( + CONTEXT, + replicated_volume + ) + self.assertEqual( + model_update['replication_status'], + 'active' + ) + self.assertTrue('replication_extended_status' in model_update) + self.assertTrue('replication_driver_data' in model_update) + + def test_reenable_replication_fail_on_cinder_exception(self): + """Test that reenable_replication fails on driver raising exception.""" + + self.driver.do_setup(None) + + replicated_volume = copy.deepcopy(REPLICATED_VOLUME) + # on purpose - set invalid value to replication_status + # expect an exception. + replicated_volume['replication_status'] = 'invalid_status_val' + self.assertRaises( + exception.CinderException, + self.driver.reenable_replication, + CONTEXT, + replicated_volume + ) + + def test_get_replication_status(self): + """Test that get_replication_status return successfully. """ + + self.driver.do_setup(None) + + # assume the replicated volume is inactive + replicated_volume = copy.deepcopy(REPLICATED_VOLUME) + replicated_volume['replication_status'] = 'inactive' + model_update = self.driver.get_replication_status( + CONTEXT, + replicated_volume + ) + self.assertEqual( + model_update['replication_status'], + 'active' + ) + + def test_get_replication_status_fail_on_exception(self): + """Test that get_replication_status fails on exception""" + + self.driver.do_setup(None) + + replicated_volume = copy.deepcopy(REPLICATED_VOLUME) + # on purpose - set invalid value to replication_status + # expect an exception. + replicated_volume['replication_status'] = 'invalid_status_val' + self.assertRaises( + exception.CinderException, + self.driver.get_replication_status, + CONTEXT, + replicated_volume + ) + + def test_promote_replica(self): + """Test that promote_replica returns successfully. """ + + self.driver.do_setup(None) + + replicated_volume = copy.deepcopy(REPLICATED_VOLUME) + # assume the replication_status should be active + replicated_volume['replication_status'] = 'active' + model_update = self.driver.promote_replica( + CONTEXT, + replicated_volume + ) + # after promoting, replication_status should be inactive + self.assertEqual( + model_update['replication_status'], + 'inactive' + ) + + def test_promote_replica_fail_on_cinder_exception(self): + """Test that promote_replica fails on CinderException. """ + + self.driver.do_setup(None) + + replicated_volume = copy.deepcopy(REPLICATED_VOLUME) + # on purpose - set invalid value to replication_status + # expect an exception. + replicated_volume['replication_status'] = 'invalid_status_val' + self.assertRaises( + exception.CinderException, + self.driver.promote_replica, + CONTEXT, + replicated_volume + ) + + def test_create_replica_test_volume(self): + """Test that create_replica_test_volume returns successfully.""" + + self.driver.do_setup(None) + tgt_volume = copy.deepcopy(VOLUME) + src_volume = copy.deepcopy(REPLICATED_VOLUME) + tgt_volume['size'] = src_volume['size'] + model_update = self.driver.create_replica_test_volume( + tgt_volume, + src_volume + ) + self.assertTrue(model_update is None) + + def test_create_replica_test_volume_fail_on_diff_size(self): + """Test that create_replica_test_volume fails on diff size.""" + + self.driver.do_setup(None) + tgt_volume = copy.deepcopy(VOLUME) + src_volume = copy.deepcopy(REPLICATED_VOLUME) + self.assertRaises( + exception.InvalidVolume, + self.driver.create_replica_test_volume, + tgt_volume, + src_volume + ) diff --git a/cinder/volume/drivers/ibm/xiv_ds8k.py b/cinder/volume/drivers/ibm/xiv_ds8k.py index 90ac83688..3ec94b500 100644 --- a/cinder/volume/drivers/ibm/xiv_ds8k.py +++ b/cinder/volume/drivers/ibm/xiv_ds8k.py @@ -64,10 +64,10 @@ class XIVDS8KDriver(san.SanDriver): proxy = importutils.import_class(self.configuration.xiv_ds8k_proxy) - #NOTE: All Array specific configurations are prefixed with: - #"xiv_ds8k_array_" - #These additional flags should be specified in the cinder.conf - #preferably in each backend configuration. + # NOTE: All Array specific configurations are prefixed with: + # "xiv_ds8k_array_" + # These additional flags should be specified in the cinder.conf + # preferably in each backend configuration. self.xiv_ds8k_proxy = proxy( { @@ -201,3 +201,23 @@ class XIVDS8KDriver(san.SanDriver): """Removes the specified volume from Cinder management.""" return self.xiv_ds8k_proxy.unmanage_volume(volume) + + def reenable_replication(self, context, volume): + """Re-enable volume replication. """ + + return self.xiv_ds8k_proxy.reenable_replication(context, volume) + + def get_replication_status(self, context, volume): + """Return replication status.""" + + return self.xiv_ds8k_proxy.get_replication_status(context, volume) + + def promote_replica(self, context, volume): + """Promote the replica to be the primary volume.""" + + return self.xiv_ds8k_proxy.promote_replica(context, volume) + + def create_replica_test_volume(self, volume, src_vref): + """Creates a test replica clone of the specified replicated volume.""" + + return self.xiv_ds8k_proxy.create_replica_test_volume(volume, src_vref)