okozachenko | cb31608 | 2021-05-07 21:30:39 +0300 | [diff] [blame] | 1 | # Email notification package
|
| 2 | # This should be upgraded by integrating with mail server to send batch
|
Oleksandr Kozachenko | 9685c15 | 2022-11-02 14:19:18 +0100 | [diff] [blame] | 3 | import staffeln.conf
|
ricolin | 66a0a9d | 2022-11-07 07:49:31 +0800 | [diff] [blame] | 4 | from oslo_log import log
|
| 5 | from staffeln.common import constants, email
|
okozachenko1203 | ef49f95 | 2022-05-16 22:27:28 +1000 | [diff] [blame] | 6 | from staffeln.common import time as xtime
|
okozachenko | cb31608 | 2021-05-07 21:30:39 +0300 | [diff] [blame] | 7 | from staffeln.conductor import backup
|
okozachenko1203 | ef49f95 | 2022-05-16 22:27:28 +1000 | [diff] [blame] | 8 | from staffeln.i18n import _
|
okozachenko | cb31608 | 2021-05-07 21:30:39 +0300 | [diff] [blame] | 9 |
|
| 10 | CONF = staffeln.conf.CONF
|
| 11 | LOG = log.getLogger(__name__)
|
| 12 |
|
| 13 |
|
| 14 | class BackupResult(object):
|
okozachenko | cb31608 | 2021-05-07 21:30:39 +0300 | [diff] [blame] | 15 | def __init__(self):
|
okozachenko | 9eae01d | 2021-05-11 16:47:27 +0300 | [diff] [blame] | 16 | pass
|
| 17 |
|
| 18 | def initialize(self):
|
okozachenko | cb31608 | 2021-05-07 21:30:39 +0300 | [diff] [blame] | 19 | self.content = ""
|
Oleksandr Kozachenko | 9685c15 | 2022-11-02 14:19:18 +0100 | [diff] [blame] | 20 | self.project_list = set()
|
okozachenko | cb31608 | 2021-05-07 21:30:39 +0300 | [diff] [blame] | 21 |
|
Oleksandr Kozachenko | 9685c15 | 2022-11-02 14:19:18 +0100 | [diff] [blame] | 22 | def add_project(self, project_id, project_name):
|
| 23 | self.project_list.add((project_id, project_name))
|
okozachenko | cb31608 | 2021-05-07 21:30:39 +0300 | [diff] [blame] | 24 |
|
| 25 | def send_result_email(self):
|
ricolin | 051cc1e | 2023-01-15 08:52:09 +0800 | [diff] [blame] | 26 | subject = "Staffeln Backup result"
|
okozachenko | cb31608 | 2021-05-07 21:30:39 +0300 | [diff] [blame] | 27 | try:
|
okozachenko1203 | fa747f2 | 2022-05-16 20:13:54 +1000 | [diff] [blame] | 28 | if len(CONF.notification.receiver) == 0:
|
ricolin | 051cc1e | 2023-01-15 08:52:09 +0800 | [diff] [blame] | 29 | LOG.info(
|
| 30 | "Directly record report in log as no receiver "
|
| 31 | "email provided. Report: %s" % self.content
|
| 32 | )
|
okozachenko1203 | fa747f2 | 2022-05-16 20:13:54 +1000 | [diff] [blame] | 33 | return
|
ricolin | 051cc1e | 2023-01-15 08:52:09 +0800 | [diff] [blame] | 34 | smtp_profile = {
|
| 35 | "src_email": CONF.notification.sender_email,
|
| 36 | "src_name": "Staffeln",
|
| 37 | "src_pwd": CONF.notification.sender_pwd,
|
| 38 | "dest_email": CONF.notification.receiver,
|
| 39 | "subject": subject,
|
| 40 | "content": self.content,
|
| 41 | "smtp_server_domain": CONF.notification.smtp_server_domain,
|
| 42 | "smtp_server_port": CONF.notification.smtp_server_port,
|
| 43 | }
|
| 44 | email.send(smtp_profile)
|
okozachenko | cb31608 | 2021-05-07 21:30:39 +0300 | [diff] [blame] | 45 | LOG.info(_("Backup result email sent"))
|
| 46 | except Exception as e:
|
okozachenko1203 | fa747f2 | 2022-05-16 20:13:54 +1000 | [diff] [blame] | 47 | LOG.error(
|
| 48 | _(
|
| 49 | "Backup result email send failed. Please check email configuration. %s"
|
| 50 | % (str(e))
|
| 51 | )
|
| 52 | )
|
okozachenko | cb31608 | 2021-05-07 21:30:39 +0300 | [diff] [blame] | 53 |
|
| 54 | def publish(self):
|
| 55 | # 1. get quota
|
| 56 | self.content = "<h3>${TIME}</h3><br>"
|
| 57 | self.content = self.content.replace("${TIME}", xtime.get_current_strtime())
|
Oleksandr Kozachenko | 9685c15 | 2022-11-02 14:19:18 +0100 | [diff] [blame] | 58 | backup_mgt = backup.Backup()
|
| 59 | project_success = {}
|
| 60 | project_failed = {}
|
ricolin | 7f3ae94 | 2022-11-14 08:09:08 +0800 | [diff] [blame] | 61 | success_tasks = backup_mgt.get_queues(
|
Oleksandr Kozachenko | 9685c15 | 2022-11-02 14:19:18 +0100 | [diff] [blame] | 62 | filters={"backup_status": constants.BACKUP_COMPLETED}
|
| 63 | )
|
ricolin | 7f3ae94 | 2022-11-14 08:09:08 +0800 | [diff] [blame] | 64 | for task in success_tasks:
|
| 65 | if task.project_id in project_success:
|
| 66 | project_success[task.project_id].append(task)
|
Oleksandr Kozachenko | 9685c15 | 2022-11-02 14:19:18 +0100 | [diff] [blame] | 67 | else:
|
ricolin | 7f3ae94 | 2022-11-14 08:09:08 +0800 | [diff] [blame] | 68 | project_success[task.project_id] = [task]
|
| 69 | failed_tasks = backup_mgt.get_queues(
|
Oleksandr Kozachenko | 9685c15 | 2022-11-02 14:19:18 +0100 | [diff] [blame] | 70 | filters={"backup_status": constants.BACKUP_FAILED}
|
| 71 | )
|
ricolin | 7f3ae94 | 2022-11-14 08:09:08 +0800 | [diff] [blame] | 72 | for task in failed_tasks:
|
| 73 | if task.project_id in project_failed:
|
| 74 | project_failed[task.project_id].append(task)
|
Oleksandr Kozachenko | 9685c15 | 2022-11-02 14:19:18 +0100 | [diff] [blame] | 75 | else:
|
ricolin | 7f3ae94 | 2022-11-14 08:09:08 +0800 | [diff] [blame] | 76 | project_failed[task.project_id] = [task]
|
Oleksandr Kozachenko | 9685c15 | 2022-11-02 14:19:18 +0100 | [diff] [blame] | 77 |
|
okozachenko | cb31608 | 2021-05-07 21:30:39 +0300 | [diff] [blame] | 78 | html = ""
|
Oleksandr Kozachenko | 9685c15 | 2022-11-02 14:19:18 +0100 | [diff] [blame] | 79 | for project_id, project_name in self.project_list:
|
| 80 | quota = backup_mgt.get_backup_quota(project_id)
|
okozachenko | cb31608 | 2021-05-07 21:30:39 +0300 | [diff] [blame] | 81 |
|
okozachenko1203 | fa747f2 | 2022-05-16 20:13:54 +1000 | [diff] [blame] | 82 | html += (
|
ricolin | 051cc1e | 2023-01-15 08:52:09 +0800 | [diff] [blame] | 83 | "<h3>Project: ${PROJECT}</h3><h3>Quota Usage</h3>"
|
| 84 | "<FONT COLOR=${QUOTA_COLLOR}><h4>Limit: ${QUOTA_LIMIT}, In Use: "
|
| 85 | "${QUOTA_IN_USE}, Reserved: ${QUOTA_RESERVED}, Total "
|
| 86 | "rate: ${QUOTA_USAGE}</h4></FONT>"
|
| 87 | "<h3>Success List</h3>"
|
| 88 | "<FONT COLOR=GREEN><h4>${SUCCESS_VOLUME_LIST}</h4></FONT><br>"
|
| 89 | "<h3>Failed List</h3>"
|
| 90 | "<FONT COLOR=RED><h4>${FAILED_VOLUME_LIST}</h4></FONT><br>"
|
okozachenko1203 | fa747f2 | 2022-05-16 20:13:54 +1000 | [diff] [blame] | 91 | )
|
okozachenko | cb31608 | 2021-05-07 21:30:39 +0300 | [diff] [blame] | 92 |
|
ricolin | 988159a | 2022-11-08 07:01:27 +0800 | [diff] [blame] | 93 | if project_id in project_success:
|
Oleksandr Kozachenko | 9685c15 | 2022-11-02 14:19:18 +0100 | [diff] [blame] | 94 | success_volumes = "<br>".join(
|
| 95 | [
|
ricolin | 2890d31 | 2023-01-16 06:58:10 +0800 | [diff] [blame] | 96 | (
|
| 97 | f"Volume ID: {str(e.volume_id)}, Backup ID: {str(e.backup_id)}, "
|
| 98 | f"Backup mode: {'Incremental' if e.incremental else 'Full'}, "
|
| 99 | f"Created at: {str(e.created_at)}, Last updated at: "
|
| 100 | f"{str(e.updated_at)}"
|
ricolin | 66a0a9d | 2022-11-07 07:49:31 +0800 | [diff] [blame] | 101 | )
|
Oleksandr Kozachenko | 9685c15 | 2022-11-02 14:19:18 +0100 | [diff] [blame] | 102 | for e in project_success[project_id]
|
| 103 | ]
|
| 104 | )
|
| 105 | else:
|
| 106 | success_volumes = "<br>"
|
ricolin | 988159a | 2022-11-08 07:01:27 +0800 | [diff] [blame] | 107 | if project_id in project_failed:
|
Oleksandr Kozachenko | 9685c15 | 2022-11-02 14:19:18 +0100 | [diff] [blame] | 108 | failed_volumes = "<br>".join(
|
| 109 | [
|
ricolin | 2890d31 | 2023-01-16 06:58:10 +0800 | [diff] [blame] | 110 | (
|
| 111 | f"Volume ID: {str(e.volume_id)}, Reason: {str(e.reason)}, "
|
| 112 | f"Created at: {str(e.created_at)}, Last updated at: "
|
| 113 | f"{str(e.updated_at)}"
|
| 114 | )
|
Oleksandr Kozachenko | 9685c15 | 2022-11-02 14:19:18 +0100 | [diff] [blame] | 115 | for e in project_failed[project_id]
|
| 116 | ]
|
| 117 | )
|
| 118 | else:
|
| 119 | failed_volumes = "<br>"
|
ricolin | 051cc1e | 2023-01-15 08:52:09 +0800 | [diff] [blame] | 120 | quota_usage = (quota["in_use"] + quota["reserved"]) / quota["limit"]
|
| 121 | if quota_usage > 0.8:
|
| 122 | quota_color = "RED"
|
| 123 | elif quota_usage > 0.5:
|
| 124 | quota_color = "YALLOW"
|
| 125 | else:
|
| 126 | quota_color = "GREEN"
|
ricolin | 2890d31 | 2023-01-16 06:58:10 +0800 | [diff] [blame] | 127 | html = html.replace("${QUOTA_USAGE}", str(quota_usage))
|
ricolin | 051cc1e | 2023-01-15 08:52:09 +0800 | [diff] [blame] | 128 | html = html.replace("${QUOTA_COLLOR}", quota_color)
|
okozachenko | cb31608 | 2021-05-07 21:30:39 +0300 | [diff] [blame] | 129 | html = html.replace("${QUOTA_LIMIT}", str(quota["limit"]))
|
| 130 | html = html.replace("${QUOTA_IN_USE}", str(quota["in_use"]))
|
| 131 | html = html.replace("${QUOTA_RESERVED}", str(quota["reserved"]))
|
| 132 | html = html.replace("${SUCCESS_VOLUME_LIST}", success_volumes)
|
| 133 | html = html.replace("${FAILED_VOLUME_LIST}", failed_volumes)
|
Oleksandr Kozachenko | 9685c15 | 2022-11-02 14:19:18 +0100 | [diff] [blame] | 134 | html = html.replace("${PROJECT}", project_name)
|
okozachenko1203 | fa747f2 | 2022-05-16 20:13:54 +1000 | [diff] [blame] | 135 | if html == "":
|
| 136 | return
|
okozachenko | cb31608 | 2021-05-07 21:30:39 +0300 | [diff] [blame] | 137 | self.content += html
|
| 138 | self.send_result_email()
|