Skip to content

Fix full restore pipeline, add bind-mount backup, two-tier test suite#19

Merged
piscue merged 2 commits into
masterfrom
fix/full-restore-and-bind-mounts
Jul 1, 2026
Merged

Fix full restore pipeline, add bind-mount backup, two-tier test suite#19
piscue merged 2 commits into
masterfrom
fix/full-restore-and-bind-mounts

Conversation

@piscue

@piscue piscue commented Jul 1, 2026

Copy link
Copy Markdown
Owner

Summary

  • Fixes Restore only restores volumes #18 — restore was only restoring volumes. Now restores images (docker load), volumes, bind-mount host paths (-B), and recreates containers from saved inspect JSON in the correct order.
  • Validates [Feature] Separate each volume in different tar file for better restore #14 — per-volume tar layout was already implemented; now locked in by regression tests so it can never silently break again.
  • New -B flag — opt-in bind-mount backup/restore: archives each host path per container with tar -P, stores a manifest.json, restores in place. Required for containers like Portainer that store config under host paths (e.g. /portainer/Files/AppData).
  • Other fixessync-dropbox.sh rewritten to match actual backup layout (old code uploaded stale .tar.xz paths); tar_opts wired into compress step; -b-p flag typo in README fixed.

New files

File Purpose
restore/restore-images.sh docker load each saved image tar
restore/restore-containers.sh Reconstruct docker run from inspect JSON; build_run_cmd() is unit-testable
backup/backup-bind-mounts.sh Archive bind-mount host paths + write manifest
restore/restore-bind-mounts.sh Restore bind-mount archives to original paths
test/helpers/docker Docker stub recording calls to $DOCKER_LOG
test/fixtures/ Canned inspect JSON
test/*.bats 38 unit tests (no daemon required)
test/integration/run.sh Host orchestrator: starts docker:28-dind, runs e2e, tears down
test/integration/e2e.sh 13 real assertions: backup → wipe → restore → verify

Test plan

  • shellcheck *.sh backup/**.sh restore/*.sh test/integration/*.sh -e SC2154 -e SC1091 -e SC2317 — clean
  • bats test/*.bats — 38/38 pass (no daemon)
  • bash test/integration/run.sh — 13/13 assertions pass (real dind cycle: volume data, bind data, image reload, container running, env/restart/ports preserved)
  • CI: unit job (macos-13) + integration job (ubuntu-latest) — will run on this PR

…st suite

Fixes #18 (restore only restored volumes) and addresses #14 (separate
volume tars — already implemented, now validated by tests).

**Restore improvements (fixes #18)**
- restore/restore-images.sh (new): docker load each saved image tar
- restore/restore-containers.sh (new): reconstruct docker run from
  inspect JSON (name, image, env, ports, volumes, restart, network);
  build_run_cmd() factored out for unit-testability; -f replaces existing
- restore/restore-all.sh: wire images → volumes → bind mounts → containers
  in both interactive and non-interactive (-s) modes
- restore/restore-volumes.sh: fix cut -f1 -d. bug that broke dotted volume
  names; use ${filename%.tar.gz} expansion; add docker volume create before
  restore; guard missing/empty volumes dir

**Bind-mount backup/restore (new -B flag, opt-in)**
- backup/backup-bind-mounts.sh: tar -P each bind-mount source path per
  container; write manifest.json mapping archive → original host path
- restore/restore-bind-mounts.sh: restore each archive to its original path
  via tar -P; respects -f; skips missing archives and existing paths
- backup-manager.sh: add -B flag; wire into backup-all.sh and restore-all.sh

**Other fixes**
- backup/sync-dropbox.sh: rewrite to match current layout (volumes/*.tar.gz
  + per-container image/data files); old code uploaded stale .tar.xz paths
- backup-manager.sh: fix tar_opts default (remove inner single quotes)
- backup/backup-all.sh: wire $tar_opts into compress step so -t flag works
- Readme.md: fix -b → -p flag error; full rewrite documenting all flags,
  backup layout, restore order, -B opt-in, jq dependency, testing tiers

**Two-tier test suite**
Unit tests (bats, no daemon, 38 tests):
- test/backup-volumes.bats: confirm #14 — one tar per volume, correct
  names (incl. dotted), no duplication
- test/restore-volumes.bats: regression for the cut parsing bug
- test/restore-all.bats: guard #18 — all three restore steps triggered
- test/restore-containers.bats: build_run_cmd correctness + skip/force
- test/backup-bind-mounts.bats: archive/manifest creation, skip on missing
- test/restore-bind-mounts.bats: file restoration, skip/force behaviour
- test/helpers/docker: stub recording all calls to $DOCKER_LOG
- test/fixtures/: canned inspect JSON

Integration tests (real Docker-in-Docker, 13 assertions):
- test/integration/run.sh: host orchestrator — starts docker:28-dind,
  mounts repo read-only, installs deps, runs e2e, always tears down
- test/integration/e2e.sh: full cycle — create volume+bind+container,
  backup -B -s, wipe everything incl. alpine image, restore -B -s -f,
  assert image/volume data/bind data/container running/env/restart/ports

CI (.github/workflows/main.yml):
- unit job (macos-13): shellcheck all scripts + bats test/*.bats
- integration job (ubuntu-latest): bash test/integration/run.sh
@piscue piscue assigned piscue and unassigned piscue Jul 1, 2026
@piscue
piscue merged commit 418f06a into master Jul 1, 2026
2 checks passed
@piscue
piscue deleted the fix/full-restore-and-bind-mounts branch July 1, 2026 18:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Restore only restores volumes

1 participant