import ipa-healthcheck-0.4-4.module+el8.2.0+5496+53199ee7
This commit is contained in:
commit
ad3d7db9de
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
SOURCES/freeipa-healthcheck-0.4.tar.gz
|
||||
1
.ipa-healthcheck.metadata
Normal file
1
.ipa-healthcheck.metadata
Normal file
@ -0,0 +1 @@
|
||||
2e61604c36f6f793612b1e3bb3f5e78df1cb58ac SOURCES/freeipa-healthcheck-0.4.tar.gz
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
187
SOURCES/0003-Abstract-ServiceCheck-to-not-be-IPA-specific.patch
Normal file
187
SOURCES/0003-Abstract-ServiceCheck-to-not-be-IPA-specific.patch
Normal 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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
1535
SOURCES/0006-Move-config-object-from-plugins-to-registry.patch
Normal file
1535
SOURCES/0006-Move-config-object-from-plugins-to-registry.patch
Normal file
File diff suppressed because it is too large
Load Diff
1
SOURCES/ipahealthcheck.conf
Normal file
1
SOURCES/ipahealthcheck.conf
Normal file
@ -0,0 +1 @@
|
||||
[default]
|
||||
173
SPECS/ipa-healthcheck.spec
Normal file
173
SPECS/ipa-healthcheck.spec
Normal 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
|
||||
Loading…
Reference in New Issue
Block a user