mirror of
https://github.com/cupcakearmy/autorestic.git
synced 2026-04-02 11:55:23 +00:00
add copy option
This commit is contained in:
@@ -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) {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user