Here is the updated patch, with usage notes added. Let me know if this is the acceptable format.
>From 1c8a61d19baf046d32e1216f731958ddb96b89d6 Mon Sep 17 00:00:00 2001 From: Dave Heller <[email protected]> Date: Thu, 22 Mar 2012 17:17:04 -0400 Subject: [PATCH] Updates to indication_tester.py --- .../libvirt-cim/lib/XenKvmLib/indication_tester.py | 901 +++++++++++++------- 1 files changed, 611 insertions(+), 290 deletions(-) diff --git a/suites/libvirt-cim/lib/XenKvmLib/indication_tester.py b/suites/libvirt-cim/lib/XenKvmLib/indication_tester.py index f6cbcf0..5d708d9 100644 --- a/suites/libvirt-cim/lib/XenKvmLib/indication_tester.py +++ b/suites/libvirt-cim/lib/XenKvmLib/indication_tester.py @@ -1,279 +1,411 @@ #!/usr/bin/python -# Copyright IBM Corp. 2007 +# Copyright IBM Corp. 2007-2012 # # indication_tester.py - Tool for testing indication subscription and # delivery against a CIMOM # Author: Dan Smith <[email protected]> +# SSL support added by Dave Heller <[email protected]> +# +# This file is both a module of the cimtest "libvirt-cim" suite and a standalone +# program for indication testing. The following notes describe the usage of the +# standalone program. +# +# USAGE: +# +# Use the -h or --help option to see the complete list of command line options. +# +# Although the script supports http or https indications to the handler +# Destination, it currently does not support https connections to the CIMOM. +# All communication to the CIMOM is over http, so the CIMOM must have a http +# port open for the script to work. +# +# Note there is some inconsistency between the --url option (CIMOM URL) and the +# --dest option (handler Destination URL). The --dest option is a true URL in +# which you may specify scheme (http or https), user and password, in addition +# to server and port. The --url option accepts only server and port. Use the +# --user and --pass options to specify CIMOM credentials. +# +# Use the --interop option to override the default interop namespace +# (root/interop). You may specify the full namespace name (with '/') or an +# abbreviated name (no '/'). In the latter case, the script will prepend +# "root/" to the name. (Example: --interop PG_InterOp) +# +# Use the --ns option to override the indication namespace (which by default is +# the same as the interop namespace). Note this option currently does not +# support abbreviations; you must specify the full namespace name. +# +# Use the --print-ind option to see responses from the CIMOM. Use the --verbose +# option to see additional debug info such as details of the CIMOM SSL +# certificates when https indications are received. +# +# Use --certFile and --keyFile to specify the indications receiver's (i.e. +# the script's) SSL certificate and key in PEM format. If --keyFile is not +# provided, the --certFile must contain the key. +# +# Use --trustStore to specify CA certificate(s) to be used to verify the CIMOM's +# certificate, or use --noverify to skip this verification. +# +# Use --trigger to cause the CIMOM to send a test indication. Currently this +# feature only supports the SFCB Test_Indication provider. (Build SFCB with +# "configure --enable-tests" before running "make".) Otherwise, the indication +# must be triggered through some independent method. +# +# EXAMPLES: +# +# Start a listener for indication class "Test_Indication" using all default +# values. The CIMOM and the listener are both running on localhost; the interop +# and indication namespaces are both: root/interop: +# +# $ indication_tester.py Test_Indication +# +# Start a listener for class "CIM_Alerts" in root/mynamespace using the +# OpenPegasus CIMOM: +# +# $ indication_tester.py --interop PG_InterOp --ns root/mynamespace CIM_Alerts +# +# Start a listener on the local host but register the subscription to a CIMOM on +# a remote host. Note the handler Destination must point to the local host in a +# manner that is resolvable to the CIMOM: +# +# $ indication_tester.py --url remotesys.mydomain.com:5988 --dest \ +# http://localsys.mydomain.com:8000 Test_Indication +# +# Start a listener to receive an indication via https, do not verify the CIMOM +# certificate: +# +# $ indication_tester.py --noverify --certFile mycert.pem --keyFile mykey.pem \ +# Test_Indication +# +# Same as above but additionally verify the CIMOM cert against known CA certs: +# +# $ indication_tester.py --trustStore CAcerts.pem --certFile mycert.pem +# --keyFile mykey.pem Test_Indication +# +# Trigger an indication using the SFCB Test_Indication provider. Note this is a +# *separate invocation* of the script, independent of the listener (presumably +# already started per the examples above). In trigger mode, the script sends +# the appropriate method call to the CIMOM and exits. If successful, the +# indication will be received at the listener: +# +# $ indication_tester.py --trigger +# +# Same as above but the CIMOM is running on a remote system: +# +# $ indication_tester.py --url remotesys:5988 --trigger import sys from optparse import OptionParser -import BaseHTTPServer +from urlparse import urlparse, urlunparse +from xml.dom.minidom import parse, parseString import httplib import base64 -from xml.dom.minidom import parse, parseString +import errno, os, re +import socket +from SocketServer import BaseServer +from SimpleHTTPServer import SimpleHTTPRequestHandler +from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer +from OpenSSL import SSL -def filter_xml(name, type, ns, sysname): +def filter_xml(name, type, ns, sysname, interopNS): return """ - <?xml version="1.0" encoding="utf-8"?> - <CIM CIMVERSION="2.0" DTDVERSION="2.0"> - <MESSAGE ID="4711" PROTOCOLVERSION="1.0"> - <SIMPLEREQ> - <IMETHODCALL NAME="CreateInstance"> - <LOCALNAMESPACEPATH> - <NAMESPACE NAME="root"/> - <NAMESPACE NAME="PG_InterOp"/> - </LOCALNAMESPACEPATH> - <IPARAMVALUE NAME="NewInstance"> + <?xml version="1.0" encoding="utf-8"?> + <CIM CIMVERSION="2.0" DTDVERSION="2.0"> + <MESSAGE ID="4711" PROTOCOLVERSION="1.0"> + <SIMPLEREQ> + <IMETHODCALL NAME="CreateInstance"> + <LOCALNAMESPACEPATH> + <NAMESPACE NAME="%s"/> + <NAMESPACE NAME="%s"/> + </LOCALNAMESPACEPATH> + <IPARAMVALUE NAME="NewInstance"> <INSTANCE CLASSNAME="CIM_IndicationFilter"> - <PROPERTY NAME="SystemCreationClassName" TYPE="string"> - <VALUE>CIM_ComputerSystem</VALUE> - </PROPERTY> - <PROPERTY NAME="SystemName" TYPE="string"> - <VALUE>%s</VALUE> - </PROPERTY> - <PROPERTY NAME="CreationClassName" TYPE="string"> - <VALUE>CIM_IndicationFilter</VALUE> - </PROPERTY> - <PROPERTY NAME="Name" TYPE="string"> - <VALUE>%sFilter</VALUE> - </PROPERTY> - <PROPERTY NAME="Query" TYPE="string"> - <VALUE> SELECT * FROM %s - </VALUE> - </PROPERTY> - <PROPERTY NAME="QueryLanguage" TYPE="string"> - <VALUE>WQL</VALUE> - </PROPERTY> - <PROPERTY NAME="SourceNamespace" TYPE="string"> - <VALUE>%s</VALUE> - </PROPERTY> - </INSTANCE> - </IPARAMVALUE> - </IMETHODCALL> - </SIMPLEREQ> - </MESSAGE> + <PROPERTY NAME="SystemCreationClassName" TYPE="string"> + <VALUE>CIM_ComputerSystem</VALUE> + </PROPERTY> + <PROPERTY NAME="SystemName" TYPE="string"> + <VALUE>%s</VALUE> + </PROPERTY> + <PROPERTY NAME="CreationClassName" TYPE="string"> + <VALUE>CIM_IndicationFilter</VALUE> + </PROPERTY> + <PROPERTY NAME="Name" TYPE="string"> + <VALUE>%sFilter</VALUE> + </PROPERTY> + <PROPERTY NAME="Query" TYPE="string"> + <VALUE> SELECT * FROM %s + </VALUE> + </PROPERTY> + <PROPERTY NAME="QueryLanguage" TYPE="string"> + <VALUE>WQL</VALUE> + </PROPERTY> + <PROPERTY NAME="SourceNamespace" TYPE="string"> + <VALUE>%s</VALUE> + </PROPERTY> + </INSTANCE> + </IPARAMVALUE> + </IMETHODCALL> + </SIMPLEREQ> + </MESSAGE> </CIM> - """ % (sysname, name, type, ns) + """ % (interopNS[0], interopNS[1], sysname, name, type, ns) -def handler_xml(name, port, sysname): +def handler_xml(name, destUrl, sysname, interopNS): return """ - <?xml version="1.0" encoding="utf-8"?> - <CIM CIMVERSION="2.0" DTDVERSION="2.0"> - <MESSAGE ID="4711" PROTOCOLVERSION="1.0"> - <SIMPLEREQ> - <IMETHODCALL NAME="CreateInstance"> - <LOCALNAMESPACEPATH> - <NAMESPACE NAME="root"/> - <NAMESPACE NAME="PG_InterOp"/> - </LOCALNAMESPACEPATH> - <IPARAMVALUE NAME="NewInstance"> - <INSTANCE CLASSNAME="CIM_IndicationHandlerCIMXML"> - <PROPERTY NAME="SystemCreationClassName" TYPE="string"> - <VALUE>CIM_ComputerSystem</VALUE> - </PROPERTY> - <PROPERTY NAME="SystemName" TYPE="string"> - <VALUE>%s</VALUE> - </PROPERTY> - <PROPERTY NAME="CreationClassName" TYPE="string"> - <VALUE>CIM_IndicationHandlerCIMXML</VALUE> - </PROPERTY> - <PROPERTY NAME="Name" TYPE="string"> - <VALUE>%sHandler</VALUE> - </PROPERTY> - <PROPERTY NAME="Destination" TYPE="string"> - <VALUE>http://localhost:%i</VALUE> - </PROPERTY> - </INSTANCE> - </IPARAMVALUE> - </IMETHODCALL> - </SIMPLEREQ> - </MESSAGE> + <?xml version="1.0" encoding="utf-8"?> + <CIM CIMVERSION="2.0" DTDVERSION="2.0"> + <MESSAGE ID="4711" PROTOCOLVERSION="1.0"> + <SIMPLEREQ> + <IMETHODCALL NAME="CreateInstance"> + <LOCALNAMESPACEPATH> + <NAMESPACE NAME="%s"/> + <NAMESPACE NAME="%s"/> + </LOCALNAMESPACEPATH> + <IPARAMVALUE NAME="NewInstance"> + <INSTANCE CLASSNAME="CIM_IndicationHandlerCIMXML"> + <PROPERTY NAME="SystemCreationClassName" TYPE="string"> + <VALUE>CIM_ComputerSystem</VALUE> + </PROPERTY> + <PROPERTY NAME="SystemName" TYPE="string"> + <VALUE>%s</VALUE> + </PROPERTY> + <PROPERTY NAME="CreationClassName" TYPE="string"> + <VALUE>CIM_IndicationHandlerCIMXML</VALUE> + </PROPERTY> + <PROPERTY NAME="Name" TYPE="string"> + <VALUE>%sHandler</VALUE> + </PROPERTY> + <PROPERTY NAME="Destination" TYPE="string"> + <VALUE>%s</VALUE> + </PROPERTY> + </INSTANCE> + </IPARAMVALUE> + </IMETHODCALL> + </SIMPLEREQ> + </MESSAGE> </CIM> - """ % (sysname, name, port) + """ % (interopNS[0], interopNS[1], sysname, name, destUrl) -def subscription_xml(name, sysname): +def subscription_xml(name, sysname, interopNS): return """ - <?xml version="1.0" encoding="utf-8"?> - <CIM CIMVERSION="2.0" DTDVERSION="2.0"> - <MESSAGE ID="4711" PROTOCOLVERSION="1.0"> - <SIMPLEREQ> - <IMETHODCALL NAME="CreateInstance"> - <LOCALNAMESPACEPATH> - <NAMESPACE NAME="root"/> - <NAMESPACE NAME="PG_InterOp"/> - </LOCALNAMESPACEPATH> - <IPARAMVALUE NAME="NewInstance"> - <INSTANCE CLASSNAME="CIM_IndicationSubscription"> - <PROPERTY.REFERENCE NAME="Filter" - REFERENCECLASS="CIM_IndicationFilter"> - <VALUE.REFERENCE> - <INSTANCENAME CLASSNAME="CIM_IndicationFilter"> - <KEYBINDING NAME="SystemCreationClassName"> - <KEYVALUE VALUETYPE="string"> - CIM_ComputerSystem - </KEYVALUE> - </KEYBINDING> - <KEYBINDING NAME="SystemName"> - <KEYVALUE VALUETYPE="string"> - %s - </KEYVALUE> - </KEYBINDING> - <KEYBINDING NAME="CreationClassName"> - <KEYVALUE VALUETYPE="string"> - CIM_IndicationFilter - </KEYVALUE> - </KEYBINDING> - <KEYBINDING NAME="Name"> - <KEYVALUE VALUETYPE="string"> - %sFilter - </KEYVALUE> - </KEYBINDING> - </INSTANCENAME> - </VALUE.REFERENCE> - </PROPERTY.REFERENCE> - <PROPERTY.REFERENCE NAME="Handler" - REFERENCECLASS="CIM_IndicationHandler"> - <VALUE.REFERENCE> - <INSTANCENAME CLASSNAME="CIM_IndicationHandlerCIMXML"> - <KEYBINDING NAME="SystemCreationClassName"> - <KEYVALUE VALUETYPE="string"> - CIM_ComputerSystem - </KEYVALUE> - </KEYBINDING> - <KEYBINDING NAME="SystemName"> - <KEYVALUE VALUETYPE="string"> + <?xml version="1.0" encoding="utf-8"?> + <CIM CIMVERSION="2.0" DTDVERSION="2.0"> + <MESSAGE ID="4711" PROTOCOLVERSION="1.0"> + <SIMPLEREQ> + <IMETHODCALL NAME="CreateInstance"> + <LOCALNAMESPACEPATH> + <NAMESPACE NAME="%s"/> + <NAMESPACE NAME="%s"/> + </LOCALNAMESPACEPATH> + <IPARAMVALUE NAME="NewInstance"> + <INSTANCE CLASSNAME="CIM_IndicationSubscription"> + <PROPERTY.REFERENCE NAME="Filter" + REFERENCECLASS="CIM_IndicationFilter"> + <VALUE.REFERENCE> + <INSTANCENAME CLASSNAME="CIM_IndicationFilter"> + <KEYBINDING NAME="SystemCreationClassName"> + <KEYVALUE VALUETYPE="string"> + CIM_ComputerSystem + </KEYVALUE> + </KEYBINDING> + <KEYBINDING NAME="SystemName"> + <KEYVALUE VALUETYPE="string"> + %s + </KEYVALUE> + </KEYBINDING> + <KEYBINDING NAME="CreationClassName"> + <KEYVALUE VALUETYPE="string"> + CIM_IndicationFilter + </KEYVALUE> + </KEYBINDING> + <KEYBINDING NAME="Name"> + <KEYVALUE VALUETYPE="string"> + %sFilter + </KEYVALUE> + </KEYBINDING> + </INSTANCENAME> + </VALUE.REFERENCE> + </PROPERTY.REFERENCE> + <PROPERTY.REFERENCE NAME="Handler" + REFERENCECLASS="CIM_IndicationHandler"> + <VALUE.REFERENCE> + <INSTANCENAME CLASSNAME="CIM_IndicationHandlerCIMXML"> + <KEYBINDING NAME="SystemCreationClassName"> + <KEYVALUE VALUETYPE="string"> + CIM_ComputerSystem + </KEYVALUE> + </KEYBINDING> + <KEYBINDING NAME="SystemName"> + <KEYVALUE VALUETYPE="string"> %s - </KEYVALUE> - </KEYBINDING> - <KEYBINDING NAME="CreationClassName"> - <KEYVALUE VALUETYPE="string"> - CIM_IndicationHandlerCIMXML - </KEYVALUE> - </KEYBINDING> - <KEYBINDING NAME="Name"> - <KEYVALUE VALUETYPE="string"> - %sHandler - </KEYVALUE> - </KEYBINDING> - </INSTANCENAME> - </VALUE.REFERENCE> - </PROPERTY.REFERENCE> - <PROPERTY NAME="SubscriptionState" TYPE="uint16"> - <VALUE> 2 </VALUE> - </PROPERTY> - </INSTANCE> - </IPARAMVALUE> - </IMETHODCALL> - </SIMPLEREQ> - </MESSAGE> + </KEYVALUE> + </KEYBINDING> + <KEYBINDING NAME="CreationClassName"> + <KEYVALUE VALUETYPE="string"> + CIM_IndicationHandlerCIMXML + </KEYVALUE> + </KEYBINDING> + <KEYBINDING NAME="Name"> + <KEYVALUE VALUETYPE="string"> + %sHandler + </KEYVALUE> + </KEYBINDING> + </INSTANCENAME> + </VALUE.REFERENCE> + </PROPERTY.REFERENCE> + <PROPERTY NAME="SubscriptionState" TYPE="uint16"> + <VALUE> 2 </VALUE> + </PROPERTY> + </INSTANCE> + </IPARAMVALUE> + </IMETHODCALL> + </SIMPLEREQ> + </MESSAGE> </CIM> - """ % (sysname, name, sysname, name) + """ % (interopNS[0], interopNS[1], sysname, name, sysname, name) -def delete_inst_xml(name, type, sysname, inst_name): +def delete_inst_xml(name, type, sysname, inst_name, interopNS): return """ - <?xml version="1.0" encoding="utf-8"?> - <CIM CIMVERSION="2.0" DTDVERSION="2.0"> - <MESSAGE ID="4711" PROTOCOLVERSION="1.0"> - <SIMPLEREQ> - <IMETHODCALL NAME="DeleteInstance"> - <LOCALNAMESPACEPATH> - <NAMESPACE NAME="root"/> - <NAMESPACE NAME="PG_InterOp"/> - </LOCALNAMESPACEPATH> - <IPARAMVALUE NAME="InstanceName"> - <INSTANCENAME CLASSNAME="CIM_Indication%s"> - <KEYBINDING NAME="SystemCreationClassName"> - <KEYVALUE>CIM_ComputerSystem</KEYVALUE> - </KEYBINDING> - <KEYBINDING NAME="SystemName"> - <KEYVALUE>%s</KEYVALUE> - </KEYBINDING> - <KEYBINDING NAME="CreationClassName"> - <KEYVALUE>CIM_Indication%s</KEYVALUE> - </KEYBINDING> - <KEYBINDING NAME="Name"> - <KEYVALUE>%s</KEYVALUE> - </KEYBINDING> - </INSTANCENAME> - </IPARAMVALUE> - </IMETHODCALL> - </SIMPLEREQ> - </MESSAGE> + <?xml version="1.0" encoding="utf-8"?> + <CIM CIMVERSION="2.0" DTDVERSION="2.0"> + <MESSAGE ID="4711" PROTOCOLVERSION="1.0"> + <SIMPLEREQ> + <IMETHODCALL NAME="DeleteInstance"> + <LOCALNAMESPACEPATH> + <NAMESPACE NAME="%s"/> + <NAMESPACE NAME="%s"/> + </LOCALNAMESPACEPATH> + <IPARAMVALUE NAME="InstanceName"> + <INSTANCENAME CLASSNAME="CIM_Indication%s"> + <KEYBINDING NAME="SystemCreationClassName"> + <KEYVALUE>CIM_ComputerSystem</KEYVALUE> + </KEYBINDING> + <KEYBINDING NAME="SystemName"> + <KEYVALUE>%s</KEYVALUE> + </KEYBINDING> + <KEYBINDING NAME="CreationClassName"> + <KEYVALUE>CIM_Indication%s</KEYVALUE> + </KEYBINDING> + <KEYBINDING NAME="Name"> + <KEYVALUE>%s</KEYVALUE> + </KEYBINDING> + </INSTANCENAME> + </IPARAMVALUE> + </IMETHODCALL> + </SIMPLEREQ> + </MESSAGE> </CIM>; - """ % (type, sysname, type, inst_name); + """ % (interopNS[0], interopNS[1], type, sysname, type, inst_name); -def delete_sub_xml(name, sysname): +def delete_sub_xml(name, sysname, interopNS): return """ - <?xml version="1.0" encoding="utf-8"?> - <CIM CIMVERSION="2.0" DTDVERSION="2.0"> - <MESSAGE ID="4711" PROTOCOLVERSION="1.0"> - <SIMPLEREQ> - <IMETHODCALL NAME="DeleteInstance"> - <LOCALNAMESPACEPATH> - <NAMESPACE NAME="root"/> - <NAMESPACE NAME="PG_InterOp"/> - </LOCALNAMESPACEPATH> - <IPARAMVALUE NAME="InstanceName"> - <INSTANCENAME CLASSNAME="CIM_IndicationSubscription"> - <KEYBINDING NAME="Filter"> - <VALUE.REFERENCE> - <INSTANCENAME CLASSNAME="CIM_IndicationFilter"> - <KEYBINDING NAME="SystemCreationClassName"> - <KEYVALUE VALUETYPE="string"> - CIM_ComputerSystem - </KEYVALUE> - </KEYBINDING> - <KEYBINDING NAME="SystemName"> - <KEYVALUE VALUETYPE="string"> + <?xml version="1.0" encoding="utf-8"?> + <CIM CIMVERSION="2.0" DTDVERSION="2.0"> + <MESSAGE ID="4711" PROTOCOLVERSION="1.0"> + <SIMPLEREQ> + <IMETHODCALL NAME="DeleteInstance"> + <LOCALNAMESPACEPATH> + <NAMESPACE NAME="%s"/> + <NAMESPACE NAME="%s"/> + </LOCALNAMESPACEPATH> + <IPARAMVALUE NAME="InstanceName"> + <INSTANCENAME CLASSNAME="CIM_IndicationSubscription"> + <KEYBINDING NAME="Filter"> + <VALUE.REFERENCE> + <INSTANCENAME CLASSNAME="CIM_IndicationFilter"> + <KEYBINDING NAME="SystemCreationClassName"> + <KEYVALUE VALUETYPE="string"> + CIM_ComputerSystem + </KEYVALUE> + </KEYBINDING> + <KEYBINDING NAME="SystemName"> + <KEYVALUE VALUETYPE="string"> %s - </KEYVALUE> - </KEYBINDING> - <KEYBINDING NAME="CreationClassName"> - <KEYVALUE VALUETYPE="string"> - CIM_IndicationFilter - </KEYVALUE> - </KEYBINDING> - <KEYBINDING NAME="Name"> - <KEYVALUE VALUETYPE="string"> - %sFilter - </KEYVALUE> - </KEYBINDING> - </INSTANCENAME> - </VALUE.REFERENCE> - </KEYBINDING> - <KEYBINDING NAME="Handler"> - <VALUE.REFERENCE> - <INSTANCENAME CLASSNAME="CIM_IndicationHandlerCIMXML"> - <KEYBINDING NAME="SystemCreationClassName"> - <KEYVALUE VALUETYPE="string"> - CIM_ComputerSystem - </KEYVALUE> - </KEYBINDING> - <KEYBINDING NAME="SystemName"> - <KEYVALUE VALUETYPE="string"> + </KEYVALUE> + </KEYBINDING> + <KEYBINDING NAME="CreationClassName"> + <KEYVALUE VALUETYPE="string"> + CIM_IndicationFilter + </KEYVALUE> + </KEYBINDING> + <KEYBINDING NAME="Name"> + <KEYVALUE VALUETYPE="string"> + %sFilter + </KEYVALUE> + </KEYBINDING> + </INSTANCENAME> + </VALUE.REFERENCE> + </KEYBINDING> + <KEYBINDING NAME="Handler"> + <VALUE.REFERENCE> + <INSTANCENAME CLASSNAME="CIM_IndicationHandlerCIMXML"> + <KEYBINDING NAME="SystemCreationClassName"> + <KEYVALUE VALUETYPE="string"> + CIM_ComputerSystem + </KEYVALUE> + </KEYBINDING> + <KEYBINDING NAME="SystemName"> + <KEYVALUE VALUETYPE="string"> %s - </KEYVALUE> - </KEYBINDING> - <KEYBINDING NAME="CreationClassName"> - <KEYVALUE VALUETYPE="string"> - CIM_IndicationHandlerCIMXML - </KEYVALUE> - </KEYBINDING> - <KEYBINDING NAME="Name"> - <KEYVALUE VALUETYPE="string"> - %sHandler - </KEYVALUE> - </KEYBINDING> - </INSTANCENAME> - </VALUE.REFERENCE> - </KEYBINDING> - </INSTANCENAME> - </IPARAMVALUE> - </IMETHODCALL> - </SIMPLEREQ> - </MESSAGE> + </KEYVALUE> + </KEYBINDING> + <KEYBINDING NAME="CreationClassName"> + <KEYVALUE VALUETYPE="string"> + CIM_IndicationHandlerCIMXML + </KEYVALUE> + </KEYBINDING> + <KEYBINDING NAME="Name"> + <KEYVALUE VALUETYPE="string"> + %sHandler + </KEYVALUE> + </KEYBINDING> + </INSTANCENAME> + </VALUE.REFERENCE> + </KEYBINDING> + </INSTANCENAME> + </IPARAMVALUE> + </IMETHODCALL> + </SIMPLEREQ> + </MESSAGE> </CIM>; - """ % (sysname, name, sysname, name) + """ % (interopNS[0], interopNS[1], sysname, name, sysname, name) + +def trigger_xml(type, interopNS): + return """ + <?xml version="1.0" encoding="utf-8"?> + <CIM CIMVERSION="2.0" DTDVERSION="2.0"> + <MESSAGE ID="4711" PROTOCOLVERSION="1.0"> + <SIMPLEREQ> + <METHODCALL NAME="SendTestIndication"> + <LOCALCLASSPATH> + <LOCALNAMESPACEPATH> + <NAMESPACE NAME="%s"/> + <NAMESPACE NAME="%s"/> + </LOCALNAMESPACEPATH> + <CLASSNAME NAME="%s"/> + </LOCALCLASSPATH> + </METHODCALL> + </SIMPLEREQ> + </MESSAGE> + </CIM> + """ % (interopNS[0], interopNS[1], type) + # FIXME: this should really use indication NS, not interop NS. + +def update_url_port(parsedUrl, port): + # Must manually reconstruct netloc to update the port value. + if isinstance(parsedUrl.username, basestring): + if isinstance(parsedUrl.password, basestring): + netloc = "%s:%s@%s:%s" % (parsedUrl.username, parsedUrl.password, + parsedUrl.hostname, port) + else: + netloc = "%s@%s:%s" % (parsedUrl.username, + parsedUrl.hostname, port) + else: + netloc = "%s:%s" % (parsedUrl.hostname, port) + + # Reassemble url with the updated netloc. return a string. + return urlunparse((parsedUrl.scheme, netloc, + parsedUrl.path, parsedUrl.params, + parsedUrl.query, parsedUrl.fragment)) class CIMIndication: def __init__(self, xmldata): @@ -286,50 +418,135 @@ class CIMIndication: def __str__(self): return self.name -class CIMSocketHandler(BaseHTTPServer.BaseHTTPRequestHandler): +def socket_handler_wrapper(*parms): + try: + CIMSocketHandler(*parms) + except Exception as e: + print "SSL error: %s" % str(e) + +class CIMSocketHandler(SimpleHTTPRequestHandler): + def setup(self): + self.connection = self.request + self.rfile = socket._fileobject(self.request, "rb", self.rbufsize) + self.wfile = socket._fileobject(self.request, "wb", self.wbufsize) + def do_POST(self): length = self.headers.getheader('content-length') data = self.rfile.read(int(length)) indication = CIMIndication(data) - print "Got indication: %s" % indication + print "Got indication: %s from %s" % (indication, self.client_address) if self.server.print_ind: - print "%s\n\n" % data + print "%s\n" % data self.server.indications.append(indication) + # Silence the unwanted log output from send_response() + realStderr = sys.stderr + sys.stderr = open(os.devnull,'a') + self.send_response(200) + sys.stderr = realStderr + +class SecureHTTPServer(HTTPServer): + def __init__(self, server_address, HandlerClass): + BaseServer.__init__(self, server_address, HandlerClass) + + def verify_cb(conn, cert, errnum, depth, ok): + if options.verbose: + print('Verify peer certificate chain: level %d:' % depth) + print('subject=%s' % cert.get_subject()) + print('issuer =%s' % cert.get_issuer()) + return ok + + ctx = SSL.Context(SSL.SSLv23_METHOD) + #ctx.use_certificate_file(options.certFile) + ctx.use_certificate_chain_file(options.certFile) + ctx.use_privatekey_file(options.keyFile) + if options.noverify: + ctx.set_verify(SSL.VERIFY_NONE, verify_cb) + else: + #ctx.set_verify(SSL.VERIFY_PEER, verify_cb) + ctx.set_verify(SSL.VERIFY_PEER|SSL.VERIFY_FAIL_IF_NO_PEER_CERT, + verify_cb) + ctx.load_verify_locations(options.trustStore) + + self.socket = SSL.Connection(ctx, socket.socket(self.address_family, + self.socket_type)) + self.server_bind() + self.server_activate() + +# The param defaults allow new options from main() w/o losing compat w/ cimtest. class CIMIndicationSubscription: - def __init__(self, name, typ, ns, print_ind, sysname, port=0): + def __init__(self, name, typ, ns, print_ind, sysname, port=0, + interopNS=('root','PG_InterOp'), destUrl="http://localhost:8000", + triggermode=False): self.name = name self.type = typ self.ns = ns self.sysname = sysname + self.interopNS = interopNS + self.print_ind = print_ind + + # We do not want to open a listener socket in trigger mode. + if triggermode: + self.trigger_xml = trigger_xml(typ, interopNS) + return + + parsedUrl = urlparse(destUrl) + + # Increment the listener port by the offset value. + if isinstance(parsedUrl.port, int): + listenerPort = parsedUrl.port + port + else: + listenerPort = 8000 + port + + destUrl = update_url_port(parsedUrl, listenerPort) + + try: + if parsedUrl.scheme == "http": + self.server = HTTPServer((parsedUrl.hostname, + listenerPort), + CIMSocketHandler) + elif parsedUrl.scheme == "https": + self.server = SecureHTTPServer((parsedUrl.hostname, + listenerPort), + socket_handler_wrapper) + except IOError as e: + print "Error creating listener socket: %s" % str(e) + exit(e.errno) - self.port = 8000 + port - self.server = BaseHTTPServer.HTTPServer(('', self.port), - CIMSocketHandler) self.server.print_ind = print_ind self.server.indications = [] - self.filter_xml = filter_xml(name, typ, ns, sysname) - self.handler_xml = handler_xml(name, self.port, sysname) - self.subscription_xml = subscription_xml(name, sysname) + self.filter_xml = filter_xml(name, typ, ns, sysname, interopNS) + self.handler_xml = handler_xml(name, destUrl, sysname, interopNS) + self.subscription_xml = subscription_xml(name, sysname, interopNS) def __do_cimpost(self, conn, body, method, auth_hdr=None): headers = {"CIMOperation" : "MethodCall", "CIMMethod" : method, - "CIMObject" : "root/PG_Interop", + #"CIMObject" : "root/PG_Interop", + "CIMObject" : "%s/%s" % self.interopNS, "Content-Type" : 'application/xml; charset="utf-8"'} - + if auth_hdr: headers["Authorization"] = "Basic %s" % auth_hdr - conn.request("POST", "/cimom", body, headers) - resp = conn.getresponse() - if not resp.getheader("content-length"): - raise Exception("Request Failed: %d %s" % - (resp.status, resp.reason)) + try: + conn.request("POST", "/cimom", body, headers) + resp = conn.getresponse() + if not resp.getheader("content-length"): + raise Exception("Request Failed: %d %s" % + (resp.status, resp.reason)) + except IOError as e: + print "Error connecting to CIMOM: %s" % str(e) + exit(e.errno) - resp.read() + if self.print_ind: + print "=== Reply from CIMOM ===" + #print resp.msg + print resp.read() + else: + resp.read() def subscribe(self, url, cred=None): self.conn = httplib.HTTPConnection(url) @@ -346,33 +563,52 @@ class CIMIndicationSubscription: self.__do_cimpost(self.conn, self.subscription_xml, "CreateInstance", auth_hdr) - def unsubscribe(self, cred=None): + # Note, param order is different here to maintain compat with cimtest. + # Better way would be to update cimtest 'indications.py' module. + def unsubscribe(self, cred=None, url=None): + # Without this, can get BadStatusLine exception in SFCB in some cases. + if url: + self.conn = httplib.HTTPConnection(url) + if cred: (u, p) = cred auth_hdr = base64.b64encode("%s:%s" % (u, p)) else: auth_hdr = None - xml = delete_sub_xml(self.name, self.sysname) + xml = delete_sub_xml(self.name, self.sysname, self.interopNS) self.__do_cimpost(self.conn, xml, "DeleteInstance", auth_hdr) xml = delete_inst_xml(self.name, "HandlerCIMXML", self.sysname, - "%sHandler" % self.name) + "%sHandler" % self.name, self.interopNS) self.__do_cimpost(self.conn, xml, "DeleteInstance", auth_hdr) xml = delete_inst_xml(self.name, "Filter", self.sysname, - "%sFilter" % self.name) + "%sFilter" % self.name, self.interopNS) self.__do_cimpost(self.conn, xml, "DeleteInstance", auth_hdr) -def dump_xml(name, typ, ns, sysname): - filter_str = filter_xml(name, typ, ns, sysname) - handler_str = handler_xml(name, 8000, sysname) - subscript_str = subscription_xml(name, sysname) - del_filter_str = delete_inst_xml(name, "Filter", sysname, "%sFilter" % name) + def trigger(self, url, cred=None): + self.conn = httplib.HTTPConnection(url) + if cred: + (u, p) = cred + auth_hdr = base64.b64encode("%s:%s" % (u, p)) + else: + auth_hdr = None + + self.__do_cimpost(self.conn, self.trigger_xml, + "SendTestIndication", auth_hdr) + +def dump_xml(name, typ, ns, sysname, interopNS, destUrl): + filter_str = filter_xml(name, typ, ns, sysname, interopNS) + handler_str = handler_xml(name, destUrl, sysname, interopNS) + subscript_str = subscription_xml(name, sysname, interopNS) + del_filter_str = delete_inst_xml(name, "Filter", sysname, "%sFilter" % name, + interopNS) del_handler_str = delete_inst_xml(name, "HandlerCIMXML", sysname, - "%sHandler" % name) - del_subscript_str = delete_sub_xml(name, sysname) + "%sHandler" % name, interopNS) + del_subscript_str = delete_sub_xml(name, sysname, interopNS) + trigger_str = trigger_xml(typ, interopNS) print "CreateFilter:\n%s\n" % filter_str print "DeleteFilter:\n%s\n" % del_filter_str @@ -380,15 +616,20 @@ def dump_xml(name, typ, ns, sysname): print "DeleteHandler:\n%s\n" % del_handler_str print "CreateSubscription:\n%s\n" % subscript_str print "DeleteSubscription:\n%s\n" % del_subscript_str - + print "Indication trigger:\n%s\n" % trigger_str + def main(): usage = "usage: %prog [options] provider\nex: %prog CIM_InstModification" parser = OptionParser(usage) - + + # FIXME: SecureHTTPServer still relies on this, need a better way. + global options + parser.add_option("-u", "--url", dest="url", default="localhost:5988", help="URL of CIMOM to connect to (host:port)") - parser.add_option("-N", "--ns", dest="ns", default="root/virt", - help="Namespace (default is root/virt)") + parser.add_option("-N", "--ns", dest="ns", + help="Namespace in which the register the indication \ + (default is the same value as the interop namespace)") parser.add_option("-n", "--name", dest="name", default="Test", help="Name for filter, handler, subscription \ (default: Test)") @@ -398,43 +639,123 @@ def main(): parser.add_option("-p", "--print-ind", dest="print_ind", default=False, action="store_true", help="Print received indications to stdout.") + parser.add_option("-v", "--verbose", dest="verbose", default=False, + action="store_true", + help="Print additional debug info.") parser.add_option("-U", "--user", dest="username", default=None, - help="HTTP Auth username") + help="HTTP Auth username (CIMOM)") parser.add_option("-P", "--pass", dest="password", default=None, - help="HTTP Auth password") + help="HTTP Auth password (CIMOM)") parser.add_option("--port", dest="port", default=0, type=int, help="Port increment value (server default: 8000)") + parser.add_option("--dest", dest="destUrl", default="localhost:8000", + help="URL of destination handler \ + (default: http://localhost:8000)") + parser.add_option("--certFile", dest="certFile", default=None, + help="File containing the local certificate to use") + parser.add_option("--keyFile", dest="keyFile", default=None, + help="File containing private key for local cert \ + (if none provided, assume key is in the certFile)") + parser.add_option("--trustStore", dest="trustStore", default=None, + help="File containing trusted certificates for \ + remote endpoint verification") + parser.add_option("--noverify", dest="noverify", default=False, + action="store_true", + help="Skip verification of remote endpoint certificate \ + for incoming https indications") + parser.add_option("-i", "--interop", dest="interop", + default="root/interop", + help="Interop namespace name (default: root/interop)") + parser.add_option("-t", "--trigger", dest="trigger", default=False, + action="store_true", + help="Trigger mode: send a request to CIMOM to trigger \ + an indication via a method call ") (options, args) = parser.parse_args() - if len(args) == 0: + if not options.trigger and len(args)==0: print "Fatal: no indication type provided." sys.exit(1) - + if options.username: auth = (options.username, options.password) else: auth = None - + if ":" in options.url: (sysname, port) = options.url.split(":") else: sysname = options.url - + + if "/" in options.interop: + options.interopNS = tuple(options.interop.split("/")) + else: + options.interopNS = ("root", options.interop) + + # If no value provided for indication NS, default is same as interopNS. + if not options.ns: + options.ns = "%s/%s" % options.interopNS + + if options.verbose: + print "Interop namespace = %s/%s" % options.interopNS + print "Indication namespace = %s" % options.ns + + # If url does not begin with http or https, assume http. + parsedUrl = urlparse(options.destUrl) + if not re.search(parsedUrl.scheme, "https"): + destUrl = "http://" + options.destUrl + else: + destUrl = options.destUrl + + if parsedUrl.scheme == "https": + if not options.trustStore and not options.noverify: + print "Error: must provide --trustStore or --noverify with https." + sys.exit(1) + elif options.trustStore and options.noverify: + print "Error: options --trustStore and --noverify are exclusive." + sys.exit(1) + if not options.certFile: + print "Error: no certificate file provided." + sys.exit(1) + elif not options.keyFile: + print "No keyFile provided; assuming private key \ + contained in certFile." + options.keyFile = options.certFile + if options.dump: - dump_xml(options.name, args[0], options.ns, sysname) + if isinstance(parsedUrl.port, int): + listenerPort = parsedUrl.port + options.port + else: + listenerPort = 8000 + options.port + + destUrl = update_url_port(parsedUrl, listenerPort) + dump_xml(options.name, args[0], options.ns, sysname, options.interopNS, + destUrl) + sys.exit(0) + + # Trigger mode: currently only supports SFCB Test_Indication provider. + if options.trigger: + classname = "Test_Indication" + sub = CIMIndicationSubscription(options.name, classname, options.ns, + options.print_ind, sysname, options.port, + options.interopNS, destUrl, True) + print "Triggering indication for %s" % classname + sub.trigger(options.url, auth) sys.exit(0) sub = CIMIndicationSubscription(options.name, args[0], options.ns, - options.print_ind, sysname, options.port) + options.print_ind, sysname, options.port, + options.interopNS, destUrl) + + print "Creating subscription for %s" % args[0] sub.subscribe(options.url, auth) print "Watching for %s" % args[0] try: sub.server.serve_forever() - except KeyboardInterrupt,e: - sub.unsubscribe(auth) + except KeyboardInterrupt as e: print "Cancelling subscription for %s" % args[0] + sub.unsubscribe(auth, options.url) if __name__=="__main__": sys.exit(main()) -- 1.7.1 > -----Original Message----- > From: [email protected] [mailto:libvirt-cim- > [email protected]] On Behalf Of Sharad Mishra > Sent: Tuesday, March 20, 2012 1:37 PM > To: List for discussion and development of libvirt CIM > Subject: Re: [Libvirt-cim] cimtest - add SSL support to > indication_tester.py > > On Mon, 2012-03-19 at 19:41 -0400, Dave Heller wrote: > > Hi Sharad, > > > > Actually, I did modify the script in a way that it is still compatible > with > > cimtest (based on tests using ComputerSystemIndication > > In that case, I am going to apply your patch and test as update to > existing indication script. > > > 01_created_indication). But if you think it makes sense to fork it to a > > standalone script (and rename it), that is fine too. > > > > The usage of the script as I intend is interactive from the command > line. I > > can add some documentation with example commands. Is there a standard > place > > this should go, or should I add a README? > > You can add it to the script header itself. > Do you want to send another patch with usage added and "orig" removed > from the file name? > > Regards, > Sharad Mishra > > > > > Thanks, > > Dave > > > > > -----Original Message----- > > > From: [email protected] [mailto:libvirt-cim- > > > [email protected]] On Behalf Of Sharad Mishra > > > Sent: Monday, March 19, 2012 5:40 PM > > > To: List for discussion and development of libvirt CIM > > > Subject: Re: [Libvirt-cim] cimtest - add SSL support to > > > indication_tester.py > > > > > > Dave, > > > > > > I assume that this patch is not going to be applied to the existing > > > indication_tester.py in cimtest. In that case, we can add this > modified > > > indication_tester.py as a new file at the same location as current > > > indication_tester.py. We do need to give this script a new name. This > > > script is currently not used/invoked by any existing cimtests. Do you > > > want to write tests to use this script? > > > > > > Regards > > > Sharad Mishra > > > > > > On Mon, 2012-03-19 at 13:21 -0400, Dave Heller wrote: > > > > In the XenKvmLib directory in cimtest, there is a > "indication_tester.py" > > > > module that is both a command-line program and a component of > cimtest. > > > Here > > > > is a proposed patch that adds new functionality to the cmdline > interface > > > > while preserving compatibility with cimtest. > > > > > > > > The most significant new feature is support for SSL indications. > There > > > is > > > > also a new --trigger mode to generate a test indication using the > SFCB > > > > Test_Indication provider. This allows the script to act as a > completely > > > > stand-alone test tool (for SFCB) without the user having to rely on > the > > > > "xmltest" files and wbemcat. > > > > > > > > Below is a complete list of the new features. I am looking for > feedback > > > and > > > > potentially, the correct process to check into "cimtest". > > > > > > > > Best regards, > > > > Dave Heller > > > > > > > > New features: > > > > > > > > - Supports https indications. Adds new options --certFile and -- > keyFile > > > to > > > > specify server certificate and private key for the SSL enabled > > > indication > > > > listener. > > > > - Supports verification of indication sender (i.e. CIMOM) SSL > > > certificate. > > > > New option --trustStore is used to specify the CA certificate file; > > > > alternately the --noverify option may be used to disable peer > > > certificate > > > > checking. > > > > - Adds new option --dest to specify handler destination. This same > URL > > > is > > > > used to register the subscription (at the CIMOM) and start the > > > indication > > > > listener (locally). Via --dest one can specify scheme (http or > https), > > > IP or > > > > hostname, listener port, and optionally userid:password, all in a > single > > > > parameter. > > > > - New option --interop can be used to override the default interop > > > namespace > > > > (i.e root/interop vs. root/PG_InterOp) allowing easy support for > both > > > > openpegasus and sfcb. > > > > - Modifies the default value of existing --ns option (indication > > > namespace); > > > > if not specified the indication namespace will default to the same > value > > > as > > > > the interop namespace. > > > > - New option --verbose can be used to display debugging info, such > as > > > > details (subject, issuer) of the indication sender cert (when peer > > > > verification enabled). > > > > - Improved error handling (i.e. catch exceptions) for the following > > > > operations: starting listener locally, receiving incoming > indications, > > > POST > > > > operations (i.e. subscribe, unsubscribe) to CIMOM. > > > > - New option --trigger can be used to send a request to CIMOM to > trigger > > > an > > > > indication via the SFCB Test_Indication provider. > > > > > > > > Limitations: > > > > > > > > - Not tested on IPv6. > > > > - The --trigger option currently only supports the sfcb > Test_Indication > > > > provider. (It could be made more general by allowing the XML send > to > > > > support an arbitrary namespace, classname and method call. Open to > > > > suggestions here.) > > > > > > > > _______________________________________________ Libvirt-cim mailing list [email protected] https://www.redhat.com/mailman/listinfo/libvirt-cim
