diff --git a/Dockerfile b/Dockerfile index 42cf6f9..4016fb6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,20 +22,12 @@ LABEL version=${appVersion} LABEL github="github.com/jkaninda/mysql-bkup" RUN apk --update add --no-cache mysql-client mariadb-connector-c tzdata ca-certificates -RUN mkdir $WORKDIR -RUN mkdir $BACKUPDIR -RUN mkdir $TEMPLATES_DIR -RUN mkdir -p $BACKUP_TMP_DIR -RUN chmod 777 $WORKDIR -RUN chmod 777 $BACKUPDIR -RUN chmod 777 $BACKUP_TMP_DIR -RUN chmod 777 $WORKDIR - +RUN mkdir -p $WORKDIR $BACKUPDIR $TEMPLATES_DIR $BACKUP_TMP_DIR && \ + chmod a+rw $WORKDIR $BACKUPDIR $BACKUP_TMP_DIR COPY --from=build /app/mysql-bkup /usr/local/bin/mysql-bkup COPY ./templates/* $TEMPLATES_DIR/ -RUN chmod +x /usr/local/bin/mysql-bkup - -RUN ln -s /usr/local/bin/mysql-bkup /usr/local/bin/bkup +RUN chmod +x /usr/local/bin/mysql-bkup && \ + ln -s /usr/local/bin/mysql-bkup /usr/local/bin/bkup # Create backup script and make it executable RUN printf '#!/bin/sh\n/usr/local/bin/mysql-bkup backup "$@"' > /usr/local/bin/backup && \ diff --git a/cmd/backup.go b/cmd/backup.go index 6085159..3263a29 100644 --- a/cmd/backup.go +++ b/cmd/backup.go @@ -27,7 +27,7 @@ var BackupCmd = &cobra.Command{ func init() { //Backup - BackupCmd.PersistentFlags().StringP("storage", "s", "local", "Storage. local or s3") + BackupCmd.PersistentFlags().StringP("storage", "s", "local", "Define storage: local, s3, ssh, ftp") BackupCmd.PersistentFlags().StringP("path", "P", "", "AWS S3 path without file name. eg: /custom_path or ssh remote path `/home/foo/backup`") BackupCmd.PersistentFlags().StringP("cron-expression", "", "", "Backup cron expression") BackupCmd.PersistentFlags().BoolP("disable-compression", "", false, "Disable backup compression") diff --git a/cmd/restore.go b/cmd/restore.go index 76e57d6..d305ad3 100644 --- a/cmd/restore.go +++ b/cmd/restore.go @@ -24,7 +24,7 @@ var RestoreCmd = &cobra.Command{ func init() { //Restore RestoreCmd.PersistentFlags().StringP("file", "f", "", "File name of database") - RestoreCmd.PersistentFlags().StringP("storage", "s", "local", "Storage. local or s3") + RestoreCmd.PersistentFlags().StringP("storage", "s", "local", "Define storage: local, s3, ssh, ftp") RestoreCmd.PersistentFlags().StringP("path", "P", "", "AWS S3 path without file name. eg: /custom_path or ssh remote path `/home/foo/backup`") } diff --git a/docs/how-tos/backup-to-s3.md b/docs/how-tos/backup-to-s3.md index a14da5e..5bb266b 100644 --- a/docs/how-tos/backup-to-s3.md +++ b/docs/how-tos/backup-to-s3.md @@ -37,7 +37,7 @@ services: - AWS_SECRET_KEY=xxxxx ## In case you are using S3 alternative such as Minio and your Minio instance is not secured, you change it to true - AWS_DISABLE_SSL="false" - - AWS_FORCE_PATH_STYLE="false" + - AWS_FORCE_PATH_STYLE=true # true for S3 alternative such as Minio # mysql-bkup container must be connected to the same network with your database networks: @@ -78,6 +78,7 @@ services: #- BACKUP_RETENTION_DAYS=7 ## In case you are using S3 alternative such as Minio and your Minio instance is not secured, you change it to true - AWS_DISABLE_SSL="false" + - AWS_FORCE_PATH_STYLE=true # true for S3 alternative such as Minio # mysql-bkup container must be connected to the same network with your database networks: - web diff --git a/examples/docker-compose.s3.yaml b/examples/docker-compose.s3.yaml index 7791da5..1142c19 100644 --- a/examples/docker-compose.s3.yaml +++ b/examples/docker-compose.s3.yaml @@ -21,6 +21,7 @@ services: - AWS_SECRET_KEY=xxxxx ## In case you are using S3 alternative such as Minio and your Minio instance is not secured, you change it to true - AWS_DISABLE_SSL="false" + - AWS_FORCE_PATH_STYLE=true # true for S3 alternative such as Minio # mysql-bkup container must be connected to the same network with your database networks: - web diff --git a/examples/docker-compose.scheduled.s3.yaml b/examples/docker-compose.scheduled.s3.yaml index d9d2449..95f8ca7 100644 --- a/examples/docker-compose.scheduled.s3.yaml +++ b/examples/docker-compose.scheduled.s3.yaml @@ -21,6 +21,7 @@ services: - AWS_SECRET_KEY=xxxxx ## In case you are using S3 alternative such as Minio and your Minio instance is not secured, you change it to true - AWS_DISABLE_SSL="false" + - AWS_FORCE_PATH_STYLE=true # true for S3 alternative such as Minio # See: https://jkaninda.github.io/mysql-bkup/reference/#predefined-schedules - BACKUP_CRON_EXPRESSION=@daily #@every 5m|@weekly | @monthly |0 1 * * * # mysql-bkup container must be connected to the same network with your database diff --git a/examples/k8s-job.yaml b/examples/k8s-job.yaml index 9ce6943..f31f487 100644 --- a/examples/k8s-job.yaml +++ b/examples/k8s-job.yaml @@ -45,5 +45,5 @@ spec: - name: AWS_DISABLE_SSL value: "false" - name: AWS_FORCE_PATH_STYLE - value: "false" + value: "true" restartPolicy: Never \ No newline at end of file diff --git a/pkg/backup.go b/pkg/backup.go index 05f9b0d..3284456 100644 --- a/pkg/backup.go +++ b/pkg/backup.go @@ -195,7 +195,7 @@ func BackupDatabase(db *dbConfig, backupFileName string, disableCompression bool if err != nil { log.Fatal(err) } - utils.Done("Database has been backed up") + utils.Info("Database has been backed up") } else { // Execute mysqldump @@ -217,7 +217,7 @@ func BackupDatabase(db *dbConfig, backupFileName string, disableCompression bool if err := gzipCmd.Wait(); err != nil { log.Fatal(err) } - utils.Done("Database has been backed up") + utils.Info("Database has been backed up") } @@ -301,7 +301,7 @@ func s3Backup(db *dbConfig, config *BackupConfig) { utils.Fatal("Error deleting old backup from S3: %s ", err) } } - utils.Done("Uploading backup archive to remote storage S3 ... done ") + utils.Info("Uploading backup archive to remote storage S3 ... done ") //Send notification utils.NotifySuccess(&utils.NotificationData{ File: finalFileName, @@ -353,7 +353,7 @@ func sshBackup(db *dbConfig, config *BackupConfig) { } - utils.Done("Uploading backup archive to remote storage ... done ") + utils.Info("Uploading backup archive to remote storage ... done ") //Send notification utils.NotifySuccess(&utils.NotificationData{ File: finalFileName, @@ -405,7 +405,7 @@ func ftpBackup(db *dbConfig, config *BackupConfig) { } - utils.Done("Uploading backup archive to the remote FTP server ... done ") + utils.Info("Uploading backup archive to the remote FTP server ... done ") //Send notification utils.NotifySuccess(&utils.NotificationData{ File: finalFileName, diff --git a/pkg/helper.go b/pkg/helper.go index 95aab41..558c795 100644 --- a/pkg/helper.go +++ b/pkg/helper.go @@ -39,7 +39,7 @@ func moveToBackup(backupFileName string, destinationPath string) { fmt.Println("Error deleting file:", err) } - utils.Done("Database has been backed up and copied to %s", filepath.Join(destinationPath, backupFileName)) + utils.Info("Database has been backed up and copied to %s", filepath.Join(destinationPath, backupFileName)) } func deleteOldBackup(retentionDays int) { utils.Info("Deleting old backups...") @@ -54,7 +54,7 @@ func deleteOldBackup(retentionDays int) { if err != nil { utils.Fatal(fmt.Sprintf("Error: %s", err)) } else { - utils.Done("File %s has been deleted successfully", filePath) + utils.Info("File %s has been deleted successfully", filePath) } return err } @@ -81,7 +81,7 @@ func deleteOldBackup(retentionDays int) { utils.Fatal(fmt.Sprintf("Error: %s", err)) return } - utils.Done("Deleting old backups...done") + utils.Info("Deleting old backups...done") } func deleteTemp() { diff --git a/pkg/restore.go b/pkg/restore.go index e4ed9f4..91caf69 100644 --- a/pkg/restore.go +++ b/pkg/restore.go @@ -125,7 +125,7 @@ func RestoreDatabase(db *dbConfig, conf *RestoreConfig) { utils.Fatal("Error, in restoring the database %v", err) } utils.Info("Restoring database... done") - utils.Done("Database has been restored") + utils.Info("Database has been restored") //Delete temp deleteTemp() @@ -137,7 +137,7 @@ func RestoreDatabase(db *dbConfig, conf *RestoreConfig) { utils.Fatal("Error in restoring the database %v", err) } utils.Info("Restoring database... done") - utils.Done("Database has been restored") + utils.Info("Database has been restored") //Delete temp deleteTemp() } else { diff --git a/pkg/s3.go b/pkg/s3.go index 00612dd..53f597f 100644 --- a/pkg/s3.go +++ b/pkg/s3.go @@ -106,6 +106,8 @@ func DownloadFile(destinationPath, key, bucket, prefix string) error { return nil } func DeleteOldBackup(bucket, prefix string, retention int) error { + utils.Info("Deleting old backups...") + utils.Info("Bucket %s Prefix: %s Retention: %d", bucket, prefix, retention) sess, err := CreateSession() if err != nil { return err @@ -113,7 +115,7 @@ func DeleteOldBackup(bucket, prefix string, retention int) error { svc := s3.New(sess) - // Get the current time and the time threshold for 7 days ago + // Get the current time now := time.Now() backupRetentionDays := now.AddDate(0, 0, -retention) @@ -125,6 +127,7 @@ func DeleteOldBackup(bucket, prefix string, retention int) error { err = svc.ListObjectsV2Pages(listObjectsInput, func(page *s3.ListObjectsV2Output, lastPage bool) bool { for _, object := range page.Contents { if object.LastModified.Before(backupRetentionDays) { + utils.Info("Deleting old backup: %s", *object.Key) // Object is older than retention days, delete it _, err := svc.DeleteObject(&s3.DeleteObjectInput{ Bucket: aws.String(bucket), @@ -133,7 +136,7 @@ func DeleteOldBackup(bucket, prefix string, retention int) error { if err != nil { utils.Info("Failed to delete object %s: %v", *object.Key, err) } else { - utils.Info("Deleted object %s\n", *object.Key) + utils.Info("Deleted object %s", *object.Key) } } } @@ -143,6 +146,6 @@ func DeleteOldBackup(bucket, prefix string, retention int) error { utils.Error("Failed to list objects: %v", err) } - utils.Info("Finished deleting old files.") + utils.Info("Deleting old backups...done") return nil } diff --git a/utils/logger.go b/utils/logger.go index a11b13b..9000976 100644 --- a/utils/logger.go +++ b/utils/logger.go @@ -41,15 +41,6 @@ func Error(msg string, args ...any) { fmt.Printf("%s ERROR: %s\n", currentTime, formattedMessage) } } -func Done(msg string, args ...any) { - var currentTime = time.Now().Format("2006/01/02 15:04:05") - formattedMessage := fmt.Sprintf(msg, args...) - if len(args) == 0 { - fmt.Printf("%s INFO: %s\n", currentTime, msg) - } else { - fmt.Printf("%s INFO: %s\n", currentTime, formattedMessage) - } -} // Fatal logs an error message and exits the program func Fatal(msg string, args ...any) {