From ccf246e0386f7b54bb0366eef2ca88afc7f41cab Mon Sep 17 00:00:00 2001 From: David Trattnig <david.trattnig@o94.at> Date: Fri, 30 Oct 2020 21:20:47 +0100 Subject: [PATCH] Mailer as event handler. #38 --- src/core/events.py | 11 ++-- src/{base/mail.py => plugins/mailer.py} | 86 ++++++++++++++++++++----- src/plugins/monitor.py | 12 +--- src/scheduling/fallback.py | 3 - 4 files changed, 77 insertions(+), 35 deletions(-) rename src/{base/mail.py => plugins/mailer.py} (62%) diff --git a/src/core/events.py b/src/core/events.py index 4ab14c63..8c75fac7 100644 --- a/src/core/events.py +++ b/src/core/events.py @@ -24,7 +24,7 @@ from threading import Thread from src.base.config import AuraConfig from src.base.utils import SimpleUtil as SU -from src.base.mail import AuraMailer +from src.plugins.mailer import AuraMailer from src.plugins.monitor import AuraMonitor from src.plugins.trackservice import TrackServiceHandler @@ -76,7 +76,6 @@ class EngineEventDispatcher(): config = None subscriber_registry = None - mailer = None engine = None scheduler = None monitor = None @@ -89,9 +88,13 @@ class EngineEventDispatcher(): self.subscriber_registry = dict() self.logger = logging.getLogger("AuraEngine") self.config = AuraConfig.config() - self.mailer = AuraMailer(self.config) self.engine = engine + binding = self.attach(AuraMailer) + binding.subscribe("on_critical") + binding.subscribe("on_sick") + binding.subscribe("on_resurrect") + binding = self.attach(AuraMonitor) binding.subscribe("on_boot") binding.subscribe("on_sick") @@ -314,8 +317,6 @@ class EngineEventDispatcher(): """ def func(self, subject, message, data): self.logger.debug("on_critical(..)") - if not data: data = "" - self.mailer.send_admin_mail(subject, message + "\n\n" + str(data)) self.call_event("on_critical", (subject, message, data)) thread = Thread(target = func, args = (self, subject, message, data)) diff --git a/src/base/mail.py b/src/plugins/mailer.py similarity index 62% rename from src/base/mail.py rename to src/plugins/mailer.py index e32c9090..fba65338 100644 --- a/src/base/mail.py +++ b/src/plugins/mailer.py @@ -18,8 +18,10 @@ import smtplib + from email.message import EmailMessage +from src.base.config import AuraConfig class MailingException(Exception): @@ -31,47 +33,97 @@ class MailingException(Exception): class AuraMailer(): + """ + Event handler to send emails to Aura administrators and programme coordinators. + + + """ + engine = None + mail = None + + def __init__(self, engine): + """ + Constructor + + Args: + engine (Engine): The Engine + """ + self.engine = engine + self.mail = MailService() + + + # + # METHODS + # + + + def on_sick(self, data): + """ + Called when the engine is in some unhealthy state. + """ + subject = "ERROR - Engine turned into some INVALID STATE!" + message = "There's an issue with your AURA Engine '%s':\n\n%s" % (data.get("engine_id"), data.get("status")) + self.mail.send_admin(subject, message) + + + + def on_resurrect(self, data): + """ + Called when the engine turned healthy again after being sick. + """ + subject = "OK - Engine became healthy again" + message = "Good news, things seem fine again with your AURA Engine '%s':\n\n%s" % (data.get("engine_id"), data.get("status")) + self.mail.send_admin(subject, message) + + + + def on_critical(self, subject, message, data=None): + """ + Callend when some critical event occurs + """ + if not data: data = "" + self.mail.send_admin(subject, message + "\n\n" + str(data)) + + + + +class MailService(): """ Service to send emails to Aura administrators. """ config = None + admin_mails = None - def __init__(self, config): + def __init__(self): """ - Constructor to initialize service with Aura `config`. - - Args: - config (AuraConfig): The configuration with the mail server details + Constructor """ - self.config = config - self.admin_mails = config.get("admin_mail") + self.config = AuraConfig.config() + self.admin_mails = self.config.get("admin_mail") # - # PUBLIC METHODS + # METHODS # - def send_admin_mail(self, subject, body): + + def send_admin(self, subject, body): """ Sends an email to the administrator as defined in the configuration. Args: - subject (String): The email's subject - body (String): The email's body text + subject (String): The email subject + body (String): The email body text """ admin_mails = self.admin_mails.split() for mail_to in admin_mails: - self.__send(mail_to, subject, body) - + self.send(mail_to, subject, body) - # - # PRIVATE METHODS - # - def __send(self, mail_to, subject, body): + def send(self, mail_to, subject, body): """ Sends an email to the given address. diff --git a/src/plugins/monitor.py b/src/plugins/monitor.py index 86759993..5c5bf769 100644 --- a/src/plugins/monitor.py +++ b/src/plugins/monitor.py @@ -33,7 +33,6 @@ import meta from src.base.config import AuraConfig from src.base.utils import SimpleUtil as SU -from src.base.mail import AuraMailer @@ -81,7 +80,6 @@ class AuraMonitor: self.logger = logging.getLogger("AuraEngine") self.config = AuraConfig.config() self.engine = engine - self.mailer = AuraMailer(self.config) self.status = dict() self.status["engine"] = dict() self.status["lqs"] = dict() @@ -267,22 +265,16 @@ class AuraMonitor: self.already_invalid = False status = json.dumps(self.get_status()) self.logger.info(SU.green("OK - Engine turned back into some healthy state!")+"\n"+str(status)) - self.mailer.send_admin_mail( \ - "OK - Engine turned back into some HEALTHY STATE!", \ - "Things seem fine again at '%s':\n\n%s" % (self.engine_id, status)) # Route call of event via event dispatcher to provide ability for additional hooks - self.engine.event_dispatcher.on_resurrect(status) + self.engine.event_dispatcher.on_resurrect({"engine_id": self.engine_id, "status": status}) else: # Engine turned into invalid state if not self.already_invalid: self.already_invalid = True status = json.dumps(self.get_status()) self.logger.critical(SU.red("Engine turned into some INVALID STATE!")+"\n"+str(status)) - self.mailer.send_admin_mail( \ - "ERROR - Engine turned into some INVALID STATE!", \ - "There's an issue with Aura Engine '%s':\n\n%s" % (self.engine_id, status)) # Route call of event via event dispatcher to provide ability for additional hooks - self.engine.event_dispatcher.on_sick(status) + self.engine.event_dispatcher.on_sick({"engine_id": self.engine_id, "status": status}) threading.Timer(self.config.get("heartbeat_frequency"), self.heartbeat).start() diff --git a/src/scheduling/fallback.py b/src/scheduling/fallback.py index 3ad56091..a8375e78 100644 --- a/src/scheduling/fallback.py +++ b/src/scheduling/fallback.py @@ -26,7 +26,6 @@ from datetime import timedelta from src.base.config import AuraConfig from src.base.utils import SimpleUtil as SU -from src.base.mail import AuraMailer from src.core.resources import ResourceClass from src.core.channels import Channel from src.core.control import EngineExecutor @@ -64,7 +63,6 @@ class FallbackManager: """ config = None logger = None - mailer = None scheduler = None @@ -77,7 +75,6 @@ class FallbackManager: """ self.config = AuraConfig.config() self.logger = logging.getLogger("AuraEngine") - self.mailer = AuraMailer(self.config) self.scheduler = scheduler -- GitLab