__init__.py 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. """
  2. Health checks for OpenShift clusters.
  3. """
  4. import operator
  5. import os
  6. from abc import ABCMeta, abstractmethod, abstractproperty
  7. from importlib import import_module
  8. from ansible.module_utils import six
  9. from ansible.module_utils.six.moves import reduce # pylint: disable=import-error,redefined-builtin
  10. class OpenShiftCheckException(Exception):
  11. """Raised when a check cannot proceed."""
  12. pass
  13. @six.add_metaclass(ABCMeta)
  14. class OpenShiftCheck(object):
  15. """A base class for defining checks for an OpenShift cluster environment."""
  16. def __init__(self, execute_module=None, module_executor=None):
  17. if execute_module is module_executor is None:
  18. raise TypeError(
  19. "__init__() takes either execute_module (recommended) "
  20. "or module_executor (deprecated), none given")
  21. self.execute_module = execute_module or module_executor
  22. self.module_executor = self.execute_module
  23. @abstractproperty
  24. def name(self):
  25. """The name of this check, usually derived from the class name."""
  26. return "openshift_check"
  27. @property
  28. def tags(self):
  29. """A list of tags that this check satisfy.
  30. Tags are used to reference multiple checks with a single '@tagname'
  31. special check name.
  32. """
  33. return []
  34. @classmethod
  35. def is_active(cls, task_vars): # pylint: disable=unused-argument
  36. """Returns true if this check applies to the ansible-playbook run."""
  37. return True
  38. @abstractmethod
  39. def run(self, tmp, task_vars):
  40. """Executes a check, normally implemented as a module."""
  41. return {}
  42. @classmethod
  43. def subclasses(cls):
  44. """Returns a generator of subclasses of this class and its subclasses."""
  45. # AUDIT: no-member makes sense due to this having a metaclass
  46. for subclass in cls.__subclasses__(): # pylint: disable=no-member
  47. yield subclass
  48. for subclass in subclass.subclasses():
  49. yield subclass
  50. LOADER_EXCLUDES = (
  51. "__init__.py",
  52. "mixins.py",
  53. )
  54. def load_checks():
  55. """Dynamically import all check modules for the side effect of registering checks."""
  56. return [
  57. import_module(__package__ + "." + name[:-3])
  58. for name in os.listdir(os.path.dirname(__file__))
  59. if name.endswith(".py") and name not in LOADER_EXCLUDES
  60. ]
  61. def get_var(task_vars, *keys, **kwargs):
  62. """Helper function to get deeply nested values from task_vars.
  63. Ansible task_vars structures are Python dicts, often mapping strings to
  64. other dicts. This helper makes it easier to get a nested value, raising
  65. OpenShiftCheckException when a key is not found or returning a default value
  66. provided as a keyword argument.
  67. """
  68. try:
  69. value = reduce(operator.getitem, keys, task_vars)
  70. except (KeyError, TypeError):
  71. if "default" in kwargs:
  72. return kwargs["default"]
  73. raise OpenShiftCheckException("'{}' is undefined".format(".".join(map(str, keys))))
  74. return value