nixos-config/configurations/nixos/pureintent/mod.just
Sridhar Ratnakumar 776c4425b0 incus-pet: shared /nix/store, restart-to-deploy, drop anywhen flake input
The incus-pet CLI gains three big changes that together cut per-container
disk usage by ~5GB, drop nix-rebuild + nix-copy from the deploy path, and
make `deploy` actually pull latest on every invocation. anywhen migrates
from a host-installed service to an incus-pet container in the process.

* Shared /nix/store mount. Each container gets host's /nix/store
  bind-mounted read-only (with shift=true for idmapped unprivileged
  containers). Zero per-container duplication of nixpkgs closures. The
  CLI builds toplevels on the host; the container sees them via the
  shared mount, no `nix copy` needed.

* Restart-to-deploy. switch-to-configuration is removed entirely (it
  was stalling on dbus-broker reload and hitting the same lock-
  contention bug across redeploys). New activation: update
  /nix/var/nix/profiles/system, repoint /sbin/init through the profile
  symlink, `incus restart`. The new toplevel's own init script handles
  /etc setup on boot. Trade-off: ~5s of container reboot per deploy.

* Marshaling flake exposes only nixosModules.default. No nixpkgs
  input, no nixosConfigurations entry. The CLI picks nixpkgs at build
  time (pinned to nixos-25.11 — matches the LXC image baseline, dodges
  unstable regressions) and assembles the full nixosSystem via
  `nix build --impure --expr`. Lets us bump nixpkgs without touching
  per-deploy state.

* `nix flake update --refresh` on every deploy. Was `nix flake lock`,
  which only locks first-seen inputs — re-deploying `github:srid/anywhen`
  stayed pinned at the first commit ever resolved. Now every deploy
  bumps the target input to the current tip of its ref and bypasses
  nix's fetcher cache.

* /sbin/init repoint. The NixOS LXC image hard-links /sbin/init to its
  own toplevel's init path. Without switch-to-configuration, `incus
  restart` re-execs that old init, which sets up /etc from the old
  toplevel — running services keep using the OLD anywhen binary even
  though the profile pointer moved. CLI now also does
  `ln -sfn /nix/var/nix/profiles/system/init /sbin/init` so the profile
  actually drives boot. Idempotent.

* Host gcroot via `nix-store --add-root --indirect`. Container's nix DB
  doesn't know about the path (it lives behind the shared mount), so
  without a host-side gcroot the host could nix-collect-garbage the
  running system out from under the container. Symlink at
  ~/.local/state/incus-pet/<name>/system. Only the LATEST toplevel is
  pinned per app — no rollback today (file a 5-line ring buffer when
  rollback matters).

* anywhen flake input removed. `modules/nixos/linux/anywhen.nix` is
  gone; the host config no longer imports anywhen as a flake input.
  The deploy command takes the flake ref as an argument, so locking it
  here was just bloat. `just pureintent anywhen-deploy` runs the
  current invocation.

* pureintent ops recipes. New `configurations/nixos/pureintent/mod.just`
  with anywhen-{deploy,rm,backup,restore,status,shell}. Namespaced via
  `mod pureintent` so each host's recipes live behind their own prefix.

* Drop ssh from deploy path. Bootstrap still pushes the operator's
  pubkey (for interactive debugging), but activation goes through
  `incus exec` exclusively. No NIX_SSHOPTS, no nix-copy-via-ssh,
  no host-key TOFU dance during deploys.

Tested end-to-end on pureintent: anywhen migrated from host-installed
(21-task SQLite DB at /var/lib/anywhen) to an incus-pet container with
the DB intact; hello-web deployed fresh with shared /nix/store; both
serve over the tailscale proxy at 100.122.32.106:{6111,8081}; lock
bumps + new toplevels confirmed after master advances.
2026-05-23 18:50:10 -04:00

55 lines
2.4 KiB
Text

# Pureintent-specific operational recipes.
#
# Imported from the top-level Justfile. Each recipe bakes in the values
# that are stable on this host (tailscale IP, container names, port
# choices) so the day-to-day operator just types `just anywhen-deploy`,
# not the full incus-pet invocation.
LISTEN_IP := "100.122.32.106" # pureintent's tailscale IP
# ----------------------------------------------------------------------
# anywhen — github:srid/anywhen as a per-app incus-pet container.
# ----------------------------------------------------------------------
# Deploy anywhen (default: master); pass `ref` to deploy a branch/PR.
[group('anywhen')]
anywhen-deploy ref="github:srid/anywhen":
nix run .#incus-pet -- deploy {{ ref }} anywhen --port 6111 --listen {{ LISTEN_IP }}
# Drop the anywhen container entirely (state goes with it — back up first).
[group('anywhen')]
anywhen-rm:
nix run .#incus-pet -- rm anywhen
# Pull a WAL-checkpointed snapshot of the live SQLite DB to PATH.
[group('anywhen')]
anywhen-backup path="/tmp/anywhen.db":
incus exec anywhen -- systemctl stop anywhen.service
incus exec anywhen -- sh -c 'cd /var/lib/private/anywhen && sqlite3 anywhen.db "PRAGMA wal_checkpoint(TRUNCATE);" 2>/dev/null || true'
incus file pull anywhen/var/lib/private/anywhen/anywhen.db {{ path }}
incus exec anywhen -- systemctl start anywhen.service
@echo "backup -> {{ path }}"
# Push a DB file into the anywhen container (stop/copy/chown/wipe-wal/start).
[group('anywhen')]
anywhen-restore db:
incus exec anywhen -- systemctl stop anywhen.service
incus file push {{ db }} anywhen/var/lib/private/anywhen/anywhen.db --mode 644
incus exec anywhen -- sh -c 'chown $(stat -c "%u:%g" /var/lib/private/anywhen) /var/lib/private/anywhen/anywhen.db'
incus exec anywhen -- rm -f /var/lib/private/anywhen/anywhen.db-wal /var/lib/private/anywhen/anywhen.db-shm
incus exec anywhen -- systemctl start anywhen.service
@echo "restored {{ db }} -> anywhen.service active"
# Health check (curl /api/health, in-container service status, full list).
[group('anywhen')]
anywhen-status:
@echo "--- tailnet ---"
@curl -sS http://{{ LISTEN_IP }}:6111/api/health && echo
@echo "--- container ---"
@incus exec anywhen -- systemctl is-active anywhen.service
@nix run .#incus-pet -- list
# Drop into a root shell inside the anywhen container.
[group('anywhen')]
anywhen-shell:
incus exec anywhen -- bash