ia64/xen-unstable

changeset 13185:bd10d08598b0

Change the way that MESSAGE_PARAMETER_COUNT_MISMATCH is diagnosed (using a
separate dictionary to record parameter counts, rather than trying to parse them
out of the exception) and tidy up the validator preprocessing and the
validators themselves.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author Ewan Mellor <ewan@xensource.com>
date Mon Dec 25 16:20:23 2006 +0000 (2006-12-25)
parents 765ada5f74cc
children eec06ba7afaa
files tools/python/xen/xend/XendAPI.py
line diff
     1.1 --- a/tools/python/xen/xend/XendAPI.py	Mon Dec 25 15:04:28 2006 +0000
     1.2 +++ b/tools/python/xen/xend/XendAPI.py	Mon Dec 25 16:20:23 2006 +0000
     1.3 @@ -17,7 +17,6 @@
     1.4  
     1.5  import inspect
     1.6  import os
     1.7 -import re
     1.8  import string
     1.9  import sys
    1.10  import traceback
    1.11 @@ -36,6 +35,8 @@ from xen.util.xmlrpclib2 import stringif
    1.12  AUTH_NONE = 'none'
    1.13  AUTH_PAM = 'pam'
    1.14  
    1.15 +argcounts = {}
    1.16 +
    1.17  # ------------------------------------------
    1.18  # Utility Methods for Xen API Implementation
    1.19  # ------------------------------------------
    1.20 @@ -84,12 +85,6 @@ def trace(func, api_name = ''):
    1.21      return trace_func
    1.22  
    1.23  
    1.24 -takesRE = re.compile(r' ([0-9]*) argument')
    1.25 -def deconstruct_typeerror(exn):
    1.26 -    m = takesRE.search(exn[0])
    1.27 -    return m and m.group(1) or None
    1.28 -
    1.29 -
    1.30  def catch_typeerror(func):
    1.31      """Decorator to catch any TypeErrors and translate them into Xen-API
    1.32      errors.
    1.33 @@ -101,23 +96,21 @@ def catch_typeerror(func):
    1.34          try:
    1.35              return func(self, *args, **kwargs)
    1.36          except TypeError, exn:
    1.37 -            if hasattr(func, 'api'):
    1.38 -                takes = deconstruct_typeerror(exn)
    1.39 -                if takes is not None:
    1.40 -                    # Assume that if the exception was thrown inside this
    1.41 -                    # file, then it is due to an invalid call from the client,
    1.42 -                    # but if it was thrown elsewhere, then it's an internal
    1.43 -                    # error (which will be handled further up).
    1.44 -                    tb = sys.exc_info()[2]
    1.45 -                    try:
    1.46 -                        sourcefile = traceback.extract_tb(tb)[-1][0]
    1.47 -                        if sourcefile == inspect.getsourcefile(XendAPI):
    1.48 -                            return xen_api_error(
    1.49 -                                ['MESSAGE_PARAMETER_COUNT_MISMATCH',
    1.50 -                                 func.api, int(takes) - 2,
    1.51 -                                 len(args) + len(kwargs) - 1])
    1.52 -                    finally:
    1.53 -                        del tb
    1.54 +            if hasattr(func, 'api') and func.api in argcounts:
    1.55 +                # Assume that if the exception was thrown inside this
    1.56 +                # file, then it is due to an invalid call from the client,
    1.57 +                # but if it was thrown elsewhere, then it's an internal
    1.58 +                # error (which will be handled further up).
    1.59 +                tb = sys.exc_info()[2]
    1.60 +                try:
    1.61 +                    sourcefile = traceback.extract_tb(tb)[-1][0]
    1.62 +                    if sourcefile == inspect.getsourcefile(XendAPI):
    1.63 +                        return xen_api_error(
    1.64 +                            ['MESSAGE_PARAMETER_COUNT_MISMATCH',
    1.65 +                             func.api, argcounts[func.api],
    1.66 +                             len(args) + len(kwargs)])
    1.67 +                finally:
    1.68 +                    del tb
    1.69              raise
    1.70  
    1.71      return f
    1.72 @@ -138,20 +131,25 @@ def session_required(func):
    1.73      return check_session
    1.74  
    1.75  
    1.76 +def _is_valid_ref(ref, validator):
    1.77 +    return type(ref) == str and validator(ref)
    1.78 +
    1.79 +def _check_ref(validator, errcode, func, api, session, ref, *args, **kwargs):
    1.80 +    if _is_valid_ref(ref, validator):
    1.81 +        return func(api, session, ref, *args, **kwargs)
    1.82 +    else:
    1.83 +        return xen_api_error([errcode, ref])
    1.84 +
    1.85 +
    1.86  def valid_host(func):
    1.87      """Decorator to verify if host_ref is valid before calling method.
    1.88  
    1.89      @param func: function with params: (self, session, host_ref, ...)
    1.90      @rtype: callable object
    1.91      """
    1.92 -    def check_host_ref(self, session, host_ref, *args, **kwargs):
    1.93 -        xennode = XendNode.instance()
    1.94 -        if type(host_ref) == type(str()) and xennode.is_valid_host(host_ref):
    1.95 -            return func(self, session, host_ref, *args, **kwargs)
    1.96 -        else:
    1.97 -            return xen_api_error(['HOST_HANDLE_INVALID', host_ref])
    1.98 -
    1.99 -    return check_host_ref
   1.100 +    return lambda *args, **kwargs: \
   1.101 +           _check_ref(XendNode.instance().is_valid_host,
   1.102 +                      'HOST_HANDLE_INVALID', func, *args, **kwargs)
   1.103  
   1.104  def valid_host_cpu(func):
   1.105      """Decorator to verify if host_cpu_ref is valid before calling method.
   1.106 @@ -159,15 +157,9 @@ def valid_host_cpu(func):
   1.107      @param func: function with params: (self, session, host_cpu_ref, ...)
   1.108      @rtype: callable object
   1.109      """    
   1.110 -    def check_host_cpu_ref(self, session, host_cpu_ref, *args, **kwargs):
   1.111 -        xennode = XendNode.instance()
   1.112 -        if type(host_cpu_ref) == type(str()) and \
   1.113 -               xennode.is_valid_cpu(host_cpu_ref):
   1.114 -            return func(self, session, host_cpu_ref, *args, **kwargs)
   1.115 -        else:
   1.116 -            return xen_api_error(['HOST_CPU_HANDLE_INVALID', host_cpu_ref])
   1.117 -        
   1.118 -    return check_host_cpu_ref
   1.119 +    return lambda *args, **kwargs: \
   1.120 +           _check_ref(XendNode.instance().is_valid_cpu,
   1.121 +                      'HOST_CPU_HANDLE_INVALID', func, *args, **kwargs)
   1.122  
   1.123  def valid_vm(func):
   1.124      """Decorator to verify if vm_ref is valid before calling method.
   1.125 @@ -175,15 +167,19 @@ def valid_vm(func):
   1.126      @param func: function with params: (self, session, vm_ref, ...)
   1.127      @rtype: callable object
   1.128      """    
   1.129 -    def check_vm_ref(self, session, vm_ref, *args, **kwargs):
   1.130 -        xendom = XendDomain.instance()
   1.131 -        if type(vm_ref) == type(str()) and \
   1.132 -               xendom.is_valid_vm(vm_ref):
   1.133 -            return func(self, session, vm_ref, *args, **kwargs)
   1.134 -        else:
   1.135 -            return xen_api_error(['VM_HANDLE_INVALID', vm_ref])
   1.136 +    return lambda *args, **kwargs: \
   1.137 +           _check_ref(XendDomain.instance().is_valid_vm,
   1.138 +                      'VM_HANDLE_INVALID', func, *args, **kwargs)
   1.139 +
   1.140 +def valid_network(func):
   1.141 +    """Decorator to verify if network_ref is valid before calling method.
   1.142  
   1.143 -    return check_vm_ref
   1.144 +    @param func: function with params: (self, session, network_ref, ...)
   1.145 +    @rtype: callable object
   1.146 +    """    
   1.147 +    return lambda *args, **kwargs: \
   1.148 +           _check_ref(XendNode.instance().is_valid_network,
   1.149 +                      'NETWORK_HANDLE_INVALID', func, *args, **kwargs)
   1.150  
   1.151  def valid_vbd(func):
   1.152      """Decorator to verify if vbd_ref is valid before calling method.
   1.153 @@ -191,15 +187,9 @@ def valid_vbd(func):
   1.154      @param func: function with params: (self, session, vbd_ref, ...)
   1.155      @rtype: callable object
   1.156      """    
   1.157 -    def check_vbd_ref(self, session, vbd_ref, *args, **kwargs):
   1.158 -        xendom = XendDomain.instance()
   1.159 -        if type(vbd_ref) == type(str()) and \
   1.160 -               xendom.is_valid_dev('vbd', vbd_ref):
   1.161 -            return func(self, session, vbd_ref, *args, **kwargs)
   1.162 -        else:
   1.163 -            return xen_api_error(['VBD_HANDLE_INVALID', vbd_ref])
   1.164 -
   1.165 -    return check_vbd_ref
   1.166 +    return lambda *args, **kwargs: \
   1.167 +           _check_ref(lambda r: XendDomain.instance().is_valid_dev('vbd', r),
   1.168 +                      'VBD_HANDLE_INVALID', func, *args, **kwargs)
   1.169  
   1.170  def valid_vif(func):
   1.171      """Decorator to verify if vif_ref is valid before calling method.
   1.172 @@ -207,16 +197,9 @@ def valid_vif(func):
   1.173      @param func: function with params: (self, session, vif_ref, ...)
   1.174      @rtype: callable object
   1.175      """
   1.176 -    def check_vif_ref(self, session, vif_ref, *args, **kwargs):
   1.177 -        xendom = XendDomain.instance()
   1.178 -        if type(vif_ref) == type(str()) and \
   1.179 -               xendom.is_valid_dev('vif', vif_ref):
   1.180 -            return func(self, session, vif_ref, *args, **kwargs)
   1.181 -        else:
   1.182 -            return xen_api_error(['VIF_HANDLE_INVALID', vif_ref])
   1.183 -
   1.184 -    return check_vif_ref
   1.185 -
   1.186 +    return lambda *args, **kwargs: \
   1.187 +           _check_ref(lambda r: XendDomain.instance().is_valid_dev('vif', r),
   1.188 +                      'VIF_HANDLE_INVALID', func, *args, **kwargs)
   1.189  
   1.190  def valid_vdi(func):
   1.191      """Decorator to verify if vdi_ref is valid before calling method.
   1.192 @@ -224,15 +207,9 @@ def valid_vdi(func):
   1.193      @param func: function with params: (self, session, vdi_ref, ...)
   1.194      @rtype: callable object
   1.195      """
   1.196 -    def check_vdi_ref(self, session, vdi_ref, *args, **kwargs):
   1.197 -        xennode = XendNode.instance()
   1.198 -        if type(vdi_ref) == type(str()) and \
   1.199 -               xennode.get_sr().is_valid_vdi(vdi_ref):
   1.200 -            return func(self, session, vdi_ref, *args, **kwargs)
   1.201 -        else:
   1.202 -            return xen_api_error(['VDI_HANDLE_INVALID', vdi_ref])
   1.203 -
   1.204 -    return check_vdi_ref
   1.205 +    return lambda *args, **kwargs: \
   1.206 +           _check_ref(XendNode.instance().get_sr().is_valid_vdi,
   1.207 +                      'VDI_HANDLE_INVALID', func, *args, **kwargs)
   1.208  
   1.209  def valid_vtpm(func):
   1.210      """Decorator to verify if vtpm_ref is valid before calling method.
   1.211 @@ -240,15 +217,9 @@ def valid_vtpm(func):
   1.212      @param func: function with params: (self, session, vtpm_ref, ...)
   1.213      @rtype: callable object
   1.214      """
   1.215 -    def check_vtpm_ref(self, session, vtpm_ref, *args, **kwargs):
   1.216 -        xendom = XendDomain.instance()
   1.217 -        if type(vtpm_ref) == type(str()) and \
   1.218 -               xendom.is_valid_dev('vtpm', vtpm_ref):
   1.219 -            return func(self, session, vtpm_ref, *args, **kwargs)
   1.220 -        else:
   1.221 -            return xen_api_error(['VTPM_HANDLE_INVALID', vtpm_ref])
   1.222 -
   1.223 -    return check_vtpm_ref
   1.224 +    return lambda *args, **kwargs: \
   1.225 +           _check_ref(lambda r: XendDomain.instance().is_valid_dev('vtpm', r),
   1.226 +                      'VTPM_HANDLE_INVALID', func, *args, **kwargs)
   1.227  
   1.228  def valid_sr(func):
   1.229      """Decorator to verify if sr_ref is valid before calling method.
   1.230 @@ -256,16 +227,9 @@ def valid_sr(func):
   1.231      @param func: function with params: (self, session, sr_ref, ...)
   1.232      @rtype: callable object
   1.233      """
   1.234 -    def check_sr_ref(self, session, sr_ref, *args, **kwargs):
   1.235 -        xennode = XendNode.instance()
   1.236 -        if type(sr_ref) == type(str()) and \
   1.237 -               xennode.get_sr().uuid == sr_ref:
   1.238 -            return func(self, session, sr_ref, *args, **kwargs)
   1.239 -        else:
   1.240 -            return xen_api_error(['SR_HANDLE_INVALID', sr_ref])
   1.241 -
   1.242 -    return check_sr_ref
   1.243 -
   1.244 +    return lambda *args, **kwargs: \
   1.245 +           _check_ref(lambda r: XendNode.instance().get_sr().uuid == r,
   1.246 +                      'SR_HANDLE_INVALID', func, *args, **kwargs)
   1.247  
   1.248  def valid_pif(func):
   1.249      """Decorator to verify if sr_ref is valid before calling
   1.250 @@ -274,20 +238,9 @@ def valid_pif(func):
   1.251      @param func: function with params: (self, session, sr_ref)
   1.252      @rtype: callable object
   1.253      """
   1.254 -    def check_pif_ref(self, session, pif_ref, *args, **kwargs):
   1.255 -        xennode = XendNode.instance()
   1.256 -        if type(pif_ref) == type(str()) and pif_ref in xennode.pifs:
   1.257 -            return func(self, session, pif_ref, *args, **kwargs)
   1.258 -        else:
   1.259 -            return xen_api_error(['PIF_HANDLE_INVALID', pif_ref])
   1.260 -
   1.261 -    # make sure we keep the 'api' attribute
   1.262 -    if hasattr(func, 'api'):
   1.263 -        check_pif_ref.api = func.api
   1.264 -        
   1.265 -    return check_pif_ref
   1.266 -
   1.267 -
   1.268 +    return lambda *args, **kwargs: \
   1.269 +           _check_ref(lambda r: r in XendNode.instance().pifs,
   1.270 +                      'PIF_HANDLE_INVALID', func, *args, **kwargs)
   1.271  
   1.272  # -----------------------------
   1.273  # Bridge to Legacy XM API calls
   1.274 @@ -1532,17 +1485,20 @@ def _decorate():
   1.275      and L{session_required}.
   1.276      """
   1.277  
   1.278 +    global_validators = [session_required, catch_typeerror]
   1.279      classes = {
   1.280 -        'session': (session_required, catch_typeerror),
   1.281 -        'host': (valid_host, session_required, catch_typeerror),
   1.282 -        'host_cpu': (valid_host_cpu, session_required, catch_typeerror),
   1.283 -        'VM': (valid_vm, session_required, catch_typeerror),
   1.284 -        'VBD': (valid_vbd, session_required, catch_typeerror),
   1.285 -        'VIF': (valid_vif, session_required, catch_typeerror),
   1.286 -        'VDI': (valid_vdi, session_required, catch_typeerror),
   1.287 -        'VTPM':(valid_vtpm, session_required, catch_typeerror),
   1.288 -        'SR':  (valid_sr, session_required, catch_typeerror),
   1.289 -        'PIF': (valid_pif, session_required, catch_typeerror)}
   1.290 +        'session' : None,
   1.291 +        'host'    : valid_host,
   1.292 +        'host_cpu': valid_host_cpu,
   1.293 +        'network' : valid_network,
   1.294 +        'VM'      : valid_vm,
   1.295 +        'VBD'     : valid_vbd,
   1.296 +        'VIF'     : valid_vif,
   1.297 +        'VDI'     : valid_vdi,
   1.298 +        'VTPM'    : valid_vtpm,
   1.299 +        'SR'      : valid_sr,
   1.300 +        'PIF'     : valid_pif
   1.301 +        }
   1.302  
   1.303      # Cheat methods
   1.304      # -------------
   1.305 @@ -1571,7 +1527,24 @@ def _decorate():
   1.306      # Wrapping validators around XMLRPC calls
   1.307      # ---------------------------------------
   1.308  
   1.309 -    for cls, validators in classes.items():
   1.310 +    for cls, validator in classes.items():
   1.311 +        def doit(n, takes_instance):
   1.312 +            n_ = n.replace('.', '_')
   1.313 +            try:
   1.314 +                f = getattr(XendAPI, n_)
   1.315 +                argcounts[n] = f.func_code.co_argcount - 1
   1.316 +
   1.317 +                validators = takes_instance and validator and [validator] \
   1.318 +                             or []
   1.319 +                validators += global_validators
   1.320 +                for v in validators:
   1.321 +                    f = v(f)
   1.322 +                    f.api = n
   1.323 +                setattr(XendAPI, n_, f)
   1.324 +            except AttributeError:
   1.325 +                log.warn("API call: %s not found" % n)
   1.326 +
   1.327 +
   1.328          ro_attrs = getattr(XendAPI, '%s_attr_ro' % cls, [])
   1.329          rw_attrs = getattr(XendAPI, '%s_attr_rw' % cls, [])
   1.330          methods  = getattr(XendAPI, '%s_methods' % cls, [])
   1.331 @@ -1579,55 +1552,19 @@ def _decorate():
   1.332  
   1.333          # wrap validators around readable class attributes
   1.334          for attr_name in ro_attrs + rw_attrs + XendAPI.Base_attr_ro:
   1.335 -            getter_name = '%s_get_%s' % (cls, attr_name)
   1.336 -            try:
   1.337 -                getter = getattr(XendAPI, getter_name)
   1.338 -                for validator in validators:
   1.339 -                    getter = validator(getter)
   1.340 -                    getter.api = '%s.get_%s' % (cls, attr_name)
   1.341 -                setattr(XendAPI, getter_name, getter)
   1.342 -            except AttributeError:
   1.343 -                pass
   1.344 -                #log.warn("API call: %s not found" % getter_name)
   1.345 +            doit('%s.get_%s' % (cls, attr_name), True)
   1.346  
   1.347          # wrap validators around writable class attrributes
   1.348          for attr_name in rw_attrs + XendAPI.Base_attr_rw:
   1.349 -            setter_name = '%s_set_%s' % (cls, attr_name)
   1.350 -            try:
   1.351 -                setter = getattr(XendAPI, setter_name)
   1.352 -                for validator in validators:
   1.353 -                    setter = validator(setter)
   1.354 -                    setter.api = '%s.set_%s' % (cls, attr_name)
   1.355 -                setattr(XendAPI, setter_name, setter)
   1.356 -            except AttributeError:
   1.357 -                pass
   1.358 -                #log.warn("API call: %s not found" % setter_name)
   1.359 +            doit('%s.set_%s' % (cls, attr_name), True)
   1.360  
   1.361          # wrap validators around methods
   1.362          for method_name in methods + XendAPI.Base_methods:
   1.363 -            method_full_name = '%s_%s' % (cls, method_name)
   1.364 -            try:
   1.365 -                method = getattr(XendAPI, method_full_name)
   1.366 -                for validator in validators:
   1.367 -                    method = validator(method)
   1.368 -                    method.api = '%s.%s' % (cls, method_name)
   1.369 -                setattr(XendAPI, method_full_name, method)
   1.370 -            except AttributeError:
   1.371 -                pass
   1.372 -                #log.warn('API call: %s not found' % method_full_name)
   1.373 +            doit('%s.%s' % (cls, method_name), True)
   1.374  
   1.375          # wrap validators around class functions
   1.376          for func_name in funcs + XendAPI.Base_funcs:
   1.377 -            func_full_name = '%s_%s' % (cls, func_name)
   1.378 -            try:
   1.379 -                method = getattr(XendAPI, func_full_name)
   1.380 -                method = session_required(method)
   1.381 -                method.api = '%s.%s' % (cls, func_name)
   1.382 -                method = catch_typeerror(method)
   1.383 -                method.api = '%s.%s' % (cls, func_name)
   1.384 -                setattr(XendAPI, func_full_name, method)
   1.385 -            except AttributeError:
   1.386 -                log.warn('API call: %s not found' % func_full_name)
   1.387 +            doit('%s.%s' % (cls, func_name), False)
   1.388  
   1.389  _decorate()
   1.390