WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] Implement the major part of the new error

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] Implement the major part of the new error handling for the Xen-API.
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Thu, 21 Dec 2006 09:05:21 -0800
Delivery-date: Thu, 21 Dec 2006 09:06:27 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# 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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] Implement the major part of the new error handling for the Xen-API., Xen patchbot-unstable <=