Changeset f8b118e
- Timestamp:
- Nov 21, 2008 10:20:31 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:
- 9460b1e
- Parents:
- cfabc40
- Location:
- fedd
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
fedd/fedd_client.py
rcfabc40 rf8b118e 20 20 import xmlrpclib 21 21 22 from fedd_util import fedid, fedd_ssl_context, pack_soap, unpack_soap, \ 23 pack_id, unpack_id, encapsulate_binaries, decapsulate_binaries, \ 22 from fedd_util import fedid, fedd_ssl_context, pack_id, unpack_id, \ 24 23 service_caller 25 24 from service_error import * -
fedd/fedd_util.py
rcfabc40 rf8b118e 174 174 creating dictionaries to be converted to messages. 175 175 """ 176 if isinstance(id, type(fedid())): return { 'fedid': id }176 if isinstance(id, fedid): return { 'fedid': id } 177 177 elif id.startswith("http:") or id.startswith("https:"): return { 'uri': id } 178 178 else: return { 'localname': id} … … 180 180 def unpack_id(id): 181 181 """return id as a type determined by the key""" 182 if id.has_key("fedid"): return fedid(id["fedid"]) 183 else: 184 for k in ("localname", "uri", "kerberosUsername"): 185 if id.has_key(k): return id[k] 182 for k in ("localname", "fedid", "uri", "kerberosUsername"): 183 if id.has_key(k): return id[k] 186 184 return None 187 185 188 def pack_soap(container, name, contents): 189 """ 190 Convert the dictionary in contents into a tree of ZSI classes. 191 192 The holder classes are constructed from factories in container and assigned 193 to either the element or attribute name. This is used to recursively 194 create the SOAP message. 195 """ 196 if getattr(contents, "__iter__", None) != None: 197 attr =getattr(container, "new_%s" % name, None) 198 if attr: obj = attr() 199 else: 200 raise TypeError("%s does not have a new_%s attribute" % \ 201 (container, name)) 202 for e, v in contents.iteritems(): 203 assign = getattr(obj, "set_element_%s" % e, None) or \ 204 getattr(obj, "set_attribute_%s" % e, None) 205 if isinstance(v, type(dict())): 206 assign(pack_soap(obj, e, v)) 207 elif getattr(v, "__iter__", None) != None: 208 assign([ pack_soap(obj, e, val ) for val in v]) 209 elif getattr(v, "pack_soap", None) != None: 210 assign(v.pack_soap()) 211 else: 212 assign(v) 213 return obj 214 else: return contents 215 216 def unpack_soap(element): 217 """ 218 Convert a tree of ZSI SOAP classes intro a hash. The inverse of pack_soap 219 220 Elements or elements that are empty are ignored. 221 """ 222 methods = [ m for m in dir(element) \ 223 if m.startswith("get_element") or m.startswith("get_attribute")] 224 if len(methods) > 0: 225 rv = { } 226 for m in methods: 227 if m.startswith("get_element_"): n = m.replace("get_element_","",1) 228 else: n = m.replace("get_attribute_", "", 1) 229 sub = getattr(element, m)() 230 if sub != None: 231 if isinstance(sub, basestring): 232 rv[n] = sub 233 elif getattr(sub, "__iter__", None) != None: 234 if len(sub) > 0: rv[n] = [unpack_soap(e) for e in sub] 235 else: 236 rv[n] = unpack_soap(sub) 237 return rv 238 else: 239 return element 240 def apply_to_tags(e, map): 241 """ 242 Map is an iterable of ordered pairs (tuples) that map a key to a function. 243 This function walks the given message and replaces any object with a key in 244 the map with the result of applying that function to the object. 245 """ 246 dict_type = type(dict()) 247 list_type = type(list()) 248 str_type = type(str()) 249 250 if isinstance(e, dict_type): 251 for k in e.keys(): 252 for tag, fcn in map: 253 if k == tag: 254 if isinstance(e[k], list_type): 255 e[k] = [ fcn(b) for b in e[k]] 256 else: 257 e[k] = fcn(e[k]) 258 elif isinstance(e[k], dict_type): 259 apply_to_tags(e[k], map) 260 elif isinstance(e[k], list_type): 261 for ee in e[k]: 262 apply_to_tags(ee, map) 263 # Other types end the recursion - they should be leaves 264 return e 265 266 # These are all just specializations of apply_to_tags 267 def fedids_to_obj(e, tags=('fedid',)): 268 """ 269 Turn the fedids in a message that are encoded as bitstrings into fedid 270 objects. 271 """ 272 map = [ (t, lambda x: fedid(bits=x)) for t in tags] 273 return apply_to_tags(e, map) 274 275 def encapsulate_binaries(e, tags): 276 """Walk through a message and encapsulate any dictionary entries in 277 tags into a binary object.""" 278 279 def to_binary(o): 280 pack = getattr(o, 'pack_xmlrpc', None) 281 if callable(pack): return Binary(pack()) 282 else: return Binary(o) 283 284 map = [ (t, to_binary) for t in tags] 285 return apply_to_tags(e, map) 286 287 def decapsulate_binaries(e, tags): 288 """Walk through a message and encapsulate any dictionary entries in 289 tags into a binary object.""" 290 291 map = [ (t, lambda x: x.data) for t in tags] 292 return apply_to_tags(e, map) 293 #end of tag specializations 294 295 def strip_unicode(obj): 296 """Walk through a message and convert all strings to non-unicode strings""" 297 if isinstance(obj, dict): 298 for k in obj.keys(): 299 obj[k] = strip_unicode(obj[k]) 300 return obj 301 elif isinstance(obj, basestring): 302 return str(obj) 303 elif getattr(obj, "__iter__", None): 304 return [ strip_unicode(x) for x in obj] 305 else: 306 return obj 307 308 def make_unicode(obj): 309 """Walk through a message and convert all strings to unicode""" 310 if isinstance(obj, dict): 311 for k in obj.keys(): 312 obj[k] = make_unicode(obj[k]) 313 return obj 314 elif isinstance(obj, basestring): 315 return unicode(obj) 316 elif getattr(obj, "__iter__", None): 317 return [ make_unicode(x) for x in obj] 318 else: 319 return obj 320 321 322 def generate_fedid(subj, bits=2048, log=None, dir=None, trace=sys.stderr): 186 def generate_fedid(subj, bits=2048, log=None, dir=None, trace=sys.stderr, 187 ssl_prog="/usr/bin/openssl"): 323 188 """ 324 189 Create a new certificate and derive a fedid from it. … … 336 201 suffix=".pem") 337 202 338 cmd = [ "/usr/bin/openssl", "req", "-text", "-newkey",203 cmd = [ssl_prog, "req", "-text", "-newkey", 339 204 "rsa:%d" % bits, "-keyout", keypath, "-nodes", 340 205 "-subj", "/CN=%s" % subj, "-x509", "-days", "30", … … 367 232 if certpath: os.remove(certpath) 368 233 369 370 class soap_handler: 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 using 238 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 to 245 # WSDL-generated and XMLRPC remote accesses. 246 247 class remote_service_base: 248 """ 249 This invisible base class encapsulates the functions used to massage the 250 dictionaries used to pass parameters into and out of the RPC formats. It's 251 mostly a container for the static methods to do that work, but defines some 252 maps sued by sub classes on apply_to_tags 253 """ 254 # A map used to convert fedid fields to fedid objects (when the field is 255 # 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.Binary 258 # 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 objects 261 encap_fedids = (('fedid', to_binary),) 262 263 @staticmethod 264 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 and 269 assigned to either the element or attribute name. This is used to 270 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 obj 291 else: return contents 292 293 @staticmethod 294 def unpack_soap(element): 295 """ 296 Convert a tree of ZSI SOAP classes intro a hash. The inverse of 297 pack_soap 298 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] = sub 314 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 rv 321 else: 322 return element 323 324 @staticmethod 325 def apply_to_tags(e, map): 326 """ 327 Map is an iterable of ordered pairs (tuples) that map a key to a 328 function. 329 This function walks the given message and replaces any object with a 330 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 leaves 346 return e 347 348 @staticmethod 349 def strip_unicode(obj): 350 """Walk through a message and convert all strings to non-unicode 351 strings""" 352 if isinstance(obj, dict): 353 for k in obj.keys(): 354 obj[k] = remote_service_base.strip_unicode(obj[k]) 355 return obj 356 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 obj 362 363 @staticmethod 364 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 obj 370 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 obj 376 377 378 379 class soap_handler(remote_service_base): 371 380 """ 372 381 Encapsulate the handler code to unpack and pack SOAP requests and responses … … 391 400 def __call__(self, ps, fid): 392 401 req = ps.Parse(self.typecode) 393 394 msg = self.method(fedids_to_obj(unpack_soap(req)), fid) 402 # Convert the message to a dict with the fedid strings converted to 403 # fedid objects 404 req = self.apply_to_tags(self.unpack_soap(req), self.fedid_to_object) 405 406 msg = self.method(req, fid) 395 407 396 408 resp = self.constructor() … … 398 410 if set_element and callable(set_element): 399 411 try: 400 set_element( pack_soap(resp, self.body_name, msg))412 set_element(self.pack_soap(resp, self.body_name, msg)) 401 413 return resp 402 414 except (NameError, TypeError): … … 405 417 return None 406 418 407 class xmlrpc_handler :419 class xmlrpc_handler(remote_service_base): 408 420 """ 409 421 Generate the handler code to unpack and pack XMLRPC requests and responses … … 422 434 self.method = method 423 435 self.body_name = body_name 424 # A map used by apply_to_tags to convert fedids from xmlrpclib.Binary425 # objects to fedid objects in one sweep.426 self.decap_fedids = (('fedid', lambda x: fedid(bits=x.data)),)427 436 428 437 def __call__(self, params, fid): 429 438 msg = None 430 439 431 p = apply_to_tags(params[0], self.decap_fedids)440 p = self.apply_to_tags(params[0], self.decap_fedids) 432 441 try: 433 442 msg = self.method(p, fid) … … 435 444 raise Fault(e.code_string(), e.desc) 436 445 if msg != None: 437 return make_unicode(encapsulate_binaries(\438 { self.body_name: msg }, ('fedid',)))446 return self.make_unicode(self.apply_to_tags(\ 447 { self.body_name: msg }, self.encap_fedids)) 439 448 else: 440 449 return None 441 450 442 class service_caller :451 class service_caller(remote_service_base): 443 452 def __init__(self, service_name, port_name, locator, request_message, 444 453 request_body_name, tracefile=None): … … 454 463 trusted_certs=None, context=None, tracefile=None): 455 464 """Send an XMLRPC request. """ 456 decap_fedids = (('fedid', lambda x: fedid(bits=x.data)),)457 465 458 466 … … 473 481 # the unicode objects converted. We also convert the url to a 474 482 # basic string if it isn't one already. 475 r = s trip_unicode(copy.deepcopy(req))483 r = self.strip_unicode(copy.deepcopy(req)) 476 484 url = str(url) 477 485 … … 481 489 try: 482 490 remote_method = getattr(port, self.service_name, None) 483 resp = remote_method( encapsulate_binaries(\484 { self.request_body_name: r}, ('fedid',)))491 resp = remote_method(self.apply_to_tags(\ 492 { self.request_body_name: r}, self.encap_fedids)) 485 493 except Fault, f: 486 494 raise service_error(None, f.faultString, f.faultCode) … … 489 497 "Remote XMLRPC Fault: %s" % e) 490 498 491 return apply_to_tags(resp,decap_fedids)499 return self.apply_to_tags(resp, self.decap_fedids) 492 500 493 501 def call_soap_service(self, url, req, cert_file=None, cert_pwd=None, … … 535 543 "Cannot get element setting method for %s" % \ 536 544 self.request_body_name) 537 set_element( pack_soap(msg, self.request_body_name, req))545 set_element(self.pack_soap(msg, self.request_body_name, req)) 538 546 try: 539 547 resp = remote_method(msg) … … 542 550 "Bad format message (XMLRPC??): %s" % e) 543 551 except ZSI.FaultException, e: 544 ee = unpack_soap(e.fault.detail[0]).get('FeddFaultBody', { })552 ee = self.unpack_soap(e.fault.detail[0]).get('FeddFaultBody', { }) 545 553 if ee: 546 554 raise service_error(ee['code'], ee['desc']) … … 548 556 raise service_error(service_error.internal, 549 557 "Unexpected fault body") 550 r = make_unicode(fedids_to_obj(unpack_soap(resp))) 558 # Unpack and convert fedids to objects 559 r = self.apply_to_tags(self.unpack_soap(resp), self.fedid_to_object) 560 # Make sure all strings are unicode 561 r = self.make_unicode(r) 551 562 return r 552 563
Note: See TracChangeset
for help on using the changeset viewer.