Added alert email
This commit is contained in:
parent
f28ccce6a0
commit
94d45fdde6
8 changed files with 165 additions and 1 deletions
|
|
@ -96,6 +96,12 @@ go build -o auspex
|
||||||
| `cfgPrimaryDBHost` | Основная БД | `10.100.10.8` |
|
| `cfgPrimaryDBHost` | Основная БД | `10.100.10.8` |
|
||||||
| `cfgSecondaryDBHost` | Резервная БД | `10.100.13.5` |
|
| `cfgSecondaryDBHost` | Резервная БД | `10.100.13.5` |
|
||||||
| `SERVICES_TO_CHECK ` | Службы для проверки | `ansible,docker` |
|
| `SERVICES_TO_CHECK ` | Службы для проверки | `ansible,docker` |
|
||||||
|
| `EMAIL_SMTP_HOST` | Адрес почтового сервера | `smtp.example.com` |
|
||||||
|
| `EMAIL_SMTP_PORT` | Порт почтового сервера | `587` |
|
||||||
|
| `EMAIL_SMTP_USER` | Юзер для отправки | `auspex@example.com` |
|
||||||
|
| `EMAIL_SMTP_PASSWORD` | Пароль | `secret` |
|
||||||
|
| `EMAIL_FROM` | Юзер для отправки | `auspex@example.com` |
|
||||||
|
| `EMAIL_TO` | Получатели | `admin1@example.com, admin2@example.com` |
|
||||||
|
|
||||||
## Зависимости
|
## Зависимости
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -193,4 +193,9 @@ func ccCheckAndAlert(cert ccCertInfo, hostname string) {
|
||||||
} else {
|
} else {
|
||||||
log.Println("✅ Алерт успешно отправлен в Telegram")
|
log.Println("✅ Алерт успешно отправлен в Telegram")
|
||||||
}
|
}
|
||||||
|
if err := emailSendHTML("Auspex: Срок действия сертификата", message); err != nil {
|
||||||
|
log.Printf("Ошибка отправки Email: %v", err)
|
||||||
|
} else {
|
||||||
|
log.Println("✅ Алерт успешно отправлен на Email")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
53
config.go
53
config.go
|
|
@ -27,6 +27,16 @@ var (
|
||||||
cfgTelegramChatID = ""
|
cfgTelegramChatID = ""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// --- Email / SMTP ---
|
||||||
|
var (
|
||||||
|
cfgEmailSMTPHost = ""
|
||||||
|
cfgEmailSMTPPort = 587
|
||||||
|
cfgEmailSMTPUser = ""
|
||||||
|
cfgEmailSMTPPassword = ""
|
||||||
|
cfgEmailFrom = ""
|
||||||
|
cfgEmailTo = []string{}
|
||||||
|
)
|
||||||
|
|
||||||
// --- PostgreSQL Database ---
|
// --- PostgreSQL Database ---
|
||||||
var (
|
var (
|
||||||
cfgDBUser = ""
|
cfgDBUser = ""
|
||||||
|
|
@ -247,6 +257,36 @@ func applyConfig(env map[string]string) {
|
||||||
}
|
}
|
||||||
cfgServicesToCheck = services
|
cfgServicesToCheck = services
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Email / SMTP
|
||||||
|
if v, ok := env["EMAIL_SMTP_HOST"]; ok && v != "" {
|
||||||
|
cfgEmailSMTPHost = v
|
||||||
|
}
|
||||||
|
if v, ok := env["EMAIL_SMTP_PORT"]; ok && v != "" {
|
||||||
|
if port, err := strconv.Atoi(v); err == nil {
|
||||||
|
cfgEmailSMTPPort = port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if v, ok := env["EMAIL_SMTP_USER"]; ok && v != "" {
|
||||||
|
cfgEmailSMTPUser = v
|
||||||
|
}
|
||||||
|
if v, ok := env["EMAIL_SMTP_PASSWORD"]; ok && v != "" {
|
||||||
|
cfgEmailSMTPPassword = v
|
||||||
|
}
|
||||||
|
if v, ok := env["EMAIL_FROM"]; ok && v != "" {
|
||||||
|
cfgEmailFrom = v
|
||||||
|
}
|
||||||
|
if v, ok := env["EMAIL_TO"]; ok && v != "" {
|
||||||
|
parts := strings.Split(v, ",")
|
||||||
|
recipients := make([]string, 0, len(parts))
|
||||||
|
for _, s := range parts {
|
||||||
|
s = strings.TrimSpace(s)
|
||||||
|
if s != "" {
|
||||||
|
recipients = append(recipients, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cfgEmailTo = recipients
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
@ -260,6 +300,12 @@ func isTelegramConfigured() bool {
|
||||||
cfgTelegramChatID != "YOUR_CHAT_ID"
|
cfgTelegramChatID != "YOUR_CHAT_ID"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isEmailConfigured() bool {
|
||||||
|
return cfgEmailSMTPHost != "" &&
|
||||||
|
cfgEmailFrom != "" &&
|
||||||
|
len(cfgEmailTo) > 0
|
||||||
|
}
|
||||||
|
|
||||||
// printConfigStatus выводит статус загруженной конфигурации
|
// printConfigStatus выводит статус загруженной конфигурации
|
||||||
func printConfigStatus() {
|
func printConfigStatus() {
|
||||||
fmt.Println("📋 Статус конфигурации:")
|
fmt.Println("📋 Статус конфигурации:")
|
||||||
|
|
@ -278,6 +324,13 @@ func printConfigStatus() {
|
||||||
fmt.Println(" ⚠️ База данных: не настроена")
|
fmt.Println(" ⚠️ База данных: не настроена")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Email
|
||||||
|
if isEmailConfigured() {
|
||||||
|
fmt.Printf(" ✅ Email: %s → %s (smtp: %s:%d)\n", cfgEmailFrom, strings.Join(cfgEmailTo, ", "), cfgEmailSMTPHost, cfgEmailSMTPPort)
|
||||||
|
} else {
|
||||||
|
fmt.Println(" ⚠️ Email: не настроен (EMAIL_SMTP_HOST, EMAIL_FROM, EMAIL_TO)")
|
||||||
|
}
|
||||||
|
|
||||||
// Services
|
// Services
|
||||||
if len(cfgServicesToCheck) > 0 {
|
if len(cfgServicesToCheck) > 0 {
|
||||||
fmt.Printf(" ✅ Службы для проверки: %s\n", strings.Join(cfgServicesToCheck, ", "))
|
fmt.Printf(" ✅ Службы для проверки: %s\n", strings.Join(cfgServicesToCheck, ", "))
|
||||||
|
|
|
||||||
|
|
@ -502,6 +502,11 @@ func dcSendAlert(hostname string, changes []dcStateChange) {
|
||||||
} else {
|
} else {
|
||||||
log.Println("✅ Алерт успешно отправлен в Telegram")
|
log.Println("✅ Алерт успешно отправлен в Telegram")
|
||||||
}
|
}
|
||||||
|
if err := emailSendHTML("Auspex: Проблемы с контейнерами", message); err != nil {
|
||||||
|
log.Printf("❌ Ошибка отправки Email: %v", err)
|
||||||
|
} else {
|
||||||
|
log.Println("✅ Алерт успешно отправлен на Email")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Вспомогательные функции ──────────────────────────────────────────────────
|
// ── Вспомогательные функции ──────────────────────────────────────────────────
|
||||||
|
|
|
||||||
85
email.go
Normal file
85
email.go
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/smtp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// emailSendHTML отправляет HTML-письмо через SMTP.
|
||||||
|
// Telegram-совместимые теги (<b>, <code>, <i>) корректно отображаются в HTML-письме.
|
||||||
|
// Если email не настроен или произошла ошибка — пишет в лог и не паникует.
|
||||||
|
func emailSendHTML(subject, message string) error {
|
||||||
|
// Проверяем минимально необходимые параметры
|
||||||
|
if !isEmailConfigured() {
|
||||||
|
log.Printf("[Email] Не настроен (нужны EMAIL_SMTP_HOST, EMAIL_FROM, EMAIL_TO) — пропускаем")
|
||||||
|
return fmt.Errorf("email не настроен")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Предупреждаем если авторизация неполная — попытку всё равно делаем,
|
||||||
|
// некоторые SMTP-серверы работают без auth (например внутренние relay)
|
||||||
|
if cfgEmailSMTPUser == "" && cfgEmailSMTPPassword == "" {
|
||||||
|
log.Printf("[Email] ⚠️ EMAIL_SMTP_USER и EMAIL_SMTP_PASSWORD не заданы — попытка без авторизации")
|
||||||
|
} else if cfgEmailSMTPUser == "" {
|
||||||
|
log.Printf("[Email] ⚠️ EMAIL_SMTP_USER не задан — авторизация невозможна, попытка без неё")
|
||||||
|
} else if cfgEmailSMTPPassword == "" {
|
||||||
|
log.Printf("[Email] ⚠️ EMAIL_SMTP_PASSWORD не задан — авторизация невозможна, попытка без неё")
|
||||||
|
}
|
||||||
|
|
||||||
|
body := emailBuildHTML(subject, message)
|
||||||
|
addr := fmt.Sprintf("%s:%d", cfgEmailSMTPHost, cfgEmailSMTPPort)
|
||||||
|
|
||||||
|
var auth smtp.Auth
|
||||||
|
if cfgEmailSMTPUser != "" && cfgEmailSMTPPassword != "" {
|
||||||
|
auth = smtp.PlainAuth("", cfgEmailSMTPUser, cfgEmailSMTPPassword, cfgEmailSMTPHost)
|
||||||
|
}
|
||||||
|
|
||||||
|
header := strings.Join([]string{
|
||||||
|
"From: " + cfgEmailFrom,
|
||||||
|
"To: " + strings.Join(cfgEmailTo, ", "),
|
||||||
|
"Subject: " + subject,
|
||||||
|
"MIME-Version: 1.0",
|
||||||
|
"Content-Type: text/html; charset=UTF-8",
|
||||||
|
"",
|
||||||
|
}, "\r\n")
|
||||||
|
|
||||||
|
msg := []byte(header + "\r\n" + body)
|
||||||
|
|
||||||
|
log.Printf("[Email] Отправка: %s → %s (smtp: %s)", cfgEmailFrom, strings.Join(cfgEmailTo, ", "), addr)
|
||||||
|
|
||||||
|
if err := smtp.SendMail(addr, auth, cfgEmailFrom, cfgEmailTo, msg); err != nil {
|
||||||
|
return fmt.Errorf("ошибка отправки письма (smtp: %s): %w", addr, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// emailBuildHTML оборачивает тело сообщения в HTML-шаблон письма.
|
||||||
|
// Telegram-теги уже являются валидным HTML, поэтому конвертация не нужна.
|
||||||
|
func emailBuildHTML(subject, body string) string {
|
||||||
|
// Заменяем переносы строк на <br> для корректного отображения в письме
|
||||||
|
htmlBody := strings.ReplaceAll(body, "\n", "<br>\n")
|
||||||
|
|
||||||
|
return fmt.Sprintf(`<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>%s</title>
|
||||||
|
<style>
|
||||||
|
body { font-family: Arial, sans-serif; font-size: 14px; color: #222; background: #f9f9f9; padding: 20px; }
|
||||||
|
.card { background: #fff; border: 1px solid #ddd; border-radius: 6px; padding: 20px; max-width: 640px; }
|
||||||
|
b { color: #c0392b; }
|
||||||
|
code { background: #f0f0f0; padding: 2px 5px; border-radius: 3px; font-family: monospace; font-size: 13px; }
|
||||||
|
i { color: #555; }
|
||||||
|
.footer { margin-top: 16px; font-size: 12px; color: #999; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="card">
|
||||||
|
%s
|
||||||
|
<div class="footer">Auspex v%s — мониторинг инфраструктуры</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>`, subject, htmlBody, appVersion)
|
||||||
|
}
|
||||||
|
|
@ -477,4 +477,9 @@ func lcSendAlerts(hostname string, staleFiles []lcLogFileStatus) {
|
||||||
} else {
|
} else {
|
||||||
log.Println("✅ Алерт успешно отправлен в Telegram")
|
log.Println("✅ Алерт успешно отправлен в Telegram")
|
||||||
}
|
}
|
||||||
|
if err := emailSendHTML("Auspex: Устаревшие логи", message); err != nil {
|
||||||
|
log.Printf("❌ Ошибка отправки Email: %v", err)
|
||||||
|
} else {
|
||||||
|
log.Println("✅ Алерт успешно отправлен на Email")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
main.go
2
main.go
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const appVersion = "1.2.0"
|
const appVersion = "1.3.0"
|
||||||
|
|
||||||
// Цвета терминала (общие для всех модулей)
|
// Цвета терминала (общие для всех модулей)
|
||||||
const (
|
const (
|
||||||
|
|
|
||||||
|
|
@ -313,6 +313,11 @@ func scSendAlert(hostname string, changes []scStateChange) {
|
||||||
} else {
|
} else {
|
||||||
log.Println("✅ Алерт успешно отправлен в Telegram")
|
log.Println("✅ Алерт успешно отправлен в Telegram")
|
||||||
}
|
}
|
||||||
|
if err := emailSendHTML("Auspex: Проблемы со службами", message); err != nil {
|
||||||
|
log.Printf("❌ Ошибка отправки Email: %v", err)
|
||||||
|
} else {
|
||||||
|
log.Println("✅ Алерт успешно отправлен на Email")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Вспомогательные функции ──────────────────────────────────────────────────
|
// ── Вспомогательные функции ──────────────────────────────────────────────────
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue