add copy option

This commit is contained in:
2022-04-13 17:07:38 +02:00
parent 1751e2babb
commit 5418f56b1a
4 changed files with 74 additions and 15 deletions

View File

@@ -13,18 +13,18 @@ import (
) )
type BackendRest struct { type BackendRest struct {
User string `yaml:"user,omitempty"` User string `mapstructure:"user,omitempty"`
Password string `yaml:"password,omitempty"` Password string `mapstructure:"password,omitempty"`
} }
type Backend struct { type Backend struct {
name string name string
Type string `yaml:"type,omitempty"` Type string `mapstructure:"type,omitempty"`
Path string `yaml:"path,omitempty"` Path string `mapstructure:"path,omitempty"`
Key string `yaml:"key,omitempty"` Key string `mapstructure:"key,omitempty"`
Env map[string]string `yaml:"env,omitempty"` Env map[string]string `mapstructure:"env,omitempty"`
Rest BackendRest `yaml:"rest,omitempty"` Rest BackendRest `mapstructure:"rest,omitempty"`
Options Options `yaml:"options,omitempty"` Options Options `mapstructure:"options,omitempty"`
} }
func GetBackend(name string) (Backend, bool) { func GetBackend(name string) (Backend, bool) {

View File

@@ -23,11 +23,11 @@ type OptionMap map[string][]interface{}
type Options map[string]OptionMap type Options map[string]OptionMap
type Config struct { type Config struct {
Version string `yaml:"version"` Version string `mapstructure:"version"`
Extras interface{} `yaml:"extras"` Extras interface{} `mapstructure:"extras"`
Locations map[string]Location `yaml:"locations"` Locations map[string]Location `mapstructure:"locations"`
Backends map[string]Backend `yaml:"backends"` Backends map[string]Backend `mapstructure:"backends"`
Global Options `yaml:"global"` Global Options `mapstructure:"global"`
} }
var once sync.Once var once sync.Once

View File

@@ -40,6 +40,8 @@ type Hooks struct {
Failure HookArray `mapstructure:"failure,omitempty"` Failure HookArray `mapstructure:"failure,omitempty"`
} }
type LocationCopy = map[string][]string
type Location struct { type Location struct {
name string `mapstructure:",omitempty"` name string `mapstructure:",omitempty"`
From []string `mapstructure:"from,omitempty"` From []string `mapstructure:"from,omitempty"`
@@ -49,6 +51,7 @@ type Location struct {
Cron string `mapstructure:"cron,omitempty"` Cron string `mapstructure:"cron,omitempty"`
Options Options `mapstructure:"options,omitempty"` Options Options `mapstructure:"options,omitempty"`
ForgetOption LocationForgetOption `mapstructure:"forget,omitempty"` ForgetOption LocationForgetOption `mapstructure:"forget,omitempty"`
CopyOption LocationCopy `mapstructure:"copy,omitempty"`
} }
func GetLocation(name string) (Location, bool) { func GetLocation(name string) (Location, bool) {
@@ -87,15 +90,34 @@ func (l Location) validate() error {
} }
if len(l.To) == 0 { if len(l.To) == 0 {
return fmt.Errorf(`Location "%s" has no "to" targets`, l.name) return fmt.Errorf(`location "%s" has no "to" targets`, l.name)
} }
// Check if backends are all valid // Check if backends are all valid
for _, to := range l.To { for _, to := range l.To {
_, ok := GetBackend(to) _, ok := GetBackend(to)
if !ok { if !ok {
return fmt.Errorf("invalid backend `%s`", to) return fmt.Errorf(`location "%s" has an invalid backend "%s"`, l.name, to)
} }
} }
// Check copy option
for copyFrom, copyTo := range l.CopyOption {
if _, ok := GetBackend(copyFrom); !ok {
return fmt.Errorf(`location "%s" has an invalid backend "%s" in copy option`, l.name, copyFrom)
}
if !ArrayContains(l.To, copyFrom) {
return fmt.Errorf(`location "%s" has an invalid copy from "%s"`, l.name, copyFrom)
}
for _, copyToTarget := range copyTo {
if _, ok := GetBackend(copyToTarget); !ok {
return fmt.Errorf(`location "%s" has an invalid backend "%s" in copy option`, l.name, copyToTarget)
}
if ArrayContains(l.To, copyToTarget) {
return fmt.Errorf(`location "%s" cannot copy to "%s" as it's already a target`, l.name, copyToTarget)
}
}
}
// Check if forget type is correct // Check if forget type is correct
if l.ForgetOption != "" { if l.ForgetOption != "" {
if l.ForgetOption != LocationForgetYes && l.ForgetOption != LocationForgetNo && l.ForgetOption != LocationForgetPrune { if l.ForgetOption != LocationForgetYes && l.ForgetOption != LocationForgetNo && l.ForgetOption != LocationForgetPrune {
@@ -249,6 +271,34 @@ func (l Location) Backup(cron bool, specificBackend string) []error {
continue continue
} }
// Copy
if md.SnapshotID != "" {
for copyFrom, copyTo := range l.CopyOption {
b1, _ := GetBackend(copyFrom)
for _, copyToTarget := range copyTo {
b2, _ := GetBackend(copyToTarget)
colors.Secondary.Println("Copying " + copyFrom + " → " + copyToTarget)
env, _ := b1.getEnv()
env2, _ := b2.getEnv()
// Add the second repo to the env with a "2" suffix
for k, v := range env2 {
env[k+"2"] = v
}
_, out, err := ExecuteResticCommand(ExecuteOptions{
Envs: env,
}, "copy", md.SnapshotID)
if flags.VERBOSE {
colors.Faint.Println(out)
}
if err != nil {
errors = append(errors, err)
}
}
}
}
if flags.VERBOSE { if flags.VERBOSE {
colors.Faint.Println(out) colors.Faint.Println(out)
} }

View File

@@ -87,3 +87,12 @@ func CheckIfVolumeExists(volume string) bool {
_, _, err := ExecuteCommand(ExecuteOptions{Command: "docker"}, "volume", "inspect", volume) _, _, err := ExecuteCommand(ExecuteOptions{Command: "docker"}, "volume", "inspect", volume)
return err == nil return err == nil
} }
func ArrayContains[T comparable](arr []T, needle T) bool {
for _, item := range arr {
if item == needle {
return true
}
}
return false
}