backend: harden rootless app lifecycle orchestration
This commit is contained in:
@@ -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"
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user