Merge "backup of active 3par ISCSI bootable volume fails" into stable/newton
This commit is contained in:
commit
79ad4598aa
|
@ -1743,6 +1743,83 @@ class HPE3PARBaseDriver(object):
|
|||
expected +
|
||||
self.standard_logout)
|
||||
|
||||
def test_get_cpg_with_volume_return_usercpg(self):
|
||||
# setup_mock_client drive with default configuration
|
||||
# and return the mock HTTP 3PAR client
|
||||
mock_client = self.setup_driver()
|
||||
mock_client.getVolume.return_value = {'name': mock.ANY,
|
||||
'userCPG': HPE3PAR_CPG2}
|
||||
with mock.patch.object(hpecommon.HPE3PARCommon,
|
||||
'_create_client') as mock_create_client:
|
||||
mock_create_client.return_value = mock_client
|
||||
volume = {'id': HPE3PARBaseDriver.VOLUME_ID,
|
||||
'name': HPE3PARBaseDriver.VOLUME_NAME,
|
||||
'display_name': 'Foo Volume',
|
||||
'size': 2,
|
||||
'host': volume_utils.append_host(self.FAKE_HOST,
|
||||
HPE3PAR_CPG2)}
|
||||
common = self.driver._login()
|
||||
user_cpg = common.get_cpg(volume)
|
||||
common = hpecommon.HPE3PARCommon(None)
|
||||
vol_name = common._get_3par_vol_name(volume['id'])
|
||||
self.assertEqual(HPE3PAR_CPG2, user_cpg)
|
||||
expected = [mock.call.getVolume(vol_name)]
|
||||
|
||||
mock_client.assert_has_calls(
|
||||
self.standard_login +
|
||||
expected)
|
||||
|
||||
def test_get_cpg_with_volume_return_snapcpg(self):
|
||||
# setup_mock_client drive with default configuration
|
||||
# and return the mock HTTP 3PAR client
|
||||
mock_client = self.setup_driver()
|
||||
mock_client.getVolume.return_value = {'name': mock.ANY,
|
||||
'snapCPG': HPE3PAR_CPG2}
|
||||
with mock.patch.object(hpecommon.HPE3PARCommon,
|
||||
'_create_client') as mock_create_client:
|
||||
mock_create_client.return_value = mock_client
|
||||
volume = {'id': HPE3PARBaseDriver.VOLUME_ID,
|
||||
'name': HPE3PARBaseDriver.VOLUME_NAME,
|
||||
'display_name': 'Foo Volume',
|
||||
'size': 2,
|
||||
'host': volume_utils.append_host(self.FAKE_HOST,
|
||||
HPE3PAR_CPG2)}
|
||||
common = self.driver._login()
|
||||
snap_cpg = common.get_cpg(volume, allowSnap=True)
|
||||
common = hpecommon.HPE3PARCommon(None)
|
||||
vol_name = common._get_3par_vol_name(volume['id'])
|
||||
self.assertEqual(HPE3PAR_CPG2, snap_cpg)
|
||||
expected = [mock.call.getVolume(vol_name)]
|
||||
|
||||
mock_client.assert_has_calls(
|
||||
self.standard_login +
|
||||
expected)
|
||||
|
||||
def test_get_cpg_with_volume_return_no_cpg(self):
|
||||
# setup_mock_client drive with default configuration
|
||||
# and return the mock HTTP 3PAR client
|
||||
mock_client = self.setup_driver()
|
||||
mock_client.getVolume.return_value = {'name': mock.ANY}
|
||||
with mock.patch.object(hpecommon.HPE3PARCommon,
|
||||
'_create_client') as mock_create_client:
|
||||
mock_create_client.return_value = mock_client
|
||||
volume = {'id': HPE3PARBaseDriver.VOLUME_ID,
|
||||
'name': HPE3PARBaseDriver.VOLUME_NAME,
|
||||
'display_name': 'Foo Volume',
|
||||
'size': 2,
|
||||
'host': volume_utils.append_host(self.FAKE_HOST,
|
||||
HPE3PAR_CPG2)}
|
||||
common = self.driver._login()
|
||||
cpg_name = common.get_cpg(volume)
|
||||
common = hpecommon.HPE3PARCommon(None)
|
||||
vol_name = common._get_3par_vol_name(volume['id'])
|
||||
self.assertEqual(HPE3PAR_CPG2, cpg_name)
|
||||
expected = [mock.call.getVolume(vol_name)]
|
||||
|
||||
mock_client.assert_has_calls(
|
||||
self.standard_login +
|
||||
expected)
|
||||
|
||||
def test_create_cloned_volume(self):
|
||||
# setup_mock_client drive with default configuration
|
||||
# and return the mock HTTP 3PAR client
|
||||
|
@ -1762,7 +1839,7 @@ class HPE3PARBaseDriver(object):
|
|||
'source_volid': HPE3PARBaseDriver.VOLUME_ID}
|
||||
src_vref = {'id': HPE3PARBaseDriver.VOLUME_ID,
|
||||
'name': HPE3PARBaseDriver.VOLUME_NAME,
|
||||
'size': 2}
|
||||
'size': 2, 'status': 'available'}
|
||||
model_update = self.driver.create_cloned_volume(volume, src_vref)
|
||||
self.assertIsNone(model_update)
|
||||
|
||||
|
@ -1787,6 +1864,153 @@ class HPE3PARBaseDriver(object):
|
|||
expected +
|
||||
self.standard_logout)
|
||||
|
||||
def test_backup_iscsi_volume_with_chap_disabled(self):
|
||||
# setup_mock_client drive with default configuration
|
||||
# and return the mock HTTP 3PAR client
|
||||
mock_client = self.setup_driver()
|
||||
mock_client.getVolume.return_value = {'name': mock.ANY}
|
||||
mock_client.copyVolume.return_value = {'taskid': 1}
|
||||
mock_client.getVolumeMetaData.side_effect = hpeexceptions.HTTPNotFound
|
||||
|
||||
with mock.patch.object(hpecommon.HPE3PARCommon,
|
||||
'_create_client') as mock_create_client:
|
||||
mock_create_client.return_value = mock_client
|
||||
|
||||
volume = {'name': HPE3PARBaseDriver.VOLUME_NAME,
|
||||
'id': HPE3PARBaseDriver.CLONE_ID,
|
||||
'display_name': 'Foo Volume',
|
||||
'size': 2,
|
||||
'host': volume_utils.append_host(self.FAKE_HOST,
|
||||
HPE3PAR_CPG2)}
|
||||
src_vref = {'id': HPE3PARBaseDriver.VOLUME_ID,
|
||||
'name': HPE3PARBaseDriver.VOLUME_NAME,
|
||||
'size': 2, 'status': 'backing-up'}
|
||||
model_update = self.driver.create_cloned_volume(volume, src_vref)
|
||||
self.assertIsNone(model_update)
|
||||
|
||||
common = hpecommon.HPE3PARCommon(None)
|
||||
vol_name = common._get_3par_vol_name(src_vref['id'])
|
||||
# snapshot name is random
|
||||
snap_name = mock.ANY
|
||||
optional = mock.ANY
|
||||
|
||||
expected = [
|
||||
mock.call.createSnapshot(snap_name, vol_name, optional),
|
||||
mock.call.getVolume(snap_name),
|
||||
mock.call.copyVolume(
|
||||
snap_name,
|
||||
'osv-0DM4qZEVSKON-AAAAAAAAA',
|
||||
HPE3PAR_CPG2,
|
||||
{'snapCPG': 'OpenStackCPGSnap', 'tpvv': True,
|
||||
'tdvv': False, 'online': True})]
|
||||
|
||||
mock_client.assert_has_calls(
|
||||
self.standard_login +
|
||||
expected +
|
||||
self.standard_logout)
|
||||
|
||||
def test_create_clone_iscsi_volume_with_chap_disabled(self):
|
||||
# setup_mock_client drive with default configuration
|
||||
# and return the mock HTTP 3PAR client
|
||||
config = self.setup_configuration()
|
||||
config.hpe3par_iscsi_chap_enabled = True
|
||||
mock_client = self.setup_driver(config=config)
|
||||
mock_client.getVolume.return_value = {'name': mock.ANY}
|
||||
mock_client.copyVolume.return_value = {'taskid': 1}
|
||||
mock_client.getVolumeMetaData.side_effect = hpeexceptions.HTTPNotFound
|
||||
|
||||
with mock.patch.object(hpecommon.HPE3PARCommon,
|
||||
'_create_client') as mock_create_client:
|
||||
mock_create_client.return_value = mock_client
|
||||
|
||||
volume = {'name': HPE3PARBaseDriver.VOLUME_NAME,
|
||||
'id': HPE3PARBaseDriver.CLONE_ID,
|
||||
'display_name': 'Foo Volume',
|
||||
'size': 2,
|
||||
'host': volume_utils.append_host(self.FAKE_HOST,
|
||||
HPE3PAR_CPG2)}
|
||||
src_vref = {'id': HPE3PARBaseDriver.VOLUME_ID,
|
||||
'name': HPE3PARBaseDriver.VOLUME_NAME,
|
||||
'size': 2, 'status': 'available'}
|
||||
model_update = self.driver.create_cloned_volume(volume, src_vref)
|
||||
self.assertIsNone(model_update)
|
||||
|
||||
common = hpecommon.HPE3PARCommon(None)
|
||||
vol_name = common._get_3par_vol_name(src_vref['id'])
|
||||
# snapshot name is random
|
||||
snap_name = mock.ANY
|
||||
optional = mock.ANY
|
||||
|
||||
expected = [
|
||||
mock.call.getVolumeMetaData(vol_name,
|
||||
'HPQ-cinder-CHAP-name'),
|
||||
mock.call.createSnapshot(snap_name, vol_name, optional),
|
||||
mock.call.getVolume(snap_name),
|
||||
mock.call.copyVolume(
|
||||
snap_name,
|
||||
'osv-0DM4qZEVSKON-AAAAAAAAA',
|
||||
HPE3PAR_CPG2,
|
||||
{'snapCPG': 'OpenStackCPGSnap', 'tpvv': True,
|
||||
'tdvv': False, 'online': True})]
|
||||
|
||||
mock_client.assert_has_calls(
|
||||
self.standard_login +
|
||||
expected +
|
||||
self.standard_logout)
|
||||
|
||||
def test_backup_iscsi_volume_with_chap_enabled(self):
|
||||
# setup_mock_client drive with default configuration
|
||||
# and return the mock HTTP 3PAR client
|
||||
config = self.setup_configuration()
|
||||
config.hpe3par_iscsi_chap_enabled = True
|
||||
mock_client = self.setup_driver(config=config)
|
||||
mock_client.getVolume.return_value = {'name': mock.ANY}
|
||||
task_id = 1
|
||||
mock_client.copyVolume.return_value = {'taskid': task_id}
|
||||
mock_client.getVolumeMetaData.return_value = {
|
||||
'value': 'random-key'}
|
||||
mock_client.getTask.return_value = {'status': 1}
|
||||
with mock.patch.object(hpecommon.HPE3PARCommon,
|
||||
'_create_client') as mock_create_client:
|
||||
mock_create_client.return_value = mock_client
|
||||
|
||||
volume = {'name': HPE3PARBaseDriver.VOLUME_NAME,
|
||||
'id': HPE3PARBaseDriver.CLONE_ID,
|
||||
'display_name': 'Foo Volume',
|
||||
'size': 5,
|
||||
'host': volume_utils.append_host(self.FAKE_HOST,
|
||||
HPE3PAR_CPG2),
|
||||
'source_volid': HPE3PARBaseDriver.VOLUME_ID}
|
||||
src_vref = {'id': HPE3PARBaseDriver.VOLUME_ID,
|
||||
'name': HPE3PARBaseDriver.VOLUME_NAME,
|
||||
'size': 5, 'status': 'backing-up'}
|
||||
model_update = self.driver.create_cloned_volume(volume, src_vref)
|
||||
self.assertIsNone(model_update)
|
||||
|
||||
common = hpecommon.HPE3PARCommon(None)
|
||||
vol_name = common._get_3par_vol_name(volume['id'])
|
||||
src_vol_name = common._get_3par_vol_name(src_vref['id'])
|
||||
optional = {'priority': 1}
|
||||
comment = mock.ANY
|
||||
|
||||
expected = [
|
||||
mock.call.getVolumeMetaData(src_vol_name,
|
||||
'HPQ-cinder-CHAP-name'),
|
||||
mock.call.createVolume(vol_name, 'fakepool',
|
||||
5120, comment),
|
||||
mock.call.copyVolume(
|
||||
src_vol_name,
|
||||
vol_name,
|
||||
None,
|
||||
optional=optional),
|
||||
mock.call.getTask(task_id),
|
||||
]
|
||||
|
||||
mock_client.assert_has_calls(
|
||||
self.standard_login +
|
||||
expected +
|
||||
self.standard_logout)
|
||||
|
||||
def test_create_cloned_volume_offline_copy(self):
|
||||
# setup_mock_client drive with default configuration
|
||||
# and return the mock HTTP 3PAR client
|
||||
|
@ -1808,7 +2032,7 @@ class HPE3PARBaseDriver(object):
|
|||
'source_volid': HPE3PARBaseDriver.VOLUME_ID}
|
||||
src_vref = {'id': HPE3PARBaseDriver.VOLUME_ID,
|
||||
'name': HPE3PARBaseDriver.VOLUME_NAME,
|
||||
'size': 2}
|
||||
'size': 2, 'status': 'available'}
|
||||
model_update = self.driver.create_cloned_volume(volume, src_vref)
|
||||
self.assertIsNone(model_update)
|
||||
|
||||
|
@ -1846,7 +2070,7 @@ class HPE3PARBaseDriver(object):
|
|||
|
||||
src_vref = {'id': HPE3PARBaseDriver.CLONE_ID,
|
||||
'name': HPE3PARBaseDriver.VOLUME_NAME,
|
||||
'size': 2}
|
||||
'size': 2, 'status': 'available'}
|
||||
volume = self.volume_qos.copy()
|
||||
host = "TEST_HOST"
|
||||
pool = "TEST_POOL"
|
||||
|
|
|
@ -244,10 +244,13 @@ class HPE3PARCommon(object):
|
|||
3.0.24 - Fix terminate connection on failover
|
||||
3.0.25 - Fix delete volume when online clone is active. bug #1349639
|
||||
3.0.26 - Fix concurrent snapshot delete conflict. bug #1600104
|
||||
3.0.27 - Fix snapCPG error during backup of attached volume.
|
||||
Bug #1646396 and also ,Fix backup of attached ISCSI
|
||||
and CHAP enabled volume.bug #1644238.
|
||||
|
||||
"""
|
||||
|
||||
VERSION = "3.0.26"
|
||||
VERSION = "3.0.27"
|
||||
|
||||
stats = {}
|
||||
|
||||
|
@ -1626,11 +1629,18 @@ class HPE3PARCommon(object):
|
|||
def get_cpg(self, volume, allowSnap=False):
|
||||
volume_name = self._get_3par_vol_name(volume['id'])
|
||||
vol = self.client.getVolume(volume_name)
|
||||
# Search for 'userCPG' in the get volume REST API,
|
||||
# if found return userCPG , else search for snapCPG attribute
|
||||
# when allowSnap=True. For the cases where 3PAR REST call for
|
||||
# get volume doesn't have either userCPG or snapCPG ,
|
||||
# take the default value of cpg from 'host' attribute from volume param
|
||||
LOG.debug("get volume response is: %s", vol)
|
||||
if 'userCPG' in vol:
|
||||
return vol['userCPG']
|
||||
elif allowSnap:
|
||||
elif allowSnap and 'snapCPG' in vol:
|
||||
return vol['snapCPG']
|
||||
return None
|
||||
else:
|
||||
return volume_utils.extract_host(volume['host'], 'pool')
|
||||
|
||||
def _get_3par_vol_comment(self, volume_name):
|
||||
vol = self.client.getVolume(volume_name)
|
||||
|
@ -1983,13 +1993,31 @@ class HPE3PARCommon(object):
|
|||
try:
|
||||
vol_name = self._get_3par_vol_name(volume['id'])
|
||||
src_vol_name = self._get_3par_vol_name(src_vref['id'])
|
||||
back_up_process = False
|
||||
vol_chap_enabled = False
|
||||
|
||||
# if the sizes of the 2 volumes are the same
|
||||
# Check whether a volume is ISCSI and CHAP enabled on it.
|
||||
if self._client_conf['hpe3par_iscsi_chap_enabled']:
|
||||
try:
|
||||
vol_chap_enabled = self.client.getVolumeMetaData(
|
||||
src_vol_name, 'HPQ-cinder-CHAP-name')['value']
|
||||
except hpeexceptions.HTTPNotFound:
|
||||
LOG.debug("CHAP is not enabled on volume %(vol)s ",
|
||||
{'vol': src_vref['id']})
|
||||
vol_chap_enabled = False
|
||||
|
||||
# Check whether a process is a backup
|
||||
if str(src_vref['status']) == 'backing-up':
|
||||
back_up_process = True
|
||||
|
||||
# if the sizes of the 2 volumes are the same and except backup
|
||||
# process for ISCSI volume with chap enabled on it.
|
||||
# we can do an online copy, which is a background process
|
||||
# on the 3PAR that makes the volume instantly available.
|
||||
# We can't resize a volume, while it's being copied.
|
||||
if volume['size'] == src_vref['size']:
|
||||
LOG.debug("Creating a clone of same size, using online copy.")
|
||||
if volume['size'] == src_vref['size'] and not (
|
||||
back_up_process and vol_chap_enabled):
|
||||
LOG.debug("Creating a clone of volume, using online copy.")
|
||||
# create a temporary snapshot
|
||||
snapshot = self._create_temp_snapshot(src_vref)
|
||||
|
||||
|
@ -2016,8 +2044,7 @@ class HPE3PARCommon(object):
|
|||
# The size of the new volume is different, so we have to
|
||||
# copy the volume and wait. Do the resize after the copy
|
||||
# is complete.
|
||||
LOG.debug("Clone a volume with a different target size. "
|
||||
"Using non-online copy.")
|
||||
LOG.debug("Creating a clone of volume, using non-online copy.")
|
||||
|
||||
# we first have to create the destination volume
|
||||
model_update = self.create_volume(volume)
|
||||
|
|
Loading…
Reference in New Issue