Changeset 058f58e


Ignore:
Timestamp:
Nov 20, 2008 7:14:58 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:
cfabc40
Parents:
c922f23
Message:

Unify the code for calling SOAP and XMLRPC services into a couple classes.
Before there were slightly different semantics everywhere.

Also make the handlers classes rather than the output of stub compiling
functions.

Location:
fedd
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • fedd/fedd.py

    rc922f23 r058f58e  
    212212    def do_POST(self):
    213213        """Treat an HTTP POST request as an XMLRPC service call"""
     214        # NB: XMLRPC faults are not HTTP errors, so the code is always 200,
     215        # unless an HTTP error occurs, which we don't handle.
    214216
    215217        resp = None
    216218        data = None
    217219        method = None
    218         code = 200
    219220        cl = int(self.headers['content-length'])
    220221        data = self.rfile.read(cl)
     
    225226            data = xmlrpclib.dumps(xmlrpclib.Fault("Client",
    226227                "Malformed request"), methodresponse=True)
    227             code = 500
    228228
    229229        if method != None:
     
    236236                data = xmlrpclib.dumps(f, methodresponse=True)
    237237                resp = None
    238                 code = 500
    239 
    240         self.send_xml(data, code)
     238
     239        self.send_xml(data)
    241240
    242241    def log_request(self, code=0, size=0):
  • fedd/fedd_access.py

    rc922f23 r058f58e  
    5252    id_list_attrs = ("restricted",)
    5353
    54     proxy_request, proxy_xmlrpc_request = make_service_callers('RequestAccess',
    55             'getfeddPortType', RequestAccessRequestMessage,
    56             'RequestAccessRequestBody')
     54    proxy_RequestAccess= \
     55            service_caller('RequestAccess', 'getfeddPortType',
     56                    feddServiceLocator, RequestAccessRequestMessage,
     57                    'RequestAccessRequestBody')
    5758
    5859    def __init__(self, config=None):
     
    153154
    154155        self.soap_services = {\
    155             'RequestAccess': make_soap_handler(\
     156            'RequestAccess': soap_handler(\
    156157                RequestAccessRequestMessage.typecode,\
    157158                self.RequestAccess, RequestAccessResponseMessage,\
    158159                "RequestAccessResponseBody"), \
    159             'ReleaseAccess': make_soap_handler(\
     160            'ReleaseAccess': soap_handler(\
    160161                ReleaseAccessRequestMessage.typecode,\
    161162                self.ReleaseAccess, ReleaseAccessResponseMessage,\
     
    163164            }
    164165        self.xmlrpc_services =  {\
    165             'RequestAccess': make_xmlrpc_handler(\
     166            'RequestAccess': xmlrpc_handler(\
    166167                self.RequestAccess, "RequestAccessResponseBody"),\
    167             'ReleaseAccess': make_xmlrpc_handler(\
     168            'ReleaseAccess': xmlrpc_handler(\
    168169                self.ReleaseAccess, "ReleaseAccessResponseBody")\
    169170            }
     
    698699            return resp
    699700        else:
    700             p_fault = None      # Any SOAP failure (sent unless XMLRPC works)
    701             try:
    702                 # Proxy the request using SOAP
    703                 self.log.debug("Sending proxy message to %s" % dt)
    704                 resp = self.proxy_request(dt, req, feddServiceLocator,
     701            resp = self.proxy_RequestAccess.call_service(dt, req,
    705702                        self.proxy_cert_file, self.proxy_cert_pwd,
    706703                        self.proxy_trusted_certs)
    707                 if resp.has_key('RequestAccessResponseBody'):
    708                     return resp['RequestAccessResponseBody']
    709                 elif resp.has_key('Fedd_FaultBody'):
    710                     raise service_error(resp['FeddFaultBody']['code'],
    711                             resp['FeddFaultBody']['desc'])
    712             except service_error, e:
    713                 if e.code == service_error.proxy: p_fault = None
    714                 else: raise
    715             except ZSI.FaultException, f:
    716                 p_fault = f.fault.detail[0]
    717                    
    718 
    719             # If we could not get a valid SOAP response to the request above,
    720             # try the same address using XMLRPC and let any faults flow back
    721             # out.
    722             if p_fault == None:
    723                 resp = self.proxy_xmlrpc_request(dt, req, self.proxy_cert_file,
    724                     self.proxy_cert_pwd, self.proxy_trusted_certs)
    725                 if resp.has_key('RequestAccessResponseBody'):
    726                     return resp['RequestAccessResponseBody']
     704            if resp.has_key('RequestAccessResponseBody'):
     705                return resp['RequestAccessResponseBody']
    727706            else:
    728                 # Build the fault
    729                 body = p_fault.get_element_FeddFaultBody()
    730                 if body != None:
    731                     raise service_error(body.get_element_code(),
    732                                 body.get_element_desc());
    733                 else:
    734                     raise service_error(\
    735                             service_error.proxy,
    736                             "Undefined fault from proxy??");
     707                return None
    737708
    738709    def ReleaseAccess(self, req, fid):
  • fedd/fedd_allocate_project.py

    rc922f23 r058f58e  
    7474        # Internal services are SOAP only
    7575        self.soap_services = {\
    76                 "AllocateProject": make_soap_handler(\
     76                "AllocateProject": soap_handler(\
    7777                AllocateProjectRequestMessage.typecode,\
    7878                self.dynamic_project, AllocateProjectResponseMessage,\
    7979                "AllocateProjectResponseBody"),
    80                 "StaticProject": make_soap_handler(\
     80                "StaticProject": soap_handler(\
    8181                StaticProjectRequestMessage.typecode,\
    8282                self.static_project, StaticProjectResponseMessage,\
    8383                "StaticProjectResponseBody"),\
    84                 "ReleaseProject": make_soap_handler(\
     84                "ReleaseProject": soap_handler(\
    8585                ReleaseProjectRequestMessage.typecode,\
    8686                self.release_project, ReleaseProjectResponseMessage,\
     
    345345        return { 'project': req['ReleaseProjectRequestBody']['project']}
    346346
    347 def make_proxy(method, req_name, req_alloc, resp_name):
    348     """
    349     Construct the proxy calling function from the given parameters.
    350     """
    351 
    352     # Define the proxy, NB, the parameters to make_proxy are visible to the
    353     # definition of proxy.
    354     def proxy(self, req, fedid=None):
    355         """
    356         Send req on to a remote project instantiator.
    357 
    358         Req is just the message to be sent.  This function re-wraps it.
    359         It also rethrows any faults.
    360         """
    361 
    362         # No retry loop here.  Proxy servers must correctly authenticate
    363         # themselves without help
    364         try:
    365             ctx = fedd_ssl_context(self.cert_file, self.trusted_certs,
    366                     password=self.cert_pwd)
    367         except SSL.SSLError:
    368             raise service_error(service_error.server_config,
    369                     "Server certificates misconfigured")
    370 
    371         loc = feddInternalServiceLocator();
    372         port = loc.getfeddInternalPortType(self.url,
    373                 transport=M2Crypto.httpslib.HTTPSConnection,
    374                 transdict={ 'ssl_context' : ctx })
    375 
    376         if req.has_key(req_name):
    377             req = req[req_name]
    378         else:
    379             raise service_error(service_error.req, "Bad formated request");
    380 
    381         # Reconstruct the full request message
    382         msg = req_alloc()
    383         set_elem = getattr(msg, "set_element_%s" % req_name)
    384         set_elem(pack_soap(msg, req_name, req))
    385         try:
    386             mattr = getattr(port, method)
    387             resp = mattr(msg)
    388         except ZSI.ParseException, e:
    389             raise service_error(service_error.proxy,
    390                     "Bad format message (XMLRPC??): %s" % str(e))
    391         except ZSI.FaultException, e:
    392             resp = e.fault.detail[0]
    393 
    394         r = unpack_soap(resp)
    395 
    396         if r.has_key(resp_name):
    397             return r[resp_name]
    398         else:
    399             raise service_error(service_error.proxy, "Bad proxy response")
    400     # NB: end of proxy function definition     
    401     return proxy
    402 
    403347class fedd_allocate_project_remote:
    404348    """
    405349    Allocate projects on a remote machine using the internal SOAP interface
    406350    """
    407     dynamic_project = make_proxy("AllocateProject",
    408             "AllocateProjectRequestBody", AllocateProjectRequestMessage,
    409             "AllocateProjectResponseBody")
    410     static_project = make_proxy("StaticProject",
    411             "StaticProjectRequestBody", StaticProjectRequestMessage,
    412             "StaticProjectResponseBody")
    413     release_project = make_proxy("ReleaseProject",
    414             "ReleaseProjectRequestBody", ReleaseProjectRequestMessage,
    415             "ReleaseProjectResponseBody")
    416 
     351    class proxy(service_caller):
     352        """
     353        This class is a proxy functor (callable) that has the same signature as
     354        a function called by soap_handler or xmlrpc_handler, but that used the
     355        service_caller class to call the function remotely.
     356        """
     357
     358        def __init__(self, url, cert_file, cert_pwd, trusted_certs,
     359                method, req_name, req_alloc, resp_name):
     360            service_caller.__init__(self, method, 'getfeddInternalPortType',
     361                    feddInternalServiceLocator, req_alloc, req_name)
     362            self.url = url
     363            self.cert_file = cert_file
     364            self.cert_pwd = cert_pwd
     365            self.trusted_certs = trusted_certs
     366            self.resp_name = resp_name
     367            # Calling the proxy object directly invokes the proxy_call method,
     368            # not the service_call method.
     369            self.__call__ = self.proxy_call
     370           
     371
     372        # Define the proxy, NB, the parameters to make_proxy are visible to the
     373        # definition of proxy.
     374        def proxy_call(self, req, fedid=None):
     375            """
     376            Send req on to a remote project instantiator.
     377
     378            Req is just the message to be sent.  This function re-wraps it.
     379            It also rethrows any faults.
     380            """
     381
     382            if req.has_key(self.request_body_name):
     383                req = req[self.request_body_name]
     384            else:
     385                raise service_error(service_error.req, "Bad formated request");
     386
     387            r = self.call_service(self.url, req, self.cert_file, self.cert_pwd,
     388                    self.trusted_certs)
     389            if r.has_key(self.resp_name):
     390                return r[self.resp_name]
     391            else:
     392                raise service_error(service_error.protocol,
     393                        "Bad proxy response")
     394
     395    # back to defining the fedd_allocate_project_remote class
    417396    def __init__(self, config):
    418397        """
     
    457436        self.log = logging.getLogger("fedd.allocate.remote")
    458437        set_log_level(config, "access", self.log)
     438        # The specializations of the proxy functions
     439        self.dynamic_project = self.proxy(self.url, self.cert_file,
     440                self.cert_pwd, self.trusted_certs, "AllocateProject",
     441                "AllocateProjectRequestBody", AllocateProjectRequestMessage,
     442                "AllocateProjectResponseBody")
     443        self.static_project = self.proxy(self.url, self.cert_file,
     444                self.cert_pwd, self.trusted_certs, "StaticProject",
     445                "StaticProjectRequestBody", StaticProjectRequestMessage,
     446                "StaticProjectResponseBody")
     447        self.release_project = self.proxy(self.url, self.cert_file,
     448                self.cert_pwd, self.trusted_certs, "ReleaseProject",
     449                "ReleaseProjectRequestBody", ReleaseProjectRequestMessage,
     450                "ReleaseProjectResponseBody")
     451
  • fedd/fedd_client.py

    rc922f23 r058f58e  
    2121
    2222from fedd_util import fedid, fedd_ssl_context, pack_soap, unpack_soap, \
    23         pack_id, unpack_id, encapsulate_binaries, decapsulate_binaries
     23        pack_id, unpack_id, encapsulate_binaries, decapsulate_binaries, \
     24        service_caller
     25from service_error import *
    2426
    2527from optparse import OptionParser, OptionValueError
     
    190192    def __init__(self, pre):
    191193        """
    192         Specialize the class for the prc method
     194        Specialize the class for the pre method
    193195        """
    194196        self.RequestMessage = globals()["%sRequestMessage" % pre]
     
    197199        self.ResponseBody="%sResponseBody" % pre
    198200        self.method = pre
     201
     202        method_call = getattr(feddServiceLocator().getfeddPortType(),
     203                self.method, None)
     204        if method_call:
     205            # The pre method is a fedd external service
     206            self.caller = service_caller(self.method, 'getfeddPortType',
     207                    feddServiceLocator, self.RequestMessage, self.RequestBody)
     208        else:
     209            # The pre method is a fedd internal service
     210            self.caller = service_caller(self.method,
     211                    'getfeddInternalPortType', feddInternalServiceLocator,
     212                    self.RequestMessage, self.RequestBody)
     213
    199214        self.RPCException = fedd_rpc.RPCException
    200215
     
    265280
    266281        if transport == "soap":
    267             loc = feddServiceLocator();
    268             port = loc.getfeddPortType(url,
    269                     transport=M2Crypto.httpslib.HTTPSConnection,
    270                     transdict={ 'ssl_context' : context },
    271                     tracefile=tracefile)
    272             method_call = getattr(port, self.method, None)
    273 
    274             if not method_call:
    275                 loc = feddInternalServiceLocator();
    276                 port = loc.getfeddInternalPortType(url,
    277                         transport=M2Crypto.httpslib.HTTPSConnection,
    278                         transdict={ 'ssl_context' : context },
    279                         tracefile=tracefile)
    280                 method_call = getattr(port, self.method, None)
    281                 if not method_call:
    282                     raise RuntimeError("Can't find method: %s" % self.method)
    283 
    284             req = self.RequestMessage()
    285 
    286             set_req = getattr(req, "set_element_%s" % self.RequestBody, None)
    287             set_req(pack_soap(req, self.RequestBody, req_dict))
    288 
    289282            if serialize_only:
    290283                sw = SoapWriter()
     
    292285                print str(sw)
    293286                sys.exit(0)
    294 
    295             try:
    296                 method_call = getattr(port, self.method, None)
    297                 resp = method_call(req)
    298             except ZSI.ParseException, e:
    299                 raise RuntimeError("Malformed response (XMLPRC?): %s" % e)
    300             except ZSI.FaultException, e:
    301                 resp = e.fault.detail[0]
    302 
    303             if resp:
    304                 resp_call = getattr(resp, "get_element_%s" %self.ResponseBody,
    305                         None)
    306                 if resp_call:
    307                     resp_body = resp_call()
    308                     if ( resp_body != None):
    309                         try:
    310                             return unpack_soap(resp_body)
    311                         except RuntimeError, e:
    312                             raise RuntimeError("Bad response. %s" % e.message)
    313                 elif 'get_element_FeddFaultBody' in dir(resp):
    314                     resp_body = resp.get_element_FeddFaultBody()
    315                     if resp_body != None:
    316                         try:
    317                             fb = unpack_soap(resp_body)
    318                         except RuntimeError, e:
    319                             raise RuntimeError("Bad response. %s" % e.message)
    320                         raise self.RPCException(fb)
    321                 else:
    322                     raise RuntimeError("No body in response!?")
    323             else:
    324                 raise RuntimeError("No response?!?")
     287            else:
     288                try:
     289                    resp = self.caller.call_soap_service(url, req_dict,
     290                            context=context, tracefile=tracefile)
     291                except service_error, e:
     292                    raise self.RPCException( {'code': e.code, 'desc': e.desc })
    325293        elif transport == "xmlrpc":
    326294            if serialize_only:
     
    328296                print ser
    329297                sys.exit(0)
    330 
    331             xtransport = SSL_Transport(context)
    332             port = ServerProxy(url, transport=xtransport)
    333 
    334             try:
    335                 method_call = getattr(port, self.method, None)
    336                 resp = method_call(
    337                         encapsulate_binaries({ self.RequestBody: req_dict},\
    338                             ('fedid',)))
    339             except Error, e:
    340                 resp = { 'FeddFaultBody': \
    341                         { 'errstr' : getattr(e, "faultCode", "No fault code"),
    342                         'desc' : getattr(e, "faultString", "No fault string") }\
    343                         }
    344             if resp:
    345                 if resp.has_key(self.ResponseBody):
    346                     return decapsulate_binaries(resp[self.ResponseBody],
    347                             ('fedid',))
    348                 elif resp.has_key('FeddFaultBody'):
    349                     raise self.RPCException(resp['FeddFaultBody'])
    350                 else:
    351                     raise RuntimeError("No body in response!?")
    352             else:
    353                 raise RuntimeError("No response?!?")
     298            else:
     299                try:
     300                    resp = self.caller.call_xmlrpc_service(url, req_dict,
     301                            context=context, tracefile=tracefile)
     302                except service_error, e:
     303                    raise self.RPCException( {'code': e.code, 'desc': e.desc })
     304
    354305        else:
    355306            raise RuntimeError("Unknown RPC transport: %s" % transport)
     307
     308        if resp.has_key(self.ResponseBody):
     309            return resp[self.ResponseBody]
     310        else:
     311            raise RuntimeError("No body in response??")
    356312
    357313# Querying experiment data follows the same control flow regardless of the
     
    606562            for id in eid:
    607563                for k in id.keys():
    608                     if k == 'fedid': print "%s: %s" % (k,fedid(bits=id[k]))
    609                     else: print "%s: %s" % (k, id[k])
     564                    print "%s: %s" % (k, id[k])
    610565
    611566class split(fedd_rpc):
  • fedd/fedd_experiment_control.py

    rc922f23 r058f58e  
    145145                self.pdata.terminate()
    146146
     147    call_RequestAccess = service_caller('RequestAccess',
     148            'getfeddPortType', feddServiceLocator,
     149            RequestAccessRequestMessage, 'RequestAccessRequestBody')
     150
     151    call_ReleaseAccess = service_caller('ReleaseAccess',
     152            'getfeddPortType', feddServiceLocator,
     153            ReleaseAccessRequestMessage, 'ReleaseAccessRequestBody')
     154
     155    call_Ns2Split = service_caller('Ns2Split',
     156            'getfeddInternalPortType', feddInternalServiceLocator,
     157            Ns2SplitRequestMessage, 'Ns2SplitRequestBody')
     158
    147159    def __init__(self, config=None):
    148160        """
     
    242254        # Dispatch tables
    243255        self.soap_services = {\
    244                 'Create': make_soap_handler(\
     256                'Create': soap_handler(\
    245257                        CreateRequestMessage.typecode,
    246258                        getattr(self, "create_experiment"),
    247259                        CreateResponseMessage,
    248260                        "CreateResponseBody"),
    249                 'Vtopo': make_soap_handler(\
     261                'Vtopo': soap_handler(\
    250262                        VtopoRequestMessage.typecode,
    251263                        getattr(self, "get_vtopo"),
    252264                        VtopoResponseMessage,
    253265                        "VtopoResponseBody"),
    254                 'Vis': make_soap_handler(\
     266                'Vis': soap_handler(\
    255267                        VisRequestMessage.typecode,
    256268                        getattr(self, "get_vis"),
    257269                        VisResponseMessage,
    258270                        "VisResponseBody"),
    259                 'Info': make_soap_handler(\
     271                'Info': soap_handler(\
    260272                        InfoRequestMessage.typecode,
    261273                        getattr(self, "get_info"),
    262274                        InfoResponseMessage,
    263275                        "InfoResponseBody"),
    264                 'Terminate': make_soap_handler(\
     276                'Terminate': soap_handler(\
    265277                        TerminateRequestMessage.typecode,
    266278                        getattr(self, "terminate_experiment"),
     
    270282
    271283        self.xmlrpc_services = {\
    272                 'Create': make_xmlrpc_handler(\
     284                'Create': xmlrpc_handler(\
    273285                        getattr(self, "create_experiment"),
    274286                        "CreateResponseBody"),
    275                 'Vtopo': make_xmlrpc_handler(\
     287                'Vtopo': xmlrpc_handler(\
    276288                        getattr(self, "get_vtopo"),
    277289                        "VtopoResponseBody"),
    278                 'Vis': make_xmlrpc_handler(\
     290                'Vis': xmlrpc_handler(\
    279291                        getattr(self, "get_vis"),
    280292                        "VisResponseBody"),
    281                 'Info': make_xmlrpc_handler(\
     293                'Info': xmlrpc_handler(\
    282294                        getattr(self, "get_info"),
    283295                        "InfoResponseBody"),
    284                 'Terminate': make_xmlrpc_handler(\
     296                'Terminate': xmlrpc_handler(\
    285297                        getattr(self, "terminate_experiment"),
    286298                        "TerminateResponseBody"),
     
    816828            req['resources']['node'] = rnodes
    817829
    818         # No retry loop here.  Proxy servers must correctly authenticate
    819         # themselves without help
    820 
    821         try:
    822             ctx = fedd_ssl_context(self.cert_file,
    823                     self.trusted_certs, password=self.cert_pwd)
    824         except SSL.SSLError:
    825             raise service_error(service_error.server_config,
    826                     "Server certificates misconfigured")
    827 
    828         loc = feddServiceLocator();
    829         port = loc.getfeddPortType(uri,
    830                 transport=M2Crypto.httpslib.HTTPSConnection,
    831                 transdict={ 'ssl_context' : ctx })
    832 
    833         # Reconstruct the full request message
    834         msg = RequestAccessRequestMessage()
    835         msg.set_element_RequestAccessRequestBody(
    836                 pack_soap(msg, "RequestAccessRequestBody", req))
    837 
    838         try:
    839             resp = port.RequestAccess(msg)
    840         except ZSI.ParseException, e:
    841             raise service_error(service_error.req,
    842                     "Bad format message (XMLRPC??): %s" % str(e))
    843         except ZSI.FaultException, e:
    844             resp = e.fault.detail[0]
    845 
    846         # Again, weird incompatibilities rear their head.  userRoles, which are
    847         # restricted strings, seem to be encoded by ZSI as non-unicode strings
    848         # in a way that confuses the pickling and XMLRPC sending systems.
    849         # Explicitly unicoding them seems to fix this, though it concerns me
    850         # some.  It may be that these things are actually a ZSI string
    851         # subclass, and the character encoding is not the major issue.  In any
    852         # case, making all the subclasses of basestring into unicode strings
    853         # unifies the response format and solves the problem.
    854         r = make_unicode(fedids_to_obj(unpack_soap(resp)))
     830        r = self.call_RequestAccess(uri, req,
     831                self.cert_file, self.cert_pwd, self.trusted_certs)
    855832
    856833        if r.has_key('RequestAccessResponseBody'):
    857834            r = r['RequestAccessResponseBody']
    858835        else:
    859             raise service_error(service_error.proxy,
     836            raise service_error(service_error.protocol,
    860837                    "Bad proxy response")
    861838
     
    894871                    "Unknown testbed: %s" % tb)
    895872
    896         # The basic request
    897         req = { 'allocID' : aid }
    898 
    899         # No retry loop here.  Proxy servers must correctly authenticate
    900         # themselves without help
    901         try:
    902             ctx = fedd_ssl_context(self.cert_file,
    903                     self.trusted_certs, password=self.cert_pwd)
    904         except SSL.SSLError:
    905             raise service_error(service_error.server_config,
    906                     "Server certificates misconfigured")
    907 
    908         loc = feddServiceLocator();
    909         port = loc.getfeddPortType(uri,
    910                 transport=M2Crypto.httpslib.HTTPSConnection,
    911                 transdict={ 'ssl_context' : ctx })
    912 
    913         # Reconstruct the full request message
    914         msg = ReleaseAccessRequestMessage()
    915         msg.set_element_ReleaseAccessRequestBody(
    916                 pack_soap(msg, "ReleaseAccessRequestBody", req))
    917 
    918         try:
    919             resp = port.ReleaseAccess(msg)
    920         except ZSI.ParseException, e:
    921             raise service_error(service_error.req,
    922                     "Bad format message (XMLRPC??): %s" % str(e))
    923         except ZSI.FaultException, e:
    924             resp = e.fault.detail[0]
     873        resp = self.call_ReleaseAccess(uri, {'allocID': aid},
     874                self.cert_file, self.cert_pwd, self.trusted_certs)
    925875
    926876        # better error coding
     
    934884            }
    935885
    936         # No retry loop here.  Proxy servers must correctly authenticate
    937         # themselves without help
    938         try:
    939             ctx = fedd_ssl_context(self.cert_file,
    940                     self.trusted_certs, password=self.cert_pwd)
    941         except SSL.SSLError:
    942             raise service_error(service_error.server_config,
    943                     "Server certificates misconfigured")
    944 
    945         loc = feddInternalServiceLocator();
    946         port = loc.getfeddInternalPortType(uri,
    947                 transport=M2Crypto.httpslib.HTTPSConnection,
    948                 transdict={ 'ssl_context' : ctx })
    949 
    950         # Reconstruct the full request message
    951         msg = Ns2SplitRequestMessage()
    952         msg.set_element_Ns2SplitRequestBody(
    953                 pack_soap(msg, "Ns2SplitRequestBody", req))
    954 
    955         try:
    956             resp = port.Ns2Split(msg)
    957         except ZSI.ParseException, e:
    958             raise service_error(service_error.req,
    959                     "Bad format message (XMLRPC??): %s" %
    960                     str(e))
    961         r = unpack_soap(resp)
     886        r = self.call_Ns2Split(uri, req, self.cert_file, self.cert_pwd,
     887                self.trusted_certs)
     888
    962889        if r.has_key('Ns2SplitResponseBody'):
    963890            r = r['Ns2SplitResponseBody']
     
    965892                return r['output'].splitlines()
    966893            else:
    967                 raise service_error(service_error.proxy,
     894                raise service_error(service_error.protocol,
    968895                        "Bad splitter response (no output)")
    969896        else:
    970             raise service_error(service_error.proxy, "Bad splitter response")
     897            raise service_error(service_error.protocol, "Bad splitter response")
    971898       
    972899    class current_testbed:
  • fedd/fedd_split.py

    rc922f23 r058f58e  
    6262        # Dispatch tables
    6363        self.soap_services = {\
    64                 'Ns2Split': make_soap_handler(\
     64                'Ns2Split': soap_handler(\
    6565                        Ns2SplitRequestMessage.typecode,
    6666                        getattr(self, "run_splitter"),
     
    7070
    7171        self.xmlrpc_services = {\
    72                 'Ns2Split': make_xmlrpc_handler(\
     72                'Ns2Split': xmlrpc_handler(\
    7373                        getattr(self, "run_splitter"),
    7474                        "Ns2SplitResponseBody"),
  • fedd/fedd_types.xsd

    rc922f23 r058f58e  
    629629        <xsd:restriction>
    630630          <xsd:enumeration value="1"/>  <!-- access denied -->
    631           <xsd:enumeration value="2"/>  <!-- proxy error -->
     631          <xsd:enumeration value="2"/>  <!-- protocol error -->
    632632          <xsd:enumeration value="3"/>  <!-- badly formed request -->
    633633          <xsd:enumeration value="4"/>  <!-- server configuration error -->
  • fedd/fedd_util.py

    rc922f23 r058f58e  
    368368
    369369
    370 def make_soap_handler(typecode, method, constructor, body_name):
    371     """
    372     Generate the handler code to unpack and pack SOAP requests and responses
     370class soap_handler:
     371    """
     372    Encapsulate the handler code to unpack and pack SOAP requests and responses
    373373    and call the given method.
    374374
    375375    The code to decapsulate and encapsulate parameters encoded in SOAP is the
    376     same modulo a few parameters.  This is basically a stub compiler for
    377     calling a fedd service trhough a soap interface.  The parameters are the
    378     typecode of the request parameters, the method to call (usually a bound
    379     instance of a method on a fedd service providing class), the constructor of
    380     a response packet and the name of the body element of that packet.  The
    381     handler takes a ParsedSoap object (the request) and returns an instance of
    382     the class created by constructor containing the response.  Failures of the
    383     constructor or badly created constructors will result in None being
    384     returned.
    385     """
    386     def handler(ps, fid):
    387         req = ps.Parse(typecode)
    388 
    389         msg = method(fedids_to_obj(unpack_soap(req)), fid)
    390 
    391         resp = constructor()
    392         set_element = getattr(resp, "set_element_%s" % body_name, None)
     376    same modulo a few parameters.  This is a functor that calls a fedd service
     377    trhough a soap interface.  The parameters are the typecode of the request
     378    parameters, the method to call (usually a bound instance of a method on a
     379    fedd service providing class), the constructor of a response packet and the
     380    name of the body element of that packet.  The handler takes a ParsedSoap
     381    object (the request) and returns an instance of the class created by
     382    constructor containing the response.  Failures of the constructor or badly
     383    created constructors will result in None being returned.
     384    """
     385    def __init__(self, typecode, method, constructor, body_name):
     386        self.typecode = typecode
     387        self.method = method
     388        self.constructor = constructor
     389        self.body_name = body_name
     390
     391    def __call__(self, ps, fid):
     392        req = ps.Parse(self.typecode)
     393
     394        msg = self.method(fedids_to_obj(unpack_soap(req)), fid)
     395
     396        resp = self.constructor()
     397        set_element = getattr(resp, "set_element_%s" % self.body_name, None)
    393398        if set_element and callable(set_element):
    394399            try:
    395                 set_element(pack_soap(resp, body_name, msg))
     400                set_element(pack_soap(resp, self.body_name, msg))
    396401                return resp
    397402            except (NameError, TypeError):
     
    400405            return None
    401406
    402     return handler
    403 
    404 def make_xmlrpc_handler(method, body_name):
    405     """
    406     Generate the handler code to unpack and pack SOAP requests and responses
     407class xmlrpc_handler:
     408    """
     409    Generate the handler code to unpack and pack XMLRPC requests and responses
    407410    and call the given method.
    408411
     
    416419    to fedid objects on input and encapsulated as Binaries on output.
    417420    """
    418     def handler(params, fid):
    419         decap_fedids = (('fedid', lambda x: fedid(bits=x.data)),)
    420 
    421         p = apply_to_tags(params[0], decap_fedids)
    422         msg = method(p, fid)
    423 
     421    def __init__(self, method, body_name):
     422        self.method = method
     423        self.body_name = body_name
     424        # A map used by apply_to_tags to convert fedids from xmlrpclib.Binary
     425        # objects to fedid objects in one sweep.
     426        self.decap_fedids = (('fedid', lambda x: fedid(bits=x.data)),)
     427
     428    def __call__(self, params, fid):
     429        msg = None
     430
     431        p = apply_to_tags(params[0], self.decap_fedids)
     432        try:
     433            msg = self.method(p, fid)
     434        except service_error, e:
     435            raise Fault(e.code_string(), e.desc)
    424436        if msg != None:
    425             return make_unicode(encapsulate_binaries({ body_name: msg }, ('fedid',)))
     437            return make_unicode(encapsulate_binaries(\
     438                    { self.body_name: msg }, ('fedid',)))
    426439        else:
    427440            return None
    428441
    429     return handler
    430 
    431 def make_service_callers(service_name, port_name, request_message,
    432         request_body_name):
     442class service_caller:
     443    def __init__(self, service_name, port_name, locator, request_message,
     444            request_body_name, tracefile=None):
     445        self.service_name = service_name
     446        self.port_name = port_name
     447        self.locator = locator
     448        self.request_message = request_message
     449        self.request_body_name = request_body_name
     450        self.tracefile = tracefile
     451        self.__call__ = self.call_service
    433452
    434453    def call_xmlrpc_service(self, url, req, cert_file=None, cert_pwd=None,
    435             trusted_certs=None):
     454            trusted_certs=None, context=None, tracefile=None):
    436455        """Send an XMLRPC request.  """
    437456        decap_fedids = (('fedid', lambda x: fedid(bits=x.data)),)
    438457
    439         # No retry loop here.  Proxy servers must correctly authenticate
    440         # themselves without help
    441         try:
    442             ctx = fedd_ssl_context(cert_file, trusted_certs, password=cert_pwd)
    443         except SSL.SSLError:
    444             raise service_error(service_error.server_config,
    445                     "Server certificates misconfigured")
     458
     459        # If a context is given, use it.  Otherwise construct one from
     460        # components.  The construction shouldn't call out for passwords.
     461        if context:
     462            ctx = context
     463        else:
     464            try:
     465                ctx = fedd_ssl_context(cert_file, trusted_certs,
     466                        password=cert_pwd)
     467            except SSL.SSLError:
     468                raise service_error(service_error.server_config,
     469                        "Certificates misconfigured")
    446470
    447471        # Of all the dumbass things.  The XMLRPC library in use here won't
    448         # properly encode unicode strings, so we make a copy of req with the
    449         # unicode objects converted.  We also convert the url to a basic string
    450         # if it isn't one already.
     472        # properly encode unicode strings, so we make a copy of req with
     473        # the unicode objects converted.  We also convert the url to a
     474        # basic string if it isn't one already.
    451475        r = strip_unicode(copy.deepcopy(req))
    452476        url = str(url)
     
    454478        transport = SSL_Transport(ctx)
    455479        port = ServerProxy(url, transport=transport)
     480        # Make the call, and convert faults back to service_errors
    456481        try:
    457             remote_method = getattr(port, service_name, None)
    458             resp = remote_method(encapsulate_binaries({ request_body_name: r},
    459                 ('fedid',)))
     482            remote_method = getattr(port, self.service_name, None)
     483            resp = remote_method(encapsulate_binaries(\
     484                    { self.request_body_name: r}, ('fedid',)))
    460485        except Fault, f:
    461486            raise service_error(None, f.faultString, f.faultCode)
    462487        except Error, e:
    463             raise service_error(service_error.proxy,
     488            raise service_error(service_error.protocol,
    464489                    "Remote XMLRPC Fault: %s" % e)
    465490
    466491        return apply_to_tags(resp, decap_fedids)
    467492
    468     def call_soap_service(self, url, req, loc_const, cert_file=None, cert_pwd=None,
    469             trusted_certs=None):
     493    def call_soap_service(self, url, req, cert_file=None, cert_pwd=None,
     494            trusted_certs=None, context=None, tracefile=None):
    470495        """
    471496        Send req on to the real destination in dt and return the response
     
    474499        also rethrows any faults.
    475500        """
    476         # No retry loop here.  Proxy servers must correctly authenticate
    477         # themselves without help
    478         try:
    479             ctx = fedd_ssl_context(cert_file, trusted_certs, password=cert_pwd)
    480         except SSL.SSLError:
    481             raise service_error(service_error.server_config,
    482                     "Server certificates misconfigured")
    483 
    484         loc = loc_const()
    485         get_port = getattr(loc, port_name, None)
     501
     502        tf = tracefile or self.tracefile or None
     503
     504        # If a context is given, use it.  Otherwise construct one from
     505        # components.  The construction shouldn't call out for passwords.
     506        if context:
     507            ctx = context
     508        else:
     509            try:
     510                ctx = fedd_ssl_context(cert_file, trusted_certs,
     511                        password=cert_pwd)
     512            except SSL.SSLError:
     513                raise service_error(service_error.server_config,
     514                        "Certificates misconfigured")
     515        loc = self.locator()
     516        get_port = getattr(loc, self.port_name, None)
    486517        if not get_port:
    487518            raise service_error(service_error.internal,
    488                     "Cannot get port %s from locator" % port_name)
     519                    "Cannot get port %s from locator" % self.port_name)
    489520        port = get_port(url,
    490521                transport=M2Crypto.httpslib.HTTPSConnection,
    491                 transdict={ 'ssl_context' : ctx })
    492         remote_method = getattr(port, service_name, None)
     522                transdict={ 'ssl_context' : ctx },
     523                tracefile=tf)
     524        remote_method = getattr(port, self.service_name, None)
    493525        if not remote_method:
    494526            raise service_error(service_error.internal,
     
    496528
    497529        # Reconstruct the full request message
    498         msg = request_message()
    499         set_element = getattr(msg, "set_element_%s" % request_body_name, None)
     530        msg = self.request_message()
     531        set_element = getattr(msg, "set_element_%s" % self.request_body_name,
     532                None)
    500533        if not set_element:
    501534            raise service_error(service_error.internal,
    502535                    "Cannot get element setting method for %s" % \
    503                             request_body_name)
    504         set_element(pack_soap(msg, request_body_name, req))
     536                            self.request_body_name)
     537        set_element(pack_soap(msg, self.request_body_name, req))
    505538        try:
    506539            resp = remote_method(msg)
    507540        except ZSI.ParseException, e:
    508             raise service_error(service_error.proxy,
    509                     "Bad format message (XMLRPC??): %s" %
    510                     str(e))
    511         r = unpack_soap(resp)
     541            raise service_error(service_error.protocol,
     542                    "Bad format message (XMLRPC??): %s" % e)
     543        except ZSI.FaultException, e:
     544            ee = unpack_soap(e.fault.detail[0]).get('FeddFaultBody', { })
     545            if ee:
     546                raise service_error(ee['code'], ee['desc'])
     547            else:
     548                raise service_error(service_error.internal,
     549                        "Unexpected fault body")
     550        r = make_unicode(fedids_to_obj(unpack_soap(resp)))
    512551        return r
    513552
    514     return (call_soap_service, call_xmlrpc_service)
     553    def call_service(self, url, req, cert_file=None, cert_pwd=None,
     554        trusted_certs=None, context=None, tracefile=None):
     555        p_fault = None  # Any SOAP failure (sent unless XMLRPC works)
     556        resp = None
     557        try:
     558            # Try the SOAP request
     559            resp = self.call_soap_service(url, req,
     560                    cert_file, cert_pwd, trusted_certs, context, tracefile)
     561            return resp
     562        except service_error, e:
     563            if e.code == service_error.protocol: p_fault = None
     564            else: raise
     565        except ZSI.FaultException, f:
     566            p_fault = f.fault.detail[0]
     567               
     568
     569        # If we could not get a valid SOAP response to the request above,
     570        # try the same address using XMLRPC and let any faults flow back
     571        # out.
     572        if p_fault == None:
     573            resp = self.call_xmlrpc_service(url, req, cert_file,
     574                    cert_pwd, trusted_certs, context, tracefile)
     575            return resp
     576        else:
     577            # Build the fault
     578            ee = unpack_soap(p_fault).get('FeddFaultBody', { })
     579            if ee:
     580                raise service_error(ee['code'], ee['desc'])
     581            else:
     582                raise service_error(service_error.internal,
     583                        "Unexpected fault body")
     584
    515585
    516586def set_log_level(config, sect, log):
  • fedd/service_error.py

    rc922f23 r058f58e  
    66class service_error(RuntimeError):
    77    access = 1
    8     proxy= 2
     8    protocol= 2
    99    req = 3
    1010    server_config = 4
     
    1414    code_str = {
    1515        access : "Access Denied",
    16         proxy : "Proxy Error",
     16        protocol : "Protocol Error",
    1717        req : "Badly Formed Request",
    1818        server_config: "Server Configuration Error",
     
    2323    str_code = dict([ (v, k) for k, v in code_str.iteritems() ])
    2424    client_errors = ( req )
    25     server_errors = ( access, proxy, server_config, internal)
     25    server_errors = ( access, protocol, server_config, internal)
    2626
    2727    def __init__(self, code=None, desc=None, from_string=None):
Note: See TracChangeset for help on using the changeset viewer.