feat: add multi backup
This commit is contained in:
@@ -20,17 +20,22 @@ import (
|
||||
|
||||
func StartBackup(cmd *cobra.Command) {
|
||||
intro()
|
||||
dbConf = initDbConfig(cmd)
|
||||
//Initialize backup configs
|
||||
config := initBackupConfig(cmd)
|
||||
|
||||
if config.cronExpression == "" {
|
||||
BackupTask(dbConf, config)
|
||||
//Load backup configuration file
|
||||
configFile, err := loadConfigFile()
|
||||
if err == nil {
|
||||
startMultiBackup(config, configFile)
|
||||
} else {
|
||||
if utils.IsValidCronExpression(config.cronExpression) {
|
||||
scheduledMode(dbConf, config)
|
||||
dbConf = initDbConfig(cmd)
|
||||
if config.cronExpression == "" {
|
||||
BackupTask(dbConf, config)
|
||||
} else {
|
||||
utils.Fatal("Cron expression is not valid: %s", config.cronExpression)
|
||||
if utils.IsValidCronExpression(config.cronExpression) {
|
||||
scheduledMode(dbConf, config)
|
||||
} else {
|
||||
utils.Fatal("Cron expression is not valid: %s", config.cronExpression)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +68,15 @@ func scheduledMode(db *dbConfig, config *BackupConfig) {
|
||||
defer c.Stop()
|
||||
select {}
|
||||
}
|
||||
func multiBackupTask(databases []Database, bkConfig *BackupConfig) {
|
||||
for _, db := range databases {
|
||||
//Check if path is defined in config file
|
||||
if db.Path != "" {
|
||||
bkConfig.remotePath = db.Path
|
||||
}
|
||||
BackupTask(getDatabase(db), bkConfig)
|
||||
}
|
||||
}
|
||||
func BackupTask(db *dbConfig, config *BackupConfig) {
|
||||
utils.Info("Starting backup task...")
|
||||
//Generate file name
|
||||
@@ -85,6 +99,55 @@ func BackupTask(db *dbConfig, config *BackupConfig) {
|
||||
localBackup(db, config)
|
||||
}
|
||||
}
|
||||
func startMultiBackup(bkConfig *BackupConfig, configFile string) {
|
||||
utils.Info("Starting multiple backup jobs...")
|
||||
var conf = &Config{}
|
||||
conf, err := readConf(configFile)
|
||||
if err != nil {
|
||||
utils.Fatal("Error reading config file: %s", err)
|
||||
}
|
||||
//Check if cronExpression is defined in config file
|
||||
if conf.CronExpression != "" {
|
||||
bkConfig.cronExpression = conf.CronExpression
|
||||
}
|
||||
// Check if cronExpression is defined
|
||||
if bkConfig.cronExpression == "" {
|
||||
multiBackupTask(conf.Databases, bkConfig)
|
||||
} else {
|
||||
// Check if cronExpression is valid
|
||||
if utils.IsValidCronExpression(bkConfig.cronExpression) {
|
||||
utils.Info("Running MultiBackup in Scheduled mode")
|
||||
utils.Info("Backup cron expression: %s", bkConfig.cronExpression)
|
||||
utils.Info("Storage type %s ", bkConfig.storage)
|
||||
|
||||
//Test backup
|
||||
utils.Info("Testing backup configurations...")
|
||||
multiBackupTask(conf.Databases, bkConfig)
|
||||
utils.Info("Testing backup configurations...done")
|
||||
utils.Info("Creating multi backup job...")
|
||||
// Create a new cron instance
|
||||
c := cron.New()
|
||||
|
||||
_, err := c.AddFunc(bkConfig.cronExpression, func() {
|
||||
// Create a channel
|
||||
multiBackupTask(conf.Databases, bkConfig)
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// Start the cron scheduler
|
||||
c.Start()
|
||||
utils.Info("Creating multi backup job...done")
|
||||
utils.Info("Backup job started")
|
||||
defer c.Stop()
|
||||
select {}
|
||||
|
||||
} else {
|
||||
utils.Fatal("Cron expression is not valid: %s", bkConfig.cronExpression)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
func intro() {
|
||||
utils.Info("Starting PostgreSQL Backup...")
|
||||
utils.Info("Copyright (c) 2024 Jonas Kaninda ")
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/jkaninda/pg-bkup/utils"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -14,7 +15,17 @@ import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Database struct {
|
||||
Host string `yaml:"host"`
|
||||
Port string `yaml:"port"`
|
||||
Name string `yaml:"name"`
|
||||
User string `yaml:"user"`
|
||||
Password string `yaml:"password"`
|
||||
Path string `yaml:"path"`
|
||||
}
|
||||
type Config struct {
|
||||
Databases []Database `yaml:"databases"`
|
||||
CronExpression string `yaml:"cronExpression"`
|
||||
}
|
||||
|
||||
type dbConfig struct {
|
||||
@@ -92,6 +103,16 @@ func initDbConfig(cmd *cobra.Command) *dbConfig {
|
||||
return &dConf
|
||||
}
|
||||
|
||||
func getDatabase(database Database) *dbConfig {
|
||||
return &dbConfig{
|
||||
dbHost: database.Host,
|
||||
dbPort: database.Port,
|
||||
dbName: database.Name,
|
||||
dbUserName: database.User,
|
||||
dbPassword: database.Password,
|
||||
}
|
||||
}
|
||||
|
||||
// loadSSHConfig loads the SSH configuration from environment variables
|
||||
func loadSSHConfig() (*SSHConfig, error) {
|
||||
utils.GetEnvVariable("SSH_HOST", "SSH_HOST_NAME")
|
||||
@@ -245,3 +266,10 @@ func initTargetDbConfig() *targetDbConfig {
|
||||
}
|
||||
return &tdbConfig
|
||||
}
|
||||
func loadConfigFile() (string, error) {
|
||||
backupConfigFile, err := checkConfigFile(os.Getenv("BACKUP_CONFIG_FILE"))
|
||||
if err == nil {
|
||||
return backupConfigFile, nil
|
||||
}
|
||||
return "", errors.New("backup config file not found")
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/jkaninda/pg-bkup/utils"
|
||||
"gopkg.in/yaml.v3"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -139,6 +140,8 @@ func testDatabaseConnection(db *dbConfig) {
|
||||
utils.Info("Successfully connected to %s database", db.dbName)
|
||||
|
||||
}
|
||||
|
||||
// checkPubKeyFile checks gpg public key
|
||||
func checkPubKeyFile(pubKey string) (string, error) {
|
||||
// Define possible key file names
|
||||
keyFiles := []string{filepath.Join(gpgHome, "public_key.asc"), filepath.Join(gpgHome, "public_key.gpg"), pubKey}
|
||||
@@ -160,6 +163,8 @@ func checkPubKeyFile(pubKey string) (string, error) {
|
||||
// Return an error if neither file exists
|
||||
return "", fmt.Errorf("no public key file found")
|
||||
}
|
||||
|
||||
// checkPrKeyFile checks private key
|
||||
func checkPrKeyFile(prKey string) (string, error) {
|
||||
// Define possible key file names
|
||||
keyFiles := []string{filepath.Join(gpgHome, "private_key.asc"), filepath.Join(gpgHome, "private_key.gpg"), prKey}
|
||||
@@ -181,3 +186,42 @@ func checkPrKeyFile(prKey string) (string, error) {
|
||||
// Return an error if neither file exists
|
||||
return "", fmt.Errorf("no public key file found")
|
||||
}
|
||||
func readConf(configFile string) (*Config, error) {
|
||||
//configFile := filepath.Join("./", filename)
|
||||
if utils.FileExists(configFile) {
|
||||
buf, err := os.ReadFile(configFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c := &Config{}
|
||||
err = yaml.Unmarshal(buf, c)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("in file %q: %w", configFile, err)
|
||||
}
|
||||
|
||||
return c, err
|
||||
}
|
||||
return nil, fmt.Errorf("config file %q not found", configFile)
|
||||
}
|
||||
func checkConfigFile(filePath string) (string, error) {
|
||||
// Define possible config file names
|
||||
configFiles := []string{filepath.Join(workingDir, "config.yaml"), filepath.Join(workingDir, "config.yml"), filePath}
|
||||
|
||||
// Loop through config file names and check if they exist
|
||||
for _, configFile := range configFiles {
|
||||
if _, err := os.Stat(configFile); err == nil {
|
||||
// File exists
|
||||
return configFile, nil
|
||||
} else if os.IsNotExist(err) {
|
||||
// File does not exist, continue to the next one
|
||||
continue
|
||||
} else {
|
||||
// An unexpected error occurred
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
// Return an error if neither file exists
|
||||
return "", fmt.Errorf("no config file found")
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ var (
|
||||
file = ""
|
||||
|
||||
storagePath = "/backup"
|
||||
workingDir = "/config"
|
||||
disableCompression = false
|
||||
encryption = false
|
||||
usingKey = false
|
||||
|
||||
Reference in New Issue
Block a user