diff options
author | Vishvananda Ishaya <vishvananda@gmail.com> | 2012-10-23 19:30:48 -0700 |
---|---|---|
committer | Vishvananda Ishaya <vishvananda@gmail.com> | 2012-10-28 11:34:05 -0700 |
commit | 7e2b93acc59dea81d52684f7f659fcff32507e14 (patch) | |
tree | 11bf7e96a3835d0002f133742dd9e1702c7cc6c6 /nova/tests/test_netapp.py | |
parent | 4e449c0843150b785bc61e87599d05ff242a8f4a (diff) | |
download | nova-7e2b93acc59dea81d52684f7f659fcff32507e14.tar.gz nova-7e2b93acc59dea81d52684f7f659fcff32507e14.tar.xz nova-7e2b93acc59dea81d52684f7f659fcff32507e14.zip |
removes the nova-volume code from nova
This removes the majority of the nova-volume code from the codebase.
It updates relevent config options to default to cinder. It updates a
number of existing tests that were depending on code that was removed.
A few things still need to be removed:
* volume/driver.py & volume/iscsi.py
These files are used by the libvirt volume driver tests. These
tests should be updated to mock the relevant calls.
* scheduler/simple.py & scheduler/multi.py
These files should no longer be necessary so they can be removed
in a subsequent patch
* exception.py cleanup
Once the above files are removed there are a number of unused
exceptions which can be removed
* database calls and database tables
The database calls have not been removed and the tables have not
been dropped. This can be done in a separate migration
* additional config options and nova.conf.sample
There may be a few extra config options that can be removed and the
conf sample can be regenerated
Implements bp delete-nova-volume
Change-Id: I0b540e54dbabd26901a7530035a38583bb521fda
Diffstat (limited to 'nova/tests/test_netapp.py')
-rw-r--r-- | nova/tests/test_netapp.py | 1380 |
1 files changed, 0 insertions, 1380 deletions
diff --git a/nova/tests/test_netapp.py b/nova/tests/test_netapp.py deleted file mode 100644 index 79a8526ee..000000000 --- a/nova/tests/test_netapp.py +++ /dev/null @@ -1,1380 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# 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 -import StringIO - -from lxml import etree - -from nova.openstack.common import log as logging -from nova import test -from nova.volume import netapp - - -LOG = logging.getLogger(__name__) - - -WSDL_HEADER = """<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<definitions xmlns="http://schemas.xmlsoap.org/wsdl/" - xmlns:na="http://www.netapp.com/management/v1" - xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" - xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="NetAppDfm" - targetNamespace="http://www.netapp.com/management/v1">""" - -WSDL_TYPES = """<types> -<xsd:schema attributeFormDefault="unqualified" elementFormDefault="qualified" - targetNamespace="http://www.netapp.com/management/v1"> -<xsd:element name="ApiProxy"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Request" type="na:Request"/> - <xsd:element name="Target" type="xsd:string"/> - <xsd:element minOccurs="0" name="Timeout" type="xsd:integer"/> - <xsd:element minOccurs="0" name="Username" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="ApiProxyResult"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Response" type="na:Response"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetEditBegin"> - <xsd:complexType> - <xsd:all> - <xsd:element name="DatasetNameOrId" type="na:ObjNameOrId"/> - <xsd:element minOccurs="0" name="Force" type="xsd:boolean"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetEditBeginResult"> - <xsd:complexType> - <xsd:all> - <xsd:element name="EditLockId" type="xsd:integer"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetEditCommit"> - <xsd:complexType> - <xsd:all> - <xsd:element minOccurs="0" name="AssumeConfirmation" - type="xsd:boolean"/> - <xsd:element name="EditLockId" type="xsd:integer"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetEditCommitResult"> - <xsd:complexType> - <xsd:all> - <xsd:element minOccurs="0" name="IsProvisioningFailure" - type="xsd:boolean"/> - <xsd:element minOccurs="0" name="JobIds" type="na:ArrayOfJobInfo"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetEditRollback"> - <xsd:complexType> - <xsd:all> - <xsd:element name="EditLockId" type="xsd:integer"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetEditRollbackResult"> - <xsd:complexType/> -</xsd:element> -<xsd:element name="DatasetListInfoIterEnd"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetListInfoIterEndResult"> - <xsd:complexType/> -</xsd:element> -<xsd:element name="DatasetListInfoIterNext"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Maximum" type="xsd:integer"/> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetListInfoIterNextResult"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Datasets" type="na:ArrayOfDatasetInfo"/> - <xsd:element name="Records" type="xsd:integer"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetListInfoIterStart"> - <xsd:complexType> - <xsd:all> - <xsd:element minOccurs="0" name="ObjectNameOrId" - type="na:ObjNameOrId"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetListInfoIterStartResult"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Records" type="xsd:integer"/> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetMemberListInfoIterEnd"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetMemberListInfoIterEndResult"> - <xsd:complexType/> -</xsd:element> -<xsd:element name="DatasetMemberListInfoIterNext"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Maximum" type="xsd:integer"/> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetMemberListInfoIterNextResult"> - <xsd:complexType> - <xsd:all> - <xsd:element name="DatasetMembers" - type="na:ArrayOfDatasetMemberInfo"/> - <xsd:element name="Records" type="xsd:integer"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetMemberListInfoIterStart"> - <xsd:complexType> - <xsd:all> - <xsd:element name="DatasetNameOrId" type="na:ObjNameOrId"/> - <xsd:element minOccurs="0" name="IncludeExportsInfo" - type="xsd:boolean"/> - <xsd:element minOccurs="0" name="IncludeIndirect" - type="xsd:boolean"/> - <xsd:element minOccurs="0" name="MemberType" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetMemberListInfoIterStartResult"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Records" type="xsd:integer"/> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetProvisionMember"> - <xsd:complexType> - <xsd:all> - <xsd:element name="EditLockId" type="xsd:integer"/> - <xsd:element name="ProvisionMemberRequestInfo" - type="na:ProvisionMemberRequestInfo"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetProvisionMemberResult"> - <xsd:complexType/> -</xsd:element> -<xsd:element name="DatasetRemoveMember"> - <xsd:complexType> - <xsd:all> - <xsd:element name="DatasetMemberParameters" - type="na:ArrayOfDatasetMemberParameter"/> - <xsd:element minOccurs="0" name="Destroy" type="xsd:boolean"/> - <xsd:element name="EditLockId" type="xsd:integer"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetRemoveMemberResult"> - <xsd:complexType/> -</xsd:element> -<xsd:element name="DpJobProgressEventListIterEnd"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DpJobProgressEventListIterEndResult"> - <xsd:complexType/> -</xsd:element> -<xsd:element name="DpJobProgressEventListIterNext"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Maximum" type="xsd:integer"/> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DpJobProgressEventListIterNextResult"> - <xsd:complexType> - <xsd:all> - <xsd:element name="ProgressEvents" - type="na:ArrayOfDpJobProgressEventInfo"/> - <xsd:element name="Records" type="xsd:integer"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DpJobProgressEventListIterStart"> - <xsd:complexType> - <xsd:all> - <xsd:element minOccurs="0" name="JobId" type="xsd:integer"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DpJobProgressEventListIterStartResult"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Records" type="xsd:integer"/> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DfmAbout"> - <xsd:complexType> - <xsd:all> - <xsd:element minOccurs="0" name="IncludeDirectorySizeInfo" - type="xsd:boolean"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DfmAboutResult"> - <xsd:complexType> - <xsd:all/> - </xsd:complexType> -</xsd:element> -<xsd:element name="HostListInfoIterEnd"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="HostListInfoIterEndResult"> - <xsd:complexType/> -</xsd:element> -<xsd:element name="HostListInfoIterNext"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Maximum" type="xsd:integer"/> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="HostListInfoIterNextResult"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Hosts" type="na:ArrayOfHostInfo"/> - <xsd:element name="Records" type="xsd:integer"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="HostListInfoIterStart"> - <xsd:complexType> - <xsd:all> - <xsd:element minOccurs="0" name="ObjectNameOrId" - type="na:ObjNameOrId"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="HostListInfoIterStartResult"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Records" type="xsd:integer"/> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="LunListInfoIterEnd"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="LunListInfoIterEndResult"> - <xsd:complexType/> -</xsd:element> -<xsd:element name="LunListInfoIterNext"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Maximum" type="xsd:integer"/> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="LunListInfoIterNextResult"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Luns" type="na:ArrayOfLunInfo"/> - <xsd:element name="Records" type="xsd:integer"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="LunListInfoIterStart"> - <xsd:complexType> - <xsd:all> - <xsd:element minOccurs="0" name="ObjectNameOrId" - type="na:ObjNameOrId"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="LunListInfoIterStartResult"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Records" type="xsd:integer"/> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="StorageServiceDatasetProvision"> - <xsd:complexType> - <xsd:all> - <xsd:element minOccurs="0" name="AssumeConfirmation" - type="xsd:boolean"/> - <xsd:element name="DatasetName" type="na:ObjName"/> - <xsd:element name="StorageServiceNameOrId" type="na:ObjNameOrId"/> - <xsd:element minOccurs="0" name="StorageSetDetails" - type="na:ArrayOfStorageSetInfo"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="StorageServiceDatasetProvisionResult"> - <xsd:complexType> - <xsd:all> - <xsd:element minOccurs="0" name="ConformanceAlerts" - type="na:ArrayOfConformanceAlert"/> - <xsd:element name="DatasetId" type="na:ObjId"/> - <xsd:element minOccurs="0" name="DryRunResults" - type="na:ArrayOfDryRunResult"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:complexType name="ArrayOfDatasetInfo"> - <xsd:sequence> - <xsd:element maxOccurs="unbounded" name="DatasetInfo" - type="na:DatasetInfo"/> - </xsd:sequence> -</xsd:complexType> -<xsd:complexType name="ArrayOfDatasetMemberInfo"> - <xsd:sequence> - <xsd:element maxOccurs="unbounded" name="DatasetMemberInfo" - type="na:DatasetMemberInfo"/> - </xsd:sequence> -</xsd:complexType> -<xsd:complexType name="ArrayOfDatasetMemberParameter"> - <xsd:sequence> - <xsd:element maxOccurs="unbounded" name="DatasetMemberParameter" - type="na:DatasetMemberParameter"/> - </xsd:sequence> -</xsd:complexType> -<xsd:complexType name="ArrayOfDfmMetadataField"> - <xsd:sequence> - <xsd:element maxOccurs="unbounded" name="DfmMetadataField" - type="na:DfmMetadataField"/> - </xsd:sequence> -</xsd:complexType> -<xsd:complexType name="ArrayOfDpJobProgressEventInfo"> - <xsd:sequence> - <xsd:element maxOccurs="unbounded" name="DpJobProgressEventInfo" - type="na:DpJobProgressEventInfo"/> - </xsd:sequence> -</xsd:complexType> -<xsd:complexType name="ArrayOfHostInfo"> - <xsd:sequence> - <xsd:element maxOccurs="unbounded" name="HostInfo" type="na:HostInfo"/> - </xsd:sequence> -</xsd:complexType> -<xsd:complexType name="ArrayOfJobInfo"> - <xsd:sequence> - <xsd:element maxOccurs="unbounded" name="JobInfo" type="na:JobInfo"/> - </xsd:sequence> -</xsd:complexType> -<xsd:complexType name="ArrayOfLunInfo"> - <xsd:sequence> - <xsd:element maxOccurs="unbounded" name="LunInfo" type="na:LunInfo"/> - </xsd:sequence> -</xsd:complexType> -<xsd:complexType name="ArrayOfStorageSetInfo"> - <xsd:sequence> - <xsd:element maxOccurs="unbounded" name="StorageSetInfo" - type="na:StorageSetInfo"/> - </xsd:sequence> -</xsd:complexType> -<xsd:complexType name="DatasetExportInfo"> - <xsd:all> - <xsd:element minOccurs="0" name="DatasetExportProtocol" - type="na:DatasetExportProtocol"/> - <xsd:element minOccurs="0" name="DatasetLunMappingInfo" - type="na:DatasetLunMappingInfo"/> - </xsd:all> -</xsd:complexType> -<xsd:simpleType name="DatasetExportProtocol"> - <xsd:restriction base="xsd:string"/> -</xsd:simpleType> -<xsd:complexType name="DatasetInfo"> - <xsd:all> - <xsd:element name="DatasetId" type="na:ObjId"/> - <xsd:element name="DatasetName" type="na:ObjName"/> - <xsd:element name="DatasetMetadata" type="na:ArrayOfDfmMetadataField"/> - </xsd:all> -</xsd:complexType> -<xsd:complexType name="DatasetLunMappingInfo"> - <xsd:all> - <xsd:element name="IgroupOsType" type="xsd:string"/> - </xsd:all> -</xsd:complexType> -<xsd:complexType name="DatasetMemberInfo"> - <xsd:all> - <xsd:element name="MemberId" type="na:ObjId"/> - <xsd:element name="MemberName" type="na:ObjName"/> - </xsd:all> -</xsd:complexType> -<xsd:complexType name="DatasetMemberParameter"> - <xsd:all> - <xsd:element name="ObjectNameOrId" type="na:ObjNameOrId"/> - </xsd:all> -</xsd:complexType> -<xsd:complexType name="DfmMetadataField"> - <xsd:all> - <xsd:element name="FieldName" type="xsd:string"/> - <xsd:element name="FieldValue" type="xsd:string"/> - </xsd:all> -</xsd:complexType> -<xsd:complexType name="DpJobProgressEventInfo"> - <xsd:all> - <xsd:element name="EventStatus" type="na:ObjStatus"/> - <xsd:element name="EventType" type="xsd:string"/> - <xsd:element minOccurs="0" name="ProgressLunInfo" - type="na:ProgressLunInfo"/> - </xsd:all> -</xsd:complexType> -<xsd:simpleType name="DpPolicyNodeName"> - <xsd:restriction base="xsd:string"/> -</xsd:simpleType> -<xsd:simpleType name="HostId"> - <xsd:restriction base="xsd:integer"/> -</xsd:simpleType> -<xsd:complexType name="HostInfo"> - <xsd:all> - <xsd:element name="HostAddress" type="xsd:string"/> - <xsd:element name="HostId" type="na:HostId"/> - <xsd:element name="HostName" type="xsd:string"/> - </xsd:all> -</xsd:complexType> -<xsd:complexType name="JobInfo"> - <xsd:all> - <xsd:element name="JobId" type="xsd:integer"/> - </xsd:all> -</xsd:complexType> -<xsd:complexType name="LunInfo"> - <xsd:all> - <xsd:element name="HostId" type="na:ObjId"/> - <xsd:element name="LunPath" type="na:ObjName"/> - </xsd:all> -</xsd:complexType> -<xsd:simpleType name="ObjId"> - <xsd:restriction base="xsd:integer"/> -</xsd:simpleType> -<xsd:simpleType name="ObjName"> - <xsd:restriction base="xsd:string"/> -</xsd:simpleType> -<xsd:simpleType name="ObjNameOrId"> - <xsd:restriction base="xsd:string"/> -</xsd:simpleType> -<xsd:simpleType name="ObjStatus"> - <xsd:restriction base="xsd:string"/> -</xsd:simpleType> -<xsd:complexType name="ProgressLunInfo"> - <xsd:all> - <xsd:element name="LunPathId" type="na:ObjId"/> - <xsd:element name="LunName" type="na:ObjName"/> - </xsd:all> -</xsd:complexType> -<xsd:complexType name="ProvisionMemberRequestInfo"> - <xsd:all> - <xsd:element minOccurs="0" name="Description" type="xsd:string"/> - <xsd:element minOccurs="0" name="MaximumSnapshotSpace" - type="xsd:integer"/> - <xsd:element name="Name" type="xsd:string"/> - <xsd:element name="Size" type="xsd:integer"/> - </xsd:all> -</xsd:complexType> -<xsd:complexType name="Request"> - <xsd:all> - <xsd:element minOccurs="0" name="Args"> - <xsd:complexType> - <xsd:sequence> - <xsd:any maxOccurs="unbounded" minOccurs="0"/> - </xsd:sequence> - </xsd:complexType> - </xsd:element> - <xsd:element name="Name" type="xsd:string"> - </xsd:element> - </xsd:all> -</xsd:complexType> -<xsd:complexType name="Response"> - <xsd:all> - <xsd:element minOccurs="0" name="Errno" type="xsd:integer"/> - <xsd:element minOccurs="0" name="Reason" type="xsd:string"/> - <xsd:element minOccurs="0" name="Results"> - <xsd:complexType> - <xsd:sequence> - <xsd:any maxOccurs="unbounded" minOccurs="0"/> - </xsd:sequence> - </xsd:complexType> - </xsd:element> - <xsd:element name="Status" type="xsd:string"/> - </xsd:all> -</xsd:complexType> -<xsd:complexType name="StorageSetInfo"> - <xsd:all> - <xsd:element minOccurs="0" name="DatasetExportInfo" - type="na:DatasetExportInfo"/> - <xsd:element minOccurs="0" name="DpNodeName" - type="na:DpPolicyNodeName"/> - <xsd:element minOccurs="0" name="ServerNameOrId" - type="na:ObjNameOrId"/> - </xsd:all> -</xsd:complexType> -</xsd:schema></types>""" - -WSDL_TRAILER = """<service name="DfmService"> -<port binding="na:DfmBinding" name="DfmPort"> -<soap:address location="https://HOST_NAME:8488/apis/soap/v1"/> -</port></service></definitions>""" - -RESPONSE_PREFIX = """<?xml version="1.0" encoding="UTF-8"?> -<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" - xmlns:na="http://www.netapp.com/management/v1"><env:Header/><env:Body>""" - -RESPONSE_SUFFIX = """</env:Body></env:Envelope>""" - -APIS = ['ApiProxy', 'DatasetListInfoIterStart', 'DatasetListInfoIterNext', - 'DatasetListInfoIterEnd', 'DatasetEditBegin', 'DatasetEditCommit', - 'DatasetProvisionMember', 'DatasetRemoveMember', 'DfmAbout', - 'DpJobProgressEventListIterStart', 'DpJobProgressEventListIterNext', - 'DpJobProgressEventListIterEnd', 'DatasetMemberListInfoIterStart', - 'DatasetMemberListInfoIterNext', 'DatasetMemberListInfoIterEnd', - 'HostListInfoIterStart', 'HostListInfoIterNext', 'HostListInfoIterEnd', - 'LunListInfoIterStart', 'LunListInfoIterNext', 'LunListInfoIterEnd', - 'StorageServiceDatasetProvision'] - -iter_count = 0 -iter_table = {} - - -class FakeDfmServerHandler(BaseHTTPServer.BaseHTTPRequestHandler): - """HTTP handler that fakes enough stuff to allow the driver to run""" - - def do_GET(s): - """Respond to a GET request.""" - if '/dfm.wsdl' != s.path: - s.send_response(404) - s.end_headers - return - s.send_response(200) - s.send_header("Content-Type", "application/wsdl+xml") - s.end_headers() - out = s.wfile - out.write(WSDL_HEADER) - out.write(WSDL_TYPES) - for api in APIS: - out.write('<message name="%sRequest">' % api) - out.write('<part element="na:%s" name="parameters"/>' % api) - out.write('</message>') - out.write('<message name="%sResponse">' % api) - out.write('<part element="na:%sResult" name="results"/>' % api) - out.write('</message>') - out.write('<portType name="DfmInterface">') - for api in APIS: - out.write('<operation name="%s">' % api) - out.write('<input message="na:%sRequest"/>' % api) - out.write('<output message="na:%sResponse"/>' % api) - out.write('</operation>') - out.write('</portType>') - out.write('<binding name="DfmBinding" type="na:DfmInterface">') - out.write('<soap:binding style="document" ' + - 'transport="http://schemas.xmlsoap.org/soap/http"/>') - for api in APIS: - out.write('<operation name="%s">' % api) - out.write('<soap:operation soapAction="urn:%s"/>' % api) - out.write('<input><soap:body use="literal"/></input>') - out.write('<output><soap:body use="literal"/></output>') - out.write('</operation>') - out.write('</binding>') - out.write(WSDL_TRAILER) - - def do_POST(s): - """Respond to a POST request.""" - if '/apis/soap/v1' != s.path: - s.send_response(404) - s.end_headers - return - request_xml = s.rfile.read(int(s.headers['Content-Length'])) - ntap_ns = 'http://www.netapp.com/management/v1' - nsmap = {'env': 'http://schemas.xmlsoap.org/soap/envelope/', - 'na': ntap_ns} - root = etree.fromstring(request_xml) - - body = root.xpath('/env:Envelope/env:Body', namespaces=nsmap)[0] - request = body.getchildren()[0] - tag = request.tag - if not tag.startswith('{' + ntap_ns + '}'): - s.send_response(500) - s.end_headers - return - api = tag[(2 + len(ntap_ns)):] - global iter_count - global iter_table - if 'DatasetListInfoIterStart' == api: - iter_name = 'dataset_%s' % iter_count - iter_count = iter_count + 1 - iter_table[iter_name] = 0 - body = """<na:DatasetListInfoIterStartResult> - <na:Records>1</na:Records> - <na:Tag>%s</na:Tag> - </na:DatasetListInfoIterStartResult>""" % iter_name - elif 'DatasetListInfoIterNext' == api: - tags = body.xpath('na:DatasetListInfoIterNext/na:Tag', - namespaces=nsmap) - iter_name = tags[0].text - if iter_table[iter_name]: - body = """<na:DatasetListInfoIterNextResult> - <na:Datasets></na:Datasets> - <na:Records>0</na:Records> - </na:DatasetListInfoIterNextResult>""" - else: - iter_table[iter_name] = 1 - body = """<na:DatasetListInfoIterNextResult> - <na:Datasets> - <na:DatasetInfo> - <na:DatasetId>0</na:DatasetId> - <na:DatasetMetadata> - <na:DfmMetadataField> - <na:FieldName>OpenStackProject</na:FieldName> - <na:FieldValue>testproj</na:FieldValue> - </na:DfmMetadataField> - <na:DfmMetadataField> - <na:FieldName>OpenStackVolType</na:FieldName> - <na:FieldValue></na:FieldValue> - </na:DfmMetadataField> - </na:DatasetMetadata> - <na:DatasetName>OpenStack_testproj</na:DatasetName> - </na:DatasetInfo> - </na:Datasets> - <na:Records>1</na:Records> - </na:DatasetListInfoIterNextResult>""" - elif 'DatasetListInfoIterEnd' == api: - body = """<na:DatasetListInfoIterEndResult/>""" - elif 'DatasetEditBegin' == api: - body = """<na:DatasetEditBeginResult> - <na:EditLockId>0</na:EditLockId> - </na:DatasetEditBeginResult>""" - elif 'DatasetEditCommit' == api: - body = """<na:DatasetEditCommitResult> - <na:IsProvisioningFailure>false</na:IsProvisioningFailure> - <na:JobIds> - <na:JobInfo> - <na:JobId>0</na:JobId> - </na:JobInfo> - </na:JobIds> - </na:DatasetEditCommitResult>""" - elif 'DatasetProvisionMember' == api: - body = """<na:DatasetProvisionMemberResult/>""" - elif 'DatasetRemoveMember' == api: - body = """<na:DatasetRemoveMemberResult/>""" - elif 'DfmAbout' == api: - body = """<na:DfmAboutResult/>""" - elif 'DpJobProgressEventListIterStart' == api: - iter_name = 'dpjobprogress_%s' % iter_count - iter_count = iter_count + 1 - iter_table[iter_name] = 0 - body = """<na:DpJobProgressEventListIterStartResult> - <na:Records>2</na:Records> - <na:Tag>%s</na:Tag> - </na:DpJobProgressEventListIterStartResult>""" % iter_name - elif 'DpJobProgressEventListIterNext' == api: - tags = body.xpath('na:DpJobProgressEventListIterNext/na:Tag', - namespaces=nsmap) - iter_name = tags[0].text - if iter_table[iter_name]: - body = """<na:DpJobProgressEventListIterNextResult/>""" - else: - iter_table[iter_name] = 1 - name = ('filer:/OpenStack_testproj/volume-00000001/' - 'volume-00000001') - body = """<na:DpJobProgressEventListIterNextResult> - <na:ProgressEvents> - <na:DpJobProgressEventInfo> - <na:EventStatus>normal</na:EventStatus> - <na:EventType>lun-create</na:EventType> - <na:ProgressLunInfo> - <na:LunPathId>0</na:LunPathId> - <na:LunName>%s</na:LunName> - </na:ProgressLunInfo> - </na:DpJobProgressEventInfo> - <na:DpJobProgressEventInfo> - <na:EventStatus>normal</na:EventStatus> - <na:EventType>job-end</na:EventType> - </na:DpJobProgressEventInfo> - </na:ProgressEvents> - <na:Records>2</na:Records> - </na:DpJobProgressEventListIterNextResult>""" % name - elif 'DpJobProgressEventListIterEnd' == api: - body = """<na:DpJobProgressEventListIterEndResult/>""" - elif 'DatasetMemberListInfoIterStart' == api: - iter_name = 'datasetmember_%s' % iter_count - iter_count = iter_count + 1 - iter_table[iter_name] = 0 - body = """<na:DatasetMemberListInfoIterStartResult> - <na:Records>1</na:Records> - <na:Tag>%s</na:Tag> - </na:DatasetMemberListInfoIterStartResult>""" % iter_name - elif 'DatasetMemberListInfoIterNext' == api: - tags = body.xpath('na:DatasetMemberListInfoIterNext/na:Tag', - namespaces=nsmap) - iter_name = tags[0].text - if iter_table[iter_name]: - body = """<na:DatasetMemberListInfoIterNextResult> - <na:DatasetMembers></na:DatasetMembers> - <na:Records>0</na:Records> - </na:DatasetMemberListInfoIterNextResult>""" - else: - iter_table[iter_name] = 1 - name = ('filer:/OpenStack_testproj/volume-00000001/' - 'volume-00000001') - body = """<na:DatasetMemberListInfoIterNextResult> - <na:DatasetMembers> - <na:DatasetMemberInfo> - <na:MemberId>0</na:MemberId> - <na:MemberName>%s</na:MemberName> - </na:DatasetMemberInfo> - </na:DatasetMembers> - <na:Records>1</na:Records> - </na:DatasetMemberListInfoIterNextResult>""" % name - elif 'DatasetMemberListInfoIterEnd' == api: - body = """<na:DatasetMemberListInfoIterEndResult/>""" - elif 'HostListInfoIterStart' == api: - body = """<na:HostListInfoIterStartResult> - <na:Records>1</na:Records> - <na:Tag>host</na:Tag> - </na:HostListInfoIterStartResult>""" - elif 'HostListInfoIterNext' == api: - body = """<na:HostListInfoIterNextResult> - <na:Hosts> - <na:HostInfo> - <na:HostAddress>1.2.3.4</na:HostAddress> - <na:HostId>0</na:HostId> - <na:HostName>filer</na:HostName> - </na:HostInfo> - </na:Hosts> - <na:Records>1</na:Records> - </na:HostListInfoIterNextResult>""" - elif 'HostListInfoIterEnd' == api: - body = """<na:HostListInfoIterEndResult/>""" - elif 'LunListInfoIterStart' == api: - body = """<na:LunListInfoIterStartResult> - <na:Records>1</na:Records> - <na:Tag>lun</na:Tag> - </na:LunListInfoIterStartResult>""" - elif 'LunListInfoIterNext' == api: - path = 'OpenStack_testproj/volume-00000001/volume-00000001' - body = """<na:LunListInfoIterNextResult> - <na:Luns> - <na:LunInfo> - <na:HostId>0</na:HostId> - <na:LunPath>%s</na:LunPath> - </na:LunInfo> - </na:Luns> - <na:Records>1</na:Records> - </na:LunListInfoIterNextResult>""" % path - elif 'LunListInfoIterEnd' == api: - body = """<na:LunListInfoIterEndResult/>""" - elif 'ApiProxy' == api: - names = body.xpath('na:ApiProxy/na:Request/na:Name', - namespaces=nsmap) - proxy = names[0].text - if 'igroup-list-info' == proxy: - igroup = 'openstack-iqn.1993-08.org.debian:01:23456789' - initiator = 'iqn.1993-08.org.debian:01:23456789' - proxy_body = """<initiator-groups> - <initiator-group-info> - <initiator-group-name>%s</initiator-group-name> - <initiator-group-type>iscsi</initiator-group-type> - <initiator-group-os-type>linux</initiator-group-os-type> - <initiators> - <initiator-info> - <initiator-name>%s</initiator-name> - </initiator-info> - </initiators> - </initiator-group-info> - </initiator-groups>""" % (igroup, initiator) - elif 'igroup-create' == proxy: - proxy_body = '' - elif 'igroup-add' == proxy: - proxy_body = '' - elif 'lun-map-list-info' == proxy: - proxy_body = '<initiator-groups/>' - elif 'lun-map' == proxy: - proxy_body = '<lun-id-assigned>0</lun-id-assigned>' - elif 'lun-unmap' == proxy: - proxy_body = '' - elif 'iscsi-portal-list-info' == proxy: - proxy_body = """<iscsi-portal-list-entries> - <iscsi-portal-list-entry-info> - <ip-address>1.2.3.4</ip-address> - <ip-port>3260</ip-port> - <tpgroup-tag>1000</tpgroup-tag> - </iscsi-portal-list-entry-info> - </iscsi-portal-list-entries>""" - elif 'iscsi-node-get-name' == proxy: - target = 'iqn.1992-08.com.netapp:sn.111111111' - proxy_body = '<node-name>%s</node-name>' % target - else: - # Unknown proxy API - s.send_response(500) - s.end_headers - return - api = api + ':' + proxy - proxy_header = '<na:ApiProxyResult><na:Response><na:Results>' - proxy_trailer = """</na:Results><na:Status>passed</na:Status> - </na:Response></na:ApiProxyResult>""" - body = proxy_header + proxy_body + proxy_trailer - 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) - s.wfile.write(body) - s.wfile.write(RESPONSE_SUFFIX) - - -class FakeHttplibSocket(object): - """A fake socket implementation for httplib.HTTPResponse""" - def __init__(self, value): - self._rbuffer = StringIO.StringIO(value) - self._wbuffer = StringIO.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 - - -class FakeHTTPConnection(object): - """A fake httplib.HTTPConnection for netapp tests - - Requests made via this connection actually get translated and routed into - the fake Dfm 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 - FakeDfmServerHandler.address_string = lambda x: '127.0.0.1' - self.app = FakeDfmServerHandler(sock, '127.0.0.1:8088', 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 NetAppDriverTestCase(test.TestCase): - """Test case for NetAppISCSIDriver""" - STORAGE_SERVICE = 'Openstack Service' - STORAGE_SERVICE_PREFIX = 'Openstack Service-' - PROJECT_ID = 'testproj' - VOLUME_NAME = 'volume-00000001' - VOLUME_TYPE = '' - VOLUME_SIZE = 2147483648L # 2 GB - INITIATOR = 'iqn.1993-08.org.debian:01:23456789' - - def setUp(self): - super(NetAppDriverTestCase, self).setUp() - driver = netapp.NetAppISCSIDriver() - self.stubs.Set(httplib, 'HTTPConnection', FakeHTTPConnection) - driver._create_client(wsdl_url='http://localhost:8088/dfm.wsdl', - login='root', password='password', - hostname='localhost', port=8088, cache=False) - driver._set_storage_service(self.STORAGE_SERVICE) - driver._set_storage_service_prefix(self.STORAGE_SERVICE_PREFIX) - driver._set_vfiler('') - self.driver = driver - - def test_connect(self): - self.driver.check_for_setup_error() - - def test_create_destroy(self): - self.driver._discover_luns() - self.driver._provision(self.VOLUME_NAME, None, self.PROJECT_ID, - self.VOLUME_TYPE, self.VOLUME_SIZE) - self.driver._remove_destroy(self.VOLUME_NAME, self.PROJECT_ID) - - def test_map_unmap(self): - self.driver._discover_luns() - self.driver._provision(self.VOLUME_NAME, None, self.PROJECT_ID, - self.VOLUME_TYPE, self.VOLUME_SIZE) - volume = {'name': self.VOLUME_NAME, 'project_id': self.PROJECT_ID, - 'id': 0, 'provider_auth': None} - updates = self.driver._get_export(volume) - self.assertTrue(updates['provider_location']) - volume['provider_location'] = updates['provider_location'] - connector = {'initiator': self.INITIATOR} - connection_info = self.driver.initialize_connection(volume, connector) - self.assertEqual(connection_info['driver_volume_type'], 'iscsi') - properties = connection_info['data'] - self.driver.terminate_connection(volume, connector) - self.driver._remove_destroy(self.VOLUME_NAME, self.PROJECT_ID) - - -WSDL_HEADER_CMODE = """<?xml version="1.0" encoding="UTF-8"?> -<definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" - xmlns:na="http://cloud.netapp.com/" -xmlns:xsd="http://www.w3.org/2001/XMLSchema" -xmlns="http://schemas.xmlsoap.org/wsdl/" -targetNamespace="http://cloud.netapp.com/" name="CloudStorageService"> -""" - -WSDL_TYPES_CMODE = """<types> -<xs:schema xmlns:na="http://cloud.netapp.com/" -xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0" -targetNamespace="http://cloud.netapp.com/"> - - <xs:element name="ProvisionLun"> - <xs:complexType> - <xs:all> - <xs:element name="Name" type="xs:string"/> - <xs:element name="Size" type="xsd:long"/> - <xs:element name="Metadata" type="na:Metadata" minOccurs="0" - maxOccurs="unbounded"/> - </xs:all> - </xs:complexType> - </xs:element> - <xs:element name="ProvisionLunResult"> - <xs:complexType> - <xs:all> - <xs:element name="Lun" type="na:Lun"/> - </xs:all> - </xs:complexType> - </xs:element> - - <xs:element name="DestroyLun"> - <xs:complexType> - <xs:all> - <xs:element name="Handle" type="xsd:string"/> - </xs:all> - </xs:complexType> - </xs:element> - <xs:element name="DestroyLunResult"> - <xs:complexType> - <xs:all/> - </xs:complexType> - </xs:element> - - <xs:element name="CloneLun"> - <xs:complexType> - <xs:all> - <xs:element name="Handle" type="xsd:string"/> - <xs:element name="NewName" type="xsd:string"/> - <xs:element name="Metadata" type="na:Metadata" minOccurs="0" - maxOccurs="unbounded"/> - </xs:all> - </xs:complexType> - </xs:element> - <xs:element name="CloneLunResult"> - <xs:complexType> - <xs:all> - <xs:element name="Lun" type="na:Lun"/> - </xs:all> - </xs:complexType> - </xs:element> - - <xs:element name="MapLun"> - <xs:complexType> - <xs:all> - <xs:element name="Handle" type="xsd:string"/> - <xs:element name="InitiatorType" type="xsd:string"/> - <xs:element name="InitiatorName" type="xsd:string"/> - </xs:all> - </xs:complexType> - </xs:element> - <xs:element name="MapLunResult"> - <xs:complexType> - <xs:all/> - </xs:complexType> - </xs:element> - - <xs:element name="UnmapLun"> - <xs:complexType> - <xs:all> - <xs:element name="Handle" type="xsd:string"/> - <xs:element name="InitiatorType" type="xsd:string"/> - <xs:element name="InitiatorName" type="xsd:string"/> - </xs:all> - </xs:complexType> - </xs:element> - <xs:element name="UnmapLunResult"> - <xs:complexType> - <xs:all/> - </xs:complexType> - </xs:element> - - <xs:element name="ListLuns"> - <xs:complexType> - <xs:all> - <xs:element name="NameFilter" type="xsd:string" minOccurs="0"/> - </xs:all> - </xs:complexType> - </xs:element> - <xs:element name="ListLunsResult"> - <xs:complexType> - <xs:all> - <xs:element name="Lun" type="na:Lun" minOccurs="0" - maxOccurs="unbounded"/> - </xs:all> - </xs:complexType> - </xs:element> - - <xs:element name="GetLunTargetDetails"> - <xs:complexType> - <xs:all> - <xs:element name="Handle" type="xsd:string"/> - <xs:element name="InitiatorType" type="xsd:string"/> - <xs:element name="InitiatorName" type="xsd:string"/> - </xs:all> - </xs:complexType> - </xs:element> - <xs:element name="GetLunTargetDetailsResult"> - <xs:complexType> - <xs:all> - <xs:element name="TargetDetails" type="na:TargetDetails" - minOccurs="0" maxOccurs="unbounded"/> - </xs:all> - </xs:complexType> - </xs:element> - - <xs:complexType name="Metadata"> - <xs:sequence> - <xs:element name="Key" type="xs:string"/> - <xs:element name="Value" type="xs:string"/> - </xs:sequence> - </xs:complexType> - - <xs:complexType name="Lun"> - <xs:sequence> - <xs:element name="Name" type="xs:string"/> - <xs:element name="Size" type="xs:long"/> - <xs:element name="Handle" type="xs:string"/> - <xs:element name="Metadata" type="na:Metadata" minOccurs="0" - maxOccurs="unbounded"/> - </xs:sequence> - </xs:complexType> - - <xs:complexType name="TargetDetails"> - <xs:sequence> - <xs:element name="Address" type="xs:string"/> - <xs:element name="Port" type="xs:int"/> - <xs:element name="Portal" type="xs:int"/> - <xs:element name="Iqn" type="xs:string"/> - <xs:element name="LunNumber" type="xs:int"/> - </xs:sequence> - </xs:complexType> - - </xs:schema></types>""" - -WSDL_TRAILER_CMODE = """<service name="CloudStorageService"> - <port name="CloudStoragePort" binding="na:CloudStorageBinding"> - <soap:address location="http://hostname:8080/ws/ntapcloud"/> - </port> - </service> -</definitions>""" - -RESPONSE_PREFIX_CMODE = """<?xml version='1.0' encoding='UTF-8'?> -<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> -<soapenv:Body>""" - -RESPONSE_SUFFIX_CMODE = """</soapenv:Body></soapenv:Envelope>""" - -CMODE_APIS = ['ProvisionLun', 'DestroyLun', 'CloneLun', 'MapLun', 'UnmapLun', - 'ListLuns', 'GetLunTargetDetails'] - - -class FakeCMODEServerHandler(BaseHTTPServer.BaseHTTPRequestHandler): - """HTTP handler that fakes enough stuff to allow the driver to run""" - - def do_GET(s): - """Respond to a GET request.""" - if '/ntap_cloud.wsdl' != s.path: - s.send_response(404) - s.end_headers - return - s.send_response(200) - s.send_header("Content-Type", "application/wsdl+xml") - s.end_headers() - out = s.wfile - out.write(WSDL_HEADER_CMODE) - out.write(WSDL_TYPES_CMODE) - for api in CMODE_APIS: - out.write('<message name="%sRequest">' % api) - out.write('<part element="na:%s" name="req"/>' % api) - out.write('</message>') - out.write('<message name="%sResponse">' % api) - out.write('<part element="na:%sResult" name="res"/>' % api) - out.write('</message>') - out.write('<portType name="CloudStorage">') - for api in CMODE_APIS: - out.write('<operation name="%s">' % api) - out.write('<input message="na:%sRequest"/>' % api) - out.write('<output message="na:%sResponse"/>' % api) - out.write('</operation>') - out.write('</portType>') - out.write('<binding name="CloudStorageBinding" ' - 'type="na:CloudStorage">') - out.write('<soap:binding style="document" ' + - 'transport="http://schemas.xmlsoap.org/soap/http"/>') - for api in CMODE_APIS: - out.write('<operation name="%s">' % api) - out.write('<soap:operation soapAction=""/>') - out.write('<input><soap:body use="literal"/></input>') - out.write('<output><soap:body use="literal"/></output>') - out.write('</operation>') - out.write('</binding>') - out.write(WSDL_TRAILER_CMODE) - - def do_POST(s): - """Respond to a POST request.""" - if '/ws/ntapcloud' != s.path: - s.send_response(404) - s.end_headers - return - request_xml = s.rfile.read(int(s.headers['Content-Length'])) - ntap_ns = 'http://cloud.netapp.com/' - nsmap = {'soapenv': 'http://schemas.xmlsoap.org/soap/envelope/', - 'na': ntap_ns} - root = etree.fromstring(request_xml) - - body = root.xpath('/soapenv:Envelope/soapenv:Body', - namespaces=nsmap)[0] - request = body.getchildren()[0] - tag = request.tag - if not tag.startswith('{' + ntap_ns + '}'): - s.send_response(500) - s.end_headers - return - api = tag[(2 + len(ntap_ns)):] - if 'ProvisionLun' == api: - body = """<ns:ProvisionLunResult xmlns:ns= - "http://cloud.netapp.com/"> - <Lun><Name>lun1</Name><Size>20</Size> - <Handle>1d9c006c-a406-42f6-a23f-5ed7a6dc33e3</Handle> - <Metadata><Key>OsType</Key> - <Value>linux</Value></Metadata></Lun> - </ns:ProvisionLunResult>""" - elif 'DestroyLun' == api: - body = """<ns:DestroyLunResult xmlns:ns="http://cloud.netapp.com/" - />""" - elif 'CloneLun' == api: - body = """<ns:CloneLunResult xmlns:ns="http://cloud.netapp.com/"> - <Lun><Name>lun2</Name><Size>2</Size> - <Handle>98ea1791d228453899d422b4611642c3</Handle> - <Metadata><Key>OsType</Key> - <Value>linux</Value></Metadata> - </Lun></ns:CloneLunResult>""" - elif 'MapLun' == api: - body = """<ns1:MapLunResult xmlns:ns="http://cloud.netapp.com/" - />""" - elif 'Unmap' == api: - body = """<ns1:UnmapLunResult xmlns:ns="http://cloud.netapp.com/" - />""" - elif 'ListLuns' == api: - body = """<ns:ListLunsResult xmlns:ns="http://cloud.netapp.com/"> - <Lun> - <Name>lun1</Name> - <Size>20</Size> - <Handle>asdjdnsd</Handle> - </Lun> - </ns:ListLunsResult>""" - elif 'GetLunTargetDetails' == api: - body = """<ns:GetLunTargetDetailsResult - xmlns:ns="http://cloud.netapp.com/"> - <TargetDetail> - <Address>1.2.3.4</Address> - <Port>3260</Port> - <Portal>1000</Portal> - <Iqn>iqn.199208.com.netapp:sn.123456789</Iqn> - <LunNumber>0</LunNumber> - </TargetDetail> - </ns:GetLunTargetDetailsResult>""" - 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_CMODE) - s.wfile.write(body) - s.wfile.write(RESPONSE_SUFFIX_CMODE) - - -class FakeCmodeHTTPConnection(object): - """A fake httplib.HTTPConnection for netapp tests - - Requests made via this connection actually get translated and routed into - the fake Dfm 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 - FakeCMODEServerHandler.address_string = lambda x: '127.0.0.1' - self.app = FakeCMODEServerHandler(sock, '127.0.0.1:8080', 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 NetAppCmodeISCSIDriverTestCase(test.TestCase): - """Test case for NetAppISCSIDriver""" - volume = { - 'name': 'lun1', 'size': 1, '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 - } - snapshot = { - 'name': 'lun2', 'size': 1, 'volume_name': 'lun1', - 'volume_size': 1, 'project_id': 'project' - } - volume_sec = { - 'name': 'vol_snapshot', 'size': 1, '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 - } - - def setUp(self): - super(NetAppCmodeISCSIDriverTestCase, self).setUp() - driver = netapp.NetAppCmodeISCSIDriver() - self.stubs.Set(httplib, 'HTTPConnection', FakeCmodeHTTPConnection) - driver._create_client(wsdl_url='http://localhost:8080/ntap_cloud.wsdl', - login='root', password='password', - hostname='localhost', port=8080, cache=False) - self.driver = driver - - def test_connect(self): - self.driver.check_for_setup_error() - - 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'] - connector = {'initiator': 'init1'} - connection_info = self.driver.initialize_connection(self.volume, - connector) - self.assertEqual(connection_info['driver_volume_type'], 'iscsi') - properties = connection_info['data'] - self.driver.terminate_connection(self.volume, connector) - self.driver.delete_volume(self.volume) |