Skip to main content

talos_api_rs/resources/
services.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3//! Typed wrappers for Service management APIs.
4//!
5//! Provides functionality to start, stop, restart, and monitor Talos services.
6
7use crate::api::generated::machine::{
8    ServiceRestart as ProtoServiceRestart, ServiceRestartRequest as ProtoServiceRestartRequest,
9    ServiceRestartResponse as ProtoServiceRestartResponse, ServiceStart as ProtoServiceStart,
10    ServiceStartRequest as ProtoServiceStartRequest,
11    ServiceStartResponse as ProtoServiceStartResponse, ServiceStop as ProtoServiceStop,
12    ServiceStopRequest as ProtoServiceStopRequest, ServiceStopResponse as ProtoServiceStopResponse,
13};
14
15// =============================================================================
16// ServiceStart
17// =============================================================================
18
19/// Request to start a service.
20#[derive(Debug, Clone)]
21pub struct ServiceStartRequest {
22    /// Service ID to start.
23    pub id: String,
24}
25
26impl ServiceStartRequest {
27    /// Create a new request to start a service.
28    #[must_use]
29    pub fn new(id: impl Into<String>) -> Self {
30        Self { id: id.into() }
31    }
32}
33
34impl From<ServiceStartRequest> for ProtoServiceStartRequest {
35    fn from(req: ServiceStartRequest) -> Self {
36        Self { id: req.id }
37    }
38}
39
40/// Result from starting a service.
41#[derive(Debug, Clone)]
42pub struct ServiceStartResult {
43    /// Node that processed the request.
44    pub node: Option<String>,
45    /// Response message.
46    pub response: String,
47}
48
49impl From<ProtoServiceStart> for ServiceStartResult {
50    fn from(proto: ProtoServiceStart) -> Self {
51        Self {
52            node: proto.metadata.map(|m| m.hostname),
53            response: proto.resp,
54        }
55    }
56}
57
58/// Response from starting a service.
59#[derive(Debug, Clone)]
60pub struct ServiceStartResponse {
61    /// Results from each node.
62    pub results: Vec<ServiceStartResult>,
63}
64
65impl From<ProtoServiceStartResponse> for ServiceStartResponse {
66    fn from(proto: ProtoServiceStartResponse) -> Self {
67        Self {
68            results: proto
69                .messages
70                .into_iter()
71                .map(ServiceStartResult::from)
72                .collect(),
73        }
74    }
75}
76
77impl ServiceStartResponse {
78    /// Check if the operation was successful.
79    #[must_use]
80    pub fn is_success(&self) -> bool {
81        !self.results.is_empty()
82    }
83}
84
85// =============================================================================
86// ServiceStop
87// =============================================================================
88
89/// Request to stop a service.
90#[derive(Debug, Clone)]
91pub struct ServiceStopRequest {
92    /// Service ID to stop.
93    pub id: String,
94}
95
96impl ServiceStopRequest {
97    /// Create a new request to stop a service.
98    #[must_use]
99    pub fn new(id: impl Into<String>) -> Self {
100        Self { id: id.into() }
101    }
102}
103
104impl From<ServiceStopRequest> for ProtoServiceStopRequest {
105    fn from(req: ServiceStopRequest) -> Self {
106        Self { id: req.id }
107    }
108}
109
110/// Result from stopping a service.
111#[derive(Debug, Clone)]
112pub struct ServiceStopResult {
113    /// Node that processed the request.
114    pub node: Option<String>,
115    /// Response message.
116    pub response: String,
117}
118
119impl From<ProtoServiceStop> for ServiceStopResult {
120    fn from(proto: ProtoServiceStop) -> Self {
121        Self {
122            node: proto.metadata.map(|m| m.hostname),
123            response: proto.resp,
124        }
125    }
126}
127
128/// Response from stopping a service.
129#[derive(Debug, Clone)]
130pub struct ServiceStopResponse {
131    /// Results from each node.
132    pub results: Vec<ServiceStopResult>,
133}
134
135impl From<ProtoServiceStopResponse> for ServiceStopResponse {
136    fn from(proto: ProtoServiceStopResponse) -> Self {
137        Self {
138            results: proto
139                .messages
140                .into_iter()
141                .map(ServiceStopResult::from)
142                .collect(),
143        }
144    }
145}
146
147impl ServiceStopResponse {
148    /// Check if the operation was successful.
149    #[must_use]
150    pub fn is_success(&self) -> bool {
151        !self.results.is_empty()
152    }
153}
154
155// =============================================================================
156// ServiceRestart
157// =============================================================================
158
159/// Request to restart a service.
160#[derive(Debug, Clone)]
161pub struct ServiceRestartRequest {
162    /// Service ID to restart.
163    pub id: String,
164}
165
166impl ServiceRestartRequest {
167    /// Create a new request to restart a service.
168    #[must_use]
169    pub fn new(id: impl Into<String>) -> Self {
170        Self { id: id.into() }
171    }
172}
173
174impl From<ServiceRestartRequest> for ProtoServiceRestartRequest {
175    fn from(req: ServiceRestartRequest) -> Self {
176        Self { id: req.id }
177    }
178}
179
180/// Result from restarting a service.
181#[derive(Debug, Clone)]
182pub struct ServiceRestartResult {
183    /// Node that processed the request.
184    pub node: Option<String>,
185    /// Response message.
186    pub response: String,
187}
188
189impl From<ProtoServiceRestart> for ServiceRestartResult {
190    fn from(proto: ProtoServiceRestart) -> Self {
191        Self {
192            node: proto.metadata.map(|m| m.hostname),
193            response: proto.resp,
194        }
195    }
196}
197
198/// Response from restarting a service.
199#[derive(Debug, Clone)]
200pub struct ServiceRestartResponse {
201    /// Results from each node.
202    pub results: Vec<ServiceRestartResult>,
203}
204
205impl From<ProtoServiceRestartResponse> for ServiceRestartResponse {
206    fn from(proto: ProtoServiceRestartResponse) -> Self {
207        Self {
208            results: proto
209                .messages
210                .into_iter()
211                .map(ServiceRestartResult::from)
212                .collect(),
213        }
214    }
215}
216
217impl ServiceRestartResponse {
218    /// Check if the operation was successful.
219    #[must_use]
220    pub fn is_success(&self) -> bool {
221        !self.results.is_empty()
222    }
223}
224
225#[cfg(test)]
226mod tests {
227    use super::*;
228
229    #[test]
230    fn test_service_start_request() {
231        let req = ServiceStartRequest::new("kubelet");
232        assert_eq!(req.id, "kubelet");
233
234        let proto: ProtoServiceStartRequest = req.into();
235        assert_eq!(proto.id, "kubelet");
236    }
237
238    #[test]
239    fn test_service_stop_request() {
240        let req = ServiceStopRequest::new("containerd");
241        assert_eq!(req.id, "containerd");
242
243        let proto: ProtoServiceStopRequest = req.into();
244        assert_eq!(proto.id, "containerd");
245    }
246
247    #[test]
248    fn test_service_restart_request() {
249        let req = ServiceRestartRequest::new("etcd");
250        assert_eq!(req.id, "etcd");
251
252        let proto: ProtoServiceRestartRequest = req.into();
253        assert_eq!(proto.id, "etcd");
254    }
255}