stormchaser_runner_docker/container_machine/mod.rs
1//! Docker container execution state machine.
2
3use serde_json::Value;
4use std::collections::HashMap;
5use stormchaser_model::dsl::Step;
6
7/// Cryptographic utilities for container state encryption.
8pub mod crypto;
9/// Docker-specific helper utilities.
10pub mod docker_utils;
11/// State machine transitions for containers.
12pub mod transitions;
13
14use bollard::Docker;
15use serde::{Deserialize, Serialize};
16use uuid::Uuid;
17
18/// Metadata associated with a container executing a workflow step.
19#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct ContainerMetadata {
21 /// The unique identifier of the workflow run.
22 pub run_id: Uuid,
23 /// The unique identifier of the step being executed.
24 pub step_id: Uuid,
25 /// The step specification from the workflow DSL.
26 pub step_dsl: Step,
27 /// When the container task was received.
28 pub received_at: chrono::DateTime<chrono::Utc>,
29 /// Optional encryption key for secure state sharing.
30 pub encryption_key: Option<String>,
31 /// Optional storage mounts configured for the container.
32 pub storage: Option<HashMap<String, Value>>,
33 /// Optional URLs for uploading test reports.
34 pub test_report_urls: Option<HashMap<String, Value>>,
35}
36
37/// Metrics collected during or after the container's execution.
38#[derive(Debug, Clone, Serialize, Deserialize, Default)]
39pub struct ContainerMetrics {
40 /// The exit code of the container, if it has finished.
41 pub exit_code: Option<i64>,
42 /// How long the container ran in milliseconds.
43 pub duration_ms: u64,
44 /// How long the container took to start after being received, in milliseconds.
45 pub latency_ms: u64,
46 /// Hashes of the storage artifacts generated by the container.
47 pub storage_hashes: Option<HashMap<String, String>>,
48 /// Artifacts generated by the container.
49 pub artifacts: Option<HashMap<String, Value>>,
50 /// Test reports generated by the container.
51 pub test_reports: Option<Value>,
52}
53
54/// The final outcome state of the container.
55#[derive(Debug, Clone, Serialize, Deserialize)]
56pub enum ContainerState {
57 /// The container completed successfully.
58 Succeeded(ContainerMetrics),
59 /// The container failed with an error message and metrics.
60 Failed(String, ContainerMetrics),
61}
62
63/// The result of attempting to start the container.
64pub enum StartResult {
65 /// The container was successfully started.
66 Running(DockerContainerMachine<state::Running>),
67 /// The container failed to start.
68 #[allow(dead_code)]
69 Failed(DockerContainerMachine<state::Finished>),
70}
71
72/// State types for the container state machine.
73pub mod state {
74 /// The initial state before starting.
75 pub struct Initialized;
76 /// The state when the container is currently running.
77 pub struct Running {
78 /// The name of the Docker container.
79 pub container_name: String,
80 /// The time the container was dispatched to run.
81 pub dispatched_at: chrono::DateTime<chrono::Utc>,
82 /// Docker volumes that need to be cleaned up after execution.
83 pub volumes_to_cleanup: Vec<String>,
84 /// Names of the storage endpoints.
85 pub storage_names: Vec<String>,
86 /// The mounts configured for this container.
87 pub mounts: Vec<bollard::service::Mount>,
88 }
89 /// The state when the container has finished executing.
90 pub struct Finished {
91 /// The final result of the execution.
92 pub result: super::ContainerState,
93 }
94}
95
96/// The core state machine representing a Docker container's lifecycle.
97#[derive(Clone)]
98pub struct DockerContainerMachine<S> {
99 /// The NATS client used for messaging, if available.
100 pub nats: Option<async_nats::Client>,
101 /// The Docker client.
102 pub docker: Docker,
103 /// Metadata associated with this container execution.
104 pub metadata: ContainerMetadata,
105 /// The current state of the machine.
106 pub state: S,
107}
108
109impl DockerContainerMachine<state::Initialized> {
110 /// Creates a new, initialized container state machine.
111 pub fn new(
112 docker: Docker,
113 metadata: ContainerMetadata,
114 nats: Option<async_nats::Client>,
115 ) -> Self {
116 Self {
117 nats,
118 docker,
119 metadata,
120 state: state::Initialized,
121 }
122 }
123}