fix(orchestrator): make legacy mempool id start/stop/restart the split stack
Found by the .228 lifecycle gate (2026-07-08, first quadlet-mode run):
stop→start on the legacy `mempool` umbrella app id destroyed the mempool
deployment. Under quadlet, package.stop removes the containers; package.start
then failed with `unknown app_id: mempool` because load_manifests drops the
umbrella manifest whenever the three split-stack members are loaded — leaving
nothing to recreate from and the stack down.
Two fixes:
- prod_orchestrator start/stop/restart now resolve the historical
`mempool`/`mempool-web` id to the split members (archy-mempool-db,
mempool-api, archy-mempool-web) whenever the umbrella manifest was dropped —
the same alias install already implements ("installing mempool assembles the
split stack"). Restart falls back to start for members whose container/unit
is gone. Legacy umbrella-only nodes are unaffected (alias inactive while the
umbrella manifest is live).
- is_missing_container_error (3 sites) now recognizes podman 5.x's
`no such object` inspect phrasing, so a genuinely absent container is
classified as missing instead of surfacing as a hard inspect error.
Tests: 2 new alias tests + 2 classifier tests; prod_orchestrator suite 61/61
green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
380f4f1947
commit
161a6e4dbd
@@ -926,6 +926,8 @@ async fn inspect_runtime_container_state(container_name: &str) -> Result<Option<
|
||||
fn is_missing_container_error(stderr: &str) -> bool {
|
||||
stderr.contains("no such container")
|
||||
|| stderr.contains("no container with name")
|
||||
// podman 5.x `inspect` phrasing: `Error: no such object: "name"`
|
||||
|| stderr.contains("no such object")
|
||||
|| stderr.contains("does not exist")
|
||||
|| stderr.contains("not found")
|
||||
}
|
||||
@@ -1966,6 +1968,22 @@ pub(super) fn orchestrator_uninstall_app_ids(package_id: &str) -> Vec<String> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn missing_container_classifier_covers_podman5_phrasings() {
|
||||
// Regression (.228 gate 2026-07-08): podman 5.x `inspect` on a missing
|
||||
// container says `Error: no such object: "mempool"` — the classifier
|
||||
// missed it, so a plain missing container surfaced as a hard inspect
|
||||
// error and package.start aborted instead of proceeding to recreate.
|
||||
assert!(is_missing_container_error(
|
||||
"Error: no such object: \"mempool\""
|
||||
));
|
||||
assert!(is_missing_container_error("Error: no such container mempool"));
|
||||
assert!(is_missing_container_error(
|
||||
"Error: no container with name or id \"x\" found"
|
||||
));
|
||||
assert!(!is_missing_container_error("Error: OCI runtime error"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn runtime_host_ports_are_manifest_derived_for_public_apps() {
|
||||
assert_eq!(runtime_host_ports("photoprism"), vec![2342]);
|
||||
|
||||
@@ -130,6 +130,8 @@ async fn wait_for_stack_container_absent(container_name: &str, timeout: Duration
|
||||
fn is_missing_container_error(stderr: &str) -> bool {
|
||||
stderr.contains("no such container")
|
||||
|| stderr.contains("no container with name")
|
||||
// podman 5.x `inspect` phrasing: `Error: no such object: "name"`
|
||||
|| stderr.contains("no such object")
|
||||
|| stderr.contains("does not exist")
|
||||
|| stderr.contains("not found")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user