base_lun_name = 'volume-1'
replication_metadata = {'host': 'host@backendsec#unit_test_pool',
- 'system': 'FNM11111'}
+ 'system': 'fake_serial'}
test_volume = {
'status': 'creating',
'name': 'volume-1',
'max_over_subscription_ratio': 20.0,
'consistencygroup_support': 'True',
'replication_enabled': False,
+ 'replication_targets': [],
'pool_name': 'unit_test_pool',
'fast_cache_enabled': True,
'fast_support': 'True'}
'thick_provisioning_support': True,
'consistencygroup_support': 'True',
'replication_enabled': False,
+ 'replication_targets': [],
'pool_name': 'unit_test_pool',
'max_over_subscription_ratio': 20.0,
'fast_cache_enabled': True,
'thick_provisioning_support': True,
'consistencygroup_support': 'True',
'replication_enabled': False,
+ 'replication_targets': [],
'pool_name': 'unit_test_pool2',
'max_over_subscription_ratio': 20.0,
'fast_cache_enabled': False,
'consistencygroup_support': 'False',
'pool_name': 'unit_test_pool',
'replication_enabled': False,
+ 'replication_targets': [],
'max_over_subscription_ratio': 20.0,
'fast_cache_enabled': 'False',
'fast_support': 'False'}
'thick_provisioning_support': True,
'consistencygroup_support': 'False',
'replication_enabled': False,
+ 'replication_targets': [],
'pool_name': 'unit_test_pool2',
'max_over_subscription_ratio': 20.0,
'fast_cache_enabled': 'False',
'max_over_subscription_ratio': 20.0,
'consistencygroup_support': 'True',
'replication_enabled': False,
+ 'replication_targets': [],
'pool_name': 'unit_test_pool',
'fast_cache_enabled': True,
'fast_support': 'True'}
class EMCVNXCLIDriverReplicationV2TestCase(DriverTestCaseBase):
def setUp(self):
super(EMCVNXCLIDriverReplicationV2TestCase, self).setUp()
- self.target_device_id = 'fake_serial'
+ self.backend_id = 'fake_serial'
self.configuration.replication_device = [{
- 'target_device_id': self.target_device_id,
- 'managed_backend_name': 'host@backend#unit_test_pool',
+ 'backend_id': self.backend_id,
'san_ip': '192.168.1.2', 'san_login': 'admin',
'san_password': 'admin', 'san_secondary_ip': '192.168.2.2',
'storage_vnx_authentication_type': 'global',
'storage_vnx_security_file_dir': None}]
- def generate_driver(self, conf):
- return emc_cli_iscsi.EMCCLIISCSIDriver(configuration=conf)
+ def generate_driver(self, conf, active_backend_id=None):
+ return emc_cli_iscsi.EMCCLIISCSIDriver(
+ configuration=conf,
+ active_backend_id=active_backend_id)
def _build_mirror_name(self, volume_id):
return 'mirror_' + volume_id
self.assertTrue(model_update['replication_status'] == 'enabled')
self.assertTrue(model_update['replication_driver_data'] ==
build_replication_data(self.configuration))
- self.assertDictMatch({'system': self.target_device_id,
- 'host': rep_volume.host,
+ self.assertDictMatch({'system': self.backend_id,
'snapcopy': 'False'},
model_update['metadata'])
fake_cli.assert_has_calls(
mock.call(*self.testData.MIRROR_DESTROY_CMD(mirror_name),
poll=True)])
- def test_enable_replication(self):
- rep_volume = EMCVNXCLIDriverTestData.convert_volume(
- self.testData.test_volume_replication)
- mirror_name = self._build_mirror_name(rep_volume.id)
- image_uid = '50:06:01:60:88:60:05:FE'
- commands = [self.testData.MIRROR_LIST_CMD(mirror_name),
- self.testData.MIRROR_SYNC_IMAGE_CMD(
- mirror_name, image_uid)]
- results = [[self.testData.MIRROR_LIST_RESULT(
- mirror_name, 'Administratively fractured'),
- self.testData.MIRROR_LIST_RESULT(
- mirror_name)],
- SUCCEED]
- fake_cli = self.driverSetup(commands, results)
- rep_volume.replication_driver_data = build_replication_data(
- self.configuration)
- self.driver.cli._mirror._secondary_client.command_execute = fake_cli
- self.driver.replication_enable(None, rep_volume)
- fake_cli.assert_has_calls([
- mock.call(*self.testData.MIRROR_LIST_CMD(mirror_name),
- poll=True),
- mock.call(*self.testData.MIRROR_SYNC_IMAGE_CMD(
- mirror_name, image_uid), poll=False),
- mock.call(*self.testData.MIRROR_LIST_CMD(mirror_name),
- poll=False)])
-
- def test_enable_already_synced(self):
- rep_volume = EMCVNXCLIDriverTestData.convert_volume(
- self.testData.test_volume_replication)
- mirror_name = self._build_mirror_name(rep_volume.id)
- commands = [self.testData.MIRROR_LIST_CMD(mirror_name)]
- results = [self.testData.MIRROR_LIST_RESULT(mirror_name)]
- fake_cli = self.driverSetup(commands, results)
- rep_volume.replication_driver_data = build_replication_data(
- self.configuration)
- self.driver.cli._mirror._secondary_client.command_execute = fake_cli
- self.driver.replication_enable(None, rep_volume)
- fake_cli.assert_has_calls([
- mock.call(*self.testData.MIRROR_LIST_CMD(mirror_name),
- poll=True)])
-
- def test_disable_replication(self):
- rep_volume = EMCVNXCLIDriverTestData.convert_volume(
- self.testData.test_volume_replication)
- mirror_name = self._build_mirror_name(rep_volume.id)
- image_uid = '50:06:01:60:88:60:05:FE'
- commands = [self.testData.MIRROR_LIST_CMD(mirror_name),
- self.testData.MIRROR_FRACTURE_IMAGE_CMD(
- mirror_name, image_uid)]
- results = [self.testData.MIRROR_LIST_RESULT(mirror_name),
- SUCCEED]
- fake_cli = self.driverSetup(commands, results)
- rep_volume.replication_driver_data = build_replication_data(
- self.configuration)
- self.driver.cli._mirror._secondary_client.command_execute = fake_cli
- self.driver.replication_disable(None, rep_volume)
- fake_cli.assert_has_calls([
- mock.call(*self.testData.MIRROR_LIST_CMD(mirror_name),
- poll=True),
- mock.call(*self.testData.MIRROR_FRACTURE_IMAGE_CMD(mirror_name,
- image_uid), poll=False)])
-
@mock.patch(
"cinder.volume.drivers.emc.emc_vnx_cli.CommandLineHelper." +
"get_lun_by_name",
mock.Mock(return_value={'lun_id': 1}))
+ @mock.patch(
+ "cinder.volume.volume_types."
+ "get_volume_type_extra_specs",
+ mock.Mock(return_value={'replication_enabled': '<is> True'}))
def test_failover_replication_from_primary(self):
rep_volume = EMCVNXCLIDriverTestData.convert_volume(
self.testData.test_volume_replication)
self.configuration)
rep_volume.metadata = self.testData.replication_metadata
self.driver.cli._mirror._secondary_client.command_execute = fake_cli
- model_update = self.driver.replication_failover(
- None, rep_volume,
- self.target_device_id)
+ back_id, model_update = self.driver.failover_host(
+ None, [rep_volume],
+ self.backend_id)
fake_cli.assert_has_calls([
mock.call(*self.testData.MIRROR_LIST_CMD(mirror_name),
poll=True),
mock.call(*self.testData.MIRROR_PROMOTE_IMAGE_CMD(mirror_name,
image_uid), poll=False)])
self.assertEqual(
- self.configuration.replication_device[0]['managed_backend_name'],
- model_update['host'])
- expected = build_provider_location('1', 'lun', rep_volume.name,
- self.target_device_id)
- provider_location = model_update['provider_location']
- # Don't compare the exact string but the set of items: dictionary
- # items are rendered in a random order because of the hash
- # randomization
- self.assertSetEqual(set(expected.split('|')),
- set(provider_location.split('|')))
+ build_provider_location(
+ '1', 'lun', rep_volume.name,
+ self.backend_id),
+ model_update[0]['updates']['provider_location'])
+ @mock.patch(
+ "cinder.volume.volume_types."
+ "get_volume_type_extra_specs",
+ mock.Mock(return_value={'replication_enabled': '<is> True'}))
def test_failover_replication_from_secondary(self):
rep_volume = EMCVNXCLIDriverTestData.convert_volume(
self.testData.test_volume_replication)
'cinder.volume.drivers.emc.emc_vnx_cli.CommandLineHelper') \
as fake_remote:
fake_remote.return_value = self.driver.cli._client
- self.driver.replication_failover(None, rep_volume,
- 'FNM11111')
+ backend_id, data = self.driver.failover_host(
+ None, [rep_volume], 'default')
+ updates = data[0]['updates']
+ rep_status = updates['replication_status']
+ self.assertEqual('enabled', rep_status)
fake_cli.assert_has_calls([
mock.call(*self.testData.MIRROR_LIST_CMD(mirror_name),
poll=True),
mock.call(*self.testData.MIRROR_PROMOTE_IMAGE_CMD(mirror_name,
image_uid), poll=False)])
+ @mock.patch(
+ "cinder.volume.volume_types."
+ "get_volume_type_extra_specs",
+ mock.Mock(return_value={'replication_enabled': '<is> True'}))
+ def test_failover_replication_invalid_backend_id(self):
+ rep_volume = EMCVNXCLIDriverTestData.convert_volume(
+ self.testData.test_volume_replication)
+ self._build_mirror_name(rep_volume.id)
+ fake_cli = self.driverSetup([], [])
+ rep_volume.replication_driver_data = build_replication_data(
+ self.configuration)
+ rep_volume.metadata = self.testData.replication_metadata
+ driver_data = json.loads(rep_volume.replication_driver_data)
+ driver_data['is_primary'] = False
+ rep_volume.replication_driver_data = json.dumps(driver_data)
+ self.driver.cli._mirror._secondary_client.command_execute = fake_cli
+ with mock.patch(
+ 'cinder.volume.drivers.emc.emc_vnx_cli.CommandLineHelper') \
+ as fake_remote:
+ fake_remote.return_value = self.driver.cli._client
+ invalid = 'invalid_backend_id'
+ self.assertRaisesRegex(exception.VolumeBackendAPIException,
+ "Invalid secondary_backend_id specified",
+ self.driver.failover_host,
+ None,
+ [rep_volume],
+ invalid)
+
+ @mock.patch(
+ "cinder.volume.volume_types."
+ "get_volume_type_extra_specs",
+ mock.Mock(return_value={'replication_enabled': '<is> True'}))
def test_failover_already_promoted(self):
rep_volume = EMCVNXCLIDriverTestData.convert_volume(
self.testData.test_volume_replication)
self.configuration)
rep_volume.metadata = self.testData.replication_metadata
self.driver.cli._mirror._secondary_client.command_execute = fake_cli
- self.assertRaisesRegex(exception.EMCVnxCLICmdError,
- 'UID of the secondary image '
- 'to be promoted is not local',
- self.driver.replication_failover,
- None, rep_volume, self.target_device_id)
+ new_backend_id, model_updates = self.driver.failover_host(
+ None, [rep_volume], self.backend_id)
+ self.assertEqual(rep_volume.id, model_updates[0]['volume_id'])
+ self.assertEqual('error',
+ model_updates[0]['updates']['replication_status'])
+
fake_cli.assert_has_calls([
mock.call(*self.testData.MIRROR_LIST_CMD(mirror_name),
poll=True),
poll=False)]
fake_cli.assert_has_calls(expected)
- def test_list_replication_targets(self):
- rep_volume = EMCVNXCLIDriverTestData.convert_volume(
- self.testData.test_volume_replication)
- rep_volume.replication_driver_data = build_replication_data(
- self.configuration)
- expect_targets = {'volume_id': rep_volume.id,
- 'targets':
- [{'type': 'managed',
- 'target_device_id': self.target_device_id}]}
+ def test_build_client_with_invalid_id(self):
+ self.driverSetup([], [])
+ self.assertRaisesRegex(
+ exception.VolumeBackendAPIException,
+ 'replication_device with backend_id .* is missing.',
+ self.driver.cli._build_client,
+ 'invalid_backend_id')
+
+ def test_build_client_with_id(self):
self.driverSetup([], [])
- data = self.driver.list_replication_targets(None, rep_volume)
- self.assertDictMatch(expect_targets, data)
+ cli_client = self.driver.cli._build_client(
+ active_backend_id='fake_serial')
+ self.assertEqual('192.168.1.2', cli_client.active_storage_ip)
+ self.assertEqual('192.168.1.2', cli_client.primary_storage_ip)
VNXError = emc_vnx_cli.VNXError
"""
def __init__(self, *args, **kwargs):
-
super(EMCCLIFCDriver, self).__init__(*args, **kwargs)
self.cli = emc_vnx_cli.getEMCVnxCli(
'FC',
- configuration=self.configuration)
+ configuration=self.configuration,
+ active_backend_id=kwargs.get('active_backend_id'))
self.VERSION = self.cli.VERSION
def check_for_setup_error(self):
def backup_use_temp_snapshot(self):
return True
- def replication_enable(self, context, volume):
- """Enables replication on a replication capable volume."""
- return self.cli.replication_enable(context, volume)
-
- def replication_disable(self, context, volume):
- """Disables replication on a replication-enabled volume."""
- return self.cli.replication_disable(context, volume)
-
- def replication_failover(self, context, volume, secondary):
+ def failover_host(self, context, volumes, secondary_backend_id):
"""Failovers volume from primary device to secondary."""
- return self.cli.replication_failover(context, volume, secondary)
-
- def list_replication_targets(self, context, volume):
- """Returns volume replication info."""
- return self.cli.list_replication_targets(context, volume)
+ return self.cli.failover_host(context, volumes, secondary_backend_id)
"""
def __init__(self, *args, **kwargs):
-
super(EMCCLIISCSIDriver, self).__init__(*args, **kwargs)
self.cli = emc_vnx_cli.getEMCVnxCli(
'iSCSI',
- configuration=self.configuration)
+ configuration=self.configuration,
+ active_backend_id=kwargs.get('active_backend_id'))
self.VERSION = self.cli.VERSION
def check_for_setup_error(self):
def backup_use_temp_snapshot(self):
return True
- def replication_enable(self, context, volume):
- """Enables replication on a replication capable volume."""
- return self.cli.replication_enable(context, volume)
-
- def replication_disable(self, context, volume):
- """Disables replication on a replication-enabled volume."""
- return self.cli.replication_disable(context, volume)
-
- def replication_failover(self, context, volume, secondary):
+ def failover_host(self, context, volumes, secondary_backend_id):
"""Failovers volume from primary device to secondary."""
- return self.cli.replication_failover(context, volume, secondary)
-
- def list_replication_targets(self, context, volume):
- """Returns volume replication info."""
- return self.cli.list_replication_targets(context, volume)
+ return self.cli.failover_host(context, volumes, secondary_backend_id)
tmp_smp_for_backup_prefix = 'tmp-smp-'
snap_as_vol_prefix = 'snap-as-vol-'
- def __init__(self, prtcl, configuration=None):
+ def __init__(self, prtcl, configuration=None, active_backend_id=None):
self.protocol = prtcl
self.configuration = configuration
self.max_luns_per_sg = self.configuration.max_luns_per_storage_group
"Initiator auto registration is not enabled. "
"Please register initiator manually."))
self.hlu_set = set(range(1, self.max_luns_per_sg + 1))
- self._client = CommandLineHelper(self.configuration)
+ self._client = self._build_client(active_backend_id)
+ self._active_backend_id = active_backend_id
# Create connection to the secondary storage device
self._mirror = self._build_mirror_view()
self.update_enabler_in_volume_stats()
pool_stats['max_over_subscription_ratio'] = (
self.max_over_subscription_ratio)
# Add replication V2 support
+ targets = []
if self._mirror:
pool_stats['replication_enabled'] = True
pool_stats['replication_count'] = 1
pool_stats['replication_type'] = ['sync']
+ for device in self.configuration.replication_device:
+ targets.append(device['backend_id'])
else:
pool_stats['replication_enabled'] = False
+ pool_stats['replication_targets'] = targets
return pool_stats
def update_enabler_in_volume_stats(self):
return specs
- def replication_enable(self, context, volume):
- """Enables replication for the volume."""
- mirror_name = self._construct_mirror_name(volume)
- mirror_view = self._get_mirror_view(volume)
- mirror_view.sync_image(mirror_name)
-
- def replication_disable(self, context, volume):
- """Disables replication for the volume."""
- mirror_name = self._construct_mirror_name(volume)
- mirror_view = self._get_mirror_view(volume)
- mirror_view.fracture_image(mirror_name)
-
- def replication_failover(self, context, volume, secondary):
+ def failover_host(self, context, volumes, secondary_backend_id):
"""Fails over the volume back and forth.
Driver needs to update following info for this volume:
- 1. host: to point to the new host
2. provider_location: update serial number and lun id
"""
- rep_data = json.loads(volume['replication_driver_data'])
- is_primary = rep_data['is_primary']
- if is_primary:
- remote_device_id = (
- self.configuration.replication_device[0]['target_device_id'])
- else:
- remote_device_id = self._get_volume_metadata(volume)['system']
- if secondary != remote_device_id:
- msg = (_('Invalid secondary specified, choose from %s.')
- % [remote_device_id])
- LOG.error(msg)
- raise exception.VolumeBackendAPIException(data=msg)
-
- mirror_name = self._construct_mirror_name(volume)
- mirror_view = self._get_mirror_view(volume)
- remote_client = mirror_view._secondary_client
- if is_primary:
- new_host = (
- self.configuration.replication_device[0][
- 'managed_backend_name'])
+ volume_update_list = []
+
+ if secondary_backend_id != 'default':
+ rep_status = 'failed-over'
+ backend_id = (
+ self.configuration.replication_device[0]['backend_id'])
+ if secondary_backend_id != backend_id:
+ msg = (_('Invalid secondary_backend_id specified. '
+ 'Valid backend id is %s.') % backend_id)
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
else:
- new_host = self._get_volume_metadata(volume)['host']
-
- rep_data.update({'is_primary': not is_primary})
- # Transfer ownership to secondary and
- # update provider_location field
- provider_location = volume['provider_location']
- provider_location = self._update_provider_location(
- provider_location,
- 'system', remote_client.get_array_serial()['array_serial'])
- self.get_array_serial()
- provider_location = self._update_provider_location(
- provider_location,
- 'id',
- six.text_type(remote_client.get_lun_by_name(volume.name)['lun_id'])
- )
-
- mirror_view.promote_image(mirror_name)
- model_update = {'host': new_host,
- 'replication_driver_data': json.dumps(rep_data),
- 'provider_location': provider_location}
- return model_update
+ rep_status = 'enabled'
- def list_replication_targets(self, context, volume):
- """Provides replication target(s) for a volume."""
- targets = {'volume_id': volume.id, 'targets': []}
- rep_data = json.loads(volume['replication_driver_data'])
- is_primary = rep_data['is_primary']
- if is_primary:
- remote_device_id = (
- self.configuration.replication_device[0]['target_device_id'])
- else:
- remote_device_id = self._get_volume_metadata(volume)['system']
+ def failover_one(volume, new_status):
+ rep_data = json.loads(volume['replication_driver_data'])
+ is_primary = rep_data['is_primary']
+ mirror_name = self._construct_mirror_name(volume)
+ mirror_view = self._get_mirror_view(volume)
+ remote_client = mirror_view._secondary_client
- targets['targets'] = [{'type': 'managed',
- 'target_device_id': remote_device_id}]
- return targets
+ provider_location = volume['provider_location']
+ try:
+ mirror_view.promote_image(mirror_name)
+ except exception.EMCVnxCLICmdError as ex:
+ msg = _LE(
+ 'Failed to failover volume %(volume_id)s '
+ 'to %(target)s: %(error)s.')
+ LOG.error(msg, {'volume_id': volume.id,
+ 'target': secondary_backend_id,
+ 'error': ex},)
+ new_status = 'error'
+ else:
+ rep_data.update({'is_primary': not is_primary})
+ # Transfer ownership to secondary_backend_id and
+ # update provider_location field
+ provider_location = self._update_provider_location(
+ provider_location,
+ 'system', remote_client.get_array_serial()['array_serial'])
+ provider_location = self._update_provider_location(
+ provider_location,
+ 'id',
+ six.text_type(
+ remote_client.get_lun_by_name(volume.name)['lun_id'])
+ )
+ model_update = {'volume_id': volume.id,
+ 'updates':
+ {'replication_driver_data':
+ json.dumps(rep_data),
+ 'replication_status': new_status,
+ 'provider_location': provider_location}}
+ volume_update_list.append(model_update)
+ for volume in volumes:
+ if self._is_replication_enabled(volume):
+ failover_one(volume, rep_status)
+ else:
+ volume_update_list.append({
+ 'volume_id': volume.id,
+ 'updates': {'status': 'error'}})
+ return secondary_backend_id, volume_update_list
def _is_replication_enabled(self, volume):
"""Return True if replication extra specs is specified.
'for volume: %s.', volume.id)
lun_size = volume['size']
mirror_name = self._construct_mirror_name(volume)
+ pool_name = vol_utils.extract_host(volume.host, 'pool')
self._mirror.create_mirror_workflow(
- mirror_name, primary_lun_id, volume.name, lun_size,
+ mirror_name, primary_lun_id, pool_name,
+ volume.name, lun_size,
provisioning, tiering)
LOG.info(_LI('Successfully setup replication for %s.'), volume.id)
self.configuration),
'replication_status': 'enabled'})
metadata_update = {
- 'host': volume.host,
'system': self.get_array_serial()}
return rep_update, metadata_update
driver_data['is_primary'] = True
return json.dumps(driver_data)
+ def _build_client(self, active_backend_id=None):
+ """Builds a client pointing to the right VNX."""
+ if not active_backend_id:
+ return CommandLineHelper(self.configuration)
+ else:
+ configuration = self.configuration
+ if not configuration.replication_device:
+ err_msg = (
+ _('replication_device should be configured '
+ 'on backend: %s.') % configuration.config_group)
+ LOG.error(err_msg)
+ raise exception.VolumeBackendAPIException(data=err_msg)
+ current_target = None
+ for target in configuration.replication_device:
+ if target['backend_id'] == active_backend_id:
+ current_target = target
+ break
+ if not current_target:
+ err_msg = (
+ _('replication_device with backend_id [%s] is missing.')
+ % active_backend_id)
+ LOG.error(err_msg)
+ raise exception.VolumeBackendAPIException(data=err_msg)
+ target_conf = copy.copy(configuration)
+ for key in self.REPLICATION_KEYS:
+ if key in current_target:
+ setattr(target_conf, key, current_target[key])
+ return CommandLineHelper(target_conf)
+
def _build_mirror_view(self, volume=None):
"""Builds a client for remote storage device.
configuration.config_group)
return None
remote_info = configuration.replication_device[0]
-
- pool_name = None
- managed_backend_name = remote_info.get('managed_backend_name')
- if managed_backend_name:
- pool_name = vol_utils.extract_host(managed_backend_name, 'pool')
# Copy info to replica configuration for remote client
replica_conf = copy.copy(configuration)
for key in self.REPLICATION_KEYS:
if key in remote_info:
- config.Configuration.__setattr__(replica_conf,
- key, remote_info[key])
+ setattr(replica_conf, key, remote_info[key])
_remote_client = CommandLineHelper(replica_conf)
- _mirror = MirrorView(self._client, _remote_client, pool_name)
+ _mirror = MirrorView(self._client, _remote_client)
return _mirror
def get_pool(self, volume):
return self.stats
-def getEMCVnxCli(prtcl, configuration=None):
+def getEMCVnxCli(prtcl, configuration=None, active_backend_id=None):
configuration.append_config_values(loc_opts)
- return EMCVnxCliBase(prtcl, configuration=configuration)
+ return EMCVnxCliBase(prtcl, configuration=configuration,
+ active_backend_id=active_backend_id)
class CreateSMPTask(task.Task):
SYNCHRONIZED_STATE = 'Synchronized'
CONSISTENT_STATE = 'Consistent'
- def __init__(self, client, secondary_client, pool_name, mode='sync'):
+ def __init__(self, client, secondary_client, mode='sync'):
"""Caller needs to initialize MirrorView via this method.
:param client: client connecting to primary system
"""
self._client = client
self._secondary_client = secondary_client
- self.pool_name = pool_name
if mode not in self.SYNCHRONIZE_MODE:
msg = _('Invalid synchronize mode specified, allowed '
'mode is %s.') % self.SYNCHRONIZE_MODE
data=msg)
self.mode = '-sync'
- def create_mirror_workflow(self, mirror_name, lun_id,
+ def create_mirror_workflow(self, mirror_name, lun_id, pool_name,
lun_name, lun_size, provisioning, tiering):
"""Creates mirror view for LUN."""
store_spec = {'mirror': self}
work_flow = self._get_create_mirror_flow(
- mirror_name, lun_id, lun_name, lun_size, provisioning, tiering)
+ mirror_name, lun_id, pool_name,
+ lun_name, lun_size, provisioning, tiering)
flow_engine = taskflow.engines.load(work_flow, store=store_spec)
flow_engine.run()
self.destroy_mirror(mirror_name)
self.delete_secondary_lun(lun_name)
- def _get_create_mirror_flow(self, mirror_name, lun_id,
+ def _get_create_mirror_flow(self, mirror_name, lun_id, pool_name,
lun_name, lun_size, provisioning, tiering):
"""Gets mirror create flow."""
flow_name = 'create_mirror_view'
work_flow = linear_flow.Flow(flow_name)
work_flow.add(MirrorCreateTask(mirror_name, lun_id),
- MirrorSecLunCreateTask(lun_name, lun_size,
+ MirrorSecLunCreateTask(pool_name, lun_name, lun_size,
provisioning, tiering),
MirrorAddImageTask(mirror_name))
return work_flow
out=out)
return rc
- def create_secondary_lun(self, lun_name, lun_size, provisioning,
+ def create_secondary_lun(self, pool_name, lun_name, lun_size,
+ provisioning,
tiering, poll=False):
"""Creates secondary LUN in remote device."""
data = self._secondary_client.create_lun_with_advance_feature(
- pool=self.pool_name,
+ pool=pool_name,
name=lun_name,
size=lun_size,
provisioning=provisioning,
Reversion strategy: Delete secondary LUN.
"""
- def __init__(self, lun_name, lun_size, provisioning, tiering):
+ def __init__(self, pool_name, lun_name, lun_size, provisioning, tiering):
super(MirrorSecLunCreateTask, self).__init__(provides='sec_lun_id')
+ self.pool_name = pool_name
self.lun_name = lun_name
self.lun_size = lun_size
self.provisioning = provisioning
def execute(self, mirror, *args, **kwargs):
LOG.debug('%s.execute', self.__class__.__name__)
sec_lun_id = mirror.create_secondary_lun(
- self.lun_name, self.lun_size, self.provisioning, self.tiering)
+ self.pool_name, self.lun_name, self.lun_size,
+ self.provisioning, self.tiering)
return sec_lun_id
def revert(self, result, mirror, *args, **kwargs):
+++ /dev/null
----
-features:
- - Replication v2 has been added in VNX Cinder driver
--- /dev/null
+---
+features:
+ - Adds v2.1 replication support in VNX Cinder driver.