From dd9536ac6e6df0e1ae6754e580b99cfbfd05eb77 Mon Sep 17 00:00:00 2001 From: Sivaramakrishna Garimella Date: Mon, 9 Dec 2013 11:11:13 +0530 Subject: [PATCH] Add additional metadata as key-value pairs in 3PAR Track status of openstack volumes on 3PAR through additional metadata added as key-value pairs. During volume attach and detach, corresponding instance metadata is updated onto the cinder volumes. Change-Id: Iea8d2f26555e6be60001bf73755cae42446afec6 Closes-Bug: #1258033 --- cinder/tests/test_hp3par.py | 57 ++++++++++++++++++ .../volume/drivers/san/hp/hp_3par_common.py | 58 ++++++++++++++++++- cinder/volume/drivers/san/hp/hp_3par_fc.py | 13 ++++- cinder/volume/drivers/san/hp/hp_3par_iscsi.py | 13 ++++- 4 files changed, 138 insertions(+), 3 deletions(-) diff --git a/cinder/tests/test_hp3par.py b/cinder/tests/test_hp3par.py index 8034bca00..942ec7a2a 100644 --- a/cinder/tests/test_hp3par.py +++ b/cinder/tests/test_hp3par.py @@ -25,6 +25,7 @@ import tempfile from hp3parclient import exceptions as hpexceptions +from cinder import context from cinder import exception from cinder.openstack.common import log as logging from cinder import test @@ -574,6 +575,33 @@ class HP3PARBaseDriver(): model_update = self.driver.create_cloned_volume(volume, src_vref) self.assertIsNotNone(model_update) + @mock.patch.object(hpdriver.hpcommon.HP3PARCommon, '_run_ssh') + def test_attach_volume(self, mock_run_ssh): + mock_run_ssh.side_effect = [[CLI_CR, ''], Exception('Custom ex')] + self.driver.attach_volume(context.get_admin_context(), + self.volume, + 'abcdef', + 'newhost', + '/dev/vdb') + self.assertTrue(mock_run_ssh.called) + self.assertRaises(exception.CinderException, + self.driver.attach_volume, + context.get_admin_context(), + self.volume, + 'abcdef', + 'newhost', + '/dev/vdb') + + @mock.patch.object(hpdriver.hpcommon.HP3PARCommon, '_run_ssh') + def test_detach_volume(self, mock_run_ssh): + mock_run_ssh.side_effect = [[CLI_CR, ''], Exception('Custom ex')] + self.driver.detach_volume(context.get_admin_context(), self.volume) + self.assertTrue(mock_run_ssh.called) + self.assertRaises(exception.CinderException, + self.driver.detach_volume, + context.get_admin_context(), + self.volume) + def test_create_snapshot(self): self.flags(lock_path=self.tempdir) self.driver.create_snapshot(self.snapshot) @@ -643,6 +671,35 @@ class HP3PARBaseDriver(): self.driver.common.client.getVLUN, self.VOLUME_3PAR_NAME) + @mock.patch.object(hpdriver.hpcommon.HP3PARCommon, '_run_ssh') + def test_update_volume_key_value_pair(self, mock_run_ssh): + mock_run_ssh.return_value = [CLI_CR, ''] + self.assertEqual( + self.driver.common.update_volume_key_value_pair(self.volume, + 'a', + 'b'), + None) + update_cmd = ['setvv', '-setkv', 'a=b', self.VOLUME_3PAR_NAME] + mock_run_ssh.assert_called_once_with(update_cmd, False) + self.assertRaises(exception.VolumeBackendAPIException, + self.driver.common.update_volume_key_value_pair, + self.volume, + None, + 'b') + + @mock.patch.object(hpdriver.hpcommon.HP3PARCommon, '_run_ssh') + def test_clear_volume_key_value_pair(self, mock_run_ssh): + mock_run_ssh.side_effect = [[CLI_CR, ''], Exception('Custom ex')] + self.assertEqual( + self.driver.common.clear_volume_key_value_pair(self.volume, 'a'), + None) + clear_cmd = ['setvv', '-clrkey', 'a', self.VOLUME_3PAR_NAME] + mock_run_ssh.assert_called_once_with(clear_cmd, False) + self.assertRaises(exception.VolumeBackendAPIException, + self.driver.common.clear_volume_key_value_pair, + self.volume, + None) + def test_extend_volume(self): self.flags(lock_path=self.tempdir) self.stubs.UnsetAll() diff --git a/cinder/volume/drivers/san/hp/hp_3par_common.py b/cinder/volume/drivers/san/hp/hp_3par_common.py index 8da5e5269..2e86530b7 100644 --- a/cinder/volume/drivers/san/hp/hp_3par_common.py +++ b/cinder/volume/drivers/san/hp/hp_3par_common.py @@ -117,10 +117,11 @@ class HP3PARCommon(object): 1.2.0 - Updated hp3parclient API use to 2.0.x 1.2.1 - Check that the VVS exists 1.2.2 - log prior to raising exceptions + 1.2.3 - Methods to update key/value pair bug #1258033 """ - VERSION = "1.2.2" + VERSION = "1.2.3" stats = {} @@ -972,6 +973,61 @@ exit LOG.error(str(ex)) raise exception.NotFound() + def update_volume_key_value_pair(self, volume, key, value): + """Updates key,value pair as metadata onto virtual volume. + + If key already exists, the value will be replaced. + """ + LOG.debug("VOLUME (%s : %s %s) Updating KEY-VALUE pair: (%s : %s)" % + (volume['display_name'], + volume['name'], + self._get_3par_vol_name(volume['id']), + str(key), + str(value))) + try: + volume_name = self._get_3par_vol_name(volume['id']) + if value is None: + value = '' + cmd = ['setvv', '-setkv', key + '=' + value, volume_name] + self._cli_run(cmd) + except Exception as ex: + msg = _('Failure in update_volume_key_value_pair:%s') % str(ex) + LOG.error(msg) + raise exception.VolumeBackendAPIException(data=msg) + + def clear_volume_key_value_pair(self, volume, key): + """Clears key,value pairs metadata from virtual volume.""" + + LOG.debug("VOLUME (%s : %s %s) Clearing Key : %s)" % + (volume['display_name'], volume['name'], + self._get_3par_vol_name(volume['id']), str(key))) + try: + volume_name = self._get_3par_vol_name(volume['id']) + cmd = ['setvv', '-clrkey', key, volume_name] + self._cli_run(cmd) + except Exception as ex: + msg = _('Failure in clear_volume_key_value_pair:%s') % str(ex) + LOG.error(msg) + raise exception.VolumeBackendAPIException(data=msg) + + def attach_volume(self, volume, instance_uuid): + LOG.debug("Attach Volume\n%s" % pprint.pformat(volume)) + try: + self.update_volume_key_value_pair(volume, + 'HPQ-CS-instance_uuid', + instance_uuid) + except Exception: + with excutils.save_and_reraise_exception(): + LOG.error(_("Error attaching volume %s") % volume) + + def detach_volume(self, volume): + LOG.debug("Detach Volume\n%s" % pprint.pformat(volume)) + try: + self.clear_volume_key_value_pair(volume, 'HPQ-CS-instance_uuid') + except Exception: + with excutils.save_and_reraise_exception(): + LOG.error(_("Error detaching volume %s") % volume) + def delete_snapshot(self, snapshot): LOG.debug("Delete Snapshot\n%s" % pprint.pformat(snapshot)) diff --git a/cinder/volume/drivers/san/hp/hp_3par_fc.py b/cinder/volume/drivers/san/hp/hp_3par_fc.py index e404f998d..ee71de92d 100644 --- a/cinder/volume/drivers/san/hp/hp_3par_fc.py +++ b/cinder/volume/drivers/san/hp/hp_3par_fc.py @@ -55,9 +55,11 @@ class HP3PARFCDriver(cinder.volume.driver.FibreChannelDriver): 1.2.1 - Synchronized extend_volume method. 1.2.2 - Added try/finally around client login/logout. 1.2.3 - Added ability to add WWNs to host. + 1.2.4 - Added metadata during attach/detach bug #1258033. + """ - VERSION = "1.2.3" + VERSION = "1.2.4" def __init__(self, *args, **kwargs): super(HP3PARFCDriver, self).__init__(*args, **kwargs) @@ -316,3 +318,12 @@ class HP3PARFCDriver(cinder.volume.driver.FibreChannelDriver): @utils.synchronized('3par', external=True) def extend_volume(self, volume, new_size): self.common.extend_volume(volume, new_size) + + @utils.synchronized('3par', external=True) + def attach_volume(self, context, volume, instance_uuid, host_name, + mountpoint): + self.common.attach_volume(volume, instance_uuid) + + @utils.synchronized('3par', external=True) + def detach_volume(self, context, volume): + self.common.detach_volume(volume) diff --git a/cinder/volume/drivers/san/hp/hp_3par_iscsi.py b/cinder/volume/drivers/san/hp/hp_3par_iscsi.py index be4e0b148..94fd27c9f 100644 --- a/cinder/volume/drivers/san/hp/hp_3par_iscsi.py +++ b/cinder/volume/drivers/san/hp/hp_3par_iscsi.py @@ -59,9 +59,11 @@ class HP3PARISCSIDriver(cinder.volume.driver.ISCSIDriver): 1.2.2 - Added try/finally around client login/logout. 1.2.3 - log exceptions before raising 1.2.4 - Fixed iSCSI active path bug #1224594 + 1.2.5 - Added metadata during attach/detach bug #1258033 + """ - VERSION = "1.2.4" + VERSION = "1.2.5" def __init__(self, *args, **kwargs): super(HP3PARISCSIDriver, self).__init__(*args, **kwargs) @@ -423,3 +425,12 @@ class HP3PARISCSIDriver(cinder.volume.driver.ISCSIDriver): @utils.synchronized('3par', external=True) def extend_volume(self, volume, new_size): self.common.extend_volume(volume, new_size) + + @utils.synchronized('3par', external=True) + def attach_volume(self, context, volume, instance_uuid, host_name, + mountpoint): + self.common.attach_volume(volume, instance_uuid) + + @utils.synchronized('3par', external=True) + def detach_volume(self, context, volume): + self.common.detach_volume(volume) -- 2.45.2