123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- """
- Health checks for OpenShift clusters.
- """
- import operator
- import os
- from abc import ABCMeta, abstractmethod, abstractproperty
- from importlib import import_module
- from ansible.module_utils import six
- from ansible.module_utils.six.moves import reduce # pylint: disable=import-error,redefined-builtin
- class OpenShiftCheckException(Exception):
- """Raised when a check cannot proceed."""
- pass
- @six.add_metaclass(ABCMeta)
- class OpenShiftCheck(object):
- """A base class for defining checks for an OpenShift cluster environment."""
- def __init__(self, execute_module=None, module_executor=None):
- if execute_module is module_executor is None:
- raise TypeError(
- "__init__() takes either execute_module (recommended) "
- "or module_executor (deprecated), none given")
- self.execute_module = execute_module or module_executor
- self.module_executor = self.execute_module
- @abstractproperty
- def name(self):
- """The name of this check, usually derived from the class name."""
- return "openshift_check"
- @property
- def tags(self):
- """A list of tags that this check satisfy.
- Tags are used to reference multiple checks with a single '@tagname'
- special check name.
- """
- return []
- @classmethod
- def is_active(cls, task_vars): # pylint: disable=unused-argument
- """Returns true if this check applies to the ansible-playbook run."""
- return True
- @abstractmethod
- def run(self, tmp, task_vars):
- """Executes a check, normally implemented as a module."""
- return {}
- @classmethod
- def subclasses(cls):
- """Returns a generator of subclasses of this class and its subclasses."""
- # AUDIT: no-member makes sense due to this having a metaclass
- for subclass in cls.__subclasses__(): # pylint: disable=no-member
- yield subclass
- for subclass in subclass.subclasses():
- yield subclass
- LOADER_EXCLUDES = (
- "__init__.py",
- "mixins.py",
- "logging.py",
- )
- def load_checks(path=None, subpkg=""):
- """Dynamically import all check modules for the side effect of registering checks."""
- if path is None:
- path = os.path.dirname(__file__)
- modules = []
- for name in os.listdir(path):
- if os.path.isdir(os.path.join(path, name)):
- modules = modules + load_checks(os.path.join(path, name), subpkg + "." + name)
- continue
- if name.endswith(".py") and name not in LOADER_EXCLUDES:
- modules.append(import_module(__package__ + subpkg + "." + name[:-3]))
- return modules
- def get_var(task_vars, *keys, **kwargs):
- """Helper function to get deeply nested values from task_vars.
- Ansible task_vars structures are Python dicts, often mapping strings to
- other dicts. This helper makes it easier to get a nested value, raising
- OpenShiftCheckException when a key is not found or returning a default value
- provided as a keyword argument.
- """
- try:
- value = reduce(operator.getitem, keys, task_vars)
- except (KeyError, TypeError):
- if "default" in kwargs:
- return kwargs["default"]
- raise OpenShiftCheckException("'{}' is undefined".format(".".join(map(str, keys))))
- return value
|