Skip to main content

ironflow_ops_docker/system/
mod.rs

1//! System operations: info, version, ping, df, prune.
2
3use async_trait::async_trait;
4use bollard::Docker;
5use ironflow_core::error::OperationError;
6use ironflow_core::operation::{Operation, OperationContext, TypedOperation};
7use serde::{Deserialize, Serialize};
8use serde_json::Value;
9
10use crate::containers::DockerRef;
11use crate::helpers::{docker_error, to_value};
12
13// ---------------------------------------------------------------------------
14// SystemInfo
15// ---------------------------------------------------------------------------
16
17/// Output of system info.
18#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct SystemInfoOutput {
20    /// The full system info as JSON.
21    pub data: Value,
22}
23
24/// Get system-wide information from the Docker daemon.
25///
26/// # Examples
27///
28/// ```no_run
29/// use ironflow_ops_docker::system::SystemInfo;
30/// use ironflow_ops_docker::DockerClient;
31/// use ironflow_core::operation::Operation;
32///
33/// let client = DockerClient::connect_local().unwrap();
34/// let op = SystemInfo::new(&client);
35/// assert_eq!(op.kind(), "docker");
36/// ```
37pub struct SystemInfo {
38    docker: Docker,
39}
40
41impl SystemInfo {
42    /// Create a new system-info operation.
43    pub fn new(client: impl Into<DockerRef>) -> Self {
44        Self {
45            docker: client.into().0,
46        }
47    }
48
49    /// Execute and return a typed result.
50    ///
51    /// # Errors
52    ///
53    /// Returns [`OperationError::External`] if the Docker daemon is
54    /// unreachable.
55    pub async fn run(&self, _ctx: &OperationContext) -> Result<SystemInfoOutput, OperationError> {
56        let info = self.docker.info().await.map_err(docker_error)?;
57        let data = serde_json::to_value(&info).map_err(|e| OperationError::External {
58            origin: "docker".to_string(),
59            message: e.to_string(),
60        })?;
61        Ok(SystemInfoOutput { data })
62    }
63}
64
65#[async_trait]
66impl Operation for SystemInfo {
67    fn kind(&self) -> &str {
68        "docker"
69    }
70
71    async fn execute(&self, ctx: &OperationContext) -> Result<Value, OperationError> {
72        to_value(&self.run(ctx).await?)
73    }
74
75    fn input(&self) -> Option<Value> {
76        Some(serde_json::json!({ "operation": "system_info" }))
77    }
78}
79
80impl TypedOperation for SystemInfo {
81    type Output = SystemInfoOutput;
82}
83
84// ---------------------------------------------------------------------------
85// SystemVersion
86// ---------------------------------------------------------------------------
87
88/// Output of system version.
89#[derive(Debug, Clone, Serialize, Deserialize)]
90pub struct SystemVersionOutput {
91    /// The full version info as JSON.
92    pub data: Value,
93}
94
95/// Get version information from the Docker daemon.
96///
97/// # Examples
98///
99/// ```no_run
100/// use ironflow_ops_docker::system::SystemVersion;
101/// use ironflow_ops_docker::DockerClient;
102/// use ironflow_core::operation::Operation;
103///
104/// let client = DockerClient::connect_local().unwrap();
105/// let op = SystemVersion::new(&client);
106/// assert_eq!(op.kind(), "docker");
107/// ```
108pub struct SystemVersion {
109    docker: Docker,
110}
111
112impl SystemVersion {
113    /// Create a new system-version operation.
114    pub fn new(client: impl Into<DockerRef>) -> Self {
115        Self {
116            docker: client.into().0,
117        }
118    }
119
120    /// Execute and return a typed result.
121    ///
122    /// # Errors
123    ///
124    /// Returns [`OperationError::External`] if the Docker daemon is
125    /// unreachable.
126    pub async fn run(
127        &self,
128        _ctx: &OperationContext,
129    ) -> Result<SystemVersionOutput, OperationError> {
130        let version = self.docker.version().await.map_err(docker_error)?;
131        let data = serde_json::to_value(&version).map_err(|e| OperationError::External {
132            origin: "docker".to_string(),
133            message: e.to_string(),
134        })?;
135        Ok(SystemVersionOutput { data })
136    }
137}
138
139#[async_trait]
140impl Operation for SystemVersion {
141    fn kind(&self) -> &str {
142        "docker"
143    }
144
145    async fn execute(&self, ctx: &OperationContext) -> Result<Value, OperationError> {
146        to_value(&self.run(ctx).await?)
147    }
148
149    fn input(&self) -> Option<Value> {
150        Some(serde_json::json!({ "operation": "system_version" }))
151    }
152}
153
154impl TypedOperation for SystemVersion {
155    type Output = SystemVersionOutput;
156}
157
158// ---------------------------------------------------------------------------
159// SystemPing
160// ---------------------------------------------------------------------------
161
162/// Output of a system ping.
163#[derive(Debug, Clone, Serialize, Deserialize)]
164pub struct SystemPingOutput {
165    /// The ping response (typically "OK").
166    pub response: String,
167}
168
169/// Ping the Docker daemon.
170///
171/// # Examples
172///
173/// ```no_run
174/// use ironflow_ops_docker::system::SystemPing;
175/// use ironflow_ops_docker::DockerClient;
176/// use ironflow_core::operation::Operation;
177///
178/// let client = DockerClient::connect_local().unwrap();
179/// let op = SystemPing::new(&client);
180/// assert_eq!(op.kind(), "docker");
181/// ```
182pub struct SystemPing {
183    docker: Docker,
184}
185
186impl SystemPing {
187    /// Create a new system-ping operation.
188    pub fn new(client: impl Into<DockerRef>) -> Self {
189        Self {
190            docker: client.into().0,
191        }
192    }
193
194    /// Execute and return a typed result.
195    ///
196    /// # Errors
197    ///
198    /// Returns [`OperationError::External`] if the Docker daemon is
199    /// unreachable.
200    pub async fn run(&self, _ctx: &OperationContext) -> Result<SystemPingOutput, OperationError> {
201        let response = self.docker.ping().await.map_err(docker_error)?;
202        Ok(SystemPingOutput { response })
203    }
204}
205
206#[async_trait]
207impl Operation for SystemPing {
208    fn kind(&self) -> &str {
209        "docker"
210    }
211
212    async fn execute(&self, ctx: &OperationContext) -> Result<Value, OperationError> {
213        to_value(&self.run(ctx).await?)
214    }
215
216    fn input(&self) -> Option<Value> {
217        Some(serde_json::json!({ "operation": "system_ping" }))
218    }
219}
220
221impl TypedOperation for SystemPing {
222    type Output = SystemPingOutput;
223}
224
225// ---------------------------------------------------------------------------
226// SystemDf
227// ---------------------------------------------------------------------------
228
229/// Output of system disk usage.
230#[derive(Debug, Clone, Serialize, Deserialize)]
231pub struct SystemDfOutput {
232    /// The full disk usage data as JSON.
233    pub data: Value,
234}
235
236/// Get disk usage information from the Docker daemon.
237///
238/// # Examples
239///
240/// ```no_run
241/// use ironflow_ops_docker::system::SystemDf;
242/// use ironflow_ops_docker::DockerClient;
243/// use ironflow_core::operation::Operation;
244///
245/// let client = DockerClient::connect_local().unwrap();
246/// let op = SystemDf::new(&client);
247/// assert_eq!(op.kind(), "docker");
248/// ```
249pub struct SystemDf {
250    docker: Docker,
251}
252
253impl SystemDf {
254    /// Create a new system-df operation.
255    pub fn new(client: impl Into<DockerRef>) -> Self {
256        Self {
257            docker: client.into().0,
258        }
259    }
260
261    /// Execute and return a typed result.
262    ///
263    /// # Errors
264    ///
265    /// Returns [`OperationError::External`] if the Docker daemon is
266    /// unreachable.
267    pub async fn run(&self, _ctx: &OperationContext) -> Result<SystemDfOutput, OperationError> {
268        let df = self
269            .docker
270            .df(None::<bollard::query_parameters::DataUsageOptions>)
271            .await
272            .map_err(docker_error)?;
273        let data = serde_json::to_value(&df).map_err(|e| OperationError::External {
274            origin: "docker".to_string(),
275            message: e.to_string(),
276        })?;
277        Ok(SystemDfOutput { data })
278    }
279}
280
281#[async_trait]
282impl Operation for SystemDf {
283    fn kind(&self) -> &str {
284        "docker"
285    }
286
287    async fn execute(&self, ctx: &OperationContext) -> Result<Value, OperationError> {
288        to_value(&self.run(ctx).await?)
289    }
290
291    fn input(&self) -> Option<Value> {
292        Some(serde_json::json!({ "operation": "system_df" }))
293    }
294}
295
296impl TypedOperation for SystemDf {
297    type Output = SystemDfOutput;
298}