131 lines
3.9 KiB
Go
131 lines
3.9 KiB
Go
package main
|
||
|
||
import (
|
||
"crypto/tls"
|
||
"fmt"
|
||
"log"
|
||
"net"
|
||
"net/smtp"
|
||
"sort"
|
||
"strings"
|
||
"time"
|
||
)
|
||
|
||
func filterEmailAlerts(alerts []Alert, settings EmailSettings) []Alert {
|
||
allowedSeverity, allowedSource := map[string]bool{}, map[string]bool{}
|
||
for _, value := range settings.Severities {
|
||
allowedSeverity[value] = true
|
||
}
|
||
for _, value := range settings.Sources {
|
||
allowedSource[value] = true
|
||
}
|
||
var result []Alert
|
||
for _, alert := range alerts {
|
||
if allowedSeverity[alert.Severity] && allowedSource[alert.Source] {
|
||
result = append(result, alert)
|
||
}
|
||
}
|
||
return result
|
||
}
|
||
|
||
func sendAlertEmail(settings EmailSettings, alerts []Alert, test bool) error {
|
||
subject := "Proxmox Dashboard: сводка уведомлений"
|
||
body := "Система не обнаружила выбранных активных событий."
|
||
if test {
|
||
subject = "Proxmox Dashboard: тест почты"
|
||
body = "Почтовые уведомления настроены правильно."
|
||
}
|
||
if len(alerts) > 0 {
|
||
groups := map[string][]Alert{}
|
||
for _, alert := range alerts {
|
||
groups[alert.Severity] = append(groups[alert.Severity], alert)
|
||
}
|
||
var lines []string
|
||
for _, severity := range []string{"critical", "warning", "info"} {
|
||
items := groups[severity]
|
||
if len(items) == 0 {
|
||
continue
|
||
}
|
||
title := map[string]string{"critical": "КРИТИЧЕСКИЕ", "warning": "ПРЕДУПРЕЖДЕНИЯ", "info": "ИНФОРМАЦИЯ"}[severity]
|
||
lines = append(lines, title)
|
||
sort.Slice(items, func(i, j int) bool { return items[i].Title < items[j].Title })
|
||
for _, item := range items {
|
||
lines = append(lines, fmt.Sprintf("• [%s] %s\n %s", item.Source, item.Title, item.Message))
|
||
}
|
||
}
|
||
body = strings.Join(lines, "\n\n")
|
||
subject = fmt.Sprintf("Proxmox Dashboard: событий — %d", len(alerts))
|
||
}
|
||
message := []byte("From: " + settings.From + "\r\nTo: " + settings.To + "\r\nSubject: " + subject + "\r\nMIME-Version: 1.0\r\nContent-Type: text/plain; charset=UTF-8\r\nContent-Transfer-Encoding: 8bit\r\n\r\n" + body + "\r\n")
|
||
address := net.JoinHostPort(settings.Host, fmt.Sprint(settings.Port))
|
||
var client *smtp.Client
|
||
if settings.Port == 465 {
|
||
connection, err := tls.Dial("tcp", address, &tls.Config{ServerName: settings.Host, MinVersion: tls.VersionTLS12})
|
||
if err != nil {
|
||
return err
|
||
}
|
||
client, err = smtp.NewClient(connection, settings.Host)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
} else {
|
||
var err error
|
||
client, err = smtp.Dial(address)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if ok, _ := client.Extension("STARTTLS"); ok {
|
||
if err = client.StartTLS(&tls.Config{ServerName: settings.Host, MinVersion: tls.VersionTLS12}); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
}
|
||
defer client.Close()
|
||
if settings.Username != "" {
|
||
if err := client.Auth(smtp.PlainAuth("", settings.Username, settings.Password, settings.Host)); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
if err := client.Mail(settings.From); err != nil {
|
||
return err
|
||
}
|
||
if err := client.Rcpt(settings.To); err != nil {
|
||
return err
|
||
}
|
||
writer, err := client.Data()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if _, err = writer.Write(message); err != nil {
|
||
return err
|
||
}
|
||
if err = writer.Close(); err != nil {
|
||
return err
|
||
}
|
||
return client.Quit()
|
||
}
|
||
|
||
func runEmailNotifier(collect func() (dashboardMetrics, error), store *Store) {
|
||
ticker := time.NewTicker(time.Minute)
|
||
defer ticker.Stop()
|
||
for range ticker.C {
|
||
settings := store.EmailSettings(true)
|
||
if !settings.Enabled || time.Since(store.LastEmailAt()) < time.Duration(settings.IntervalMinutes)*time.Minute {
|
||
continue
|
||
}
|
||
metrics, err := collect()
|
||
if err != nil {
|
||
continue
|
||
}
|
||
alerts := filterEmailAlerts(metrics.Alerts, settings)
|
||
if len(alerts) == 0 {
|
||
continue
|
||
}
|
||
if err := sendAlertEmail(settings, alerts, false); err != nil {
|
||
log.Printf("Не удалось отправить почтовую сводку: %v", err)
|
||
continue
|
||
}
|
||
store.SetLastEmailAt(time.Now())
|
||
}
|
||
}
|