# Copyright (c) 2016 Huawei Technologies Co., Ltd. # 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. """Tests for huawei drivers.""" import ddt import json import mock import re import tempfile import time from xml.dom import minidom from oslo_log import log as logging from cinder import exception from cinder import test from cinder.volume import configuration as conf from cinder.volume.drivers.huawei import constants from cinder.volume.drivers.huawei import fc_zone_helper from cinder.volume.drivers.huawei import huawei_conf from cinder.volume.drivers.huawei import huawei_driver from cinder.volume.drivers.huawei import hypermetro from cinder.volume.drivers.huawei import replication from cinder.volume.drivers.huawei import rest_client from cinder.volume.drivers.huawei import smartx LOG = logging.getLogger(__name__) hypermetro_devices = """{ "remote_device": { "RestURL": "http://100.115.10.69:8082/deviceManager/rest", "UserName": "admin", "UserPassword": "Admin@storage1", "StoragePool": "StoragePool001", "domain_name": "hypermetro-domain", "remote_target_ip": "111.111.101.241" } } """ test_volume = {'name': 'volume-21ec7341-9256-497b-97d9-ef48edcf0635', 'size': 2, 'volume_name': 'vol1', 'id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'volume_id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'provider_auth': None, 'project_id': 'project', 'display_name': 'vol1', 'display_description': 'test volume', 'volume_type_id': None, 'host': 'ubuntu001@backend001#OpenStack_Pool', 'provider_location': '11', } fake_smartx_value = {'smarttier': 'true', 'smartcache': 'true', 'smartpartition': 'true', 'thin_provisioning_support': 'true', 'thick_provisioning_support': False, 'policy': '2', 'cachename': 'cache-test', 'partitionname': 'partition-test', } fake_hypermetro_opts = {'hypermetro': 'true', 'smarttier': False, 'smartcache': False, 'smartpartition': False, 'thin_provisioning_support': False, 'thick_provisioning_support': False, } hyper_volume = {'name': 'volume-21ec7341-9256-497b-97d9-ef48edcf0635', 'size': 2, 'volume_name': 'vol1', 'id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'volume_id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'provider_auth': None, 'project_id': 'project', 'display_name': 'vol1', 'display_description': 'test volume', 'volume_type_id': None, 'host': 'ubuntu@huawei#OpenStack_Pool', 'provider_location': '11', 'volume_metadata': [{'key': 'hypermetro_id', 'value': '1'}, {'key': 'remote_lun_id', 'value': '11'}], } sync_replica_specs = {'replication_enabled': ' True', 'replication_type': ' sync'} async_replica_specs = {'replication_enabled': ' True', 'replication_type': ' async'} TEST_PAIR_ID = "3400a30d844d0004" replication_volume = { 'name': 'volume-21ec7341-9256-497b-97d9-ef48edcf0635', 'size': 2, 'volume_name': 'vol1', 'id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'volume_id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'provider_auth': None, 'project_id': 'project', 'display_name': 'vol1', 'display_description': 'test volume', 'volume_type_id': None, 'host': 'ubuntu@huawei#OpenStack_Pool', 'provider_location': '11', 'metadata': {'lun_wwn': '6643e8c1004c5f6723e9f454003'}, 'replication_status': 'disabled', 'replication_driver_data': '{"pair_id": "%s", "rmt_lun_id": "1"}' % TEST_PAIR_ID, } test_snap = {'name': 'volume-21ec7341-9256-497b-97d9-ef48edcf0635', 'size': 1, 'volume_name': 'vol1', 'id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'volume_id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'provider_auth': None, 'project_id': 'project', 'display_name': 'vol1', 'display_description': 'test volume', 'volume_type_id': None, 'provider_location': '11', 'volume': {"volume_id": '21ec7341-9256-497b-97d9-ef48edcf0635'}, 'volume': {'provider_location': '12'}, } test_host = {'host': 'ubuntu001@backend001#OpenStack_Pool', 'capabilities': {'smartcache': True, 'location_info': '210235G7J20000000000', 'QoS_support': True, 'pool_name': 'OpenStack_Pool', 'timestamp': '2015-07-13T11:41:00.513549', 'smartpartition': True, 'allocated_capacity_gb': 0, 'volume_backend_name': 'HuaweiFCDriver', 'free_capacity_gb': 20.0, 'driver_version': '1.1.0', 'total_capacity_gb': 20.0, 'smarttier': True, 'hypermetro': True, 'reserved_percentage': 0, 'vendor_name': None, 'thick_provisioning_support': False, 'thin_provisioning_support': True, 'storage_protocol': 'FC', } } test_new_type = { 'name': u'new_type', 'qos_specs_id': None, 'deleted': False, 'created_at': None, 'updated_at': None, 'extra_specs': { 'smarttier': ' true', 'smartcache': ' true', 'smartpartition': ' true', 'thin_provisioning_support': ' true', 'thick_provisioning_support': ' False', 'policy': '2', 'smartcache:cachename': 'cache-test', 'smartpartition:partitionname': 'partition-test', }, 'is_public': True, 'deleted_at': None, 'id': u'530a56e1-a1a4-49f3-ab6c-779a6e5d999f', 'description': None, } test_new_replication_type = { 'name': u'new_type', 'qos_specs_id': None, 'deleted': False, 'created_at': None, 'updated_at': None, 'extra_specs': { 'replication_enabled': ' True', 'replication_type': ' sync', }, 'is_public': True, 'deleted_at': None, 'id': u'530a56e1-a1a4-49f3-ab6c-779a6e5d999f', 'description': None, } hypermetro_devices = """ { "remote_device": { "RestURL": "http://100.115.10.69:8082/deviceManager/rest", "UserName":"admin", "UserPassword":"Admin@storage2", "StoragePool":"StoragePool001", "domain_name":"hypermetro_test"} } """ FAKE_FIND_POOL_RESPONSE = {'CAPACITY': '985661440', 'ID': '0', 'TOTALCAPACITY': '985661440'} FAKE_CREATE_VOLUME_RESPONSE = {"ID": "1", "NAME": "5mFHcBv4RkCcD+JyrWc0SA"} FakeConnector = {'initiator': 'iqn.1993-08.debian:01:ec2bff7ac3a3', 'wwpns': ['10000090fa0d6754'], 'wwnns': ['10000090fa0d6755'], 'host': 'ubuntuc', } smarttier_opts = {'smarttier': 'true', 'smartpartition': False, 'smartcache': False, 'thin_provisioning_support': True, 'thick_provisioning_support': False, 'policy': '3', 'readcachepolicy': '1', 'writecachepolicy': None, } fake_fabric_mapping = { 'swd1': { 'target_port_wwn_list': ['2000643e8c4c5f66'], 'initiator_port_wwn_list': ['10000090fa0d6754'] } } CHANGE_OPTS = {'policy': ('1', '2'), 'partitionid': (['1', 'partition001'], ['2', 'partition002']), 'cacheid': (['1', 'cache001'], ['2', 'cache002']), 'qos': (['11', {'MAXIOPS': '100', 'IOType': '1'}], {'MAXIOPS': '100', 'IOType': '2', 'MIN': 1, 'LATENCY': 1}), 'host': ('ubuntu@huawei#OpenStack_Pool', 'ubuntu@huawei#OpenStack_Pool'), 'LUNType': ('0', '1'), } # A fake response of create a host FAKE_CREATE_HOST_RESPONSE = """ { "error": { "code": 0 }, "data":{"NAME": "ubuntuc001", "ID": "1"} } """ # A fake response of success response storage FAKE_COMMON_SUCCESS_RESPONSE = """ { "error": { "code": 0 }, "data":{} } """ # A fake response of login huawei storage FAKE_GET_LOGIN_STORAGE_RESPONSE = """ { "error": { "code": 0 }, "data": { "username": "admin", "iBaseToken": "2001031430", "deviceid": "210235G7J20000000000" } } """ # A fake response of login out huawei storage FAKE_LOGIN_OUT_STORAGE_RESPONSE = """ { "error": { "code": 0 }, "data": { "ID": 11 } } """ # A fake response of mock storage pool info FAKE_STORAGE_POOL_RESPONSE = """ { "error": { "code": 0 }, "data": [{ "USERFREECAPACITY": "985661440", "ID": "0", "NAME": "OpenStack_Pool", "USERTOTALCAPACITY": "985661440" }] } """ # A fake response of lun or lungroup response FAKE_LUN_INFO_RESPONSE = """ { "error": { "code": 0 }, "data": { "ID": "1", "NAME": "5mFHcBv4RkCcD+JyrWc0SA", "WWN": "6643e8c1004c5f6723e9f454003", "DESCRIPTION": "21ec7341-9256-497b-97d9-ef48edcf0635", "HEALTHSTATUS": "1", "RUNNINGSTATUS": "27", "ALLOCTYPE": "1", "CAPACITY": "2097152" } } """ FAKE_LUN_GET_SUCCESS_RESPONSE = """ { "error": { "code": 0 }, "data": { "ID": "11", "IOCLASSID": "11", "NAME": "5mFHcBv4RkCcD+JyrWc0SA", "DESCRIPTION": "21ec7341-9256-497b-97d9-ef48edcf0635", "RUNNINGSTATUS": "10", "HEALTHSTATUS": "1", "RUNNINGSTATUS": "27", "LUNLIST": "", "ALLOCTYPE": "1", "CAPACITY": "2097152", "WRITEPOLICY": "1", "MIRRORPOLICY": "0", "PREFETCHPOLICY": "1", "PREFETCHVALUE": "20", "DATATRANSFERPOLICY": "1", "READCACHEPOLICY": "2", "WRITECACHEPOLICY": "5", "OWNINGCONTROLLER": "0B", "SMARTCACHEPARTITIONID": "", "CACHEPARTITIONID": "", "WWN": "6643e8c1004c5f6723e9f454003", "PARENTNAME": "OpenStack_Pool" } } """ FAKE_QUERY_ALL_LUN_RESPONSE = """ { "error": { "code": 0 }, "data": [{ "ID": "1", "NAME": "IexzQZJWSXuX2e9I7c8GNQ" }] } """ FAKE_LUN_ASSOCIATE_RESPONSE = """ { "error":{ "code":0 }, "data":[{ "ID":"11" }] } """ FAKE_QUERY_LUN_GROUP_INFO_RESPONSE = """ { "error": { "code":0 }, "data":[{ "NAME":"OpenStack_LunGroup_1", "DESCRIPTION":"5mFHcBv4RkCcD+JyrWc0SA", "ID":"11", "TYPE":256 }] } """ FAKE_QUERY_LUN_GROUP_RESPONSE = """ { "error": { "code":0 }, "data":{ "NAME":"5mFHcBv4RkCcD+JyrWc0SA", "DESCRIPTION":"5mFHcBv4RkCcD+JyrWc0SA", "ID":"11", "TYPE":256 } } """ FAKE_QUERY_LUN_GROUP_ASSOCIAT_RESPONSE = """ { "error":{ "code":0 }, "data":{ "NAME":"5mFHcBv4RkCcD+JyrWc0SA", "DESCRIPTION":"5mFHcBv4RkCcD+JyrWc0SA", "ID":"11", "TYPE":256 } } """ FAKE_LUN_COUNT_RESPONSE = """ { "data":{ "COUNT":"0" }, "error":{ "code":0, "description":"0" } } """ # A fake response of snapshot list response FAKE_SNAPSHOT_LIST_INFO_RESPONSE = """ { "error": { "code": 0 }, "data": [{ "ID": 11, "NAME": "wr_LMKAjS7O_VtsEIREGYw" }, { "ID": 12, "NAME": "SDFAJSDFLKJ" }, { "ID": 13, "NAME": "s1Ew5v36To-hR2txJitX5Q" }] } """ # A fake response of create snapshot response FAKE_CREATE_SNAPSHOT_INFO_RESPONSE = """ { "error": { "code": 0 }, "data": { "ID": 11, "NAME": "YheUoRwbSX2BxN7" } } """ # A fake response of get snapshot response FAKE_GET_SNAPSHOT_INFO_RESPONSE = """ { "error": { "code": 0 }, "data": { "ID": 11, "NAME": "YheUoRwbSX2BxN7" } } """ # A fake response of get iscsi response FAKE_GET_ISCSI_INFO_RESPONSE = """ { "data": [{ "ETHPORTID": "139267", "ID": "iqn.oceanstor:21004846fb8ca15f::22003:111.111.101.244", "TPGT": "8196", "TYPE": 249 }, { "ETHPORTID": "139268", "ID": "iqn.oceanstor:21004846fb8ca15f::22003:111.111.102.244", "TPGT": "8196", "TYPE": 249 } ], "error": { "code": 0, "description": "0" } } """ # A fake response of get eth info response FAKE_GET_ETH_INFO_RESPONSE = """ { "error": { "code": 0 }, "data": [{ "PARENTTYPE": 209, "MACADDRESS": "00:22:a1:0a:79:57", "ETHNEGOTIATE": "-1", "ERRORPACKETS": "0", "IPV4ADDR": "192.168.1.2", "IPV6GATEWAY": "", "IPV6MASK": "0", "OVERFLOWEDPACKETS": "0", "ISCSINAME": "P0", "HEALTHSTATUS": "1", "ETHDUPLEX": "2", "ID": "16909568", "LOSTPACKETS": "0", "TYPE": 213, "NAME": "P0", "INIORTGT": "4", "RUNNINGSTATUS": "10", "IPV4GATEWAY": "", "BONDNAME": "", "STARTTIME": "1371684218", "SPEED": "1000", "ISCSITCPPORT": "0", "IPV4MASK": "255.255.0.0", "IPV6ADDR": "", "LOGICTYPE": "0", "LOCATION": "ENG0.A5.P0", "MTU": "1500", "PARENTID": "1.5" }, { "PARENTTYPE": 209, "MACADDRESS": "00:22:a1:0a:79:57", "ETHNEGOTIATE": "-1", "ERRORPACKETS": "0", "IPV4ADDR": "192.168.1.1", "IPV6GATEWAY": "", "IPV6MASK": "0", "OVERFLOWEDPACKETS": "0", "ISCSINAME": "P0", "HEALTHSTATUS": "1", "ETHDUPLEX": "2", "ID": "16909568", "LOSTPACKETS": "0", "TYPE": 213, "NAME": "P0", "INIORTGT": "4", "RUNNINGSTATUS": "10", "IPV4GATEWAY": "", "BONDNAME": "", "STARTTIME": "1371684218", "SPEED": "1000", "ISCSITCPPORT": "0", "IPV4MASK": "255.255.0.0", "IPV6ADDR": "", "LOGICTYPE": "0", "LOCATION": "ENG0.A5.P3", "MTU": "1500", "PARENTID": "1.5" }] } """ FAKE_GET_ETH_ASSOCIATE_RESPONSE = """ { "error":{ "code":0 }, "data":[{ "IPV4ADDR": "192.168.1.1", "HEALTHSTATUS": "1", "RUNNINGSTATUS": "10" }, { "IPV4ADDR": "192.168.1.2", "HEALTHSTATUS": "1", "RUNNINGSTATUS": "10" } ] } """ # A fake response of get iscsi device info response FAKE_GET_ISCSI_DEVICE_RESPONSE = """ { "error": { "code": 0 }, "data": [{ "CMO_ISCSI_DEVICE_NAME": "iqn.2006-08.com.huawei:oceanstor:21000022a:" }] } """ # A fake response of get iscsi device info response FAKE_GET_ALL_HOST_INFO_RESPONSE = """ { "error": { "code": 0 }, "data": [{ "PARENTTYPE": 245, "NAME": "ubuntuc", "DESCRIPTION": "", "RUNNINGSTATUS": "1", "IP": "", "PARENTNAME": "", "OPERATIONSYSTEM": "0", "LOCATION": "", "HEALTHSTATUS": "1", "MODEL": "", "ID": "1", "PARENTID": "", "NETWORKNAME": "", "TYPE": 21 }, { "PARENTTYPE": 245, "NAME": "ubuntu", "DESCRIPTION": "", "RUNNINGSTATUS": "1", "IP": "", "PARENTNAME": "", "OPERATIONSYSTEM": "0", "LOCATION": "", "HEALTHSTATUS": "1", "MODEL": "", "ID": "2", "PARENTID": "", "NETWORKNAME": "", "TYPE": 21 }] } """ # A fake response of get host or hostgroup info response FAKE_GET_ALL_HOST_GROUP_INFO_RESPONSE = """ { "error": { "code": 0 }, "data": [{ "NAME":"ubuntuc", "DESCRIPTION":"", "ID":"0", "TYPE":14 }, {"NAME":"OpenStack_HostGroup_1", "DESCRIPTION":"", "ID":"0", "TYPE":14 } ] } """ FAKE_GET_HOST_GROUP_INFO_RESPONSE = """ { "error": { "code": 0 }, "data":{ "NAME":"ubuntuc", "DESCRIPTION":"", "ID":"0", "TYPE":14 } } """ # A fake response of lun copy info response FAKE_GET_LUN_COPY_INFO_RESPONSE = """ { "error": { "code": 0 }, "data": { "COPYSTOPTIME": "-1", "HEALTHSTATUS": "1", "NAME": "w1PSNvu6RumcZMmSh4/l+Q==", "RUNNINGSTATUS": "36", "DESCRIPTION": "w1PSNvu6RumcZMmSh4/l+Q==", "ID": "0", "LUNCOPYTYPE": "1", "COPYPROGRESS": "0", "COPYSPEED": "2", "TYPE": 219, "COPYSTARTTIME": "-1" } } """ # A fake response of lun copy list info response FAKE_GET_LUN_COPY_LIST_INFO_RESPONSE = """ { "error": { "code": 0 }, "data": [{ "COPYSTOPTIME": "1372209335", "HEALTHSTATUS": "1", "NAME": "w1PSNvu6RumcZMmSh4/l+Q==", "RUNNINGSTATUS": "40", "DESCRIPTION": "w1PSNvu6RumcZMmSh4/l+Q==", "ID": "0", "LUNCOPYTYPE": "1", "COPYPROGRESS": "100", "COPYSPEED": "2", "TYPE": 219, "COPYSTARTTIME": "1372209329" }] } """ # A fake response of mappingview info response FAKE_GET_MAPPING_VIEW_INFO_RESPONSE = """ { "error":{ "code":0 }, "data":[{ "WORKMODE":"255", "HEALTHSTATUS":"1", "NAME":"OpenStack_Mapping_View_1", "RUNNINGSTATUS":"27", "DESCRIPTION":"", "ENABLEINBANDCOMMAND":"true", "ID":"1", "INBANDLUNWWN":"", "TYPE":245 }, { "WORKMODE":"255", "HEALTHSTATUS":"1", "NAME":"YheUoRwbSX2BxN767nvLSw", "RUNNINGSTATUS":"27", "DESCRIPTION":"", "ENABLEINBANDCOMMAND":"true", "ID":"2", "INBANDLUNWWN": "", "TYPE": 245 }] } """ FAKE_GET_MAPPING_VIEW_RESPONSE = """ { "error":{ "code":0 }, "data":[{ "WORKMODE":"255", "HEALTHSTATUS":"1", "NAME":"mOWtSXnaQKi3hpB3tdFRIQ", "RUNNINGSTATUS":"27", "DESCRIPTION":"", "ENABLEINBANDCOMMAND":"true", "ID":"11", "INBANDLUNWWN":"", "TYPE": 245, "AVAILABLEHOSTLUNIDLIST": "" }] } """ FAKE_GET_SPEC_MAPPING_VIEW_RESPONSE = """ { "error":{ "code":0 }, "data":{ "WORKMODE":"255", "HEALTHSTATUS":"1", "NAME":"mOWtSXnaQKi3hpB3tdFRIQ", "RUNNINGSTATUS":"27", "DESCRIPTION":"", "ENABLEINBANDCOMMAND":"true", "ID":"1", "INBANDLUNWWN":"", "TYPE":245 } } """ FAKE_FC_INFO_RESPONSE = """ { "error":{ "code":0 }, "data":[{ "HEALTHSTATUS":"1", "NAME":"", "MULTIPATHTYPE":"1", "ISFREE":"true", "RUNNINGSTATUS":"27", "ID":"10000090fa0d6754", "OPERATIONSYSTEM":"255", "TYPE":223 }, { "HEALTHSTATUS":"1", "NAME":"", "MULTIPATHTYPE":"1", "ISFREE":"true", "RUNNINGSTATUS":"27", "ID":"10000090fa0d6755", "OPERATIONSYSTEM":"255", "TYPE":223 }] } """ FAKE_ISCSI_INITIATOR_RESPONSE = """ { "error":{ "code":0 }, "data":[{ "CHAPNAME":"mm-user", "HEALTHSTATUS":"1", "ID":"iqn.1993-08.org.debian:01:9073aba6c6f", "ISFREE":"true", "MULTIPATHTYPE":"1", "NAME":"", "OPERATIONSYSTEM":"255", "RUNNINGSTATUS":"28", "TYPE":222, "USECHAP":"true" }] } """ FAKE_HOST_LINK_RESPONSE = """ { "error":{ "code":0 }, "data":[{ "PARENTTYPE":21, "TARGET_ID":"0000000000000000", "INITIATOR_NODE_WWN":"20000090fa0d6754", "INITIATOR_TYPE":"223", "RUNNINGSTATUS":"27", "PARENTNAME":"ubuntuc", "INITIATOR_ID":"10000090fa0d6754", "TARGET_PORT_WWN":"24000022a10a2a39", "HEALTHSTATUS":"1", "INITIATOR_PORT_WWN":"10000090fa0d6754", "ID":"010000090fa0d675-0000000000110400", "TARGET_NODE_WWN":"21000022a10a2a39", "PARENTID":"1", "CTRL_ID":"0", "TYPE":255, "TARGET_TYPE":"212" }] } """ FAKE_PORT_GROUP_RESPONSE = """ { "error":{ "code":0 }, "data":[{ "ID":11, "NAME": "portgroup-test" }] } """ FAKE_ISCSI_INITIATOR_RESPONSE = """ { "error":{ "code": 0 }, "data":[{ "CHAPNAME": "mm-user", "HEALTHSTATUS": "1", "ID": "iqn.1993-08.org.debian:01:9073aba6c6f", "ISFREE": "true", "MULTIPATHTYPE": "1", "NAME": "", "OPERATIONSYSTEM": "255", "RUNNINGSTATUS": "28", "TYPE": 222, "USECHAP": "true" }] } """ FAKE_ISCSI_INITIATOR_RESPONSE = """ { "error":{ "code":0 }, "data":[{ "CHAPNAME":"mm-user", "HEALTHSTATUS":"1", "ID":"iqn.1993-08.org.debian:01:9073aba6c6f", "ISFREE":"true", "MULTIPATHTYPE":"1", "NAME":"", "OPERATIONSYSTEM":"255", "RUNNINGSTATUS":"28", "TYPE":222, "USECHAP":"true" }] } """ FAKE_ERROR_INFO_RESPONSE = """ { "error":{ "code":31755596 } } """ FAKE_ERROR_CONNECT_RESPONSE = """ { "error":{ "code":-403 } } """ FAKE_ERROR_LUN_INFO_RESPONSE = """ { "error":{ "code":0 }, "data":{ "ID":"11", "IOCLASSID":"11", "NAME":"5mFHcBv4RkCcD+JyrWc0SA", "ALLOCTYPE": "0", "DATATRANSFERPOLICY": "0", "SMARTCACHEPARTITIONID": "0", "CACHEPARTITIONID": "0" } } """ FAKE_GET_FC_INI_RESPONSE = """ { "error":{ "code":0 }, "data":[{ "ID":"10000090fa0d6754", "ISFREE":"true" }] } """ FAKE_GET_FC_PORT_RESPONSE = """ { "error":{ "code":0 }, "data":[{ "RUNNINGSTATUS":"10", "WWN":"2000643e8c4c5f66", "PARENTID":"0A.1" }] } """ FAKE_SYSTEM_VERSION_RESPONSE = """ { "error":{ "code": 0 }, "data":{ "PRODUCTVERSION": "V100R001C10", "wwn": "21003400a30d844d" } } """ FAKE_GET_LUN_MIGRATION_RESPONSE = """ { "data":[{"ENDTIME":"1436816174", "ID":"9", "PARENTID":"11", "PARENTNAME":"xmRBHMlVRruql5vwthpPXQ", "PROCESS":"-1", "RUNNINGSTATUS":"76", "SPEED":"2", "STARTTIME":"1436816111", "TARGETLUNID":"1", "TARGETLUNNAME":"4924891454902893639", "TYPE":253, "WORKMODE":"0" }], "error":{"code":0, "description":"0"} } """ FAKE_GET_FC_INI_RESPONSE = """ { "error":{ "code":0 }, "data":[{ "ID":"10000090fa0d6754", "ISFREE":"true" }] } """ FAKE_HYPERMETRODOMAIN_RESPONSE = """ { "error":{ "code": 0 }, "data":{ "PRODUCTVERSION": "V100R001C10", "ID": "11", "NAME": "hypermetro_test", "RUNNINGSTATUS": "42" } } """ FAKE_HYPERMETRO_RESPONSE = """ { "error":{ "code": 0 }, "data":{ "PRODUCTVERSION": "V100R001C10", "ID": "11", "NAME": "hypermetro_test", "RUNNINGSTATUS": "1", "HEALTHSTATUS": "1" } } """ FAKE_QOS_INFO_RESPONSE = """ { "error":{ "code": 0 }, "data":{ "ID": "11" } } """ FAKE_GET_FC_PORT_RESPONSE = """ { "error":{ "code":0 }, "data":[{ "RUNNINGSTATUS":"10", "WWN":"2000643e8c4c5f66", "PARENTID":"0A.1", "ID": "1114368", "RUNSPEED": "16000" }, { "RUNNINGSTATUS":"10", "WWN":"2009643e8c4c5f67", "PARENTID":"0A.1", "ID": "1114369", "RUNSPEED": "16000" }] } """ FAKE_SMARTCACHEPARTITION_RESPONSE = """ { "error":{ "code":0 }, "data":{ "ID":"11", "NAME":"cache-name" } } """ FAKE_CONNECT_FC_RESPONCE = { "driver_volume_type": 'fibre_channel', "data": { "target_wwn": ["10000090fa0d6754"], "target_lun": "1", "volume_id": "21ec7341-9256-497b-97d9-ef48edcf0635" } } FAKE_METRO_INFO_RESPONCE = { "error": { "code": 0 }, "data": { "PRODUCTVERSION": "V100R001C10", "ID": "11", "NAME": "hypermetro_test", "RUNNINGSTATUS": "42" } } # mock login info map MAP_COMMAND_TO_FAKE_RESPONSE = {} MAP_COMMAND_TO_FAKE_RESPONSE['/xx/sessions'] = ( FAKE_GET_LOGIN_STORAGE_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/sessions'] = ( FAKE_LOGIN_OUT_STORAGE_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/LUN_MIGRATION/POST'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/LUN_MIGRATION?range=[0-256]/GET'] = ( FAKE_GET_LUN_MIGRATION_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/LUN_MIGRATION/11/DELETE'] = ( FAKE_COMMON_SUCCESS_RESPONSE) # mock storage info map MAP_COMMAND_TO_FAKE_RESPONSE['/storagepool'] = ( FAKE_STORAGE_POOL_RESPONSE) # mock lun info map MAP_COMMAND_TO_FAKE_RESPONSE['/lun'] = ( FAKE_LUN_INFO_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/lun/11/GET'] = ( FAKE_LUN_GET_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/lun/1/GET'] = ( FAKE_LUN_GET_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/lun/11/DELETE'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/lun/1/DELETE'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/lun/1/PUT'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/lun/11/PUT'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/lun?range=[0-65535]/GET'] = ( FAKE_QUERY_ALL_LUN_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/lun/associate?TYPE=11&ASSOCIATEOBJTYPE=256' '&ASSOCIATEOBJID=11/GET'] = ( FAKE_LUN_ASSOCIATE_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/lun/associate?TYPE=11&ASSOCIATEOBJTYPE=256' '&ASSOCIATEOBJID=12/GET'] = ( FAKE_LUN_ASSOCIATE_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/lun/associate?ID=1&TYPE=11&ASSOCIATEOBJTYPE=21' '&ASSOCIATEOBJID=0/GET'] = ( FAKE_LUN_ASSOCIATE_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/lun/associate?TYPE=11&ASSOCIATEOBJTYPE=21' '&ASSOCIATEOBJID=1/GET'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/lun/associate/cachepartition?ID=1' '&ASSOCIATEOBJTYPE=11&ASSOCIATEOBJID=11' '/DELETE'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/lungroup?range=[0-8191]/GET'] = ( FAKE_QUERY_LUN_GROUP_INFO_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/lungroup'] = ( FAKE_QUERY_LUN_GROUP_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/lungroup/associate'] = ( FAKE_QUERY_LUN_GROUP_ASSOCIAT_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/LUNGroup/11/DELETE'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/lungroup/associate?ID=11&ASSOCIATEOBJTYPE=11' '&ASSOCIATEOBJID=1/DELETE'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/lungroup/associate?TYPE=256&ASSOCIATEOBJTYPE=11' '&ASSOCIATEOBJID=11/GET'] = ( FAKE_LUN_ASSOCIATE_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/lungroup/associate?TYPE=256&ASSOCIATEOBJTYPE=11' '&ASSOCIATEOBJID=1/GET'] = ( FAKE_LUN_ASSOCIATE_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/lungroup/associate?ID=11&ASSOCIATEOBJTYPE=11' '&ASSOCIATEOBJID=11/DELETE'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/lun/count?TYPE=11&ASSOCIATEOBJTYPE=256' '&ASSOCIATEOBJID=11/GET'] = ( FAKE_LUN_COUNT_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/lun/expand/PUT'] = ( FAKE_LUN_INFO_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/lungroup/associate?ID=12&ASSOCIATEOBJTYPE=11' '&ASSOCIATEOBJID=12/DELETE'] = ( FAKE_COMMON_SUCCESS_RESPONSE) # mock snapshot info map MAP_COMMAND_TO_FAKE_RESPONSE['/snapshot'] = ( FAKE_CREATE_SNAPSHOT_INFO_RESPONSE) # mock snapshot info map MAP_COMMAND_TO_FAKE_RESPONSE['/snapshot/11/GET'] = ( FAKE_GET_SNAPSHOT_INFO_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/snapshot/activate'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/snapshot/stop/PUT'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/snapshot/11/DELETE'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/snapshot?range=[0-32767]/GET'] = ( FAKE_SNAPSHOT_LIST_INFO_RESPONSE) # mock QoS info map MAP_COMMAND_TO_FAKE_RESPONSE['/ioclass/11/GET'] = ( FAKE_LUN_GET_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/ioclass/11/DELETE'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/ioclass/active/11/PUT'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/ioclass/'] = ( FAKE_QOS_INFO_RESPONSE) # mock iscsi info map MAP_COMMAND_TO_FAKE_RESPONSE['/iscsi_tgt_port/GET'] = ( FAKE_GET_ISCSI_INFO_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/eth_port/GET'] = ( FAKE_GET_ETH_INFO_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/eth_port/associate?TYPE=213&ASSOCIATEOBJTYPE' '=257&ASSOCIATEOBJID=11/GET'] = ( FAKE_GET_ETH_ASSOCIATE_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/iscsidevicename'] = ( FAKE_GET_ISCSI_DEVICE_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/iscsi_initiator?range=[0-256]/GET'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/iscsi_initiator/'] = ( FAKE_ISCSI_INITIATOR_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/iscsi_initiator/POST'] = ( FAKE_ISCSI_INITIATOR_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/iscsi_initiator/PUT'] = ( FAKE_ISCSI_INITIATOR_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/iscsi_initiator/remove_iscsi_from_host/PUT'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/iscsi_initiator/' 'iqn.1993-08.debian:01:ec2bff7ac3a3/PUT'] = ( FAKE_ISCSI_INITIATOR_RESPONSE) # mock host info map MAP_COMMAND_TO_FAKE_RESPONSE['/host?range=[0-65535]/GET'] = ( FAKE_GET_ALL_HOST_INFO_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/host/1/DELETE'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/host'] = ( FAKE_CREATE_HOST_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/hostgroup?range=[0-8191]/GET'] = ( FAKE_GET_ALL_HOST_GROUP_INFO_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/hostgroup'] = ( FAKE_GET_HOST_GROUP_INFO_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/host/associate?TYPE=14&ID=0' '&ASSOCIATEOBJTYPE=21&ASSOCIATEOBJID=1' '/DELETE'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/host/associate?TYPE=14&ID=0' '&ASSOCIATEOBJID=0/GET'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/host/associate?TYPE=21&' 'ASSOCIATEOBJTYPE=14&ASSOCIATEOBJID=0/GET'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/hostgroup/0/DELETE'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/host/associate?TYPE=21&' 'ASSOCIATEOBJTYPE=14&ASSOCIATEOBJID=0/GET'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/hostgroup/associate'] = ( FAKE_COMMON_SUCCESS_RESPONSE) # mock copy info map MAP_COMMAND_TO_FAKE_RESPONSE['/luncopy'] = ( FAKE_GET_LUN_COPY_INFO_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/LUNCOPY?range=[0-1023]/GET'] = ( FAKE_GET_LUN_COPY_LIST_INFO_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/LUNCOPY/start/PUT'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/LUNCOPY/0/DELETE'] = ( FAKE_COMMON_SUCCESS_RESPONSE) # mock mapping view info map MAP_COMMAND_TO_FAKE_RESPONSE['/mappingview?range=[0-8191]/GET'] = ( FAKE_GET_MAPPING_VIEW_INFO_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/mappingview'] = ( FAKE_GET_MAPPING_VIEW_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/MAPPINGVIEW/1/GET'] = ( FAKE_GET_SPEC_MAPPING_VIEW_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/mappingview/1/DELETE'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/mappingview/associate/lungroup?TYPE=256&' 'ASSOCIATEOBJTYPE=245&ASSOCIATEOBJID=1/GET'] = ( FAKE_GET_MAPPING_VIEW_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/mappingview/associate?TYPE=245&' 'ASSOCIATEOBJTYPE=14&ASSOCIATEOBJID=0/GET'] = ( FAKE_GET_MAPPING_VIEW_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/mappingview/associate?TYPE=245&' 'ASSOCIATEOBJTYPE=256&ASSOCIATEOBJID=11/GET'] = ( FAKE_GET_MAPPING_VIEW_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/mappingview/associate?TYPE=245&' 'ASSOCIATEOBJTYPE=257&ASSOCIATEOBJID=11/GET'] = ( FAKE_GET_MAPPING_VIEW_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/portgroup/associate?ASSOCIATEOBJTYPE=245&' 'ASSOCIATEOBJID=1&range=[0-8191]/GET'] = ( FAKE_GET_MAPPING_VIEW_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/MAPPINGVIEW/CREATE_ASSOCIATE/PUT'] = ( FAKE_COMMON_SUCCESS_RESPONSE) # mock FC info map MAP_COMMAND_TO_FAKE_RESPONSE['/fc_initiator?ISFREE=true&' 'range=[0-8191]/GET'] = ( FAKE_FC_INFO_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/MAPPINGVIEW/CREATE_ASSOCIATE/PUT'] = ( FAKE_COMMON_SUCCESS_RESPONSE) # mock FC info map MAP_COMMAND_TO_FAKE_RESPONSE['/fc_initiator?ISFREE=true&' 'range=[0-8191]/GET'] = ( FAKE_FC_INFO_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/fc_initiator/10000090fa0d6754/GET'] = ( FAKE_FC_INFO_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/fc_initiator/10000090fa0d6754/PUT'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/host_link?INITIATOR_TYPE=223' '&INITIATOR_PORT_WWN=10000090fa0d6754/GET'] = ( FAKE_HOST_LINK_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/portgroup?range=[0-8191]&TYPE=257/GET'] = ( FAKE_PORT_GROUP_RESPONSE) # mock system info map MAP_COMMAND_TO_FAKE_RESPONSE['/system//GET'] = ( FAKE_SYSTEM_VERSION_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/fc_initiator?range=[0-256]/GET'] = ( FAKE_GET_FC_INI_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/fc_port/GET'] = ( FAKE_GET_FC_PORT_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/fc_initiator/GET'] = ( FAKE_GET_FC_PORT_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['fc_initiator?range=[0-256]/GET'] = ( FAKE_GET_FC_PORT_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/fc_initiator?PARENTTYPE=21&PARENTID=1/GET'] = ( FAKE_GET_FC_PORT_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/lun/associate/cachepartition/POST'] = ( FAKE_SYSTEM_VERSION_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/fc_initiator?range=[0-256]&PARENTID=1/GET'] = ( FAKE_GET_FC_PORT_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/fc_initiator?PARENTTYPE=21&PARENTID=1/GET'] = ( FAKE_GET_FC_PORT_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/SMARTCACHEPARTITION/0/GET'] = ( FAKE_SMARTCACHEPARTITION_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/SMARTCACHEPARTITION/REMOVE_ASSOCIATE/PUT'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/cachepartition/0/GET'] = ( FAKE_SMARTCACHEPARTITION_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/HyperMetroDomain?range=[0-32]/GET'] = ( FAKE_HYPERMETRODOMAIN_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/HyperMetroPair/POST'] = ( FAKE_HYPERMETRODOMAIN_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/HyperMetroPair/11/GET'] = ( FAKE_HYPERMETRODOMAIN_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/HyperMetroPair/disable_hcpair/PUT'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/HyperMetroPair/11/DELETE'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/HyperMetroPair/1/GET'] = ( FAKE_HYPERMETRO_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/HyperMetroPair?range=[0-65535]/GET'] = ( FAKE_COMMON_SUCCESS_RESPONSE) MAP_COMMAND_TO_FAKE_RESPONSE['/splitmirror?range=[0-512]/GET'] = ( FAKE_COMMON_SUCCESS_RESPONSE) FACK_GET_PORTG_BY_VIEW = """ { "data": [{ "DESCRIPTION": "Please do NOT modify this. Engine ID: 0", "ID": "0", "NAME": "OpenStack_PortGroup_1", "TYPE": 257 }], "error": { "code": 0 } } """ MAP_COMMAND_TO_FAKE_RESPONSE['/portgroup/associate/mappingview?TYPE=257&AS' 'SOCIATEOBJTYPE=245&ASSOCIATEOBJID=1/GET'] = ( FACK_GET_PORTG_BY_VIEW) FACK_GET_PORT_BY_PORTG = """ { "data":[{ "CONFSPEED":"0","FCCONFMODE":"3", "FCRUNMODE":"0","HEALTHSTATUS":"1","ID":"2000643e8c4c5f66", "MAXSUPPORTSPEED":"16000","NAME":"P0","PARENTID":"0B.1", "PARENTTYPE":209,"RUNNINGSTATUS":"10","RUNSPEED":"8000", "WWN":"2000643e8c4c5f66" }], "error":{ "code":0,"description":"0" } } """ MAP_COMMAND_TO_FAKE_RESPONSE['/fc_port/associate/portgroup?TYPE=212&ASSOCI' 'ATEOBJTYPE=257&ASSOCIATEOBJID=0/GET'] = ( FACK_GET_PORT_BY_PORTG) FACK_GET_PORTG = """ { "data": { "TYPE": 257, "NAME": "OpenStack_PortGroup_1", "DESCRIPTION": "Please DO NOT change thefollowing message: 0", "ID": "0" }, "error": { "code": 0, "description": "0" } } """ MAP_COMMAND_TO_FAKE_RESPONSE['/portgroup/0/GET'] = FACK_GET_PORTG MAP_COMMAND_TO_FAKE_RESPONSE['/portgroup/0/PUT'] = FACK_GET_PORTG MAP_COMMAND_TO_FAKE_RESPONSE['/port/associate/portgroup/POST'] = ( FACK_GET_PORT_BY_PORTG) MAP_COMMAND_TO_FAKE_RESPONSE['/port/associate/portgroup?ID=0&TYPE=257&ASSOCIA' 'TEOBJTYPE=212&ASSOCIATEOBJID=2000643e8c4c5f66/DE' 'LETE'] = ( FAKE_COMMON_SUCCESS_RESPONSE) FAKE_CREATE_PORTG = """ { "data": { "DESCRIPTION": "Please DO NOT change the following message: 0", "ID": "0", "NAME": "OpenStack_PortGroup_1", "TYPE": 257 }, "error": { "code": 0, "description": "0" } } """ MAP_COMMAND_TO_FAKE_RESPONSE['/PortGroup/POST'] = FAKE_CREATE_PORTG FAKE_GET_PORTG_FROM_PORT = """ { "data": [{ "TYPE": 257, "NAME": "OpenStack_PortGroup_1", "DESCRIPTION": "PleaseDONOTchangethefollowingmessage: 0", "ID": "0" }], "error": { "code": 0, "description": "0" } } """ MAP_COMMAND_TO_FAKE_RESPONSE['/portgroup/associate/fc_port?TYPE=257&ASSOCIA' 'TEOBJTYPE=212&ASSOCIATEOBJID=1114368/GET'] = ( FAKE_GET_PORTG_FROM_PORT) FACK_GET_VIEW_BY_PORTG = """ { "data": [{ "ASSOCIATEOBJID": "0", "COUNT": "0", "ASSOCIATEOBJTYPE": "0", "INBANDLUNWWN": "", "FORFILESYSTEM": "false", "ID": "2", "ENABLEINBANDCOMMAND": "false", "NAME": "OpenStack_Mapping_View_1", "WORKMODE": "0", "TYPE": 245, "HOSTLUNID": "0", "DESCRIPTION": "" }], "error": { "code": 0, "description": "0" } } """ MAP_COMMAND_TO_FAKE_RESPONSE['/mappingview/associate/portgroup?TYPE=245&ASS' 'OCIATEOBJTYPE=257&ASSOCIATEOBJID=0/GET'] = ( FACK_GET_VIEW_BY_PORTG) FACK_GET_LUNG_BY_VIEW = """ { "data": [{ "TYPE": 256, "NAME": "OpenStack_LunGroup_1", "DESCRIPTION": "OpenStack_LunGroup_1", "ID": "1" }], "error": { "code": 0, "description": "0" } } """ MAP_COMMAND_TO_FAKE_RESPONSE['/lungroup/associate/mappingview?TYPE=256&ASSO' 'CIATEOBJTYPE=245&ASSOCIATEOBJID=2/GET'] = ( FACK_GET_LUNG_BY_VIEW) FAKE_LUN_COUNT_RESPONSE_1 = """ { "data":{ "COUNT":"2" }, "error":{ "code":0, "description":"0" } } """ MAP_COMMAND_TO_FAKE_RESPONSE['/lun/count?TYPE=11&ASSOCIATEOB' 'JTYPE=256&ASSOCIATEOBJID=1/GET'] = ( FAKE_LUN_COUNT_RESPONSE_1) FAKE_PORTS_IN_PG_RESPONSE = """ { "data": [{ "ID": "1114114", "WWN": "2002643e8c4c5f66" }, { "ID": "1114113", "WWN": "2001643e8c4c5f66" }], "error": { "code": 0, "description": "0" } } """ MAP_COMMAND_TO_FAKE_RESPONSE['/fc_port/associate?TYPE=213&ASSOCIATEOBJTYPE=' '257&ASSOCIATEOBJID=0/GET'] = ( FAKE_PORTS_IN_PG_RESPONSE) # Replication response FAKE_GET_REMOTEDEV_RESPONSE = """ { "data":[{ "ARRAYTYPE":"1", "HEALTHSTATUS":"1", "ID":"0", "NAME":"Huawei.Storage", "RUNNINGSTATUS":"1", "WWN":"21003400a30d844d" }], "error":{ "code":0, "description":"0" } } """ MAP_COMMAND_TO_FAKE_RESPONSE['/remote_device/GET'] = ( FAKE_GET_REMOTEDEV_RESPONSE) FAKE_CREATE_PAIR_RESPONSE = """ { "data":{ "ID":"%s" }, "error":{ "code":0, "description":"0" } } """ % TEST_PAIR_ID MAP_COMMAND_TO_FAKE_RESPONSE['/REPLICATIONPAIR/POST'] = ( FAKE_CREATE_PAIR_RESPONSE) FAKE_DELETE_PAIR_RESPONSE = """ { "data":{}, "error":{ "code":0, "description":"0" } } """ MAP_COMMAND_TO_FAKE_RESPONSE['/REPLICATIONPAIR/%s/DELETE' % TEST_PAIR_ID] = ( FAKE_DELETE_PAIR_RESPONSE) FAKE_SET_PAIR_ACCESS_RESPONSE = """ { "data":{}, "error":{ "code":0, "description":"0" } } """ MAP_COMMAND_TO_FAKE_RESPONSE['/REPLICATIONPAIR/%s/PUT' % TEST_PAIR_ID] = ( FAKE_SET_PAIR_ACCESS_RESPONSE) FAKE_GET_PAIR_NORMAL_RESPONSE = """ { "data":{ "REPLICATIONMODEL": "1", "RUNNINGSTATUS": "1", "SECRESACCESS": "2", "HEALTHSTATUS": "1", "ISPRIMARY": "true" }, "error":{ "code":0, "description":"0" } } """ FAKE_GET_PAIR_SPLIT_RESPONSE = """ { "data":{ "REPLICATIONMODEL": "1", "RUNNINGSTATUS": "26", "SECRESACCESS": "2", "ISPRIMARY": "true" }, "error":{ "code":0, "description":"0" } } """ FAKE_GET_PAIR_SYNC_RESPONSE = """ { "data":{ "REPLICATIONMODEL": "1", "RUNNINGSTATUS": "23", "SECRESACCESS": "2" }, "error":{ "code":0, "description":"0" } } """ MAP_COMMAND_TO_FAKE_RESPONSE['/REPLICATIONPAIR/%s/GET' % TEST_PAIR_ID] = ( FAKE_GET_PAIR_NORMAL_RESPONSE) FAKE_SYNC_PAIR_RESPONSE = """ { "data":{}, "error":{ "code":0, "description":"0" } } """ MAP_COMMAND_TO_FAKE_RESPONSE['/REPLICATIONPAIR/sync/PUT'] = ( FAKE_SYNC_PAIR_RESPONSE) FAKE_SPLIT_PAIR_RESPONSE = """ { "data":{}, "error":{ "code":0, "description":"0" } } """ MAP_COMMAND_TO_FAKE_RESPONSE['/REPLICATIONPAIR/split/PUT'] = ( FAKE_SPLIT_PAIR_RESPONSE) FAKE_SWITCH_PAIR_RESPONSE = """ { "data":{}, "error":{ "code":0, "description":"0" } } """ MAP_COMMAND_TO_FAKE_RESPONSE['/REPLICATIONPAIR/switch/PUT'] = ( FAKE_SWITCH_PAIR_RESPONSE) def Fake_sleep(time): pass class FakeHuaweiConf(object): def __init__(self, conf, protocol): self.conf = conf self.protocol = protocol def safe_get(self, key): try: return getattr(self.conf, key) except Exception: return def update_config_value(self): setattr(self.conf, 'volume_backend_name', 'huawei_storage') setattr(self.conf, 'san_address', ['http://100.115.10.69:8082/deviceManager/rest/']) setattr(self.conf, 'san_user', 'admin') setattr(self.conf, 'san_password', 'Admin@storage') setattr(self.conf, 'san_product', 'V3') setattr(self.conf, 'san_protocol', self.protocol) setattr(self.conf, 'lun_type', constants.THICK_LUNTYPE) setattr(self.conf, 'lun_ready_wait_interval', 2) setattr(self.conf, 'lun_copy_wait_interval', 2) setattr(self.conf, 'lun_timeout', 43200) setattr(self.conf, 'lun_write_type', '1') setattr(self.conf, 'lun_mirror_switch', '1') setattr(self.conf, 'lun_prefetch_type', '1') setattr(self.conf, 'lun_prefetch_value', '0') setattr(self.conf, 'lun_policy', '0') setattr(self.conf, 'lun_read_cache_policy', '2') setattr(self.conf, 'lun_write_cache_policy', '5') setattr(self.conf, 'storage_pools', ['OpenStack_Pool']) setattr(self.conf, 'iscsi_default_target_ip', ['100.115.10.68']) setattr(self.conf, 'metro_san_address', ['https://100.97.50.240:8088/deviceManager/rest/']) setattr(self.conf, 'metro_storage_pools', 'StoragePool001') setattr(self.conf, 'metro_san_user', 'admin') setattr(self.conf, 'metro_san_password', 'Admin@storage1') setattr(self.conf, 'metro_domain_name', 'hypermetro_test') iscsi_info = {'Name': 'iqn.1993-08.debian:01:ec2bff7ac3a3', 'TargetIP': '192.168.100.2', 'CHAPinfo': 'mm-user;mm-user@storage', 'ALUA': '1', 'TargetPortGroup': 'portgroup-test', } setattr(self.conf, 'iscsi_info', [iscsi_info]) targets = [{'target_device_id': 'huawei-replica-1', 'managed_backend_name': 'ubuntu@huawei2#OpenStack_Pool', 'san_address': 'https://100.97.10.69:8088/deviceManager/rest/', 'san_user': 'admin', 'san_password': 'Admin@storage1'}] setattr(self.conf, 'replication_device', targets) setattr(self.conf, 'safe_get', self.safe_get) class FakeClient(rest_client.RestClient): def __init__(self, configuration): san_address = configuration.san_address san_user = configuration.san_user san_password = configuration.san_password rest_client.RestClient.__init__(self, configuration, san_address, san_user, san_password) self.test_fail = False self.test_multi_url_flag = False self.cache_not_exist = False self.partition_not_exist = False def _get_snapshotid_by_name(self, snapshot_name): return "11" def _check_snapshot_exist(self, snapshot_id): return True def get_partition_id_by_name(self, name): if self.partition_not_exist: return None return "11" def get_cache_id_by_name(self, name): if self.cache_not_exist: return None return "11" def add_lun_to_cache(self, lunid, cache_id): pass def do_call(self, url=False, data=None, method=None, calltimeout=4): url = url.replace('http://100.115.10.69:8082/deviceManager/rest', '') command = url.replace('/210235G7J20000000000/', '') data = json.dumps(data) if data else None if method: command = command + "/" + method for item in MAP_COMMAND_TO_FAKE_RESPONSE.keys(): if command == item: data = MAP_COMMAND_TO_FAKE_RESPONSE[item] if self.test_fail: data = FAKE_ERROR_INFO_RESPONSE if command == 'lun/11/GET': data = FAKE_ERROR_LUN_INFO_RESPONSE self.test_fail = False if self.test_multi_url_flag: data = FAKE_ERROR_CONNECT_RESPONSE self.test_multi_url_flag = False return json.loads(data) class FakeDB(object): def volume_update(self, context, volume_id, model_update): pass def volume_get_all_by_group(self, context, group_id): volumes = [] volumes.append(test_volume) return volumes class FakeReplicaPairManager(replication.ReplicaPairManager): def _init_rmt_client(self): self.rmt_client = FakeClient(self.conf) class FakeISCSIStorage(huawei_driver.HuaweiISCSIDriver): """Fake Huawei Storage, Rewrite some methods of HuaweiISCSIDriver.""" def __init__(self, configuration): self.configuration = configuration self.db = FakeDB() self.huawei_conf = FakeHuaweiConf(self.configuration, 'iSCSI') def do_setup(self): self.metro_flag = True self.huawei_conf.update_config_value() self.client = FakeClient(configuration=self.configuration) self.rmt_client = FakeClient(configuration=self.configuration) self.metro = hypermetro.HuaweiHyperMetro(self.client, self.rmt_client, self.configuration, self.db) self.replica = FakeReplicaPairManager(self.client, self.configuration) class FakeFCStorage(huawei_driver.HuaweiFCDriver): """Fake Huawei Storage, Rewrite some methods of HuaweiISCSIDriver.""" def __init__(self, configuration): self.configuration = configuration self.fcsan = None self.db = FakeDB() self.huawei_conf = FakeHuaweiConf(self.configuration, 'iSCSI') def do_setup(self): self.metro_flag = True self.huawei_conf.update_config_value() self.client = FakeClient(configuration=self.configuration) self.rmt_client = FakeClient(configuration=self.configuration) self.metro = hypermetro.HuaweiHyperMetro(self.client, self.rmt_client, self.configuration, self.db) self.replica = FakeReplicaPairManager(self.client, self.configuration) @ddt.ddt class HuaweiISCSIDriverTestCase(test.TestCase): def setUp(self): super(HuaweiISCSIDriverTestCase, self).setUp() self.configuration = mock.Mock(spec=conf.Configuration) self.configuration.hypermetro_devices = hypermetro_devices self.stubs.Set(time, 'sleep', Fake_sleep) self.driver = FakeISCSIStorage(configuration=self.configuration) self.driver.do_setup() self.portgroup = 'portgroup-test' self.iscsi_iqns = ['iqn.2006-08.com.huawei:oceanstor:21000022a:' ':20503:192.168.1.1', 'iqn.2006-08.com.huawei:oceanstor:21000022a:' ':20500:192.168.1.2'] self.target_ips = ['192.168.1.1', '192.168.1.2'] self.portgroup_id = 11 self.driver.client.login() def test_login_success(self): device_id = self.driver.client.login() self.assertEqual('210235G7J20000000000', device_id) def test_create_volume_success(self): # Have pool info in the volume. test_volume = {'name': 'volume-21ec7341-9256-497b-97d9-ef48edcf0635', 'size': 2, 'volume_name': 'vol1', 'id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'volume_id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'provider_auth': None, 'project_id': 'project', 'display_name': 'vol1', 'display_description': 'test volume', 'volume_type_id': None, 'host': 'ubuntu001@backend001#OpenStack_Pool', 'provider_location': '11', } lun_info = self.driver.create_volume(test_volume) self.assertEqual('1', lun_info['provider_location']) # No pool info in the volume. test_volume = {'name': 'volume-21ec7341-9256-497b-97d9-ef48edcf0635', 'size': 2, 'volume_name': 'vol1', 'id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'volume_id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'provider_auth': None, 'project_id': 'project', 'display_name': 'vol1', 'display_description': 'test volume', 'volume_type_id': None, 'host': 'ubuntu001@backend001', 'provider_location': '11', } lun_info = self.driver.create_volume(test_volume) self.assertEqual('1', lun_info['provider_location']) def test_delete_volume_success(self): self.driver.delete_volume(test_volume) def test_create_snapshot_success(self): lun_info = self.driver.create_snapshot(test_snap) self.assertEqual(11, lun_info['provider_location']) test_snap['volume']['provider_location'] = '' lun_info = self.driver.create_snapshot(test_snap) self.assertEqual(11, lun_info['provider_location']) test_snap['volume']['provider_location'] = None lun_info = self.driver.create_snapshot(test_snap) self.assertEqual(11, lun_info['provider_location']) def test_delete_snapshot_success(self): delete_flag = self.driver.delete_snapshot(test_snap) self.assertTrue(delete_flag) def test_create_volume_from_snapsuccess(self): self.mock_object( huawei_driver.HuaweiBaseDriver, '_get_volume_type', mock.Mock(return_value={'extra_specs': sync_replica_specs})) self.mock_object(replication.ReplicaCommonDriver, 'sync') model_update = self.driver.create_volume_from_snapshot(test_volume, test_volume) self.assertEqual('1', model_update['provider_location']) driver_data = {'pair_id': TEST_PAIR_ID, 'rmt_lun_id': '1'} driver_data = replication.to_string(driver_data) self.assertEqual(driver_data, model_update['replication_driver_data']) self.assertEqual('enabled', model_update['replication_status']) def test_initialize_connection_success(self): iscsi_properties = self.driver.initialize_connection(test_volume, FakeConnector) self.assertEqual(1, iscsi_properties['data']['target_lun']) def test_terminate_connection_success(self): self.driver.terminate_connection(test_volume, FakeConnector) def test_get_volume_status(self): data = self.driver.get_volume_stats() self.assertEqual('2.0.5', data['driver_version']) def test_extend_volume(self): self.driver.extend_volume(test_volume, 3) def test_login_fail(self): self.driver.client.test_fail = True self.assertRaises(exception.VolumeBackendAPIException, self.driver.client.login) def test_create_snapshot_fail(self): self.driver.client.test_fail = True self.assertRaises(exception.VolumeBackendAPIException, self.driver.create_snapshot, test_snap) def test_create_volume_fail(self): self.driver.client.test_fail = True self.assertRaises(exception.VolumeBackendAPIException, self.driver.create_volume, test_volume) def test_delete_volume_fail(self): self.driver.client.test_fail = True self.driver.delete_volume(test_volume) def test_delete_snapshot_fail(self): self.driver.client.test_fail = True self.driver.delete_volume(test_snap) def test_initialize_connection_fail(self): self.driver.client.test_fail = True self.assertRaises(exception.VolumeBackendAPIException, self.driver.initialize_connection, test_volume, FakeConnector) def test_lun_is_associated_to_lungroup(self): self.driver.client.associate_lun_to_lungroup('11', '11') result = self.driver.client._is_lun_associated_to_lungroup('11', '11') self.assertTrue(result) def test_lun_is_not_associated_to_lun_group(self): self.driver.client.associate_lun_to_lungroup('12', '12') self.driver.client.remove_lun_from_lungroup('12', '12') result = self.driver.client._is_lun_associated_to_lungroup('12', '12') self.assertFalse(result) def test_get_tgtip(self): portg_id = self.driver.client.get_tgt_port_group(self.portgroup) target_ip = self.driver.client._get_tgt_ip_from_portgroup(portg_id) self.assertEqual(self.target_ips, target_ip) def test_find_chap_info(self): tmp_dict = {} iscsi_info = {} tmp_dict['Name'] = 'iqn.1993-08.debian:01:ec2bff7ac3a3' tmp_dict['CHAPinfo'] = 'mm-user;mm-user@storage' iscsi_info = [tmp_dict] initiator_name = FakeConnector['initiator'] chapinfo = self.driver.client.find_chap_info(iscsi_info, initiator_name) chap_username, chap_password = chapinfo.split(';') self.assertEqual('mm-user', chap_username) self.assertEqual('mm-user@storage', chap_password) def test_find_alua_info(self): tmp_dict = {} iscsi_info = {} tmp_dict['Name'] = 'iqn.1993-08.debian:01:ec2bff7ac3a3' tmp_dict['ALUA'] = '1' iscsi_info = [tmp_dict] initiator_name = FakeConnector['initiator'] type = self.driver.client._find_alua_info(iscsi_info, initiator_name) self.assertEqual('1', type) def test_get_pool_info(self): pools = [{"NAME": "test001", "ID": "0", "USERFREECAPACITY": "36", "USERTOTALCAPACITY": "48", "USAGETYPE": constants.BLOCK_STORAGE_POOL_TYPE}, {"NAME": "test002", "ID": "1", "USERFREECAPACITY": "37", "USERTOTALCAPACITY": "49", "USAGETYPE": constants.FILE_SYSTEM_POOL_TYPE}, {"NAME": "test003", "ID": "0", "USERFREECAPACITY": "36", "DATASPACE": "35", "USERTOTALCAPACITY": "48", "USAGETYPE": constants.BLOCK_STORAGE_POOL_TYPE}] pool_name = 'test001' test_info = {'CAPACITY': '36', 'ID': '0', 'TOTALCAPACITY': '48'} pool_info = self.driver.client.get_pool_info(pool_name, pools) self.assertEqual(test_info, pool_info) pool_name = 'test002' test_info = {} pool_info = self.driver.client.get_pool_info(pool_name, pools) self.assertEqual(test_info, pool_info) pool_name = 'test000' test_info = {} pool_info = self.driver.client.get_pool_info(pool_name, pools) self.assertEqual(test_info, pool_info) pool_name = 'test003' test_info = {'CAPACITY': '35', 'ID': '0', 'TOTALCAPACITY': '48'} pool_info = self.driver.client.get_pool_info(pool_name, pools) self.assertEqual(test_info, pool_info) def test_get_smartx_specs_opts(self): smartx_opts = smartx.SmartX().get_smartx_specs_opts(smarttier_opts) self.assertEqual('3', smartx_opts['policy']) @mock.patch.object(smartx.SmartQos, 'get_qos_by_volume_type', return_value={'MAXIOPS': '100', 'IOType': '2'}) def test_create_smartqos(self, mock_qos_value): lun_info = self.driver.create_volume(test_volume) self.assertEqual('1', lun_info['provider_location']) @mock.patch.object(rest_client.RestClient, 'add_lun_to_partition') @mock.patch.object(huawei_driver.HuaweiBaseDriver, '_get_volume_params', return_value={'smarttier': 'true', 'smartcache': 'true', 'smartpartition': 'true', 'thin_provisioning_support': 'true', 'thick_provisioning_support': 'false', 'policy': '2', 'cachename': 'cache-test', 'partitionname': 'partition-test'}) def test_creat_smartx(self, mock_volume_types, mock_add_lun_to_partition): lun_info = self.driver.create_volume(test_volume) self.assertEqual('1', lun_info['provider_location']) def test_find_available_qos(self): qos = {'MAXIOPS': '100', 'IOType': '2'} fake_qos_info_response_equal = { "error": { "code": 0 }, "data": [{ "ID": "11", "MAXIOPS": "100", "IOType": "2", "LUNLIST": u'["1", "2", "3", "4", "5", "6", "7", "8", "9",\ "10", ,"11", "12", "13", "14", "15", "16", "17", "18", "19",\ "20", ,"21", "22", "23", "24", "25", "26", "27", "28", "29",\ "30", ,"31", "32", "33", "34", "35", "36", "37", "38", "39",\ "40", ,"41", "42", "43", "44", "45", "46", "47", "48", "49",\ "50", ,"51", "52", "53", "54", "55", "56", "57", "58", "59",\ "60", ,"61", "62", "63", "64"]' }] } # Number of LUNs in QoS is equal to 64 with mock.patch.object(rest_client.RestClient, 'get_qos', return_value=fake_qos_info_response_equal): (qos_id, lun_list) = self.driver.client.find_available_qos(qos) self.assertEqual((None, []), (qos_id, lun_list)) # Number of LUNs in QoS is less than 64 fake_qos_info_response_less = { "error": { "code": 0 }, "data": [{ "ID": "11", "MAXIOPS": "100", "IOType": "2", "LUNLIST": u'["0", "1", "2"]' }] } with mock.patch.object(rest_client.RestClient, 'get_qos', return_value=fake_qos_info_response_less): (qos_id, lun_list) = self.driver.client.find_available_qos(qos) self.assertEqual(("11", u'["0", "1", "2"]'), (qos_id, lun_list)) @mock.patch.object(huawei_driver.HuaweiBaseDriver, '_get_volume_params', return_value=fake_hypermetro_opts) @mock.patch.object(rest_client.RestClient, 'get_all_pools', return_value=FAKE_STORAGE_POOL_RESPONSE) @mock.patch.object(rest_client.RestClient, 'get_pool_info', return_value=FAKE_FIND_POOL_RESPONSE) @mock.patch.object(rest_client.RestClient, 'get_hyper_domain_id', return_value='11') @mock.patch.object(hypermetro.HuaweiHyperMetro, '_wait_volume_ready', return_value=True) def test_create_hypermetro_success(self, mock_volume_ready, mock_hyper_domain, mock_pool_info, mock_all_pool_info, mock_login_return): metadata = {"hypermetro_id": '11', "remote_lun_id": '1'} lun_info = self.driver.create_volume(hyper_volume) self.assertEqual(metadata, lun_info['metadata']) @mock.patch.object(huawei_driver.HuaweiBaseDriver, '_get_volume_params', return_value=fake_hypermetro_opts) @mock.patch.object(rest_client.RestClient, 'get_all_pools', return_value=FAKE_STORAGE_POOL_RESPONSE) @mock.patch.object(rest_client.RestClient, 'get_pool_info', return_value=FAKE_FIND_POOL_RESPONSE) @mock.patch.object(rest_client.RestClient, 'get_hyper_domain_id', return_value='11') @mock.patch.object(hypermetro.HuaweiHyperMetro, '_wait_volume_ready', return_value=True) @mock.patch.object(hypermetro.HuaweiHyperMetro, '_create_hypermetro_pair') @mock.patch.object(rest_client.RestClient, 'delete_lun') def test_create_hypermetro_fail(self, mock_delete_lun, mock_hyper_pair_info, mock_volume_ready, mock_hyper_domain, mock_pool_info, mock_all_pool_info, mock_hypermetro_opts): self.driver.client.login() mock_hyper_pair_info.side_effect = exception.VolumeBackendAPIException( data='Create hypermetro error.') self.assertRaises(exception.VolumeBackendAPIException, self.driver.create_volume, hyper_volume) mock_delete_lun.assert_called_with('1') @mock.patch.object(rest_client.RestClient, 'check_lun_exist', return_value=True) @mock.patch.object(rest_client.RestClient, 'check_hypermetro_exist', return_value=True) @mock.patch.object(rest_client.RestClient, 'delete_hypermetro', return_value=FAKE_COMMON_SUCCESS_RESPONSE) @mock.patch.object(rest_client.RestClient, 'delete_lun', return_value=None) def test_delete_hypermetro_success(self, mock_delete_lun, mock_delete_hypermetro, mock_check_hyermetro, mock_lun_exit): self.driver.delete_volume(hyper_volume) @mock.patch.object(rest_client.RestClient, 'check_lun_exist', return_value=True) @mock.patch.object(rest_client.RestClient, 'check_hypermetro_exist', return_value=True) @mock.patch.object(rest_client.RestClient, 'get_hypermetro_by_id', return_value=FAKE_METRO_INFO_RESPONCE) @mock.patch.object(rest_client.RestClient, 'delete_hypermetro') @mock.patch.object(rest_client.RestClient, 'delete_lun', return_value=None) def test_delete_hypermetro_fail(self, mock_delete_lun, mock_delete_hypermetro, mock_metro_info, mock_check_hyermetro, mock_lun_exit): mock_delete_hypermetro.side_effect = ( exception.VolumeBackendAPIException(data='Delete hypermetro ' 'error.')) self.assertRaises(exception.VolumeBackendAPIException, self.driver.delete_volume, hyper_volume) mock_delete_lun.assert_called_with('11') def test_manage_existing_get_size_invalid_reference(self): # Can't find LUN by source-name. external_ref = {'source-name': 'LUN1'} with mock.patch.object(rest_client.RestClient, 'get_lun_id_by_name', return_value=None): ex = self.assertRaises(exception.ManageExistingInvalidReference, self.driver.manage_existing_get_size, test_volume, external_ref) self.assertIsNotNone(re.search('please check the source-name ' 'or source-id', ex.msg)) # Can't find LUN by source-id. external_ref = {'source-id': 'ID1'} with mock.patch.object(rest_client.RestClient, 'get_lun_info') as m_gt: m_gt.side_effect = exception.VolumeBackendAPIException( data='Error') self.assertRaises(exception.VolumeBackendAPIException, self.driver.manage_existing_get_size, test_volume, external_ref) self.assertIsNotNone(re.search('please check the source-name ' 'or source-id', ex.msg)) def test_manage_existing_get_size_improper_lunsize(self): # LUN size is not multiple of 1 GB. external_ref = {'source-id': 'ID1'} with mock.patch.object(rest_client.RestClient, 'get_lun_info', return_value={'CAPACITY': 2097150}): ex = self.assertRaises(exception.VolumeBackendAPIException, self.driver.manage_existing_get_size, test_volume, external_ref) self.assertIsNotNone( re.search('Volume size must be multiple of 1 GB', ex.msg)) @ddt.data({'source-id': 'ID1'}, {'source-name': 'LUN1'}, {'source-name': 'LUN1', 'source-id': 'ID1'}) @mock.patch.object(rest_client.RestClient, 'get_lun_info', return_value={'CAPACITY': 2097152}) @mock.patch.object(rest_client.RestClient, 'get_lun_id_by_name', return_value='ID1') def test_manage_existing_get_size_success(self, mock_get_lun_id_by_name, mock_get_lun_info, external_ref): size = self.driver.manage_existing_get_size(test_volume, external_ref) self.assertEqual(1, size) @mock.patch.object(rest_client.RestClient, 'get_lun_info', return_value={'CAPACITY': 2097152, 'ID': 'ID1', 'PARENTNAME': 'StoragePool001'}) @mock.patch.object(rest_client.RestClient, 'get_lun_id_by_name', return_value='ID1') def test_manage_existing_pool_mismatch(self, mock_get_by_name, mock_get_info): # LUN does not belong to the specified pool. with mock.patch.object(huawei_driver.HuaweiBaseDriver, '_get_lun_info_by_ref', return_value={'PARENTNAME': 'StoragePool001'}): test_volume = {'host': 'ubuntu-204@v3r3#StoragePool002', 'name': 'volume-21ec7341-9256-497b-97d9-ef48edcf'} external_ref = {'source-name': 'LUN1'} ex = self.assertRaises(exception.ManageExistingInvalidReference, self.driver.manage_existing, test_volume, external_ref) self.assertIsNotNone(re.search('The specified LUN does not belong' ' to the given pool', ex.msg)) @mock.patch.object(rest_client.RestClient, 'get_lun_info', return_value={'CAPACITY': 2097152, 'ID': 'ID1', 'PARENTNAME': 'StoragePool001'}) @mock.patch.object(rest_client.RestClient, 'get_lun_id_by_name', return_value='ID1') def test_manage_existing_lun_abnormal(self, mock_get_by_name, mock_get_info): # Status is not normal. ret = {'PARENTNAME': "StoragePool001", 'HEALTHSTATUS': '2'} with mock.patch.object(huawei_driver.HuaweiBaseDriver, '_get_lun_info_by_ref', return_value=ret): test_volume = {'host': 'ubuntu-204@v3r3#StoragePool001', 'name': 'volume-21ec7341-9256-497b-97d9-ef48edcf'} external_ref = {'source-name': 'LUN1'} ex = self.assertRaises(exception.ManageExistingInvalidReference, self.driver.manage_existing, test_volume, external_ref) self.assertIsNotNone(re.search('LUN status is not normal', ex.msg)) @mock.patch.object(rest_client.RestClient, 'get_hypermetro_pairs', return_value=[{'LOCALOBJID': 'ID1'}]) @mock.patch.object(rest_client.RestClient, 'get_lun_info', return_value={'CAPACITY': 2097152, 'ID': 'ID1', 'PARENTNAME': 'StoragePool001', 'HEALTHSTATUS': constants.STATUS_HEALTH}) @mock.patch.object(rest_client.RestClient, 'get_lun_id_by_name', return_value='ID1') def test_manage_existing_with_hypermetro(self, mock_get_by_name, mock_get_info, mock_get_hyper_pairs): test_volume = {'host': 'ubuntu-204@v3r3#StoragePool001', 'name': 'volume-21ec7341-9256-497b-97d9-ef48edcf'} # Exists in a HyperMetroPair. with mock.patch.object(rest_client.RestClient, 'get_hypermetro_pairs', return_value=[{'LOCALOBJID': 'ID1'}]): external_ref = {'source-name': 'LUN1'} ex = self.assertRaises(exception.ManageExistingInvalidReference, self.driver.manage_existing, test_volume, external_ref) self.assertIsNotNone(re.search('HyperMetroPair', ex.msg)) @ddt.data([[{'PRILUNID': 'ID1'}], []], [[{'PRILUNID': 'ID2'}], ['ID1', 'ID2']]) @mock.patch.object(rest_client.RestClient, 'get_lun_info', return_value={'CAPACITY': 2097152, 'ID': 'ID1', 'PARENTNAME': 'StoragePool001', 'HEALTHSTATUS': constants.STATUS_HEALTH}) @mock.patch.object(rest_client.RestClient, 'get_lun_id_by_name', return_value='ID1') def test_manage_existing_with_splitmirror(self, ddt_data, mock_get_by_name, mock_get_info): test_volume = {'host': 'ubuntu-204@v3r3#StoragePool001', 'name': 'volume-21ec7341-9256-497b-97d9-ef48edcf', 'id': '21ec7341-9256-497b-97d9-ef48edcf'} # Exists in a SplitMirror. with mock.patch.object(rest_client.RestClient, 'get_split_mirrors', return_value=ddt_data[0]), \ mock.patch.object(rest_client.RestClient, 'get_target_luns', return_value=ddt_data[1]): external_ref = {'source-name': 'LUN1'} ex = self.assertRaises(exception.ManageExistingInvalidReference, self.driver.manage_existing, test_volume, external_ref) self.assertIsNotNone(re.search('SplitMirror', ex.msg)) @ddt.data([{'PARENTID': 'ID1'}], [{'TARGETLUNID': 'ID1'}]) @mock.patch.object(rest_client.RestClient, 'get_lun_info', return_value={'CAPACITY': 2097152, 'ID': 'ID1', 'PARENTNAME': 'StoragePool001', 'HEALTHSTATUS': constants.STATUS_HEALTH}) @mock.patch.object(rest_client.RestClient, 'get_lun_id_by_name', return_value='ID1') def test_manage_existing_under_migration(self, ddt_data, mock_get_by_name, mock_get_info): test_volume = {'host': 'ubuntu-204@v3r3#StoragePool001', 'name': 'volume-21ec7341-9256-497b-97d9-ef48edcf', 'id': '21ec7341-9256-497b-97d9-ef48edcf'} # Exists in a migration task. with mock.patch.object(rest_client.RestClient, 'get_migration_task', return_value=ddt_data): external_ref = {'source-name': 'LUN1'} ex = self.assertRaises(exception.ManageExistingInvalidReference, self.driver.manage_existing, test_volume, external_ref) self.assertIsNotNone(re.search('migration', ex.msg)) @mock.patch.object(rest_client.RestClient, 'get_lun_info', return_value={'CAPACITY': 2097152, 'ID': 'ID1', 'PARENTNAME': 'StoragePool001', 'SNAPSHOTIDS': [], 'ISADD2LUNGROUP': 'true', 'HEALTHSTATUS': constants.STATUS_HEALTH}) @mock.patch.object(rest_client.RestClient, 'get_lun_id_by_name', return_value='ID1') def test_manage_existing_with_lungroup(self, mock_get_by_name, mock_get_info): # Already in LUN group. test_volume = {'host': 'ubuntu-204@v3r3#StoragePool001', 'name': 'volume-21ec7341-9256-497b-97d9-ef48edcf'} external_ref = {'source-name': 'LUN1'} ex = self.assertRaises(exception.ManageExistingInvalidReference, self.driver.manage_existing, test_volume, external_ref) self.assertIsNotNone(re.search('Already exists in a LUN group', ex.msg)) @ddt.data({'source-name': 'LUN1'}, {'source-id': 'ID1'}) @mock.patch.object(rest_client.RestClient, 'rename_lun') @mock.patch.object(huawei_driver.HuaweiBaseDriver, '_get_lun_info_by_ref', return_value={'PARENTNAME': 'StoragePool001', 'SNAPSHOTIDS': [], 'ID': 'ID1', 'HEALTHSTATUS': constants.STATUS_HEALTH}) @mock.patch.object(rest_client.RestClient, 'get_lun_info', return_value={'CAPACITY': 2097152, 'ALLOCTYPE': 1}) @mock.patch.object(rest_client.RestClient, 'get_lun_id_by_name', return_value='ID1') def test_manage_existing_success(self, mock_get_by_name, mock_get_info, mock_check_lun, mock_rename, external_ref): test_volume = {'host': 'ubuntu-204@v3r3#StoragePool001', 'id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'name': 'volume-21ec7341-9256-497b-97d9-ef48edcf'} model_update = self.driver.manage_existing(test_volume, external_ref) self.assertEqual({'provider_location': 'ID1'}, model_update) @ddt.data([None, 0], ['ID1', 1]) @mock.patch.object(rest_client.RestClient, 'rename_lun') def test_unmanage(self, ddt_data, mock_rename): test_volume = {'host': 'ubuntu-204@v3r3#StoragePool001', 'id': '21ec7341-9256-497b-97d9-ef48edcf0635'} with mock.patch.object(rest_client.RestClient, 'get_lun_id_by_name', return_value=ddt_data[0]): self.driver.unmanage(test_volume) self.assertEqual(ddt_data[1], mock_rename.call_count) @mock.patch.object(rest_client.RestClient, 'get_snapshot_info', return_value={'ID': 'ID1', 'NAME': 'test1', 'PARENTID': '12', 'USERCAPACITY': 2097152, 'HEALTHSTATUS': '2'}) @mock.patch.object(rest_client.RestClient, 'get_snapshot_id_by_name', return_value='ID1') def test_manage_existing_snapshot_abnormal(self, mock_get_by_name, mock_get_info): with mock.patch.object(huawei_driver.HuaweiBaseDriver, '_get_snapshot_info_by_ref', return_value={'HEALTHSTATUS': '2', 'PARENTID': '12'}): test_snapshot = {'volume_id': '21ec7341-9256-497b-97d9-ef48edcf', 'id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'volume': {'provider_location': '12'}} external_ref = {'source-name': 'test1'} ex = self.assertRaises(exception.ManageExistingInvalidReference, self.driver.manage_existing_snapshot, test_snapshot, external_ref) self.assertIsNotNone(re.search('Snapshot status is not normal', ex.msg)) @mock.patch.object(rest_client.RestClient, 'get_snapshot_info', return_value={'ID': 'ID1', 'EXPOSEDTOINITIATOR': 'true', 'NAME': 'test1', 'PARENTID': '12', 'USERCAPACITY': 2097152, 'HEALTHSTATUS': constants.STATUS_HEALTH}) @mock.patch.object(rest_client.RestClient, 'get_snapshot_id_by_name', return_value='ID1') def test_manage_existing_snapshot_with_lungroup(self, mock_get_by_name, mock_get_info): # Already in LUN group. test_snapshot = {'volume_id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'volume': {'provider_location': '12'}} external_ref = {'source-name': 'test1'} ex = self.assertRaises(exception.ManageExistingInvalidReference, self.driver.manage_existing_snapshot, test_snapshot, external_ref) self.assertIsNotNone(re.search('Snapshot is exposed to initiator', ex.msg)) @mock.patch.object(rest_client.RestClient, 'rename_snapshot') @mock.patch.object(huawei_driver.HuaweiBaseDriver, '_get_snapshot_info_by_ref', return_value={'ID': 'ID1', 'EXPOSEDTOINITIATOR': 'false', 'NAME': 'test1', 'PARENTID': '12', 'USERCAPACITY': 2097152, 'HEALTHSTATUS': constants.STATUS_HEALTH}) @mock.patch.object(rest_client.RestClient, 'get_snapshot_info', return_value={'ID': 'ID1', 'EXPOSEDTOINITIATOR': 'false', 'NAME': 'test1', 'PARENTID': '12', 'USERCAPACITY': 2097152, 'HEALTHSTATUS': constants.STATUS_HEALTH}) @mock.patch.object(rest_client.RestClient, 'get_snapshot_id_by_name', return_value='ID1') def test_manage_existing_snapshot_success(self, mock_get_by_name, mock_get_info, mock_check_snapshot, mock_rename): test_snapshot = {'volume_id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'volume': {'provider_location': '12'}} external_ref = {'source-name': 'test1'} model_update = self.driver.manage_existing_snapshot(test_snapshot, external_ref) self.assertEqual({'provider_location': 'ID1'}, model_update) test_snapshot = {'volume_id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'volume': {'provider_location': '12'}} external_ref = {'source-id': 'ID1'} model_update = self.driver.manage_existing_snapshot(test_snapshot, external_ref) self.assertEqual({'provider_location': 'ID1'}, model_update) @mock.patch.object(rest_client.RestClient, 'get_snapshot_info', return_value={'ID': 'ID1', 'EXPOSEDTOINITIATOR': 'false', 'NAME': 'test1', 'USERCAPACITY': 2097152, 'PARENTID': '11', 'HEALTHSTATUS': constants.STATUS_HEALTH}) @mock.patch.object(rest_client.RestClient, 'get_snapshot_id_by_name', return_value='ID1') def test_manage_existing_snapshot_mismatch_lun(self, mock_get_by_name, mock_get_info): external_ref = {'source-name': 'test1'} test_snapshot = {'volume_id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'volume': {'provider_location': '12'}} ex = self.assertRaises(exception.ManageExistingInvalidReference, self.driver.manage_existing_snapshot, test_snapshot, external_ref) self.assertIsNotNone(re.search("Snapshot doesn't belong to volume", ex.msg)) @mock.patch.object(rest_client.RestClient, 'get_snapshot_info', return_value={'USERCAPACITY': 2097152}) @mock.patch.object(rest_client.RestClient, 'get_snapshot_id_by_name', return_value='ID1') def test_manage_existing_snapshot_get_size_success(self, mock_get_id_by_name, mock_get_info): external_ref = {'source-name': 'test1', 'source-id': 'ID1'} test_snapshot = {'volume_id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'volume': {'provider_location': '12'}} size = self.driver.manage_existing_snapshot_get_size(test_snapshot, external_ref) self.assertEqual(1, size) external_ref = {'source-name': 'test1'} test_snapshot = {'volume_id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'volume': {'provider_location': '12'}} size = self.driver.manage_existing_snapshot_get_size(test_snapshot, external_ref) self.assertEqual(1, size) external_ref = {'source-id': 'ID1'} test_snapshot = {'volume_id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'volume': {'provider_location': '12'}} size = self.driver.manage_existing_snapshot_get_size(test_snapshot, external_ref) self.assertEqual(1, size) @mock.patch.object(rest_client.RestClient, 'rename_snapshot') def test_unmanage_snapshot(self, mock_rename): test_snapshot = {'volume_id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'id': '21ec7341-9256-497b-97d9-ef48edcf0635'} with mock.patch.object(rest_client.RestClient, 'get_snapshot_id_by_name', return_value=None): self.driver.unmanage_snapshot(test_snapshot) self.assertEqual(0, mock_rename.call_count) with mock.patch.object(rest_client.RestClient, 'get_snapshot_id_by_name', return_value='ID1'): self.driver.unmanage_snapshot(test_snapshot) self.assertEqual(1, mock_rename.call_count) def test_init_rmt_client(self): self.mock_object(rest_client, 'RestClient', mock.Mock(return_value=None)) replica = replication.ReplicaPairManager(self.driver.client, self.configuration) self.assertEqual(replica.rmt_pool, 'OpenStack_Pool') self.assertEqual(replica.target_dev_id, 'huawei-replica-1') @ddt.data(sync_replica_specs, async_replica_specs) def test_create_replication_success(self, mock_type): self.mock_object(replication.ReplicaCommonDriver, 'sync') self.mock_object( huawei_driver.HuaweiBaseDriver, '_get_volume_type', mock.Mock(return_value={'extra_specs': mock_type})) model_update = self.driver.create_volume(replication_volume) driver_data = {'pair_id': TEST_PAIR_ID, 'rmt_lun_id': '1'} driver_data = replication.to_string(driver_data) self.assertEqual(driver_data, model_update['replication_driver_data']) self.assertEqual('enabled', model_update['replication_status']) @ddt.data( [ rest_client.RestClient, 'get_array_info', mock.Mock( side_effect=exception.VolumeBackendAPIException(data='err')) ], [ rest_client.RestClient, 'get_remote_devices', mock.Mock( side_effect=exception.VolumeBackendAPIException(data='err')) ], [ rest_client.RestClient, 'get_remote_devices', mock.Mock(return_value={}) ], [ replication.ReplicaPairManager, 'wait_volume_online', mock.Mock(side_effect=[ None, exception.VolumeBackendAPIException(data='err')]) ], [ rest_client.RestClient, 'create_pair', mock.Mock( side_effect=exception.VolumeBackendAPIException(data='err')) ], [ replication.ReplicaCommonDriver, 'sync', mock.Mock( side_effect=exception.VolumeBackendAPIException(data='err')) ], ) @ddt.unpack def test_create_replication_fail(self, mock_module, mock_func, mock_value): self.mock_object( huawei_driver.HuaweiBaseDriver, '_get_volume_type', mock.Mock(return_value={'extra_specs': sync_replica_specs})) self.mock_object(replication.ReplicaPairManager, '_delete_pair') self.mock_object(mock_module, mock_func, mock_value) self.assertRaises( exception.VolumeBackendAPIException, self.driver.create_volume, replication_volume) def test_delete_replication_success(self): self.mock_object(replication.ReplicaCommonDriver, 'split') self.mock_object( huawei_driver.HuaweiBaseDriver, '_get_volume_type', mock.Mock(return_value={'extra_specs': sync_replica_specs})) self.driver.delete_volume(replication_volume) self.mock_object(rest_client.RestClient, 'check_lun_exist', mock.Mock(return_value=False)) self.driver.delete_volume(replication_volume) def test_wait_volume_online(self): replica = FakeReplicaPairManager(self.driver.client, self.configuration) lun_info = {'ID': '11'} replica.wait_volume_online(self.driver.client, lun_info) offline_status = {'RUNNINGSTATUS': '28'} replica.wait_volume_online(self.driver.client, lun_info) with mock.patch.object(rest_client.RestClient, 'get_lun_info', offline_status): self.assertRaises(exception.VolumeBackendAPIException, replica.wait_volume_online, self.driver.client, lun_info) def test_wait_second_access(self): pair_id = '1' access_ro = constants.REPLICA_SECOND_RO access_rw = constants.REPLICA_SECOND_RW op = replication.PairOp(self.driver.client) common_driver = replication.ReplicaCommonDriver(self.configuration, op) self.mock_object(replication.PairOp, 'get_replica_info', mock.Mock(return_value={'SECRESACCESS': access_ro})) common_driver.wait_second_access(pair_id, access_ro) self.assertRaises(exception.VolumeBackendAPIException, common_driver.wait_second_access, pair_id, access_rw) def test_wait_replica_ready(self): normal_status = { 'RUNNINGSTATUS': constants.REPLICA_RUNNING_STATUS_NORMAL, 'HEALTHSTATUS': constants.REPLICA_HEALTH_STATUS_NORMAL } split_status = { 'RUNNINGSTATUS': constants.REPLICA_RUNNING_STATUS_SPLIT, 'HEALTHSTATUS': constants.REPLICA_HEALTH_STATUS_NORMAL } sync_status = { 'RUNNINGSTATUS': constants.REPLICA_RUNNING_STATUS_SYNC, 'HEALTHSTATUS': constants.REPLICA_HEALTH_STATUS_NORMAL } pair_id = '1' op = replication.PairOp(self.driver.client) common_driver = replication.ReplicaCommonDriver(self.configuration, op) with mock.patch.object(replication.PairOp, 'get_replica_info', mock.Mock(return_value=normal_status)): common_driver.wait_replica_ready(pair_id) with mock.patch.object( replication.PairOp, 'get_replica_info', mock.Mock(side_effect=[sync_status, normal_status])): common_driver.wait_replica_ready(pair_id) with mock.patch.object(replication.PairOp, 'get_replica_info', mock.Mock(return_value=split_status)): self.assertRaises(exception.VolumeBackendAPIException, common_driver.wait_replica_ready, pair_id) def test_replication_enable_success(self): self.mock_object(replication.ReplicaCommonDriver, 'unprotect_second') self.mock_object(replication.ReplicaCommonDriver, 'split') self.mock_object(replication.PairOp, 'is_primary', mock.Mock(side_effect=[False, True])) self.driver.replication_enable(None, replication_volume) @ddt.data( [ replication.AbsReplicaOp, 'is_running_status', mock.Mock(return_value=False) ], [ replication, 'get_replication_driver_data', mock.Mock(return_value={}) ], [ replication.PairOp, 'get_replica_info', mock.Mock(return_value={}) ], ) @ddt.unpack def test_replication_enable_fail(self, mock_module, mock_func, mock_value): self.mock_object(mock_module, mock_func, mock_value) self.assertRaises( exception.VolumeBackendAPIException, self.driver.replication_enable, None, replication_volume) def test_replication_disable_fail(self): self.assertRaises( exception.VolumeBackendAPIException, self.driver.replication_disable, None, replication_volume) def test_replication_disable_success(self): self.mock_object(replication.ReplicaCommonDriver, 'split') self.driver.replication_disable(None, replication_volume) self.mock_object(replication, 'get_replication_driver_data', mock.Mock(return_value={})) self.driver.replication_disable(None, replication_volume) def test_replication_failover_success(self): self.mock_object(replication.ReplicaCommonDriver, 'split') self.mock_object(replication.PairOp, 'is_primary', mock.Mock(return_value=False)) model_update = self.driver.replication_failover( None, replication_volume, None) self.assertEqual('ubuntu@huawei2#OpenStack_Pool', model_update['host']) self.assertEqual('1', model_update['provider_location']) driver_data = {'pair_id': TEST_PAIR_ID, 'rmt_lun_id': '11'} driver_data = replication.to_string(driver_data) self.assertEqual(driver_data, model_update['replication_driver_data']) @ddt.data( [ replication.PairOp, 'is_primary', mock.Mock(return_value=True) ], [ replication.PairOp, 'is_primary', mock.Mock(return_value=False) ], [ replication, 'get_replication_driver_data', mock.Mock(return_value={}) ], [ replication, 'get_replication_driver_data', mock.Mock(return_value={'pair_id': '1'}) ], ) @ddt.unpack def test_replication_failover_fail(self, mock_module, mock_func, mock_value): self.mock_object( replication.ReplicaCommonDriver, 'wait_second_access', mock.Mock( side_effect=exception.VolumeBackendAPIException(data="error"))) self.mock_object(mock_module, mock_func, mock_value) self.assertRaises( exception.VolumeBackendAPIException, self.driver.replication_failover, None, replication_volume, None) def test_list_replication_targets(self): info = self.driver.list_replication_targets(None, replication_volume) targets = [{'target_device_id': 'huawei-replica-1'}] self.assertEqual(targets, info['targets']) self.mock_object(replication, 'get_replication_driver_data', mock.Mock(return_value={})) info = self.driver.list_replication_targets(None, replication_volume) self.assertEqual(targets, info['targets']) @ddt.data(constants.REPLICA_SECOND_RW, constants.REPLICA_SECOND_RO) def test_replication_protect_second(self, mock_access): replica_id = TEST_PAIR_ID op = replication.PairOp(self.driver.client) common_driver = replication.ReplicaCommonDriver(self.configuration, op) self.mock_object(replication.ReplicaCommonDriver, 'wait_second_access') self.mock_object( replication.PairOp, 'get_replica_info', mock.Mock(return_value={'SECRESACCESS': mock_access})) common_driver.protect_second(replica_id) common_driver.unprotect_second(replica_id) def test_replication_sync(self): replica_id = TEST_PAIR_ID op = replication.PairOp(self.driver.client) common_driver = replication.ReplicaCommonDriver(self.configuration, op) async_normal_status = { 'REPLICATIONMODEL': constants.REPLICA_ASYNC_MODEL, 'RUNNINGSTATUS': constants.REPLICA_RUNNING_STATUS_NORMAL, 'HEALTHSTATUS': constants.REPLICA_HEALTH_STATUS_NORMAL } self.mock_object(replication.ReplicaCommonDriver, 'protect_second') self.mock_object(replication.PairOp, 'get_replica_info', mock.Mock(return_value=async_normal_status)) common_driver.sync(replica_id, True) common_driver.sync(replica_id, False) def test_replication_split(self): replica_id = TEST_PAIR_ID op = replication.PairOp(self.driver.client) common_driver = replication.ReplicaCommonDriver(self.configuration, op) self.mock_object(replication.ReplicaCommonDriver, 'wait_expect_state') self.mock_object(replication.PairOp, 'split', mock.Mock( side_effect=exception.VolumeBackendAPIException(data='err'))) common_driver.split(replica_id) def test_replication_base_op(self): replica_id = '1' op = replication.AbsReplicaOp(None) op.create() op.delete(replica_id) op.protect_second(replica_id) op.unprotect_second(replica_id) op.sync(replica_id) op.split(replica_id) op.switch(replica_id) op.is_primary({}) op.get_replica_info(replica_id) op._is_status(None, {'key': 'volue'}, None) @mock.patch.object(rest_client.RestClient, 'call', return_value={"error": {"code": 0}}) def test_get_tgt_port_group_no_portg_exist(self, mock_call): portg = self.driver.client.get_tgt_port_group('test_portg') self.assertIsNone(portg) class FCSanLookupService(object): def get_device_mapping_from_network(self, initiator_list, target_list): return fake_fabric_mapping class HuaweiFCDriverTestCase(test.TestCase): def setUp(self): super(HuaweiFCDriverTestCase, self).setUp() self.configuration = mock.Mock(spec=conf.Configuration) self.huawei_conf = FakeHuaweiConf(self.configuration, 'FC') self.configuration.hypermetro_devices = hypermetro_devices self.stubs.Set(time, 'sleep', Fake_sleep) driver = FakeFCStorage(configuration=self.configuration) self.driver = driver self.driver.do_setup() self.driver.client.login() def test_login_success(self): device_id = self.driver.client.login() self.assertEqual('210235G7J20000000000', device_id) def test_create_volume_success(self): lun_info = self.driver.create_volume(test_volume) self.assertEqual('1', lun_info['provider_location']) def test_delete_volume_success(self): self.driver.delete_volume(test_volume) def test_create_snapshot_success(self): lun_info = self.driver.create_snapshot(test_snap) self.assertEqual(11, lun_info['provider_location']) test_snap['volume']['provider_location'] = '' lun_info = self.driver.create_snapshot(test_snap) self.assertEqual(11, lun_info['provider_location']) test_snap['volume']['provider_location'] = None lun_info = self.driver.create_snapshot(test_snap) self.assertEqual(11, lun_info['provider_location']) def test_delete_snapshot_success(self): delete_flag = self.driver.delete_snapshot(test_snap) self.assertTrue(delete_flag) def test_create_volume_from_snapsuccess(self): lun_info = self.driver.create_volume_from_snapshot(test_volume, test_volume) self.assertEqual('1', lun_info['provider_location']) def test_initialize_connection_success(self): iscsi_properties = self.driver.initialize_connection(test_volume, FakeConnector) self.assertEqual(1, iscsi_properties['data']['target_lun']) def test_terminate_connection_success(self): self.driver.client.terminateFlag = True self.driver.terminate_connection(test_volume, FakeConnector) self.assertTrue(self.driver.client.terminateFlag) def test_get_volume_status(self): remote_device_info = {"ARRAYTYPE": "1", "HEALTHSTATUS": "1", "RUNNINGSTATUS": "10"} self.mock_object( replication.ReplicaPairManager, 'get_remote_device_by_wwn', mock.Mock(return_value=remote_device_info)) data = self.driver.get_volume_stats() self.assertEqual('2.0.5', data['driver_version']) self.assertTrue(data['pools'][0]['replication_enabled']) self.assertListEqual(['sync', 'async'], data['pools'][0]['replication_type']) self.mock_object( replication.ReplicaPairManager, 'get_remote_device_by_wwn', mock.Mock(return_value={})) data = self.driver.get_volume_stats() self.assertNotIn('replication_enabled', data['pools'][0]) self.mock_object( replication.ReplicaPairManager, 'try_get_remote_wwn', mock.Mock(return_value={})) data = self.driver.get_volume_stats() self.assertEqual('2.0.5', data['driver_version']) self.assertNotIn('replication_enabled', data['pools'][0]) def test_extend_volume(self): self.driver.extend_volume(test_volume, 3) def test_login_fail(self): self.driver.client.test_fail = True self.assertRaises(exception.VolumeBackendAPIException, self.driver.client.login) def test_create_snapshot_fail(self): self.driver.client.test_fail = True self.assertRaises(exception.VolumeBackendAPIException, self.driver.create_snapshot, test_snap) def test_create_volume_fail(self): self.driver.client.test_fail = True self.assertRaises(exception.VolumeBackendAPIException, self.driver.create_volume, test_volume) def test_delete_volume_fail(self): self.driver.client.test_fail = True self.driver.delete_volume(test_volume) def test_delete_snapshot_fail(self): self.driver.client.test_fail = True self.driver.delete_snapshot(test_snap) def test_initialize_connection_fail(self): self.driver.client.test_fail = True self.assertRaises(exception.VolumeBackendAPIException, self.driver.initialize_connection, test_volume, FakeConnector) def test_lun_is_associated_to_lungroup(self): self.driver.client.associate_lun_to_lungroup('11', '11') result = self.driver.client._is_lun_associated_to_lungroup('11', '11') self.assertTrue(result) def test_lun_is_not_associated_to_lun_group(self): self.driver.client.associate_lun_to_lungroup('12', '12') self.driver.client.remove_lun_from_lungroup('12', '12') result = self.driver.client._is_lun_associated_to_lungroup('12', '12') self.assertFalse(result) @mock.patch.object(rest_client.RestClient, 'add_lun_to_partition') def test_migrate_volume_success(self, mock_add_lun_to_partition): # Migrate volume without new type. model_update = None moved = False empty_dict = {} # Migrate volume without new type. moved, model_update = self.driver.migrate_volume(None, test_volume, test_host, None) self.assertTrue(moved) self.assertEqual(empty_dict, model_update) # Migrate volume with new type. moved = False empty_dict = {} new_type = {'extra_specs': {'smarttier': ' true', 'smartcache': ' true', 'smartpartition': ' true', 'thin_provisioning_support': ' true', 'thick_provisioning_support': ' False', 'policy': '2', 'smartcache:cachename': 'cache-test', 'smartpartition:partitionname': 'partition-test'}} moved, model_update = self.driver.migrate_volume(None, test_volume, test_host, new_type) self.assertTrue(moved) self.assertEqual(empty_dict, model_update) def test_migrate_volume_fail(self): self.driver.client.test_fail = True # Migrate volume without new type. self.assertRaises(exception.VolumeBackendAPIException, self.driver.migrate_volume, None, test_volume, test_host, None) # Migrate volume with new type. new_type = {'extra_specs': {'smarttier': ' true', 'smartcache': ' true', 'thin_provisioning_support': ' true', 'thick_provisioning_support': ' False', 'policy': '2', 'smartcache:cachename': 'cache-test', 'partitionname': 'partition-test'}} self.driver.client.test_fail = True self.assertRaises(exception.VolumeBackendAPIException, self.driver.migrate_volume, None, test_volume, test_host, new_type) def test_check_migration_valid(self): is_valid = self.driver._check_migration_valid(test_host, test_volume) self.assertTrue(is_valid) # No pool_name in capabilities. invalid_host1 = {'host': 'ubuntu001@backend002#OpenStack_Pool', 'capabilities': {'location_info': '210235G7J20000000000', 'allocated_capacity_gb': 0, 'volume_backend_name': 'HuaweiFCDriver', 'storage_protocol': 'FC'}} is_valid = self.driver._check_migration_valid(invalid_host1, test_volume) self.assertFalse(is_valid) # location_info in capabilities is not matched. invalid_host2 = {'host': 'ubuntu001@backend002#OpenStack_Pool', 'capabilities': {'location_info': '210235G7J20000000001', 'allocated_capacity_gb': 0, 'pool_name': 'OpenStack_Pool', 'volume_backend_name': 'HuaweiFCDriver', 'storage_protocol': 'FC'}} is_valid = self.driver._check_migration_valid(invalid_host2, test_volume) self.assertFalse(is_valid) # storage_protocol is not match current protocol and volume status is # 'in-use'. volume_in_use = {'name': 'volume-21ec7341-9256-497b-97d9-ef48edcf0635', 'size': 2, 'volume_name': 'vol1', 'id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'volume_id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'volume_attachment': 'in-use', 'provider_location': '11'} invalid_host2 = {'host': 'ubuntu001@backend002#OpenStack_Pool', 'capabilities': {'location_info': '210235G7J20000000001', 'allocated_capacity_gb': 0, 'pool_name': 'OpenStack_Pool', 'volume_backend_name': 'HuaweiFCDriver', 'storage_protocol': 'iSCSI'}} is_valid = self.driver._check_migration_valid(invalid_host2, volume_in_use) self.assertFalse(is_valid) # pool_name is empty. invalid_host3 = {'host': 'ubuntu001@backend002#OpenStack_Pool', 'capabilities': {'location_info': '210235G7J20000000001', 'allocated_capacity_gb': 0, 'pool_name': '', 'volume_backend_name': 'HuaweiFCDriver', 'storage_protocol': 'iSCSI'}} is_valid = self.driver._check_migration_valid(invalid_host3, test_volume) self.assertFalse(is_valid) @mock.patch.object(rest_client.RestClient, 'rename_lun') def test_update_migrated_volume_success(self, mock_rename_lun): original_volume = {'id': '21ec7341-9256-497b-97d9-ef48edcf0635'} current_volume = {'id': '21ec7341-9256-497b-97d9-ef48edcf0636'} model_update = self.driver.update_migrated_volume(None, original_volume, current_volume, 'available') self.assertEqual({'_name_id': None}, model_update) @mock.patch.object(rest_client.RestClient, 'rename_lun') def test_update_migrated_volume_fail(self, mock_rename_lun): mock_rename_lun.side_effect = exception.VolumeBackendAPIException( data='Error occurred.') original_volume = {'id': '21ec7341-9256-497b-97d9-ef48edcf0635'} current_volume = {'id': '21ec7341-9256-497b-97d9-ef48edcf0636', '_name_id': '21ec7341-9256-497b-97d9-ef48edcf0637'} model_update = self.driver.update_migrated_volume(None, original_volume, current_volume, 'available') self.assertEqual({'_name_id': '21ec7341-9256-497b-97d9-ef48edcf0637'}, model_update) @mock.patch.object(rest_client.RestClient, 'add_lun_to_partition') def test_retype_volume_success(self, mock_add_lun_to_partition): retype = self.driver.retype(None, test_volume, test_new_type, None, test_host) self.assertTrue(retype) @mock.patch.object(rest_client.RestClient, 'add_lun_to_partition') @mock.patch.object( huawei_driver.HuaweiBaseDriver, '_get_volume_type', return_value={'extra_specs': sync_replica_specs}) def test_retype_replication_volume_success(self, mock_get_type, mock_add_lun_to_partition): retype = self.driver.retype(None, test_volume, test_new_replication_type, None, test_host) self.assertTrue(retype) def test_retype_volume_cache_fail(self): self.driver.client.cache_not_exist = True self.assertRaises(exception.VolumeBackendAPIException, self.driver.retype, None, test_volume, test_new_type, None, test_host) def test_retype_volume_partition_fail(self): self.driver.client.partition_not_exist = True self.assertRaises(exception.VolumeBackendAPIException, self.driver.retype, None, test_volume, test_new_type, None, test_host) @mock.patch.object(rest_client.RestClient, 'add_lun_to_partition') def test_retype_volume_fail(self, mock_add_lun_to_partition): mock_add_lun_to_partition.side_effect = ( exception.VolumeBackendAPIException(data='Error occurred.')) retype = self.driver.retype(None, test_volume, test_new_type, None, test_host) self.assertFalse(retype) @mock.patch.object(rest_client.RestClient, 'get_all_engines', return_value=[{'NODELIST': '["0A","0B"]', 'ID': '0'}]) def test_build_ini_targ_map_engie_recorded(self, mock_engines): fake_lookup_service = FCSanLookupService() zone_helper = fc_zone_helper.FCZoneHelper( fake_lookup_service, self.driver.client) (tgt_wwns, portg_id, init_targ_map) = zone_helper.build_ini_targ_map( ['10000090fa0d6754'], '1', '11') target_port_wwns = ['2000643e8c4c5f66'] self.assertEqual(target_port_wwns, tgt_wwns) self.assertEqual({}, init_targ_map) @mock.patch.object(rest_client.RestClient, 'get_all_engines', return_value=[{'NODELIST': '["0A"]', 'ID': '0'}, {'NODELIST': '["0B"]', 'ID': '1'}]) def test_build_ini_targ_map_engie_not_recorded(self, mock_engines): fake_lookup_service = FCSanLookupService() zone_helper = fc_zone_helper.FCZoneHelper( fake_lookup_service, self.driver.client) (tgt_wwns, portg_id, init_targ_map) = zone_helper.build_ini_targ_map( ['10000090fa0d6754'], '1', '11') expected_wwns = ['2000643e8c4c5f66'] expected_map = {'10000090fa0d6754': ['2000643e8c4c5f66']} self.assertEqual(expected_wwns, tgt_wwns) self.assertEqual(expected_map, init_targ_map) @mock.patch.object(rest_client.RestClient, 'get_all_engines', return_value=[{'NODELIST': '["0A", "0B"]', 'ID': '0'}]) def test_build_ini_targ_map_no_map(self, mock_engines): fake_lookup_service = FCSanLookupService() zone_helper = fc_zone_helper.FCZoneHelper( fake_lookup_service, self.driver.client) # Host with id '5' has no map on the array. (tgt_wwns, portg_id, init_targ_map) = zone_helper.build_ini_targ_map( ['10000090fa0d6754'], '5', '11') expected_wwns = ['2000643e8c4c5f66'] expected_map = {'10000090fa0d6754': ['2000643e8c4c5f66']} self.assertEqual(expected_wwns, tgt_wwns) self.assertEqual(expected_map, init_targ_map) def test_get_init_targ_map(self): fake_lookup_service = FCSanLookupService() zone_helper = fc_zone_helper.FCZoneHelper( fake_lookup_service, self.driver.client) (tgt_wwns, portg_id, init_targ_map) = zone_helper.get_init_targ_map( ['10000090fa0d6754'], '1') expected_wwns = ['2000643e8c4c5f66'] expected_map = {'10000090fa0d6754': ['2000643e8c4c5f66']} self.assertEqual(expected_wwns, tgt_wwns) self.assertEqual(expected_map, init_targ_map) def test_multi_resturls_success(self): self.driver.client.test_multi_url_flag = True lun_info = self.driver.create_volume(test_volume) self.assertEqual('1', lun_info['provider_location']) def test_get_id_from_result(self): result = {} name = 'test_name' key = 'NAME' re = self.driver.client._get_id_from_result(result, name, key) self.assertIsNone(re) result = {'data': {}} re = self.driver.client._get_id_from_result(result, name, key) self.assertIsNone(re) result = {'data': [{'COUNT': 1, 'ID': '1'}, {'COUNT': 2, 'ID': '2'}]} re = self.driver.client._get_id_from_result(result, name, key) self.assertIsNone(re) result = {'data': [{'NAME': 'test_name1', 'ID': '1'}, {'NAME': 'test_name2', 'ID': '2'}]} re = self.driver.client._get_id_from_result(result, name, key) self.assertIsNone(re) result = {'data': [{'NAME': 'test_name', 'ID': '1'}, {'NAME': 'test_name2', 'ID': '2'}]} re = self.driver.client._get_id_from_result(result, name, key) self.assertEqual('1', re) @mock.patch.object(rest_client.RestClient, 'get_pool_info', return_value={'ID': 1, 'CAPACITY': 110362624, 'TOTALCAPACITY': 209715200}) def test_get_capacity(self, mock_get_pool_info): expected_pool_capacity = {'total_capacity': 100.0, 'free_capacity': 52.625} pool_capacity = self.driver.client._get_capacity(None, None) self.assertEqual(expected_pool_capacity, pool_capacity) @mock.patch.object(huawei_driver.HuaweiBaseDriver, '_get_volume_params', return_value=fake_hypermetro_opts) @mock.patch.object(rest_client.RestClient, 'get_all_pools', return_value=FAKE_STORAGE_POOL_RESPONSE) @mock.patch.object(rest_client.RestClient, 'get_pool_info', return_value=FAKE_FIND_POOL_RESPONSE) @mock.patch.object(rest_client.RestClient, 'get_hyper_domain_id', return_value='11') @mock.patch.object(hypermetro.HuaweiHyperMetro, '_wait_volume_ready', return_value=True) @mock.patch.object(hypermetro.HuaweiHyperMetro, '_create_hypermetro_pair', return_value={"ID": '11', "NAME": 'hypermetro-pair'}) @mock.patch.object(rest_client.RestClient, 'logout', return_value=None) def test_create_hypermetro_success(self, mock_hypermetro_opts, mock_login_return, mock_all_pool_info, mock_pool_info, mock_hyper_domain, mock_volume_ready, mock_logout): metadata = {"hypermetro_id": '11', "remote_lun_id": '1'} lun_info = self.driver.create_volume(hyper_volume) self.assertEqual(metadata, lun_info['metadata']) @mock.patch.object(rest_client.RestClient, 'call', return_value={"data": [{"RUNNINGSTATUS": "27", "ID": '1'}, {"RUNNINGSTATUS": "26", "ID": '2'}], "error": {"code": 0}}) def test_get_online_free_wwns(self, mock_call): wwns = self.driver.client.get_online_free_wwns() self.assertEqual(['1'], wwns) class HuaweiConfTestCase(test.TestCase): def setUp(self): super(HuaweiConfTestCase, self).setUp() self.tmp_dir = tempfile.mkdtemp() self.fake_xml_file = self.tmp_dir + '/cinder_huawei_conf.xml' self.conf = mock.Mock() self.conf.cinder_huawei_conf_file = self.fake_xml_file self.huawei_conf = huawei_conf.HuaweiConf(self.conf) def _create_fake_conf_file(self): """Create a fake Config file. Huawei storage customize a XML configuration file, the configuration file is used to set the Huawei storage custom parameters, therefore, in the UT test we need to simulate such a configuration file. """ doc = minidom.Document() config = doc.createElement('config') doc.appendChild(config) storage = doc.createElement('Storage') config.appendChild(storage) url = doc.createElement('RestURL') url_text = doc.createTextNode('http://100.115.10.69:8082/' 'deviceManager/rest/') url.appendChild(url_text) storage.appendChild(url) username = doc.createElement('UserName') username_text = doc.createTextNode('admin') username.appendChild(username_text) storage.appendChild(username) password = doc.createElement('UserPassword') password_text = doc.createTextNode('Admin@storage') password.appendChild(password_text) storage.appendChild(password) product = doc.createElement('Product') product_text = doc.createTextNode('V3') product.appendChild(product_text) storage.appendChild(product) protocol = doc.createElement('Protocol') protocol_text = doc.createTextNode('iSCSI') protocol.appendChild(protocol_text) storage.appendChild(protocol) lun = doc.createElement('LUN') config.appendChild(lun) luntype = doc.createElement('LUNType') luntype_text = doc.createTextNode('Thick') luntype.appendChild(luntype_text) lun.appendChild(luntype) lun_ready_wait_interval = doc.createElement('LUNReadyWaitInterval') lun_ready_wait_interval_text = doc.createTextNode('2') lun_ready_wait_interval.appendChild(lun_ready_wait_interval_text) lun.appendChild(lun_ready_wait_interval) lun_copy_wait_interval = doc.createElement('LUNcopyWaitInterval') lun_copy_wait_interval_text = doc.createTextNode('2') lun_copy_wait_interval.appendChild(lun_copy_wait_interval_text) lun.appendChild(lun_copy_wait_interval) timeout = doc.createElement('Timeout') timeout_text = doc.createTextNode('43200') timeout.appendChild(timeout_text) lun.appendChild(timeout) write_type = doc.createElement('WriteType') write_type_text = doc.createTextNode('1') write_type.appendChild(write_type_text) lun.appendChild(write_type) mirror_switch = doc.createElement('MirrorSwitch') mirror_switch_text = doc.createTextNode('1') mirror_switch.appendChild(mirror_switch_text) lun.appendChild(mirror_switch) prefetch = doc.createElement('Prefetch') prefetch.setAttribute('Type', '1') prefetch.setAttribute('Value', '0') lun.appendChild(prefetch) pool = doc.createElement('StoragePool') pool_text = doc.createTextNode('OpenStack_Pool') pool.appendChild(pool_text) lun.appendChild(pool) iscsi = doc.createElement('iSCSI') config.appendChild(iscsi) defaulttargetip = doc.createElement('DefaultTargetIP') defaulttargetip_text = doc.createTextNode('100.115.10.68') defaulttargetip.appendChild(defaulttargetip_text) iscsi.appendChild(defaulttargetip) initiator = doc.createElement('Initiator') initiator.setAttribute('Name', 'iqn.1993-08.debian:01:ec2bff7ac3a3') initiator.setAttribute('TargetIP', '192.168.100.2') initiator.setAttribute('CHAPinfo', 'mm-user;mm-user@storage') initiator.setAttribute('ALUA', '1') initiator.setAttribute('TargetPortGroup', 'PortGroup001') iscsi.appendChild(initiator) fakefile = open(self.conf.cinder_huawei_conf_file, 'w') fakefile.write(doc.toprettyxml(indent='')) fakefile.close()