~ubuntu-branches/ubuntu/raring/nova/raring-proposed

« back to all changes in this revision

Viewing changes to nova/tests/test_netapp.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short, Adam Gandelman, Chuck Short
  • Date: 2012-11-23 09:04:58 UTC
  • mfrom: (1.1.66)
  • Revision ID: package-import@ubuntu.com-20121123090458-91565o7aev1i1h71
Tags: 2013.1~g1-0ubuntu1
[ Adam Gandelman ]
* debian/control: Ensure novaclient is upgraded with nova,
  require python-keystoneclient >= 1:2.9.0. (LP: #1073289)
* debian/patches/{ubuntu/*, rbd-security.patch}: Dropped, applied
  upstream.
* debian/control: Add python-testtools to Build-Depends.

[ Chuck Short ]
* New upstream version.
* Refreshed debian/patches/avoid_setuptools_git_dependency.patch.
* debian/rules: FTBFS if missing binaries.
* debian/nova-scheudler.install: Add missing rabbit-queues and
  nova-rpc-zmq-receiver.
* Remove nova-volume since it doesnt exist anymore, transition to cinder-*.
* debian/rules: install apport hook in the right place.
* debian/patches/ubuntu-show-tests.patch: Display test failures.
* debian/control: Add depends on genisoimage
* debian/control: Suggest guestmount.
* debian/control: Suggest websockify. (LP: #1076442)
* debian/nova.conf: Disable nova-volume service.
* debian/control: Depend on xen-system-* rather than the hypervisor.
* debian/control, debian/mans/nova-conductor.8, debian/nova-conductor.init,
  debian/nova-conductor.install, debian/nova-conductor.logrotate
  debian/nova-conductor.manpages, debian/nova-conductor.postrm
  debian/nova-conductor.upstart.in: Add nova-conductor service.
* debian/control: Add python-fixtures as a build deps.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
 
 
3
 
# Copyright (c) 2012 NetApp, Inc.
4
 
# All Rights Reserved.
5
 
#
6
 
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
7
 
#    not use this file except in compliance with the License. You may obtain
8
 
#    a copy of the License at
9
 
#
10
 
#         http://www.apache.org/licenses/LICENSE-2.0
11
 
#
12
 
#    Unless required by applicable law or agreed to in writing, software
13
 
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
 
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
 
#    License for the specific language governing permissions and limitations
16
 
#    under the License.
17
 
"""
18
 
Tests for NetApp volume driver
19
 
 
20
 
"""
21
 
 
22
 
import BaseHTTPServer
23
 
import httplib
24
 
import StringIO
25
 
 
26
 
from lxml import etree
27
 
 
28
 
from nova.openstack.common import log as logging
29
 
from nova import test
30
 
from nova.volume import netapp
31
 
 
32
 
 
33
 
LOG = logging.getLogger(__name__)
34
 
 
35
 
 
36
 
WSDL_HEADER = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
37
 
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
38
 
    xmlns:na="http://www.netapp.com/management/v1"
39
 
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
40
 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="NetAppDfm"
41
 
    targetNamespace="http://www.netapp.com/management/v1">"""
42
 
 
43
 
WSDL_TYPES = """<types>
44
 
<xsd:schema attributeFormDefault="unqualified" elementFormDefault="qualified"
45
 
    targetNamespace="http://www.netapp.com/management/v1">
46
 
<xsd:element name="ApiProxy">
47
 
    <xsd:complexType>
48
 
        <xsd:all>
49
 
            <xsd:element name="Request" type="na:Request"/>
50
 
            <xsd:element name="Target" type="xsd:string"/>
51
 
            <xsd:element minOccurs="0" name="Timeout" type="xsd:integer"/>
52
 
            <xsd:element minOccurs="0" name="Username" type="xsd:string"/>
53
 
        </xsd:all>
54
 
    </xsd:complexType>
55
 
</xsd:element>
56
 
<xsd:element name="ApiProxyResult">
57
 
    <xsd:complexType>
58
 
        <xsd:all>
59
 
            <xsd:element name="Response" type="na:Response"/>
60
 
        </xsd:all>
61
 
    </xsd:complexType>
62
 
</xsd:element>
63
 
<xsd:element name="DatasetEditBegin">
64
 
    <xsd:complexType>
65
 
        <xsd:all>
66
 
            <xsd:element name="DatasetNameOrId" type="na:ObjNameOrId"/>
67
 
            <xsd:element minOccurs="0" name="Force" type="xsd:boolean"/>
68
 
        </xsd:all>
69
 
    </xsd:complexType>
70
 
</xsd:element>
71
 
<xsd:element name="DatasetEditBeginResult">
72
 
    <xsd:complexType>
73
 
        <xsd:all>
74
 
            <xsd:element name="EditLockId" type="xsd:integer"/>
75
 
        </xsd:all>
76
 
    </xsd:complexType>
77
 
</xsd:element>
78
 
<xsd:element name="DatasetEditCommit">
79
 
    <xsd:complexType>
80
 
        <xsd:all>
81
 
            <xsd:element minOccurs="0" name="AssumeConfirmation"
82
 
                type="xsd:boolean"/>
83
 
            <xsd:element name="EditLockId" type="xsd:integer"/>
84
 
        </xsd:all>
85
 
    </xsd:complexType>
86
 
</xsd:element>
87
 
<xsd:element name="DatasetEditCommitResult">
88
 
    <xsd:complexType>
89
 
        <xsd:all>
90
 
            <xsd:element minOccurs="0" name="IsProvisioningFailure"
91
 
                type="xsd:boolean"/>
92
 
            <xsd:element minOccurs="0" name="JobIds" type="na:ArrayOfJobInfo"/>
93
 
        </xsd:all>
94
 
    </xsd:complexType>
95
 
</xsd:element>
96
 
<xsd:element name="DatasetEditRollback">
97
 
    <xsd:complexType>
98
 
        <xsd:all>
99
 
            <xsd:element name="EditLockId" type="xsd:integer"/>
100
 
        </xsd:all>
101
 
    </xsd:complexType>
102
 
</xsd:element>
103
 
<xsd:element name="DatasetEditRollbackResult">
104
 
    <xsd:complexType/>
105
 
</xsd:element>
106
 
<xsd:element name="DatasetListInfoIterEnd">
107
 
    <xsd:complexType>
108
 
        <xsd:all>
109
 
            <xsd:element name="Tag" type="xsd:string"/>
110
 
        </xsd:all>
111
 
    </xsd:complexType>
112
 
</xsd:element>
113
 
<xsd:element name="DatasetListInfoIterEndResult">
114
 
    <xsd:complexType/>
115
 
</xsd:element>
116
 
<xsd:element name="DatasetListInfoIterNext">
117
 
    <xsd:complexType>
118
 
        <xsd:all>
119
 
            <xsd:element name="Maximum" type="xsd:integer"/>
120
 
            <xsd:element name="Tag" type="xsd:string"/>
121
 
        </xsd:all>
122
 
    </xsd:complexType>
123
 
</xsd:element>
124
 
<xsd:element name="DatasetListInfoIterNextResult">
125
 
    <xsd:complexType>
126
 
        <xsd:all>
127
 
            <xsd:element name="Datasets" type="na:ArrayOfDatasetInfo"/>
128
 
            <xsd:element name="Records" type="xsd:integer"/>
129
 
        </xsd:all>
130
 
    </xsd:complexType>
131
 
</xsd:element>
132
 
<xsd:element name="DatasetListInfoIterStart">
133
 
    <xsd:complexType>
134
 
        <xsd:all>
135
 
            <xsd:element minOccurs="0" name="ObjectNameOrId"
136
 
                type="na:ObjNameOrId"/>
137
 
        </xsd:all>
138
 
    </xsd:complexType>
139
 
</xsd:element>
140
 
<xsd:element name="DatasetListInfoIterStartResult">
141
 
    <xsd:complexType>
142
 
        <xsd:all>
143
 
            <xsd:element name="Records" type="xsd:integer"/>
144
 
            <xsd:element name="Tag" type="xsd:string"/>
145
 
        </xsd:all>
146
 
    </xsd:complexType>
147
 
</xsd:element>
148
 
<xsd:element name="DatasetMemberListInfoIterEnd">
149
 
    <xsd:complexType>
150
 
        <xsd:all>
151
 
            <xsd:element name="Tag" type="xsd:string"/>
152
 
        </xsd:all>
153
 
    </xsd:complexType>
154
 
</xsd:element>
155
 
<xsd:element name="DatasetMemberListInfoIterEndResult">
156
 
    <xsd:complexType/>
157
 
</xsd:element>
158
 
<xsd:element name="DatasetMemberListInfoIterNext">
159
 
    <xsd:complexType>
160
 
        <xsd:all>
161
 
            <xsd:element name="Maximum" type="xsd:integer"/>
162
 
            <xsd:element name="Tag" type="xsd:string"/>
163
 
        </xsd:all>
164
 
    </xsd:complexType>
165
 
</xsd:element>
166
 
<xsd:element name="DatasetMemberListInfoIterNextResult">
167
 
    <xsd:complexType>
168
 
        <xsd:all>
169
 
            <xsd:element name="DatasetMembers"
170
 
                type="na:ArrayOfDatasetMemberInfo"/>
171
 
            <xsd:element name="Records" type="xsd:integer"/>
172
 
        </xsd:all>
173
 
    </xsd:complexType>
174
 
</xsd:element>
175
 
<xsd:element name="DatasetMemberListInfoIterStart">
176
 
    <xsd:complexType>
177
 
        <xsd:all>
178
 
            <xsd:element name="DatasetNameOrId" type="na:ObjNameOrId"/>
179
 
            <xsd:element minOccurs="0" name="IncludeExportsInfo"
180
 
                type="xsd:boolean"/>
181
 
            <xsd:element minOccurs="0" name="IncludeIndirect"
182
 
                type="xsd:boolean"/>
183
 
            <xsd:element minOccurs="0" name="MemberType" type="xsd:string"/>
184
 
        </xsd:all>
185
 
    </xsd:complexType>
186
 
</xsd:element>
187
 
<xsd:element name="DatasetMemberListInfoIterStartResult">
188
 
    <xsd:complexType>
189
 
        <xsd:all>
190
 
            <xsd:element name="Records" type="xsd:integer"/>
191
 
            <xsd:element name="Tag" type="xsd:string"/>
192
 
        </xsd:all>
193
 
    </xsd:complexType>
194
 
</xsd:element>
195
 
<xsd:element name="DatasetProvisionMember">
196
 
    <xsd:complexType>
197
 
        <xsd:all>
198
 
            <xsd:element name="EditLockId" type="xsd:integer"/>
199
 
            <xsd:element name="ProvisionMemberRequestInfo"
200
 
                type="na:ProvisionMemberRequestInfo"/>
201
 
        </xsd:all>
202
 
    </xsd:complexType>
203
 
</xsd:element>
204
 
<xsd:element name="DatasetProvisionMemberResult">
205
 
    <xsd:complexType/>
206
 
</xsd:element>
207
 
<xsd:element name="DatasetRemoveMember">
208
 
    <xsd:complexType>
209
 
        <xsd:all>
210
 
            <xsd:element name="DatasetMemberParameters"
211
 
                type="na:ArrayOfDatasetMemberParameter"/>
212
 
            <xsd:element minOccurs="0" name="Destroy" type="xsd:boolean"/>
213
 
            <xsd:element name="EditLockId" type="xsd:integer"/>
214
 
        </xsd:all>
215
 
    </xsd:complexType>
216
 
</xsd:element>
217
 
<xsd:element name="DatasetRemoveMemberResult">
218
 
    <xsd:complexType/>
219
 
</xsd:element>
220
 
<xsd:element name="DpJobProgressEventListIterEnd">
221
 
    <xsd:complexType>
222
 
        <xsd:all>
223
 
            <xsd:element name="Tag" type="xsd:string"/>
224
 
        </xsd:all>
225
 
    </xsd:complexType>
226
 
</xsd:element>
227
 
<xsd:element name="DpJobProgressEventListIterEndResult">
228
 
    <xsd:complexType/>
229
 
</xsd:element>
230
 
<xsd:element name="DpJobProgressEventListIterNext">
231
 
    <xsd:complexType>
232
 
        <xsd:all>
233
 
            <xsd:element name="Maximum" type="xsd:integer"/>
234
 
            <xsd:element name="Tag" type="xsd:string"/>
235
 
        </xsd:all>
236
 
    </xsd:complexType>
237
 
</xsd:element>
238
 
<xsd:element name="DpJobProgressEventListIterNextResult">
239
 
    <xsd:complexType>
240
 
        <xsd:all>
241
 
            <xsd:element name="ProgressEvents"
242
 
                type="na:ArrayOfDpJobProgressEventInfo"/>
243
 
            <xsd:element name="Records" type="xsd:integer"/>
244
 
        </xsd:all>
245
 
    </xsd:complexType>
246
 
</xsd:element>
247
 
<xsd:element name="DpJobProgressEventListIterStart">
248
 
    <xsd:complexType>
249
 
        <xsd:all>
250
 
            <xsd:element minOccurs="0" name="JobId" type="xsd:integer"/>
251
 
        </xsd:all>
252
 
    </xsd:complexType>
253
 
</xsd:element>
254
 
<xsd:element name="DpJobProgressEventListIterStartResult">
255
 
    <xsd:complexType>
256
 
        <xsd:all>
257
 
            <xsd:element name="Records" type="xsd:integer"/>
258
 
            <xsd:element name="Tag" type="xsd:string"/>
259
 
        </xsd:all>
260
 
    </xsd:complexType>
261
 
</xsd:element>
262
 
<xsd:element name="DfmAbout">
263
 
    <xsd:complexType>
264
 
        <xsd:all>
265
 
            <xsd:element minOccurs="0" name="IncludeDirectorySizeInfo"
266
 
                type="xsd:boolean"/>
267
 
        </xsd:all>
268
 
    </xsd:complexType>
269
 
</xsd:element>
270
 
<xsd:element name="DfmAboutResult">
271
 
    <xsd:complexType>
272
 
        <xsd:all/>
273
 
    </xsd:complexType>
274
 
</xsd:element>
275
 
<xsd:element name="HostListInfoIterEnd">
276
 
    <xsd:complexType>
277
 
        <xsd:all>
278
 
            <xsd:element name="Tag" type="xsd:string"/>
279
 
        </xsd:all>
280
 
    </xsd:complexType>
281
 
</xsd:element>
282
 
<xsd:element name="HostListInfoIterEndResult">
283
 
    <xsd:complexType/>
284
 
</xsd:element>
285
 
<xsd:element name="HostListInfoIterNext">
286
 
    <xsd:complexType>
287
 
        <xsd:all>
288
 
            <xsd:element name="Maximum" type="xsd:integer"/>
289
 
            <xsd:element name="Tag" type="xsd:string"/>
290
 
        </xsd:all>
291
 
    </xsd:complexType>
292
 
</xsd:element>
293
 
<xsd:element name="HostListInfoIterNextResult">
294
 
    <xsd:complexType>
295
 
        <xsd:all>
296
 
            <xsd:element name="Hosts" type="na:ArrayOfHostInfo"/>
297
 
            <xsd:element name="Records" type="xsd:integer"/>
298
 
        </xsd:all>
299
 
    </xsd:complexType>
300
 
</xsd:element>
301
 
<xsd:element name="HostListInfoIterStart">
302
 
    <xsd:complexType>
303
 
        <xsd:all>
304
 
            <xsd:element minOccurs="0" name="ObjectNameOrId"
305
 
                type="na:ObjNameOrId"/>
306
 
        </xsd:all>
307
 
    </xsd:complexType>
308
 
</xsd:element>
309
 
<xsd:element name="HostListInfoIterStartResult">
310
 
    <xsd:complexType>
311
 
        <xsd:all>
312
 
            <xsd:element name="Records" type="xsd:integer"/>
313
 
            <xsd:element name="Tag" type="xsd:string"/>
314
 
        </xsd:all>
315
 
    </xsd:complexType>
316
 
</xsd:element>
317
 
<xsd:element name="LunListInfoIterEnd">
318
 
    <xsd:complexType>
319
 
        <xsd:all>
320
 
            <xsd:element name="Tag" type="xsd:string"/>
321
 
        </xsd:all>
322
 
    </xsd:complexType>
323
 
</xsd:element>
324
 
<xsd:element name="LunListInfoIterEndResult">
325
 
    <xsd:complexType/>
326
 
</xsd:element>
327
 
<xsd:element name="LunListInfoIterNext">
328
 
    <xsd:complexType>
329
 
        <xsd:all>
330
 
            <xsd:element name="Maximum" type="xsd:integer"/>
331
 
            <xsd:element name="Tag" type="xsd:string"/>
332
 
        </xsd:all>
333
 
    </xsd:complexType>
334
 
</xsd:element>
335
 
<xsd:element name="LunListInfoIterNextResult">
336
 
    <xsd:complexType>
337
 
        <xsd:all>
338
 
            <xsd:element name="Luns" type="na:ArrayOfLunInfo"/>
339
 
            <xsd:element name="Records" type="xsd:integer"/>
340
 
        </xsd:all>
341
 
    </xsd:complexType>
342
 
</xsd:element>
343
 
<xsd:element name="LunListInfoIterStart">
344
 
    <xsd:complexType>
345
 
        <xsd:all>
346
 
            <xsd:element minOccurs="0" name="ObjectNameOrId"
347
 
                type="na:ObjNameOrId"/>
348
 
        </xsd:all>
349
 
    </xsd:complexType>
350
 
</xsd:element>
351
 
<xsd:element name="LunListInfoIterStartResult">
352
 
    <xsd:complexType>
353
 
        <xsd:all>
354
 
            <xsd:element name="Records" type="xsd:integer"/>
355
 
            <xsd:element name="Tag" type="xsd:string"/>
356
 
        </xsd:all>
357
 
    </xsd:complexType>
358
 
</xsd:element>
359
 
<xsd:element name="StorageServiceDatasetProvision">
360
 
    <xsd:complexType>
361
 
        <xsd:all>
362
 
            <xsd:element minOccurs="0" name="AssumeConfirmation"
363
 
                type="xsd:boolean"/>
364
 
            <xsd:element name="DatasetName" type="na:ObjName"/>
365
 
            <xsd:element name="StorageServiceNameOrId" type="na:ObjNameOrId"/>
366
 
            <xsd:element minOccurs="0" name="StorageSetDetails"
367
 
                type="na:ArrayOfStorageSetInfo"/>
368
 
        </xsd:all>
369
 
    </xsd:complexType>
370
 
</xsd:element>
371
 
<xsd:element name="StorageServiceDatasetProvisionResult">
372
 
    <xsd:complexType>
373
 
        <xsd:all>
374
 
            <xsd:element minOccurs="0" name="ConformanceAlerts"
375
 
                type="na:ArrayOfConformanceAlert"/>
376
 
            <xsd:element name="DatasetId" type="na:ObjId"/>
377
 
            <xsd:element minOccurs="0" name="DryRunResults"
378
 
                type="na:ArrayOfDryRunResult"/>
379
 
        </xsd:all>
380
 
    </xsd:complexType>
381
 
</xsd:element>
382
 
<xsd:complexType name="ArrayOfDatasetInfo">
383
 
    <xsd:sequence>
384
 
        <xsd:element maxOccurs="unbounded" name="DatasetInfo"
385
 
            type="na:DatasetInfo"/>
386
 
    </xsd:sequence>
387
 
</xsd:complexType>
388
 
<xsd:complexType name="ArrayOfDatasetMemberInfo">
389
 
    <xsd:sequence>
390
 
        <xsd:element maxOccurs="unbounded" name="DatasetMemberInfo"
391
 
            type="na:DatasetMemberInfo"/>
392
 
    </xsd:sequence>
393
 
</xsd:complexType>
394
 
<xsd:complexType name="ArrayOfDatasetMemberParameter">
395
 
    <xsd:sequence>
396
 
        <xsd:element maxOccurs="unbounded" name="DatasetMemberParameter"
397
 
            type="na:DatasetMemberParameter"/>
398
 
    </xsd:sequence>
399
 
</xsd:complexType>
400
 
<xsd:complexType name="ArrayOfDfmMetadataField">
401
 
    <xsd:sequence>
402
 
        <xsd:element maxOccurs="unbounded" name="DfmMetadataField"
403
 
            type="na:DfmMetadataField"/>
404
 
    </xsd:sequence>
405
 
</xsd:complexType>
406
 
<xsd:complexType name="ArrayOfDpJobProgressEventInfo">
407
 
    <xsd:sequence>
408
 
        <xsd:element maxOccurs="unbounded" name="DpJobProgressEventInfo"
409
 
            type="na:DpJobProgressEventInfo"/>
410
 
    </xsd:sequence>
411
 
</xsd:complexType>
412
 
<xsd:complexType name="ArrayOfHostInfo">
413
 
    <xsd:sequence>
414
 
        <xsd:element maxOccurs="unbounded" name="HostInfo" type="na:HostInfo"/>
415
 
    </xsd:sequence>
416
 
</xsd:complexType>
417
 
<xsd:complexType name="ArrayOfJobInfo">
418
 
    <xsd:sequence>
419
 
        <xsd:element maxOccurs="unbounded" name="JobInfo" type="na:JobInfo"/>
420
 
    </xsd:sequence>
421
 
</xsd:complexType>
422
 
<xsd:complexType name="ArrayOfLunInfo">
423
 
    <xsd:sequence>
424
 
        <xsd:element maxOccurs="unbounded" name="LunInfo" type="na:LunInfo"/>
425
 
    </xsd:sequence>
426
 
</xsd:complexType>
427
 
<xsd:complexType name="ArrayOfStorageSetInfo">
428
 
    <xsd:sequence>
429
 
        <xsd:element maxOccurs="unbounded" name="StorageSetInfo"
430
 
            type="na:StorageSetInfo"/>
431
 
    </xsd:sequence>
432
 
</xsd:complexType>
433
 
<xsd:complexType name="DatasetExportInfo">
434
 
    <xsd:all>
435
 
        <xsd:element minOccurs="0" name="DatasetExportProtocol"
436
 
            type="na:DatasetExportProtocol"/>
437
 
        <xsd:element minOccurs="0" name="DatasetLunMappingInfo"
438
 
            type="na:DatasetLunMappingInfo"/>
439
 
    </xsd:all>
440
 
</xsd:complexType>
441
 
<xsd:simpleType name="DatasetExportProtocol">
442
 
    <xsd:restriction base="xsd:string"/>
443
 
</xsd:simpleType>
444
 
<xsd:complexType name="DatasetInfo">
445
 
    <xsd:all>
446
 
        <xsd:element name="DatasetId" type="na:ObjId"/>
447
 
        <xsd:element name="DatasetName" type="na:ObjName"/>
448
 
        <xsd:element name="DatasetMetadata" type="na:ArrayOfDfmMetadataField"/>
449
 
    </xsd:all>
450
 
</xsd:complexType>
451
 
<xsd:complexType name="DatasetLunMappingInfo">
452
 
    <xsd:all>
453
 
        <xsd:element name="IgroupOsType" type="xsd:string"/>
454
 
    </xsd:all>
455
 
</xsd:complexType>
456
 
<xsd:complexType name="DatasetMemberInfo">
457
 
    <xsd:all>
458
 
        <xsd:element name="MemberId" type="na:ObjId"/>
459
 
        <xsd:element name="MemberName" type="na:ObjName"/>
460
 
    </xsd:all>
461
 
</xsd:complexType>
462
 
<xsd:complexType name="DatasetMemberParameter">
463
 
    <xsd:all>
464
 
        <xsd:element name="ObjectNameOrId" type="na:ObjNameOrId"/>
465
 
    </xsd:all>
466
 
</xsd:complexType>
467
 
<xsd:complexType name="DfmMetadataField">
468
 
    <xsd:all>
469
 
        <xsd:element name="FieldName" type="xsd:string"/>
470
 
        <xsd:element name="FieldValue" type="xsd:string"/>
471
 
    </xsd:all>
472
 
</xsd:complexType>
473
 
<xsd:complexType name="DpJobProgressEventInfo">
474
 
    <xsd:all>
475
 
        <xsd:element name="EventStatus" type="na:ObjStatus"/>
476
 
        <xsd:element name="EventType" type="xsd:string"/>
477
 
        <xsd:element minOccurs="0" name="ProgressLunInfo"
478
 
            type="na:ProgressLunInfo"/>
479
 
    </xsd:all>
480
 
</xsd:complexType>
481
 
<xsd:simpleType name="DpPolicyNodeName">
482
 
    <xsd:restriction base="xsd:string"/>
483
 
</xsd:simpleType>
484
 
<xsd:simpleType name="HostId">
485
 
    <xsd:restriction base="xsd:integer"/>
486
 
</xsd:simpleType>
487
 
<xsd:complexType name="HostInfo">
488
 
    <xsd:all>
489
 
        <xsd:element name="HostAddress" type="xsd:string"/>
490
 
        <xsd:element name="HostId" type="na:HostId"/>
491
 
        <xsd:element name="HostName" type="xsd:string"/>
492
 
    </xsd:all>
493
 
</xsd:complexType>
494
 
<xsd:complexType name="JobInfo">
495
 
    <xsd:all>
496
 
        <xsd:element name="JobId" type="xsd:integer"/>
497
 
    </xsd:all>
498
 
</xsd:complexType>
499
 
<xsd:complexType name="LunInfo">
500
 
    <xsd:all>
501
 
        <xsd:element name="HostId" type="na:ObjId"/>
502
 
        <xsd:element name="LunPath" type="na:ObjName"/>
503
 
    </xsd:all>
504
 
</xsd:complexType>
505
 
<xsd:simpleType name="ObjId">
506
 
    <xsd:restriction base="xsd:integer"/>
507
 
</xsd:simpleType>
508
 
<xsd:simpleType name="ObjName">
509
 
    <xsd:restriction base="xsd:string"/>
510
 
</xsd:simpleType>
511
 
<xsd:simpleType name="ObjNameOrId">
512
 
    <xsd:restriction base="xsd:string"/>
513
 
</xsd:simpleType>
514
 
<xsd:simpleType name="ObjStatus">
515
 
    <xsd:restriction base="xsd:string"/>
516
 
</xsd:simpleType>
517
 
<xsd:complexType name="ProgressLunInfo">
518
 
    <xsd:all>
519
 
        <xsd:element name="LunPathId" type="na:ObjId"/>
520
 
        <xsd:element name="LunName" type="na:ObjName"/>
521
 
    </xsd:all>
522
 
</xsd:complexType>
523
 
<xsd:complexType name="ProvisionMemberRequestInfo">
524
 
    <xsd:all>
525
 
        <xsd:element minOccurs="0" name="Description" type="xsd:string"/>
526
 
        <xsd:element minOccurs="0" name="MaximumSnapshotSpace"
527
 
            type="xsd:integer"/>
528
 
        <xsd:element name="Name" type="xsd:string"/>
529
 
        <xsd:element name="Size" type="xsd:integer"/>
530
 
    </xsd:all>
531
 
</xsd:complexType>
532
 
<xsd:complexType name="Request">
533
 
    <xsd:all>
534
 
        <xsd:element minOccurs="0" name="Args">
535
 
            <xsd:complexType>
536
 
                <xsd:sequence>
537
 
                    <xsd:any maxOccurs="unbounded" minOccurs="0"/>
538
 
                </xsd:sequence>
539
 
            </xsd:complexType>
540
 
        </xsd:element>
541
 
        <xsd:element name="Name" type="xsd:string">
542
 
        </xsd:element>
543
 
    </xsd:all>
544
 
</xsd:complexType>
545
 
<xsd:complexType name="Response">
546
 
    <xsd:all>
547
 
        <xsd:element minOccurs="0" name="Errno" type="xsd:integer"/>
548
 
        <xsd:element minOccurs="0" name="Reason" type="xsd:string"/>
549
 
        <xsd:element minOccurs="0" name="Results">
550
 
            <xsd:complexType>
551
 
                <xsd:sequence>
552
 
                    <xsd:any maxOccurs="unbounded" minOccurs="0"/>
553
 
                </xsd:sequence>
554
 
            </xsd:complexType>
555
 
        </xsd:element>
556
 
        <xsd:element name="Status" type="xsd:string"/>
557
 
    </xsd:all>
558
 
</xsd:complexType>
559
 
<xsd:complexType name="StorageSetInfo">
560
 
    <xsd:all>
561
 
        <xsd:element minOccurs="0" name="DatasetExportInfo"
562
 
            type="na:DatasetExportInfo"/>
563
 
        <xsd:element minOccurs="0" name="DpNodeName"
564
 
            type="na:DpPolicyNodeName"/>
565
 
        <xsd:element minOccurs="0" name="ServerNameOrId"
566
 
            type="na:ObjNameOrId"/>
567
 
    </xsd:all>
568
 
</xsd:complexType>
569
 
</xsd:schema></types>"""
570
 
 
571
 
WSDL_TRAILER = """<service name="DfmService">
572
 
<port binding="na:DfmBinding" name="DfmPort">
573
 
<soap:address location="https://HOST_NAME:8488/apis/soap/v1"/>
574
 
</port></service></definitions>"""
575
 
 
576
 
RESPONSE_PREFIX = """<?xml version="1.0" encoding="UTF-8"?>
577
 
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
578
 
    xmlns:na="http://www.netapp.com/management/v1"><env:Header/><env:Body>"""
579
 
 
580
 
RESPONSE_SUFFIX = """</env:Body></env:Envelope>"""
581
 
 
582
 
APIS = ['ApiProxy', 'DatasetListInfoIterStart', 'DatasetListInfoIterNext',
583
 
    'DatasetListInfoIterEnd', 'DatasetEditBegin', 'DatasetEditCommit',
584
 
    'DatasetProvisionMember', 'DatasetRemoveMember', 'DfmAbout',
585
 
    'DpJobProgressEventListIterStart', 'DpJobProgressEventListIterNext',
586
 
    'DpJobProgressEventListIterEnd', 'DatasetMemberListInfoIterStart',
587
 
    'DatasetMemberListInfoIterNext', 'DatasetMemberListInfoIterEnd',
588
 
    'HostListInfoIterStart', 'HostListInfoIterNext', 'HostListInfoIterEnd',
589
 
    'LunListInfoIterStart', 'LunListInfoIterNext', 'LunListInfoIterEnd',
590
 
    'StorageServiceDatasetProvision']
591
 
 
592
 
iter_count = 0
593
 
iter_table = {}
594
 
 
595
 
 
596
 
class FakeDfmServerHandler(BaseHTTPServer.BaseHTTPRequestHandler):
597
 
    """HTTP handler that fakes enough stuff to allow the driver to run"""
598
 
 
599
 
    def do_GET(s):
600
 
        """Respond to a GET request."""
601
 
        if '/dfm.wsdl' != s.path:
602
 
            s.send_response(404)
603
 
            s.end_headers
604
 
            return
605
 
        s.send_response(200)
606
 
        s.send_header("Content-Type", "application/wsdl+xml")
607
 
        s.end_headers()
608
 
        out = s.wfile
609
 
        out.write(WSDL_HEADER)
610
 
        out.write(WSDL_TYPES)
611
 
        for api in APIS:
612
 
            out.write('<message name="%sRequest">' % api)
613
 
            out.write('<part element="na:%s" name="parameters"/>' % api)
614
 
            out.write('</message>')
615
 
            out.write('<message name="%sResponse">' % api)
616
 
            out.write('<part element="na:%sResult" name="results"/>' % api)
617
 
            out.write('</message>')
618
 
        out.write('<portType name="DfmInterface">')
619
 
        for api in APIS:
620
 
            out.write('<operation name="%s">' % api)
621
 
            out.write('<input message="na:%sRequest"/>' % api)
622
 
            out.write('<output message="na:%sResponse"/>' % api)
623
 
            out.write('</operation>')
624
 
        out.write('</portType>')
625
 
        out.write('<binding name="DfmBinding" type="na:DfmInterface">')
626
 
        out.write('<soap:binding style="document" ' +
627
 
            'transport="http://schemas.xmlsoap.org/soap/http"/>')
628
 
        for api in APIS:
629
 
            out.write('<operation name="%s">' % api)
630
 
            out.write('<soap:operation soapAction="urn:%s"/>' % api)
631
 
            out.write('<input><soap:body use="literal"/></input>')
632
 
            out.write('<output><soap:body use="literal"/></output>')
633
 
            out.write('</operation>')
634
 
        out.write('</binding>')
635
 
        out.write(WSDL_TRAILER)
636
 
 
637
 
    def do_POST(s):
638
 
        """Respond to a POST request."""
639
 
        if '/apis/soap/v1' != s.path:
640
 
            s.send_response(404)
641
 
            s.end_headers
642
 
            return
643
 
        request_xml = s.rfile.read(int(s.headers['Content-Length']))
644
 
        ntap_ns = 'http://www.netapp.com/management/v1'
645
 
        nsmap = {'env': 'http://schemas.xmlsoap.org/soap/envelope/',
646
 
            'na': ntap_ns}
647
 
        root = etree.fromstring(request_xml)
648
 
 
649
 
        body = root.xpath('/env:Envelope/env:Body', namespaces=nsmap)[0]
650
 
        request = body.getchildren()[0]
651
 
        tag = request.tag
652
 
        if not tag.startswith('{' + ntap_ns + '}'):
653
 
            s.send_response(500)
654
 
            s.end_headers
655
 
            return
656
 
        api = tag[(2 + len(ntap_ns)):]
657
 
        global iter_count
658
 
        global iter_table
659
 
        if 'DatasetListInfoIterStart' == api:
660
 
            iter_name = 'dataset_%s' % iter_count
661
 
            iter_count = iter_count + 1
662
 
            iter_table[iter_name] = 0
663
 
            body = """<na:DatasetListInfoIterStartResult>
664
 
                    <na:Records>1</na:Records>
665
 
                    <na:Tag>%s</na:Tag>
666
 
                </na:DatasetListInfoIterStartResult>""" % iter_name
667
 
        elif 'DatasetListInfoIterNext' == api:
668
 
            tags = body.xpath('na:DatasetListInfoIterNext/na:Tag',
669
 
                              namespaces=nsmap)
670
 
            iter_name = tags[0].text
671
 
            if iter_table[iter_name]:
672
 
                body = """<na:DatasetListInfoIterNextResult>
673
 
                        <na:Datasets></na:Datasets>
674
 
                        <na:Records>0</na:Records>
675
 
                    </na:DatasetListInfoIterNextResult>"""
676
 
            else:
677
 
                iter_table[iter_name] = 1
678
 
                body = """<na:DatasetListInfoIterNextResult>
679
 
                        <na:Datasets>
680
 
                            <na:DatasetInfo>
681
 
                                <na:DatasetId>0</na:DatasetId>
682
 
                                <na:DatasetMetadata>
683
 
                                    <na:DfmMetadataField>
684
 
                                  <na:FieldName>OpenStackProject</na:FieldName>
685
 
                                        <na:FieldValue>testproj</na:FieldValue>
686
 
                                    </na:DfmMetadataField>
687
 
                                    <na:DfmMetadataField>
688
 
                                  <na:FieldName>OpenStackVolType</na:FieldName>
689
 
                                        <na:FieldValue></na:FieldValue>
690
 
                                    </na:DfmMetadataField>
691
 
                                </na:DatasetMetadata>
692
 
                            <na:DatasetName>OpenStack_testproj</na:DatasetName>
693
 
                            </na:DatasetInfo>
694
 
                        </na:Datasets>
695
 
                        <na:Records>1</na:Records>
696
 
                    </na:DatasetListInfoIterNextResult>"""
697
 
        elif 'DatasetListInfoIterEnd' == api:
698
 
            body = """<na:DatasetListInfoIterEndResult/>"""
699
 
        elif 'DatasetEditBegin' == api:
700
 
            body = """<na:DatasetEditBeginResult>
701
 
                    <na:EditLockId>0</na:EditLockId>
702
 
                </na:DatasetEditBeginResult>"""
703
 
        elif 'DatasetEditCommit' == api:
704
 
            body = """<na:DatasetEditCommitResult>
705
 
                    <na:IsProvisioningFailure>false</na:IsProvisioningFailure>
706
 
                    <na:JobIds>
707
 
                        <na:JobInfo>
708
 
                            <na:JobId>0</na:JobId>
709
 
                        </na:JobInfo>
710
 
                    </na:JobIds>
711
 
                </na:DatasetEditCommitResult>"""
712
 
        elif 'DatasetProvisionMember' == api:
713
 
            body = """<na:DatasetProvisionMemberResult/>"""
714
 
        elif 'DatasetRemoveMember' == api:
715
 
            body = """<na:DatasetRemoveMemberResult/>"""
716
 
        elif 'DfmAbout' == api:
717
 
            body = """<na:DfmAboutResult/>"""
718
 
        elif 'DpJobProgressEventListIterStart' == api:
719
 
            iter_name = 'dpjobprogress_%s' % iter_count
720
 
            iter_count = iter_count + 1
721
 
            iter_table[iter_name] = 0
722
 
            body = """<na:DpJobProgressEventListIterStartResult>
723
 
                    <na:Records>2</na:Records>
724
 
                    <na:Tag>%s</na:Tag>
725
 
                </na:DpJobProgressEventListIterStartResult>""" % iter_name
726
 
        elif 'DpJobProgressEventListIterNext' == api:
727
 
            tags = body.xpath('na:DpJobProgressEventListIterNext/na:Tag',
728
 
                              namespaces=nsmap)
729
 
            iter_name = tags[0].text
730
 
            if iter_table[iter_name]:
731
 
                body = """<na:DpJobProgressEventListIterNextResult/>"""
732
 
            else:
733
 
                iter_table[iter_name] = 1
734
 
                name = ('filer:/OpenStack_testproj/volume-00000001/'
735
 
                        'volume-00000001')
736
 
                body = """<na:DpJobProgressEventListIterNextResult>
737
 
                        <na:ProgressEvents>
738
 
                            <na:DpJobProgressEventInfo>
739
 
                                <na:EventStatus>normal</na:EventStatus>
740
 
                                <na:EventType>lun-create</na:EventType>
741
 
                                <na:ProgressLunInfo>
742
 
                                    <na:LunPathId>0</na:LunPathId>
743
 
                                    <na:LunName>%s</na:LunName>
744
 
                                 </na:ProgressLunInfo>
745
 
                            </na:DpJobProgressEventInfo>
746
 
                            <na:DpJobProgressEventInfo>
747
 
                                <na:EventStatus>normal</na:EventStatus>
748
 
                                <na:EventType>job-end</na:EventType>
749
 
                            </na:DpJobProgressEventInfo>
750
 
                        </na:ProgressEvents>
751
 
                        <na:Records>2</na:Records>
752
 
                    </na:DpJobProgressEventListIterNextResult>""" % name
753
 
        elif 'DpJobProgressEventListIterEnd' == api:
754
 
            body = """<na:DpJobProgressEventListIterEndResult/>"""
755
 
        elif 'DatasetMemberListInfoIterStart' == api:
756
 
            iter_name = 'datasetmember_%s' % iter_count
757
 
            iter_count = iter_count + 1
758
 
            iter_table[iter_name] = 0
759
 
            body = """<na:DatasetMemberListInfoIterStartResult>
760
 
                    <na:Records>1</na:Records>
761
 
                    <na:Tag>%s</na:Tag>
762
 
                </na:DatasetMemberListInfoIterStartResult>""" % iter_name
763
 
        elif 'DatasetMemberListInfoIterNext' == api:
764
 
            tags = body.xpath('na:DatasetMemberListInfoIterNext/na:Tag',
765
 
                              namespaces=nsmap)
766
 
            iter_name = tags[0].text
767
 
            if iter_table[iter_name]:
768
 
                body = """<na:DatasetMemberListInfoIterNextResult>
769
 
                        <na:DatasetMembers></na:DatasetMembers>
770
 
                        <na:Records>0</na:Records>
771
 
                    </na:DatasetMemberListInfoIterNextResult>"""
772
 
            else:
773
 
                iter_table[iter_name] = 1
774
 
                name = ('filer:/OpenStack_testproj/volume-00000001/'
775
 
                        'volume-00000001')
776
 
                body = """<na:DatasetMemberListInfoIterNextResult>
777
 
                        <na:DatasetMembers>
778
 
                            <na:DatasetMemberInfo>
779
 
                                <na:MemberId>0</na:MemberId>
780
 
                                <na:MemberName>%s</na:MemberName>
781
 
                            </na:DatasetMemberInfo>
782
 
                        </na:DatasetMembers>
783
 
                        <na:Records>1</na:Records>
784
 
                    </na:DatasetMemberListInfoIterNextResult>""" % name
785
 
        elif 'DatasetMemberListInfoIterEnd' == api:
786
 
            body = """<na:DatasetMemberListInfoIterEndResult/>"""
787
 
        elif 'HostListInfoIterStart' == api:
788
 
            body = """<na:HostListInfoIterStartResult>
789
 
                    <na:Records>1</na:Records>
790
 
                    <na:Tag>host</na:Tag>
791
 
                </na:HostListInfoIterStartResult>"""
792
 
        elif 'HostListInfoIterNext' == api:
793
 
            body = """<na:HostListInfoIterNextResult>
794
 
                    <na:Hosts>
795
 
                        <na:HostInfo>
796
 
                            <na:HostAddress>1.2.3.4</na:HostAddress>
797
 
                            <na:HostId>0</na:HostId>
798
 
                            <na:HostName>filer</na:HostName>
799
 
                        </na:HostInfo>
800
 
                    </na:Hosts>
801
 
                    <na:Records>1</na:Records>
802
 
                </na:HostListInfoIterNextResult>"""
803
 
        elif 'HostListInfoIterEnd' == api:
804
 
            body = """<na:HostListInfoIterEndResult/>"""
805
 
        elif 'LunListInfoIterStart' == api:
806
 
            body = """<na:LunListInfoIterStartResult>
807
 
                    <na:Records>1</na:Records>
808
 
                    <na:Tag>lun</na:Tag>
809
 
                </na:LunListInfoIterStartResult>"""
810
 
        elif 'LunListInfoIterNext' == api:
811
 
            path = 'OpenStack_testproj/volume-00000001/volume-00000001'
812
 
            body = """<na:LunListInfoIterNextResult>
813
 
                    <na:Luns>
814
 
                        <na:LunInfo>
815
 
                            <na:HostId>0</na:HostId>
816
 
                            <na:LunPath>%s</na:LunPath>
817
 
                        </na:LunInfo>
818
 
                    </na:Luns>
819
 
                    <na:Records>1</na:Records>
820
 
                </na:LunListInfoIterNextResult>""" % path
821
 
        elif 'LunListInfoIterEnd' == api:
822
 
            body = """<na:LunListInfoIterEndResult/>"""
823
 
        elif 'ApiProxy' == api:
824
 
            names = body.xpath('na:ApiProxy/na:Request/na:Name',
825
 
                               namespaces=nsmap)
826
 
            proxy = names[0].text
827
 
            if 'igroup-list-info' == proxy:
828
 
                igroup = 'openstack-iqn.1993-08.org.debian:01:23456789'
829
 
                initiator = 'iqn.1993-08.org.debian:01:23456789'
830
 
                proxy_body = """<initiator-groups>
831
 
                        <initiator-group-info>
832
 
                            <initiator-group-name>%s</initiator-group-name>
833
 
                            <initiator-group-type>iscsi</initiator-group-type>
834
 
                       <initiator-group-os-type>linux</initiator-group-os-type>
835
 
                            <initiators>
836
 
                                <initiator-info>
837
 
                                    <initiator-name>%s</initiator-name>
838
 
                                </initiator-info>
839
 
                            </initiators>
840
 
                        </initiator-group-info>
841
 
                    </initiator-groups>""" % (igroup, initiator)
842
 
            elif 'igroup-create' == proxy:
843
 
                proxy_body = ''
844
 
            elif 'igroup-add' == proxy:
845
 
                proxy_body = ''
846
 
            elif 'lun-map-list-info' == proxy:
847
 
                proxy_body = '<initiator-groups/>'
848
 
            elif 'lun-map' == proxy:
849
 
                proxy_body = '<lun-id-assigned>0</lun-id-assigned>'
850
 
            elif 'lun-unmap' == proxy:
851
 
                proxy_body = ''
852
 
            elif 'iscsi-portal-list-info' == proxy:
853
 
                proxy_body = """<iscsi-portal-list-entries>
854
 
                        <iscsi-portal-list-entry-info>
855
 
                            <ip-address>1.2.3.4</ip-address>
856
 
                            <ip-port>3260</ip-port>
857
 
                            <tpgroup-tag>1000</tpgroup-tag>
858
 
                        </iscsi-portal-list-entry-info>
859
 
                    </iscsi-portal-list-entries>"""
860
 
            elif 'iscsi-node-get-name' == proxy:
861
 
                target = 'iqn.1992-08.com.netapp:sn.111111111'
862
 
                proxy_body = '<node-name>%s</node-name>' % target
863
 
            else:
864
 
                # Unknown proxy API
865
 
                s.send_response(500)
866
 
                s.end_headers
867
 
                return
868
 
            api = api + ':' + proxy
869
 
            proxy_header = '<na:ApiProxyResult><na:Response><na:Results>'
870
 
            proxy_trailer = """</na:Results><na:Status>passed</na:Status>
871
 
                </na:Response></na:ApiProxyResult>"""
872
 
            body = proxy_header + proxy_body + proxy_trailer
873
 
        else:
874
 
            # Unknown API
875
 
            s.send_response(500)
876
 
            s.end_headers
877
 
            return
878
 
        s.send_response(200)
879
 
        s.send_header("Content-Type", "text/xml; charset=utf-8")
880
 
        s.end_headers()
881
 
        s.wfile.write(RESPONSE_PREFIX)
882
 
        s.wfile.write(body)
883
 
        s.wfile.write(RESPONSE_SUFFIX)
884
 
 
885
 
 
886
 
class FakeHttplibSocket(object):
887
 
    """A fake socket implementation for httplib.HTTPResponse"""
888
 
    def __init__(self, value):
889
 
        self._rbuffer = StringIO.StringIO(value)
890
 
        self._wbuffer = StringIO.StringIO('')
891
 
        oldclose = self._wbuffer.close
892
 
 
893
 
        def newclose():
894
 
            self.result = self._wbuffer.getvalue()
895
 
            oldclose()
896
 
        self._wbuffer.close = newclose
897
 
 
898
 
    def makefile(self, mode, _other):
899
 
        """Returns the socket's internal buffer"""
900
 
        if mode == 'r' or mode == 'rb':
901
 
            return self._rbuffer
902
 
        if mode == 'w' or mode == 'wb':
903
 
            return self._wbuffer
904
 
 
905
 
 
906
 
class FakeHTTPConnection(object):
907
 
    """A fake httplib.HTTPConnection for netapp tests
908
 
 
909
 
    Requests made via this connection actually get translated and routed into
910
 
    the fake Dfm handler above, we then turn the response into
911
 
    the httplib.HTTPResponse that the caller expects.
912
 
    """
913
 
    def __init__(self, host, timeout=None):
914
 
        self.host = host
915
 
 
916
 
    def request(self, method, path, data=None, headers=None):
917
 
        if not headers:
918
 
            headers = {}
919
 
        req_str = '%s %s HTTP/1.1\r\n' % (method, path)
920
 
        for key, value in headers.iteritems():
921
 
            req_str += "%s: %s\r\n" % (key, value)
922
 
        if data:
923
 
            req_str += '\r\n%s' % data
924
 
 
925
 
        # NOTE(vish): normally the http transport normailizes from unicode
926
 
        sock = FakeHttplibSocket(req_str.decode("latin-1").encode("utf-8"))
927
 
        # NOTE(vish): stop the server from trying to look up address from
928
 
        #             the fake socket
929
 
        FakeDfmServerHandler.address_string = lambda x: '127.0.0.1'
930
 
        self.app = FakeDfmServerHandler(sock, '127.0.0.1:8088', None)
931
 
 
932
 
        self.sock = FakeHttplibSocket(sock.result)
933
 
        self.http_response = httplib.HTTPResponse(self.sock)
934
 
 
935
 
    def set_debuglevel(self, level):
936
 
        pass
937
 
 
938
 
    def getresponse(self):
939
 
        self.http_response.begin()
940
 
        return self.http_response
941
 
 
942
 
    def getresponsebody(self):
943
 
        return self.sock.result
944
 
 
945
 
 
946
 
class NetAppDriverTestCase(test.TestCase):
947
 
    """Test case for NetAppISCSIDriver"""
948
 
    STORAGE_SERVICE = 'Openstack Service'
949
 
    STORAGE_SERVICE_PREFIX = 'Openstack Service-'
950
 
    PROJECT_ID = 'testproj'
951
 
    VOLUME_NAME = 'volume-00000001'
952
 
    VOLUME_TYPE = ''
953
 
    VOLUME_SIZE = 2147483648L  # 2 GB
954
 
    INITIATOR = 'iqn.1993-08.org.debian:01:23456789'
955
 
 
956
 
    def setUp(self):
957
 
        super(NetAppDriverTestCase, self).setUp()
958
 
        driver = netapp.NetAppISCSIDriver()
959
 
        self.stubs.Set(httplib, 'HTTPConnection', FakeHTTPConnection)
960
 
        driver._create_client(wsdl_url='http://localhost:8088/dfm.wsdl',
961
 
                              login='root', password='password',
962
 
                              hostname='localhost', port=8088, cache=False)
963
 
        driver._set_storage_service(self.STORAGE_SERVICE)
964
 
        driver._set_storage_service_prefix(self.STORAGE_SERVICE_PREFIX)
965
 
        driver._set_vfiler('')
966
 
        self.driver = driver
967
 
 
968
 
    def test_connect(self):
969
 
        self.driver.check_for_setup_error()
970
 
 
971
 
    def test_create_destroy(self):
972
 
        self.driver._discover_luns()
973
 
        self.driver._provision(self.VOLUME_NAME, None, self.PROJECT_ID,
974
 
                               self.VOLUME_TYPE, self.VOLUME_SIZE)
975
 
        self.driver._remove_destroy(self.VOLUME_NAME, self.PROJECT_ID)
976
 
 
977
 
    def test_map_unmap(self):
978
 
        self.driver._discover_luns()
979
 
        self.driver._provision(self.VOLUME_NAME, None, self.PROJECT_ID,
980
 
                               self.VOLUME_TYPE, self.VOLUME_SIZE)
981
 
        volume = {'name': self.VOLUME_NAME, 'project_id': self.PROJECT_ID,
982
 
            'id': 0, 'provider_auth': None}
983
 
        updates = self.driver._get_export(volume)
984
 
        self.assertTrue(updates['provider_location'])
985
 
        volume['provider_location'] = updates['provider_location']
986
 
        connector = {'initiator': self.INITIATOR}
987
 
        connection_info = self.driver.initialize_connection(volume, connector)
988
 
        self.assertEqual(connection_info['driver_volume_type'], 'iscsi')
989
 
        properties = connection_info['data']
990
 
        self.driver.terminate_connection(volume, connector)
991
 
        self.driver._remove_destroy(self.VOLUME_NAME, self.PROJECT_ID)
992
 
 
993
 
 
994
 
WSDL_HEADER_CMODE = """<?xml version="1.0" encoding="UTF-8"?>
995
 
<definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
996
 
 xmlns:na="http://cloud.netapp.com/"
997
 
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
998
 
xmlns="http://schemas.xmlsoap.org/wsdl/"
999
 
targetNamespace="http://cloud.netapp.com/" name="CloudStorageService">
1000
 
"""
1001
 
 
1002
 
WSDL_TYPES_CMODE = """<types>
1003
 
<xs:schema xmlns:na="http://cloud.netapp.com/"
1004
 
xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0"
1005
 
targetNamespace="http://cloud.netapp.com/">
1006
 
 
1007
 
      <xs:element name="ProvisionLun">
1008
 
        <xs:complexType>
1009
 
          <xs:all>
1010
 
            <xs:element name="Name" type="xs:string"/>
1011
 
            <xs:element name="Size" type="xsd:long"/>
1012
 
            <xs:element name="Metadata" type="na:Metadata" minOccurs="0"
1013
 
              maxOccurs="unbounded"/>
1014
 
          </xs:all>
1015
 
        </xs:complexType>
1016
 
      </xs:element>
1017
 
      <xs:element name="ProvisionLunResult">
1018
 
        <xs:complexType>
1019
 
          <xs:all>
1020
 
            <xs:element name="Lun" type="na:Lun"/>
1021
 
          </xs:all>
1022
 
        </xs:complexType>
1023
 
      </xs:element>
1024
 
 
1025
 
      <xs:element name="DestroyLun">
1026
 
        <xs:complexType>
1027
 
          <xs:all>
1028
 
            <xs:element name="Handle" type="xsd:string"/>
1029
 
          </xs:all>
1030
 
        </xs:complexType>
1031
 
      </xs:element>
1032
 
      <xs:element name="DestroyLunResult">
1033
 
        <xs:complexType>
1034
 
          <xs:all/>
1035
 
        </xs:complexType>
1036
 
      </xs:element>
1037
 
 
1038
 
      <xs:element name="CloneLun">
1039
 
        <xs:complexType>
1040
 
          <xs:all>
1041
 
            <xs:element name="Handle" type="xsd:string"/>
1042
 
            <xs:element name="NewName" type="xsd:string"/>
1043
 
            <xs:element name="Metadata" type="na:Metadata" minOccurs="0"
1044
 
              maxOccurs="unbounded"/>
1045
 
          </xs:all>
1046
 
        </xs:complexType>
1047
 
      </xs:element>
1048
 
      <xs:element name="CloneLunResult">
1049
 
        <xs:complexType>
1050
 
          <xs:all>
1051
 
            <xs:element name="Lun" type="na:Lun"/>
1052
 
          </xs:all>
1053
 
        </xs:complexType>
1054
 
      </xs:element>
1055
 
 
1056
 
      <xs:element name="MapLun">
1057
 
        <xs:complexType>
1058
 
          <xs:all>
1059
 
            <xs:element name="Handle" type="xsd:string"/>
1060
 
            <xs:element name="InitiatorType" type="xsd:string"/>
1061
 
            <xs:element name="InitiatorName" type="xsd:string"/>
1062
 
          </xs:all>
1063
 
        </xs:complexType>
1064
 
      </xs:element>
1065
 
      <xs:element name="MapLunResult">
1066
 
        <xs:complexType>
1067
 
          <xs:all/>
1068
 
        </xs:complexType>
1069
 
      </xs:element>
1070
 
 
1071
 
      <xs:element name="UnmapLun">
1072
 
        <xs:complexType>
1073
 
          <xs:all>
1074
 
            <xs:element name="Handle" type="xsd:string"/>
1075
 
            <xs:element name="InitiatorType" type="xsd:string"/>
1076
 
            <xs:element name="InitiatorName" type="xsd:string"/>
1077
 
          </xs:all>
1078
 
        </xs:complexType>
1079
 
      </xs:element>
1080
 
      <xs:element name="UnmapLunResult">
1081
 
        <xs:complexType>
1082
 
          <xs:all/>
1083
 
        </xs:complexType>
1084
 
      </xs:element>
1085
 
 
1086
 
      <xs:element name="ListLuns">
1087
 
        <xs:complexType>
1088
 
          <xs:all>
1089
 
            <xs:element name="NameFilter" type="xsd:string" minOccurs="0"/>
1090
 
          </xs:all>
1091
 
        </xs:complexType>
1092
 
      </xs:element>
1093
 
      <xs:element name="ListLunsResult">
1094
 
        <xs:complexType>
1095
 
          <xs:all>
1096
 
            <xs:element name="Lun" type="na:Lun" minOccurs="0"
1097
 
              maxOccurs="unbounded"/>
1098
 
          </xs:all>
1099
 
        </xs:complexType>
1100
 
      </xs:element>
1101
 
 
1102
 
      <xs:element name="GetLunTargetDetails">
1103
 
        <xs:complexType>
1104
 
          <xs:all>
1105
 
            <xs:element name="Handle" type="xsd:string"/>
1106
 
            <xs:element name="InitiatorType" type="xsd:string"/>
1107
 
            <xs:element name="InitiatorName" type="xsd:string"/>
1108
 
          </xs:all>
1109
 
        </xs:complexType>
1110
 
      </xs:element>
1111
 
      <xs:element name="GetLunTargetDetailsResult">
1112
 
        <xs:complexType>
1113
 
          <xs:all>
1114
 
            <xs:element name="TargetDetails" type="na:TargetDetails"
1115
 
              minOccurs="0" maxOccurs="unbounded"/>
1116
 
          </xs:all>
1117
 
        </xs:complexType>
1118
 
      </xs:element>
1119
 
 
1120
 
      <xs:complexType name="Metadata">
1121
 
        <xs:sequence>
1122
 
          <xs:element name="Key" type="xs:string"/>
1123
 
          <xs:element name="Value" type="xs:string"/>
1124
 
        </xs:sequence>
1125
 
      </xs:complexType>
1126
 
 
1127
 
      <xs:complexType name="Lun">
1128
 
        <xs:sequence>
1129
 
          <xs:element name="Name" type="xs:string"/>
1130
 
          <xs:element name="Size" type="xs:long"/>
1131
 
          <xs:element name="Handle" type="xs:string"/>
1132
 
          <xs:element name="Metadata" type="na:Metadata" minOccurs="0"
1133
 
            maxOccurs="unbounded"/>
1134
 
        </xs:sequence>
1135
 
      </xs:complexType>
1136
 
 
1137
 
      <xs:complexType name="TargetDetails">
1138
 
        <xs:sequence>
1139
 
          <xs:element name="Address" type="xs:string"/>
1140
 
          <xs:element name="Port" type="xs:int"/>
1141
 
          <xs:element name="Portal" type="xs:int"/>
1142
 
          <xs:element name="Iqn" type="xs:string"/>
1143
 
          <xs:element name="LunNumber" type="xs:int"/>
1144
 
        </xs:sequence>
1145
 
      </xs:complexType>
1146
 
 
1147
 
    </xs:schema></types>"""
1148
 
 
1149
 
WSDL_TRAILER_CMODE = """<service name="CloudStorageService">
1150
 
    <port name="CloudStoragePort" binding="na:CloudStorageBinding">
1151
 
      <soap:address location="http://hostname:8080/ws/ntapcloud"/>
1152
 
    </port>
1153
 
  </service>
1154
 
</definitions>"""
1155
 
 
1156
 
RESPONSE_PREFIX_CMODE = """<?xml version='1.0' encoding='UTF-8'?>
1157
 
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
1158
 
<soapenv:Body>"""
1159
 
 
1160
 
RESPONSE_SUFFIX_CMODE = """</soapenv:Body></soapenv:Envelope>"""
1161
 
 
1162
 
CMODE_APIS = ['ProvisionLun', 'DestroyLun', 'CloneLun', 'MapLun', 'UnmapLun',
1163
 
              'ListLuns', 'GetLunTargetDetails']
1164
 
 
1165
 
 
1166
 
class FakeCMODEServerHandler(BaseHTTPServer.BaseHTTPRequestHandler):
1167
 
    """HTTP handler that fakes enough stuff to allow the driver to run"""
1168
 
 
1169
 
    def do_GET(s):
1170
 
        """Respond to a GET request."""
1171
 
        if '/ntap_cloud.wsdl' != s.path:
1172
 
            s.send_response(404)
1173
 
            s.end_headers
1174
 
            return
1175
 
        s.send_response(200)
1176
 
        s.send_header("Content-Type", "application/wsdl+xml")
1177
 
        s.end_headers()
1178
 
        out = s.wfile
1179
 
        out.write(WSDL_HEADER_CMODE)
1180
 
        out.write(WSDL_TYPES_CMODE)
1181
 
        for api in CMODE_APIS:
1182
 
            out.write('<message name="%sRequest">' % api)
1183
 
            out.write('<part element="na:%s" name="req"/>' % api)
1184
 
            out.write('</message>')
1185
 
            out.write('<message name="%sResponse">' % api)
1186
 
            out.write('<part element="na:%sResult" name="res"/>' % api)
1187
 
            out.write('</message>')
1188
 
        out.write('<portType name="CloudStorage">')
1189
 
        for api in CMODE_APIS:
1190
 
            out.write('<operation name="%s">' % api)
1191
 
            out.write('<input message="na:%sRequest"/>' % api)
1192
 
            out.write('<output message="na:%sResponse"/>' % api)
1193
 
            out.write('</operation>')
1194
 
        out.write('</portType>')
1195
 
        out.write('<binding name="CloudStorageBinding" '
1196
 
                  'type="na:CloudStorage">')
1197
 
        out.write('<soap:binding style="document" ' +
1198
 
            'transport="http://schemas.xmlsoap.org/soap/http"/>')
1199
 
        for api in CMODE_APIS:
1200
 
            out.write('<operation name="%s">' % api)
1201
 
            out.write('<soap:operation soapAction=""/>')
1202
 
            out.write('<input><soap:body use="literal"/></input>')
1203
 
            out.write('<output><soap:body use="literal"/></output>')
1204
 
            out.write('</operation>')
1205
 
        out.write('</binding>')
1206
 
        out.write(WSDL_TRAILER_CMODE)
1207
 
 
1208
 
    def do_POST(s):
1209
 
        """Respond to a POST request."""
1210
 
        if '/ws/ntapcloud' != s.path:
1211
 
            s.send_response(404)
1212
 
            s.end_headers
1213
 
            return
1214
 
        request_xml = s.rfile.read(int(s.headers['Content-Length']))
1215
 
        ntap_ns = 'http://cloud.netapp.com/'
1216
 
        nsmap = {'soapenv': 'http://schemas.xmlsoap.org/soap/envelope/',
1217
 
            'na': ntap_ns}
1218
 
        root = etree.fromstring(request_xml)
1219
 
 
1220
 
        body = root.xpath('/soapenv:Envelope/soapenv:Body',
1221
 
                          namespaces=nsmap)[0]
1222
 
        request = body.getchildren()[0]
1223
 
        tag = request.tag
1224
 
        if not tag.startswith('{' + ntap_ns + '}'):
1225
 
            s.send_response(500)
1226
 
            s.end_headers
1227
 
            return
1228
 
        api = tag[(2 + len(ntap_ns)):]
1229
 
        if 'ProvisionLun' == api:
1230
 
            body = """<ns:ProvisionLunResult xmlns:ns=
1231
 
            "http://cloud.netapp.com/">
1232
 
            <Lun><Name>lun1</Name><Size>20</Size>
1233
 
             <Handle>1d9c006c-a406-42f6-a23f-5ed7a6dc33e3</Handle>
1234
 
            <Metadata><Key>OsType</Key>
1235
 
            <Value>linux</Value></Metadata></Lun>
1236
 
            </ns:ProvisionLunResult>"""
1237
 
        elif 'DestroyLun' == api:
1238
 
            body = """<ns:DestroyLunResult xmlns:ns="http://cloud.netapp.com/"
1239
 
             />"""
1240
 
        elif 'CloneLun' == api:
1241
 
            body = """<ns:CloneLunResult xmlns:ns="http://cloud.netapp.com/">
1242
 
                     <Lun><Name>lun2</Name><Size>2</Size>
1243
 
                     <Handle>98ea1791d228453899d422b4611642c3</Handle>
1244
 
                     <Metadata><Key>OsType</Key>
1245
 
                     <Value>linux</Value></Metadata>
1246
 
                     </Lun></ns:CloneLunResult>"""
1247
 
        elif 'MapLun' == api:
1248
 
            body = """<ns1:MapLunResult xmlns:ns="http://cloud.netapp.com/"
1249
 
             />"""
1250
 
        elif 'Unmap' == api:
1251
 
            body = """<ns1:UnmapLunResult xmlns:ns="http://cloud.netapp.com/"
1252
 
             />"""
1253
 
        elif 'ListLuns' == api:
1254
 
            body = """<ns:ListLunsResult xmlns:ns="http://cloud.netapp.com/">
1255
 
                 <Lun>
1256
 
                 <Name>lun1</Name>
1257
 
                 <Size>20</Size>
1258
 
                 <Handle>asdjdnsd</Handle>
1259
 
                 </Lun>
1260
 
                 </ns:ListLunsResult>"""
1261
 
        elif 'GetLunTargetDetails' == api:
1262
 
            body = """<ns:GetLunTargetDetailsResult
1263
 
            xmlns:ns="http://cloud.netapp.com/">
1264
 
                    <TargetDetail>
1265
 
                     <Address>1.2.3.4</Address>
1266
 
                     <Port>3260</Port>
1267
 
                     <Portal>1000</Portal>
1268
 
                     <Iqn>iqn.199208.com.netapp:sn.123456789</Iqn>
1269
 
                     <LunNumber>0</LunNumber>
1270
 
                    </TargetDetail>
1271
 
                    </ns:GetLunTargetDetailsResult>"""
1272
 
        else:
1273
 
            # Unknown API
1274
 
            s.send_response(500)
1275
 
            s.end_headers
1276
 
            return
1277
 
        s.send_response(200)
1278
 
        s.send_header("Content-Type", "text/xml; charset=utf-8")
1279
 
        s.end_headers()
1280
 
        s.wfile.write(RESPONSE_PREFIX_CMODE)
1281
 
        s.wfile.write(body)
1282
 
        s.wfile.write(RESPONSE_SUFFIX_CMODE)
1283
 
 
1284
 
 
1285
 
class FakeCmodeHTTPConnection(object):
1286
 
    """A fake httplib.HTTPConnection for netapp tests
1287
 
 
1288
 
    Requests made via this connection actually get translated and routed into
1289
 
    the fake Dfm handler above, we then turn the response into
1290
 
    the httplib.HTTPResponse that the caller expects.
1291
 
    """
1292
 
    def __init__(self, host, timeout=None):
1293
 
        self.host = host
1294
 
 
1295
 
    def request(self, method, path, data=None, headers=None):
1296
 
        if not headers:
1297
 
            headers = {}
1298
 
        req_str = '%s %s HTTP/1.1\r\n' % (method, path)
1299
 
        for key, value in headers.iteritems():
1300
 
            req_str += "%s: %s\r\n" % (key, value)
1301
 
        if data:
1302
 
            req_str += '\r\n%s' % data
1303
 
 
1304
 
        # NOTE(vish): normally the http transport normailizes from unicode
1305
 
        sock = FakeHttplibSocket(req_str.decode("latin-1").encode("utf-8"))
1306
 
        # NOTE(vish): stop the server from trying to look up address from
1307
 
        #             the fake socket
1308
 
        FakeCMODEServerHandler.address_string = lambda x: '127.0.0.1'
1309
 
        self.app = FakeCMODEServerHandler(sock, '127.0.0.1:8080', None)
1310
 
 
1311
 
        self.sock = FakeHttplibSocket(sock.result)
1312
 
        self.http_response = httplib.HTTPResponse(self.sock)
1313
 
 
1314
 
    def set_debuglevel(self, level):
1315
 
        pass
1316
 
 
1317
 
    def getresponse(self):
1318
 
        self.http_response.begin()
1319
 
        return self.http_response
1320
 
 
1321
 
    def getresponsebody(self):
1322
 
        return self.sock.result
1323
 
 
1324
 
 
1325
 
class NetAppCmodeISCSIDriverTestCase(test.TestCase):
1326
 
    """Test case for NetAppISCSIDriver"""
1327
 
    volume = {
1328
 
            'name': 'lun1', 'size': 1, 'volume_name': 'lun1',
1329
 
            'os_type': 'linux', 'provider_location': 'lun1',
1330
 
            'id': 'lun1', 'provider_auth': None, 'project_id': 'project',
1331
 
            'display_name': None, 'display_description': 'lun1',
1332
 
            'volume_type_id': None
1333
 
            }
1334
 
    snapshot = {
1335
 
            'name': 'lun2', 'size': 1, 'volume_name': 'lun1',
1336
 
            'volume_size': 1, 'project_id': 'project'
1337
 
            }
1338
 
    volume_sec = {
1339
 
            'name': 'vol_snapshot', 'size': 1, 'volume_name': 'lun1',
1340
 
            'os_type': 'linux', 'provider_location': 'lun1',
1341
 
            'id': 'lun1', 'provider_auth': None, 'project_id': 'project',
1342
 
            'display_name': None, 'display_description': 'lun1',
1343
 
            'volume_type_id': None
1344
 
            }
1345
 
 
1346
 
    def setUp(self):
1347
 
        super(NetAppCmodeISCSIDriverTestCase, self).setUp()
1348
 
        driver = netapp.NetAppCmodeISCSIDriver()
1349
 
        self.stubs.Set(httplib, 'HTTPConnection', FakeCmodeHTTPConnection)
1350
 
        driver._create_client(wsdl_url='http://localhost:8080/ntap_cloud.wsdl',
1351
 
                              login='root', password='password',
1352
 
                              hostname='localhost', port=8080, cache=False)
1353
 
        self.driver = driver
1354
 
 
1355
 
    def test_connect(self):
1356
 
        self.driver.check_for_setup_error()
1357
 
 
1358
 
    def test_create_destroy(self):
1359
 
        self.driver.create_volume(self.volume)
1360
 
        self.driver.delete_volume(self.volume)
1361
 
 
1362
 
    def test_create_vol_snapshot_destroy(self):
1363
 
        self.driver.create_volume(self.volume)
1364
 
        self.driver.create_snapshot(self.snapshot)
1365
 
        self.driver.create_volume_from_snapshot(self.volume_sec, self.snapshot)
1366
 
        self.driver.delete_snapshot(self.snapshot)
1367
 
        self.driver.delete_volume(self.volume)
1368
 
 
1369
 
    def test_map_unmap(self):
1370
 
        self.driver.create_volume(self.volume)
1371
 
        updates = self.driver.create_export(None, self.volume)
1372
 
        self.assertTrue(updates['provider_location'])
1373
 
        self.volume['provider_location'] = updates['provider_location']
1374
 
        connector = {'initiator': 'init1'}
1375
 
        connection_info = self.driver.initialize_connection(self.volume,
1376
 
                                                             connector)
1377
 
        self.assertEqual(connection_info['driver_volume_type'], 'iscsi')
1378
 
        properties = connection_info['data']
1379
 
        self.driver.terminate_connection(self.volume, connector)
1380
 
        self.driver.delete_volume(self.volume)