feat: add email notification for failed and success backup

This commit is contained in:
Jonas Kaninda
2024-10-09 22:39:44 +02:00
parent 45826d19cd
commit 4a43a28888
13 changed files with 480 additions and 85 deletions

42
utils/config.go Normal file
View File

@@ -0,0 +1,42 @@
package utils
import "os"
type MailConfig struct {
MailHost string
MailPort int
MailUserName string
MailPassword string
MailTo string
MailFrom string
SkipTls bool
}
type NotificationData struct {
File string
BackupSize int64
Database string
StartTime string
EndTime string
Storage string
BackupLocation string
}
type ErrorMessage struct {
Database string
EndTime string
Error string
}
func loadMailConfig() *MailConfig {
return &MailConfig{
MailHost: os.Getenv("MAIL_HOST"),
MailPort: GetIntEnv("MAIL_PORT"),
MailUserName: os.Getenv("MAIL_USERNAME"),
MailPassword: os.Getenv("MAIL_PASSWORD"),
MailTo: os.Getenv("MAIL_TO"),
MailFrom: os.Getenv("MAIL_FROM"),
SkipTls: os.Getenv("MAIL_SKIP_TLS") == "false",
}
}
const templatePath = "/config/templates"

163
utils/notification.go Normal file
View File

@@ -0,0 +1,163 @@
package utils
import (
"bytes"
"crypto/tls"
"encoding/json"
"fmt"
"github.com/go-mail/mail"
"github.com/robfig/cron/v3"
"html/template"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"strings"
"time"
)
func parseTemplate[T any](data T, fileName string) (string, error) {
// Open the file
tmpl, err := template.ParseFiles(filepath.Join(templatePath, fileName))
if err != nil {
return "", err
}
var buf bytes.Buffer
if err = tmpl.Execute(&buf, data); err != nil {
return "", err
}
return buf.String(), nil
}
func SendEmail(subject, body string) {
Info("Start sending email....")
config := loadMailConfig()
emails := strings.Split(config.MailTo, ",")
m := mail.NewMessage()
m.SetHeader("From", config.MailFrom)
m.SetHeader("To", emails...)
m.SetHeader("Subject", subject)
m.SetBody("text/html", body)
d := mail.NewDialer(config.MailHost, config.MailPort, config.MailUserName, config.MailPassword)
d.TLSConfig = &tls.Config{InsecureSkipVerify: config.SkipTls}
if err := d.DialAndSend(m); err != nil {
Fatal("Error could not send email : %v", err)
}
Info("Email has been sent")
}
func sendMessage(msg string) {
Info("Sending notification... ")
chatId := os.Getenv("TG_CHAT_ID")
body, _ := json.Marshal(map[string]string{
"chat_id": chatId,
"text": msg,
})
url := fmt.Sprintf("%s/sendMessage", getTgUrl())
// Create an HTTP post request
request, err := http.NewRequest("POST", url, bytes.NewBuffer(body))
if err != nil {
panic(err)
}
request.Header.Add("Content-Type", "application/json")
client := &http.Client{}
response, err := client.Do(request)
if err != nil {
panic(err)
}
code := response.StatusCode
if code == 200 {
Info("Notification has been sent")
} else {
body, _ := ioutil.ReadAll(response.Body)
Fatal("Error could not send message, error: %s", string(body))
}
}
func NotifySuccess(notificationData *NotificationData) {
var vars = []string{
"TG_TOKEN",
"TG_CHAT_ID",
}
var mailVars = []string{
"MAIL_HOST",
"MAIL_PORT",
"MAIL_USERNAME",
"MAIL_PASSWORD",
"MAIL_FROM",
"MAIL_TO",
}
//Email notification
err := CheckEnvVars(mailVars)
if err == nil {
body, err := parseTemplate(*notificationData, "email.template")
if err != nil {
Error("Could not parse email template: %v", err)
}
SendEmail(fmt.Sprintf("✅ Database Backup Notification %s", notificationData.Database), body)
}
//Telegram notification
err = CheckEnvVars(vars)
if err == nil {
message, err := parseTemplate(*notificationData, "telegram.template")
if err != nil {
Error("Could not parse email template: %v", err)
}
sendMessage(message)
}
}
func NotifyError(error string) {
var vars = []string{
"TG_TOKEN",
"TG_CHAT_ID",
}
var mailVars = []string{
"MAIL_HOST",
"MAIL_PORT",
"MAIL_USERNAME",
"MAIL_PASSWORD",
"MAIL_FROM",
"MAIL_TO",
}
//Email notification
err := CheckEnvVars(mailVars)
if err == nil {
body, err := parseTemplate(ErrorMessage{
Error: error,
EndTime: time.Now().Format("2006-01-02 15:04:05"),
}, "email-error.template")
if err != nil {
Error("Could not parse email template: %v", err)
}
SendEmail(fmt.Sprintf("🔴 Urgent: Database Backup Failure Notification"), body)
}
//Telegram notification
err = CheckEnvVars(vars)
if err == nil {
message, err := parseTemplate(ErrorMessage{
Error: error,
EndTime: time.Now().Format("2006-01-02 15:04:05"),
}, "telegram-error.template")
if err != nil {
Error("Could not parse email template: %v", err)
}
sendMessage(message)
}
}
func getTgUrl() string {
return fmt.Sprintf("https://api.telegram.org/bot%s", os.Getenv("TG_TOKEN"))
}
func IsValidCronExpression(cronExpr string) bool {
_, err := cron.ParseStandard(cronExpr)
return err == nil
}

View File

@@ -7,15 +7,10 @@
package utils
import (
"bytes"
"encoding/json"
"fmt"
"github.com/robfig/cron/v3"
"github.com/spf13/cobra"
"io"
"io/fs"
"io/ioutil"
"net/http"
"os"
"strconv"
)
@@ -185,72 +180,3 @@ func GetIntEnv(envName string) int {
}
return ret
}
func sendMessage(msg string) {
Info("Sending notification... ")
chatId := os.Getenv("TG_CHAT_ID")
body, _ := json.Marshal(map[string]string{
"chat_id": chatId,
"text": msg,
})
url := fmt.Sprintf("%s/sendMessage", getTgUrl())
// Create an HTTP post request
request, err := http.NewRequest("POST", url, bytes.NewBuffer(body))
if err != nil {
panic(err)
}
request.Header.Add("Content-Type", "application/json")
client := &http.Client{}
response, err := client.Do(request)
if err != nil {
panic(err)
}
code := response.StatusCode
if code == 200 {
Info("Notification has been sent")
} else {
body, _ := ioutil.ReadAll(response.Body)
Error("Message not sent, error: %s", string(body))
}
}
func NotifySuccess(fileName string) {
var vars = []string{
"TG_TOKEN",
"TG_CHAT_ID",
}
//Telegram notification
err := CheckEnvVars(vars)
if err == nil {
message := "[✅ PostgreSQL Backup ]\n" +
"Database has been backed up \n" +
"Backup name is " + fileName
sendMessage(message)
}
}
func NotifyError(error string) {
var vars = []string{
"TG_TOKEN",
"TG_CHAT_ID",
}
//Telegram notification
err := CheckEnvVars(vars)
if err == nil {
message := "[🔴 PostgreSQL Backup ]\n" +
"An error occurred during database backup \n" +
"Error: " + error
sendMessage(message)
}
}
func getTgUrl() string {
return fmt.Sprintf("https://api.telegram.org/bot%s", os.Getenv("TG_TOKEN"))
}
func IsValidCronExpression(cronExpr string) bool {
_, err := cron.ParseStandard(cronExpr)
return err == nil
}