mirror of
https://github.com/garethgeorge/backrest.git
synced 2026-08-26 10:56:33 +00:00
fix: hook bug fixes
This commit is contained in:
@@ -64,6 +64,13 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# download dist artifacts from previous job
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: release-artifacts
|
||||
path: dist
|
||||
|
||||
- name: Get Release Artifact URL # used to append installer executables to the release after GoReleaser runs
|
||||
id: geturl
|
||||
run: |
|
||||
|
||||
@@ -43,6 +43,7 @@ Backrest is a web-accessible backup solution built on top of [restic](https://re
|
||||
```bash [MacOS]
|
||||
brew tap garethgeorge/homebrew-backrest-tap
|
||||
brew install backrest
|
||||
brew services start backrest
|
||||
```
|
||||
```bash [Arch Linux]
|
||||
paru -Sy backrest
|
||||
|
||||
@@ -12,6 +12,48 @@ When run on `CONDITION_SNAPSHOT_START` command hooks have the ability to send co
|
||||
- `ON_ERROR_FATAL` - If the script exits with a non-zero status, it is treated as a backup failure and error notifications are triggered.
|
||||
- `ON_ERROR_IGNORE` - If the script exits with a non-zero status, the backup operation will continue and the error will be ignored.
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
#### Notify a healthcheck service
|
||||
|
||||
Ping a healthcheck service (e.g. https://healthchecks.io/ in the example) to notify it of backup status (or failure) using a command hook.
|
||||
|
||||
Note that this hook example takes advantage of the fact that the hook is a golang template to render different commands based on whether an error occurred.
|
||||
|
||||
**Condition** `CONDITION_SNAPSHOT_END`
|
||||
|
||||
**Script**
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
{{ if .Error -}}
|
||||
curl -fsS --retry 3 https://hc-ping.com/your-uuid/fail
|
||||
{{ else -}}
|
||||
curl -fsS --retry 3 https://hc-ping.com/your-uuid
|
||||
{{ end -}}
|
||||
```
|
||||
|
||||
**Error Behavior:** `ON_ERROR_IGNORE`
|
||||
|
||||
#### (MacOS) Show system notification
|
||||
|
||||
Show a system notification using the `osascript` command on MacOS.
|
||||
|
||||
**Condition** `CONDITION_SNAPSHOT_END`, `CONDITION_PRUNE_ERROR`, `CONDITION_CHECK_ERROR`
|
||||
|
||||
**Script**
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
{{ if .Error -}}
|
||||
osascript -e 'display notification "{{ .ShellEscape .Task }} failed" with title "Backrest"'
|
||||
{{ else -}}
|
||||
osascript -e 'display notification "{{ .ShellEscape .Task }} succeeded" with title "Backrest"'
|
||||
{{ end -}}
|
||||
```
|
||||
|
||||
|
||||
#### Check for internet connectivity
|
||||
|
||||
Add a hook to check for internet connectivity before running a backup.
|
||||
@@ -74,24 +116,3 @@ fi
|
||||
```
|
||||
|
||||
**Error Behavior:** `ON_ERROR_CANCEL`
|
||||
|
||||
#### Notify a healthcheck service
|
||||
|
||||
Ping a healthcheck service (e.g. https://healthchecks.io/ in the example) to notify it of backup status (or failure) using a command hook.
|
||||
|
||||
Note that this hook example takes advantage of the fact that the hook is a golang template to render different commands based on whether an error occurred.
|
||||
|
||||
**Condition** `CONDITION_SNAPSHOT_END`
|
||||
|
||||
**Script**
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
{{ if .Error -}}
|
||||
curl -fsS --retry 3 https://hc-ping.com/your-uuid/fail
|
||||
{{ else -}}
|
||||
curl -fsS --retry 3 https://hc-ping.com/your-uuid
|
||||
{{ end -}}
|
||||
```
|
||||
|
||||
**Error Behavior:** `ON_ERROR_IGNORE`
|
||||
|
||||
+27
-13
@@ -37,6 +37,20 @@ func (v HookVars) EventName(cond v1.Hook_Condition) string {
|
||||
return "error"
|
||||
case v1.Hook_CONDITION_SNAPSHOT_ERROR:
|
||||
return "snapshot error"
|
||||
case v1.Hook_CONDITION_SNAPSHOT_WARNING:
|
||||
return "snapshot warning"
|
||||
case v1.Hook_CONDITION_CHECK_START:
|
||||
return "check start"
|
||||
case v1.Hook_CONDITION_CHECK_ERROR:
|
||||
return "check error"
|
||||
case v1.Hook_CONDITION_CHECK_SUCCESS:
|
||||
return "check success"
|
||||
case v1.Hook_CONDITION_PRUNE_START:
|
||||
return "prune start"
|
||||
case v1.Hook_CONDITION_PRUNE_ERROR:
|
||||
return "prune error"
|
||||
case v1.Hook_CONDITION_PRUNE_SUCCESS:
|
||||
return "prune success"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
@@ -96,13 +110,9 @@ func (v HookVars) Summary() (string, error) {
|
||||
switch v.Event {
|
||||
case v1.Hook_CONDITION_SNAPSHOT_START:
|
||||
return v.renderTemplate(templateForSnapshotStart)
|
||||
case v1.Hook_CONDITION_SNAPSHOT_END:
|
||||
case v1.Hook_CONDITION_SNAPSHOT_END, v1.Hook_CONDITION_SNAPSHOT_WARNING, v1.Hook_CONDITION_SNAPSHOT_SUCCESS:
|
||||
return v.renderTemplate(templateForSnapshotEnd)
|
||||
case v1.Hook_CONDITION_ANY_ERROR:
|
||||
return v.renderTemplate(templateForError)
|
||||
case v1.Hook_CONDITION_SNAPSHOT_ERROR:
|
||||
return v.renderTemplate(templateForError)
|
||||
case v1.Hook_CONDITION_SNAPSHOT_WARNING:
|
||||
case v1.Hook_CONDITION_ANY_ERROR, v1.Hook_CONDITION_SNAPSHOT_ERROR, v1.Hook_CONDITION_CHECK_ERROR, v1.Hook_CONDITION_PRUNE_ERROR:
|
||||
return v.renderTemplate(templateForError)
|
||||
default:
|
||||
return "unknown event", nil
|
||||
@@ -123,15 +133,21 @@ func (v HookVars) renderTemplate(templ string) (string, error) {
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
var templateForSnapshotEnd = `
|
||||
Backrest Notification for Snapshot End
|
||||
var defaultTemplate = `
|
||||
{{ if .Error -}}
|
||||
Backrest Notification for Error
|
||||
Task: "{{ .Task }}" at {{ .FormatTime .CurTime }}
|
||||
Event: {{ .EventName .Event }}
|
||||
Repo: {{ .Repo.Id }}
|
||||
Plan: {{ .Plan.Id }}
|
||||
Repo: {{ .Repo.Id }}
|
||||
`
|
||||
|
||||
var templateForSnapshotEnd = `
|
||||
Backrest Snapshot Notification
|
||||
Task: {{ .Task }} at {{ .FormatTime .CurTime }}
|
||||
Event: {{ .EventName .Event }}
|
||||
Snapshot: {{ .SnapshotId }}
|
||||
{{ if .Error -}}
|
||||
Failed to create snapshot: {{ .Error }}
|
||||
Error: {{ .Error }}
|
||||
{{ else -}}
|
||||
{{ if .SnapshotStats -}}
|
||||
|
||||
@@ -154,8 +170,6 @@ Backup Statistics:
|
||||
{{ end }}`
|
||||
|
||||
var templateForError = `
|
||||
Backrest Notification for Error
|
||||
Task: "{{ .Task }}" at {{ .FormatTime .CurTime }}
|
||||
{{ if .Error -}}
|
||||
Error: {{ .Error }}
|
||||
{{ end }}
|
||||
|
||||
@@ -190,11 +190,16 @@ func (t *BackupTask) Run(ctx context.Context, st ScheduledTask, runner TaskRunne
|
||||
}
|
||||
op.Status = v1.OperationStatus_STATUS_WARNING
|
||||
op.DisplayMessage = "Partial backup, some files may not have been read completely."
|
||||
}
|
||||
|
||||
runner.ExecuteHooks([]v1.Hook_Condition{
|
||||
v1.Hook_CONDITION_SNAPSHOT_END,
|
||||
}, vars)
|
||||
runner.ExecuteHooks([]v1.Hook_Condition{
|
||||
v1.Hook_CONDITION_SNAPSHOT_END,
|
||||
}, vars)
|
||||
} else {
|
||||
runner.ExecuteHooks([]v1.Hook_Condition{
|
||||
v1.Hook_CONDITION_SNAPSHOT_SUCCESS,
|
||||
v1.Hook_CONDITION_SNAPSHOT_END,
|
||||
}, vars)
|
||||
}
|
||||
|
||||
op.SnapshotId = summary.SnapshotId
|
||||
backupOp.OperationBackup.LastStatus = protoutil.BackupProgressEntryToProto(summary)
|
||||
|
||||
@@ -25,7 +25,7 @@ type CheckTask struct {
|
||||
func NewCheckTask(repoID, planID string, force bool) Task {
|
||||
return &CheckTask{
|
||||
BaseTask: BaseTask{
|
||||
TaskName: fmt.Sprintf("prune repo %q", repoID),
|
||||
TaskName: fmt.Sprintf("check for repo %q", repoID),
|
||||
TaskRepoID: repoID,
|
||||
TaskPlanID: planID,
|
||||
},
|
||||
|
||||
@@ -120,15 +120,17 @@ export const HooksFormList = () => {
|
||||
style={{ marginBottom: "5px" }}
|
||||
>
|
||||
<Form.Item name={[field.name, "conditions"]}>
|
||||
<Select
|
||||
mode="multiple"
|
||||
allowClear
|
||||
style={{ width: "100%" }}
|
||||
placeholder="Runs when..."
|
||||
options={proto3
|
||||
.getEnumType(Hook_Condition)
|
||||
.values.map((v) => ({ label: v.name, value: v.name }))}
|
||||
/>
|
||||
<HookConditionsTooltip>
|
||||
<Select
|
||||
mode="multiple"
|
||||
allowClear
|
||||
style={{ width: "100%" }}
|
||||
placeholder="Runs when..."
|
||||
options={proto3
|
||||
.getEnumType(Hook_Condition)
|
||||
.values.map((v) => ({ label: v.name, value: v.name }))}
|
||||
/>
|
||||
</HookConditionsTooltip>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
shouldUpdate={(prevValues, curValues) => {
|
||||
@@ -410,8 +412,8 @@ const ItemOnErrorSelector = ({ field }: { field: FormListFieldData }) => {
|
||||
<Tooltip
|
||||
title={
|
||||
<>
|
||||
What happens when the hook fails (currently only has effect on
|
||||
backup start hooks)
|
||||
What happens when the hook fails (only effective on start hooks e.g.
|
||||
backup start, prune start, check start)
|
||||
<ul>
|
||||
<li>
|
||||
IGNORE - the failure is ignored, subsequent hooks and the backup
|
||||
@@ -449,3 +451,43 @@ const requiredField = (message: string, extra?: Rule) => ({
|
||||
required: true,
|
||||
message: message,
|
||||
});
|
||||
|
||||
const HookConditionsTooltip = ({ children }: { children: React.ReactNode }) => {
|
||||
return (
|
||||
<Tooltip
|
||||
title={
|
||||
<div>
|
||||
Available conditions
|
||||
<ul>
|
||||
<li>CONDITION_ANY_ERROR - error executing any task</li>
|
||||
<li>CONDITION_SNAPSHOT_START - start of a backup operation</li>
|
||||
<li>
|
||||
CONDITION_SNAPSHOT_END - end of backup operation (success or
|
||||
failure)
|
||||
</li>
|
||||
<li>
|
||||
CONDITION_SNAPSHOT_SUCCESS - end of successful backup operation
|
||||
</li>
|
||||
<li>CONDITION_SNAPSHOT_ERROR - end of failed backup</li>
|
||||
<li>CONDITION_SNAPSHOT_WARNING - end of partial backup</li>
|
||||
<li>CONDITION_PRUNE_START - start of prune operation</li>
|
||||
<li>CONDITION_PRUNE_SUCCESS - end of successful prune</li>
|
||||
<li>CONDITION_PRUNE_ERROR - end of failed prune</li>
|
||||
<li>CONDITION_CHECK_START - start of check operation</li>
|
||||
<li>CONDITION_CHECK_SUCCESS - end of successful check</li>
|
||||
<li>CONDITION_CHECK_ERROR - end of failed check</li>
|
||||
</ul>
|
||||
for more info see the{" "}
|
||||
<a
|
||||
href="https://garethgeorge.github.io/backrest/docs/hooks"
|
||||
target="_blank"
|
||||
>
|
||||
documentation
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user