Skip to content

Control Panel: one-shot backup choices when the backup drive is not mounted - #30

Merged
jclima merged 3 commits into
mainfrom
claude/control-panel-upgrade-backup-97dd96
Nov 7, 2026
Merged

jclima merged 3 commits into
mainfrom
claude/control-panel-upgrade-backup-97dd96

Conversation

@jclima

@jclima jclima commented Nov 7, 2026

Copy link
Copy Markdown
Owner

Problem

The Control Panel upgrade ran vesselstackctl backup --require-mounted with no terminal attached. An unmounted backup drive always failed the upgrade ("backup location not mounted"), with no way to mount it, pick another location or skip from the panel.

Change

Before Back up & install or Update from folder, the panel checks the backup drive (GET /api/backup-preflight). If the drive is mounted, nothing changes. If it isn't, a dialog offers, for that one run only:

  • mount the /etc/fstab entry
  • mount a USB drive the panel found (chosen by UUID)
  • back up to the system disk once, to /var/backups/vesselstack
  • change the backup folder
  • install without a backup (checkbox plus danger button)

Script changes:

  • vesselstackctl backup --system-disk-once
  • vesselstackctl backup-drive list --json
  • vesselstackctl backup-drive mount --fstab|--uuid:
    • mounts with nodev,nosuid,noexec
    • verifies the UUID after mounting and unmounts on failure
    • never writes /etc/fstab
  • vesselstackctl update --backup-choice=system-disk-once|skip, used by the panel and the installer and left out of --help
  • Terminal menu choice [4] now writes to /var/backups/vesselstack, so the unmounted drive folder stays empty.

Safety:

  • The choice is validated in the panel and again in the worker.
  • It is never written to vesselstack.env or reused.
  • VESSELSTACK_BACKUP_ALLOW_UNMOUNTED=false, in the env file or the process environment, blocks system-disk-once and skip.
  • The worker checks the lock again after the dry-run.
  • No device path or folder from the browser reaches root.
  • A non-update action that includes a backup choice gets a 400.
  • With the drive mounted, the default path runs the same commands as before.

README, docs/CONTROL_PANEL.md, docs/UPDATING.md, docs/CONTROL_PANEL_TESTING.md and CHANGELOG (Unreleased) are updated.

Known limitation

The upgrade that delivers this still runs the installed (old) worker. For that one upgrade, mount the drive by hand or update from a terminal.

Testing

  • python3 -m unittest discover -s tests -p 'test_*.py': 1162 OK, 17 skipped (macOS)
  • node tests/test_control_panel_ui.cjs
  • python3 scripts/check-public-tree.py, tests/test-distribution.sh, bash -n / shellcheck -x
  • sudo tests/test-lifecycle.sh and sudo tests/test-get-vesselstack.sh (Linux only; new cases written without being run)
  • On a Pi: a drive mounted from the panel is visible to the host (findmnt); see docs/CONTROL_PANEL_TESTING.md

🤖 Generated with Claude Code

jclima and others added 3 commits November 6, 2026 22:59
…ounted

The browser upgrade ran `vesselstackctl backup --require-mounted` with no
terminal, so an unmounted backup drive always failed the upgrade with no way
to recover from the panel. Before an upgrade or folder update the panel now
runs a backup preflight and, when the drive is not mounted, lets the owner
choose for that one run: mount the fstab entry, mount a listed USB drive by
UUID, back up to the system disk once (/var/backups/vesselstack), change the
backup folder, or install without a backup (explicit confirmation).

- vesselstackctl: backup --system-disk-once, backup-drive list --json,
  backup-drive mount --fstab|--uuid (nodev,nosuid,noexec, UUID verified after
  mount, never writes /etc/fstab), update --backup-choice for the panel.
- Choices are validated in the panel and again in the worker, never persisted,
  and blocked by VESSELSTACK_BACKUP_ALLOW_UNMOUNTED=false (file or env).
- Terminal menu choice [4] now writes to /var/backups/vesselstack so the
  unmounted drive folder stays empty.
- Default (drive mounted) path is unchanged.
- README, docs and CHANGELOG updated. Linux-only shell tests not yet run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tar -t | grep -q under pipefail fails when grep matches early in a listing
longer than one pipe write; which entry comes first depends on the
filesystem's directory order, so CI failed on the Prometheus marker check.
Read the listing into a variable first. Product backup behaviour is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jclima
jclima merged commit da7ec27 into main Nov 7, 2026
4 checks passed
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.

1 participant