import ipa-healthcheck-0.4-4.module+el8.2.0+5496+53199ee7

This commit is contained in:
CentOS Sources 2020-07-28 10:19:48 -04:00 committed by Stepan Oksanichenko
commit ad3d7db9de
10 changed files with 2837 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
SOURCES/freeipa-healthcheck-0.4.tar.gz

View File

@ -0,0 +1 @@
2e61604c36f6f793612b1e3bb3f5e78df1cb58ac SOURCES/freeipa-healthcheck-0.4.tar.gz

View File

@ -0,0 +1,26 @@
From 611a7d51ac6b49770cdc0da02d101023a4a49536 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Fri, 3 May 2019 10:10:57 -0400
Subject: [PATCH] Remove requirement for pytest-runner since PyPI isn't
available
We won't be executing make check because the dependencies aren't
available due to IDM being in a module.
---
setup.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/setup.py b/setup.py
index 801323f..c3cd215 100644
--- a/setup.py
+++ b/setup.py
@@ -60,6 +60,5 @@ setup(
'Programming Language :: Python :: 3.6',
],
python_requires='!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*',
- setup_requires=['pytest-runner',],
tests_require=['pytest',],
)
--
2.17.2

View File

@ -0,0 +1,106 @@
From eb87d277442dd1a1076ba9ae74c18ace8cc7dda8 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Mon, 11 Nov 2019 10:29:53 -0500
Subject: [PATCH 2/5] Move main to run_healthcheck for abstraction purposes
Take as arguments the entry point name and the configuration
file.
---
src/ipahealthcheck/core/config.py | 4 ++--
src/ipahealthcheck/core/main.py | 37 +++++++++++++++++--------------
2 files changed, 22 insertions(+), 19 deletions(-)
diff --git a/src/ipahealthcheck/core/config.py b/src/ipahealthcheck/core/config.py
index 46da507..0cb72b7 100644
--- a/src/ipahealthcheck/core/config.py
+++ b/src/ipahealthcheck/core/config.py
@@ -5,7 +5,7 @@
import logging
from configparser import ConfigParser, ParsingError
-from ipahealthcheck.core.constants import CONFIG_FILE, CONFIG_SECTION
+from ipahealthcheck.core.constants import CONFIG_SECTION
from ipahealthcheck.core.constants import DEFAULT_CONFIG
logger = logging.getLogger()
@@ -70,7 +70,7 @@ class Config:
self.__d[key] = d[key]
-def read_config(config_file=CONFIG_FILE):
+def read_config(config_file):
"""
Simple configuration file reader
diff --git a/src/ipahealthcheck/core/main.py b/src/ipahealthcheck/core/main.py
index b3fbe6a..f59a8a8 100644
--- a/src/ipahealthcheck/core/main.py
+++ b/src/ipahealthcheck/core/main.py
@@ -28,11 +28,14 @@ else:
from ipahealthcheck.meta.services import ServiceCheck
-def find_registries():
- return {
- ep.name: ep.resolve()
- for ep in pkg_resources.iter_entry_points('ipahealthcheck.registry')
- }
+def find_registries(entry_points):
+ registries = {}
+ for entry_point in entry_points:
+ registries.update({
+ ep.name: ep.resolve()
+ for ep in pkg_resources.iter_entry_points(entry_point)
+ })
+ return registries
def find_plugins(name, registry):
@@ -194,9 +197,7 @@ def limit_results(results, source, check):
return new_results
-def main():
- environ["KRB5_CLIENT_KTNAME"] = "/etc/krb5.keytab"
- environ["KRB5CCNAME"] = "MEMORY:"
+def run_healthcheck(entry_points, configfile):
framework = object()
plugins = []
output = constants.DEFAULT_OUTPUT
@@ -208,17 +209,11 @@ def main():
if options.debug:
logger.setLevel(logging.DEBUG)
- config = read_config()
+ config = read_config(configfile)
if config is None:
sys.exit(1)
- if not (
- options.source or options.list_sources
- ) and not is_ipa_configured():
- logging.error("IPA is not configured on this system.")
- sys.exit(1)
-
- for name, registry in find_registries().items():
+ for name, registry in find_registries(entry_points).items():
try:
registry.initialize(framework)
except Exception as e:
@@ -283,4 +278,12 @@ def main():
return_value = 1
break
- sys.exit(return_value)
+ return return_value
+
+
+def main():
+ environ["KRB5_CLIENT_KTNAME"] = "/etc/krb5.keytab"
+ environ["KRB5CCNAME"] = "MEMORY:"
+
+ sys.exit(run_healthcheck(['ipahealthcheck.registry'],
+ constants.CONFIG_FILE))
--
2.20.1

View File

@ -0,0 +1,187 @@
From c40e32b9d0ac49806b8336bd5065350574d29672 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Mon, 18 Nov 2019 12:51:27 -0500
Subject: [PATCH 3/5] Abstract ServiceCheck to not be IPA-specific
It is up to the implementor to check for services running for now.
---
src/ipahealthcheck/core/main.py | 9 +--------
src/ipahealthcheck/core/service.py | 10 ++++++++++
src/ipahealthcheck/meta/services.py | 29 +++++++++++++++--------------
3 files changed, 26 insertions(+), 22 deletions(-)
create mode 100644 src/ipahealthcheck/core/service.py
diff --git a/src/ipahealthcheck/core/main.py b/src/ipahealthcheck/core/main.py
index f59a8a8..2b818d4 100644
--- a/src/ipahealthcheck/core/main.py
+++ b/src/ipahealthcheck/core/main.py
@@ -15,18 +15,11 @@ from ipahealthcheck.core.config import read_config
from ipahealthcheck.core.plugin import Result, Results, json_to_results
from ipahealthcheck.core.output import output_registry
from ipahealthcheck.core import constants
+from ipahealthcheck.core.service import ServiceCheck
logging.basicConfig(format='%(message)s')
logger = logging.getLogger()
-try:
- from ipaserver.install.installutils import is_ipa_configured
-except ImportError:
- logging.error("IPA server packages are not installed on this system.")
- sys.exit(1)
-else:
- from ipahealthcheck.meta.services import ServiceCheck
-
def find_registries(entry_points):
registries = {}
diff --git a/src/ipahealthcheck/core/service.py b/src/ipahealthcheck/core/service.py
new file mode 100644
index 0000000..f9e2645
--- /dev/null
+++ b/src/ipahealthcheck/core/service.py
@@ -0,0 +1,10 @@
+#
+# Copyright (C) 2019 FreeIPA Contributors see COPYING for license
+#
+
+from ipahealthcheck.core.plugin import Plugin
+
+
+class ServiceCheck(Plugin):
+ def check(self, instance=''):
+ raise NotImplementedError
diff --git a/src/ipahealthcheck/meta/services.py b/src/ipahealthcheck/meta/services.py
index d375066..a987108 100644
--- a/src/ipahealthcheck/meta/services.py
+++ b/src/ipahealthcheck/meta/services.py
@@ -6,7 +6,8 @@ import logging
from ipahealthcheck.core import constants
from ipahealthcheck.core.plugin import Result, duration
-from ipahealthcheck.meta.plugin import Plugin, registry
+from ipahealthcheck.core.service import ServiceCheck
+from ipahealthcheck.meta.plugin import registry
try:
from ipapython.ipaldap import realm_to_serverid
except ImportError:
@@ -20,7 +21,7 @@ from ipaserver.install import cainstance
logger = logging.getLogger()
-class ServiceCheck(Plugin):
+class IPAServiceCheck(ServiceCheck):
@duration
def check(self, instance=''):
try:
@@ -47,7 +48,7 @@ class ServiceCheck(Plugin):
@registry
-class certmonger(ServiceCheck):
+class certmonger(IPAServiceCheck):
def check(self):
self.service_name = 'certmonger'
@@ -55,7 +56,7 @@ class certmonger(ServiceCheck):
@registry
-class dirsrv(ServiceCheck):
+class dirsrv(IPAServiceCheck):
def check(self):
self.service_name = 'dirsrv'
@@ -63,7 +64,7 @@ class dirsrv(ServiceCheck):
@registry
-class gssproxy(ServiceCheck):
+class gssproxy(IPAServiceCheck):
def check(self):
self.service_name = 'gssproxy'
@@ -71,7 +72,7 @@ class gssproxy(ServiceCheck):
@registry
-class httpd(ServiceCheck):
+class httpd(IPAServiceCheck):
def check(self):
self.service_name = 'httpd'
@@ -79,7 +80,7 @@ class httpd(ServiceCheck):
@registry
-class ipa_custodia(ServiceCheck):
+class ipa_custodia(IPAServiceCheck):
def check(self):
self.service_name = 'ipa-custodia'
@@ -87,7 +88,7 @@ class ipa_custodia(ServiceCheck):
@registry
-class ipa_dnskeysyncd(ServiceCheck):
+class ipa_dnskeysyncd(IPAServiceCheck):
def check(self):
self.service_name = 'ipa-dnskeysyncd'
@@ -98,7 +99,7 @@ class ipa_dnskeysyncd(ServiceCheck):
@registry
-class ipa_otpd(ServiceCheck):
+class ipa_otpd(IPAServiceCheck):
def check(self):
self.service_name = 'ipa-otpd'
@@ -106,7 +107,7 @@ class ipa_otpd(ServiceCheck):
@registry
-class kadmin(ServiceCheck):
+class kadmin(IPAServiceCheck):
def check(self):
self.service_name = 'kadmin'
@@ -114,7 +115,7 @@ class kadmin(ServiceCheck):
@registry
-class krb5kdc(ServiceCheck):
+class krb5kdc(IPAServiceCheck):
def check(self):
self.service_name = 'krb5kdc'
@@ -122,7 +123,7 @@ class krb5kdc(ServiceCheck):
@registry
-class named(ServiceCheck):
+class named(IPAServiceCheck):
def check(self):
self.service_name = 'named'
@@ -133,7 +134,7 @@ class named(ServiceCheck):
@registry
-class pki_tomcatd(ServiceCheck):
+class pki_tomcatd(IPAServiceCheck):
def check(self):
self.service_name = 'pki_tomcatd'
@@ -145,7 +146,7 @@ class pki_tomcatd(ServiceCheck):
@registry
-class sssd(ServiceCheck):
+class sssd(IPAServiceCheck):
def check(self):
self.service_name = 'sssd'
--
2.20.1

View File

@ -0,0 +1,579 @@
From 952fc6f6dee99523360c9826ad865086cd31474f Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Mon, 18 Nov 2019 14:33:32 -0500
Subject: [PATCH 4/5] Move the abstracted plugin runner code into a separate
file
This way main.py contains just the ipa-healthcheck main code
and not the rest of the abstracted code.
Also replace sys.exit(1) with return 1.
---
src/ipahealthcheck/core/core.py | 272 ++++++++++++++++++++++++++++++++
src/ipahealthcheck/core/main.py | 267 +------------------------------
2 files changed, 273 insertions(+), 266 deletions(-)
create mode 100644 src/ipahealthcheck/core/core.py
diff --git a/src/ipahealthcheck/core/core.py b/src/ipahealthcheck/core/core.py
new file mode 100644
index 0000000..182eac3
--- /dev/null
+++ b/src/ipahealthcheck/core/core.py
@@ -0,0 +1,272 @@
+#
+# Copyright (C) 2019 FreeIPA Contributors see COPYING for license
+#
+
+import argparse
+import json
+import logging
+import pkg_resources
+
+from datetime import datetime
+
+from ipahealthcheck.core.config import read_config
+from ipahealthcheck.core.plugin import Result, Results, json_to_results
+from ipahealthcheck.core.output import output_registry
+from ipahealthcheck.core import constants
+from ipahealthcheck.core.service import ServiceCheck
+
+logging.basicConfig(format='%(message)s')
+logger = logging.getLogger()
+
+
+def find_registries(entry_points):
+ registries = {}
+ for entry_point in entry_points:
+ registries.update({
+ ep.name: ep.resolve()
+ for ep in pkg_resources.iter_entry_points(entry_point)
+ })
+ return registries
+
+
+def find_plugins(name, registry):
+ for ep in pkg_resources.iter_entry_points(name):
+ # load module
+ ep.load()
+ return registry.get_plugins()
+
+
+def run_plugin(plugin, available=()):
+ # manually calculate duration when we create results of our own
+ start = datetime.utcnow()
+ try:
+ for result in plugin.check():
+ if result is None:
+ # Treat no result as success, fudge start time
+ result = Result(plugin, constants.SUCCESS, start=start)
+ yield result
+ except Exception as e:
+ logger.debug('Exception raised: %s', e)
+ yield Result(plugin, constants.CRITICAL, exception=str(e),
+ start=start)
+
+
+def source_or_check_matches(plugin, source, check):
+ """Determine whether a given a plugin matches if a source
+ and optional check are provided.
+ """
+ if source is not None and plugin.__module__ != source:
+ return False
+
+ if check and plugin.__class__.__name__ != check:
+ return False
+
+ return True
+
+
+def run_service_plugins(plugins, config, source, check):
+ """Execute plugins with the base class of ServiceCheck
+
+ This is a specialized check to use systemd to determine
+ if a service is running or not.
+ """
+ results = Results()
+ available = []
+
+ for plugin in plugins:
+ if not isinstance(plugin, ServiceCheck):
+ continue
+
+ logger.debug('Calling check %s', plugin)
+ for result in plugin.check():
+ # always run the service checks so dependencies work
+ if result is not None and result.result == constants.SUCCESS:
+ available.append(plugin.service.service_name)
+ if not source_or_check_matches(plugin, source, check):
+ continue
+ if result is not None:
+ results.add(result)
+
+ return results, set(available)
+
+
+def run_plugins(plugins, config, available, source, check):
+ """Execute plugins without the base class of ServiceCheck
+
+ These are the remaining, non-service checking checks
+ that do validation for various parts of a system.
+ """
+ results = Results()
+
+ for plugin in plugins:
+ if isinstance(plugin, ServiceCheck):
+ continue
+
+ if not source_or_check_matches(plugin, source, check):
+ continue
+
+ logger.debug('Calling check %s' % plugin)
+ plugin.config = config
+ if not set(plugin.requires).issubset(available):
+ logger.debug('Skipping %s:%s because %s service(s) not running',
+ plugin.__class__.__module__,
+ plugin.__class__.__name__,
+ ', '.join(set(plugin.requires) - available))
+ # Not providing a Result in this case because if a required
+ # service isn't available then this could generate a lot of
+ # false positives.
+ else:
+ for result in run_plugin(plugin, available):
+ results.add(result)
+
+ return results
+
+
+def list_sources(plugins):
+ """Print list of all sources and checks"""
+ source = None
+ for plugin in plugins:
+ if source != plugin.__class__.__module__:
+ print(plugin.__class__.__module__)
+ source = plugin.__class__.__module__
+ print(" ", plugin.__class__.__name__)
+
+ return 0
+
+
+def parse_options(output_registry):
+ output_names = [plugin.__name__.lower() for
+ plugin in output_registry.plugins]
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--debug', dest='debug', action='store_true',
+ default=False, help='Include debug output')
+ parser.add_argument('--list-sources', dest='list_sources',
+ action='store_true', default=False,
+ help='List all available sources')
+ parser.add_argument('--source', dest='source',
+ default=None,
+ help='Source of checks, e.g. ipahealthcheck.foo.bar')
+ parser.add_argument('--check', dest='check',
+ default=None,
+ help='Check to execute, e.g. BazCheck')
+ parser.add_argument('--output-type', dest='output', choices=output_names,
+ default='json', help='Output method')
+ parser.add_argument('--output-file', dest='outfile', default=None,
+ help='File to store output')
+ parser.add_argument('--input-file', dest='infile',
+ help='File to read as input')
+ parser.add_argument('--failures-only', dest='failures_only',
+ action='store_true', default=False,
+ help='Exclude SUCCESS results on output')
+ parser.add_argument('--severity', dest='severity', action="append",
+ help='Include only the selected severity(s)',
+ choices=[key for key in constants._nameToLevel])
+ for plugin in output_registry.plugins:
+ onelinedoc = plugin.__doc__.split('\n\n', 1)[0].strip()
+ group = parser.add_argument_group(plugin.__name__.lower(),
+ onelinedoc)
+ for option in plugin.options:
+ group.add_argument(option[0], **option[1])
+
+ options = parser.parse_args()
+
+ # Validation
+ if options.check and not options.source:
+ print("--source is required when --check is used")
+ return 1
+
+ return options
+
+
+def limit_results(results, source, check):
+ """Return ony those results which match source and/or check"""
+ new_results = Results()
+ for result in results.results:
+ if result.source == source:
+ if check is None or result.check == check:
+ new_results.add(result)
+ return new_results
+
+
+def run_healthcheck(entry_points, configfile):
+ framework = object()
+ plugins = []
+ output = constants.DEFAULT_OUTPUT
+
+ logger.setLevel(logging.INFO)
+
+ options = parse_options(output_registry)
+
+ if options.debug:
+ logger.setLevel(logging.DEBUG)
+
+ config = read_config(configfile)
+ if config is None:
+ return 1
+
+ for name, registry in find_registries(entry_points).items():
+ try:
+ registry.initialize(framework)
+ except Exception as e:
+ print("Unable to initialize %s: %s" % (name, e))
+ return 1
+ for plugin in find_plugins(name, registry):
+ plugins.append(plugin)
+
+ for out in output_registry.plugins:
+ if out.__name__.lower() == options.output:
+ output = out(options)
+
+ if options.list_sources:
+ return list_sources(plugins)
+
+ if options.infile:
+ try:
+ with open(options.infile, 'r') as f:
+ raw_data = f.read()
+
+ json_data = json.loads(raw_data)
+ results = json_to_results(json_data)
+ available = ()
+ except Exception as e:
+ print("Unable to import '%s': %s" % (options.infile, e))
+ return 1
+ if options.source:
+ results = limit_results(results, options.source, options.check)
+ else:
+ results, available = run_service_plugins(plugins, config,
+ options.source,
+ options.check)
+ results.extend(run_plugins(plugins, config, available,
+ options.source, options.check))
+
+ if options.source and len(results.results) == 0:
+ for plugin in plugins:
+ if not source_or_check_matches(plugin, options.source,
+ options.check):
+ continue
+
+ if not set(plugin.requires).issubset(available):
+ print("Source '%s' is missing one or more requirements '%s'" %
+ (options.source, ', '.join(plugin.requires)))
+ return 1
+
+ if options.check:
+ print("Check '%s' not found in Source '%s'" %
+ (options.check, options.source))
+ else:
+ print("Source '%s' not found" % options.source)
+ return 1
+
+ try:
+ output.render(results)
+ except Exception as e:
+ logger.error('Output raised %s: %s', e.__class__.__name__, e)
+
+ return_value = 0
+ for result in results.results:
+ if result.result != constants.SUCCESS:
+ return_value = 1
+ break
+
+ return return_value
diff --git a/src/ipahealthcheck/core/main.py b/src/ipahealthcheck/core/main.py
index 2b818d4..d9e85d7 100644
--- a/src/ipahealthcheck/core/main.py
+++ b/src/ipahealthcheck/core/main.py
@@ -2,276 +2,11 @@
# Copyright (C) 2019 FreeIPA Contributors see COPYING for license
#
-import argparse
-import json
-import logging
from os import environ
-import pkg_resources
import sys
-from datetime import datetime
-
-from ipahealthcheck.core.config import read_config
-from ipahealthcheck.core.plugin import Result, Results, json_to_results
-from ipahealthcheck.core.output import output_registry
from ipahealthcheck.core import constants
-from ipahealthcheck.core.service import ServiceCheck
-
-logging.basicConfig(format='%(message)s')
-logger = logging.getLogger()
-
-
-def find_registries(entry_points):
- registries = {}
- for entry_point in entry_points:
- registries.update({
- ep.name: ep.resolve()
- for ep in pkg_resources.iter_entry_points(entry_point)
- })
- return registries
-
-
-def find_plugins(name, registry):
- for ep in pkg_resources.iter_entry_points(name):
- # load module
- ep.load()
- return registry.get_plugins()
-
-
-def run_plugin(plugin, available=()):
- # manually calculate duration when we create results of our own
- start = datetime.utcnow()
- try:
- for result in plugin.check():
- if result is None:
- # Treat no result as success, fudge start time
- result = Result(plugin, constants.SUCCESS, start=start)
- yield result
- except Exception as e:
- logger.debug('Exception raised: %s', e)
- yield Result(plugin, constants.CRITICAL, exception=str(e),
- start=start)
-
-
-def source_or_check_matches(plugin, source, check):
- """Determine whether a given a plugin matches if a source
- and optional check are provided.
- """
- if source is not None and plugin.__module__ != source:
- return False
-
- if check and plugin.__class__.__name__ != check:
- return False
-
- return True
-
-
-def run_service_plugins(plugins, config, source, check):
- """Execute plugins with the base class of ServiceCheck
-
- This is a specialized check to use systemd to determine
- if a service is running or not.
- """
- results = Results()
- available = []
-
- for plugin in plugins:
- if not isinstance(plugin, ServiceCheck):
- continue
-
- logger.debug('Calling check %s', plugin)
- for result in plugin.check():
- # always run the service checks so dependencies work
- if result is not None and result.result == constants.SUCCESS:
- available.append(plugin.service.service_name)
- if not source_or_check_matches(plugin, source, check):
- continue
- if result is not None:
- results.add(result)
-
- return results, set(available)
-
-
-def run_plugins(plugins, config, available, source, check):
- """Execute plugins without the base class of ServiceCheck
-
- These are the remaining, non-service checking checks
- that do validation for various parts of a system.
- """
- results = Results()
-
- for plugin in plugins:
- if isinstance(plugin, ServiceCheck):
- continue
-
- if not source_or_check_matches(plugin, source, check):
- continue
-
- logger.debug('Calling check %s' % plugin)
- plugin.config = config
- if not set(plugin.requires).issubset(available):
- logger.debug('Skipping %s:%s because %s service(s) not running',
- plugin.__class__.__module__,
- plugin.__class__.__name__,
- ', '.join(set(plugin.requires) - available))
- # Not providing a Result in this case because if a required
- # service isn't available then this could generate a lot of
- # false positives.
- else:
- for result in run_plugin(plugin, available):
- results.add(result)
-
- return results
-
-
-def list_sources(plugins):
- """Print list of all sources and checks"""
- source = None
- for plugin in plugins:
- if source != plugin.__class__.__module__:
- print(plugin.__class__.__module__)
- source = plugin.__class__.__module__
- print(" ", plugin.__class__.__name__)
-
- return 0
-
-
-def parse_options(output_registry):
- output_names = [plugin.__name__.lower() for
- plugin in output_registry.plugins]
- parser = argparse.ArgumentParser()
- parser.add_argument('--debug', dest='debug', action='store_true',
- default=False, help='Include debug output')
- parser.add_argument('--list-sources', dest='list_sources',
- action='store_true', default=False,
- help='List all available sources')
- parser.add_argument('--source', dest='source',
- default=None,
- help='Source of checks, e.g. ipahealthcheck.foo.bar')
- parser.add_argument('--check', dest='check',
- default=None,
- help='Check to execute, e.g. BazCheck')
- parser.add_argument('--output-type', dest='output', choices=output_names,
- default='json', help='Output method')
- parser.add_argument('--output-file', dest='outfile', default=None,
- help='File to store output')
- parser.add_argument('--input-file', dest='infile',
- help='File to read as input')
- parser.add_argument('--failures-only', dest='failures_only',
- action='store_true', default=False,
- help='Exclude SUCCESS results on output')
- parser.add_argument('--severity', dest='severity', action="append",
- help='Include only the selected severity(s)',
- choices=[key for key in constants._nameToLevel])
- for plugin in output_registry.plugins:
- onelinedoc = plugin.__doc__.split('\n\n', 1)[0].strip()
- group = parser.add_argument_group(plugin.__name__.lower(),
- onelinedoc)
- for option in plugin.options:
- group.add_argument(option[0], **option[1])
-
- options = parser.parse_args()
-
- # Validation
- if options.check and not options.source:
- print("--source is required when --check is used")
- sys.exit(1)
-
- return options
-
-
-def limit_results(results, source, check):
- """Return ony those results which match source and/or check"""
- new_results = Results()
- for result in results.results:
- if result.source == source:
- if check is None or result.check == check:
- new_results.add(result)
- return new_results
-
-
-def run_healthcheck(entry_points, configfile):
- framework = object()
- plugins = []
- output = constants.DEFAULT_OUTPUT
-
- logger.setLevel(logging.INFO)
-
- options = parse_options(output_registry)
-
- if options.debug:
- logger.setLevel(logging.DEBUG)
-
- config = read_config(configfile)
- if config is None:
- sys.exit(1)
-
- for name, registry in find_registries(entry_points).items():
- try:
- registry.initialize(framework)
- except Exception as e:
- print("Unable to initialize %s: %s" % (name, e))
- sys.exit(1)
- for plugin in find_plugins(name, registry):
- plugins.append(plugin)
-
- for out in output_registry.plugins:
- if out.__name__.lower() == options.output:
- output = out(options)
-
- if options.list_sources:
- return list_sources(plugins)
-
- if options.infile:
- try:
- with open(options.infile, 'r') as f:
- raw_data = f.read()
-
- json_data = json.loads(raw_data)
- results = json_to_results(json_data)
- available = ()
- except Exception as e:
- print("Unable to import '%s': %s" % (options.infile, e))
- sys.exit(1)
- if options.source:
- results = limit_results(results, options.source, options.check)
- else:
- results, available = run_service_plugins(plugins, config,
- options.source,
- options.check)
- results.extend(run_plugins(plugins, config, available,
- options.source, options.check))
-
- if options.source and len(results.results) == 0:
- for plugin in plugins:
- if not source_or_check_matches(plugin, options.source,
- options.check):
- continue
-
- if not set(plugin.requires).issubset(available):
- print("Source '%s' is missing one or more requirements '%s'" %
- (options.source, ', '.join(plugin.requires)))
- sys.exit(1)
-
- if options.check:
- print("Check '%s' not found in Source '%s'" %
- (options.check, options.source))
- else:
- print("Source '%s' not found" % options.source)
- sys.exit(1)
-
- try:
- output.render(results)
- except Exception as e:
- logger.error('Output raised %s: %s', e.__class__.__name__, e)
-
- return_value = 0
- for result in results.results:
- if result.result != constants.SUCCESS:
- return_value = 1
- break
-
- return return_value
+from ipahealthcheck.core.core import run_healthcheck
def main():
--
2.20.1

View File

@ -0,0 +1,228 @@
From af5c169151f0697d34954ac5c9dd0686dc73ef3f Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Mon, 18 Nov 2019 15:13:44 -0500
Subject: [PATCH 5/5] Convert running healthchecks into a class and add
pre-check
Add a pre-check so that dependencies can be checked per product.
In the case of IPA verify that the server is installed otherwise
bail out.
---
src/ipahealthcheck/core/core.py | 168 +++++++++++++++++---------------
src/ipahealthcheck/core/main.py | 17 +++-
2 files changed, 104 insertions(+), 81 deletions(-)
diff --git a/src/ipahealthcheck/core/core.py b/src/ipahealthcheck/core/core.py
index 182eac3..aef6197 100644
--- a/src/ipahealthcheck/core/core.py
+++ b/src/ipahealthcheck/core/core.py
@@ -188,85 +188,97 @@ def limit_results(results, source, check):
return new_results
-def run_healthcheck(entry_points, configfile):
- framework = object()
- plugins = []
- output = constants.DEFAULT_OUTPUT
-
- logger.setLevel(logging.INFO)
-
- options = parse_options(output_registry)
-
- if options.debug:
- logger.setLevel(logging.DEBUG)
-
- config = read_config(configfile)
- if config is None:
- return 1
-
- for name, registry in find_registries(entry_points).items():
- try:
- registry.initialize(framework)
- except Exception as e:
- print("Unable to initialize %s: %s" % (name, e))
- return 1
- for plugin in find_plugins(name, registry):
- plugins.append(plugin)
-
- for out in output_registry.plugins:
- if out.__name__.lower() == options.output:
- output = out(options)
-
- if options.list_sources:
- return list_sources(plugins)
-
- if options.infile:
- try:
- with open(options.infile, 'r') as f:
- raw_data = f.read()
-
- json_data = json.loads(raw_data)
- results = json_to_results(json_data)
- available = ()
- except Exception as e:
- print("Unable to import '%s': %s" % (options.infile, e))
+class RunChecks:
+ def __init__(self, entry_points, configfile):
+ self.entry_points = entry_points
+ self.configfile = configfile
+
+ def pre_check(self):
+ pass
+
+ def run_healthcheck(self):
+ framework = object()
+ plugins = []
+ output = constants.DEFAULT_OUTPUT
+
+ logger.setLevel(logging.INFO)
+
+ options = parse_options(output_registry)
+
+ if options.debug:
+ logger.setLevel(logging.DEBUG)
+
+ config = read_config(self.configfile)
+ if config is None:
return 1
- if options.source:
- results = limit_results(results, options.source, options.check)
- else:
- results, available = run_service_plugins(plugins, config,
- options.source,
- options.check)
- results.extend(run_plugins(plugins, config, available,
- options.source, options.check))
-
- if options.source and len(results.results) == 0:
- for plugin in plugins:
- if not source_or_check_matches(plugin, options.source,
- options.check):
- continue
- if not set(plugin.requires).issubset(available):
- print("Source '%s' is missing one or more requirements '%s'" %
- (options.source, ', '.join(plugin.requires)))
+ rval = self.pre_check()
+ if rval is not None:
+ return rval
+
+ for name, registry in find_registries(self.entry_points).items():
+ try:
+ registry.initialize(framework)
+ except Exception as e:
+ print("Unable to initialize %s: %s" % (name, e))
return 1
-
- if options.check:
- print("Check '%s' not found in Source '%s'" %
- (options.check, options.source))
+ for plugin in find_plugins(name, registry):
+ plugins.append(plugin)
+
+ for out in output_registry.plugins:
+ if out.__name__.lower() == options.output:
+ output = out(options)
+
+ if options.list_sources:
+ return list_sources(plugins)
+
+ if options.infile:
+ try:
+ with open(options.infile, 'r') as f:
+ raw_data = f.read()
+
+ json_data = json.loads(raw_data)
+ results = json_to_results(json_data)
+ available = ()
+ except Exception as e:
+ print("Unable to import '%s': %s" % (options.infile, e))
+ return 1
+ if options.source:
+ results = limit_results(results, options.source, options.check)
else:
- print("Source '%s' not found" % options.source)
- return 1
-
- try:
- output.render(results)
- except Exception as e:
- logger.error('Output raised %s: %s', e.__class__.__name__, e)
-
- return_value = 0
- for result in results.results:
- if result.result != constants.SUCCESS:
- return_value = 1
- break
-
- return return_value
+ results, available = run_service_plugins(plugins, config,
+ options.source,
+ options.check)
+ results.extend(run_plugins(plugins, config, available,
+ options.source, options.check))
+
+ if options.source and len(results.results) == 0:
+ for plugin in plugins:
+ if not source_or_check_matches(plugin, options.source,
+ options.check):
+ continue
+
+ if not set(plugin.requires).issubset(available):
+ print("Source '%s' is missing one or more requirements '%s'" %
+ (options.source, ', '.join(plugin.requires)))
+ return 1
+
+ if options.check:
+ print("Check '%s' not found in Source '%s'" %
+ (options.check, options.source))
+ else:
+ print("Source '%s' not found" % options.source)
+ return 1
+
+ try:
+ output.render(results)
+ except Exception as e:
+ logger.error('Output raised %s: %s', e.__class__.__name__, e)
+
+ return_value = 0
+ for result in results.results:
+ if result.result != constants.SUCCESS:
+ return_value = 1
+ break
+
+ return return_value
diff --git a/src/ipahealthcheck/core/main.py b/src/ipahealthcheck/core/main.py
index d9e85d7..63a1de6 100644
--- a/src/ipahealthcheck/core/main.py
+++ b/src/ipahealthcheck/core/main.py
@@ -6,12 +6,23 @@ from os import environ
import sys
from ipahealthcheck.core import constants
-from ipahealthcheck.core.core import run_healthcheck
+from ipahealthcheck.core.core import RunChecks
+
+from ipaserver.install.installutils import is_ipa_configured
+
+
+class IPAChecks(RunChecks):
+ def pre_check(self):
+ if not is_ipa_configured():
+ print("IPA is not configured")
+ return 1
def main():
environ["KRB5_CLIENT_KTNAME"] = "/etc/krb5.keytab"
environ["KRB5CCNAME"] = "MEMORY:"
- sys.exit(run_healthcheck(['ipahealthcheck.registry'],
- constants.CONFIG_FILE))
+ ipachecks = IPAChecks(['ipahealthcheck.registry',
+ 'pkihealthcheck.registry'],
+ constants.CONFIG_FILE)
+ sys.exit(ipachecks.run_healthcheck())
--
2.20.1

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
[default]

173
SPECS/ipa-healthcheck.spec Normal file
View File

@ -0,0 +1,173 @@
%global project freeipa
%global shortname healthcheck
%global longname ipa%{shortname}
%global debug_package %{nil}
%global python3dir %{_builddir}/python3-%{name}-%{version}-%{release}
%{!?python3_sitelib: %global python3_sitelib %(%{__python3} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")}
Name: ipa-healthcheck
Version: 0.4
Release: 4%{?dist}
Summary: Health check tool for IdM
BuildArch: noarch
License: GPLv3
URL: https://github.com/%{project}/freeipa-healthcheck
Source0: https://github.com/%{project}/%{name}/archive/%{version}.tar.gz#/%{project}-%{shortname}-%{version}.tar.gz
Source1: %{longname}.conf
Patch0001: 0001-Remove-requirement-for-pytest-runner-since-PyPI-isn-.patch
Patch0002: 0002-Move-main-to-run_healthcheck-for-abstraction-purpose.patch
Patch0003: 0003-Abstract-ServiceCheck-to-not-be-IPA-specific.patch
Patch0004: 0004-Move-the-abstracted-plugin-runner-code-into-a-separa.patch
Patch0005: 0005-Convert-running-healthchecks-into-a-class-and-add-pr.patch
Patch0006: 0006-Move-config-object-from-plugins-to-registry.patch
Requires: ipa-server
Requires: python3-ipalib
Requires: python3-ipaserver
# cronie-anacron provides anacron
Requires: anacron
Requires: logrotate
Requires(post): systemd-units
Requires: %{name}-core = %{version}-%{release}
BuildRequires: python3-devel
BuildRequires: systemd-devel
%{?systemd_requires}
%description
The FreeIPA health check tool provides a set of checks to
proactively detect defects in a FreeIPA cluster.
%package -n %{name}-core
Summary: Core plugin system for healthcheck
# to allow package downgrades where this subpackage doesn't exist
Obsoletes: %{name} < 0.4
%description -n %{name}-core
Core files
%prep
%autosetup -p1 -n %{project}-%{shortname}-%{version}
%build
%py3_build
%install
%py3_install
mkdir -p %{buildroot}%{_sysconfdir}/%{longname}
install -m644 %{SOURCE1} %{buildroot}%{_sysconfdir}/%{longname}
mkdir -p %{buildroot}/%{_unitdir}
install -p -m644 %{_builddir}/%{project}-%{shortname}-%{version}/systemd/ipa-%{shortname}.service %{buildroot}%{_unitdir}
install -p -m644 %{_builddir}/%{project}-%{shortname}-%{version}/systemd/ipa-%{shortname}.timer %{buildroot}%{_unitdir}
mkdir -p %{buildroot}/%{_libexecdir}/ipa
install -p -m755 %{_builddir}/%{project}-%{shortname}-%{version}/systemd/ipa-%{shortname}.sh %{buildroot}%{_libexecdir}/ipa/
mkdir -p %{buildroot}%{_sysconfdir}/logrotate.d
install -p -m644 %{_builddir}/%{project}-%{shortname}-%{version}/logrotate/%{longname} %{buildroot}%{_sysconfdir}/logrotate.d
mkdir -p %{buildroot}/%{_localstatedir}/log/ipa/%{shortname}
mkdir -p %{buildroot}/%{_mandir}/man1
mkdir -p %{buildroot}/%{_mandir}/man5
install -p -m644 %{_builddir}/%{project}-%{shortname}-%{version}/man/man1/ipa-%{shortname}.1 %{buildroot}%{_mandir}/man1/
install -p -m644 %{_builddir}/%{project}-%{shortname}-%{version}/man/man5/%{longname}.conf.5 %{buildroot}%{_mandir}/man5/
(cd %{buildroot}/%{python3_sitelib}/ipahealthcheck && find . -type f | \
grep -v '^./core' | \
grep -v 'opt-1' | \
sed -e 's,\.py.*$,.*,g' | sort -u | \
sed -e 's,\./,%%{python3_sitelib}/ipahealthcheck/,g' ) >healthcheck.list
%post
%systemd_post ipa-%{shortname}.service
%preun
%systemd_preun ipa-%{shortname}.service
%postun
%systemd_postun_with_restart ipa-%{shortname}.service
%files -f healthcheck.list
%{!?_licensedir:%global license %%doc}
%license COPYING
%doc README.md
%{_bindir}/ipa-%{shortname}
%dir %{_sysconfdir}/%{longname}
%dir %{_localstatedir}/log/ipa/%{shortname}
%config(noreplace) %{_sysconfdir}/%{longname}/%{longname}.conf
%config(noreplace) %{_sysconfdir}/logrotate.d/%{longname}
%{python3_sitelib}/%{longname}-%{version}-*.egg-info/
%{python3_sitelib}/%{longname}-%{version}-*-nspkg.pth
%{_unitdir}/*
%{_libexecdir}/*
%{_mandir}/man1/*
%{_mandir}/man5/*
%files -n %{name}-core
%{!?_licensedir:%global license %%doc}
%license COPYING
%doc README.md
%{python3_sitelib}/%{longname}/core/
%changelog
* Thu Jan 16 2020 Rob Crittenden <rcritten@redhat.com> - 0.4-4
- Allow plugins to read contents from config during initialization (#1784037)
* Thu Dec 5 2019 Rob Crittenden <rcritten@redhat.com> - 0.4-3
- Add Obsoletes to core subpackage (#1780121)
* Mon Dec 2 2019 Rob Crittenden <rcritten@redhat.com> - 0.4-2
- Abstract processing so core package is standalone (#1771710)
* Mon Dec 2 2019 Rob Crittenden <rcritten@redhat.com> - 0.4-1
- Rebase to upstream 0.4 (#1770346)
- Create subpackage to split out core processing (#1771710)
- Correct URL (#1773512)
- Errors not translated to strings (#1752849)
- JSON output not indented by default (#1729043)
- Add dependencies to checks to avoid false-positives (#1727900)
- Verify expected DNS records (#1695125)
* Mon Aug 12 2019 Rob Crittenden <rcritten@redhat.com> - 0.3-4
- Lookup AD user by SID and not by hardcoded username (#1739500)
* Thu Aug 8 2019 Rob Crittenden <rcritten@redhat.com> - 0.3-3
- The AD trust agent and controller are not being initialized (#1738314)
* Mon Aug 5 2019 Rob Crittenden <rcritten@redhat.com> - 0.3-2
- Change DNA plugin to return WARNING if no range is set (#1737492)
* Mon Jul 29 2019 François Cami <fcami@redhat.com> - 0.3-1
- Update to upstream 0.3 (#1701351)
- Add logrotate configs + depend on anacron and logrotate (#1729207)
* Thu Jul 11 2019 François Cami <fcami@redhat.com> - 0.2-4
- Fix ipa-healthcheck.sh installation path (rhbz#1729188)
- Create and own log directory (rhbz#1729188)
* Tue Apr 30 2019 François Cami <fcami@redhat.com> - 0.2-3
- Add python3-lib389 to BRs
* Tue Apr 30 2019 François Cami <fcami@redhat.com> - 0.2-2
- Fix changelog
* Thu Apr 25 2019 Rob Crittenden <rcritten@redhat.com> - 0.2-1
- Update to upstream 0.2
* Thu Apr 4 2019 François Cami <fcami@redhat.com> - 0.1-2
- Explicitly list dependencies
* Tue Apr 2 2019 François Cami <fcami@redhat.com> - 0.1-1
- Initial package import