Merge "Add CG capability to generic groups in VNX driver"

This commit is contained in:
Jenkins 2017-01-13 03:04:38 +00:00 committed by Gerrit Code Review
commit de813e7a74
9 changed files with 436 additions and 62 deletions

View File

@ -175,12 +175,12 @@ test_create_snapshot_adapter:
test_delete_snapshot_adapter:
snapshot: *snapshot_base
test_create_cgsnapshot: &cg_snap_and_snaps
test_do_create_cgsnap: &cg_snap_and_snaps
cg_snap: *cg_snapshot_base
snap1: *snapshot_base
snap2: *snapshot_base
test_delete_cgsnapshot: *cg_snap_and_snaps
test_do_delete_cgsnap: *cg_snap_and_snaps
test_manage_existing_lun_no_exist:
volume: *volume_base
@ -244,7 +244,7 @@ test_create_volume_from_snapshot_snapcopy:
test_get_base_lun_name:
volume: *volume_base
test_create_cg_from_cgsnapshot:
test_do_create_cg_from_cgsnap:
vol1:
_type: 'volume'
_properties:
@ -257,8 +257,6 @@ test_create_cg_from_cgsnapshot:
<<: *volume_base_properties
id:
_uuid: volume2_id
cg: *cg_base
cg_snap: *cg_snapshot_base
snap1:
_type: 'snapshot'
_properties:
@ -272,21 +270,13 @@ test_create_cg_from_cgsnapshot:
id:
_uuid: snapshot2_id
test_create_cloned_cg:
test_do_clone_cg:
vol1:
_type: 'volume'
_properties:
<<: *volume_base_properties
id:
_uuid: consistency_group_id
cg: *cg_base
src_cg:
_type: 'cg'
_properties:
<<: *cg_base_properties
id:
_uuid: consistency_group2_id
name: 'src_cg_name'
src_vol1:
_type: 'volume'
@ -322,7 +312,7 @@ test_remove_host_access_sg_absent:
test_remove_host_access_volume_not_in_sg:
volume: *volume_base
test_update_consistencygroup:
test_do_update_cg:
cg: *cg_base
volume_add:
<<: *volume_base
@ -421,13 +411,36 @@ test_update_migrated_volume_smp:
<<: *provider_location_dict
type: smp
test_create_group_snap:
test_create_cgsnapshot:
test_create_cloned_cg:
test_create_cloned_group:
test_create_cg_from_cgsnapshot:
test_create_group_from_group_snapshot:
test_create_cgsnapshot:
test_create_group_snapshot:
test_delete_group_snapshot:
test_delete_cgsnapshot:
###########################################################
# TestUtils
###########################################################
test_validate_cg_type:
cg: *cg_base_with_type
cg:
_properties:
id:
_uuid: GROUP_ID
volume_type_ids: ['type1']
###########################################################

View File

@ -150,6 +150,7 @@ mirror_base: &mirror_base
_type: VNXMirrorImageState
value: 'SYNCHRONIZED'
###########################################################
# TestClient
###########################################################
@ -1365,7 +1366,9 @@ test_delete_snapshot_adapter: *test_delete_snapshot
test_create_cgsnapshot: *test_create_cg_snapshot
test_delete_cgsnapshot:
test_do_create_cgsnap: *test_create_cg_snapshot
test_do_delete_cgsnap:
cg_snap: &cg_snap_delete
_methods:
delete:
@ -1373,7 +1376,7 @@ test_delete_cgsnapshot:
_methods:
get_snap: *cg_snap_delete
test_create_cg_from_cgsnapshot:
test_do_create_cg_from_cgsnap:
snap: &copied_cg_snap
_methods:
copy:
@ -1400,7 +1403,7 @@ test_create_cg_from_cgsnapshot:
get_migration_session: *session_verify
create_cg: *cg_for_create
test_create_cloned_cg:
test_do_clone_cg:
vnx:
_properties:
_methods:
@ -1773,6 +1776,8 @@ test_terminate_connection_cleanup_sg_is_not_empty:
test_update_consistencygroup:
test_do_update_cg:
test_update_migrated_volume:
test_update_migrated_volume_smp:
@ -1785,6 +1790,26 @@ test_normalize_config_iscsi_initiators_empty_str:
test_normalize_config_iscsi_initiators_not_dict:
test_create_group_snap:
test_create_cgsnapshot:
test_create_cloned_cg:
test_create_cloned_group:
test_create_cg_from_cgsnapshot:
test_create_group_from_group_snapshot:
test_create_cgsnapshot:
test_create_group_snapshot:
test_delete_group_snapshot:
test_delete_cgsnapshot:
###########################################################
# TestISCSIAdapter

