Add some bits of magic to simplify the way we yield test items

This commit is contained in:
Alexandre Aubin 2020-04-09 01:55:25 +02:00
parent 587a07a6e6
commit 3cff370c62
11 changed files with 94 additions and 77 deletions

View file

@ -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):

View file

@ -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 ?) ?

View file

@ -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

View file

@ -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):

View file

@ -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

View file

@ -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")

View file

@ -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

View file

@ -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

View file

@ -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:

View file

@ -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"
)

View file

@ -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"]]