|
|
@ -33,6 +33,13 @@ const (
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
type Hooks struct {
|
|
|
|
type Hooks struct {
|
|
|
|
|
|
|
|
RestoreOption HooksList `mapstructure:"restore,omitempty"`
|
|
|
|
|
|
|
|
BackupOption HooksList `mapstructure:"backup,omitempty"`
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type LocationCopy = map[string][]string
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type HooksList struct {
|
|
|
|
Dir string `mapstructure:"dir"`
|
|
|
|
Dir string `mapstructure:"dir"`
|
|
|
|
Before HookArray `mapstructure:"before,omitempty"`
|
|
|
|
Before HookArray `mapstructure:"before,omitempty"`
|
|
|
|
After HookArray `mapstructure:"after,omitempty"`
|
|
|
|
After HookArray `mapstructure:"after,omitempty"`
|
|
|
@ -40,8 +47,6 @@ 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"`
|
|
|
@ -123,12 +128,12 @@ func (l Location) validate() error {
|
|
|
|
return nil
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (l Location) ExecuteHooks(commands []string, options ExecuteOptions) error {
|
|
|
|
func (l Location) ExecuteHooks(commands []string, directory string, options ExecuteOptions) error {
|
|
|
|
if len(commands) == 0 {
|
|
|
|
if len(commands) == 0 {
|
|
|
|
return nil
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if l.Hooks.Dir != "" {
|
|
|
|
if directory != "" {
|
|
|
|
if dir, err := GetPathRelativeToConfig(l.Hooks.Dir); err != nil {
|
|
|
|
if dir, err := GetPathRelativeToConfig(directory); err != nil {
|
|
|
|
return err
|
|
|
|
return err
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
options.Dir = dir
|
|
|
|
options.Dir = dir
|
|
|
@ -190,7 +195,7 @@ func (l Location) Backup(cron bool, specificBackend string) []error {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Hooks
|
|
|
|
// Hooks
|
|
|
|
if err := l.ExecuteHooks(l.Hooks.Before, options); err != nil {
|
|
|
|
if err := l.ExecuteHooks(l.Hooks.BackupOption.Before, l.Hooks.BackupOption.Dir, options); err != nil {
|
|
|
|
errors = append(errors, err)
|
|
|
|
errors = append(errors, err)
|
|
|
|
goto after
|
|
|
|
goto after
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -290,7 +295,7 @@ func (l Location) Backup(cron bool, specificBackend string) []error {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// After hooks
|
|
|
|
// After hooks
|
|
|
|
if err := l.ExecuteHooks(l.Hooks.After, options); err != nil {
|
|
|
|
if err := l.ExecuteHooks(l.Hooks.BackupOption.After, l.Hooks.BackupOption.Dir, options); err != nil {
|
|
|
|
errors = append(errors, err)
|
|
|
|
errors = append(errors, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -298,11 +303,11 @@ after:
|
|
|
|
var commands []string
|
|
|
|
var commands []string
|
|
|
|
var isSuccess = len(errors) == 0
|
|
|
|
var isSuccess = len(errors) == 0
|
|
|
|
if isSuccess {
|
|
|
|
if isSuccess {
|
|
|
|
commands = l.Hooks.Success
|
|
|
|
commands = l.Hooks.BackupOption.Success
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
commands = l.Hooks.Failure
|
|
|
|
commands = l.Hooks.BackupOption.Failure
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if err := l.ExecuteHooks(commands, options); err != nil {
|
|
|
|
if err := l.ExecuteHooks(commands, l.Hooks.BackupOption.Dir, options); err != nil {
|
|
|
|
errors = append(errors, err)
|
|
|
|
errors = append(errors, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -367,11 +372,35 @@ func buildRestoreCommand(l Location, to string, snapshot string, options []strin
|
|
|
|
return base
|
|
|
|
return base
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (l Location) Restore(to, from string, force bool, snapshot string, options []string) error {
|
|
|
|
func (l Location) Restore(to, from string, force bool, snapshot string, options []string) (errors []error) {
|
|
|
|
|
|
|
|
cwd, _ := GetPathRelativeToConfig(".")
|
|
|
|
|
|
|
|
hooksOptions := ExecuteOptions{
|
|
|
|
|
|
|
|
Command: "bash",
|
|
|
|
|
|
|
|
Dir: cwd,
|
|
|
|
|
|
|
|
Envs: map[string]string{
|
|
|
|
|
|
|
|
"AUTORESTIC_LOCATION": l.name,
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
|
|
|
|
var commands []string
|
|
|
|
|
|
|
|
var isSuccess = len(errors) == 0
|
|
|
|
|
|
|
|
if isSuccess {
|
|
|
|
|
|
|
|
commands = l.Hooks.RestoreOption.Success
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
commands = l.Hooks.RestoreOption.Failure
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := l.ExecuteHooks(commands, l.Hooks.RestoreOption.Dir, hooksOptions); err != nil {
|
|
|
|
|
|
|
|
errors = append(errors, err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
colors.Success.Println("Done")
|
|
|
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
|
|
if from == "" {
|
|
|
|
if from == "" {
|
|
|
|
from = l.To[0]
|
|
|
|
from = l.To[0]
|
|
|
|
} else if !l.hasBackend(from) {
|
|
|
|
} else if !l.hasBackend(from) {
|
|
|
|
return fmt.Errorf("invalid backend: \"%s\"", from)
|
|
|
|
errors = append(errors, fmt.Errorf("invalid backend: \"%s\"", from))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if snapshot == "" {
|
|
|
|
if snapshot == "" {
|
|
|
@ -382,15 +411,23 @@ func (l Location) Restore(to, from string, force bool, snapshot string, options
|
|
|
|
backend, _ := GetBackend(from)
|
|
|
|
backend, _ := GetBackend(from)
|
|
|
|
colors.Secondary.Printf("Restoring %s@%s → %s\n", snapshot, backend.name, to)
|
|
|
|
colors.Secondary.Printf("Restoring %s@%s → %s\n", snapshot, backend.name, to)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Before Hooks for restore
|
|
|
|
|
|
|
|
if err := l.ExecuteHooks(l.Hooks.RestoreOption.Before, l.Hooks.RestoreOption.Dir, hooksOptions); err != nil {
|
|
|
|
|
|
|
|
errors = append(errors, err)
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
t, err := l.getType()
|
|
|
|
t, err := l.getType()
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
errors = append(errors, err)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
switch t {
|
|
|
|
switch t {
|
|
|
|
case TypeLocal:
|
|
|
|
case TypeLocal:
|
|
|
|
to, err = filepath.Abs(to)
|
|
|
|
to, err = filepath.Abs(to)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
errors = append(errors, err)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Check if target is empty
|
|
|
|
// Check if target is empty
|
|
|
|
if !force {
|
|
|
|
if !force {
|
|
|
@ -399,14 +436,17 @@ func (l Location) Restore(to, from string, force bool, snapshot string, options
|
|
|
|
if err == nil {
|
|
|
|
if err == nil {
|
|
|
|
files, err := ioutil.ReadDir(to)
|
|
|
|
files, err := ioutil.ReadDir(to)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
errors = append(errors, err)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(files) > 0 {
|
|
|
|
if len(files) > 0 {
|
|
|
|
return notEmptyError
|
|
|
|
errors = append(errors, notEmptyError)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
if !os.IsNotExist(err) {
|
|
|
|
if !os.IsNotExist(err) {
|
|
|
|
return err
|
|
|
|
errors = append(errors, err)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -415,10 +455,17 @@ func (l Location) Restore(to, from string, force bool, snapshot string, options
|
|
|
|
_, _, err = backend.ExecDocker(l, buildRestoreCommand(l, "/", snapshot, options))
|
|
|
|
_, _, err = backend.ExecDocker(l, buildRestoreCommand(l, "/", snapshot, options))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
errors = append(errors, err)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
colors.Success.Println("Done")
|
|
|
|
|
|
|
|
return nil
|
|
|
|
// After Hooks for restore
|
|
|
|
|
|
|
|
if err := l.ExecuteHooks(l.Hooks.RestoreOption.After, l.Hooks.RestoreOption.Dir, hooksOptions); err != nil {
|
|
|
|
|
|
|
|
errors = append(errors, err)
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (l Location) RunCron() error {
|
|
|
|
func (l Location) RunCron() error {
|
|
|
|