Changeset 0a20ef8


Ignore:
Timestamp:
Nov 29, 2008 10:22:17 PM (15 years ago)
Author:
Ted Faber <faber@…>
Branches:
axis_example, compt_changes, info-ops, master, version-1.30, version-2.00, version-3.01, version-3.02
Children:
2729e48
Parents:
1b57352
Message:

Cleaner split for module definition

Location:
fedd
Files:
2 added
1 edited

Legend:

Unmodified
Added
Removed
  • fedd/fedd.py

    r1b57352 r0a20ef8  
    33import sys
    44
    5 from socket import error as socket_error
    6 from BaseHTTPServer import BaseHTTPRequestHandler
    7 
    8 from ZSI import Fault, ParseException, FaultFromNotUnderstood, \
    9     FaultFromZSIException, FaultFromException, ParsedSoap, SoapWriter
    10 
    11 from M2Crypto import SSL
    12 from M2Crypto.SSL.SSLServer import ThreadingSSLServer
    13 import xmlrpclib
    14 
    155from optparse import OptionParser
    166
     7from fedd_server import fedd_server, fedd_xmlrpc_handler, fedd_soap_handler
     8from fedd_config_parser import fedd_config_parser
    179from fedd_util import fedd_ssl_context
    18 from fedid import fedid
    1910from fedd_deter_impl import new_feddservice
    20 from fedd_services import ns0
    21 from service_error import *
    2211
    2312from threading import *
     
    2615from time import sleep
    2716import logging
    28 from ConfigParser import *
    29 
    30 # The SSL server here is based on the implementation described at
    31 # http://www.xml.com/pub/a/ws/2004/01/20/salz.html
    32 
    33 # Turn off the matching of hostname to certificate ID
    34 SSL.Connection.clientPostConnectionCheck = None
    35 
    36 class fedd_config_parser(SafeConfigParser):
    37     """
    38     A SafeConfig parser with a more forgiving get attribute
    39     """
    40 
    41     def safe_get(self, sect, opt, method, default=None):
    42         """
    43         If the option is present, return it, otherwise the default.
    44         """
    45         if self.has_option(sect, opt): return method(self, sect, opt)
    46         else: return default
    47 
    48     def get(self, sect, opt, default=None):
    49         """
    50         This returns the requested option or a given default.
    51 
    52         It's more like getattr than get.
    53         """
    54 
    55         return self.safe_get(sect, opt, SafeConfigParser.get, default)
    56 
    57     def getint(self, sect, opt, default=0):
    58         """
    59         Returns the selected option as an int or a default.
    60         """
    61 
    62         return self.safe_get(sect, opt, SafeConfigParser.getint, default)
    63 
    64     def getfloat(self, sect, opt, default=0.0):
    65         """
    66         Returns the selected option as an int or a default.
    67         """
    68 
    69         return self.safe_get(sect, opt, SafeConfigParser.getfloat, default)
    70 
    71     def getboolean(self, sect, opt, default=False):
    72         """
    73         Returns the selected option as a boolean or a default.
    74         """
    75 
    76         return self.safe_get(sect, opt, SafeConfigParser.getboolean, default)
    77 
    78 class fedd_server(ThreadingSSLServer):
    79     """
    80     Interface the fedd services to the XMLRPC and SOAP interfaces
    81     """
    82     def __init__(self, ME, handler, ssl_ctx, impl):
    83         """
    84         Create an SSL server that handles the transport in handler using the
    85         credentials in ssl_ctx, and interfacing to the implementation of fedd
    86         services in fedd.  ME is the host port pair on which to bind.
    87         """
    88         ThreadingSSLServer.__init__(self, ME, handler, ssl_ctx)
    89         self.impl = impl
    90         self.soap_methods = impl.soap_services
    91         self.xmlrpc_methods = impl.xmlrpc_services
    92         self.log = logging.getLogger("fedd")
    93 
    94     def handle_error(self, request, address):
    95         """
    96         The default SSLServer prints a stack trace here.  This is a little
    97         friendlier.
    98         """
    99         if request or address:
    100             self.log.warn("[fedd] Error on incoming connection: %s %s" % \
    101                     (request, address))
    102         else:
    103             self.log.warn("[fedd] Error on incoming connection " + \
    104                     "(Likely SSL error)")
    105 
    106 class fedd_soap_handler(BaseHTTPRequestHandler):
    107     """
    108     Standard connection between SOAP and the fedd services in impl.
    109 
    110     Much of this is boilerplate from
    111     http://www.xml.com/pub/a/ws/2004/01/20/salz.html
    112     """
    113     server_version = "ZSI/2.0 fedd/0.1 " + BaseHTTPRequestHandler.server_version
    114 
    115     def send_xml(self, text, code=200):
    116         """Send an XML document as reply"""
    117         self.send_response(code)
    118         self.send_header('Content-type', 'text/xml; charset="utf-8"')
    119         self.send_header('Content-Length', str(len(text)))
    120         self.end_headers()
    121         self.wfile.write(text)
    122         self.wfile.flush()
    123         self.request.socket.close()
    124 
    125     def send_fault(self, f, code=500):
    126         """Send a SOAP encoded fault as reply"""
    127         self.send_xml(f.AsSOAP(processContents="lax"), code)
    128 
    129     def check_headers(self, ps):
    130         """Send a fault for any required envelope headers"""
    131         for (uri, localname) in ps.WhatMustIUnderstand():
    132             self.send_fault(FaultFromNotUnderstood(uri, lname, 'fedd'))
    133             return False
    134         return  True
    135 
    136     def check_method(self, ps):
    137         """Confirm that this class implements the namespace and SOAP method"""
    138         root = ps.body_root
    139         if root.namespaceURI not in self.server.impl.soap_namespaces:
    140             self.send_fault(Fault(Fault.Client,
    141                 'Unknown namespace "%s"' % root.namespaceURI))
    142             return False
    143 
    144         if getattr(root, 'localName', None) == None:
    145             self.send_fault(Fault(Fault.Client, 'No method"'))
    146             return False
    147         return True
    148 
    149     def do_POST(self):
    150         """Treat an HTTP POST request as a SOAP service call"""
    151         try:
    152             cl = int(self.headers['content-length'])
    153             data = self.rfile.read(cl)
    154             ps = ParsedSoap(data)
    155         except ParseException, e:
    156             self.send_fault(Fault(Fault.Client, str(e)))
    157             return
    158         except Exception, e:
    159             self.send_fault(FaultFromException(e, 0, sys.exc_info()[2]))
    160             return
    161         if not self.check_headers(ps): return
    162         if not self.check_method(ps): return
    163         try:
    164             resp = self.soap_dispatch(ps.body_root.localName, ps,
    165                     fedid(cert=self.request.get_peer_cert()))
    166         except Fault, f:
    167             self.send_fault(f)
    168             resp = None
    169        
    170         if resp != None:
    171             sw = SoapWriter()
    172             sw.serialize(resp)
    173             self.send_xml(str(sw))
    174 
    175     def log_request(self, code=0, size=0):
    176         """
    177         Log request to the fedd logger
    178         """
    179         self.server.log.info("Successful SOAP request code %d" % code)
    180 
    181     def soap_dispatch(self, method, req, fid):
    182         """
    183         The connection to the implementation, using the  method maps
    184 
    185         The implementation provides a mapping from SOAP method name to the
    186         method in the implementation that provides the service.
    187         """
    188         if self.server.soap_methods.has_key(method):
    189             try:
    190                 return self.server.soap_methods[method](req, fid)
    191             except service_error, e:
    192                 de = ns0.faultType_Def(
    193                         (ns0.faultType_Def.schema,
    194                             "FeddFaultBody")).pyclass()
    195                 de._code=e.code
    196                 de._errstr=e.code_string()
    197                 de._desc=e.desc
    198                 if  e.is_server_error():
    199                     raise Fault(Fault.Server, e.code_string(), detail=de)
    200                 else:
    201                     raise Fault(Fault.Client, e.code_string(), detail=de)
    202         else:
    203             raise Fault(Fault.Client, "Unknown method: %s" % method)
    204 
    205 
    206 class fedd_xmlrpc_handler(BaseHTTPRequestHandler):
    207     """
    208     Standard connection between XMLRPC and the fedd services in impl.
    209 
    210     Much of this is boilerplate from
    211     http://www.xml.com/pub/a/ws/2004/01/20/salz.html
    212     """
    213     server_version = "ZSI/2.0 fedd/0.1 " + BaseHTTPRequestHandler.server_version
    214 
    215     def send_xml(self, text, code=200):
    216         """Send an XML document as reply"""
    217         self.send_response(code)
    218         self.send_header('Content-type', 'text/xml; charset="utf-8"')
    219         self.send_header('Content-Length', str(len(text)))
    220         self.end_headers()
    221         self.wfile.write(text)
    222         self.wfile.flush()
    223         # Make sure to close the socket when we're done
    224         self.request.socket.close()
    225 
    226     def do_POST(self):
    227         """Treat an HTTP POST request as an XMLRPC service call"""
    228         # NB: XMLRPC faults are not HTTP errors, so the code is always 200,
    229         # unless an HTTP error occurs, which we don't handle.
    230 
    231         resp = None
    232         data = None
    233         method = None
    234         cl = int(self.headers['content-length'])
    235         data = self.rfile.read(cl)
    236 
    237         try:
    238             params, method = xmlrpclib.loads(data)
    239         except xmlrpclib.ResponseError:
    240             data = xmlrpclib.dumps(xmlrpclib.Fault("Client",
    241                 "Malformed request"), methodresponse=True)
    242 
    243         if method != None:
    244             try:
    245                 resp = self.xmlrpc_dispatch(method, params,
    246                             fedid(cert=self.request.get_peer_cert()))
    247                 data = xmlrpclib.dumps((resp,), encoding='UTF-8',
    248                         methodresponse=True)
    249             except xmlrpclib.Fault, f:
    250                 data = xmlrpclib.dumps(f, methodresponse=True)
    251                 resp = None
    252 
    253         self.send_xml(data)
    254 
    255     def log_request(self, code=0, size=0):
    256         """
    257         Log request to the fedd logger
    258         """
    259         self.server.log.info("Successful XMLRPC request code %d" % code)
    260 
    261 
    262     def xmlrpc_dispatch(self, method, req, fid):
    263         """
    264         The connection to the implementation, using the  method maps
    265 
    266         The implementation provides a mapping from XMLRPC method name to the
    267         method in the implementation that provides the service.
    268         """
    269         if self.server.xmlrpc_methods.has_key(method):
    270             try:
    271                 return self.server.xmlrpc_methods[method](req, fid)
    272             except service_error, e:
    273                 raise xmlrpclib.Fault(e.code_string(), e.desc)
    274         else:
    275             raise xmlrpclib.Fault(100, "Unknown method: %s" % method)
    27617
    27718class fedd_opts(OptionParser):
Note: See TracChangeset for help on using the changeset viewer.