tools.win_pg_dump_controller

Yohn Y. 2022-05-05 Parent:a22dd63ba19e Child:34db5b44491d

2:7c93b0305522 Browse Files

+ Возможность отправлять оповещения по почте

README.md win_pg_dump_controller/__main__.py win_pg_dump_controller/config.py win_pg_dump_controller/log_controller.py win_pg_dump_controller/smtp_connector.py

     1.1 --- a/README.md	Fri Feb 11 23:55:12 2022 +0300
     1.2 +++ b/README.md	Thu May 05 22:25:18 2022 +0300
     1.3 @@ -26,6 +26,7 @@
     1.4  
     1.5  * `main` - основная конфигурация скрипта
     1.6  * `common` - общие параметры заданий
     1.7 +* `smtp` - настройка оповещения через почту
     1.8  * `${Имя задания}` - параметры задания. `${Имя задания}` задаётся пользователем, чтобы ему было понятно. 
     1.9    Оно фигурирует в журналах, используется в файлах резерных копий. Поэтому есть смысл избегать в нём русских букв
    1.10    и специальных символов
    1.11 @@ -45,6 +46,14 @@
    1.12  * `keep_logs_days` - количество дней за который хранить журналы.
    1.13  
    1.14  
    1.15 +### Параметры в `smtp`
    1.16 +
    1.17 +* `smtp server` - IP или имя узла SMTP сервера
    1.18 +* `smtp port` - Порт SMTP сервера
    1.19 +* `mail from` - E-Mail источника почты
    1.20 +* `mail to` - Имя ПЯ куда отправлять письма
    1.21 +
    1.22 +
    1.23  ### Параметры `common` и раздела задач
    1.24  
    1.25  * `host_name` - имя или IP узла баз данных. По умолчанию `127.0.0.1`
     2.1 --- a/win_pg_dump_controller/__main__.py	Fri Feb 11 23:55:12 2022 +0300
     2.2 +++ b/win_pg_dump_controller/__main__.py	Thu May 05 22:25:18 2022 +0300
     2.3 @@ -4,6 +4,7 @@
     2.4  from .config import Config
     2.5  from .executor import backup
     2.6  from .error import Error
     2.7 +from .smtp_connector import MailError, MailSender
     2.8  
     2.9  config = Config()
    2.10  log_controller = LogController(config)
    2.11 @@ -24,6 +25,13 @@
    2.12      log_controller.clean()
    2.13      log(log_t('Завершено'))
    2.14  
    2.15 +    if log_controller.main_log is not None:
    2.16 +        with open(log_controller.main_log) as IN:
    2.17 +            mail_content = IN.read()
    2.18 +
    2.19 +    mail = MailSender.from_config(config)
    2.20 +    mail.sendmail(mail_content, logs=log_controller.log_files)
    2.21 +
    2.22  except Error as e:
    2.23      log.err(str(e))
    2.24      print('FAIL')
     3.1 --- a/win_pg_dump_controller/config.py	Fri Feb 11 23:55:12 2022 +0300
     3.2 +++ b/win_pg_dump_controller/config.py	Thu May 05 22:25:18 2022 +0300
     3.3 @@ -14,6 +14,7 @@
     3.4  
     3.5  COMMON_SECTION = 'common'
     3.6  MAIN = 'main'
     3.7 +SMTP = 'smtp'
     3.8  DEFAULT_PG_PORT = 5432
     3.9  
    3.10  
    3.11 @@ -74,7 +75,7 @@
    3.12  
    3.13              tmpl = cls(host_name=host_name, user_name=user_name, passwd=passwd, dst_dir=dst_dir, port=port)
    3.14  
    3.15 -        for _section in filter(lambda x: x not in (COMMON_SECTION, MAIN), config.sections()):
    3.16 +        for _section in filter(lambda x: x not in (COMMON_SECTION, MAIN, SMTP), config.sections()):
    3.17              yield tmpl.parse_section(config[_section])
    3.18  
    3.19  
    3.20 @@ -97,6 +98,18 @@
    3.21          self.tier2_store_days = _main_section.getint('tier2_store_days', 30)
    3.22          self.keep_logs_days = _main_section.getint('keep_logs_days', 30)
    3.23  
    3.24 +        self.smtp_server = None
    3.25 +        self.mail_from = None
    3.26 +        self.mail_to = None
    3.27 +        self.smtp_port = None
    3.28 +
    3.29 +        if _config.has_section(SMTP):
    3.30 +            _smtp_section = _config[SMTP]
    3.31 +            self.smtp_server = _smtp_section.get('smtp server')
    3.32 +            self.mail_from = _smtp_section.get('mail from')
    3.33 +            self.mail_to = _smtp_section.get('mail to', fallback='root')
    3.34 +            self.smtp_port = _smtp_section.getint('smtp port', fallback=25)
    3.35 +
    3.36          if not isdir(self.pg_bin_path):
    3.37              raise ConfigError(f'No valid directory with binnary files of PostgreSQL is set: {self.pg_bin_path}')
    3.38  
     4.1 --- a/win_pg_dump_controller/log_controller.py	Fri Feb 11 23:55:12 2022 +0300
     4.2 +++ b/win_pg_dump_controller/log_controller.py	Thu May 05 22:25:18 2022 +0300
     4.3 @@ -141,6 +141,8 @@
     4.4      def __init__(self, config: Config):
     4.5          self.log_dir = config.log_dir
     4.6          self.keep_logs_days = config.keep_logs_days
     4.7 +        self.log_files = []
     4.8 +        self.main_log = None
     4.9  
    4.10      @staticmethod
    4.11      def _get_timeprefix() -> str:
    4.12 @@ -148,7 +150,15 @@
    4.13  
    4.14      def get_logger(self, name: str) -> BaseLogger:
    4.15          if self.log_dir is not None:
    4.16 -            return FileLogger(p_join(self.log_dir, f'{self._get_timeprefix()} - {name}.log'), appname=name)
    4.17 +            _log_name = p_join(self.log_dir, f'{self._get_timeprefix()} - {name}.log')
    4.18 +            if name.lower() != 'main':
    4.19 +                self.log_files.append(_log_name)
    4.20 +
    4.21 +            else:
    4.22 +                self.main_log = _log_name
    4.23 +
    4.24 +            return FileLogger(_log_name, appname=name)
    4.25 +
    4.26          else:
    4.27              return NullLogger(appname=name)
    4.28  
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/win_pg_dump_controller/smtp_connector.py	Thu May 05 22:25:18 2022 +0300
     5.3 @@ -0,0 +1,63 @@
     5.4 +# coding: utf-8
     5.5 +
     5.6 +from .config import Config
     5.7 +
     5.8 +from email.message import EmailMessage
     5.9 +from smtplib import SMTP, SMTPException
    5.10 +from typing import List, Optional
    5.11 +from socket import gethostname
    5.12 +from datetime import datetime
    5.13 +from os.path import basename, exists
    5.14 +
    5.15 +
    5.16 +class MailError(Exception):
    5.17 +    pass
    5.18 +
    5.19 +
    5.20 +class MailSender(object):
    5.21 +    def __init__(self,
    5.22 +                 server: Optional[str], port: Optional[int],
    5.23 +                 mail_from: Optional[str], mail_to: Optional[str]):
    5.24 +        self.server = server
    5.25 +        self.mail_from = mail_from
    5.26 +        self.mail_to = mail_to if mail_to is not None else 'root'
    5.27 +        self.port = port if port is not None else 25
    5.28 +
    5.29 +    def sendmail(self, content: str, logs: List[str]) -> None:
    5.30 +        if self.server:
    5.31 +            msg = EmailMessage()
    5.32 +            msg['To'] = self.mail_to
    5.33 +            if self.mail_from:
    5.34 +                msg['From'] = self.mail_from
    5.35 +
    5.36 +            msg['Subject'] = f'{gethostname()}: Posgres backup - {datetime.now()}'
    5.37 +            msg.set_content(content)
    5.38 +            msg.make_mixed()
    5.39 +            for f in logs:
    5.40 +                try:
    5.41 +                    if exists(f):
    5.42 +                        msg.add_attachment(open(f).read(), filename=basename(f))
    5.43 +
    5.44 +                except IOError as e:
    5.45 +                    raise MailError(f'Error on open logfile "{f}": {e}')
    5.46 +
    5.47 +            try:
    5.48 +                s = SMTP(host=self.server, port=self.port)
    5.49 +                s.helo(gethostname())
    5.50 +                s.sendmail(
    5.51 +                    from_addr=(self.mail_from if self.mail_from is not None else ''),
    5.52 +                    to_addrs=self.mail_to,
    5.53 +                    msg=msg.as_bytes()
    5.54 +                )
    5.55 +                s.quit()
    5.56 +            except SMTPException as e:
    5.57 +                raise MailError(f'Error on sending Email: {e}')
    5.58 +
    5.59 +    @classmethod
    5.60 +    def from_config(cls, config: Config):
    5.61 +        return cls(
    5.62 +            server=config.smtp_server,
    5.63 +            mail_from=config.mail_from,
    5.64 +            mail_to=config.mail_to,
    5.65 +            port=config.smtp_port
    5.66 +        )
    5.67 \ No newline at end of file