chore: fix infinity calling Fatal, add a backup reference

This commit is contained in:
Jonas Kaninda
2024-10-10 04:14:42 +02:00
parent df490af7b6
commit e5dd7e76ce
9 changed files with 133 additions and 59 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:
@@ -27,9 +27,13 @@ services:
- MAIL_PORT=587
- MAIL_USERNAME=
- MAIL_PASSWORD=!
- MAIL_FROM=sender@example.com
- 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 identifier 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 identifier every backup instance
- BACKUP_REFERENCE=database/Paris cluster
networks:
- web
networks:
@@ -62,12 +70,13 @@ networks:
### Customize notifications
The body of the notifications can be tailored to your needs using Go templates.
The title and body of the notifications can be tailored to your needs using Go templates.
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,7 +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:
@@ -88,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>
@@ -110,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}}.
@@ -121,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

@@ -218,7 +218,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 {
@@ -241,7 +241,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 {
@@ -256,7 +256,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)
@@ -301,7 +301,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()
@@ -310,7 +310,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)
@@ -353,7 +353,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()
@@ -362,7 +362,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)
@@ -405,7 +405,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/mysql-bkup">mysql-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/mysql-bkup">mysql-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

@@ -1,4 +1,4 @@
✅ Database Backup Notification {{.Database}}
[✅ Database Backup Notification {{.Database}}
Hi,
Backup of the {{.Database}} database has been successfully completed on {{.EndTime}}.
@@ -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

@@ -6,9 +6,9 @@
**/
package utils
const RestoreExample = "mysql-bkup restore --dbname database --file db_20231219_022941.sql.gz\n" +
const RestoreExample = "restore --dbname database --file db_20231219_022941.sql.gz\n" +
"restore --dbname database --storage s3 --path /custom-path --file db_20231219_022941.sql.gz"
const BackupExample = "mysql-bkup backup --dbname database --disable-compression\n" +
const BackupExample = "backup --dbname database --disable-compression\n" +
"backup --dbname database --storage s3 --path /custom-path --disable-compression"
const MainExample = "mysql-bkup backup --dbname database --disable-compression\n" +

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)
}
}
}