feat: replace --operation flag by backup and restore command

This commit is contained in:
2024-01-20 13:04:39 +01:00
parent 4b07a78f29
commit 05eda4213a
22 changed files with 327 additions and 283 deletions

View File

@@ -38,21 +38,23 @@ MySQL Backup and Restoration tool. Backup database to AWS S3 storage or any S3 A
## Usage ## Usage
| Options | Shorts | Usage | | Options | Shorts | Usage |
|-----------------------|--------|------------------------------------| |-----------------------|--------|--------------------------------------------------------------------|
| mysql-bkup | bkup | CLI utility | | mysql-bkup | bkup | CLI utility |
| --operation | -o | Set operation. backup or restore (default: backup) | | backup | | Backup database operation |
| --storage | -s | Set storage. local or s3 (default: local) | | restore | | Restore database operation |
| --file | -f | Set file name for restoration | | --operation | -o | Set operation. backup or restore (default: backup) |
| --path | | Set s3 path without file name. eg: /custom_path | | --storage | -s | Set storage. local or s3 (default: local) |
| --dbname | -d | Set database name | | --file | -f | Set file name for restoration |
| --port | -p | Set database port (default: 3306) | | --path | | Set s3 path without file name. eg: /custom_path |
| --dbname | -d | Set database name |
| --port | -p | Set database port (default: 3306) |
| --mode | -m | Set execution mode. default or scheduled (default: default) | | --mode | -m | Set execution mode. default or scheduled (default: default) |
| --disable-compression | | Disable database backup compression | | --disable-compression | | Disable database backup compression |
| --period | | Set crontab period for scheduled mode only. (default: "0 1 * * *") | | --period | | Set crontab period for scheduled mode only. (default: "0 1 * * *") |
| --timeout | -t | Set timeout (default: 60s) | | --timeout | -t | Set timeout (default: 60s) |
| --help | -h | Print this help message and exit | | --help | -h | Print this help message and exit |
| --version | -V | Print version information and exit | | --version | -V | Print version information and exit |
## Note: ## Note:
@@ -81,20 +83,20 @@ FLUSH PRIVILEGES;
Simple backup usage Simple backup usage
```sh ```sh
bkup --operation backup --dbname database_name bkup backup --dbname database_name
``` ```
```sh ```sh
bkup -o backup -d database_name bkup backup -d database_name
``` ```
### S3 ### S3
```sh ```sh
bkup --operation backup --storage s3 --dbname database_name bkup backup --storage s3 --dbname database_name
``` ```
## Docker run: ## Docker run:
```sh ```sh
docker run --rm --network your_network_name --name mysql-bkup -v $PWD/backup:/backup/ -e "DB_HOST=database_host_name" -e "DB_USERNAME=username" -e "DB_PASSWORD=password" jkaninda/mysql-bkup:latest bkup -o backup -d database_name docker run --rm --network your_network_name --name mysql-bkup -v $PWD/backup:/backup/ -e "DB_HOST=database_host_name" -e "DB_USERNAME=username" -e "DB_PASSWORD=password" jkaninda/mysql-bkup:latest bkup backup -d database_name
``` ```
## Docker compose file: ## Docker compose file:
@@ -115,7 +117,7 @@ services:
command: command:
- /bin/sh - /bin/sh
- -c - -c
- bkup --operation backup -d database_name - bkup backup -d database_name
volumes: volumes:
- ./backup:/backup - ./backup:/backup
environment: environment:
@@ -129,22 +131,22 @@ services:
Simple database restore operation usage Simple database restore operation usage
```sh ```sh
bkup --operation restore --dbname database_name --file database_20231217_115621.sql bkup restore --dbname database_name --file database_20231217_115621.sql
``` ```
```sh ```sh
bkup -o restore -f database_20231217_115621.sql bkup restore -f database_20231217_115621.sql
``` ```
### S3 ### S3
```sh ```sh
bkup --operation restore --storage s3 --file database_20231217_115621.sql bkup restore --storage s3 --file database_20231217_115621.sql
``` ```
## Docker run: ## Docker run:
```sh ```sh
docker run --rm --network your_network_name --name mysql-bkup -v $PWD/backup:/backup/ -e "DB_HOST=database_host_name" -e "DB_USERNAME=username" -e "DB_PASSWORD=password" jkaninda/mysql-bkup bkup -o backup -d database_name -f mydb_20231219_022941.sql.gz docker run --rm --network your_network_name --name mysql-bkup -v $PWD/backup:/backup/ -e "DB_HOST=database_host_name" -e "DB_USERNAME=username" -e "DB_PASSWORD=password" jkaninda/mysql-bkup bkup backup -d database_name -f db_20231219_022941.sql.gz
``` ```
## Docker compose file: ## Docker compose file:
@@ -166,7 +168,7 @@ services:
command: command:
- /bin/sh - /bin/sh
- -c - -c
- bkup --operation restore --file database_20231217_115621.sql --dbname database_name - bkup restore --file database_20231217_115621.sql --dbname database_name
volumes: volumes:
- ./backup:/backup - ./backup:/backup
environment: environment:
@@ -185,14 +187,14 @@ docker-compose up -d
## Backup to S3 ## Backup to S3
```sh ```sh
docker run --rm --privileged --device /dev/fuse --name mysql-bkup -e "DB_HOST=db_hostname" -e "DB_USERNAME=username" -e "DB_PASSWORD=password" -e "ACCESS_KEY=your_access_key" -e "SECRET_KEY=your_secret_key" -e "BUCKETNAME=your_bucket_name" -e "S3_ENDPOINT=https://s3.us-west-2.amazonaws.com" jkaninda/mysql-bkup bkup -o backup -s s3 -d database_name docker run --rm --privileged --device /dev/fuse --name mysql-bkup -e "DB_HOST=db_hostname" -e "DB_USERNAME=username" -e "DB_PASSWORD=password" -e "ACCESS_KEY=your_access_key" -e "SECRET_KEY=your_secret_key" -e "BUCKETNAME=your_bucket_name" -e "S3_ENDPOINT=https://s3.us-west-2.amazonaws.com" jkaninda/mysql-bkup bkup backup -s s3 -d database_name
``` ```
> To change s3 backup path add this flag : --path /myPath . default path is /mysql_bkup > To change s3 backup path add this flag : --path /myPath . default path is /mysql_bkup
Simple S3 backup usage Simple S3 backup usage
```sh ```sh
bkup --operation backup --storage s3 --dbname mydatabase bkup backup --storage s3 --dbname mydatabase
``` ```
```yaml ```yaml
version: '3' version: '3'
@@ -206,7 +208,7 @@ services:
command: command:
- /bin/sh - /bin/sh
- -c - -c
- mysql-bkup --operation restore --storage s3 -f database_20231217_115621.sql.gz - mysql-bkup restore --storage s3 -f database_20231217_115621.sql.gz
environment: environment:
- DB_PORT=3306 - DB_PORT=3306
- DB_HOST=mysql - DB_HOST=mysql
@@ -273,7 +275,7 @@ Easy to remember format:
> Docker run : > Docker run :
```sh ```sh
docker run --rm --name mysql-bkup -v $BACKUP_DIR:/backup/ -e "DB_HOST=$DB_HOST" -e "DB_USERNAME=$DB_USERNAME" -e "DB_PASSWORD=$DB_PASSWORD" jkaninda/mysql-bkup bkup --operation backup --dbname $DB_NAME --mode scheduled --period "0 1 * * *" docker run --rm --name mysql-bkup -v $BACKUP_DIR:/backup/ -e "DB_HOST=$DB_HOST" -e "DB_USERNAME=$DB_USERNAME" -e "DB_PASSWORD=$DB_PASSWORD" jkaninda/mysql-bkup bkup backup --dbname $DB_NAME --mode scheduled --period "0 1 * * *"
``` ```
> With Docker compose > With Docker compose
@@ -290,7 +292,7 @@ services:
command: command:
- /bin/sh - /bin/sh
- -c - -c
- bkup --operation backup --storage s3 --path /mys3_custome_path --dbname database_name --mode scheduled --period "*/30 * * * *" - bkup backup --storage s3 --path /mys3_custome_path --dbname database_name --mode scheduled --period "*/30 * * * *"
environment: environment:
- DB_PORT=3306 - DB_PORT=3306
- DB_HOST=mysqlhost - DB_HOST=mysqlhost
@@ -327,7 +329,7 @@ spec:
command: command:
- /bin/sh - /bin/sh
- -c - -c
- bkup -o backup -s s3 --path /custom_path - bkup backup -s s3 --path /custom_path
env: env:
- name: DB_PORT - name: DB_PORT
value: "3306" value: "3306"

