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
This commit is contained in:
parent
8a5ce963dc
commit
dd9536ac6e
|
@ -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()
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue