mirror of
https://github.com/jkaninda/mysql-bkup.git
synced 2025-12-07 22:19:42 +01:00
feat: add Azure Blob storage
This commit is contained in:
122
internal/azure.go
Normal file
122
internal/azure.go
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Jonas Kaninda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/jkaninda/go-storage/pkg/azure"
|
||||
"github.com/jkaninda/mysql-bkup/pkg/logger"
|
||||
"github.com/jkaninda/mysql-bkup/utils"
|
||||
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
func azureBackup(db *dbConfig, config *BackupConfig) {
|
||||
logger.Info("Backup database to the remote FTP server")
|
||||
startTime = time.Now().Format(utils.TimeFormat())
|
||||
|
||||
// Backup database
|
||||
BackupDatabase(db, config.backupFileName, disableCompression)
|
||||
finalFileName := config.backupFileName
|
||||
if config.encryption {
|
||||
encryptBackup(config)
|
||||
finalFileName = fmt.Sprintf("%s.%s", config.backupFileName, "gpg")
|
||||
}
|
||||
logger.Info("Uploading backup archive to Azure Blob storage ...")
|
||||
logger.Info("Backup name is %s", finalFileName)
|
||||
azureConfig := loadAzureConfig()
|
||||
azureStorage, err := azure.NewStorage(azure.Config{
|
||||
ContainerName: azureConfig.containerName,
|
||||
AccountName: azureConfig.accountName,
|
||||
AccountKey: azureConfig.accountKey,
|
||||
RemotePath: config.remotePath,
|
||||
LocalPath: tmpPath,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Fatal("Error creating SSH storage: %s", err)
|
||||
}
|
||||
err = azureStorage.Copy(finalFileName)
|
||||
if err != nil {
|
||||
logger.Fatal("Error copying backup file: %s", err)
|
||||
}
|
||||
logger.Info("Backup saved in %s", filepath.Join(config.remotePath, finalFileName))
|
||||
// Get backup info
|
||||
fileInfo, err := os.Stat(filepath.Join(tmpPath, finalFileName))
|
||||
if err != nil {
|
||||
logger.Error("Error: %s", err)
|
||||
}
|
||||
backupSize = fileInfo.Size()
|
||||
// Delete backup file from tmp folder
|
||||
err = utils.DeleteFile(filepath.Join(tmpPath, finalFileName))
|
||||
if err != nil {
|
||||
logger.Error("Error deleting file: %v", err)
|
||||
|
||||
}
|
||||
if config.prune {
|
||||
err := azureStorage.Prune(config.backupRetention)
|
||||
if err != nil {
|
||||
logger.Fatal("Error deleting old backup from %s storage: %s ", config.storage, err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
logger.Info("Uploading backup archive to Azure Blob storage ... done ")
|
||||
|
||||
// Send notification
|
||||
utils.NotifySuccess(&utils.NotificationData{
|
||||
File: finalFileName,
|
||||
BackupSize: backupSize,
|
||||
Database: db.dbName,
|
||||
Storage: config.storage,
|
||||
BackupLocation: filepath.Join(config.remotePath, finalFileName),
|
||||
StartTime: startTime,
|
||||
EndTime: time.Now().Format(utils.TimeFormat()),
|
||||
})
|
||||
// Delete temp
|
||||
deleteTemp()
|
||||
logger.Info("Backup completed successfully")
|
||||
}
|
||||
func azureRestore(db *dbConfig, conf *RestoreConfig) {
|
||||
logger.Info("Restore database from Azure Blob storage")
|
||||
azureConfig := loadAzureConfig()
|
||||
azureStorage, err := azure.NewStorage(azure.Config{
|
||||
ContainerName: azureConfig.containerName,
|
||||
AccountName: azureConfig.accountName,
|
||||
AccountKey: azureConfig.accountKey,
|
||||
RemotePath: conf.remotePath,
|
||||
LocalPath: tmpPath,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Fatal("Error creating SSH storage: %s", err)
|
||||
}
|
||||
|
||||
err = azureStorage.CopyFrom(conf.file)
|
||||
if err != nil {
|
||||
logger.Fatal("Error downloading backup file: %s", err)
|
||||
}
|
||||
RestoreDatabase(db, conf)
|
||||
}
|
||||
@@ -27,10 +27,7 @@ package internal
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/jkaninda/encryptor"
|
||||
"github.com/jkaninda/go-storage/pkg/ftp"
|
||||
"github.com/jkaninda/go-storage/pkg/local"
|
||||
"github.com/jkaninda/go-storage/pkg/s3"
|
||||
"github.com/jkaninda/go-storage/pkg/ssh"
|
||||
"github.com/jkaninda/mysql-bkup/pkg/logger"
|
||||
"github.com/jkaninda/mysql-bkup/utils"
|
||||
"github.com/robfig/cron/v3"
|
||||
@@ -125,6 +122,8 @@ func BackupTask(db *dbConfig, config *BackupConfig) {
|
||||
sshBackup(db, config)
|
||||
case "ftp", "FTP":
|
||||
ftpBackup(db, config)
|
||||
case "azure":
|
||||
azureBackup(db, config)
|
||||
default:
|
||||
localBackup(db, config)
|
||||
}
|
||||
@@ -302,214 +301,6 @@ func localBackup(db *dbConfig, config *BackupConfig) {
|
||||
logger.Info("Backup completed successfully")
|
||||
}
|
||||
|
||||
func s3Backup(db *dbConfig, config *BackupConfig) {
|
||||
|
||||
logger.Info("Backup database to s3 storage")
|
||||
startTime = time.Now().Format(utils.TimeFormat())
|
||||
// Backup database
|
||||
BackupDatabase(db, config.backupFileName, disableCompression)
|
||||
finalFileName := config.backupFileName
|
||||
if config.encryption {
|
||||
encryptBackup(config)
|
||||
finalFileName = fmt.Sprintf("%s.%s", config.backupFileName, "gpg")
|
||||
}
|
||||
logger.Info("Uploading backup archive to remote storage S3 ... ")
|
||||
awsConfig := initAWSConfig()
|
||||
if config.remotePath == "" {
|
||||
config.remotePath = awsConfig.remotePath
|
||||
}
|
||||
logger.Info("Backup name is %s", finalFileName)
|
||||
s3Storage, err := s3.NewStorage(s3.Config{
|
||||
Endpoint: awsConfig.endpoint,
|
||||
Bucket: awsConfig.bucket,
|
||||
AccessKey: awsConfig.accessKey,
|
||||
SecretKey: awsConfig.secretKey,
|
||||
Region: awsConfig.region,
|
||||
DisableSsl: awsConfig.disableSsl,
|
||||
ForcePathStyle: awsConfig.forcePathStyle,
|
||||
RemotePath: awsConfig.remotePath,
|
||||
LocalPath: tmpPath,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Fatal("Error creating s3 storage: %s", err)
|
||||
}
|
||||
err = s3Storage.Copy(finalFileName)
|
||||
if err != nil {
|
||||
logger.Fatal("Error copying backup file: %s", err)
|
||||
}
|
||||
// Get backup info
|
||||
fileInfo, err := os.Stat(filepath.Join(tmpPath, finalFileName))
|
||||
if err != nil {
|
||||
logger.Error("Error: %s", err)
|
||||
}
|
||||
backupSize = fileInfo.Size()
|
||||
|
||||
// Delete backup file from tmp folder
|
||||
err = utils.DeleteFile(filepath.Join(tmpPath, config.backupFileName))
|
||||
if err != nil {
|
||||
fmt.Println("Error deleting file: ", err)
|
||||
|
||||
}
|
||||
// Delete old backup
|
||||
if config.prune {
|
||||
err := s3Storage.Prune(config.backupRetention)
|
||||
if err != nil {
|
||||
logger.Fatal("Error deleting old backup from %s storage: %s ", config.storage, err)
|
||||
}
|
||||
}
|
||||
logger.Info("Backup saved in %s", filepath.Join(config.remotePath, finalFileName))
|
||||
logger.Info("Uploading backup archive to remote storage S3 ... done ")
|
||||
// Send notification
|
||||
utils.NotifySuccess(&utils.NotificationData{
|
||||
File: finalFileName,
|
||||
BackupSize: backupSize,
|
||||
Database: db.dbName,
|
||||
Storage: config.storage,
|
||||
BackupLocation: filepath.Join(config.remotePath, finalFileName),
|
||||
StartTime: startTime,
|
||||
EndTime: time.Now().Format(utils.TimeFormat()),
|
||||
})
|
||||
// Delete temp
|
||||
deleteTemp()
|
||||
logger.Info("Backup completed successfully")
|
||||
|
||||
}
|
||||
func sshBackup(db *dbConfig, config *BackupConfig) {
|
||||
logger.Info("Backup database to Remote server")
|
||||
startTime = time.Now().Format(utils.TimeFormat())
|
||||
// Backup database
|
||||
BackupDatabase(db, config.backupFileName, disableCompression)
|
||||
finalFileName := config.backupFileName
|
||||
if config.encryption {
|
||||
encryptBackup(config)
|
||||
finalFileName = fmt.Sprintf("%s.%s", config.backupFileName, "gpg")
|
||||
}
|
||||
logger.Info("Uploading backup archive to remote storage ... ")
|
||||
logger.Info("Backup name is %s", finalFileName)
|
||||
sshConfig, err := loadSSHConfig()
|
||||
if err != nil {
|
||||
logger.Fatal("Error loading ssh config: %s", err)
|
||||
}
|
||||
|
||||
sshStorage, err := ssh.NewStorage(ssh.Config{
|
||||
Host: sshConfig.hostName,
|
||||
Port: sshConfig.port,
|
||||
User: sshConfig.user,
|
||||
Password: sshConfig.password,
|
||||
RemotePath: config.remotePath,
|
||||
LocalPath: tmpPath,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Fatal("Error creating SSH storage: %s", err)
|
||||
}
|
||||
err = sshStorage.Copy(finalFileName)
|
||||
if err != nil {
|
||||
logger.Fatal("Error copying backup file: %s", err)
|
||||
}
|
||||
// Get backup info
|
||||
fileInfo, err := os.Stat(filepath.Join(tmpPath, finalFileName))
|
||||
if err != nil {
|
||||
logger.Error("Error: %s", err)
|
||||
}
|
||||
backupSize = fileInfo.Size()
|
||||
logger.Info("Backup saved in %s", filepath.Join(config.remotePath, finalFileName))
|
||||
|
||||
// Delete backup file from tmp folder
|
||||
err = utils.DeleteFile(filepath.Join(tmpPath, finalFileName))
|
||||
if err != nil {
|
||||
logger.Error("Error deleting file: %v", err)
|
||||
|
||||
}
|
||||
if config.prune {
|
||||
err := sshStorage.Prune(config.backupRetention)
|
||||
if err != nil {
|
||||
logger.Fatal("Error deleting old backup from %s storage: %s ", config.storage, err)
|
||||
}
|
||||
|
||||
}
|
||||
logger.Info("Uploading backup archive to remote storage ... done ")
|
||||
// Send notification
|
||||
utils.NotifySuccess(&utils.NotificationData{
|
||||
File: finalFileName,
|
||||
BackupSize: backupSize,
|
||||
Database: db.dbName,
|
||||
Storage: config.storage,
|
||||
BackupLocation: filepath.Join(config.remotePath, finalFileName),
|
||||
StartTime: startTime,
|
||||
EndTime: time.Now().Format(utils.TimeFormat()),
|
||||
})
|
||||
// Delete temp
|
||||
deleteTemp()
|
||||
logger.Info("Backup completed successfully")
|
||||
|
||||
}
|
||||
func ftpBackup(db *dbConfig, config *BackupConfig) {
|
||||
logger.Info("Backup database to the remote FTP server")
|
||||
startTime = time.Now().Format(utils.TimeFormat())
|
||||
|
||||
// Backup database
|
||||
BackupDatabase(db, config.backupFileName, disableCompression)
|
||||
finalFileName := config.backupFileName
|
||||
if config.encryption {
|
||||
encryptBackup(config)
|
||||
finalFileName = fmt.Sprintf("%s.%s", config.backupFileName, "gpg")
|
||||
}
|
||||
logger.Info("Uploading backup archive to the remote FTP server ... ")
|
||||
logger.Info("Backup name is %s", finalFileName)
|
||||
ftpConfig := loadFtpConfig()
|
||||
ftpStorage, err := ftp.NewStorage(ftp.Config{
|
||||
Host: ftpConfig.host,
|
||||
Port: ftpConfig.port,
|
||||
User: ftpConfig.user,
|
||||
Password: ftpConfig.password,
|
||||
RemotePath: config.remotePath,
|
||||
LocalPath: tmpPath,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Fatal("Error creating SSH storage: %s", err)
|
||||
}
|
||||
err = ftpStorage.Copy(finalFileName)
|
||||
if err != nil {
|
||||
logger.Fatal("Error copying backup file: %s", err)
|
||||
}
|
||||
logger.Info("Backup saved in %s", filepath.Join(config.remotePath, finalFileName))
|
||||
// Get backup info
|
||||
fileInfo, err := os.Stat(filepath.Join(tmpPath, finalFileName))
|
||||
if err != nil {
|
||||
logger.Error("Error: %s", err)
|
||||
}
|
||||
backupSize = fileInfo.Size()
|
||||
// Delete backup file from tmp folder
|
||||
err = utils.DeleteFile(filepath.Join(tmpPath, finalFileName))
|
||||
if err != nil {
|
||||
logger.Error("Error deleting file: %v", err)
|
||||
|
||||
}
|
||||
if config.prune {
|
||||
err := ftpStorage.Prune(config.backupRetention)
|
||||
if err != nil {
|
||||
logger.Fatal("Error deleting old backup from %s storage: %s ", config.storage, err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
logger.Info("Uploading backup archive to the remote FTP server ... done ")
|
||||
|
||||
// Send notification
|
||||
utils.NotifySuccess(&utils.NotificationData{
|
||||
File: finalFileName,
|
||||
BackupSize: backupSize,
|
||||
Database: db.dbName,
|
||||
Storage: config.storage,
|
||||
BackupLocation: filepath.Join(config.remotePath, finalFileName),
|
||||
StartTime: startTime,
|
||||
EndTime: time.Now().Format(utils.TimeFormat()),
|
||||
})
|
||||
// Delete temp
|
||||
deleteTemp()
|
||||
logger.Info("Backup completed successfully")
|
||||
}
|
||||
|
||||
func encryptBackup(config *BackupConfig) {
|
||||
backupFile, err := os.ReadFile(filepath.Join(tmpPath, config.backupFileName))
|
||||
outputFile := fmt.Sprintf("%s.%s", filepath.Join(tmpPath, config.backupFileName), gpgExtension)
|
||||
|
||||
@@ -84,6 +84,11 @@ type FTPConfig struct {
|
||||
port string
|
||||
remotePath string
|
||||
}
|
||||
type AzureConfig struct {
|
||||
accountName string
|
||||
accountKey string
|
||||
containerName string
|
||||
}
|
||||
|
||||
// SSHConfig holds the SSH connection details
|
||||
type SSHConfig struct {
|
||||
@@ -164,6 +169,21 @@ func loadFtpConfig() *FTPConfig {
|
||||
}
|
||||
return &fConfig
|
||||
}
|
||||
func loadAzureConfig() *AzureConfig {
|
||||
// Initialize data configs
|
||||
aConfig := AzureConfig{}
|
||||
aConfig.containerName = os.Getenv("AZURE_STORAGE_CONTAINER_NAME")
|
||||
aConfig.accountName = os.Getenv("AZURE_STORAGE_ACCOUNT_NAME")
|
||||
aConfig.accountKey = os.Getenv("AZURE_STORAGE_ACCOUNT_KEY")
|
||||
|
||||
err := utils.CheckEnvVars(azureVars)
|
||||
if err != nil {
|
||||
logger.Error("Please make sure all required environment variables for Azure Blob storage are set")
|
||||
logger.Fatal("Error missing environment variables: %s", err)
|
||||
}
|
||||
return &aConfig
|
||||
}
|
||||
|
||||
func initAWSConfig() *AWSConfig {
|
||||
// Initialize AWS configs
|
||||
aConfig := AWSConfig{}
|
||||
|
||||
218
internal/remote.go
Normal file
218
internal/remote.go
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Jonas Kaninda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/jkaninda/go-storage/pkg/ftp"
|
||||
"github.com/jkaninda/go-storage/pkg/ssh"
|
||||
"github.com/jkaninda/mysql-bkup/pkg/logger"
|
||||
"github.com/jkaninda/mysql-bkup/utils"
|
||||
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
func sshBackup(db *dbConfig, config *BackupConfig) {
|
||||
logger.Info("Backup database to Remote server")
|
||||
startTime = time.Now().Format(utils.TimeFormat())
|
||||
// Backup database
|
||||
BackupDatabase(db, config.backupFileName, disableCompression)
|
||||
finalFileName := config.backupFileName
|
||||
if config.encryption {
|
||||
encryptBackup(config)
|
||||
finalFileName = fmt.Sprintf("%s.%s", config.backupFileName, "gpg")
|
||||
}
|
||||
logger.Info("Uploading backup archive to remote storage ... ")
|
||||
logger.Info("Backup name is %s", finalFileName)
|
||||
sshConfig, err := loadSSHConfig()
|
||||
if err != nil {
|
||||
logger.Fatal("Error loading ssh config: %s", err)
|
||||
}
|
||||
|
||||
sshStorage, err := ssh.NewStorage(ssh.Config{
|
||||
Host: sshConfig.hostName,
|
||||
Port: sshConfig.port,
|
||||
User: sshConfig.user,
|
||||
Password: sshConfig.password,
|
||||
RemotePath: config.remotePath,
|
||||
LocalPath: tmpPath,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Fatal("Error creating SSH storage: %s", err)
|
||||
}
|
||||
err = sshStorage.Copy(finalFileName)
|
||||
if err != nil {
|
||||
logger.Fatal("Error copying backup file: %s", err)
|
||||
}
|
||||
// Get backup info
|
||||
fileInfo, err := os.Stat(filepath.Join(tmpPath, finalFileName))
|
||||
if err != nil {
|
||||
logger.Error("Error: %s", err)
|
||||
}
|
||||
backupSize = fileInfo.Size()
|
||||
logger.Info("Backup saved in %s", filepath.Join(config.remotePath, finalFileName))
|
||||
|
||||
// Delete backup file from tmp folder
|
||||
err = utils.DeleteFile(filepath.Join(tmpPath, finalFileName))
|
||||
if err != nil {
|
||||
logger.Error("Error deleting file: %v", err)
|
||||
|
||||
}
|
||||
if config.prune {
|
||||
err := sshStorage.Prune(config.backupRetention)
|
||||
if err != nil {
|
||||
logger.Fatal("Error deleting old backup from %s storage: %s ", config.storage, err)
|
||||
}
|
||||
|
||||
}
|
||||
logger.Info("Uploading backup archive to remote storage ... done ")
|
||||
// Send notification
|
||||
utils.NotifySuccess(&utils.NotificationData{
|
||||
File: finalFileName,
|
||||
BackupSize: backupSize,
|
||||
Database: db.dbName,
|
||||
Storage: config.storage,
|
||||
BackupLocation: filepath.Join(config.remotePath, finalFileName),
|
||||
StartTime: startTime,
|
||||
EndTime: time.Now().Format(utils.TimeFormat()),
|
||||
})
|
||||
// Delete temp
|
||||
deleteTemp()
|
||||
logger.Info("Backup completed successfully")
|
||||
|
||||
}
|
||||
func ftpBackup(db *dbConfig, config *BackupConfig) {
|
||||
logger.Info("Backup database to the remote FTP server")
|
||||
startTime = time.Now().Format(utils.TimeFormat())
|
||||
|
||||
// Backup database
|
||||
BackupDatabase(db, config.backupFileName, disableCompression)
|
||||
finalFileName := config.backupFileName
|
||||
if config.encryption {
|
||||
encryptBackup(config)
|
||||
finalFileName = fmt.Sprintf("%s.%s", config.backupFileName, "gpg")
|
||||
}
|
||||
logger.Info("Uploading backup archive to the remote FTP server ... ")
|
||||
logger.Info("Backup name is %s", finalFileName)
|
||||
ftpConfig := loadFtpConfig()
|
||||
ftpStorage, err := ftp.NewStorage(ftp.Config{
|
||||
Host: ftpConfig.host,
|
||||
Port: ftpConfig.port,
|
||||
User: ftpConfig.user,
|
||||
Password: ftpConfig.password,
|
||||
RemotePath: config.remotePath,
|
||||
LocalPath: tmpPath,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Fatal("Error creating SSH storage: %s", err)
|
||||
}
|
||||
err = ftpStorage.Copy(finalFileName)
|
||||
if err != nil {
|
||||
logger.Fatal("Error copying backup file: %s", err)
|
||||
}
|
||||
logger.Info("Backup saved in %s", filepath.Join(config.remotePath, finalFileName))
|
||||
// Get backup info
|
||||
fileInfo, err := os.Stat(filepath.Join(tmpPath, finalFileName))
|
||||
if err != nil {
|
||||
logger.Error("Error: %s", err)
|
||||
}
|
||||
backupSize = fileInfo.Size()
|
||||
// Delete backup file from tmp folder
|
||||
err = utils.DeleteFile(filepath.Join(tmpPath, finalFileName))
|
||||
if err != nil {
|
||||
logger.Error("Error deleting file: %v", err)
|
||||
|
||||
}
|
||||
if config.prune {
|
||||
err := ftpStorage.Prune(config.backupRetention)
|
||||
if err != nil {
|
||||
logger.Fatal("Error deleting old backup from %s storage: %s ", config.storage, err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
logger.Info("Uploading backup archive to the remote FTP server ... done ")
|
||||
|
||||
// Send notification
|
||||
utils.NotifySuccess(&utils.NotificationData{
|
||||
File: finalFileName,
|
||||
BackupSize: backupSize,
|
||||
Database: db.dbName,
|
||||
Storage: config.storage,
|
||||
BackupLocation: filepath.Join(config.remotePath, finalFileName),
|
||||
StartTime: startTime,
|
||||
EndTime: time.Now().Format(utils.TimeFormat()),
|
||||
})
|
||||
// Delete temp
|
||||
deleteTemp()
|
||||
logger.Info("Backup completed successfully")
|
||||
}
|
||||
func remoteRestore(db *dbConfig, conf *RestoreConfig) {
|
||||
logger.Info("Restore database from remote server")
|
||||
sshConfig, err := loadSSHConfig()
|
||||
if err != nil {
|
||||
logger.Fatal("Error loading ssh config: %s", err)
|
||||
}
|
||||
|
||||
sshStorage, err := ssh.NewStorage(ssh.Config{
|
||||
Host: sshConfig.hostName,
|
||||
Port: sshConfig.port,
|
||||
User: sshConfig.user,
|
||||
Password: sshConfig.password,
|
||||
IdentifyFile: sshConfig.identifyFile,
|
||||
RemotePath: conf.remotePath,
|
||||
LocalPath: tmpPath,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Fatal("Error creating SSH storage: %s", err)
|
||||
}
|
||||
err = sshStorage.CopyFrom(conf.file)
|
||||
if err != nil {
|
||||
logger.Fatal("Error copying backup file: %s", err)
|
||||
}
|
||||
RestoreDatabase(db, conf)
|
||||
}
|
||||
func ftpRestore(db *dbConfig, conf *RestoreConfig) {
|
||||
logger.Info("Restore database from FTP server")
|
||||
ftpConfig := loadFtpConfig()
|
||||
ftpStorage, err := ftp.NewStorage(ftp.Config{
|
||||
Host: ftpConfig.host,
|
||||
Port: ftpConfig.port,
|
||||
User: ftpConfig.user,
|
||||
Password: ftpConfig.password,
|
||||
RemotePath: conf.remotePath,
|
||||
LocalPath: tmpPath,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Fatal("Error creating SSH storage: %s", err)
|
||||
}
|
||||
err = ftpStorage.CopyFrom(conf.file)
|
||||
if err != nil {
|
||||
logger.Fatal("Error copying backup file: %s", err)
|
||||
}
|
||||
RestoreDatabase(db, conf)
|
||||
}
|
||||
@@ -26,10 +26,7 @@ SOFTWARE.
|
||||
*/
|
||||
import (
|
||||
"github.com/jkaninda/encryptor"
|
||||
"github.com/jkaninda/go-storage/pkg/ftp"
|
||||
"github.com/jkaninda/go-storage/pkg/local"
|
||||
"github.com/jkaninda/go-storage/pkg/s3"
|
||||
"github.com/jkaninda/go-storage/pkg/ssh"
|
||||
"github.com/jkaninda/mysql-bkup/pkg/logger"
|
||||
"github.com/jkaninda/mysql-bkup/utils"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -47,11 +44,13 @@ func StartRestore(cmd *cobra.Command) {
|
||||
case "local":
|
||||
localRestore(dbConf, restoreConf)
|
||||
case "s3", "S3":
|
||||
restoreFromS3(dbConf, restoreConf)
|
||||
s3Restore(dbConf, restoreConf)
|
||||
case "ssh", "SSH", "remote":
|
||||
restoreFromRemote(dbConf, restoreConf)
|
||||
remoteRestore(dbConf, restoreConf)
|
||||
case "ftp", "FTP":
|
||||
restoreFromFTP(dbConf, restoreConf)
|
||||
ftpRestore(dbConf, restoreConf)
|
||||
case "azure":
|
||||
azureRestore(dbConf, restoreConf)
|
||||
default:
|
||||
localRestore(dbConf, restoreConf)
|
||||
}
|
||||
@@ -69,77 +68,6 @@ func localRestore(dbConf *dbConfig, restoreConf *RestoreConfig) {
|
||||
RestoreDatabase(dbConf, restoreConf)
|
||||
|
||||
}
|
||||
func restoreFromS3(db *dbConfig, conf *RestoreConfig) {
|
||||
logger.Info("Restore database from s3")
|
||||
awsConfig := initAWSConfig()
|
||||
if conf.remotePath == "" {
|
||||
conf.remotePath = awsConfig.remotePath
|
||||
}
|
||||
s3Storage, err := s3.NewStorage(s3.Config{
|
||||
Endpoint: awsConfig.endpoint,
|
||||
Bucket: awsConfig.bucket,
|
||||
AccessKey: awsConfig.accessKey,
|
||||
SecretKey: awsConfig.secretKey,
|
||||
Region: awsConfig.region,
|
||||
DisableSsl: awsConfig.disableSsl,
|
||||
ForcePathStyle: awsConfig.forcePathStyle,
|
||||
RemotePath: awsConfig.remotePath,
|
||||
LocalPath: tmpPath,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Fatal("Error creating s3 storage: %s", err)
|
||||
}
|
||||
err = s3Storage.CopyFrom(conf.file)
|
||||
if err != nil {
|
||||
logger.Fatal("Error download file from S3 storage: %s", err)
|
||||
}
|
||||
RestoreDatabase(db, conf)
|
||||
}
|
||||
func restoreFromRemote(db *dbConfig, conf *RestoreConfig) {
|
||||
logger.Info("Restore database from remote server")
|
||||
sshConfig, err := loadSSHConfig()
|
||||
if err != nil {
|
||||
logger.Fatal("Error loading ssh config: %s", err)
|
||||
}
|
||||
|
||||
sshStorage, err := ssh.NewStorage(ssh.Config{
|
||||
Host: sshConfig.hostName,
|
||||
Port: sshConfig.port,
|
||||
User: sshConfig.user,
|
||||
Password: sshConfig.password,
|
||||
IdentifyFile: sshConfig.identifyFile,
|
||||
RemotePath: conf.remotePath,
|
||||
LocalPath: tmpPath,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Fatal("Error creating SSH storage: %s", err)
|
||||
}
|
||||
err = sshStorage.CopyFrom(conf.file)
|
||||
if err != nil {
|
||||
logger.Fatal("Error copying backup file: %s", err)
|
||||
}
|
||||
RestoreDatabase(db, conf)
|
||||
}
|
||||
func restoreFromFTP(db *dbConfig, conf *RestoreConfig) {
|
||||
logger.Info("Restore database from FTP server")
|
||||
ftpConfig := loadFtpConfig()
|
||||
ftpStorage, err := ftp.NewStorage(ftp.Config{
|
||||
Host: ftpConfig.host,
|
||||
Port: ftpConfig.port,
|
||||
User: ftpConfig.user,
|
||||
Password: ftpConfig.password,
|
||||
RemotePath: conf.remotePath,
|
||||
LocalPath: tmpPath,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Fatal("Error creating SSH storage: %s", err)
|
||||
}
|
||||
err = ftpStorage.CopyFrom(conf.file)
|
||||
if err != nil {
|
||||
logger.Fatal("Error copying backup file: %s", err)
|
||||
}
|
||||
RestoreDatabase(db, conf)
|
||||
}
|
||||
|
||||
// RestoreDatabase restore database
|
||||
func RestoreDatabase(db *dbConfig, conf *RestoreConfig) {
|
||||
|
||||
135
internal/s3.go
Normal file
135
internal/s3.go
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Jonas Kaninda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/jkaninda/go-storage/pkg/s3"
|
||||
"github.com/jkaninda/mysql-bkup/pkg/logger"
|
||||
"github.com/jkaninda/mysql-bkup/utils"
|
||||
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
func s3Backup(db *dbConfig, config *BackupConfig) {
|
||||
|
||||
logger.Info("Backup database to s3 storage")
|
||||
startTime = time.Now().Format(utils.TimeFormat())
|
||||
// Backup database
|
||||
BackupDatabase(db, config.backupFileName, disableCompression)
|
||||
finalFileName := config.backupFileName
|
||||
if config.encryption {
|
||||
encryptBackup(config)
|
||||
finalFileName = fmt.Sprintf("%s.%s", config.backupFileName, "gpg")
|
||||
}
|
||||
logger.Info("Uploading backup archive to remote storage S3 ... ")
|
||||
awsConfig := initAWSConfig()
|
||||
if config.remotePath == "" {
|
||||
config.remotePath = awsConfig.remotePath
|
||||
}
|
||||
logger.Info("Backup name is %s", finalFileName)
|
||||
s3Storage, err := s3.NewStorage(s3.Config{
|
||||
Endpoint: awsConfig.endpoint,
|
||||
Bucket: awsConfig.bucket,
|
||||
AccessKey: awsConfig.accessKey,
|
||||
SecretKey: awsConfig.secretKey,
|
||||
Region: awsConfig.region,
|
||||
DisableSsl: awsConfig.disableSsl,
|
||||
ForcePathStyle: awsConfig.forcePathStyle,
|
||||
RemotePath: awsConfig.remotePath,
|
||||
LocalPath: tmpPath,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Fatal("Error creating s3 storage: %s", err)
|
||||
}
|
||||
err = s3Storage.Copy(finalFileName)
|
||||
if err != nil {
|
||||
logger.Fatal("Error copying backup file: %s", err)
|
||||
}
|
||||
// Get backup info
|
||||
fileInfo, err := os.Stat(filepath.Join(tmpPath, finalFileName))
|
||||
if err != nil {
|
||||
logger.Error("Error: %s", err)
|
||||
}
|
||||
backupSize = fileInfo.Size()
|
||||
|
||||
// Delete backup file from tmp folder
|
||||
err = utils.DeleteFile(filepath.Join(tmpPath, config.backupFileName))
|
||||
if err != nil {
|
||||
fmt.Println("Error deleting file: ", err)
|
||||
|
||||
}
|
||||
// Delete old backup
|
||||
if config.prune {
|
||||
err := s3Storage.Prune(config.backupRetention)
|
||||
if err != nil {
|
||||
logger.Fatal("Error deleting old backup from %s storage: %s ", config.storage, err)
|
||||
}
|
||||
}
|
||||
logger.Info("Backup saved in %s", filepath.Join(config.remotePath, finalFileName))
|
||||
logger.Info("Uploading backup archive to remote storage S3 ... done ")
|
||||
// Send notification
|
||||
utils.NotifySuccess(&utils.NotificationData{
|
||||
File: finalFileName,
|
||||
BackupSize: backupSize,
|
||||
Database: db.dbName,
|
||||
Storage: config.storage,
|
||||
BackupLocation: filepath.Join(config.remotePath, finalFileName),
|
||||
StartTime: startTime,
|
||||
EndTime: time.Now().Format(utils.TimeFormat()),
|
||||
})
|
||||
// Delete temp
|
||||
deleteTemp()
|
||||
logger.Info("Backup completed successfully")
|
||||
|
||||
}
|
||||
func s3Restore(db *dbConfig, conf *RestoreConfig) {
|
||||
logger.Info("Restore database from s3")
|
||||
awsConfig := initAWSConfig()
|
||||
if conf.remotePath == "" {
|
||||
conf.remotePath = awsConfig.remotePath
|
||||
}
|
||||
s3Storage, err := s3.NewStorage(s3.Config{
|
||||
Endpoint: awsConfig.endpoint,
|
||||
Bucket: awsConfig.bucket,
|
||||
AccessKey: awsConfig.accessKey,
|
||||
SecretKey: awsConfig.secretKey,
|
||||
Region: awsConfig.region,
|
||||
DisableSsl: awsConfig.disableSsl,
|
||||
ForcePathStyle: awsConfig.forcePathStyle,
|
||||
RemotePath: awsConfig.remotePath,
|
||||
LocalPath: tmpPath,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Fatal("Error creating s3 storage: %s", err)
|
||||
}
|
||||
err = s3Storage.CopyFrom(conf.file)
|
||||
if err != nil {
|
||||
logger.Fatal("Error download file from S3 storage: %s", err)
|
||||
}
|
||||
RestoreDatabase(db, conf)
|
||||
}
|
||||
@@ -74,6 +74,11 @@ var ftpVars = []string{
|
||||
"FTP_PASSWORD",
|
||||
"FTP_PORT",
|
||||
}
|
||||
var azureVars = []string{
|
||||
"AZURE_STORAGE_CONTAINER_NAME",
|
||||
"AZURE_STORAGE_ACCOUNT_NAME",
|
||||
"AZURE_STORAGE_ACCOUNT_KEY",
|
||||
}
|
||||
|
||||
// AwsVars Required environment variables for AWS S3 storage
|
||||
var awsVars = []string{
|
||||
|
||||
Reference in New Issue
Block a user