View File

@ -15,9 +15,12 @@
import mock
import re
from cinder import context
from cinder import exception
from cinder.objects import fields
from cinder import test
from cinder.tests.unit import fake_constants
from cinder.tests.unit import utils as test_utils
from cinder.tests.unit.volume.drivers.dell_emc.vnx import fake_exception \
as storops_ex
from cinder.tests.unit.volume.drivers.dell_emc.vnx import fake_storops \
@ -39,6 +42,7 @@ class TestCommonAdapter(test.TestCase):
vnx_utils.init_ops(self.configuration)
self.configuration.san_ip = '192.168.1.1'
self.configuration.storage_vnx_authentication_type = 'global'
self.ctxt = context.get_admin_context()
def tearDown(self):
super(TestCommonAdapter, self).tearDown()
@ -136,32 +140,124 @@ class TestCommonAdapter(test.TestCase):
update = vnx_common.create_volume_from_snapshot(volume, snapshot)
self.assertEqual('True', update['metadata']['snapcopy'])
@res_mock.patch_common_adapter
def test_create_cg_from_cgsnapshot(self, common, _):
common.do_create_cg_from_cgsnap = mock.Mock(
return_value='fake_return')
new_cg = test_utils.create_consistencygroup(
self.ctxt,
id=fake_constants.CONSISTENCY_GROUP_ID,
host='host@backend#unit_test_pool',
group_type_id=fake_constants.VOLUME_TYPE_ID)
cg_snapshot = test_utils.create_cgsnapshot(
self.ctxt,
fake_constants.CONSISTENCY_GROUP2_ID)
vol = test_utils.create_volume(self.ctxt)
snaps = [
test_utils.create_snapshot(self.ctxt, vol.id)]
vol_new = test_utils.create_volume(self.ctxt)
ret = common.create_cg_from_cgsnapshot(
None, new_cg, [vol_new], cg_snapshot, snaps)
self.assertEqual('fake_return', ret)
common.do_create_cg_from_cgsnap.assert_called_once_with(
new_cg.id, new_cg.host, [vol_new], cg_snapshot.id, snaps)
@res_mock.patch_common_adapter
def test_create_group_from_group_snapshot(self, common, _):
common.do_create_cg_from_cgsnap = mock.Mock(
return_value='fake_return')
group = test_utils.create_group(
self.ctxt,
id=fake_constants.CONSISTENCY_GROUP_ID,
host='host@backend#unit_test_pool',
group_type_id=fake_constants.VOLUME_TYPE_ID)
group_snapshot = test_utils.create_group_snapshot(
self.ctxt,
fake_constants.CGSNAPSHOT_ID,
host='host@backend#unit_test_pool',
group_type_id=fake_constants.VOLUME_TYPE_ID)
vol = test_utils.create_volume(self.ctxt)
snaps = [
test_utils.create_snapshot(self.ctxt, vol.id)]
vol_new = test_utils.create_volume(self.ctxt)
ret = common.create_group_from_group_snapshot(
None, group, [vol_new], group_snapshot, snaps)
self.assertEqual('fake_return', ret)
common.do_create_cg_from_cgsnap.assert_called_once_with(
group.id, group.host, [vol_new], group_snapshot.id, snaps)
@res_mock.mock_driver_input
@res_mock.patch_common_adapter
def test_create_cg_from_cgsnapshot(self, vnx_common, mocked,
cinder_input):
group = cinder_input['cg']
def test_do_create_cg_from_cgsnap(
self, vnx_common, mocked, cinder_input):
cg_id = fake_constants.CONSISTENCY_GROUP_ID
cg_host = 'host@backend#unit_test_pool'
volumes = [cinder_input['vol1']]
cg_snap = cinder_input['cg_snap']
cgsnap_id = fake_constants.CGSNAPSHOT_ID
snaps = [cinder_input['snap1']]
model_update, volume_updates = vnx_common.create_cg_from_cgsnapshot(
None, group, volumes, cg_snap, snaps)
model_update, volume_updates = (
vnx_common.do_create_cg_from_cgsnap(
cg_id, cg_host, volumes, cgsnap_id, snaps))
self.assertIsNone(model_update)
self.assertIsNotNone(
re.findall('id^12',
volume_updates[0]['provider_location']))
@res_mock.patch_common_adapter
def test_create_cloned_cg(self, common, _):
common.do_clone_cg = mock.Mock(
return_value='fake_return')
group = test_utils.create_consistencygroup(
self.ctxt,
id=fake_constants.CONSISTENCY_GROUP_ID,
host='host@backend#unit_test_pool',
group_type_id=fake_constants.VOLUME_TYPE_ID)
src_group = test_utils.create_consistencygroup(
self.ctxt,
id=fake_constants.CONSISTENCY_GROUP2_ID,
host='host@backend#unit_test_pool2',
group_type_id=fake_constants.VOLUME_TYPE_ID)
vol = test_utils.create_volume(self.ctxt)
src_vol = test_utils.create_volume(self.ctxt)
ret = common.create_cloned_group(
None, group, [vol], src_group, [src_vol])
self.assertEqual('fake_return', ret)
common.do_clone_cg.assert_called_once_with(
group.id, group.host, [vol], src_group.id, [src_vol])
@res_mock.patch_common_adapter
def test_create_cloned_group(self, common, _):
common.do_clone_cg = mock.Mock(
return_value='fake_return')
group = test_utils.create_group(
self.ctxt,
id=fake_constants.GROUP_ID,
host='host@backend#unit_test_pool',
group_type_id=fake_constants.VOLUME_TYPE_ID)
src_group = test_utils.create_group(
self.ctxt,
id=fake_constants.GROUP2_ID,
host='host@backend#unit_test_pool2',
group_type_id=fake_constants.VOLUME_TYPE_ID)
vol = test_utils.create_volume(self.ctxt)
src_vol = test_utils.create_volume(self.ctxt)
ret = common.create_cloned_group(
None, group, [vol], src_group, [src_vol])
self.assertEqual('fake_return', ret)
common.do_clone_cg.assert_called_once_with(
group.id, group.host, [vol], src_group.id, [src_vol])
@res_mock.mock_driver_input
@res_mock.patch_common_adapter
def test_create_cloned_cg(self, vnx_common, mocked,
cinder_input):
group = cinder_input['cg']
src_group = cinder_input['src_cg']
def test_do_clone_cg(self, vnx_common, _, cinder_input):
cg_id = fake_constants.CONSISTENCY_GROUP_ID
cg_host = 'host@backend#unit_test_pool'
volumes = [cinder_input['vol1']]
src_cg_id = fake_constants.CONSISTENCY_GROUP2_ID
src_volumes = [cinder_input['src_vol1']]
model_update, volume_updates = vnx_common.create_cloned_cg(
None, group, volumes, src_group, src_volumes)
model_update, volume_updates = vnx_common.do_clone_cg(
cg_id, cg_host, volumes, src_cg_id, src_volumes)
self.assertIsNone(model_update)
self.assertIsNotNone(
re.findall('id^12',
@ -474,24 +570,105 @@ class TestCommonAdapter(test.TestCase):
mocked_input):
common_adapter.delete_snapshot(mocked_input['snapshot'])
@res_mock.patch_common_adapter
def test_create_cgsnapshot(self, common_adapter, _):
common_adapter.do_create_cgsnap = mock.Mock(
return_value='fake_return')
cg_snapshot = test_utils.create_cgsnapshot(
self.ctxt,
fake_constants.CONSISTENCY_GROUP_ID)
vol = test_utils.create_volume(self.ctxt)
snaps = [
test_utils.create_snapshot(self.ctxt, vol.id)]
ret = common_adapter.create_cgsnapshot(
None, cg_snapshot, snaps)
self.assertEqual('fake_return', ret)
common_adapter.do_create_cgsnap.assert_called_once_with(
cg_snapshot.consistencygroup_id,
cg_snapshot.id,
snaps)
@res_mock.patch_common_adapter
def test_create_group_snap(self, common_adapter, _):
common_adapter.do_create_cgsnap = mock.Mock(
return_value='fake_return')
group_snapshot = test_utils.create_group_snapshot(
self.ctxt,
fake_constants.GROUP_ID,
host='host@backend#unit_test_pool',
group_type_id=fake_constants.VOLUME_TYPE_ID)
vol = test_utils.create_volume(self.ctxt)
snaps = [
test_utils.create_snapshot(self.ctxt, vol.id)]
ret = common_adapter.create_group_snapshot(
None, group_snapshot, snaps)
self.assertEqual('fake_return', ret)
common_adapter.do_create_cgsnap.assert_called_once_with(
group_snapshot.group_id,
group_snapshot.id,
snaps)
@res_mock.mock_driver_input
@res_mock.patch_common_adapter
def test_create_cgsnapshot(self, common_adapter, mocked, mocked_input):
cg_snap = mocked_input['cg_snap']
def test_do_create_cgsnap(self, common_adapter, _, mocked_input):
group_name = fake_constants.CONSISTENCY_GROUP_ID
snap_name = fake_constants.CGSNAPSHOT_ID
snap1 = mocked_input['snap1']
snap2 = mocked_input['snap2']
model_update, snapshots_model_update = (
common_adapter.create_cgsnapshot(None, cg_snap, [snap1, snap2]))
common_adapter.do_create_cgsnap(group_name, snap_name,
[snap1, snap2]))
self.assertEqual('available', model_update['status'])
for update in snapshots_model_update:
self.assertEqual(fields.SnapshotStatus.AVAILABLE, update['status'])
@res_mock.patch_common_adapter
def test_delete_group_snapshot(self, common_adapter, _):
common_adapter.do_delete_cgsnap = mock.Mock(
return_value='fake_return')
group_snapshot = test_utils.create_group_snapshot(
self.ctxt,
fake_constants.GROUP_ID,
host='host@backend#unit_test_pool',
group_type_id=fake_constants.VOLUME_TYPE_ID)
vol = test_utils.create_volume(self.ctxt)
snaps = [
test_utils.create_snapshot(self.ctxt, vol.id)]
ret = common_adapter.delete_group_snapshot(
None, group_snapshot, snaps)
self.assertEqual('fake_return', ret)
common_adapter.do_delete_cgsnap.assert_called_once_with(
group_snapshot.group_id,
group_snapshot.id,
group_snapshot.status,
snaps)
@res_mock.patch_common_adapter
def test_delete_cgsnapshot(self, common_adapter, _):
common_adapter.do_delete_cgsnap = mock.Mock(
return_value='fake_return')
cg_snapshot = test_utils.create_cgsnapshot(
self.ctxt,
fake_constants.CONSISTENCY_GROUP_ID)
vol = test_utils.create_volume(self.ctxt)
snaps = [
test_utils.create_snapshot(self.ctxt, vol.id)]
ret = common_adapter.delete_cgsnapshot(None, cg_snapshot, snaps)
self.assertEqual('fake_return', ret)
common_adapter.do_delete_cgsnap.assert_called_once_with(
cg_snapshot.consistencygroup_id,
cg_snapshot.id,
cg_snapshot.status,
snaps)
@res_mock.mock_driver_input
@res_mock.patch_common_adapter
def test_delete_cgsnapshot(self, common_adapter, mocked, mocked_input):
def test_do_delete_cgsnap(self, common_adapter, _, mocked_input):
group_name = fake_constants.CGSNAPSHOT_ID
snap_name = fake_constants.CGSNAPSHOT_ID
model_update, snapshot_updates = (
common_adapter.delete_cgsnapshot(
None, mocked_input['cg_snap'],
common_adapter.do_delete_cgsnap(
group_name, snap_name, 'available',
[mocked_input['snap1'], mocked_input['snap2']]))
self.assertEqual('deleted', model_update['status'])
for snap in snapshot_updates:
@ -792,15 +969,13 @@ class TestCommonAdapter(test.TestCase):
@res_mock.mock_driver_input
@res_mock.patch_common_adapter
def test_update_consistencygroup(self, common_adapter, mocked_res,
mocked_input):
def test_do_update_cg(self, common_adapter, _, mocked_input):
common_adapter.client.update_consistencygroup = mock.Mock()
cg = mocked_input['cg']
common_adapter.client.get_cg = mock.Mock(return_value=cg)
common_adapter.update_consistencygroup(None, cg,
[mocked_input['volume_add']],
[mocked_input['volume_remove']])
common_adapter.do_update_cg(cg.id,
[mocked_input['volume_add']],
[mocked_input['volume_remove']])
common_adapter.client.update_consistencygroup.assert_called_once_with(
cg, [1], [2])

View File

@ -71,3 +71,11 @@ class TestVNXDriver(test.TestCase):
_driver.terminate_connection('fake_volume', {'host': 'fake_host'})
_driver.adapter.terminate_connection.assert_called_once_with(
'fake_volume', {'host': 'fake_host'})
def test_is_consistent_group_snapshot_enabled(self):
_driver = self._get_driver('iscsi')
_driver._stats = {'consistent_group_snapshot_enabled': True}
self.assertTrue(_driver.is_consistent_group_snapshot_enabled())
_driver._stats = {'consistent_group_snapshot_enabled': False}
self.assertFalse(_driver.is_consistent_group_snapshot_enabled())
self.assertFalse(_driver.is_consistent_group_snapshot_enabled())

View File

@ -27,6 +27,18 @@ from cinder.volume.drivers.dell_emc.vnx import common
from cinder.volume.drivers.dell_emc.vnx import utils
class FakeDriver(object):
def __init__(self, support):
self.support = support
def is_consistent_group_snapshot_enabled(self):
return self.support
@utils.require_consistent_group_snapshot_enabled
def fake_method(self):
return 'called'
class TestUtils(test.TestCase):
def setUp(self):
super(TestUtils, self).setUp()
@ -173,3 +185,14 @@ class TestUtils(test.TestCase):
'wwn2_1': ['wwnt_1', 'wwnt_3'],
'wwn2_2': ['wwnt_1', 'wwnt_3']},
itor_tgt_map)
def test_cg_snapshot_is_not_enabled(self):
def do():
driver = FakeDriver(False)
driver.fake_method()
self.assertRaises(NotImplementedError, do)
def test_cg_snapshot_is_enabled(self):
driver = FakeDriver(True)
ret = driver.fake_method()
self.assertEqual('called', ret)

View File

@ -222,9 +222,10 @@ class CommonAdapter(object):
'provision': provision,
'tier': tier})
cg_id = volume.group_id or volume.consistencygroup_id
lun = self.client.create_lun(
pool, volume_name, volume_size,
provision, tier, volume.consistencygroup_id,
provision, tier, cg_id,
ignore_thresholds=self.config.ignore_pool_full_threshold)
location = self._build_provider_location(
lun_type='lun',
@ -464,15 +465,21 @@ class CommonAdapter(object):
return model_update, volumes_model_update
def create_cgsnapshot(self, context, cgsnapshot, snapshots):
"""Creates a CG snapshot(snap group)."""
return self.do_create_cgsnap(cgsnapshot.consistencygroup_id,
cgsnapshot.id,
snapshots)
def do_create_cgsnap(self, group_name, snap_name, snapshots):
model_update = {}
snapshots_model_update = []
LOG.info(_LI('Creating CG snapshot for consistency group'
LOG.info(_LI('Creating consistency snapshot for group'
': %(group_name)s'),
{'group_name': cgsnapshot.consistencygroup_id})
{'group_name': group_name})
self.client.create_cg_snapshot(cgsnapshot.id,
cgsnapshot.consistencygroup_id)
self.client.create_cg_snapshot(snap_name,
group_name)
for snapshot in snapshots:
snapshots_model_update.append(
{'id': snapshot.id, 'status': 'available'})
@ -482,15 +489,22 @@ class CommonAdapter(object):
def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
"""Deletes a CG snapshot(snap group)."""
return self.do_delete_cgsnap(cgsnapshot.consistencygroup_id,
cgsnapshot.id,
cgsnapshot.status,
snapshots)
def do_delete_cgsnap(self, group_name, snap_name,
snap_status, snapshots):
model_update = {}
snapshots_model_update = []
model_update['status'] = cgsnapshot.status
LOG.info(_LI('Deleting CG snapshot %(snap_name)s for consistency '
model_update['status'] = snap_status
LOG.info(_LI('Deleting consistency snapshot %(snap_name)s for '
'group: %(group_name)s'),
{'snap_name': cgsnapshot.id,
'group_name': cgsnapshot.consistencygroup_id})
{'snap_name': snap_name,
'group_name': group_name})
self.client.delete_cg_snapshot(cgsnapshot.id)
self.client.delete_cg_snapshot(snap_name)
for snapshot in snapshots:
snapshots_model_update.append(
{'id': snapshot.id, 'status': 'deleted'})
@ -500,6 +514,11 @@ class CommonAdapter(object):
def create_cg_from_cgsnapshot(self, context, group,
volumes, cgsnapshot, snapshots):
return self.do_create_cg_from_cgsnap(
group.id, group.host, volumes, cgsnapshot.id, snapshots)
def do_create_cg_from_cgsnap(self, cg_id, cg_host, volumes,
cgsnap_id, snapshots):
# 1. Copy a temp CG snapshot from CG snapshot
# and allow RW for it
# 2. Create SMPs from source volumes
@ -509,9 +528,9 @@ class CommonAdapter(object):
# 6. Wait completion of migration
# 7. Create a new CG, add all LUNs to it
# 8. Delete the temp CG snapshot
cg_name = group.id
src_cg_snap_name = cgsnapshot.id
pool_name = utils.get_pool_from_host(group.host)
cg_name = cg_id
src_cg_snap_name = cgsnap_id
pool_name = utils.get_pool_from_host(cg_host)
lun_sizes = []
lun_names = []
src_lun_names = []
@ -549,9 +568,14 @@ class CommonAdapter(object):
def create_cloned_cg(self, context, group,
volumes, source_cg, source_vols):
self.do_clone_cg(group.id, group.host, volumes,
source_cg.id, source_vols)
def do_clone_cg(self, cg_id, cg_host, volumes,
source_cg_id, source_vols):
# 1. Create temp CG snapshot from source_cg
# Same with steps 2-8 of create_cg_from_cgsnapshot
pool_name = utils.get_pool_from_host(group.host)
pool_name = utils.get_pool_from_host(cg_host)
lun_sizes = []
lun_names = []
src_lun_names = []
@ -564,8 +588,8 @@ class CommonAdapter(object):
lun_id_list = emc_taskflow.create_cloned_cg(
client=self.client,
cg_name=group.id,
src_cg_name=source_cg.id,
cg_name=cg_id,
src_cg_name=source_cg_id,
pool_name=pool_name,
lun_sizes=lun_sizes,
lun_names=lun_names,
@ -623,6 +647,8 @@ class CommonAdapter(object):
stats['thin_provisioning_support'] = self.client.is_thin_enabled()
stats['consistencygroup_support'] = self.client.is_snap_enabled()
stats['replication_enabled'] = True if self.mirror_view else False
stats['consistent_group_snapshot_enabled'] = (
self.client.is_snap_enabled())
return stats
def get_pool_stats(self, enabler_stats=None):
@ -1017,7 +1043,12 @@ class CommonAdapter(object):
def update_consistencygroup(self, context, group, add_volumes,
remove_volumes):
cg = self.client.get_cg(name=group.id)
return self.do_update_cg(group.id, add_volumes,
remove_volumes)
def do_update_cg(self, cg_name, add_volumes,
remove_volumes):
cg = self.client.get_cg(name=cg_name)
lun_ids_to_add = [self.client.get_lun_id(volume)
for volume in add_volumes]
lun_ids_to_remove = [self.client.get_lun_id(volume)
@ -1204,6 +1235,46 @@ class CommonAdapter(object):
return {'provider_location': new_volume.provider_location,
'metadata': metadata}
def create_group(self, context, group):
return self.create_consistencygroup(context, group)
def delete_group(self, context, group, volumes):
return self.delete_consistencygroup(context, group, volumes)
def create_group_snapshot(self, context, group_snapshot, snapshots):
"""Creates a group_snapshot."""
return self.do_create_cgsnap(group_snapshot.group_id,
group_snapshot.id,
snapshots)
def delete_group_snapshot(self, context, group_snapshot, snapshots):
"""Deletes a group snapshot."""
return self.do_delete_cgsnap(
group_snapshot.group_id,
group_snapshot.id,
group_snapshot.status,
snapshots)
def create_group_from_group_snapshot(self,
context, group, volumes,
group_snapshot, snapshots):
"""Creates a group from a group snapshot."""
return self.do_create_cg_from_cgsnap(group.id, group.host, volumes,
group_snapshot.id, snapshots)
def update_group(self, context, group,
add_volumes=None, remove_volumes=None):
"""Updates a group."""
return self.do_update_cg(group.id,
add_volumes,
remove_volumes)
def create_cloned_group(self, context, group, volumes,
source_group, source_vols):
"""Clones a group"""
return self.do_clone_cg(group.id, group.host, volumes,
source_group.id, source_vols)
class ISCSIAdapter(CommonAdapter):
def __init__(self, configuration, active_backend_id):

View File

@ -86,6 +86,7 @@ class VNXDriver(driver.TransferVD,
self.protocol = self.configuration.storage_protocol.lower()
self.active_backend_id = kwargs.get('active_backend_id', None)
self.adapter = None
self._stats = {}
def do_setup(self, context):
if self.protocol == common.PROTOCOL_FC:
@ -331,3 +332,49 @@ class VNXDriver(driver.TransferVD,
def failover_host(self, context, volumes, secondary_id=None):
"""Fail-overs volumes from primary device to secondary."""
return self.adapter.failover_host(context, volumes, secondary_id)
@utils.require_consistent_group_snapshot_enabled
def create_group(self, context, group):
"""Creates a group."""
return self.adapter.create_group(context, group)
@utils.require_consistent_group_snapshot_enabled
def delete_group(self, context, group, volumes):
"""Deletes a group."""
return self.adapter.delete_group(
context, group, volumes)
@utils.require_consistent_group_snapshot_enabled
def update_group(self, context, group,
add_volumes=None, remove_volumes=None):
"""Updates a group."""
return self.adapter.update_group(context, group,
add_volumes,
remove_volumes)
@utils.require_consistent_group_snapshot_enabled
def create_group_from_src(self, context, group, volumes,
group_snapshot=None, snapshots=None,
source_group=None, source_vols=None):
"""Creates a group from source."""
if group_snapshot:
return self.adapter.create_group_from_group_snapshot(
context, group, volumes, group_snapshot, snapshots)
elif source_group:
return self.adapter.create_cloned_group(
context, group, volumes, source_group, source_vols)
@utils.require_consistent_group_snapshot_enabled
def create_group_snapshot(self, context, group_snapshot, snapshots):
"""Creates a group_snapshot."""
return self.adapter.create_group_snapshot(
context, group_snapshot, snapshots)
@utils.require_consistent_group_snapshot_enabled
def delete_group_snapshot(self, context, group_snapshot, snapshots):
"""Deletes a group_snapshot."""
return self.adapter.delete_group_snapshot(
context, group_snapshot, snapshots)
def is_consistent_group_snapshot_enabled(self):
return self._stats.get('consistent_group_snapshot_enabled')

View File

@ -246,9 +246,9 @@ def get_migration_rate(volume):
def validate_cg_type(group):
if group.get('volume_type_id') is None:
if not group.get('volume_type_ids'):
return
for type_id in group['volume_type_id'].split(","):
for type_id in group.get('volume_type_ids'):
if type_id:
specs = volume_types.get_volume_type_extra_specs(type_id)
extra_specs = common.ExtraSpecs(specs)
@ -337,3 +337,12 @@ def truncate_fc_port_wwn(wwn):
def is_volume_smp(volume):
return 'smp' == extract_provider_location(volume.provider_location, 'type')
def require_consistent_group_snapshot_enabled(func):
@six.wraps(func)
def inner(self, *args, **kwargs):
if not self.is_consistent_group_snapshot_enabled():
raise NotImplementedError
return func(self, *args, **kwargs)
return inner

View File

@ -0,0 +1,3 @@
---
features:
- Add consistent group capability to generic volume groups in VNX driver.