3PAR: Support extend volume based on snapshot
If extend volume fails with an HTTP Forbidden error 150, convert the volume to a base volume and retry extending. Change-Id: Id407058e954b2630f4a7f31c6149361301b502f2 Closes-Bug: #1285906
This commit is contained in:
parent
ee371dfc56
commit
fb25917fe1
@ -781,6 +781,52 @@ class HP3PARBaseDriver(object):
|
||||
|
||||
mock_client.assert_has_calls(expected)
|
||||
|
||||
def test_extend_volume_non_base(self):
|
||||
extend_ex = hpexceptions.HTTPForbidden(error={'code': 150})
|
||||
conf = {
|
||||
'getPorts.return_value': {
|
||||
'members': self.FAKE_FC_PORTS + [self.FAKE_ISCSI_PORT]},
|
||||
'getTask.return_value': {
|
||||
'status': 1},
|
||||
'getCPG.return_value': {},
|
||||
'copyVolume.return_value': {'taskid': 1},
|
||||
'getVolume.return_value': {},
|
||||
# Throw an exception first time only
|
||||
'growVolume.side_effect': [extend_ex,
|
||||
None],
|
||||
}
|
||||
|
||||
mock_client = self.setup_driver(mock_conf=conf)
|
||||
grow_size = 3
|
||||
old_size = self.volume['size']
|
||||
new_size = old_size + grow_size
|
||||
self.driver.extend_volume(self.volume, str(new_size))
|
||||
|
||||
self.assertEqual(2, mock_client.growVolume.call_count)
|
||||
|
||||
def test_extend_volume_non_base_failure(self):
|
||||
extend_ex = hpexceptions.HTTPForbidden(error={'code': 150})
|
||||
conf = {
|
||||
'getPorts.return_value': {
|
||||
'members': self.FAKE_FC_PORTS + [self.FAKE_ISCSI_PORT]},
|
||||
'getTask.return_value': {
|
||||
'status': 1},
|
||||
'getCPG.return_value': {},
|
||||
'copyVolume.return_value': {'taskid': 1},
|
||||
'getVolume.return_value': {},
|
||||
# Always fail
|
||||
'growVolume.side_effect': extend_ex
|
||||
}
|
||||
|
||||
mock_client = self.setup_driver(mock_conf=conf)
|
||||
grow_size = 3
|
||||
old_size = self.volume['size']
|
||||
new_size = old_size + grow_size
|
||||
self.assertRaises(hpexceptions.HTTPForbidden,
|
||||
self.driver.extend_volume,
|
||||
self.volume,
|
||||
str(new_size))
|
||||
|
||||
def test_get_ports(self):
|
||||
# setup_mock_client drive with default configuration
|
||||
# and return the mock HTTP 3PAR client
|
||||
|
@ -120,10 +120,11 @@ class HP3PARCommon(object):
|
||||
2.0.4 - Allow volumes created from snapshots to be larger bug #1279478
|
||||
2.0.5 - Fix extend volume units bug #1284368
|
||||
2.0.6 - use loopingcall.wait instead of time.sleep
|
||||
2.0.7 - Allow extend volume based on snapshot bug #1285906
|
||||
|
||||
"""
|
||||
|
||||
VERSION = "2.0.6"
|
||||
VERSION = "2.0.7"
|
||||
|
||||
stats = {}
|
||||
|
||||
@ -248,14 +249,39 @@ class HP3PARCommon(object):
|
||||
volume_name = self._get_3par_vol_name(volume['id'])
|
||||
old_size = volume['size']
|
||||
growth_size = int(new_size) - old_size
|
||||
LOG.debug("Extending Volume %s from %s to %s, by %s GB." %
|
||||
(volume_name, old_size, new_size, growth_size))
|
||||
LOG.debug(_("Extending Volume %(vol)s from %(old)s to %(new)s, "
|
||||
" by %(diff)s GB.") %
|
||||
{'vol': volume_name, 'old': old_size, 'new': new_size,
|
||||
'diff': growth_size})
|
||||
growth_size_mib = growth_size * units.KiB
|
||||
self._extend_volume(volume, volume_name, growth_size_mib)
|
||||
|
||||
def _extend_volume(self, volume, volume_name, growth_size_mib,
|
||||
_convert_to_base=False):
|
||||
try:
|
||||
if _convert_to_base:
|
||||
LOG.debug(_("Converting to base volume prior to growing."))
|
||||
self._convert_to_base_volume(volume)
|
||||
self.client.growVolume(volume_name, growth_size_mib)
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_("Error extending volume %s") % volume)
|
||||
except Exception as ex:
|
||||
with excutils.save_and_reraise_exception() as ex_ctxt:
|
||||
if (not _convert_to_base and
|
||||
isinstance(ex, hpexceptions.HTTPForbidden) and
|
||||
ex.get_code() == 150):
|
||||
# Error code 150 means 'invalid operation: Cannot grow
|
||||
# this type of volume'.
|
||||
# Suppress raising this exception because we can
|
||||
# resolve it by converting it into a base volume.
|
||||
# Afterwards, extending the volume should succeed, or
|
||||
# fail with a different exception/error code.
|
||||
ex_ctxt.reraise = False
|
||||
self._extend_volume(volume, volume_name,
|
||||
growth_size_mib,
|
||||
_convert_to_base=True)
|
||||
else:
|
||||
LOG.error(_("Error extending volume: %(vol)s. "
|
||||
"Exception: %(ex)s") %
|
||||
{'vol': volume_name, 'ex': ex})
|
||||
|
||||
def _get_3par_vol_name(self, volume_id):
|
||||
"""Get converted 3PAR volume name.
|
||||
|
Loading…
x
Reference in New Issue
Block a user