import mock
from oslo_concurrency import processutils
+import six
from cinder import exception
from cinder import test
return ('storagegroup', '-removehlu',
'-hlu', hlu, '-gname', gname, '-o')
+ def SNAP_COPY_CMD(self, src_snap, snap_name):
+ return ('snap', '-copy', '-id', src_snap, '-name', snap_name,
+ '-ignoreMigrationCheck', '-ignoreDeduplicationCheck')
+
+ def ALLOW_READWRITE_ON_SNAP_CMD(self, snap_name):
+ return ('snap', '-modify', '-id', snap_name,
+ '-allowReadWrite', 'yes', '-allowAutoDelete', 'yes')
+
provisioning_values = {
'thin': ['-type', 'Thin'],
'thick': ['-type', 'NonThin'],
return ('storagepool', '-list', '-name',
storage_pool, '-fastcache')
- def CREATE_CONSISTENCYGROUP_CMD(self, cg_name):
- return ('-np', 'snap', '-group', '-create',
- '-name', cg_name, '-allowSnapAutoDelete', 'no')
+ def CREATE_CONSISTENCYGROUP_CMD(self, cg_name, members=None):
+ create_cmd = ('-np', 'snap', '-group', '-create',
+ '-name', cg_name, '-allowSnapAutoDelete', 'no')
+
+ if not members:
+ return create_cmd
+ else:
+ return create_cmd + ('-res', ','.join(map(six.text_type,
+ members)))
def DELETE_CONSISTENCYGROUP_CMD(self, cg_name):
return ('-np', 'snap', '-group', '-destroy',
"Switch Present: NO\n", 0)
def LUN_PROPERTY(self, name, is_thin=False, has_snap=False, size=1,
- state='Ready', faulted='false', operation='None'):
+ state='Ready', faulted='false', operation='None',
+ lunid=1):
return ("""
- LOGICAL UNIT NUMBER 1
+ LOGICAL UNIT NUMBER %(lunid)s
Name: %(name)s
UID: 60:06:01:60:09:20:32:00:13:DF:B4:EF:C2:63:E3:11
Current Owner: SP A
Current Operation Status: N/A
Current Operation Percent Completed: 0
Is Thin LUN: %(is_thin)s""" % {
+ 'lunid': lunid,
'name': name,
'has_snap': 'FakeSnap' if has_snap else 'N/A',
'size': size,
cg_name, ['1', '3']), poll=False)]
fake_cli.assert_has_calls(expect_cmd)
+ 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'})
+ 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_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'})
+ snap2_in_src_cgsnap = self.testData.test_member_cgsnapshot.copy()
+ snap2_in_src_cgsnap.update(
+ {'volume': self.testData.test_volume2,
+ 'volume_name': 'src_vol2'})
+ 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']),
+ td.SNAP_ATTACH_CMD(vol1_in_new_cg['name'],
+ copied_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'],
+ 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',
+ 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(copied_snap_name)
+ ]
+ results = [SUCCEED, 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=src_cgsnap, snapshots=[snap1_in_src_cgsnap,
+ snap2_in_src_cgsnap]))
+ 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'])
+
+ expect_cmd = [
+ 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']),
+ poll=False),
+ mock.call(*td.SNAP_ATTACH_CMD(vol1_in_new_cg['name'],
+ copied_snap_name)),
+ mock.call(*td.LUN_CREATION_CMD(vol1_in_new_cg['name'] + '_dest',
+ vol1_in_new_cg['size'],
+ 'unit_test_pool', 'thick', None)),
+ mock.call(*td.LUN_PROPERTY_ALL_CMD(
+ vol1_in_new_cg['name'] + '_dest'), poll=False),
+ mock.call(*td.LUN_PROPERTY_ALL_CMD(
+ vol1_in_new_cg['name'] + '_dest'), poll=False),
+ mock.call(*td.LUN_PROPERTY_ALL_CMD(vol1_in_new_cg['name']),
+ poll=True),
+ 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']),
+ poll=False),
+ mock.call(*td.SNAP_ATTACH_CMD(vol2_in_new_cg['name'],
+ copied_snap_name)),
+ mock.call(*td.LUN_CREATION_CMD(vol2_in_new_cg['name'] + '_dest',
+ vol2_in_new_cg['size'],
+ 'unit_test_pool', 'thick', None)),
+ mock.call(*td.LUN_PROPERTY_ALL_CMD(
+ vol2_in_new_cg['name'] + '_dest'), poll=False),
+ mock.call(*td.LUN_PROPERTY_ALL_CMD(
+ vol2_in_new_cg['name'] + '_dest'), poll=False),
+ mock.call(*td.LUN_PROPERTY_ALL_CMD(vol2_in_new_cg['name']),
+ poll=True),
+ mock.call(*td.MIGRATION_CMD(6232, 2),
+ poll=True, retry_disable=True),
+ mock.call(*td.MIGRATION_VERIFY_CMD(6232), poll=True),
+ mock.call(*td.MIGRATION_VERIFY_CMD(6231), poll=True),
+ mock.call(*td.CREATE_CONSISTENCYGROUP_CMD(
+ new_cg['id'], [6232, 6231])),
+ 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})
+ self.driverSetup()
+ self.assertRaises(
+ exception.InvalidInput,
+ self.driver.create_consistencygroup_from_src,
+ new_cg, [vol1_in_new_cg, vol2_in_new_cg],
+ None, None)
+
+ def test_create_cg_from_cgsnapshot_migrate_failed(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})
+ 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'})
+ snap2_in_src_cgsnap = self.testData.test_member_cgsnapshot.copy()
+ snap2_in_src_cgsnap.update(
+ {'volume': self.testData.test_volume2,
+ 'volume_name': 'src_vol2'})
+ 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'),
+ td.LUN_PROPERTY_ALL_CMD(vol1_in_new_cg['name']),
+ 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)]
+ results = [td.LUN_PROPERTY(vol1_in_new_cg['name'] + '_dest',
+ lunid=1),
+ td.LUN_PROPERTY(vol1_in_new_cg['name'], lunid=6231),
+ td.LUN_PROPERTY(vol2_in_new_cg['name'] + '_dest',
+ lunid=2),
+ td.LUN_PROPERTY(vol2_in_new_cg['name'], lunid=6232),
+ FAKE_ERROR_RETURN]
+
+ fake_cli = self.driverSetup(commands, results)
+ self.assertRaisesRegexp(exception.VolumeBackendAPIException,
+ 'Migrate volume failed',
+ self.driver.create_consistencygroup_from_src,
+ None, new_cg, [vol1_in_new_cg, vol2_in_new_cg],
+ cgsnapshot=src_cgsnap,
+ snapshots=[snap1_in_src_cgsnap,
+ snap2_in_src_cgsnap])
+
+ expect_cmd = [
+ mock.call(*self.testData.LUN_DELETE_CMD(
+ vol2_in_new_cg['name'] + '_dest')),
+ mock.call('lun', '-detach', '-name', vol2_in_new_cg['name'], '-o'),
+ mock.call(*self.testData.LUN_DELETE_CMD(vol2_in_new_cg['name'])),
+ mock.call(*self.testData.LUN_DELETE_CMD(
+ vol1_in_new_cg['name'] + '_dest')),
+ mock.call('lun', '-detach', '-name', vol1_in_new_cg['name'], '-o'),
+ mock.call(*self.testData.LUN_DELETE_CMD(vol1_in_new_cg['name'])),
+ mock.call(*td.DELETE_CG_SNAPSHOT(copied_snap_name))]
+ fake_cli.assert_has_calls(expect_cmd)
+
def test_deregister_initiator(self):
fake_cli = self.driverSetup()
self.driver.cli.destroy_empty_sg = True
5.2.0 - Pool-aware scheduler support
5.3.0 - Consistency group modification support
6.0.0 - Over subscription support
+ Create consistency group from cgsnapshot support
"""
def __init__(self, *args, **kwargs):
def unmanage(self, volume):
"""Unmanages a volume."""
return self.cli.unmanage(volume)
+
+ def create_consistencygroup_from_src(self, context, group, volumes,
+ cgsnapshot=None, snapshots=None):
+ """Creates a consistency group from source."""
+ return self.cli.create_consistencygroup_from_src(context,
+ group,
+ volumes,
+ cgsnapshot,
+ snapshots)
5.2.0 - Pool-aware scheduler support
5.3.0 - Consistency group modification support
6.0.0 - Over subscription support
+ Create consistency group from cgsnapshot support
"""
def __init__(self, *args, **kwargs):
def unmanage(self, volume):
"""Unmanages a volume."""
self.cli.unmanage(volume)
+
+ def create_consistencygroup_from_src(self, context, group, volumes,
+ cgsnapshot=None, snapshots=None):
+ """Creates a consistency group from source."""
+ return self.cli.create_consistencygroup_from_src(context,
+ group,
+ volumes,
+ cgsnapshot,
+ snapshots)
CLI_RESP_PATTERN_LUN_NOT_MIGRATING = ('The specified source LUN '
'is not currently migrating')
CLI_RESP_PATTERN_LUN_IS_PREPARING = '0x712d8e0e'
+ CLI_RESP_PATTERM_IS_NOT_SMP = 'it is not a snapshot mount point'
def __init__(self, configuration):
configuration.append_config_values(san.san_opts)
if rc != 0:
self._raise_cli_error(command_modify_lun, rc, out)
- def create_consistencygroup(self, context, group):
+ def create_consistencygroup(self, cg_name, members=None):
"""create the consistency group."""
- cg_name = group['id']
command_create_cg = ('-np', 'snap', '-group',
'-create',
'-name', cg_name,
'-allowSnapAutoDelete', 'no')
+ if members:
+ command_create_cg += ('-res', ','.join(map(six.text_type,
+ members)))
out, rc = self.command_execute(*command_create_cg)
if rc != 0:
else:
self._raise_cli_error(create_cg_snap_cmd, rc, out)
- def delete_cgsnapshot(self, cgsnapshot):
+ def delete_cgsnapshot(self, snap_name):
"""Delete a cgsnapshot (snap group)."""
- snap_name = cgsnapshot['id']
delete_cg_snap_cmd = ('-np', 'snap', '-destroy',
'-id', snap_name, '-o')
return rc
+ def copy_snapshot(self, src_snap_name, new_name):
+
+ copy_snap_cmd = ('snap', '-copy',
+ '-id', src_snap_name,
+ '-name', new_name,
+ '-ignoreMigrationCheck',
+ '-ignoreDeduplicationCheck')
+
+ out, rc = self.command_execute(*copy_snap_cmd)
+ if rc != 0:
+ self._raise_cli_error(copy_snap_cmd, rc, out)
+
+ def allow_snapshot_readwrite_and_autodelete(self, snap_name):
+
+ modify_cmd = ('snap', '-modify', '-id', snap_name,
+ '-allowReadWrite', 'yes', '-allowAutoDelete', 'yes')
+
+ out, rc = self.command_execute(*modify_cmd)
+ if rc != 0:
+ self._raise_cli_error(modify_cmd, rc, out)
+
def attach_mount_point(self, name, snapshot_name):
command_attach_mount_point = ('lun', '-attach',
return rc
- def migrate_lun_with_verification(self, src_id,
- dst_id=None,
- dst_name=None):
+ def migrate_lun_without_verification(self, src_id, dst_id,
+ dst_name=None):
try:
self.migrate_lun(src_id, dst_id)
+ return True
except exception.EMCVnxCLICmdError as ex:
migration_succeed = False
orig_out = "\n".join(ex.kwargs["out"])
"start failed. LUN: %s"), dst_name)
self.delete_lun(dst_name)
return False
+ else:
+ return True
+ def verify_lun_migration(self, src_id):
# Set the proper interval to verify the migration status
def migration_is_ready(poll=False):
mig_ready = False
self._raise_cli_error(cmd_migrate_list, rc, out)
return False
- eventlet.sleep(INTERVAL_30_SEC)
-
try:
if migration_is_ready(True):
return True
if rc != 0:
self._raise_cli_error(cmd_migrate_cancel, rc, out)
+ def migrate_lun_with_verification(self, src_id,
+ dst_id,
+ dst_name=None):
+ migration_started = self.migrate_lun_without_verification(
+ src_id, dst_id, dst_name)
+ if not migration_started:
+ return False
+
+ eventlet.sleep(INTERVAL_30_SEC)
+ return self.verify_lun_migration(src_id)
+
def get_storage_group(self, name, poll=True):
# ALU/HLU as key/value map
new_lun_id = flow_engine.storage.fetch('new_lun_id')
# Delete temp Snapshot
if consistencygroup_id:
- self._client.delete_cgsnapshot(snapshot)
+ self._client.delete_cgsnapshot(snapshot['id'])
else:
self.delete_snapshot(snapshot)
model_update = {'status': 'available'}
try:
- self._client.create_consistencygroup(context, group)
+ self._client.create_consistencygroup(group['id'])
except Exception:
with excutils.save_and_reraise_exception():
LOG.error(_LE('Create consistency group %s failed.'),
'group_name': cgsnapshot['consistencygroup_id']})
try:
- self._client.delete_cgsnapshot(cgsnapshot)
+ self._client.delete_cgsnapshot(cgsnapshot['id'])
for snapshot in snapshots:
snapshot['status'] = 'deleted'
except Exception:
"""Unmanages a volume"""
pass
+ def create_consistencygroup_from_src(self, context, group, volumes,
+ cgsnapshot=None, snapshots=None):
+ """Creates a consistency group from cgsnapshot."""
+
+ 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)
+
+ flow_name = 'create_consistencygroup_from_cgsnapshot'
+ work_flow = linear_flow.Flow(flow_name)
+ copied_snapshot_name = 'temp_snapshot_for_%s' % group['id']
+ store_spec = {
+ 'group': group,
+ 'src_snap_name': cgsnapshot['id'],
+ 'snap_name': copied_snapshot_name,
+ 'client': self._client
+ }
+
+ work_flow.add(CopySnapshotTask(),
+ AllowReadWriteOnSnapshotTask())
+
+ # 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)):
+ specs = self.get_volumetype_extraspecs(volume)
+ provisioning, tiering = self._get_and_validate_extra_specs(specs)
+ pool_name = self. get_target_storagepool(volume, snap['volume'])
+ sub_store_spec = {
+ 'volume': volume,
+ 'source_vol_name': snap['volume_name'],
+ 'pool_name': pool_name,
+ 'dest_vol_name': volume['name'] + '_dest',
+ 'volume_size': volume['size'],
+ 'provisioning': provisioning,
+ 'tiering': tiering,
+ }
+ work_flow.add(
+ CreateSMPTask(name="CreateSMPTask%s" % i,
+ inject=sub_store_spec),
+ AttachSnapTask(name="AttachSnapTask%s" % i,
+ inject=sub_store_spec),
+ CreateDestLunTask(name="CreateDestLunTask%s" % i,
+ providers=lun_data_key_template % i,
+ inject=sub_store_spec),
+ MigrateLunTask(name="MigrateLunTask%s" % i,
+ providers=lun_id_key_template % i,
+ inject=sub_store_spec,
+ rebind={'lun_data': lun_data_key_template % i},
+ wait_for_completion=False))
+
+ volume_model_updates.append({'id': volume['id']})
+ volume_host = volume['host']
+ host = vol_utils.extract_host(volume_host, 'backend')
+ host_and_pool = vol_utils.append_host(host, pool_name)
+ if volume_host != host_and_pool:
+ volume_model_updates[i]['host'] = host_and_pool
+
+ work_flow.add(WaitMigrationsCompleteTask(lun_id_key_template,
+ len(volumes)),
+ CreateConsistencyGroupTask(lun_id_key_template,
+ len(volumes)))
+
+ 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_for_lun(new_lun_id))
+
+ return None, volume_model_updates
+
@decorate_all_methods(log_enter_exit)
class EMCVnxCliPool(EMCVnxCliBase):
else:
LOG.warning(_LW('AttachSnapTask.revert: detach mount point %s'),
volume['name'])
- client.detach_mount_point(volume['name'])
+ try:
+ client.detach_mount_point(volume['name'])
+ except exception.EMCVnxCLICmdError as ex:
+ with excutils.save_and_reraise_exception() as ctxt:
+ is_not_smp_err = (
+ ex.kwargs["rc"] == 163 and
+ client.CLI_RESP_PATTERM_IS_NOT_SMP in
+ "".join(ex.kwargs["out"]))
+ ctxt.reraise = not is_not_smp_err
class CreateDestLunTask(task.Task):
Reversion strategy: Delete the temp destination lun.
"""
- def __init__(self):
- super(CreateDestLunTask, self).__init__(provides='lun_data')
+ def __init__(self, name=None, providers='lun_data', inject=None):
+ super(CreateDestLunTask, self).__init__(name=name,
+ provides=providers,
+ inject=inject)
def execute(self, client, pool_name, dest_vol_name, volume_size,
provisioning, tiering, *args, **kwargs):
Reversion strategy: None
"""
- def __init__(self):
- super(MigrateLunTask, self).__init__(provides='new_lun_id')
+ def __init__(self, name=None, providers='new_lun_id', inject=None,
+ rebind=None, wait_for_completion=True):
+ super(MigrateLunTask, self).__init__(name=name,
+ provides=providers,
+ inject=inject,
+ rebind=rebind)
+ self.wait_for_completion = wait_for_completion
def execute(self, client, dest_vol_name, volume, lun_data,
*args, **kwargs):
dest_vol_lun_id = lun_data['lun_id']
LOG.info(_LI('Migrating Mount Point Volume: %s'), new_vol_name)
-
- migrated = client.migrate_lun_with_verification(new_vol_lun_id,
- dest_vol_lun_id,
- None)
+ if self.wait_for_completion:
+ migrated = client.migrate_lun_with_verification(new_vol_lun_id,
+ dest_vol_lun_id,
+ None)
+ else:
+ migrated = client.migrate_lun_without_verification(
+ new_vol_lun_id, dest_vol_lun_id, None)
if not migrated:
msg = (_("Migrate volume failed between source vol %(src)s"
" and dest vol %(dst)s.") %
LOG.warning(_LW('CreateSnapshotTask.revert: '
'delete temp cgsnapshot %s'),
snapshot['consistencygroup_id'])
- client.delete_cgsnapshot(snapshot)
+ client.delete_cgsnapshot(snapshot['id'])
else:
LOG.warning(_LW('CreateSnapshotTask.revert: '
'delete temp snapshot %s'),
snapshot['name'])
client.delete_snapshot(snapshot['name'])
+
+
+class CopySnapshotTask(task.Task):
+ """Task to copy a volume snapshot/consistency group snapshot.
+
+ Reversion Strategy: Delete the copied snapshot/cgsnapshot
+ """
+ def execute(self, client, src_snap_name, snap_name, *args, **kwargs):
+ LOG.debug('CopySnapshotTask.execute')
+ client.copy_snapshot(src_snap_name,
+ snap_name)
+
+ def revert(self, result, client, src_snap_name, snap_name,
+ *args, **kwargs):
+ LOG.debug('CopySnapshotTask.revert')
+ if isinstance(result, failure.Failure):
+ return
+ else:
+ LOG.warning(_LW('CopySnapshotTask.revert: delete the '
+ 'copied snapshot %(new_name)s of '
+ '%(source_name)s.'),
+ {'new_name': snap_name,
+ 'source_name': src_snap_name})
+ client.delete_cgsnapshot(snap_name)
+
+
+class AllowReadWriteOnSnapshotTask(task.Task):
+ """Task to modify a Snapshot to allow ReadWrite on it."""
+ def execute(self, client, snap_name, *args, **kwargs):
+ LOG.debug('AllowReadWriteOnSnapshotTask.execute')
+ client.allow_snapshot_readwrite_and_autodelete(snap_name)
+
+
+class CreateConsistencyGroupTask(task.Task):
+ """Task to create a consistency group."""
+ def __init__(self, lun_id_key_template, num_of_members):
+ self.lun_id_keys = set(
+ [lun_id_key_template % i for i in range(num_of_members)])
+ super(CreateConsistencyGroupTask, self).__init__(
+ requires=self.lun_id_keys)
+
+ def execute(self, client, group, *args, **kwargs):
+ LOG.debug('CreateConsistencyGroupTask.execute')
+ lun_ids = [kwargs[key] for key in self.lun_id_keys]
+ client.create_consistencygroup(group['id'], lun_ids)
+
+
+class WaitMigrationsCompleteTask(task.Task):
+ """Task to wait migrations to be completed."""
+ def __init__(self, lun_id_key_template, num_of_members):
+ self.lun_id_keys = set(
+ [lun_id_key_template % i for i in range(num_of_members)])
+ super(WaitMigrationsCompleteTask, self).__init__(
+ requires=self.lun_id_keys)
+
+ def execute(self, client, *args, **kwargs):
+ LOG.debug('WaitMigrationsCompleteTask.execute')
+ lun_ids = [kwargs[key] for key in self.lun_id_keys]
+ for lun_id in lun_ids:
+ migrated = client.verify_lun_migration(lun_id)
+ if not migrated:
+ msg = _("Migrate volume %(src)s failed.") % {'src': lun_id}
+ raise exception.VolumeBackendAPIException(data=msg)