X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=sfa%2Futil%2Fapi.py;h=67d155e78fab8b18f7df2c2c68c3ad2ddec0057c;hb=3eea82897aba845da0d12c1ba56012e599f58853;hp=1b86aae7e6be5d8b8f2d717f3c95f8f9912a1fc1;hpb=1f96bfc77a793cc88422c967e12102211523e459;p=sfa.git diff --git a/sfa/util/api.py b/sfa/util/api.py index 1b86aae7..67d155e7 100644 --- a/sfa/util/api.py +++ b/sfa/util/api.py @@ -1,8 +1,5 @@ # -# Geniwrapper XML-RPC and SOAP interfaces -# -### $Id: api.py 15596 2009-10-31 21:42:05Z anil $ -### $URL: https://svn.planet-lab.org/svn/sfa/trunk/sfa/plc/api.py $ +# SFA XML-RPC and SOAP interfaces # import sys @@ -11,14 +8,12 @@ import traceback import string import xmlrpclib +from sfa.util.sfalogging import logger from sfa.trust.auth import Auth from sfa.util.config import * from sfa.util.faults import * -from sfa.util.debug import * from sfa.trust.credential import * from sfa.trust.certificate import * -from sfa.util.misc import * -from sfa.util.sfalogging import * # See "2.2 Characters" in the XML specification: # @@ -95,17 +90,41 @@ def import_deep(name): mod = getattr(mod, comp) return mod +class ManagerWrapper: + """ + This class acts as a wrapper around an SFA interface manager module, but + can be used with any python module. The purpose of this class is raise a + SfaNotImplemented exception if the a someone attepmts to use an attribute + (could be a callable) thats not available in the library by checking the + library using hasattr. This helps to communicate better errors messages + to the users and developers in the event that a specifiec operation + is not implemented by a libarary and will generally be more helpful than + the standard AttributeError + """ + def __init__(self, manager, interface): + self.manager = manager + self.interface = interface + + def __getattr__(self, method): + + if not hasattr(self.manager, method): + raise SfaNotImplemented(method, self.interface) + return getattr(self.manager, method) + class BaseAPI: - def __init__(self, config = "/etc/sfa/sfa_config", encoding = "utf-8", methods='sfa.methods', - peer_cert = None, interface = None, key_file = None, cert_file = None): + cache = None + protocol = None + + def __init__(self, config = "/etc/sfa/sfa_config.py", encoding = "utf-8", + methods='sfa.methods', peer_cert = None, interface = None, + key_file = None, cert_file = None, cache = cache): self.encoding = encoding # flat list of method names - methods_module = __import__(methods) - self.methods_module = methods_module - self.methods = methods_module.methods.all + self.methods_module = methods_module = __import__(methods, fromlist=[methods]) + self.methods = methods_module.all # Better just be documenting the API if config is None: @@ -114,33 +133,70 @@ class BaseAPI: # Load configuration self.config = Config(config) self.auth = Auth(peer_cert) + self.hrn = self.config.SFA_INTERFACE_HRN self.interface = interface self.key_file = key_file self.key = Keypair(filename=self.key_file) self.cert_file = cert_file self.cert = Certificate(filename=self.cert_file) + self.cache = cache self.credential = None - + self.source = None self.time_format = "%Y-%m-%d %H:%M:%S" - self.logger=get_sfa_logger() + self.logger = logger + + # load registries + from sfa.server.registry import Registries + self.registries = Registries(self) + + # load aggregates + from sfa.server.aggregate import Aggregates + self.aggregates = Aggregates(self) + def get_interface_manager(self, manager_base = 'sfa.managers'): + """ + Returns the appropriate manager module for this interface. + Modules are usually found in sfa/managers/ + """ + + if self.interface in ['registry']: + mgr_type = self.config.SFA_REGISTRY_TYPE + manager_module = manager_base + ".registry_manager_%s" % mgr_type + elif self.interface in ['aggregate']: + mgr_type = self.config.SFA_AGGREGATE_TYPE + manager_module = manager_base + ".aggregate_manager_%s" % mgr_type + elif self.interface in ['slicemgr', 'sm']: + mgr_type = self.config.SFA_SM_TYPE + manager_module = manager_base + ".slice_manager_%s" % mgr_type + elif self.interface in ['component', 'cm']: + mgr_type = self.config.SFA_CM_TYPE + manager_module = manager_base + ".component_manager_%s" % mgr_type + else: + raise SfaAPIError("No manager for interface: %s" % self.interface) + manager = __import__(manager_module, fromlist=[manager_base]) + # this isnt necessary but will hlep to produce better error messages + # if someone tries to access an operation this manager doesn't implement + manager = ManagerWrapper(manager, self.interface) + + return manager + def callable(self, method): """ Return a new instance of the specified method. """ # Look up method if method not in self.methods: - raise GeniInvalidAPIMethod, method + raise SfaInvalidAPIMethod, method # Get new instance of method try: classname = method.split(".")[-1] - module = __import__(self.methods_module.methods.__name__ + "." + method, globals(), locals(), [classname]) + module = __import__(self.methods_module.__name__ + "." + method, globals(), locals(), [classname]) callablemethod = getattr(module, classname)(self) return getattr(module, classname)(self) except ImportError, AttributeError: - raise GeniInvalidAPIMethod, method + raise SfaInvalidAPIMethod, method def call(self, source, method, *args): """ @@ -149,19 +205,26 @@ class BaseAPI: """ function = self.callable(method) function.source = source + self.source = source return function(*args) - def handle(self, source, data): + + def handle(self, source, data, method_map): """ Handle an XML-RPC or SOAP request from the specified source. """ # Parse request into method name and arguments try: interface = xmlrpclib + self.protocol = 'xmlrpclib' (args, method) = xmlrpclib.loads(data) + if method_map.has_key(method): + method = method_map[method] methodresponse = True + except Exception, e: if SOAPpy is not None: + self.protocol = 'soap' interface = SOAPpy (r, header, body, attrs) = parseSOAPRPC(data, header = 1, body = 1, attrs = 1) method = r._name @@ -172,26 +235,34 @@ class BaseAPI: try: result = self.call(source, method, *args) + except SfaFault, fault: + result = fault except Exception, fault: - traceback.print_exc(file = log) - # Handle expected faults - if interface == xmlrpclib: - result = fault - methodresponse = None - elif interface == SOAPpy: - result = faultParameter(NS.ENV_T + ":Server", "Method Failed", method) - result._setDetail("Fault %d: %s" % (fault.faultCode, fault.faultString)) - else: - raise + logger.log_exc("BaseAPI.handle has caught Exception") + result = SfaAPIError(fault) + # Return result - if interface == xmlrpclib: - if not isinstance(result, GeniFault): + response = self.prepare_response(result, method) + return response + + def prepare_response(self, result, method=""): + """ + convert result to a valid xmlrpc or soap response + """ + + if self.protocol == 'xmlrpclib': + if not isinstance(result, SfaFault): result = (result,) - - data = xmlrpclib.dumps(result, methodresponse = True, encoding = self.encoding, allow_none = 1) - elif interface == SOAPpy: - data = buildSOAP(kw = {'%sResponse' % method: {'Result': result}}, encoding = self.encoding) - - return data - + response = xmlrpclib.dumps(result, methodresponse = True, encoding = self.encoding, allow_none = 1) + elif self.protocol == 'soap': + if isinstance(result, Exception): + result = faultParameter(NS.ENV_T + ":Server", "Method Failed", method) + result._setDetail("Fault %d: %s" % (result.faultCode, result.faultString)) + else: + response = buildSOAP(kw = {'%sResponse' % method: {'Result': result}}, encoding = self.encoding) + else: + if isinstance(result, Exception): + raise result + + return response