Merge "Added CG capability to volume group in CoprHD"

This commit is contained in:
Jenkins 2017-07-21 03:20:55 +00:00 committed by Gerrit Code Review
commit dd8e524e94
6 changed files with 597 additions and 345 deletions

View File

@ -13,13 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
from mock import Mock
import mock
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 fake_constants as fake
from cinder.volume.drivers.coprhd import common as coprhd_common
from cinder.volume.drivers.coprhd import fc as coprhd_fc
from cinder.volume.drivers.coprhd import iscsi as coprhd_iscsi
@ -185,60 +184,68 @@ scaleio_itl_list = {"itl": [{"hlu": -1,
"target": {}}]}
def get_test_volume_data(volume_type_id):
test_volume = {'name': 'test-vol1',
'size': 1,
'volume_name': 'test-vol1',
'id': '1',
'consistencygroup_id': None,
'provider_auth': None,
'project_id': 'project',
'display_name': 'test-vol1',
'display_description': 'test volume',
'volume_type_id': volume_type_id,
'provider_id': '1',
}
return test_volume
class test_volume_data(object):
name = 'test-vol1'
size = 1
volume_name = 'test-vol1'
id = fake.VOLUME_ID
group_id = None
provider_auth = None
project_id = fake.PROJECT_ID
display_name = 'test-vol1'
display_description = 'test volume',
volume_type_id = None
provider_id = fake.PROVIDER_ID
def __init__(self, volume_type_id):
self.volume_type_id = volume_type_id
def get_source_test_volume_data(volume_type_id):
test_volume = {'name': 'source_test-vol1',
'size': 1,
'volume_name': 'source_test-vol1',
'id': '1234',
'consistencygroup_id': None,
'provider_auth': None,
'project_id': 'project',
'display_name': 'source_test-vol1',
'display_description': 'test volume',
'volume_type_id': volume_type_id}
return test_volume
class source_test_volume_data(object):
name = 'source_test-vol1'
size = 1
volume_name = 'source_test-vol1'
id = fake.VOLUME2_ID
group_id = None
provider_auth = None
project_id = fake.PROJECT_ID
display_name = 'source_test-vol1'
display_description = 'test volume'
volume_type_id = None
def __init__(self, volume_type_id):
self.volume_type_id = volume_type_id
def get_clone_volume_data(volume_type_id):
clone_test_volume = {'name': 'clone-test-vol1',
'size': 1,
'volume_name': 'clone-test-vol1',
'id': '2',
'provider_auth': None,
'project_id': 'project',
'display_name': 'clone-test-vol1',
'display_description': 'clone test volume',
'volume_type_id': volume_type_id}
return clone_test_volume
class test_clone_volume_data(object):
name = 'clone-test-vol1'
size = 1
volume_name = 'clone-test-vol1'
id = fake.VOLUME3_ID
provider_auth = None
project_id = fake.PROJECT_ID
display_name = 'clone-test-vol1'
display_description = 'clone test volume'
volume_type_id = None
def __init__(self, volume_type_id):
self.volume_type_id = volume_type_id
def get_test_snapshot_data(src_volume):
test_snapshot = {'name': 'snapshot1',
'display_name': 'snapshot1',
'size': 1,
'id': '1111',
'volume_name': 'test-vol1',
'volume_id': '1234',
'volume': src_volume,
'volume_size': 1,
'project_id': 'project'}
return test_snapshot
class test_snapshot_data(object):
name = 'snapshot1'
display_name = 'snapshot1'
size = 1
id = fake.SNAPSHOT_ID
volume_name = 'test-vol1'
volume_id = fake.VOLUME_ID
volume = None
volume_size = 1
project_id = fake.PROJECT_ID
status = fields.SnapshotStatus.AVAILABLE
def __init__(self, src_volume):
self.volume = src_volume
def get_connector_data():
@ -250,26 +257,41 @@ def get_connector_data():
return connector
def get_test_CG_data(volume_type_id):
test_CG = {'name': 'consistency_group_name',
'id': fake_constants.CONSISTENCY_GROUP_ID,
'volume_type_id': volume_type_id,
'status': fields.ConsistencyGroupStatus.AVAILABLE
}
return test_CG
class test_group_data(object):
name = 'group_name'
display_name = 'group_name'
id = fake.GROUP_ID
volume_type_ids = None
volume_types = None
group_type_id = None
status = fields.GroupStatus.AVAILABLE
def __init__(self, volume_types, group_type_id):
self.group_type_id = group_type_id
self.volume_types = volume_types
def get_test_CG_snap_data(volume_type_id):
test_CG_snapshot = {'name': 'cg_snap_name',
'id': fake_constants.SNAPSHOT_ID,
'consistencygroup_id':
fake_constants.CONSISTENCY_GROUP_ID,
'status': fields.ConsistencyGroupStatus.AVAILABLE,
'snapshots': [],
'consistencygroup': get_test_CG_data(volume_type_id),
'cgsnapshot_id': fake_constants.CGSNAPSHOT_ID,
}
return test_CG_snapshot
class test_group_type_data(object):
name = 'group_name'
display_name = 'group_name'
groupsnapshot_id = None
id = fake.GROUP_TYPE_ID
description = 'group'
class test_group_snap_data(object):
name = 'cg_snap_name'
display_name = 'cg_snap_name'
id = fake.GROUP_SNAPSHOT_ID
group_id = fake.GROUP_ID
status = fields.GroupStatus.AVAILABLE
snapshots = []
group = None
group_type_id = None
def __init__(self, volume_types, group_type_id):
self.group_type_id = group_type_id
self.group = test_group_data(volume_types, group_type_id)
class MockedEMCCoprHDDriverCommon(coprhd_common.EMCCoprHDDriverCommon):
@ -300,22 +322,21 @@ class MockedEMCCoprHDDriverCommon(coprhd_common.EMCCoprHDDriverCommon):
return "cg_uri"
def init_volume_api(self):
self.volume_api = Mock()
self.volume_api = mock.Mock()
self.volume_api.get.return_value = {
'name': 'source_test-vol1',
'size': 1,
'volume_name': 'source_test-vol1',
'id': fake_constants.VOLUME_ID,
'consistencygroup_id': fake_constants.CONSISTENCYGROUP_ID,
'id': fake.VOLUME_ID,
'group_id': fake.GROUP_ID,
'provider_auth': None,
'project_id': fake_constants.PROJECT_ID,
'project_id': fake.PROJECT_ID,
'display_name': 'source_test-vol1',
'display_description': 'test volume',
'volume_type_id': fake_constants.VOLUME_TYPE_ID,
}
'volume_type_id': fake.VOLUME_TYPE_ID}
def init_coprhd_api_components(self):
self.volume_obj = Mock()
self.volume_obj = mock.Mock()
self.volume_obj.create.return_value = "volume_created"
self.volume_obj.volume_query.return_value = "volume_uri"
self.volume_obj.get_storageAttributes.return_value = (
@ -342,12 +363,12 @@ class MockedEMCCoprHDDriverCommon(coprhd_common.EMCCoprHDDriverCommon):
self.volume_obj.show.return_value = {"id": "vol_id"}
self.volume_obj.expand.return_value = "expanded"
self.tag_obj = Mock()
self.tag_obj = mock.Mock()
self.tag_obj.list_tags.return_value = [
"Openstack-vol", "Openstack-vol1"]
self.tag_obj.tag_resource.return_value = "Tagged"
self.exportgroup_obj = Mock()
self.exportgroup_obj = mock.Mock()
self.exportgroup_obj.exportgroup_list.return_value = (
export_group_list)
self.exportgroup_obj.exportgroup_show.return_value = (
@ -356,7 +377,7 @@ class MockedEMCCoprHDDriverCommon(coprhd_common.EMCCoprHDDriverCommon):
self.exportgroup_obj.exportgroup_add_volumes.return_value = (
"volume-added")
self.host_obj = Mock()
self.host_obj = mock.Mock()
self.host_obj.list_by_tenant.return_value = []
self.host_obj.list_all.return_value = [{'id': "host1_id",
'name': "host1"}]
@ -365,11 +386,11 @@ class MockedEMCCoprHDDriverCommon(coprhd_common.EMCCoprHDDriverCommon):
{'name': "12:34:56:78:90:54:32:11"},
{'name': "bfdf432500000004"}]
self.hostinitiator_obj = Mock()
self.varray_obj = Mock()
self.hostinitiator_obj = mock.Mock()
self.varray_obj = mock.Mock()
self.varray_obj.varray_show.return_value = varray_detail_data
self.snapshot_obj = Mock()
self.snapshot_obj = mock.Mock()
mocked_snap_obj = self.snapshot_obj.return_value
mocked_snap_obj.storageResource_query.return_value = (
"resourceUri")
@ -377,10 +398,10 @@ class MockedEMCCoprHDDriverCommon(coprhd_common.EMCCoprHDDriverCommon):
"snapshot_created")
mocked_snap_obj.snapshot_query.return_value = "snapshot_uri"
self.consistencygroup_obj = Mock()
mocked_cg_object = self.consistencygroup_obj.return_value
mocked_cg_object.create.return_value = "CG-Created"
mocked_cg_object.consistencygroup_query.return_value = "CG-uri"
self.consistencygroup_obj = mock.Mock()
mocked_group_object = self.consistencygroup_obj.return_value
mocked_group_object.create.return_value = "CG-Created"
mocked_group_object.consistencygroup_query.return_value = "CG-uri"
class EMCCoprHDISCSIDriverTest(test.TestCase):
@ -391,7 +412,7 @@ class EMCCoprHDISCSIDriverTest(test.TestCase):
def create_coprhd_setup(self):
self.configuration = Mock()
self.configuration = mock.Mock()
self.configuration.coprhd_hostname = "10.10.10.10"
self.configuration.coprhd_port = "4443"
self.configuration.volume_backend_name = "EMCCoprHDISCSIDriver"
@ -402,7 +423,10 @@ class EMCCoprHDISCSIDriverTest(test.TestCase):
self.configuration.coprhd_varray = "varray"
self.configuration.coprhd_emulate_snapshot = False
self.volume_type_id = self.create_coprhd_volume_type()
self.volume_type = self.create_coprhd_volume_type()
self.volume_type_id = self.volume_type.id
self.group_type = test_group_type_data()
self.group_type_id = self.group_type.id
self.mock_object(coprhd_iscsi.EMCCoprHDISCSIDriver,
'_get_common_driver',
@ -423,8 +447,7 @@ class EMCCoprHDISCSIDriverTest(test.TestCase):
"coprhd-volume-type",
{'CoprHD:VPOOL':
'vpool_coprhd'})
volume_id = vipr_volume_type['id']
return volume_id
return vipr_volume_type
def _get_mocked_common_driver(self):
return MockedEMCCoprHDDriverCommon(
@ -437,7 +460,7 @@ class EMCCoprHDISCSIDriverTest(test.TestCase):
volume_types.destroy(ctx, self.volume_type_id)
def test_create_destroy(self):
volume = get_test_volume_data(self.volume_type_id)
volume = test_volume_data(self.volume_type_id)
self.driver.create_volume(volume)
self.driver.delete_volume(volume)
@ -447,17 +470,17 @@ class EMCCoprHDISCSIDriverTest(test.TestCase):
self.assertEqual('unknown', vol_stats['free_capacity_gb'])
def test_create_volume_clone(self):
src_volume_data = get_test_volume_data(self.volume_type_id)
clone_volume_data = get_clone_volume_data(self.volume_type_id)
src_volume_data = test_volume_data(self.volume_type_id)
clone_volume_data = test_clone_volume_data(self.volume_type_id)
self.driver.create_volume(src_volume_data)
self.driver.create_cloned_volume(clone_volume_data, src_volume_data)
self.driver.delete_volume(src_volume_data)
self.driver.delete_volume(clone_volume_data)
def test_create_destroy_snapshot(self):
volume_data = get_test_volume_data(self.volume_type_id)
snapshot_data = get_test_snapshot_data(
get_source_test_volume_data(self.volume_type_id))
volume_data = test_volume_data(self.volume_type_id)
snapshot_data = test_snapshot_data(
source_test_volume_data(self.volume_type_id))
self.driver.create_volume(volume_data)
self.driver.create_snapshot(snapshot_data)
@ -466,11 +489,11 @@ class EMCCoprHDISCSIDriverTest(test.TestCase):
def test_create_volume_from_snapshot(self):
src_vol_data = get_source_test_volume_data(self.volume_type_id)
src_vol_data = source_test_volume_data(self.volume_type_id)
self.driver.create_volume(src_vol_data)
volume_data = get_test_volume_data(self.volume_type_id)
snapshot_data = get_test_snapshot_data(src_vol_data)
volume_data = test_volume_data(self.volume_type_id)
snapshot_data = test_snapshot_data(src_vol_data)
self.driver.create_snapshot(snapshot_data)
self.driver.create_volume_from_snapshot(volume_data, snapshot_data)
@ -480,14 +503,14 @@ class EMCCoprHDISCSIDriverTest(test.TestCase):
self.driver.delete_volume(volume_data)
def test_extend_volume(self):
volume_data = get_test_volume_data(self.volume_type_id)
volume_data = test_volume_data(self.volume_type_id)
self.driver.create_volume(volume_data)
self.driver.extend_volume(volume_data, 2)
self.driver.delete_volume(volume_data)
def test_initialize_and_terminate_connection(self):
connector_data = get_connector_data()
volume_data = get_test_volume_data(self.volume_type_id)
volume_data = test_volume_data(self.volume_type_id)
self.driver.create_volume(volume_data)
res_initialize = self.driver.initialize_connection(
@ -498,54 +521,63 @@ class EMCCoprHDISCSIDriverTest(test.TestCase):
'target_iqn':
'50:00:09:73:00:18:95:19',
'target_discovered': False,
'volume_id': '1'}}
'volume_id': fake.VOLUME_ID}}
self.assertEqual(
expected_initialize, res_initialize, 'Unexpected return data')
self.driver.terminate_connection(volume_data, connector_data)
self.driver.delete_volume(volume_data)
def test_create_delete_empty_CG(self):
cg_data = get_test_CG_data(self.volume_type_id)
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_create_delete_empty_group(self, cg_ss_enabled):
cg_ss_enabled.side_effect = [True, True]
group_data = test_group_data([self.volume_type],
self.group_type_id)
ctx = context.get_admin_context()
self.driver.create_consistencygroup(ctx, cg_data)
self.driver.create_group(ctx, group_data)
model_update, volumes_model_update = (
self.driver.delete_consistencygroup(ctx, cg_data, []))
self.driver.delete_group(ctx, group_data, []))
self.assertEqual([], volumes_model_update, 'Unexpected return data')
def test_create_update_delete_CG(self):
cg_data = get_test_CG_data(self.volume_type_id)
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_create_update_delete_group(self, cg_ss_enabled):
cg_ss_enabled.side_effect = [True, True, True, True]
group_data = test_group_data([self.volume_type],
self.group_type_id)
ctx = context.get_admin_context()
self.driver.create_consistencygroup(ctx, cg_data)
self.driver.create_group(ctx, group_data)
volume = get_test_volume_data(self.volume_type_id)
volume = test_volume_data(self.volume_type_id)
self.driver.create_volume(volume)
model_update, ret1, ret2 = (
self.driver.update_consistencygroup(ctx, cg_data, [volume], []))
self.driver.update_group(ctx, group_data, [volume], []))
self.assertEqual({'status': fields.ConsistencyGroupStatus.AVAILABLE},
self.assertEqual({'status': fields.GroupStatus.AVAILABLE},
model_update)
model_update, volumes_model_update = (
self.driver.delete_consistencygroup(ctx, cg_data, [volume]))
self.assertEqual({'status': fields.ConsistencyGroupStatus.AVAILABLE},
self.driver.delete_group(ctx, group_data, [volume]))
self.assertEqual({'status': fields.GroupStatus.AVAILABLE},
model_update)
self.assertEqual([{'status': 'deleted', 'id': '1'}],
self.assertEqual([{'status': 'deleted', 'id': fake.VOLUME_ID}],
volumes_model_update)
def test_create_delete_CG_snap(self):
cg_snap_data = get_test_CG_snap_data(self.volume_type_id)
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_create_delete_group_snap(self, cg_ss_enabled):
cg_ss_enabled.side_effect = [True, True]
group_snap_data = test_group_snap_data([self.volume_type],
self.group_type_id)
ctx = context.get_admin_context()
model_update, snapshots_model_update = (
self.driver.create_cgsnapshot(ctx, cg_snap_data, []))
self.assertEqual({'status': fields.ConsistencyGroupStatus.AVAILABLE},
self.driver.create_group_snapshot(ctx, group_snap_data, []))
self.assertEqual({'status': fields.GroupStatus.AVAILABLE},
model_update)
self.assertEqual([], snapshots_model_update, 'Unexpected return data')
model_update, snapshots_model_update = (
self.driver.delete_cgsnapshot(ctx, cg_snap_data, []))
self.driver.delete_group_snapshot(ctx, group_snap_data, []))
self.assertEqual({}, model_update, 'Unexpected return data')
self.assertEqual([], snapshots_model_update, 'Unexpected return data')
@ -558,7 +590,7 @@ class EMCCoprHDFCDriverTest(test.TestCase):
def create_coprhd_setup(self):
self.configuration = Mock()
self.configuration = mock.Mock()
self.configuration.coprhd_hostname = "10.10.10.10"
self.configuration.coprhd_port = "4443"
self.configuration.volume_backend_name = "EMCCoprHDFCDriver"
@ -569,7 +601,10 @@ class EMCCoprHDFCDriverTest(test.TestCase):
self.configuration.coprhd_varray = "varray"
self.configuration.coprhd_emulate_snapshot = False
self.volume_type_id = self.create_coprhd_volume_type()
self.volume_type = self.create_coprhd_volume_type()
self.volume_type_id = self.volume_type.id
self.group_type = test_group_type_data()
self.group_type_id = self.group_type.id
self.mock_object(coprhd_fc.EMCCoprHDFCDriver,
'_get_common_driver',
@ -589,8 +624,7 @@ class EMCCoprHDFCDriverTest(test.TestCase):
vipr_volume_type = volume_types.create(ctx,
"coprhd-volume-type",
{'CoprHD:VPOOL': 'vpool_vipr'})
volume_id = vipr_volume_type['id']
return volume_id
return vipr_volume_type
def _get_mocked_common_driver(self):
return MockedEMCCoprHDDriverCommon(
@ -603,7 +637,7 @@ class EMCCoprHDFCDriverTest(test.TestCase):
volume_types.destroy(ctx, self.volume_type_id)
def test_create_destroy(self):
volume = get_test_volume_data(self.volume_type_id)
volume = test_volume_data(self.volume_type_id)
self.driver.create_volume(volume)
self.driver.delete_volume(volume)
@ -614,8 +648,8 @@ class EMCCoprHDFCDriverTest(test.TestCase):
def test_create_volume_clone(self):
src_volume_data = get_test_volume_data(self.volume_type_id)
clone_volume_data = get_clone_volume_data(self.volume_type_id)
src_volume_data = test_volume_data(self.volume_type_id)
clone_volume_data = test_clone_volume_data(self.volume_type_id)
self.driver.create_volume(src_volume_data)
self.driver.create_cloned_volume(clone_volume_data, src_volume_data)
self.driver.delete_volume(src_volume_data)
@ -623,9 +657,9 @@ class EMCCoprHDFCDriverTest(test.TestCase):
def test_create_destroy_snapshot(self):
volume_data = get_test_volume_data(self.volume_type_id)
snapshot_data = get_test_snapshot_data(
get_source_test_volume_data(self.volume_type_id))
volume_data = test_volume_data(self.volume_type_id)
snapshot_data = test_snapshot_data(
source_test_volume_data(self.volume_type_id))
self.driver.create_volume(volume_data)
self.driver.create_snapshot(snapshot_data)
@ -633,11 +667,11 @@ class EMCCoprHDFCDriverTest(test.TestCase):
self.driver.delete_volume(volume_data)
def test_create_volume_from_snapshot(self):
src_vol_data = get_source_test_volume_data(self.volume_type_id)
src_vol_data = source_test_volume_data(self.volume_type_id)
self.driver.create_volume(src_vol_data)
volume_data = get_test_volume_data(self.volume_type_id)
snapshot_data = get_test_snapshot_data(src_vol_data)
volume_data = test_volume_data(self.volume_type_id)
snapshot_data = test_snapshot_data(src_vol_data)
self.driver.create_snapshot(snapshot_data)
self.driver.create_volume_from_snapshot(volume_data, snapshot_data)
@ -646,22 +680,8 @@ class EMCCoprHDFCDriverTest(test.TestCase):
self.driver.delete_volume(src_vol_data)
self.driver.delete_volume(volume_data)
def test_create_volume_from_cg_snapshot(self):
ctx = context.get_admin_context()
volume_data = get_test_volume_data(self.volume_type_id)
cg_snap_data = get_test_CG_snap_data(self.volume_type_id)
self.driver.create_cgsnapshot(ctx, cg_snap_data, [])
self.assertRaises(exception.VolumeBackendAPIException,
self.driver.create_volume_from_snapshot,
volume_data, cg_snap_data)
self.driver.delete_cgsnapshot(ctx, cg_snap_data, [])
self.driver.delete_volume(volume_data)
def test_extend_volume(self):
volume_data = get_test_volume_data(self.volume_type_id)
volume_data = test_volume_data(self.volume_type_id)
self.driver.create_volume(volume_data)
self.driver.extend_volume(volume_data, 2)
self.driver.delete_volume(volume_data)
@ -669,7 +689,7 @@ class EMCCoprHDFCDriverTest(test.TestCase):
def test_initialize_and_terminate_connection(self):
connector_data = get_connector_data()
volume_data = get_test_volume_data(self.volume_type_id)
volume_data = test_volume_data(self.volume_type_id)
self.driver.create_volume(volume_data)
res_initiatlize = self.driver.initialize_connection(
@ -686,7 +706,7 @@ class EMCCoprHDFCDriverTest(test.TestCase):
'target_wwn': ['1234567890123456',
'1234567890123456'],
'target_discovered': False,
'volume_id': '1'}}
'volume_id': fake.VOLUME_ID}}
self.assertEqual(
expected_initialize, res_initiatlize, 'Unexpected return data')
@ -707,47 +727,56 @@ class EMCCoprHDFCDriverTest(test.TestCase):
self.driver.delete_volume(volume_data)
def test_create_delete_empty_CG(self):
cg_data = get_test_CG_data(self.volume_type_id)
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_create_delete_empty_group(self, cg_ss_enabled):
cg_ss_enabled.side_effect = [True, True]
group_data = test_group_data([self.volume_type],
self.group_type_id)
ctx = context.get_admin_context()
self.driver.create_consistencygroup(ctx, cg_data)
self.driver.create_group(ctx, group_data)
model_update, volumes_model_update = (
self.driver.delete_consistencygroup(ctx, cg_data, []))
self.driver.delete_group(ctx, group_data, []))
self.assertEqual([], volumes_model_update, 'Unexpected return data')
def test_create_update_delete_CG(self):
cg_data = get_test_CG_data(self.volume_type_id)
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_create_update_delete_group(self, cg_ss_enabled):
cg_ss_enabled.side_effect = [True, True, True]
group_data = test_group_data([self.volume_type],
self.group_type_id)
ctx = context.get_admin_context()
self.driver.create_consistencygroup(ctx, cg_data)
self.driver.create_group(ctx, group_data)
volume = get_test_volume_data(self.volume_type_id)
volume = test_volume_data(self.volume_type_id)
self.driver.create_volume(volume)
model_update, ret1, ret2 = (
self.driver.update_consistencygroup(ctx, cg_data, [volume], []))
self.driver.update_group(ctx, group_data, [volume], []))
self.assertEqual({'status': fields.ConsistencyGroupStatus.AVAILABLE},
self.assertEqual({'status': fields.GroupStatus.AVAILABLE},
model_update)
model_update, volumes_model_update = (
self.driver.delete_consistencygroup(ctx, cg_data, [volume]))
self.assertEqual({'status': fields.ConsistencyGroupStatus.AVAILABLE},
self.driver.delete_group(ctx, group_data, [volume]))
self.assertEqual({'status': fields.GroupStatus.AVAILABLE},
model_update)
self.assertEqual([{'status': 'deleted', 'id': '1'}],
self.assertEqual([{'status': 'deleted', 'id': fake.VOLUME_ID}],
volumes_model_update)
def test_create_delete_CG_snap(self):
cg_snap_data = get_test_CG_snap_data(self.volume_type_id)
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_create_delete_group_snap(self, cg_ss_enabled):
cg_ss_enabled.side_effect = [True, True]
group_snap_data = test_group_snap_data([self.volume_type],
self.group_type_id)
ctx = context.get_admin_context()
model_update, snapshots_model_update = (
self.driver.create_cgsnapshot(ctx, cg_snap_data, []))
self.assertEqual({'status': fields.ConsistencyGroupStatus.AVAILABLE},
self.driver.create_group_snapshot(ctx, group_snap_data, []))
self.assertEqual({'status': fields.GroupStatus.AVAILABLE},
model_update)
self.assertEqual([], snapshots_model_update, 'Unexpected return data')
model_update, snapshots_model_update = (
self.driver.delete_cgsnapshot(ctx, cg_snap_data, []))
self.driver.delete_group_snapshot(ctx, group_snap_data, []))
self.assertEqual({}, model_update, 'Unexpected return data')
self.assertEqual([], snapshots_model_update, 'Unexpected return data')
@ -760,7 +789,7 @@ class EMCCoprHDScaleIODriverTest(test.TestCase):
def create_coprhd_setup(self):
self.configuration = Mock()
self.configuration = mock.Mock()
self.configuration.coprhd_hostname = "10.10.10.10"
self.configuration.coprhd_port = "4443"
self.configuration.volume_backend_name = "EMCCoprHDFCDriver"
@ -779,7 +808,10 @@ class EMCCoprHDScaleIODriverTest(test.TestCase):
self.configuration.scaleio_server_certificate_path = (
"/etc/scaleio/certs")
self.volume_type_id = self.create_coprhd_volume_type()
self.volume_type = self.create_coprhd_volume_type()
self.volume_type_id = self.volume_type.id
self.group_type = test_group_type_data()
self.group_type_id = self.group_type.id
self.mock_object(coprhd_scaleio.EMCCoprHDScaleIODriver,
'_get_common_driver',
@ -802,8 +834,7 @@ class EMCCoprHDScaleIODriverTest(test.TestCase):
vipr_volume_type = volume_types.create(ctx,
"coprhd-volume-type",
{'CoprHD:VPOOL': 'vpool_vipr'})
volume_id = vipr_volume_type['id']
return volume_id
return vipr_volume_type
def _get_mocked_common_driver(self):
return MockedEMCCoprHDDriverCommon(
@ -820,7 +851,7 @@ class EMCCoprHDScaleIODriverTest(test.TestCase):
volume_types.destroy(ctx, self.volume_type_id)
def test_create_destroy(self):
volume = get_test_volume_data(self.volume_type_id)
volume = test_volume_data(self.volume_type_id)
self.driver.create_volume(volume)
self.driver.delete_volume(volume)
@ -831,8 +862,8 @@ class EMCCoprHDScaleIODriverTest(test.TestCase):
def test_create_volume_clone(self):
src_volume_data = get_test_volume_data(self.volume_type_id)
clone_volume_data = get_clone_volume_data(self.volume_type_id)
src_volume_data = test_volume_data(self.volume_type_id)
clone_volume_data = test_clone_volume_data(self.volume_type_id)
self.driver.create_volume(src_volume_data)
self.driver.create_cloned_volume(clone_volume_data, src_volume_data)
self.driver.delete_volume(src_volume_data)
@ -840,9 +871,9 @@ class EMCCoprHDScaleIODriverTest(test.TestCase):
def test_create_destroy_snapshot(self):
volume_data = get_test_volume_data(self.volume_type_id)
snapshot_data = get_test_snapshot_data(
get_source_test_volume_data(self.volume_type_id))
volume_data = test_volume_data(self.volume_type_id)
snapshot_data = test_snapshot_data(
source_test_volume_data(self.volume_type_id))
self.driver.create_volume(volume_data)
self.driver.create_snapshot(snapshot_data)
@ -850,11 +881,11 @@ class EMCCoprHDScaleIODriverTest(test.TestCase):
self.driver.delete_volume(volume_data)
def test_create_volume_from_snapshot(self):
src_vol_data = get_source_test_volume_data(self.volume_type_id)
src_vol_data = source_test_volume_data(self.volume_type_id)
self.driver.create_volume(src_vol_data)
volume_data = get_test_volume_data(self.volume_type_id)
snapshot_data = get_test_snapshot_data(src_vol_data)
volume_data = test_volume_data(self.volume_type_id)
snapshot_data = test_snapshot_data(src_vol_data)
self.driver.create_snapshot(snapshot_data)
self.driver.create_volume_from_snapshot(volume_data, snapshot_data)
@ -864,7 +895,7 @@ class EMCCoprHDScaleIODriverTest(test.TestCase):
self.driver.delete_volume(volume_data)
def test_extend_volume(self):
volume_data = get_test_volume_data(self.volume_type_id)
volume_data = test_volume_data(self.volume_type_id)
self.driver.create_volume(volume_data)
self.driver.extend_volume(volume_data, 2)
self.driver.delete_volume(volume_data)
@ -872,16 +903,17 @@ class EMCCoprHDScaleIODriverTest(test.TestCase):
def test_initialize_and_terminate_connection(self):
connector_data = get_connector_data()
volume_data = get_test_volume_data(self.volume_type_id)
volume_data = test_volume_data(self.volume_type_id)
self.driver.create_volume(volume_data)
res_initiatlize = self.driver.initialize_connection(
volume_data, connector_data)
exp_name = res_initiatlize['data']['scaleIO_volname']
expected_initialize = {'data': {'bandwidthLimit': None,
'hostIP': '10.0.0.2',
'iopsLimit': None,
'scaleIO_volname': 'test-vol1',
'scaleIO_volume_id': '1',
'scaleIO_volname': exp_name,
'scaleIO_volume_id': fake.PROVIDER_ID,
'serverIP': '10.10.10.11',
'serverPassword': 'scaleio_password',
'serverPort': 443,
@ -895,46 +927,55 @@ class EMCCoprHDScaleIODriverTest(test.TestCase):
volume_data, connector_data)
self.driver.delete_volume(volume_data)
def test_create_delete_empty_CG(self):
cg_data = get_test_CG_data(self.volume_type_id)
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_create_delete_empty_group(self, cg_ss_enabled):
cg_ss_enabled.side_effect = [True, True]
group_data = test_group_data([self.volume_type],
self.group_type_id)
ctx = context.get_admin_context()
self.driver.create_consistencygroup(ctx, cg_data)
self.driver.create_group(ctx, group_data)
model_update, volumes_model_update = (
self.driver.delete_consistencygroup(ctx, cg_data, []))
self.driver.delete_group(ctx, group_data, []))
self.assertEqual([], volumes_model_update, 'Unexpected return data')
def test_create_update_delete_CG(self):
cg_data = get_test_CG_data(self.volume_type_id)
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_create_update_delete_group(self, cg_ss_enabled):
cg_ss_enabled.side_effect = [True, True, True, True]
group_data = test_group_data([self.volume_type],
self.group_type_id)
ctx = context.get_admin_context()
self.driver.create_consistencygroup(ctx, cg_data)
self.driver.create_group(ctx, group_data)
volume = get_test_volume_data(self.volume_type_id)
volume = test_volume_data(self.volume_type_id)
self.driver.create_volume(volume)
model_update, ret1, ret2 = (
self.driver.update_consistencygroup(ctx, cg_data, [volume], []))
self.driver.update_group(ctx, group_data, [volume], []))
self.assertEqual({'status': fields.ConsistencyGroupStatus.AVAILABLE},
self.assertEqual({'status': fields.GroupStatus.AVAILABLE},
model_update)
model_update, volumes_model_update = (
self.driver.delete_consistencygroup(ctx, cg_data, [volume]))
self.assertEqual({'status': fields.ConsistencyGroupStatus.AVAILABLE},
self.driver.delete_group(ctx, group_data, [volume]))
self.assertEqual({'status': fields.GroupStatus.AVAILABLE},
model_update)
self.assertEqual([{'status': 'deleted', 'id': '1'}],
self.assertEqual([{'status': 'deleted', 'id': fake.VOLUME_ID}],
volumes_model_update)
def test_create_delete_CG_snap(self):
cg_snap_data = get_test_CG_snap_data(self.volume_type_id)
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_create_delete_group_snap(self, cg_ss_enabled):
cg_ss_enabled.side_effect = [True, True]
group_snap_data = test_group_snap_data([self.volume_type],
self.group_type_id)
ctx = context.get_admin_context()
model_update, snapshots_model_update = (
self.driver.create_cgsnapshot(ctx, cg_snap_data, []))
self.assertEqual({'status': fields.ConsistencyGroupStatus.AVAILABLE},
self.driver.create_group_snapshot(ctx, group_snap_data, []))
self.assertEqual({'status': fields.GroupStatus.AVAILABLE},
model_update)
self.assertEqual([], snapshots_model_update, 'Unexpected return data')
model_update, snapshots_model_update = (
self.driver.delete_cgsnapshot(ctx, cg_snap_data, []))
self.driver.delete_group_snapshot(ctx, group_snap_data, []))
self.assertEqual({}, model_update, 'Unexpected return data')
self.assertEqual([], snapshots_model_update, 'Unexpected return data')

View File

@ -45,9 +45,9 @@ from cinder.volume.drivers.coprhd.helpers import tag as coprhd_tag
from cinder.volume.drivers.coprhd.helpers import (
virtualarray as coprhd_varray)
from cinder.volume.drivers.coprhd.helpers import volume as coprhd_vol
from cinder.volume import utils as volume_utils
from cinder.volume import volume_types
LOG = logging.getLogger(__name__)
MAX_RETRIES = 10
@ -88,6 +88,10 @@ CONF.register_opts(volume_opts, group=configuration.SHARED_CONF_GROUP)
URI_VPOOL_VARRAY_CAPACITY = '/block/vpools/{0}/varrays/{1}/capacity'
URI_BLOCK_EXPORTS_FOR_INITIATORS = '/block/exports?initiators={0}'
EXPORT_RETRY_COUNT = 5
MAX_DEFAULT_NAME_LENGTH = 128
MAX_SNAPSHOT_NAME_LENGTH = 63
MAX_CONSISTENCY_GROUP_NAME_LENGTH = 64
MAX_SIO_LEN = 31
def retry_wrapper(func):
@ -225,8 +229,9 @@ class EMCCoprHDDriverCommon(object):
def create_volume(self, vol, driver, truncate_name=False):
self.authenticate_user()
name = self._get_resource_name(vol, truncate_name)
size = int(vol['size']) * units.Gi
name = self._get_resource_name(vol, MAX_DEFAULT_NAME_LENGTH,
truncate_name)
size = int(vol.size) * units.Gi
vpool = self._get_vpool(vol)
self.vpool = vpool['CoprHD:VPOOL']
@ -234,14 +239,17 @@ class EMCCoprHDDriverCommon(object):
try:
coprhd_cgid = None
try:
cgid = vol['consistencygroup_id']
if cgid:
coprhd_cgid = self._get_coprhd_cgid(cgid)
if vol.group_id:
if volume_utils.is_group_a_cg_snapshot_type(vol.group):
coprhd_cgid = self._get_coprhd_cgid(vol.group_id)
except KeyError:
coprhd_cgid = None
except AttributeError:
coprhd_cgid = None
full_project_name = ("%s/%s" % (self.configuration.coprhd_tenant,
self.configuration.coprhd_project))
self.configuration.coprhd_project)
)
self.volume_obj.create(full_project_name, name, size,
self.configuration.coprhd_varray,
self.vpool,
@ -249,6 +257,7 @@ class EMCCoprHDDriverCommon(object):
sync=True,
# no longer specified in volume creation
consistencygroup=coprhd_cgid)
except coprhd_utils.CoprHdError as e:
coprhd_err_msg = (_("Volume %(name)s: create failed\n%(err)s") %
{'name': name, 'err': six.text_type(e.msg)})
@ -260,7 +269,9 @@ class EMCCoprHDDriverCommon(object):
@retry_wrapper
def create_consistencygroup(self, context, group, truncate_name=False):
self.authenticate_user()
name = self._get_resource_name(group, truncate_name)
name = self._get_resource_name(group,
MAX_CONSISTENCY_GROUP_NAME_LENGTH,
truncate_name)
try:
self.consistencygroup_obj.create(
@ -291,8 +302,8 @@ class EMCCoprHDDriverCommon(object):
def update_consistencygroup(self, group, add_volumes,
remove_volumes):
self.authenticate_user()
model_update = {'status': fields.ConsistencyGroupStatus.AVAILABLE}
cg_uri = self._get_coprhd_cgid(group['id'])
model_update = {'status': fields.GroupStatus.AVAILABLE}
cg_uri = self._get_coprhd_cgid(group.id)
add_volnames = []
remove_volnames = []
@ -329,7 +340,9 @@ class EMCCoprHDDriverCommon(object):
def delete_consistencygroup(self, context, group, volumes,
truncate_name=False):
self.authenticate_user()
name = self._get_resource_name(group, truncate_name)
name = self._get_resource_name(group,
MAX_CONSISTENCY_GROUP_NAME_LENGTH,
truncate_name)
volumes_model_update = []
try:
@ -344,20 +357,20 @@ class EMCCoprHDDriverCommon(object):
sync=True,
force_delete=True)
update_item = {'id': vol['id'],
update_item = {'id': vol.id,
'status':
fields.ConsistencyGroupStatus.DELETED}
fields.GroupStatus.DELETED}
volumes_model_update.append(update_item)
except exception.VolumeBackendAPIException:
update_item = {'id': vol['id'],
update_item = {'id': vol.id,
'status': fields.ConsistencyGroupStatus.
ERROR_DELETING}
volumes_model_update.append(update_item)
LOG.exception("Failed to delete the volume %s of CG.",
vol['name'])
vol.name)
self.consistencygroup_obj.delete(
name,
@ -365,7 +378,7 @@ class EMCCoprHDDriverCommon(object):
self.configuration.coprhd_tenant)
model_update = {}
model_update['status'] = group['status']
model_update['status'] = group.status
return model_update, volumes_model_update
@ -384,9 +397,19 @@ class EMCCoprHDDriverCommon(object):
self.authenticate_user()
snapshots_model_update = []
cgsnapshot_name = self._get_resource_name(cgsnapshot, truncate_name)
cg_id = cgsnapshot['consistencygroup_id']
cg_group = cgsnapshot.get('consistencygroup')
cgsnapshot_name = self._get_resource_name(cgsnapshot,
MAX_SNAPSHOT_NAME_LENGTH,
truncate_name)
cg_id = None
cg_group = None
try:
cg_id = cgsnapshot.group_id
cg_group = cgsnapshot.group
except AttributeError:
pass
cg_name = None
coprhd_cgid = None
@ -408,7 +431,7 @@ class EMCCoprHDDriverCommon(object):
True)
for snapshot in snapshots:
vol_id_of_snap = snapshot['volume_id']
vol_id_of_snap = snapshot.volume_id
# Finding the volume in CoprHD for this volume id
tagname = "OpenStack:id:" + vol_id_of_snap
@ -470,7 +493,7 @@ class EMCCoprHDDriverCommon(object):
snapshot['status'] = fields.SnapshotStatus.AVAILABLE
snapshots_model_update.append(
{'id': snapshot['id'], 'status':
{'id': snapshot.id, 'status':
fields.SnapshotStatus.AVAILABLE})
model_update = {'status': fields.ConsistencyGroupStatus.AVAILABLE}
@ -493,19 +516,28 @@ class EMCCoprHDDriverCommon(object):
@retry_wrapper
def delete_cgsnapshot(self, cgsnapshot, snapshots, truncate_name=False):
self.authenticate_user()
cgsnapshot_id = cgsnapshot['id']
cgsnapshot_name = self._get_resource_name(cgsnapshot, truncate_name)
cgsnapshot_id = cgsnapshot.id
cgsnapshot_name = self._get_resource_name(cgsnapshot,
MAX_SNAPSHOT_NAME_LENGTH,
truncate_name)
snapshots_model_update = []
cg_id = cgsnapshot['consistencygroup_id']
cg_group = cgsnapshot.get('consistencygroup')
cg_id = None
cg_group = None
try:
cg_id = cgsnapshot.group_id
cg_group = cgsnapshot.group
except AttributeError:
pass
coprhd_cgid = self._get_coprhd_cgid(cg_id)
cg_name = self._get_consistencygroup_name(cg_group)
model_update = {}
LOG.info('Delete cgsnapshot %(snap_name)s for consistency group: '
'%(group_name)s', {'snap_name': cgsnapshot['name'],
'%(group_name)s', {'snap_name': cgsnapshot.name,
'group_name': cg_name})
try:
@ -531,7 +563,7 @@ class EMCCoprHDDriverCommon(object):
for snapshot in snapshots:
snapshots_model_update.append(
{'id': snapshot['id'],
{'id': snapshot.id,
'status': fields.SnapshotStatus.DELETED})
return model_update, snapshots_model_update
@ -557,7 +589,9 @@ class EMCCoprHDDriverCommon(object):
exempt_tags = []
self.authenticate_user()
name = self._get_resource_name(vol, truncate_name)
name = self._get_resource_name(vol,
MAX_DEFAULT_NAME_LENGTH,
truncate_name)
full_project_name = ("%s/%s" % (
self.configuration.coprhd_tenant,
self.configuration.coprhd_project))
@ -613,11 +647,16 @@ class EMCCoprHDDriverCommon(object):
if ((not prop.startswith("status") and not
prop.startswith("obj_status") and
prop != "obj_volume") and value):
add_tags.append(
"%s:%s:%s" % (self.OPENSTACK_TAG, prop,
six.text_type(value)))
tag = ("%s:%s:%s" %
(self.OPENSTACK_TAG, prop,
six.text_type(value)))
if len(tag) > 128:
tag = tag[0:128]
add_tags.append(tag)
except TypeError:
LOG.error("Error tagging the resource property %s", prop)
LOG.error(
"Error tagging the resource property %s", prop)
except TypeError:
LOG.error("Error tagging the resource properties")
@ -638,17 +677,21 @@ class EMCCoprHDDriverCommon(object):
def create_cloned_volume(self, vol, src_vref, truncate_name=False):
"""Creates a clone of the specified volume."""
self.authenticate_user()
name = self._get_resource_name(vol, truncate_name)
name = self._get_resource_name(vol,
MAX_DEFAULT_NAME_LENGTH,
truncate_name)
srcname = self._get_coprhd_volume_name(src_vref)
try:
if src_vref['consistencygroup_id']:
if src_vref.group_id:
raise coprhd_utils.CoprHdError(
coprhd_utils.CoprHdError.SOS_FAILURE_ERR,
_("Clone can't be taken individually on a volume"
" that is part of a Consistency Group"))
except KeyError as e:
pass
except AttributeError:
pass
try:
(storageres_type,
storageres_typename) = self.volume_obj.get_storageAttributes(
@ -691,13 +734,21 @@ class EMCCoprHDDriverCommon(object):
self._raise_or_log_exception(e.err_code, coprhd_err_msg,
log_err_msg)
try:
src_vol_size = src_vref['size']
except KeyError:
src_vol_size = src_vref['volume_size']
src_vol_size = 0
dest_vol_size = 0
if vol['size'] > src_vol_size:
size_in_bytes = coprhd_utils.to_bytes("%sG" % vol['size'])
try:
src_vol_size = src_vref.size
except AttributeError:
src_vol_size = src_vref.volume_size
try:
dest_vol_size = vol.size
except AttributeError:
dest_vol_size = vol.volume_size
if dest_vol_size > src_vol_size:
size_in_bytes = coprhd_utils.to_bytes("%sG" % dest_vol_size)
try:
self.volume_obj.expand(
("%s/%s" % (self.configuration.coprhd_tenant,
@ -733,7 +784,8 @@ class EMCCoprHDDriverCommon(object):
{'volume_name': volume_name,
'err': six.text_type(e.msg)})
log_err_msg = "Volume : %s expand failed" % volume_name
log_err_msg = ("Volume : %s expand failed" %
volume_name)
self._raise_or_log_exception(e.err_code, coprhd_err_msg,
log_err_msg)
@ -747,15 +799,20 @@ class EMCCoprHDDriverCommon(object):
self.create_cloned_volume(volume, snapshot, truncate_name)
return
if snapshot.get('cgsnapshot_id'):
raise coprhd_utils.CoprHdError(
coprhd_utils.CoprHdError.SOS_FAILURE_ERR,
_("Volume cannot be created individually from a snapshot "
"that is part of a Consistency Group"))
try:
if snapshot.group_snapshot_id:
raise coprhd_utils.CoprHdError(
coprhd_utils.CoprHdError.SOS_FAILURE_ERR,
_("Volume cannot be created individually from a snapshot "
"that is part of a Consistency Group"))
except AttributeError:
pass
src_snapshot_name = None
src_vol_ref = snapshot['volume']
new_volume_name = self._get_resource_name(volume, truncate_name)
src_vol_ref = snapshot.volume
new_volume_name = self._get_resource_name(volume,
MAX_DEFAULT_NAME_LENGTH,
truncate_name)
try:
coprhd_vol_info = self._get_coprhd_volume_name(
@ -786,12 +843,13 @@ class EMCCoprHDDriverCommon(object):
{'src_snapshot_name': src_snapshot_name,
'err': six.text_type(e.msg)})
log_err_msg = "Snapshot : %s clone failed" % src_snapshot_name
log_err_msg = ("Snapshot : %s clone failed" %
src_snapshot_name)
self._raise_or_log_exception(e.err_code, coprhd_err_msg,
log_err_msg)
if volume['size'] > snapshot['volume_size']:
size_in_bytes = coprhd_utils.to_bytes("%sG" % volume['size'])
if volume.size > snapshot.volume_size:
size_in_bytes = coprhd_utils.to_bytes("%sG" % volume.size)
try:
self.volume_obj.expand(
@ -805,7 +863,8 @@ class EMCCoprHDDriverCommon(object):
{'volume_name': new_volume_name,
'err': six.text_type(e.msg)})
log_err_msg = "Volume : %s expand failed" % new_volume_name
log_err_msg = ("Volume : %s expand failed" %
new_volume_name)
self._raise_or_log_exception(e.err_code, coprhd_err_msg,
log_err_msg)
@ -829,7 +888,7 @@ class EMCCoprHDDriverCommon(object):
"\n%(err)s") %
{'name': name, 'err': six.text_type(e.msg)})
log_err_msg = "Volume : %s delete failed" % name
log_err_msg = ("Volume : %s delete failed" % name)
self._raise_or_log_exception(e.err_code, coprhd_err_msg,
log_err_msg)
@ -837,10 +896,10 @@ class EMCCoprHDDriverCommon(object):
def create_snapshot(self, snapshot, truncate_name=False):
self.authenticate_user()
volume = snapshot['volume']
volume = snapshot.volume
try:
if volume['consistencygroup_id']:
if volume.group_id:
raise coprhd_utils.CoprHdError(
coprhd_utils.CoprHdError.SOS_FAILURE_ERR,
_("Snapshot can't be taken individually on a volume"
@ -855,8 +914,10 @@ class EMCCoprHDDriverCommon(object):
return
try:
snapshotname = self._get_resource_name(snapshot, truncate_name)
vol = snapshot['volume']
snapshotname = self._get_resource_name(snapshot,
MAX_SNAPSHOT_NAME_LENGTH,
truncate_name)
vol = snapshot.volume
volumename = self._get_coprhd_volume_name(vol)
projectname = self.configuration.coprhd_project
@ -894,7 +955,7 @@ class EMCCoprHDDriverCommon(object):
"\n%(err)s") % {'snapshotname': snapshotname,
'err': six.text_type(e.msg)})
log_err_msg = "Snapshot : %s create failed" % snapshotname
log_err_msg = ("Snapshot : %s create failed" % snapshotname)
self._raise_or_log_exception(e.err_code, coprhd_err_msg,
log_err_msg)
@ -902,10 +963,10 @@ class EMCCoprHDDriverCommon(object):
def delete_snapshot(self, snapshot):
self.authenticate_user()
vol = snapshot['volume']
vol = snapshot.volume
try:
if vol['consistencygroup_id']:
if vol.group_id:
raise coprhd_utils.CoprHdError(
coprhd_utils.CoprHdError.SOS_FAILURE_ERR,
_("Snapshot delete can't be done individually on a volume"
@ -949,7 +1010,7 @@ class EMCCoprHDDriverCommon(object):
coprhd_err_msg = (_("Snapshot %s : Delete Failed\n") %
snapshotname)
log_err_msg = "Snapshot : %s delete failed" % snapshotname
log_err_msg = ("Snapshot : %s delete failed" % snapshotname)
self._raise_or_log_exception(e.err_code, coprhd_err_msg,
log_err_msg)
@ -1170,7 +1231,7 @@ class EMCCoprHDDriverCommon(object):
(_("Consistency Group %s not found") % cgid))
def _get_consistencygroup_name(self, consisgrp):
return consisgrp['name']
return consisgrp.name
def _get_coprhd_snapshot_name(self, snapshot, resUri):
tagname = self.OPENSTACK_TAG + ":id:" + snapshot['id']
@ -1200,7 +1261,7 @@ class EMCCoprHDDriverCommon(object):
return rslt_snap['name']
def _get_coprhd_volume_name(self, vol, verbose=False):
tagname = self.OPENSTACK_TAG + ":id:" + vol['id']
tagname = self.OPENSTACK_TAG + ":id:" + vol.id
rslt = coprhd_utils.search_by_tag(
coprhd_vol.Volume.URI_SEARCH_VOLUMES_BY_TAG.format(tagname),
self.configuration.coprhd_hostname,
@ -1210,7 +1271,7 @@ class EMCCoprHDDriverCommon(object):
# as "OpenStack:obj_id"
# as snapshots will be having the obj_id instead of just id.
if len(rslt) == 0:
tagname = self.OPENSTACK_TAG + ":obj_id:" + vol['id']
tagname = self.OPENSTACK_TAG + ":obj_id:" + vol.id
rslt = coprhd_utils.search_by_tag(
coprhd_vol.Volume.URI_SEARCH_VOLUMES_BY_TAG.format(tagname),
self.configuration.coprhd_hostname,
@ -1228,21 +1289,36 @@ class EMCCoprHDDriverCommon(object):
coprhd_utils.CoprHdError.NOT_FOUND_ERR,
(_("Volume %s not found") % vol['display_name']))
def _get_resource_name(self, resource, truncate_name=False):
name = resource.get('display_name', None)
def _get_resource_name(self, resource,
max_name_cap=MAX_DEFAULT_NAME_LENGTH,
truncate_name=False):
# 36 refers to the length of UUID and +1 for '-'
permitted_name_length = max_name_cap - (36 + 1)
name = resource.display_name
if not name:
name = resource['name']
name = resource.name
if truncate_name and len(name) > 31:
'''
for scaleio, truncate_name will be true. We make sure the
total name is less than or equal to 31 characters.
_id_to_base64 will return a 24 character name'''
if truncate_name:
name = self._id_to_base64(resource.id)
return name
return name
elif len(name) > permitted_name_length:
'''
The maximum length of resource name in CoprHD is 128. Hence we use
only first 91 characters of the resource name'''
return name[0:permitted_name_length] + "-" + resource.id
else:
return name + "-" + resource.id
def _get_vpool(self, volume):
vpool = {}
ctxt = context.get_admin_context()
type_id = volume['volume_type_id']
type_id = volume.volume_type_id
if type_id is not None:
volume_type = volume_types.get_volume_type(ctxt, type_id)
specs = volume_type.get('extra_specs')
@ -1363,7 +1439,8 @@ class EMCCoprHDDriverCommon(object):
self.authenticate_user()
try:
self.stats['consistencygroup_support'] = 'True'
self.stats['consistencygroup_support'] = True
self.stats['consistent_group_snapshot_enabled'] = True
vols = self.volume_obj.list_volumes(
self.configuration.coprhd_tenant +
"/" +

View File

@ -20,9 +20,13 @@ import re
from oslo_log import log as logging
from cinder import exception
from cinder.i18n import _
from cinder import interface
from cinder.volume import driver
from cinder.volume.drivers.coprhd import common as coprhd_common
from cinder.volume import utils as volume_utils
from cinder.zonemanager import utils as fczm_utils
LOG = logging.getLogger(__name__)
@ -89,30 +93,67 @@ class EMCCoprHDFCDriver(driver.FibreChannelDriver):
pass
def remove_export(self, context, volume):
"""Driver exntry point to remove an export for a volume."""
"""Driver entry point to remove an export for a volume."""
pass
def create_consistencygroup(self, context, group):
"""Creates a consistencygroup."""
return self.common.create_consistencygroup(context, group)
def create_group(self, context, group):
"""Creates a group."""
if volume_utils.is_group_a_cg_snapshot_type(group):
return self.common.create_consistencygroup(context, group)
def update_consistencygroup(self, context, group, add_volumes=None,
remove_volumes=None):
"""Updates volumes in consistency group."""
return self.common.update_consistencygroup(group, add_volumes,
remove_volumes)
# If the group is not consistency group snapshot enabled, then
# we shall rely on generic volume group implementation
raise NotImplementedError()
def delete_consistencygroup(self, context, group, volumes):
"""Deletes a consistency group."""
return self.common.delete_consistencygroup(context, group, volumes)
def update_group(self, context, group, add_volumes=None,
remove_volumes=None):
"""Updates volumes in group."""
if volume_utils.is_group_a_cg_snapshot_type(group):
return self.common.update_consistencygroup(group, add_volumes,
remove_volumes)
def create_cgsnapshot(self, context, cgsnapshot, snapshots):
"""Creates a cgsnapshot."""
return self.common.create_cgsnapshot(cgsnapshot, snapshots)
# If the group is not consistency group snapshot enabled, then
# we shall rely on generic volume group implementation
raise NotImplementedError()
def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
"""Deletes a cgsnapshot."""
return self.common.delete_cgsnapshot(cgsnapshot, snapshots)
def create_group_from_src(self, ctxt, group, volumes,
group_snapshot=None, snapshots=None,
source_group=None, source_vols=None):
"""Creates a group from source."""
if volume_utils.is_group_a_cg_snapshot_type(group):
message = _("create group from source is not supported "
"for CoprHD if the group type supports "
"consistent group snapshot.")
raise exception.VolumeBackendAPIException(data=message)
else:
raise NotImplementedError()
def delete_group(self, context, group, volumes):
"""Deletes a group."""
if volume_utils.is_group_a_cg_snapshot_type(group):
return self.common.delete_consistencygroup(context, group, volumes)
# If the group is not consistency group snapshot enabled, then
# we shall rely on generic volume group implementation
raise NotImplementedError()
def create_group_snapshot(self, context, group_snapshot, snapshots):
"""Creates a group snapshot."""
if volume_utils.is_group_a_cg_snapshot_type(group_snapshot):
return self.common.create_cgsnapshot(group_snapshot, snapshots)
# If the group is not consistency group snapshot enabled, then
# we shall rely on generic volume group implementation
raise NotImplementedError()
def delete_group_snapshot(self, context, group_snapshot, snapshots):
"""Deletes a group snapshot."""
if volume_utils.is_group_a_cg_snapshot_type(group_snapshot):
return self.common.delete_cgsnapshot(group_snapshot, snapshots)
# If the group is not consistency group snapshot enabled, then
# we shall rely on generic volume group implementation
raise NotImplementedError()
def check_for_export(self, context, volume_id):
"""Make sure volume is exported."""
@ -123,14 +164,12 @@ class EMCCoprHDFCDriver(driver.FibreChannelDriver):
"""Initializes the connection and returns connection info."""
properties = {}
properties['volume_id'] = volume['id']
properties['volume_id'] = volume.id
properties['target_discovered'] = False
properties['target_wwn'] = []
init_ports = self._build_initport_list(connector)
itls = self.common.initialize_connection(volume,
'FC',
init_ports,
itls = self.common.initialize_connection(volume, 'FC', init_ports,
connector['host'])
target_wwns = None
@ -144,7 +183,12 @@ class EMCCoprHDFCDriver(driver.FibreChannelDriver):
properties['target_wwn'] = target_wwns
properties['initiator_target_map'] = initiator_target_map
auth = volume['provider_auth']
auth = None
try:
auth = volume.provider_auth
except AttributeError:
pass
if auth:
(auth_method, auth_username, auth_secret) = auth.split()
properties['auth_method'] = auth_method
@ -162,9 +206,7 @@ class EMCCoprHDFCDriver(driver.FibreChannelDriver):
"""Driver entry point to detach a volume from an instance."""
init_ports = self._build_initport_list(connector)
itls = self.common.terminate_connection(volume,
'FC',
init_ports,
itls = self.common.terminate_connection(volume, 'FC', init_ports,
connector['host'])
volumes_count = self.common.get_exports_count_by_initiators(init_ports)

View File

@ -18,10 +18,12 @@
from oslo_log import log as logging
from cinder import exception
from cinder.i18n import _
from cinder import interface
from cinder.volume import driver
from cinder.volume.drivers.coprhd import common as coprhd_common
from cinder.volume import utils as volume_utils
LOG = logging.getLogger(__name__)
@ -67,7 +69,7 @@ class EMCCoprHDISCSIDriver(driver.ISCSIDriver):
self.common.expand_volume(volume, new_size)
def delete_volume(self, volume):
"""Deletes an volume."""
"""Deletes a volume."""
self.common.delete_volume(volume)
def create_snapshot(self, snapshot):
@ -90,27 +92,65 @@ class EMCCoprHDISCSIDriver(driver.ISCSIDriver):
"""Driver entry point to remove an export for a volume."""
pass
def create_consistencygroup(self, context, group):
"""Creates a consistencygroup."""
return self.common.create_consistencygroup(context, group)
def create_group(self, context, group):
"""Creates a group."""
if volume_utils.is_group_a_cg_snapshot_type(group):
return self.common.create_consistencygroup(context, group)
def delete_consistencygroup(self, context, group, volumes):
"""Deletes a consistency group."""
return self.common.delete_consistencygroup(context, group, volumes)
# If the group is not consistency group snapshot enabled, then
# we shall rely on generic volume group implementation
raise NotImplementedError()
def update_consistencygroup(self, context, group,
add_volumes=None, remove_volumes=None):
"""Updates volumes in consistency group."""
return self.common.update_consistencygroup(group, add_volumes,
remove_volumes)
def create_group_from_src(self, ctxt, group, volumes,
group_snapshot=None, snapshots=None,
source_group=None, source_vols=None):
"""Creates a group from source."""
if volume_utils.is_group_a_cg_snapshot_type(group):
message = _("create group from source is not supported "
"for CoprHD if the group type supports "
"consistent group snapshot.")
raise exception.VolumeBackendAPIException(data=message)
else:
raise NotImplementedError()
def create_cgsnapshot(self, context, cgsnapshot, snapshots):
"""Creates a cgsnapshot."""
return self.common.create_cgsnapshot(cgsnapshot, snapshots)
def update_group(self, context, group, add_volumes=None,
remove_volumes=None):
"""Updates volumes in group."""
if volume_utils.is_group_a_cg_snapshot_type(group):
return self.common.update_consistencygroup(group, add_volumes,
remove_volumes)
def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
"""Deletes a cgsnapshot."""
return self.common.delete_cgsnapshot(cgsnapshot, snapshots)
# If the group is not consistency group snapshot enabled, then
# we shall rely on generic volume group implementation
raise NotImplementedError()
def delete_group(self, context, group, volumes):
"""Deletes a group."""
if volume_utils.is_group_a_cg_snapshot_type(group):
return self.common.delete_consistencygroup(context, group, volumes)
# If the group is not consistency group snapshot enabled, then
# we shall rely on generic volume group implementation
raise NotImplementedError()
def create_group_snapshot(self, context, group_snapshot, snapshots):
"""Creates a group snapshot."""
if volume_utils.is_group_a_cg_snapshot_type(group_snapshot):
LOG.debug("creating a group snapshot")
return self.common.create_cgsnapshot(group_snapshot, snapshots)
# If the group is not consistency group snapshot enabled, then
# we shall rely on generic volume group implementation
raise NotImplementedError()
def delete_group_snapshot(self, context, group_snapshot, snapshots):
"""Deletes a group snapshot."""
if volume_utils.is_group_a_cg_snapshot_type(group_snapshot):
return self.common.delete_cgsnapshot(group_snapshot, snapshots)
# If the group is not consistency group snapshot enabled, then
# we shall rely on generic volume group implementation
raise NotImplementedError()
def check_for_export(self, context, volume_id):
"""Make sure volume is exported."""
@ -127,14 +167,20 @@ class EMCCoprHDISCSIDriver(driver.ISCSIDriver):
connector['host'])
properties = {}
properties['target_discovered'] = False
properties['volume_id'] = volume['id']
properties['volume_id'] = volume.id
if itls:
properties['target_iqn'] = itls[0]['target']['port']
properties['target_portal'] = '%s:%s' % (
itls[0]['target']['ip_address'],
itls[0]['target']['tcp_port'])
properties['target_lun'] = itls[0]['hlu']
auth = volume['provider_auth']
auth = None
try:
auth = volume.provider_auth
except AttributeError:
pass
if auth:
(auth_method, auth_username, auth_secret) = auth.split()
properties['auth_method'] = auth_method

View File

@ -29,6 +29,7 @@ from cinder import interface
from cinder.volume import configuration
from cinder.volume import driver
from cinder.volume.drivers.coprhd import common as coprhd_common
from cinder.volume import utils as volume_utils
LOG = logging.getLogger(__name__)
@ -92,7 +93,7 @@ class EMCCoprHDScaleIODriver(driver.VolumeDriver):
"""Creates a Volume."""
self.common.create_volume(volume, self, True)
self.common.set_volume_tags(volume, ['_obj_volume_type'], True)
vol_size = self._update_volume_size(int(volume['size']))
vol_size = self._update_volume_size(int(volume.size))
return {'size': vol_size}
def _update_volume_size(self, vol_size):
@ -141,28 +142,68 @@ class EMCCoprHDScaleIODriver(driver.VolumeDriver):
"""Driver exntry point to remove an export for a volume."""
pass
def create_consistencygroup(self, context, group):
"""Creates a consistencygroup."""
return self.common.create_consistencygroup(context, group, True)
def create_group(self, context, group):
"""Creates a group."""
if volume_utils.is_group_a_cg_snapshot_type(group):
return self.common.create_consistencygroup(context, group, True)
def update_consistencygroup(self, context, group,
add_volumes=None, remove_volumes=None):
"""Updates volumes in consistency group."""
return self.common.update_consistencygroup(group, add_volumes,
remove_volumes)
# If the group is not consistency group snapshot enabled, then
# we shall rely on generic volume group implementation
raise NotImplementedError()
def delete_consistencygroup(self, context, group, volumes):
"""Deletes a consistency group."""
return self.common.delete_consistencygroup(context, group,
volumes, True)
def update_group(self, context, group, add_volumes=None,
remove_volumes=None):
"""Updates volumes in group."""
if volume_utils.is_group_a_cg_snapshot_type(group):
return self.common.update_consistencygroup(group, add_volumes,
remove_volumes)
def create_cgsnapshot(self, context, cgsnapshot, snapshots):
"""Creates a cgsnapshot."""
return self.common.create_cgsnapshot(cgsnapshot, snapshots, True)
# If the group is not consistency group snapshot enabled, then
# we shall rely on generic volume group implementation
raise NotImplementedError()
def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
"""Deletes a cgsnapshot."""
return self.common.delete_cgsnapshot(cgsnapshot, snapshots, True)
def create_group_from_src(self, ctxt, group, volumes,
group_snapshot=None, snapshots=None,
source_group=None, source_vols=None):
"""Creates a group from source."""
if volume_utils.is_group_a_cg_snapshot_type(group):
message = _("create group from source is not supported "
"for CoprHD if the group type supports "
"consistent group snapshot.")
raise exception.VolumeBackendAPIException(data=message)
else:
raise NotImplementedError()
def delete_group(self, context, group, volumes):
"""Deletes a group."""
if volume_utils.is_group_a_cg_snapshot_type(group):
return self.common.delete_consistencygroup(context, group,
volumes, True)
# If the group is not consistency group snapshot enabled, then
# we shall rely on generic volume group implementation
raise NotImplementedError()
def create_group_snapshot(self, context, group_snapshot, snapshots):
"""Creates a group snapshot."""
if volume_utils.is_group_a_cg_snapshot_type(group_snapshot):
LOG.debug("creating a group snapshot")
return self.common.create_cgsnapshot(group_snapshot, snapshots,
True)
# If the group is not consistency group snapshot enabled, then
# we shall rely on generic volume group implementation
raise NotImplementedError()
def delete_group_snapshot(self, context, group_snapshot, snapshots):
"""Deletes a group snapshot."""
if volume_utils.is_group_a_cg_snapshot_type(group_snapshot):
return self.common.delete_cgsnapshot(group_snapshot, snapshots,
True)
# If the group is not consistency group snapshot enabled, then
# we shall rely on generic volume group implementation
raise NotImplementedError()
def check_for_export(self, context, volume_id):
"""Make sure volume is exported."""
@ -171,11 +212,13 @@ class EMCCoprHDScaleIODriver(driver.VolumeDriver):
def initialize_connection(self, volume, connector):
"""Initializes the connection and returns connection info."""
volname = self.common._get_resource_name(volume, True)
volname = self.common._get_resource_name(volume,
coprhd_common.MAX_SIO_LEN,
True)
properties = {}
properties['scaleIO_volname'] = volname
properties['scaleIO_volume_id'] = volume['provider_id']
properties['scaleIO_volume_id'] = volume.provider_id
properties['hostIP'] = connector['ip']
properties[
'serverIP'] = self.configuration.coprhd_scaleio_rest_gateway_host
@ -215,10 +258,10 @@ class EMCCoprHDScaleIODriver(driver.VolumeDriver):
def terminate_connection(self, volume, connector, **kwargs):
"""Disallow connection from connector."""
volname = volume['display_name']
volname = volume.display_name
properties = {}
properties['scaleIO_volname'] = volname
properties['scaleIO_volume_id'] = volume['provider_id']
properties['scaleIO_volume_id'] = volume.provider_id
properties['hostIP'] = connector['ip']
properties[
'serverIP'] = self.configuration.coprhd_scaleio_rest_gateway_host

View File

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