Add CG capability to generic groups in VNX driver

This patch adds the consistency group capability to generic group in
VNX driver. Consistency groups will be used as generic groups.

DocImpact:
Implements: blueprint vnx-generic-group
Change-Id: I92ad0032e5b4e0f72157febe64205a4d72a561e5
This commit is contained in:
Tina Tang 2016-11-14 16:40:26 +08:00 committed by Tina
parent 6a1af6c168
commit 6359dcecd5
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.