Merge "Add CG capability to generic groups in VNX driver"
This commit is contained in:
commit
de813e7a74
@ -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