mirror of
https://github.com/jkaninda/mysql-bkup.git
synced 2025-12-06 13:39:41 +01:00
Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
041e0a07e9 | ||
|
|
9daac9c654 | ||
|
|
f6098769cd | ||
|
|
5cdfaa4d94 | ||
|
|
b205cd61ea | ||
|
|
e1307250e8 | ||
|
|
17ac951deb | ||
|
|
6e2e08224d | ||
|
|
570b775f48 | ||
|
|
e38e106983 | ||
|
|
3040420a09 | ||
|
|
eac5f70408 | ||
|
|
3476c6f529 | ||
|
|
1a9c8483f8 | ||
|
|
f8722f7ae4 | ||
|
|
421bf12910 | ||
|
|
3da4a27baa | ||
|
|
0881f075ef | ||
|
|
066e73f8e4 | ||
|
|
645243ff77 | ||
|
|
9384998127 | ||
|
|
390e7dad0c | ||
|
|
67ea22385f | ||
|
|
cde82d8cfc | ||
|
|
4808f093e5 | ||
|
|
c7a03861fe | ||
|
|
36ec63d522 | ||
|
|
0f07de1d83 | ||
|
|
ae55839996 | ||
|
|
a7f7e57a0d | ||
|
|
b2ddaec93b | ||
|
|
b3570d774c | ||
|
|
38f7e91c03 | ||
|
|
07c2935925 |
3
.github/FUNDING.yml
vendored
Normal file
3
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
ko_fi: jkaninda
|
||||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -1,4 +1,4 @@
|
|||||||
name: Release
|
name: CI
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
# MySQL Backup
|
# MySQL Backup
|
||||||
MySQL Backup is a Docker container image that can be used to backup and restore MySQL database. It supports local storage, AWS S3 or any S3 Alternatives for Object Storage, and SSH compatible storage.
|
MySQL Backup is a Docker container image that can be used to backup, restore and migrate MySQL database. It supports local storage, AWS S3 or any S3 Alternatives for Object Storage, and SSH compatible storage.
|
||||||
It also supports __encrypting__ your backups using GPG.
|
It also supports __encrypting__ your backups using GPG.
|
||||||
|
|
||||||
The [jkaninda/mysql-bkup](https://hub.docker.com/r/jkaninda/mysql-bkup) Docker image can be deployed on Docker, Docker Swarm and Kubernetes.
|
The [jkaninda/mysql-bkup](https://hub.docker.com/r/jkaninda/mysql-bkup) Docker image can be deployed on Docker, Docker Swarm and Kubernetes.
|
||||||
It handles __recurring__ backups of postgres database on Docker and can be deployed as __CronJob on Kubernetes__ using local, AWS S3 or SSH compatible storage.
|
It handles __recurring__ backups of postgres database on Docker and can be deployed as __CronJob on Kubernetes__ using local, AWS S3 or SSH compatible storage.
|
||||||
|
|
||||||
It also supports __encrypting__ your backups using GPG.
|
It also supports database __encryption__ using GPG.
|
||||||
|
|
||||||
[](https://github.com/jkaninda/mysql-bkup/actions/workflows/release.yml)
|
[](https://github.com/jkaninda/mysql-bkup/actions/workflows/release.yml)
|
||||||
[](https://goreportcard.com/report/github.com/jkaninda/mysql-bkup)
|
[](https://goreportcard.com/report/github.com/jkaninda/mysql-bkup)
|
||||||

|

|
||||||

|

|
||||||
|
<a href="https://ko-fi.com/jkaninda"><img src="https://uploads-ssl.webflow.com/5c14e387dab576fe667689cf/5cbed8a4ae2b88347c06c923_BuyMeACoffee_blue.png" height="20" alt="buy ma a coffee"></a>
|
||||||
|
|
||||||
Successfully tested on:
|
Successfully tested on:
|
||||||
- Docker
|
- Docker
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
// Package cmd /
|
||||||
|
/*****
|
||||||
|
@author Jonas Kaninda
|
||||||
|
@license MIT License <https://opensource.org/licenses/MIT>
|
||||||
|
@Copyright © 2024 Jonas Kaninda
|
||||||
|
**/
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
// Package cmd /
|
||||||
|
/*****
|
||||||
|
@author Jonas Kaninda
|
||||||
|
@license MIT License <https://opensource.org/licenses/MIT>
|
||||||
|
@Copyright © 2024 Jonas Kaninda
|
||||||
|
**/
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
11
cmd/root.go
11
cmd/root.go
@@ -1,7 +1,9 @@
|
|||||||
// Package cmd /*
|
// Package cmd /
|
||||||
/*
|
/*****
|
||||||
Copyright © 2024 Jonas Kaninda
|
@author Jonas Kaninda
|
||||||
*/
|
@license MIT License <https://opensource.org/licenses/MIT>
|
||||||
|
@Copyright © 2024 Jonas Kaninda
|
||||||
|
**/
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -31,7 +33,6 @@ func Execute() {
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.PersistentFlags().StringP("dbname", "d", "", "Database name")
|
rootCmd.PersistentFlags().StringP("dbname", "d", "", "Database name")
|
||||||
rootCmd.PersistentFlags().StringVarP(&operation, "operation", "o", "", "Set operation, for old version only")
|
|
||||||
rootCmd.AddCommand(VersionCmd)
|
rootCmd.AddCommand(VersionCmd)
|
||||||
rootCmd.AddCommand(BackupCmd)
|
rootCmd.AddCommand(BackupCmd)
|
||||||
rootCmd.AddCommand(RestoreCmd)
|
rootCmd.AddCommand(RestoreCmd)
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
|
// Package cmd /
|
||||||
|
/*****
|
||||||
|
@author Jonas Kaninda
|
||||||
|
@license MIT License <https://opensource.org/licenses/MIT>
|
||||||
|
@Copyright © 2024 Jonas Kaninda
|
||||||
|
**/
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright © 2024 Jonas Kaninda
|
|
||||||
*/
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ RUN go mod download
|
|||||||
RUN CGO_ENABLED=0 GOOS=linux go build -o /app/mysql-bkup
|
RUN CGO_ENABLED=0 GOOS=linux go build -o /app/mysql-bkup
|
||||||
|
|
||||||
FROM ubuntu:24.04
|
FROM ubuntu:24.04
|
||||||
ENV DB_HOST=""
|
ENV DB_HOST="localhost"
|
||||||
ENV DB_NAME=""
|
ENV DB_NAME=""
|
||||||
ENV DB_USERNAME=""
|
ENV DB_USERNAME=""
|
||||||
ENV DB_PASSWORD=""
|
ENV DB_PASSWORD=""
|
||||||
@@ -30,14 +30,16 @@ ENV SSH_PASSWORD=""
|
|||||||
ENV SSH_HOST_NAME=""
|
ENV SSH_HOST_NAME=""
|
||||||
ENV SSH_IDENTIFY_FILE=""
|
ENV SSH_IDENTIFY_FILE=""
|
||||||
ENV SSH_PORT="22"
|
ENV SSH_PORT="22"
|
||||||
ENV SOURCE_DB_HOST=""
|
ENV TARGET_DB_HOST=""
|
||||||
ENV SOURCE_DB_PORT=3306
|
ENV TARGET_DB_PORT=3306
|
||||||
ENV SOURCE_DB_NAME=""
|
ENV TARGET_DB_NAME="localhost"
|
||||||
ENV SOURCE_DB_USERNAME=""
|
ENV TARGET_DB_USERNAME=""
|
||||||
ENV SOURCE_DB_PASSWORD=""
|
ENV TARGET_DB_PASSWORD=""
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
ENV VERSION="v1.2.3"
|
ENV VERSION="v1.2.7"
|
||||||
ENV BACKUP_CRON_EXPRESSION=""
|
ENV BACKUP_CRON_EXPRESSION=""
|
||||||
|
ENV TG_TOKEN=""
|
||||||
|
ENV TG_CHAT_ID=""
|
||||||
ARG WORKDIR="/config"
|
ARG WORKDIR="/config"
|
||||||
ARG BACKUPDIR="/backup"
|
ARG BACKUPDIR="/backup"
|
||||||
ARG BACKUP_TMP_DIR="/tmp/backup"
|
ARG BACKUP_TMP_DIR="/tmp/backup"
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
FROM ruby:3.3.4
|
|
||||||
|
|
||||||
ENV LC_ALL C.UTF-8
|
|
||||||
ENV LANG en_US.UTF-8
|
|
||||||
ENV LANGUAGE en_US.UTF-8
|
|
||||||
|
|
||||||
WORKDIR /usr/src/app
|
|
||||||
|
|
||||||
COPY . ./
|
|
||||||
RUN gem install bundler && bundle install
|
|
||||||
|
|
||||||
EXPOSE 4000
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
services:
|
|
||||||
jekyll:
|
|
||||||
build:
|
|
||||||
context: ./
|
|
||||||
ports:
|
|
||||||
- 4000:4000
|
|
||||||
environment:
|
|
||||||
- JEKYLL_ENV=development
|
|
||||||
volumes:
|
|
||||||
- .:/usr/src/app
|
|
||||||
stdin_open: true
|
|
||||||
tty: true
|
|
||||||
command: bundle exec jekyll serve -H 0.0.0.0 -t
|
|
||||||
@@ -104,7 +104,7 @@ spec:
|
|||||||
command:
|
command:
|
||||||
- /bin/sh
|
- /bin/sh
|
||||||
- -c
|
- -c
|
||||||
- mysql-bkup backup -s s3 --path /custom_path
|
- backup -s s3 --path /custom_path
|
||||||
env:
|
env:
|
||||||
- name: DB_PORT
|
- name: DB_PORT
|
||||||
value: "3306"
|
value: "3306"
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ spec:
|
|||||||
command:
|
command:
|
||||||
- /bin/sh
|
- /bin/sh
|
||||||
- -c
|
- -c
|
||||||
- mysql-bkup backup -s ssh
|
- backup -s ssh
|
||||||
env:
|
env:
|
||||||
- name: DB_PORT
|
- name: DB_PORT
|
||||||
value: "3306"
|
value: "3306"
|
||||||
|
|||||||
@@ -30,10 +30,7 @@ spec:
|
|||||||
command:
|
command:
|
||||||
- /bin/sh
|
- /bin/sh
|
||||||
- -c
|
- -c
|
||||||
- bkup
|
- backup --storage s3
|
||||||
- backup
|
|
||||||
- --storage
|
|
||||||
- s3
|
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
memory: "128Mi"
|
memory: "128Mi"
|
||||||
|
|||||||
@@ -10,11 +10,13 @@ nav_order: 9
|
|||||||
To migrate the database, you need to add `migrate` command.
|
To migrate the database, you need to add `migrate` command.
|
||||||
|
|
||||||
{: .note }
|
{: .note }
|
||||||
The Mysql backup has another great feature: migrating your database from a source database to another.
|
The Mysql backup has another great feature: migrating your database from a source database to a target.
|
||||||
|
|
||||||
As you know, to restore a database from a source to a target database, you need 2 operations: which is to start by backing up the source database and then restoring the source backed database to the target database.
|
As you know, to restore a database from a source to a target database, you need 2 operations: which is to start by backing up the source database and then restoring the source backed database to the target database.
|
||||||
Instead of proceeding like that, you can use the integrated feature `(migrate)`, which will help you migrate your database by doing only one operation.
|
Instead of proceeding like that, you can use the integrated feature `(migrate)`, which will help you migrate your database by doing only one operation.
|
||||||
|
|
||||||
|
{: .warning }
|
||||||
|
The `migrate` operation is irreversible, please backup your target database before this action.
|
||||||
|
|
||||||
### Docker compose
|
### Docker compose
|
||||||
```yml
|
```yml
|
||||||
@@ -30,18 +32,18 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ./backup:/backup
|
- ./backup:/backup
|
||||||
environment:
|
environment:
|
||||||
## Target database
|
## Source database
|
||||||
- DB_PORT=3306
|
- DB_PORT=3306
|
||||||
- DB_HOST=mysql
|
- DB_HOST=mysql
|
||||||
- DB_NAME=database
|
- DB_NAME=database
|
||||||
- DB_USERNAME=username
|
- DB_USERNAME=username
|
||||||
- DB_PASSWORD=password
|
- DB_PASSWORD=password
|
||||||
## Source database
|
## Target database
|
||||||
- SOURCE_DB_HOST=mysql2
|
- TARGET_DB_HOST=target-mysql
|
||||||
- SOURCE_DB_PORT=3306
|
- TARGET_DB_PORT=3306
|
||||||
- SOURCE_DB_NAME=sourcedb
|
- TARGET_DB_NAME=dbname
|
||||||
- SOURCE_DB_USERNAME=jonas
|
- TARGET_DB_USERNAME=username
|
||||||
- SOURCE_DB_PASSWORD=password
|
- TARGET_DB_PASSWORD=password
|
||||||
# mysql-bkup container must be connected to the same network with your database
|
# mysql-bkup container must be connected to the same network with your database
|
||||||
networks:
|
networks:
|
||||||
- web
|
- web
|
||||||
@@ -49,30 +51,31 @@ networks:
|
|||||||
web:
|
web:
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Migrate database using Docker CLI
|
### Migrate database using Docker CLI
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
## Target database
|
## Source database
|
||||||
DB_PORT=3306
|
|
||||||
DB_HOST=mysql
|
DB_HOST=mysql
|
||||||
DB_NAME=targetdb
|
DB_PORT=3306
|
||||||
DB_USERNAME=targetuser
|
DB_NAME=dbname
|
||||||
|
DB_USERNAME=username
|
||||||
DB_PASSWORD=password
|
DB_PASSWORD=password
|
||||||
|
|
||||||
## Source database
|
## Taget database
|
||||||
SOURCE_DB_HOST=mysql2
|
TARGET_DB_HOST=target-mysql
|
||||||
SOURCE_DB_PORT=3306
|
TARGET_DB_PORT=3306
|
||||||
SOURCE_DB_NAME=sourcedb
|
TARGET_DB_NAME=dbname
|
||||||
SOURCE_DB_USERNAME=sourceuser
|
TARGET_DB_USERNAME=username
|
||||||
SOURCE_DB_PASSWORD=password
|
TARGET_DB_PASSWORD=password
|
||||||
```
|
```
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
docker run --rm --network your_network_name \
|
docker run --rm --network your_network_name \
|
||||||
--env-file your-env
|
--env-file your-env
|
||||||
-v $PWD/backup:/backup/ \
|
-v $PWD/backup:/backup/ \
|
||||||
jkaninda/mysql-bkup migrate -d database_name
|
jkaninda/mysql-bkup migrate
|
||||||
```
|
```
|
||||||
|
|
||||||
## Kubernetes
|
## Kubernetes
|
||||||
@@ -96,28 +99,33 @@ spec:
|
|||||||
command:
|
command:
|
||||||
- /bin/sh
|
- /bin/sh
|
||||||
- -c
|
- -c
|
||||||
- migrate -d targetdb
|
- migrate
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
memory: "128Mi"
|
memory: "128Mi"
|
||||||
cpu: "500m"
|
cpu: "500m"
|
||||||
env:
|
env:
|
||||||
## Target DB
|
## Source Database
|
||||||
- name: DB_HOST
|
- name: DB_HOST
|
||||||
value: "postgres-target"
|
|
||||||
- name: DB_USERNAME
|
|
||||||
value: "mysql"
|
value: "mysql"
|
||||||
|
- name: DB_PORT
|
||||||
|
value: "3306"
|
||||||
|
- name: DB_NAME
|
||||||
|
value: "dbname"
|
||||||
|
- name: DB_USERNAME
|
||||||
|
value: "username"
|
||||||
- name: DB_PASSWORD
|
- name: DB_PASSWORD
|
||||||
value: "password"
|
value: "password"
|
||||||
## Source DB
|
## Target Database
|
||||||
- name: SOURCE_DB_HOST
|
- name: TARGET_DB_HOST
|
||||||
value: "postgres-source"
|
value: "target-mysql"
|
||||||
- name: SOURCE_DB_NAME
|
- name: TARGET_DB_PORT
|
||||||
value: "sourcedb"
|
value: "3306"
|
||||||
- name: SOURCE_DB_USERNAME
|
- name: TARGET_DB_NAME
|
||||||
value: "postgres"
|
value: "dbname"
|
||||||
# Please use secret!
|
- name: TARGET_DB_USERNAME
|
||||||
- name: SOURCE_DB_PASSWORD
|
value: "username"
|
||||||
|
- name: TARGET_DB_PASSWORD
|
||||||
value: "password"
|
value: "password"
|
||||||
restartPolicy: Never
|
restartPolicy: Never
|
||||||
```
|
```
|
||||||
@@ -65,7 +65,7 @@ spec:
|
|||||||
command:
|
command:
|
||||||
- /bin/sh
|
- /bin/sh
|
||||||
- -c
|
- -c
|
||||||
- bkup restore -s s3 --path /custom_path -f store_20231219_022941.sql.gz
|
- restore -s s3 --path /custom_path -f store_20231219_022941.sql.gz
|
||||||
env:
|
env:
|
||||||
- name: DB_PORT
|
- name: DB_PORT
|
||||||
value: "3306"
|
value: "3306"
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ spec:
|
|||||||
command:
|
command:
|
||||||
- /bin/sh
|
- /bin/sh
|
||||||
- -c
|
- -c
|
||||||
- bkup restore -s ssh -f store_20231219_022941.sql.gz
|
- restore -s ssh -f store_20231219_022941.sql.gz
|
||||||
env:
|
env:
|
||||||
- name: DB_PORT
|
- name: DB_PORT
|
||||||
value: "3306"
|
value: "3306"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ nav_order: 1
|
|||||||
|
|
||||||
# About mysql-bkup
|
# About mysql-bkup
|
||||||
{:.no_toc}
|
{:.no_toc}
|
||||||
MySQL Backup is a Docker container image that can be used to backup and restore MySQL database. It supports local storage, AWS S3 or any S3 Alternatives for Object Storage, and SSH remote storage.
|
MySQL Backup is a Docker container image that can be used to backup, restore and migrate MySQL database. It supports local storage, AWS S3 or any S3 Alternatives for Object Storage, and SSH remote storage.
|
||||||
It also supports __encrypting__ your backups using GPG.
|
It also supports __encrypting__ your backups using GPG.
|
||||||
|
|
||||||
We are open to receiving stars, PRs, and issues!
|
We are open to receiving stars, PRs, and issues!
|
||||||
@@ -19,7 +19,8 @@ We are open to receiving stars, PRs, and issues!
|
|||||||
The [jkaninda/mysql-bkup](https://hub.docker.com/r/jkaninda/mysql-bkup) Docker image can be deployed on Docker, Docker Swarm and Kubernetes.
|
The [jkaninda/mysql-bkup](https://hub.docker.com/r/jkaninda/mysql-bkup) Docker image can be deployed on Docker, Docker Swarm and Kubernetes.
|
||||||
It handles __recurring__ backups of postgres database on Docker and can be deployed as __CronJob on Kubernetes__ using local, AWS S3 or SSH compatible storage.
|
It handles __recurring__ backups of postgres database on Docker and can be deployed as __CronJob on Kubernetes__ using local, AWS S3 or SSH compatible storage.
|
||||||
|
|
||||||
It also supports __encrypting__ your backups using GPG.
|
It also supports database __encryption__ using GPG.
|
||||||
|
|
||||||
|
|
||||||
{: .note }
|
{: .note }
|
||||||
Code and documentation for `v1` version on [this branch][v1-branch].
|
Code and documentation for `v1` version on [this branch][v1-branch].
|
||||||
|
|||||||
@@ -57,12 +57,13 @@ Backup, restore and migrate targets, schedule and retention are configured using
|
|||||||
| SSH_IDENTIFY_FILE | Optional, required for SSH storage | ssh remote user's private key |
|
| SSH_IDENTIFY_FILE | Optional, required for SSH storage | ssh remote user's private key |
|
||||||
| SSH_PORT | Optional, required for SSH storage | ssh remote server port |
|
| SSH_PORT | Optional, required for SSH storage | ssh remote server port |
|
||||||
| SSH_REMOTE_PATH | Optional, required for SSH storage | ssh remote path (/home/toto/backup) |
|
| SSH_REMOTE_PATH | Optional, required for SSH storage | ssh remote path (/home/toto/backup) |
|
||||||
| SOURCE_DB_HOST | Optional, required for database migration | Source database host |
|
| TARGET_DB_HOST | Optional, required for database migration | Target database host |
|
||||||
| SOURCE_DB_PORT | Optional, required for database migration | Source database port |
|
| TARGET_DB_PORT | Optional, required for database migration | Target database port |
|
||||||
| SOURCE_DB_NAME | Optional, required for database migration | Source database name |
|
| TARGET_DB_NAME | Optional, required for database migration | Target database name |
|
||||||
| SOURCE_DB_USERNAME | Optional, required for database migration | Source database username |
|
| TARGET_DB_USERNAME | Optional, required for database migration | Target database username |
|
||||||
| SOURCE_DB_PASSWORD | Optional, required for database migration | Source database password |
|
| TARGET_DB_PASSWORD | Optional, required for database migration | Target database password |
|
||||||
|
| TG_TOKEN | Optional, required for Telegram notification | Telegram token |
|
||||||
|
| TG_CHAT_ID | Optional, required for Telegram notification | Telegram Chat ID |
|
||||||
---
|
---
|
||||||
## Run in Scheduled mode
|
## Run in Scheduled mode
|
||||||
|
|
||||||
|
|||||||
@@ -15,10 +15,7 @@ spec:
|
|||||||
command:
|
command:
|
||||||
- /bin/sh
|
- /bin/sh
|
||||||
- -c
|
- -c
|
||||||
- bkup
|
- backup --storage s3
|
||||||
- backup
|
|
||||||
- --storage
|
|
||||||
- s3
|
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
memory: "128Mi"
|
memory: "128Mi"
|
||||||
|
|||||||
13
main.go
13
main.go
@@ -1,12 +1,11 @@
|
|||||||
|
// Package main /
|
||||||
|
/*****
|
||||||
|
@author Jonas Kaninda
|
||||||
|
@license MIT License <https://opensource.org/licenses/MIT>
|
||||||
|
@Copyright © 2024 Jonas Kaninda
|
||||||
|
**/
|
||||||
package main
|
package main
|
||||||
|
|
||||||
//main
|
|
||||||
/*****
|
|
||||||
* MySQL Backup & Restore
|
|
||||||
* @author Jonas Kaninda
|
|
||||||
* @license MIT License <https://opensource.org/licenses/MIT>
|
|
||||||
* @link https://github.com/jkaninda/mysql-bkup
|
|
||||||
**/
|
|
||||||
import "github.com/jkaninda/mysql-bkup/cmd"
|
import "github.com/jkaninda/mysql-bkup/cmd"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
// Package pkg /*
|
// Package pkg /
|
||||||
/*
|
/*****
|
||||||
Copyright © 2024 Jonas Kaninda
|
@author Jonas Kaninda
|
||||||
*/
|
@license MIT License <https://opensource.org/licenses/MIT>
|
||||||
|
@Copyright © 2024 Jonas Kaninda
|
||||||
|
**/
|
||||||
package pkg
|
package pkg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -17,7 +19,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func StartBackup(cmd *cobra.Command) {
|
func StartBackup(cmd *cobra.Command) {
|
||||||
_, _ = cmd.Flags().GetString("operation")
|
intro()
|
||||||
//Set env
|
//Set env
|
||||||
utils.SetEnv("STORAGE_PATH", storagePath)
|
utils.SetEnv("STORAGE_PATH", storagePath)
|
||||||
utils.GetEnv(cmd, "period", "BACKUP_CRON_EXPRESSION")
|
utils.GetEnv(cmd, "period", "BACKUP_CRON_EXPRESSION")
|
||||||
@@ -114,6 +116,10 @@ func scheduledMode(db *dbConfig, storage string) {
|
|||||||
fmt.Println(line.Text)
|
fmt.Println(line.Text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func intro() {
|
||||||
|
utils.Info("Starting MySQL Backup...")
|
||||||
|
utils.Info("Copyright © 2024 Jonas Kaninda ")
|
||||||
|
}
|
||||||
|
|
||||||
// BackupDatabase backup database
|
// BackupDatabase backup database
|
||||||
func BackupDatabase(db *dbConfig, backupFileName string, disableCompression bool) {
|
func BackupDatabase(db *dbConfig, backupFileName string, disableCompression bool) {
|
||||||
@@ -126,6 +132,10 @@ func BackupDatabase(db *dbConfig, backupFileName string, disableCompression bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
utils.Info("Starting database backup...")
|
utils.Info("Starting database backup...")
|
||||||
|
err = os.Setenv("MYSQL_PWD", db.dbPassword)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
testDatabaseConnection(db)
|
testDatabaseConnection(db)
|
||||||
|
|
||||||
// Backup Database database
|
// Backup Database database
|
||||||
@@ -137,7 +147,6 @@ func BackupDatabase(db *dbConfig, backupFileName string, disableCompression bool
|
|||||||
"-h", db.dbHost,
|
"-h", db.dbHost,
|
||||||
"-P", db.dbPort,
|
"-P", db.dbPort,
|
||||||
"-u", db.dbUserName,
|
"-u", db.dbUserName,
|
||||||
"--password="+db.dbPassword,
|
|
||||||
db.dbName,
|
db.dbName,
|
||||||
)
|
)
|
||||||
output, err := cmd.Output()
|
output, err := cmd.Output()
|
||||||
@@ -160,7 +169,7 @@ func BackupDatabase(db *dbConfig, backupFileName string, disableCompression bool
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Execute mysqldump
|
// Execute mysqldump
|
||||||
cmd := exec.Command("mysqldump", "-h", db.dbHost, "-P", db.dbPort, "-u", db.dbUserName, "--password="+db.dbPassword, db.dbName)
|
cmd := exec.Command("mysqldump", "-h", db.dbHost, "-P", db.dbPort, "-u", db.dbUserName, db.dbName)
|
||||||
stdout, err := cmd.StdoutPipe()
|
stdout, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
@@ -193,6 +202,8 @@ func localBackup(db *dbConfig, backupFileName string, disableCompression bool, p
|
|||||||
}
|
}
|
||||||
utils.Info("Backup name is %s", finalFileName)
|
utils.Info("Backup name is %s", finalFileName)
|
||||||
moveToBackup(finalFileName, storagePath)
|
moveToBackup(finalFileName, storagePath)
|
||||||
|
//Send notification
|
||||||
|
utils.NotifySuccess(finalFileName)
|
||||||
//Delete old backup
|
//Delete old backup
|
||||||
if prune {
|
if prune {
|
||||||
deleteOldBackup(backupRetention)
|
deleteOldBackup(backupRetention)
|
||||||
@@ -234,9 +245,13 @@ func s3Backup(db *dbConfig, backupFileName string, disableCompression bool, prun
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
utils.Done("Uploading backup archive to remote storage S3 ... done ")
|
utils.Done("Uploading backup archive to remote storage S3 ... done ")
|
||||||
|
//Send notification
|
||||||
|
utils.NotifySuccess(finalFileName)
|
||||||
//Delete temp
|
//Delete temp
|
||||||
deleteTemp()
|
deleteTemp()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sshBackup backup database to SSH remote server
|
||||||
func sshBackup(db *dbConfig, backupFileName, remotePath string, disableCompression bool, prune bool, backupRetention int, encrypt bool) {
|
func sshBackup(db *dbConfig, backupFileName, remotePath string, disableCompression bool, prune bool, backupRetention int, encrypt bool) {
|
||||||
utils.Info("Backup database to Remote server")
|
utils.Info("Backup database to Remote server")
|
||||||
//Backup database
|
//Backup database
|
||||||
@@ -267,9 +282,13 @@ func sshBackup(db *dbConfig, backupFileName, remotePath string, disableCompressi
|
|||||||
}
|
}
|
||||||
|
|
||||||
utils.Done("Uploading backup archive to remote storage ... done ")
|
utils.Done("Uploading backup archive to remote storage ... done ")
|
||||||
|
//Send notification
|
||||||
|
utils.NotifySuccess(finalFileName)
|
||||||
//Delete temp
|
//Delete temp
|
||||||
deleteTemp()
|
deleteTemp()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// encryptBackup encrypt backup
|
||||||
func encryptBackup(backupFileName string) {
|
func encryptBackup(backupFileName string) {
|
||||||
gpgPassphrase := os.Getenv("GPG_PASSPHRASE")
|
gpgPassphrase := os.Getenv("GPG_PASSPHRASE")
|
||||||
err := Encrypt(filepath.Join(tmpPath, backupFileName), gpgPassphrase)
|
err := Encrypt(filepath.Join(tmpPath, backupFileName), gpgPassphrase)
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
// Package pkg /
|
||||||
|
/*****
|
||||||
|
@author Jonas Kaninda
|
||||||
|
@license MIT License <https://opensource.org/licenses/MIT>
|
||||||
|
@Copyright © 2024 Jonas Kaninda
|
||||||
|
**/
|
||||||
package pkg
|
package pkg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -16,12 +22,12 @@ type dbConfig struct {
|
|||||||
dbUserName string
|
dbUserName string
|
||||||
dbPassword string
|
dbPassword string
|
||||||
}
|
}
|
||||||
type dbSourceConfig struct {
|
type targetDbConfig struct {
|
||||||
sourceDbHost string
|
targetDbHost string
|
||||||
sourceDbPort string
|
targetDbPort string
|
||||||
sourceDbUserName string
|
targetDbUserName string
|
||||||
sourceDbPassword string
|
targetDbPassword string
|
||||||
sourceDbName string
|
targetDbName string
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDbConfig(cmd *cobra.Command) *dbConfig {
|
func getDbConfig(cmd *cobra.Command) *dbConfig {
|
||||||
@@ -41,18 +47,18 @@ func getDbConfig(cmd *cobra.Command) *dbConfig {
|
|||||||
}
|
}
|
||||||
return &dConf
|
return &dConf
|
||||||
}
|
}
|
||||||
func getSourceDbConfig() *dbSourceConfig {
|
func getTargetDbConfig() *targetDbConfig {
|
||||||
sdbConfig := dbSourceConfig{}
|
tdbConfig := targetDbConfig{}
|
||||||
sdbConfig.sourceDbHost = os.Getenv("SOURCE_DB_HOST")
|
tdbConfig.targetDbHost = os.Getenv("TARGET_DB_HOST")
|
||||||
sdbConfig.sourceDbPort = os.Getenv("SOURCE_DB_PORT")
|
tdbConfig.targetDbPort = os.Getenv("TARGET_DB_PORT")
|
||||||
sdbConfig.sourceDbName = os.Getenv("SOURCE_DB_NAME")
|
tdbConfig.targetDbName = os.Getenv("TARGET_DB_NAME")
|
||||||
sdbConfig.sourceDbUserName = os.Getenv("SOURCE_DB_USERNAME")
|
tdbConfig.targetDbUserName = os.Getenv("TARGET_DB_USERNAME")
|
||||||
sdbConfig.sourceDbPassword = os.Getenv("SOURCE_DB_PASSWORD")
|
tdbConfig.targetDbPassword = os.Getenv("TARGET_DB_PASSWORD")
|
||||||
|
|
||||||
err := utils.CheckEnvVars(sdbRVars)
|
err := utils.CheckEnvVars(tdbRVars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error("Please make sure all required environment variables for source database are set")
|
utils.Error("Please make sure all required environment variables for the target database are set")
|
||||||
utils.Fatal("Error checking environment variables: %s", err)
|
utils.Fatal("Error checking target database environment variables: %s", err)
|
||||||
}
|
}
|
||||||
return &sdbConfig
|
return &tdbConfig
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
// Package pkg /
|
||||||
|
/*****
|
||||||
|
@author Jonas Kaninda
|
||||||
|
@license MIT License <https://opensource.org/licenses/MIT>
|
||||||
|
@Copyright © 2024 Jonas Kaninda
|
||||||
|
**/
|
||||||
package pkg
|
package pkg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
// Package pkg /
|
||||||
|
/*****
|
||||||
|
@author Jonas Kaninda
|
||||||
|
@license MIT License <https://opensource.org/licenses/MIT>
|
||||||
|
@Copyright © 2024 Jonas Kaninda
|
||||||
|
**/
|
||||||
package pkg
|
package pkg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -101,19 +107,19 @@ func deleteTemp() {
|
|||||||
|
|
||||||
// TestDatabaseConnection tests the database connection
|
// TestDatabaseConnection tests the database connection
|
||||||
func testDatabaseConnection(db *dbConfig) {
|
func testDatabaseConnection(db *dbConfig) {
|
||||||
|
err := os.Setenv("MYSQL_PWD", db.dbPassword)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
utils.Info("Connecting to %s database ...", db.dbName)
|
utils.Info("Connecting to %s database ...", db.dbName)
|
||||||
|
cmd := exec.Command("mysql", "-h", db.dbHost, "-P", db.dbPort, "-u", db.dbUserName, db.dbName, "-e", "quit")
|
||||||
cmd := exec.Command("mysql", "-h", db.dbHost, "-P", db.dbPort, "-u", db.dbUserName, "--password="+db.dbPassword, db.dbName, "-e", "quit")
|
|
||||||
|
|
||||||
// Capture the output
|
// Capture the output
|
||||||
var out bytes.Buffer
|
var out bytes.Buffer
|
||||||
cmd.Stdout = &out
|
cmd.Stdout = &out
|
||||||
cmd.Stderr = &out
|
cmd.Stderr = &out
|
||||||
err := cmd.Run()
|
err = cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error("Error testing database connection: %v\nOutput: %s", err, out.String())
|
utils.Fatal("Error testing database connection: %v\nOutput: %s", err, out.String())
|
||||||
os.Exit(1)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
utils.Info("Successfully connected to %s database", db.dbName)
|
utils.Info("Successfully connected to %s database", db.dbName)
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
// Package pkg /
|
||||||
|
/*****
|
||||||
|
@author Jonas Kaninda
|
||||||
|
@license MIT License <https://opensource.org/licenses/MIT>
|
||||||
|
@Copyright © 2024 Jonas Kaninda
|
||||||
|
**/
|
||||||
package pkg
|
package pkg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -8,24 +14,27 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func StartMigration(cmd *cobra.Command) {
|
func StartMigration(cmd *cobra.Command) {
|
||||||
|
intro()
|
||||||
utils.Info("Starting database migration...")
|
utils.Info("Starting database migration...")
|
||||||
//Get DB config
|
//Get DB config
|
||||||
dbConf = getDbConfig(cmd)
|
dbConf = getDbConfig(cmd)
|
||||||
sDbConf = getSourceDbConfig()
|
targetDbConf = getTargetDbConfig()
|
||||||
|
|
||||||
|
//Defining the target database variables
|
||||||
|
newDbConfig := dbConfig{}
|
||||||
|
newDbConfig.dbHost = targetDbConf.targetDbHost
|
||||||
|
newDbConfig.dbPort = targetDbConf.targetDbPort
|
||||||
|
newDbConfig.dbName = targetDbConf.targetDbName
|
||||||
|
newDbConfig.dbUserName = targetDbConf.targetDbUserName
|
||||||
|
newDbConfig.dbPassword = targetDbConf.targetDbPassword
|
||||||
|
|
||||||
//Generate file name
|
//Generate file name
|
||||||
backupFileName := fmt.Sprintf("%s_%s.sql", sDbConf.sourceDbName, time.Now().Format("20060102_150405"))
|
backupFileName := fmt.Sprintf("%s_%s.sql", dbConf.dbName, time.Now().Format("20060102_150405"))
|
||||||
//Backup Source Database
|
//Backup source Database
|
||||||
newDbConfig := dbConfig{}
|
BackupDatabase(dbConf, backupFileName, true)
|
||||||
newDbConfig.dbHost = sDbConf.sourceDbHost
|
|
||||||
newDbConfig.dbPort = sDbConf.sourceDbPort
|
|
||||||
newDbConfig.dbName = sDbConf.sourceDbName
|
|
||||||
newDbConfig.dbUserName = sDbConf.sourceDbUserName
|
|
||||||
newDbConfig.dbPassword = sDbConf.sourceDbPassword
|
|
||||||
BackupDatabase(&newDbConfig, backupFileName, true)
|
|
||||||
//Restore source database into target database
|
//Restore source database into target database
|
||||||
utils.Info("Restoring [%s] database into [%s] database...", sDbConf.sourceDbName, dbConf.dbName)
|
utils.Info("Restoring [%s] database into [%s] database...", dbConf.dbName, targetDbConf.targetDbName)
|
||||||
RestoreDatabase(dbConf, backupFileName)
|
RestoreDatabase(&newDbConfig, backupFileName)
|
||||||
utils.Info("[%s] database has been restored into [%s] database", sDbConf.sourceDbName, dbConf.dbName)
|
utils.Info("[%s] database has been restored into [%s] database", dbConf.dbName, targetDbConf.targetDbName)
|
||||||
utils.Info("Database migration completed!")
|
utils.Info("Database migration completed.")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
// Package pkg /
|
||||||
|
/*****
|
||||||
|
@author Jonas Kaninda
|
||||||
|
@license MIT License <https://opensource.org/licenses/MIT>
|
||||||
|
@Copyright © 2024 Jonas Kaninda
|
||||||
|
**/
|
||||||
package pkg
|
package pkg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -10,7 +16,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func StartRestore(cmd *cobra.Command) {
|
func StartRestore(cmd *cobra.Command) {
|
||||||
|
intro()
|
||||||
//Set env
|
//Set env
|
||||||
utils.SetEnv("STORAGE_PATH", storagePath)
|
utils.SetEnv("STORAGE_PATH", storagePath)
|
||||||
|
|
||||||
@@ -89,13 +95,17 @@ func RestoreDatabase(db *dbConfig, file string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if utils.FileExists(fmt.Sprintf("%s/%s", tmpPath, file)) {
|
if utils.FileExists(fmt.Sprintf("%s/%s", tmpPath, file)) {
|
||||||
|
err = os.Setenv("MYSQL_PWD", db.dbPassword)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
testDatabaseConnection(db)
|
testDatabaseConnection(db)
|
||||||
utils.Info("Restoring database...")
|
utils.Info("Restoring database...")
|
||||||
|
|
||||||
extension := filepath.Ext(fmt.Sprintf("%s/%s", tmpPath, file))
|
extension := filepath.Ext(fmt.Sprintf("%s/%s", tmpPath, file))
|
||||||
// Restore from compressed file / .sql.gz
|
// Restore from compressed file / .sql.gz
|
||||||
if extension == ".gz" {
|
if extension == ".gz" {
|
||||||
str := "zcat " + fmt.Sprintf("%s/%s", tmpPath, 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")
|
str := "zcat " + filepath.Join(tmpPath, file) + " | mysql -h " + db.dbHost + " -P " + db.dbPort + " -u " + db.dbUserName + " " + db.dbName
|
||||||
_, err := exec.Command("bash", "-c", str).Output()
|
_, err := exec.Command("bash", "-c", str).Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatal("Error, in restoring the database %v", err)
|
utils.Fatal("Error, in restoring the database %v", err)
|
||||||
@@ -107,20 +117,20 @@ func RestoreDatabase(db *dbConfig, file string) {
|
|||||||
|
|
||||||
} else if extension == ".sql" {
|
} else if extension == ".sql" {
|
||||||
//Restore from sql file
|
//Restore from sql file
|
||||||
str := "cat " + fmt.Sprintf("%s/%s", tmpPath, 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")
|
str := "cat " + filepath.Join(tmpPath, file) + " | mysql -h " + db.dbHost + " -P " + db.dbPort + " -u " + db.dbUserName + " " + db.dbName
|
||||||
_, err := exec.Command("bash", "-c", str).Output()
|
_, err := exec.Command("bash", "-c", str).Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatal(fmt.Sprintf("Error in restoring the database %s", err))
|
utils.Fatal("Error in restoring the database %v", err)
|
||||||
}
|
}
|
||||||
utils.Info("Restoring database... done")
|
utils.Info("Restoring database... done")
|
||||||
utils.Done("Database has been restored")
|
utils.Done("Database has been restored")
|
||||||
//Delete temp
|
//Delete temp
|
||||||
deleteTemp()
|
deleteTemp()
|
||||||
} else {
|
} else {
|
||||||
utils.Fatal(fmt.Sprintf("Unknown file extension %s", extension))
|
utils.Fatal("Unknown file extension %s", extension)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
utils.Fatal(fmt.Sprintf("File not found in %s", fmt.Sprintf("%s/%s", tmpPath, file)))
|
utils.Fatal("File not found in %s", filepath.Join(tmpPath, file))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
// Package pkg /
|
||||||
|
/*****
|
||||||
|
@author Jonas Kaninda
|
||||||
|
@license MIT License <https://opensource.org/licenses/MIT>
|
||||||
|
@Copyright © 2024 Jonas Kaninda
|
||||||
|
**/
|
||||||
package pkg
|
package pkg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
|
// Package pkg /
|
||||||
|
/*****
|
||||||
|
@author Jonas Kaninda
|
||||||
|
@license MIT License <https://opensource.org/licenses/MIT>
|
||||||
|
@Copyright © 2024 Jonas Kaninda
|
||||||
|
**/
|
||||||
package pkg
|
package pkg
|
||||||
|
|
||||||
// Package pkg /*
|
|
||||||
/*
|
|
||||||
Copyright © 2024 Jonas Kaninda
|
|
||||||
*/
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/jkaninda/mysql-bkup/utils"
|
"github.com/jkaninda/mysql-bkup/utils"
|
||||||
@@ -24,8 +26,8 @@ func CreateCrontabScript(disableCompression bool, storage string) {
|
|||||||
|
|
||||||
scriptContent := fmt.Sprintf(`#!/usr/bin/env bash
|
scriptContent := fmt.Sprintf(`#!/usr/bin/env bash
|
||||||
set -e
|
set -e
|
||||||
/usr/local/bin/mysql-bkup backup --dbname %s --port %s --storage %s %v
|
/usr/local/bin/mysql-bkup backup --dbname %s --storage %s %v
|
||||||
`, os.Getenv("DB_NAME"), os.Getenv("DB_PORT"), storage, disableC)
|
`, os.Getenv("DB_NAME"), storage, disableC)
|
||||||
|
|
||||||
if err := utils.WriteToFile(backupCronFile, scriptContent); err != nil {
|
if err := utils.WriteToFile(backupCronFile, scriptContent); err != nil {
|
||||||
utils.Fatal("Error writing to %s: %v\n", backupCronFile, err)
|
utils.Fatal("Error writing to %s: %v\n", backupCronFile, err)
|
||||||
|
|||||||
20
pkg/var.go
20
pkg/var.go
@@ -1,3 +1,9 @@
|
|||||||
|
// Package pkg /
|
||||||
|
/*****
|
||||||
|
@author Jonas Kaninda
|
||||||
|
@license MIT License <https://opensource.org/licenses/MIT>
|
||||||
|
@Copyright © 2024 Jonas Kaninda
|
||||||
|
**/
|
||||||
package pkg
|
package pkg
|
||||||
|
|
||||||
const cronLogFile = "/var/log/mysql-bkup.log"
|
const cronLogFile = "/var/log/mysql-bkup.log"
|
||||||
@@ -23,16 +29,16 @@ var dbHVars = []string{
|
|||||||
"DB_USERNAME",
|
"DB_USERNAME",
|
||||||
"DB_NAME",
|
"DB_NAME",
|
||||||
}
|
}
|
||||||
var sdbRVars = []string{
|
var tdbRVars = []string{
|
||||||
"SOURCE_DB_HOST",
|
"TARGET_DB_HOST",
|
||||||
"SOURCE_DB_PORT",
|
"TARGET_DB_PORT",
|
||||||
"SOURCE_DB_NAME",
|
"TARGET_DB_NAME",
|
||||||
"SOURCE_DB_USERNAME",
|
"TARGET_DB_USERNAME",
|
||||||
"SOURCE_DB_PASSWORD",
|
"TARGET_DB_PASSWORD",
|
||||||
}
|
}
|
||||||
|
|
||||||
var dbConf *dbConfig
|
var dbConf *dbConfig
|
||||||
var sDbConf *dbSourceConfig
|
var targetDbConf *targetDbConfig
|
||||||
|
|
||||||
// sshHVars Required environment variables for SSH remote server storage
|
// sshHVars Required environment variables for SSH remote server storage
|
||||||
var sshHVars = []string{
|
var sshHVars = []string{
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
// Package utils /
|
||||||
|
/*****
|
||||||
|
@author Jonas Kaninda
|
||||||
|
@license MIT License <https://opensource.org/licenses/MIT>
|
||||||
|
@Copyright © 2024 Jonas Kaninda
|
||||||
|
**/
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
const RestoreExample = "mysql-bkup restore --dbname database --file db_20231219_022941.sql.gz\n" +
|
const RestoreExample = "mysql-bkup restore --dbname database --file db_20231219_022941.sql.gz\n" +
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
// Package utils /
|
||||||
|
/*****
|
||||||
|
@author Jonas Kaninda
|
||||||
|
@license MIT License <https://opensource.org/licenses/MIT>
|
||||||
|
@Copyright © 2024 Jonas Kaninda
|
||||||
|
**/
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -49,8 +55,13 @@ func Fatal(msg string, args ...any) {
|
|||||||
formattedMessage := fmt.Sprintf(msg, args...)
|
formattedMessage := fmt.Sprintf(msg, args...)
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
fmt.Printf("%s ERROR: %s\n", currentTime, msg)
|
fmt.Printf("%s ERROR: %s\n", currentTime, msg)
|
||||||
|
NotifyError(msg)
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("%s ERROR: %s\n", currentTime, formattedMessage)
|
fmt.Printf("%s ERROR: %s\n", currentTime, formattedMessage)
|
||||||
|
NotifyError(formattedMessage)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
os.Kill.Signal()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
// Package utils /
|
||||||
|
/*****
|
||||||
|
@author Jonas Kaninda
|
||||||
|
@license MIT License <https://opensource.org/licenses/MIT>
|
||||||
|
@Copyright © 2024 Jonas Kaninda
|
||||||
|
**/
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -122,7 +128,7 @@ func DownloadFile(destinationPath, key, bucket, prefix string) error {
|
|||||||
fmt.Println("Failed to download file", err)
|
fmt.Println("Failed to download file", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
Info(fmt.Sprintf("Backup downloaded: ", file.Name(), " bytes size ", numBytes))
|
Info("Backup downloaded: %s bytes size %s ", file.Name(), numBytes)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,22 @@
|
|||||||
|
// Package utils /
|
||||||
|
/*****
|
||||||
|
@author Jonas Kaninda
|
||||||
|
@license MIT License <https://opensource.org/licenses/MIT>
|
||||||
|
@Copyright © 2024 Jonas Kaninda
|
||||||
|
**/
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
/*****
|
|
||||||
* MySQL Backup & Restore
|
|
||||||
* @author Jonas Kaninda
|
|
||||||
* @license MIT License <https://opensource.org/licenses/MIT>
|
|
||||||
* @link https://github.com/jkaninda/mysql-bkup
|
|
||||||
**/
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
func FileExists(filename string) bool {
|
func FileExists(filename string) bool {
|
||||||
@@ -170,3 +175,78 @@ func MakeDirAll(dirPath string) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
func GetIntEnv(envName string) int {
|
||||||
|
val := os.Getenv(envName)
|
||||||
|
if val == "" {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
ret, err := strconv.Atoi(val)
|
||||||
|
if err != nil {
|
||||||
|
Error("Error: %v", err)
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
func sendMessage(msg string) {
|
||||||
|
|
||||||
|
Info("Sending notification... ")
|
||||||
|
chatId := os.Getenv("TG_CHAT_ID")
|
||||||
|
body, _ := json.Marshal(map[string]string{
|
||||||
|
"chat_id": chatId,
|
||||||
|
"text": msg,
|
||||||
|
})
|
||||||
|
url := fmt.Sprintf("%s/sendMessage", getTgUrl())
|
||||||
|
// Create an HTTP post request
|
||||||
|
request, err := http.NewRequest("POST", url, bytes.NewBuffer(body))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
request.Header.Add("Content-Type", "application/json")
|
||||||
|
client := &http.Client{}
|
||||||
|
response, err := client.Do(request)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
code := response.StatusCode
|
||||||
|
if code == 200 {
|
||||||
|
Info("Notification has been sent")
|
||||||
|
} else {
|
||||||
|
body, _ := ioutil.ReadAll(response.Body)
|
||||||
|
Error("Message not sent, error: %s", string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
func NotifySuccess(fileName string) {
|
||||||
|
var vars = []string{
|
||||||
|
"TG_TOKEN",
|
||||||
|
"TG_CHAT_ID",
|
||||||
|
}
|
||||||
|
|
||||||
|
//Telegram notification
|
||||||
|
err := CheckEnvVars(vars)
|
||||||
|
if err == nil {
|
||||||
|
message := "MySQL Backup \n" +
|
||||||
|
"Database has been backed up \n" +
|
||||||
|
"Backup name is " + fileName
|
||||||
|
sendMessage(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func NotifyError(error string) {
|
||||||
|
var vars = []string{
|
||||||
|
"TG_TOKEN",
|
||||||
|
"TG_CHAT_ID",
|
||||||
|
}
|
||||||
|
|
||||||
|
//Telegram notification
|
||||||
|
err := CheckEnvVars(vars)
|
||||||
|
if err == nil {
|
||||||
|
message := "MySQL Backup \n" +
|
||||||
|
"An error occurred during database backup \n" +
|
||||||
|
"Error: " + error
|
||||||
|
sendMessage(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTgUrl() string {
|
||||||
|
return fmt.Sprintf("https://api.telegram.org/bot%s", os.Getenv("TG_TOKEN"))
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user