chore: fix infinity calling Fatal, add backup reference

This commit is contained in:
Jonas Kaninda
2024-10-10 04:32:03 +02:00
parent 4a43a28888
commit f763600915
8 changed files with 128 additions and 53 deletions

View File

@@ -4,10 +4,10 @@ layout: default
parent: How Tos
nav_order: 12
---
Send Email or Telegram notifications on success or failed backup.
Send Email or Telegram notifications on successfully or failed backup.
### Email
To send out email notifications on failed backup runs, provide SMTP credentials, a sender and a recipient:
To send out email notifications on failed or successfully backup runs, provide SMTP credentials, a sender and a recipient:
```yaml
services:
@@ -30,6 +30,10 @@ services:
- MAIL_FROM=
- MAIL_TO=me@example.com,team@example.com,manager@example.com
- MAIL_SKIP_TLS=false
## Time format for notification
- TIME_FORMAT=2006-01-02 at 15:04:05
## Backup reference, in case you want to identify every backup instance
- BACKUP_REFERENCE=database/Paris cluster
networks:
- web
networks:
@@ -54,6 +58,10 @@ services:
- DB_PASSWORD=password
- TG_TOKEN=[BOT ID]:[BOT TOKEN]
- TG_CHAT_ID=
## Time format for notification
- TIME_FORMAT=2006-01-02 at 15:04:05
## Backup reference, in case you want to identify every backup instance
- BACKUP_REFERENCE=database/Paris cluster
networks:
- web
networks:
@@ -67,7 +75,8 @@ Template sources must be mounted inside the container in /config/templates:
- email.template: Email notification template
- telegram.template: Telegram notification template
- error.template: Error notification template
- email-error.template: Error notification template
- telegram-error.template: Error notification template
### Data
@@ -78,6 +87,7 @@ Here is a list of all data passed to the template:
- `Storage`: Backup storage
- `BackupLocation`: Backup location
- `BackupSize`: Backup size
- `BackupReference`: Backup reference(eg: database/cluster name or server name)
> email.template:
@@ -87,19 +97,20 @@ Here is a list of all data passed to the template:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>[✅ Database Backup Notification {{.Database}}</title>
<title>✅ Database Backup Notification {{.Database}}</title>
</head>
<body>
<h2>Hi,</h2>
<p>Backup of the {{.Database}} database has been successfully completed on {{.EndTime}}.</p>
<h3>Backup Details:</h3>
<ul>
<li>Database Name: {{.Database}}</li>
<li>Backup Start Time: {{.StartTime}}</li>
<li>Backup End Time: {{.EndTime}}</li>
<li>Backup Storage: {{.Storage}}</li>
<li>Backup Location: {{.BackupLocation}}</li>
<li>Backup Size: {{.BackupSize}} bytes</li>
<li>Database Name: {{.Database}}</li>
<li>Backup Start Time: {{.StartTime}}</li>
<li>Backup End Time: {{.EndTime}}</li>
<li>Backup Storage: {{.Storage}}</li>
<li>Backup Location: {{.BackupLocation}}</li>
<li>Backup Size: {{.BackupSize}} bytes</li>
<li>Backup Reference: {{.BackupReference}} </li>
</ul>
<p>Best regards,</p>
</body>
@@ -109,7 +120,7 @@ Here is a list of all data passed to the template:
> telegram.template
```html
[✅ Database Backup Notification {{.Database}}
✅ Database Backup Notification {{.Database}}
Hi,
Backup of the {{.Database}} database has been successfully completed on {{.EndTime}}.
@@ -120,9 +131,32 @@ Backup Details:
- Backup Storage: {{.Storage}}
- Backup Location: {{.BackupLocation}}
- Backup Size: {{.BackupSize}} bytes
- Backup Reference: {{.BackupReference}}
```
> error.template
> email-error.template
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>🔴 Urgent: Database Backup Failure Notification</title>
</head>
<body>
<h2>Hi,</h2>
<p>An error occurred during database backup.</p>
<h3>Failure Details:</h3>
<ul>
<li>Error Message: {{.Error}}</li>
<li>Date: {{.EndTime}}</li>
<li>Backup Reference: {{.BackupReference}} </li>
</ul>
</body>
</html>
```
> telegram-error.template
```html

View File

@@ -224,7 +224,7 @@ func BackupDatabase(db *dbConfig, backupFileName string, disableCompression bool
}
func localBackup(db *dbConfig, config *BackupConfig) {
utils.Info("Backup database to local storage")
startTime = time.Now().Format("2006-01-02 15:04:05")
startTime = time.Now().Format(utils.TimeFormat())
BackupDatabase(db, config.backupFileName, disableCompression)
finalFileName := config.backupFileName
if config.encryption {
@@ -247,7 +247,7 @@ func localBackup(db *dbConfig, config *BackupConfig) {
Storage: config.storage,
BackupLocation: filepath.Join(config.remotePath, finalFileName),
StartTime: startTime,
EndTime: time.Now().Format("2006-01-02 15:04:05"),
EndTime: time.Now().Format(utils.TimeFormat()),
})
//Delete old backup
if config.prune {
@@ -262,7 +262,7 @@ func s3Backup(db *dbConfig, config *BackupConfig) {
bucket := utils.GetEnvVariable("AWS_S3_BUCKET_NAME", "BUCKET_NAME")
s3Path := utils.GetEnvVariable("AWS_S3_PATH", "S3_PATH")
utils.Info("Backup database to s3 storage")
startTime = time.Now().Format("2006-01-02 15:04:05")
startTime = time.Now().Format(utils.TimeFormat())
//Backup database
BackupDatabase(db, config.backupFileName, disableCompression)
finalFileName := config.backupFileName
@@ -307,7 +307,7 @@ func s3Backup(db *dbConfig, config *BackupConfig) {
Storage: config.storage,
BackupLocation: filepath.Join(config.remotePath, finalFileName),
StartTime: startTime,
EndTime: time.Now().Format("2006-01-02 15:04:05"),
EndTime: time.Now().Format(utils.TimeFormat()),
})
//Delete temp
deleteTemp()
@@ -316,7 +316,7 @@ func s3Backup(db *dbConfig, config *BackupConfig) {
}
func sshBackup(db *dbConfig, config *BackupConfig) {
utils.Info("Backup database to Remote server")
startTime = time.Now().Format("2006-01-02 15:04:05")
startTime = time.Now().Format(utils.TimeFormat())
//Backup database
BackupDatabase(db, config.backupFileName, disableCompression)
finalFileName := config.backupFileName
@@ -359,7 +359,7 @@ func sshBackup(db *dbConfig, config *BackupConfig) {
Storage: config.storage,
BackupLocation: filepath.Join(config.remotePath, finalFileName),
StartTime: startTime,
EndTime: time.Now().Format("2006-01-02 15:04:05"),
EndTime: time.Now().Format(utils.TimeFormat()),
})
//Delete temp
deleteTemp()
@@ -368,7 +368,7 @@ func sshBackup(db *dbConfig, config *BackupConfig) {
}
func ftpBackup(db *dbConfig, config *BackupConfig) {
utils.Info("Backup database to the remote FTP server")
startTime = time.Now().Format("2006-01-02 15:04:05")
startTime = time.Now().Format(utils.TimeFormat())
//Backup database
BackupDatabase(db, config.backupFileName, disableCompression)
@@ -412,7 +412,7 @@ func ftpBackup(db *dbConfig, config *BackupConfig) {
Storage: config.storage,
BackupLocation: filepath.Join(config.remotePath, finalFileName),
StartTime: startTime,
EndTime: time.Now().Format("2006-01-02 15:04:05"),
EndTime: time.Now().Format(utils.TimeFormat()),
})
//Delete temp
deleteTemp()

View File

@@ -11,6 +11,7 @@
<ul>
<li>Error Message: {{.Error}}</li>
<li>Date: {{.EndTime}}</li>
<li>Backup Reference: {{.BackupReference}} </li>
</ul>
<p>©2024 <a href="github.com/jkaninda/pg-bkup">pg-bkup</a></p>
</body>

View File

@@ -15,6 +15,7 @@
<li>Backup Storage: {{.Storage}}</li>
<li>Backup Location: {{.BackupLocation}}</li>
<li>Backup Size: {{.BackupSize}} bytes</li>
<li>Backup Reference: {{.BackupReference}} </li>
</ul>
<p>Best regards,</p>
<p>©2024 <a href="github.com/jkaninda/pg-bkup">pg-bkup</a></p>

View File

@@ -2,6 +2,7 @@
Hi,
An error occurred during database backup.
Failure Details:
Date: {{.EndTime}}
Error Message: {{.Error}}
- Date: {{.EndTime}}
- Backup Reference: {{.BackupReference}}
- Error Message: {{.Error}}

View File

@@ -8,4 +8,5 @@ Backup Details:
- Backup EndTime: {{.EndTime}}
- Backup Storage: {{.Storage}}
- Backup Location: {{.BackupLocation}}
- Backup Size: {{.BackupSize}} bytes
- Backup Size: {{.BackupSize}} bytes
- Backup Reference: {{.BackupReference}}

View File

@@ -12,20 +12,23 @@ type MailConfig struct {
SkipTls bool
}
type NotificationData struct {
File string
BackupSize int64
Database string
StartTime string
EndTime string
Storage string
BackupLocation string
File string
BackupSize int64
Database string
StartTime string
EndTime string
Storage string
BackupLocation string
BackupReference string
}
type ErrorMessage struct {
Database string
EndTime string
Error string
Database string
EndTime string
Error string
BackupReference string
}
// loadMailConfig gets mail environment variables and returns MailConfig
func loadMailConfig() *MailConfig {
return &MailConfig{
MailHost: os.Getenv("MAIL_HOST"),
@@ -39,4 +42,18 @@ func loadMailConfig() *MailConfig {
}
// TimeFormat returns the format of the time
func TimeFormat() string {
format := os.Getenv("TIME_FORMAT")
if format == "" {
return "2006-01-02 at 15:04:05"
}
return format
}
func backupReference() string {
return os.Getenv("BACKUP_REFERENCE")
}
const templatePath = "/config/templates"

View File

@@ -31,8 +31,8 @@ func parseTemplate[T any](data T, fileName string) (string, error) {
return buf.String(), nil
}
func SendEmail(subject, body string) {
Info("Start sending email....")
func SendEmail(subject, body string) error {
Info("Start sending email notification....")
config := loadMailConfig()
emails := strings.Split(config.MailTo, ",")
m := mail.NewMessage()
@@ -44,14 +44,16 @@ func SendEmail(subject, body string) {
d.TLSConfig = &tls.Config{InsecureSkipVerify: config.SkipTls}
if err := d.DialAndSend(m); err != nil {
Fatal("Error could not send email : %v", err)
Error("Error could not send email : %v", err)
return err
}
Info("Email has been sent")
Info("Email notification has been sent")
return nil
}
func sendMessage(msg string) {
func sendMessage(msg string) error {
Info("Sending notification... ")
Info("Sending Telegram notification... ")
chatId := os.Getenv("TG_CHAT_ID")
body, _ := json.Marshal(map[string]string{
"chat_id": chatId,
@@ -67,18 +69,21 @@ func sendMessage(msg string) {
client := &http.Client{}
response, err := client.Do(request)
if err != nil {
panic(err)
return err
}
code := response.StatusCode
if code == 200 {
Info("Notification has been sent")
Info("Telegram notification has been sent")
return nil
} else {
body, _ := ioutil.ReadAll(response.Body)
Fatal("Error could not send message, error: %s", string(body))
Error("Error could not send message, error: %s", string(body))
return fmt.Errorf("error could not send message %s", string(body))
}
}
func NotifySuccess(notificationData *NotificationData) {
notificationData.BackupReference = backupReference()
var vars = []string{
"TG_TOKEN",
"TG_CHAT_ID",
@@ -99,17 +104,23 @@ func NotifySuccess(notificationData *NotificationData) {
if err != nil {
Error("Could not parse email template: %v", err)
}
SendEmail(fmt.Sprintf("✅ Database Backup Notification %s", notificationData.Database), body)
err = SendEmail(fmt.Sprintf("✅ Database Backup Notification %s", notificationData.Database), body)
if err != nil {
Error("Could not send email: %v", err)
}
}
//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)
Error("Could not parse telegram template: %v", err)
}
sendMessage(message)
err = sendMessage(message)
if err != nil {
Error("Could not send Telegram message: %v", err)
}
}
}
func NotifyError(error string) {
@@ -130,26 +141,35 @@ func NotifyError(error string) {
err := CheckEnvVars(mailVars)
if err == nil {
body, err := parseTemplate(ErrorMessage{
Error: error,
EndTime: time.Now().Format("2006-01-02 15:04:05"),
Error: error,
EndTime: time.Now().Format(TimeFormat()),
BackupReference: os.Getenv("BACKUP_REFERENCE"),
}, "email-error.template")
if err != nil {
Error("Could not parse email template: %v", err)
Error("Could not parse error template: %v", err)
}
err = SendEmail(fmt.Sprintf("🔴 Urgent: Database Backup Failure Notification"), body)
if err != nil {
Error("Could not send email: %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"),
Error: error,
EndTime: time.Now().Format(TimeFormat()),
BackupReference: os.Getenv("BACKUP_REFERENCE"),
}, "telegram-error.template")
if err != nil {
Error("Could not parse email template: %v", err)
Error("Could not parse error template: %v", err)
}
sendMessage(message)
err = sendMessage(message)
if err != nil {
Error("Could not send telegram message: %v", err)
}
}
}