1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 """pywbem.twisted - WBEM client bindings for Twisted Python.
22
23 This module contains factory classes that produce WBEMClient instances
24 that perform WBEM requests over HTTP using the
25 twisted.protocols.http.HTTPClient base class.
26 """
27
28 import string
29 import base64
30 from types import StringTypes
31 from datetime import datetime, timedelta
32 import urllib
33 try:
34 from elementtree.ElementTree import fromstring, tostring
35 except ImportError, arg:
36 from xml.etree.ElementTree import fromstring, tostring
37
38 from twisted.internet import reactor, protocol, defer
39 from twisted.web import http
40
41
42
43 from pywbem import cim_types, cim_xml, cim_obj, tupleparse, tupletree
44 from pywbem.cim_obj import CIMClass, CIMClassName, CIMInstance, CIMInstanceName
45 from pywbem.cim_operations import CIMError
46 from pywbem.cim_types import CIMDateTime
47
48 __all__ = ['WBEMClient', 'WBEMClientFactory', 'EnumerateInstances',
49 'EnumerateInstanceNames', 'GetInstance', 'DeleteInstance',
50 'CreateInstance', 'ModifyInstance', 'EnumerateClassNames',
51 'EnumerateClasses', 'GetClass', 'Associators', 'AssociatorNames',
52 'References', 'ReferenceNames', 'InvokeMethod', 'ExecQuery']
53
55 """A HTTPClient subclass that handles WBEM requests."""
56
57 status = None
58
60 """Send a HTTP POST command with the appropriate CIM over HTTP
61 headers and payload."""
62
63 self.factory.request_xml = str(self.factory.payload)
64
65 self.sendCommand('POST', '/cimom')
66
67 self.sendHeader('Host', '%s:%d' %
68 (self.transport.addr[0], self.transport.addr[1]))
69 self.sendHeader('User-Agent', 'pywbem/twisted')
70 self.sendHeader('Content-length', len(self.factory.payload))
71 self.sendHeader('Content-type', 'application/xml')
72
73 if self.factory.creds:
74 auth = base64.b64encode('%s:%s' % (self.factory.creds[0],
75 self.factory.creds[1]))
76
77 self.sendHeader('Authorization', 'Basic %s' % auth)
78
79 self.sendHeader('CIMOperation', str(self.factory.operation))
80 self.sendHeader('CIMMethod', str(self.factory.method))
81 self.sendHeader('CIMObject', str(self.factory.object))
82
83 self.endHeaders()
84
85
86
87
88
89 self.transport.write(str(self.factory.payload))
90
92 """Called when all response data has been received."""
93
94 self.factory.response_xml = data
95
96 if self.status == '200':
97 self.factory.parseErrorAndResponse(data)
98
99 self.factory.deferred = None
100 self.transport.loseConnection()
101
103 """Save the status code for processing when we get to the end
104 of the headers."""
105
106 self.status = status
107 self.message = message
108
110 """Handle header values."""
111
112 if key == 'CIMError':
113 self.CIMError = urllib.unquote(value)
114 if key == 'PGErrorDetail':
115 self.PGErrorDetail = urllib.unquote(value)
116
118 """Check whether the status was OK and raise an error if not
119 using previously saved header information."""
120
121 if self.status != '200':
122
123 if not hasattr(self, 'cimerror') or \
124 not hasattr(self, 'errordetail'):
125
126 self.factory.deferred.errback(
127 CIMError(0, 'HTTP error %s: %s' %
128 (self.status, self.message)))
129
130 else:
131
132 self.factory.deferred.errback(
133 CIMError(0, '%s: %s' % (cimerror, errordetail)))
134
136 """Create instances of the WBEMClient class."""
137
138 request_xml = None
139 response_xml = None
140 xml_header = '<?xml version="1.0" encoding="utf-8" ?>'
141
142 - def __init__(self, creds, operation, method, object, payload):
143 self.creds = creds
144 self.operation = operation
145 self.method = method
146 self.object = object
147 self.payload = payload
148 self.protocol = lambda: WBEMClient()
149 self.deferred = defer.Deferred()
150
152 if self.deferred is not None:
153 reactor.callLater(0, self.deferred.errback, reason)
154
156 if self.deferred is not None:
157 reactor.callLater(0, self.deferred.errback, reason)
158
178
180 """Generate the XML payload for an extrinsic methodcall."""
181
182 if isinstance(obj, CIMInstanceName):
183
184 path = obj.copy()
185
186 path.host = None
187 path.namespace = None
188
189 localpath = cim_xml.LOCALINSTANCEPATH(
190 cim_xml.LOCALNAMESPACEPATH(
191 [cim_xml.NAMESPACE(ns)
192 for ns in string.split(namespace, '/')]),
193 path.tocimxml())
194 else:
195 localpath = cim_xml.LOCALCLASSPATH(
196 cim_xml.LOCALNAMESPACEPATH(
197 [cim_xml.NAMESPACE(ns)
198 for ns in string.split(namespace, '/')]),
199 obj)
200
201 def paramtype(obj):
202 """Return a string to be used as the CIMTYPE for a parameter."""
203 if isinstance(obj, cim_types.CIMType):
204 return obj.cimtype
205 elif type(obj) == bool:
206 return 'boolean'
207 elif isinstance(obj, StringTypes):
208 return 'string'
209 elif isinstance(obj, (datetime, timedelta)):
210 return 'datetime'
211 elif isinstance(obj, (CIMClassName, CIMInstanceName)):
212 return 'reference'
213 elif isinstance(obj, (CIMClass, CIMInstance)):
214 return 'string'
215 elif isinstance(obj, list):
216 return paramtype(obj[0])
217 raise TypeError('Unsupported parameter type "%s"' % type(obj))
218
219 def paramvalue(obj):
220 """Return a cim_xml node to be used as the value for a
221 parameter."""
222 if isinstance(obj, (datetime, timedelta)):
223 obj = CIMDateTime(obj)
224 if isinstance(obj, (cim_types.CIMType, bool, StringTypes)):
225 return cim_xml.VALUE(cim_types.atomic_to_cim_xml(obj))
226 if isinstance(obj, (CIMClassName, CIMInstanceName)):
227 return cim_xml.VALUE_REFERENCE(obj.tocimxml())
228 if isinstance(obj, (CIMClass, CIMInstance)):
229 return cim_xml.VALUE(obj.tocimxml().toxml())
230 if isinstance(obj, list):
231 if isinstance(obj[0], (CIMClassName, CIMInstanceName)):
232 return cim_xml.VALUE_REFARRAY([paramvalue(x) for x in obj])
233 return cim_xml.VALUE_ARRAY([paramvalue(x) for x in obj])
234 raise TypeError('Unsupported parameter type "%s"' % type(obj))
235
236 param_list = [cim_xml.PARAMVALUE(x[0],
237 paramvalue(x[1]),
238 paramtype(x[1]))
239 for x in kwargs.items()]
240
241 payload = cim_xml.CIM(
242 cim_xml.MESSAGE(
243 cim_xml.SIMPLEREQ(
244 cim_xml.METHODCALL(methodname,
245 localpath,
246 param_list)),
247 '1001', '1.0'),
248 '2.0', '2.0')
249
250 return self.xml_header + payload.toxml()
251
253 """Parse returned XML for errors, then convert into
254 appropriate Python objects."""
255
256 xml = fromstring(data)
257 error = xml.find('.//ERROR')
258
259 if error is None:
260 self.deferred.callback(self.parseResponse(xml))
261 return
262
263 try:
264 code = int(error.attrib['CODE'])
265 except ValueError:
266 code = 0
267
268 self.deferred.errback(CIMError(code, error.attrib['DESCRIPTION']))
269
271 """Parse returned XML and convert into appropriate Python
272 objects. Override in subclass"""
273
274 pass
275
277 """Factory to produce EnumerateInstances WBEM clients."""
278
279 - def __init__(self, creds, classname, namespace='root/cimv2', **kwargs):
280
281 self.classname = classname
282 self.namespace = namespace
283
284 payload = self.imethodcallPayload(
285 'EnumerateInstances',
286 namespace,
287 ClassName=CIMClassName(classname),
288 **kwargs)
289
290 WBEMClientFactory.__init__(
291 self,
292 creds,
293 operation='MethodCall',
294 method='EnumerateInstances',
295 object=namespace,
296 payload=payload)
297
299 return '<%s(/%s:%s) at 0x%x>' % \
300 (self.__class__, self.namespace, self.classname, id(self))
301
308
310 """Factory to produce EnumerateInstanceNames WBEM clients."""
311
312 - def __init__(self, creds, classname, namespace='root/cimv2', **kwargs):
313
314 self.classname = classname
315 self.namespace = namespace
316
317 payload = self.imethodcallPayload(
318 'EnumerateInstanceNames',
319 namespace,
320 ClassName=CIMClassName(classname),
321 **kwargs)
322
323 WBEMClientFactory.__init__(
324 self,
325 creds,
326 operation='MethodCall',
327 method='EnumerateInstanceNames',
328 object=namespace,
329 payload=payload)
330
332 return '<%s(/%s:%s) at 0x%x>' % \
333 (self.__class__, self.namespace, self.classname, id(self))
334
336
337 tt = [tupletree.xml_to_tupletree(tostring(x))
338 for x in xml.findall('.//INSTANCENAME')]
339
340 names = [tupleparse.parse_instancename(x) for x in tt]
341
342 [setattr(n, 'namespace', self.namespace) for n in names]
343
344 return names
345
347 """Factory to produce GetInstance WBEM clients."""
348
349 - def __init__(self, creds, instancename, namespace='root/cimv2', **kwargs):
350
351 self.instancename = instancename
352 self.namespace = namespace
353
354 payload = self.imethodcallPayload(
355 'GetInstance',
356 namespace,
357 InstanceName=instancename,
358 **kwargs)
359
360 WBEMClientFactory.__init__(
361 self,
362 creds,
363 operation='MethodCall',
364 method='GetInstance',
365 object=namespace,
366 payload=payload)
367
369 return '<%s(/%s:%s) at 0x%x>' % \
370 (self.__class__, self.namespace, self.instancename, id(self))
371
378
380 """Factory to produce DeleteInstance WBEM clients."""
381
382 - def __init__(self, creds, instancename, namespace='root/cimv2', **kwargs):
383
384 self.instancename = instancename
385 self.namespace = namespace
386
387 payload = self.imethodcallPayload(
388 'DeleteInstance',
389 namespace,
390 InstanceName=instancename,
391 **kwargs)
392
393 WBEMClientFactory.__init__(
394 self,
395 creds,
396 operation='MethodCall',
397 method='DeleteInstance',
398 object=namespace,
399 payload=payload)
400
402 return '<%s(/%s:%s) at 0x%x>' % \
403 (self.__class__, self.namespace, self.instancename, id(self))
404
406 """Factory to produce CreateInstance WBEM clients."""
407
408
409
410 - def __init__(self, creds, instance, namespace='root/cimv2', **kwargs):
411
412 payload = self.imethodcallPayload(
413 'CreateInstance',
414 namespace,
415 NewInstance=instance,
416 **kwargs)
417
418 WBEMClientFactory.__init__(
419 self,
420 creds,
421 operation='MethodCall',
422 method='CreateInstance',
423 object=namespace,
424 payload=payload)
425
432
434 """Factory to produce ModifyInstance WBEM clients."""
435
436
437
438 - def __init__(self, creds, instancename, instance, namespace='root/cimv2',
439 **kwargs):
440
441 wrapped_instance = CIMNamedInstance(instancename, instance)
442
443 payload = self.imethodcallPayload(
444 'ModifyInstance',
445 namespace,
446 ModifiedInstance=wrapped_instance,
447 **kwargs)
448
449 WBEMClientFactory.__init__(
450 self,
451 creds,
452 operation='MethodCall',
453 method='ModifyInstance',
454 object=namespace,
455 payload=payload)
456
458 """Factory to produce EnumerateClassNames WBEM clients."""
459
460 - def __init__(self, creds, namespace='root/cimv2', **kwargs):
461
462 self.localnsp = namespace
463
464 payload = self.imethodcallPayload(
465 'EnumerateClassNames',
466 namespace,
467 **kwargs)
468
469 WBEMClientFactory.__init__(
470 self,
471 creds,
472 operation='MethodCall',
473 method='EnumerateClassNames',
474 object=namespace,
475 payload=payload)
476
478 return '<%s(/%s) at 0x%x>' % \
479 (self.__class__, self.namespace, id(self))
480
487
489 """Factory to produce EnumerateClasses WBEM clients."""
490
491 - def __init__(self, creds, namespace='root/cimv2', **kwargs):
492
493 self.localnsp = namespace
494 self.namespace = namespace
495
496 payload = self.imethodcallPayload(
497 'EnumerateClasses',
498 namespace,
499 **kwargs)
500
501 WBEMClientFactory.__init__(
502 self,
503 creds,
504 operation='MethodCall',
505 method='EnumerateClasses',
506 object=namespace,
507 payload=payload)
508
510 return '<%s(/%s) at 0x%x>' % \
511 (self.__class__, self.namespace, id(self))
512
519
521 """Factory to produce GetClass WBEM clients."""
522
523 - def __init__(self, creds, classname, namespace='root/cimv2', **kwargs):
524
525 self.classname = classname
526 self.namespace = namespace
527
528 payload = self.imethodcallPayload(
529 'GetClass',
530 namespace,
531 ClassName=CIMClassName(classname),
532 **kwargs)
533
534 WBEMClientFactory.__init__(
535 self,
536 creds,
537 operation='MethodCall',
538 method='GetClass',
539 object=namespace,
540 payload=payload)
541
543 return '<%s(/%s:%s) at 0x%x>' % \
544 (self.__class__, self.namespace, self.classname, id(self))
545
552
554 """Factory to produce Associators WBEM clients."""
555
556
557
558 - def __init__(self, creds, obj, namespace='root/cimv2', **kwargs):
559
560 if isinstance(obj, CIMInstanceName):
561 kwargs['ObjectName'] = obj
562 else:
563 kwargs['ObjectName'] = CIMClassName(obj)
564
565 payload = self.imethodcallPayload(
566 'Associators',
567 namespace,
568 **kwargs)
569
570 WBEMClientFactory.__init__(
571 self,
572 creds,
573 operation='MethodCall',
574 method='Associators',
575 object=namespace,
576 payload=payload)
577
579 """Factory to produce AssociatorNames WBEM clients."""
580
581
582
583 - def __init__(self, creds, obj, namespace='root/cimv2', **kwargs):
584
585 if isinstance(obj, CIMInstanceName):
586 kwargs['ObjectName'] = obj
587 else:
588 kwargs['ObjectName'] = CIMClassName(obj)
589
590 payload = self.imethodcallPayload(
591 'AssociatorNames',
592 namespace,
593 **kwargs)
594
595 WBEMClientFactory.__init__(
596 self,
597 creds,
598 operation='MethodCall',
599 method='AssociatorNames',
600 object=namespace,
601 payload=payload)
602
604
605 if len(xml.findall('.//INSTANCENAME')) > 0:
606
607 tt = [tupletree.xml_to_tupletree(tostring(x))
608 for x in xml.findall('.//INSTANCENAME')]
609
610 return [tupleparse.parse_instancename(x) for x in tt]
611
612 else:
613
614 tt = [tupletree.xml_to_tupletree(tostring(x))
615 for x in xml.findall('.//OBJECTPATH')]
616
617 return [tupleparse.parse_objectpath(x)[2] for x in tt]
618
620 """Factory to produce References WBEM clients."""
621
622 - def __init__(self, creds, obj, namespace='root/cimv2', **kwargs):
623
624 if isinstance(obj, CIMInstanceName):
625 kwargs['ObjectName'] = obj
626 else:
627 kwargs['ObjectName'] = CIMClassName(obj)
628
629 payload = self.imethodcallPayload(
630 'References',
631 namespace,
632 **kwargs)
633
634 WBEMClientFactory.__init__(
635 self,
636 creds,
637 operation='MethodCall',
638 method='References',
639 object=namespace,
640 payload=payload)
641
643 """Factory to produce ReferenceNames WBEM clients."""
644
645
646
647 - def __init__(self, creds, obj, namespace='root/cimv2', **kwargs):
648
649 if isinstance(obj, CIMInstanceName):
650 kwargs['ObjectName'] = obj
651 else:
652 kwargs['ObjectName'] = CIMClassName(obj)
653
654 payload = self.imethodcallPayload(
655 'ReferenceNames',
656 namespace,
657 **kwargs)
658
659 WBEMClientFactory.__init__(
660 self,
661 creds,
662 operation='MethodCall',
663 method='ReferenceNames',
664 object=namespace,
665 payload=payload)
666
668
669 if len(xml.findall('.//INSTANCENAME')) > 0:
670
671 tt = [tupletree.xml_to_tupletree(tostring(x))
672 for x in xml.findall('.//INSTANCENAME')]
673
674 return [tupleparse.parse_instancename(x) for x in tt]
675
676 else:
677
678 tt = [tupletree.xml_to_tupletree(tostring(x))
679 for x in xml.findall('.//OBJECTPATH')]
680
681 return [tupleparse.parse_objectpath(x)[2] for x in tt]
682
684 """Factory to produce InvokeMethod WBEM clients."""
685
686 - def __init__(self, creds, MethodName, ObjectName, namespace='root/cimv2',
687 **kwargs):
688
689
690
691 obj = ObjectName
692
693 if isinstance(obj, StringTypes):
694 obj = CIMClassName(obj, namespace=namespace)
695
696 if isinstance(obj, CIMInstanceName) and obj.namespace is None:
697 obj = ObjectName.copy()
698 obj.namespace = namespace
699
700
701
702 payload = self.methodcallPayload(
703 MethodName,
704 obj,
705 namespace,
706 **kwargs)
707
708 WBEMClientFactory.__init__(
709 self,
710 creds,
711 operation='MethodCall',
712 method=MethodName,
713 object=obj,
714 payload=payload)
715
717
718
719
720 result_xml = tupletree.xml_to_tupletree(
721 tostring(xml.find('.//RETURNVALUE')))
722
723 result_tt = tupleparse.parse_any(result_xml)
724
725 result = cim_obj.tocimobj(result_tt[1]['PARAMTYPE'],
726 result_tt[2])
727
728
729
730 params_xml = [tupletree.xml_to_tupletree(tostring(x))
731 for x in xml.findall('.//PARAMVALUE')]
732
733 params_tt = [tupleparse.parse_any(x) for x in params_xml]
734
735 params = {}
736
737 for p in params_tt:
738 if p[1] == 'reference':
739 params[p[0]] = p[2]
740 else:
741 params[p[0]] = cim_obj.tocimobj(p[1], p[2])
742
743 return (result, params)
744
746
747 - def __init__(self, creds, QueryLanguage, Query, namespace='root/cimv2'):
748
749 self.QueryLanguage = QueryLanguage
750 self.Query = Query
751 self.namespace = namespace
752
753 payload = self.imethodcallPayload(
754 'ExecQuery',
755 namespace,
756 QueryLanguage = QueryLanguage,
757 Query = Query)
758
759 WBEMClientFactory.__init__(
760 self,
761 creds,
762 operation='MethodCall',
763 method='ExecQuery',
764 object=namespace,
765 payload=payload)
766
768 return '<%s(/%s:%s) at 0x%x>' % \
769 (self.__class__, self.namespace, self.Query, id(self))
770
775