You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
backy/cmd/backy/backy.go

224 lines
5.3 KiB

package backy
import (
"os/exec"
"github.com/melbahja/goph"
"github.com/spf13/viper"
)
type logging struct {
err error
output string
}
type Host struct {
Empty bool
Host string
Port uint16
PrivateKeyPath string
PrivateKeyPassword string
User string
}
type Command struct {
Empty bool
Remote bool
RemoteHost Host
Cmd string
Args []string
}
type Commands struct {
Before Command
Backup Command
After Command
}
type BackupConfig struct {
Name string
BackupType string
ConfigPath string
Cmds Commands
dstDir string
srcDir string
}
func ReadConfig(backup string, config viper.Viper) (*viper.Viper, error) {
err := viper.ReadInConfig()
if err != nil {
return &viper.Viper{}, err
}
conf := config.Sub("backup." + backup)
backupConfig := config.Unmarshal(&conf)
if backupConfig == nil {
return &viper.Viper{}, backupConfig
}
return conf, nil
}
// pass Name-level (i.e. "backups."+configName) to function
func CreateConfig(backup BackupConfig) BackupConfig {
newBackupConfig := BackupConfig{
Name: backup.Name,
BackupType: backup.BackupType,
dstDir: backup.dstDir,
srcDir: backup.srcDir,
ConfigPath: backup.ConfigPath,
}
if !backup.Cmds.Before.Empty {
newBackupConfig.Cmds.Before.Cmd = backup.Cmds.Before.Cmd
newBackupConfig.Cmds.After.Args = backup.Cmds.Before.Args
if backup.Cmds.Before.Remote {
newBackupConfig.Cmds.Before.RemoteHost.Host = backup.Cmds.Before.RemoteHost.Host
newBackupConfig.Cmds.Before.RemoteHost.Port = backup.Cmds.Before.RemoteHost.Port
newBackupConfig.Cmds.Before.RemoteHost.PrivateKeyPath = backup.Cmds.Before.RemoteHost.PrivateKeyPath
} else {
newBackupConfig.Cmds.Before.RemoteHost.Empty = true
}
}
if !backup.Cmds.Backup.Empty {
newBackupConfig.Cmds.Backup.Cmd = backup.Cmds.Backup.Cmd
newBackupConfig.Cmds.Backup.Args = backup.Cmds.Backup.Args
if backup.Cmds.Backup.Remote {
newBackupConfig.Cmds.Backup.RemoteHost.Host = backup.Cmds.Backup.RemoteHost.Host
newBackupConfig.Cmds.Backup.RemoteHost.Port = backup.Cmds.Backup.RemoteHost.Port
newBackupConfig.Cmds.Backup.RemoteHost.PrivateKeyPath = backup.Cmds.Backup.RemoteHost.PrivateKeyPath
} else {
newBackupConfig.Cmds.Backup.RemoteHost.Empty = true
}
}
if !backup.Cmds.After.Empty {
newBackupConfig.Cmds.After.Cmd = backup.Cmds.After.Cmd
newBackupConfig.Cmds.After.Args = backup.Cmds.After.Args
if backup.Cmds.After.Remote {
newBackupConfig.Cmds.After.RemoteHost.Host = backup.Cmds.After.RemoteHost.Host
newBackupConfig.Cmds.After.RemoteHost.Port = backup.Cmds.After.RemoteHost.Port
newBackupConfig.Cmds.After.RemoteHost.PrivateKeyPath = backup.Cmds.After.RemoteHost.PrivateKeyPath
} else {
newBackupConfig.Cmds.Before.RemoteHost.Empty = true
}
}
return backup
}
// writes config to file
func WriteConfig(config viper.Viper, backup BackupConfig) error {
configName := "backup." + backup.Name
config.Set(configName+".BackupType", backup.BackupType)
if !backup.Cmds.After.Empty {
config.Set(configName+".Cmds.After.Cmd", backup.Cmds.After.Cmd)
config.Set(configName+".Cmds.After.Args", backup.Cmds.After.Args)
if backup.Cmds.Before.Remote {
config.Set(configName+".Cmds.After.RemoteHost.Host", backup.Cmds.After.RemoteHost.Host)
}
}
config.Set(configName+"..Cmds.backup.Cmd", backup.Cmds.Backup.Cmd)
if !backup.Cmds.Before.Empty {
config.Set(configName+"Cmds.Before.Cmd", backup.Cmds.Before.Cmd)
config.Set(configName+"Cmds.Before.Args", backup.Cmds.Before.Args)
}
err := config.WriteConfig()
if err != nil {
return err
}
return nil
}
/*
* Runs a backup configuration
*/
func Run(backup BackupConfig) logging {
beforeConfig := backup.Cmds.Before
beforeOutput := runCmd(beforeConfig)
if beforeOutput.err != nil {
return logging{
output: beforeOutput.output,
err: beforeOutput.err,
}
}
backupConfig := backup.Cmds.Backup
backupOutput := runCmd(backupConfig)
if backupOutput.err != nil {
return logging{
output: backupOutput.output,
err: beforeOutput.err,
}
}
afterConfig := backup.Cmds.After
afterOutput := runCmd(afterConfig)
if afterOutput.err != nil {
return logging{
output: afterOutput.output,
err: afterOutput.err,
}
}
return logging{
output: afterOutput.output,
err: nil,
}
}
func runCmd(cmd Command) logging {
if !cmd.Empty {
if cmd.Remote {
// Start new ssh connection with private key.
auth, err := goph.Key(cmd.RemoteHost.PrivateKeyPath, cmd.RemoteHost.PrivateKeyPassword)
if err != nil {
return logging{
output: err.Error(),
err: err,
}
}
client, err := goph.New(cmd.RemoteHost.User, cmd.RemoteHost.Host, auth)
if err != nil {
return logging{
output: err.Error(),
err: err,
}
}
// Defer closing the network connection.
defer client.Close()
command := cmd.Cmd
for _, v := range cmd.Args {
command += v
}
// Execute your command.
out, err := client.Run(command)
if err != nil {
return logging{
output: string(out),
err: err,
}
}
}
cmdOut := exec.Command(cmd.Cmd, cmd.Args...)
output, err := cmdOut.Output()
if err != nil {
return logging{
output: string(output),
err: err,
}
}
}
return logging{
output: "",
err: nil,
}
}