site-manager¶
The Site manager. The Site is the umbrella over a whole TAPPaaS installation: site-wide identity, location, hardware (Proxmox nodes + storage pools), backup, update schedule, repositories, and references to the environment/organization config. (Domain / DNS / identity are per-environment, owned by environment-manager, not here.)
What it owns¶
config/site.json (default ${TAPPAAS_CONFIG:-/home/tappaas/config}/site.json), validated against site-fields.json. It also migrates the legacy config/configuration.json into site.json.
site-manager¶
The site-manager bin is the front door. It owns the Site as a singleton and the node / repository sub-entities, following the same <entity> <verb> shape as network-manager. The heavy git/cluster I/O stays in the still-live bash tools, invoked as thin delegations: add → create-site.sh, repository add/delete → repository.sh, validate → validate-site.sh. The bin owns config CRUD (site modify, node CRUD, the site.json writes) + validate + reconcile.
Entities and verbs¶
site (singleton) site show [--json]
site modify --<field> <value> [...]
node node list [--json]
node add <N> [--pxe] [--boot-disk <d>] [--mac <m>]
[--wan-port <if>|--no-wan] [--pool <p>] [--ttl <s>]
[--config-only]
node delete <name>
node reconcile [--apply]
repository repository list [--json]
repository add <url> [--branch <b>] [--managed full|tracked] [--catalog <p>]
repository delete <name> [--force]
repository reconcile [--apply]
top-level add --name <site-code> [--organization <org>] [create-site options] (= create-site.sh)
validate [FILE] [--schema-dir PATH] (= validate-site.sh)
reconcile [--apply] [--deep]
update [--dry-run] [--force] [--no-git-pull] (= update-tappaas)
test [--deep] (= module-manager test each)
update packages the whole-site update sweep: it delegates to update-tappaas and always runs now (update-tappaas --force, the scheduling override — the update window is ignored). Its own --force is a different axis: it authorizes a disruptive change (reboot / offline migrate) on every module (TAPPAAS_MODULE_FORCE → each module modify --force; legitimate under ADR-020 D8 because an operator is explicitly asking, not the unattended sweep). --no-git-pull (TAPPAAS_NO_GIT_PULL) updates whatever is checked out — pre-update.sh skips the per-repo pull — so local, not-yet-pushed changes can be tested. --dry-run previews the plan.
test runs every deployed module's tests: it iterates module-manager list (foundation + apps, from every registered repository) and runs module-manager test <m>, forwarding --deep. Continue-on-failure; exits non-zero if any module test failed.
Common options: --config-dir DIR, --json (machine output for list/show), --apply (reconcile commits; default is preview), --deep (reconcile cascade), --force (repository delete → repository.sh remove --force).
site modify editable fields (scalar, site-wide): --displayName, --owner, --email, --automaticReboot, --snapshotRetention, --backupTarget, --backupOffsite, --locationCountry, --locationTimezone, --locationLocale, --networkIsp, --networkPublicIp. The discovery-derived hardware.nodes[] (use node …) and the repositories/environments/ organizations lists (own CRUD / own managers) are not modifiable here.
node add — standing up a follow-on node (design N3/N4)¶
node add <tappaasN> is the operator front door for growing the cluster; hardware-validated end-to-end on 2026-07-07. Three modes:
- default (adopt) — a Proxmox was already installed by hand (USB stick, §2.1 media) at the node's DESIGNATED mgmt IP (
tappaasN→10.0.0.<9+N>): verifies the hostname +pveversionover ssh, then runs the join pipeline. A node that is already clustered skips straight to capture. --pxe— bare machine: registers the node withnode-provisioner, arms the TTL-limited PXE trap, waits for the unattended install (the ONLY console interaction is the boot-disk question, and only when--boot-diskwas not given), then continues with the same join pipeline. Requires the netboot assets staged once per PVE version — done automatically by the cicd install (prepare-netboot.sh). Booting the SAME prepared ISO from a USB stick instead of PXE works identically (the answer still comes over HTTP from the mothership).--config-only— just write thehardware.nodes[]entry (no machine contact); the pre-N3 behaviour.
The join pipeline (shared by adopt and --pxe): asks for the WAN NIC and the data-pool declarations with the node's REAL hardware listed (skip the questions with --wan-port <if>/--no-wan and --pool 'tanka1=…'), serves the repo from the mothership on :8090 (committed branch state — no GitHub dependency), runs the node step (install.sh --join), corrects /etc/hosts, seeds node→tappaas1 ssh trust, pvecm add, and captures the node + its pools via node reconcile --apply. Every wait is time-boxed and the PXE trap is disarmed on every exit path. Fully unattended example:
site-manager node add tappaas2 --pxe --boot-disk sda \
--mac aa:bb:cc:dd:ee:ff --no-wan --pool 'tanka1=single:nvme0n1'
Afterwards run update-tappaas --force to fold HA + replication.
reconcile and the --deep cascade¶
reconcile is shallow by default — it converges the site's own concern: validate site.json, then bring each repositories[] entry to a live clone (clone if missing, checkout if the branch drifts). Default output is a preview; --apply commits. repository reconcile is the repo-scoped subset of the same engine.
reconcile --deep then cascades to the dependent managers in dependency order:
site reconcile --deep
→ people-manager reconcile (people → Authentik)
→ network-manager reconcile (the 4 network planes — ONE system-wide pass)
→ for each environment in config/environments/*.json:
environment-manager reconcile <env> --deep --skip-network
people/network are single bins; environments fan out — one deep reconcile per registered environment. The network pass runs once for the whole site: network-manager reconcile has no zone or environment filter, so letting each environment run its own would repeat the identical whole-platform operation once per environment. Every leg is idempotent, so re-running is safe; this is the natural whole-platform converge after update-tappaas.
A cascade that exits non-zero is reported by name and makes site reconcile exit 1 — the remaining legs still run, so one bad environment does not strand the rest.
Build¶
Built by default.nix into result/bin/site-manager — mirroring people-manager / network-manager. install.sh is not yet wired to build it (the bash tools below remain the installed entry points for now).
Commands (legacy bash tools — kept live until cutover)¶
All scripts are bash, linked onto PATH by install.sh. repository.sh and validate-site.sh remain live and are the tools the repository add/delete and validate verbs delegate to; create-site.sh backs the add verb.
repository.sh — manage module repositories¶
The current, supported tool for registering the external module repositories TAPPaaS pulls modules from (add / remove / modify / list). It stays until the site-manager subsumes it as a verb. (It currently reads/writes the repository list in the legacy configuration.json; repointing it to site.json .repositories is pending — see DESIGN.md.)
repository.sh add <url> [--branch <b>] [--managed full|tracked] [--catalog <path>]
repository.sh remove <name> [--force]
repository.sh modify <name> [--url <new>] [--branch <new>]
repository.sh list
validate-site.sh — validate site.json¶
This is the manager's validate operation, named validate-site.sh per the script-manager validate-<manager>.sh convention; runnable directly.
FILE— site.json to validate (default$TAPPAAS_CONFIG/site.json).--schema-dir PATH— directory holdingsite-fields.json.--quiet— errors/warnings only.
Legacy tools (kept until the flag-day cutover)¶
These predate site.json and operate on the legacy configuration.json:
create-configuration.sh¶
Create/update configuration.json by discovering the running Proxmox cluster. Accepts named flags (--upstream-git, --branch, --domain, --email, --schedule monthly|weekly|daily|none, --weekday, --hour, --primary-node, --update) or legacy positionals (<upstreamGit> <branch> <domain> <email> <schedule> [weekday] [hour]). Idempotent.
validate-configuration.sh¶
Validate configuration.json. Flags: --config <path>, --check-connectivity (ping nodes), --check-cluster (SSH the first node, compare cluster membership), --check-repos (git ls-remote each repo URL), --quiet.
convert-json-to-config.sh¶
Convert a flat module JSON into the canonical config-block form. CLI: convert-json-to-config.sh [--in-place|--dry-run] <module-json>; or source it and call regroup_to_pattern_a.