Merge "Clone cg support in VNX driver"
This commit is contained in:
commit
686db70dfd
@ -22,6 +22,7 @@ import six
|
||||
from cinder import context
|
||||
from cinder import exception
|
||||
from cinder import test
|
||||
from cinder.tests.unit import fake_consistencygroup
|
||||
from cinder.tests.unit import fake_snapshot
|
||||
from cinder.tests.unit import fake_volume
|
||||
from cinder.tests.unit import utils
|
||||
@ -3879,9 +3880,9 @@ Time Remaining: 0 second(s)
|
||||
def test_create_consistencygroup_from_cgsnapshot(self):
|
||||
output_migrate_verify = ('The specified source LUN '
|
||||
'is not currently migrating.', 23)
|
||||
new_cg = self.testData.test_cg.copy()
|
||||
new_cg.update(
|
||||
{'id': 'new_cg_id'})
|
||||
new_cg = fake_consistencygroup.fake_consistencyobject_obj(
|
||||
None, **self.testData.test_cg)
|
||||
new_cg.id = 'new_cg_id'
|
||||
vol1_in_new_cg = self.testData.test_volume_cg.copy()
|
||||
vol1_in_new_cg.update(
|
||||
{'name': 'vol1_in_cg',
|
||||
@ -3897,18 +3898,24 @@ Time Remaining: 0 second(s)
|
||||
src_cgsnap = self.testData.test_cgsnapshot
|
||||
snap1_in_src_cgsnap = self.testData.test_member_cgsnapshot.copy()
|
||||
snap1_in_src_cgsnap.update(
|
||||
{'volume': self.testData.test_volume,
|
||||
'volume_name': 'src_vol1'})
|
||||
{'volume': fake_volume.fake_volume_obj(
|
||||
None, **self.testData.test_volume),
|
||||
'expected_attrs': ['volume']})
|
||||
snap1_in_src_cgsnap = fake_snapshot.fake_snapshot_obj(
|
||||
None, **snap1_in_src_cgsnap)
|
||||
snap2_in_src_cgsnap = self.testData.test_member_cgsnapshot.copy()
|
||||
snap2_in_src_cgsnap.update(
|
||||
{'volume': self.testData.test_volume2,
|
||||
'volume_name': 'src_vol2'})
|
||||
{'volume': fake_volume.fake_volume_obj(
|
||||
None, **self.testData.test_volume2),
|
||||
'expected_attrs': ['volume']})
|
||||
snap2_in_src_cgsnap = fake_snapshot.fake_snapshot_obj(
|
||||
None, **snap2_in_src_cgsnap)
|
||||
copied_snap_name = 'temp_snapshot_for_%s' % new_cg['id']
|
||||
td = self.testData
|
||||
commands = [td.SNAP_COPY_CMD(src_cgsnap['id'], copied_snap_name),
|
||||
td.ALLOW_READWRITE_ON_SNAP_CMD(copied_snap_name),
|
||||
td.SNAP_MP_CREATE_CMD(vol1_in_new_cg['name'],
|
||||
snap1_in_src_cgsnap['volume_name']),
|
||||
snap1_in_src_cgsnap.volume_name),
|
||||
td.SNAP_ATTACH_CMD(vol1_in_new_cg['name'],
|
||||
copied_snap_name),
|
||||
td.LUN_CREATION_CMD(vol1_in_new_cg['name'] + '_dest',
|
||||
@ -3919,7 +3926,7 @@ Time Remaining: 0 second(s)
|
||||
td.MIGRATION_CMD(6231, 1),
|
||||
|
||||
td.SNAP_MP_CREATE_CMD(vol2_in_new_cg['name'],
|
||||
snap2_in_src_cgsnap['volume_name']),
|
||||
snap2_in_src_cgsnap.volume_name),
|
||||
td.SNAP_ATTACH_CMD(vol2_in_new_cg['name'],
|
||||
copied_snap_name),
|
||||
td.LUN_CREATION_CMD(vol2_in_new_cg['name'] + '_dest',
|
||||
@ -3963,7 +3970,7 @@ Time Remaining: 0 second(s)
|
||||
mock.call(*td.SNAP_COPY_CMD(src_cgsnap['id'], copied_snap_name)),
|
||||
mock.call(*td.ALLOW_READWRITE_ON_SNAP_CMD(copied_snap_name)),
|
||||
mock.call(*td.SNAP_MP_CREATE_CMD(vol1_in_new_cg['name'],
|
||||
snap1_in_src_cgsnap['volume_name']),
|
||||
snap1_in_src_cgsnap.volume_name),
|
||||
poll=False),
|
||||
mock.call(*td.LUN_PROPERTY_ALL_CMD(vol1_in_new_cg['name']),
|
||||
poll=True),
|
||||
@ -3979,7 +3986,7 @@ Time Remaining: 0 second(s)
|
||||
mock.call(*td.MIGRATION_CMD(6231, 1),
|
||||
poll=True, retry_disable=True),
|
||||
mock.call(*td.SNAP_MP_CREATE_CMD(vol2_in_new_cg['name'],
|
||||
snap2_in_src_cgsnap['volume_name']),
|
||||
snap2_in_src_cgsnap.volume_name),
|
||||
poll=False),
|
||||
mock.call(*td.LUN_PROPERTY_ALL_CMD(vol2_in_new_cg['name']),
|
||||
poll=True),
|
||||
@ -4001,33 +4008,56 @@ Time Remaining: 0 second(s)
|
||||
mock.call(*td.DELETE_CG_SNAPSHOT(copied_snap_name))]
|
||||
self.assertEqual(expect_cmd, fake_cli.call_args_list)
|
||||
|
||||
def test_create_consistencygroup_from_othersource(self):
|
||||
new_cg = self.testData.test_cg.copy()
|
||||
new_cg.update(
|
||||
{'id': 'new_cg_id'})
|
||||
vol1_in_new_cg = self.testData.test_volume_cg.copy()
|
||||
vol1_in_new_cg.update(
|
||||
{'name': 'vol1_in_cg',
|
||||
'id': '111111',
|
||||
'consistencygroup_id': 'new_cg_id',
|
||||
'provider_location': None})
|
||||
vol2_in_new_cg = self.testData.test_volume_cg.copy()
|
||||
vol2_in_new_cg.update(
|
||||
{'name': 'vol2_in_cg',
|
||||
'id': '222222',
|
||||
'consistencygroup_id': 'new_cg_id',
|
||||
'provider_location': None})
|
||||
def test_create_cg_from_src_failed_without_source(self):
|
||||
new_cg = fake_consistencygroup.fake_consistencyobject_obj(
|
||||
None, **self.testData.test_cg)
|
||||
vol1_in_new_cg = self.testData.test_volume_cg
|
||||
self.driverSetup()
|
||||
self.assertRaises(
|
||||
exception.InvalidInput,
|
||||
self.driver.create_consistencygroup_from_src,
|
||||
new_cg, [vol1_in_new_cg, vol2_in_new_cg],
|
||||
new_cg, [vol1_in_new_cg],
|
||||
None, None, None, None)
|
||||
|
||||
def test_create_cg_from_src_failed_with_multiple_sources(self):
|
||||
new_cg = fake_consistencygroup.fake_consistencyobject_obj(
|
||||
None, **self.testData.test_cg)
|
||||
vol1_in_new_cg = self.testData.test_volume_cg
|
||||
src_cgsnap = self.testData.test_cgsnapshot
|
||||
snap1_in_src_cgsnap = fake_snapshot.fake_snapshot_obj(
|
||||
None, **self.testData.test_member_cgsnapshot)
|
||||
src_cg = fake_consistencygroup.fake_consistencyobject_obj(
|
||||
None, **self.testData.test_cg)
|
||||
src_cg.id = 'fake_source_cg'
|
||||
vol1_in_src_cg = {'id': 'fake_volume',
|
||||
'consistencygroup_id': src_cg.id}
|
||||
self.driverSetup()
|
||||
self.assertRaises(
|
||||
exception.InvalidInput,
|
||||
self.driver.create_consistencygroup_from_src,
|
||||
new_cg, [vol1_in_new_cg],
|
||||
src_cgsnap, [snap1_in_src_cgsnap], src_cg, [vol1_in_src_cg])
|
||||
|
||||
def test_create_cg_from_src_failed_with_invalid_source(self):
|
||||
new_cg = fake_consistencygroup.fake_consistencyobject_obj(
|
||||
None, **self.testData.test_cg)
|
||||
src_cgsnap = self.testData.test_cgsnapshot
|
||||
vol1_in_new_cg = self.testData.test_volume_cg
|
||||
|
||||
src_cg = fake_consistencygroup.fake_consistencyobject_obj(
|
||||
None, **self.testData.test_cg)
|
||||
src_cg.id = 'fake_source_cg'
|
||||
self.driverSetup()
|
||||
self.assertRaises(
|
||||
exception.InvalidInput,
|
||||
self.driver.create_consistencygroup_from_src,
|
||||
new_cg, [vol1_in_new_cg],
|
||||
src_cgsnap, None, src_cg, None)
|
||||
|
||||
def test_create_cg_from_cgsnapshot_migrate_failed(self):
|
||||
new_cg = self.testData.test_cg.copy()
|
||||
new_cg.update(
|
||||
{'id': 'new_cg_id'})
|
||||
new_cg = fake_consistencygroup.fake_consistencyobject_obj(
|
||||
None, **self.testData.test_cg)
|
||||
new_cg.id = 'new_cg_id'
|
||||
vol1_in_new_cg = self.testData.test_volume_cg.copy()
|
||||
vol1_in_new_cg.update(
|
||||
{'name': 'vol1_in_cg',
|
||||
@ -4043,12 +4073,18 @@ Time Remaining: 0 second(s)
|
||||
src_cgsnap = self.testData.test_cgsnapshot
|
||||
snap1_in_src_cgsnap = self.testData.test_member_cgsnapshot.copy()
|
||||
snap1_in_src_cgsnap.update(
|
||||
{'volume': self.testData.test_volume,
|
||||
'volume_name': 'src_vol1'})
|
||||
{'volume': fake_volume.fake_volume_obj(
|
||||
None, **self.testData.test_volume),
|
||||
'expected_attrs': ['volume']})
|
||||
snap1_in_src_cgsnap = fake_snapshot.fake_snapshot_obj(
|
||||
None, **snap1_in_src_cgsnap)
|
||||
snap2_in_src_cgsnap = self.testData.test_member_cgsnapshot.copy()
|
||||
snap2_in_src_cgsnap.update(
|
||||
{'volume': self.testData.test_volume2,
|
||||
'volume_name': 'src_vol2'})
|
||||
{'volume': fake_volume.fake_volume_obj(
|
||||
None, **self.testData.test_volume2),
|
||||
'expected_attrs': ['volume']})
|
||||
snap2_in_src_cgsnap = fake_snapshot.fake_snapshot_obj(
|
||||
None, **snap2_in_src_cgsnap)
|
||||
copied_snap_name = 'temp_snapshot_for_%s' % new_cg['id']
|
||||
td = self.testData
|
||||
commands = [td.LUN_PROPERTY_ALL_CMD(vol1_in_new_cg['name'] + '_dest'),
|
||||
@ -4086,6 +4122,154 @@ Time Remaining: 0 second(s)
|
||||
mock.call(*td.SNAP_DELETE_CMD(copied_snap_name), poll=True)]
|
||||
fake_cli.assert_has_calls(expect_cmd)
|
||||
|
||||
def test_create_consistencygroup_from_cg(self):
|
||||
output_migrate_verify = ('The specified source LUN '
|
||||
'is not currently migrating.', 23)
|
||||
new_cg = fake_consistencygroup.fake_consistencyobject_obj(
|
||||
None, **self.testData.test_cg)
|
||||
new_cg.id = 'new_cg_id'
|
||||
vol1_in_new_cg = self.testData.test_volume_cg.copy()
|
||||
vol1_in_new_cg.update(
|
||||
{'name': 'vol1_in_cg',
|
||||
'id': '111111',
|
||||
'consistencygroup_id': 'new_cg_id',
|
||||
'provider_location': None})
|
||||
vol2_in_new_cg = self.testData.test_volume_cg.copy()
|
||||
vol2_in_new_cg.update(
|
||||
{'name': 'vol2_in_cg',
|
||||
'id': '222222',
|
||||
'consistencygroup_id': 'new_cg_id',
|
||||
'provider_location': None})
|
||||
src_cg = fake_consistencygroup.fake_consistencyobject_obj(
|
||||
None, **self.testData.test_cg)
|
||||
src_cg.id = 'src_cg_id'
|
||||
vol1_in_src_cg = self.testData.test_volume_cg.copy()
|
||||
vol1_in_src_cg.update(
|
||||
{'name': 'vol1_in_src_cg',
|
||||
'id': '111110000',
|
||||
'consistencygroup_id': 'src_cg_id',
|
||||
'provider_location': None})
|
||||
vol2_in_src_cg = self.testData.test_volume_cg.copy()
|
||||
vol2_in_src_cg.update(
|
||||
{'name': 'vol2_in_src_cg',
|
||||
'id': '222220000',
|
||||
'consistencygroup_id': 'src_cg_id',
|
||||
'provider_location': None})
|
||||
temp_snap_name = 'temp_snapshot_for_%s' % new_cg['id']
|
||||
td = self.testData
|
||||
commands = [td.CREATE_CG_SNAPSHOT(src_cg['id'], temp_snap_name),
|
||||
td.SNAP_MP_CREATE_CMD(vol1_in_new_cg['name'],
|
||||
vol1_in_src_cg['name']),
|
||||
td.SNAP_ATTACH_CMD(vol1_in_new_cg['name'],
|
||||
temp_snap_name),
|
||||
td.LUN_CREATION_CMD(vol1_in_new_cg['name'] + '_dest',
|
||||
vol1_in_new_cg['size'],
|
||||
'unit_test_pool', 'thin', None),
|
||||
td.LUN_PROPERTY_ALL_CMD(vol1_in_new_cg['name'] + '_dest'),
|
||||
td.LUN_PROPERTY_ALL_CMD(vol1_in_new_cg['name']),
|
||||
td.MIGRATION_CMD(6231, 1),
|
||||
|
||||
td.SNAP_MP_CREATE_CMD(vol2_in_new_cg['name'],
|
||||
vol2_in_src_cg['name']),
|
||||
td.SNAP_ATTACH_CMD(vol2_in_new_cg['name'],
|
||||
temp_snap_name),
|
||||
td.LUN_CREATION_CMD(vol2_in_new_cg['name'] + '_dest',
|
||||
vol2_in_new_cg['size'],
|
||||
'unit_test_pool', 'thin', None),
|
||||
td.LUN_PROPERTY_ALL_CMD(vol2_in_new_cg['name'] + '_dest'),
|
||||
td.LUN_PROPERTY_ALL_CMD(vol2_in_new_cg['name']),
|
||||
td.MIGRATION_CMD(6232, 2),
|
||||
|
||||
td.MIGRATION_VERIFY_CMD(6231),
|
||||
td.MIGRATION_VERIFY_CMD(6232),
|
||||
td.CREATE_CONSISTENCYGROUP_CMD(new_cg['id'], [6231, 6232]),
|
||||
td.DELETE_CG_SNAPSHOT(temp_snap_name)
|
||||
]
|
||||
results = [SUCCEED, SUCCEED, SUCCEED, SUCCEED,
|
||||
td.LUN_PROPERTY(vol1_in_new_cg['name'] + '_dest',
|
||||
lunid=1),
|
||||
td.LUN_PROPERTY(vol1_in_new_cg['name'], lunid=6231),
|
||||
SUCCEED, SUCCEED, SUCCEED, SUCCEED,
|
||||
td.LUN_PROPERTY(vol2_in_new_cg['name'] + '_dest',
|
||||
lunid=2),
|
||||
td.LUN_PROPERTY(vol2_in_new_cg['name'], lunid=6232),
|
||||
SUCCEED, output_migrate_verify, output_migrate_verify,
|
||||
SUCCEED, SUCCEED]
|
||||
|
||||
fake_cli = self.driverSetup(commands, results)
|
||||
|
||||
cg_model_update, volumes_model_update = (
|
||||
self.driver.create_consistencygroup_from_src(
|
||||
None, new_cg, [vol1_in_new_cg, vol2_in_new_cg],
|
||||
cgsnapshot=None, snapshots=None,
|
||||
source_cg=src_cg, source_vols=[vol1_in_src_cg,
|
||||
vol2_in_src_cg]))
|
||||
self.assertEqual(2, len(volumes_model_update))
|
||||
self.assertTrue('id^%s' % 6231 in
|
||||
volumes_model_update[0]['provider_location'])
|
||||
self.assertTrue('id^%s' % 6232 in
|
||||
volumes_model_update[1]['provider_location'])
|
||||
|
||||
delete_temp_snap_cmd = [
|
||||
mock.call(*td.DELETE_CG_SNAPSHOT(temp_snap_name))]
|
||||
fake_cli.assert_has_calls(delete_temp_snap_cmd)
|
||||
|
||||
@mock.patch.object(emc_vnx_cli, 'LOG')
|
||||
@mock.patch.object(emc_vnx_cli.CommandLineHelper,
|
||||
'delete_cgsnapshot')
|
||||
def test_delete_temp_cgsnapshot_failed_will_not_raise_exception(
|
||||
self, mock_delete_cgsnapshot, mock_logger):
|
||||
temp_snap_name = 'fake_temp'
|
||||
self.driverSetup()
|
||||
mock_delete_cgsnapshot.side_effect = exception.EMCVnxCLICmdError(
|
||||
cmd='fake_cmd', rc=200, out='fake_output')
|
||||
self.driver.cli._delete_temp_cgsnap(temp_snap_name)
|
||||
mock_delete_cgsnapshot.assert_called_once_with(temp_snap_name)
|
||||
self.assertTrue(mock_logger.warning.called)
|
||||
|
||||
@mock.patch.object(emc_vnx_cli.CreateSMPTask, 'execute',
|
||||
mock.Mock(side_effect=exception.EMCVnxCLICmdError(
|
||||
cmd='fake_cmd', rc=20, out='fake_output')))
|
||||
@mock.patch.object(emc_vnx_cli.CreateSMPTask, 'revert',
|
||||
mock.Mock())
|
||||
def test_create_consistencygroup_from_cg_roll_back(self):
|
||||
new_cg = fake_consistencygroup.fake_consistencyobject_obj(
|
||||
None, **self.testData.test_cg)
|
||||
new_cg.id = 'new_cg_id'
|
||||
vol1_in_new_cg = self.testData.test_volume_cg.copy()
|
||||
vol1_in_new_cg.update(
|
||||
{'name': 'vol1_in_cg',
|
||||
'id': '111111',
|
||||
'consistencygroup_id': 'new_cg_id',
|
||||
'provider_location': None})
|
||||
src_cg = fake_consistencygroup.fake_consistencyobject_obj(
|
||||
None, **self.testData.test_cg)
|
||||
src_cg.id = 'src_cg_id'
|
||||
vol1_in_src_cg = self.testData.test_volume_cg.copy()
|
||||
vol1_in_src_cg.update(
|
||||
{'name': 'vol1_in_src_cg',
|
||||
'id': '111110000',
|
||||
'consistencygroup_id': 'src_cg_id',
|
||||
'provider_location': None})
|
||||
temp_snap_name = 'temp_snapshot_for_%s' % new_cg['id']
|
||||
td = self.testData
|
||||
commands = [td.CREATE_CG_SNAPSHOT(src_cg['id'], temp_snap_name),
|
||||
td.DELETE_CG_SNAPSHOT(temp_snap_name)]
|
||||
results = [SUCCEED, SUCCEED]
|
||||
|
||||
fake_cli = self.driverSetup(commands, results)
|
||||
|
||||
self.assertRaises(
|
||||
exception.EMCVnxCLICmdError,
|
||||
self.driver.create_consistencygroup_from_src,
|
||||
None, new_cg, [vol1_in_new_cg],
|
||||
cgsnapshot=None, snapshots=None,
|
||||
source_cg=src_cg, source_vols=[vol1_in_src_cg])
|
||||
|
||||
rollback_cmd = [
|
||||
mock.call(*td.DELETE_CG_SNAPSHOT(temp_snap_name))]
|
||||
fake_cli.assert_has_calls(rollback_cmd)
|
||||
|
||||
def test_deregister_initiator(self):
|
||||
fake_cli = self.driverSetup()
|
||||
self.driver.cli.destroy_empty_sg = True
|
||||
|
@ -58,6 +58,7 @@ class EMCCLIFCDriver(driver.FibreChannelDriver):
|
||||
White list target ports support
|
||||
Snap copy support
|
||||
Support efficient non-disruptive backup
|
||||
7.0.0 - Clone consistency group support
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
@ -267,7 +268,9 @@ class EMCCLIFCDriver(driver.FibreChannelDriver):
|
||||
group,
|
||||
volumes,
|
||||
cgsnapshot,
|
||||
snapshots)
|
||||
snapshots,
|
||||
source_cg,
|
||||
source_vols)
|
||||
|
||||
def update_migrated_volume(self, context, volume, new_volume,
|
||||
original_volume_status=None):
|
||||
|
@ -56,6 +56,7 @@ class EMCCLIISCSIDriver(driver.ISCSIDriver):
|
||||
White list target ports support
|
||||
Snap copy support
|
||||
Support efficient non-disruptive backup
|
||||
7.0.0 - Clone consistency group support
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
@ -246,7 +247,9 @@ class EMCCLIISCSIDriver(driver.ISCSIDriver):
|
||||
group,
|
||||
volumes,
|
||||
cgsnapshot,
|
||||
snapshots)
|
||||
snapshots,
|
||||
source_cg,
|
||||
source_vols)
|
||||
|
||||
def update_migrated_volume(self, context, volume, new_volume,
|
||||
original_volume_status=None):
|
||||
|
@ -759,10 +759,8 @@ class CommandLineHelper(object):
|
||||
LOG.info(_LI('Consistency group %s was deleted '
|
||||
'successfully.'), cg_name)
|
||||
|
||||
def create_cgsnapshot(self, cgsnapshot):
|
||||
def create_cgsnapshot(self, cg_name, snap_name):
|
||||
"""Create a cgsnapshot (snap group)."""
|
||||
cg_name = cgsnapshot['consistencygroup_id']
|
||||
snap_name = cgsnapshot['id']
|
||||
create_cg_snap_cmd = ('-np', 'snap', '-create',
|
||||
'-res', cg_name,
|
||||
'-resType', 'CG',
|
||||
@ -1750,7 +1748,7 @@ class CommandLineHelper(object):
|
||||
class EMCVnxCliBase(object):
|
||||
"""This class defines the functions to use the native CLI functionality."""
|
||||
|
||||
VERSION = '06.00.00'
|
||||
VERSION = '07.00.00'
|
||||
stats = {'driver_version': VERSION,
|
||||
'storage_protocol': None,
|
||||
'vendor_name': 'EMC',
|
||||
@ -2749,7 +2747,8 @@ class EMCVnxCliBase(object):
|
||||
{'group_name': cgsnapshot['consistencygroup_id']})
|
||||
|
||||
try:
|
||||
self._client.create_cgsnapshot(cgsnapshot)
|
||||
self._client.create_cgsnapshot(cgsnapshot['consistencygroup_id'],
|
||||
cgsnapshot['id'])
|
||||
for snapshot in snapshots:
|
||||
snapshot['status'] = 'available'
|
||||
except Exception:
|
||||
@ -3437,17 +3436,49 @@ class EMCVnxCliBase(object):
|
||||
pass
|
||||
|
||||
def create_consistencygroup_from_src(self, context, group, volumes,
|
||||
cgsnapshot=None, snapshots=None):
|
||||
cgsnapshot=None, snapshots=None,
|
||||
source_cg=None, source_vols=None):
|
||||
"""Creates a consistency group from cgsnapshot."""
|
||||
if cgsnapshot and snapshots and not source_cg:
|
||||
return self._create_consisgroup_from_cgsnapshot(
|
||||
group, volumes, cgsnapshot, snapshots)
|
||||
elif source_cg and source_vols and not cgsnapshot:
|
||||
return self._clone_consisgroup(
|
||||
group, volumes, source_cg, source_vols)
|
||||
else:
|
||||
msg = _("create_consistencygroup_from_src supports a "
|
||||
"cgsnapshot source or a consistency group source. "
|
||||
"Multiple sources cannot be used.")
|
||||
raise exception.InvalidInput(reason=msg)
|
||||
|
||||
if not cgsnapshot or not snapshots:
|
||||
msg = _("create_consistencygroup_from_src only supports a "
|
||||
"cgsnapshot source, other sources cannot be used.")
|
||||
raise exception.InvalidInput(msg)
|
||||
def _clone_consisgroup(self, group, volumes, source_cg, source_vols):
|
||||
temp_cgsnapshot_name = 'temp_snapshot_for_{}'.format(group.id)
|
||||
store_spec = {
|
||||
'group': group,
|
||||
'snapshot': {'id': temp_cgsnapshot_name,
|
||||
'consistencygroup_id': source_cg.id},
|
||||
'snap_name': temp_cgsnapshot_name,
|
||||
'source_lun_id': None,
|
||||
'client': self._client
|
||||
}
|
||||
flow_name = 'clone_consisgroup'
|
||||
snap_build_tasks = [CreateSnapshotTask()]
|
||||
|
||||
flow_name = 'create_consistencygroup_from_cgsnapshot'
|
||||
work_flow = linear_flow.Flow(flow_name)
|
||||
copied_snapshot_name = 'temp_snapshot_for_%s' % group['id']
|
||||
volume_model_updates = self._create_cg_from_cgsnap_use_workflow(
|
||||
flow_name, snap_build_tasks, store_spec,
|
||||
volumes, source_vols)
|
||||
|
||||
self._delete_temp_cgsnap(temp_cgsnapshot_name)
|
||||
|
||||
LOG.info(_LI('Consistency group %(cg)s is created successfully.'),
|
||||
{'cg': group.id})
|
||||
|
||||
return None, volume_model_updates
|
||||
|
||||
def _create_consisgroup_from_cgsnapshot(self, group, volumes,
|
||||
cgsnapshot, snapshots):
|
||||
flow_name = 'create_consisgroup_from_cgsnapshot'
|
||||
copied_snapshot_name = 'temp_snapshot_for_%s' % group.id
|
||||
store_spec = {
|
||||
'group': group,
|
||||
'src_snap_name': cgsnapshot['id'],
|
||||
@ -3455,29 +3486,55 @@ class EMCVnxCliBase(object):
|
||||
'client': self._client
|
||||
}
|
||||
|
||||
work_flow.add(CopySnapshotTask(),
|
||||
AllowReadWriteOnSnapshotTask())
|
||||
snap_build_tasks = [CopySnapshotTask(),
|
||||
AllowReadWriteOnSnapshotTask()]
|
||||
|
||||
src_vols = map(lambda snap: snap.volume, snapshots)
|
||||
|
||||
volume_model_updates = self._create_cg_from_cgsnap_use_workflow(
|
||||
flow_name, snap_build_tasks, store_spec, volumes, src_vols)
|
||||
|
||||
self._delete_temp_cgsnap(copied_snapshot_name)
|
||||
|
||||
LOG.info(_LI('Consistency group %(cg)s is created successfully.'),
|
||||
{'cg': group.id})
|
||||
|
||||
return None, volume_model_updates
|
||||
|
||||
def _delete_temp_cgsnap(self, snap):
|
||||
try:
|
||||
self._client.delete_cgsnapshot(snap)
|
||||
except exception.EMCVnxCLICmdError as ex:
|
||||
LOG.warning(_LW('Delete the temporary cgsnapshot %(name)s failed. '
|
||||
'This temporary cgsnapshot can be deleted '
|
||||
'manually. '
|
||||
'Message: %(msg)s'),
|
||||
{'name': snap,
|
||||
'msg': ex.kwargs['out']})
|
||||
|
||||
def _create_cg_from_cgsnap_use_workflow(self, flow_name, snap_build_tasks,
|
||||
store_spec, volumes, source_vols):
|
||||
work_flow = linear_flow.Flow(flow_name)
|
||||
work_flow.add(*snap_build_tasks)
|
||||
# Add tasks for each volumes in the consistency group
|
||||
lun_id_key_template = 'new_lun_id_%s'
|
||||
lun_data_key_template = 'vol_%s'
|
||||
volume_model_updates = []
|
||||
|
||||
for i, (volume, snap) in enumerate(zip(volumes, snapshots)):
|
||||
for i, (volume, src_volume) in enumerate(zip(volumes, source_vols)):
|
||||
specs = self.get_volumetype_extraspecs(volume)
|
||||
provisioning, tiering, snapcopy = (
|
||||
provisioning, tiering, snap_copy = (
|
||||
self._get_and_validate_extra_specs(specs))
|
||||
pool_name = self. get_target_storagepool(volume, snap['volume'])
|
||||
pool_name = self.get_target_storagepool(volume, src_volume)
|
||||
sub_store_spec = {
|
||||
'volume': volume,
|
||||
'source_vol_name': snap['volume_name'],
|
||||
'source_vol_name': src_volume['name'],
|
||||
'pool_name': pool_name,
|
||||
'dest_vol_name': volume['name'] + '_dest',
|
||||
'volume_size': volume['size'],
|
||||
'provisioning': provisioning,
|
||||
'tiering': tiering,
|
||||
'ignore_pool_full_threshold': self.ignore_pool_full_threshold,
|
||||
'snapcopy': snapcopy
|
||||
}
|
||||
work_flow.add(
|
||||
CreateSMPTask(name="CreateSMPTask%s" % i,
|
||||
@ -3508,26 +3565,11 @@ class EMCVnxCliBase(object):
|
||||
flow_engine = taskflow.engines.load(work_flow, store=store_spec)
|
||||
flow_engine.run()
|
||||
|
||||
# Delete copied snapshot
|
||||
try:
|
||||
self._client.delete_cgsnapshot(copied_snapshot_name)
|
||||
except exception.EMCVnxCLICmdError as ex:
|
||||
LOG.warning(_LW('Delete the temporary cgsnapshot %(name)s failed. '
|
||||
'This temporary cgsnapshot can be deleted '
|
||||
'manually. Consistency group %(cg)s is created '
|
||||
'successfully from cgsnapshot %(cgsnapshot)s. '
|
||||
'Message: %(msg)s'),
|
||||
{'name': copied_snapshot_name,
|
||||
'cg': group['id'],
|
||||
'cgsnapshot': cgsnapshot['id'],
|
||||
'msg': ex.kwargs['out']})
|
||||
|
||||
for i, update in enumerate(volume_model_updates):
|
||||
new_lun_id = flow_engine.storage.fetch(lun_id_key_template % i)
|
||||
update['provider_location'] = (
|
||||
self._build_provider_location(new_lun_id))
|
||||
|
||||
return None, volume_model_updates
|
||||
return volume_model_updates
|
||||
|
||||
def get_target_storagepool(self, volume, source_volume=None):
|
||||
pool = vol_utils.extract_host(volume['host'], 'pool')
|
||||
@ -3633,7 +3675,7 @@ class AttachSnapTask(task.Task):
|
||||
|
||||
Reversion strategy: Detach the SMP.
|
||||
"""
|
||||
def execute(self, client, volume, snapcopy, snap_name,
|
||||
def execute(self, client, volume, snap_name,
|
||||
*args, **kwargs):
|
||||
LOG.debug('AttachSnapTask.execute')
|
||||
client.attach_mount_point(volume['name'], snap_name)
|
||||
@ -3733,7 +3775,8 @@ class CreateSnapshotTask(task.Task):
|
||||
LOG.debug('CreateSnapshotTask.execute')
|
||||
# Create temp Snapshot
|
||||
if snapshot['consistencygroup_id']:
|
||||
client.create_cgsnapshot(snapshot)
|
||||
client.create_cgsnapshot(snapshot['consistencygroup_id'],
|
||||
snapshot['id'])
|
||||
else:
|
||||
snapshot_name = snapshot['name']
|
||||
volume_name = snapshot['volume_name']
|
||||
|
Loading…
x
Reference in New Issue
Block a user