mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
Add a --human-readable option to diagnosis_show() and a --email to diagnosis_run() to email issues found by cron job
This commit is contained in:
parent
23147161d6
commit
aecbb14aa4
3 changed files with 56 additions and 13 deletions
|
@ -1691,6 +1691,9 @@ diagnosis:
|
||||||
--share:
|
--share:
|
||||||
help: Share the logs using yunopaste
|
help: Share the logs using yunopaste
|
||||||
action: store_true
|
action: store_true
|
||||||
|
--human-readable:
|
||||||
|
help: Show a human-readable output
|
||||||
|
action: store_true
|
||||||
|
|
||||||
run:
|
run:
|
||||||
action_help: Run diagnosis
|
action_help: Run diagnosis
|
||||||
|
@ -1705,6 +1708,9 @@ diagnosis:
|
||||||
--except-if-never-ran-yet:
|
--except-if-never-ran-yet:
|
||||||
help: Don't run anything if diagnosis never ran yet ... (this is meant to be used by the webadmin)
|
help: Don't run anything if diagnosis never ran yet ... (this is meant to be used by the webadmin)
|
||||||
action: store_true
|
action: store_true
|
||||||
|
--email:
|
||||||
|
help: Send an email to root with issues found (this is meant to be used by cron job)
|
||||||
|
action: store_true
|
||||||
|
|
||||||
ignore:
|
ignore:
|
||||||
action_help: Configure some diagnosis results to be ignored and therefore not considered as actual issues
|
action_help: Configure some diagnosis results to be ignored and therefore not considered as actual issues
|
||||||
|
|
|
@ -60,7 +60,7 @@ do_pre_regen() {
|
||||||
mkdir -p $pending_dir/etc/cron.d/
|
mkdir -p $pending_dir/etc/cron.d/
|
||||||
cat > $pending_dir/etc/cron.d/yunohost-diagnosis << EOF
|
cat > $pending_dir/etc/cron.d/yunohost-diagnosis << EOF
|
||||||
SHELL=/bin/bash
|
SHELL=/bin/bash
|
||||||
0 7,19 * * * root : YunoHost Diagnosis; sleep \$((RANDOM\\%600)); yunohost diagnosis run > /dev/null
|
0 7,19 * * * root : YunoHost Automatic Diagnosis; sleep \$((RANDOM\\%600)); yunohost diagnosis run --email > /dev/null 2>/dev/null || echo "Running the automatic diagnosis failed miserably"
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
import smtplib
|
||||||
|
|
||||||
from moulinette import m18n, msettings
|
from moulinette import m18n, msettings
|
||||||
from moulinette.utils import log
|
from moulinette.utils import log
|
||||||
|
@ -41,6 +42,7 @@ DIAGNOSIS_CACHE = "/var/cache/yunohost/diagnosis/"
|
||||||
DIAGNOSIS_CONFIG_FILE = '/etc/yunohost/diagnosis.yml'
|
DIAGNOSIS_CONFIG_FILE = '/etc/yunohost/diagnosis.yml'
|
||||||
DIAGNOSIS_SERVER = "diagnosis.yunohost.org"
|
DIAGNOSIS_SERVER = "diagnosis.yunohost.org"
|
||||||
|
|
||||||
|
|
||||||
def diagnosis_list():
|
def diagnosis_list():
|
||||||
all_categories_names = [h for h, _ in _list_diagnosis_categories()]
|
all_categories_names = [h for h, _ in _list_diagnosis_categories()]
|
||||||
return {"categories": all_categories_names}
|
return {"categories": all_categories_names}
|
||||||
|
@ -65,7 +67,7 @@ def diagnosis_get(category, item):
|
||||||
return Diagnoser.get_cached_report(category, item=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, human_readable=False):
|
||||||
|
|
||||||
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"))
|
||||||
|
@ -93,7 +95,7 @@ def diagnosis_show(categories=[], issues=False, full=False, share=False):
|
||||||
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)
|
Diagnoser.i18n(report, force_remove_html_tags=share or human_readable)
|
||||||
|
|
||||||
add_ignore_flag_to_issues(report)
|
add_ignore_flag_to_issues(report)
|
||||||
if not full:
|
if not full:
|
||||||
|
@ -123,9 +125,12 @@ def diagnosis_show(categories=[], issues=False, full=False, share=False):
|
||||||
return {"url": url}
|
return {"url": url}
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
elif human_readable:
|
||||||
|
print(_dump_human_readable_reports(all_reports))
|
||||||
else:
|
else:
|
||||||
return {"reports": all_reports}
|
return {"reports": all_reports}
|
||||||
|
|
||||||
|
|
||||||
def _dump_human_readable_reports(reports):
|
def _dump_human_readable_reports(reports):
|
||||||
|
|
||||||
output = ""
|
output = ""
|
||||||
|
@ -137,16 +142,16 @@ def _dump_human_readable_reports(reports):
|
||||||
for item in report["items"]:
|
for item in report["items"]:
|
||||||
output += "[{status}] {summary}\n".format(**item)
|
output += "[{status}] {summary}\n".format(**item)
|
||||||
for detail in item.get("details", []):
|
for detail in item.get("details", []):
|
||||||
output += " - " + detail + "\n"
|
output += " - " + detail.replace("\n", "\n ") + "\n"
|
||||||
output += "\n"
|
output += "\n"
|
||||||
output += "\n\n"
|
output += "\n\n"
|
||||||
|
|
||||||
return(output)
|
return(output)
|
||||||
|
|
||||||
|
|
||||||
def diagnosis_run(categories=[], force=False, except_if_never_ran_yet=False):
|
def diagnosis_run(categories=[], force=False, except_if_never_ran_yet=False, email=False):
|
||||||
|
|
||||||
if except_if_never_ran_yet and not os.path.exists(DIAGNOSIS_CACHE):
|
if (email or except_if_never_ran_yet) and not os.path.exists(DIAGNOSIS_CACHE):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Get all the categories
|
# Get all the categories
|
||||||
|
@ -170,7 +175,7 @@ def diagnosis_run(categories=[], force=False, except_if_never_ran_yet=False):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
code, report = hook_exec(path, args={"force": force}, env=None)
|
code, report = hook_exec(path, args={"force": force}, env=None)
|
||||||
except Exception as e:
|
except Exception:
|
||||||
import traceback
|
import traceback
|
||||||
logger.error(m18n.n("diagnosis_failed_for_category", category=category, error='\n'+traceback.format_exc()))
|
logger.error(m18n.n("diagnosis_failed_for_category", category=category, error='\n'+traceback.format_exc()))
|
||||||
else:
|
else:
|
||||||
|
@ -178,10 +183,11 @@ def diagnosis_run(categories=[], force=False, except_if_never_ran_yet=False):
|
||||||
if report != {}:
|
if report != {}:
|
||||||
issues.extend([item for item in report["items"] if item["status"] in ["WARNING", "ERROR"]])
|
issues.extend([item for item in report["items"] if item["status"] in ["WARNING", "ERROR"]])
|
||||||
|
|
||||||
if issues and msettings.get("interface") == "cli":
|
if issues:
|
||||||
logger.warning(m18n.n("diagnosis_display_tip"))
|
if email:
|
||||||
|
_email_diagnosis_issues()
|
||||||
return
|
elif msettings.get("interface") == "cli":
|
||||||
|
logger.warning(m18n.n("diagnosis_display_tip"))
|
||||||
|
|
||||||
|
|
||||||
def diagnosis_ignore(add_filter=None, remove_filter=None, list=False):
|
def diagnosis_ignore(add_filter=None, remove_filter=None, list=False):
|
||||||
|
@ -318,6 +324,7 @@ def issue_matches_criterias(issue, criterias):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def add_ignore_flag_to_issues(report):
|
def add_ignore_flag_to_issues(report):
|
||||||
"""
|
"""
|
||||||
Iterate over issues in a report, and flag them as ignored if they match an
|
Iterate over issues in a report, and flag them as ignored if they match an
|
||||||
|
@ -448,7 +455,7 @@ class Diagnoser():
|
||||||
return descr if descr != key else id_
|
return descr if descr != key else id_
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def i18n(report):
|
def i18n(report, force_remove_html_tags=False):
|
||||||
|
|
||||||
# "Render" the strings with m18n.n
|
# "Render" the strings with m18n.n
|
||||||
# N.B. : we do those m18n.n right now instead of saving the already-translated report
|
# N.B. : we do those m18n.n right now instead of saving the already-translated report
|
||||||
|
@ -477,7 +484,7 @@ class Diagnoser():
|
||||||
info[1].update(meta_data)
|
info[1].update(meta_data)
|
||||||
s = m18n.n(info[0], **(info[1]))
|
s = m18n.n(info[0], **(info[1]))
|
||||||
# In cli, we remove the html tags
|
# In cli, we remove the html tags
|
||||||
if msettings.get("interface") != "api":
|
if msettings.get("interface") != "api" or force_remove_html_tags:
|
||||||
s = s.replace("<cmd>", "'").replace("</cmd>", "'")
|
s = s.replace("<cmd>", "'").replace("</cmd>", "'")
|
||||||
s = html_tags.sub('', s.replace("<br>","\n"))
|
s = html_tags.sub('', s.replace("<br>","\n"))
|
||||||
else:
|
else:
|
||||||
|
@ -547,3 +554,33 @@ def _list_diagnosis_categories():
|
||||||
hooks.append((name, info["path"]))
|
hooks.append((name, info["path"]))
|
||||||
|
|
||||||
return hooks
|
return hooks
|
||||||
|
|
||||||
|
|
||||||
|
def _email_diagnosis_issues():
|
||||||
|
from yunohost.domain import _get_maindomain
|
||||||
|
from_ = "diagnosis@%s (Automatic diagnosis)" % _get_maindomain()
|
||||||
|
to_ = "root"
|
||||||
|
subject_ = "Issues found by automatic diagnosis"
|
||||||
|
|
||||||
|
disclaimer = "The automatic diagnosis on your YunoHost server identified some issues on your server. You will find a description of the issues below. You can manage those issues in the 'Diagnosis' section in your webadmin."
|
||||||
|
|
||||||
|
content = _dump_human_readable_reports(diagnosis_show(issues=True)["reports"])
|
||||||
|
|
||||||
|
message = """\
|
||||||
|
From: %s
|
||||||
|
To: %s
|
||||||
|
Subject: %s
|
||||||
|
|
||||||
|
%s
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
%s
|
||||||
|
""" % (from_, to_, subject_, disclaimer, content)
|
||||||
|
|
||||||
|
print(message)
|
||||||
|
|
||||||
|
smtp = smtplib.SMTP("localhost")
|
||||||
|
smtp.sendmail(from_, [to_], message)
|
||||||
|
smtp.quit()
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue