jenkins-bot has submitted this change and it was merged. ( https://gerrit.wikimedia.org/r/343365 )
Change subject: Send failmail ...................................................................... Send failmail TODO: check the send args in tests Change-Id: I987df527c07e95b5bde31c89118d72681673d94a --- M job_wrapper.py A mailer.py M test-requirements.txt M tests/test_job_wrapper.py 4 files changed, 65 insertions(+), 9 deletions(-) Approvals: jenkins-bot: Verified Awight: Looks good to me, approved diff --git a/job_wrapper.py b/job_wrapper.py index 4813b3a..4c3cae6 100644 --- a/job_wrapper.py +++ b/job_wrapper.py @@ -7,7 +7,7 @@ import yaml import lock - +import mailer # TODO: Global config. DEFAULT_TIMEOUT = 600 @@ -21,6 +21,7 @@ self.name = self.config["name"] self.start_time = datetime.datetime.utcnow().isoformat() + self.mailer = mailer.Mailer(self.config) if "timeout" in self.config: self.timeout = self.config["timeout"] @@ -61,16 +62,23 @@ self.fail_exitcode(return_code) def fail_exitcode(self, return_code): - print("Job {name} failed with code {code}".format(name=self.name, code=return_code), file=sys.stderr) + message = "Job {name} failed with code {code}".format(name=self.name, code=return_code) + print(message, file=sys.stderr) # TODO: Prevent future jobs according to config. + self.mailer.fail_mail(message) def fail_has_stderr(self, stderr_data): - print("Job {name} printed things to stderr:".format(name=self.name), file=sys.stderr) - print(stderr_data.decode("utf-8"), file=sys.stderr) + message = "Job {name} printed things to stderr:".format(name=self.name) + print(message, file=sys.stderr) + body = stderr_data.decode("utf-8") + print(body, file=sys.stderr) + self.mailer.fail_mail(message, body) def fail_timeout(self): self.process.kill() - print("Job {name} timed out after {timeout} seconds".format(name=self.name, timeout=self.timeout), file=sys.stderr) + message = "Job {name} timed out after {timeout} seconds".format(name=self.name, timeout=self.timeout) + print(message, file=sys.stderr) + self.mailer.fail_mail(message) # FIXME: Job will return SIGKILL now, fail_exitcode should ignore that signal now? def store_job_output(self, stdout_data): diff --git a/mailer.py b/mailer.py new file mode 100644 index 0000000..526f750 --- /dev/null +++ b/mailer.py @@ -0,0 +1,36 @@ +from email.mime.text import MIMEText +import smtplib + + +class Mailer(object): + def __init__(self, config): + # defaults + self.config = { + "from_address": "Fail Mail <fr-t...@wikimedia.org>", + "to_address": "fr-t...@wikimedia.org" + } + self.config.update(config) + # FIXME: this is set to ensure one failmail per instance. Should + # do something more sophisticated to collect all calls and send + # the mail before exiting. + self.sent_fail_mail = False + + def fail_mail(self, subject, body="Hope your wits are freshly sharpened!"): + if self.sent_fail_mail: + return + + msg = MIMEText(body) + + msg["Subject"] = "Fail Mail : " + subject + msg["From"] = self.config["from_address"] + msg["To"] = self.config["to_address"] + + mailer = smtplib.SMTP("localhost") + mailer.sendmail( + self.config["from_address"], + self.config["to_address"], + msg.as_string() + ) + mailer.quit() + # only send one failmail per instance + self.sent_fail_mail = True diff --git a/test-requirements.txt b/test-requirements.txt index dbff9b7..54d3bb9 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,3 +1,4 @@ iocapture +mock nose pytest diff --git a/tests/test_job_wrapper.py b/tests/test_job_wrapper.py index 730ca2c..450a051 100644 --- a/tests/test_job_wrapper.py +++ b/tests/test_job_wrapper.py @@ -1,3 +1,4 @@ +from mock import patch import iocapture import nose import os @@ -23,17 +24,22 @@ assert captured.stderr == "" -def test_return_code(): +@patch("smtplib.SMTP") +def test_return_code(MockSmtp): + expected = "Job False job failed with code 1\n" with iocapture.capture() as captured: run_job("return_code.yaml") assert captured.stdout == "" - assert captured.stderr == "Job False job failed with code 1\n" + assert captured.stderr == expected + + MockSmtp().sendmail.assert_called_once() # Must finish in less than two seconds, i.e. must have timed out. @nose.tools.timed(2) -def test_timeout(): +@patch("smtplib.SMTP") +def test_timeout(MockSmtp): with iocapture.capture() as captured: run_job("timeout.yaml") @@ -43,8 +49,11 @@ "Job Timing out job failed with code -9\n" ) + MockSmtp().sendmail.assert_called_once() -def test_stderr(): + +@patch("smtplib.SMTP") +def test_stderr(MockSmtp): with iocapture.capture() as captured: run_job("errors.yaml") @@ -55,6 +64,8 @@ "Job Bad grep job failed with code 2\n" ) + MockSmtp().sendmail.assert_called_once() + def test_store_output(): path = "/tmp/which_out.log" -- To view, visit https://gerrit.wikimedia.org/r/343365 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I987df527c07e95b5bde31c89118d72681673d94a Gerrit-PatchSet: 7 Gerrit-Project: wikimedia/fundraising/process-control Gerrit-Branch: master Gerrit-Owner: Ejegg <eeggles...@wikimedia.org> Gerrit-Reviewer: Awight <awi...@wikimedia.org> Gerrit-Reviewer: Cdentinger <cdentin...@wikimedia.org> Gerrit-Reviewer: Ejegg <eeggles...@wikimedia.org> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits