Merge "backup of active 3par ISCSI bootable volume fails" into stable/newton

This commit is contained in:
Jenkins 2017-02-01 18:05:54 +00:00 committed by Gerrit Code Review
commit 79ad4598aa
2 changed files with 262 additions and 11 deletions

View File

@ -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"

View File

@ -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)