1use crate::client::RestClient;
4use crate::error::Result;
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct ClusterNode {
11 pub id: u32,
12 pub address: String,
13 pub status: String,
14 pub role: Option<String>,
15 pub total_memory: Option<u64>,
16 pub used_memory: Option<u64>,
17 pub cpu_cores: Option<u32>,
18
19 #[serde(flatten)]
20 pub extra: Value,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct ClusterInfo {
26 pub name: String,
27 pub version: Option<String>,
28 pub license_expired: Option<bool>,
29 pub nodes: Option<Vec<u32>>,
30 pub databases: Option<Vec<u32>>,
31 pub status: Option<String>,
32 pub email_alerts: Option<bool>,
33 pub rack_aware: Option<bool>,
34
35 pub total_memory: Option<u64>,
37 pub used_memory: Option<u64>,
38 pub total_shards: Option<u32>,
39
40 #[serde(flatten)]
41 pub extra: Value,
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize)]
46pub struct ClusterSettings {
47 pub auto_recovery: Option<bool>,
49
50 pub automatic_node_offload: Option<bool>,
52
53 pub bigstore_migrate_node_threshold: Option<u32>,
55 pub bigstore_migrate_node_threshold_p: Option<u32>,
56 pub bigstore_provision_node_threshold: Option<u32>,
57 pub bigstore_provision_node_threshold_p: Option<u32>,
58
59 pub default_bigstore_version: Option<u32>,
61
62 pub data_internode_encryption: Option<bool>,
64
65 pub db_conns_auditing: Option<bool>,
67
68 pub default_concurrent_restore_actions: Option<u32>,
70
71 pub default_fork_evict_ram: Option<bool>,
73
74 pub default_non_sharded_proxy_policy: Option<String>,
76 pub default_sharded_proxy_policy: Option<String>,
77
78 pub default_oss_cluster: Option<bool>,
80 pub default_oss_sharding: Option<bool>,
81
82 pub default_provisioned_redis_version: Option<String>,
84
85 pub default_recovery_wait_time: Option<u32>,
87
88 pub default_shards_placement: Option<String>,
90
91 pub default_tracking_table_max_keys_policy: Option<String>,
93
94 pub email_alerts: Option<bool>,
96 pub endpoint_rebind_enabled: Option<bool>,
97 pub failure_detection_sensitivity: Option<String>,
98 pub gossip_envoy_admin_port: Option<u32>,
99 pub gossip_envoy_port: Option<u32>,
100 pub gossip_envoy_proxy_mode: Option<bool>,
101 pub hot_spare: Option<bool>,
102 pub max_saved_events_per_type: Option<u32>,
103 pub max_simultaneous_backups: Option<u32>,
104 pub parallel_shards_upgrade: Option<u32>,
105 pub persistent_node_removal: Option<bool>,
106 pub rack_aware: Option<bool>,
107 pub redis_migrate_node_threshold: Option<String>,
108 pub redis_migrate_node_threshold_p: Option<u32>,
109 pub redis_provision_node_threshold: Option<String>,
110 pub redis_provision_node_threshold_p: Option<u32>,
111 pub redis_upgrade_policy: Option<String>,
112 pub resp3_default: Option<bool>,
113 pub show_internals: Option<bool>,
114 pub slave_threads_when_master: Option<bool>,
115 pub use_empty_shard_backups: Option<bool>,
116
117 #[serde(flatten)]
118 pub extra: Value,
119}
120
121#[derive(Debug, Serialize)]
123pub struct BootstrapRequest {
124 pub action: String,
125 pub cluster: ClusterBootstrapInfo,
126 pub credentials: BootstrapCredentials,
127}
128
129#[derive(Debug, Serialize)]
131pub struct ClusterBootstrapInfo {
132 pub name: String,
133}
134
135#[derive(Debug, Serialize)]
137pub struct BootstrapCredentials {
138 pub username: String,
139 pub password: String,
140}
141
142pub struct ClusterHandler {
144 client: RestClient,
145}
146
147impl ClusterHandler {
148 pub fn new(client: RestClient) -> Self {
149 ClusterHandler { client }
150 }
151
152 pub async fn info(&self) -> Result<ClusterInfo> {
154 self.client.get("/v1/cluster").await
155 }
156
157 pub async fn bootstrap(&self, request: BootstrapRequest) -> Result<Value> {
159 self.client
162 .post_bootstrap("/v1/bootstrap/create_cluster", &request)
163 .await
164 }
165
166 pub async fn update(&self, updates: Value) -> Result<Value> {
168 self.client.put("/v1/cluster", &updates).await
169 }
170
171 pub async fn stats(&self) -> Result<Value> {
173 self.client.get("/v1/cluster/stats").await
174 }
175
176 pub async fn nodes(&self) -> Result<Vec<NodeInfo>> {
178 self.client.get("/v1/nodes").await
179 }
180
181 pub async fn license(&self) -> Result<LicenseInfo> {
183 self.client.get("/v1/license").await
184 }
185
186 pub async fn join_node(
188 &self,
189 node_address: &str,
190 username: &str,
191 password: &str,
192 ) -> Result<Value> {
193 let body = serde_json::json!({
194 "action": "join_cluster",
195 "cluster": {
196 "nodes": [node_address]
197 },
198 "credentials": {
199 "username": username,
200 "password": password
201 }
202 });
203 self.client.post("/v1/bootstrap/join", &body).await
204 }
205
206 pub async fn remove_node(&self, node_uid: u32) -> Result<Value> {
208 self.client
209 .delete(&format!("/v1/nodes/{}", node_uid))
210 .await?;
211 Ok(serde_json::json!({"message": format!("Node {} removed", node_uid)}))
212 }
213
214 pub async fn reset(&self) -> Result<Value> {
216 self.client
217 .post("/v1/cluster/actions/reset", &serde_json::json!({}))
218 .await
219 }
220
221 pub async fn recover(&self) -> Result<Value> {
223 self.client
224 .post("/v1/cluster/actions/recover", &serde_json::json!({}))
225 .await
226 }
227
228 pub async fn settings(&self) -> Result<Value> {
230 self.client.get("/v1/cluster/settings").await
231 }
232
233 pub async fn topology(&self) -> Result<Value> {
235 self.client.get("/v1/cluster/topology").await
236 }
237}
238
239#[derive(Debug, Clone, Serialize, Deserialize)]
241pub struct NodeInfo {
242 pub uid: u32,
243 pub address: String,
244 pub status: String,
245 pub role: Option<String>,
246 pub shards: Option<Vec<u32>>,
247 pub total_memory: Option<u64>,
248 pub used_memory: Option<u64>,
249
250 #[serde(flatten)]
251 pub extra: Value,
252}
253
254#[derive(Debug, Clone, Serialize, Deserialize)]
256pub struct LicenseInfo {
257 pub license_type: Option<String>,
258 pub expired: Option<bool>,
259 pub expiration_date: Option<String>,
260 pub shards_limit: Option<u32>,
261 pub features: Option<Vec<String>>,
262
263 #[serde(flatten)]
264 pub extra: Value,
265}