[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [bridgedb/develop] Refactor script.
commit 91af6c1bbad6a71663372642c5b6531cd197e806
Author: Philipp Winter <phw@xxxxxxxxx>
Date: Tue Feb 18 10:59:14 2020 -0800
Refactor script.
---
scripts/nagios-email-check | 191 +++++++++++++++++++++++++++++++++++++++++++++
scripts/nagios_email_check | 162 --------------------------------------
2 files changed, 191 insertions(+), 162 deletions(-)
diff --git a/scripts/nagios-email-check b/scripts/nagios-email-check
new file mode 100755
index 0000000..7287646
--- /dev/null
+++ b/scripts/nagios-email-check
@@ -0,0 +1,191 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# This file is part of BridgeDB, a Tor bridge distribution system.
+#
+# This script sends an email request for bridges to BridgeDB and then checks if
+# it got a response. The result is written to STATUS_FILE, which is consumed
+# by Nagios. Whenever BridgeDB fails to respond with bridges, we will get a
+# Nagios alert.
+#
+# Run this script via crontab every three hours as follows:
+# 0 */3 * * * path/to/nagios-email-check $(cat path/to/gmail.key)
+
+
+import sys
+import smtplib
+import time
+import imaplib
+import email
+import email.utils
+
+# Standard Nagios return codes
+OK, WARNING, CRITICAL, UNKNOWN = range(4)
+
+FROM_EMAIL = "testbridgestorbrowser@xxxxxxxxx"
+TO_EMAIL = "bridges@xxxxxxxxxxxxxx"
+SMTP_SERVER = "imap.gmail.com"
+SMTP_PORT = 993
+
+MESSAGE_FROM = TO_EMAIL
+MESSAGE_BODY = "Here are your bridges:"
+
+STATUS_FILE = "/srv/bridges.torproject.org/check/status"
+
+# This will contain our test email's message ID. We later make sure that this
+# message ID is referenced in the In-Reply-To header of BridgeDB's response.
+MESSAGE_ID = None
+
+
+def log(*args, **kwargs):
+ """
+ Generic log function.
+ """
+
+ print("[+]", *args, file=sys.stderr, **kwargs)
+
+
+def get_email_response(password):
+ """
+ Open our Gmail inbox and see if we got a response.
+ """
+
+ log("Checking for email response.")
+ mail = imaplib.IMAP4_SSL(SMTP_SERVER)
+ try:
+ mail.login(FROM_EMAIL, password)
+ except Exception as e:
+ return WARNING, str(e)
+
+ mail.select("INBOX")
+
+ _, data = mail.search(None, "ALL")
+ email_ids = data[0].split()
+ if len(email_ids) == 0:
+ log("Found no response.")
+ return CRITICAL, "No emails from BridgeDB found"
+
+ return check_email(mail, email_ids)
+
+
+def check_email(mail, email_ids):
+ """
+ Check if we got our expected email response.
+ """
+
+ log("Checking {:,} emails.".format(len(email_ids)))
+ for email_id in email_ids:
+ _, data = mail.fetch(email_id, "(RFC822)")
+
+ # The variable `data` contains the full email object fetched by imaplib
+ # <https://docs.python.org/3/library/imaplib.html#imaplib.IMAP4.fetch>
+ # We are only interested in the response part containing the email
+ # envelope.
+ for response_part in data:
+ if isinstance(response_part, tuple):
+ m = str(response_part[1], "utf-8")
+ msg = email.message_from_string(m)
+ email_from = "{}".format(msg["From"])
+ email_body = "{}".format(msg.as_string())
+ email_reply_to = "{}".format(msg["In-Reply-To"])
+
+ if (MESSAGE_FROM == email_from) and \
+ (MESSAGE_BODY in email_body) and \
+ (MESSAGE_ID == email_reply_to):
+ mail.store(email_id, '+X-GM-LABELS', '\\Trash')
+ mail.expunge()
+ mail.close()
+ mail.logout()
+ log("Found correct response (referencing {})."
+ .format(MESSAGE_ID))
+ return OK, "BridgeDB's email responder works"
+ else:
+ mail.store(email_id, '+X-GM-LABELS', '\\Trash')
+ mail.expunge()
+ mail.close()
+ mail.logout()
+ log("Found no response.")
+ return WARNING, "No emails from BridgeDB found"
+
+
+def send_email_request(password):
+ """
+ Attempt to send a bridge request over Gmail.
+ """
+
+ subject = "Bridges"
+ body = "get bridges"
+
+ log("Sending email.")
+ global MESSAGE_ID
+ MESSAGE_ID = email.utils.make_msgid(idstring="test-bridgedb",
+ domain="gmail.com")
+ email_text = "From: %s\r\nTo: %s\r\nMessage-ID: %s\r\nSubject: %s\r\n" \
+ "\r\n%s" % (FROM_EMAIL, TO_EMAIL, MESSAGE_ID, subject, body)
+
+ try:
+ mail = smtplib.SMTP_SSL("smtp.gmail.com", 465)
+ mail.login(FROM_EMAIL, password)
+ mail.sendmail(FROM_EMAIL, TO_EMAIL, email_text)
+ mail.close()
+ log("Email successfully sent (message ID: %s)." % MESSAGE_ID)
+ return OK, "Sent email bridge request"
+ except Exception as e:
+ log("Error while sending email: %s" % err)
+ return UNKNOWN, str(e)
+
+
+def write_status_file(status, message):
+ """
+ Write the given `status` and `message` to our Nagios status file.
+ """
+
+ codes = {
+ 0: "OK",
+ 1: "WARNING",
+ 2: "CRITICAL",
+ 3: "UNKNOWN"
+ }
+ code = codes.get(status, UNKNOWN)
+
+ with open(STATUS_FILE, "w") as fd:
+ fd.write("{}\n{}: {}".format(code, status, message))
+ log("Wrote status='%s', message='%s' to status file." % (status, message))
+
+
+if __name__ == "__main__":
+ status, message = None, None
+
+ # Our Gmail password should be in sys.argv[1].
+
+ if len(sys.argv) == 2:
+ password = sys.argv[1]
+ else:
+ log("No email password provided.")
+ write_status_file(UNKNOWN, "No email password provided")
+ sys.exit(1)
+
+ # Send an email request to BridgeDB.
+
+ try:
+ status, message = send_email_request(password)
+ except Exception as e:
+ write_status_file(UNKNOWN, repr(e))
+ sys.exit(1)
+
+ wait_time = 60
+ log("Waiting %d seconds for a response." % wait_time)
+ time.sleep(wait_time)
+
+ # Check if we've received an email response.
+
+ try:
+ status, message = get_email_response(password)
+ except KeyboardInterrupt:
+ status, message = CRITICAL, "Caught Control-C..."
+ except Exception as e:
+ status = CRITICAL
+ message = repr(e)
+ finally:
+ write_status_file(status, message)
+ sys.exit(status)
diff --git a/scripts/nagios_email_check b/scripts/nagios_email_check
deleted file mode 100644
index 767d055..0000000
--- a/scripts/nagios_email_check
+++ /dev/null
@@ -1,162 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-#
-# This file is part of BridgeDB, a Tor bridge distribution system.
-#
-# This scripts send an email to bridgedb requesting a bridge and check if the
-# service reply with a valid bridge. A status file is written in path specified
-# by STATUS_FILE.
-#
-# The STATUS_FILE is read by nagios that will send an alert whenever bridgedb
-# will not send a valid email response.
-#
-# Run via crontab
-# Ex: */10 * * * * <path_to_bridgedb>/scripts/nagios_email_check $(cat <path_to_email_key/gmail.key)
-#
-# :authors: hiro <hiro@xxxxxxxxxxxxxx>
-# see also AUTHORS file
-#
-# :license: This is Free Software. See LICENSE for license information.
-#
-#
-
-
-import sys
-import smtplib
-import time
-import imaplib
-import email
-import time
-
-# Standard Nagios return codes
-OK, WARNING, CRITICAL, UNKNOWN = range(4)
-
-ORG_EMAIL = "@gmail.com"
-FROM_EMAIL = "test.bridges.browser" + ORG_EMAIL
-SMTP_SERVER = "imap.gmail.com"
-SMTP_PORT = 993
-
-MESSAGE_FROM = "bridges@xxxxxxxxxxxxxx"
-MESSAGE_SUBJECT = "Bridges"
-MESSAGE_BODY = "Here are your bridges:"
-
-STATUS_FILE = "/srv/bridgedb.torproject.org/check/status"
-
-# -------------------------------------------------
-#
-# Utility to read email from Gmail Using Python
-#
-# ------------------------------------------------
-
-def test_email_from_gmail(password):
- mail = imaplib.IMAP4_SSL(SMTP_SERVER)
- try:
- mail.login(FROM_EMAIL, password)
- except Exception as e:
- return WARNING, str(e)
-
- mail.select('INBOX')
-
- _, data = mail.search(None, 'ALL')
- mail_ids = data[0]
-
- id_list = mail_ids.split()
-
- status, message = check_email(id_list)
-
- return status, message
-
-
-def check_email(id_list):
- first_email_id = int(str(id_list[0], 'utf-8'))
- latest_email_id = int(str(id_list[-1], 'utf-8'))
-
- for i in range(int(latest_email_id), int(first_email_id), -1):
- _, data = mail.fetch(str(i), '(RFC822)')
-
-
- # The variable data contains the full email object fetched by imaplib
- # https://docs.python.org/3/library/imaplib.html#imaplib.IMAP4.fetch
- # We are only interested in the response part containing the email envelope.
-
- for response_part in data:
- if isinstance(response_part, tuple):
- m = str(response_part[1], 'utf-8')
- msg = email.message_from_string(m)
- email_subject = "{}".format(msg['subject'])
- email_from = "{}".format(msg['from'])
- email_body = "{}".format(msg.as_string())
-
- if (MESSAGE_FROM == email_from) and (MESSAGE_SUBJECT == email_subject) and (MESSAGE_BODY in email_body):
- mail.store(str(i), '+FLAGS', '\\Deleted')
- mail.close()
- return OK, "Bridgedb is good and sending emails with working bridges"
- else:
- mail.store(str(i), '+FLAGS', '\\Deleted')
-
- mail.close()
- return WARNING, "No emails from gettor found"
-
-
-def send_email_from_gmail(password):
- sent_from = FROM_EMAIL
- sent_to = ["{}".format(MESSAGE_FROM)]
- subject = 'Bridges'
- body = 'get bridges'
-
- email_text = """From: %s\nTo: %s\nSubject: %s\n\n%s""" % (sent_from, ", ".join(sent_to), subject, body)
-
- try:
- mail = smtplib.SMTP_SSL('smtp.gmail.com', 465)
- mail.login(sent_from, password)
- mail.sendmail(sent_from, sent_to, email_text)
- mail.close()
- return OK, "Test email sent"
- except Exception as e:
- return UNKNOWN, str(e)
-
-if __name__ == "__main__":
- status, message = None, None
-
- if len(sys.argv) == 2:
- password = sys.argv[1]
- else:
- return UNKNOWN, "Empty email password"
-
- try:
- status_file = open(STATUS_FILE, 'r')
- message = status_file.read()
- status_file.close()
- except OSError:
- status = UNKNOWN
- message = "Status file has been created {}".format(STATUS_FILE)
- status_file = open(STATUS_FILE,'w')
- status_file.write("UNKNOWN\n3: %s" % message)
- status_file.close()
-
- try:
- status, message = send_email_from_gmail(password)
- except Exception as e:
- status = UNKNOWN
- message = repr(e)
- status_file = open(STATUS_FILE,'w')
- status_file.write("UNKNOWN\n3: %s" % message)
- status_file.close()
-
- time.sleep(600)
-
- try:
- status, message = test_email_from_gmail(password)
- except KeyboardInterrupt:
- status, message = CRITICAL, "Caught Control-C..."
- except Exception as e:
- status = CRITICAL
- message = repr(e)
- finally:
- d = {0: "OK", 1: "WARNING", 2: "CRITICAL", 3: "UNKNOWN"}
- status_file = open(STATUS_FILE,'w')
- status_file.write("{}\n{}: {}" % (d[status], status, message))
-
- status_file.close()
-
- sys.exit(status)
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits