backend: harden rootless app lifecycle orchestration

This commit is contained in:
archipelago
2026-06-11 00:24:32 -04:00
parent 09ec64932f
commit c393b96da3
56 changed files with 7543 additions and 1994 deletions
+31 -6
View File
@@ -7,6 +7,7 @@ use std::time::Duration;
use tokio::process::Command as TokioCommand;
const PODMAN_CLI_DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
const PODMAN_CLI_IMAGE_CHECK_TIMEOUT: Duration = Duration::from_secs(10);
const PODMAN_CLI_BUILD_TIMEOUT: Duration = Duration::from_secs(900);
#[async_trait]
@@ -150,7 +151,25 @@ impl ContainerRuntime for PodmanRuntime {
if is_missing_container_error(&stderr) {
return Ok(());
}
Err(api_err.context(format!("podman rm fallback failed: {}", stderr.trim())))
let zero_timeout = self.podman_cli(&["rm", "-f", "--time", "0", name]).await?;
if zero_timeout.status.success() {
return Ok(());
}
let _ = self.podman_cli(&["container", "cleanup", name]).await;
let cleanup_rm = self.podman_cli(&["rm", "-f", name]).await?;
if cleanup_rm.status.success() {
return Ok(());
}
let cleanup_stderr = String::from_utf8_lossy(&cleanup_rm.stderr);
if is_missing_container_error(&cleanup_stderr) {
return Ok(());
}
Err(api_err.context(format!(
"podman rm fallback failed: {}; cleanup rm failed: {}",
stderr.trim(),
cleanup_stderr.trim()
)))
}
}
}
@@ -196,20 +215,26 @@ impl ContainerRuntime for PodmanRuntime {
}
async fn image_exists(&self, image_ref: &str) -> Result<bool> {
// `podman image exists` returns 0 if present, 1 if absent. Any other
// exit code is an environment failure we should surface.
let output = self.podman_cli(&["image", "exists", image_ref]).await?;
// Avoid `podman image exists`: on production nodes with a stressed
// rootless store it can hang even when targeted at one image. A bounded
// inspect is the local-storage probe the trait contract describes.
let output = self
.podman_cli_timeout(
&["image", "inspect", image_ref],
PODMAN_CLI_IMAGE_CHECK_TIMEOUT,
)
.await?;
match output.status.code() {
Some(0) => Ok(true),
Some(1) => Ok(false),
Some(code) => {
let stderr = String::from_utf8_lossy(&output.stderr);
Err(anyhow::anyhow!(
"podman image exists {image_ref} exited with {code}: {stderr}"
"podman image inspect {image_ref} exited with {code}: {stderr}"
))
}
None => Err(anyhow::anyhow!(
"podman image exists {image_ref} terminated by signal"
"podman image inspect {image_ref} terminated by signal"
)),
}
}