import ipa-healthcheck-0.12-3.module+el8.9.0+19692+fac39a03

c8-beta-stream-client imports/c8-beta-stream-client/ipa-healthcheck-0.12-3.module+el8.9.0+19692+fac39a03
MSVSphere Packaging Team 11 months ago
commit 64688182f5

1
.gitignore vendored

@ -0,0 +1 @@
SOURCES/0.12.tar.gz

@ -0,0 +1 @@
dc05dc0ca441dcb1a87e3b3bd7d440d79c17ac0a SOURCES/0.12.tar.gz

@ -0,0 +1,639 @@
From 9d5f9d21442ee483044fc55a5c02039af23869d7 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Thu, 1 Dec 2022 14:22:46 -0500
Subject: [PATCH] Remove ipaclustercheck
---
setup.py | 12 +-
src/ipaclustercheck/__init__.py | 5 -
src/ipaclustercheck/core/__init__.py | 0
src/ipaclustercheck/core/main.py | 32 ------
src/ipaclustercheck/core/output.py | 68 -----------
src/ipaclustercheck/ipa/__init__.py | 0
src/ipaclustercheck/ipa/crlmanager.py | 36 ------
src/ipaclustercheck/ipa/plugin.py | 117 -------------------
src/ipaclustercheck/ipa/ruv.py | 155 --------------------------
tests/test_cluster_ruv.py | 106 ------------------
10 files changed, 1 insertion(+), 530 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 0cfa486..b9e1ca1 100644
--- a/setup.py
+++ b/setup.py
@@ -4,7 +4,7 @@ from setuptools import find_packages, setup
setup(
name='ipahealthcheck',
version='0.12',
- 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': [
@@ -72,13 +69,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 f475832..0000000
--- a/src/ipaclustercheck/core/main.py
+++ /dev/null
@@ -1,32 +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().validate_options()
-
- if self.options.dir is None:
- print("--directory containing logs to check is required")
- return 1
-
- return None
-
-
-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 909eac4..0000000
--- a/src/ipaclustercheck/core/output.py
+++ /dev/null
@@ -1,68 +0,0 @@
-#
-# Copyright (C) 2019 FreeIPA Contributors see COPYING for license
-#
-
-import json
-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.output_file
-
- def strip_output(self, results):
- """Nothing to strip out"""
- return list(results.output())
-
- def generate(self, data):
- raise NotImplementedError
-
-
-@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().__init__(options)
- self.indent = options.indent
-
- def generate(self, data):
- output = []
- for line in data:
- kw = line.get('kw')
- 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 a111988..0000000
--- a/src/ipaclustercheck/ipa/plugin.py
+++ /dev/null
@@ -1,117 +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):
- pass
-
-
-class ClusterRegistry(Registry):
- def __init__(self):
- super().__init__()
- self.json = None
-
- def initialize(self, framework, config, options=None):
- super().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 6477738..0000000
--- a/src/ipaclustercheck/ipa/ruv.py
+++ /dev/null
@@ -1,155 +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 _unused, master_info in info.items():
- for ruv in master_info['clean_ruv']:
- logger.debug(
- "Dangling RUV id: %s, hostname: %s", ruv[1], ruv[0]
- )
- clean_ruvs.add(ruv[1])
- for csruv in master_info['clean_csruv']:
- logger.debug(
- "Dangling CS RUV id: %s, hostname: %s",
- csruv[1],
- 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.38.1

@ -0,0 +1,64 @@
From d2cd8292d8a1d7c2fd2a5f978f8ed76c0769e5e9 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Tue, 8 Feb 2022 14:16:06 -0500
Subject: [PATCH] Disable two failing tests
These test that healthcheck can properly detect when IPA
is not installed or configured. Its not ideal to remove them
from the check process but they aren't critical.
---
tests/test_commands.py | 41 -----------------------------------------
1 file changed, 41 deletions(-)
diff --git a/tests/test_commands.py b/tests/test_commands.py
index 988d7fc..e14114b 100644
--- a/tests/test_commands.py
+++ b/tests/test_commands.py
@@ -14,44 +14,3 @@ def test_version():
"""
output = run(['ipa-healthcheck', '--version'], env=os.environ)
assert 'ipahealthcheck' in output.raw_output.decode('utf-8')
-
-
-@pytest.fixture
-def python_ipalib_dir(tmpdir):
- ipalib_dir = tmpdir.mkdir("ipalib")
- ipalib_dir.join("__init__.py").write("")
-
- def _make_facts(configured=None):
- if configured is None:
- module_text = ""
- elif isinstance(configured, bool):
- module_text = f"def is_ipa_configured(): return {configured}"
- else:
- raise TypeError(
- f"'configured' must be None or bool, got '{configured!r}'"
- )
-
- ipalib_dir.join("facts.py").write(module_text)
- return str(tmpdir)
-
- return _make_facts
-
-
-def test_ipa_notinstalled(python_ipalib_dir, monkeypatch):
- """
- Test ipa-healthcheck handles the missing IPA stuff
- """
- monkeypatch.setenv("PYTHONPATH", python_ipalib_dir(configured=None))
- output = run(["ipa-healthcheck"], raiseonerr=False, env=os.environ)
- assert output.returncode == 1
- assert "IPA server is not installed" in output.raw_output.decode("utf-8")
-
-
-def test_ipa_unconfigured(python_ipalib_dir, monkeypatch):
- """
- Test ipa-healthcheck handles the unconfigured IPA server
- """
- monkeypatch.setenv("PYTHONPATH", python_ipalib_dir(configured=False))
- output = run(["ipa-healthcheck"], raiseonerr=False, env=os.environ)
- assert output.returncode == 1
- assert "IPA server is not configured" in output.raw_output.decode("utf-8")
--
2.31.1

@ -0,0 +1,29 @@
From 0f485a0921a39c08e7259f9b38f0b10e425384a5 Mon Sep 17 00:00:00 2001
From: root <root@ipa.example.test>
Date: Mon, 5 Dec 2022 16:17:17 -0500
Subject: [PATCH] Fix logging issue related to dtype
It is an integer in earlier versions of python3-dns and a class
in later versions. Log the integer value.
Related: #2099484
---
src/ipahealthcheck/ipa/idns.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ipa/idns.py b/ipa/idns.py
index e294db2..1adb69d 100644
--- a/src/ipahealthcheck/ipa/idns.py
+++ b/src/ipahealthcheck/ipa/idns.py
@@ -176,7 +176,7 @@ class IPADNSSystemRecordsCheck(IPAPlugin):
qname = "ipa-ca." + api.env.domain + "."
ipa_ca_records = []
for dtype in (rdatatype.A, rdatatype.AAAA):
- logger.debug("Search DNS for %s records of %s", dtype.name, qname)
+ logger.debug("Search DNS for %s records of %s", dtype, qname)
try:
answers = resolve(qname, dtype)
except DNSException as e:
--
2.31.1

@ -0,0 +1,340 @@
From 30471ebdc9fe5871c115ca06f78a415275a320e6 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Thu, 16 Jun 2022 20:02:51 +0000
Subject: [PATCH] Skip AD domains with posix ranges in the catalog check
The catalog check is intended to ensure that the trust is
working by looking up a user. For a non-posix range we can use
the Administrator user because it has a predicible SID.
With a posix range the UID/GID may not be set so the lookup
can fail (with an empty return value).
So skip domain which have a posix range associated with it.
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1775199
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
---
src/ipahealthcheck/ipa/trust.py | 34 ++++-
tests/test_ipa_trust.py | 214 +++++++++++++++++++++++++++++++-
2 files changed, 243 insertions(+), 5 deletions(-)
diff --git a/src/ipahealthcheck/ipa/trust.py b/src/ipahealthcheck/ipa/trust.py
index 27a2c86..b962807 100644
--- a/src/ipahealthcheck/ipa/trust.py
+++ b/src/ipahealthcheck/ipa/trust.py
@@ -183,6 +183,7 @@ class IPATrustDomainsCheck(IPAPlugin):
except Exception as e:
yield Result(self, constants.WARNING,
key='domain-status',
+ domain=domain,
error=str(e),
msg='Execution of {key} failed: {error}')
continue
@@ -262,6 +263,10 @@ class IPATrustCatalogCheck(IPAPlugin):
This should populate the 'AD Global catalog' and 'AD Domain Controller'
fields in 'sssctl domain-status' output (means SSSD actually talks to AD
DCs)
+
+ If the associated idrange type is ipa-ad-trust-posix then the
+ check will be skipped because we can't predict what the UID of the
+ Administrator account will be.
"""
@duration
def check(self):
@@ -280,20 +285,41 @@ class IPATrustCatalogCheck(IPAPlugin):
for trust_domain in trust_domains:
sid = trust_domain.get('domainsid')
+ domain = trust_domain['domain']
+ idrange = api.Command.idrange_find(sid)
+ if len(idrange['result']) == 0:
+ yield Result(self, constants.WARNING,
+ key=sid,
+ domain=domain,
+ msg='Domain {domain} does not have an idrange')
+ continue
+
+ if 'ipa-ad-trust-posix' in idrange['result'][0]['iparangetyperaw']:
+ yield Result(self, constants.SUCCESS,
+ key=sid,
+ domain=domain,
+ type='ipa-ad-trust-posix')
+ logger.debug("Domain %s is a POSIX range, skip the lookup",
+ domain)
+ continue
+
try:
id = pysss_nss_idmap.getnamebysid(sid + '-500')
except Exception as e:
yield Result(self, constants.ERROR,
- key=sid,
+ key=id,
+ domain=domain,
error=str(e),
- msg='Look up of{key} failed: {error}')
+ msg='Look up of ID {key} for {domain} failed: '
+ '{error}')
continue
if not id:
yield Result(self, constants.WARNING,
- key=sid,
+ key=id,
+ domain=trust_domain['domain'],
error='returned nothing',
- msg='Look up of {key} {error}')
+ msg='Look up of ID {key} for {domain} {error}')
else:
yield Result(self, constants.SUCCESS,
key='Domain Security Identifier',
diff --git a/tests/test_ipa_trust.py b/tests/test_ipa_trust.py
index c314b70..6c4754a 100644
--- a/tests/test_ipa_trust.py
+++ b/tests/test_ipa_trust.py
@@ -129,6 +129,74 @@ def trustdomain_find():
]
+def idrange_find_adrange_type():
+ """
+ Return a set of idranges of type "Active Directory domain range"
+ """
+
+ return {
+ "result": [
+ {
+ "cn": ["AD.EXAMPLE_id_range"],
+ "ipabaseid": ["1664000000"],
+ "ipabaserid": ["0"],
+ "ipaidrangesize": ["200000"],
+ "ipanttrusteddomainsid": ["S-1-5-21-abc"],
+ "iparangetype": ["Active Directory domain range"],
+ "iparangetyperaw": ["ipa-ad-trust"]
+ },
+ {
+ "cn": ["CHILD.AD.EXAMPLE_id_range"],
+ "ipabaseid": ["538600000"],
+ "ipabaserid": ["0"],
+ "ipaidrangesize": ["200000"],
+ "ipanttrusteddomainsid": [
+ "S-1-5-21-38045160-610119595-3099869984"
+ ],
+ "iparangetype": ["Active Directory domain range"],
+ "iparangetyperaw": ["ipa-ad-trust"]
+ },
+ {
+ "cn": ["IPA.EXAMPLE_id_range"],
+ "ipabaseid": ["447400000"],
+ "ipabaserid": ["1000"],
+ "ipaidrangesize": ["200000"],
+ "iparangetype": ["local domain range"],
+ "iparangetyperaw": ["ipa-local"],
+ "ipasecondarybaserid": ["100000000"]
+ }]
+ }
+
+
+def idrange_find_adrange_posix():
+ """
+ Return a set of idranges of type
+ "Active Directory trust range with POSIX attributes"
+ """
+
+ return {
+ "result": [
+ {
+ "cn": ["AD.EXAMPLE_id_range"],
+ "ipabaseid": ["1664000000"],
+ "ipaidrangesize": ["200000"],
+ "ipanttrusteddomainsid": ["S-1-5-21-abc"],
+ "iparangetype": [
+ "Active Directory trust range with POSIX attributes"],
+ "iparangetyperaw": ["ipa-ad-trust-posix"]
+ },
+ {
+ "cn": ["IPA.EXAMPLE_id_range"],
+ "ipabaseid": ["447400000"],
+ "ipabaserid": ["1000"],
+ "ipaidrangesize": ["200000"],
+ "iparangetype": ["local domain range"],
+ "iparangetyperaw": ["ipa-local"],
+ "ipasecondarybaserid": ["100000000"]
+ }]
+ }
+
+
class SSSDDomain:
def __init__(self, return_ipa_server_mode=True, provider='ipa'):
self.return_ipa_server_mode = return_ipa_server_mode
@@ -454,7 +522,8 @@ class TestTrustCatalog(BaseTest):
@patch('pysss_nss_idmap.getnamebysid')
@patch('ipapython.ipautil.run')
- def test_trust_catalog_ok(self, mock_run, mock_getnamebysid):
+ def test_trust_catalog_adrange(self, mock_run, mock_getnamebysid):
+ """The associated ID ranges are Active Directory domain range"""
# id Administrator@ad.example
dsresult = namedtuple('run', ['returncode', 'error_log'])
dsresult.returncode = 0
@@ -478,6 +547,11 @@ class TestTrustCatalog(BaseTest):
# get_trust_domains()
m_api.Command.trust_find.side_effect = trust_find()
m_api.Command.trustdomain_find.side_effect = trustdomain_find()
+ m_api.Command.idrange_find.side_effect = [
+ idrange_find_adrange_type(),
+ idrange_find_adrange_type(),
+ idrange_find_adrange_type()
+ ]
framework = object()
registry.initialize(framework, config.Config)
@@ -550,6 +624,144 @@ class TestTrustCatalog(BaseTest):
assert result.kw.get('key') == 'AD Domain Controller'
assert result.kw.get('domain') == 'child.example'
+ @patch('pysss_nss_idmap.getnamebysid')
+ @patch('ipapython.ipautil.run')
+ def test_trust_catalog_posix(self, mock_run, mock_getnamebysid):
+ """AD POSIX ranges"""
+ # id Administrator@ad.example
+ dsresult = namedtuple('run', ['returncode', 'error_log'])
+ dsresult.returncode = 0
+ dsresult.error_log = ''
+ dsresult.output = 'Active servers:\nAD Global Catalog: ' \
+ 'root-dc.ad.vm\nAD Domain Controller: root-dc.ad.vm\n' \
+ 'IPA: master.ipa.vm\n\n'
+ ds2result = namedtuple('run', ['returncode', 'error_log'])
+ ds2result.returncode = 0
+ ds2result.error_log = ''
+ ds2result.output = 'Active servers:\nAD Global Catalog: ' \
+ 'root-dc.ad.vm\nAD Domain Controller: root-dc.ad.vm\n' \
+
+ mock_run.side_effect = [dsresult, dsresult, 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 = trust_find()
+ m_api.Command.trustdomain_find.side_effect = trustdomain_find()
+ m_api.Command.idrange_find.side_effect = [
+ idrange_find_adrange_posix(),
+ idrange_find_adrange_posix(),
+ idrange_find_adrange_posix()
+ ]
+
+ framework = object()
+ registry.initialize(framework, config.Config)
+ registry.trust_agent = True
+ f = IPATrustCatalogCheck(registry)
+
+ self.results = capture_results(f)
+
+ assert len(self.results) == 3
+
+ result = self.results.results[0]
+ assert result.result == constants.SUCCESS
+ assert result.source == 'ipahealthcheck.ipa.trust'
+ assert result.check == 'IPATrustCatalogCheck'
+ assert result.kw.get('key') == 'S-1-5-21-abc'
+ assert result.kw.get('domain') == 'ad.example'
+ assert result.kw.get('type') == 'ipa-ad-trust-posix'
+
+ result = self.results.results[1]
+ assert result.result == constants.SUCCESS
+ assert result.source == 'ipahealthcheck.ipa.trust'
+ assert result.check == 'IPATrustCatalogCheck'
+ assert result.kw.get('key') == 'S-1-5-22-def'
+ assert result.kw.get('domain') == 'child.ad.example'
+ assert result.kw.get('type') == 'ipa-ad-trust-posix'
+
+ result = self.results.results[2]
+ assert result.result == constants.SUCCESS
+ assert result.source == 'ipahealthcheck.ipa.trust'
+ assert result.check == 'IPATrustCatalogCheck'
+ assert result.kw.get('key') == 'S-1-5-21-ghi'
+ assert result.kw.get('domain') == 'child.example'
+ assert result.kw.get('type') == 'ipa-ad-trust-posix'
+
+ @patch('pysss_nss_idmap.getnamebysid')
+ @patch('ipapython.ipautil.run')
+ def test_trust_catalog_posix_missing(self, mock_run, mock_getnamebysid):
+ """AD POSIX ranges"""
+ # id Administrator@ad.example
+ dsresult = namedtuple('run', ['returncode', 'error_log'])
+ dsresult.returncode = 0
+ dsresult.error_log = ''
+ dsresult.output = 'Active servers:\nAD Global Catalog: ' \
+ 'root-dc.ad.vm\nAD Domain Controller: root-dc.ad.vm\n' \
+ 'IPA: master.ipa.vm\n\n'
+ ds2result = namedtuple('run', ['returncode', 'error_log'])
+ ds2result.returncode = 0
+ ds2result.error_log = ''
+ ds2result.output = 'Active servers:\nAD Global Catalog: ' \
+ 'root-dc.ad.vm\nAD Domain Controller: root-dc.ad.vm\n' \
+
+ mock_run.side_effect = [dsresult, dsresult, 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 = trust_find()
+ m_api.Command.trustdomain_find.side_effect = trustdomain_find()
+ m_api.Command.idrange_find.side_effect = [
+ idrange_find_adrange_posix(),
+ {'result': []},
+ {'result': []}
+ ]
+
+ framework = object()
+ registry.initialize(framework, config.Config)
+ registry.trust_agent = True
+ f = IPATrustCatalogCheck(registry)
+
+ self.results = capture_results(f)
+
+ assert len(self.results) == 3
+
+ result = self.results.results[0]
+ assert result.result == constants.SUCCESS
+ assert result.source == 'ipahealthcheck.ipa.trust'
+ assert result.check == 'IPATrustCatalogCheck'
+ assert result.kw.get('key') == 'S-1-5-21-abc'
+ assert result.kw.get('domain') == 'ad.example'
+ assert result.kw.get('type') == 'ipa-ad-trust-posix'
+
+ result = self.results.results[1]
+ assert result.result == constants.WARNING
+ assert result.source == 'ipahealthcheck.ipa.trust'
+ assert result.check == 'IPATrustCatalogCheck'
+ assert result.kw.get('key') == 'S-1-5-22-def'
+ assert result.kw.get('domain') == 'child.ad.example'
+ assert (
+ result.kw.get('msg')
+ == 'Domain {domain} does not have an idrange'
+ )
+
+ result = self.results.results[2]
+ assert result.result == constants.WARNING
+ assert result.source == 'ipahealthcheck.ipa.trust'
+ assert result.check == 'IPATrustCatalogCheck'
+ assert result.kw.get('key') == 'S-1-5-21-ghi'
+ assert result.kw.get('domain') == 'child.example'
+ assert (
+ result.kw.get('msg')
+ == 'Domain {domain} does not have an idrange'
+ )
+
class Testsidgen(BaseTest):
patches = {
--
2.39.2

@ -0,0 +1,372 @@
From 29855ec76bcb445543e1f2b16b13e5bcfeb67723 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Mon, 27 Mar 2023 16:43:11 -0400
Subject: [PATCH] Don't error in DogtagCertsConnectivityCheck with external CAs
The purpose of the check is to validate that communication
with the CA works. In the past we looked up serial number 1
for this check. The problem is that if the server was
installed with RSNv3 so had no predictable CA serial number.
It also was broken with externally-issued CA certificate which
cannot be looked up in IPA.
Instead use the IPA RA agent certificate which should definitely
have a serial number in the IPA CA if one is configured.
Fixes: https://github.com/freeipa/freeipa-healthcheck/issues/285
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
---
src/ipahealthcheck/dogtag/ca.py | 45 +++-----
tests/test_dogtag_connectivity.py | 175 +++++-------------------------
2 files changed, 39 insertions(+), 181 deletions(-)
diff --git a/src/ipahealthcheck/dogtag/ca.py b/src/ipahealthcheck/dogtag/ca.py
index 868876f..4afa5d7 100644
--- a/src/ipahealthcheck/dogtag/ca.py
+++ b/src/ipahealthcheck/dogtag/ca.py
@@ -12,10 +12,8 @@ from ipahealthcheck.core import constants
from ipalib import api, errors, x509
from ipaplatform.paths import paths
from ipaserver.install import certs
-from ipaserver.install import ca
from ipaserver.install import krainstance
from ipapython.directivesetter import get_directive
-from ipapython.dn import DN
from cryptography.hazmat.primitives.serialization import Encoding
logger = logging.getLogger()
@@ -95,6 +93,10 @@ class DogtagCertsConfigCheck(DogtagPlugin):
class DogtagCertsConnectivityCheck(DogtagPlugin):
"""
Test basic connectivity by using cert-show to fetch a cert
+
+ The RA agent certificate is used because if a CA is configured we
+ know this certificate should exist. Use its serial number to do
+ the lookup.
"""
requires = ('dirsrv',)
@@ -104,59 +106,38 @@ class DogtagCertsConnectivityCheck(DogtagPlugin):
logger.debug('CA is not configured, skipping connectivity check')
return
- config = api.Command.config_show()
-
- subject_base = config['result']['ipacertificatesubjectbase'][0]
- ipa_subject = ca.lookup_ca_subject(api, subject_base)
try:
- certs = x509.load_certificate_list_from_file(paths.IPA_CA_CRT)
+ cert = x509.load_certificate_from_file(paths.RA_AGENT_PEM)
except Exception as e:
yield Result(self, constants.ERROR,
- key='ipa_ca_crt_file_missing',
- path=paths.IPA_CA_CRT,
+ key='ipa_ra_crt_file_missing',
+ path=paths.RA_AGENT_PEM,
error=str(e),
- msg='The IPA CA cert file {path} could not be '
+ msg='The IPA RA cert file {path} could not be '
'opened: {error}')
return
- found = False
- for cert in certs:
- if DN(cert.subject) == ipa_subject:
- found = True
- break
-
- if not found:
- yield Result(self, constants.ERROR,
- key='ipa_ca_cert_not_found',
- subject=str(ipa_subject),
- path=paths.IPA_CA_CRT,
- msg='The CA certificate with subject {subject} '
- 'was not found in {path}')
- return
- # Load the IPA CA certificate to obtain its serial number. This
- # was traditionally 1 prior to random serial number support.
- # There is nothing special about cert 1. Even if there is no cert
- # serial number 1 but the connection is ok it is considered passing.
+ # We used to use serial #1 but with RSNv3 it can be anything.
try:
api.Command.cert_show(cert.serial_number, all=True)
except errors.CertificateOperationError as e:
if 'not found' in str(e):
yield Result(self, constants.ERROR,
- key='cert_show_1',
+ key='cert_show_ra',
error=str(e),
serial=str(cert.serial_number),
msg='Serial number not found: {error}')
else:
yield Result(self, constants.ERROR,
- key='cert_show_1',
+ key='cert_show_ra',
error=str(e),
serial=str(cert.serial_number),
msg='Request for certificate failed: {error}')
except Exception as e:
yield Result(self, constants.ERROR,
- key='cert_show_1',
+ key='cert_show_ra',
error=str(e),
serial=str(cert.serial_number),
- msg='Request for certificate failed: {error')
+ msg='Request for certificate failed: {error}')
else:
yield Result(self, constants.SUCCESS)
diff --git a/tests/test_dogtag_connectivity.py b/tests/test_dogtag_connectivity.py
index d81e598..4413fe1 100644
--- a/tests/test_dogtag_connectivity.py
+++ b/tests/test_dogtag_connectivity.py
@@ -13,14 +13,23 @@ from ipahealthcheck.dogtag.ca import DogtagCertsConnectivityCheck
from ipalib.errors import CertificateOperationError
from ipaplatform.paths import paths
-from ipapython.dn import DN
+
+
+default_subject_base = [{
+ 'result':
+ {
+ 'ipacertificatesubjectbase': [f'O={m_api.env.realm}'],
+ },
+}]
class IPACertificate:
def __init__(self, serial_number=1,
- subject='CN=Certificate Authority, O=%s' % m_api.env.realm):
+ subject='CN=Certificate Authority, O=%s' % m_api.env.realm,
+ issuer='CN=Certificate Authority, O=%s' % m_api.env.realm):
self.serial_number = serial_number
self.subject = subject
+ self.issuer = issuer
def __eq__(self, other):
return self.serial_number == other.serial_number
@@ -50,18 +59,15 @@ class TestCAConnectivity(BaseTest):
Mock(return_value=CAInstance()),
}
- @patch('ipaserver.install.ca.lookup_ca_subject')
- @patch('ipalib.x509.load_certificate_list_from_file')
- def test_ca_connection_ok(self, mock_load_cert, mock_ca_subject):
+ @patch('ipalib.x509.load_certificate_from_file')
+ def test_ca_connection_ok(self, mock_load_cert):
"""CA connectivity check when cert_show returns a valid value"""
m_api.Command.cert_show.side_effect = None
m_api.Command.config_show.side_effect = subject_base
m_api.Command.cert_show.return_value = {
u'result': {u'revoked': False}
}
- mock_load_cert.return_value = [IPACertificate(12345)]
- mock_ca_subject.return_value = DN(('cn', 'Certificate Authority'),
- f'O={m_api.env.realm}')
+ mock_load_cert.return_value = IPACertificate(12345)
framework = object()
registry.initialize(framework, config.Config)
@@ -76,10 +82,8 @@ class TestCAConnectivity(BaseTest):
assert result.source == 'ipahealthcheck.dogtag.ca'
assert result.check == 'DogtagCertsConnectivityCheck'
- @patch('ipaserver.install.ca.lookup_ca_subject')
- @patch('ipalib.x509.load_certificate_list_from_file')
- def test_ca_connection_cert_not_found(self, mock_load_cert,
- mock_ca_subject):
+ @patch('ipalib.x509.load_certificate_from_file')
+ def test_ca_connection_cert_not_found(self, mock_load_cert):
"""CA connectivity check for a cert that doesn't exist"""
m_api.Command.cert_show.reset_mock()
m_api.Command.config_show.side_effect = subject_base
@@ -87,9 +91,7 @@ class TestCAConnectivity(BaseTest):
message='Certificate operation cannot be completed: '
'EXCEPTION (Certificate serial number 0x0 not found)'
)
- mock_load_cert.return_value = [IPACertificate()]
- mock_ca_subject.return_value = DN(('cn', 'Certificate Authority'),
- f'O={m_api.env.realm}')
+ mock_load_cert.return_value = IPACertificate(serial_number=7)
framework = object()
registry.initialize(framework, config.Config)
@@ -103,46 +105,16 @@ class TestCAConnectivity(BaseTest):
assert result.result == constants.ERROR
assert result.source == 'ipahealthcheck.dogtag.ca'
assert result.check == 'DogtagCertsConnectivityCheck'
- assert result.kw.get('key') == 'cert_show_1'
- assert result.kw.get('serial') == '1'
+ assert result.kw.get('key') == 'cert_show_ra'
+ assert result.kw.get('serial') == '7'
assert result.kw.get('msg') == 'Serial number not found: {error}'
- @patch('ipaserver.install.ca.lookup_ca_subject')
- @patch('ipalib.x509.load_certificate_list_from_file')
- def test_ca_connection_cert_file_not_found(self, mock_load_cert,
- mock_ca_subject):
+ @patch('ipalib.x509.load_certificate_from_file')
+ def test_ca_connection_cert_file_not_found(self, mock_load_cert):
"""CA connectivity check for a cert that doesn't exist"""
m_api.Command.cert_show.reset_mock()
m_api.Command.config_show.side_effect = subject_base
mock_load_cert.side_effect = FileNotFoundError()
- mock_ca_subject.return_value = DN(('cn', 'Certificate Authority'),
- f'O={m_api.env.realm}')
-
- framework = object()
- registry.initialize(framework, config.Config)
- f = DogtagCertsConnectivityCheck(registry)
-
- self.results = capture_results(f)
-
- assert len(self.results) == 1
-
- result = self.results.results[0]
- assert result.result == constants.ERROR
- assert result.source == 'ipahealthcheck.dogtag.ca'
- assert result.check == 'DogtagCertsConnectivityCheck'
- assert result.kw.get('key') == 'ipa_ca_crt_file_missing'
- assert result.kw.get('path') == paths.IPA_CA_CRT
-
- @patch('ipaserver.install.ca.lookup_ca_subject')
- @patch('ipalib.x509.load_certificate_list_from_file')
- def test_ca_connection_cert_not_in_file_list(self, mock_load_cert,
- mock_ca_subject):
- """CA connectivity check for a cert that isn't in IPA_CA_CRT"""
- m_api.Command.cert_show.reset_mock()
- m_api.Command.config_show.side_effect = bad_subject_base
- mock_load_cert.return_value = [IPACertificate()]
- mock_ca_subject.return_value = DN(('cn', 'Certificate Authority'),
- 'O=BAD')
framework = object()
registry.initialize(framework, config.Config)
@@ -156,26 +128,18 @@ class TestCAConnectivity(BaseTest):
assert result.result == constants.ERROR
assert result.source == 'ipahealthcheck.dogtag.ca'
assert result.check == 'DogtagCertsConnectivityCheck'
- bad = bad_subject_base[0]['result']['ipacertificatesubjectbase'][0]
- bad_subject = DN(f'CN=Certificate Authority,{bad}')
- assert DN(result.kw['subject']) == bad_subject
- assert result.kw['path'] == paths.IPA_CA_CRT
- assert result.kw['msg'] == (
- 'The CA certificate with subject {subject} was not found in {path}'
- )
+ assert result.kw.get('key') == 'ipa_ra_crt_file_missing'
+ assert result.kw.get('path') == paths.RA_AGENT_PEM
- @patch('ipaserver.install.ca.lookup_ca_subject')
- @patch('ipalib.x509.load_certificate_list_from_file')
- def test_ca_connection_down(self, mock_load_cert, mock_ca_subject):
+ @patch('ipalib.x509.load_certificate_from_file')
+ def test_ca_connection_down(self, mock_load_cert):
"""CA connectivity check with the CA down"""
m_api.Command.cert_show.side_effect = CertificateOperationError(
message='Certificate operation cannot be completed: '
'Unable to communicate with CMS (503)'
)
m_api.Command.config_show.side_effect = subject_base
- mock_load_cert.return_value = [IPACertificate()]
- mock_ca_subject.return_value = DN(('cn', 'Certificate Authority'),
- f'O={m_api.env.realm}')
+ mock_load_cert.return_value = IPACertificate()
framework = object()
registry.initialize(framework, config.Config)
@@ -192,90 +156,3 @@ class TestCAConnectivity(BaseTest):
assert result.kw.get('msg') == (
'Request for certificate failed: {error}'
)
-
- @patch('ipaserver.install.ca.lookup_ca_subject')
- @patch('ipalib.x509.load_certificate_list_from_file')
- def test_ca_connection_multiple_ok(self, mock_load_cert, mock_ca_subject):
- """CA connectivity check when cert_show returns a valid value"""
- m_api.Command.cert_show.side_effect = None
- m_api.Command.config_show.side_effect = subject_base
- m_api.Command.cert_show.return_value = {
- u'result': {u'revoked': False}
- }
- mock_load_cert.return_value = [
- IPACertificate(1, 'CN=something'),
- IPACertificate(12345),
- ]
- mock_ca_subject.return_value = DN(('cn', 'Certificate Authority'),
- f'O={m_api.env.realm}')
-
- framework = object()
- registry.initialize(framework, config.Config)
- f = DogtagCertsConnectivityCheck(registry)
-
- self.results = capture_results(f)
-
- assert len(self.results) == 1
-
- result = self.results.results[0]
- assert result.result == constants.SUCCESS
- assert result.source == 'ipahealthcheck.dogtag.ca'
-
- @patch('ipaserver.install.ca.lookup_ca_subject')
- @patch('ipalib.x509.load_certificate_list_from_file')
- def test_ca_connection_multiple_ok_reverse(self, mock_load_cert,
- mock_ca_subject):
- """CA connectivity check when cert_show returns a valid value"""
- m_api.Command.cert_show.side_effect = None
- m_api.Command.config_show.side_effect = subject_base
- m_api.Command.cert_show.return_value = {
- u'result': {u'revoked': False}
- }
- mock_load_cert.return_value = [
- IPACertificate(12345),
- IPACertificate(1, 'CN=something'),
- ]
- mock_ca_subject.return_value = DN(('cn', 'Certificate Authority'),
- f'O={m_api.env.realm}')
-
- framework = object()
- registry.initialize(framework, config.Config)
- f = DogtagCertsConnectivityCheck(registry)
-
- self.results = capture_results(f)
-
- assert len(self.results) == 1
-
- result = self.results.results[0]
- assert result.result == constants.SUCCESS
- assert result.source == 'ipahealthcheck.dogtag.ca'
-
- @patch('ipaserver.install.ca.lookup_ca_subject')
- @patch('ipalib.x509.load_certificate_list_from_file')
- def test_ca_connection_not_found(self, mock_load_cert, mock_ca_subject):
- """CA connectivity check when cert_show returns a valid value"""
- m_api.Command.cert_show.side_effect = None
- m_api.Command.config_show.side_effect = subject_base
- m_api.Command.cert_show.return_value = {
- u'result': {u'revoked': False}
- }
- mock_load_cert.return_value = [
- IPACertificate(1, 'CN=something'),
- ]
- mock_ca_subject.return_value = DN(('cn', 'Certificate Authority'),
- f'O={m_api.env.realm}')
-
- framework = object()
- registry.initialize(framework, config.Config)
- f = DogtagCertsConnectivityCheck(registry)
-
- self.results = capture_results(f)
-
- assert len(self.results) == 1
-
- result = self.results.results[0]
- assert result.result == constants.ERROR
- assert result.source == 'ipahealthcheck.dogtag.ca'
- assert result.kw['msg'] == (
- 'The CA certificate with subject {subject} was not found in {path}'
- )
--
2.41.0

