middleware.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. import inspect
  2. import logging
  3. import sys
  4. import six
  5. from ..base.events import intercept
  6. from ..base.events import observe
  7. from ..interfaces.events import EventHandler
  8. from ..interfaces.exceptions import CloudBridgeBaseException
  9. from ..interfaces.middleware import Middleware
  10. from ..interfaces.middleware import MiddlewareManager
  11. log = logging.getLogger(__name__)
  12. class SimpleMiddlewareManager(MiddlewareManager):
  13. def __init__(self, event_manager):
  14. self.events = event_manager
  15. self.middleware_list = []
  16. def add(self, middleware):
  17. if isinstance(middleware, Middleware):
  18. m = middleware
  19. else:
  20. m = AutoDiscoveredMiddleware(middleware)
  21. m.install(self.events)
  22. self.middleware_list.append(m)
  23. return m
  24. def remove(self, middleware):
  25. middleware.uninstall()
  26. self.middleware_list.remove(middleware)
  27. class BaseMiddleware(Middleware):
  28. def __init__(self):
  29. self.event_handlers = []
  30. self.events = None
  31. def install(self, event_manager):
  32. self.events = event_manager
  33. discovered_handlers = self.discover_handlers(self)
  34. self.add_handlers(discovered_handlers)
  35. def add_handlers(self, handlers):
  36. if not hasattr(self, "event_handlers"):
  37. # In case the user forgot to call super class init
  38. self.event_handlers = []
  39. for handler in handlers:
  40. self.events.subscribe(handler)
  41. self.event_handlers.extend(handlers)
  42. def uninstall(self):
  43. for handler in self.event_handlers:
  44. handler.unsubscribe()
  45. self.event_handlers = []
  46. self.events = None
  47. @staticmethod
  48. def discover_handlers(class_or_obj):
  49. # https://bugs.python.org/issue30533
  50. # simulating a getmembers_static to be easily replaced with the
  51. # function if they add it to inspect module
  52. def getmembers_static(obj, predicate=None):
  53. results = []
  54. for key in dir(obj):
  55. if not inspect.isdatadescriptor(getattr(obj.__class__,
  56. key,
  57. None)):
  58. try:
  59. value = getattr(obj, key)
  60. except AttributeError:
  61. continue
  62. if not predicate or predicate(value):
  63. results.append((key, value))
  64. return results
  65. discovered_handlers = []
  66. for _, func in getmembers_static(class_or_obj, inspect.ismethod):
  67. handler = getattr(func, "__event_handler", None)
  68. if handler and isinstance(handler, EventHandler):
  69. # Set the properly bound method as the callback
  70. handler.callback = func
  71. discovered_handlers.append(handler)
  72. return discovered_handlers
  73. class AutoDiscoveredMiddleware(BaseMiddleware):
  74. def __init__(self, class_or_obj):
  75. super(AutoDiscoveredMiddleware, self).__init__()
  76. self.obj_to_discover = class_or_obj
  77. def install(self, event_manager):
  78. super(AutoDiscoveredMiddleware, self).install(event_manager)
  79. discovered_handlers = self.discover_handlers(self.obj_to_discover)
  80. self.add_handlers(discovered_handlers)
  81. class EventDebugLoggingMiddleware(BaseMiddleware):
  82. """
  83. Logs all event parameters. This middleware should not be enabled other
  84. than for debugging, as it could log sensitive parameters such as
  85. access keys.
  86. """
  87. def setup(self):
  88. self.add_observer(
  89. event_pattern="*", priority=1100, callback=self.pre_log_event)
  90. self.add_interceptor(
  91. event_pattern="*", priority=1150, callback=self.post_log_event)
  92. @observe(event_pattern="*", priority=1100)
  93. def pre_log_event(self, **kwargs):
  94. log.debug("Event: {0} invoked with args: {1}".format(
  95. kwargs.get("event"), kwargs))
  96. @intercept(event_pattern="*", priority=1150)
  97. def post_log_event(self, **kwargs):
  98. next_handler = kwargs.pop("next_handler")
  99. result = next_handler.invoke(**kwargs)
  100. log.debug("Event: {0} result: {1}".format(
  101. kwargs.get("event"), result))
  102. return result
  103. class ExceptionWrappingMiddleware(BaseMiddleware):
  104. """
  105. Wraps all unhandled exceptions in cloudbridge exceptions.
  106. """
  107. def setup(self):
  108. self.add_interceptor(
  109. event_pattern="*", priority=1050, callback=self.wrap_exception)
  110. def wrap_exception(self, **kwargs):
  111. next_handler = kwargs.pop("next_handler")
  112. try:
  113. return next_handler.invoke(**kwargs)
  114. except Exception as e:
  115. if isinstance(e, CloudBridgeBaseException):
  116. raise
  117. else:
  118. ex_type, ex_value, traceback = sys.exc_info()
  119. cb_ex = CloudBridgeBaseException(
  120. "CloudBridgeBaseException: {0} from exception type: {1}"
  121. .format(ex_value, ex_type))
  122. if sys.version_info >= (3, 0):
  123. six.raise_from(cb_ex, e)
  124. else:
  125. six.reraise(CloudBridgeBaseException, cb_ex, traceback)