Added CG capability to volume group in CoprHD
CoprHD has been supporting consistency group starting from kilo release. This code change makes sure that cg support is added for generic volume groups for PIKE. Volume group maps to consistency group in CoprHD when the consistency group snapshot flag is enabled for the generic volume group. Change-Id: I3ec946ca594e7c18a84f0b030607f0cc6f5864fb Closes-Bug: #1682239
This commit is contained in:
parent
09cdfa0176
commit
b248aad12a
@ -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')
|
||||
|
@ -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 +
|
||||
"/" +
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -0,0 +1,3 @@
|
||||
---
|
||||
features:
|
||||
- Add consistent group capability to generic volume groups in CoprHD driver.
|
Loading…
x
Reference in New Issue
Block a user