Source code for libsolace.Decorators

import functools
import logging
from functools import wraps

from libsolace.Exceptions import MissingException, MissingClientUser
from libsolace.util import get_calling_module

# plugin_name = "Decorators"

__doc__ = """
Some decorators which are used within the Plugins in order to control / limit execution.
"""


[docs]def deprecation_warning(warning_msg): """ Log a deprecation warning and carry on. :param warning_msg: the warning text :type warning_msg: str :rtype: object :returns: the decorated object """ def wrap(f): @wraps(f) def wrapped_f(*args, **kwargs): module = get_calling_module() logging.warning("Deprecation Warning: %s: %s %s" % (warning_msg, module, f.__name__)) return f(*args, **kwargs) return wrapped_f return wrap
[docs]def before(method_name, skip_before=False): """ Call a named method before. This is typically used to tell a object to shutdown so some modification can be made. This decorator passes all kwargs and args on to the "before" method so keep your params and keywords in sync! Example: .. doctest:: :options: +SKIP >>> def shutdown(self, **kwargs): >>> # shutdown some object >>> @before("shutdown") >>> def delete(self, **kwargs): >>> # delete object since its shutdown :param method_name: the method name to call :type method_name: str :param skip_before: skips the before hook :type skip_before: bool :returns: the decorated object :rtype: obj """ def wrap(f): @wraps(f) def wrapped_f(*args, **kwargs): # force kwarg, just return the method to allow exec if kwargs["skip_before"]: return f(*args, **kwargs) api = getattr(args[0], "api") logging.info("calling object %s's shutdown hook" % api) try: api.rpc(str(getattr(args[0], method_name)(**kwargs))) return f(*args, **kwargs) except Exception, e: raise BaseException( "Error calling @before(%s) method in %s kwargs: %s" % (method_name, args[0], kwargs)) return wrapped_f return wrap
[docs]def only_on_shutdown(entity, **kwargs): """ Only calls the method if the shutdown_on_apply rules apply to the `entity` type. The entity can be either `queue` or `user`. Methods decorated with this can optionally be decorated with the @shutdown decorator to actually call whatever method is capable of shutting down the object. If the object is not shutdown correcty, the appliance can not change the property and will raise an exception. Example: .. doctest:: :options: +SKIP >>> @only_on_shutdown('user') >>> def delete_user(**kwargs): >>> return True >>> delete_user(shutdown_on_apply='u') True >>> delete_user(shutdown_on_apply='q') None :param entity: the type of entity were expecting for the following comparisons: "user": If shutdown_on_apply is True | b | u for a "user" entity, then allow the method to run. "queue": If shutdown_on_apply is True | b | q for a "queue" entity, then allow the method to run. :type entity: str :param force: :data:`libsolace.Kwargs.force` :type force: bool :param shutdown_on_apply: :data:`libsolace.Kwargs.shutdown_on_apply` :rtype: object :returns: the object to call """ def wrap(f): @wraps(f) def wrapped_f(*args, **kwargs): # if force, return the method to allow exec if "force" in kwargs and kwargs.get('force'): args[0].set_exists(True) return f(*args, **kwargs) mode = kwargs.get('shutdown_on_apply', None) if entity == 'queue' and mode in ['b', 'q', True]: return f(*args, **kwargs) if entity == 'user' and mode in ['b', 'u', True]: return f(*args, **kwargs) module = get_calling_module() logging.info( "Package %s requires shutdown of this object, shutdown_on_apply is not set for this object type, bypassing %s for entity %s" % ( module, f.__name__, entity)) return wrapped_f return wrap
[docs]def only_if_not_exists(entity, data_path, primaryOnly=False, backupOnly=False, **kwargs): """ Call the method only if the Solace object does NOT exist in the Solace appliance. - if the object's exists caching bit is False, return the method - If the object does not exist, return the method and set the exists bit to False - If the object exists in the appliance, set the exists bit to True Example: .. doctest:: :options: +SKIP >>> @only_if_not_exists('get', 'rpc-reply.rpc.show.client-username.client-usernames.client-username') >>> def create_user(**kwargs): >>> return True >>> create_user() :param entity: the "getter" method to call by name :type entity: str :param data_path: a dot name spaced string which will be used to descend into the response document to verify existence :type data_path: str :param primaryOnly: :data:`libsolace.Kwargs.primaryOnly` :type primaryOnly: bool :param backupOnly: :data:`libsolace.Kwargs.backupOnly` :type backupOnly: bool :param force: :data:`libsolace.Kwargs.force` :type force: bool :rtype: object :returns: the object to call """ def wrap(f): @wraps(f) def wrapped_f(*args, **kwargs): logging.info(kwargs) # force kwarg, just return the method to allow exec if "force" in kwargs and kwargs.get('force'): args[0].set_exists(True) return f(*args, **kwargs) # default false check_primary = False check_backup = False # extract package name module = get_calling_module() # force kwarg, just return the method to allow exec if "force" in kwargs and kwargs.get('force'): logging.info("Force being used, returning obj") args[0].set_exists(False) return f(*args, **kwargs) else: logging.info("Not forcing return of object") # determine if were checking both or a single node if primaryOnly: kwargs['primaryOnly'] = primaryOnly check_primary = True elif backupOnly: kwargs['backupOnly'] = backupOnly check_backup = True else: logging.info("Package: %s requests that Both primary and backup be queried" % module) check_primary = True check_backup = True # if exists bit is set on the object ( caching ) try: if not args[0].exists: logging.info("Cache hit, object does NOT exist") return f(*args, **kwargs) except Exception, e: pass logging.debug("Cache miss") logging.info("Package: %s, asking entity: %s, for args: %s, kwargs: %s via data_path: %s" % ( module, entity, str(args), str(kwargs), data_path)) response_path = data_path.split('.') # if the getattr fails with a MissingException, which means our condition is met try: res = getattr(args[0], entity)(**kwargs) except MissingException: exists = False args[0].set_exists(exists) return f(*args, **kwargs) logging.info("Response %s" % res) # try peek into attributes, any raises means one of the nodes does not have the object. o_res = res exists = True for p in response_path: if check_primary: try: res[0] = res[0][p] except (KeyError, TypeError, IndexError): logging.info("Object not found on PRIMARY, key:%s setting primaryOnly" % p) logging.info(o_res) kwargs['primaryOnly'] = True exists = False if check_backup: try: res[1] = res[1][p] except (KeyError, TypeError, IndexError): logging.info("Object not found on BACKUP, key:%s setting backupOnly" % p) logging.info(o_res) kwargs['backupOnly'] = True exists = False if not exists: args[0].set_exists(exists) return f(*args, **kwargs) else: # if we reach here, the object exists logging.info( "Package %s - %s, the requested object already exists, ignoring creation" % ( module, f.__name__)) args[0].set_exists(exists) return wrapped_f return wrap
[docs]def only_if_exists(entity, data_path, primaryOnly=False, backupOnly=False, **kwargs): """ The inverse of :func:`only_if_not_exists` """ def wrap(f): @wraps(f) def wrapped_f(*args, **kwargs): # default false check_primary = False check_backup = False # extract package name module = get_calling_module() # force kwarg, just return the method to allow exec if "force" in kwargs and kwargs.get('force'): logging.info("Force being used, returning obj") args[0].set_exists(True) return f(*args, **kwargs) else: logging.info("Not forcing return of object") # determine if were checking both or a single node if primaryOnly: kwargs['primaryOnly'] = primaryOnly check_primary = True elif backupOnly: kwargs['backupOnly'] = backupOnly check_backup = True else: logging.info("Package: %s requests that Both primary and backup be queried" % module) check_primary = True check_backup = True # if exists bit is set on the object ( caching ) try: if args[0].exists: logging.info("Cache hit, object exists") return f(*args, **kwargs) except Exception, e: pass logging.debug("Cache miss") logging.info("Package: %s, asking entity: %s, for args: %s, kwargs: %s via data_path: %s" % ( module, entity, str(args), str(kwargs), data_path)) response_path = data_path.split('.') res = getattr(args[0], entity)(**kwargs) o_res = res logging.debug("Response %s" % res) exists = True # try peek into attributes, any raises means one of the nodes does not have the object. for p in response_path: if check_primary: try: res[0] = res[0][p] except (TypeError, IndexError): logging.info("Object not found on PRIMARY, key:%s error" % p) logging.info(o_res) kwargs['primaryOnly'] = True args[0].set_exists(False) exists = False if check_backup: try: res[1] = res[1][p] except (TypeError, IndexError): logging.info("Object not found on BACKUP, key:%s error" % p) logging.info(o_res) kwargs['backupOnly'] = True args[0].set_exists(False) exists = False if exists: module = get_calling_module() logging.info( "Package %s - the requested object exists, calling method %s, check entity was: %s" % ( module, f.__name__, entity)) args[0].set_exists(True) return f(*args, **kwargs) return wrapped_f return wrap
[docs]def primary(): """ Sets the primaryOnly kwarg before calling the method. Use this to add a specific router to the appliances to call list. Note, this does not unset backupOnly kwarg, so you can actualy double target. :returns: method """ def wrap(f): @wraps(f) def wrapped_f(*args, **kwargs): kwargs['primaryOnly'] = True module = get_calling_module() logging.info("Calling package %s - Setting primaryOnly: %s" % (module, f.__name__)) return f(*args, **kwargs) return wrapped_f return wrap
[docs]def backup(): """ Sets the backupOnly kwarg before calling the method. Use this to add a specific router to the appliances to call list. Note, this does not unset primaryOnly kwarg, so you can actualy double target. :returns: method """ def wrap(f): @wraps(f) def wrapped_f(*args, **kwargs): kwargs['backupOnly'] = True module = get_calling_module() logging.info("Calling package %s - Setting backupOnly: %s" % (module, f.__name__)) return f(*args, **kwargs) return wrapped_f return wrap