@ -0,0 +1,255 @@
%global project freeipa
%global shortname healthcheck
%global longname ipa%{shortname}
%global debug_package %{nil}
%global python3dir %{_builddir}/python3-%{name}-%{version}-%{release}
%{!?python3_sitelib: %global python3_sitelib %(%{__python3} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")}
Name: ipa-healthcheck
Version: 0.12
Release: 3%{?dist}
Summary: Health check tool for IdM
BuildArch: noarch
License: GPLv3
URL: https://github.com/%{project}/freeipa-healthcheck
Source0: https://github.com/%{project}/%{name}/archive/%{version}.tar.gz#/%{version}.tar.gz
Source1: %{longname}.conf
Patch0001: 0001-Remove-ipaclustercheck.patch
Patch0002: 0002-Disable-two-failing-tests.patch
Patch0003: 0003-Fix-logging-issue-related-to-dtype.patch
Patch0004: 0004-Skip-AD-domains-with-posix-ranges-in-the-catalog-che.patch
Patch0005: 0005-Don-t-error-in-DogtagCertsConnectivityCheck-with-ext.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
Requires(post): systemd-units
Requires: %{name}-core = %{version}-%{release}
BuildRequires: python3-devel
BuildRequires: systemd-devel
%{?systemd_requires}
%description
The FreeIPA health check tool provides a set of checks to
proactively detect defects in a FreeIPA cluster.
%package -n %{name}-core
Summary: Core plugin system for healthcheck
# No Requires on %%{name} = %%{version}-%%{release} since this can be
# installed standalone
Conflicts: %{name} < 0.4
%description -n %{name}-core
Core files
%prep
%autosetup -p1 -n %{project}-%{shortname}-%{version}
%build
%py3_build
%install
%py3_install
mkdir -p %{buildroot}%{_sysconfdir}/%{longname}
install -m644 %{SOURCE1} %{buildroot}%{_sysconfdir}/%{longname}
mkdir -p %{buildroot}/%{_unitdir}
install -p -m644 %{_builddir}/%{project}-%{shortname}-%{version}/systemd/ipa-%{shortname}.service %{buildroot}%{_unitdir}
install -p -m644 %{_builddir}/%{project}-%{shortname}-%{version}/systemd/ipa-%{shortname}.timer %{buildroot}%{_unitdir}
mkdir -p %{buildroot}/%{_libexecdir}/ipa
install -p -m755 %{_builddir}/%{project}-%{shortname}-%{version}/systemd/ipa-%{shortname}.sh %{buildroot}%{_libexecdir}/ipa/
mkdir -p %{buildroot}%{_sysconfdir}/logrotate.d
install -p -m644 %{_builddir}/%{project}-%{shortname}-%{version}/logrotate/%{longname} %{buildroot}%{_sysconfdir}/logrotate.d
mkdir -p %{buildroot}/%{_localstatedir}/log/ipa/%{shortname}
mkdir -p %{buildroot}/%{_mandir}/man8
mkdir -p %{buildroot}/%{_mandir}/man5
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 | \
grep -v '^./core' | \
grep -v 'opt-1' | \
sed -e 's,\.py.*$,.*,g' | sort -u | \
sed -e 's,\./,%%{python3_sitelib}/ipahealthcheck/,g' ) >healthcheck.list
%post
%systemd_post ipa-%{shortname}.service
%preun
%systemd_preun ipa-%{shortname}.service
%postun
%systemd_postun_with_restart ipa-%{shortname}.service
%files -f healthcheck.list
%{!?_licensedir:%global license %%doc}
%license COPYING
%doc README.md
%{_bindir}/ipa-%{shortname}
%dir %{_sysconfdir}/%{longname}
%dir %{_localstatedir}/log/ipa/%{shortname}
%config(noreplace) %{_sysconfdir}/%{longname}/%{longname}.conf
%config(noreplace) %{_sysconfdir}/logrotate.d/%{longname}
%{python3_sitelib}/%{longname}-%{version}-*.egg-info/
%{python3_sitelib}/%{longname}-%{version}-*-nspkg.pth
%{_unitdir}/*
%{_libexecdir}/*
%{_mandir}/man8/*
%{_mandir}/man5/*
%files -n %{name}-core
%{!?_licensedir:%global license %%doc}
%license COPYING
%doc README.md
%{python3_sitelib}/%{longname}/core/
%changelog
* Mon Jul 24 2023 Rob Crittenden <rcritten@redhat.com> - 0.12-3
- Error in DogtagCertsConnectivityCheckCA with external CA (#2223942)
* Wed May 03 2023 Rob Crittenden <rcritten@redhat.com> - 0.12-2
- Skip AD domains with posix ranges in the catalog check (#1775199)
* Thu Dec 01 2022 Rob Crittenden <rcritten@redhat.com> - 0.12-1
- Update to upstream 0.12 (#2139529)
- Verify that the number of krb5kdc worker processes is aligned to the
number of configured CPUs (#2052930)
- IPADNSSystemRecordsCheck displays warning message for 2 expected
ipa-ca AAAA records (#2099484)
* Wed May 25 2022 Rob Crittenden <rcritten@redhat.com> - 0.7-14
- Add CLI options to healthcheck configuration file (#1872467)
* Fri Apr 29 2022 Rob Crittenden <rcritten@redhat.com> - 0.7-13
- Allow multiple file modes in the FileChecker (#2058239)
* Thu Mar 31 2022 Rob Crittenden <rcritten@redhat.com> - 0.7-12
- Use the subject base from the IPA configuration, not REALM (#2066308)
* Fri Mar 18 2022 Rob Crittenden <rcritten@redhat.com> - 0.7-11
- Add support for the DNS URI type (#2037847)
* Thu Feb 17 2022 Rob Crittenden <rcritten@redhat.com> - 0.7-10
- Don't depend on IPA status when suppressing pki checks (#2055316)
* Mon Jan 17 2022 Rob Crittenden <rcritten@redhat.com> - 0.7-9
- Don't assume the entry_point order when determining if there is a
CA installed (#2041995)
* Thu Jan 06 2022 Rob Crittenden <rcritten@redhat.com> - 0.7-8
- Suppress the CRLManager check false positive when a CA is not
configured (#1983060)
- Fix the backport of the pki.server.healthcheck suppression (#1983060)
* Thu Oct 07 2021 Rob Crittenden <rcritten@redhat.com> - 0.7-7
- ipa-healthcheck command takes some extra time to complete when dirsrv
instance is stopped (#1776687)
- ipa-healthcheck complains about pki.server.healthcheck errors even CA
is not configured on the replica (#1983060)
* Mon Jun 14 2021 Rob Crittenden <rcritten@redhat.com> - 0.7-6
- Fix patch fuzz issues, apply add'l upstream for log files (#1780020)
* Wed Jun 2 2021 Rob Crittenden <rcritten@redhat.com> - 0.7-5
- Return a user-friendly message when no issues are found (#1780062)
- Report on FIPS status (#1781107)
- Detect mismatches beteween certificates in LDAP and filesystem (#1886770)
- Verify owner/perms for important log files (#1780020)
* Tue Apr 6 2021 Rob Crittenden <rcritten@redhat.com> - 0.7-4
- Add check to validate the KRA Agent is correct (#1894781)
* Fri Dec 4 2020 Rob Crittenden <rcritten@redhat.com> - 0.7-3
- Translate result names when reading input from a json file (#1866558)
* Tue Nov 3 2020 Rob Crittenden <rcritten@redhat.com> - 0.7-2
- Fix collection of AD trust domains (#1891505)
* Tue Nov 3 2020 Rob Crittenden <rcritten@redhat.com> - 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 <rcritten@redhat.com> - 0.4-6
- The core subpackage can be installed standalone, drop the Requires
on the base package. (#1852244)
- Add Conflicts < 0.4 to to core to allow downgrading with
--allowerasing (#1852244)
* Tue Aug 4 2020 Rob Crittenden <rcritten@redhat.com> - 0.4-5
- Remove the Obsoletes < 0.4 and add same-version Requires to each
subpackage so that upgrades from 0.3 will work (#1852244)
* Thu Jan 16 2020 Rob Crittenden <rcritten@redhat.com> - 0.4-4
- Allow plugins to read contents from config during initialization (#1784037)
* Thu Dec 5 2019 Rob Crittenden <rcritten@redhat.com> - 0.4-3
- Add Obsoletes to core subpackage (#1780121)
* Mon Dec 2 2019 Rob Crittenden <rcritten@redhat.com> - 0.4-2
- Abstract processing so core package is standalone (#1771710)
* Mon Dec 2 2019 Rob Crittenden <rcritten@redhat.com> - 0.4-1
- Rebase to upstream 0.4 (#1770346)
- Create subpackage to split out core processing (#1771710)
- Correct URL (#1773512)
- Errors not translated to strings (#1752849)
- JSON output not indented by default (#1729043)
- Add dependencies to checks to avoid false-positives (#1727900)
- Verify expected DNS records (#1695125)
* Mon Aug 12 2019 Rob Crittenden <rcritten@redhat.com> - 0.3-4
- Lookup AD user by SID and not by hardcoded username (#1739500)
* Thu Aug 8 2019 Rob Crittenden <rcritten@redhat.com> - 0.3-3
- The AD trust agent and controller are not being initialized (#1738314)
* Mon Aug 5 2019 Rob Crittenden <rcritten@redhat.com> - 0.3-2
- Change DNA plugin to return WARNING if no range is set (#1737492)
* Mon Jul 29 2019 François Cami <fcami@redhat.com> - 0.3-1
- Update to upstream 0.3 (#1701351)
- Add logrotate configs + depend on anacron and logrotate (#1729207)
* Thu Jul 11 2019 François Cami <fcami@redhat.com> - 0.2-4
- Fix ipa-healthcheck.sh installation path (rhbz#1729188)
- Create and own log directory (rhbz#1729188)
* Tue Apr 30 2019 François Cami <fcami@redhat.com> - 0.2-3
- Add python3-lib389 to BRs
* Tue Apr 30 2019 François Cami <fcami@redhat.com> - 0.2-2
- Fix changelog
* Thu Apr 25 2019 Rob Crittenden <rcritten@redhat.com> - 0.2-1
- Update to upstream 0.2
* Thu Apr 4 2019 François Cami <fcami@redhat.com> - 0.1-2
- Explicitly list dependencies
* Tue Apr 2 2019 François Cami <fcami@redhat.com> - 0.1-1
- Initial package import
Loading…
Cancel
Save