28
cmd/backup.go Normal file
View File

@@ -0,0 +1,28 @@
package cmd
import (
"github.com/jkaninda/mysql-bkup/pkg"
"github.com/jkaninda/mysql-bkup/utils"
"github.com/spf13/cobra"
)
var BackupCmd = &cobra.Command{
Use: "backup ",
Short: "Backup database operation",
Example: utils.BackupExample,
Run: func(cmd *cobra.Command, args []string) {
if len(args) == 0 {
pkg.StartBackup(cmd)
} else {
utils.Fatal("Error, no argument required")
}
},
}
func init() {
//Backup
BackupCmd.PersistentFlags().StringP("mode", "m", "default", "Set execution mode. default or scheduled")
BackupCmd.PersistentFlags().StringP("period", "", "0 1 * * *", "Set schedule period time")
BackupCmd.PersistentFlags().BoolP("disable-compression", "", false, "Disable backup compression")
}

14
cmd/history.go Normal file
View File

@@ -0,0 +1,14 @@
package cmd
import (
"github.com/jkaninda/mysql-bkup/utils"
"github.com/spf13/cobra"
)
var HistoryCmd = &cobra.Command{
Use: "history",
Short: "Show the history of backup",
Run: func(cmd *cobra.Command, args []string) {
utils.ShowHistory()
},
}

28
cmd/restore.go Normal file
View File

@@ -0,0 +1,28 @@
package cmd
import (
"github.com/jkaninda/mysql-bkup/pkg"
"github.com/jkaninda/mysql-bkup/utils"
"github.com/spf13/cobra"
)
var RestoreCmd = &cobra.Command{
Use: "restore",
Short: "Restore database operation",
Example: utils.RestoreExample,
Run: func(cmd *cobra.Command, args []string) {
if len(args) == 0 {
pkg.StartRestore(cmd)
} else {
utils.Fatal("Error, no argument required")
}
},
}
func init() {
//Restore
RestoreCmd.PersistentFlags().StringP("file", "f", "", "File name of database")
}

View File

@@ -5,20 +5,32 @@ Copyright © 2024 Jonas Kaninda <jonaskaninda@gmail.com>
package cmd package cmd
import ( import (
"os" "fmt"
"github.com/jkaninda/mysql-bkup/utils"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"os"
) )
// rootCmd represents the base command when called without any subcommands // rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{ var rootCmd = &cobra.Command{
Use: "mysql-bkup", Use: "mysql-bkup [Command]",
Short: "MySQL Backup tool, backup database to S3 or Object Storage", Short: "MySQL Backup tool, backup database to S3 or Object Storage",
Long: `MySQL Database backup and restoration tool. Backup database to AWS S3 storage or any S3 Alternatives for Object Storage.`, Long: `MySQL Database backup and restoration tool. Backup database to AWS S3 storage or any S3 Alternatives for Object Storage.`,
// Uncomment the following line if your bare application Example: utils.MainExample,
// has an action associated with it: Version: appVersion,
// Run: func(cmd *cobra.Command, args []string) { }, //TODO: To remove
//For old user || To remove
Run: func(cmd *cobra.Command, args []string) {
if operation != "" {
if operation == "backup" || operation == "restore" {
fmt.Println(utils.Notice)
utils.Fatal("New config required, please check --help")
}
}
},
} }
var operation = ""
var s3Path = "/mysql-bkup"
// Execute adds all child commands to the root command and sets flags appropriately. // Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd. // This is called by main.main(). It only needs to happen once to the rootCmd.
@@ -30,22 +42,16 @@ func Execute() {
} }
func init() { func init() {
// rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.mysql-bkup.yaml)")
// Cobra also supports local flags, which will only run
// when this action is called directly.
rootCmd.PersistentFlags().StringP("operation", "o", "backup", "Set operation")
rootCmd.PersistentFlags().StringP("storage", "s", "local", "Set storage. local or s3") rootCmd.PersistentFlags().StringP("storage", "s", "local", "Set storage. local or s3")
rootCmd.PersistentFlags().StringP("file", "f", "", "Set file name") rootCmd.PersistentFlags().StringP("path", "P", s3Path, "Set s3 path, without file name. for S3 storage only")
rootCmd.PersistentFlags().StringP("path", "P", "/mysql-bkup", "Set s3 path, without file name")
rootCmd.PersistentFlags().StringP("dbname", "d", "", "Set database name") rootCmd.PersistentFlags().StringP("dbname", "d", "", "Set database name")
rootCmd.PersistentFlags().StringP("mode", "m", "default", "Set execution mode. default or scheduled")
rootCmd.PersistentFlags().StringP("period", "", "0 1 * * *", "Set schedule period time")
rootCmd.PersistentFlags().IntP("timeout", "t", 30, "Set timeout") rootCmd.PersistentFlags().IntP("timeout", "t", 30, "Set timeout")
rootCmd.PersistentFlags().BoolP("disable-compression", "", false, "Disable backup compression")
rootCmd.PersistentFlags().IntP("port", "p", 3306, "Set database port") rootCmd.PersistentFlags().IntP("port", "p", 3306, "Set database port")
rootCmd.PersistentFlags().BoolP("help", "h", false, "Print this help message") rootCmd.PersistentFlags().StringVarP(&operation, "operation", "o", "", "Set operation, for old version only")
rootCmd.PersistentFlags().BoolP("version", "v", false, "shows version information")
rootCmd.AddCommand(VersionCmd) rootCmd.AddCommand(VersionCmd)
rootCmd.AddCommand(BackupCmd)
rootCmd.AddCommand(RestoreCmd)
rootCmd.AddCommand(S3MountCmd)
rootCmd.AddCommand(HistoryCmd)
} }

14
cmd/s3mount.go Normal file
View File

@@ -0,0 +1,14 @@
package cmd
import (
"github.com/jkaninda/mysql-bkup/pkg"
"github.com/spf13/cobra"
)
var S3MountCmd = &cobra.Command{
Use: "s3mount",
Short: "Mount AWS S3 storage",
Run: func(cmd *cobra.Command, args []string) {
pkg.S3Mount()
},
}

View File

@@ -1,5 +1,9 @@
package cmd package cmd
/*
Copyright © 2024 Jonas Kaninda <jonaskaninda@gmail.com>
*/
import ( import (
"fmt" "fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@@ -16,8 +20,7 @@ var VersionCmd = &cobra.Command{
}, },
} }
// Version display application version
func Version() { func Version() {
fmt.Printf("Version: %s \n", appVersion) fmt.Printf("Version: %s \n", appVersion)
fmt.Print() fmt.Println()
} }

View File

@@ -21,7 +21,7 @@ ENV ACCESS_KEY=""
ENV SECRET_KEY="" ENV SECRET_KEY=""
ENV S3_ENDPOINT=https://s3.amazonaws.com ENV S3_ENDPOINT=https://s3.amazonaws.com
ARG DEBIAN_FRONTEND=noninteractive ARG DEBIAN_FRONTEND=noninteractive
ENV VERSION="v0.4" ENV VERSION="v0.5"
LABEL authors="Jonas Kaninda" LABEL authors="Jonas Kaninda"
RUN apt-get update -qq RUN apt-get update -qq

View File

@@ -9,7 +9,7 @@ services:
command: command:
- /bin/sh - /bin/sh
- -c - -c
- bkup --operation backup --storage s3 --path /mys3_custom_path --dbname database_name - bkup backup --storage s3 --path /mys3_custom_path --dbname database_name
environment: environment:
- DB_PORT=3306 - DB_PORT=3306
- DB_HOST=mysqlhost - DB_HOST=mysqlhost

View File

@@ -6,7 +6,7 @@ services:
command: command:
- /bin/sh - /bin/sh
- -c - -c
- bkup --operation backup --dbname database_name --mode scheduled --period "0 1 * * *" - bkup backup --dbname database_name --mode scheduled --period "0 1 * * *"
volumes: volumes:
- ./backup:/backup - ./backup:/backup
environment: environment:

View File

@@ -9,7 +9,7 @@ services:
command: command:
- /bin/sh - /bin/sh
- -c - -c
- bkup --operation backup --storage s3 --path /mys3_custom_path --dbname database_name --mode scheduled --period "0 1 * * *" - bkup backup --storage s3 --path /mys3_custom_path --dbname database_name --mode scheduled --period "0 1 * * *"
environment: environment:
- DB_PORT=3306 - DB_PORT=3306
- DB_HOST=mysqlhost - DB_HOST=mysqlhost

View File

@@ -6,7 +6,7 @@ services:
command: command:
- /bin/sh - /bin/sh
- -c - -c
- bkup --operation backup --dbname database_name - bkup backup --dbname database_name
volumes: volumes:
- ./backup:/backup - ./backup:/backup
environment: environment:

View File

@@ -16,7 +16,7 @@ spec:
command: command:
- /bin/sh - /bin/sh
- -c - -c
- bkup --operation backup --storage s3 --path /custom_path - bkup backup --storage s3 --path /custom_path
env: env:
- name: DB_PORT - name: DB_PORT
value: "3306" value: "3306"

208
main.go
View File

@@ -1,218 +1,16 @@
package main package main
//main
/***** /*****
* MySQL Backup & Restore * MySQL Backup & Restore
* @author Jonas Kaninda * @author Jonas Kaninda
* @license MIT License <https://opensource.org/licenses/MIT> * @license MIT License <https://opensource.org/licenses/MIT>
* @link https://github.com/jkaninda/mysql-bkup * @link https://github.com/jkaninda/mysql-bkup
**/ **/
import ( import "github.com/jkaninda/mysql-bkup/cmd"
"fmt"
"github.com/jkaninda/mysql-bkup/cmd"
"github.com/jkaninda/mysql-bkup/pkg"
"github.com/jkaninda/mysql-bkup/utils"
flag "github.com/spf13/pflag"
"os"
"os/exec"
)
const s3MountPath string = "/s3mnt"
var (
operation string = "backup"
storage string = "local"
file string = ""
s3Path string = "/mysql-bkup"
dbName string = ""
dbHost string = ""
dbPort string = ""
dbPassword string = ""
dbUserName string = ""
executionMode string = "default"
storagePath string = "/backup"
accessKey string = ""
secretKey string = ""
bucketName string = ""
s3Endpoint string = ""
s3fsPasswdFile string = "/etc/passwd-s3fs"
disableCompression bool = false
startBackup bool = true
timeout int = 30
period string = "0 1 * * *"
)
func init() {
var (
operationFlag = flag.StringP("operation", "o", "backup", "Operation")
storageFlag = flag.StringP("storage", "s", "local", "Storage, local or s3")
fileFlag = flag.StringP("file", "f", "", "File name")
pathFlag = flag.StringP("path", "P", "/mysql-bkup", "S3 path, without file name")
dbnameFlag = flag.StringP("dbname", "d", "", "Database name")
modeFlag = flag.StringP("mode", "m", "default", "Execution mode. default or scheduled")
periodFlag = flag.StringP("period", "", "0 1 * * *", "Schedule period time")
timeoutFlag = flag.IntP("timeout", "t", 30, "Timeout (in seconds) to stop database connexion")
disableCompressionFlag = flag.BoolP("disable-compression", "", false, "Disable backup compression")
portFlag = flag.IntP("port", "p", 3306, "Database port")
helpFlag = flag.BoolP("help", "h", false, "Print this help message")
versionFlag = flag.BoolP("version", "v", false, "Version information")
)
flag.Parse()
operation = *operationFlag
storage = *storageFlag
file = *fileFlag
s3Path = *pathFlag
dbName = *dbnameFlag
executionMode = *modeFlag
dbPort = fmt.Sprint(*portFlag)
timeout = *timeoutFlag
period = *periodFlag
disableCompression = *disableCompressionFlag
flag.Usage = func() {
fmt.Print("MySQL Database backup and restoration tool. Backup database to AWS S3 storage or any S3 Alternatives for Object Storage.\n\n")
fmt.Print("Usage: bkup --operation backup -storage s3 --dbname databasename --path /my_path ...\n")
fmt.Print(" bkup -o backup -d databasename --disable-compression ...\n")
fmt.Print(" Restore: bkup -o restore -d databasename -f db_20231217_051339.sql.gz ...\n\n")
flag.PrintDefaults()
}
if *helpFlag {
startBackup = false
flag.Usage()
os.Exit(0)
}
if *versionFlag {
startBackup = false
cmd.Version()
os.Exit(0)
}
if *dbnameFlag != "" {
err := os.Setenv("DB_NAME", dbName)
if err != nil {
return
}
}
if *pathFlag != "" {
s3Path = *pathFlag
err := os.Setenv("S3_PATH", fmt.Sprint(*pathFlag))
if err != nil {
return
}
}
if *fileFlag != "" {
file = *fileFlag
err := os.Setenv("FILE_NAME", fmt.Sprint(*fileFlag))
if err != nil {
return
}
}
if *portFlag != 3306 {
err := os.Setenv("DB_PORT", fmt.Sprint(*portFlag))
if err != nil {
return
}
}
if *periodFlag != "" {
err := os.Setenv("SCHEDULE_PERIOD", fmt.Sprint(*periodFlag))
if err != nil {
return
}
}
if *storageFlag != "" {
err := os.Setenv("STORAGE", fmt.Sprint(*storageFlag))
if err != nil {
return
}
}
storage = os.Getenv("STORAGE")
err := os.Setenv("STORAGE_PATH", storagePath)
if err != nil {
return
}
}
func main() { func main() {
err := os.Setenv("STORAGE_PATH", storagePath)
if err != nil {
return
}
if startBackup { cmd.Execute()
start()
}
} }
func start() {
if executionMode == "default" {
if operation != "backup" {
if storage != "s3" {
utils.Info("Restore database from local")
pkg.RestoreDatabase(file)
} else {
//Restore from S3
utils.Info("Restore database from s3")
s3Restore()
}
} else {
if storage != "s3" {
utils.Info("Backup database to local storage")
pkg.BackupDatabase(disableCompression)
} else {
//Backup to S3
utils.Info("Backup database to s3 storage")
s3Backup()
}
}
} else if executionMode == "scheduled" {
scheduledMode()
} else {
utils.Fatal("Error, unknown execution mode!")
}
}
func s3Backup() {
// Backup Database to S3 storage
pkg.MountS3Storage(s3Path)
pkg.BackupDatabase(disableCompression)
}
// Run in scheduled mode
func scheduledMode() {
// Verify operation
if operation == "backup" {
fmt.Println()
fmt.Println("**********************************")
fmt.Println(" Starting MySQL Bkup... ")
fmt.Println("***********************************")
utils.Info("Running in Scheduled mode")
utils.Info("Log file in /var/log/mysql-bkup.log")
utils.Info("Execution period ", os.Getenv("SCHEDULE_PERIOD"))
//Test database connexion
utils.TestDatabaseConnection()
utils.Info("Creating backup job...")
pkg.CreateCrontabScript(disableCompression, storage)
//Start Supervisor
supervisordCmd := exec.Command("supervisord", "-c", "/etc/supervisor/supervisord.conf")
if err := supervisordCmd.Run(); err != nil {
utils.Fatalf("Error starting supervisord: %v\n", err)
}
} else {
utils.Fatal("Scheduled mode supports only backup operation")
}
}
func s3Restore() {
// Restore database from S3
pkg.MountS3Storage(s3Path)
pkg.RestoreDatabase(file)
}

View File

@@ -7,26 +7,75 @@ package pkg
import ( import (
"fmt" "fmt"
"github.com/jkaninda/mysql-bkup/utils" "github.com/jkaninda/mysql-bkup/utils"
"github.com/spf13/cobra"
"log" "log"
"os" "os"
"os/exec" "os/exec"
"time" "time"
) )
var ( func StartBackup(cmd *cobra.Command) {
dbName = "" _, _ = cmd.Flags().GetString("operation")
dbHost = ""
dbPort = "" //Set env
dbPassword = "" utils.SetEnv("STORAGE_PATH", storagePath)
dbUserName = "" utils.GetEnv(cmd, "dbname", "DB_NAME")
storagePath = "/backup" utils.GetEnv(cmd, "port", "DB_PORT")
) utils.GetEnv(cmd, "period", "SCHEDULE_PERIOD")
//Get flag value and set env
s3Path = utils.GetEnv(cmd, "path", "S3_PATH")
storage = utils.GetEnv(cmd, "storage", "STORAGE")
file = utils.GetEnv(cmd, "file", "FILE_NAME")
disableCompression, _ = cmd.Flags().GetBool("disable-compression")
executionMode, _ = cmd.Flags().GetString("mode")
if executionMode == "default" {
if storage == "s3" {
utils.Info("Backup database to s3 storage")
s3Backup(disableCompression, s3Path)
} else {
utils.Info("Backup database to local storage")
BackupDatabase(disableCompression)
}
} else if executionMode == "scheduled" {
scheduledMode()
} else {
utils.Fatal("Error, unknown execution mode!")
}
}
// Run in scheduled mode
func scheduledMode() {
fmt.Println()
fmt.Println("**********************************")
fmt.Println(" Starting MySQL Bkup... ")
fmt.Println("***********************************")
utils.Info("Running in Scheduled mode")
utils.Info("Log file in /var/log/mysql-bkup.log")
utils.Info("Execution period ", os.Getenv("SCHEDULE_PERIOD"))
//Test database connexion
utils.TestDatabaseConnection()
utils.Info("Creating backup job...")
CreateCrontabScript(disableCompression, storage)
//Start Supervisor
supervisordCmd := exec.Command("supervisord", "-c", "/etc/supervisor/supervisord.conf")
if err := supervisordCmd.Run(); err != nil {
utils.Fatalf("Error starting supervisord: %v\n", err)
}
}
// BackupDatabase backup database // BackupDatabase backup database
func BackupDatabase(disableCompression bool) { func BackupDatabase(disableCompression bool) {
dbHost = os.Getenv("DB_HOST") dbHost = os.Getenv("DB_HOST")
dbPassword = os.Getenv("DB_PASSWORD") dbPassword := os.Getenv("DB_PASSWORD")
dbUserName = os.Getenv("DB_USERNAME") dbUserName := os.Getenv("DB_USERNAME")
dbName = os.Getenv("DB_NAME") dbName = os.Getenv("DB_NAME")
dbPort = os.Getenv("DB_PORT") dbPort = os.Getenv("DB_PORT")
storagePath = os.Getenv("STORAGE_PATH") storagePath = os.Getenv("STORAGE_PATH")
@@ -105,3 +154,9 @@ func BackupDatabase(disableCompression bool) {
} }
} }
func s3Backup(disableCompression bool, s3Path string) {
// Backup Database to S3 storage
MountS3Storage(s3Path)
BackupDatabase(disableCompression)
}

View File

@@ -3,19 +3,44 @@ package pkg
import ( import (
"fmt" "fmt"
"github.com/jkaninda/mysql-bkup/utils" "github.com/jkaninda/mysql-bkup/utils"
"github.com/spf13/cobra"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
) )
func StartRestore(cmd *cobra.Command) {
//Set env
utils.SetEnv("STORAGE_PATH", storagePath)
utils.GetEnv(cmd, "dbname", "DB_NAME")
utils.GetEnv(cmd, "port", "DB_PORT")
//Get flag value and set env
s3Path = utils.GetEnv(cmd, "path", "S3_PATH")
storage = utils.GetEnv(cmd, "storage", "STORAGE")
file = utils.GetEnv(cmd, "file", "FILE_NAME")
executionMode, _ = cmd.Flags().GetString("mode")
if storage == "s3" {
utils.Info("Restore database from s3")
s3Restore(file, s3Path)
} else {
utils.Info("Restore database from local")
RestoreDatabase(file)
}
}
// RestoreDatabase restore database // RestoreDatabase restore database
func RestoreDatabase(file string) { func RestoreDatabase(file string) {
dbHost = os.Getenv("DB_HOST") dbHost = os.Getenv("DB_HOST")
dbPassword = os.Getenv("DB_PASSWORD")
dbUserName = os.Getenv("DB_USERNAME")
dbName = os.Getenv("DB_NAME") dbName = os.Getenv("DB_NAME")
dbPort = os.Getenv("DB_PORT") dbPort = os.Getenv("DB_PORT")
storagePath = os.Getenv("STORAGE_PATH") storagePath = os.Getenv("STORAGE_PATH")
if file == "" {
utils.Fatal("Error required --file")
}
if os.Getenv("DB_HOST") == "" || os.Getenv("DB_NAME") == "" || os.Getenv("DB_USERNAME") == "" || os.Getenv("DB_PASSWORD") == "" || file == "" { if os.Getenv("DB_HOST") == "" || os.Getenv("DB_NAME") == "" || os.Getenv("DB_USERNAME") == "" || os.Getenv("DB_PASSWORD") == "" || file == "" {
utils.Fatal("Please make sure all required environment variables are set") utils.Fatal("Please make sure all required environment variables are set")
@@ -54,3 +79,8 @@ func RestoreDatabase(file string) {
} }
} }
func s3Restore(file, s3Path string) {
// Restore database from S3
MountS3Storage(s3Path)
RestoreDatabase(file)
}

View File

@@ -11,9 +11,6 @@ import (
"os/exec" "os/exec"
) )
const s3MountPath string = "/s3mnt"
const s3fsPasswdFile string = "/etc/passwd-s3fs"
var ( var (
accessKey = "" accessKey = ""
secretKey = "" secretKey = ""
@@ -21,6 +18,10 @@ var (
s3Endpoint = "" s3Endpoint = ""
) )
func S3Mount() {
MountS3Storage(s3Path)
}
// MountS3Storage Mount s3 storage using s3fs // MountS3Storage Mount s3 storage using s3fs
func MountS3Storage(s3Path string) { func MountS3Storage(s3Path string) {
accessKey = os.Getenv("ACCESS_KEY") accessKey = os.Getenv("ACCESS_KEY")
@@ -46,7 +47,7 @@ func MountS3Storage(s3Path string) {
utils.ChangePermission(s3fsPasswdFile, 0600) utils.ChangePermission(s3fsPasswdFile, 0600)
//Mount object storage //Mount object storage
utils.Info("Mounting Object storage in", s3MountPath) utils.Info("Mounting Object storage in ", s3MountPath)
if isEmpty, _ := utils.IsDirEmpty(s3MountPath); isEmpty { if isEmpty, _ := utils.IsDirEmpty(s3MountPath); isEmpty {
cmd := exec.Command("s3fs", bucketName, s3MountPath, cmd := exec.Command("s3fs", bucketName, s3MountPath,
"-o", "passwd_file="+s3fsPasswdFile, "-o", "passwd_file="+s3fsPasswdFile,

View File

@@ -30,12 +30,12 @@ func CreateCrontabScript(disableCompression bool, storage string) {
if storage == "s3" { if storage == "s3" {
scriptContent = fmt.Sprintf(`#!/usr/bin/env bash scriptContent = fmt.Sprintf(`#!/usr/bin/env bash
set -e set -e
bkup --operation backup --dbname %s --port %s --storage s3 --path %s %v bkup backup --dbname %s --port %s --storage s3 --path %s %v
`, os.Getenv("DB_NAME"), os.Getenv("DB_PORT"), os.Getenv("S3_PATH"), disableC) `, os.Getenv("DB_NAME"), os.Getenv("DB_PORT"), os.Getenv("S3_PATH"), disableC)
} else { } else {
scriptContent = fmt.Sprintf(`#!/usr/bin/env bash scriptContent = fmt.Sprintf(`#!/usr/bin/env bash
set -e set -e
bkup --operation backup --dbname %s --port %s %v bkup backup --dbname %s --port %s %v
`, os.Getenv("DB_NAME"), os.Getenv("DB_PORT"), disableC) `, os.Getenv("DB_NAME"), os.Getenv("DB_PORT"), disableC)
} }

16
pkg/var.go Normal file
View File

@@ -0,0 +1,16 @@
package pkg
const s3MountPath string = "/s3mnt"
const s3fsPasswdFile string = "/etc/passwd-s3fs"
var (
storage = "local"
file = ""
s3Path = "/mysql-bkup"
dbName = ""
dbHost = ""
dbPort = "3306"
executionMode = "default"
storagePath = "/backup"
disableCompression = false
)

View File

@@ -5,4 +5,4 @@ DB_HOST='db_hostname'
DB_NAME='db_name' DB_NAME='db_name'
BACKUP_DIR="$PWD/backup" BACKUP_DIR="$PWD/backup"
docker run --rm --name mysql-bkup -v $BACKUP_DIR:/backup/ -e "DB_HOST=$DB_HOST" -e "DB_USERNAME=$DB_USERNAME" -e "DB_PASSWORD=$DB_PASSWORD" jkaninda/mysql-bkup:latest bkup -o backup -d $DB_NAME docker run --rm --name mysql-bkup -v $BACKUP_DIR:/backup/ -e "DB_HOST=$DB_HOST" -e "DB_USERNAME=$DB_USERNAME" -e "DB_PASSWORD=$DB_PASSWORD" jkaninda/mysql-bkup:latest backup -d $DB_NAME

15
utils/constant.go Normal file
View File

@@ -0,0 +1,15 @@
package utils
const Notice = "Please remove --operation flag.\n" +
"Use: \n" +
"- backup for backup operation [eg: bkup backup -d database_name ...]\n" +
"- restore for restore operation [eg. bkup restore -d database_name ...]\n" +
"We are sorry for this inconvenient"
const RestoreExample = "mysql-bkup restore --dbname database --file db_20231219_022941.sql.gz\n" +
"bkup restore --dbname database --storage s3 --path /custom-path --file db_20231219_022941.sql.gz"
const BackupExample = "mysql-bkup backup --dbname database --disable-compression\n" +
"mysql-bkup backup --dbname database --storage s3 --path /custom-path --disable-compression"
const MainExample = "mysql-bkup backup --dbname database --disable-compression\n" +
"mysql-bkup backup --dbname database --storage s3 --path /custom-path\n" +
"mysql-bkup restore --dbname database --file db_20231219_022941.sql.gz"

View File

@@ -8,6 +8,7 @@ package utils
**/ **/
import ( import (
"fmt" "fmt"
"github.com/spf13/cobra"
"io/fs" "io/fs"
"os" "os"
"os/exec" "os/exec"
@@ -78,3 +79,36 @@ func TestDatabaseConnection() {
} }
} }
func GetEnv(cmd *cobra.Command, flagName, envName string) string {
value, _ := cmd.Flags().GetString(flagName)
if value != "" {
err := os.Setenv(envName, value)
if err != nil {
return value
}
}
return os.Getenv(envName)
}
func FlagGetString(cmd *cobra.Command, flagName string) string {
value, _ := cmd.Flags().GetString(flagName)
if value != "" {
return value
}
return ""
}
func FlagGetBool(cmd *cobra.Command, flagName string) bool {
value, _ := cmd.Flags().GetBool(flagName)
return value
}
func SetEnv(key, value string) {
err := os.Setenv(key, value)
if err != nil {
return
}
}
func ShowHistory() {
}