From 3cff370c62f2150b0a306871b2258c42f01b29d1 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 9 Apr 2020 01:55:25 +0200 Subject: [PATCH] Add some bits of magic to simplify the way we yield test items --- data/hooks/diagnosis/00-basesystem.py | 37 +++++++++------------- data/hooks/diagnosis/10-ip.py | 26 +++++++-------- data/hooks/diagnosis/12-dnsrecords.py | 7 ++-- data/hooks/diagnosis/14-ports.py | 11 ++++--- data/hooks/diagnosis/21-web.py | 6 ++-- data/hooks/diagnosis/24-mail.py | 4 +-- data/hooks/diagnosis/30-services.py | 13 ++++---- data/hooks/diagnosis/50-systemresources.py | 34 +++++++++++--------- data/hooks/diagnosis/70-regenconf.py | 6 ++-- data/hooks/diagnosis/90-security.py | 6 ++-- src/yunohost/diagnosis.py | 21 ++++++++++++ 11 files changed, 94 insertions(+), 77 deletions(-) diff --git a/data/hooks/diagnosis/00-basesystem.py b/data/hooks/diagnosis/00-basesystem.py index 3c932b488..97f77cc1d 100644 --- a/data/hooks/diagnosis/00-basesystem.py +++ b/data/hooks/diagnosis/00-basesystem.py @@ -23,55 +23,48 @@ class BaseSystemDiagnoser(Diagnoser): hardware = dict(meta={"test": "hardware"}, status="INFO", data={"virt": virt, "arch": arch}, - summary=("diagnosis_basesystem_hardware", {"virt": virt, "arch": arch})) + summary="diagnosis_basesystem_hardware") if os.path.exists("/proc/device-tree/model"): model = read_file('/proc/device-tree/model').strip() - hardware["data"]["board"] = model - hardware["details"] = [("diagnosis_basesystem_hardware_board", {"model": model})] + hardware["data"]["model"] = model + hardware["details"] = ["diagnosis_basesystem_hardware_board"] yield hardware # Kernel version kernel_version = read_file('/proc/sys/kernel/osrelease').strip() yield dict(meta={"test": "kernel"}, + data={"kernel_version": kernel_version}, status="INFO", - summary=("diagnosis_basesystem_kernel", {"kernel_version": kernel_version})) + summary="diagnosis_basesystem_kernel") # Debian release debian_version = read_file("/etc/debian_version").strip() yield dict(meta={"test": "host"}, + data={"debian_version": debian_version}, status="INFO", - summary=("diagnosis_basesystem_host", {"debian_version": debian_version})) + summary="diagnosis_basesystem_host") # Yunohost packages versions - ynh_packages = ynh_packages_version() # We check if versions are consistent (e.g. all 3.6 and not 3 packages with 3.6 and the other with 3.5) # This is a classical issue for upgrades that failed in the middle # (or people upgrading half of the package because they did 'apt upgrade' instead of 'dist-upgrade') # Here, ynh_core_version is for example "3.5.4.12", so [:3] is "3.5" and we check it's the same for all packages + ynh_packages = ynh_packages_version() ynh_core_version = ynh_packages["yunohost"]["version"] consistent_versions = all(infos["version"][:3] == ynh_core_version[:3] for infos in ynh_packages.values()) ynh_version_details = [("diagnosis_basesystem_ynh_single_version", {"package":package, "version": infos["version"], "repo": infos["repo"]} - ) - for package, infos in ynh_packages.items()] + ) + for package, infos in ynh_packages.items()] - if consistent_versions: - yield dict(meta={"test": "ynh_versions"}, - data={"main_version": ynh_core_version, "repo": ynh_packages["yunohost"]["repo"]}, - status="INFO", - summary=("diagnosis_basesystem_ynh_main_version", - {"main_version": ynh_core_version, - "repo": ynh_packages["yunohost"]["repo"]}), - details=ynh_version_details) - else: - yield dict(meta={"test": "ynh_versions"}, - data={"main_version": ynh_core_version, "repo": ynh_packages["yunohost"]["repo"]}, - status="ERROR", - summary=("diagnosis_basesystem_ynh_inconsistent_versions", {}), - details=ynh_version_details) + yield dict(meta={"test": "ynh_versions"}, + data={"main_version": ynh_core_version, "repo": ynh_packages["yunohost"]["repo"]}, + status="INFO" if consistent_versions else "ERROR", + summary="diagnosis_basesystem_ynh_main_version" if consistent_versions else "diagnosis_basesystem_ynh_inconsistent_versions", + details=ynh_version_details) def main(args, env, loggers): diff --git a/data/hooks/diagnosis/10-ip.py b/data/hooks/diagnosis/10-ip.py index 7e96a7b56..3f197a7bc 100644 --- a/data/hooks/diagnosis/10-ip.py +++ b/data/hooks/diagnosis/10-ip.py @@ -28,7 +28,7 @@ class IPDiagnoser(Diagnoser): if not can_ping_ipv4 and not can_ping_ipv6: yield dict(meta={"test": "ping"}, status="ERROR", - summary=("diagnosis_ip_not_connected_at_all", {})) + summary="diagnosis_ip_not_connected_at_all") # Not much else we can do if there's no internet at all return @@ -49,20 +49,19 @@ class IPDiagnoser(Diagnoser): if not can_resolve_dns: yield dict(meta={"test": "dnsresolv"}, status="ERROR", - summary=("diagnosis_ip_broken_dnsresolution", {}) if good_resolvconf - else ("diagnosis_ip_broken_resolvconf", {})) + summary="diagnosis_ip_broken_dnsresolution" if good_resolvconf else "diagnosis_ip_broken_resolvconf") return # Otherwise, if the resolv conf is bad but we were able to resolve domain name, # still warn that we're using a weird resolv conf ... elif not good_resolvconf: yield dict(meta={"test": "dnsresolv"}, status="WARNING", - summary=("diagnosis_ip_weird_resolvconf", {}), - details=[("diagnosis_ip_weird_resolvconf_details", {})]) + summary="diagnosis_ip_weird_resolvconf", + details=["diagnosis_ip_weird_resolvconf_details"]) else: yield dict(meta={"test": "dnsresolv"}, status="SUCCESS", - summary=("diagnosis_ip_dnsresolution_working", {})) + summary="diagnosis_ip_dnsresolution_working") # ##################################################### # # IP DIAGNOSIS : Check that we're actually able to talk # @@ -72,17 +71,16 @@ class IPDiagnoser(Diagnoser): ipv4 = self.get_public_ip(4) if can_ping_ipv4 else None ipv6 = self.get_public_ip(6) if can_ping_ipv6 else None - yield dict(meta={"test": "ip", "version": '4'}, - data=ipv4, + yield dict(meta={"test": "ipv4"}, + data={"global": ipv4}, status="SUCCESS" if ipv4 else "ERROR", - summary=("diagnosis_ip_connected_ipv4", {}) if ipv4 - else ("diagnosis_ip_no_ipv4", {})) + summary="diagnosis_ip_connected_ipv4" if ipv4 else "diagnosis_ip_no_ipv4") - yield dict(meta={"test": "ip", "version": '6'}, - data=ipv6, + yield dict(meta={"test": "ipv6"}, + data={"global": ipv6}, status="SUCCESS" if ipv6 else "WARNING", - summary=("diagnosis_ip_connected_ipv6", {}) if ipv6 - else ("diagnosis_ip_no_ipv6", {})) + summary="diagnosis_ip_connected_ipv6" if ipv6 else "diagnosis_ip_no_ipv6") + # TODO / FIXME : add some attempt to detect ISP (using whois ?) ? diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index 5d8a12ebb..d653b044c 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -62,19 +62,18 @@ class DNSRecordsDiagnoser(Diagnoser): discrepancies.append(("diagnosis_dns_discrepancy", r)) if discrepancies: - discrepancies = [("diagnosis_dns_point_to_doc", {})] + discrepancies status = "ERROR" if (category == "basic" or (is_main_domain and category != "extra")) else "WARNING" - summary = ("diagnosis_dns_bad_conf", {"domain": domain, "category": category}) + summary = "diagnosis_dns_bad_conf" else: status = "SUCCESS" - summary = ("diagnosis_dns_good_conf", {"domain": domain, "category": category}) + summary = "diagnosis_dns_good_conf" output = dict(meta={"domain": domain, "category": category}, status=status, summary=summary) if discrepancies: - output["details"] = discrepancies + output["details"] = ["diagnosis_dns_point_to_doc"] + discrepancies yield output diff --git a/data/hooks/diagnosis/14-ports.py b/data/hooks/diagnosis/14-ports.py index fe7c9003d..f973a3275 100644 --- a/data/hooks/diagnosis/14-ports.py +++ b/data/hooks/diagnosis/14-ports.py @@ -47,15 +47,16 @@ class PortsDiagnoser(Diagnoser): category = services[service].get("category", "[?]") if r["ports"].get(str(port), None) is not True: yield dict(meta={"port": str(port)}, + data={"service": service, "category": category}, status="ERROR", - summary=("diagnosis_ports_unreachable", {"port": port}), - details=[("diagnosis_ports_needed_by", {"service": service, "category": category}), - ("diagnosis_ports_forwarding_tip", {})]) + summary="diagnosis_ports_unreachable", + details=["diagnosis_ports_needed_by", "diagnosis_ports_forwarding_tip"]) else: yield dict(meta={"port": str(port)}, + data={"service": service, "category": category}, status="SUCCESS", - summary=("diagnosis_ports_ok", {"port": port}), - details=[("diagnosis_ports_needed_by", {"service": service, "category": category})]) + summary="diagnosis_ports_ok", + details=["diagnosis_ports_needed_by"]) def main(args, env, loggers): diff --git a/data/hooks/diagnosis/21-web.py b/data/hooks/diagnosis/21-web.py index 6b65b8da3..5008f0360 100644 --- a/data/hooks/diagnosis/21-web.py +++ b/data/hooks/diagnosis/21-web.py @@ -45,13 +45,13 @@ class WebDiagnoser(Diagnoser): if r["status"] == "ok": yield dict(meta={"domain": domain}, status="SUCCESS", - summary=("diagnosis_http_ok", {"domain": domain})) + summary="diagnosis_http_ok") else: detail = r["code"].replace("error_http_check", "diagnosis_http") if "code" in r else "diagnosis_http_unknown_error" yield dict(meta={"domain": domain}, status="ERROR", - summary=("diagnosis_http_unreachable", {"domain": domain}), - details=[(detail,{})]) + summary="diagnosis_http_unreachable", + details=[detail]) # In there or idk where else ... # try to diagnose hairpinning situation by crafting a request for the diff --git a/data/hooks/diagnosis/24-mail.py b/data/hooks/diagnosis/24-mail.py index f0060df52..0a3a97102 100644 --- a/data/hooks/diagnosis/24-mail.py +++ b/data/hooks/diagnosis/24-mail.py @@ -17,11 +17,11 @@ class MailDiagnoser(Diagnoser): if os.system('/bin/nc -z -w2 yunohost.org 25') == 0: yield dict(meta={"test": "ougoing_port_25"}, status="SUCCESS", - summary=("diagnosis_mail_ougoing_port_25_ok",{})) + summary="diagnosis_mail_ougoing_port_25_ok") else: yield dict(meta={"test": "outgoing_port_25"}, status="ERROR", - summary=("diagnosis_mail_ougoing_port_25_blocked",{})) + summary="diagnosis_mail_ougoing_port_25_blocked") diff --git a/data/hooks/diagnosis/30-services.py b/data/hooks/diagnosis/30-services.py index 9d6879933..6217d89d3 100644 --- a/data/hooks/diagnosis/30-services.py +++ b/data/hooks/diagnosis/30-services.py @@ -17,21 +17,22 @@ class ServicesDiagnoser(Diagnoser): for service, result in sorted(all_result.items()): - item = dict(meta={"service": service}) + item = dict(meta={"service": service}, + data={"status": result["status"], "configuration": result["configuration"]}) if result["status"] != "running": item["status"] = "ERROR" - item["summary"] = ("diagnosis_services_bad_status", {"service": service, "status": result["status"]}) - item["details"] = [("diagnosis_services_bad_status_tip", {"service":service})] + item["summary"] = "diagnosis_services_bad_status" + item["details"] = ["diagnosis_services_bad_status_tip"] elif result["configuration"] == "broken": item["status"] = "WARNING" - item["summary"] = ("diagnosis_services_conf_broken", {"service": service}) - item["details"] = [(d, {}) for d in result["configuration-details"]] + item["summary"] = "diagnosis_services_conf_broken" + item["details"] = result["configuration-details"] else: item["status"] = "SUCCESS" - item["summary"] = ("diagnosis_services_running", {"service": service, "status": result["status"]}) + item["summary"] = "diagnosis_services_running" yield item diff --git a/data/hooks/diagnosis/50-systemresources.py b/data/hooks/diagnosis/50-systemresources.py index 95f58ddb7..1f0c07f47 100644 --- a/data/hooks/diagnosis/50-systemresources.py +++ b/data/hooks/diagnosis/50-systemresources.py @@ -20,17 +20,19 @@ class SystemResourcesDiagnoser(Diagnoser): ram_total_abs_MB = ram.total / (1024**2) ram_available_abs_MB = ram.available / (1024**2) ram_available_percent = round(100 * ram.available / ram.total) - item = dict(meta={"test": "ram"}) - infos = {"total_abs_MB": ram_total_abs_MB, "available_abs_MB": ram_available_abs_MB, "available_percent": ram_available_percent} + item = dict(meta={"test": "ram"}, + data={"total_abs_MB": ram_total_abs_MB, + "available_abs_MB": ram_available_abs_MB, + "available_percent": ram_available_percent}) if ram_available_abs_MB < 100 or ram_available_percent < 5: item["status"] = "ERROR" - item["summary"] = ("diagnosis_ram_verylow", infos) + item["summary"] = "diagnosis_ram_verylow" elif ram_available_abs_MB < 200 or ram_available_percent < 10: item["status"] = "WARNING" - item["summary"] = ("diagnosis_ram_low", infos) + item["summary"] = "diagnosis_ram_low" else: item["status"] = "SUCCESS" - item["summary"] = ("diagnosis_ram_ok", infos) + item["summary"] = "diagnosis_ram_ok" yield item # @@ -39,19 +41,21 @@ class SystemResourcesDiagnoser(Diagnoser): swap = psutil.swap_memory() swap_total_abs_MB = swap.total / (1024*1024) - item = dict(meta={"test": "swap"}) - infos = {"total_MB": swap_total_abs_MB} + item = dict(meta={"test": "swap"}, + data={"total_MB": swap_total_abs_MB}) if swap_total_abs_MB <= 0: item["status"] = "ERROR" - item["summary"] = ("diagnosis_swap_none", infos) + item["summary"] = "diagnosis_swap_none" elif swap_total_abs_MB <= 256: item["status"] = "WARNING" - item["summary"] = ("diagnosis_swap_notsomuch", infos) + item["summary"] = "diagnosis_swap_notsomuch" else: item["status"] = "SUCCESS" - item["summary"] = ("diagnosis_swap_ok", infos) + item["summary"] = "diagnosis_swap_ok" yield item + # FIXME : add a check that swapiness is low if swap is on a sdcard... + # # Disks usage # @@ -66,17 +70,17 @@ class SystemResourcesDiagnoser(Diagnoser): free_abs_GB = usage.free / (1024 ** 3) free_percent = 100 - usage.percent - item = dict(meta={"test": "diskusage", "mountpoint": mountpoint}) - infos = {"mountpoint": mountpoint, "device": device, "free_abs_GB": free_abs_GB, "free_percent": free_percent} + item = dict(meta={"test": "diskusage", "mountpoint": mountpoint}, + data={"device": device, "free_abs_GB": free_abs_GB, "free_percent": free_percent}) if free_abs_GB < 1 or free_percent < 5: item["status"] = "ERROR" - item["summary"] = ("diagnosis_diskusage_verylow", infos) + item["summary"] = "diagnosis_diskusage_verylow" elif free_abs_GB < 2 or free_percent < 10: item["status"] = "WARNING" - item["summary"] = ("diagnosis_diskusage_low", infos) + item["summary"] = "diagnosis_diskusage_low" else: item["status"] = "SUCCESS" - item["summary"] = ("diagnosis_diskusage_ok", infos) + item["summary"] = "diagnosis_diskusage_ok" yield item diff --git a/data/hooks/diagnosis/70-regenconf.py b/data/hooks/diagnosis/70-regenconf.py index a3e284f90..75db146ab 100644 --- a/data/hooks/diagnosis/70-regenconf.py +++ b/data/hooks/diagnosis/70-regenconf.py @@ -22,14 +22,14 @@ class RegenconfDiagnoser(Diagnoser): if regenconf_modified_files == []: yield dict(meta={"test": "regenconf"}, status="SUCCESS", - summary=("diagnosis_regenconf_allgood", {}) + summary="diagnosis_regenconf_allgood" ) else: for f in regenconf_modified_files: yield dict(meta={"test": "regenconf", "file": f}, status="WARNING", - summary=("diagnosis_regenconf_manually_modified", {"file": f}), - details=[("diagnosis_regenconf_manually_modified_details", {})] + summary="diagnosis_regenconf_manually_modified", + details=["diagnosis_regenconf_manually_modified_details"] ) #for f in debian_modified_files: diff --git a/data/hooks/diagnosis/90-security.py b/data/hooks/diagnosis/90-security.py index 1eedcc8ca..d281042b0 100644 --- a/data/hooks/diagnosis/90-security.py +++ b/data/hooks/diagnosis/90-security.py @@ -21,13 +21,13 @@ class SecurityDiagnoser(Diagnoser): if self.is_vulnerable_to_meltdown(): yield dict(meta={"test": "meltdown"}, status="ERROR", - summary=("diagnosis_security_vulnerable_to_meltdown", {}), - details=[("diagnosis_security_vulnerable_to_meltdown_details", {})] + summary="diagnosis_security_vulnerable_to_meltdown", + details=["diagnosis_security_vulnerable_to_meltdown_details"] ) else: yield dict(meta={}, status="SUCCESS", - summary=("diagnosis_security_all_good", {}) + summary="diagnosis_security_all_good" ) diff --git a/src/yunohost/diagnosis.py b/src/yunohost/diagnosis.py index 7f93f7c0d..effd610cc 100644 --- a/src/yunohost/diagnosis.py +++ b/src/yunohost/diagnosis.py @@ -453,11 +453,32 @@ class Diagnoser(): report["description"] = Diagnoser.get_description(report["id"]) + def is_tuple_or_list(stuff): + return isinstance(stuff, tuple) or isinstance(stuff, list) + for item in report["items"]: + + # For the summary and each details, we want to call + # m18n() on the string, with the appropriate data for string + # formatting which can come from : + # - infos super-specific to the summary/details (if it's a tuple(key,dict_with_info) and not just a string) + # - 'meta' info = parameters of the test (e.g. which domain/category for DNS conf record) + # - actual 'data' retrieved from the test (e.g. actual global IP, ...) + + meta_data = item.get("meta", {}).copy() + meta_data.update(item.get("data", {})) + + if not is_tuple_or_list(item["summary"]): + item["summary"] = (item["summary"], {}) summary_key, summary_args = item["summary"] + summary_args.update(meta_data) + item["summary"] = m18n.n(summary_key, **summary_args) if "details" in item: + item["details"] = [(d[0], d[1]) if is_tuple_or_list(d) else (d, {}) for d in item["details"]] + for d in item["details"]: + d[1].update(meta_data) item["details"] = [m18n.n(key, **values) for key, values in item["details"]]