Add a 'yunohost diagnosis get' to get one specific raw info

This commit is contained in:
Alexandre Aubin 2020-04-07 00:16:18 +02:00
parent 7cfd553c3f
commit 8e83f8aa29
4 changed files with 70 additions and 27 deletions

View file

@ -1676,7 +1676,7 @@ diagnosis:
action: store_true action: store_true
run: run:
action_help: Show most recents diagnosis results action_help: Run diagnosis
api: POST /diagnosis/run api: POST /diagnosis/run
arguments: arguments:
categories: categories:
@ -1701,3 +1701,14 @@ diagnosis:
--list: --list:
help: List active ignore filters help: List active ignore filters
action: store_true action: store_true
get:
action_help: Low-level command to fetch raw data and status about a specific diagnosis test
api: GET /diagnosis/item/<category>
arguments:
category:
help: Diagnosis category to fetch results from
item:
help: "List of criteria describing the test. Must correspond exactly to the 'meta' infos in 'yunohost diagnosis show'"
metavar: CRITERIA
nargs: "*"

View file

@ -72,13 +72,13 @@ class IPDiagnoser(Diagnoser):
ipv4 = self.get_public_ip(4) if can_ping_ipv4 else None ipv4 = self.get_public_ip(4) if can_ping_ipv4 else None
ipv6 = self.get_public_ip(6) if can_ping_ipv6 else None ipv6 = self.get_public_ip(6) if can_ping_ipv6 else None
yield dict(meta={"test": "ip", "version": 4}, yield dict(meta={"test": "ip", "version": '4'},
data=ipv4, data=ipv4,
status="SUCCESS" if ipv4 else "ERROR", status="SUCCESS" if ipv4 else "ERROR",
summary=("diagnosis_ip_connected_ipv4", {}) if ipv4 summary=("diagnosis_ip_connected_ipv4", {}) if ipv4
else ("diagnosis_ip_no_ipv4", {})) else ("diagnosis_ip_no_ipv4", {}))
yield dict(meta={"test": "ip", "version": 6}, yield dict(meta={"test": "ip", "version": '6'},
data=ipv6, data=ipv6,
status="SUCCESS" if ipv6 else "WARNING", status="SUCCESS" if ipv6 else "WARNING",
summary=("diagnosis_ip_connected_ipv6", {}) if ipv6 summary=("diagnosis_ip_connected_ipv6", {}) if ipv6

View file

@ -46,12 +46,12 @@ class PortsDiagnoser(Diagnoser):
for port, service in sorted(ports.items()): for port, service in sorted(ports.items()):
category = services[service].get("category", "[?]") category = services[service].get("category", "[?]")
if r["ports"].get(str(port), None) is not True: if r["ports"].get(str(port), None) is not True:
yield dict(meta={"port": port, "needed_by": service}, yield dict(meta={"port": str(port)},
status="ERROR", status="ERROR",
summary=("diagnosis_ports_unreachable", {"port": port}), summary=("diagnosis_ports_unreachable", {"port": port}),
details=[("diagnosis_ports_needed_by", (service, category)), ("diagnosis_ports_forwarding_tip", ())]) details=[("diagnosis_ports_needed_by", (service, category)), ("diagnosis_ports_forwarding_tip", ())])
else: else:
yield dict(meta={"port": port, "needed_by": service}, yield dict(meta={"port": str(port)},
status="SUCCESS", status="SUCCESS",
summary=("diagnosis_ports_ok", {"port": port}), summary=("diagnosis_ports_ok", {"port": port}),
details=[("diagnosis_ports_needed_by", (service, category))]) details=[("diagnosis_ports_needed_by", (service, category))])

View file

@ -44,6 +44,25 @@ def diagnosis_list():
return {"categories": all_categories_names} return {"categories": all_categories_names}
def diagnosis_get(category, item):
# Get all the categories
all_categories = _list_diagnosis_categories()
all_categories_names = [c for c, _ in all_categories]
if category not in all_categories_names:
raise YunohostError('diagnosis_unknown_categories', categories=category)
if isinstance(item, list):
if any("=" not in criteria for criteria in item):
raise YunohostError("Criterias should be of the form key=value (e.g. domain=yolo.test)")
# Convert the provided criteria into a nice dict
item = {c.split("=")[0]: c.split("=")[1] for c in item}
return Diagnoser.get_cached_report(category, item=item)
def diagnosis_show(categories=[], issues=False, full=False, share=False): def diagnosis_show(categories=[], issues=False, full=False, share=False):
# Get all the categories # Get all the categories
@ -56,7 +75,7 @@ def diagnosis_show(categories=[], issues=False, full=False, share=False):
else: else:
unknown_categories = [c for c in categories if c not in all_categories_names] unknown_categories = [c for c in categories if c not in all_categories_names]
if unknown_categories: if unknown_categories:
raise YunohostError('diagnosis_unknown_categories', categories=", ".join(categories)) raise YunohostError('diagnosis_unknown_categories', categories=", ".join(unknown_categories))
if not os.path.exists(DIAGNOSIS_CACHE): if not os.path.exists(DIAGNOSIS_CACHE):
logger.warning(m18n.n("diagnosis_never_ran_yet")) logger.warning(m18n.n("diagnosis_never_ran_yet"))
@ -65,20 +84,15 @@ def diagnosis_show(categories=[], issues=False, full=False, share=False):
# Fetch all reports # Fetch all reports
all_reports = [] all_reports = []
for category in categories: for category in categories:
if not os.path.exists(Diagnoser.cache_file(category)):
logger.warning(m18n.n("diagnosis_no_cache", category=category))
report = {"id": category,
"cached_for": -1,
"timestamp": -1,
"items": []}
Diagnoser.i18n(report)
else:
try: try:
report = Diagnoser.get_cached_report(category) report = Diagnoser.get_cached_report(category)
except Exception as e: except Exception as e:
logger.error(m18n.n("diagnosis_failed", category=category, error=str(e))) logger.error(m18n.n("diagnosis_failed", category=category, error=str(e)))
continue continue
Diagnoser.i18n(report)
add_ignore_flag_to_issues(report) add_ignore_flag_to_issues(report)
if not full: if not full:
del report["timestamp"] del report["timestamp"]
@ -221,7 +235,7 @@ def diagnosis_ignore(add_filter=None, remove_filter=None, list=False):
if category not in all_categories_names: if category not in all_categories_names:
raise YunohostError("%s is not a diagnosis category" % category) raise YunohostError("%s is not a diagnosis category" % category)
if any("=" not in criteria for criteria in filter_[1:]): if any("=" not in criteria for criteria in filter_[1:]):
raise YunohostError("Extra criterias should be of the form key=value (e.g. domain=yolo.test)") raise YunohostError("Criterias should be of the form key=value (e.g. domain=yolo.test)")
# Convert the provided criteria into a nice dict # Convert the provided criteria into a nice dict
criterias = {c.split("=")[0]: c.split("=")[1] for c in filter_[1:]} criterias = {c.split("=")[0]: c.split("=")[1] for c in filter_[1:]}
@ -356,7 +370,12 @@ class Diagnoser():
for dependency in self.dependencies: for dependency in self.dependencies:
dep_report = Diagnoser.get_cached_report(dependency) dep_report = Diagnoser.get_cached_report(dependency)
if dep_report["timestamp"] == -1: # No cache yet for this dep
dep_errors = True
else:
dep_errors = [item for item in dep_report["items"] if item["status"] == "ERROR"] dep_errors = [item for item in dep_report["items"] if item["status"] == "ERROR"]
if dep_errors: if dep_errors:
logger.error(m18n.n("diagnosis_cant_run_because_of_dep", category=self.description, dep=Diagnoser.get_description(dependency))) logger.error(m18n.n("diagnosis_cant_run_because_of_dep", category=self.description, dep=Diagnoser.get_description(dependency)))
return 1, {} return 1, {}
@ -396,11 +415,24 @@ class Diagnoser():
return os.path.join(DIAGNOSIS_CACHE, "%s.json" % id_) return os.path.join(DIAGNOSIS_CACHE, "%s.json" % id_)
@staticmethod @staticmethod
def get_cached_report(id_): def get_cached_report(id_, item=None):
filename = Diagnoser.cache_file(id_) cache_file = Diagnoser.cache_file(id_)
report = read_json(filename) if not os.path.exists(cache_file):
report["timestamp"] = int(os.path.getmtime(filename)) logger.warning(m18n.n("diagnosis_no_cache", category=id_))
Diagnoser.i18n(report) report = {"id": category,
"cached_for": -1,
"timestamp": -1,
"items": []}
else:
report = read_json(cache_file)
report["timestamp"] = int(os.path.getmtime(cache_file))
if item:
for report_item in report["items"]:
if report_item.get("meta") == item:
return report_item
return {}
else:
return report return report
@staticmethod @staticmethod