feat: support restic check operation (#303)

This commit is contained in:
Gareth
2024-05-27 10:26:18 -07:00
committed by GitHub
parent 5a51ae7c20
commit ce42f68d0d
43 changed files with 1807 additions and 989 deletions

View File

@@ -1,7 +1,6 @@
package tasks
import (
"bytes"
"context"
"errors"
"fmt"
@@ -59,14 +58,20 @@ func (t *PruneTask) Next(now time.Time, runner TaskRunner) (ScheduledTask, error
}
var lastRan time.Time
var foundBackup bool
if err := runner.OpLog().ForEach(oplog.Query{RepoId: t.RepoID()}, indexutil.Reversed(indexutil.CollectAll()), func(op *v1.Operation) error {
if _, ok := op.Op.(*v1.Operation_OperationPrune); ok {
lastRan = time.Unix(0, op.UnixTimeEndMs*int64(time.Millisecond))
return oplog.ErrStopIteration
}
if _, ok := op.Op.(*v1.Operation_OperationBackup); ok {
foundBackup = true
}
return nil
}); err != nil {
return NeverScheduledTask, fmt.Errorf("finding last backup run time: %w", err)
return NeverScheduledTask, fmt.Errorf("finding last prune run time: %w", err)
} else if !foundBackup {
return NeverScheduledTask, nil
}
zap.L().Debug("last prune time", zap.Time("time", lastRan), zap.String("repo", t.RepoID()))
@@ -95,6 +100,20 @@ func (t *PruneTask) Run(ctx context.Context, st ScheduledTask, runner TaskRunner
return fmt.Errorf("couldn't get repo %q: %w", t.RepoID(), err)
}
if err := runner.ExecuteHooks([]v1.Hook_Condition{
v1.Hook_CONDITION_PRUNE_START,
}, hook.HookVars{}); err != nil {
op.DisplayMessage = err.Error()
// TODO: generalize this logic
var cancelErr *hook.HookErrorRequestCancel
if errors.As(err, &cancelErr) {
op.Status = v1.OperationStatus_STATUS_USER_CANCELLED // user visible cancelled status
return nil
}
op.Status = v1.OperationStatus_STATUS_ERROR
return fmt.Errorf("execute prune start hooks: %w", err)
}
err = repo.UnlockIfAutoEnabled(ctx)
if err != nil {
return fmt.Errorf("auto unlock repo %q: %w", t.RepoID(), err)
@@ -108,7 +127,7 @@ func (t *PruneTask) Run(ctx context.Context, st ScheduledTask, runner TaskRunner
ctx, cancel := context.WithCancel(ctx)
interval := time.NewTicker(1 * time.Second)
defer interval.Stop()
var buf bytes.Buffer
buf := ioutil.HeadWriter{Limit: 16 * 1024}
bufWriter := ioutil.SynchronizedWriter{W: &buf}
var wg sync.WaitGroup
wg.Add(1)
@@ -118,14 +137,11 @@ func (t *PruneTask) Run(ctx context.Context, st ScheduledTask, runner TaskRunner
select {
case <-interval.C:
bufWriter.Mu.Lock()
output := buf.String()
output := string(buf.Bytes())
bufWriter.Mu.Unlock()
if len(output) > 8*1024 { // only provide live status upto the first 8K of output.
output = output[:len(output)-8*1024]
}
if opPrune.OperationPrune.Output != output {
opPrune.OperationPrune.Output = buf.String()
if opPrune.OperationPrune.Output != string(output) {
opPrune.OperationPrune.Output = string(output)
if err := runner.OpLog().Update(op); err != nil {
zap.L().Error("update prune operation with status output", zap.Error(err))
@@ -151,17 +167,18 @@ func (t *PruneTask) Run(ctx context.Context, st ScheduledTask, runner TaskRunner
cancel()
wg.Wait()
output := buf.String()
if len(output) > 8*1024 { // only save the first 4K of output.
output = output[:len(output)-8*1024]
}
opPrune.OperationPrune.Output = output
opPrune.OperationPrune.Output = string(buf.Bytes())
// Run a stats task after a successful prune
if err := runner.ScheduleTask(NewStatsTask(t.RepoID(), PlanForSystemTasks, false), TaskPriorityStats); err != nil {
zap.L().Error("schedule stats task", zap.Error(err))
}
if err := runner.ExecuteHooks([]v1.Hook_Condition{
v1.Hook_CONDITION_PRUNE_SUCCESS,
}, hook.HookVars{}); err != nil {
return fmt.Errorf("execute prune end hooks: %w", err)
}
return nil
}