P3 wrap: agent auto-creates restore target; tasks.md ticked
1. Agent-side MkdirAll on the new-dir restore target. Restic creates
missing leaves but won't traverse multiple missing levels, and
under the systemd sandbox writes outside ReadWritePaths fail
anyway. Calling os.MkdirAll(target, 0700) before invoking restic
means the operator never has to pre-create the per-job subdir,
and a path the sandbox rejects surfaces as a clean
'restic restore: prepare target ...: read-only file system' error
in the job log instead of a cryptic restic-side stat failure.
2. tasks.md Phase 3 — Restore section refreshed:
- P3-X4 added (job log download dropdown — txt + ndjson)
- P3-X5 added (UK lint locale switch + 73-correction sweep)
- P3-X6 added (SIZE/FILES tooltip when host's restic < 0.17)
- P3-03 entry expanded to cover version-gated --no-ownership,
editable target, $HOME expansion, agent-side MkdirAll
- As-shipped sweep summary mentions custom-target restore +
download dropdown + tooltip in addition to the original walk
Test: TestRunRestoreNewDirAutoCreatesTarget seeds a multi-level
target the operator hasn't created and confirms RunRestore mkdir's
the chain before invoking restic.
This commit is contained in:
@@ -2,6 +2,8 @@ package runner
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -188,6 +190,35 @@ esac
|
||||
}
|
||||
}
|
||||
|
||||
// TestRunRestoreNewDirAutoCreatesTarget: a new-directory restore
|
||||
// should mkdir the requested target chain before invoking restic, so
|
||||
// operators don't have to pre-create the per-job subdir.
|
||||
func TestRunRestoreNewDirAutoCreatesTarget(t *testing.T) {
|
||||
t.Parallel()
|
||||
bin := setupScript(t, `
|
||||
case "$1" in
|
||||
restore)
|
||||
echo '{"message_type":"summary","seconds_elapsed":0,"total_files":0,"files_restored":0,"total_bytes":0,"bytes_restored":0}'
|
||||
;;
|
||||
esac
|
||||
`)
|
||||
tx := &fakeSender{}
|
||||
r := New(Config{ResticBin: bin}, tx, 0)
|
||||
|
||||
// Multi-level path the operator hasn't created yet.
|
||||
target := filepath.Join(t.TempDir(), "deep", "deeper", "deepest")
|
||||
if err := r.RunRestore(context.Background(), "job-rmkdir", "abc",
|
||||
[]string{"/etc/foo"}, false, target); err != nil {
|
||||
t.Fatalf("RunRestore: %v", err)
|
||||
}
|
||||
|
||||
if st, err := os.Stat(target); err != nil {
|
||||
t.Fatalf("expected target dir to exist: %v", err)
|
||||
} else if !st.IsDir() {
|
||||
t.Fatalf("expected directory, got %v", st.Mode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestRunDiffShipsLogLines: diff output is forwarded as log.stream.
|
||||
func TestRunDiffShipsLogLines(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -67,13 +67,24 @@ func (e Env) RunRestore(ctx context.Context, snapshotID string, paths []string,
|
||||
target = "/"
|
||||
} else {
|
||||
// Expand $HOME / ${HOME} / leading ~/ in the operator-supplied
|
||||
// path, using the agent's own HOME (which under the systemd
|
||||
// unit is the agent user's home — typically /root for the
|
||||
// path, using the agent's own HOME (typically /root for the
|
||||
// User=root unit). The expansion runs agent-side so the
|
||||
// operator can specify a portable default like
|
||||
// $HOME/rm-restore/<job-id>/ in the wizard without the server
|
||||
// needing to know which user the agent runs as.
|
||||
target = expandHome(target)
|
||||
// Ensure the target directory exists. Restic itself creates
|
||||
// missing leaves but won't traverse multiple missing levels
|
||||
// (and we don't want the operator to have to pre-create the
|
||||
// per-job subdir). 0700 keeps the data root-only — the agent
|
||||
// runs as root, and operators who want a different mode can
|
||||
// chmod after the fact. If MkdirAll fails (operator typed a
|
||||
// path inside a read-only sandbox mount, ENOSPC, etc.) we
|
||||
// surface a clean error rather than letting restic fail with
|
||||
// something cryptic.
|
||||
if err := os.MkdirAll(target, 0o700); err != nil {
|
||||
return nil, fmt.Errorf("restic restore: prepare target %q: %w", target, err)
|
||||
}
|
||||
}
|
||||
args = append(args, "--target", target)
|
||||
// --no-ownership was added in restic 0.17. Older versions reject
|
||||
|
||||
Reference in New Issue
Block a user