Compare commits

...

8 Commits

Author SHA1 Message Date
fliespl 454409b712
Merge d332f4476b into 6e34196220 2024-03-20 17:07:40 -06:00
Nicco 6e34196220
Update config.go 2024-03-13 12:40:11 +01:00
Florian dc56911a45
fix(unlock cmd): ignore process if its the current id (#360) 2024-03-13 12:39:51 +01:00
Nicco edb3ba35d8
Update config.go 2024-03-12 15:27:11 +01:00
Florian 12f6143bb4
fix: cli command to unlock the autorestic running value (#329)
* fix: cli command to unlock the autorestic running value

* fix(unlock cmd): get user confirmation in case an instance is still running

* fix(cmd unlock): add force flag
2024-03-12 15:26:12 +01:00
Pete a6bf1d1408
fix relative path to options forget (#331)
/location/options/forget instead of /location/forget.
2024-03-12 15:24:25 +01:00
Stuart Hickinbottom 13aa560fda
Add PreValidate hook (#359)
Fix #332.

This adds a new "PreValidate" hook that is executed before checking
the backup location. This allows, for example, mounting a remote
source to make the directories of the location available.

"PreValidate" is added as a new hook to avoid any breakage that might
have been caused by changing the behaviour of the "before" hook.

Documentataion updates included.
2024-03-12 15:22:43 +01:00
fliespl d332f4476b
do not replace all shell paths in the example 2023-10-24 22:10:41 +02:00
9 changed files with 152 additions and 21 deletions

View File

@ -34,7 +34,7 @@ Autorestic is a wrapper around the amazing [restic](https://restic.net/). While
- Backup locations to multiple backends
- Snapshot policies and pruning
- Fully encrypted
- Pre/After hooks
- Before/after backup hooks
- Exclude pattern/files
- Cron jobs for automatic backup
- Backup & Restore docker volume

81
cmd/unlock.go Normal file
View File

@ -0,0 +1,81 @@
package cmd
import (
"bytes"
"fmt"
"os"
"os/exec"
"strings"
"github.com/cupcakearmy/autorestic/internal"
"github.com/cupcakearmy/autorestic/internal/colors"
"github.com/cupcakearmy/autorestic/internal/lock"
"github.com/spf13/cobra"
)
var unlockCmd = &cobra.Command{
Use: "unlock",
Short: "Unlock autorestic only if you are sure that no other instance is running",
Long: `Unlock autorestic only if you are sure that no other instance is running.
To check you can run "ps aux | grep autorestic".`,
Run: func(cmd *cobra.Command, args []string) {
internal.GetConfig()
force, _ := cmd.Flags().GetBool("force")
if !force && isAutoresticRunning() {
colors.Error.Print("Another autorestic instance is running. Are you sure you want to unlock? (yes/no): ")
var response string
fmt.Scanln(&response)
if strings.ToLower(response) != "yes" {
colors.Primary.Println("Unlocking aborted.")
return
}
}
err := lock.Unlock()
if err != nil {
colors.Error.Println("Could not unlock:", err)
return
}
colors.Success.Println("Unlock successful")
},
}
func init() {
rootCmd.AddCommand(unlockCmd)
unlockCmd.Flags().Bool("force", false, "force unlock")
}
// isAutoresticRunning checks if autorestic is running
// and returns true if it is.
// It also prints the processes to stdout.
func isAutoresticRunning() bool {
cmd := exec.Command("sh", "-c", "ps aux | grep autorestic")
var out bytes.Buffer
cmd.Stdout = &out
err := cmd.Run()
if err != nil {
return false
}
lines := strings.Split(out.String(), "\n")
autoresticProcesses := []string{}
currentPid := fmt.Sprint(os.Getpid())
for _, line := range lines {
if strings.Contains(line, "autorestic") && !strings.Contains(line, "grep autorestic") && !strings.Contains(line, currentPid) {
autoresticProcesses = append(autoresticProcesses, line)
}
}
if len(autoresticProcesses) > 0 {
colors.Faint.Println("Found autorestic processes:")
for _, proc := range autoresticProcesses {
colors.Faint.Println(proc)
}
return true
}
return false
}

32
docs/pages/cli/unlock.md Normal file
View File

@ -0,0 +1,32 @@
# Unlock
In case autorestic throws the error message `an instance is already running. exiting`, but there is no instance running you can unlock the lock.
To verify that there is no instance running you can use `ps aux | grep autorestic`.
Example with no instance running:
```bash
> ps aux | grep autorestic
root 39260 0.0 0.0 6976 2696 pts/11 S+ 19:41 0:00 grep autorestic
```
Example with an instance running:
```bash
> ps aux | grep autorestic
root 29465 0.0 0.0 1162068 7380 pts/7 Sl+ 19:28 0:00 autorestic --ci backup -a
root 39260 0.0 0.0 6976 2696 pts/11 S+ 19:41 0:00 grep autorestic
```
**If an instance is running you should not unlock as it could lead to data loss!**
```bash
autorestic unlock
```
Use the `--force` to prevent the confirmation prompt if an instance is running.
```bash
autorestic unlock --force
```

View File

@ -56,6 +56,8 @@ version: 2
extras:
hooks: &foo
prevalidate:
- echo "Wake up!"
before:
- echo "Hello"
after:

View File

@ -13,7 +13,7 @@ Autorestic is a wrapper around the amazing [restic](https://restic.net/). While
- Backup locations to multiple backends
- Snapshot policies and pruning
- Fully encrypted
- Pre/After hooks
- Before/after backup hooks
- Exclude pattern/files
- Cron jobs for automatic backup
- Backup & Restore docker volumes

View File

@ -34,7 +34,7 @@ Then paste this at the bottom of the file and save it. Note that in this specifi
```bash
# This is required, as it otherwise cannot find restic as a command.
PATH="/usr/local/bin:/usr/bin:/bin"
PATH="/usr/local/bin:$PATH"
# Example running every 5 minutes
*/5 * * * * autorestic -c /path/to/my/.autorestic.yml --ci cron

View File

@ -6,23 +6,28 @@ They consist of a list of commands that will be executed in the same directory a
The following hooks groups are supported, none are required:
- `prevalidate`
- `before`
- `after`
- `failure`
- `success`
The difference between `prevalidate` and `before` hooks are that `prevalidate` is run before checking the backup location is valid, including checking that the `from` directories exist. This can be useful, for example, to mount the source filesystem that contains the directories listed in `from`.
```yml | .autorestic.yml
locations:
my-location:
from: /data
to: my-backend
hooks:
prevalidate:
- echo "Checks"
before:
- echo "One"
- echo "Two"
- echo "Three"
after:
- echo "Byte"
- echo "Bye"
failure:
- echo "Something went wrong"
success:
@ -31,13 +36,15 @@ locations:
## Flowchart
1. `before` hook
2. Run backup
3. `after` hook
4. - `success` hook if no errors were found
1. `prevalidate` hook
2. Check backup location
3. `before` hook
4. Run backup
5. `after` hook
6. - `success` hook if no errors were found
- `failure` hook if at least one error was encountered
If the `before` hook encounters errors the backup and `after` hooks will be skipped and only the `failed` hooks will run.
If either the `prevalidate` or `before` hook encounters errors then the backup and `after` hooks will be skipped and only the `failed` hooks will run.
## Environment variables

View File

@ -17,7 +17,7 @@ import (
"github.com/spf13/viper"
)
const VERSION = "1.7.11"
const VERSION = "1.8.1"
type OptionMap map[string][]interface{}
type Options map[string]OptionMap
@ -132,10 +132,11 @@ 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,
"PreValidate": l.Hooks.PreValidate,
"Before": l.Hooks.Before,
"After": l.Hooks.After,
"Failure": l.Hooks.Failure,
"Success": l.Hooks.Success,
}
for hook, commands := range hooks {
if len(commands) > 0 {

View File

@ -33,11 +33,12 @@ const (
)
type Hooks struct {
Dir string `mapstructure:"dir"`
Before HookArray `mapstructure:"before,omitempty"`
After HookArray `mapstructure:"after,omitempty"`
Success HookArray `mapstructure:"success,omitempty"`
Failure HookArray `mapstructure:"failure,omitempty"`
Dir string `mapstructure:"dir"`
PreValidate HookArray `mapstructure:"prevalidate,omitempty"`
Before HookArray `mapstructure:"before,omitempty"`
After HookArray `mapstructure:"after,omitempty"`
Success HookArray `mapstructure:"success,omitempty"`
Failure HookArray `mapstructure:"failure,omitempty"`
}
type LocationCopy = map[string][]string
@ -184,12 +185,18 @@ func (l Location) Backup(cron bool, specificBackend string) []error {
},
}
// Hooks before location validation
if err := l.ExecuteHooks(l.Hooks.PreValidate, options); err != nil {
errors = append(errors, err)
goto after
}
if err := l.validate(); err != nil {
errors = append(errors, err)
goto after
}
// Hooks
// Hooks after location validation
if err := l.ExecuteHooks(l.Hooks.Before, options); err != nil {
errors = append(errors, err)
goto after
@ -289,12 +296,13 @@ func (l Location) Backup(cron bool, specificBackend string) []error {
}
}
// After hooks
// After backup hooks
if err := l.ExecuteHooks(l.Hooks.After, options); err != nil {
errors = append(errors, err)
}
after:
// Success/failure hooks
var commands []string
var isSuccess = len(errors) == 0
if isSuccess {