From a4a8a2f462699046ed168696d1a1e6534e62ed3c Mon Sep 17 00:00:00 2001 From: Einar Forselv Date: Wed, 4 Dec 2019 19:36:14 +0100 Subject: [PATCH] Working mail alerts + alert system tweaks --- restic_compose_backup/alerts/__init__.py | 17 ++++++++ restic_compose_backup/alerts/base.py | 12 +++--- restic_compose_backup/alerts/config.py | 20 --------- restic_compose_backup/alerts/discord.py | 11 +++-- restic_compose_backup/alerts/smtp.py | 54 +++++++++++++++++++++--- 5 files changed, 79 insertions(+), 35 deletions(-) delete mode 100644 restic_compose_backup/alerts/config.py diff --git a/restic_compose_backup/alerts/__init__.py b/restic_compose_backup/alerts/__init__.py index 5c0453a..136b044 100644 --- a/restic_compose_backup/alerts/__init__.py +++ b/restic_compose_backup/alerts/__init__.py @@ -1,8 +1,25 @@ +from restic_compose_backup.alerts.smtp import SMTPAlert +from restic_compose_backup.alerts.discord import DiscordWebhookAlert +from restic_compose_backup.config import Config + ALERT_INFO = 'INFO', ALERT_ERROR = 'ERROR' ALERT_TYPES = [ALERT_INFO, ALERT_ERROR] +BACKENDS = [SMTPAlert, DiscordWebhookAlert] def send(subject: str = None, attachment: str = None, alert_type: str = ALERT_ERROR): """Send an alert""" pass + + +def configured_alert_classes(): + """Returns a list of configured alert class instances""" + entires = [] + + for cls in BACKENDS: + instance = cls.create_from_env() + if instance: + entires.append(instance) + + return entires diff --git a/restic_compose_backup/alerts/base.py b/restic_compose_backup/alerts/base.py index 4df5ad2..2426758 100644 --- a/restic_compose_backup/alerts/base.py +++ b/restic_compose_backup/alerts/base.py @@ -1,14 +1,14 @@ -from restic_compose_backup.alerts import ALERT_INFO, ALERT_ERROR, ALERT_TYPES class BaseAlert: name = None - def __init__(self): - pass + def create_from_env(self): + return None - def create_from_config(self, config): - pass + @property + def properly_configured(self) -> bool: + return False - def send(self, self, subject=None, attachment=None, alert_type=ALERT_ERROR): + def send(self, subject: str = None, body: str = None, alert_type: str = None): pass diff --git a/restic_compose_backup/alerts/config.py b/restic_compose_backup/alerts/config.py deleted file mode 100644 index 2333c2a..0000000 --- a/restic_compose_backup/alerts/config.py +++ /dev/null @@ -1,20 +0,0 @@ -"""Check config and expose properly configured alert backends""" -from restic_compose_backup.alerts.smtp import SMTPAlert -from restic_compose_backup.alerts.discord import DiscordWebhookAlert -from restic_compose_backup.config import Config - - -BACKENDS = [SMTPAlert, DiscordWebhookAlert] - - -def configured_alert_classes(): - """Returns a list of configured alert class instances""" - config = Config() - entires = [] - - for cls in BACKENDS: - instance = cls.create_from_config(config) - if instance: - entires.append(instance) - - return entires diff --git a/restic_compose_backup/alerts/discord.py b/restic_compose_backup/alerts/discord.py index 98c3a54..3fa918b 100644 --- a/restic_compose_backup/alerts/discord.py +++ b/restic_compose_backup/alerts/discord.py @@ -7,8 +7,13 @@ class DiscordWebhookAlert(BaseAlert): def __init__(self): pass - def create_from_config(self, config): - pass + @classmethod + def create_from_env(self): + return None - def send(self, self, subject=None, attachment=None, alert_type=ALERT_ERROR): + @property + def properly_configured(self) -> bool: + return False + + def send(self, subject: str = None, attachment: str = None, alert_type: str = None): pass diff --git a/restic_compose_backup/alerts/smtp.py b/restic_compose_backup/alerts/smtp.py index 91b721e..5a9c18c 100644 --- a/restic_compose_backup/alerts/smtp.py +++ b/restic_compose_backup/alerts/smtp.py @@ -1,14 +1,56 @@ +import os +import smtplib +import logging +from email.mime.text import MIMEText + from restic_compose_backup.alerts.base import BaseAlert +logger = logging.getLogger(__name__) + class SMTPAlert(BaseAlert): name = 'smtp' - def __init__(self): - pass + def __init__(self, host, port, user, password, to): + self.host = host + self.port = port + self.user = user + self.password = password + self.to = to - def create_from_config(self, config): - pass + @classmethod + def create_from_env(cls): + instance = cls( + os.environ.get('EMAIL_HOST'), + os.environ.get('EMAIL_PORT'), + os.environ.get('EMAIL_HOST_USER'), + os.environ.get('EMAIL_HOST_PASSWORD'), + (os.environ.get('EMAIL_SEND_TO') or "").split(','), + ) + if instance.properly_configured: + return instance - def send(self, self, subject=None, attachment=None, alert_type=ALERT_ERROR): - pass + return None + + @property + def properly_configured(self) -> bool: + return self.host and self.port and self.user and self.password and len(self.to) > 0 + + def send(self, subject: str = None, body: str = None, alert_type: str = 'INFO'): + # send_mail("Hello world!") + msg = MIMEText(body) + msg['Subject'] = f"[{alert_type}] {subject}" + msg['From'] = self.user + msg['To'] = ', '.join(self.to) + + try: + logger.info("Connecting to %s port %s", self.host, self.port) + server = smtplib.SMTP_SSL(self.host, self.port) + server.ehlo() + server.login(self.user, self.password) + server.sendmail(self.user, self.to, msg.as_string()) + logger.info('Email Sent') + except Exception as ex: + logger.error(ex) + finally: + server.close()