Skip to main content

zlayer_types/api/
deployments.rs

1//! Deployment DTOs.
2
3use serde::{Deserialize, Serialize};
4
5/// Deployment summary
6#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
7pub struct DeploymentSummary {
8    /// Deployment name
9    pub name: String,
10    /// Deployment status
11    pub status: String,
12    /// Number of services
13    pub service_count: usize,
14    /// Created timestamp
15    pub created_at: String,
16}
17
18/// Per-service health info included in deployment details
19#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
20pub struct ServiceHealthInfo {
21    /// Service name
22    pub name: String,
23    /// Running replica count
24    pub replicas_running: u32,
25    /// Desired replica count
26    pub replicas_desired: u32,
27    /// Health status ("healthy", "unhealthy", "unknown")
28    pub health: String,
29    /// Endpoint URLs for this service
30    pub endpoints: Vec<String>,
31}
32
33/// Deployment details (enhanced with per-service health and endpoints)
34#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
35pub struct DeploymentDetails {
36    /// Deployment name
37    pub name: String,
38    /// Deployment status
39    pub status: String,
40    /// Service names (for backwards compatibility)
41    pub services: Vec<String>,
42    /// Per-service health and endpoint info
43    pub service_health: Vec<ServiceHealthInfo>,
44    /// Created timestamp
45    pub created_at: String,
46    /// Updated timestamp
47    pub updated_at: String,
48}
49
50/// Create deployment request
51#[derive(Debug, Deserialize, utoipa::ToSchema)]
52pub struct CreateDeploymentRequest {
53    /// Deployment specification (YAML content)
54    pub spec: String,
55}
56
57/// Deployment progress event sent over SSE during orchestration.
58#[derive(Debug, Clone, Serialize)]
59#[serde(tag = "kind", rename_all = "snake_case")]
60pub enum DeploymentProgressEvent {
61    /// Deployment orchestration has started
62    Started {
63        /// Deployment name
64        deployment: String,
65        /// List of services being deployed
66        services: Vec<String>,
67    },
68    /// A service was successfully registered with the service manager
69    ServiceRegistered {
70        /// Service name
71        service: String,
72    },
73    /// A service failed to register
74    ServiceRegistrationFailed {
75        /// Service name
76        service: String,
77        /// Error message
78        error: String,
79    },
80    /// Overlay network created for a service
81    OverlayCreated {
82        /// Service name
83        service: String,
84        /// Network interface name
85        interface: String,
86    },
87    /// Overlay creation failed (non-fatal)
88    OverlayFailed {
89        /// Service name
90        service: String,
91        /// Error message
92        error: String,
93    },
94    /// Proxy routes configured for a service
95    ProxyConfigured {
96        /// Service name
97        service: String,
98    },
99    /// Proxy configuration failed (non-fatal)
100    ProxyFailed {
101        /// Service name
102        service: String,
103        /// Error message
104        error: String,
105    },
106    /// Service scaling has started
107    ServiceScaling {
108        /// Service name
109        service: String,
110        /// Target replica count
111        target: u32,
112    },
113    /// Service successfully scaled
114    ServiceScaled {
115        /// Service name
116        service: String,
117        /// Number of replicas running
118        replicas: u32,
119    },
120    /// Service scaling failed
121    ServiceScaleFailed {
122        /// Service name
123        service: String,
124        /// Error message
125        error: String,
126    },
127    /// Waiting for stabilization
128    Stabilizing,
129    /// Service registration is about to begin
130    ServiceRegistrationStarted {
131        /// Service name
132        service: String,
133    },
134    /// Overlay network setup is about to begin
135    OverlaySetupStarted {
136        /// Service name
137        service: String,
138    },
139    /// Proxy setup is about to begin
140    ProxySetupStarted {
141        /// Service name
142        service: String,
143    },
144    /// Periodic stabilization progress update
145    StabilizationProgress {
146        /// Service name
147        service: String,
148        /// Number of replicas currently running
149        replicas_running: u32,
150        /// Target replica count
151        target: u32,
152    },
153    /// Image pull is about to begin
154    ImagePullStarted {
155        /// Image reference
156        image: String,
157    },
158    /// Image pull completed
159    ImagePullComplete {
160        /// Image reference
161        image: String,
162        /// Resolved image digest
163        digest: String,
164    },
165    /// Re-deploy detected no digest drift; service is up-to-date and skipped
166    ServiceUpToDate {
167        /// Service name
168        service: String,
169        /// Image digest
170        digest: String,
171    },
172    /// Re-deploy detected drift; service is being recreated
173    ServiceRecreating {
174        /// Service name
175        service: String,
176        /// Previous image digest
177        old_digest: String,
178        /// New image digest
179        new_digest: String,
180    },
181    /// Deployment is ready and running
182    Ready,
183    /// Deployment failed
184    Failed {
185        /// Error message describing the failure
186        message: String,
187    },
188}
189
190/// Wrapper for serializing deployment progress events as SSE.
191///
192/// Converts each [`DeploymentProgressEvent`] variant into an `event_type` string
193/// and a JSON `data` payload, following the same pattern as `BuildEventWrapper`.
194#[derive(Debug, Clone, Serialize)]
195pub struct DeploymentEventWrapper {
196    /// SSE event type (used as the `event:` field)
197    #[serde(rename = "type")]
198    pub event_type: String,
199    /// JSON data payload
200    pub data: serde_json::Value,
201}
202
203impl From<DeploymentProgressEvent> for DeploymentEventWrapper {
204    #[allow(clippy::too_many_lines)]
205    fn from(event: DeploymentProgressEvent) -> Self {
206        match event {
207            DeploymentProgressEvent::Started {
208                deployment,
209                services,
210            } => DeploymentEventWrapper {
211                event_type: "started".to_string(),
212                data: serde_json::json!({
213                    "deployment": deployment,
214                    "services": services,
215                }),
216            },
217            DeploymentProgressEvent::ServiceRegistered { service } => DeploymentEventWrapper {
218                event_type: "service_registered".to_string(),
219                data: serde_json::json!({ "service": service }),
220            },
221            DeploymentProgressEvent::ServiceRegistrationFailed { service, error } => {
222                DeploymentEventWrapper {
223                    event_type: "service_registration_failed".to_string(),
224                    data: serde_json::json!({ "service": service, "error": error }),
225                }
226            }
227            DeploymentProgressEvent::OverlayCreated { service, interface } => {
228                DeploymentEventWrapper {
229                    event_type: "overlay_created".to_string(),
230                    data: serde_json::json!({ "service": service, "interface": interface }),
231                }
232            }
233            DeploymentProgressEvent::OverlayFailed { service, error } => DeploymentEventWrapper {
234                event_type: "overlay_failed".to_string(),
235                data: serde_json::json!({ "service": service, "error": error }),
236            },
237            DeploymentProgressEvent::ProxyConfigured { service } => DeploymentEventWrapper {
238                event_type: "proxy_configured".to_string(),
239                data: serde_json::json!({ "service": service }),
240            },
241            DeploymentProgressEvent::ProxyFailed { service, error } => DeploymentEventWrapper {
242                event_type: "proxy_failed".to_string(),
243                data: serde_json::json!({ "service": service, "error": error }),
244            },
245            DeploymentProgressEvent::ServiceScaling { service, target } => DeploymentEventWrapper {
246                event_type: "service_scaling".to_string(),
247                data: serde_json::json!({ "service": service, "target": target }),
248            },
249            DeploymentProgressEvent::ServiceScaled { service, replicas } => {
250                DeploymentEventWrapper {
251                    event_type: "service_scaled".to_string(),
252                    data: serde_json::json!({ "service": service, "replicas": replicas }),
253                }
254            }
255            DeploymentProgressEvent::ServiceScaleFailed { service, error } => {
256                DeploymentEventWrapper {
257                    event_type: "service_scale_failed".to_string(),
258                    data: serde_json::json!({ "service": service, "error": error }),
259                }
260            }
261            DeploymentProgressEvent::Stabilizing => DeploymentEventWrapper {
262                event_type: "stabilizing".to_string(),
263                data: serde_json::json!({}),
264            },
265            DeploymentProgressEvent::ServiceRegistrationStarted { service } => {
266                DeploymentEventWrapper {
267                    event_type: "service_registration_started".to_string(),
268                    data: serde_json::json!({ "service": service }),
269                }
270            }
271            DeploymentProgressEvent::OverlaySetupStarted { service } => DeploymentEventWrapper {
272                event_type: "overlay_setup_started".to_string(),
273                data: serde_json::json!({ "service": service }),
274            },
275            DeploymentProgressEvent::ProxySetupStarted { service } => DeploymentEventWrapper {
276                event_type: "proxy_setup_started".to_string(),
277                data: serde_json::json!({ "service": service }),
278            },
279            DeploymentProgressEvent::StabilizationProgress {
280                service,
281                replicas_running,
282                target,
283            } => DeploymentEventWrapper {
284                event_type: "stabilization_progress".to_string(),
285                data: serde_json::json!({
286                    "service": service,
287                    "replicas_running": replicas_running,
288                    "target": target,
289                }),
290            },
291            DeploymentProgressEvent::ImagePullStarted { image } => DeploymentEventWrapper {
292                event_type: "image_pull_started".to_string(),
293                data: serde_json::json!({ "image": image }),
294            },
295            DeploymentProgressEvent::ImagePullComplete { image, digest } => {
296                DeploymentEventWrapper {
297                    event_type: "image_pull_complete".to_string(),
298                    data: serde_json::json!({ "image": image, "digest": digest }),
299                }
300            }
301            DeploymentProgressEvent::ServiceUpToDate { service, digest } => {
302                DeploymentEventWrapper {
303                    event_type: "service_up_to_date".to_string(),
304                    data: serde_json::json!({ "service": service, "digest": digest }),
305                }
306            }
307            DeploymentProgressEvent::ServiceRecreating {
308                service,
309                old_digest,
310                new_digest,
311            } => DeploymentEventWrapper {
312                event_type: "service_recreating".to_string(),
313                data: serde_json::json!({
314                    "service": service,
315                    "old_digest": old_digest,
316                    "new_digest": new_digest,
317                }),
318            },
319            DeploymentProgressEvent::Ready => DeploymentEventWrapper {
320                event_type: "ready".to_string(),
321                data: serde_json::json!({}),
322            },
323            DeploymentProgressEvent::Failed { message } => DeploymentEventWrapper {
324                event_type: "failed".to_string(),
325                data: serde_json::json!({ "message": message }),
326            },
327        }
328    }
329}