[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] Implement the major part of the new error handling for the Xen-API.
# HG changeset patch # User Ewan Mellor <ewan@xxxxxxxxxxxxx> # Date 1166714185 0 # Node ID c3d84afbbb47a4871aa2f4e9262ab1e18d6c8c36 # Parent 38213c2544d769ccc3fc6ad2fe432a65ea61de36 Implement the major part of the new error handling for the Xen-API. Signed-off-by: Ewan Mellor <ewan@xxxxxxxxxxxxx> --- tools/python/xen/xend/XendAPI.py | 175 ++++++++++++++++++++---------- tools/python/xen/xend/XendAuthSessions.py | 13 -- 2 files changed, 117 insertions(+), 71 deletions(-) diff -r 38213c2544d7 -r c3d84afbbb47 tools/python/xen/xend/XendAPI.py --- a/tools/python/xen/xend/XendAPI.py Thu Dec 21 13:12:09 2006 +0000 +++ b/tools/python/xen/xend/XendAPI.py Thu Dec 21 15:16:25 2006 +0000 @@ -15,11 +15,12 @@ # Copyright (C) 2006 XenSource Ltd. #============================================================================ +import re + from xen.xend import XendDomain, XendDomainInfo, XendNode from xen.xend import XendLogging from xen.xend.XendAuthSessions import instance as auth_manager -from xen.xend.XendAuthSessions import session_required from xen.xend.XendError import * from xen.xend.XendClient import ERROR_INVALID_DOMAIN from xen.xend.XendLogging import log @@ -44,7 +45,16 @@ def xen_api_success_void(): def xen_api_error(error): """Wraps an error value in XenAPI format.""" - return {"Status": "Error", "ErrorDescription": error} + if type(error) == tuple: + error = list(error) + if type(error) != list: + error = [error] + if len(error) == 0: + error = ['INTERNAL_ERROR', 'Empty list given to xen_api_error'] + + return { "Status": "Error", + "ErrorDescription": [str(x) for x in error] } + def xen_api_todo(): """Temporary method to make sure we track down all the TODOs""" @@ -68,6 +78,56 @@ def trace(func, api_name = ''): trace_func.api = api_name return trace_func + +takesRE = re.compile(r'^(.*)\(\) takes exactly ([0-9]*) argument') +def deconstruct_typeerror(exn): + m = takesRE.search(exn[0]) + return m and m.groups() 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) + @rtype: callable object + """ + def f(self, *args, **kwargs): + try: + 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]) + raise + + # make sure we keep the 'api' attribute + if hasattr(func, 'api'): + f.api = func.api + + return f + + +def session_required(func): + 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. @@ -80,8 +140,7 @@ def valid_host(func): if type(host_ref) == type(str()) and xennode.is_valid_host(host_ref): return func(self, session, host_ref, *args, **kwargs) else: - return {'Status': 'Failure', - 'ErrorDescription': XEND_ERROR_HOST_INVALID} + return xen_api_error(['HOST_HANDLE_INVALID', host_ref]) # make sure we keep the 'api' attribute if hasattr(func, 'api'): @@ -102,8 +161,7 @@ def valid_host_cpu(func): xennode.is_valid_cpu(host_cpu_ref): return func(self, session, host_cpu_ref, *args, **kwargs) else: - return {'Status': 'Failure', - 'ErrorDescription': XEND_ERROR_HOST_CPU_INVALID} + return xen_api_error(['HOST_CPU_HANDLE_INVALID', host_cpu_ref]) # make sure we keep the 'api' attribute if hasattr(func, 'api'): @@ -120,8 +178,10 @@ def valid_vm(func): """ def check_vm_ref(self, session, *args, **kwargs): if len(args) == 0: - return {'Status': 'Failure', - 'ErrorDescription': XEND_ERROR_VM_INVALID} + # 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] xendom = XendDomain.instance() @@ -129,8 +189,7 @@ def valid_vm(func): xendom.is_valid_vm(vm_ref): return func(self, session, *args, **kwargs) else: - return {'Status': 'Failure', - 'ErrorDescription': XEND_ERROR_VM_INVALID} + return xen_api_error(['VM_HANDLE_INVALID', vm_ref]) # make sure we keep the 'api' attribute if hasattr(func, 'api'): @@ -151,8 +210,7 @@ def valid_vbd(func): xendom.is_valid_dev('vbd', vbd_ref): return func(self, session, vbd_ref, *args, **kwargs) else: - return {'Status': 'Failure', - 'ErrorDescription': XEND_ERROR_VBD_INVALID} + return xen_api_error(['VBD_HANDLE_INVALID', vbd_ref]) # make sure we keep the 'api' attribute if hasattr(func, 'api'): @@ -173,8 +231,7 @@ def valid_vif(func): xendom.is_valid_dev('vif', vif_ref): return func(self, session, vif_ref, *args, **kwargs) else: - return {'Status': 'Failure', - 'ErrorDescription': XEND_ERROR_VIF_INVALID} + return xen_api_error(['VIF_HANDLE_INVALID', vif_ref]) # make sure we keep the 'api' attribute if hasattr(func, 'api'): @@ -196,8 +253,7 @@ def valid_vdi(func): xennode.get_sr().is_valid_vdi(vdi_ref): return func(self, session, vdi_ref, *args, **kwargs) else: - return {'Status': 'Failure', - 'ErrorDescription': XEND_ERROR_VDI_INVALID} + return xen_api_error(['VDI_HANDLE_INVALID', vdi_ref]) # make sure we keep the 'api' attribute if hasattr(func, 'api'): @@ -218,8 +274,7 @@ def valid_vtpm(func): xendom.is_valid_dev('vtpm', vtpm_ref): return func(self, session, vtpm_ref, *args, **kwargs) else: - return {'Status': 'Failure', - 'ErrorDescription': XEND_ERROR_VTPM_INVALID} + return xen_api_error(['VTPM_HANDLE_INVALID', vtpm_ref]) # make sure we keep the 'api' attribute if hasattr(func, 'api'): @@ -240,8 +295,7 @@ def valid_sr(func): xennode.get_sr().uuid == sr_ref: return func(self, session, sr_ref, *args, **kwargs) else: - return {'Status': 'Failure', - 'ErrorDescription': XEND_ERROR_SR_INVALID} + return xen_api_error(['SR_HANDLE_INVALID', sr_ref]) # make sure we keep the 'api' attribute if hasattr(func, 'api'): @@ -274,7 +328,7 @@ class XendAPI: used via XMLRPCServer. All methods that need a valid session are marked with - a L{XendAuthManager.session_required} decorator that will + a L{session_required} decorator that will transparently perform the required session authentication. We need to support Python <2.4, so we use the old decorator syntax. @@ -291,15 +345,15 @@ class XendAPI: self.auth = auth classes = { - 'session': (session_required,), - 'host': (valid_host, session_required), - 'host_cpu': (valid_host_cpu, session_required), - 'VM': (valid_vm, session_required), - 'VBD': (valid_vbd, session_required), - 'VIF': (valid_vif, session_required), - 'VDI': (valid_vdi, session_required), - 'VTPM':(valid_vtpm, session_required), - 'SR': (valid_sr, session_required)} + '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 # ------------- @@ -375,7 +429,7 @@ class XendAPI: func_full_name = '%s_%s' % (cls, func_name) try: method = getattr(XendAPI, func_full_name) - method = session_required(method) + method = catch_typeerror(session_required(method)) method.api = '%s.%s' % (cls, func_name) setattr(XendAPI, func_full_name, method) except AttributeError: @@ -396,14 +450,20 @@ class XendAPI: session_methods = ['logout'] # session_funcs = ['login_with_password'] - def session_login_with_password(self, username, password): + def session_login_with_password(self, *args): + if len(args) != 2: + return xen_api_error( + ['MESSAGE_PARAMETER_COUNT_MISMATCH', + 'session.login_with_password', 2, len(args)]) + username = args[0] + password = args[1] try: session = (self.auth == AUTH_NONE and auth_manager().login_unconditionally(username) or auth_manager().login_with_password(username, password)) return xen_api_success(session) except XendError, e: - return xen_api_error(XEND_ERROR_AUTHENTICATION_FAILED) + return xen_api_error(['SESSION_AUTHENTICATION_FAILED']) session_login_with_password.api = 'session.login_with_password' @@ -425,7 +485,7 @@ class XendAPI: user = auth_manager().get_user(session) if user: return xen_api_success(user) - return xen_api_error(XEND_ERROR_SESSION_INVALID) + return xen_api_error(['SESSION_INVALID', session]) # Xen API: Class User @@ -937,7 +997,7 @@ class XendAPI: dom = xendom.domain_lookup_nr(label) if dom: return xen_api_success([dom.get_uuid()]) - return xen_api_error(XEND_ERROR_VM_INVALID) + return xen_api_success([]) def VM_create(self, session, vm_struct): xendom = XendDomain.instance() @@ -949,7 +1009,7 @@ class XendAPI: xendom = XendDomain.instance() xeninfo = xendom.get_vm_by_uuid(vm_ref) if not xeninfo: - return xen_api_error(XEND_ERROR_VM_INVALID) + return xen_api_error(['VM_HANDLE_INVALID', vm_ref]) record = { 'uuid': xeninfo.get_uuid(), @@ -1051,10 +1111,10 @@ class XendAPI: xendom = XendDomain.instance() vm = xendom.get_vm_with_dev_uuid('vbd', vbd_ref) if not vm: - return xen_api_error(XEND_ERROR_VBD_INVALID) + return xen_api_error(['VBD_HANDLE_INVALID', vbd_ref]) cfg = vm.get_dev_xenapi_config('vbd', vbd_ref) if not cfg: - return xen_api_error(XEND_ERROR_VBD_INVALID) + return xen_api_error(['VBD_HANDLE_INVALID', vbd_ref]) valid_vbd_keys = self.VBD_attr_ro + self.VBD_attr_rw + \ self.Base_attr_ro + self.Base_attr_rw @@ -1073,7 +1133,7 @@ class XendAPI: def VBD_create(self, session, vbd_struct): xendom = XendDomain.instance() if not xendom.is_valid_vm(vbd_struct['VM']): - return xen_api_error(XEND_ERROR_DOMAIN_INVALID) + return xen_api_error(['VM_HANDLE_INVALID', vbd_struct['VM']]) dom = xendom.get_vm_by_uuid(vbd_struct['VM']) vbd_ref = '' @@ -1087,7 +1147,7 @@ class XendAPI: sr = XendNode.instance().get_sr() vdi_image = sr.xen_api_get_by_uuid(vdi_ref) if not vdi_image: - return xen_api_error(XEND_ERROR_VDI_INVALID) + return xen_api_error(['VDI_HANDLE_INVALID', vdi_ref]) vdi_image = vdi_image.qcow_path vbd_ref = dom.create_vbd_with_vdi(vbd_struct, vdi_image) except XendError: @@ -1137,10 +1197,10 @@ class XendAPI: xendom = XendDomain.instance() vm = xendom.get_vm_with_dev_uuid('vif', vif_ref) if not vm: - return xen_api_error(XEND_ERROR_VIF_INVALID) + return xen_api_error(['VIF_HANDLE_INVALID', vif_ref]) cfg = vm.get_dev_xenapi_config('vif', vif_ref) if not cfg: - return xen_api_error(XEND_ERROR_VIF_INVALID) + return xen_api_error(['VIF_HANDLE_INVALID', vif_ref]) valid_vif_keys = self.VIF_attr_ro + self.VIF_attr_rw + \ self.Base_attr_ro + self.Base_attr_rw @@ -1164,7 +1224,7 @@ class XendAPI: except XendError: return xen_api_error(XEND_ERROR_TODO) else: - return xen_api_error(XEND_ERROR_DOMAIN_INVALID) + return xen_api_error(['VM_HANDLE_INVALID', vif_struct['VM']]) # Xen API: Class VDI @@ -1295,14 +1355,14 @@ class XendAPI: 'read_only': image.read_only, }) - return xen_api_error(XEND_ERROR_VDI_INVALID) + return xen_api_error(['VDI_HANDLE_INVALID', vdi_ref]) # Class Functions def VDI_create(self, session, vdi_struct): sr = XendNode.instance().get_sr() sr_ref = vdi_struct['SR'] if sr.uuid != sr_ref: - return xen_api_error(XEND_ERROR_SR_INVALID) + return xen_api_error(['SR_HANDLE_INVALID', vdi_struct['SR']]) vdi_uuid = sr.create_image(vdi_struct) return xen_api_success(vdi_uuid) @@ -1315,9 +1375,8 @@ class XendAPI: sr = XendNode.instance().get_sr() image_uuid = sr.xen_api_get_by_name_label(name) if image_uuid: - return xen_api_success(image_uuid) - - return xen_api_error(XEND_ERROR_VDI_INVALID) + return xen_api_success([image_uuid]) + return xen_api_success([]) # Xen API: Class VTPM @@ -1336,10 +1395,10 @@ class XendAPI: xendom = XendDomain.instance() vm = xendom.get_vm_with_dev_uuid('vtpm', vtpm_ref) if not vm: - return xen_api_error(XEND_ERROR_VTPM_INVALID) + return xen_api_error(['VTPM_HANDLE_INVALID', vtpm_ref]) cfg = vm.get_dev_xenapi_config('vtpm', vtpm_ref) if not cfg: - return xen_api_error(XEND_ERROR_VTPM_INVALID) + return xen_api_error(['VTPM_HANDLE_INVALID', vtpm_ref]) valid_vtpm_keys = self.VTPM_attr_ro + self.VTPM_attr_rw + \ self.Base_attr_ro + self.Base_attr_rw for k in cfg.keys(): @@ -1353,10 +1412,10 @@ class XendAPI: xendom = XendDomain.instance() vm = xendom.get_vm_with_dev_uuid('vtpm', vtpm_ref) if not vm: - return xen_api_error(XEND_ERROR_VTPM_INVALID) + return xen_api_error(['VTPM_HANDLE_INVALID', vtpm_ref]) cfg = vm.get_dev_xenapi_config('vtpm', vtpm_ref) if not cfg: - return xen_api_error(XEND_ERROR_VTPM_INVALID) + return xen_api_error(['VTPM_HANDLE_INVALID', vtpm_ref]) if cfg.has_key('instance'): instance = cfg['instance'] else: @@ -1367,10 +1426,10 @@ class XendAPI: xendom = XendDomain.instance() vm = xendom.get_vm_with_dev_uuid('vtpm', vtpm_ref) if not vm: - return xen_api_error(XEND_ERROR_VTPM_INVALID) + return xen_api_error(['VTPM_HANDLE_INVALID', vtpm_ref]) cfg = vm.get_dev_xenapi_config('vtpm', vtpm_ref) if not cfg: - return xen_api_error(XEND_ERROR_VTPM_INVALID) + return xen_api_error(['VTPM_HANDLE_INVALID', vtpm_ref]) if cfg.has_key('type'): driver = cfg['type'] else: @@ -1381,10 +1440,10 @@ class XendAPI: xendom = XendDomain.instance() vm = xendom.get_vm_with_dev_uuid('vtpm', vtpm_ref) if not vm: - return xen_api_error(XEND_ERROR_VTPM_INVALID) + return xen_api_error(['VTPM_HANDLE_INVALID', vtpm_ref]) cfg = vm.get_dev_xenapi_config('vtpm', vtpm_ref) if not cfg: - return xen_api_error(XEND_ERROR_VTPM_INVALID) + return xen_api_error(['VTPM_HANDLE_INVALID', vtpm_ref]) if cfg.has_key('backend'): backend = cfg['backend'] else: @@ -1407,7 +1466,7 @@ class XendAPI: except XendError: return xen_api_error(XEND_ERROR_TODO) else: - return xen_api_error(XEND_ERROR_DOMAIN_INVALID) + return xen_api_error(['VM_HANDLE_INVALID', vtpm_struct['VM']]) # Xen API: Class SR @@ -1439,7 +1498,7 @@ class XendAPI: def SR_get_by_name_label(self, session, label): sr = XendNode.instance().get_sr() if sr.name_label != label: - return xen_api_error(XEND_ERROR_SR_INVALID) + return xen_api_success([]) return xen_api_success([sr.uuid]) def SR_create(self, session): diff -r 38213c2544d7 -r c3d84afbbb47 tools/python/xen/xend/XendAuthSessions.py --- a/tools/python/xen/xend/XendAuthSessions.py Thu Dec 21 13:12:09 2006 +0000 +++ b/tools/python/xen/xend/XendAuthSessions.py Thu Dec 21 15:16:25 2006 +0000 @@ -130,16 +130,3 @@ def instance(): inst = XendAuthSessions() inst.init() return inst - -# Handy Authentication Decorators -# ------------------------------- -def session_required(func): - def check_session(self, session, *args, **kwargs): - if instance().is_session_valid(session): - return func(self, session, *args, **kwargs) - else: - return {'Status': 'Failure', - 'ErrorDescription': XEND_ERROR_SESSION_INVALID} - return check_session - - _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |