Compare commits

...

16 Commits
v0.4 ... v0.5

Author SHA1 Message Date
bf566af4f8 Merge pull request #45 from jkaninda/refactor
Refactor
2024-01-20 14:07:32 +01:00
99ea4e18e5 chore: update app version 2024-01-20 14:06:42 +01:00
748416af9b chore: update error message 2024-01-20 14:01:23 +01:00
bce9512d6a chore: update error message 2024-01-20 13:59:47 +01:00
8eff38bdb1 docs: update readme 2024-01-20 13:09:15 +01:00
c12a6751ae docs: update readme 2024-01-20 13:07:04 +01:00
05eda4213a feat: replace --operation flag by backup and restore command 2024-01-20 13:04:39 +01:00
a919b161c8 Merge pull request #44 from jkaninda/develop
Develop
2024-01-20 04:06:19 +01:00
4b07a78f29 chore: add mysql_bkup Symlink link 2024-01-20 04:05:28 +01:00
4a0ad39d70 docs: update readme 2024-01-20 04:02:39 +01:00
0be493d51f Merge pull request #43 from jkaninda/develop
Merge pull request #42 from jkaninda/develop
2024-01-19 14:53:34 +01:00
cdb4b2017a Merge pull request #42 from jkaninda/develop
refactor: refactoring of code
2024-01-19 14:52:02 +01:00
09ba8f8981 Merge pull request #42 from jkaninda/develop
refactore: refactoring of code
2024-01-19 14:32:29 +01:00
2ae78fec57 refactore: refactoring of code 2024-01-19 14:29:37 +01:00
2cd74167de Merge pull request #41 from jkaninda/develop
chore: clean up code
2024-01-19 14:13:38 +01:00
aaad8a010c chore: clean up code 2024-01-19 14:12:05 +01:00
23 changed files with 377 additions and 309 deletions

View File

@@ -35,5 +35,5 @@ jobs:
file: "./docker/Dockerfile"
platforms: linux/amd64,linux/arm64
tags: |
"${{env.BUILDKIT_IMAGE}}:v0.4"
"${{env.BUILDKIT_IMAGE}}:v0.5"
"${{env.BUILDKIT_IMAGE}}:latest"

View File

