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 000..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 ",
+"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