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:
parent
6a1af6c168
commit
6359dcecd5
@ -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']
|
||||
|
||||
|
||||
###########################################################
|
||||
|
@ -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
|
||||
|
@ -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])
|
||||
|
@ -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())
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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')
|
||||
|
@ -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
|
||||
|
@ -0,0 +1,3 @@
|
||||
---
|
||||
features:
|
||||
- Add consistent group capability to generic volume groups in VNX driver.
|
Loading…
Reference in New Issue
Block a user