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] Move the decoration of all the Xen-API me

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] Move the decoration of all the Xen-API methods out of XendAPI.__init__ and
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Fri, 22 Dec 2006 05:10:07 -0800
Delivery-date: Fri, 22 Dec 2006 05:10:41 -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 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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] Move the decoration of all the Xen-API methods out of XendAPI.__init__ and, Xen patchbot-unstable <=