@@ -38,21 +38,23 @@ MySQL Backup and Restoration tool. Backup database to AWS S3 storage or any S3 A
## Usage
| Options | Shorts | Usage |
|---------------|--------|------------------------------------|
| mysql_bkup | bkup | CLI utility |
| --operation | -o | Set operation. backup or restore (default: backup) |
| --storage | -s | Set storage. local or s3 (default: local) |
| --file | -f | Set file name for restoration |
| --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) |
| --disable-compression | | Disable database backup compression |
| --period | | Set crontab period for scheduled mode only. (default: "0 1 * * *") |
| --timeout | -t | Set timeout (default: 60s) |
| --help | -h | Print this help message and exit |
| --version | -V | Print version information and exit |
| Options | Shorts | Usage |
|-----------------------|--------|--------------------------------------------------------------------|
| mysql-bkup | bkup | CLI utility |
| backup | | Backup database operation |
| restore | | Restore database operation |
| history | | Show the history of backup |
| --storage | -s | Set storage. local or s3 (default: local) |
| --file | -f | Set file name for restoration |
| --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) |
| --disable-compression | | Disable database backup compression |
| --period | | Set crontab period for scheduled mode only. (default: "0 1 * * *") |
| --timeout | -t | Set timeout (default: 60s) |
| --help | -h | Print this help message and exit |
| --version | -V | Print version information and exit |
## Note:
@@ -81,20 +83,20 @@ FLUSH PRIVILEGES;
Simple backup usage
```sh
bkup --operation backup --dbname database_name
bkup backup --dbname database_name
```
```sh
bkup -o backup -d database_name
bkup backup -d database_name
```
### S3
```sh
bkup --operation backup --storage s3 --dbname database_name
bkup backup --storage s3 --dbname database_name
```
## Docker run:
```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:
@@ -115,7 +117,7 @@ services:
command:
- /bin/sh
- -c
- bkup --operation backup -d database_name
- bkup backup -d database_name
volumes:
- ./backup:/backup
environment:
@@ -129,22 +131,22 @@ services:
Simple database restore operation usage
```sh
bkup --operation restore --dbname database_name --file database_20231217_115621.sql
bkup restore --dbname database_name --file database_20231217_115621.sql
```
```sh
bkup -o restore -f database_20231217_115621.sql
bkup restore -f database_20231217_115621.sql
```
### S3
```sh
bkup --operation restore --storage s3 --file database_20231217_115621.sql
bkup restore --storage s3 --file database_20231217_115621.sql
```
## Docker run:
```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:
@@ -166,7 +168,7 @@ services:
command:
- /bin/sh
- -c
- bkup --operation restore --file database_20231217_115621.sql --dbname database_name
- bkup restore --file database_20231217_115621.sql --dbname database_name
volumes:
- ./backup:/backup
environment:
@@ -185,14 +187,14 @@ docker-compose up -d
## Backup to S3
```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
Simple S3 backup usage
```sh
bkup --operation backup --storage s3 --dbname mydatabase
bkup backup --storage s3 --dbname mydatabase
```
```yaml
version: '3'
@@ -206,7 +208,7 @@ services:
command:
- /bin/sh
- -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:
- DB_PORT=3306
- DB_HOST=mysql
@@ -273,7 +275,7 @@ Easy to remember format:
> Docker run :
```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
@@ -290,7 +292,7 @@ services:
command:
- /bin/sh
- -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:
- DB_PORT=3306
- DB_HOST=mysqlhost
@@ -327,7 +329,7 @@ spec:
command:
- /bin/sh
- -c
- bkup -o backup -s s3 --path /custom_path
- bkup backup -s s3 --path /custom_path
env:
- name: DB_PORT
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
import (
"os"
"fmt"
"github.com/jkaninda/mysql-bkup/utils"
"github.com/spf13/cobra"
"os"
)
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "mysql-bkup",
Short: "MySQL Backup tool, backup database to S3 or Object Storage",
Long: `MySQL 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
// has an action associated with it:
// Run: func(cmd *cobra.Command, args []string) { },
Use: "mysql-bkup [Command]",
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.`,
Example: utils.MainExample,
Version: appVersion,
//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.
// This is called by main.main(). It only needs to happen once to the rootCmd.
@@ -30,25 +42,21 @@ func Execute() {
}
func init() {
// Here you will define your flags and configuration settings.
// Cobra supports persistent flags, which, if defined here,
// will be global for your application.
// 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("file", "f", "", "Set file name")
rootCmd.PersistentFlags().StringP("path", "P", "/mysql-bkup", "Set s3 path, without file name")
rootCmd.PersistentFlags().StringP("path", "P", s3Path, "Set s3 path, without file name. for S3 storage only")
rootCmd.PersistentFlags().StringP("dbname", "d", "", "Set database name")
rootCmd.PersistentFlags().IntP("timeout", "t", 30, "Set timeout")
rootCmd.PersistentFlags().IntP("port", "p", 3306, "Set database port")
rootCmd.PersistentFlags().StringVarP(&operation, "operation", "o", "", "Set operation, for old version only")
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().BoolP("disable-compression", "", false, "Disable backup compression")
rootCmd.PersistentFlags().IntP("port", "p", 3306, "Set database port")
rootCmd.PersistentFlags().BoolP("help", "h", false, "Print this help message")
rootCmd.PersistentFlags().BoolP("version", "v", false, "shows version information")
rootCmd.PersistentFlags().StringP("file", "f", "", "File name of database")
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()
},
}

26
cmd/version.go Normal file
View File

@@ -0,0 +1,26 @@
package cmd
/*
Copyright © 2024 Jonas Kaninda <jonaskaninda@gmail.com>
*/
import (
"fmt"
"github.com/spf13/cobra"
"os"
)
var appVersion = os.Getenv("VERSION")
var VersionCmd = &cobra.Command{
Use: "version",
Short: "Show version",
Run: func(cmd *cobra.Command, args []string) {
Version()
},
}
func Version() {
fmt.Printf("Version: %s \n", appVersion)
fmt.Println()
}

View File

@@ -21,7 +21,7 @@ ENV ACCESS_KEY=""
ENV SECRET_KEY=""
ENV S3_ENDPOINT=https://s3.amazonaws.com
ARG DEBIAN_FRONTEND=noninteractive
ENV VERSION="v0.4"
ENV VERSION="v0.5"
LABEL authors="Jonas Kaninda"
RUN apt-get update -qq
@@ -40,6 +40,8 @@ COPY --from=build /app/mysql-bkup /usr/local/bin/mysql-bkup
RUN chmod +x /usr/local/bin/mysql-bkup
RUN ln -s /usr/local/bin/mysql-bkup /usr/local/bin/bkup
RUN ln -s /usr/local/bin/mysql-bkup /usr/local/bin/mysql_bkup
ADD docker/supervisord.conf /etc/supervisor/supervisord.conf

View File

@@ -9,7 +9,7 @@ services:
command:
- /bin/sh
- -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:
- DB_PORT=3306
- DB_HOST=mysqlhost

View File

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

View File

@@ -9,7 +9,7 @@ services:
command:
- /bin/sh
- -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:
- DB_PORT=3306
- DB_HOST=mysqlhost

View File

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

View File

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

214
main.go
View File

@@ -1,222 +1,16 @@
package main
//main
/*****
* MySQL Backup & Restore
* MySQL Backup & Restore
* @author Jonas Kaninda
* @license MIT License <https://opensource.org/licenses/MIT>
* @link https://github.com/jkaninda/mysql-bkup
**/
import (
"fmt"
"github.com/jkaninda/mysql-bkup/pkg"
"github.com/jkaninda/mysql-bkup/utils"
flag "github.com/spf13/pflag"
"os"
"os/exec"
)
import "github.com/jkaninda/mysql-bkup/cmd"
var appVersion string = os.Getenv("VERSION")
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 BackupDatabase and Restoration tool. BackupDatabase 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(" RestoreDatabase: 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
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 version() {
fmt.Printf("Version: %s \n", appVersion)
fmt.Print()
}
func main() {
//cmd.Execute()
err := os.Setenv("STORAGE_PATH", storagePath)
if err != nil {
return
}
if startBackup {
start()
}
cmd.Execute()
}
func start() {
if executionMode == "default" {
if operation != "backup" {
if storage != "s3" {
utils.Info("RestoreDatabase from local")
pkg.RestoreDatabase(file)
} else {
utils.Info("RestoreDatabase from s3")
s3Restore()
}
} else {
if storage != "s3" {
utils.Info("BackupDatabase to local storage")
pkg.BackupDatabase(disableCompression)
} else {
utils.Info("BackupDatabase 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)
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 (
"fmt"
"github.com/jkaninda/mysql-bkup/utils"
"github.com/spf13/cobra"
"log"
"os"
"os/exec"
"time"
)
var (
dbName = ""
dbHost = ""
dbPort = ""
dbPassword = ""
dbUserName = ""
storagePath = "/backup"
)
func StartBackup(cmd *cobra.Command) {
_, _ = cmd.Flags().GetString("operation")
//Set env
utils.SetEnv("STORAGE_PATH", storagePath)
utils.GetEnv(cmd, "dbname", "DB_NAME")
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
func BackupDatabase(disableCompression bool) {
dbHost = os.Getenv("DB_HOST")
dbPassword = os.Getenv("DB_PASSWORD")
dbUserName = os.Getenv("DB_USERNAME")
dbPassword := os.Getenv("DB_PASSWORD")
dbUserName := os.Getenv("DB_USERNAME")
dbName = os.Getenv("DB_NAME")
dbPort = os.Getenv("DB_PORT")
storagePath = os.Getenv("STORAGE_PATH")
@@ -37,10 +86,14 @@ func BackupDatabase(disableCompression bool) {
utils.TestDatabaseConnection()
// Backup Database database
utils.Info("Backing up database...")
//Generate file name
bkFileName := fmt.Sprintf("%s_%s.sql.gz", dbName, time.Now().Format("20060102_150405"))
// Verify is compression is disabled
if disableCompression {
//Generate file name
bkFileName = fmt.Sprintf("%s_%s.sql", dbName, time.Now().Format("20060102_150405"))
// Execute mysqldump
cmd := exec.Command("mysqldump",
"-h", dbHost,
"-P", dbPort,
@@ -53,6 +106,7 @@ func BackupDatabase(disableCompression bool) {
log.Fatal(err)
}
// save output
file, err := os.Create(fmt.Sprintf("%s/%s", storagePath, bkFileName))
if err != nil {
log.Fatal(err)
@@ -63,14 +117,13 @@ func BackupDatabase(disableCompression bool) {
if err != nil {
log.Fatal(err)
}
utils.Info("Database has been backed up")
utils.Done("Database has been backed up")
} else {
// Execute mysqldump
cmd := exec.Command("mysqldump", "-h", dbHost, "-P", dbPort, "-u", dbUserName, "--password="+dbPassword, dbName)
stdout, err := cmd.StdoutPipe()
if err != nil {
utils.Info("Mysql")
log.Fatal(err)
}
gzipCmd := exec.Command("gzip")
@@ -86,7 +139,7 @@ func BackupDatabase(disableCompression bool) {
if err := gzipCmd.Wait(); err != nil {
log.Fatal(err)
}
utils.Info("Database has been backed up")
utils.Done("Database has been backed up")
}
@@ -101,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 (
"fmt"
"github.com/jkaninda/mysql-bkup/utils"
"github.com/spf13/cobra"
"os"
"os/exec"
"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
func RestoreDatabase(file string) {
dbHost = os.Getenv("DB_HOST")
dbPassword = os.Getenv("DB_PASSWORD")
dbUserName = os.Getenv("DB_USERNAME")
dbName = os.Getenv("DB_NAME")
dbPort = os.Getenv("DB_PORT")
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 == "" {
utils.Fatal("Please make sure all required environment variables are set")
@@ -25,7 +50,7 @@ func RestoreDatabase(file string) {
utils.TestDatabaseConnection()
extension := filepath.Ext(fmt.Sprintf("%s/%s", storagePath, file))
// GZ compressed file
// Restore from compressed file / .sql.gz
if extension == ".gz" {
str := "zcat " + fmt.Sprintf("%s/%s", storagePath, file) + " | mysql -h " + os.Getenv("DB_HOST") + " -P " + os.Getenv("DB_PORT") + " -u " + os.Getenv("DB_USERNAME") + " --password=" + os.Getenv("DB_PASSWORD") + " " + os.Getenv("DB_NAME")
_, err := exec.Command("bash", "-c", str).Output()
@@ -33,17 +58,17 @@ func RestoreDatabase(file string) {
utils.Fatal("Error, in restoring the database")
}
utils.Info("Database has been restored")
utils.Done("Database has been restored")
} else if extension == ".sql" {
//SQL file
//Restore from sql file
str := "cat " + fmt.Sprintf("%s/%s", storagePath, file) + " | mysql -h " + os.Getenv("DB_HOST") + " -P " + os.Getenv("DB_PORT") + " -u " + os.Getenv("DB_USERNAME") + " --password=" + os.Getenv("DB_PASSWORD") + " " + os.Getenv("DB_NAME")
_, err := exec.Command("bash", "-c", str).Output()
if err != nil {
utils.Fatal("Error, in restoring the database", err)
}
utils.Info("Database has been restored")
utils.Done("Database has been restored")
} else {
utils.Fatal("Unknown file extension ", extension)
}
@@ -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"
)
const s3MountPath string = "/s3mnt"
const s3fsPasswdFile string = "/etc/passwd-s3fs"
var (
accessKey = ""
secretKey = ""
@@ -21,6 +18,10 @@ var (
s3Endpoint = ""
)
func S3Mount() {
MountS3Storage(s3Path)
}
// MountS3Storage Mount s3 storage using s3fs
func MountS3Storage(s3Path string) {
accessKey = os.Getenv("ACCESS_KEY")
@@ -44,7 +45,9 @@ func MountS3Storage(s3Path string) {
}
//Change file permission
utils.ChangePermission(s3fsPasswdFile, 0600)
utils.Info("Mounting Object storage in", s3MountPath)
//Mount object storage
utils.Info("Mounting Object storage in ", s3MountPath)
if isEmpty, _ := utils.IsDirEmpty(s3MountPath); isEmpty {
cmd := exec.Command("s3fs", bucketName, s3MountPath,
"-o", "passwd_file="+s3fsPasswdFile,

View File

@@ -30,12 +30,12 @@ func CreateCrontabScript(disableCompression bool, storage string) {
if storage == "s3" {
scriptContent = fmt.Sprintf(`#!/usr/bin/env bash
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)
} else {
scriptContent = fmt.Sprintf(`#!/usr/bin/env bash
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)
}

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'
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

16
utils/constant.go Normal file
View File

@@ -0,0 +1,16 @@
package utils
const Notice = "Please remove --operation flag.\n" +
"Use: \n" +
"- backup for database backup operation [eg: bkup backup -d database_name ...]\n" +
"- restore for database restore operation [eg. bkup restore -d database_name ...]\n" +
"Example: bkup backup --storage s3 ...( instead of < bkup --operation backup >)\n" +
"We are sorry for this inconvenient\n"
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,29 +8,24 @@ package utils
**/
import (
"fmt"
"github.com/spf13/cobra"
"io/fs"
"os"
"os/exec"
)
func Info(v ...any) {
fmt.Println("[INFO] ", fmt.Sprint(v...))
fmt.Println(" ", fmt.Sprint(v...))
}
func Infof(msg string, v ...any) {
fmt.Printf("[INFO] "+msg, v...)
}
func Warning(message string) {
fmt.Println("[WARNING]", message)
}
func Warningf(msg string, v ...any) {
fmt.Printf("[WARNING] "+msg, v...)
func Done(v ...any) {
fmt.Println("✔ ", fmt.Sprint(v...))
}
func Fatal(v ...any) {
fmt.Println("[ERROR] ", fmt.Sprint(v...))
fmt.Println(" ", fmt.Sprint(v...))
os.Exit(1)
}
func Fatalf(msg string, v ...any) {
fmt.Printf("[ERROR] "+msg, v...)
fmt.Printf(" "+msg, v...)
os.Exit(1)
}
@@ -84,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() {
}