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
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from mock import Mock
|
import mock
|
||||||
|
|
||||||
from cinder import context
|
from cinder import context
|
||||||
from cinder import exception
|
|
||||||
from cinder.objects import fields
|
from cinder.objects import fields
|
||||||
from cinder import test
|
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 common as coprhd_common
|
||||||
from cinder.volume.drivers.coprhd import fc as coprhd_fc
|
from cinder.volume.drivers.coprhd import fc as coprhd_fc
|
||||||
from cinder.volume.drivers.coprhd import iscsi as coprhd_iscsi
|
from cinder.volume.drivers.coprhd import iscsi as coprhd_iscsi
|
||||||
@ -185,60 +184,68 @@ scaleio_itl_list = {"itl": [{"hlu": -1,
|
|||||||
"target": {}}]}
|
"target": {}}]}
|
||||||
|
|
||||||
|
|
||||||
def get_test_volume_data(volume_type_id):
|
class test_volume_data(object):
|
||||||
test_volume = {'name': 'test-vol1',
|
name = 'test-vol1'
|
||||||
'size': 1,
|
size = 1
|
||||||
'volume_name': 'test-vol1',
|
volume_name = 'test-vol1'
|
||||||
'id': '1',
|
id = fake.VOLUME_ID
|
||||||
'consistencygroup_id': None,
|
group_id = None
|
||||||
'provider_auth': None,
|
provider_auth = None
|
||||||
'project_id': 'project',
|
project_id = fake.PROJECT_ID
|
||||||
'display_name': 'test-vol1',
|
display_name = 'test-vol1'
|
||||||
'display_description': 'test volume',
|
display_description = 'test volume',
|
||||||
'volume_type_id': volume_type_id,
|
volume_type_id = None
|
||||||
'provider_id': '1',
|
provider_id = fake.PROVIDER_ID
|
||||||
}
|
|
||||||
return test_volume
|
def __init__(self, volume_type_id):
|
||||||
|
self.volume_type_id = volume_type_id
|
||||||
|
|
||||||
|
|
||||||
def get_source_test_volume_data(volume_type_id):
|
class source_test_volume_data(object):
|
||||||
test_volume = {'name': 'source_test-vol1',
|
name = 'source_test-vol1'
|
||||||
'size': 1,
|
size = 1
|
||||||
'volume_name': 'source_test-vol1',
|
volume_name = 'source_test-vol1'
|
||||||
'id': '1234',
|
id = fake.VOLUME2_ID
|
||||||
'consistencygroup_id': None,
|
group_id = None
|
||||||
'provider_auth': None,
|
provider_auth = None
|
||||||
'project_id': 'project',
|
project_id = fake.PROJECT_ID
|
||||||
'display_name': 'source_test-vol1',
|
display_name = 'source_test-vol1'
|
||||||
'display_description': 'test volume',
|
display_description = 'test volume'
|
||||||
'volume_type_id': volume_type_id}
|
volume_type_id = None
|
||||||
return test_volume
|
|
||||||
|
def __init__(self, volume_type_id):
|
||||||
|
self.volume_type_id = volume_type_id
|
||||||
|
|
||||||
|
|
||||||
def get_clone_volume_data(volume_type_id):
|
class test_clone_volume_data(object):
|
||||||
clone_test_volume = {'name': 'clone-test-vol1',
|
name = 'clone-test-vol1'
|
||||||
'size': 1,
|
size = 1
|
||||||
'volume_name': 'clone-test-vol1',
|
volume_name = 'clone-test-vol1'
|
||||||
'id': '2',
|
id = fake.VOLUME3_ID
|
||||||
'provider_auth': None,
|
provider_auth = None
|
||||||
'project_id': 'project',
|
project_id = fake.PROJECT_ID
|
||||||
'display_name': 'clone-test-vol1',
|
display_name = 'clone-test-vol1'
|
||||||
'display_description': 'clone test volume',
|
display_description = 'clone test volume'
|
||||||
'volume_type_id': volume_type_id}
|
volume_type_id = None
|
||||||
return clone_test_volume
|
|
||||||
|
def __init__(self, volume_type_id):
|
||||||
|
self.volume_type_id = volume_type_id
|
||||||
|
|
||||||
|
|
||||||
def get_test_snapshot_data(src_volume):
|
class test_snapshot_data(object):
|
||||||
test_snapshot = {'name': 'snapshot1',
|
name = 'snapshot1'
|
||||||
'display_name': 'snapshot1',
|
display_name = 'snapshot1'
|
||||||
'size': 1,
|
size = 1
|
||||||
'id': '1111',
|
id = fake.SNAPSHOT_ID
|
||||||
'volume_name': 'test-vol1',
|
volume_name = 'test-vol1'
|
||||||
'volume_id': '1234',
|
volume_id = fake.VOLUME_ID
|
||||||
'volume': src_volume,
|
volume = None
|
||||||
'volume_size': 1,
|
volume_size = 1
|
||||||
'project_id': 'project'}
|
project_id = fake.PROJECT_ID
|
||||||
return test_snapshot
|
status = fields.SnapshotStatus.AVAILABLE
|
||||||
|
|
||||||
|
def __init__(self, src_volume):
|
||||||
|
self.volume = src_volume
|
||||||
|
|
||||||
|
|
||||||
def get_connector_data():
|
def get_connector_data():
|
||||||
@ -250,26 +257,41 @@ def get_connector_data():
|
|||||||
return connector
|
return connector
|
||||||
|
|
||||||
|
|
||||||
def get_test_CG_data(volume_type_id):
|
class test_group_data(object):
|
||||||
test_CG = {'name': 'consistency_group_name',
|
name = 'group_name'
|
||||||
'id': fake_constants.CONSISTENCY_GROUP_ID,
|
display_name = 'group_name'
|
||||||
'volume_type_id': volume_type_id,
|
id = fake.GROUP_ID
|
||||||
'status': fields.ConsistencyGroupStatus.AVAILABLE
|
volume_type_ids = None
|
||||||
}
|
volume_types = None
|
||||||
return test_CG
|
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):
|
class test_group_type_data(object):
|
||||||
test_CG_snapshot = {'name': 'cg_snap_name',
|
name = 'group_name'
|
||||||
'id': fake_constants.SNAPSHOT_ID,
|
display_name = 'group_name'
|
||||||
'consistencygroup_id':
|
groupsnapshot_id = None
|
||||||
fake_constants.CONSISTENCY_GROUP_ID,
|
id = fake.GROUP_TYPE_ID
|
||||||
'status': fields.ConsistencyGroupStatus.AVAILABLE,
|
description = 'group'
|
||||||
'snapshots': [],
|
|
||||||
'consistencygroup': get_test_CG_data(volume_type_id),
|
|
||||||
'cgsnapshot_id': fake_constants.CGSNAPSHOT_ID,
|
class test_group_snap_data(object):
|
||||||
}
|
name = 'cg_snap_name'
|
||||||
return test_CG_snapshot
|
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):
|
class MockedEMCCoprHDDriverCommon(coprhd_common.EMCCoprHDDriverCommon):
|
||||||
@ -300,22 +322,21 @@ class MockedEMCCoprHDDriverCommon(coprhd_common.EMCCoprHDDriverCommon):
|
|||||||
return "cg_uri"
|
return "cg_uri"
|
||||||
|
|
||||||
def init_volume_api(self):
|
def init_volume_api(self):
|
||||||
self.volume_api = Mock()
|
self.volume_api = mock.Mock()
|
||||||
self.volume_api.get.return_value = {
|
self.volume_api.get.return_value = {
|
||||||
'name': 'source_test-vol1',
|
'name': 'source_test-vol1',
|
||||||
'size': 1,
|
'size': 1,
|
||||||
'volume_name': 'source_test-vol1',
|
'volume_name': 'source_test-vol1',
|
||||||
'id': fake_constants.VOLUME_ID,
|
'id': fake.VOLUME_ID,
|
||||||
'consistencygroup_id': fake_constants.CONSISTENCYGROUP_ID,
|
'group_id': fake.GROUP_ID,
|
||||||
'provider_auth': None,
|
'provider_auth': None,
|
||||||
'project_id': fake_constants.PROJECT_ID,
|
'project_id': fake.PROJECT_ID,
|
||||||
'display_name': 'source_test-vol1',
|
'display_name': 'source_test-vol1',
|
||||||
'display_description': 'test volume',
|
'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):
|
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.create.return_value = "volume_created"
|
||||||
self.volume_obj.volume_query.return_value = "volume_uri"
|
self.volume_obj.volume_query.return_value = "volume_uri"
|
||||||
self.volume_obj.get_storageAttributes.return_value = (
|
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.show.return_value = {"id": "vol_id"}
|
||||||
self.volume_obj.expand.return_value = "expanded"
|
self.volume_obj.expand.return_value = "expanded"
|
||||||
|
|
||||||
self.tag_obj = Mock()
|
self.tag_obj = mock.Mock()
|
||||||
self.tag_obj.list_tags.return_value = [
|
self.tag_obj.list_tags.return_value = [
|
||||||
"Openstack-vol", "Openstack-vol1"]
|
"Openstack-vol", "Openstack-vol1"]
|
||||||
self.tag_obj.tag_resource.return_value = "Tagged"
|
self.tag_obj.tag_resource.return_value = "Tagged"
|
||||||
|
|
||||||
self.exportgroup_obj = Mock()
|
self.exportgroup_obj = mock.Mock()
|
||||||
self.exportgroup_obj.exportgroup_list.return_value = (
|
self.exportgroup_obj.exportgroup_list.return_value = (
|
||||||
export_group_list)
|
export_group_list)
|
||||||
self.exportgroup_obj.exportgroup_show.return_value = (
|
self.exportgroup_obj.exportgroup_show.return_value = (
|
||||||
@ -356,7 +377,7 @@ class MockedEMCCoprHDDriverCommon(coprhd_common.EMCCoprHDDriverCommon):
|
|||||||
self.exportgroup_obj.exportgroup_add_volumes.return_value = (
|
self.exportgroup_obj.exportgroup_add_volumes.return_value = (
|
||||||
"volume-added")
|
"volume-added")
|
||||||
|
|
||||||
self.host_obj = Mock()
|
self.host_obj = mock.Mock()
|
||||||
self.host_obj.list_by_tenant.return_value = []
|
self.host_obj.list_by_tenant.return_value = []
|
||||||
self.host_obj.list_all.return_value = [{'id': "host1_id",
|
self.host_obj.list_all.return_value = [{'id': "host1_id",
|
||||||
'name': "host1"}]
|
'name': "host1"}]
|
||||||
@ -365,11 +386,11 @@ class MockedEMCCoprHDDriverCommon(coprhd_common.EMCCoprHDDriverCommon):
|
|||||||
{'name': "12:34:56:78:90:54:32:11"},
|
{'name': "12:34:56:78:90:54:32:11"},
|
||||||
{'name': "bfdf432500000004"}]
|
{'name': "bfdf432500000004"}]
|
||||||
|
|
||||||
self.hostinitiator_obj = Mock()
|
self.hostinitiator_obj = mock.Mock()
|
||||||
self.varray_obj = Mock()
|
self.varray_obj = mock.Mock()
|
||||||
self.varray_obj.varray_show.return_value = varray_detail_data
|
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 = self.snapshot_obj.return_value
|
||||||
mocked_snap_obj.storageResource_query.return_value = (
|
mocked_snap_obj.storageResource_query.return_value = (
|
||||||
"resourceUri")
|
"resourceUri")
|
||||||
@ -377,10 +398,10 @@ class MockedEMCCoprHDDriverCommon(coprhd_common.EMCCoprHDDriverCommon):
|
|||||||
"snapshot_created")
|
"snapshot_created")
|
||||||
mocked_snap_obj.snapshot_query.return_value = "snapshot_uri"
|
mocked_snap_obj.snapshot_query.return_value = "snapshot_uri"
|
||||||
|
|
||||||
self.consistencygroup_obj = Mock()
|
self.consistencygroup_obj = mock.Mock()
|
||||||
mocked_cg_object = self.consistencygroup_obj.return_value
|
mocked_group_object = self.consistencygroup_obj.return_value
|
||||||
mocked_cg_object.create.return_value = "CG-Created"
|
mocked_group_object.create.return_value = "CG-Created"
|
||||||
mocked_cg_object.consistencygroup_query.return_value = "CG-uri"
|
mocked_group_object.consistencygroup_query.return_value = "CG-uri"
|
||||||
|
|
||||||
|
|
||||||
class EMCCoprHDISCSIDriverTest(test.TestCase):
|
class EMCCoprHDISCSIDriverTest(test.TestCase):
|
||||||
@ -391,7 +412,7 @@ class EMCCoprHDISCSIDriverTest(test.TestCase):
|
|||||||
|
|
||||||
def create_coprhd_setup(self):
|
def create_coprhd_setup(self):
|
||||||
|
|
||||||
self.configuration = Mock()
|
self.configuration = mock.Mock()
|
||||||
self.configuration.coprhd_hostname = "10.10.10.10"
|
self.configuration.coprhd_hostname = "10.10.10.10"
|
||||||
self.configuration.coprhd_port = "4443"
|
self.configuration.coprhd_port = "4443"
|
||||||
self.configuration.volume_backend_name = "EMCCoprHDISCSIDriver"
|
self.configuration.volume_backend_name = "EMCCoprHDISCSIDriver"
|
||||||
@ -402,7 +423,10 @@ class EMCCoprHDISCSIDriverTest(test.TestCase):
|
|||||||
self.configuration.coprhd_varray = "varray"
|
self.configuration.coprhd_varray = "varray"
|
||||||
self.configuration.coprhd_emulate_snapshot = False
|
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,
|
self.mock_object(coprhd_iscsi.EMCCoprHDISCSIDriver,
|
||||||
'_get_common_driver',
|
'_get_common_driver',
|
||||||
@ -423,8 +447,7 @@ class EMCCoprHDISCSIDriverTest(test.TestCase):
|
|||||||
"coprhd-volume-type",
|
"coprhd-volume-type",
|
||||||
{'CoprHD:VPOOL':
|
{'CoprHD:VPOOL':
|
||||||
'vpool_coprhd'})
|
'vpool_coprhd'})
|
||||||
volume_id = vipr_volume_type['id']
|
return vipr_volume_type
|
||||||
return volume_id
|
|
||||||
|
|
||||||
def _get_mocked_common_driver(self):
|
def _get_mocked_common_driver(self):
|
||||||
return MockedEMCCoprHDDriverCommon(
|
return MockedEMCCoprHDDriverCommon(
|
||||||
@ -437,7 +460,7 @@ class EMCCoprHDISCSIDriverTest(test.TestCase):
|
|||||||
volume_types.destroy(ctx, self.volume_type_id)
|
volume_types.destroy(ctx, self.volume_type_id)
|
||||||
|
|
||||||
def test_create_destroy(self):
|
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.create_volume(volume)
|
||||||
self.driver.delete_volume(volume)
|
self.driver.delete_volume(volume)
|
||||||
@ -447,17 +470,17 @@ class EMCCoprHDISCSIDriverTest(test.TestCase):
|
|||||||
self.assertEqual('unknown', vol_stats['free_capacity_gb'])
|
self.assertEqual('unknown', vol_stats['free_capacity_gb'])
|
||||||
|
|
||||||
def test_create_volume_clone(self):
|
def test_create_volume_clone(self):
|
||||||
src_volume_data = get_test_volume_data(self.volume_type_id)
|
src_volume_data = test_volume_data(self.volume_type_id)
|
||||||
clone_volume_data = get_clone_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_volume(src_volume_data)
|
||||||
self.driver.create_cloned_volume(clone_volume_data, 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(src_volume_data)
|
||||||
self.driver.delete_volume(clone_volume_data)
|
self.driver.delete_volume(clone_volume_data)
|
||||||
|
|
||||||
def test_create_destroy_snapshot(self):
|
def test_create_destroy_snapshot(self):
|
||||||
volume_data = get_test_volume_data(self.volume_type_id)
|
volume_data = test_volume_data(self.volume_type_id)
|
||||||
snapshot_data = get_test_snapshot_data(
|
snapshot_data = test_snapshot_data(
|
||||||
get_source_test_volume_data(self.volume_type_id))
|
source_test_volume_data(self.volume_type_id))
|
||||||
|
|
||||||
self.driver.create_volume(volume_data)
|
self.driver.create_volume(volume_data)
|
||||||
self.driver.create_snapshot(snapshot_data)
|
self.driver.create_snapshot(snapshot_data)
|
||||||
@ -466,11 +489,11 @@ class EMCCoprHDISCSIDriverTest(test.TestCase):
|
|||||||
|
|
||||||
def test_create_volume_from_snapshot(self):
|
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)
|
self.driver.create_volume(src_vol_data)
|
||||||
|
|
||||||
volume_data = get_test_volume_data(self.volume_type_id)
|
volume_data = test_volume_data(self.volume_type_id)
|
||||||
snapshot_data = get_test_snapshot_data(src_vol_data)
|
snapshot_data = test_snapshot_data(src_vol_data)
|
||||||
|
|
||||||
self.driver.create_snapshot(snapshot_data)
|
self.driver.create_snapshot(snapshot_data)
|
||||||
self.driver.create_volume_from_snapshot(volume_data, 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)
|
self.driver.delete_volume(volume_data)
|
||||||
|
|
||||||
def test_extend_volume(self):
|
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.create_volume(volume_data)
|
||||||
self.driver.extend_volume(volume_data, 2)
|
self.driver.extend_volume(volume_data, 2)
|
||||||
self.driver.delete_volume(volume_data)
|
self.driver.delete_volume(volume_data)
|
||||||
|
|
||||||
def test_initialize_and_terminate_connection(self):
|
def test_initialize_and_terminate_connection(self):
|
||||||
connector_data = get_connector_data()
|
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)
|
self.driver.create_volume(volume_data)
|
||||||
res_initialize = self.driver.initialize_connection(
|
res_initialize = self.driver.initialize_connection(
|
||||||
@ -498,54 +521,63 @@ class EMCCoprHDISCSIDriverTest(test.TestCase):
|
|||||||
'target_iqn':
|
'target_iqn':
|
||||||
'50:00:09:73:00:18:95:19',
|
'50:00:09:73:00:18:95:19',
|
||||||
'target_discovered': False,
|
'target_discovered': False,
|
||||||
'volume_id': '1'}}
|
'volume_id': fake.VOLUME_ID}}
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
expected_initialize, res_initialize, 'Unexpected return data')
|
expected_initialize, res_initialize, 'Unexpected return data')
|
||||||
|
|
||||||
self.driver.terminate_connection(volume_data, connector_data)
|
self.driver.terminate_connection(volume_data, connector_data)
|
||||||
self.driver.delete_volume(volume_data)
|
self.driver.delete_volume(volume_data)
|
||||||
|
|
||||||
def test_create_delete_empty_CG(self):
|
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
|
||||||
cg_data = get_test_CG_data(self.volume_type_id)
|
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()
|
ctx = context.get_admin_context()
|
||||||
self.driver.create_consistencygroup(ctx, cg_data)
|
self.driver.create_group(ctx, group_data)
|
||||||
model_update, volumes_model_update = (
|
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')
|
self.assertEqual([], volumes_model_update, 'Unexpected return data')
|
||||||
|
|
||||||
def test_create_update_delete_CG(self):
|
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
|
||||||
cg_data = get_test_CG_data(self.volume_type_id)
|
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()
|
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)
|
self.driver.create_volume(volume)
|
||||||
|
|
||||||
model_update, ret1, ret2 = (
|
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)
|
||||||
|
|
||||||
model_update, volumes_model_update = (
|
model_update, volumes_model_update = (
|
||||||
self.driver.delete_consistencygroup(ctx, cg_data, [volume]))
|
self.driver.delete_group(ctx, group_data, [volume]))
|
||||||
self.assertEqual({'status': fields.ConsistencyGroupStatus.AVAILABLE},
|
self.assertEqual({'status': fields.GroupStatus.AVAILABLE},
|
||||||
model_update)
|
model_update)
|
||||||
self.assertEqual([{'status': 'deleted', 'id': '1'}],
|
self.assertEqual([{'status': 'deleted', 'id': fake.VOLUME_ID}],
|
||||||
volumes_model_update)
|
volumes_model_update)
|
||||||
|
|
||||||
def test_create_delete_CG_snap(self):
|
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
|
||||||
cg_snap_data = get_test_CG_snap_data(self.volume_type_id)
|
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()
|
ctx = context.get_admin_context()
|
||||||
|
|
||||||
model_update, snapshots_model_update = (
|
model_update, snapshots_model_update = (
|
||||||
self.driver.create_cgsnapshot(ctx, cg_snap_data, []))
|
self.driver.create_group_snapshot(ctx, group_snap_data, []))
|
||||||
self.assertEqual({'status': fields.ConsistencyGroupStatus.AVAILABLE},
|
self.assertEqual({'status': fields.GroupStatus.AVAILABLE},
|
||||||
model_update)
|
model_update)
|
||||||
self.assertEqual([], snapshots_model_update, 'Unexpected return data')
|
self.assertEqual([], snapshots_model_update, 'Unexpected return data')
|
||||||
|
|
||||||
model_update, snapshots_model_update = (
|
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({}, model_update, 'Unexpected return data')
|
||||||
self.assertEqual([], snapshots_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):
|
def create_coprhd_setup(self):
|
||||||
|
|
||||||
self.configuration = Mock()
|
self.configuration = mock.Mock()
|
||||||
self.configuration.coprhd_hostname = "10.10.10.10"
|
self.configuration.coprhd_hostname = "10.10.10.10"
|
||||||
self.configuration.coprhd_port = "4443"
|
self.configuration.coprhd_port = "4443"
|
||||||
self.configuration.volume_backend_name = "EMCCoprHDFCDriver"
|
self.configuration.volume_backend_name = "EMCCoprHDFCDriver"
|
||||||
@ -569,7 +601,10 @@ class EMCCoprHDFCDriverTest(test.TestCase):
|
|||||||
self.configuration.coprhd_varray = "varray"
|
self.configuration.coprhd_varray = "varray"
|
||||||
self.configuration.coprhd_emulate_snapshot = False
|
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,
|
self.mock_object(coprhd_fc.EMCCoprHDFCDriver,
|
||||||
'_get_common_driver',
|
'_get_common_driver',
|
||||||
@ -589,8 +624,7 @@ class EMCCoprHDFCDriverTest(test.TestCase):
|
|||||||
vipr_volume_type = volume_types.create(ctx,
|
vipr_volume_type = volume_types.create(ctx,
|
||||||
"coprhd-volume-type",
|
"coprhd-volume-type",
|
||||||
{'CoprHD:VPOOL': 'vpool_vipr'})
|
{'CoprHD:VPOOL': 'vpool_vipr'})
|
||||||
volume_id = vipr_volume_type['id']
|
return vipr_volume_type
|
||||||
return volume_id
|
|
||||||
|
|
||||||
def _get_mocked_common_driver(self):
|
def _get_mocked_common_driver(self):
|
||||||
return MockedEMCCoprHDDriverCommon(
|
return MockedEMCCoprHDDriverCommon(
|
||||||
@ -603,7 +637,7 @@ class EMCCoprHDFCDriverTest(test.TestCase):
|
|||||||
volume_types.destroy(ctx, self.volume_type_id)
|
volume_types.destroy(ctx, self.volume_type_id)
|
||||||
|
|
||||||
def test_create_destroy(self):
|
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.create_volume(volume)
|
||||||
self.driver.delete_volume(volume)
|
self.driver.delete_volume(volume)
|
||||||
@ -614,8 +648,8 @@ class EMCCoprHDFCDriverTest(test.TestCase):
|
|||||||
|
|
||||||
def test_create_volume_clone(self):
|
def test_create_volume_clone(self):
|
||||||
|
|
||||||
src_volume_data = get_test_volume_data(self.volume_type_id)
|
src_volume_data = test_volume_data(self.volume_type_id)
|
||||||
clone_volume_data = get_clone_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_volume(src_volume_data)
|
||||||
self.driver.create_cloned_volume(clone_volume_data, 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(src_volume_data)
|
||||||
@ -623,9 +657,9 @@ class EMCCoprHDFCDriverTest(test.TestCase):
|
|||||||
|
|
||||||
def test_create_destroy_snapshot(self):
|
def test_create_destroy_snapshot(self):
|
||||||
|
|
||||||
volume_data = get_test_volume_data(self.volume_type_id)
|
volume_data = test_volume_data(self.volume_type_id)
|
||||||
snapshot_data = get_test_snapshot_data(
|
snapshot_data = test_snapshot_data(
|
||||||
get_source_test_volume_data(self.volume_type_id))
|
source_test_volume_data(self.volume_type_id))
|
||||||
|
|
||||||
self.driver.create_volume(volume_data)
|
self.driver.create_volume(volume_data)
|
||||||
self.driver.create_snapshot(snapshot_data)
|
self.driver.create_snapshot(snapshot_data)
|
||||||
@ -633,11 +667,11 @@ class EMCCoprHDFCDriverTest(test.TestCase):
|
|||||||
self.driver.delete_volume(volume_data)
|
self.driver.delete_volume(volume_data)
|
||||||
|
|
||||||
def test_create_volume_from_snapshot(self):
|
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)
|
self.driver.create_volume(src_vol_data)
|
||||||
|
|
||||||
volume_data = get_test_volume_data(self.volume_type_id)
|
volume_data = test_volume_data(self.volume_type_id)
|
||||||
snapshot_data = get_test_snapshot_data(src_vol_data)
|
snapshot_data = test_snapshot_data(src_vol_data)
|
||||||
|
|
||||||
self.driver.create_snapshot(snapshot_data)
|
self.driver.create_snapshot(snapshot_data)
|
||||||
self.driver.create_volume_from_snapshot(volume_data, 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(src_vol_data)
|
||||||
self.driver.delete_volume(volume_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):
|
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.create_volume(volume_data)
|
||||||
self.driver.extend_volume(volume_data, 2)
|
self.driver.extend_volume(volume_data, 2)
|
||||||
self.driver.delete_volume(volume_data)
|
self.driver.delete_volume(volume_data)
|
||||||
@ -669,7 +689,7 @@ class EMCCoprHDFCDriverTest(test.TestCase):
|
|||||||
def test_initialize_and_terminate_connection(self):
|
def test_initialize_and_terminate_connection(self):
|
||||||
|
|
||||||
connector_data = get_connector_data()
|
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)
|
self.driver.create_volume(volume_data)
|
||||||
res_initiatlize = self.driver.initialize_connection(
|
res_initiatlize = self.driver.initialize_connection(
|
||||||
@ -686,7 +706,7 @@ class EMCCoprHDFCDriverTest(test.TestCase):
|
|||||||
'target_wwn': ['1234567890123456',
|
'target_wwn': ['1234567890123456',
|
||||||
'1234567890123456'],
|
'1234567890123456'],
|
||||||
'target_discovered': False,
|
'target_discovered': False,
|
||||||
'volume_id': '1'}}
|
'volume_id': fake.VOLUME_ID}}
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
expected_initialize, res_initiatlize, 'Unexpected return data')
|
expected_initialize, res_initiatlize, 'Unexpected return data')
|
||||||
|
|
||||||
@ -707,47 +727,56 @@ class EMCCoprHDFCDriverTest(test.TestCase):
|
|||||||
|
|
||||||
self.driver.delete_volume(volume_data)
|
self.driver.delete_volume(volume_data)
|
||||||
|
|
||||||
def test_create_delete_empty_CG(self):
|
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
|
||||||
cg_data = get_test_CG_data(self.volume_type_id)
|
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()
|
ctx = context.get_admin_context()
|
||||||
self.driver.create_consistencygroup(ctx, cg_data)
|
self.driver.create_group(ctx, group_data)
|
||||||
model_update, volumes_model_update = (
|
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')
|
self.assertEqual([], volumes_model_update, 'Unexpected return data')
|
||||||
|
|
||||||
def test_create_update_delete_CG(self):
|
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
|
||||||
cg_data = get_test_CG_data(self.volume_type_id)
|
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()
|
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)
|
self.driver.create_volume(volume)
|
||||||
|
|
||||||
model_update, ret1, ret2 = (
|
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)
|
||||||
|
|
||||||
model_update, volumes_model_update = (
|
model_update, volumes_model_update = (
|
||||||
self.driver.delete_consistencygroup(ctx, cg_data, [volume]))
|
self.driver.delete_group(ctx, group_data, [volume]))
|
||||||
self.assertEqual({'status': fields.ConsistencyGroupStatus.AVAILABLE},
|
self.assertEqual({'status': fields.GroupStatus.AVAILABLE},
|
||||||
model_update)
|
model_update)
|
||||||
self.assertEqual([{'status': 'deleted', 'id': '1'}],
|
self.assertEqual([{'status': 'deleted', 'id': fake.VOLUME_ID}],
|
||||||
volumes_model_update)
|
volumes_model_update)
|
||||||
|
|
||||||
def test_create_delete_CG_snap(self):
|
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
|
||||||
cg_snap_data = get_test_CG_snap_data(self.volume_type_id)
|
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()
|
ctx = context.get_admin_context()
|
||||||
|
|
||||||
model_update, snapshots_model_update = (
|
model_update, snapshots_model_update = (
|
||||||
self.driver.create_cgsnapshot(ctx, cg_snap_data, []))
|
self.driver.create_group_snapshot(ctx, group_snap_data, []))
|
||||||
self.assertEqual({'status': fields.ConsistencyGroupStatus.AVAILABLE},
|
self.assertEqual({'status': fields.GroupStatus.AVAILABLE},
|
||||||
model_update)
|
model_update)
|
||||||
self.assertEqual([], snapshots_model_update, 'Unexpected return data')
|
self.assertEqual([], snapshots_model_update, 'Unexpected return data')
|
||||||
|
|
||||||
model_update, snapshots_model_update = (
|
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({}, model_update, 'Unexpected return data')
|
||||||
self.assertEqual([], snapshots_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):
|
def create_coprhd_setup(self):
|
||||||
|
|
||||||
self.configuration = Mock()
|
self.configuration = mock.Mock()
|
||||||
self.configuration.coprhd_hostname = "10.10.10.10"
|
self.configuration.coprhd_hostname = "10.10.10.10"
|
||||||
self.configuration.coprhd_port = "4443"
|
self.configuration.coprhd_port = "4443"
|
||||||
self.configuration.volume_backend_name = "EMCCoprHDFCDriver"
|
self.configuration.volume_backend_name = "EMCCoprHDFCDriver"
|
||||||
@ -779,7 +808,10 @@ class EMCCoprHDScaleIODriverTest(test.TestCase):
|
|||||||
self.configuration.scaleio_server_certificate_path = (
|
self.configuration.scaleio_server_certificate_path = (
|
||||||
"/etc/scaleio/certs")
|
"/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,
|
self.mock_object(coprhd_scaleio.EMCCoprHDScaleIODriver,
|
||||||
'_get_common_driver',
|
'_get_common_driver',
|
||||||
@ -802,8 +834,7 @@ class EMCCoprHDScaleIODriverTest(test.TestCase):
|
|||||||
vipr_volume_type = volume_types.create(ctx,
|
vipr_volume_type = volume_types.create(ctx,
|
||||||
"coprhd-volume-type",
|
"coprhd-volume-type",
|
||||||
{'CoprHD:VPOOL': 'vpool_vipr'})
|
{'CoprHD:VPOOL': 'vpool_vipr'})
|
||||||
volume_id = vipr_volume_type['id']
|
return vipr_volume_type
|
||||||
return volume_id
|
|
||||||
|
|
||||||
def _get_mocked_common_driver(self):
|
def _get_mocked_common_driver(self):
|
||||||
return MockedEMCCoprHDDriverCommon(
|
return MockedEMCCoprHDDriverCommon(
|
||||||
@ -820,7 +851,7 @@ class EMCCoprHDScaleIODriverTest(test.TestCase):
|
|||||||
volume_types.destroy(ctx, self.volume_type_id)
|
volume_types.destroy(ctx, self.volume_type_id)
|
||||||
|
|
||||||
def test_create_destroy(self):
|
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.create_volume(volume)
|
||||||
self.driver.delete_volume(volume)
|
self.driver.delete_volume(volume)
|
||||||
@ -831,8 +862,8 @@ class EMCCoprHDScaleIODriverTest(test.TestCase):
|
|||||||
|
|
||||||
def test_create_volume_clone(self):
|
def test_create_volume_clone(self):
|
||||||
|
|
||||||
src_volume_data = get_test_volume_data(self.volume_type_id)
|
src_volume_data = test_volume_data(self.volume_type_id)
|
||||||
clone_volume_data = get_clone_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_volume(src_volume_data)
|
||||||
self.driver.create_cloned_volume(clone_volume_data, 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(src_volume_data)
|
||||||
@ -840,9 +871,9 @@ class EMCCoprHDScaleIODriverTest(test.TestCase):
|
|||||||
|
|
||||||
def test_create_destroy_snapshot(self):
|
def test_create_destroy_snapshot(self):
|
||||||
|
|
||||||
volume_data = get_test_volume_data(self.volume_type_id)
|
volume_data = test_volume_data(self.volume_type_id)
|
||||||
snapshot_data = get_test_snapshot_data(
|
snapshot_data = test_snapshot_data(
|
||||||
get_source_test_volume_data(self.volume_type_id))
|
source_test_volume_data(self.volume_type_id))
|
||||||
|
|
||||||
self.driver.create_volume(volume_data)
|
self.driver.create_volume(volume_data)
|
||||||
self.driver.create_snapshot(snapshot_data)
|
self.driver.create_snapshot(snapshot_data)
|
||||||
@ -850,11 +881,11 @@ class EMCCoprHDScaleIODriverTest(test.TestCase):
|
|||||||
self.driver.delete_volume(volume_data)
|
self.driver.delete_volume(volume_data)
|
||||||
|
|
||||||
def test_create_volume_from_snapshot(self):
|
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)
|
self.driver.create_volume(src_vol_data)
|
||||||
|
|
||||||
volume_data = get_test_volume_data(self.volume_type_id)
|
volume_data = test_volume_data(self.volume_type_id)
|
||||||
snapshot_data = get_test_snapshot_data(src_vol_data)
|
snapshot_data = test_snapshot_data(src_vol_data)
|
||||||
|
|
||||||
self.driver.create_snapshot(snapshot_data)
|
self.driver.create_snapshot(snapshot_data)
|
||||||
self.driver.create_volume_from_snapshot(volume_data, 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)
|
self.driver.delete_volume(volume_data)
|
||||||
|
|
||||||
def test_extend_volume(self):
|
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.create_volume(volume_data)
|
||||||
self.driver.extend_volume(volume_data, 2)
|
self.driver.extend_volume(volume_data, 2)
|
||||||
self.driver.delete_volume(volume_data)
|
self.driver.delete_volume(volume_data)
|
||||||
@ -872,16 +903,17 @@ class EMCCoprHDScaleIODriverTest(test.TestCase):
|
|||||||
def test_initialize_and_terminate_connection(self):
|
def test_initialize_and_terminate_connection(self):
|
||||||
|
|
||||||
connector_data = get_connector_data()
|
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)
|
self.driver.create_volume(volume_data)
|
||||||
res_initiatlize = self.driver.initialize_connection(
|
res_initiatlize = self.driver.initialize_connection(
|
||||||
volume_data, connector_data)
|
volume_data, connector_data)
|
||||||
|
exp_name = res_initiatlize['data']['scaleIO_volname']
|
||||||
expected_initialize = {'data': {'bandwidthLimit': None,
|
expected_initialize = {'data': {'bandwidthLimit': None,
|
||||||
'hostIP': '10.0.0.2',
|
'hostIP': '10.0.0.2',
|
||||||
'iopsLimit': None,
|
'iopsLimit': None,
|
||||||
'scaleIO_volname': 'test-vol1',
|
'scaleIO_volname': exp_name,
|
||||||
'scaleIO_volume_id': '1',
|
'scaleIO_volume_id': fake.PROVIDER_ID,
|
||||||
'serverIP': '10.10.10.11',
|
'serverIP': '10.10.10.11',
|
||||||
'serverPassword': 'scaleio_password',
|
'serverPassword': 'scaleio_password',
|
||||||
'serverPort': 443,
|
'serverPort': 443,
|
||||||
@ -895,46 +927,55 @@ class EMCCoprHDScaleIODriverTest(test.TestCase):
|
|||||||
volume_data, connector_data)
|
volume_data, connector_data)
|
||||||
self.driver.delete_volume(volume_data)
|
self.driver.delete_volume(volume_data)
|
||||||
|
|
||||||
def test_create_delete_empty_CG(self):
|
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
|
||||||
cg_data = get_test_CG_data(self.volume_type_id)
|
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()
|
ctx = context.get_admin_context()
|
||||||
self.driver.create_consistencygroup(ctx, cg_data)
|
self.driver.create_group(ctx, group_data)
|
||||||
model_update, volumes_model_update = (
|
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')
|
self.assertEqual([], volumes_model_update, 'Unexpected return data')
|
||||||
|
|
||||||
def test_create_update_delete_CG(self):
|
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
|
||||||
cg_data = get_test_CG_data(self.volume_type_id)
|
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()
|
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)
|
self.driver.create_volume(volume)
|
||||||
|
|
||||||
model_update, ret1, ret2 = (
|
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)
|
||||||
|
|
||||||
model_update, volumes_model_update = (
|
model_update, volumes_model_update = (
|
||||||
self.driver.delete_consistencygroup(ctx, cg_data, [volume]))
|
self.driver.delete_group(ctx, group_data, [volume]))
|
||||||
self.assertEqual({'status': fields.ConsistencyGroupStatus.AVAILABLE},
|
self.assertEqual({'status': fields.GroupStatus.AVAILABLE},
|
||||||
model_update)
|
model_update)
|
||||||
self.assertEqual([{'status': 'deleted', 'id': '1'}],
|
self.assertEqual([{'status': 'deleted', 'id': fake.VOLUME_ID}],
|
||||||
volumes_model_update)
|
volumes_model_update)
|
||||||
|
|
||||||
def test_create_delete_CG_snap(self):
|
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
|
||||||
cg_snap_data = get_test_CG_snap_data(self.volume_type_id)
|
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()
|
ctx = context.get_admin_context()
|
||||||
|
|
||||||
model_update, snapshots_model_update = (
|
model_update, snapshots_model_update = (
|
||||||
self.driver.create_cgsnapshot(ctx, cg_snap_data, []))
|
self.driver.create_group_snapshot(ctx, group_snap_data, []))
|
||||||
self.assertEqual({'status': fields.ConsistencyGroupStatus.AVAILABLE},
|
self.assertEqual({'status': fields.GroupStatus.AVAILABLE},
|
||||||
model_update)
|
model_update)
|
||||||
self.assertEqual([], snapshots_model_update, 'Unexpected return data')
|
self.assertEqual([], snapshots_model_update, 'Unexpected return data')
|
||||||
|
|
||||||
model_update, snapshots_model_update = (
|
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({}, model_update, 'Unexpected return data')
|
||||||
self.assertEqual([], snapshots_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 (
|
from cinder.volume.drivers.coprhd.helpers import (
|
||||||
virtualarray as coprhd_varray)
|
virtualarray as coprhd_varray)
|
||||||
from cinder.volume.drivers.coprhd.helpers import volume as coprhd_vol
|
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
|
from cinder.volume import volume_types
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
MAX_RETRIES = 10
|
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_VPOOL_VARRAY_CAPACITY = '/block/vpools/{0}/varrays/{1}/capacity'
|
||||||
URI_BLOCK_EXPORTS_FOR_INITIATORS = '/block/exports?initiators={0}'
|
URI_BLOCK_EXPORTS_FOR_INITIATORS = '/block/exports?initiators={0}'
|
||||||
EXPORT_RETRY_COUNT = 5
|
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):
|
def retry_wrapper(func):
|
||||||
@ -225,8 +229,9 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
|
|
||||||
def create_volume(self, vol, driver, truncate_name=False):
|
def create_volume(self, vol, driver, truncate_name=False):
|
||||||
self.authenticate_user()
|
self.authenticate_user()
|
||||||
name = self._get_resource_name(vol, truncate_name)
|
name = self._get_resource_name(vol, MAX_DEFAULT_NAME_LENGTH,
|
||||||
size = int(vol['size']) * units.Gi
|
truncate_name)
|
||||||
|
size = int(vol.size) * units.Gi
|
||||||
|
|
||||||
vpool = self._get_vpool(vol)
|
vpool = self._get_vpool(vol)
|
||||||
self.vpool = vpool['CoprHD:VPOOL']
|
self.vpool = vpool['CoprHD:VPOOL']
|
||||||
@ -234,14 +239,17 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
try:
|
try:
|
||||||
coprhd_cgid = None
|
coprhd_cgid = None
|
||||||
try:
|
try:
|
||||||
cgid = vol['consistencygroup_id']
|
if vol.group_id:
|
||||||
if cgid:
|
if volume_utils.is_group_a_cg_snapshot_type(vol.group):
|
||||||
coprhd_cgid = self._get_coprhd_cgid(cgid)
|
coprhd_cgid = self._get_coprhd_cgid(vol.group_id)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
coprhd_cgid = None
|
coprhd_cgid = None
|
||||||
|
except AttributeError:
|
||||||
|
coprhd_cgid = None
|
||||||
|
|
||||||
full_project_name = ("%s/%s" % (self.configuration.coprhd_tenant,
|
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.volume_obj.create(full_project_name, name, size,
|
||||||
self.configuration.coprhd_varray,
|
self.configuration.coprhd_varray,
|
||||||
self.vpool,
|
self.vpool,
|
||||||
@ -249,6 +257,7 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
sync=True,
|
sync=True,
|
||||||
# no longer specified in volume creation
|
# no longer specified in volume creation
|
||||||
consistencygroup=coprhd_cgid)
|
consistencygroup=coprhd_cgid)
|
||||||
|
|
||||||
except coprhd_utils.CoprHdError as e:
|
except coprhd_utils.CoprHdError as e:
|
||||||
coprhd_err_msg = (_("Volume %(name)s: create failed\n%(err)s") %
|
coprhd_err_msg = (_("Volume %(name)s: create failed\n%(err)s") %
|
||||||
{'name': name, 'err': six.text_type(e.msg)})
|
{'name': name, 'err': six.text_type(e.msg)})
|
||||||
@ -260,7 +269,9 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
@retry_wrapper
|
@retry_wrapper
|
||||||
def create_consistencygroup(self, context, group, truncate_name=False):
|
def create_consistencygroup(self, context, group, truncate_name=False):
|
||||||
self.authenticate_user()
|
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:
|
try:
|
||||||
self.consistencygroup_obj.create(
|
self.consistencygroup_obj.create(
|
||||||
@ -291,8 +302,8 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
def update_consistencygroup(self, group, add_volumes,
|
def update_consistencygroup(self, group, add_volumes,
|
||||||
remove_volumes):
|
remove_volumes):
|
||||||
self.authenticate_user()
|
self.authenticate_user()
|
||||||
model_update = {'status': fields.ConsistencyGroupStatus.AVAILABLE}
|
model_update = {'status': fields.GroupStatus.AVAILABLE}
|
||||||
cg_uri = self._get_coprhd_cgid(group['id'])
|
cg_uri = self._get_coprhd_cgid(group.id)
|
||||||
add_volnames = []
|
add_volnames = []
|
||||||
remove_volnames = []
|
remove_volnames = []
|
||||||
|
|
||||||
@ -329,7 +340,9 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
def delete_consistencygroup(self, context, group, volumes,
|
def delete_consistencygroup(self, context, group, volumes,
|
||||||
truncate_name=False):
|
truncate_name=False):
|
||||||
self.authenticate_user()
|
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 = []
|
volumes_model_update = []
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -344,20 +357,20 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
sync=True,
|
sync=True,
|
||||||
force_delete=True)
|
force_delete=True)
|
||||||
|
|
||||||
update_item = {'id': vol['id'],
|
update_item = {'id': vol.id,
|
||||||
'status':
|
'status':
|
||||||
fields.ConsistencyGroupStatus.DELETED}
|
fields.GroupStatus.DELETED}
|
||||||
volumes_model_update.append(update_item)
|
volumes_model_update.append(update_item)
|
||||||
|
|
||||||
except exception.VolumeBackendAPIException:
|
except exception.VolumeBackendAPIException:
|
||||||
update_item = {'id': vol['id'],
|
update_item = {'id': vol.id,
|
||||||
'status': fields.ConsistencyGroupStatus.
|
'status': fields.ConsistencyGroupStatus.
|
||||||
ERROR_DELETING}
|
ERROR_DELETING}
|
||||||
|
|
||||||
volumes_model_update.append(update_item)
|
volumes_model_update.append(update_item)
|
||||||
|
|
||||||
LOG.exception("Failed to delete the volume %s of CG.",
|
LOG.exception("Failed to delete the volume %s of CG.",
|
||||||
vol['name'])
|
vol.name)
|
||||||
|
|
||||||
self.consistencygroup_obj.delete(
|
self.consistencygroup_obj.delete(
|
||||||
name,
|
name,
|
||||||
@ -365,7 +378,7 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
self.configuration.coprhd_tenant)
|
self.configuration.coprhd_tenant)
|
||||||
|
|
||||||
model_update = {}
|
model_update = {}
|
||||||
model_update['status'] = group['status']
|
model_update['status'] = group.status
|
||||||
|
|
||||||
return model_update, volumes_model_update
|
return model_update, volumes_model_update
|
||||||
|
|
||||||
@ -384,9 +397,19 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
self.authenticate_user()
|
self.authenticate_user()
|
||||||
|
|
||||||
snapshots_model_update = []
|
snapshots_model_update = []
|
||||||
cgsnapshot_name = self._get_resource_name(cgsnapshot, truncate_name)
|
cgsnapshot_name = self._get_resource_name(cgsnapshot,
|
||||||
cg_id = cgsnapshot['consistencygroup_id']
|
MAX_SNAPSHOT_NAME_LENGTH,
|
||||||
cg_group = cgsnapshot.get('consistencygroup')
|
truncate_name)
|
||||||
|
|
||||||
|
cg_id = None
|
||||||
|
cg_group = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
cg_id = cgsnapshot.group_id
|
||||||
|
cg_group = cgsnapshot.group
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
cg_name = None
|
cg_name = None
|
||||||
coprhd_cgid = None
|
coprhd_cgid = None
|
||||||
|
|
||||||
@ -408,7 +431,7 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
True)
|
True)
|
||||||
|
|
||||||
for snapshot in snapshots:
|
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
|
# Finding the volume in CoprHD for this volume id
|
||||||
tagname = "OpenStack:id:" + vol_id_of_snap
|
tagname = "OpenStack:id:" + vol_id_of_snap
|
||||||
@ -470,7 +493,7 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
|
|
||||||
snapshot['status'] = fields.SnapshotStatus.AVAILABLE
|
snapshot['status'] = fields.SnapshotStatus.AVAILABLE
|
||||||
snapshots_model_update.append(
|
snapshots_model_update.append(
|
||||||
{'id': snapshot['id'], 'status':
|
{'id': snapshot.id, 'status':
|
||||||
fields.SnapshotStatus.AVAILABLE})
|
fields.SnapshotStatus.AVAILABLE})
|
||||||
|
|
||||||
model_update = {'status': fields.ConsistencyGroupStatus.AVAILABLE}
|
model_update = {'status': fields.ConsistencyGroupStatus.AVAILABLE}
|
||||||
@ -493,19 +516,28 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
@retry_wrapper
|
@retry_wrapper
|
||||||
def delete_cgsnapshot(self, cgsnapshot, snapshots, truncate_name=False):
|
def delete_cgsnapshot(self, cgsnapshot, snapshots, truncate_name=False):
|
||||||
self.authenticate_user()
|
self.authenticate_user()
|
||||||
cgsnapshot_id = cgsnapshot['id']
|
cgsnapshot_id = cgsnapshot.id
|
||||||
cgsnapshot_name = self._get_resource_name(cgsnapshot, truncate_name)
|
cgsnapshot_name = self._get_resource_name(cgsnapshot,
|
||||||
|
MAX_SNAPSHOT_NAME_LENGTH,
|
||||||
|
truncate_name)
|
||||||
|
|
||||||
snapshots_model_update = []
|
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)
|
coprhd_cgid = self._get_coprhd_cgid(cg_id)
|
||||||
cg_name = self._get_consistencygroup_name(cg_group)
|
cg_name = self._get_consistencygroup_name(cg_group)
|
||||||
|
|
||||||
model_update = {}
|
model_update = {}
|
||||||
LOG.info('Delete cgsnapshot %(snap_name)s for consistency group: '
|
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})
|
'group_name': cg_name})
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -531,7 +563,7 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
|
|
||||||
for snapshot in snapshots:
|
for snapshot in snapshots:
|
||||||
snapshots_model_update.append(
|
snapshots_model_update.append(
|
||||||
{'id': snapshot['id'],
|
{'id': snapshot.id,
|
||||||
'status': fields.SnapshotStatus.DELETED})
|
'status': fields.SnapshotStatus.DELETED})
|
||||||
|
|
||||||
return model_update, snapshots_model_update
|
return model_update, snapshots_model_update
|
||||||
@ -557,7 +589,9 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
exempt_tags = []
|
exempt_tags = []
|
||||||
|
|
||||||
self.authenticate_user()
|
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" % (
|
full_project_name = ("%s/%s" % (
|
||||||
self.configuration.coprhd_tenant,
|
self.configuration.coprhd_tenant,
|
||||||
self.configuration.coprhd_project))
|
self.configuration.coprhd_project))
|
||||||
@ -613,11 +647,16 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
if ((not prop.startswith("status") and not
|
if ((not prop.startswith("status") and not
|
||||||
prop.startswith("obj_status") and
|
prop.startswith("obj_status") and
|
||||||
prop != "obj_volume") and value):
|
prop != "obj_volume") and value):
|
||||||
add_tags.append(
|
tag = ("%s:%s:%s" %
|
||||||
"%s:%s:%s" % (self.OPENSTACK_TAG, prop,
|
(self.OPENSTACK_TAG, prop,
|
||||||
six.text_type(value)))
|
six.text_type(value)))
|
||||||
|
|
||||||
|
if len(tag) > 128:
|
||||||
|
tag = tag[0:128]
|
||||||
|
add_tags.append(tag)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
LOG.error("Error tagging the resource property %s", prop)
|
LOG.error(
|
||||||
|
"Error tagging the resource property %s", prop)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
LOG.error("Error tagging the resource properties")
|
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):
|
def create_cloned_volume(self, vol, src_vref, truncate_name=False):
|
||||||
"""Creates a clone of the specified volume."""
|
"""Creates a clone of the specified volume."""
|
||||||
self.authenticate_user()
|
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)
|
srcname = self._get_coprhd_volume_name(src_vref)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if src_vref['consistencygroup_id']:
|
if src_vref.group_id:
|
||||||
raise coprhd_utils.CoprHdError(
|
raise coprhd_utils.CoprHdError(
|
||||||
coprhd_utils.CoprHdError.SOS_FAILURE_ERR,
|
coprhd_utils.CoprHdError.SOS_FAILURE_ERR,
|
||||||
_("Clone can't be taken individually on a volume"
|
_("Clone can't be taken individually on a volume"
|
||||||
" that is part of a Consistency Group"))
|
" that is part of a Consistency Group"))
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
pass
|
pass
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
try:
|
try:
|
||||||
(storageres_type,
|
(storageres_type,
|
||||||
storageres_typename) = self.volume_obj.get_storageAttributes(
|
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,
|
self._raise_or_log_exception(e.err_code, coprhd_err_msg,
|
||||||
log_err_msg)
|
log_err_msg)
|
||||||
|
|
||||||
try:
|
src_vol_size = 0
|
||||||
src_vol_size = src_vref['size']
|
dest_vol_size = 0
|
||||||
except KeyError:
|
|
||||||
src_vol_size = src_vref['volume_size']
|
|
||||||
|
|
||||||
if vol['size'] > src_vol_size:
|
try:
|
||||||
size_in_bytes = coprhd_utils.to_bytes("%sG" % vol['size'])
|
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:
|
try:
|
||||||
self.volume_obj.expand(
|
self.volume_obj.expand(
|
||||||
("%s/%s" % (self.configuration.coprhd_tenant,
|
("%s/%s" % (self.configuration.coprhd_tenant,
|
||||||
@ -733,7 +784,8 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
{'volume_name': volume_name,
|
{'volume_name': volume_name,
|
||||||
'err': six.text_type(e.msg)})
|
'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,
|
self._raise_or_log_exception(e.err_code, coprhd_err_msg,
|
||||||
log_err_msg)
|
log_err_msg)
|
||||||
|
|
||||||
@ -747,15 +799,20 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
self.create_cloned_volume(volume, snapshot, truncate_name)
|
self.create_cloned_volume(volume, snapshot, truncate_name)
|
||||||
return
|
return
|
||||||
|
|
||||||
if snapshot.get('cgsnapshot_id'):
|
try:
|
||||||
raise coprhd_utils.CoprHdError(
|
if snapshot.group_snapshot_id:
|
||||||
coprhd_utils.CoprHdError.SOS_FAILURE_ERR,
|
raise coprhd_utils.CoprHdError(
|
||||||
_("Volume cannot be created individually from a snapshot "
|
coprhd_utils.CoprHdError.SOS_FAILURE_ERR,
|
||||||
"that is part of a Consistency Group"))
|
_("Volume cannot be created individually from a snapshot "
|
||||||
|
"that is part of a Consistency Group"))
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
src_snapshot_name = None
|
src_snapshot_name = None
|
||||||
src_vol_ref = snapshot['volume']
|
src_vol_ref = snapshot.volume
|
||||||
new_volume_name = self._get_resource_name(volume, truncate_name)
|
new_volume_name = self._get_resource_name(volume,
|
||||||
|
MAX_DEFAULT_NAME_LENGTH,
|
||||||
|
truncate_name)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
coprhd_vol_info = self._get_coprhd_volume_name(
|
coprhd_vol_info = self._get_coprhd_volume_name(
|
||||||
@ -786,12 +843,13 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
{'src_snapshot_name': src_snapshot_name,
|
{'src_snapshot_name': src_snapshot_name,
|
||||||
'err': six.text_type(e.msg)})
|
'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,
|
self._raise_or_log_exception(e.err_code, coprhd_err_msg,
|
||||||
log_err_msg)
|
log_err_msg)
|
||||||
|
|
||||||
if volume['size'] > snapshot['volume_size']:
|
if volume.size > snapshot.volume_size:
|
||||||
size_in_bytes = coprhd_utils.to_bytes("%sG" % volume['size'])
|
size_in_bytes = coprhd_utils.to_bytes("%sG" % volume.size)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.volume_obj.expand(
|
self.volume_obj.expand(
|
||||||
@ -805,7 +863,8 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
{'volume_name': new_volume_name,
|
{'volume_name': new_volume_name,
|
||||||
'err': six.text_type(e.msg)})
|
'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,
|
self._raise_or_log_exception(e.err_code, coprhd_err_msg,
|
||||||
log_err_msg)
|
log_err_msg)
|
||||||
|
|
||||||
@ -829,7 +888,7 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
"\n%(err)s") %
|
"\n%(err)s") %
|
||||||
{'name': name, 'err': six.text_type(e.msg)})
|
{'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,
|
self._raise_or_log_exception(e.err_code, coprhd_err_msg,
|
||||||
log_err_msg)
|
log_err_msg)
|
||||||
|
|
||||||
@ -837,10 +896,10 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
def create_snapshot(self, snapshot, truncate_name=False):
|
def create_snapshot(self, snapshot, truncate_name=False):
|
||||||
self.authenticate_user()
|
self.authenticate_user()
|
||||||
|
|
||||||
volume = snapshot['volume']
|
volume = snapshot.volume
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if volume['consistencygroup_id']:
|
if volume.group_id:
|
||||||
raise coprhd_utils.CoprHdError(
|
raise coprhd_utils.CoprHdError(
|
||||||
coprhd_utils.CoprHdError.SOS_FAILURE_ERR,
|
coprhd_utils.CoprHdError.SOS_FAILURE_ERR,
|
||||||
_("Snapshot can't be taken individually on a volume"
|
_("Snapshot can't be taken individually on a volume"
|
||||||
@ -855,8 +914,10 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
snapshotname = self._get_resource_name(snapshot, truncate_name)
|
snapshotname = self._get_resource_name(snapshot,
|
||||||
vol = snapshot['volume']
|
MAX_SNAPSHOT_NAME_LENGTH,
|
||||||
|
truncate_name)
|
||||||
|
vol = snapshot.volume
|
||||||
|
|
||||||
volumename = self._get_coprhd_volume_name(vol)
|
volumename = self._get_coprhd_volume_name(vol)
|
||||||
projectname = self.configuration.coprhd_project
|
projectname = self.configuration.coprhd_project
|
||||||
@ -894,7 +955,7 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
"\n%(err)s") % {'snapshotname': snapshotname,
|
"\n%(err)s") % {'snapshotname': snapshotname,
|
||||||
'err': six.text_type(e.msg)})
|
'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,
|
self._raise_or_log_exception(e.err_code, coprhd_err_msg,
|
||||||
log_err_msg)
|
log_err_msg)
|
||||||
|
|
||||||
@ -902,10 +963,10 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
def delete_snapshot(self, snapshot):
|
def delete_snapshot(self, snapshot):
|
||||||
self.authenticate_user()
|
self.authenticate_user()
|
||||||
|
|
||||||
vol = snapshot['volume']
|
vol = snapshot.volume
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if vol['consistencygroup_id']:
|
if vol.group_id:
|
||||||
raise coprhd_utils.CoprHdError(
|
raise coprhd_utils.CoprHdError(
|
||||||
coprhd_utils.CoprHdError.SOS_FAILURE_ERR,
|
coprhd_utils.CoprHdError.SOS_FAILURE_ERR,
|
||||||
_("Snapshot delete can't be done individually on a volume"
|
_("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") %
|
coprhd_err_msg = (_("Snapshot %s : Delete Failed\n") %
|
||||||
snapshotname)
|
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,
|
self._raise_or_log_exception(e.err_code, coprhd_err_msg,
|
||||||
log_err_msg)
|
log_err_msg)
|
||||||
|
|
||||||
@ -1170,7 +1231,7 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
(_("Consistency Group %s not found") % cgid))
|
(_("Consistency Group %s not found") % cgid))
|
||||||
|
|
||||||
def _get_consistencygroup_name(self, consisgrp):
|
def _get_consistencygroup_name(self, consisgrp):
|
||||||
return consisgrp['name']
|
return consisgrp.name
|
||||||
|
|
||||||
def _get_coprhd_snapshot_name(self, snapshot, resUri):
|
def _get_coprhd_snapshot_name(self, snapshot, resUri):
|
||||||
tagname = self.OPENSTACK_TAG + ":id:" + snapshot['id']
|
tagname = self.OPENSTACK_TAG + ":id:" + snapshot['id']
|
||||||
@ -1200,7 +1261,7 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
return rslt_snap['name']
|
return rslt_snap['name']
|
||||||
|
|
||||||
def _get_coprhd_volume_name(self, vol, verbose=False):
|
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(
|
rslt = coprhd_utils.search_by_tag(
|
||||||
coprhd_vol.Volume.URI_SEARCH_VOLUMES_BY_TAG.format(tagname),
|
coprhd_vol.Volume.URI_SEARCH_VOLUMES_BY_TAG.format(tagname),
|
||||||
self.configuration.coprhd_hostname,
|
self.configuration.coprhd_hostname,
|
||||||
@ -1210,7 +1271,7 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
# as "OpenStack:obj_id"
|
# as "OpenStack:obj_id"
|
||||||
# as snapshots will be having the obj_id instead of just id.
|
# as snapshots will be having the obj_id instead of just id.
|
||||||
if len(rslt) == 0:
|
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(
|
rslt = coprhd_utils.search_by_tag(
|
||||||
coprhd_vol.Volume.URI_SEARCH_VOLUMES_BY_TAG.format(tagname),
|
coprhd_vol.Volume.URI_SEARCH_VOLUMES_BY_TAG.format(tagname),
|
||||||
self.configuration.coprhd_hostname,
|
self.configuration.coprhd_hostname,
|
||||||
@ -1228,21 +1289,36 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
coprhd_utils.CoprHdError.NOT_FOUND_ERR,
|
coprhd_utils.CoprHdError.NOT_FOUND_ERR,
|
||||||
(_("Volume %s not found") % vol['display_name']))
|
(_("Volume %s not found") % vol['display_name']))
|
||||||
|
|
||||||
def _get_resource_name(self, resource, truncate_name=False):
|
def _get_resource_name(self, resource,
|
||||||
name = resource.get('display_name', None)
|
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:
|
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)
|
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):
|
def _get_vpool(self, volume):
|
||||||
vpool = {}
|
vpool = {}
|
||||||
ctxt = context.get_admin_context()
|
ctxt = context.get_admin_context()
|
||||||
type_id = volume['volume_type_id']
|
type_id = volume.volume_type_id
|
||||||
if type_id is not None:
|
if type_id is not None:
|
||||||
volume_type = volume_types.get_volume_type(ctxt, type_id)
|
volume_type = volume_types.get_volume_type(ctxt, type_id)
|
||||||
specs = volume_type.get('extra_specs')
|
specs = volume_type.get('extra_specs')
|
||||||
@ -1363,7 +1439,8 @@ class EMCCoprHDDriverCommon(object):
|
|||||||
self.authenticate_user()
|
self.authenticate_user()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.stats['consistencygroup_support'] = 'True'
|
self.stats['consistencygroup_support'] = True
|
||||||
|
self.stats['consistent_group_snapshot_enabled'] = True
|
||||||
vols = self.volume_obj.list_volumes(
|
vols = self.volume_obj.list_volumes(
|
||||||
self.configuration.coprhd_tenant +
|
self.configuration.coprhd_tenant +
|
||||||
"/" +
|
"/" +
|
||||||
|
@ -20,9 +20,13 @@ import re
|
|||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
|
from cinder import exception
|
||||||
|
from cinder.i18n import _
|
||||||
from cinder import interface
|
from cinder import interface
|
||||||
from cinder.volume import driver
|
from cinder.volume import driver
|
||||||
from cinder.volume.drivers.coprhd import common as coprhd_common
|
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
|
from cinder.zonemanager import utils as fczm_utils
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@ -89,30 +93,67 @@ class EMCCoprHDFCDriver(driver.FibreChannelDriver):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def remove_export(self, context, volume):
|
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
|
pass
|
||||||
|
|
||||||
def create_consistencygroup(self, context, group):
|
def create_group(self, context, group):
|
||||||
"""Creates a consistencygroup."""
|
"""Creates a group."""
|
||||||
return self.common.create_consistencygroup(context, 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,
|
# If the group is not consistency group snapshot enabled, then
|
||||||
remove_volumes=None):
|
# we shall rely on generic volume group implementation
|
||||||
"""Updates volumes in consistency group."""
|
raise NotImplementedError()
|
||||||
return self.common.update_consistencygroup(group, add_volumes,
|
|
||||||
remove_volumes)
|
|
||||||
|
|
||||||
def delete_consistencygroup(self, context, group, volumes):
|
def update_group(self, context, group, add_volumes=None,
|
||||||
"""Deletes a consistency group."""
|
remove_volumes=None):
|
||||||
return self.common.delete_consistencygroup(context, group, volumes)
|
"""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):
|
# If the group is not consistency group snapshot enabled, then
|
||||||
"""Creates a cgsnapshot."""
|
# we shall rely on generic volume group implementation
|
||||||
return self.common.create_cgsnapshot(cgsnapshot, snapshots)
|
raise NotImplementedError()
|
||||||
|
|
||||||
def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
|
def create_group_from_src(self, ctxt, group, volumes,
|
||||||
"""Deletes a cgsnapshot."""
|
group_snapshot=None, snapshots=None,
|
||||||
return self.common.delete_cgsnapshot(cgsnapshot, snapshots)
|
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):
|
def check_for_export(self, context, volume_id):
|
||||||
"""Make sure volume is exported."""
|
"""Make sure volume is exported."""
|
||||||
@ -123,14 +164,12 @@ class EMCCoprHDFCDriver(driver.FibreChannelDriver):
|
|||||||
"""Initializes the connection and returns connection info."""
|
"""Initializes the connection and returns connection info."""
|
||||||
|
|
||||||
properties = {}
|
properties = {}
|
||||||
properties['volume_id'] = volume['id']
|
properties['volume_id'] = volume.id
|
||||||
properties['target_discovered'] = False
|
properties['target_discovered'] = False
|
||||||
properties['target_wwn'] = []
|
properties['target_wwn'] = []
|
||||||
|
|
||||||
init_ports = self._build_initport_list(connector)
|
init_ports = self._build_initport_list(connector)
|
||||||
itls = self.common.initialize_connection(volume,
|
itls = self.common.initialize_connection(volume, 'FC', init_ports,
|
||||||
'FC',
|
|
||||||
init_ports,
|
|
||||||
connector['host'])
|
connector['host'])
|
||||||
|
|
||||||
target_wwns = None
|
target_wwns = None
|
||||||
@ -144,7 +183,12 @@ class EMCCoprHDFCDriver(driver.FibreChannelDriver):
|
|||||||
properties['target_wwn'] = target_wwns
|
properties['target_wwn'] = target_wwns
|
||||||
properties['initiator_target_map'] = initiator_target_map
|
properties['initiator_target_map'] = initiator_target_map
|
||||||
|
|
||||||
auth = volume['provider_auth']
|
auth = None
|
||||||
|
try:
|
||||||
|
auth = volume.provider_auth
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
if auth:
|
if auth:
|
||||||
(auth_method, auth_username, auth_secret) = auth.split()
|
(auth_method, auth_username, auth_secret) = auth.split()
|
||||||
properties['auth_method'] = auth_method
|
properties['auth_method'] = auth_method
|
||||||
@ -162,9 +206,7 @@ class EMCCoprHDFCDriver(driver.FibreChannelDriver):
|
|||||||
"""Driver entry point to detach a volume from an instance."""
|
"""Driver entry point to detach a volume from an instance."""
|
||||||
|
|
||||||
init_ports = self._build_initport_list(connector)
|
init_ports = self._build_initport_list(connector)
|
||||||
itls = self.common.terminate_connection(volume,
|
itls = self.common.terminate_connection(volume, 'FC', init_ports,
|
||||||
'FC',
|
|
||||||
init_ports,
|
|
||||||
connector['host'])
|
connector['host'])
|
||||||
|
|
||||||
volumes_count = self.common.get_exports_count_by_initiators(init_ports)
|
volumes_count = self.common.get_exports_count_by_initiators(init_ports)
|
||||||
|
@ -18,10 +18,12 @@
|
|||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
|
from cinder import exception
|
||||||
|
from cinder.i18n import _
|
||||||
from cinder import interface
|
from cinder import interface
|
||||||
from cinder.volume import driver
|
from cinder.volume import driver
|
||||||
from cinder.volume.drivers.coprhd import common as coprhd_common
|
from cinder.volume.drivers.coprhd import common as coprhd_common
|
||||||
|
from cinder.volume import utils as volume_utils
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -67,7 +69,7 @@ class EMCCoprHDISCSIDriver(driver.ISCSIDriver):
|
|||||||
self.common.expand_volume(volume, new_size)
|
self.common.expand_volume(volume, new_size)
|
||||||
|
|
||||||
def delete_volume(self, volume):
|
def delete_volume(self, volume):
|
||||||
"""Deletes an volume."""
|
"""Deletes a volume."""
|
||||||
self.common.delete_volume(volume)
|
self.common.delete_volume(volume)
|
||||||
|
|
||||||
def create_snapshot(self, snapshot):
|
def create_snapshot(self, snapshot):
|
||||||
@ -90,27 +92,65 @@ class EMCCoprHDISCSIDriver(driver.ISCSIDriver):
|
|||||||
"""Driver entry point to remove an export for a volume."""
|
"""Driver entry point to remove an export for a volume."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def create_consistencygroup(self, context, group):
|
def create_group(self, context, group):
|
||||||
"""Creates a consistencygroup."""
|
"""Creates a group."""
|
||||||
return self.common.create_consistencygroup(context, 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):
|
# If the group is not consistency group snapshot enabled, then
|
||||||
"""Deletes a consistency group."""
|
# we shall rely on generic volume group implementation
|
||||||
return self.common.delete_consistencygroup(context, group, volumes)
|
raise NotImplementedError()
|
||||||
|
|
||||||
def update_consistencygroup(self, context, group,
|
def create_group_from_src(self, ctxt, group, volumes,
|
||||||
add_volumes=None, remove_volumes=None):
|
group_snapshot=None, snapshots=None,
|
||||||
"""Updates volumes in consistency group."""
|
source_group=None, source_vols=None):
|
||||||
return self.common.update_consistencygroup(group, add_volumes,
|
"""Creates a group from source."""
|
||||||
remove_volumes)
|
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):
|
def update_group(self, context, group, add_volumes=None,
|
||||||
"""Creates a cgsnapshot."""
|
remove_volumes=None):
|
||||||
return self.common.create_cgsnapshot(cgsnapshot, snapshots)
|
"""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):
|
# If the group is not consistency group snapshot enabled, then
|
||||||
"""Deletes a cgsnapshot."""
|
# we shall rely on generic volume group implementation
|
||||||
return self.common.delete_cgsnapshot(cgsnapshot, snapshots)
|
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):
|
def check_for_export(self, context, volume_id):
|
||||||
"""Make sure volume is exported."""
|
"""Make sure volume is exported."""
|
||||||
@ -127,14 +167,20 @@ class EMCCoprHDISCSIDriver(driver.ISCSIDriver):
|
|||||||
connector['host'])
|
connector['host'])
|
||||||
properties = {}
|
properties = {}
|
||||||
properties['target_discovered'] = False
|
properties['target_discovered'] = False
|
||||||
properties['volume_id'] = volume['id']
|
properties['volume_id'] = volume.id
|
||||||
if itls:
|
if itls:
|
||||||
properties['target_iqn'] = itls[0]['target']['port']
|
properties['target_iqn'] = itls[0]['target']['port']
|
||||||
properties['target_portal'] = '%s:%s' % (
|
properties['target_portal'] = '%s:%s' % (
|
||||||
itls[0]['target']['ip_address'],
|
itls[0]['target']['ip_address'],
|
||||||
itls[0]['target']['tcp_port'])
|
itls[0]['target']['tcp_port'])
|
||||||
properties['target_lun'] = itls[0]['hlu']
|
properties['target_lun'] = itls[0]['hlu']
|
||||||
auth = volume['provider_auth']
|
|
||||||
|
auth = None
|
||||||
|
try:
|
||||||
|
auth = volume.provider_auth
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
if auth:
|
if auth:
|
||||||
(auth_method, auth_username, auth_secret) = auth.split()
|
(auth_method, auth_username, auth_secret) = auth.split()
|
||||||
properties['auth_method'] = auth_method
|
properties['auth_method'] = auth_method
|
||||||
|
@ -29,6 +29,7 @@ from cinder import interface
|
|||||||
from cinder.volume import configuration
|
from cinder.volume import configuration
|
||||||
from cinder.volume import driver
|
from cinder.volume import driver
|
||||||
from cinder.volume.drivers.coprhd import common as coprhd_common
|
from cinder.volume.drivers.coprhd import common as coprhd_common
|
||||||
|
from cinder.volume import utils as volume_utils
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@ -92,7 +93,7 @@ class EMCCoprHDScaleIODriver(driver.VolumeDriver):
|
|||||||
"""Creates a Volume."""
|
"""Creates a Volume."""
|
||||||
self.common.create_volume(volume, self, True)
|
self.common.create_volume(volume, self, True)
|
||||||
self.common.set_volume_tags(volume, ['_obj_volume_type'], 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}
|
return {'size': vol_size}
|
||||||
|
|
||||||
def _update_volume_size(self, 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."""
|
"""Driver exntry point to remove an export for a volume."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def create_consistencygroup(self, context, group):
|
def create_group(self, context, group):
|
||||||
"""Creates a consistencygroup."""
|
"""Creates a group."""
|
||||||
return self.common.create_consistencygroup(context, group, True)
|
if volume_utils.is_group_a_cg_snapshot_type(group):
|
||||||
|
return self.common.create_consistencygroup(context, group, True)
|
||||||
|
|
||||||
def update_consistencygroup(self, context, group,
|
# If the group is not consistency group snapshot enabled, then
|
||||||
add_volumes=None, remove_volumes=None):
|
# we shall rely on generic volume group implementation
|
||||||
"""Updates volumes in consistency group."""
|
raise NotImplementedError()
|
||||||
return self.common.update_consistencygroup(group, add_volumes,
|
|
||||||
remove_volumes)
|
|
||||||
|
|
||||||
def delete_consistencygroup(self, context, group, volumes):
|
def update_group(self, context, group, add_volumes=None,
|
||||||
"""Deletes a consistency group."""
|
remove_volumes=None):
|
||||||
return self.common.delete_consistencygroup(context, group,
|
"""Updates volumes in group."""
|
||||||
volumes, True)
|
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):
|
# If the group is not consistency group snapshot enabled, then
|
||||||
"""Creates a cgsnapshot."""
|
# we shall rely on generic volume group implementation
|
||||||
return self.common.create_cgsnapshot(cgsnapshot, snapshots, True)
|
raise NotImplementedError()
|
||||||
|
|
||||||
def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
|
def create_group_from_src(self, ctxt, group, volumes,
|
||||||
"""Deletes a cgsnapshot."""
|
group_snapshot=None, snapshots=None,
|
||||||
return self.common.delete_cgsnapshot(cgsnapshot, snapshots, True)
|
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):
|
def check_for_export(self, context, volume_id):
|
||||||
"""Make sure volume is exported."""
|
"""Make sure volume is exported."""
|
||||||
@ -171,11 +212,13 @@ class EMCCoprHDScaleIODriver(driver.VolumeDriver):
|
|||||||
def initialize_connection(self, volume, connector):
|
def initialize_connection(self, volume, connector):
|
||||||
"""Initializes the connection and returns connection info."""
|
"""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 = {}
|
||||||
properties['scaleIO_volname'] = volname
|
properties['scaleIO_volname'] = volname
|
||||||
properties['scaleIO_volume_id'] = volume['provider_id']
|
properties['scaleIO_volume_id'] = volume.provider_id
|
||||||
properties['hostIP'] = connector['ip']
|
properties['hostIP'] = connector['ip']
|
||||||
properties[
|
properties[
|
||||||
'serverIP'] = self.configuration.coprhd_scaleio_rest_gateway_host
|
'serverIP'] = self.configuration.coprhd_scaleio_rest_gateway_host
|
||||||
@ -215,10 +258,10 @@ class EMCCoprHDScaleIODriver(driver.VolumeDriver):
|
|||||||
def terminate_connection(self, volume, connector, **kwargs):
|
def terminate_connection(self, volume, connector, **kwargs):
|
||||||
"""Disallow connection from connector."""
|
"""Disallow connection from connector."""
|
||||||
|
|
||||||
volname = volume['display_name']
|
volname = volume.display_name
|
||||||
properties = {}
|
properties = {}
|
||||||
properties['scaleIO_volname'] = volname
|
properties['scaleIO_volname'] = volname
|
||||||
properties['scaleIO_volume_id'] = volume['provider_id']
|
properties['scaleIO_volume_id'] = volume.provider_id
|
||||||
properties['hostIP'] = connector['ip']
|
properties['hostIP'] = connector['ip']
|
||||||
properties[
|
properties[
|
||||||
'serverIP'] = self.configuration.coprhd_scaleio_rest_gateway_host
|
'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