[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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.