diff --git a/CHANGELOG.md b/CHANGELOG.md index 56c55c4..ab92c9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,50 @@ ## Changelog +### v0.26.0 — Storage Namespace `felhom-data/` + Test Node Wipe Script (2026-02-22) + +All felhom-managed data on external drives now lives under a `felhom-data/` subdirectory, cleanly separating controller-managed data from user files. Plus a multi-level wipe script for repeatable test node cleanup. + +**Key design principle:** `HDD_PATH` env var stays as the mount point (e.g., `/mnt/hdd_1`). The `felhom-data` segment is embedded in path helpers and compose templates — not in `HDD_PATH`. + +#### Changed +- **`internal/backup/paths.go`** — Added `FelhomDataDir = "felhom-data"` constant. Updated 8 path functions to insert `felhom-data` between the drive root and data subdirectory: + - `PrimaryBackupPath` → `/felhom-data/backups/primary` + - `PrimaryResticRepoPath` → `/felhom-data/backups/primary/restic` + - `AppDBDumpPath` → `/felhom-data/backups/primary//db-dumps` + - `SecondaryBackupPath` → `/felhom-data/backups/secondary` + - `AppSecondaryRsyncPath` → `/felhom-data/backups/secondary//rsync` + - `SecondaryResticRepoPath` → `/felhom-data/backups/secondary/restic` + - `SecondaryInfraPath` → `/felhom-data/backups/secondary/_infra` + - `AppDataDir` → `/felhom-data/appdata/` + - `InfraBackupDir` **unchanged** — stays at drive root for DR scanner +- **`internal/stacks/delete.go`** — Added local `felhomDataDir = "felhom-data"` constant (cannot import `backup` due to architectural boundary). Updated `ProtectedHDDPaths()` to protect `/felhom-data`, `/felhom-data/appdata`, `/felhom-data/backups`. Fixed hardcoded paths in `GetStackBackupData()`. +- **`internal/storage/migrate_drive.go`** — Added `backup` package import. Fixed 4 issues: + - Conflict check: uses `backup.AppDataDir()` instead of hardcoded `appdata/` + - Verify step: uses `backup.AppDataDir()` instead of hardcoded `appdata/` + - rsync excludes: updated from `backups/primary/restic/` to `felhom-data/backups/primary/restic/` + - Size estimation: now scans inside `felhom-data/` namespace, skipping restic repos correctly +- **`internal/storage/migrate.go`** — Added `backup` package import. Post-migration DB dump copy now uses `backup.AppDBDumpPath()` instead of hardcoded paths. +- **`internal/web/handlers.go`** — Fixed legacy `"storage"` path in storage app detail size calculation (was dead code — path never existed); now uses `backup.AppDataDir()`. +- **`internal/storage/format_linux.go`** — Format wizard creates `felhom-data/` subdirectory instead of legacy `storage/`. +- **`internal/storage/attach_linux.go`** — Attach wizard creates `felhom-data/` subdirectory instead of legacy `storage/`. + +#### Added +- **`scripts/felhom-wipe.sh`** — Test node cleanup script with 4 wipe levels: + - `soft` — Removes controller state files (settings.json, metrics.db, session/setup/update/snapshot state) + - `controller` — Soft + removes all app containers, volumes, and stack directories (skips protected stacks by default) + - `full` — Controller + removes `felhom-data/` on all storage drives (also removes old-style `appdata/` and `backups/` for migration compatibility); restarts controller + - `nuclear` — Full + removes controller.yaml, all infrastructure containers (controller, traefik, cloudflared, portainer), DR markers, and runs `docker system prune -af --volumes` + - Auto-detects paths from `controller.yaml` and `settings.json` + - Dry-run by default; requires `--yes` to execute + - Interactive confirmation prompt with `--yes` execution + +#### Notes +- **Migration**: Pre-v0.26.0 restic snapshots reference old paths (without `felhom-data/`). Existing installations need data migration before upgrading. +- **App catalog**: Compose templates need separate update: `${HDD_PATH}/appdata/` → `${HDD_PATH}/felhom-data/appdata/` (tracked as separate task). +- All backup, crossdrive, and restore logic automatically picks up new paths via `paths.go` helpers — no changes needed in `backup.go`, `crossdrive.go`, or `restore.go`. + +--- + ### v0.25.0 — Debug Page: Operator Testing & Diagnostics Dashboard (2026-02-21) **Full debug dashboard with 8 sections for testing all controller subsystems in debug mode.** diff --git a/TASK.md b/TASK.md index 6e31a38..40e13ab 100644 --- a/TASK.md +++ b/TASK.md @@ -335,7 +335,7 @@ Must compile cleanly with no errors or warnings. ## Phase 7: Wipe Script -### File: `controller/scripts/felhom-wipe.sh` +### File: `scripts/felhom-wipe.sh` Create the following script. It must be executable (`chmod +x`). diff --git a/controller/README.md b/controller/README.md index 899071a..918a053 100644 --- a/controller/README.md +++ b/controller/README.md @@ -4,7 +4,7 @@ A single, lightweight Go container that replaces Portainer + scattered systemd scripts with a unified, Hungarian-language web dashboard for managing Docker Compose stacks, backups, storage, monitoring, and notifications on customer hardware. -**Current version: v0.25.0** +**Current version: v0.26.0** --- @@ -227,21 +227,35 @@ self-sufficient backup** — any single tier can fully restore an app. The nightly backup has two phases that run sequentially. All paths are **per-drive** — each physical drive gets its own restic repo and per-app DB dump directories. -**Drive layout (v0.14.1):** +**Drive layout (v0.26.0):** ``` / -├── appdata// ← app user data -└── backups/ - └── primary/ - ├── restic/ ← one restic repo per drive (all apps on this drive) - └── /db-dumps/ ← per-app DB dump files +├── felhom-data/ ← all controller-managed data (namespace, v0.26.0+) +│ ├── appdata// ← app user data +│ └── backups/ +│ ├── primary/ +│ │ ├── restic/ ← one restic repo per drive (all apps on this drive) +│ │ └── /db-dumps/ ← per-app DB dump files +│ └── secondary/ +│ ├── restic/ ← secondary restic repo (cross-drive) +│ ├── _infra/ ← infra config mirror +│ └── /rsync/ ← per-app rsync data +├── .felhom-infra-backup/ ← DR marker (stays at drive root for scanner) +├── Dokumentumok/ ← user files (not controller-managed) +└── media/ ← user files (not controller-managed) ``` -Path computation is centralized in `backup/paths.go`: -- `PrimaryResticRepoPath(drivePath)` → `/backups/primary/restic/` -- `AppDBDumpPath(drivePath, stackName)` → `/backups/primary//db-dumps/` -- `AppDataDir(drivePath, stackName)` → `/appdata//` -- `SecondaryInfraPath(drivePath)` → `/backups/secondary/_infra/` +> **Note:** `HDD_PATH` env var in `app.yaml` is still the mount point (e.g., `/mnt/hdd_1`). The `felhom-data` segment is embedded in path helpers — not in `HDD_PATH`. +> Pre-v0.26.0 installations use `/appdata/` and `/backups/` directly (no `felhom-data/` namespace). + +Path computation is centralized in `backup/paths.go` via the `FelhomDataDir = "felhom-data"` constant: +- `PrimaryResticRepoPath(drivePath)` → `/felhom-data/backups/primary/restic/` +- `AppDBDumpPath(drivePath, stackName)` → `/felhom-data/backups/primary//db-dumps/` +- `AppDataDir(drivePath, stackName)` → `/felhom-data/appdata//` +- `SecondaryResticRepoPath(drivePath)` → `/felhom-data/backups/secondary/restic/` +- `AppSecondaryRsyncPath(drivePath, stackName)` → `/felhom-data/backups/secondary//rsync/` +- `SecondaryInfraPath(drivePath)` → `/felhom-data/backups/secondary/_infra/` +- `InfraBackupDir(mountPath)` → `/.felhom-infra-backup/` (**unchanged** — stays at drive root for DR scanner) **Phase 1 — Database Dumps** (`internal/backup/dbdump.go`, scheduled 02:30) @@ -405,7 +419,7 @@ A step-by-step UI at `/settings/storage/init`: 1. **Scan** — Lists available disks with model, size, partition info 2. **Select** — User picks a disk and enters a mount name (e.g., `hdd_1`) 3. **Confirm** — User types "FORMAZAS" to confirm destructive operation -4. **Format pipeline**: `wipefs` → `sfdisk` (GPT) → `mkfs.ext4` → `blkid` UUID → backup fstab → append UUID-based fstab entry → mount → `findmnt` verification → `chown 1000:1000` → create `appdata/`, `backups/`, and `Dokumentumok/` subdirectories +4. **Format pipeline**: `wipefs` → `sfdisk` (GPT) → `mkfs.ext4` → `blkid` UUID → backup fstab → append UUID-based fstab entry → mount → `findmnt` verification → `chown 1000:1000` → create `felhom-data/` and `Dokumentumok/` subdirectories 5. Auto-registers new storage path in settings.json 6. Smart partition detection: skips repartitioning for existing empty partitions @@ -415,7 +429,7 @@ Safety guards: system disk detection, mount path conflict check, confirmation re A step-by-step UI at `/settings/storage/attach` for drives that already have a filesystem (e.g., a previously used ext4 drive). Unlike the init wizard, this does **not** format the drive — existing data is preserved. -**Problem solved:** Mounting a whole drive at `/mnt/` would mix existing user data with the controller's directory structure (`storage/`, `Dokumentumok/`, backup repos). The bind-mount approach isolates the controller's working directory from other data on the drive. +**Problem solved:** Mounting a whole drive at `/mnt/` would mix existing user data with the controller's directory structure (`felhom-data/`, `Dokumentumok/`, etc.). The bind-mount approach isolates the controller's working directory from other data on the drive. 1. **Scan** — Lists available disks, filtered to partitions that have an existing filesystem (FSType != "") 2. **Mount raw** — Partition is mounted read-only at a hidden staging path (`/mnt/.felhom-raw/