EMC VNX Direct Driver Consistency Group support
Consistency Group support is newly introduced in Juno. This commit is to add the changes in EMC VNX Direct Driver to support CG. Implements: blueprint emc-vnx-direct-driver-cg-support Change-Id: I6c30ef2609ca8a559f5635129ce6a7c960a9f0a7
This commit is contained in:
parent
5d2cc2f7f0
commit
3742e51312
@ -46,6 +46,35 @@ class EMCVNXCLIDriverTestData():
|
|||||||
'display_name': 'vol1',
|
'display_name': 'vol1',
|
||||||
'display_description': 'test volume',
|
'display_description': 'test volume',
|
||||||
'volume_type_id': None,
|
'volume_type_id': None,
|
||||||
|
'consistencygroup_id': None,
|
||||||
|
'volume_admin_metadata': [{'key': 'readonly', 'value': 'True'}]
|
||||||
|
}
|
||||||
|
|
||||||
|
test_volume_clone_cg = {
|
||||||
|
'name': 'vol1',
|
||||||
|
'size': 1,
|
||||||
|
'volume_name': 'vol1',
|
||||||
|
'id': '1',
|
||||||
|
'provider_auth': None,
|
||||||
|
'project_id': 'project',
|
||||||
|
'display_name': 'vol1',
|
||||||
|
'display_description': 'test volume',
|
||||||
|
'volume_type_id': None,
|
||||||
|
'consistencygroup_id': None,
|
||||||
|
'volume_admin_metadata': [{'key': 'readonly', 'value': 'True'}]
|
||||||
|
}
|
||||||
|
|
||||||
|
test_volume_cg = {
|
||||||
|
'name': 'vol1',
|
||||||
|
'size': 1,
|
||||||
|
'volume_name': 'vol1',
|
||||||
|
'id': '1',
|
||||||
|
'provider_auth': None,
|
||||||
|
'project_id': 'project',
|
||||||
|
'display_name': 'vol1',
|
||||||
|
'display_description': 'test volume',
|
||||||
|
'volume_type_id': None,
|
||||||
|
'consistencygroup_id': 'cg_id',
|
||||||
'volume_admin_metadata': [{'key': 'readonly', 'value': 'True'}]
|
'volume_admin_metadata': [{'key': 'readonly', 'value': 'True'}]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +88,8 @@ class EMCVNXCLIDriverTestData():
|
|||||||
'display_name': 'vol1',
|
'display_name': 'vol1',
|
||||||
'display_description': 'test volume',
|
'display_description': 'test volume',
|
||||||
'volume_type_id': None,
|
'volume_type_id': None,
|
||||||
'volume_admin_metadata': [{'key': 'access_mode', 'value': 'rw'},
|
'consistencygroup_id': None,
|
||||||
|
'volume_admin_metadata': [{'key': 'attached_mode', 'value': 'rw'},
|
||||||
{'key': 'readonly', 'value': 'False'}]
|
{'key': 'readonly', 'value': 'False'}]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,6 +101,19 @@ class EMCVNXCLIDriverTestData():
|
|||||||
'provider_auth': None,
|
'provider_auth': None,
|
||||||
'project_id': 'project',
|
'project_id': 'project',
|
||||||
'display_name': 'vol2',
|
'display_name': 'vol2',
|
||||||
|
'consistencygroup_id': None,
|
||||||
|
'display_description': 'test volume',
|
||||||
|
'volume_type_id': None}
|
||||||
|
|
||||||
|
volume_in_cg = {
|
||||||
|
'name': 'vol2',
|
||||||
|
'size': 1,
|
||||||
|
'volume_name': 'vol2',
|
||||||
|
'id': '1',
|
||||||
|
'provider_auth': None,
|
||||||
|
'project_id': 'project',
|
||||||
|
'display_name': 'vol2',
|
||||||
|
'consistencygroup_id': None,
|
||||||
'display_description': 'test volume',
|
'display_description': 'test volume',
|
||||||
'volume_type_id': None}
|
'volume_type_id': None}
|
||||||
|
|
||||||
@ -82,6 +125,7 @@ class EMCVNXCLIDriverTestData():
|
|||||||
'provider_auth': None,
|
'provider_auth': None,
|
||||||
'project_id': 'project',
|
'project_id': 'project',
|
||||||
'display_name': 'thin_vol',
|
'display_name': 'thin_vol',
|
||||||
|
'consistencygroup_id': None,
|
||||||
'display_description': 'vol with type',
|
'display_description': 'vol with type',
|
||||||
'volume_type_id': 'abc1-2320-9013-8813-8941-1374-8112-1231'}
|
'volume_type_id': 'abc1-2320-9013-8813-8941-1374-8112-1231'}
|
||||||
|
|
||||||
@ -93,6 +137,7 @@ class EMCVNXCLIDriverTestData():
|
|||||||
'provider_auth': None,
|
'provider_auth': None,
|
||||||
'project_id': 'project',
|
'project_id': 'project',
|
||||||
'display_name': 'failed_vol',
|
'display_name': 'failed_vol',
|
||||||
|
'consistencygroup_id': None,
|
||||||
'display_description': 'test failed volume',
|
'display_description': 'test failed volume',
|
||||||
'volume_type_id': None}
|
'volume_type_id': None}
|
||||||
test_snapshot = {
|
test_snapshot = {
|
||||||
@ -101,6 +146,8 @@ class EMCVNXCLIDriverTestData():
|
|||||||
'id': '4444',
|
'id': '4444',
|
||||||
'volume_name': 'vol1',
|
'volume_name': 'vol1',
|
||||||
'volume_size': 1,
|
'volume_size': 1,
|
||||||
|
'consistencygroup_id': None,
|
||||||
|
'cgsnapshot_id': None,
|
||||||
'project_id': 'project'}
|
'project_id': 'project'}
|
||||||
test_failed_snapshot = {
|
test_failed_snapshot = {
|
||||||
'name': 'failed_snapshot',
|
'name': 'failed_snapshot',
|
||||||
@ -117,6 +164,18 @@ class EMCVNXCLIDriverTestData():
|
|||||||
'provider_auth': None,
|
'provider_auth': None,
|
||||||
'project_id': 'project',
|
'project_id': 'project',
|
||||||
'display_name': 'clone1',
|
'display_name': 'clone1',
|
||||||
|
'consistencygroup_id': None,
|
||||||
|
'display_description': 'volume created from snapshot',
|
||||||
|
'volume_type_id': None}
|
||||||
|
test_clone_cg = {
|
||||||
|
'name': 'clone1',
|
||||||
|
'size': 1,
|
||||||
|
'id': '2',
|
||||||
|
'volume_name': 'vol1',
|
||||||
|
'provider_auth': None,
|
||||||
|
'project_id': 'project',
|
||||||
|
'display_name': 'clone1',
|
||||||
|
'consistencygroup_id': 'consistencygroup_id',
|
||||||
'display_description': 'volume created from snapshot',
|
'display_description': 'volume created from snapshot',
|
||||||
'volume_type_id': None}
|
'volume_type_id': None}
|
||||||
connector = {
|
connector = {
|
||||||
@ -206,6 +265,26 @@ class EMCVNXCLIDriverTestData():
|
|||||||
'volume_backend_name': 'array_backend_1',
|
'volume_backend_name': 'array_backend_1',
|
||||||
'storage_protocol': 'iSCSI'}}
|
'storage_protocol': 'iSCSI'}}
|
||||||
|
|
||||||
|
test_cg = {'id': 'consistencygroup_id',
|
||||||
|
'name': 'group_name',
|
||||||
|
'status': 'deleting'}
|
||||||
|
|
||||||
|
test_cgsnapshot = {
|
||||||
|
'consistencygroup_id': 'consistencygroup_id',
|
||||||
|
'id': 'cgsnapshot_id',
|
||||||
|
'status': 'available'}
|
||||||
|
|
||||||
|
test_member_cgsnapshot = {
|
||||||
|
'name': 'snapshot1',
|
||||||
|
'size': 1,
|
||||||
|
'id': 'cgsnapshot_id',
|
||||||
|
'volume_name': 'vol1',
|
||||||
|
'volume_size': 1,
|
||||||
|
'consistencygroup_id': 'consistencygroup_id',
|
||||||
|
'cgsnapshot_id': 'cgsnapshot_id',
|
||||||
|
'project_id': 'project'
|
||||||
|
}
|
||||||
|
|
||||||
test_lun_id = 1
|
test_lun_id = 1
|
||||||
test_existing_ref = {'id': test_lun_id}
|
test_existing_ref = {'id': test_lun_id}
|
||||||
test_pool_name = 'Pool_02_SASFLASH'
|
test_pool_name = 'Pool_02_SASFLASH'
|
||||||
@ -324,6 +403,53 @@ class EMCVNXCLIDriverTestData():
|
|||||||
return ('-np', 'storagepool', '-list', '-name',
|
return ('-np', 'storagepool', '-list', '-name',
|
||||||
storage_pool, '-fastcache')
|
storage_pool, '-fastcache')
|
||||||
|
|
||||||
|
def CREATE_CONSISTENCYGROUP_CMD(self, cg_name):
|
||||||
|
return ('-np', 'snap', '-group', '-create',
|
||||||
|
'-name', cg_name, '-allowSnapAutoDelete', 'no')
|
||||||
|
|
||||||
|
def DELETE_CONSISTENCYGROUP_CMD(self, cg_name):
|
||||||
|
return ('-np', 'snap', '-group', '-destroy',
|
||||||
|
'-id', cg_name)
|
||||||
|
|
||||||
|
def GET_CONSISTENCYGROUP_BY_NAME(self, cg_name):
|
||||||
|
return ('snap', '-group', '-list', '-id', cg_name)
|
||||||
|
|
||||||
|
def ADD_LUN_TO_CG_CMD(self, cg_name, lun_id):
|
||||||
|
return ('-np', 'snap', '-group',
|
||||||
|
'-addmember', '-id', cg_name, '-res', lun_id)
|
||||||
|
|
||||||
|
def CREATE_CG_SNAPSHOT(self, cg_name, snap_name):
|
||||||
|
return ('-np', 'snap', '-create', '-res', cg_name,
|
||||||
|
'-resType', 'CG', '-name', snap_name, '-allowReadWrite',
|
||||||
|
'yes', '-allowAutoDelete', 'no')
|
||||||
|
|
||||||
|
def DELETE_CG_SNAPSHOT(self, snap_name):
|
||||||
|
return ('-np', 'snap', '-destroy', '-id', snap_name, '-o')
|
||||||
|
|
||||||
|
def GET_CG_BY_NAME_CMD(self, cg_name):
|
||||||
|
return ('snap', '-group', '-list', '-id', cg_name)
|
||||||
|
|
||||||
|
def CONSISTENCY_GROUP_VOLUMES(self):
|
||||||
|
volumes = []
|
||||||
|
volumes.append(self.test_volume)
|
||||||
|
volumes.append(self.test_volume)
|
||||||
|
return volumes
|
||||||
|
|
||||||
|
def SNAPS_IN_SNAP_GROUP(self):
|
||||||
|
snaps = []
|
||||||
|
snaps.append(self.test_snapshot)
|
||||||
|
snaps.append(self.test_snapshot)
|
||||||
|
return snaps
|
||||||
|
|
||||||
|
def CG_PROPERTY(self, cg_name):
|
||||||
|
return """
|
||||||
|
Name: %(cg_name)s
|
||||||
|
Description:
|
||||||
|
Allow auto delete: No
|
||||||
|
Member LUN ID(s): 1, 3
|
||||||
|
State: Ready
|
||||||
|
""" % {'cg_name': cg_name}
|
||||||
|
|
||||||
POOL_PROPERTY = ("""\
|
POOL_PROPERTY = ("""\
|
||||||
Pool Name: unit_test_pool
|
Pool Name: unit_test_pool
|
||||||
Pool ID: 1
|
Pool ID: 1
|
||||||
@ -851,7 +977,7 @@ class EMCVNXCLIDriverISCSITestCase(test.TestCase):
|
|||||||
"volume backend name is not correct")
|
"volume backend name is not correct")
|
||||||
self.assertTrue(stats['location_info'] == "unit_test_pool|fakeSerial")
|
self.assertTrue(stats['location_info'] == "unit_test_pool|fakeSerial")
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
stats['driver_version'] == "04.00.00",
|
stats['driver_version'] == "04.01.00",
|
||||||
"driver version is incorrect.")
|
"driver version is incorrect.")
|
||||||
|
|
||||||
@mock.patch("cinder.volume.drivers.emc.emc_vnx_cli."
|
@mock.patch("cinder.volume.drivers.emc.emc_vnx_cli."
|
||||||
@ -2028,6 +2154,185 @@ Time Remaining: 0 second(s)
|
|||||||
'volume_admin_metadata': [{'key': 'readonly', 'value': 'True'}]}
|
'volume_admin_metadata': [{'key': 'readonly', 'value': 'True'}]}
|
||||||
self.assertEqual(self.driver.cli.get_lun_id(volume_02), 2)
|
self.assertEqual(self.driver.cli.get_lun_id(volume_02), 2)
|
||||||
|
|
||||||
|
def test_create_consistency_group(self):
|
||||||
|
cg_name = self.testData.test_cg['id']
|
||||||
|
commands = [self.testData.CREATE_CONSISTENCYGROUP_CMD(cg_name)]
|
||||||
|
results = [SUCCEED]
|
||||||
|
fake_cli = self.driverSetup(commands, results)
|
||||||
|
|
||||||
|
model_update = self.driver.create_consistencygroup(
|
||||||
|
None, self.testData.test_cg)
|
||||||
|
self.assertDictMatch({'status': 'available'}, model_update)
|
||||||
|
expect_cmd = [
|
||||||
|
mock.call(
|
||||||
|
*self.testData.CREATE_CONSISTENCYGROUP_CMD(
|
||||||
|
cg_name))]
|
||||||
|
fake_cli.assert_has_calls(expect_cmd)
|
||||||
|
|
||||||
|
def test_delete_consistency_group(self):
|
||||||
|
cg_name = self.testData.test_cg['id']
|
||||||
|
commands = [self.testData.DELETE_CONSISTENCYGROUP_CMD(cg_name),
|
||||||
|
self.testData.LUN_DELETE_CMD('vol1')]
|
||||||
|
results = [SUCCEED, SUCCEED]
|
||||||
|
fake_cli = self.driverSetup(commands, results)
|
||||||
|
self.driver.db = mock.MagicMock()
|
||||||
|
self.driver.db.volume_get_all_by_group.return_value =\
|
||||||
|
self.testData.CONSISTENCY_GROUP_VOLUMES()
|
||||||
|
self.driver.delete_consistencygroup(None,
|
||||||
|
self.testData.test_cg)
|
||||||
|
expect_cmd = [
|
||||||
|
mock.call(
|
||||||
|
*self.testData.DELETE_CONSISTENCYGROUP_CMD(
|
||||||
|
cg_name)),
|
||||||
|
mock.call(
|
||||||
|
*self.testData.LUN_DELETE_CMD('vol1')),
|
||||||
|
mock.call(
|
||||||
|
*self.testData.LUN_DELETE_CMD('vol1'))]
|
||||||
|
fake_cli.assert_has_calls(expect_cmd)
|
||||||
|
|
||||||
|
def test_create_cgsnapshot(self):
|
||||||
|
cgsnapshot = self.testData.test_cgsnapshot['id']
|
||||||
|
cg_name = self.testData.test_cgsnapshot['consistencygroup_id']
|
||||||
|
commands = [self.testData.CREATE_CG_SNAPSHOT(cg_name, cgsnapshot)]
|
||||||
|
results = [SUCCEED]
|
||||||
|
fake_cli = self.driverSetup(commands, results)
|
||||||
|
self.driver.db = mock.MagicMock()
|
||||||
|
self.driver.db.volume_get_all_by_group.return_value =\
|
||||||
|
self.testData.SNAPS_IN_SNAP_GROUP()
|
||||||
|
self.driver.create_cgsnapshot(None, self.testData.test_cgsnapshot)
|
||||||
|
expect_cmd = [
|
||||||
|
mock.call(
|
||||||
|
*self.testData.CREATE_CG_SNAPSHOT(
|
||||||
|
cg_name, cgsnapshot))]
|
||||||
|
fake_cli.assert_has_calls(expect_cmd)
|
||||||
|
|
||||||
|
def test_delete_cgsnapshot(self):
|
||||||
|
snap_name = self.testData.test_cgsnapshot['id']
|
||||||
|
commands = [self.testData.DELETE_CG_SNAPSHOT(snap_name)]
|
||||||
|
results = [SUCCEED]
|
||||||
|
fake_cli = self.driverSetup(commands, results)
|
||||||
|
self.driver.db = mock.MagicMock()
|
||||||
|
self.driver.db.snapshot_get_all_for_cgsnapshot.return_value =\
|
||||||
|
self.testData.SNAPS_IN_SNAP_GROUP()
|
||||||
|
self.driver.delete_cgsnapshot(None,
|
||||||
|
self.testData.test_cgsnapshot)
|
||||||
|
expect_cmd = [
|
||||||
|
mock.call(
|
||||||
|
*self.testData.DELETE_CG_SNAPSHOT(
|
||||||
|
snap_name))]
|
||||||
|
fake_cli.assert_has_calls(expect_cmd)
|
||||||
|
|
||||||
|
@mock.patch(
|
||||||
|
"eventlet.event.Event.wait",
|
||||||
|
mock.Mock(return_value=None))
|
||||||
|
def test_add_volume_to_cg(self):
|
||||||
|
commands = [self.testData.LUN_PROPERTY_ALL_CMD('vol1'),
|
||||||
|
self.testData.ADD_LUN_TO_CG_CMD('cg_id', 1),
|
||||||
|
self.testData.GET_CG_BY_NAME_CMD('cg_id')
|
||||||
|
]
|
||||||
|
results = [self.testData.LUN_PROPERTY('vol1', True),
|
||||||
|
SUCCEED,
|
||||||
|
self.testData.CG_PROPERTY('cg_id')]
|
||||||
|
fake_cli = self.driverSetup(commands, results)
|
||||||
|
|
||||||
|
self.driver.create_volume(self.testData.test_volume_cg)
|
||||||
|
|
||||||
|
expect_cmd = [
|
||||||
|
mock.call(*self.testData.LUN_CREATION_CMD(
|
||||||
|
'vol1', 1,
|
||||||
|
'unit_test_pool',
|
||||||
|
None, None)),
|
||||||
|
mock.call('lun', '-list', '-name', 'vol1',
|
||||||
|
'-state', '-status', '-opDetails',
|
||||||
|
'-userCap', '-owner', '-attachedSnapshot'),
|
||||||
|
mock.call(*self.testData.ADD_LUN_TO_CG_CMD(
|
||||||
|
'cg_id', 1))]
|
||||||
|
fake_cli.assert_has_calls(expect_cmd)
|
||||||
|
|
||||||
|
def test_create_cloned_volume_from_consistnecy_group(self):
|
||||||
|
cmd_smp = ('lun', '-list', '-name', 'vol1', '-attachedSnapshot')
|
||||||
|
output_smp = ("""LOGICAL UNIT NUMBER 1
|
||||||
|
Name: vol1
|
||||||
|
Attached Snapshot: N/A""", 0)
|
||||||
|
cmd_dest = self.testData.LUN_PROPERTY_ALL_CMD("vol1_dest")
|
||||||
|
output_dest = self.testData.LUN_PROPERTY("vol1_dest")
|
||||||
|
cmd_migrate = self.testData.MIGRATION_CMD(1, 1)
|
||||||
|
output_migrate = ("", 0)
|
||||||
|
cmd_migrate_verify = self.testData.MIGRATION_VERIFY_CMD(1)
|
||||||
|
output_migrate_verify = (r'The specified source LUN '
|
||||||
|
'is not currently migrating', 23)
|
||||||
|
cg_name = self.testData.test_cgsnapshot['consistencygroup_id']
|
||||||
|
|
||||||
|
commands = [cmd_smp, cmd_dest, cmd_migrate,
|
||||||
|
cmd_migrate_verify]
|
||||||
|
results = [output_smp, output_dest, output_migrate,
|
||||||
|
output_migrate_verify]
|
||||||
|
fake_cli = self.driverSetup(commands, results)
|
||||||
|
|
||||||
|
self.driver.create_cloned_volume(self.testData.test_volume_clone_cg,
|
||||||
|
self.testData.test_clone_cg)
|
||||||
|
tmp_cgsnapshot = 'tmp-cgsnapshot-' + self.testData.test_volume['id']
|
||||||
|
expect_cmd = [
|
||||||
|
mock.call(
|
||||||
|
*self.testData.CREATE_CG_SNAPSHOT(cg_name, tmp_cgsnapshot)),
|
||||||
|
mock.call(*self.testData.SNAP_MP_CREATE_CMD(name='vol1',
|
||||||
|
source='clone1')),
|
||||||
|
mock.call(
|
||||||
|
*self.testData.SNAP_ATTACH_CMD(
|
||||||
|
name='vol1', snapName=tmp_cgsnapshot)),
|
||||||
|
mock.call(*self.testData.LUN_CREATION_CMD(
|
||||||
|
'vol1_dest', 1, 'unit_test_pool', None, None)),
|
||||||
|
mock.call(*self.testData.LUN_PROPERTY_ALL_CMD('vol1_dest')),
|
||||||
|
mock.call(*self.testData.LUN_PROPERTY_ALL_CMD('vol1_dest')),
|
||||||
|
mock.call(*self.testData.LUN_PROPERTY_ALL_CMD('vol1')),
|
||||||
|
mock.call(*self.testData.LUN_PROPERTY_ALL_CMD('vol1_dest')),
|
||||||
|
mock.call(*self.testData.MIGRATION_CMD(1, 1),
|
||||||
|
retry_disable=True),
|
||||||
|
mock.call(*self.testData.MIGRATION_VERIFY_CMD(1)),
|
||||||
|
mock.call('lun', '-list', '-name', 'vol1', '-attachedSnapshot'),
|
||||||
|
mock.call(*self.testData.LUN_PROPERTY_ALL_CMD('vol1')),
|
||||||
|
mock.call(*self.testData.DELETE_CG_SNAPSHOT(tmp_cgsnapshot))]
|
||||||
|
fake_cli.assert_has_calls(expect_cmd)
|
||||||
|
|
||||||
|
def test_create_volume_from_cgsnapshot(self):
|
||||||
|
cmd_smp = ('lun', '-list', '-name', 'vol2', '-attachedSnapshot')
|
||||||
|
output_smp = ("""LOGICAL UNIT NUMBER 1
|
||||||
|
Name: vol2
|
||||||
|
Attached Snapshot: N/A""", 0)
|
||||||
|
cmd_dest = self.testData.LUN_PROPERTY_ALL_CMD("vol2_dest")
|
||||||
|
output_dest = self.testData.LUN_PROPERTY("vol2_dest")
|
||||||
|
cmd_migrate = self.testData.MIGRATION_CMD(1, 1)
|
||||||
|
output_migrate = ("", 0)
|
||||||
|
cmd_migrate_verify = self.testData.MIGRATION_VERIFY_CMD(1)
|
||||||
|
output_migrate_verify = (r'The specified source LUN '
|
||||||
|
'is not currently migrating', 23)
|
||||||
|
commands = [cmd_smp, cmd_dest, cmd_migrate, cmd_migrate_verify]
|
||||||
|
results = [output_smp, output_dest, output_migrate,
|
||||||
|
output_migrate_verify]
|
||||||
|
fake_cli = self.driverSetup(commands, results)
|
||||||
|
|
||||||
|
self.driver.create_volume_from_snapshot(
|
||||||
|
self.testData.volume_in_cg, self.testData.test_member_cgsnapshot)
|
||||||
|
expect_cmd = [
|
||||||
|
mock.call(
|
||||||
|
*self.testData.SNAP_MP_CREATE_CMD(
|
||||||
|
name='vol2', source='vol1')),
|
||||||
|
mock.call(
|
||||||
|
*self.testData.SNAP_ATTACH_CMD(
|
||||||
|
name='vol2', snapName='cgsnapshot_id')),
|
||||||
|
mock.call(*self.testData.LUN_CREATION_CMD(
|
||||||
|
'vol2_dest', 1, 'unit_test_pool', None, None)),
|
||||||
|
mock.call(*self.testData.LUN_PROPERTY_ALL_CMD('vol2_dest')),
|
||||||
|
mock.call(*self.testData.LUN_PROPERTY_ALL_CMD('vol2_dest')),
|
||||||
|
mock.call(*self.testData.LUN_PROPERTY_ALL_CMD('vol2')),
|
||||||
|
mock.call(*self.testData.LUN_PROPERTY_ALL_CMD('vol2_dest')),
|
||||||
|
mock.call(*self.testData.MIGRATION_CMD(1, 1),
|
||||||
|
retry_disable=True),
|
||||||
|
mock.call(*self.testData.MIGRATION_VERIFY_CMD(1)),
|
||||||
|
mock.call('lun', '-list', '-name', 'vol2', '-attachedSnapshot'),
|
||||||
|
mock.call(*self.testData.LUN_PROPERTY_ALL_CMD('vol2'))]
|
||||||
|
fake_cli.assert_has_calls(expect_cmd)
|
||||||
|
|
||||||
def succeed_fake_command_execute(self, *command, **kwargv):
|
def succeed_fake_command_execute(self, *command, **kwargv):
|
||||||
return SUCCEED
|
return SUCCEED
|
||||||
|
|
||||||
@ -2394,7 +2699,7 @@ class EMCVNXCLIDriverFCTestCase(test.TestCase):
|
|||||||
"volume backend name is not correct")
|
"volume backend name is not correct")
|
||||||
self.assertTrue(stats['location_info'] == "unit_test_pool|fakeSerial")
|
self.assertTrue(stats['location_info'] == "unit_test_pool|fakeSerial")
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
stats['driver_version'] == "04.00.00",
|
stats['driver_version'] == "04.01.00",
|
||||||
"driver version is incorrect.")
|
"driver version is incorrect.")
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,6 +46,7 @@ class EMCCLIFCDriver(driver.FibreChannelDriver):
|
|||||||
FAST Cache Support), Storage-assisted Retype,
|
FAST Cache Support), Storage-assisted Retype,
|
||||||
External Volume Management, Read-only Volume,
|
External Volume Management, Read-only Volume,
|
||||||
FC Auto Zoning
|
FC Auto Zoning
|
||||||
|
4.1.0 - Consistency group support
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@ -217,3 +218,21 @@ class EMCCLIFCDriver(driver.FibreChannelDriver):
|
|||||||
"""Return size of volume to be managed by manage_existing.
|
"""Return size of volume to be managed by manage_existing.
|
||||||
"""
|
"""
|
||||||
return self.cli.manage_existing_get_size(volume, existing_ref)
|
return self.cli.manage_existing_get_size(volume, existing_ref)
|
||||||
|
|
||||||
|
def create_consistencygroup(self, context, group):
|
||||||
|
"""Creates a consistencygroup."""
|
||||||
|
return self.cli.create_consistencygroup(context, group)
|
||||||
|
|
||||||
|
def delete_consistencygroup(self, context, group):
|
||||||
|
"""Deletes a consistency group."""
|
||||||
|
return self.cli.delete_consistencygroup(
|
||||||
|
self, context, group)
|
||||||
|
|
||||||
|
def create_cgsnapshot(self, context, cgsnapshot):
|
||||||
|
"""Creates a cgsnapshot."""
|
||||||
|
return self.cli.create_cgsnapshot(
|
||||||
|
self, context, cgsnapshot)
|
||||||
|
|
||||||
|
def delete_cgsnapshot(self, context, cgsnapshot):
|
||||||
|
"""Deletes a cgsnapshot."""
|
||||||
|
return self.cli.delete_cgsnapshot(self, context, cgsnapshot)
|
@ -43,6 +43,7 @@ class EMCCLIISCSIDriver(driver.ISCSIDriver):
|
|||||||
FAST Cache Support), Storage-assisted Retype,
|
FAST Cache Support), Storage-assisted Retype,
|
||||||
External Volume Management, Read-only Volume,
|
External Volume Management, Read-only Volume,
|
||||||
FC Auto Zoning
|
FC Auto Zoning
|
||||||
|
4.1.0 - Consistency group support
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@ -174,3 +175,21 @@ class EMCCLIISCSIDriver(driver.ISCSIDriver):
|
|||||||
"""Return size of volume to be managed by manage_existing.
|
"""Return size of volume to be managed by manage_existing.
|
||||||
"""
|
"""
|
||||||
return self.cli.manage_existing_get_size(volume, existing_ref)
|
return self.cli.manage_existing_get_size(volume, existing_ref)
|
||||||
|
|
||||||
|
def create_consistencygroup(self, context, group):
|
||||||
|
"""Creates a consistencygroup."""
|
||||||
|
return self.cli.create_consistencygroup(context, group)
|
||||||
|
|
||||||
|
def delete_consistencygroup(self, context, group):
|
||||||
|
"""Deletes a consistency group."""
|
||||||
|
return self.cli.delete_consistencygroup(
|
||||||
|
self, context, group)
|
||||||
|
|
||||||
|
def create_cgsnapshot(self, context, cgsnapshot):
|
||||||
|
"""Creates a cgsnapshot."""
|
||||||
|
return self.cli.create_cgsnapshot(
|
||||||
|
self, context, cgsnapshot)
|
||||||
|
|
||||||
|
def delete_cgsnapshot(self, context, cgsnapshot):
|
||||||
|
"""Deletes a cgsnapshot."""
|
||||||
|
return self.cli.delete_cgsnapshot(self, context, cgsnapshot)
|
@ -22,6 +22,7 @@ import re
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
from oslo.config import cfg
|
from oslo.config import cfg
|
||||||
|
import six
|
||||||
|
|
||||||
from cinder import exception
|
from cinder import exception
|
||||||
from cinder.exception import EMCVnxCLICmdError
|
from cinder.exception import EMCVnxCLICmdError
|
||||||
@ -187,6 +188,9 @@ class CommandLineHelper(object):
|
|||||||
|
|
||||||
POOL_ALL = [POOL_TOTAL_CAPACITY, POOL_FREE_CAPACITY]
|
POOL_ALL = [POOL_TOTAL_CAPACITY, POOL_FREE_CAPACITY]
|
||||||
|
|
||||||
|
CLI_RESP_PATTERN_CG_NOT_FOUND = 'Cannot find'
|
||||||
|
CLI_RESP_PATTERN_SNAP_NOT_FOUND = 'The specified snapshot does not exist'
|
||||||
|
|
||||||
def __init__(self, configuration):
|
def __init__(self, configuration):
|
||||||
configuration.append_config_values(san.san_opts)
|
configuration.append_config_values(san.san_opts)
|
||||||
|
|
||||||
@ -281,7 +285,8 @@ class CommandLineHelper(object):
|
|||||||
|
|
||||||
@log_enter_exit
|
@log_enter_exit
|
||||||
def create_lun_with_advance_feature(self, pool, name, size,
|
def create_lun_with_advance_feature(self, pool, name, size,
|
||||||
provisioning, tiering):
|
provisioning, tiering,
|
||||||
|
consistencygroup_id=None):
|
||||||
command_create_lun = ['lun', '-create',
|
command_create_lun = ['lun', '-create',
|
||||||
'-capacity', size,
|
'-capacity', size,
|
||||||
'-sq', 'gb',
|
'-sq', 'gb',
|
||||||
@ -305,7 +310,19 @@ class CommandLineHelper(object):
|
|||||||
except EMCVnxCLICmdError as ex:
|
except EMCVnxCLICmdError as ex:
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
self.delete_lun(name)
|
self.delete_lun(name)
|
||||||
LOG.error(_("Failed to enable compression on lun: %s") % ex)
|
LOG.error(_("Error on enable compression on lun %s.")
|
||||||
|
% six.text_type(ex))
|
||||||
|
|
||||||
|
# handle consistency group
|
||||||
|
try:
|
||||||
|
if consistencygroup_id:
|
||||||
|
self.add_lun_to_consistency_group(
|
||||||
|
consistencygroup_id, data['lun_id'])
|
||||||
|
except EMCVnxCLICmdError as ex:
|
||||||
|
with excutils.save_and_reraise_exception():
|
||||||
|
self.delete_lun(name)
|
||||||
|
LOG.error(_("Error on adding lun to consistency"
|
||||||
|
" group. %s") % six.text_type(ex))
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@log_enter_exit
|
@log_enter_exit
|
||||||
@ -432,6 +449,143 @@ class CommandLineHelper(object):
|
|||||||
if rc != 0:
|
if rc != 0:
|
||||||
raise EMCVnxCLICmdError(command_modify_lun, rc, out)
|
raise EMCVnxCLICmdError(command_modify_lun, rc, out)
|
||||||
|
|
||||||
|
@log_enter_exit
|
||||||
|
def create_consistencygroup(self, context, group):
|
||||||
|
"""create the consistency group."""
|
||||||
|
cg_name = group['id']
|
||||||
|
command_create_cg = ('-np', 'snap', '-group',
|
||||||
|
'-create',
|
||||||
|
'-name', cg_name,
|
||||||
|
'-allowSnapAutoDelete', 'no')
|
||||||
|
|
||||||
|
out, rc = self.command_execute(*command_create_cg)
|
||||||
|
if rc != 0:
|
||||||
|
# Ignore the error if consistency group already exists
|
||||||
|
if (rc == 33 and
|
||||||
|
out.find("(0x716d8021)") >= 0):
|
||||||
|
LOG.warn(_('Consistency group %(name)s already '
|
||||||
|
'exists. Message: %(msg)s') %
|
||||||
|
{'name': cg_name, 'msg': out})
|
||||||
|
else:
|
||||||
|
raise EMCVnxCLICmdError(command_create_cg, rc, out)
|
||||||
|
|
||||||
|
@log_enter_exit
|
||||||
|
def get_consistency_group_by_name(self, cg_name):
|
||||||
|
cmd = ('snap', '-group', '-list', '-id', cg_name)
|
||||||
|
data = {
|
||||||
|
'Name': None,
|
||||||
|
'Luns': None,
|
||||||
|
'State': None
|
||||||
|
}
|
||||||
|
out, rc = self.command_execute(*cmd)
|
||||||
|
if rc == 0:
|
||||||
|
cg_pat = r"Name:(.*)\n"\
|
||||||
|
r"Description:(.*)\n"\
|
||||||
|
r"Allow auto delete:(.*)\n"\
|
||||||
|
r"Member LUN ID\(s\):(.*)\n"\
|
||||||
|
r"State:(.*)\n"
|
||||||
|
for m in re.finditer(cg_pat, out):
|
||||||
|
data['Name'] = m.groups()[0].strip()
|
||||||
|
data['State'] = m.groups()[4].strip()
|
||||||
|
luns_of_cg = m.groups()[3].split(',')
|
||||||
|
if luns_of_cg:
|
||||||
|
data['Luns'] = [lun.strip() for lun in luns_of_cg]
|
||||||
|
LOG.debug("Found consistent group %s." % data['Name'])
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
@log_enter_exit
|
||||||
|
def add_lun_to_consistency_group(self, cg_name, lun_id):
|
||||||
|
add_lun_to_cg_cmd = ('-np', 'snap', '-group',
|
||||||
|
'-addmember', '-id',
|
||||||
|
cg_name, '-res', lun_id)
|
||||||
|
|
||||||
|
out, rc = self.command_execute(*add_lun_to_cg_cmd)
|
||||||
|
if rc != 0:
|
||||||
|
msg = (_("Can not add the lun %(lun)s to consistency "
|
||||||
|
"group %(cg_name)s.") % {'lun': lun_id,
|
||||||
|
'cg_name': cg_name})
|
||||||
|
LOG.error(msg)
|
||||||
|
raise EMCVnxCLICmdError(add_lun_to_cg_cmd, rc, out)
|
||||||
|
|
||||||
|
def add_lun_to_consistency_success():
|
||||||
|
data = self.get_consistency_group_by_name(cg_name)
|
||||||
|
if str(lun_id) in data['Luns']:
|
||||||
|
LOG.debug(("Add lun %(lun)s to consistency "
|
||||||
|
"group %(cg_name)s successfully.") %
|
||||||
|
{'lun': lun_id, 'cg_name': cg_name})
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
LOG.debug(("Adding lun %(lun)s to consistency "
|
||||||
|
"group %(cg_name)s.") %
|
||||||
|
{'lun': lun_id, 'cg_name': cg_name})
|
||||||
|
return False
|
||||||
|
|
||||||
|
self._wait_for_a_condition(add_lun_to_consistency_success,
|
||||||
|
interval=INTERVAL_30_SEC)
|
||||||
|
|
||||||
|
@log_enter_exit
|
||||||
|
def delete_consistencygroup(self, cg_name):
|
||||||
|
delete_cg_cmd = ('-np', 'snap', '-group',
|
||||||
|
'-destroy', '-id', cg_name)
|
||||||
|
out, rc = self.command_execute(*delete_cg_cmd)
|
||||||
|
if rc != 0:
|
||||||
|
# Ignore the error if CG doesn't exist
|
||||||
|
if rc == 13 and out.find(self.CLI_RESP_PATTERN_CG_NOT_FOUND) >= 0:
|
||||||
|
LOG.warn(_("CG %(cg_name)s does not exist. "
|
||||||
|
"Message: %(msg)s") %
|
||||||
|
{'cg_name': cg_name, 'msg': out})
|
||||||
|
elif rc == 1 and out.find("0x712d8801") >= 0:
|
||||||
|
LOG.warn(_("CG %(cg_name)s is deleting. "
|
||||||
|
"Message: %(msg)s") %
|
||||||
|
{'cg_name': cg_name, 'msg': out})
|
||||||
|
else:
|
||||||
|
raise EMCVnxCLICmdError(delete_cg_cmd, rc, out)
|
||||||
|
else:
|
||||||
|
LOG.info(_('Consistency group %s was deleted '
|
||||||
|
'successfully.') % cg_name)
|
||||||
|
|
||||||
|
@log_enter_exit
|
||||||
|
def create_cgsnapshot(self, cgsnapshot):
|
||||||
|
"""Create a cgsnapshot (snap group)."""
|
||||||
|
cg_name = cgsnapshot['consistencygroup_id']
|
||||||
|
snap_name = cgsnapshot['id']
|
||||||
|
create_cg_snap_cmd = ('-np', 'snap', '-create',
|
||||||
|
'-res', cg_name,
|
||||||
|
'-resType', 'CG',
|
||||||
|
'-name', snap_name,
|
||||||
|
'-allowReadWrite', 'yes',
|
||||||
|
'-allowAutoDelete', 'no')
|
||||||
|
|
||||||
|
out, rc = self.command_execute(*create_cg_snap_cmd)
|
||||||
|
if rc != 0:
|
||||||
|
# Ignore the error if cgsnapshot already exists
|
||||||
|
if (rc == 5 and
|
||||||
|
out.find("(0x716d8005)") >= 0):
|
||||||
|
LOG.warn(_('Cgsnapshot name %(name)s already '
|
||||||
|
'exists. Message: %(msg)s') %
|
||||||
|
{'name': snap_name, 'msg': out})
|
||||||
|
else:
|
||||||
|
raise EMCVnxCLICmdError(create_cg_snap_cmd, rc, out)
|
||||||
|
|
||||||
|
@log_enter_exit
|
||||||
|
def delete_cgsnapshot(self, cgsnapshot):
|
||||||
|
"""Delete a cgsnapshot (snap group)."""
|
||||||
|
snap_name = cgsnapshot['id']
|
||||||
|
delete_cg_snap_cmd = ('-np', 'snap', '-destroy',
|
||||||
|
'-id', snap_name, '-o')
|
||||||
|
|
||||||
|
out, rc = self.command_execute(*delete_cg_snap_cmd)
|
||||||
|
if rc != 0:
|
||||||
|
# Ignore the error if cgsnapshot does not exist.
|
||||||
|
if (rc == 5 and
|
||||||
|
out.find(self.CLI_RESP_PATTERN_SNAP_NOT_FOUND) >= 0):
|
||||||
|
LOG.warn(_('Snapshot %(name)s for consistency group '
|
||||||
|
'does not exist. Message: %(msg)s') %
|
||||||
|
{'name': snap_name, 'msg': out})
|
||||||
|
else:
|
||||||
|
raise EMCVnxCLICmdError(delete_cg_snap_cmd, rc, out)
|
||||||
|
|
||||||
@log_enter_exit
|
@log_enter_exit
|
||||||
def create_snapshot(self, volume_name, name):
|
def create_snapshot(self, volume_name, name):
|
||||||
data = self.get_lun_by_name(volume_name)
|
data = self.get_lun_by_name(volume_name)
|
||||||
@ -445,15 +599,15 @@ class CommandLineHelper(object):
|
|||||||
out, rc = self.command_execute(*command_create_snapshot)
|
out, rc = self.command_execute(*command_create_snapshot)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
# Ignore the error that due to retry
|
# Ignore the error that due to retry
|
||||||
if rc == 5 and \
|
if (rc == 5 and
|
||||||
out.find("(0x716d8005)") >= 0:
|
out.find("(0x716d8005)") >= 0):
|
||||||
LOG.warn(_('Snapshot %(name)s already exists. '
|
LOG.warn(_('Snapshot %(name)s already exists. '
|
||||||
'Message: %(msg)s') %
|
'Message: %(msg)s') %
|
||||||
{'name': name, 'msg': out})
|
{'name': name, 'msg': out})
|
||||||
else:
|
else:
|
||||||
raise EMCVnxCLICmdError(command_create_snapshot, rc, out)
|
raise EMCVnxCLICmdError(command_create_snapshot, rc, out)
|
||||||
else:
|
else:
|
||||||
msg = _('Failed to get LUN ID for volume %s') % volume_name
|
msg = _('Failed to get LUN ID for volume %s.') % volume_name
|
||||||
raise exception.VolumeBackendAPIException(data=msg)
|
raise exception.VolumeBackendAPIException(data=msg)
|
||||||
|
|
||||||
@log_enter_exit
|
@log_enter_exit
|
||||||
@ -1265,7 +1419,7 @@ class CommandLineHelper(object):
|
|||||||
class EMCVnxCliBase(object):
|
class EMCVnxCliBase(object):
|
||||||
"""This class defines the functions to use the native CLI functionality."""
|
"""This class defines the functions to use the native CLI functionality."""
|
||||||
|
|
||||||
VERSION = '04.00.00'
|
VERSION = '04.01.00'
|
||||||
stats = {'driver_version': VERSION,
|
stats = {'driver_version': VERSION,
|
||||||
'free_capacity_gb': 'unknown',
|
'free_capacity_gb': 'unknown',
|
||||||
'reserved_percentage': 0,
|
'reserved_percentage': 0,
|
||||||
@ -1346,7 +1500,7 @@ class EMCVnxCliBase(object):
|
|||||||
|
|
||||||
data = self._client.create_lun_with_advance_feature(
|
data = self._client.create_lun_with_advance_feature(
|
||||||
pool, volumename, volumesize,
|
pool, volumename, volumesize,
|
||||||
provisioning, tiering)
|
provisioning, tiering, volume['consistencygroup_id'])
|
||||||
pl_dict = {'system': self.get_array_serial(),
|
pl_dict = {'system': self.get_array_serial(),
|
||||||
'type': 'lun',
|
'type': 'lun',
|
||||||
'id': str(data['lun_id'])}
|
'id': str(data['lun_id'])}
|
||||||
@ -1676,6 +1830,10 @@ class EMCVnxCliBase(object):
|
|||||||
self.stats['fast_cache_enabled'] = 'True'
|
self.stats['fast_cache_enabled'] = 'True'
|
||||||
else:
|
else:
|
||||||
self.stats['fast_cache_enabled'] = 'False'
|
self.stats['fast_cache_enabled'] = 'False'
|
||||||
|
if '-VNXSnapshots' in self.enablers:
|
||||||
|
self.stats['consistencygroup_support'] = 'True'
|
||||||
|
else:
|
||||||
|
self.stats['consistencygroup_support'] = 'False'
|
||||||
|
|
||||||
return self.stats
|
return self.stats
|
||||||
|
|
||||||
@ -1722,6 +1880,9 @@ class EMCVnxCliBase(object):
|
|||||||
@log_enter_exit
|
@log_enter_exit
|
||||||
def create_volume_from_snapshot(self, volume, snapshot):
|
def create_volume_from_snapshot(self, volume, snapshot):
|
||||||
"""Creates a volume from a snapshot."""
|
"""Creates a volume from a snapshot."""
|
||||||
|
if snapshot['cgsnapshot_id']:
|
||||||
|
snapshot_name = snapshot['cgsnapshot_id']
|
||||||
|
else:
|
||||||
snapshot_name = snapshot['name']
|
snapshot_name = snapshot['name']
|
||||||
source_volume_name = snapshot['volume_name']
|
source_volume_name = snapshot['volume_name']
|
||||||
volume_name = volume['name']
|
volume_name = volume['name']
|
||||||
@ -1772,21 +1933,132 @@ class EMCVnxCliBase(object):
|
|||||||
"""Creates a clone of the specified volume."""
|
"""Creates a clone of the specified volume."""
|
||||||
source_volume_name = src_vref['name']
|
source_volume_name = src_vref['name']
|
||||||
volume_size = src_vref['size']
|
volume_size = src_vref['size']
|
||||||
|
consistencygroup_id = src_vref['consistencygroup_id']
|
||||||
snapshot_name = 'tmp-snap-%s' % volume['id']
|
snapshot_name = 'tmp-snap-%s' % volume['id']
|
||||||
|
tmp_cgsnapshot_name = None
|
||||||
|
if consistencygroup_id:
|
||||||
|
tmp_cgsnapshot_name = 'tmp-cgsnapshot-%s' % volume['id']
|
||||||
|
|
||||||
snapshot = {
|
snapshot = {
|
||||||
'name': snapshot_name,
|
'name': snapshot_name,
|
||||||
'volume_name': source_volume_name,
|
'volume_name': source_volume_name,
|
||||||
'volume_size': volume_size,
|
'volume_size': volume_size,
|
||||||
|
'cgsnapshot_id': tmp_cgsnapshot_name,
|
||||||
|
'consistencygroup_id': consistencygroup_id,
|
||||||
|
'id': tmp_cgsnapshot_name
|
||||||
}
|
}
|
||||||
# Create temp Snapshot
|
# Create temp Snapshot
|
||||||
|
if consistencygroup_id:
|
||||||
|
self._client.create_cgsnapshot(snapshot)
|
||||||
|
else:
|
||||||
self.create_snapshot(snapshot)
|
self.create_snapshot(snapshot)
|
||||||
|
|
||||||
# Create volume
|
# Create volume
|
||||||
model_update = self.create_volume_from_snapshot(volume, snapshot)
|
model_update = self.create_volume_from_snapshot(volume, snapshot)
|
||||||
# Delete temp Snapshot
|
# Delete temp Snapshot
|
||||||
|
if consistencygroup_id:
|
||||||
|
self._client.delete_cgsnapshot(snapshot)
|
||||||
|
else:
|
||||||
self.delete_snapshot(snapshot)
|
self.delete_snapshot(snapshot)
|
||||||
return model_update
|
return model_update
|
||||||
|
|
||||||
|
@log_enter_exit
|
||||||
|
def create_consistencygroup(self, context, group):
|
||||||
|
"""Create a consistency group."""
|
||||||
|
LOG.info(_('Start to create consistency group: %(group_name)s '
|
||||||
|
'id: %(id)s') %
|
||||||
|
{'group_name': group['name'], 'id': group['id']})
|
||||||
|
|
||||||
|
model_update = {'status': 'available'}
|
||||||
|
try:
|
||||||
|
self._client.create_consistencygroup(context, group)
|
||||||
|
except Exception:
|
||||||
|
with excutils.save_and_reraise_exception():
|
||||||
|
msg = (_('Create consistency group %s failed.')
|
||||||
|
% group['id'])
|
||||||
|
LOG.error(msg)
|
||||||
|
|
||||||
|
return model_update
|
||||||
|
|
||||||
|
@log_enter_exit
|
||||||
|
def delete_consistencygroup(self, driver, context, group):
|
||||||
|
"""Delete a consistency group."""
|
||||||
|
cg_name = group['id']
|
||||||
|
volumes = driver.db.volume_get_all_by_group(context, group['id'])
|
||||||
|
|
||||||
|
model_update = {}
|
||||||
|
model_update['status'] = group['status']
|
||||||
|
LOG.info(_('Start to delete consistency group: %(cg_name)s')
|
||||||
|
% {'cg_name': cg_name})
|
||||||
|
try:
|
||||||
|
self._client.delete_consistencygroup(cg_name)
|
||||||
|
except Exception:
|
||||||
|
with excutils.save_and_reraise_exception():
|
||||||
|
msg = (_('Delete consistency group %s failed.')
|
||||||
|
% cg_name)
|
||||||
|
LOG.error(msg)
|
||||||
|
|
||||||
|
for volume_ref in volumes:
|
||||||
|
try:
|
||||||
|
self._client.delete_lun(volume_ref['name'])
|
||||||
|
volume_ref['status'] = 'deleted'
|
||||||
|
except Exception:
|
||||||
|
volume_ref['status'] = 'error_deleting'
|
||||||
|
model_update['status'] = 'error_deleting'
|
||||||
|
|
||||||
|
return model_update, volumes
|
||||||
|
|
||||||
|
@log_enter_exit
|
||||||
|
def create_cgsnapshot(self, driver, context, cgsnapshot):
|
||||||
|
"""Create a cgsnapshot (snap group)."""
|
||||||
|
cgsnapshot_id = cgsnapshot['id']
|
||||||
|
snapshots = driver.db.snapshot_get_all_for_cgsnapshot(
|
||||||
|
context, cgsnapshot_id)
|
||||||
|
|
||||||
|
model_update = {}
|
||||||
|
LOG.info(_('Start to create cgsnapshot for consistency group'
|
||||||
|
': %(group_name)s') %
|
||||||
|
{'group_name': cgsnapshot['consistencygroup_id']})
|
||||||
|
|
||||||
|
try:
|
||||||
|
self._client.create_cgsnapshot(cgsnapshot)
|
||||||
|
for snapshot in snapshots:
|
||||||
|
snapshot['status'] = 'available'
|
||||||
|
except Exception:
|
||||||
|
with excutils.save_and_reraise_exception():
|
||||||
|
msg = (_('Create cg snapshot %s failed.')
|
||||||
|
% cgsnapshot_id)
|
||||||
|
LOG.error(msg)
|
||||||
|
|
||||||
|
model_update['status'] = 'available'
|
||||||
|
|
||||||
|
return model_update, snapshots
|
||||||
|
|
||||||
|
@log_enter_exit
|
||||||
|
def delete_cgsnapshot(self, driver, context, cgsnapshot):
|
||||||
|
"""delete a cgsnapshot (snap group)."""
|
||||||
|
cgsnapshot_id = cgsnapshot['id']
|
||||||
|
snapshots = driver.db.snapshot_get_all_for_cgsnapshot(
|
||||||
|
context, cgsnapshot_id)
|
||||||
|
|
||||||
|
model_update = {}
|
||||||
|
model_update['status'] = cgsnapshot['status']
|
||||||
|
LOG.info(_('Delete cgsnapshot %(snap_name)s for consistency group: '
|
||||||
|
'%(group_name)s') % {'snap_name': cgsnapshot['id'],
|
||||||
|
'group_name': cgsnapshot['consistencygroup_id']})
|
||||||
|
|
||||||
|
try:
|
||||||
|
self._client.delete_cgsnapshot(cgsnapshot)
|
||||||
|
for snapshot in snapshots:
|
||||||
|
snapshot['status'] = 'deleted'
|
||||||
|
except Exception:
|
||||||
|
with excutils.save_and_reraise_exception():
|
||||||
|
msg = (_('Delete cgsnapshot %s failed.')
|
||||||
|
% cgsnapshot_id)
|
||||||
|
LOG.error(msg)
|
||||||
|
|
||||||
|
return model_update, snapshots
|
||||||
|
|
||||||
def get_lun_id_by_name(self, volume_name):
|
def get_lun_id_by_name(self, volume_name):
|
||||||
data = self._client.get_lun_by_name(volume_name)
|
data = self._client.get_lun_by_name(volume_name)
|
||||||
return data['lun_id']
|
return data['lun_id']
|
||||||
|
Loading…
Reference in New Issue
Block a user