From e6a568dccbdd30083629427d46eccc21808992b8 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: May 18 2021 06:46:55 +0000 Subject: import ipa-healthcheck-0.7-3.module+el8.4.0+9008+94c5103b --- diff --git a/.gitignore b/.gitignore index 7218656..7f7a491 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/freeipa-healthcheck-0.4.tar.gz +SOURCES/freeipa-healthcheck-0.7.tar.gz diff --git a/.ipa-healthcheck.metadata b/.ipa-healthcheck.metadata index f0c76cd..6b83e2a 100644 --- a/.ipa-healthcheck.metadata +++ b/.ipa-healthcheck.metadata @@ -1 +1 @@ -2e61604c36f6f793612b1e3bb3f5e78df1cb58ac SOURCES/freeipa-healthcheck-0.4.tar.gz +93e4d1554a11ba94947a816b008fb1092abbf591 SOURCES/freeipa-healthcheck-0.7.tar.gz diff --git a/SOURCES/0002-Move-main-to-run_healthcheck-for-abstraction-purpose.patch b/SOURCES/0002-Move-main-to-run_healthcheck-for-abstraction-purpose.patch deleted file mode 100644 index c14ea28..0000000 --- a/SOURCES/0002-Move-main-to-run_healthcheck-for-abstraction-purpose.patch +++ /dev/null @@ -1,106 +0,0 @@ -From eb87d277442dd1a1076ba9ae74c18ace8cc7dda8 Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -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 - diff --git a/SOURCES/0002-Remove-ipaclustercheck.patch b/SOURCES/0002-Remove-ipaclustercheck.patch new file mode 100644 index 0000000..21d08ff --- /dev/null +++ b/SOURCES/0002-Remove-ipaclustercheck.patch @@ -0,0 +1,630 @@ +From ea9e00e47307b4ab81cc31c37796dd7b6a4c8785 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Thu, 29 Oct 2020 11:49:22 -0400 +Subject: [PATCH] Remove ipaclustercheck + +Not shipping it from upstream into Fedora just yet +--- + setup.py | 12 +- + src/ipaclustercheck/__init__.py | 5 - + src/ipaclustercheck/core/__init__.py | 0 + src/ipaclustercheck/core/main.py | 30 ----- + src/ipaclustercheck/core/output.py | 67 ------------ + src/ipaclustercheck/ipa/__init__.py | 0 + src/ipaclustercheck/ipa/crlmanager.py | 36 ------ + src/ipaclustercheck/ipa/plugin.py | 114 ------------------- + src/ipaclustercheck/ipa/ruv.py | 151 -------------------------- + tests/test_cluster_ruv.py | 106 ------------------ + 10 files changed, 1 insertion(+), 520 deletions(-) + delete mode 100644 src/ipaclustercheck/__init__.py + delete mode 100644 src/ipaclustercheck/core/__init__.py + delete mode 100644 src/ipaclustercheck/core/main.py + delete mode 100644 src/ipaclustercheck/core/output.py + delete mode 100644 src/ipaclustercheck/ipa/__init__.py + delete mode 100644 src/ipaclustercheck/ipa/crlmanager.py + delete mode 100644 src/ipaclustercheck/ipa/plugin.py + delete mode 100644 src/ipaclustercheck/ipa/ruv.py + delete mode 100644 tests/test_cluster_ruv.py + +diff --git a/setup.py b/setup.py +index 2b519fc..c25b2d7 100644 +--- a/setup.py ++++ b/setup.py +@@ -4,7 +4,7 @@ from setuptools import find_packages, setup + setup( + name='ipahealthcheck', + version='0.7', +- namespace_packages=['ipahealthcheck', 'ipaclustercheck'], ++ namespace_packages=['ipahealthcheck'], + package_dir={'': 'src'}, + # packages=find_packages(where='src'), + packages=[ +@@ -14,14 +14,11 @@ setup( + 'ipahealthcheck.ipa', + 'ipahealthcheck.meta', + 'ipahealthcheck.system', +- 'ipaclustercheck.core', +- 'ipaclustercheck.ipa', + ], + entry_points={ + # creates bin/ipahealthcheck + 'console_scripts': [ + 'ipa-healthcheck = ipahealthcheck.core.main:main', +- 'ipa-clustercheck = ipaclustercheck.core.main:main', + ], + # subsystem registries + 'ipahealthcheck.registry': [ +@@ -69,13 +66,6 @@ setup( + 'ipahealthcheck.system': [ + 'filesystemspace = ipahealthcheck.system.filesystemspace', + ], +- 'ipaclustercheck.registry': [ +- 'ipaclustercheck.ipa = ipaclustercheck.ipa.plugin:registry', +- ], +- 'ipaclustercheck.ipa': [ +- 'crl = ipaclustercheck.ipa.crlmanager', +- 'ruv = ipaclustercheck.ipa.ruv', +- ], + }, + classifiers=[ + 'Programming Language :: Python :: 3.6', +diff --git a/src/ipaclustercheck/__init__.py b/src/ipaclustercheck/__init__.py +deleted file mode 100644 +index 6c91ef7..0000000 +--- a/src/ipaclustercheck/__init__.py ++++ /dev/null +@@ -1,5 +0,0 @@ +-# +-# Copyright (C) 2019 FreeIPA Contributors see COPYING for license +-# +- +-__import__('pkg_resources').declare_namespace(__name__) +diff --git a/src/ipaclustercheck/core/__init__.py b/src/ipaclustercheck/core/__init__.py +deleted file mode 100644 +index e69de29..0000000 +diff --git a/src/ipaclustercheck/core/main.py b/src/ipaclustercheck/core/main.py +deleted file mode 100644 +index 45fda9f..0000000 +--- a/src/ipaclustercheck/core/main.py ++++ /dev/null +@@ -1,30 +0,0 @@ +-# +-# Copyright (C) 2020 FreeIPA Contributors see COPYING for license +-# +- +-import sys +- +-from ipaclustercheck.core.output import output_registry +-from ipahealthcheck.core.core import RunChecks +- +- +-class ClusterChecks(RunChecks): +- +- def add_options(self): +- parser = self.parser +- parser.add_argument('--directory', dest='dir', +- help='Directory holding healthcheck logs') +- +- def validate_options(self): +- super(ClusterChecks, self).validate_options() +- +- if self.options.dir is None: +- print("--directory containing logs to check is required") +- return 1 +- +- +-def main(): +- clusterchecks = ClusterChecks(['ipaclustercheck.registry'], +- '/etc/ipa/clustercheck.conf', +- output_registry, 'ansible') +- sys.exit(clusterchecks.run_healthcheck()) +diff --git a/src/ipaclustercheck/core/output.py b/src/ipaclustercheck/core/output.py +deleted file mode 100644 +index 2f02b52..0000000 +--- a/src/ipaclustercheck/core/output.py ++++ /dev/null +@@ -1,67 +0,0 @@ +-# +-# Copyright (C) 2019 FreeIPA Contributors see COPYING for license +-# +- +-import json +-import sys +-from ipahealthcheck.core.output import OutputRegistry, Output +- +- +-output_registry = OutputRegistry() +- +-class ClusterOutput(Output): +- """Base class for writing/display output of cluster results +- +- severity doesn't apply in this case so exclude those. +- """ +- def __init__(self, options): +- self.filename = options.outfile +- +- def strip_output(self, results): +- """Nothing to strip out""" +- return [result for result in results.output()] +- +- +-@output_registry +-class Ansible(ClusterOutput): +- """Output information JSON format for consumption by Ansible +- +- Required keywords in a Result: +- name - unique identifier for the return value +- +- One of these is required: +- value - the return value. Type? I dunno yet +- error - if an error was returned +- """ +- +- options = ( +- ('--indent', dict(dest='indent', type=int, default=2, +- help='Indention level of JSON output')), +- ) +- +- def __init__(self, options): +- super(Ansible, self).__init__(options) +- self.indent = options.indent +- +- def generate(self, data): +- output = [] +- for line in data: +- kw = line.get('kw') +- result = line.get('result') +- name = kw.get('name') +- value = kw.get('value') +- error = kw.get('error') +- +- if value and error: +- value = '%s: %s' % (error, value) +- elif error: +- value = error +- +- rval = {'%s' % name: value} +- output.append(rval) +- +- output = json.dumps(output, indent=self.indent) +- if self.filename is None: +- output += '\n' +- +- return output +diff --git a/src/ipaclustercheck/ipa/__init__.py b/src/ipaclustercheck/ipa/__init__.py +deleted file mode 100644 +index e69de29..0000000 +diff --git a/src/ipaclustercheck/ipa/crlmanager.py b/src/ipaclustercheck/ipa/crlmanager.py +deleted file mode 100644 +index 6806d74..0000000 +--- a/src/ipaclustercheck/ipa/crlmanager.py ++++ /dev/null +@@ -1,36 +0,0 @@ +-# +-# Copyright (C) 2019 FreeIPA Contributors see COPYING for license +-# +- +-from ipaclustercheck.ipa.plugin import ClusterPlugin, registry, find_checks +-from ipahealthcheck.core.plugin import Result, duration +-from ipahealthcheck.core import constants +- +- +-@registry +-class ClusterCRLManagerCheck(ClusterPlugin): +- +- @duration +- def check(self): +- data = self.registry.json +- crlmanagers = [] +- +- for fqdn in data.keys(): +- output = find_checks(data[fqdn], 'ipahealthcheck.ipa.roles', +- 'IPACRLManagerCheck') +- enabled = output[0].get('kw').get('crlgen_enabled') +- if enabled: +- crlmanagers.append(fqdn) +- if len(crlmanagers) == 0: +- yield Result(self, constants.ERROR, +- name='crlmanager', +- error='No CRL Manager defined') +- elif len(crlmanagers) == 1: +- yield Result(self, constants.SUCCESS, +- name='crlmanager', +- value=crlmanagers[0]) +- else: +- yield Result(self, constants.ERROR, +- name='crlmanager', +- value=','.join(crlmanagers), +- error='Multiple CRL Managers defined') +diff --git a/src/ipaclustercheck/ipa/plugin.py b/src/ipaclustercheck/ipa/plugin.py +deleted file mode 100644 +index d9b6063..0000000 +--- a/src/ipaclustercheck/ipa/plugin.py ++++ /dev/null +@@ -1,114 +0,0 @@ +-# +-# Copyright (C) 2020 FreeIPA Contributors see COPYING for license +-# +- +-from copy import deepcopy +-import json +-import logging +-from os import listdir +-from os.path import isfile, join +- +-from ipahealthcheck.core.plugin import Plugin, Registry +-from ipalib import api +- +- +-logger = logging.getLogger() +- +-def find_checks(data, source, check): +- """Look through the dict for a matching source and check. +- +- data: dict of source and check output +- source: name of source to find +- check: name of check to find +- +- Returns list of contents of source + check or empty list +- """ +- rval = [] +- for d in data: +- if d.get('source') == source and d.get('check') == check: +- rval.append(d) +- +- return rval +- +- +-def get_masters(data): +- """ +- Return the list of known masters +- +- This is determined from the list of loaded healthcheck logs. It +- is possible that mixed versions are used so some may not be +- reporting the full list of masters, so check them all, and raise +- an exception if the list cannot be determined. +- """ +- test_masters = list(data) +- masters = None +- for master in test_masters: +- output = find_checks(data[master], 'ipahealthcheck.ipa.meta', +- 'IPAMetaCheck') +- if len(output) == 0: +- raise ValueError('Unable to determine full list of masters. ' +- 'ipahealthcheck.ipa.meta:IPAMetaCheck not ' +- 'found.') +- +- masters = output[0].get('kw').get('masters') +- if masters: +- return masters +- +- raise ValueError('Unable to determine full list of masters. ' +- 'None of ipahealthcheck.ipa.meta:IPAMetaCheck ' +- 'contain masters.') +- +- +-class ClusterPlugin(Plugin): +- def __init__(self, registry): +- super(ClusterPlugin, self).__init__(registry) +- +- +-class ClusterRegistry(Registry): +- def initialize(self, framework, config, options): +- super(ClusterRegistry, self).initialize(framework, config, options) +- +- self.json = {} +- +- self.load_files(options.dir) +- +- if not api.isdone('finalize'): +- if not api.isdone('bootstrap'): +- api.bootstrap(in_server=True, +- context='ipahealthcheck', +- log=None) +- if not api.isdone('finalize'): +- api.finalize() +- +- def load_files(self, dir): +- if self.json: +- return +- +- files = [f for f in listdir(dir) if isfile(join(dir, f))] +- for file in files: +- fname = join(dir, file) +- logger.debug("Reading %s", fname) +- try: +- with open(fname, 'r') as fd: +- data = fd.read() +- except Exception as e: +- logger.error("Unable to read %s: %s", fname, e) +- continue +- +- try: +- data = json.loads(data) +- except Exception as e: +- logger.error("Unable to parse JSON in %s: %s", fname, e) +- continue +- +- meta = find_checks(data, 'ipahealthcheck.meta.core', +- 'MetaCheck') +- if meta: +- fqdn = meta[0].get('kw').get('fqdn') +- self.json[fqdn] = deepcopy(data) +- else: +- logger.error("No fqdn defined in JSON in %s", fname) +- continue +- +- +-registry = ClusterRegistry() +diff --git a/src/ipaclustercheck/ipa/ruv.py b/src/ipaclustercheck/ipa/ruv.py +deleted file mode 100644 +index 0e51da9..0000000 +--- a/src/ipaclustercheck/ipa/ruv.py ++++ /dev/null +@@ -1,151 +0,0 @@ +-# +-# Copyright (C) 2019 FreeIPA Contributors see COPYING for license +-# +- +-import logging +- +-from ipaclustercheck.ipa.plugin import ( +- ClusterPlugin, +- registry, +- find_checks, +- get_masters +-) +-from ipahealthcheck.core.plugin import Result, duration +-from ipahealthcheck.core import constants +-from ipalib import api +-from ipapython.dn import DN +- +- +-logger = logging.getLogger() +- +- +-@registry +-class ClusterRUVCheck(ClusterPlugin): +- +- # TODO: confirm that all masters are represented, otherwise the +- # trustworthiness of dangling RUV is mixed. +- # +- # gah, need to provide full list of all masters in a check. +- +- @duration +- def check(self): +- data = self.registry.json +- +- # Start with the list of masters from the file(s) collected +- # and find a MetaCheck with a full list of masters. For +- # backwards compatibility. +- try: +- masters = get_masters(data) +- except ValueError as e: +- yield Result(self, constants.ERROR, +- name='dangling_ruv', +- error=str(e)) +- return +- +- if len(data.keys()) < len(masters): +- yield Result(self, constants.ERROR, +- name='dangling_ruv', +- error='Unable to determine list of RUVs, missing ' +- 'some masters: %s' % +- ''.join(set(masters) - set(data.keys()))) +- return +- +- # collect the full set of known RUVs for each master +- info = {} +- for master in masters: +- info[master] = { +- 'ca': False, # does the host have ca configured? +- 'ruvs': set(), # ruvs on the host +- 'csruvs': set(), # csruvs on the host +- 'clean_ruv': set(), # ruvs to be cleaned from the host +- 'clean_csruv': set() # csruvs to be cleaned from the host +- } +- +- for fqdn in data.keys(): +- outputs = find_checks(data[fqdn], 'ipahealthcheck.ds.ruv', +- 'KnownRUVCheck') +- for output in outputs: +- if not 'suffix' in output.get('kw'): +- continue +- basedn = DN(output.get('kw').get('suffix')) +- +- ruvset = set() +- ruvtmp = output.get('kw').get('ruvs') +- for ruv in ruvtmp: +- ruvset.add(tuple(ruv)) +- +- if basedn == DN('o=ipaca'): +- info[fqdn]['ca'] = True +- info[fqdn]['csruvs'] = ruvset +- elif basedn == api.env.basedn: +- info[fqdn]['ruvs'] = ruvset +- else: +- yield Result(self, constants.WARNING, +- name='dangling_ruv', +- error='Unknown suffix found %s expected %s' +- % (basedn, api.env.basedn)) +- +- # Collect the nsDS5ReplicaID for each master +- ruvs = set() +- csruvs = set() +- for fqdn in data.keys(): +- outputs = find_checks(data[fqdn], 'ipahealthcheck.ds.ruv', +- 'RUVCheck') +- for output in outputs: +- if not 'key' in output.get('kw'): +- continue +- basedn = DN(output.get('kw').get('key')) +- ruv = (fqdn, (output.get('kw').get('ruv'))) +- if basedn == DN('o=ipaca'): +- csruvs.add(ruv) +- elif basedn == api.env.basedn: +- ruvs.add(ruv) +- else: +- yield Result(self, constants.WARNING, +- name='dangling_ruv', +- error='Unknown suffix found %s expected %s' +- % (basedn, api.env.basedn)) +- +- dangles = False +- # get the dangling RUVs +- for master_info in info.values(): +- for ruv in master_info['ruvs']: +- if ruv not in ruvs: +- master_info['clean_ruv'].add(ruv) +- dangles = True +- +- # if ca is not configured, there will be no csruvs in master_info +- for csruv in master_info['csruvs']: +- if csruv not in csruvs: +- master_info['clean_csruv'].add(csruv) +- dangles = True +- +- clean_csruvs = set() +- clean_ruvs = set() +- if dangles: +- for master_cn, master_info in info.items(): +- for ruv in master_info['clean_ruv']: +- logger.debug('Dangling RUV id: {id}, hostname: {host}' +- .format(id=ruv[1], host=ruv[0])) +- clean_ruvs.add(ruv[1]) +- for csruv in master_info['clean_csruv']: +- logger.debug('Dangling CS RUV id: {id}, hostname: {host}' +- .format(id=csruv[1], host=csruv[0])) +- clean_csruvs.add(csruv[1]) +- +- if clean_ruvs: +- yield Result(self, constants.ERROR, +- name='dangling_ruv', +- value=', '.join(clean_ruvs)) +- else: +- yield Result(self, constants.SUCCESS, +- name='dangling_ruv', +- value='No dangling RUVs found') +- if clean_csruvs: +- yield Result(self, constants.ERROR, +- name='dangling_csruv', +- value=', '.join(clean_csruvs)) +- else: +- yield Result(self, constants.SUCCESS, +- name='dangling_csruv', +- value='No dangling CS RUVs found') +diff --git a/tests/test_cluster_ruv.py b/tests/test_cluster_ruv.py +deleted file mode 100644 +index 7583c84..0000000 +--- a/tests/test_cluster_ruv.py ++++ /dev/null +@@ -1,106 +0,0 @@ +-# +-# Copyright (C) 2019 FreeIPA Contributors see COPYING for license +-# +- +-from base import BaseTest +-from util import capture_results +- +-from ipahealthcheck.core import config +-from ipaclustercheck.ipa.plugin import ClusterRegistry +-from ipaclustercheck.ipa.ruv import ClusterRUVCheck +- +-import clusterdata +- +- +-class RUVRegistry(ClusterRegistry): +- def load_files(self, dir): +- self.json = dir +- +- +-class Options: +- def __init__(self, data): +- self.data = data +- +- @property +- def dir(self): +- return self.data +- +- +-registry = RUVRegistry() +- +- +-class TestClusterRUV(BaseTest): +- +- def test_no_ruvs(self): +- """Single master test that has never created a replica +- +- This type of master will have no RUVs created at all. +- """ +- framework = object() +- registry.initialize(framework, config.Config, +- Options(clusterdata.ONE_MASTER)) +- f = ClusterRUVCheck(registry) +- +- self.results = capture_results(f) +- +- assert len(self.results) == 2 +- result = self.results.results[0] +- assert result.kw.get('name') == 'dangling_ruv' +- assert result.kw.get('value') == 'No dangling RUVs found' +- result = self.results.results[1] +- assert result.kw.get('name') == 'dangling_csruv' +- assert result.kw.get('value') == 'No dangling CS RUVs found' +- +- def test_six_ruvs_ok(self): +- """Three master test with each having a CA, no dangling +- """ +- framework = object() +- registry.initialize(framework, config.Config, +- Options(clusterdata.THREE_MASTERS_OK)) +- f = ClusterRUVCheck(registry) +- +- self.results = capture_results(f) +- +- assert len(self.results) == 2 +- result = self.results.results[0] +- assert result.kw.get('name') == 'dangling_ruv' +- assert result.kw.get('value') == 'No dangling RUVs found' +- result = self.results.results[1] +- assert result.kw.get('name') == 'dangling_csruv' +- assert result.kw.get('value') == 'No dangling CS RUVs found' +- +- def test_six_ruvs_ipa_bad(self): +- """Three master test with each having a CA, dangling IPA RUV +- """ +- framework = object() +- registry.initialize(framework, config.Config, +- Options(clusterdata.THREE_MASTERS_BAD_IPA_RUV)) +- f = ClusterRUVCheck(registry) +- +- self.results = capture_results(f) +- +- assert len(self.results) == 2 +- result = self.results.results[0] +- assert result.kw.get('name') == 'dangling_ruv' +- assert result.kw.get('value') == '9' +- result = self.results.results[1] +- assert result.kw.get('name') == 'dangling_csruv' +- assert result.kw.get('value') == 'No dangling CS RUVs found' +- +- def test_six_ruvs_cs_bad(self): +- """Three master test with each having a CA, dangling CA RUV +- """ +- framework = object() +- registry.initialize(framework, config.Config, +- Options(clusterdata.THREE_MASTERS_BAD_CS_RUV)) +- f = ClusterRUVCheck(registry) +- +- self.results = capture_results(f) +- +- assert len(self.results) == 2 +- result = self.results.results[0] +- assert result.kw.get('name') == 'dangling_ruv' +- assert result.kw.get('value') == 'No dangling RUVs found' +- result = self.results.results[1] +- assert result.kw.get('name') == 'dangling_csruv' +- assert result.kw.get('value') == '9' +-- +2.25.4 + diff --git a/SOURCES/0003-Abstract-ServiceCheck-to-not-be-IPA-specific.patch b/SOURCES/0003-Abstract-ServiceCheck-to-not-be-IPA-specific.patch deleted file mode 100644 index 1ae8db6..0000000 --- a/SOURCES/0003-Abstract-ServiceCheck-to-not-be-IPA-specific.patch +++ /dev/null @@ -1,187 +0,0 @@ -From c40e32b9d0ac49806b8336bd5065350574d29672 Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -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 - diff --git a/SOURCES/0003-Use-trust-find-and-trustdomain-find-to-identify-all-.patch b/SOURCES/0003-Use-trust-find-and-trustdomain-find-to-identify-all-.patch new file mode 100644 index 0000000..f643aa0 --- /dev/null +++ b/SOURCES/0003-Use-trust-find-and-trustdomain-find-to-identify-all-.patch @@ -0,0 +1,303 @@ +From 886153da7dd1ca1f5d37dd9c1e2141850b7177b2 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Tue, 17 Nov 2020 20:37:52 -0500 +Subject: [PATCH] Use trust-find and trustdomain-find to identify all AD trusts + +Not all AD domains are visible to trust-find. For each trust +iterate over trustdomain-find to find the complete +list of domains. + +Signed-off-by: Rob Crittenden +--- + src/ipahealthcheck/ipa/trust.py | 20 +++-- + tests/test_ipa_trust.py | 155 ++++++++++++++++++++------------ + 2 files changed, 108 insertions(+), 67 deletions(-) + +diff --git a/src/ipahealthcheck/ipa/trust.py b/src/ipahealthcheck/ipa/trust.py +index 0abe5cd..00971c4 100644 +--- a/src/ipahealthcheck/ipa/trust.py ++++ b/src/ipahealthcheck/ipa/trust.py +@@ -42,16 +42,18 @@ def get_trust_domains(): + + Each entry is a dictionary representating an AD domain. + """ +- result = api.Command.trust_find() +- results = result['result'] + trust_domains = [] +- for result in results: +- if result.get('trusttype')[0] == 'Active Directory domain': +- domain = dict() +- domain['domain'] = result.get('cn')[0] +- domain['domainsid'] = result.get('ipanttrusteddomainsid')[0] +- domain['netbios'] = result.get('ipantflatname')[0] +- trust_domains.append(domain) ++ trusts = api.Command.trust_find(pkey_only=True, raw=True) ++ for trust in trusts['result']: ++ for cn in trust.get('cn'): ++ trustdomains = api.Command.trustdomain_find(cn, raw=True) ++ for trustdomain in trustdomains['result']: ++ domain = dict() ++ domain['domain'] = trustdomain.get('cn')[0] ++ domain['domainsid'] = trustdomain.get( ++ 'ipanttrusteddomainsid')[0] ++ domain['netbios'] = trustdomain.get('ipantflatname')[0] ++ trust_domains.append(domain) + return trust_domains + + +diff --git a/tests/test_ipa_trust.py b/tests/test_ipa_trust.py +index 3c4b947..f3a9f27 100644 +--- a/tests/test_ipa_trust.py ++++ b/tests/test_ipa_trust.py +@@ -72,6 +72,56 @@ class mock_ldap_conn: + return tuple() + + ++# ++# Construct a setup with two direct trusts and one sub domain ++# ++def trust_find(): ++ return [{ ++ 'result': [ ++ { ++ 'cn': ['ad.example'], ++ }, ++ { ++ 'cn': ['child.example'], ++ }, ++ ] ++ }] ++ ++ ++def trustdomain_find(): ++ return [ ++ { ++ "result": [ ++ { ++ "cn": ["ad.example"], ++ "ipantflatname": ["ADROOT"], ++ "ipanttrusteddomainsid": ["S-1-5-21-abc"], ++ "ipanttrusttype": ["2"], ++ "ipanttrustattributes": ["8"], ++ }, ++ { ++ "cn": ["child.ad.example"], ++ "ipantflatname": ["CHILD.ADROOT"], ++ "ipanttrusteddomainsid": ["S-1-5-22-def"], ++ "ipanttrusttype": ["2"], ++ "ipanttrustattributes": ["1"], ++ }, ++ ], ++ }, ++ { ++ "result": [ ++ { ++ "cn": ["child.example"], ++ "ipantflatname": ["CHILD"], ++ "ipanttrusteddomainsid": ["S-1-5-21-ghi"], ++ "ipanttrusttype": ["2"], ++ "ipanttrustattributes": ["8"], ++ }, ++ ], ++ }, ++ ] ++ ++ + class SSSDDomain: + def __init__(self, return_ipa_server_mode=True, provider='ipa'): + self.return_ipa_server_mode = return_ipa_server_mode +@@ -246,31 +296,17 @@ class TestTrustDomains(BaseTest): + dlresult.returncode = 0 + dlresult.error_log = '' + dlresult.output = 'implicit_files\nipa.example\nad.example\n' \ +- 'child.example\n' ++ 'child.ad.example\nchild.example\n' + olresult = namedtuple('run', ['returncode', 'error_log']) + olresult.returncode = 0 + olresult.error_log = '' + olresult.output = 'Online status: Online\n\n' + +- mock_run.side_effect = [dlresult, olresult, olresult] ++ mock_run.side_effect = [dlresult, olresult, olresult, olresult] + + # get_trust_domains() +- m_api.Command.trust_find.side_effect = [{ +- 'result': [ +- { +- 'cn': ['ad.example'], +- 'ipantflatname': ['ADROOT'], +- 'ipanttrusteddomainsid': ['S-1-5-21-abc'], +- 'trusttype': ['Active Directory domain'], +- }, +- { +- 'cn': ['child.example'], +- 'ipantflatname': ['ADROOT'], +- 'ipanttrusteddomainsid': ['S-1-5-21-def'], +- 'trusttype': ['Active Directory domain'], +- }, +- ] +- }] ++ m_api.Command.trust_find.side_effect = trust_find() ++ m_api.Command.trustdomain_find.side_effect = trustdomain_find() + + framework = object() + registry.initialize(framework, config.Config) +@@ -279,15 +315,17 @@ class TestTrustDomains(BaseTest): + + self.results = capture_results(f) + +- assert len(self.results) == 3 ++ assert len(self.results) == 4 + + result = self.results.results[0] + assert result.result == constants.SUCCESS + assert result.source == 'ipahealthcheck.ipa.trust' + assert result.check == 'IPATrustDomainsCheck' + assert result.kw.get('key') == 'domain-list' +- assert result.kw.get('trust_domains') == 'ad.example, child.example' +- assert result.kw.get('sssd_domains') == 'ad.example, child.example' ++ assert result.kw.get('trust_domains') == \ ++ 'ad.example, child.ad.example, child.example' ++ assert result.kw.get('sssd_domains') == \ ++ 'ad.example, child.ad.example, child.example' + + result = self.results.results[1] + assert result.result == constants.SUCCESS +@@ -301,6 +339,13 @@ class TestTrustDomains(BaseTest): + assert result.source == 'ipahealthcheck.ipa.trust' + assert result.check == 'IPATrustDomainsCheck' + assert result.kw.get('key') == 'domain-status' ++ assert result.kw.get('domain') == 'child.ad.example' ++ ++ result = self.results.results[3] ++ assert result.result == constants.SUCCESS ++ assert result.source == 'ipahealthcheck.ipa.trust' ++ assert result.check == 'IPATrustDomainsCheck' ++ assert result.kw.get('key') == 'domain-status' + assert result.kw.get('domain') == 'child.example' + + @patch('ipapython.ipautil.run') +@@ -319,22 +364,8 @@ class TestTrustDomains(BaseTest): + mock_run.side_effect = [dlresult, olresult, olresult] + + # get_trust_domains() +- m_api.Command.trust_find.side_effect = [{ +- 'result': [ +- { +- 'cn': ['ad.example'], +- 'ipantflatname': ['ADROOT'], +- 'ipanttrusteddomainsid': ['S-1-5-21-abc'], +- 'trusttype': ['Active Directory domain'], +- }, +- { +- 'cn': ['child.example'], +- 'ipantflatname': ['ADROOT'], +- 'ipanttrusteddomainsid': ['S-1-5-21-def'], +- 'trusttype': ['Active Directory domain'], +- }, +- ] +- }] ++ m_api.Command.trust_find.side_effect = trust_find() ++ m_api.Command.trustdomain_find.side_effect = trustdomain_find() + + framework = object() + registry.initialize(framework, config.Config) +@@ -350,7 +381,8 @@ class TestTrustDomains(BaseTest): + assert result.source == 'ipahealthcheck.ipa.trust' + assert result.check == 'IPATrustDomainsCheck' + assert result.kw.get('key') == 'domain-list' +- assert result.kw.get('trust_domains') == 'ad.example, child.example' ++ assert result.kw.get('trust_domains') == \ ++ 'ad.example, child.ad.example, child.example' + assert result.kw.get('sssd_domains') == 'child.example' + + result = self.results.results[1] +@@ -428,29 +460,16 @@ class TestTrustCatalog(BaseTest): + ds2result.output = 'Active servers:\nAD Global Catalog: ' \ + 'root-dc.ad.vm\nAD Domain Controller: root-dc.ad.vm\n' \ + +- mock_run.side_effect = [dsresult, ds2result] ++ mock_run.side_effect = [dsresult, ds2result, ds2result] + mock_getnamebysid.side_effect = [ + {'S-1-5-21-abc-500': {'name': 'admin@ad.example', 'type': 3}}, ++ {'S-1-5-21-ghi-500': {'name': 'admin@child.ad.example', 'type': 3}}, + {'S-1-5-21-def-500': {'name': 'admin@child.example', 'type': 3}} + ] + + # get_trust_domains() +- m_api.Command.trust_find.side_effect = [{ +- 'result': [ +- { +- 'cn': ['ad.example'], +- 'ipantflatname': ['ADROOT'], +- 'ipanttrusteddomainsid': ['S-1-5-21-abc'], +- 'trusttype': ['Active Directory domain'], +- }, +- { +- 'cn': ['child.example'], +- 'ipantflatname': ['ADROOT'], +- 'ipanttrusteddomainsid': ['S-1-5-21-def'], +- 'trusttype': ['Active Directory domain'], +- }, +- ] +- }] ++ m_api.Command.trust_find.side_effect = trust_find() ++ m_api.Command.trustdomain_find.side_effect = trustdomain_find() + + framework = object() + registry.initialize(framework, config.Config) +@@ -459,7 +478,7 @@ class TestTrustCatalog(BaseTest): + + self.results = capture_results(f) + +- assert len(self.results) == 6 ++ assert len(self.results) == 9 + + result = self.results.results[0] + assert result.result == constants.SUCCESS +@@ -487,20 +506,40 @@ class TestTrustCatalog(BaseTest): + assert result.source == 'ipahealthcheck.ipa.trust' + assert result.check == 'IPATrustCatalogCheck' + assert result.kw.get('key') == 'Domain Security Identifier' +- assert result.kw.get('sid') == 'S-1-5-21-def' ++ assert result.kw.get('sid') == 'S-1-5-22-def' + + result = self.results.results[4] + assert result.result == constants.SUCCESS + assert result.source == 'ipahealthcheck.ipa.trust' + assert result.check == 'IPATrustCatalogCheck' + assert result.kw.get('key') == 'AD Global Catalog' +- assert result.kw.get('domain') == 'child.example' ++ assert result.kw.get('domain') == 'child.ad.example' + + result = self.results.results[5] + assert result.result == constants.SUCCESS + assert result.source == 'ipahealthcheck.ipa.trust' + assert result.check == 'IPATrustCatalogCheck' + assert result.kw.get('key') == 'AD Domain Controller' ++ ++ result = self.results.results[6] ++ assert result.result == constants.SUCCESS ++ assert result.source == 'ipahealthcheck.ipa.trust' ++ assert result.check == 'IPATrustCatalogCheck' ++ assert result.kw.get('key') == 'Domain Security Identifier' ++ assert result.kw.get('sid') == 'S-1-5-21-ghi' ++ ++ result = self.results.results[7] ++ assert result.result == constants.SUCCESS ++ assert result.source == 'ipahealthcheck.ipa.trust' ++ assert result.check == 'IPATrustCatalogCheck' ++ assert result.kw.get('key') == 'AD Global Catalog' ++ assert result.kw.get('domain') == 'child.example' ++ ++ result = self.results.results[8] ++ assert result.result == constants.SUCCESS ++ assert result.source == 'ipahealthcheck.ipa.trust' ++ assert result.check == 'IPATrustCatalogCheck' ++ assert result.kw.get('key') == 'AD Domain Controller' + assert result.kw.get('domain') == 'child.example' + + +-- +2.25.4 + diff --git a/SOURCES/0004-Move-the-abstracted-plugin-runner-code-into-a-separa.patch b/SOURCES/0004-Move-the-abstracted-plugin-runner-code-into-a-separa.patch deleted file mode 100644 index a27845e..0000000 --- a/SOURCES/0004-Move-the-abstracted-plugin-runner-code-into-a-separa.patch +++ /dev/null @@ -1,579 +0,0 @@ -From 952fc6f6dee99523360c9826ad865086cd31474f Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -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 - diff --git a/SOURCES/0004-result-names-are-not-translated-when-reading-input-f.patch b/SOURCES/0004-result-names-are-not-translated-when-reading-input-f.patch new file mode 100644 index 0000000..7dcef19 --- /dev/null +++ b/SOURCES/0004-result-names-are-not-translated-when-reading-input-f.patch @@ -0,0 +1,90 @@ +From 5efeafa16a893cb6277ece4d573184bb64ee2744 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Mon, 30 Nov 2020 15:06:03 -0500 +Subject: [PATCH] result names are not translated when reading input from json + file + +The strings were being retained so when processing the results to +determine the return code it was always a 1 because none of +the values were being translated. It was always comparing +the string like 'SUCCESS' to constants.SUCCESS which is 0. + +https://bugzilla.redhat.com/show_bug.cgi?id=1866558 +--- + src/ipahealthcheck/core/constants.py | 20 +++++++++++++++++++- + src/ipahealthcheck/core/plugin.py | 4 ++-- + tests/test_results.py | 8 ++++++++ + 3 files changed, 29 insertions(+), 3 deletions(-) + +diff --git a/src/ipahealthcheck/core/constants.py b/src/ipahealthcheck/core/constants.py +index a55469c..b6ee029 100644 +--- a/src/ipahealthcheck/core/constants.py ++++ b/src/ipahealthcheck/core/constants.py +@@ -36,7 +36,25 @@ def getLevelName(level): + is passed in instead the corresponding string representation is + returned. + """ +- return _levelToName.get(level) or _nameToLevel.get(level) or level ++ name = _levelToName.get(level) or _nameToLevel.get(level) ++ if name is not None: ++ return name ++ ++ return level ++ ++ ++def getLevel(name): ++ """ ++ Translate between level text and their numeric constants ++ ++ If the level is one of the predefined levels then returns the ++ corresponding number. ++ """ ++ level = _nameToLevel.get(name) ++ if level is not None: ++ return level ++ ++ return name + + + CONFIG_FILE = '/etc/ipahealthcheck/ipahealthcheck.conf' +diff --git a/src/ipahealthcheck/core/plugin.py b/src/ipahealthcheck/core/plugin.py +index 7ac923a..26dddd4 100644 +--- a/src/ipahealthcheck/core/plugin.py ++++ b/src/ipahealthcheck/core/plugin.py +@@ -6,7 +6,7 @@ import uuid + from datetime import datetime + from functools import wraps + +-from ipahealthcheck.core.constants import getLevelName ++from ipahealthcheck.core.constants import getLevelName, getLevel + + + def duration(f): +@@ -204,7 +204,7 @@ def json_to_results(data): + results = Results() + + for line in data: +- result = line.pop('result') ++ result = getLevel(line.pop('result')) + source = line.pop('source') + check = line.pop('check') + duration = line.pop('duration') +diff --git a/tests/test_results.py b/tests/test_results.py +index dd6e8fd..99c18d7 100644 +--- a/tests/test_results.py ++++ b/tests/test_results.py +@@ -69,3 +69,11 @@ def test_Result(): + assert x['result'] in (constants.getLevelName(constants.SUCCESS), + constants.getLevelName(constants.CRITICAL)) + assert len(x['kw']) == 0 ++ ++ ++def test_getLevel(): ++ assert constants.getLevel('SUCCESS') == constants.SUCCESS ++ assert constants.getLevel('WARNING') == constants.WARNING ++ assert constants.getLevel('ERROR') == constants.ERROR ++ assert constants.getLevel('CRITICAL') == constants.CRITICAL ++ assert constants.getLevel('FOO') == 'FOO' +-- +2.25.4 + diff --git a/SOURCES/0005-Convert-running-healthchecks-into-a-class-and-add-pr.patch b/SOURCES/0005-Convert-running-healthchecks-into-a-class-and-add-pr.patch deleted file mode 100644 index 7a071e4..0000000 --- a/SOURCES/0005-Convert-running-healthchecks-into-a-class-and-add-pr.patch +++ /dev/null @@ -1,228 +0,0 @@ -From af5c169151f0697d34954ac5c9dd0686dc73ef3f Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -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 - diff --git a/SOURCES/0006-Move-config-object-from-plugins-to-registry.patch b/SOURCES/0006-Move-config-object-from-plugins-to-registry.patch deleted file mode 100644 index df32763..0000000 --- a/SOURCES/0006-Move-config-object-from-plugins-to-registry.patch +++ /dev/null @@ -1,1535 +0,0 @@ -From 9b6a90f1fc2508252bcb33791b24ec53f6b471cb Mon Sep 17 00:00:00 2001 -From: Dinesh Prasanth M K -Date: Tue, 10 Dec 2019 14:02:16 -0500 -Subject: [PATCH] Move config object from plugins to registry - -This patch moves the config object from the plugins -to the registry, thereby allowing the plugins to use -the values parsed from the healthcheck.conf file while -initializing. This improves the way a plugin can use -the values defined in the conf - -Signed-off-by: Dinesh Prasanth M K ---- - src/ipahealthcheck/core/core.py | 11 ++- - src/ipahealthcheck/core/plugin.py | 6 +- - src/ipahealthcheck/dogtag/plugin.py | 3 +- - src/ipahealthcheck/ds/plugin.py | 3 +- - src/ipahealthcheck/ipa/plugin.py | 3 +- - src/ipahealthcheck/system/plugin.py | 2 +- - tests/test_dogtag_ca.py | 9 +-- - tests/test_dogtag_connectivity.py | 8 +-- - tests/test_ds_replication.py | 6 +- - tests/test_ds_ruv.py | 9 +-- - tests/test_ipa_agent.py | 21 ++---- - tests/test_ipa_certfile_expiration.py | 9 +-- - tests/test_ipa_certmonger_ca.py | 6 +- - tests/test_ipa_dna.py | 9 +-- - tests/test_ipa_dns.py | 27 +++----- - tests/test_ipa_expiration.py | 18 ++--- - tests/test_ipa_nssdb.py | 12 ++-- - tests/test_ipa_nssvalidation.py | 9 +-- - tests/test_ipa_opensslvalidation.py | 6 +- - tests/test_ipa_revocation.py | 6 +- - tests/test_ipa_roles.py | 15 ++--- - tests/test_ipa_topology.py | 12 ++-- - tests/test_ipa_tracking.py | 8 +-- - tests/test_ipa_trust.py | 96 +++++++++------------------ - tests/test_meta_services.py | 3 +- - tests/test_system_filesystemspace.py | 9 +-- - 26 files changed, 120 insertions(+), 206 deletions(-) - -diff --git a/src/ipahealthcheck/core/core.py b/src/ipahealthcheck/core/core.py -index aef6197..ade8455 100644 ---- a/src/ipahealthcheck/core/core.py -+++ b/src/ipahealthcheck/core/core.py -@@ -64,7 +64,7 @@ def source_or_check_matches(plugin, source, check): - return True - - --def run_service_plugins(plugins, config, source, check): -+def run_service_plugins(plugins, source, check): - """Execute plugins with the base class of ServiceCheck - - This is a specialized check to use systemd to determine -@@ -90,7 +90,7 @@ def run_service_plugins(plugins, config, source, check): - return results, set(available) - - --def run_plugins(plugins, config, available, source, check): -+def run_plugins(plugins, available, source, check): - """Execute plugins without the base class of ServiceCheck - - These are the remaining, non-service checking checks -@@ -106,7 +106,6 @@ def run_plugins(plugins, config, available, 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__, -@@ -218,7 +217,7 @@ class RunChecks: - - for name, registry in find_registries(self.entry_points).items(): - try: -- registry.initialize(framework) -+ registry.initialize(framework, config) - except Exception as e: - print("Unable to initialize %s: %s" % (name, e)) - return 1 -@@ -246,10 +245,10 @@ class RunChecks: - if options.source: - results = limit_results(results, options.source, options.check) - else: -- results, available = run_service_plugins(plugins, config, -+ results, available = run_service_plugins(plugins, - options.source, - options.check) -- results.extend(run_plugins(plugins, config, available, -+ results.extend(run_plugins(plugins, available, - options.source, options.check)) - - if options.source and len(results.results) == 0: -diff --git a/src/ipahealthcheck/core/plugin.py b/src/ipahealthcheck/core/plugin.py -index 6a29a7f..5754808 100644 ---- a/src/ipahealthcheck/core/plugin.py -+++ b/src/ipahealthcheck/core/plugin.py -@@ -41,9 +41,11 @@ class Registry: - def __init__(self): - self.plugins = [] - self.framework = None -+ self.config = dict() - -- def initialize(self, framework): -+ def initialize(self, framework, config): - self.framework = framework -+ self.config = config - - def __call__(self, cls): - if not callable(cls): -@@ -98,7 +100,7 @@ class Plugin: - - def __init__(self, registry): - self.registry = registry -- self.config = dict() -+ self.config = registry.config - - - class Result: -diff --git a/src/ipahealthcheck/dogtag/plugin.py b/src/ipahealthcheck/dogtag/plugin.py -index 3d8257e..d54fe3b 100644 ---- a/src/ipahealthcheck/dogtag/plugin.py -+++ b/src/ipahealthcheck/dogtag/plugin.py -@@ -16,7 +16,8 @@ class DogtagPlugin(Plugin): - - - class DogtagRegistry(Registry): -- def initialize(self, framework): -+ def initialize(self, framework, config): -+ super(DogtagRegistry, self).initialize(framework, config) - installutils.check_server_configuration() - if not api.isdone('bootstrap'): - api.bootstrap(in_server=True, -diff --git a/src/ipahealthcheck/ds/plugin.py b/src/ipahealthcheck/ds/plugin.py -index 9ef3461..0e40922 100644 ---- a/src/ipahealthcheck/ds/plugin.py -+++ b/src/ipahealthcheck/ds/plugin.py -@@ -16,7 +16,8 @@ class DSPlugin(Plugin): - - - class DSRegistry(Registry): -- def initialize(self, framework): -+ def initialize(self, framework, config): -+ super(DSRegistry, self).initialize(framework, config) - installutils.check_server_configuration() - if not api.isdone('bootstrap'): - api.bootstrap(in_server=True, -diff --git a/src/ipahealthcheck/ipa/plugin.py b/src/ipahealthcheck/ipa/plugin.py -index 34cb8c9..c1a6d39 100644 ---- a/src/ipahealthcheck/ipa/plugin.py -+++ b/src/ipahealthcheck/ipa/plugin.py -@@ -36,7 +36,8 @@ class IPARegistry(Registry): - self.trust_agent = False - self.trust_controller = False - -- def initialize(self, framework): -+ def initialize(self, framework, config): -+ super(IPARegistry, self).initialize(framework, config) - # deferred import for mock - from ipaserver.servroles import ADtrustBasedRole, ServiceBasedRole - -diff --git a/src/ipahealthcheck/system/plugin.py b/src/ipahealthcheck/system/plugin.py -index 23e8b5e..03d8c23 100644 ---- a/src/ipahealthcheck/system/plugin.py -+++ b/src/ipahealthcheck/system/plugin.py -@@ -12,7 +12,7 @@ class SystemPlugin(Plugin): - - - class SystemRegistry(Registry): -- def initialize(self, framework): -+ def initialize(self, framework, config): - pass - - -diff --git a/tests/test_dogtag_ca.py b/tests/test_dogtag_ca.py -index 48eba20..0820aba 100644 ---- a/tests/test_dogtag_ca.py -+++ b/tests/test_dogtag_ca.py -@@ -59,10 +59,9 @@ class TestCACerts(BaseTest): - mock_directive.side_effect = [name for name, nsstrust in trust.items()] - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config()) - f = DogtagCertsConfigCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 6 -@@ -98,10 +97,9 @@ class TestCACerts(BaseTest): - mock_directive.side_effect = nicknames - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = DogtagCertsConfigCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - num = len(self.results.results) -@@ -129,10 +127,9 @@ class TestCACerts(BaseTest): - mock_cainstance.return_value = CAInstance(False) - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config) - f = DogtagCertsConfigCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 0 -diff --git a/tests/test_dogtag_connectivity.py b/tests/test_dogtag_connectivity.py -index 544e325..7165706 100644 ---- a/tests/test_dogtag_connectivity.py -+++ b/tests/test_dogtag_connectivity.py -@@ -5,7 +5,7 @@ - from util import capture_results, CAInstance - from util import m_api - from base import BaseTest --from ipahealthcheck.core import constants -+from ipahealthcheck.core import constants, config - from ipahealthcheck.dogtag.plugin import registry - from ipahealthcheck.dogtag.ca import DogtagCertsConnectivityCheck - from unittest.mock import Mock -@@ -26,7 +26,7 @@ class TestCAConnectivity(BaseTest): - } - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = DogtagCertsConnectivityCheck(registry) - - self.results = capture_results(f) -@@ -47,7 +47,7 @@ class TestCAConnectivity(BaseTest): - ) - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = DogtagCertsConnectivityCheck(registry) - - self.results = capture_results(f) -@@ -67,7 +67,7 @@ class TestCAConnectivity(BaseTest): - ) - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = DogtagCertsConnectivityCheck(registry) - - self.results = capture_results(f) -diff --git a/tests/test_ds_replication.py b/tests/test_ds_replication.py -index b6b3652..24e909e 100644 ---- a/tests/test_ds_replication.py -+++ b/tests/test_ds_replication.py -@@ -44,10 +44,9 @@ class TestReplicationConflicts(BaseTest): - mock_conn.return_value = mock_ldap(None) - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = ReplicationConflictCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - # A valid call relies on a success to be set by core -@@ -73,10 +72,9 @@ class TestReplicationConflicts(BaseTest): - mock_conn.return_value = mock_ldap([ldapentry]) - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = ReplicationConflictCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - result = self.results.results[0] - -diff --git a/tests/test_ds_ruv.py b/tests/test_ds_ruv.py -index 37070f5..8a3fe84 100644 ---- a/tests/test_ds_ruv.py -+++ b/tests/test_ds_ruv.py -@@ -63,11 +63,10 @@ class TestRUV(BaseTest): - - def test_no_ruvs(self): - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = RUVCheck(registry) - - f.conn = mock_ldap(None) -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 0 -@@ -88,11 +87,10 @@ class TestRUV(BaseTest): - ) - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = RUVCheck(registry) - - f.conn = mock_ldap(entries) -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 2 -@@ -123,11 +121,10 @@ class TestRUV(BaseTest): - entries.append(None) - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = RUVCheck(registry) - - f.conn = mock_ldap(entries) -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 1 -diff --git a/tests/test_ipa_agent.py b/tests/test_ipa_agent.py -index c58c7a6..8021298 100644 ---- a/tests/test_ipa_agent.py -+++ b/tests/test_ipa_agent.py -@@ -76,11 +76,10 @@ class TestNSSAgent(BaseTest): - ldapentry[attr] = values - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config()) - f = IPARAAgent(registry) - - f.conn = mock_ldap([ldapentry]) -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 1 -@@ -101,11 +100,10 @@ class TestNSSAgent(BaseTest): - ldapentry[attr] = values - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config()) - f = IPARAAgent(registry) - - f.conn = mock_ldap([ldapentry]) -- f.config = config.Config() - self.results = capture_results(f) - result = self.results.results[0] - -@@ -118,10 +116,9 @@ class TestNSSAgent(BaseTest): - mock_load_cert.side_effect = IOError('test') - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config()) - f = IPARAAgent(registry) - -- f.config = config.Config() - self.results = capture_results(f) - result = self.results.results[0] - -@@ -131,11 +128,10 @@ class TestNSSAgent(BaseTest): - def test_nss_agent_no_entry_found(self): - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config()) - f = IPARAAgent(registry) - - f.conn = mock_ldap(None) # None == NotFound -- f.config = config.Config() - self.results = capture_results(f) - result = self.results.results[0] - -@@ -158,11 +154,10 @@ class TestNSSAgent(BaseTest): - ldapentry[attr] = values - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config()) - f = IPARAAgent(registry) - - f.conn = mock_ldap([ldapentry, ldapentry2]) -- f.config = config.Config() - self.results = capture_results(f) - result = self.results.results[0] - -@@ -183,11 +178,10 @@ class TestNSSAgent(BaseTest): - ldapentry[attr] = values - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config()) - f = IPARAAgent(registry) - - f.conn = mock_ldap([ldapentry]) -- f.config = config.Config() - self.results = capture_results(f) - result = self.results.results[0] - -@@ -208,11 +202,10 @@ class TestNSSAgent(BaseTest): - ldapentry[attr] = values - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPARAAgent(registry) - - f.conn = mock_ldap([ldapentry]) -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 1 -diff --git a/tests/test_ipa_certfile_expiration.py b/tests/test_ipa_certfile_expiration.py -index d5601c5..43e59b4 100644 ---- a/tests/test_ipa_certfile_expiration.py -+++ b/tests/test_ipa_certfile_expiration.py -@@ -41,10 +41,9 @@ class TestIPACertificateFile(BaseTest): - mock_load_cert.return_value = cert - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPACertfileExpirationCheck(registry) - -- f.config = config.Config() - f.config.cert_expiration_days = 28 - self.results = capture_results(f) - -@@ -65,10 +64,9 @@ class TestIPACertificateFile(BaseTest): - mock_load_cert.return_value = cert - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPACertfileExpirationCheck(registry) - -- f.config = config.Config() - f.config.cert_expiration_days = 30 - self.results = capture_results(f) - -@@ -90,10 +88,9 @@ class TestIPACertificateFile(BaseTest): - mock_load_cert.return_value = cert - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPACertfileExpirationCheck(registry) - -- f.config = config.Config() - f.config.cert_expiration_days = 30 - self.results = capture_results(f) - -diff --git a/tests/test_ipa_certmonger_ca.py b/tests/test_ipa_certmonger_ca.py -index 4eec1ba..3b67784 100644 ---- a/tests/test_ipa_certmonger_ca.py -+++ b/tests/test_ipa_certmonger_ca.py -@@ -4,7 +4,7 @@ - - from util import capture_results, CAInstance - from base import BaseTest --from ipahealthcheck.core import constants -+from ipahealthcheck.core import constants, config - from ipahealthcheck.ipa.plugin import registry - from ipahealthcheck.ipa.certs import IPACertmongerCA - from unittest.mock import Mock, patch -@@ -24,7 +24,7 @@ class TestCertmonger(BaseTest): - 'dogtag-ipa-ca-renew-agent-reuse' - ] - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPACertmongerCA(registry) - - self.results = capture_results(f) -@@ -44,7 +44,7 @@ class TestCertmonger(BaseTest): - ] - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPACertmongerCA(registry) - - self.results = capture_results(f) -diff --git a/tests/test_ipa_dna.py b/tests/test_ipa_dna.py -index 5450642..5c88c22 100644 ---- a/tests/test_ipa_dna.py -+++ b/tests/test_ipa_dna.py -@@ -31,10 +31,9 @@ class TestDNARange(BaseTest): - def test_dnarange_set(self, mock_manager): - mock_manager.return_value = mock_ReplicationManager(start=1, max=100) - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPADNARangeCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 1 -@@ -52,10 +51,9 @@ class TestDNARange(BaseTest): - def test_dnarange_noset(self, mock_manager): - mock_manager.return_value = mock_ReplicationManager() - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPADNARangeCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 1 -@@ -76,10 +74,9 @@ class TestDNARange(BaseTest): - next=101, - next_max=200) - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPADNARangeCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 1 -diff --git a/tests/test_ipa_dns.py b/tests/test_ipa_dns.py -index dde4c4d..61e9a27 100644 ---- a/tests/test_ipa_dns.py -+++ b/tests/test_ipa_dns.py -@@ -192,10 +192,9 @@ class TestDNSSystemRecords(BaseTest): - ] - }] - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPADNSSystemRecordsCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 9 -@@ -235,10 +234,9 @@ class TestDNSSystemRecords(BaseTest): - }] - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPADNSSystemRecordsCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 17 -@@ -286,10 +284,9 @@ class TestDNSSystemRecords(BaseTest): - }] - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPADNSSystemRecordsCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 25 -@@ -335,10 +332,9 @@ class TestDNSSystemRecords(BaseTest): - }] - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPADNSSystemRecordsCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 23 -@@ -389,10 +385,9 @@ class TestDNSSystemRecords(BaseTest): - }] - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPADNSSystemRecordsCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 25 -@@ -447,10 +442,9 @@ class TestDNSSystemRecords(BaseTest): - }] - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPADNSSystemRecordsCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 25 -@@ -509,10 +503,9 @@ class TestDNSSystemRecords(BaseTest): - }] - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPADNSSystemRecordsCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 32 -@@ -545,10 +538,9 @@ class TestDNSSystemRecords(BaseTest): - ] - }] - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPADNSSystemRecordsCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 9 -@@ -581,10 +573,9 @@ class TestDNSSystemRecords(BaseTest): - ] - }] - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPADNSSystemRecordsCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 15 -diff --git a/tests/test_ipa_expiration.py b/tests/test_ipa_expiration.py -index 6cd6952..cd7de82 100644 ---- a/tests/test_ipa_expiration.py -+++ b/tests/test_ipa_expiration.py -@@ -30,10 +30,9 @@ class TestExpiration(BaseTest): - set_requests() - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPACertmongerExpirationCheck(registry) - -- f.config = config.Config() - f.config.cert_expiration_days = 7 - self.results = capture_results(f) - -@@ -66,10 +65,9 @@ class TestExpiration(BaseTest): - set_requests(remove=0, add=replaceme) - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPACertmongerExpirationCheck(registry) - -- f.config = config.Config() - f.config.cert_expiration_days = 30 - self.results = capture_results(f) - -@@ -122,10 +120,9 @@ class TestChainExpiration(BaseTest): - ) - ] - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPACAChainExpirationCheck(registry) - -- f.config = config.Config() - f.config.cert_expiration_days = 7 - self.results = capture_results(f) - -@@ -160,10 +157,9 @@ class TestChainExpiration(BaseTest): - ) - ] - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPACAChainExpirationCheck(registry) - -- f.config = config.Config() - f.config.cert_expiration_days = 7 - self.results = capture_results(f) - -@@ -200,10 +196,9 @@ class TestChainExpiration(BaseTest): - ) - ] - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPACAChainExpirationCheck(registry) - -- f.config = config.Config() - f.config.cert_expiration_days = 7 - self.results = capture_results(f) - -@@ -238,10 +233,9 @@ class TestChainExpiration(BaseTest): - ) - ] - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPACAChainExpirationCheck(registry) - -- f.config = config.Config() - f.config.cert_expiration_days = 7 - self.results = capture_results(f) - -diff --git a/tests/test_ipa_nssdb.py b/tests/test_ipa_nssdb.py -index 590401c..9def3d1 100644 ---- a/tests/test_ipa_nssdb.py -+++ b/tests/test_ipa_nssdb.py -@@ -48,10 +48,9 @@ class TestNSSDBTrust(BaseTest): - mock_certdb.return_value = mock_CertDB(trust) - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPACertNSSTrust(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 4 -@@ -74,10 +73,9 @@ class TestNSSDBTrust(BaseTest): - mock_certdb.return_value = mock_CertDB(trust) - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPACertNSSTrust(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - # The check reports success for those that it found and are correct and -@@ -114,10 +112,9 @@ class TestNSSDBTrust(BaseTest): - mock_certdb.return_value = mock_CertDB(trust) - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPACertNSSTrust(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - result = self.results.results[1] -@@ -149,10 +146,9 @@ class TestNSSDBTrust(BaseTest): - mock_cainstance.return_value = CAInstance(False) - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPACertNSSTrust(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 0 -diff --git a/tests/test_ipa_nssvalidation.py b/tests/test_ipa_nssvalidation.py -index 1e567d8..08135e7 100644 ---- a/tests/test_ipa_nssvalidation.py -+++ b/tests/test_ipa_nssvalidation.py -@@ -38,10 +38,9 @@ class TestNSSValidation(BaseTest): - mock_cainstance.return_value = CAInstance() - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPANSSChainValidation(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 2 -@@ -68,10 +67,9 @@ class TestNSSValidation(BaseTest): - mock_cainstance.return_value = CAInstance() - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPANSSChainValidation(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 2 -@@ -97,10 +95,9 @@ class TestNSSValidation(BaseTest): - mock_cainstance.return_value = CAInstance(False) - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPANSSChainValidation(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 1 -diff --git a/tests/test_ipa_opensslvalidation.py b/tests/test_ipa_opensslvalidation.py -index 0d334cd..e73138c 100644 ---- a/tests/test_ipa_opensslvalidation.py -+++ b/tests/test_ipa_opensslvalidation.py -@@ -30,10 +30,9 @@ class TestOpenSSLValidation(BaseTest): - mock_run.side_effect = run - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPAOpenSSLChainValidation(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 2 -@@ -59,10 +58,9 @@ class TestOpenSSLValidation(BaseTest): - mock_run.side_effect = run - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPAOpenSSLChainValidation(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 2 -diff --git a/tests/test_ipa_revocation.py b/tests/test_ipa_revocation.py -index 39cf3e7..c6423c0 100644 ---- a/tests/test_ipa_revocation.py -+++ b/tests/test_ipa_revocation.py -@@ -54,10 +54,9 @@ class TestRevocation(BaseTest): - set_requests() - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPACertRevocation(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 2 -@@ -84,10 +83,9 @@ class TestRevocation(BaseTest): - set_requests() - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPACertRevocation(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 2 -diff --git a/tests/test_ipa_roles.py b/tests/test_ipa_roles.py -index 453db06..21c0069 100644 ---- a/tests/test_ipa_roles.py -+++ b/tests/test_ipa_roles.py -@@ -18,10 +18,9 @@ class TestCRLManagerRole(BaseTest): - def test_not_crlmanager(self, mock_ca): - mock_ca.return_value = CAInstance(crlgen=False) - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPACRLManagerCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 1 -@@ -36,10 +35,9 @@ class TestCRLManagerRole(BaseTest): - def test_crlmanager(self, mock_ca): - mock_ca.return_value = CAInstance() - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPACRLManagerCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 1 -@@ -54,7 +52,7 @@ class TestCRLManagerRole(BaseTest): - class TestRenewalMaster(BaseTest): - def test_renewal_master_not_set(self): - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPARenewalMasterCheck(registry) - - m_api.Command.config_show.side_effect = [{ -@@ -62,7 +60,6 @@ class TestRenewalMaster(BaseTest): - } - }] - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 1 -@@ -75,7 +72,7 @@ class TestRenewalMaster(BaseTest): - - def test_not_renewal_master(self): - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPARenewalMasterCheck(registry) - - m_api.Command.config_show.side_effect = [{ -@@ -84,7 +81,6 @@ class TestRenewalMaster(BaseTest): - } - }] - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 1 -@@ -97,7 +93,7 @@ class TestRenewalMaster(BaseTest): - - def test_is_renewal_master(self): - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPARenewalMasterCheck(registry) - - m_api.Command.config_show.side_effect = [{ -@@ -106,7 +102,6 @@ class TestRenewalMaster(BaseTest): - } - }] - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 1 -diff --git a/tests/test_ipa_topology.py b/tests/test_ipa_topology.py -index a4ff6d9..11931d9 100644 ---- a/tests/test_ipa_topology.py -+++ b/tests/test_ipa_topology.py -@@ -28,10 +28,9 @@ class TestTopology(BaseTest): - m_api.Command.ca_is_enabled.return_value = {'result': True} - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPATopologyDomainCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 2 -@@ -71,10 +70,9 @@ class TestTopology(BaseTest): - m_api.Command.ca_is_enabled.return_value = {'result': True} - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPATopologyDomainCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 3 -@@ -135,10 +133,9 @@ class TestTopology(BaseTest): - m_api.Command.ca_is_enabled.return_value = {'result': True} - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPATopologyDomainCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 3 -@@ -193,10 +190,9 @@ class TestTopology(BaseTest): - m_api.Command.ca_is_enabled.return_value = {'result': True} - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPATopologyDomainCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 2 -diff --git a/tests/test_ipa_tracking.py b/tests/test_ipa_tracking.py -index c40d8f4..4b982d0 100644 ---- a/tests/test_ipa_tracking.py -+++ b/tests/test_ipa_tracking.py -@@ -5,7 +5,7 @@ - from util import capture_results - from base import BaseTest - --from ipahealthcheck.core import constants -+from ipahealthcheck.core import constants, config - from ipahealthcheck.ipa.plugin import registry - from ipahealthcheck.ipa.certs import IPACertTracking - from unittest.mock import Mock -@@ -27,7 +27,7 @@ class TestTracking(BaseTest): - set_requests() - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPACertTracking(registry) - - self.results = capture_results(f) -@@ -39,7 +39,7 @@ class TestTracking(BaseTest): - set_requests(remove=0) - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPACertTracking(registry) - - self.results = capture_results(f) -@@ -71,7 +71,7 @@ class TestTracking(BaseTest): - set_requests(add=unknown) - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = IPACertTracking(registry) - - self.results = capture_results(f) -diff --git a/tests/test_ipa_trust.py b/tests/test_ipa_trust.py -index 01fdf3c..cf2281c 100644 ---- a/tests/test_ipa_trust.py -+++ b/tests/test_ipa_trust.py -@@ -109,11 +109,10 @@ class SSSDConfig(): - class TestTrustAgent(BaseTest): - def test_no_trust_agent(self): - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_agent = False - f = IPATrustAgentCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - # Zero because the call was skipped altogether -@@ -124,11 +123,10 @@ class TestTrustAgent(BaseTest): - mock_sssd.return_value = SSSDConfig(return_domains=True, - return_ipa_server_mode=True) - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_agent = True - f = IPATrustAgentCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 1 -@@ -143,11 +141,10 @@ class TestTrustAgent(BaseTest): - mock_sssd.return_value = SSSDConfig(return_domains=True, - return_ipa_server_mode=False) - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_agent = True - f = IPATrustAgentCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 1 -@@ -164,11 +161,10 @@ class TestTrustAgent(BaseTest): - mock_sssd.return_value = SSSDConfig(return_domains=True, - return_ipa_server_mode=None) - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_agent = True - f = IPATrustAgentCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 1 -@@ -184,11 +180,10 @@ class TestTrustAgent(BaseTest): - class TestTrustDomains(BaseTest): - def test_no_trust_agent(self): - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_agent = False - f = IPATrustDomainsCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - # Zero because the call was skipped altogether -@@ -202,11 +197,10 @@ class TestTrustDomains(BaseTest): - mock_run.return_value = run_result - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_agent = True - f = IPATrustDomainsCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 1 -@@ -230,11 +224,10 @@ class TestTrustDomains(BaseTest): - mock_trust.side_effect = errors.NotFound(reason='bad') - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_agent = True - f = IPATrustDomainsCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - # There are more than one result I just care about this particular -@@ -279,11 +272,10 @@ class TestTrustDomains(BaseTest): - }] - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_agent = True - f = IPATrustDomainsCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 3 -@@ -344,11 +336,10 @@ class TestTrustDomains(BaseTest): - }] - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_agent = True - f = IPATrustDomainsCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 2 -@@ -374,12 +365,11 @@ class TestIPADomain(BaseTest): - def test_ipa_domain_ok(self, mock_sssd): - mock_sssd.return_value = SSSDConfig(provider='ipa') - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - # being a trust agent isn't mandatory, test without - registry.trust_agent = False - f = IPADomainCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - print(self.results.results) -@@ -394,11 +384,10 @@ class TestIPADomain(BaseTest): - def test_ipa_domain_ad(self, mock_sssd): - mock_sssd.return_value = SSSDConfig(provider='ad') - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_agent = True - f = IPADomainCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 4 -@@ -413,11 +402,10 @@ class TestIPADomain(BaseTest): - class TestTrustCatalog(BaseTest): - def test_no_trust_agent(self): - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_agent = False - f = IPATrustCatalogCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - # Zero because the call was skipped altogether -@@ -464,11 +452,10 @@ class TestTrustCatalog(BaseTest): - }] - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_agent = True - f = IPATrustCatalogCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 6 -@@ -524,11 +511,10 @@ class Testsidgen(BaseTest): - - def test_no_trust_agent(self): - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_agent = False - f = IPAsidgenpluginCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - # Zero because the call was skipped altogether -@@ -544,12 +530,11 @@ class Testsidgen(BaseTest): - ldapentry[attr] = values - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_agent = True - f = IPAsidgenpluginCheck(registry) - - f.conn = mock_ldap(ldapentry) -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 2 -@@ -576,12 +561,11 @@ class Testsidgen(BaseTest): - ldapentry[attr] = values - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_agent = True - f = IPAsidgenpluginCheck(registry) - - f.conn = mock_ldap(ldapentry) -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 2 -@@ -607,11 +591,10 @@ class TestTrustAgentMember(BaseTest): - - def test_no_trust_agent(self): - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_agent = False - f = IPATrustAgentMemberCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - # Zero because the call was skipped altogether -@@ -632,12 +615,11 @@ class TestTrustAgentMember(BaseTest): - ldapentry[attr] = values - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_agent = True - f = IPATrustAgentMemberCheck(registry) - - f.conn = mock_ldap(ldapentry) -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 1 -@@ -660,12 +642,11 @@ class TestTrustAgentMember(BaseTest): - ldapentry[attr] = values - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_agent = True - f = IPATrustAgentMemberCheck(registry) - - f.conn = mock_ldap(ldapentry) -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 1 -@@ -685,11 +666,10 @@ class TestControllerPrincipal(BaseTest): - - def test_not_trust_controller(self): - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_controller = False - f = IPATrustControllerPrincipalCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - # Zero because the call was skipped altogether -@@ -711,12 +691,11 @@ class TestControllerPrincipal(BaseTest): - ldapentry[attr] = values - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_controller = True - f = IPATrustControllerPrincipalCheck(registry) - - f.conn = mock_ldap(ldapentry) -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 1 -@@ -740,12 +719,11 @@ class TestControllerPrincipal(BaseTest): - ldapentry[attr] = values - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_controller = True - f = IPATrustControllerPrincipalCheck(registry) - - f.conn = mock_ldap(ldapentry) -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 1 -@@ -765,11 +743,10 @@ class TestControllerService(BaseTest): - - def test_not_trust_controller(self): - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_controller = False - f = IPATrustControllerServiceCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - # Zero because the call was skipped altogether -@@ -786,12 +763,11 @@ class TestControllerService(BaseTest): - ldapentry[attr] = values - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_controller = True - f = IPATrustControllerServiceCheck(registry) - - f.conn = mock_ldap(ldapentry) -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 1 -@@ -813,12 +789,11 @@ class TestControllerService(BaseTest): - ldapentry[attr] = values - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_controller = True - f = IPATrustControllerServiceCheck(registry) - - f.conn = mock_ldap(ldapentry) -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 1 -@@ -837,11 +812,10 @@ class TestControllerGroupSID(BaseTest): - - def test_not_trust_controller(self): - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_controller = False - f = IPATrustControllerGroupSIDCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - # Zero because the call was skipped altogether -@@ -859,12 +833,11 @@ class TestControllerGroupSID(BaseTest): - ldapentry[attr] = values - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_controller = True - f = IPATrustControllerGroupSIDCheck(registry) - - f.conn = mock_ldap(ldapentry) -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 1 -@@ -888,12 +861,11 @@ class TestControllerGroupSID(BaseTest): - ldapentry[attr] = values - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_controller = True - f = IPATrustControllerGroupSIDCheck(registry) - - f.conn = mock_ldap(ldapentry) -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 1 -@@ -914,11 +886,10 @@ class TestControllerConf(BaseTest): - - def test_not_trust_controller(self): - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_controller = False - f = IPATrustControllerConfCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - # Zero because the call was skipped altogether -@@ -934,11 +905,10 @@ class TestControllerConf(BaseTest): - mock_run.return_value = run_result - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_controller = True - f = IPATrustControllerConfCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - assert len(self.results) == 1 -@@ -954,11 +924,10 @@ class TestPackageCheck(BaseTest): - def test_agent_with_package(self): - # Note that this test assumes the import is installed - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_controller = False - registry.trust_agent = True - f = IPATrustPackageCheck(registry) -- f.config = config.Config() - self.results = capture_results(f) - assert len(self.results) == 1 - result = self.results.results[0] -@@ -969,14 +938,13 @@ class TestPackageCheck(BaseTest): - def test_agent_without_package(self): - # Note that this test assumes the import is installed - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - registry.trust_controller = False - registry.trust_agent = True - # Hose up the module so the import fails - save = sys.modules['ipaserver.install'] - sys.modules['ipaserver.install'] = 'foo' - f = IPATrustPackageCheck(registry) -- f.config = config.Config() - self.results = capture_results(f) - assert len(self.results) == 1 - result = self.results.results[0] -diff --git a/tests/test_meta_services.py b/tests/test_meta_services.py -index 6fbea13..b7a71a4 100644 ---- a/tests/test_meta_services.py -+++ b/tests/test_meta_services.py -@@ -7,6 +7,7 @@ from base import BaseTest - - from ipahealthcheck.ipa.plugin import registry - from ipahealthcheck.meta.services import httpd -+from ipahealthcheck.core import config - - - class TestServices(BaseTest): -@@ -19,7 +20,7 @@ class TestServices(BaseTest): - running. - """ - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = httpd(registry) - - self.results = capture_results(f) -diff --git a/tests/test_system_filesystemspace.py b/tests/test_system_filesystemspace.py -index 3317f62..873b977 100644 ---- a/tests/test_system_filesystemspace.py -+++ b/tests/test_system_filesystemspace.py -@@ -28,10 +28,9 @@ class TestFileSystemNotEnoughFreeSpace(BaseTest): - def test_filesystem_near_enospc(self): - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = FileSystemSpaceCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - expected_results = 10 if in_container() else 12 -@@ -64,10 +63,9 @@ class TestFileSystemNotEnoughFreeSpacePercentage(BaseTest): - def test_filesystem_risking_fragmentation(self): - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = FileSystemSpaceCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - expected_results = 10 if in_container() else 12 -@@ -100,10 +98,9 @@ class TestFileSystemEnoughFreeSpace(BaseTest): - def test_filesystem_with_enough_space(self): - - framework = object() -- registry.initialize(framework) -+ registry.initialize(framework, config.Config) - f = FileSystemSpaceCheck(registry) - -- f.config = config.Config() - self.results = capture_results(f) - - expected_results = 10 if in_container() else 12 --- -2.21.0 - diff --git a/SPECS/ipa-healthcheck.spec b/SPECS/ipa-healthcheck.spec index 1fca951..6fb3b64 100644 --- a/SPECS/ipa-healthcheck.spec +++ b/SPECS/ipa-healthcheck.spec @@ -7,8 +7,8 @@ Name: ipa-healthcheck -Version: 0.4 -Release: 6%{?dist} +Version: 0.7 +Release: 3%{?dist} Summary: Health check tool for IdM BuildArch: noarch License: GPLv3 @@ -17,16 +17,15 @@ Source0: https://github.com/%{project}/%{name}/archive/%{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 +Patch0002: 0002-Remove-ipaclustercheck.patch +Patch0003: 0003-Use-trust-find-and-trustdomain-find-to-identify-all-.patch +Patch0004: 0004-result-names-are-not-translated-when-reading-input-f.patch Requires: %{name}-core = %{version}-%{release} Requires: ipa-server Requires: python3-ipalib Requires: python3-ipaserver +Requires: python3-lib389 # cronie-anacron provides anacron Requires: anacron Requires: logrotate @@ -77,9 +76,9 @@ install -p -m644 %{_builddir}/%{project}-%{shortname}-%{version}/logrotate/%{lon mkdir -p %{buildroot}/%{_localstatedir}/log/ipa/%{shortname} -mkdir -p %{buildroot}/%{_mandir}/man1 +mkdir -p %{buildroot}/%{_mandir}/man8 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/man8/ipa-%{shortname}.8 %{buildroot}%{_mandir}/man8/ install -p -m644 %{_builddir}/%{project}-%{shortname}-%{version}/man/man5/%{longname}.conf.5 %{buildroot}%{_mandir}/man5/ (cd %{buildroot}/%{python3_sitelib}/ipahealthcheck && find . -type f | \ @@ -113,7 +112,7 @@ install -p -m644 %{_builddir}/%{project}-%{shortname}-%{version}/man/man5/%{long %{python3_sitelib}/%{longname}-%{version}-*-nspkg.pth %{_unitdir}/* %{_libexecdir}/* -%{_mandir}/man1/* +%{_mandir}/man8/* %{_mandir}/man5/* %files -n %{name}-core @@ -124,6 +123,21 @@ install -p -m644 %{_builddir}/%{project}-%{shortname}-%{version}/man/man5/%{long %changelog +* Fri Dec 4 2020 Rob Crittenden - 0.7-3 +- Translate result names when reading input from a json file (#1866558) + +* Tue Nov 3 2020 Rob Crittenden - 0.7-2 +- Fix collection of AD trust domains (#1891505) + +* Tue Nov 3 2020 Rob Crittenden - 0.7-1 +- Update to upstream 0.7 (#1891850) +- Include Directory Server healthchecks (#1824193) +- Document that default output format is JSON (#1780328) +- Fix return value on exit with --input-file (#1866558) +- Fix examples in man page (#1809215) +- Replace man page reference to output-format with output-type (#1780303) +- Add dependencies on services to avoid false positives (#1780510) + * Wed Aug 19 2020 Rob Crittenden - 0.4-6 - The core subpackage can be installed standalone, drop the Requires on the base package. (#1852244)