Changeset 9460b1e
- Timestamp:
- Nov 21, 2008 10:43:39 AM (16 years ago)
- Branches:
- axis_example, compt_changes, info-ops, master, version-1.30, version-2.00, version-3.01, version-3.02
- Children:
- 51cc9df
- Parents:
- f8b118e
- Location:
- fedd
- Files:
-
- 1 added
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
fedd/fedd_access.py
rf8b118e r9460b1e 24 24 import parse_detail 25 25 from service_error import * 26 from remote_service import xmlrpc_handler, soap_handler, service_caller 26 27 import logging 27 28 -
fedd/fedd_allocate_project.py
rf8b118e r9460b1e 21 21 from fedd_util import * 22 22 from fixed_resource import read_key_db, read_project_db 23 from remote_service import xmlrpc_handler, soap_handler, service_caller 23 24 from service_error import * 24 25 import logging -
fedd/fedd_client.py
rf8b118e r9460b1e 20 20 import xmlrpclib 21 21 22 from fedd_util import fedid, fedd_ssl_context, pack_id, unpack_id , \23 22 from fedd_util import fedid, fedd_ssl_context, pack_id, unpack_id 23 from remote_service import service_caller 24 24 from service_error import * 25 25 -
fedd/fedd_experiment_control.py
rf8b118e r9460b1e 27 27 from fedd_internal_services import * 28 28 from fedd_util import * 29 from remote_service import xmlrpc_handler, soap_handler, service_caller 29 30 import parse_detail 30 31 from service_error import * -
fedd/fedd_split.py
rf8b118e r9460b1e 27 27 from fedd_internal_services import * 28 28 from fedd_util import * 29 from remote_service import xmlrpc_handler, soap_handler 29 30 import parse_detail 30 31 from service_error import * -
fedd/fedd_util.py
rf8b118e r9460b1e 8 8 9 9 from M2Crypto import SSL, X509, EVP 10 from M2Crypto.m2xmlrpclib import SSL_Transport11 import M2Crypto.httpslib12 10 from pyasn1.codec.der import decoder 13 14 from fedd_services import *15 from fedd_internal_services import *16 from service_error import *17 from xmlrpclib import ServerProxy, dumps, loads, Fault, Error, Binary18 19 11 20 12 # The version of M2Crypto on users is pretty old and doesn't have all the … … 232 224 if certpath: os.remove(certpath) 233 225 234 # Used by the remote_service_base class.235 def to_binary(o):236 """237 A function that converts an object into an xmlrpclib.Binary using238 either its internal packing method, or the standard Binary constructor.239 """240 pack = getattr(o, 'pack_xmlrpc', None)241 if callable(pack): return Binary(pack())242 else: return Binary(o)243 244 # Classes that encapsulate the process of making and dealing with requests to245 # WSDL-generated and XMLRPC remote accesses.246 247 class remote_service_base:248 """249 This invisible base class encapsulates the functions used to massage the250 dictionaries used to pass parameters into and out of the RPC formats. It's251 mostly a container for the static methods to do that work, but defines some252 maps sued by sub classes on apply_to_tags253 """254 # A map used to convert fedid fields to fedid objects (when the field is255 # already a string)256 fedid_to_object = ( ('fedid', lambda x: fedid(bits=x)),)257 # A map used by apply_to_tags to convert fedids from xmlrpclib.Binary258 # objects to fedid objects in one sweep.259 decap_fedids = (('fedid', lambda x: fedid(bits=x.data)),)260 # A map used to encapsulate fedids into xmlrpclib.Binary objects261 encap_fedids = (('fedid', to_binary),)262 263 @staticmethod264 def pack_soap(container, name, contents):265 """266 Convert the dictionary in contents into a tree of ZSI classes.267 268 The holder classes are constructed from factories in container and269 assigned to either the element or attribute name. This is used to270 recursively create the SOAP message.271 """272 if getattr(contents, "__iter__", None) != None:273 attr =getattr(container, "new_%s" % name, None)274 if attr: obj = attr()275 else:276 raise TypeError("%s does not have a new_%s attribute" % \277 (container, name))278 for e, v in contents.iteritems():279 assign = getattr(obj, "set_element_%s" % e, None) or \280 getattr(obj, "set_attribute_%s" % e, None)281 if isinstance(v, type(dict())):282 assign(remote_service_base.pack_soap(obj, e, v))283 elif getattr(v, "__iter__", None) != None:284 assign([ remote_service_base.pack_soap(obj, e, val ) \285 for val in v])286 elif getattr(v, "pack_soap", None) != None:287 assign(v.pack_soap())288 else:289 assign(v)290 return obj291 else: return contents292 293 @staticmethod294 def unpack_soap(element):295 """296 Convert a tree of ZSI SOAP classes intro a hash. The inverse of297 pack_soap298 299 Elements or elements that are empty are ignored.300 """301 methods = [ m for m in dir(element) \302 if m.startswith("get_element") or m.startswith("get_attribute")]303 if len(methods) > 0:304 rv = { }305 for m in methods:306 if m.startswith("get_element_"):307 n = m.replace("get_element_","",1)308 else:309 n = m.replace("get_attribute_", "", 1)310 sub = getattr(element, m)()311 if sub != None:312 if isinstance(sub, basestring):313 rv[n] = sub314 elif getattr(sub, "__iter__", None) != None:315 if len(sub) > 0: rv[n] = \316 [remote_service_base.unpack_soap(e) \317 for e in sub]318 else:319 rv[n] = remote_service_base.unpack_soap(sub)320 return rv321 else:322 return element323 324 @staticmethod325 def apply_to_tags(e, map):326 """327 Map is an iterable of ordered pairs (tuples) that map a key to a328 function.329 This function walks the given message and replaces any object with a330 key in the map with the result of applying that function to the object.331 """332 if isinstance(e, dict):333 for k in e.keys():334 for tag, fcn in map:335 if k == tag:336 if isinstance(e[k], list):337 e[k] = [ fcn(b) for b in e[k]]338 else:339 e[k] = fcn(e[k])340 elif isinstance(e[k], dict):341 remote_service_base.apply_to_tags(e[k], map)342 elif isinstance(e[k], list):343 for ee in e[k]:344 remote_service_base.apply_to_tags(ee, map)345 # Other types end the recursion - they should be leaves346 return e347 348 @staticmethod349 def strip_unicode(obj):350 """Walk through a message and convert all strings to non-unicode351 strings"""352 if isinstance(obj, dict):353 for k in obj.keys():354 obj[k] = remote_service_base.strip_unicode(obj[k])355 return obj356 elif isinstance(obj, basestring) and not isinstance(obj, str):357 return str(obj)358 elif getattr(obj, "__iter__", None):359 return [ remote_service_base.strip_unicode(x) for x in obj]360 else:361 return obj362 363 @staticmethod364 def make_unicode(obj):365 """Walk through a message and convert all strings to unicode"""366 if isinstance(obj, dict):367 for k in obj.keys():368 obj[k] = remote_service_base.make_unicode(obj[k])369 return obj370 elif isinstance(obj, basestring) and not isinstance(obj, unicode):371 return unicode(obj)372 elif getattr(obj, "__iter__", None):373 return [ remote_service_base.make_unicode(x) for x in obj]374 else:375 return obj376 377 378 379 class soap_handler(remote_service_base):380 """381 Encapsulate the handler code to unpack and pack SOAP requests and responses382 and call the given method.383 384 The code to decapsulate and encapsulate parameters encoded in SOAP is the385 same modulo a few parameters. This is a functor that calls a fedd service386 trhough a soap interface. The parameters are the typecode of the request387 parameters, the method to call (usually a bound instance of a method on a388 fedd service providing class), the constructor of a response packet and the389 name of the body element of that packet. The handler takes a ParsedSoap390 object (the request) and returns an instance of the class created by391 constructor containing the response. Failures of the constructor or badly392 created constructors will result in None being returned.393 """394 def __init__(self, typecode, method, constructor, body_name):395 self.typecode = typecode396 self.method = method397 self.constructor = constructor398 self.body_name = body_name399 400 def __call__(self, ps, fid):401 req = ps.Parse(self.typecode)402 # Convert the message to a dict with the fedid strings converted to403 # fedid objects404 req = self.apply_to_tags(self.unpack_soap(req), self.fedid_to_object)405 406 msg = self.method(req, fid)407 408 resp = self.constructor()409 set_element = getattr(resp, "set_element_%s" % self.body_name, None)410 if set_element and callable(set_element):411 try:412 set_element(self.pack_soap(resp, self.body_name, msg))413 return resp414 except (NameError, TypeError):415 return None416 else:417 return None418 419 class xmlrpc_handler(remote_service_base):420 """421 Generate the handler code to unpack and pack XMLRPC requests and responses422 and call the given method.423 424 The code to marshall and unmarshall XMLRPC parameters to and from a fedd425 service is largely the same. This helper creates such a handler. The426 parameters are the method name, and the name of the body struct that427 contains the response. A handler is created that takes the params response428 from an xmlrpclib.loads on the incoming rpc and a fedid and responds with429 a hash representing the struct ro be returned to the other side. On error430 None is returned. Fedid fields are decapsulated from binary and converted431 to fedid objects on input and encapsulated as Binaries on output.432 """433 def __init__(self, method, body_name):434 self.method = method435 self.body_name = body_name436 437 def __call__(self, params, fid):438 msg = None439 440 p = self.apply_to_tags(params[0], self.decap_fedids)441 try:442 msg = self.method(p, fid)443 except service_error, e:444 raise Fault(e.code_string(), e.desc)445 if msg != None:446 return self.make_unicode(self.apply_to_tags(\447 { self.body_name: msg }, self.encap_fedids))448 else:449 return None450 451 class service_caller(remote_service_base):452 def __init__(self, service_name, port_name, locator, request_message,453 request_body_name, tracefile=None):454 self.service_name = service_name455 self.port_name = port_name456 self.locator = locator457 self.request_message = request_message458 self.request_body_name = request_body_name459 self.tracefile = tracefile460 self.__call__ = self.call_service461 462 def call_xmlrpc_service(self, url, req, cert_file=None, cert_pwd=None,463 trusted_certs=None, context=None, tracefile=None):464 """Send an XMLRPC request. """465 466 467 # If a context is given, use it. Otherwise construct one from468 # components. The construction shouldn't call out for passwords.469 if context:470 ctx = context471 else:472 try:473 ctx = fedd_ssl_context(cert_file, trusted_certs,474 password=cert_pwd)475 except SSL.SSLError:476 raise service_error(service_error.server_config,477 "Certificates misconfigured")478 479 # Of all the dumbass things. The XMLRPC library in use here won't480 # properly encode unicode strings, so we make a copy of req with481 # the unicode objects converted. We also convert the url to a482 # basic string if it isn't one already.483 r = self.strip_unicode(copy.deepcopy(req))484 url = str(url)485 486 transport = SSL_Transport(ctx)487 port = ServerProxy(url, transport=transport)488 # Make the call, and convert faults back to service_errors489 try:490 remote_method = getattr(port, self.service_name, None)491 resp = remote_method(self.apply_to_tags(\492 { self.request_body_name: r}, self.encap_fedids))493 except Fault, f:494 raise service_error(None, f.faultString, f.faultCode)495 except Error, e:496 raise service_error(service_error.protocol,497 "Remote XMLRPC Fault: %s" % e)498 499 return self.apply_to_tags(resp, self.decap_fedids)500 501 def call_soap_service(self, url, req, cert_file=None, cert_pwd=None,502 trusted_certs=None, context=None, tracefile=None):503 """504 Send req on to the real destination in dt and return the response505 506 Req is just the requestType object. This function re-wraps it. It507 also rethrows any faults.508 """509 510 tf = tracefile or self.tracefile or None511 512 # If a context is given, use it. Otherwise construct one from513 # components. The construction shouldn't call out for passwords.514 if context:515 ctx = context516 else:517 try:518 ctx = fedd_ssl_context(cert_file, trusted_certs,519 password=cert_pwd)520 except SSL.SSLError:521 raise service_error(service_error.server_config,522 "Certificates misconfigured")523 loc = self.locator()524 get_port = getattr(loc, self.port_name, None)525 if not get_port:526 raise service_error(service_error.internal,527 "Cannot get port %s from locator" % self.port_name)528 port = get_port(url,529 transport=M2Crypto.httpslib.HTTPSConnection,530 transdict={ 'ssl_context' : ctx },531 tracefile=tf)532 remote_method = getattr(port, self.service_name, None)533 if not remote_method:534 raise service_error(service_error.internal,535 "Cannot get service from SOAP port")536 537 # Reconstruct the full request message538 msg = self.request_message()539 set_element = getattr(msg, "set_element_%s" % self.request_body_name,540 None)541 if not set_element:542 raise service_error(service_error.internal,543 "Cannot get element setting method for %s" % \544 self.request_body_name)545 set_element(self.pack_soap(msg, self.request_body_name, req))546 try:547 resp = remote_method(msg)548 except ZSI.ParseException, e:549 raise service_error(service_error.protocol,550 "Bad format message (XMLRPC??): %s" % e)551 except ZSI.FaultException, e:552 ee = self.unpack_soap(e.fault.detail[0]).get('FeddFaultBody', { })553 if ee:554 raise service_error(ee['code'], ee['desc'])555 else:556 raise service_error(service_error.internal,557 "Unexpected fault body")558 # Unpack and convert fedids to objects559 r = self.apply_to_tags(self.unpack_soap(resp), self.fedid_to_object)560 # Make sure all strings are unicode561 r = self.make_unicode(r)562 return r563 564 def call_service(self, url, req, cert_file=None, cert_pwd=None,565 trusted_certs=None, context=None, tracefile=None):566 p_fault = None # Any SOAP failure (sent unless XMLRPC works)567 resp = None568 try:569 # Try the SOAP request570 resp = self.call_soap_service(url, req,571 cert_file, cert_pwd, trusted_certs, context, tracefile)572 return resp573 except service_error, e:574 if e.code == service_error.protocol: p_fault = None575 else: raise576 except ZSI.FaultException, f:577 p_fault = f.fault.detail[0]578 579 580 # If we could not get a valid SOAP response to the request above,581 # try the same address using XMLRPC and let any faults flow back582 # out.583 if p_fault == None:584 resp = self.call_xmlrpc_service(url, req, cert_file,585 cert_pwd, trusted_certs, context, tracefile)586 return resp587 else:588 # Build the fault589 ee = unpack_soap(p_fault).get('FeddFaultBody', { })590 if ee:591 raise service_error(ee['code'], ee['desc'])592 else:593 raise service_error(service_error.internal,594 "Unexpected fault body")595 596 597 226 def set_log_level(config, sect, log): 598 227 """ Set the logging level to the value passed in sect of config."""
Note: See TracChangeset
for help on using the changeset viewer.