[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] Move the decoration of all the Xen-API methods out of XendAPI.__init__ and
# HG changeset patch # User Ewan Mellor <ewan@xxxxxxxxxxxxx> # Date 1166787485 0 # Node ID 0d0e13ff1adfd55862f6d79438549f5f0d6b2c03 # Parent f7ac2c963f772e905f56c3c8ad0af57893628774 Move the decoration of all the Xen-API methods out of XendAPI.__init__ and into the module scope. This avoids the decorators being added multiple times, once for each server running. Fix handling of MESSAGE_PARAMETER_COUNT_MISMATCH in many cases. Move the get_by_uuid declarations, so that those functions get the per-class validator as well, to check for existence of the object requested. Signed-off-by: Ewan Mellor <ewan@xxxxxxxxxxxxx> --- tools/python/xen/xend/XendAPI.py | 363 ++++++++++++++++++--------------------- 1 files changed, 168 insertions(+), 195 deletions(-) diff -r f7ac2c963f77 -r 0d0e13ff1adf tools/python/xen/xend/XendAPI.py --- a/tools/python/xen/xend/XendAPI.py Fri Dec 22 11:34:13 2006 +0000 +++ b/tools/python/xen/xend/XendAPI.py Fri Dec 22 11:38:05 2006 +0000 @@ -15,7 +15,12 @@ # Copyright (C) 2006 XenSource Ltd. #============================================================================ +import inspect +import os import re +import string +import sys +import traceback from xen.xend import XendDomain, XendDomainInfo, XendNode from xen.xend import XendLogging @@ -52,7 +57,7 @@ def xen_api_error(error): if len(error) == 0: error = ['INTERNAL_ERROR', 'Empty list given to xen_api_error'] - return { "Status": "Error", + return { "Status": "Failure", "ErrorDescription": [str(x) for x in error] } @@ -79,17 +84,17 @@ def trace(func, api_name = ''): return trace_func -takesRE = re.compile(r'^(.*)\(\) takes exactly ([0-9]*) argument') +takesRE = re.compile(r' ([0-9]*) argument') def deconstruct_typeerror(exn): m = takesRE.search(exn[0]) - return m and m.groups() or None + return m and m.group(1) or None def catch_typeerror(func): """Decorator to catch any TypeErrors and translate them into Xen-API errors. - @param func: function with params: (self, session, host_ref) + @param func: function with params: (self, ...) @rtype: callable object """ def f(self, *args, **kwargs): @@ -97,44 +102,48 @@ def catch_typeerror(func): return func(self, *args, **kwargs) except TypeError, exn: if hasattr(func, 'api'): - mt = deconstruct_typeerror(exn) - if mt: - method, takes = mt - if method.endswith(func.api.split('.')[-1]): - return xen_api_error( - ['MESSAGE_PARAMETER_COUNT_MISMATCH', - func.api, int(takes) - 2, - len(args) + len(kwargs) - 1]) + takes = deconstruct_typeerror(exn) + if takes is not None: + # Assume that if the exception was thrown inside this + # file, then it is due to an invalid call from the client, + # but if it was thrown elsewhere, then it's an internal + # error (which will be handled further up). + tb = sys.exc_info()[2] + try: + sourcefile = traceback.extract_tb(tb)[-1][0] + if sourcefile == inspect.getsourcefile(XendAPI): + return xen_api_error( + ['MESSAGE_PARAMETER_COUNT_MISMATCH', + func.api, int(takes) - 2, + len(args) + len(kwargs) - 1]) + finally: + del tb raise - # make sure we keep the 'api' attribute - if hasattr(func, 'api'): - f.api = func.api - return f def session_required(func): + """Decorator to verify if session is valid before calling method. + + @param func: function with params: (self, session, ...) + @rtype: callable object + """ def check_session(self, session, *args, **kwargs): if auth_manager().is_session_valid(session): return func(self, session, *args, **kwargs) else: return xen_api_error(['SESSION_INVALID', session]) - # make sure we keep the 'api' attribute - if hasattr(func, 'api'): - check_session.api = func.api - return check_session def valid_host(func): - """Decorator to verify if host_ref is valid before calling - method. - - @param func: function with params: (self, session, host_ref) + """Decorator to verify if host_ref is valid before calling method. + + @param func: function with params: (self, session, host_ref, ...) @rtype: callable object - """ + """ def check_host_ref(self, session, host_ref, *args, **kwargs): xennode = XendNode.instance() if type(host_ref) == type(str()) and xennode.is_valid_host(host_ref): @@ -142,17 +151,12 @@ def valid_host(func): else: return xen_api_error(['HOST_HANDLE_INVALID', host_ref]) - # make sure we keep the 'api' attribute - if hasattr(func, 'api'): - check_host_ref.api = func.api - return check_host_ref def valid_host_cpu(func): - """Decorator to verify if host_cpu_ref is valid before calling - method. - - @param func: function with params: (self, session, host_cpu_ref) + """Decorator to verify if host_cpu_ref is valid before calling method. + + @param func: function with params: (self, session, host_cpu_ref, ...) @rtype: callable object """ def check_host_cpu_ref(self, session, host_cpu_ref, *args, **kwargs): @@ -163,45 +167,28 @@ def valid_host_cpu(func): else: return xen_api_error(['HOST_CPU_HANDLE_INVALID', host_cpu_ref]) - # make sure we keep the 'api' attribute - if hasattr(func, 'api'): - check_host_cpu_ref.api = func.api - return check_host_cpu_ref def valid_vm(func): - """Decorator to verify if vm_ref is valid before calling - method. - - @param func: function with params: (self, session, vm_ref) + """Decorator to verify if vm_ref is valid before calling method. + + @param func: function with params: (self, session, vm_ref, ...) @rtype: callable object """ - def check_vm_ref(self, session, *args, **kwargs): - if len(args) == 0: - # This will trigger a TypeError, because there aren't enough - # arguments, which will be caught higher up and diagnosed. - func(self, session) - assert false - - vm_ref = args[0] + def check_vm_ref(self, session, vm_ref, *args, **kwargs): xendom = XendDomain.instance() if type(vm_ref) == type(str()) and \ xendom.is_valid_vm(vm_ref): - return func(self, session, *args, **kwargs) + return func(self, session, vm_ref, *args, **kwargs) else: return xen_api_error(['VM_HANDLE_INVALID', vm_ref]) - # make sure we keep the 'api' attribute - if hasattr(func, 'api'): - check_vm_ref.api = func.api - return check_vm_ref def valid_vbd(func): - """Decorator to verify if vbd_ref is valid before calling - method. - - @param func: function with params: (self, session, vbd_ref) + """Decorator to verify if vbd_ref is valid before calling method. + + @param func: function with params: (self, session, vbd_ref, ...) @rtype: callable object """ def check_vbd_ref(self, session, vbd_ref, *args, **kwargs): @@ -212,17 +199,12 @@ def valid_vbd(func): else: return xen_api_error(['VBD_HANDLE_INVALID', vbd_ref]) - # make sure we keep the 'api' attribute - if hasattr(func, 'api'): - check_vbd_ref.api = func.api - return check_vbd_ref def valid_vif(func): - """Decorator to verify if vif_ref is valid before calling - method. - - @param func: function with params: (self, session, vif_ref) + """Decorator to verify if vif_ref is valid before calling method. + + @param func: function with params: (self, session, vif_ref, ...) @rtype: callable object """ def check_vif_ref(self, session, vif_ref, *args, **kwargs): @@ -233,18 +215,13 @@ def valid_vif(func): else: return xen_api_error(['VIF_HANDLE_INVALID', vif_ref]) - # make sure we keep the 'api' attribute - if hasattr(func, 'api'): - check_vif_ref.api = func.api - return check_vif_ref def valid_vdi(func): - """Decorator to verify if vdi_ref is valid before calling - method. - - @param func: function with params: (self, session, vdi_ref) + """Decorator to verify if vdi_ref is valid before calling method. + + @param func: function with params: (self, session, vdi_ref, ...) @rtype: callable object """ def check_vdi_ref(self, session, vdi_ref, *args, **kwargs): @@ -255,17 +232,12 @@ def valid_vdi(func): else: return xen_api_error(['VDI_HANDLE_INVALID', vdi_ref]) - # make sure we keep the 'api' attribute - if hasattr(func, 'api'): - check_vdi_ref.api = func.api - return check_vdi_ref def valid_vtpm(func): - """Decorator to verify if vtpm_ref is valid before calling - method. - - @param func: function with params: (self, session, vtpm_ref) + """Decorator to verify if vtpm_ref is valid before calling method. + + @param func: function with params: (self, session, vtpm_ref, ...) @rtype: callable object """ def check_vtpm_ref(self, session, vtpm_ref, *args, **kwargs): @@ -276,17 +248,12 @@ def valid_vtpm(func): else: return xen_api_error(['VTPM_HANDLE_INVALID', vtpm_ref]) - # make sure we keep the 'api' attribute - if hasattr(func, 'api'): - check_vtpm_ref.api = func.api - return check_vtpm_ref def valid_sr(func): - """Decorator to verify if sr_ref is valid before calling - method. - - @param func: function with params: (self, session, sr_ref) + """Decorator to verify if sr_ref is valid before calling method. + + @param func: function with params: (self, session, sr_ref, ...) @rtype: callable object """ def check_sr_ref(self, session, sr_ref, *args, **kwargs): @@ -297,10 +264,6 @@ def valid_sr(func): else: return xen_api_error(['SR_HANDLE_INVALID', sr_ref]) - # make sure we keep the 'api' attribute - if hasattr(func, 'api'): - check_sr_ref.api = func.api - return check_sr_ref # ----------------------------- @@ -338,109 +301,13 @@ class XendAPI: """ def __init__(self, auth): - """Initialised Xen API wrapper by making sure all functions - have the correct validation decorators such as L{valid_host} - and L{session_required}. - """ self.auth = auth - - classes = { - 'session': (session_required, catch_typeerror), - 'host': (valid_host, session_required, catch_typeerror), - 'host_cpu': (valid_host_cpu, session_required, catch_typeerror), - 'VM': (valid_vm, session_required, catch_typeerror), - 'VBD': (valid_vbd, session_required, catch_typeerror), - 'VIF': (valid_vif, session_required, catch_typeerror), - 'VDI': (valid_vdi, session_required, catch_typeerror), - 'VTPM':(valid_vtpm, session_required, catch_typeerror), - 'SR': (valid_sr, session_required, catch_typeerror)} - - # Cheat methods - # ------------- - # Methods that have a trivial implementation for all classes. - # 1. get_by_uuid == getting by ref, so just return uuid for - # all get_by_uuid() methods. - - for cls in classes.keys(): - get_by_uuid = '%s_get_by_uuid' % cls - get_uuid = '%s_get_uuid' % cls - setattr(XendAPI, get_by_uuid, - lambda s, sess, obj_ref: xen_api_success(obj_ref)) - setattr(XendAPI, get_uuid, - lambda s, sess, obj_ref: xen_api_success(obj_ref)) - - # 2. get_record is just getting all the attributes, so provide - # a fake template implementation. - # - # TODO: ... - - - # Wrapping validators around XMLRPC calls - # --------------------------------------- - - for cls, validators in classes.items(): - ro_attrs = getattr(self, '%s_attr_ro' % cls, []) - rw_attrs = getattr(self, '%s_attr_rw' % cls, []) - methods = getattr(self, '%s_methods' % cls, []) - funcs = getattr(self, '%s_funcs' % cls, []) - - # wrap validators around readable class attributes - for attr_name in ro_attrs + rw_attrs + self.Base_attr_ro: - getter_name = '%s_get_%s' % (cls, attr_name) - try: - getter = getattr(XendAPI, getter_name) - for validator in validators: - getter = validator(getter) - getter.api = '%s.get_%s' % (cls, attr_name) - setattr(XendAPI, getter_name, getter) - except AttributeError: - pass - #log.warn("API call: %s not found" % getter_name) - - # wrap validators around writable class attrributes - for attr_name in rw_attrs + self.Base_attr_rw: - setter_name = '%s_set_%s' % (cls, attr_name) - try: - setter = getattr(XendAPI, setter_name) - for validator in validators: - setter = validator(setter) - setter.api = '%s.set_%s' % (cls, attr_name) - setattr(XendAPI, setter_name, setter) - except AttributeError: - pass - #log.warn("API call: %s not found" % setter_name) - - # wrap validators around methods - for method_name in methods + self.Base_methods: - method_full_name = '%s_%s' % (cls, method_name) - - try: - method = getattr(XendAPI, method_full_name) - for validator in validators: - method = validator(method) - method.api = '%s.%s' % (cls, method_name) - setattr(XendAPI, method_full_name, method) - except AttributeError: - pass - #log.warn('API call: %s not found' % method_full_name) - - # wrap validators around class functions - for func_name in funcs + self.Base_funcs: - func_full_name = '%s_%s' % (cls, func_name) - try: - method = getattr(XendAPI, func_full_name) - method = catch_typeerror(session_required(method)) - method.api = '%s.%s' % (cls, func_name) - setattr(XendAPI, func_full_name, method) - except AttributeError: - pass - #log.warn('API call: %s not found' % func_full_name) Base_attr_ro = ['uuid'] Base_attr_rw = [] Base_methods = ['destroy', 'get_record'] - Base_funcs = ['create', 'get_by_uuid', 'get_all'] + Base_funcs = ['create', 'get_all'] # Xen API: Class Session # ---------------------------------------------------------------- @@ -511,7 +378,7 @@ class XendAPI: 'reboot', 'shutdown'] - host_funcs = ['get_by_name_label'] + host_funcs = ['get_by_uuid', 'get_by_name_label'] # attributes def host_get_name_label(self, session, host_ref): @@ -680,7 +547,7 @@ class XendAPI: 'suspend', 'resume'] - VM_funcs = ['get_by_name_label'] + VM_funcs = ['get_by_uuid', 'get_by_name_label'] # parameters required for _create() VM_attr_inst = [ @@ -1244,7 +1111,7 @@ class XendAPI: VDI_attr_inst = VDI_attr_ro + VDI_attr_rw VDI_methods = ['snapshot'] - VDI_funcs = ['get_by_name_label'] + VDI_funcs = ['get_by_uuid', 'get_by_name_label'] def VDI_get_VBDs(self, session, vdi_ref): return xen_api_todo() @@ -1488,7 +1355,7 @@ class XendAPI: 'name_description'] SR_methods = ['clone'] - SR_funcs = ['get_by_name_label'] + SR_funcs = ['get_by_uuid', 'get_by_name_label'] # Class Functions def SR_get_all(self, session): @@ -1571,6 +1438,112 @@ class XendAPI: sr.name_description = value return xen_api_success_void() + +def _decorate(): + """Initialise Xen API wrapper by making sure all functions + have the correct validation decorators such as L{valid_host} + and L{session_required}. + """ + + classes = { + 'session': (session_required, catch_typeerror), + 'host': (valid_host, session_required, catch_typeerror), + 'host_cpu': (valid_host_cpu, session_required, catch_typeerror), + 'VM': (valid_vm, session_required, catch_typeerror), + 'VBD': (valid_vbd, session_required, catch_typeerror), + 'VIF': (valid_vif, session_required, catch_typeerror), + 'VDI': (valid_vdi, session_required, catch_typeerror), + 'VTPM':(valid_vtpm, session_required, catch_typeerror), + 'SR': (valid_sr, session_required, catch_typeerror)} + + # Cheat methods + # ------------- + # Methods that have a trivial implementation for all classes. + # 1. get_by_uuid == getting by ref, so just return uuid for + # all get_by_uuid() methods. + + for cls in classes.keys(): + get_by_uuid = '%s_get_by_uuid' % cls + get_uuid = '%s_get_uuid' % cls + def _get_by_uuid(_1, _2, ref): + return xen_api_success(ref) + + def _get_uuid(_1, _2, ref): + return xen_api_success(ref) + + setattr(XendAPI, get_by_uuid, _get_by_uuid) + setattr(XendAPI, get_uuid, _get_uuid) + + # 2. get_record is just getting all the attributes, so provide + # a fake template implementation. + # + # TODO: ... + + + # Wrapping validators around XMLRPC calls + # --------------------------------------- + + for cls, validators in classes.items(): + ro_attrs = getattr(XendAPI, '%s_attr_ro' % cls, []) + rw_attrs = getattr(XendAPI, '%s_attr_rw' % cls, []) + methods = getattr(XendAPI, '%s_methods' % cls, []) + funcs = getattr(XendAPI, '%s_funcs' % cls, []) + + # wrap validators around readable class attributes + for attr_name in ro_attrs + rw_attrs + XendAPI.Base_attr_ro: + getter_name = '%s_get_%s' % (cls, attr_name) + try: + getter = getattr(XendAPI, getter_name) + for validator in validators: + getter = validator(getter) + getter.api = '%s.get_%s' % (cls, attr_name) + setattr(XendAPI, getter_name, getter) + except AttributeError: + pass + #log.warn("API call: %s not found" % getter_name) + + # wrap validators around writable class attrributes + for attr_name in rw_attrs + XendAPI.Base_attr_rw: + setter_name = '%s_set_%s' % (cls, attr_name) + try: + setter = getattr(XendAPI, setter_name) + for validator in validators: + setter = validator(setter) + setter.api = '%s.set_%s' % (cls, attr_name) + setattr(XendAPI, setter_name, setter) + except AttributeError: + pass + #log.warn("API call: %s not found" % setter_name) + + # wrap validators around methods + for method_name in methods + XendAPI.Base_methods: + method_full_name = '%s_%s' % (cls, method_name) + try: + method = getattr(XendAPI, method_full_name) + for validator in validators: + method = validator(method) + method.api = '%s.%s' % (cls, method_name) + setattr(XendAPI, method_full_name, method) + except AttributeError: + pass + #log.warn('API call: %s not found' % method_full_name) + + # wrap validators around class functions + for func_name in funcs + XendAPI.Base_funcs: + func_full_name = '%s_%s' % (cls, func_name) + try: + method = getattr(XendAPI, func_full_name) + method = session_required(method) + method.api = '%s.%s' % (cls, func_name) + method = catch_typeerror(method) + method.api = '%s.%s' % (cls, func_name) + setattr(XendAPI, func_full_name, method) + except AttributeError: + log.warn('API call: %s not found' % func_full_name) + +_decorate() + + # # Auto generate some stubs based on XendAPI introspection # _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |