From b1eea8c05386e6968a4b63a4c51d0f9ff4dc621d Mon Sep 17 00:00:00 2001 From: archipelago Date: Sun, 21 Jun 2026 15:46:26 -0400 Subject: [PATCH] feat(indeedhub): manifest-driven 7-member stack, orchestrator-first (#20 phase 3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Author the IndeedHub stack as 7 manifests (postgres/redis/minio/relay/api/ ffmpeg + frontend) and route install_indeedhub_stack through the orchestrator first (immich pattern), falling back to the legacy installer only when the manifests aren't deployed. Data-preserving by construction — the manifests reproduce the live install exactly so an existing node ADOPTS rather than recreates: - container_name = the live hyphenated names the runtime already references (health_monitor tiers/deps, crash_recovery). - named volumes indeedhub-{postgres,redis,minio,relay}-data (not bind mounts). - dedicated indeedhub-net + network_aliases [postgres|redis|minio|relay|api] so the api/ffmpeg env hostnames and the frontend nginx upstreams resolve unchanged. - generated_secrets (indeedhub-db-password/-minio-password owned by their backends, indeedhub-jwt by the api) reuse the live /var/lib/archipelago/ secrets values (ensure_one no-ops on existing files; postgres pw is fixed at PGDATA init). minio user "indeeadmin" + AES_MASTER_SECRET literal kept. The frontend carries the post_install hook (#20) that replaces the hardcoded patch_indeedhub_nostr_provider: strip X-Frame-Options, refresh nostr-provider.js from /opt/archipelago/web-ui, inject the #' /etc/nginx/conf.d/default.conf"] + - exec: ["nginx", "-s", "reload"] health_check: type: http - endpoint: http://localhost:3000 + endpoint: http://localhost:7777 path: / interval: 30s timeout: 10s diff --git a/core/archipelago/src/api/rpc/package/stacks.rs b/core/archipelago/src/api/rpc/package/stacks.rs index 2d410c88..ed088964 100644 --- a/core/archipelago/src/api/rpc/package/stacks.rs +++ b/core/archipelago/src/api/rpc/package/stacks.rs @@ -696,6 +696,23 @@ fn immich_stack_app_ids() -> &'static [&'static str] { &["immich-postgres", "immich-redis", "immich"] } +fn indeedhub_stack_app_ids() -> &'static [&'static str] { + // Dependency order: backends + their generated secrets first, then the api + // (owns indeedhub-jwt; reads the db/minio secrets the backends materialised), + // then the ffmpeg worker, then the user-facing frontend ("indeedhub", which + // carries the post_install nginx hook). The frontend's nginx reaches the + // backends by their short network_aliases (api/minio/relay) on indeedhub-net. + &[ + "indeedhub-postgres", + "indeedhub-redis", + "indeedhub-minio", + "indeedhub-relay", + "indeedhub-api", + "indeedhub-ffmpeg", + "indeedhub", + ] +} + const REGISTRY: &str = "146.59.87.168:3000/lfg2025"; const NETBIRD_DASHBOARD_IMAGE: &str = "docker.io/netbirdio/dashboard:v2.38.0"; @@ -1422,6 +1439,20 @@ impl RpcHandler { /// Install the IndeedHub multi-container stack. pub(super) async fn install_indeedhub_stack(&self) -> Result { + // Manifest-driven path (#20 phase 3): render the 7-member stack from + // apps/indeedhub-*/manifest.yml via the orchestrator (dedicated + // indeedhub-net + network_aliases, generated_secrets, the frontend's + // post_install nginx hook, reboot-survivable). The manifests use the exact + // live container names / named volumes, so on an existing node this ADOPTS + // the running stack rather than recreating it (data preserved). Falls back + // to the legacy installer below only when the orchestrator doesn't know + // these app_ids (manifests not yet deployed). See PRODUCTION-MASTER-PLAN.md. + if let Some(orchestrated) = + install_stack_via_orchestrator(self, "indeedhub", indeedhub_stack_app_ids()).await? + { + return Ok(orchestrated); + } + let registry = crate::container::registry::load_registries(&self.config.data_dir) .await .unwrap_or_default()