1use std::collections::HashMap;
4
5use chrono::{DateTime, Utc};
6
7use crate::state::WorkloadState;
8
9#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct DeployResult {
12 pub id: String,
14 pub name: String,
16 pub state: WorkloadState,
18}
19
20#[derive(Debug, Clone, Default, PartialEq, Eq)]
22pub struct WaitResult {
23 pub status_code: i64,
25 pub error: Option<String>,
27}
28
29#[derive(Debug, Clone, Default, PartialEq, Eq)]
31pub struct WorkloadStatus {
32 pub id: String,
34 pub name: String,
36 pub image: String,
38 pub state: WorkloadState,
40 pub running: bool,
42 pub healthy: bool,
44 pub ready: bool,
46 pub started_at: Option<DateTime<Utc>>,
48 pub stopped_at: Option<DateTime<Utc>>,
50 pub exit_code: Option<i32>,
52 pub message: String,
54 pub restarts: u32,
56}
57
58#[derive(Debug, Clone, PartialEq, Eq)]
60pub struct WorkloadInfo {
61 pub id: String,
63 pub name: String,
65 pub image: String,
67 pub state: WorkloadState,
69 pub labels: HashMap<String, String>,
71 pub created: DateTime<Utc>,
73 pub namespace: String,
75}
76
77#[derive(Debug, Clone, Default, PartialEq)]
79pub struct WorkloadStats {
80 pub cpu_percent: f64,
82 pub memory_usage: i64,
84 pub memory_limit: i64,
86 pub network_rx_bytes: i64,
88 pub network_tx_bytes: i64,
90 pub disk_read_bytes: i64,
92 pub disk_write_bytes: i64,
94 pub pids: i64,
96}
97
98#[derive(Debug, Clone, PartialEq, Eq)]
100pub struct WorkloadEvent {
101 pub id: String,
103 pub name: String,
105 pub event: String,
107 pub timestamp: DateTime<Utc>,
109 pub message: String,
111}
112
113#[derive(Debug, Clone, Default, PartialEq, Eq)]
115pub struct ExecResult {
116 pub exit_code: i32,
118 pub stdout: String,
120 pub stderr: String,
122}
123
124#[derive(Debug, Clone, Default, PartialEq, Eq)]
126pub struct SystemInfo {
127 pub os: String,
129 pub architecture: String,
131 pub total_memory_mb: i64,
133 pub cpus: u32,
135 pub storage_driver: String,
137 pub runtime_version: String,
139 pub kernel_version: String,
141 pub operating_system: String,
143 pub gpus: Vec<GpuInfo>,
145}
146
147#[derive(Debug, Clone, Default, PartialEq, Eq)]
149pub struct GpuInfo {
150 pub name: String,
152 pub memory_mb: i64,
154 pub driver_version: String,
156}
157
158#[derive(Debug, Clone, Default, PartialEq, Eq)]
160pub struct DiskUsage {
161 pub images_size: i64,
163 pub containers_size: i64,
165 pub volumes_size: i64,
167 pub build_cache_size: i64,
169 pub data_root_path: String,
171 pub data_root_total: i64,
173 pub data_root_free: i64,
175 pub images: Vec<ImageDiskEntry>,
177}
178
179#[derive(Debug, Clone, PartialEq, Eq)]
181pub struct ImageDiskEntry {
182 pub id: String,
184 pub repo_tags: Vec<String>,
186 pub size: i64,
188 pub shared_size: i64,
190 pub created: DateTime<Utc>,
192}
193
194#[derive(Debug, Clone, PartialEq, Eq)]
196pub struct ImageDetail {
197 pub id: String,
199 pub repo_tags: Vec<String>,
201 pub repo_digests: Vec<String>,
203 pub size: i64,
205 pub architecture: String,
207 pub os: String,
209 pub created: DateTime<Utc>,
211 pub config: ImageConfig,
213 pub layers: Vec<String>,
215}
216
217#[derive(Debug, Clone, Default, PartialEq, Eq)]
219pub struct ImageConfig {
220 pub env: Vec<String>,
222 pub labels: HashMap<String, String>,
224 pub cmd: Vec<String>,
226 pub entrypoint: Vec<String>,
228}
229
230#[derive(Debug, Clone, PartialEq, Eq)]
232pub struct ImageEvent {
233 pub action: String,
235 pub image_ref: String,
237 pub image_id: String,
239 pub timestamp: DateTime<Utc>,
241}
242
243#[cfg(test)]
244mod tests {
245 use super::*;
246
247 #[test]
248 fn status_default_state_is_unknown() {
249 let status = WorkloadStatus::default();
250 assert_eq!(status.state, WorkloadState::Unknown);
251 assert!(status.started_at.is_none());
252 assert!(status.exit_code.is_none());
253 }
254
255 #[test]
256 fn deploy_result_carries_initial_state() {
257 let result = DeployResult {
258 id: "abc123".into(),
259 name: "api".into(),
260 state: WorkloadState::Running,
261 };
262 assert!(result.state.is_running());
263 }
264
265 #[test]
266 fn wait_result_default_is_success() {
267 let result = WaitResult::default();
268 assert_eq!(result.status_code, 0);
269 assert!(result.error.is_none());
270 }
271
272 #[test]
273 fn system_info_default_is_empty() {
274 let info = SystemInfo::default();
275 assert_eq!(info.cpus, 0);
276 assert!(info.gpus.is_empty());
277 }
278
279 #[test]
280 fn disk_usage_carries_image_breakdown() {
281 let usage = DiskUsage {
282 images_size: 2048,
283 images: vec![ImageDiskEntry {
284 id: "img1".into(),
285 repo_tags: vec!["nginx:latest".into()],
286 size: 1024,
287 shared_size: 512,
288 created: Utc::now(),
289 }],
290 ..Default::default()
291 };
292 assert_eq!(usage.images.len(), 1);
293 assert_eq!(usage.images[0].size, 1024);
294 }
295
296 #[test]
297 fn image_detail_holds_config_and_layers() {
298 let detail = ImageDetail {
299 id: "img1".into(),
300 repo_tags: vec!["nginx:latest".into()],
301 repo_digests: Vec::new(),
302 size: 4096,
303 architecture: "amd64".into(),
304 os: "linux".into(),
305 created: Utc::now(),
306 config: ImageConfig {
307 env: vec!["PATH=/usr/bin".into()],
308 ..Default::default()
309 },
310 layers: vec!["sha256:layer".into()],
311 };
312 assert_eq!(detail.config.env.len(), 1);
313 assert_eq!(detail.layers.len(), 1);
314 }
315
316 #[test]
317 fn image_event_records_action() {
318 let event = ImageEvent {
319 action: "pull".into(),
320 image_ref: "nginx:latest".into(),
321 image_id: "sha256:abc".into(),
322 timestamp: Utc::now(),
323 };
324 assert_eq!(event.action, "pull");
325 }
326
327 #[test]
328 fn gpu_info_default_is_empty() {
329 assert_eq!(GpuInfo::default().memory_mb, 0);
330 }
331}