From b9e64eb619ae04c0bd7ce29ef38027312ecb154b Mon Sep 17 00:00:00 2001 From: archipelago Date: Fri, 7 Aug 2026 22:06:01 -0400 Subject: [PATCH] fix(container): drift-gate the per-app ownership-repair hooks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The reconciler's pre-start hooks for the btcpay stack, fedimint and fmcd chowned unconditionally on EVERY prepare — and prepare re-runs far more often than install (every reconcile that touches the app). archi-dev-box's journal showed the same three dirs re-chowned every ~15s. The hooks exist to repair old installs; they now skip when ownership is already correct (root stat probe — the daemon's rootless metadata read can't see the subuid-owned dirs). Co-Authored-By: Claude --- .../src/container/prod_orchestrator.rs | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/core/archipelago/src/container/prod_orchestrator.rs b/core/archipelago/src/container/prod_orchestrator.rs index fb05df92..718dbbdc 100644 --- a/core/archipelago/src/container/prod_orchestrator.rs +++ b/core/archipelago/src/container/prod_orchestrator.rs @@ -3159,6 +3159,10 @@ impl ProdContainerOrchestrator { if !mkdir.success() { return Err(anyhow::anyhow!("mkdir -p {dir} failed with status {mkdir}")); } + // Drift-gated like the other ownership hooks. + if ownership_already_correct_from_host(dir, "1000:1000").await { + return Ok(Some(HookOutcome::Unchanged)); + } let chown = host_sudo(&["chown", "-R", "1000:1000", dir]) .await .with_context(|| format!("chown {dir}"))?; @@ -3194,6 +3198,13 @@ impl ProdContainerOrchestrator { "/var/lib/archipelago/btcpay", "/var/lib/archipelago/nbxplorer", ] { + // These hooks exist to repair old installs, not to churn on every + // prepare — a healthy stack was being re-chowned on each reconcile + // tick (operator-visible journal flood, 2026-08-07). Skip when the + // ownership is already right. + if ownership_already_correct_from_host(dir, "1000:1000").await { + continue; + } let status = host_sudo(&["chown", "-R", "1000:1000", dir]) .await .with_context(|| format!("chown {dir}"))?; @@ -3203,13 +3214,15 @@ impl ProdContainerOrchestrator { } let db_dir = "/var/lib/archipelago/postgres-btcpay"; - let status = host_sudo(&["chown", "-R", "100998:100998", db_dir]) - .await - .with_context(|| format!("chown {db_dir}"))?; - if !status.success() { - return Err(anyhow::anyhow!( - "chown {db_dir} failed with status {status}" - )); + if !ownership_already_correct_from_host(db_dir, "100998:100998").await { + let status = host_sudo(&["chown", "-R", "100998:100998", db_dir]) + .await + .with_context(|| format!("chown {db_dir}"))?; + if !status.success() { + return Err(anyhow::anyhow!( + "chown {db_dir} failed with status {status}" + )); + } } Ok(()) } @@ -3230,6 +3243,10 @@ impl ProdContainerOrchestrator { // container. Container uid 0 maps to the Archipelago host user // (1000), not to subuid 100000. Repair old installs that were // chowned into the subuid range and crash on database.db.lock. + // Drift-gated like the btcpay hook — see ensure_btcpay_stack_dirs. + if ownership_already_correct_from_host(dir, "1000:1000").await { + continue; + } let chown = host_sudo(&["chown", "-R", "1000:1000", dir]) .await .with_context(|| format!("chown {dir}"))?;