|
3 | 3 | use std::collections::HashSet; |
4 | 4 |
|
5 | 5 | use { |
6 | | - serde::Serialize, |
| 6 | + serde::{Deserialize, Serialize}, |
7 | 7 | sha2::{Digest, Sha256}, |
8 | 8 | tracing::warn, |
9 | 9 | }; |
@@ -433,6 +433,42 @@ pub enum ContainerRunState { |
433 | 433 | Unknown, |
434 | 434 | } |
435 | 435 |
|
| 436 | +#[derive(Debug, Clone, Copy, Deserialize)] |
| 437 | +#[serde(rename_all = "lowercase")] |
| 438 | +enum AppleContainerState { |
| 439 | + Running, |
| 440 | + Stopped, |
| 441 | + Exited, |
| 442 | + #[serde(other)] |
| 443 | + Unknown, |
| 444 | +} |
| 445 | + |
| 446 | +#[derive(Debug, Deserialize)] |
| 447 | +#[serde(untagged)] |
| 448 | +enum AppleContainerStatus { |
| 449 | + Legacy(AppleContainerState), |
| 450 | + Current { state: AppleContainerState }, |
| 451 | +} |
| 452 | + |
| 453 | +impl AppleContainerStatus { |
| 454 | + fn run_state(&self) -> ContainerRunState { |
| 455 | + match self { |
| 456 | + Self::Legacy(state) | Self::Current { state } => match state { |
| 457 | + AppleContainerState::Running => ContainerRunState::Running, |
| 458 | + AppleContainerState::Stopped => ContainerRunState::Stopped, |
| 459 | + AppleContainerState::Exited => ContainerRunState::Exited, |
| 460 | + AppleContainerState::Unknown => ContainerRunState::Unknown, |
| 461 | + }, |
| 462 | + } |
| 463 | + } |
| 464 | +} |
| 465 | + |
| 466 | +fn apple_container_run_state(entry: &serde_json::Value) -> Option<ContainerRunState> { |
| 467 | + let status = |
| 468 | + serde_json::from_value::<AppleContainerStatus>(entry.get("status")?.clone()).ok()?; |
| 469 | + Some(status.run_state()) |
| 470 | +} |
| 471 | + |
436 | 472 | /// Which container backend manages this container. |
437 | 473 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)] |
438 | 474 | #[serde(rename_all = "kebab-case")] |
@@ -524,16 +560,7 @@ pub async fn list_running_containers_for_prefixes( |
524 | 560 | { |
525 | 561 | continue; |
526 | 562 | } |
527 | | - let state_str = entry |
528 | | - .pointer("/status/state") |
529 | | - .and_then(|v| v.as_str()) |
530 | | - .unwrap_or_default(); |
531 | | - let state = match state_str { |
532 | | - "running" => ContainerRunState::Running, |
533 | | - "stopped" => ContainerRunState::Stopped, |
534 | | - "exited" => ContainerRunState::Exited, |
535 | | - _ => ContainerRunState::Unknown, |
536 | | - }; |
| 563 | + let state = apple_container_run_state(&entry).unwrap_or(ContainerRunState::Unknown); |
537 | 564 | let image = entry |
538 | 565 | .pointer("/configuration/image/reference") |
539 | 566 | .and_then(|v| v.as_str()) |
@@ -845,8 +872,8 @@ pub async fn remove_container(name: &str) -> Result<()> { |
845 | 872 | match inspect { |
846 | 873 | Ok(ref ins) if ins.status.success() => { |
847 | 874 | let stdout = String::from_utf8_lossy(&ins.stdout); |
848 | | - let status = apple_container_status_from_inspect(&stdout); |
849 | | - if status == Some("running") { |
| 875 | + let status = apple_container_run_state_from_inspect(&stdout); |
| 876 | + if status == Some(ContainerRunState::Running) { |
850 | 877 | // Container is genuinely running — return the rm error. |
851 | 878 | let stderr = output |
852 | 879 | .as_ref() |
@@ -946,21 +973,14 @@ pub async fn restart_container_daemon() -> Result<()> { |
946 | 973 | )) |
947 | 974 | } |
948 | 975 |
|
949 | | -pub(crate) fn apple_container_status_from_inspect(stdout: &str) -> Option<&'static str> { |
| 976 | +pub(crate) fn apple_container_run_state_from_inspect(stdout: &str) -> Option<ContainerRunState> { |
950 | 977 | let inspect = stdout.trim(); |
951 | 978 | if inspect.is_empty() || inspect == "[]" { |
952 | 979 | return None; |
953 | 980 | } |
954 | 981 |
|
955 | | - if inspect.contains(r#""status":"running""#) { |
956 | | - return Some("running"); |
957 | | - } |
958 | | - |
959 | | - if inspect.contains(r#""status":"stopped""#) || inspect.contains(r#""status":"exited""#) { |
960 | | - return Some("stopped"); |
961 | | - } |
962 | | - |
963 | | - None |
| 982 | + let entries = serde_json::from_str::<Vec<serde_json::Value>>(inspect).ok()?; |
| 983 | + entries.first().and_then(apple_container_run_state) |
964 | 984 | } |
965 | 985 |
|
966 | 986 | pub(crate) fn is_apple_container_service_error(stderr: &str) -> bool { |
|
0 commit comments