use crate::error::{ComposeError, Result};
use crate::engine::Engine;
use crate::libpod::API_PREFIX;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(super) enum LifecycleGoal {
Running,
NotRunning,
Gone,
}
impl LifecycleGoal {
pub(super) fn reached(self, state: Option<&str>) -> bool {
match self {
Self::Running => state == Some("running"),
Self::NotRunning => state != Some("running"),
Self::Gone => state.is_none(),
}
}
}
impl Engine {
pub(super) async fn confirm_lost_response(
&self,
container: &str,
done: &str,
goal: LifecycleGoal,
e: crate::libpod::PodmanError,
) -> Result<bool> {
match self.container_state(container).await {
Ok(state) if goal.reached(state.as_deref()) => {
tracing::warn!(
"{container}: {done} lost its response [{}] but the container reached \
{goal:?}, so the operation landed",
e.stream_end_kind()
);
crate::ui::progress_line("Container", container, done);
Ok(true)
}
Ok(state) => {
tracing::warn!(
"{container}: {done} lost its response [{}] and the container is \
{state:?}, not {goal:?}",
e.stream_end_kind()
);
Err(ComposeError::Podman(e))
}
Err(recheck) => {
tracing::warn!(
"{container}: {done} lost its response [{}] and the state could not be \
re-checked: {recheck}",
e.stream_end_kind()
);
Err(ComposeError::Podman(e))
}
}
}
pub(super) async fn container_state(&self, container: &str) -> Result<Option<String>> {
let filters = serde_json::json!({ "name": [container] });
let path = format!(
"{API_PREFIX}/containers/json?all=true&filters={}",
crate::libpod::urlencoded(&filters.to_string()),
);
let entries = self
.client
.get_json::<Vec<crate::libpod::types::container::ContainerListEntry>>(&path)
.await
.map_err(ComposeError::Podman)?;
Ok(entries
.into_iter()
.find(|e| {
e.names
.iter()
.any(|n| n.trim_start_matches('/') == container)
})
.map(|e| e.state))
}
}