fix(container): drift-gate the per-app ownership-repair hooks

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 <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-08-07 22:06:01 -04:00
co-authored by Claude
parent b886930708
commit b9e64eb619
@@ -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}"))?;