Commit Graph

6 Commits

Author SHA1 Message Date
darroyo 667576e5bd fix(nfs): assign non-zero fsid during MigrateNFSClients migration
When migrating old clients format (string array) to new format
(NFSClient objects), also fix any exports that have fsid=0 by
generating a new random fsid. This resolves exportfs errors like:
  exportfs: /path fsid=0 requires fsid= for NFS export

The migration now checks if r.FSID == 0 and generates a new one
using system.GenerateRandomFSID() before updating the row.
2026-07-06 12:00:56 -04:00
darroyo 512feaffd7 feat(nfs): per-host NFS options (IP/CIDR with own ro/async/squash flags)
This is a backward-compatible MINOR bump (0.4.0 → 0.5.0).

BREAKING NOTES (for users upgrading from pre-0.5.0):
- The nfs_exports.clients column schema changed from []string to
  []NFSClient (per-host options). A migration (0005) transforms existing
  string arrays into object arrays, taking export-level options as
  defaults for each host.
- ValidateNFSClient now only accepts IPv4 (192.168.1.1) or IPv4/CIDR
  (192.168.1.0/24). Hostnames, wildcards, netgroups are rejected.
- If you use NASCTL_IMPORT_ON_BOOT, re-import your /etc/exports to pick
  up per-host options.

What changed:
- NFSClient type: {host, read_only, async, root_squash, subtree_check, advanced}
- NFSExport.Clients is now []NFSClient (was []string)
- export-level flags (ro/async/root_squash/subtree_check/advanced) are
  preserved as template defaults for newly added hosts in the UI.
- buildExportLine generates: path host1(ro,sync,...) host2(rw,async,...) fsid=N
- ValidateNFSClient: strict IPv4/CIDR only (0-255 octets, /0-32 prefix)
- parseExportLine now parses per-host options from /etc/exports (previously
  only the first host's options were kept, others were discarded)
- UI: per-host rows with toggles (ro/async/root_squash/subtree_check) and
  advanced options (all_squash, secure, wdelay, hide, crossmnt)
2026-07-06 11:30:27 -04:00
darroyo 0da789cd96 fix: populate fsid for legacy NFS exports on migration
Migration 0002 added fsid column with DEFAULT 0 but never
populated existing rows. Now PopulateLegacyFSIDs() runs after 0002
to extract fsid from legacy options string or generate random.

Also: move generateRandomFSID to internal/system to avoid import
cycles. Migration 0004 drops the legacy options column.

Version: 0.3.1 -> 0.3.2
2026-07-06 01:22:16 -04:00
darroyo 63e0b5146a fix: tolerate duplicate column errors in migration runner
The previous SAVEPOINT approach failed because Go's tx.Exec() stops at
the first error and never reaches the ROLLBACK TO statements. This caused
every subsequent startup to re-run migration 0002, fail on the first
ALTER (column already exists from a prior partial run), and crash.

Fix runMigration() to:
- Execute migrations without a wrapping transaction (DDL in SQLite is
  auto-commit anyway)
- Treat "duplicate column name" / "already exists" errors as success
  and record the migration anyway, covering cases where a previous
  failed attempt already partially modified the schema

Also simplify 0002_nfs_structured.sql back to plain ALTER TABLE
statements (no SAVEPOINT needed with the new Go-level tolerance).

Bump VERSION 0.1.9 -> 0.1.10
2026-07-06 00:05:02 -04:00
darroyo 9a9d4cc753 fix: implement migration tracking and make 0002 idempotent
- Add schema_migrations table to track applied migrations
- Migrate() now checks if a migration was already applied before running
- 0002 rewritten to use SAVEPOINT+ROLLBACK per column, making it safe
  to run even if some columns were partially added previously
- Each migration runs in its own transaction; INSERT into schema_migrations
  only happens if the SQL executes without error
- Bump VERSION 0.1.8 -> 0.1.9
2026-07-05 23:54:14 -04:00
darroyo 4f0754ecc5 Add nasctl: Go NAS control plane with React frontend 2026-07-05 17:37:19 -04:00