Add restore hooks feature

pull/213/head
Romain de Laage 2 years ago
parent 4d9a2b828e
commit 4375a38bba
No known key found for this signature in database
GPG Key ID: 534845FADDF0C329

@ -4,6 +4,7 @@ import (
"fmt"
"github.com/cupcakearmy/autorestic/internal"
"github.com/cupcakearmy/autorestic/internal/colors"
"github.com/cupcakearmy/autorestic/internal/lock"
"github.com/spf13/cobra"
)
@ -42,8 +43,13 @@ var restoreCmd = &cobra.Command{
}
}
err = l.Restore(target, from, force, snapshot, optional)
CheckErr(err)
errs := l.Restore(target, from, force, snapshot, optional)
for _, err := range errs {
colors.Error.Printf("%s\n\n", err)
}
if len(errs) > 0 {
CheckErr(fmt.Errorf("%d errors were found", len(errs)))
}
},
}

@ -83,7 +83,7 @@ func GetConfig() *Config {
exitConfig(nil, "version specified in config file is not an int")
} else {
// Check for version
if version != 2 {
if version != 3 {
exitConfig(nil, "unsupported config version number. please check the docs for migration\nhttps://autorestic.vercel.app/migration/")
}
}
@ -132,10 +132,14 @@ func (c *Config) Describe() {
tmp = ""
hooks := map[string][]string{
"Before": l.Hooks.Before,
"After": l.Hooks.After,
"Failure": l.Hooks.Failure,
"Success": l.Hooks.Success,
"Before backup": l.Hooks.BackupOption.Before,
"After backup": l.Hooks.BackupOption.After,
"Failure backup": l.Hooks.BackupOption.Failure,
"Success backup": l.Hooks.BackupOption.Success,
"Before restore": l.Hooks.RestoreOption.Before,
"After restore": l.Hooks.RestoreOption.After,
"Failure restore": l.Hooks.RestoreOption.Failure,
"Success restore": l.Hooks.RestoreOption.Success,
}
for hook, commands := range hooks {
if len(commands) > 0 {

@ -33,6 +33,13 @@ const (
)
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"`
Before HookArray `mapstructure:"before,omitempty"`
After HookArray `mapstructure:"after,omitempty"`
@ -40,8 +47,6 @@ type Hooks struct {
Failure HookArray `mapstructure:"failure,omitempty"`
}
type LocationCopy = map[string][]string
type Location struct {
name string `mapstructure:",omitempty"`
From []string `mapstructure:"from,omitempty"`
@ -123,12 +128,12 @@ func (l Location) validate() error {
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 {
return nil
}
if l.Hooks.Dir != "" {
if dir, err := GetPathRelativeToConfig(l.Hooks.Dir); err != nil {
if directory != "" {
if dir, err := GetPathRelativeToConfig(directory); err != nil {
return err
} else {
options.Dir = dir
@ -190,7 +195,7 @@ func (l Location) Backup(cron bool, specificBackend string) []error {
}
// 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)
goto after
}
@ -290,7 +295,7 @@ func (l Location) Backup(cron bool, specificBackend string) []error {
}
// 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)
}
@ -298,11 +303,11 @@ after:
var commands []string
var isSuccess = len(errors) == 0
if isSuccess {
commands = l.Hooks.Success
commands = l.Hooks.BackupOption.Success
} 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)
}
@ -367,11 +372,35 @@ func buildRestoreCommand(l Location, to string, snapshot string, options []strin
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 == "" {
from = l.To[0]
} else if !l.hasBackend(from) {
return fmt.Errorf("invalid backend: \"%s\"", from)
errors = append(errors, fmt.Errorf("invalid backend: \"%s\"", from))
}
if snapshot == "" {
@ -382,15 +411,23 @@ func (l Location) Restore(to, from string, force bool, snapshot string, options
backend, _ := GetBackend(from)
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()
if err != nil {
return err
errors = append(errors, err)
return
}
switch t {
case TypeLocal:
to, err = filepath.Abs(to)
if err != nil {
return err
errors = append(errors, err)
return
}
// Check if target is empty
if !force {
@ -399,14 +436,17 @@ func (l Location) Restore(to, from string, force bool, snapshot string, options
if err == nil {
files, err := ioutil.ReadDir(to)
if err != nil {
return err
errors = append(errors, err)
return
}
if len(files) > 0 {
return notEmptyError
errors = append(errors, notEmptyError)
return
}
} else {
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))
}
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 {

Loading…
Cancel
Save