Changeset 058f58e for fedd/fedd_util.py
- Timestamp:
- Nov 20, 2008 7:14:58 PM (15 years ago)
- Branches:
- axis_example, compt_changes, info-ops, master, version-1.30, version-2.00, version-3.01, version-3.02
- Children:
- cfabc40
- Parents:
- c922f23
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
fedd/fedd_util.py
rc922f23 r058f58e 368 368 369 369 370 def make_soap_handler(typecode, method, constructor, body_name):371 """ 372 Generate the handler code to unpack and pack SOAP requests and responses370 class soap_handler: 371 """ 372 Encapsulate the handler code to unpack and pack SOAP requests and responses 373 373 and call the given method. 374 374 375 375 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) 393 398 if set_element and callable(set_element): 394 399 try: 395 set_element(pack_soap(resp, body_name, msg))400 set_element(pack_soap(resp, self.body_name, msg)) 396 401 return resp 397 402 except (NameError, TypeError): … … 400 405 return None 401 406 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 407 class xmlrpc_handler: 408 """ 409 Generate the handler code to unpack and pack XMLRPC requests and responses 407 410 and call the given method. 408 411 … … 416 419 to fedid objects on input and encapsulated as Binaries on output. 417 420 """ 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) 424 436 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',))) 426 439 else: 427 440 return None 428 441 429 return handler 430 431 def make_service_callers(service_name, port_name, request_message, 432 request_body_name): 442 class 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 433 452 434 453 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): 436 455 """Send an XMLRPC request. """ 437 456 decap_fedids = (('fedid', lambda x: fedid(bits=x.data)),) 438 457 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") 446 470 447 471 # 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 the449 # unicode objects converted. We also convert the url to a basic string450 # 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. 451 475 r = strip_unicode(copy.deepcopy(req)) 452 476 url = str(url) … … 454 478 transport = SSL_Transport(ctx) 455 479 port = ServerProxy(url, transport=transport) 480 # Make the call, and convert faults back to service_errors 456 481 try: 457 remote_method = getattr(port, se rvice_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',))) 460 485 except Fault, f: 461 486 raise service_error(None, f.faultString, f.faultCode) 462 487 except Error, e: 463 raise service_error(service_error.pro xy,488 raise service_error(service_error.protocol, 464 489 "Remote XMLRPC Fault: %s" % e) 465 490 466 491 return apply_to_tags(resp, decap_fedids) 467 492 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): 470 495 """ 471 496 Send req on to the real destination in dt and return the response … … 474 499 also rethrows any faults. 475 500 """ 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) 486 517 if not get_port: 487 518 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) 489 520 port = get_port(url, 490 521 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) 493 525 if not remote_method: 494 526 raise service_error(service_error.internal, … … 496 528 497 529 # 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) 500 533 if not set_element: 501 534 raise service_error(service_error.internal, 502 535 "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)) 505 538 try: 506 539 resp = remote_method(msg) 507 540 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))) 512 551 return r 513 552 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 515 585 516 586 def set_log_level(config, sect, log):
Note: See TracChangeset
for help on using the changeset viewer.