Skip to content

Commit

Permalink
reorganized sftp and added rotation to it
Browse files Browse the repository at this point in the history
  • Loading branch information
LobbyLobster committed Mar 20, 2024
1 parent 2f2ce39 commit d2b85d8
Show file tree
Hide file tree
Showing 9 changed files with 179 additions and 78 deletions.
68 changes: 37 additions & 31 deletions backup/backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,37 +77,44 @@ func Backup() {
filePath, fileName, err := dumpDB(db, dst)
if err != nil {
notify.SendAlarm("Problem during backing up "+db+" - Error: "+err.Error(), true)
err = os.Remove(filePath)
if err != nil {
logger.Error("Couldn't delete faulty dump file at " + filePath + " - Error: " + err.Error())
} else {
logger.Info("Faulty dump file at " + filePath + " successfully deleted.")
}
} else {
logger.Info("Successfully backed up database:" + db + " at " + filePath)
notify.SendAlarm("Successfully backed up "+db+" at "+filePath, false)
}
if params.Rotation.Enabled {
shouldRotate, name := rotate(db)
if shouldRotate {
var newDst string
if params.Minio.Path != "" {
newDst = params.Minio.Path
}
newDst = params.Minio.S3FS.MountPath + "/" + newDst
newDst = strings.TrimSuffix(newDst, "/")
err := os.MkdirAll(strings.TrimSuffix(newDst, "/")+"/"+rotatePath(), os.FileMode(0750))
if err != nil {
notify.SendAlarm("Couldn't create folder in MinIO at path: "+dst+" - Error: "+err.Error(), true)
logger.Fatal("Couldn't create folder in MinIO at path: " + dst + " - Error: " + err.Error())
return
}
extension := strings.Split(fileName, ".")
for i := 1; i < len(extension); i++ {
name = name + "." + extension[i]
}
name = newDst + "/" + name
_, err = copyFile(filePath, name)
if err != nil {
logger.Error("Couldn't create a copy of " + filePath + " for rotation\npath: " + name + "\n Error: " + err.Error())
notify.SendAlarm("Couldn't create a copy of "+filePath+" for rotation\npath: "+name+"\n Error: "+err.Error(), true)
} else {
logger.Info("Successfully created a copy of " + filePath + " for rotation\npath: " + name)
notify.SendAlarm("Successfully created a copy of "+filePath+" for rotation\npath: "+name, false)

if params.Rotation.Enabled {
shouldRotate, name := rotate(db)
if shouldRotate {
var newDst string
if params.Minio.Path != "" {
newDst = params.Minio.Path
}
newDst = params.Minio.S3FS.MountPath + "/" + newDst
newDst = strings.TrimSuffix(newDst, "/")
err := os.MkdirAll(strings.TrimSuffix(newDst, "/")+"/"+rotatePath(), os.FileMode(0750))
if err != nil {
notify.SendAlarm("Couldn't create folder in MinIO at path: "+dst+" - Error: "+err.Error(), true)
logger.Fatal("Couldn't create folder in MinIO at path: " + dst + " - Error: " + err.Error())
return
}
extension := strings.Split(fileName, ".")
for i := 1; i < len(extension); i++ {
name = name + "." + extension[i]
}
name = newDst + "/" + name
_, err = copyFile(filePath, name)
if err != nil {
logger.Error("Couldn't create a copy of " + filePath + " for rotation\npath: " + name + "\n Error: " + err.Error())
notify.SendAlarm("Couldn't create a copy of "+filePath+" for rotation\npath: "+name+"\n Error: "+err.Error(), true)
} else {
logger.Info("Successfully created a copy of " + filePath + " for rotation\npath: " + name)
notify.SendAlarm("Successfully created a copy of "+filePath+" for rotation\npath: "+name, false)
}
}
}
}
Expand Down Expand Up @@ -139,9 +146,8 @@ func Backup() {
}

if params.SFTP.Enabled {
err = SendSFTP(filePath, "/root/"+name, params.SFTP.User, params.SFTP.Target, params.SFTP.Port)
if err != nil {
logger.Error("Couldn't upload " + name + " at " + filePath + " to target with sftp" + " - Error: " + err.Error())
for _, target := range params.SFTP.Targets {
SendSFTP(filePath, name, db, target)
}
}
}
Expand Down
7 changes: 5 additions & 2 deletions backup/mysql.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os"
"os/exec"
"strconv"
"strings"
)

func getMySQLList() []string {
Expand Down Expand Up @@ -142,8 +143,10 @@ func dumpMySQLDb(db, dst string) (string, string, error) {
}
n, _ := stderr2.Read(output)
if n > 0 {
logger.Error("Couldn't back up " + db + " - Error: " + string(string(output[:n])))
return dumpPath, name, errors.New(string(output[:n]))
if !strings.Contains(string(string(output[:n])), "[Warning] Using a password on the command line interface can be insecure.") {
logger.Error("Couldn't back up " + db + " - Error: " + string(string(output[:n])))
return dumpPath, name, errors.New(string(output[:n]))
}
}
return dumpPath, name, nil
}
79 changes: 65 additions & 14 deletions backup/sftp.go
Original file line number Diff line number Diff line change
@@ -1,77 +1,128 @@
package backup

import (
"monodb-backup/config"
"monodb-backup/notify"
"net"
"os"
"strings"

"github.com/pkg/sftp"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
)

func SendSFTP(srcPath, dstPath, user, target, port string) error {
func SendSFTP(srcPath, dstPath, db string, target config.Target) {
dstPath = target.Path + "/" + nameWithPath(dstPath)
logger.Info("SFTP transfer started.\n Source: " + srcPath + " - Destination: " + target.Host + ":" + dstPath)
sock, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
if err != nil {
return err
logger.Error("Couldn't get environment variable SSH_AUTH_SOCK - Error: " + err.Error())
notify.SendAlarm("Couldn't upload backup "+srcPath+" to "+target.Host+":"+dstPath+"\nCouldn't get environment variable SSH_AUTH_SOCK - Error: "+err.Error(), true)
return
}

sockAgent := agent.NewClient(sock)

signers, err := sockAgent.Signers()
if err != nil {
return err
logger.Error("Couldn't get signers for ssh keys - Error: " + err.Error())
notify.SendAlarm("Couldn't upload backup "+srcPath+" to "+target.Host+":"+dstPath+"\nCouldn't get signers for ssh keys - Error: "+err.Error(), true)
return
}
auths := []ssh.AuthMethod{ssh.PublicKeys(signers...)}

config := &ssh.ClientConfig{
User: user,
User: target.User,
Auth: auths,
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}

client, _ := ssh.Dial("tcp", target+":"+port, config)
client, _ := ssh.Dial("tcp", target.Host+":"+target.Port, config)
defer func() {
err = client.Close()
if err != nil {
// TODO
logger.Error("Couldn't close SSH client - Error: " + err.Error())
notify.SendAlarm("Couldn't close SSH client - Error: "+err.Error(), true)
}
}()

sftpCli, err := sftp.NewClient(client)
if err != nil {
return err
logger.Error("Couldn't create an SFTP client - Error: " + err.Error())
notify.SendAlarm("Couldn't upload backup "+srcPath+" to "+target.Host+":"+dstPath+"\nCouldn't create an SFTP client - Error: "+err.Error(), true)
return
}
defer func() {
err = sftpCli.Close()
if err != nil {
// TODO
logger.Error("Couldn't close SFTP client - Error: " + err.Error())
notify.SendAlarm("Couldn't close SFTP client - Error: "+err.Error(), true)
}
}()

src, err := os.Open(srcPath)
if err != nil {
return err
logger.Error("Couldn't open source file " + srcPath + " for copying - Error: " + err.Error())
notify.SendAlarm("Couldn't upload backup "+srcPath+" to "+target.Host+":"+dstPath+"\nCouldn't open source file "+srcPath+" for copying - Error: "+err.Error(), true)
return
}
defer func() {
err = src.Close()
if err != nil {
// TODO
logger.Error("Couldn't close source file: " + srcPath + " - Error: " + err.Error())
notify.SendAlarm("Couldn't close source file: "+srcPath+" - Error: "+err.Error(), true)
}
}()

sendOverSFTp(srcPath, dstPath, src, target, sftpCli)

if params.Rotation.Enabled {
shouldRotate, newDst := rotate(db)
if shouldRotate {
extension := strings.Split(dstPath, ".")
for i := 1; i < len(extension); i++ {
newDst = newDst + "." + extension[i]
}
newDst = target.Path + "/" + newDst
sendOverSFTp(srcPath, newDst, src, target, sftpCli)
}
}

}

func sendOverSFTp(srcPath, dstPath string, src *os.File, target config.Target, sftpCli *sftp.Client) {
fullPath := strings.Split(dstPath, "/")
newPath := "/"
for i := 0; i < len(fullPath)-1; i++ {
newPath = newPath + "/" + fullPath[i]
}
err := sftpCli.MkdirAll(newPath)
if err != nil {
logger.Error("Couldn't create folders " + newPath + " - Error: " + err.Error())
notify.SendAlarm("Couldn't upload backup "+srcPath+" to "+target.Host+":"+dstPath+"\nCouldn't create folders "+newPath+" - Error: "+err.Error(), true)
return
}
dst, err := sftpCli.Create(dstPath)
if err != nil {
return err
logger.Error("Couldn't create file " + dstPath + " - Error: " + err.Error())
notify.SendAlarm("Couldn't upload backup "+srcPath+" to "+target.Host+":"+dstPath+"\nCouldn't create file "+dstPath+" - Error: "+err.Error(), true)
return
}
defer func() {
err = dst.Close()
if err != nil {
// TODO
logger.Error("Couldn't close destination file: " + dstPath + " - Error: " + err.Error())
notify.SendAlarm("Couldn't close destination file: "+dstPath+" - Error: "+err.Error(), true)
}
}()
logger.Info("Created destination file " + dstPath + " Now starting copying")

if _, err := dst.ReadFrom(src); err != nil {
return err
logger.Error("Couldn't read from file " + srcPath + " to write at " + dstPath + " - Error: " + err.Error())
notify.SendAlarm("Couldn't upload backup "+srcPath+" to "+target.Host+":"+dstPath+"\nCouldn't read from file "+srcPath+" to write at "+dstPath+" - Error: "+err.Error(), true)
return
}
return nil
logger.Info("Successfully copied " + srcPath + " to " + target.Host + ":" + dstPath)
notify.SendAlarm("Successfully copied "+srcPath+" to "+target.Host+":"+dstPath, false)
}
13 changes: 10 additions & 3 deletions config/config.sample.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,20 @@ minio:
keepPasswdFile: true
sftp:
enabled: false
user: username
target: ssh.example.com
port: 22
targets:
- user: username
host: ssh.example.com
path: /var/backups
port: 22
- user: username2
host: ssh.example2.com
path: /var/backups
port: 22
notify:
email:
enabled: false
onlyOnError: false
insecureSkipVerify: false
info:
smtpHost: smtp.gmail.com
smtpPort: 587
Expand Down
20 changes: 13 additions & 7 deletions config/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ type Params struct {
Cluster Cluster
Notify struct {
Email struct {
Enabled bool
OnlyOnError bool
Info EmailConfig
Error EmailConfig
Enabled bool
OnlyOnError bool
InsecureSkipVerify bool
Info EmailConfig
Error EmailConfig
}
Webhook Webhook
}
Expand All @@ -39,9 +40,7 @@ type Params struct {
Minio MinIO
SFTP struct {
Enabled bool
User string
Target string
Port string
Targets []Target
}
Log LoggerParams
Fqdn string
Expand All @@ -59,6 +58,13 @@ type MinIO struct {
S3FS S3FS
}

type Target struct {
User string
Host string
Port string
Path string
}

type S3FS struct {
ShouldMount bool
MountPath string
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/snowzach/rotatefilehook v0.0.0-20220211133110-53752135082d
github.com/spf13/viper v1.18.2
golang.org/x/crypto v0.21.0
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
)

require (
Expand Down Expand Up @@ -43,6 +44,7 @@ require (
golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,13 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
Expand Down
Loading

0 comments on commit d2b85d8

Please sign in to comment.