# Copyright (c) 2012 NetApp, Inc. # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """ Tests for NetApp volume driver """ import BaseHTTPServer import httplib from lxml import etree import mock import six from cinder import exception from cinder.openstack.common import log as logging from cinder import test from cinder.volume import configuration as conf from cinder.volume.drivers.netapp import common from cinder.volume.drivers.netapp.dataontap.client import client_base from cinder.volume.drivers.netapp.dataontap import ssc_cmode from cinder.volume.drivers.netapp import options from cinder.volume.drivers.netapp import utils LOG = logging.getLogger("cinder.volume.driver") def create_configuration(): configuration = conf.Configuration(None) configuration.append_config_values(options.netapp_connection_opts) configuration.append_config_values(options.netapp_transport_opts) configuration.append_config_values(options.netapp_basicauth_opts) configuration.append_config_values(options.netapp_cluster_opts) configuration.append_config_values(options.netapp_7mode_opts) configuration.append_config_values(options.netapp_provisioning_opts) return configuration class FakeHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): """HTTP handler that doesn't spam the log.""" def log_message(self, format, *args): pass class FakeHttplibSocket(object): """A fake socket implementation for httplib.HTTPResponse.""" def __init__(self, value): self._rbuffer = six.StringIO(value) self._wbuffer = six.StringIO('') oldclose = self._wbuffer.close def newclose(): self.result = self._wbuffer.getvalue() oldclose() self._wbuffer.close = newclose def makefile(self, mode, _other): """Returns the socket's internal buffer""" if mode == 'r' or mode == 'rb': return self._rbuffer if mode == 'w' or mode == 'wb': return self._wbuffer RESPONSE_PREFIX_DIRECT_CMODE = """ """ RESPONSE_PREFIX_DIRECT_7MODE = """ """ RESPONSE_PREFIX_DIRECT = """ """ RESPONSE_SUFFIX_DIRECT = """""" class FakeDirectCMODEServerHandler(FakeHTTPRequestHandler): """HTTP handler that fakes enough stuff to allow the driver to run.""" def do_GET(s): """Respond to a GET request.""" if '/servlets/netapp.servlets.admin.XMLrequest_filer' not in s.path: s.send_response(404) s.end_headers return s.send_response(200) s.send_header("Content-Type", "text/xml; charset=utf-8") s.end_headers() out = s.wfile out.write('' '') def do_POST(s): # noqa """Respond to a POST request.""" if '/servlets/netapp.servlets.admin.XMLrequest_filer' not in s.path: s.send_response(404) s.end_headers return request_xml = s.rfile.read(int(s.headers['Content-Length'])) root = etree.fromstring(request_xml) body = [x for x in root.iterchildren()] request = body[0] tag = request.tag api = etree.QName(tag).localname or tag if 'lun-get-iter' == api: tag = \ FakeDirectCMODEServerHandler._get_child_by_name(request, 'tag') if tag is None: body = """ indeterminate 512 1354536362 false true falselinux true/vol/navneet/lun1 0 false2FfGI$APyN68 none20971520 0false 0 cec1f3d7-3d41-11e2-9cf4-123478563412 navneetben_vserver <lun-get-iter-key-td> <key-0>ben_vserver</key-0> <key-1>/vol/navneet/lun2</key-1> <key-2>navneet</key-2> <key-3></key-3> <key-4>lun2</key-4> </lun-get-iter-key-td> 1""" else: body = """ indeterminate 512 1354536362 false true falselinux true/vol/navneet/lun3 0 false2FfGI$APyN68 none20971520 0false 0 cec1f3d7-3d41-11e2-9cf4-123478563412 navneetben_vserver 1""" elif 'volume-get-iter' == api: tag = \ FakeDirectCMODEServerHandler._get_child_by_name(request, 'tag') if tag is None: body = """ iscsi Openstack 214748364 true falseonline nfsvol openstack 247483648 true falseonline <volume-get-iter-key-td> <key-0>openstack</key-0> <key-1>nfsvol</key-1> </volume-get-iter-key-td> 2""" else: body = """ iscsi Openstack 4147483648 true falseonline nfsvol openstack 8147483648 true falseonline 2""" elif 'lun-create-by-size' == api: body = """ 22020096""" elif 'lun-destroy' == api: body = """""" elif 'igroup-get-iter' == api: init_found = True query = FakeDirectCMODEServerHandler._get_child_by_name(request, 'query') if query is not None: igroup_info = FakeDirectCMODEServerHandler._get_child_by_name( query, 'initiator-group-info') if igroup_info is not None: inits = FakeDirectCMODEServerHandler._get_child_by_name( igroup_info, 'initiators') if inits is not None: init_info = \ FakeDirectCMODEServerHandler._get_child_by_name( inits, 'initiator-info') init_name = \ FakeDirectCMODEServerHandler._get_child_content( init_info, 'initiator-name') if init_name == 'iqn.1993-08.org.debian:01:10': init_found = True else: init_found = False if init_found: tag = \ FakeDirectCMODEServerHandler._get_child_by_name( request, 'tag') if tag is None: body = """ openstack-01f5297b-00f7-4170-bf30-69b1314b2118 windows iscsi iqn.1993-08.org.debian:01:10 openstack <igroup-get-iter-key-td> <key-0>openstack</key-0> <key-1> openstack-01f5297b-00f7-4170-bf30-69b1314b2118< /key-1> </igroup-get-iter-key-td> 1""" else: body = """ openstack-01f5297b-00f7-4170-bf30-69b1314b2118 linux iscsi iqn.1993-08.org.debian:01:10 openstack 1""" else: body = """ 0 """ elif 'lun-map-get-iter' == api: tag = \ FakeDirectCMODEServerHandler._get_child_by_name(request, 'tag') if tag is None: body = """ openstack-44c5e7e1-3306-4800-9623-259e57d56a83 948ae304-06e9-11e2 0 5587e563-06e9-11e2-9cf4-123478563412 /vol/openvol/lun1 openstack <lun-map-get-iter-key-td> <key-0>openstack</key-0> <key-1>openstack-01f5297b-00f7-4170-bf30-69b1314b2118< /key-1> </lun-map-get-iter-key-td> 1 """ else: body = """ openstack-44c5e7e1-3306-4800-9623-259e57d56a83 948ae304-06e9-11e2 0 5587e563-06e9-11e2-9cf4-123478563412 /vol/openvol/lun1 openstack 1 """ elif 'lun-map' == api: body = """1 """ elif 'lun-get-geometry' == api: body = """256 512 3221225472512 2147483648 256""" elif 'iscsi-service-get-iter' == api: body = """ openstack true iqn.1992-08.com.netapp:sn.fa9:vs.105 openstack 1""" elif 'iscsi-interface-get-iter' == api: body = """ fas3170rre-cmode-01 e1b-1165 iscsi_data_if 10.63.165.216 3260true 5 iscsi_data_if 1038 openstack 1""" elif 'igroup-create' == api: body = """""" elif 'igroup-add' == api: body = """""" elif 'clone-create' == api: body = """""" elif 'lun-unmap' == api: body = """""" elif 'system-get-ontapi-version' == api: body = """ 1 19 """ elif 'vserver-get-iter' == api: body = """ vserver node 1""" elif 'ems-autosupport-log' == api: body = """""" elif 'lun-resize' == api: body = """""" elif 'lun-get-geometry' == api: body = """ 1 2 8 2 4 5 """ elif 'volume-options-list-info' == api: body = """ """ elif 'lun-move' == api: body = """""" else: # Unknown API s.send_response(500) s.end_headers return s.send_response(200) s.send_header("Content-Type", "text/xml; charset=utf-8") s.end_headers() s.wfile.write(RESPONSE_PREFIX_DIRECT_CMODE) s.wfile.write(RESPONSE_PREFIX_DIRECT) s.wfile.write(body) s.wfile.write(RESPONSE_SUFFIX_DIRECT) @staticmethod def _get_child_by_name(self, name): for child in self.iterchildren(): if child.tag == name or etree.QName(child.tag).localname == name: return child return None @staticmethod def _get_child_content(self, name): """Get the content of the child.""" for child in self.iterchildren(): if child.tag == name or etree.QName(child.tag).localname == name: return child.text return None class FakeDirectCmodeHTTPConnection(object): """A fake httplib.HTTPConnection for netapp tests Requests made via this connection actually get translated and routed into the fake direct handler above, we then turn the response into the httplib.HTTPResponse that the caller expects. """ def __init__(self, host, timeout=None): self.host = host def request(self, method, path, data=None, headers=None): if not headers: headers = {} req_str = '%s %s HTTP/1.1\r\n' % (method, path) for key, value in headers.iteritems(): req_str += "%s: %s\r\n" % (key, value) if data: req_str += '\r\n%s' % data # NOTE(vish): normally the http transport normalizes from unicode sock = FakeHttplibSocket(req_str.decode("latin-1").encode("utf-8")) # NOTE(vish): stop the server from trying to look up address from # the fake socket FakeDirectCMODEServerHandler.address_string = lambda x: '127.0.0.1' self.app = FakeDirectCMODEServerHandler(sock, '127.0.0.1:80', None) self.sock = FakeHttplibSocket(sock.result) self.http_response = httplib.HTTPResponse(self.sock) def set_debuglevel(self, level): pass def getresponse(self): self.http_response.begin() return self.http_response def getresponsebody(self): return self.sock.result class NetAppDirectCmodeISCSIDriverTestCase(test.TestCase): """Test case for NetAppISCSIDriver""" volume = {'name': 'lun1', 'size': 2, 'volume_name': 'lun1', 'os_type': 'linux', 'provider_location': 'lun1', 'id': 'lun1', 'provider_auth': None, 'project_id': 'project', 'display_name': None, 'display_description': 'lun1', 'volume_type_id': None, 'host': 'hostname@backend#vol1'} snapshot = {'name': 'snapshot1', 'size': 2, 'volume_name': 'lun1', 'volume_size': 2, 'project_id': 'project', 'display_name': None, 'display_description': 'lun1', 'volume_type_id': None} snapshot_fail = {'name': 'snapshot2', 'size': 2, 'volume_name': 'lun1', 'volume_size': 1, 'project_id': 'project'} volume_sec = {'name': 'vol_snapshot', 'size': 2, 'volume_name': 'lun1', 'os_type': 'linux', 'provider_location': 'lun1', 'id': 'lun1', 'provider_auth': None, 'project_id': 'project', 'display_name': None, 'display_description': 'lun1', 'volume_type_id': None} volume_clone = {'name': 'cl_sm', 'size': 3, 'volume_name': 'lun1', 'os_type': 'linux', 'provider_location': 'cl_sm', 'id': 'lun1', 'provider_auth': None, 'project_id': 'project', 'display_name': None, 'display_description': 'lun1', 'volume_type_id': None} volume_clone_large = {'name': 'cl_lg', 'size': 6, 'volume_name': 'lun1', 'os_type': 'linux', 'provider_location': 'cl_lg', 'id': 'lun1', 'provider_auth': None, 'project_id': 'project', 'display_name': None, 'display_description': 'lun1', 'volume_type_id': None} connector = {'initiator': 'iqn.1993-08.org.debian:01:10'} vol_fail = {'name': 'lun_fail', 'size': 10000, 'volume_name': 'lun1', 'os_type': 'linux', 'provider_location': 'lun1', 'id': 'lun1', 'provider_auth': None, 'project_id': 'project', 'display_name': None, 'display_description': 'lun1', 'volume_type_id': None, 'host': 'hostname@backend#vol1'} vol1 = ssc_cmode.NetAppVolume('lun1', 'openstack') vol1.state['vserver_root'] = False vol1.state['status'] = 'online' vol1.state['junction_active'] = True vol1.space['size_avl_bytes'] = '4000000000' vol1.space['size_total_bytes'] = '5000000000' vol1.space['space-guarantee-enabled'] = False vol1.space['space-guarantee'] = 'file' vol1.space['thin_provisioned'] = True vol1.mirror['mirrored'] = True vol1.qos['qos_policy_group'] = None vol1.aggr['name'] = 'aggr1' vol1.aggr['junction'] = '/vola' vol1.sis['dedup'] = True vol1.sis['compression'] = True vol1.aggr['raid_type'] = 'raiddp' vol1.aggr['ha_policy'] = 'cfo' vol1.aggr['disk_type'] = 'SSD' ssc_map = {'mirrored': set([vol1]), 'dedup': set([vol1]), 'compression': set([vol1]), 'thin': set([vol1]), 'all': set([vol1])} def setUp(self): super(NetAppDirectCmodeISCSIDriverTestCase, self).setUp() self._custom_setup() def _custom_setup(self): self.stubs.Set( ssc_cmode, 'refresh_cluster_ssc', lambda a, b, c, synchronous: None) self.mock_object(utils, 'OpenStackInfo') configuration = self._set_config(create_configuration()) driver = common.NetAppDriver(configuration=configuration) self.stubs.Set(httplib, 'HTTPConnection', FakeDirectCmodeHTTPConnection) driver.do_setup(context='') self.driver = driver self.driver.ssc_vols = self.ssc_map def _set_config(self, configuration): configuration.netapp_storage_protocol = 'iscsi' configuration.netapp_login = 'admin' configuration.netapp_password = 'pass' configuration.netapp_server_hostname = '127.0.0.1' configuration.netapp_transport_type = 'http' configuration.netapp_server_port = None configuration.netapp_vserver = 'openstack' return configuration def test_connect(self): self.driver.library.zapi_client = mock.MagicMock() self.driver.library.zapi_client.get_ontapi_version.return_value = \ (1, 20) self.driver.check_for_setup_error() def test_do_setup_all_default(self): self.mock_object(utils, 'OpenStackInfo') configuration = self._set_config(create_configuration()) driver = common.NetAppDriver(configuration=configuration) driver.do_setup(context='') na_server = driver.library.zapi_client.get_connection() self.assertEqual('80', na_server.get_port()) self.assertEqual('http', na_server.get_transport_type()) @mock.patch.object(client_base.Client, 'get_ontapi_version', mock.Mock(return_value=(1, 20))) def test_do_setup_http_default_port(self): self.mock_object(utils, 'OpenStackInfo') configuration = self._set_config(create_configuration()) configuration.netapp_transport_type = 'http' driver = common.NetAppDriver(configuration=configuration) driver.do_setup(context='') na_server = driver.library.zapi_client.get_connection() self.assertEqual('80', na_server.get_port()) self.assertEqual('http', na_server.get_transport_type()) @mock.patch.object(client_base.Client, 'get_ontapi_version', mock.Mock(return_value=(1, 20))) def test_do_setup_https_default_port(self): self.mock_object(utils, 'OpenStackInfo') configuration = self._set_config(create_configuration()) configuration.netapp_transport_type = 'https' driver = common.NetAppDriver(configuration=configuration) driver.library._get_root_volume_name = mock.Mock() driver.do_setup(context='') na_server = driver.library.zapi_client.get_connection() self.assertEqual('443', na_server.get_port()) self.assertEqual('https', na_server.get_transport_type()) @mock.patch.object(client_base.Client, 'get_ontapi_version', mock.Mock(return_value=(1, 20))) def test_do_setup_http_non_default_port(self): self.mock_object(utils, 'OpenStackInfo') configuration = self._set_config(create_configuration()) configuration.netapp_server_port = 81 driver = common.NetAppDriver(configuration=configuration) driver.do_setup(context='') na_server = driver.library.zapi_client.get_connection() self.assertEqual('81', na_server.get_port()) self.assertEqual('http', na_server.get_transport_type()) @mock.patch.object(client_base.Client, 'get_ontapi_version', mock.Mock(return_value=(1, 20))) def test_do_setup_https_non_default_port(self): self.mock_object(utils, 'OpenStackInfo') configuration = self._set_config(create_configuration()) configuration.netapp_transport_type = 'https' configuration.netapp_server_port = 446 driver = common.NetAppDriver(configuration=configuration) driver.library._get_root_volume_name = mock.Mock() driver.do_setup(context='') na_server = driver.library.zapi_client.get_connection() self.assertEqual('446', na_server.get_port()) self.assertEqual('https', na_server.get_transport_type()) def test_create_destroy(self): self.driver.create_volume(self.volume) self.driver.delete_volume(self.volume) def test_create_vol_snapshot_destroy(self): self.driver.create_volume(self.volume) self.driver.create_snapshot(self.snapshot) self.driver.create_volume_from_snapshot(self.volume_sec, self.snapshot) self.driver.delete_snapshot(self.snapshot) self.driver.delete_volume(self.volume) def test_map_unmap(self): self.driver.create_volume(self.volume) updates = self.driver.create_export(None, self.volume) self.assertTrue(updates['provider_location']) self.volume['provider_location'] = updates['provider_location'] connection_info = self.driver.initialize_connection(self.volume, self.connector) self.assertEqual(connection_info['driver_volume_type'], 'iscsi') properties = connection_info['data'] if not properties: raise AssertionError('Target portal is none') self.driver.terminate_connection(self.volume, self.connector) self.driver.delete_volume(self.volume) def test_cloned_volume_destroy(self): self.driver.create_volume(self.volume) self.driver.create_cloned_volume(self.snapshot, self.volume) self.driver.delete_volume(self.snapshot) self.driver.delete_volume(self.volume) def test_map_by_creating_igroup(self): self.driver.create_volume(self.volume) updates = self.driver.create_export(None, self.volume) self.assertTrue(updates['provider_location']) self.volume['provider_location'] = updates['provider_location'] connector_new = {'initiator': 'iqn.1993-08.org.debian:01:1001'} connection_info = self.driver.initialize_connection(self.volume, connector_new) self.assertEqual(connection_info['driver_volume_type'], 'iscsi') properties = connection_info['data'] if not properties: raise AssertionError('Target portal is none') def test_vol_stats(self): self.mock_object(client_base.Client, 'provide_ems') stats = self.driver.get_volume_stats(refresh=True) self.assertEqual(stats['vendor_name'], 'NetApp') def test_create_vol_snapshot_diff_size_resize(self): self.driver.create_volume(self.volume) self.driver.create_snapshot(self.snapshot) self.driver.create_volume_from_snapshot( self.volume_clone, self.snapshot) self.driver.delete_snapshot(self.snapshot) self.driver.delete_volume(self.volume) def test_create_vol_snapshot_diff_size_subclone(self): self.driver.create_volume(self.volume) self.driver.create_snapshot(self.snapshot) self.driver.create_volume_from_snapshot( self.volume_clone_large, self.snapshot) self.driver.delete_snapshot(self.snapshot) self.driver.delete_volume(self.volume) def test_extend_vol_same_size(self): self.driver.create_volume(self.volume) self.driver.extend_volume(self.volume, self.volume['size']) def test_extend_vol_direct_resize(self): self.driver.create_volume(self.volume) self.driver.extend_volume(self.volume, 3) def test_extend_vol_sub_lun_clone(self): self.driver.create_volume(self.volume) self.driver.extend_volume(self.volume, 4) class NetAppDriverNegativeTestCase(test.TestCase): """Test case for NetAppDriver""" def setUp(self): super(NetAppDriverNegativeTestCase, self).setUp() def test_incorrect_family(self): self.mock_object(utils, 'OpenStackInfo') configuration = create_configuration() configuration.netapp_storage_family = 'xyz_abc' try: common.NetAppDriver(configuration=configuration) raise AssertionError('Wrong storage family is getting accepted.') except exception.InvalidInput: pass def test_incorrect_protocol(self): self.mock_object(utils, 'OpenStackInfo') configuration = create_configuration() configuration.netapp_storage_family = 'ontap' configuration.netapp_storage_protocol = 'ontap' try: common.NetAppDriver(configuration=configuration) raise AssertionError('Wrong storage protocol is getting accepted.') except exception.InvalidInput: pass class FakeDirect7MODEServerHandler(FakeHTTPRequestHandler): """HTTP handler that fakes enough stuff to allow the driver to run.""" def do_GET(s): """Respond to a GET request.""" if '/servlets/netapp.servlets.admin.XMLrequest_filer' not in s.path: s.send_response(404) s.end_headers return s.send_response(200) s.send_header("Content-Type", "text/xml; charset=utf-8") s.end_headers() out = s.wfile out.write('' '') def do_POST(s): """Respond to a POST request.""" if '/servlets/netapp.servlets.admin.XMLrequest_filer' not in s.path: s.send_response(404) s.end_headers return request_xml = s.rfile.read(int(s.headers['Content-Length'])) root = etree.fromstring(request_xml) body = [x for x in root.iterchildren()] request = body[0] tag = request.tag api = etree.QName(tag).localname or tag if 'lun-list-info' == api: body = """ false false /vol/vol1/lun1 20971520 true false false false none linux e867d844-c2c0-11e0-9282-00a09825b3b5 P3lgP4eTyaNl 512 true 0 indeterminate /vol/vol1/lun1 20971520 true false false false none linux 8e1e9284-c288-11e0-9282-00a09825b3b5 P3lgP4eTc3lp 512 true 0 indeterminate """ elif 'volume-list-info' == api: body = """ vol0 019c8f7a-9243-11e0-9281-00a09825b3b5 flex 32_bit online 576914493440 13820354560 563094110208 2 20 140848264 0 0 0 0 20907162 7010 518 31142 31142 0 false aggr0 disabled idle idle for 70:36:44 regular sun-sat@0 Mon Aug 8 09:34:15 EST 2011 Mon Aug 8 09:34:15 EST 2011 0 0 0 0 0 0 0 0 0 0 false volume true 14 raid_dp,sis block true false false false false unmirrored 3 1 /aggr0/plex0 true false vol1 2d50ecf4-c288-11e0-9282-00a09825b3b5 flex 32_bit online 42949672960 44089344 42905583616 0 20 10485760 8192 8192 0 0 1556480 110 504 31142 31142 0 false aggr1 disabled idle idle for 89:19:59 regular sun-sat@0 Sun Aug 7 14:51:00 EST 2011 Sun Aug 7 14:51:00 EST 2011 0 0 0 0 0 0 0 0 0 0 false volume true 7 raid4,sis block true false false false false unmirrored 2 1 /aggr1/plex0 true false """ elif 'volume-options-list-info' == api: body = """ snapmirrored off root false ha_policy cfo striping not_striped compression off """ elif 'lun-create-by-size' == api: body = """ 22020096""" elif 'lun-destroy' == api: body = """""" elif 'igroup-list-info' == api: body = """ openstack-8bc96490 iscsi b8e1d274-c378-11e0 linux 0 false false false true iqn.1993-08.org.debian:01:10 iscsi_group iscsi ccb8cbe4-c36f linux 0 false false false true iqn.1993-08.org.debian:01:10ca """ elif 'lun-map-list-info' == api: body = """ """ elif 'lun-map' == api: body = """1 """ elif 'iscsi-node-get-name' == api: body = """ iqn.1992-08.com.netapp:sn.135093938 """ elif 'iscsi-portal-list-info' == api: body = """ 10.61.176.156 3260 1000 e0a """ elif 'igroup-create' == api: body = """""" elif 'igroup-add' == api: body = """""" elif 'clone-start' == api: body = """ 2d50ecf4-c288-11e0-9282-00a09825b3b5 11 """ elif 'clone-list-status' == api: body = """ completed """ elif 'lun-unmap' == api: body = """""" elif 'system-get-ontapi-version' == api: body = """ 1 8 """ elif 'lun-set-space-reservation-info' == api: body = """""" elif 'ems-autosupport-log' == api: body = """""" elif 'lun-resize' == api: body = """""" elif 'lun-get-geometry' == api: body = """ 1 2 8 2 4 5 """ elif 'volume-options-list-info' == api: body = """ """ elif 'lun-move' == api: body = """""" else: # Unknown API s.send_response(500) s.end_headers return s.send_response(200) s.send_header("Content-Type", "text/xml; charset=utf-8") s.end_headers() s.wfile.write(RESPONSE_PREFIX_DIRECT_7MODE) s.wfile.write(RESPONSE_PREFIX_DIRECT) s.wfile.write(body) s.wfile.write(RESPONSE_SUFFIX_DIRECT) class FakeDirect7modeHTTPConnection(object): """A fake httplib.HTTPConnection for netapp tests Requests made via this connection actually get translated and routed into the fake direct handler above, we then turn the response into the httplib.HTTPResponse that the caller expects. """ def __init__(self, host, timeout=None): self.host = host def request(self, method, path, data=None, headers=None): if not headers: headers = {} req_str = '%s %s HTTP/1.1\r\n' % (method, path) for key, value in headers.iteritems(): req_str += "%s: %s\r\n" % (key, value) if data: req_str += '\r\n%s' % data # NOTE(vish): normally the http transport normailizes from unicode sock = FakeHttplibSocket(req_str.decode("latin-1").encode("utf-8")) # NOTE(vish): stop the server from trying to look up address from # the fake socket FakeDirect7MODEServerHandler.address_string = lambda x: '127.0.0.1' self.app = FakeDirect7MODEServerHandler(sock, '127.0.0.1:80', None) self.sock = FakeHttplibSocket(sock.result) self.http_response = httplib.HTTPResponse(self.sock) def set_debuglevel(self, level): pass def getresponse(self): self.http_response.begin() return self.http_response def getresponsebody(self): return self.sock.result class NetAppDirect7modeISCSIDriverTestCase_NV( NetAppDirectCmodeISCSIDriverTestCase): """Test case for NetAppISCSIDriver No vfiler """ def setUp(self): super(NetAppDirect7modeISCSIDriverTestCase_NV, self).setUp() def _custom_setup(self): self.mock_object(utils, 'OpenStackInfo') configuration = self._set_config(create_configuration()) driver = common.NetAppDriver(configuration=configuration) self.stubs.Set(httplib, 'HTTPConnection', FakeDirect7modeHTTPConnection) driver.do_setup(context='') driver.root_volume_name = 'root' self.driver = driver def _set_config(self, configuration): configuration.netapp_storage_family = 'ontap_7mode' configuration.netapp_storage_protocol = 'iscsi' configuration.netapp_login = 'admin' configuration.netapp_password = 'pass' configuration.netapp_server_hostname = '127.0.0.1' configuration.netapp_transport_type = 'http' configuration.netapp_server_port = None return configuration def test_create_on_select_vol(self): self.driver.volume_list = ['vol0', 'vol1'] self.driver.create_volume(self.volume) self.driver.delete_volume(self.volume) self.driver.volume_list = [] def test_connect(self): self.driver.library.zapi_client = mock.MagicMock() self.driver.library.zapi_client.get_ontapi_version.\ return_value = (1, 20) self.driver.check_for_setup_error() def test_check_for_setup_error_version(self): drv = self.driver drv.zapi_client = mock.Mock() drv.zapi_client.get_ontapi_version.return_value = None # check exception raises when version not found self.assertRaises(exception.VolumeBackendAPIException, drv.check_for_setup_error) drv.zapi_client.get_ontapi_version.return_value = (1, 8) # check exception raises when not supported version self.assertRaises(exception.VolumeBackendAPIException, drv.check_for_setup_error) class NetAppDirect7modeISCSIDriverTestCase_WV( NetAppDirect7modeISCSIDriverTestCase_NV): """Test case for NetAppISCSIDriver With vfiler """ def setUp(self): super(NetAppDirect7modeISCSIDriverTestCase_WV, self).setUp() def _custom_setup(self): self.mock_object(utils, 'OpenStackInfo') configuration = self._set_config(create_configuration()) driver = common.NetAppDriver(configuration=configuration) self.stubs.Set(httplib, 'HTTPConnection', FakeDirect7modeHTTPConnection) driver.do_setup(context='') self.driver = driver self.driver.root_volume_name = 'root' def _set_config(self, configuration): configuration.netapp_storage_family = 'ontap_7mode' configuration.netapp_storage_protocol = 'iscsi' configuration.netapp_login = 'admin' configuration.netapp_password = 'pass' configuration.netapp_server_hostname = '127.0.0.1' configuration.netapp_transport_type = 'http' configuration.netapp_server_port = None configuration.netapp_vfiler = 'openstack' return configuration