Skip to main content

soma_infra/
docker.rs

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/// Neutral Docker daemon information.
11#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12pub struct DockerSystemInfo {
13    /// Target host.
14    pub host: HostId,
15    /// Exact topology revision.
16    pub topology_revision: TopologyRevision,
17    /// Docker daemon identity.
18    pub daemon_id: Option<String>,
19    /// Daemon name.
20    pub name: Option<String>,
21    /// Server version.
22    pub server_version: Option<String>,
23    /// Operating-system description.
24    pub operating_system: Option<String>,
25    /// Architecture.
26    pub architecture: Option<String>,
27    /// Kernel version.
28    pub kernel_version: Option<String>,
29    /// Storage driver.
30    pub storage_driver: Option<String>,
31    /// Total containers known to the daemon.
32    pub containers: u64,
33    /// Running containers.
34    pub containers_running: u64,
35    /// Paused containers.
36    pub containers_paused: u64,
37    /// Stopped containers.
38    pub containers_stopped: u64,
39    /// Images known to the daemon.
40    pub images: u64,
41    /// Logical CPU count.
42    pub cpus: u64,
43    /// Total host memory reported by Docker.
44    pub memory_total_bytes: u64,
45}
46
47/// Closed container-list options.
48#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
49pub struct ContainerListOptions {
50    /// Include stopped containers.
51    pub all: bool,
52    /// Optional exact runtime-state filter.
53    pub state: Option<ContainerState>,
54    /// Optional Docker label selector.
55    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/// Neutral container runtime state.
69#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
70#[serde(rename_all = "snake_case")]
71pub enum ContainerState {
72    /// Created but not started.
73    Created,
74    /// Running.
75    Running,
76    /// Paused.
77    Paused,
78    /// Restarting.
79    Restarting,
80    /// Removing.
81    Removing,
82    /// Exited.
83    Exited,
84    /// Dead.
85    Dead,
86    /// Driver supplied an unrecognized state.
87    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/// Neutral Docker container summary.
107#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
108pub struct ContainerSummary {
109    /// Target host.
110    pub host: HostId,
111    /// Exact topology revision.
112    pub topology_revision: TopologyRevision,
113    /// Container ID.
114    pub id: Option<String>,
115    /// Container names without Docker's leading slash normalization requirement.
116    pub names: Vec<String>,
117    /// Configured image reference.
118    pub image: Option<String>,
119    /// Image content ID.
120    pub image_id: Option<String>,
121    /// Configured command.
122    pub command: Option<String>,
123    /// Creation time in Unix seconds.
124    pub created_unix_seconds: Option<i64>,
125    /// Runtime state.
126    pub state: ContainerState,
127    /// Engine status text.
128    pub status: Option<String>,
129    /// Container labels.
130    pub labels: BTreeMap<String, String>,
131}
132
133/// Selected neutral container inspection fields.
134#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
135pub struct ContainerInspect {
136    /// Target host.
137    pub host: HostId,
138    /// Exact topology revision.
139    pub topology_revision: TopologyRevision,
140    /// Container ID.
141    pub id: Option<String>,
142    /// Container name.
143    pub name: Option<String>,
144    /// Creation timestamp text reported by Docker.
145    pub created: Option<String>,
146    /// Executable path.
147    pub path: Option<String>,
148    /// Process arguments.
149    pub args: Vec<String>,
150    /// Image content ID.
151    pub image: Option<String>,
152    /// Current state.
153    pub state: ContainerState,
154    /// Process ID when running.
155    pub pid: Option<i64>,
156    /// Exit code when reported.
157    pub exit_code: Option<i64>,
158    /// Restart count.
159    pub restart_count: Option<i64>,
160    /// Config labels.
161    pub labels: BTreeMap<String, String>,
162}
163
164/// Closed image-list options.
165#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
166pub struct ImageListOptions {
167    /// Include intermediate images.
168    pub all: bool,
169    /// Return dangling images only.
170    pub dangling_only: bool,
171}
172
173/// Neutral Docker image summary.
174#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
175pub struct ImageSummary {
176    /// Target host.
177    pub host: HostId,
178    /// Exact topology revision.
179    pub topology_revision: TopologyRevision,
180    /// Image ID.
181    pub id: String,
182    /// Repository tags.
183    pub repo_tags: Vec<String>,
184    /// Repository digests.
185    pub repo_digests: Vec<String>,
186    /// Creation time in Unix seconds.
187    pub created_unix_seconds: i64,
188    /// Image size in bytes.
189    pub size_bytes: i64,
190    /// Number of containers referencing the image when reported.
191    pub containers: i64,
192    /// Image labels.
193    pub labels: BTreeMap<String, String>,
194}
195
196/// Neutral Docker network summary.
197#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
198pub struct NetworkSummary {
199    /// Target host.
200    pub host: HostId,
201    /// Exact topology revision.
202    pub topology_revision: TopologyRevision,
203    /// Network ID.
204    pub id: Option<String>,
205    /// Network name.
206    pub name: Option<String>,
207    /// Driver name.
208    pub driver: Option<String>,
209    /// Scope.
210    pub scope: Option<String>,
211    /// Whether the network is internal.
212    pub internal: Option<bool>,
213    /// Whether containers may attach manually.
214    pub attachable: Option<bool>,
215    /// Network labels.
216    pub labels: BTreeMap<String, String>,
217}
218
219/// Neutral Docker volume summary.
220#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
221pub struct VolumeSummary {
222    /// Target host.
223    pub host: HostId,
224    /// Exact topology revision.
225    pub topology_revision: TopologyRevision,
226    /// Volume name.
227    pub name: String,
228    /// Volume driver.
229    pub driver: String,
230    /// Host mountpoint.
231    pub mountpoint: String,
232    /// Volume scope.
233    pub scope: Option<String>,
234    /// Volume labels.
235    pub labels: BTreeMap<String, String>,
236}
237
238/// Docker system-level read operations.
239#[async_trait]
240pub trait DockerSystemReader: Send + Sync {
241    /// Reads Docker daemon information.
242    async fn system_info(
243        &self,
244        host: &HostRecord,
245        cancellation: &CancellationToken,
246    ) -> InfraResult<DockerSystemInfo>;
247}
248
249/// Docker container read operations.
250#[async_trait]
251pub trait ContainerReader: Send + Sync {
252    /// Lists containers.
253    async fn list_containers(
254        &self,
255        host: &HostRecord,
256        options: &ContainerListOptions,
257        cancellation: &CancellationToken,
258    ) -> InfraResult<Vec<ContainerSummary>>;
259
260    /// Inspects one container.
261    async fn inspect_container(
262        &self,
263        host: &HostRecord,
264        container: &str,
265        cancellation: &CancellationToken,
266    ) -> InfraResult<ContainerInspect>;
267
268    /// Returns one container process table.
269    async fn top_container(
270        &self,
271        host: &HostRecord,
272        container: &str,
273        cancellation: &CancellationToken,
274    ) -> InfraResult<ContainerProcessTable>;
275}
276
277/// Process table returned by Docker top.
278#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
279pub struct ContainerProcessTable {
280    /// Target host.
281    pub host: HostId,
282    /// Exact topology revision.
283    pub topology_revision: TopologyRevision,
284    /// Container identifier.
285    pub container: String,
286    /// Process column titles.
287    pub titles: Vec<String>,
288    /// Process value rows.
289    pub processes: Vec<Vec<String>>,
290}
291
292/// Docker image read operations.
293#[async_trait]
294pub trait ImageReader: Send + Sync {
295    /// Lists images.
296    async fn list_images(
297        &self,
298        host: &HostRecord,
299        options: &ImageListOptions,
300        cancellation: &CancellationToken,
301    ) -> InfraResult<Vec<ImageSummary>>;
302}
303
304/// Docker network read operations.
305#[async_trait]
306pub trait NetworkReader: Send + Sync {
307    /// Lists networks.
308    async fn list_networks(
309        &self,
310        host: &HostRecord,
311        cancellation: &CancellationToken,
312    ) -> InfraResult<Vec<NetworkSummary>>;
313}
314
315/// Docker volume read operations.
316#[async_trait]
317pub trait VolumeReader: Send + Sync {
318    /// Lists volumes.
319    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;