From 7ec233f3bb0bd31de3e32883ac89ef6f72c36d1a Mon Sep 17 00:00:00 2001 From: Guilhem MARION Date: Mon, 10 Oct 2022 07:48:14 +1030 Subject: [PATCH] Refactor reporting to provide instant feedback on default output --- certo/__main__.py | 21 ++++++++-------- certo/checks/hostname.py | 2 +- certo/output.py | 34 -------------------------- certo/report.py | 53 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 45 deletions(-) delete mode 100644 certo/output.py create mode 100644 certo/report.py diff --git a/certo/__main__.py b/certo/__main__.py index ff20d0e..e9cf8d5 100644 --- a/certo/__main__.py +++ b/certo/__main__.py @@ -12,7 +12,7 @@ import logging from docopt import docopt from certo.checks.hostname import check_host_certificate_expiration -from certo.output import default_output, json_output +from certo.report import JSONReporter, DefaultReporter if __name__ == "__main__": args = docopt(__doc__) @@ -23,17 +23,18 @@ if __name__ == "__main__": hostnames = args.get("") days_to_expiration = int(args.get("--days-to-expiration")) - results = [] + # @todo factory + if output_as_json: + reporter = JSONReporter() + else: + reporter = DefaultReporter() + # @todo async for hs in hostnames: logging.info(f"Getting CERT from {hs}") - results.append(check_host_certificate_expiration(hs, days_to_expiration)) + reporter.add_check(check_host_certificate_expiration(hs, days_to_expiration)) - failed = list(r for r in results if not r.check_successful) + if log := reporter.report(): + print(log) - if output_as_json: - print(json_output(results)) - else: - print(default_output(results)) - - exit(len(failed)) + exit(reporter.num_failed()) diff --git a/certo/checks/hostname.py b/certo/checks/hostname.py index da62b32..7f59bd4 100644 --- a/certo/checks/hostname.py +++ b/certo/checks/hostname.py @@ -34,7 +34,7 @@ def check_host_certificate_expiration(hostname, days_to_expiration, timeout=5): hostname, False, expdate, - f"Certificate expires in {(expdate - curdate).days} days - expected more than {days_to_expiration}", + f"Certificate expires in {(expdate - curdate).days} days, expected more than {days_to_expiration}", ) return CertCheckResult( hostname, diff --git a/certo/output.py b/certo/output.py deleted file mode 100644 index a1c0395..0000000 --- a/certo/output.py +++ /dev/null @@ -1,34 +0,0 @@ -import json -from typing import List - -from certo.checks.hostname import CertCheckResult - - -def json_output(cert_check_results: List[CertCheckResult]): - def make_check_serialisable(check): - """ - Converts a CertCheckResult for json serialisation - :param check: CertCheckResult as output by checks - :return: check as dict() with appropriate type conversions for json.dumps - """ - ret = check._asdict() - if check.expiration_date: - ret["expiration_date"] = check.expiration_date.strftime("%c %Z") - return ret - - return json.dumps( - list(map(lambda check: make_check_serialisable(check), cert_check_results)), - indent=4, - ) - - -def default_output(cert_check_results: List[CertCheckResult]): - res = list() - for check in cert_check_results: - result = f"[{'PASS' if check.check_successful else 'FAIL'}] Check host {check.hostname}" - if check.debug: - result += f" - {check.debug}" - if check.expiration_date: - result += f" - Certificate expires on {check.expiration_date} {check.expiration_date.tzname()}" - res.append(result) - return "\n".join(res) diff --git a/certo/report.py b/certo/report.py new file mode 100644 index 0000000..51387ee --- /dev/null +++ b/certo/report.py @@ -0,0 +1,53 @@ +import json + + +class CheckReporter: + def __init__(self): + self.checks = list() + + def add_check(self, check): + self.checks.append(check) + + def failed(self): + return list(r for r in self.checks if not r.check_successful) + + def num_failed(self): + return len(self.failed()) + + def report(self): + ... + + +class JSONReporter(CheckReporter): + def __make_check_serialisable(check): + """ + Converts a CertCheckResult for json serialisation + :param check: CertCheckResult as output by checks + :return: check as dict() with appropriate type conversions for json.dumps + """ + ret = check._asdict() + if check.expiration_date: + ret["expiration_date"] = check.expiration_date.strftime("%c %Z") + return ret + + def report(self): + return json.dumps( + list( + map( + lambda check: JSONReporter.__make_check_serialisable(check), + self.checks, + ) + ), + indent=4, + ) + + +class DefaultReporter(CheckReporter): + def add_check(self, check): + super().add_check(check) + result = f"[{'PASS' if check.check_successful else 'FAIL'}] Check host {check.hostname}" + if check.debug: + result += f" - {check.debug}" + if check.expiration_date: + result += f" - Certificate expires on {check.expiration_date} {check.expiration_date.tzname()}" + print(result)