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
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)
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()
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 = {}
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))
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)
@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)
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)
@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)