1use std::collections::BTreeMap;
2
3use async_trait::async_trait;
4use serde::{Deserialize, Serialize};
5use soma_fleet::{HostId, HostRecord, TopologyRevision};
6use tokio_util::sync::CancellationToken;
7
8use crate::InfraResult;
9
10#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12pub struct DockerSystemInfo {
13 pub host: HostId,
15 pub topology_revision: TopologyRevision,
17 pub daemon_id: Option<String>,
19 pub name: Option<String>,
21 pub server_version: Option<String>,
23 pub operating_system: Option<String>,
25 pub architecture: Option<String>,
27 pub kernel_version: Option<String>,
29 pub storage_driver: Option<String>,
31 pub containers: u64,
33 pub containers_running: u64,
35 pub containers_paused: u64,
37 pub containers_stopped: u64,
39 pub images: u64,
41 pub cpus: u64,
43 pub memory_total_bytes: u64,
45}
46
47#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
49pub struct ContainerListOptions {
50 pub all: bool,
52 pub state: Option<ContainerState>,
54 pub label: Option<String>,
56}
57
58impl Default for ContainerListOptions {
59 fn default() -> Self {
60 Self {
61 all: true,
62 state: None,
63 label: None,
64 }
65 }
66}
67
68#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
70#[serde(rename_all = "snake_case")]
71pub enum ContainerState {
72 Created,
74 Running,
76 Paused,
78 Restarting,
80 Removing,
82 Exited,
84 Dead,
86 Unknown(String),
88}
89
90impl ContainerState {
91 #[cfg(any(feature = "bollard-driver", test))]
92 pub(crate) fn from_text(value: Option<&str>) -> Self {
93 match value.unwrap_or_default().to_ascii_lowercase().as_str() {
94 "created" => Self::Created,
95 "running" => Self::Running,
96 "paused" => Self::Paused,
97 "restarting" => Self::Restarting,
98 "removing" => Self::Removing,
99 "exited" => Self::Exited,
100 "dead" => Self::Dead,
101 other => Self::Unknown(other.to_owned()),
102 }
103 }
104}
105
106#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
108pub struct ContainerSummary {
109 pub host: HostId,
111 pub topology_revision: TopologyRevision,
113 pub id: Option<String>,
115 pub names: Vec<String>,
117 pub image: Option<String>,
119 pub image_id: Option<String>,
121 pub command: Option<String>,
123 pub created_unix_seconds: Option<i64>,
125 pub state: ContainerState,
127 pub status: Option<String>,
129 pub labels: BTreeMap<String, String>,
131}
132
133#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
135pub struct ContainerInspect {
136 pub host: HostId,
138 pub topology_revision: TopologyRevision,
140 pub id: Option<String>,
142 pub name: Option<String>,
144 pub created: Option<String>,
146 pub path: Option<String>,
148 pub args: Vec<String>,
150 pub image: Option<String>,
152 pub state: ContainerState,
154 pub pid: Option<i64>,
156 pub exit_code: Option<i64>,
158 pub restart_count: Option<i64>,
160 pub labels: BTreeMap<String, String>,
162}
163
164#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
166pub struct ImageListOptions {
167 pub all: bool,
169 pub dangling_only: bool,
171}
172
173#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
175pub struct ImageSummary {
176 pub host: HostId,
178 pub topology_revision: TopologyRevision,
180 pub id: String,
182 pub repo_tags: Vec<String>,
184 pub repo_digests: Vec<String>,
186 pub created_unix_seconds: i64,
188 pub size_bytes: i64,
190 pub containers: i64,
192 pub labels: BTreeMap<String, String>,
194}
195
196#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
198pub struct NetworkSummary {
199 pub host: HostId,
201 pub topology_revision: TopologyRevision,
203 pub id: Option<String>,
205 pub name: Option<String>,
207 pub driver: Option<String>,
209 pub scope: Option<String>,
211 pub internal: Option<bool>,
213 pub attachable: Option<bool>,
215 pub labels: BTreeMap<String, String>,
217}
218
219#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
221pub struct VolumeSummary {
222 pub host: HostId,
224 pub topology_revision: TopologyRevision,
226 pub name: String,
228 pub driver: String,
230 pub mountpoint: String,
232 pub scope: Option<String>,
234 pub labels: BTreeMap<String, String>,
236}
237
238#[async_trait]
240pub trait DockerSystemReader: Send + Sync {
241 async fn system_info(
243 &self,
244 host: &HostRecord,
245 cancellation: &CancellationToken,
246 ) -> InfraResult<DockerSystemInfo>;
247}
248
249#[async_trait]
251pub trait ContainerReader: Send + Sync {
252 async fn list_containers(
254 &self,
255 host: &HostRecord,
256 options: &ContainerListOptions,
257 cancellation: &CancellationToken,
258 ) -> InfraResult<Vec<ContainerSummary>>;
259
260 async fn inspect_container(
262 &self,
263 host: &HostRecord,
264 container: &str,
265 cancellation: &CancellationToken,
266 ) -> InfraResult<ContainerInspect>;
267
268 async fn top_container(
270 &self,
271 host: &HostRecord,
272 container: &str,
273 cancellation: &CancellationToken,
274 ) -> InfraResult<ContainerProcessTable>;
275}
276
277#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
279pub struct ContainerProcessTable {
280 pub host: HostId,
282 pub topology_revision: TopologyRevision,
284 pub container: String,
286 pub titles: Vec<String>,
288 pub processes: Vec<Vec<String>>,
290}
291
292#[async_trait]
294pub trait ImageReader: Send + Sync {
295 async fn list_images(
297 &self,
298 host: &HostRecord,
299 options: &ImageListOptions,
300 cancellation: &CancellationToken,
301 ) -> InfraResult<Vec<ImageSummary>>;
302}
303
304#[async_trait]
306pub trait NetworkReader: Send + Sync {
307 async fn list_networks(
309 &self,
310 host: &HostRecord,
311 cancellation: &CancellationToken,
312 ) -> InfraResult<Vec<NetworkSummary>>;
313}
314
315#[async_trait]
317pub trait VolumeReader: Send + Sync {
318 async fn list_volumes(
320 &self,
321 host: &HostRecord,
322 cancellation: &CancellationToken,
323 ) -> InfraResult<Vec<VolumeSummary>>;
324}
325
326#[cfg(test)]
327#[path = "docker_tests.rs"]
328mod tests;