middleware.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. import logging
  2. import sys
  3. from inspect import ismethod
  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 discover_handlers(self, class_or_obj):
  43. discovered_handlers = []
  44. for key in dir(class_or_obj):
  45. try:
  46. func = getattr(object, key)
  47. # Properties can sometimes cause various exceptions (e.g. during
  48. # auth failure testing)
  49. except Exception:
  50. continue
  51. if ismethod(func):
  52. handler = getattr(func, "__event_handler", None)
  53. if handler and isinstance(handler, EventHandler):
  54. # Set the properly bound method as the callback
  55. handler.callback = func
  56. discovered_handlers.append(handler)
  57. return discovered_handlers
  58. def uninstall(self):
  59. for handler in self.event_handlers:
  60. handler.unsubscribe()
  61. self.event_handlers = []
  62. self.events = None
  63. class AutoDiscoveredMiddleware(BaseMiddleware):
  64. def __init__(self, class_or_obj):
  65. super(AutoDiscoveredMiddleware, self).__init__()
  66. self.obj_to_discover = class_or_obj
  67. def install(self, event_manager):
  68. super(AutoDiscoveredMiddleware, self).install(event_manager)
  69. discovered_handlers = self.discover_handlers(self.obj_to_discover)
  70. self.add_handlers(discovered_handlers)
  71. class EventDebugLoggingMiddleware(BaseMiddleware):
  72. """
  73. Logs all event parameters. This middleware should not be enabled other
  74. than for debugging, as it could log sensitive parameters such as
  75. access keys.
  76. """
  77. def setup(self):
  78. self.add_observer(
  79. event_pattern="*", priority=1100, callback=self.pre_log_event)
  80. self.add_interceptor(
  81. event_pattern="*", priority=1150, callback=self.post_log_event)
  82. @observe(event_pattern="*", priority=1100)
  83. def pre_log_event(self, **kwargs):
  84. log.debug("Event: {0} invoked with args: {1}".format(
  85. kwargs.get("event"), kwargs))
  86. @intercept(event_pattern="*", priority=1150)
  87. def post_log_event(self, **kwargs):
  88. next_handler = kwargs.pop("next_handler")
  89. result = next_handler.invoke(**kwargs)
  90. log.debug("Event: {0} result: {1}".format(
  91. kwargs.get("event"), result))
  92. return result
  93. class ExceptionWrappingMiddleware(BaseMiddleware):
  94. """
  95. Wraps all unhandled exceptions in cloudbridge exceptions.
  96. """
  97. def setup(self):
  98. self.add_interceptor(
  99. event_pattern="*", priority=1050, callback=self.wrap_exception)
  100. def wrap_exception(self, **kwargs):
  101. next_handler = kwargs.pop("next_handler")
  102. try:
  103. return next_handler.invoke(**kwargs)
  104. except Exception as e:
  105. if isinstance(e, CloudBridgeBaseException):
  106. raise
  107. else:
  108. ex_type, ex_value, traceback = sys.exc_info()
  109. cb_ex = CloudBridgeBaseException(
  110. "CloudBridgeBaseException: {0} from exception type: {1}"
  111. .format(ex_value, ex_type))
  112. if sys.version_info >= (3, 0):
  113. six.raise_from(cb_ex, e)
  114. else:
  115. six.reraise(CloudBridgeBaseException, cb_ex, traceback)