Skip to main content

zlayer_types/api/
services.rs

1//! Service endpoint DTOs.
2
3use serde::{Deserialize, Serialize};
4
5use utoipa::IntoParams;
6
7/// Service summary
8#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
9pub struct ServiceSummary {
10    /// Service name
11    pub name: String,
12    /// Deployment name
13    pub deployment: String,
14    /// Service status
15    pub status: String,
16    /// Current replica count
17    pub replicas: u32,
18    /// Desired replica count
19    pub desired_replicas: u32,
20    /// Service endpoints
21    pub endpoints: Vec<ServiceEndpoint>,
22}
23
24/// Service details
25#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
26pub struct ServiceDetails {
27    /// Service name
28    pub name: String,
29    /// Deployment name
30    pub deployment: String,
31    /// Service status
32    pub status: String,
33    /// Current replica count
34    pub replicas: u32,
35    /// Desired replica count
36    pub desired_replicas: u32,
37    /// Service endpoints
38    pub endpoints: Vec<ServiceEndpoint>,
39    /// Service metrics
40    pub metrics: ServiceMetrics,
41}
42
43/// Service endpoint
44#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
45pub struct ServiceEndpoint {
46    /// Endpoint name
47    pub name: String,
48    /// Protocol
49    pub protocol: String,
50    /// Port
51    pub port: u16,
52    /// URL (if public)
53    pub url: Option<String>,
54}
55
56/// Service metrics
57#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
58pub struct ServiceMetrics {
59    /// CPU usage percentage
60    pub cpu_percent: f64,
61    /// Memory usage percentage
62    pub memory_percent: f64,
63    /// Requests per second
64    pub rps: Option<f64>,
65}
66
67/// Scale request
68#[derive(Debug, Deserialize, utoipa::ToSchema)]
69pub struct ScaleRequest {
70    /// Target replica count
71    pub replicas: u32,
72}
73
74/// Log query parameters
75#[derive(Debug, Deserialize, IntoParams)]
76pub struct LogQuery {
77    /// Number of lines to return
78    #[serde(default = "default_lines")]
79    pub lines: u32,
80    /// Follow logs (streaming)
81    #[serde(default)]
82    pub follow: bool,
83    /// Filter by container/instance
84    pub instance: Option<String>,
85}
86
87fn default_lines() -> u32 {
88    100
89}
90
91/// Container summary for API responses
92#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
93pub struct ContainerSummary {
94    /// Container identifier (service-rep-N)
95    pub id: String,
96    /// Service name
97    pub service: String,
98    /// Replica number
99    pub replica: u32,
100    /// Container state
101    pub state: String,
102    /// Process ID (if running)
103    pub pid: Option<u32>,
104    /// Overlay IP (if assigned)
105    pub overlay_ip: Option<String>,
106}
107
108/// Exec request body
109#[derive(Debug, Deserialize, utoipa::ToSchema)]
110pub struct ExecRequest {
111    /// Command and arguments to execute
112    pub command: Vec<String>,
113    /// Optional replica number to target
114    #[serde(default)]
115    pub replica: Option<u32>,
116}
117
118/// Exec response body
119#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
120pub struct ExecResponse {
121    /// Exit code from the command
122    pub exit_code: i32,
123    /// Standard output
124    pub stdout: String,
125    /// Standard error
126    pub stderr: String,
127}
128
129#[cfg(test)]
130mod tests {
131    use super::*;
132
133    #[test]
134    fn test_service_summary_serialize() {
135        let summary = ServiceSummary {
136            name: "api".to_string(),
137            deployment: "my-app".to_string(),
138            status: "running".to_string(),
139            replicas: 3,
140            desired_replicas: 3,
141            endpoints: vec![ServiceEndpoint {
142                name: "http".to_string(),
143                protocol: "http".to_string(),
144                port: 8080,
145                url: None,
146            }],
147        };
148        let json = serde_json::to_string(&summary).unwrap();
149        assert!(json.contains("api"));
150        assert!(json.contains("my-app"));
151    }
152
153    #[test]
154    fn test_scale_request_deserialize() {
155        let json = r#"{"replicas": 5}"#;
156        let request: ScaleRequest = serde_json::from_str(json).unwrap();
157        assert_eq!(request.replicas, 5);
158    }
159
160    #[test]
161    fn test_log_query_defaults() {
162        let query: LogQuery = serde_json::from_str("{}").unwrap();
163        assert_eq!(query.lines, 100);
164        assert!(!query.follow);
165        assert!(query.instance.is_none());
166    }
167}