redis_enterprise/
services.rs

1//! Service configuration and management
2//!
3//! ## Overview
4//! - Configure cluster services
5//! - Start/stop services
6//! - Query service status
7
8use crate::client::RestClient;
9use crate::error::Result;
10use serde::{Deserialize, Serialize};
11use serde_json::Value;
12use typed_builder::TypedBuilder;
13
14/// Service configuration
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct Service {
17    /// Unique identifier for the service
18    pub service_id: String,
19    /// Human-readable name of the service
20    pub name: String,
21    /// Type of service (e.g., "mdns_server", "cm_server", "stats_archiver")
22    pub service_type: String,
23    /// Whether the service is enabled
24    pub enabled: bool,
25    /// Service-specific configuration parameters
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub config: Option<Value>,
28    /// Current operational status of the service
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub status: Option<String>,
31    /// List of node UIDs where this service is running
32    #[serde(skip_serializing_if = "Option::is_none")]
33    pub node_uids: Option<Vec<u32>>,
34
35    #[serde(flatten)]
36    pub extra: Value,
37}
38
39/// Service configuration request
40#[derive(Debug, Clone, Serialize, Deserialize, TypedBuilder)]
41pub struct ServiceConfigRequest {
42    /// Whether to enable or disable the service
43    pub enabled: bool,
44    /// Service-specific configuration parameters
45    #[serde(skip_serializing_if = "Option::is_none")]
46    #[builder(default, setter(strip_option))]
47    pub config: Option<Value>,
48    /// Specific nodes where the service should run (optional)
49    #[serde(skip_serializing_if = "Option::is_none")]
50    #[builder(default, setter(strip_option))]
51    pub node_uids: Option<Vec<u32>>,
52}
53
54/// Service status
55#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct ServiceStatus {
57    /// Unique identifier for the service
58    pub service_id: String,
59    /// Overall status of the service (e.g., "running", "stopped", "error")
60    pub status: String,
61    /// Additional status message or error description
62    #[serde(skip_serializing_if = "Option::is_none")]
63    pub message: Option<String>,
64    /// Status of the service on individual nodes
65    #[serde(skip_serializing_if = "Option::is_none")]
66    pub node_statuses: Option<Vec<NodeServiceStatus>>,
67
68    #[serde(flatten)]
69    pub extra: Value,
70}
71
72/// Node service status
73#[derive(Debug, Clone, Serialize, Deserialize)]
74pub struct NodeServiceStatus {
75    /// Node unique identifier where the service is running
76    pub node_uid: u32,
77    /// Service status on this specific node (e.g., "running", "stopped", "error")
78    pub status: String,
79    /// Node-specific status message or error description
80    #[serde(skip_serializing_if = "Option::is_none")]
81    pub message: Option<String>,
82}
83
84/// Services handler
85pub struct ServicesHandler {
86    client: RestClient,
87}
88
89impl ServicesHandler {
90    pub fn new(client: RestClient) -> Self {
91        ServicesHandler { client }
92    }
93
94    /// List all services
95    pub async fn list(&self) -> Result<Vec<Service>> {
96        self.client.get("/v1/services").await
97    }
98
99    /// Get specific service
100    pub async fn get(&self, service_id: &str) -> Result<Service> {
101        self.client
102            .get(&format!("/v1/services/{}", service_id))
103            .await
104    }
105
106    /// Update service configuration
107    pub async fn update(&self, service_id: &str, request: ServiceConfigRequest) -> Result<Service> {
108        self.client
109            .put(&format!("/v1/services/{}", service_id), &request)
110            .await
111    }
112
113    /// Get service status
114    pub async fn status(&self, service_id: &str) -> Result<ServiceStatus> {
115        self.client
116            .get(&format!("/v1/services/{}/status", service_id))
117            .await
118    }
119
120    /// Restart service
121    pub async fn restart(&self, service_id: &str) -> Result<ServiceStatus> {
122        self.client
123            .post(
124                &format!("/v1/services/{}/restart", service_id),
125                &Value::Null,
126            )
127            .await
128    }
129
130    /// Stop service
131    pub async fn stop(&self, service_id: &str) -> Result<ServiceStatus> {
132        self.client
133            .post(&format!("/v1/services/{}/stop", service_id), &Value::Null)
134            .await
135    }
136
137    /// Start service
138    pub async fn start(&self, service_id: &str) -> Result<ServiceStatus> {
139        self.client
140            .post(&format!("/v1/services/{}/start", service_id), &Value::Null)
141            .await
142    }
143
144    /// Create a service - POST /v1/services
145    pub async fn create(&self, body: Value) -> Result<Service> {
146        self.client.post("/v1/services", &body).await
147    }
148}