# Copyright (c) 2014 ProphetStor, Inc. # All Rights Reserved. # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import errno import re from unittest import mock from oslo_utils import units from six.moves import http_client from cinder import context from cinder import exception from cinder.objects import fields from cinder.tests.unit import fake_constants from cinder.tests.unit import fake_snapshot from cinder.tests.unit import test from cinder.tests.unit import utils as test_utils from cinder.volume import configuration as conf from cinder.volume.drivers.prophetstor import dpl_iscsi as DPLDRIVER from cinder.volume.drivers.prophetstor import dplcommon as DPLCOMMON from cinder.volume import group_types POOLUUID = 'ac33fc6e417440d5a1ef27d7231e1cc4' VOLUMEUUID = 'a000000000000000000000000000001' INITIATOR = 'iqn.2013-08.org.debian:01:aaaaaaaa' DATA_IN_CONNECTOR = {'initiator': INITIATOR} DATA_SERVER_INFO = 0, { 'metadata': {'vendor': 'ProphetStor', 'version': '1.5'}} DATA_POOLS = 0, { 'children': [POOLUUID] } DATA_POOLINFO = 0, { 'capabilitiesURI': '', 'children': [], 'childrenrange': '', 'completionStatus': 'Complete', 'metadata': {'available_capacity': 4294967296, 'ctime': 1390551362349, 'vendor': 'prophetstor', 'version': '1.5', 'display_description': 'Default Pool', 'display_name': 'default_pool', 'event_uuid': '4f7c4d679a664857afa4d51f282a516a', 'physical_device': {'cache': [], 'data': ['disk_uuid_0', 'disk_uuid_1', 'disk_uuid_2'], 'log': [], 'spare': []}, 'pool_uuid': POOLUUID, 'properties': {'raid_level': 'raid0'}, 'state': 'Online', 'used_capacity': 0, 'total_capacity': 4294967296, 'zpool_guid': '8173612007304181810'}, 'objectType': 'application/cdmi-container', 'percentComplete': 100} DATA_ASSIGNVDEV = 0, { 'children': [], 'childrenrange': '', 'completionStatus': 'Complete', 'domainURI': '', 'exports': {'Network/iSCSI': [ {'logical_unit_name': '', 'logical_unit_number': '101', 'permissions': [INITIATOR], 'portals': ['172.31.1.210:3260'], 'target_identifier': 'iqn.2013-09.com.prophetstor:hypervisor.886423051816' }]}, 'metadata': {'ctime': 0, 'event_uuid': 'c11e90287e9348d0b4889695f1ec4be5', 'type': 'volume'}, 'objectID': '', 'objectName': 'd827e23d403f4f12bb208a6fec208fd8', 'objectType': 'application/cdmi-container', 'parentID': '8daa374670af447e8efea27e16bf84cd', 'parentURI': '/dpl_volume', 'snapshots': [] } DATA_OUTPUT = 0, None MOD_OUTPUT = {'status': 'available'} DATA_IN_GROUP = {'id': 'fe2dbc51-5810-451d-ab2f-8c8a48d15bee', 'name': 'group123', 'description': 'des123', 'status': ''} DATA_IN_VOLUME = {'id': 'c11e902-87e9-348d-0b48-89695f1ec4be5', 'display_name': 'abc123', 'display_description': '', 'size': 10, 'host': "hostname@backend#%s" % POOLUUID} DATA_IN_VOLUME_VG = {'id': 'fe2dbc5-1581-0451-dab2-f8c8a48d15bee', 'display_name': 'abc123', 'display_description': '', 'size': 10, 'group_id': 'fe2dbc51-5810-451d-ab2f-8c8a48d15bee', 'status': 'available', 'host': "hostname@backend#%s" % POOLUUID} DATA_IN_REMOVE_VOLUME_VG = { 'id': 'fe2dbc515810451dab2f8c8a48d15bee', 'display_name': 'fe2dbc515810451dab2f8c8a48d15bee', 'display_description': '', 'size': 10, 'group_id': 'fe2dbc51-5810-451d-ab2f-8c8a48d15bee', 'status': 'available', 'host': "hostname@backend#%s" % POOLUUID} DATA_IN_VOLUME1 = {'id': 'c11e902-87e9-348d-0b48-89695f1ec4bef', 'display_name': 'abc456', 'display_description': '', 'size': 10, 'host': "hostname@backend#%s" % POOLUUID} DATA_IN_CG_SNAPSHOT = { 'group_id': 'fe2dbc51-5810-451d-ab2f-8c8a48d15bee', 'id': 'cgsnapshot1', 'name': 'cgsnapshot1', 'description': 'cgsnapshot1', 'status': ''} DATA_IN_SNAPSHOT = {'id': 'fe2dbc5-1581-0451-dab2-f8c8a48d15bee', 'volume_id': 'c11e902-87e9-348d-0b48-89695f1ec4be5', 'display_name': 'snapshot1', 'display_description': '', 'volume_size': 5} DATA_OUT_SNAPSHOT_CG = { 'id': 'snapshot1', 'volume_id': 'c11e902-87e9-348d-0b48-89695f1ec4be5', 'display_name': 'snapshot1', 'display_description': '', 'group_snapshot_id': 'fe2dbc51-5810-451d-ab2f-8c8a48d15bee'} DATA_OUT_CG = { "objectType": "application/cdmi-container", "objectID": "fe2dbc515810451dab2f8c8a48d15bee", "objectName": "", "parentURI": "/dpl_volgroup", "parentID": "fe2dbc515810451dab2f8c8a48d15bee", "domainURI": "", "capabilitiesURI": "", "completionStatus": "Complete", "percentComplete": 100, "metadata": { "type": "volume|snapshot|replica", "volume_group_uuid": "", "origin_uuid": "", "snapshot_uuid": "", "display_name": "", "display_description": "", "ctime": 12345678, "total_capacity": 1024, "snapshot_used_capacity": 0, "maximum_snapshot": 1024, "snapshot_quota": 0, "state": "", "properties": { "snapshot_rotation": True, } }, "childrenrange": "", "children": [ 'fe2dbc515810451dab2f8c8a48d15bee', ], } class TestProphetStorDPLVolume(test.TestCase): def _gen_snapshot_url(self, vdevid, snapshotid): snapshot_url = '/%s/%s/%s' % (vdevid, DPLCOMMON.DPL_OBJ_SNAPSHOT, snapshotid) return snapshot_url def setUp(self): super(TestProphetStorDPLVolume, self).setUp() self.dplcmd = DPLCOMMON.DPLVolume('1.1.1.1', 8356, 'admin', 'password') self.DPL_MOCK = mock.MagicMock() self.dplcmd.objCmd = self.DPL_MOCK self.DPL_MOCK.send_cmd.return_value = DATA_OUTPUT def test_getserverinfo(self): self.dplcmd.get_server_info() self.DPL_MOCK.send_cmd.assert_called_once_with( 'GET', '/%s/%s/' % (DPLCOMMON.DPL_VER_V1, DPLCOMMON.DPL_OBJ_SYSTEM), None, [http_client.OK, http_client.ACCEPTED]) def test_createvdev(self): self.dplcmd.create_vdev(DATA_IN_VOLUME['id'], DATA_IN_VOLUME['display_name'], DATA_IN_VOLUME['display_description'], POOLUUID, int(DATA_IN_VOLUME['size']) * units.Gi) metadata = {} metadata['display_name'] = DATA_IN_VOLUME['display_name'] metadata['display_description'] = DATA_IN_VOLUME['display_description'] metadata['pool_uuid'] = POOLUUID metadata['total_capacity'] = int(DATA_IN_VOLUME['size']) * units.Gi metadata['maximum_snapshot'] = 1024 metadata['properties'] = dict(thin_provision=True) params = {} params['metadata'] = metadata self.DPL_MOCK.send_cmd.assert_called_once_with( 'PUT', '/%s/%s/%s/' % (DPLCOMMON.DPL_VER_V1, DPLCOMMON.DPL_OBJ_VOLUME, DATA_IN_VOLUME['id']), params, [http_client.OK, http_client.ACCEPTED, http_client.CREATED]) def test_extendvdev(self): self.dplcmd.extend_vdev(DATA_IN_VOLUME['id'], DATA_IN_VOLUME['display_name'], DATA_IN_VOLUME['display_description'], int(DATA_IN_VOLUME['size']) * units.Gi) metadata = {} metadata['display_name'] = DATA_IN_VOLUME['display_name'] metadata['display_description'] = DATA_IN_VOLUME['display_description'] metadata['total_capacity'] = int(DATA_IN_VOLUME['size']) * units.Gi metadata['maximum_snapshot'] = 1024 params = {} params['metadata'] = metadata self.DPL_MOCK.send_cmd.assert_called_once_with( 'PUT', '/%s/%s/%s/' % (DPLCOMMON.DPL_VER_V1, DPLCOMMON.DPL_OBJ_VOLUME, DATA_IN_VOLUME['id']), params, [http_client.OK, http_client.ACCEPTED, http_client.CREATED]) def test_deletevdev(self): self.dplcmd.delete_vdev(DATA_IN_VOLUME['id'], True) metadata = {} params = {} metadata['force'] = True params['metadata'] = metadata self.DPL_MOCK.send_cmd.assert_called_once_with( 'DELETE', '/%s/%s/%s/' % (DPLCOMMON.DPL_VER_V1, DPLCOMMON.DPL_OBJ_VOLUME, DATA_IN_VOLUME['id']), params, [http_client.OK, http_client.ACCEPTED, http_client.NOT_FOUND, http_client.NO_CONTENT]) def test_createvdevfromsnapshot(self): self.dplcmd.create_vdev_from_snapshot( DATA_IN_VOLUME['id'], DATA_IN_VOLUME['display_name'], DATA_IN_VOLUME['display_description'], DATA_IN_SNAPSHOT['id'], POOLUUID) metadata = {} params = {} metadata['snapshot_operation'] = 'copy' metadata['display_name'] = DATA_IN_VOLUME['display_name'] metadata['display_description'] = DATA_IN_VOLUME['display_description'] metadata['pool_uuid'] = POOLUUID metadata['maximum_snapshot'] = 1024 metadata['properties'] = dict(thin_provision=True) params['metadata'] = metadata params['copy'] = self._gen_snapshot_url(DATA_IN_VOLUME['id'], DATA_IN_SNAPSHOT['id']) self.DPL_MOCK.send_cmd.assert_called_once_with( 'PUT', '/%s/%s/%s/' % (DPLCOMMON.DPL_VER_V1, DPLCOMMON.DPL_OBJ_VOLUME, DATA_IN_VOLUME['id']), params, [http_client.OK, http_client.ACCEPTED, http_client.CREATED]) def test_getpool(self): self.dplcmd.get_pool(POOLUUID) self.DPL_MOCK.send_cmd.assert_called_once_with( 'GET', '/%s/%s/%s/' % (DPLCOMMON.DPL_VER_V1, DPLCOMMON.DPL_OBJ_POOL, POOLUUID), None, [http_client.OK, http_client.ACCEPTED]) def test_clonevdev(self): self.dplcmd.clone_vdev( DATA_IN_VOLUME['id'], DATA_IN_VOLUME1['id'], POOLUUID, DATA_IN_VOLUME['display_name'], DATA_IN_VOLUME['display_description'], int(DATA_IN_VOLUME['size']) * units.Gi ) metadata = {} params = {} metadata["snapshot_operation"] = "clone" metadata["display_name"] = DATA_IN_VOLUME['display_name'] metadata["display_description"] = DATA_IN_VOLUME['display_description'] metadata["pool_uuid"] = POOLUUID metadata["total_capacity"] = int(DATA_IN_VOLUME['size']) * units.Gi metadata['maximum_snapshot'] = 1024 metadata['properties'] = dict(thin_provision=True) params["metadata"] = metadata params["copy"] = DATA_IN_VOLUME['id'] self.DPL_MOCK.send_cmd.assert_called_once_with( 'PUT', '/%s/%s/%s/' % (DPLCOMMON.DPL_VER_V1, DPLCOMMON.DPL_OBJ_VOLUME, DATA_IN_VOLUME1['id']), params, [http_client.OK, http_client.CREATED, http_client.ACCEPTED]) def test_createvdevsnapshot(self): self.dplcmd.create_vdev_snapshot( DATA_IN_VOLUME['id'], DATA_IN_SNAPSHOT['id'], DATA_IN_SNAPSHOT['display_name'], DATA_IN_SNAPSHOT['display_description'] ) metadata = {} params = {} metadata['display_name'] = DATA_IN_SNAPSHOT['display_name'] metadata['display_description'] = ( DATA_IN_SNAPSHOT['display_description']) params['metadata'] = metadata params['snapshot'] = DATA_IN_SNAPSHOT['id'] self.DPL_MOCK.send_cmd.assert_called_once_with( 'PUT', '/%s/%s/%s/' % (DPLCOMMON.DPL_VER_V1, DPLCOMMON.DPL_OBJ_VOLUME, DATA_IN_VOLUME['id']), params, [http_client.OK, http_client.CREATED, http_client.ACCEPTED]) def test_getvdev(self): self.dplcmd.get_vdev(DATA_IN_VOLUME['id']) self.DPL_MOCK.send_cmd.assert_called_once_with( 'GET', '/%s/%s/%s/' % (DPLCOMMON.DPL_VER_V1, DPLCOMMON.DPL_OBJ_VOLUME, DATA_IN_VOLUME['id']), None, [http_client.OK, http_client.ACCEPTED, http_client.NOT_FOUND]) def test_getvdevstatus(self): self.dplcmd.get_vdev_status(DATA_IN_VOLUME['id'], '123456') self.DPL_MOCK.send_cmd.assert_called_once_with( 'GET', '/%s/%s/%s/?event_uuid=%s' % (DPLCOMMON.DPL_VER_V1, DPLCOMMON.DPL_OBJ_VOLUME, DATA_IN_VOLUME['id'], '123456'), None, [http_client.OK, http_client.NOT_FOUND]) def test_getpoolstatus(self): self.dplcmd.get_pool_status(POOLUUID, '123456') self.DPL_MOCK.send_cmd.assert_called_once_with( 'GET', '/%s/%s/%s/?event_uuid=%s' % (DPLCOMMON.DPL_VER_V1, DPLCOMMON.DPL_OBJ_POOL, POOLUUID, '123456'), None, [http_client.OK, http_client.NOT_FOUND]) def test_assignvdev(self): self.dplcmd.assign_vdev( DATA_IN_VOLUME['id'], 'iqn.1993-08.org.debian:01:test1', '', '1.1.1.1:3260', 0 ) params = {} metadata = {} exports = {} metadata['export_operation'] = 'assign' exports['Network/iSCSI'] = {} target_info = {} target_info['logical_unit_number'] = 0 target_info['logical_unit_name'] = '' permissions = [] portals = [] portals.append('1.1.1.1:3260') permissions.append('iqn.1993-08.org.debian:01:test1') target_info['permissions'] = permissions target_info['portals'] = portals exports['Network/iSCSI'] = target_info params['metadata'] = metadata params['exports'] = exports self.DPL_MOCK.send_cmd.assert_called_once_with( 'PUT', '/%s/%s/%s/' % (DPLCOMMON.DPL_VER_V1, DPLCOMMON.DPL_OBJ_VOLUME, DATA_IN_VOLUME['id']), params, [http_client.OK, http_client.ACCEPTED, http_client.CREATED]) def test_unassignvdev(self): self.dplcmd.unassign_vdev(DATA_IN_VOLUME['id'], 'iqn.1993-08.org.debian:01:test1', '') params = {} metadata = {} exports = {} metadata['export_operation'] = 'unassign' params['metadata'] = metadata exports['Network/iSCSI'] = {} exports['Network/iSCSI']['target_identifier'] = '' permissions = [] permissions.append('iqn.1993-08.org.debian:01:test1') exports['Network/iSCSI']['permissions'] = permissions params['exports'] = exports self.DPL_MOCK.send_cmd.assert_called_once_with( 'PUT', '/%s/%s/%s/' % (DPLCOMMON.DPL_VER_V1, DPLCOMMON.DPL_OBJ_VOLUME, DATA_IN_VOLUME['id']), params, [http_client.OK, http_client.ACCEPTED, http_client.NO_CONTENT, http_client.NOT_FOUND]) def test_deletevdevsnapshot(self): self.dplcmd.delete_vdev_snapshot(DATA_IN_VOLUME['id'], DATA_IN_SNAPSHOT['id']) params = {} params['copy'] = self._gen_snapshot_url(DATA_IN_VOLUME['id'], DATA_IN_SNAPSHOT['id']) self.DPL_MOCK.send_cmd.assert_called_once_with( 'DELETE', '/%s/%s/%s/%s/%s/' % (DPLCOMMON.DPL_VER_V1, DPLCOMMON.DPL_OBJ_VOLUME, DATA_IN_VOLUME['id'], DPLCOMMON.DPL_OBJ_SNAPSHOT, DATA_IN_SNAPSHOT['id']), None, [http_client.OK, http_client.ACCEPTED, http_client.NO_CONTENT, http_client.NOT_FOUND]) def test_listvdevsnapshots(self): self.dplcmd.list_vdev_snapshots(DATA_IN_VOLUME['id']) self.DPL_MOCK.send_cmd.assert_called_once_with( 'GET', '/%s/%s/%s/%s/' % (DPLCOMMON.DPL_VER_V1, DPLCOMMON.DPL_OBJ_VOLUME, DATA_IN_VOLUME['id'], DPLCOMMON.DPL_OBJ_SNAPSHOT), None, [http_client.OK]) class TestProphetStorDPLDriver(test.TestCase): def __init__(self, method): super(TestProphetStorDPLDriver, self).__init__(method) def _conver_uuid2hex(self, strID): return strID.replace('-', '') def setUp(self): super(TestProphetStorDPLDriver, self).setUp() self.configuration = mock.Mock(conf.Configuration) self.configuration.san_ip = '1.1.1.1' self.configuration.dpl_port = 8356 self.configuration.san_login = 'admin' self.configuration.san_password = 'password' self.configuration.dpl_pool = POOLUUID self.configuration.target_port = 3260 self.configuration.san_is_local = False self.configuration.san_thin_provision = True self.configuration.driver_ssl_cert_verify = False self.configuration.driver_ssl_cert_path = None self.context = context.get_admin_context() self.DPL_MOCK = mock.MagicMock() self.DB_MOCK = mock.MagicMock() self.dpldriver = DPLDRIVER.DPLISCSIDriver( configuration=self.configuration) self.dpldriver.dpl = self.DPL_MOCK self.dpldriver.db = self.DB_MOCK self.dpldriver.do_setup(self.context) def test_get_volume_stats(self): self.DPL_MOCK.get_pool.return_value = DATA_POOLINFO self.DPL_MOCK.get_server_info.return_value = DATA_SERVER_INFO res = self.dpldriver.get_volume_stats(True) self.assertEqual('ProphetStor', res['vendor_name']) self.assertEqual('1.5', res['driver_version']) pool = res["pools"][0] self.assertEqual(4, pool['total_capacity_gb']) self.assertEqual(4, pool['free_capacity_gb']) self.assertEqual(0, pool['reserved_percentage']) self.assertFalse(pool['QoS_support']) def test_create_volume(self): volume = test_utils.create_volume( self.context, id=DATA_IN_VOLUME['id'], display_name=DATA_IN_VOLUME['display_name'], size=DATA_IN_VOLUME['size'], host=DATA_IN_VOLUME['host']) self.DPL_MOCK.create_vdev.return_value = DATA_OUTPUT self.dpldriver.create_volume(volume) self.DPL_MOCK.create_vdev.assert_called_once_with( self._conver_uuid2hex(volume.id), volume.display_name, volume.display_description, self.configuration.dpl_pool, int(volume.size) * units.Gi, True) def test_create_volume_without_pool(self): volume = test_utils.create_volume( self.context, id=DATA_IN_VOLUME['id'], display_name=DATA_IN_VOLUME['display_name'], size=DATA_IN_VOLUME['size'], host=DATA_IN_VOLUME['host']) self.DPL_MOCK.create_vdev.return_value = DATA_OUTPUT self.configuration.dpl_pool = "" volume.host = "host@backend" # missing pool self.assertRaises(exception.InvalidHost, self.dpldriver.create_volume, volume=volume) def test_create_volume_with_configuration_pool(self): volume = test_utils.create_volume( self.context, id=DATA_IN_VOLUME['id'], display_name=DATA_IN_VOLUME['display_name'], size=DATA_IN_VOLUME['size'], host="host@backend") self.DPL_MOCK.create_vdev.return_value = DATA_OUTPUT self.dpldriver.create_volume(volume) self.DPL_MOCK.create_vdev.assert_called_once_with( self._conver_uuid2hex(volume.id), volume.display_name, volume.display_description, self.configuration.dpl_pool, int(volume.size) * units.Gi, True) def test_create_volume_of_group(self): group_type = group_types.create( self.context, 'group', {'consistent_group_snapshot_enabled': ' True'} ) group = test_utils.create_group( self.context, id=fake_constants.CONSISTENCY_GROUP_ID, host='host@backend#unit_test_pool', group_type_id=group_type.id) self.DPL_MOCK.create_vdev.return_value = DATA_OUTPUT self.DPL_MOCK.join_vg.return_value = DATA_OUTPUT volume = test_utils.create_volume( self.context, id=DATA_IN_VOLUME_VG['id'], display_name=DATA_IN_VOLUME_VG['display_name'], size=DATA_IN_VOLUME_VG['size'], group_id=group.id, host=DATA_IN_VOLUME_VG['host']) self.dpldriver.create_volume(volume) self.DPL_MOCK.create_vdev.assert_called_once_with( self._conver_uuid2hex(volume.id), volume.display_name, volume.display_description, self.configuration.dpl_pool, int(volume.size) * units.Gi, True) self.DPL_MOCK.join_vg.assert_called_once_with( self._conver_uuid2hex(volume.id), self._conver_uuid2hex(volume.group_id)) def test_delete_volume(self): volume = test_utils.create_volume( self.context, id=DATA_IN_VOLUME['id'], display_name=DATA_IN_VOLUME['display_name'], size=DATA_IN_VOLUME['size'], host=DATA_IN_VOLUME['host']) self.DPL_MOCK.delete_vdev.return_value = DATA_OUTPUT self.dpldriver.delete_volume(volume) self.DPL_MOCK.delete_vdev.assert_called_once_with( self._conver_uuid2hex(volume.id)) def test_delete_volume_of_group(self): group_type = group_types.create( self.context, 'group', {'consistent_group_snapshot_enabled': ' True'} ) group = test_utils.create_group( self.context, id=fake_constants.CONSISTENCY_GROUP_ID, host='host@backend#unit_test_pool', group_type_id=group_type.id) volume = test_utils.create_volume( self.context, id=DATA_IN_VOLUME_VG['id'], display_name=DATA_IN_VOLUME_VG['display_name'], size=DATA_IN_VOLUME_VG['size'], group_id=group.id, host=DATA_IN_VOLUME_VG['host']) self.DPL_MOCK.delete_vdev.return_value = DATA_OUTPUT self.DPL_MOCK.leave_vg.return_volume = DATA_OUTPUT self.dpldriver.delete_volume(volume) self.DPL_MOCK.leave_vg.assert_called_once_with( self._conver_uuid2hex(volume.id), self._conver_uuid2hex(volume.group_id) ) self.DPL_MOCK.delete_vdev.assert_called_once_with( self._conver_uuid2hex(volume.id)) def test_create_volume_from_snapshot(self): self.DPL_MOCK.create_vdev_from_snapshot.return_value = DATA_OUTPUT self.DPL_MOCK.extend_vdev.return_value = DATA_OUTPUT volume = test_utils.create_volume( self.context, id=DATA_IN_VOLUME_VG['id'], display_name=DATA_IN_VOLUME_VG['display_name'], size=DATA_IN_VOLUME_VG['size'], host=DATA_IN_VOLUME_VG['host']) self.dpldriver.create_volume_from_snapshot( volume, DATA_IN_SNAPSHOT) self.DPL_MOCK.create_vdev_from_snapshot.assert_called_once_with( self._conver_uuid2hex(volume.id), volume.display_name, volume.display_description, self._conver_uuid2hex(volume.id), self.configuration.dpl_pool, True) self.DPL_MOCK.extend_vdev.assert_called_once_with( self._conver_uuid2hex(volume.id), volume.display_name, volume.display_description, volume.size * units.Gi) def test_create_cloned_volume(self): new_volume = test_utils.create_volume( self.context, id=DATA_IN_VOLUME1['id'], display_name=DATA_IN_VOLUME1['display_name'], size=DATA_IN_VOLUME1['size'], host=DATA_IN_VOLUME1['host']) src_volume = test_utils.create_volume( self.context, id=DATA_IN_VOLUME['id']) self.DPL_MOCK.clone_vdev.return_value = DATA_OUTPUT self.dpldriver.create_cloned_volume(new_volume, src_volume) self.DPL_MOCK.clone_vdev.assert_called_once_with( self._conver_uuid2hex(src_volume.id), self._conver_uuid2hex(new_volume.id), self.configuration.dpl_pool, new_volume.display_name, new_volume.display_description, int(new_volume.size) * units.Gi, True) def test_create_snapshot(self): self.DPL_MOCK.create_vdev_snapshot.return_value = DATA_OUTPUT self.dpldriver.create_snapshot(DATA_IN_SNAPSHOT) self.DPL_MOCK.create_vdev_snapshot.assert_called_once_with( self._conver_uuid2hex(DATA_IN_SNAPSHOT['volume_id']), self._conver_uuid2hex(DATA_IN_SNAPSHOT['id']), DATA_IN_SNAPSHOT['display_name'], DATA_IN_SNAPSHOT['display_description']) def test_delete_snapshot(self): self.DPL_MOCK.delete_vdev_snapshot.return_value = DATA_OUTPUT self.dpldriver.delete_snapshot(DATA_IN_SNAPSHOT) self.DPL_MOCK.delete_vdev_snapshot.assert_called_once_with( self._conver_uuid2hex(DATA_IN_SNAPSHOT['volume_id']), self._conver_uuid2hex(DATA_IN_SNAPSHOT['id'])) def test_initialize_connection(self): self.DPL_MOCK.assign_vdev.return_value = DATA_ASSIGNVDEV self.DPL_MOCK.get_vdev.return_value = DATA_ASSIGNVDEV res = self.dpldriver.initialize_connection(DATA_IN_VOLUME, DATA_IN_CONNECTOR) self.assertEqual('iscsi', res['driver_volume_type']) self.assertEqual(101, res['data']['target_lun']) self.assertTrue(res['data']['target_discovered']) self.assertEqual('172.31.1.210:3260', res['data']['target_portal']) self.assertEqual( 'iqn.2013-09.com.prophetstor:hypervisor.886423051816', res['data']['target_iqn']) def test_terminate_connection(self): self.DPL_MOCK.unassign_vdev.return_value = DATA_OUTPUT self.dpldriver.terminate_connection(DATA_IN_VOLUME, DATA_IN_CONNECTOR) self.DPL_MOCK.unassign_vdev.assert_called_once_with( self._conver_uuid2hex(DATA_IN_VOLUME['id']), DATA_IN_CONNECTOR['initiator']) def test_terminate_connection_volume_detached(self): self.DPL_MOCK.unassign_vdev.return_value = errno.ENODATA, None self.dpldriver.terminate_connection(DATA_IN_VOLUME, DATA_IN_CONNECTOR) self.DPL_MOCK.unassign_vdev.assert_called_once_with( self._conver_uuid2hex(DATA_IN_VOLUME['id']), DATA_IN_CONNECTOR['initiator']) def test_terminate_connection_failed(self): self.DPL_MOCK.unassign_vdev.return_value = errno.EFAULT, None ex = self.assertRaises( exception.VolumeBackendAPIException, self.dpldriver.terminate_connection, volume=DATA_IN_VOLUME, connector=DATA_IN_CONNECTOR) self.assertIsNotNone( re.match(r".*Flexvisor failed", ex.msg)) def test_get_pool_info(self): self.DPL_MOCK.get_pool.return_value = DATA_POOLINFO _, res = self.dpldriver._get_pool_info(POOLUUID) self.assertEqual(4294967296, res['metadata']['available_capacity']) self.assertEqual(1390551362349, res['metadata']['ctime']) self.assertEqual('Default Pool', res['metadata']['display_description']) self.assertEqual('default_pool', res['metadata']['display_name']) self.assertEqual('4f7c4d679a664857afa4d51f282a516a', res['metadata']['event_uuid']) self.assertEqual( {'cache': [], 'data': ['disk_uuid_0', 'disk_uuid_1', 'disk_uuid_2'], 'log': [], 'spare': []}, res['metadata']['physical_device']) self.assertEqual(POOLUUID, res['metadata']['pool_uuid']) self.assertEqual( {'raid_level': 'raid0'}, res['metadata']['properties']) self.assertEqual('Online', res['metadata']['state']) self.assertEqual(4294967296, res['metadata']['total_capacity']) self.assertEqual('8173612007304181810', res['metadata']['zpool_guid']) def test_create_group(self): group_type = group_types.create( self.context, 'group', {'consistent_group_snapshot_enabled': ' True'} ) group = test_utils.create_group( self.context, id=fake_constants.CONSISTENCY_GROUP_ID, host='host@backend#unit_test_pool', group_type_id=group_type.id) self.DPL_MOCK.create_vg.return_value = DATA_OUTPUT model_update = self.dpldriver.create_group(self.context, group) self.DPL_MOCK.create_vg.assert_called_once_with( self._conver_uuid2hex(fake_constants.CONSISTENCY_GROUP_ID), 'test_group', 'this is a test group') self.assertDictEqual({'status': ( fields.ConsistencyGroupStatus.AVAILABLE)}, model_update) def test_delete_group(self): group_type = group_types.create( self.context, 'group', {'consistent_group_snapshot_enabled': ' True'} ) group = test_utils.create_group( self.context, id=fake_constants.CONSISTENCY_GROUP_ID, host='host@backend#unit_test_pool', group_type_id=group_type.id) self.DB_MOCK.volume_get_all_by_group.return_value = ( [DATA_IN_VOLUME_VG]) self.DPL_MOCK.delete_vdev.return_value = DATA_OUTPUT self.DPL_MOCK.delete_cg.return_value = DATA_OUTPUT model_update, volumes = self.dpldriver.delete_group( self.context, group, []) self.DPL_MOCK.delete_vg.assert_called_once_with( self._conver_uuid2hex(fake_constants.CONSISTENCY_GROUP_ID)) self.DPL_MOCK.delete_vdev.assert_called_once_with( self._conver_uuid2hex((DATA_IN_VOLUME_VG['id']))) self.assertDictEqual({'status': ( fields.ConsistencyGroupStatus.DELETED)}, model_update) def test_update_group(self): group_type = group_types.create( self.context, 'group', {'consistent_group_snapshot_enabled': ' True'} ) self.DPL_MOCK.get_vg.return_value = (0, DATA_OUT_CG) self.DPL_MOCK.join_vg.return_value = DATA_OUTPUT self.DPL_MOCK.leave_vg.return_value = DATA_OUTPUT group = test_utils.create_group( self.context, id='fe2dbc51-5810-451d-ab2f-8c8a48d15bee', host='host@backend#unit_test_pool', group_type_id=group_type.id) vol_add = test_utils.create_volume( self.context, id=fake_constants.VOLUME2_ID, display_name=DATA_IN_VOLUME_VG['display_name'], size=DATA_IN_VOLUME_VG['size'], group_id='fe2dbc51-5810-451d-ab2f-8c8a48d15bee', host=DATA_IN_VOLUME_VG['host']) vol_del = test_utils.create_volume( self.context, id=DATA_IN_REMOVE_VOLUME_VG['id'], display_name=DATA_IN_REMOVE_VOLUME_VG['display_name'], size=DATA_IN_REMOVE_VOLUME_VG['size'], group_id='fe2dbc51-5810-451d-ab2f-8c8a48d15bee', host=DATA_IN_REMOVE_VOLUME_VG['host']) (model_update, add_vols, remove_vols) = ( self.dpldriver.update_group( self.context, group, [vol_add], [vol_del])) self.DPL_MOCK.join_vg.assert_called_once_with( self._conver_uuid2hex(vol_add.id), self._conver_uuid2hex(group.id)) self.DPL_MOCK.leave_vg.assert_called_once_with( self._conver_uuid2hex(vol_del.id), self._conver_uuid2hex(group.id)) self.assertDictEqual({'status': ( fields.ConsistencyGroupStatus.AVAILABLE)}, model_update) def test_update_group_exception_join(self): group_type = group_types.create( self.context, 'group', {'consistent_group_snapshot_enabled': ' True'} ) self.DPL_MOCK.get_vg.return_value = (0, DATA_OUT_CG) self.DPL_MOCK.join_vg.return_value = -1, None self.DPL_MOCK.leave_vg.return_value = DATA_OUTPUT volume = test_utils.create_volume( self.context, id=fake_constants.VOLUME2_ID, display_name=DATA_IN_VOLUME_VG['display_name'], size=DATA_IN_VOLUME_VG['size'], host=DATA_IN_VOLUME_VG['host']) group = test_utils.create_group( self.context, id=fake_constants.CONSISTENCY_GROUP_ID, host='host@backend#unit_test_pool', group_type_id=group_type.id) self.assertRaises(exception.VolumeBackendAPIException, self.dpldriver.update_group, context=None, group=group, add_volumes=[volume], remove_volumes=None) def test_update_group_exception_leave(self): group_type = group_types.create( self.context, 'group', {'consistent_group_snapshot_enabled': ' True'} ) self.DPL_MOCK.get_vg.return_value = (0, DATA_OUT_CG) self.DPL_MOCK.leave_vg.return_value = -1, None volume = test_utils.create_volume( self.context, id='fe2dbc51-5810-451d-ab2f-8c8a48d15bee', display_name=DATA_IN_VOLUME_VG['display_name'], size=DATA_IN_VOLUME_VG['size'], host=DATA_IN_VOLUME_VG['host']) group = test_utils.create_group( self.context, id=fake_constants.CONSISTENCY_GROUP_ID, host='host@backend#unit_test_pool', group_type_id=group_type.id) self.assertRaises(exception.VolumeBackendAPIException, self.dpldriver.update_group, context=None, group=group, add_volumes=None, remove_volumes=[volume]) @mock.patch( 'cinder.objects.snapshot.SnapshotList.get_all_for_group_snapshot') def test_create_group_snapshot(self, get_all_for_group_snapshot): group_type = group_types.create( self.context, 'group', {'consistent_group_snapshot_enabled': ' True'} ) snapshot_obj = fake_snapshot.fake_snapshot_obj(self.context) snapshot_obj.group_id = \ DATA_IN_CG_SNAPSHOT['group_id'] snapshot_obj.group_type_id = group_type.id get_all_for_group_snapshot.return_value = [snapshot_obj] self.DPL_MOCK.create_vdev_snapshot.return_value = DATA_OUTPUT model_update, snapshots = self.dpldriver.create_group_snapshot( self.context, snapshot_obj, []) self.assertDictEqual({'status': 'available'}, model_update) @mock.patch( 'cinder.objects.snapshot.SnapshotList.get_all_for_group_snapshot') def test_delete_group_snapshot(self, get_all_for_group_snapshot): group_type = group_types.create( self.context, 'group', {'consistent_group_snapshot_enabled': ' True'} ) snapshot_obj = fake_snapshot.fake_snapshot_obj(self.context) snapshot_obj.group_id = \ DATA_IN_CG_SNAPSHOT['group_id'] snapshot_obj.group_type_id = group_type.id get_all_for_group_snapshot.return_value = [snapshot_obj] self.DPL_MOCK.delete_group_snapshot.return_value = DATA_OUTPUT model_update, snapshots = self.dpldriver.delete_group_snapshot( self.context, snapshot_obj, []) self.DPL_MOCK.delete_vdev_snapshot.assert_called_once_with( self._conver_uuid2hex(snapshot_obj.group_id), self._conver_uuid2hex(snapshot_obj.id), True) self.assertDictEqual({'status': 'deleted'}, model_update)