xianyun_cluster/driver/
mock.rs1use super::{Driver as DriverTrait, DriverError, State, Status};
6use std::collections::HashMap;
7use std::sync::{LazyLock, RwLock};
8use xianyun_core::config::types::ClusterConfig;
9
10pub const DRIVER_NAME: &str = "mock";
11pub const MOCK_KUBERNETES_VERSION: &str = "v1.30.0+mock";
12
13const MOCK_IP_ADDRESS: &str = "192.168.64.100";
14
15#[derive(Debug, Clone, Default)]
17pub struct ErrorConfig {
18 pub start_error: Option<DriverError>,
19 pub stop_error: Option<DriverError>,
20 pub destroy_error: Option<DriverError>,
21 pub status_error: Option<DriverError>,
22 pub get_kubeconfig_error: Option<DriverError>,
23}
24
25#[derive(Debug, Clone, Default)]
28pub struct ClusterState {
29 pub state: Option<State>,
30 pub kubernetes_version: String,
31 pub ip_address: String,
32 pub kubeconfig: String,
33 pub start_call_count: u32,
34 pub stop_call_count: u32,
35 pub destroy_call_count: u32,
36 pub status_call_count: u32,
37}
38
39static GLOBAL_STATE: LazyLock<RwLock<HashMap<String, ClusterState>>> =
40 LazyLock::new(|| RwLock::new(HashMap::new()));
41
42static ERROR_CONFIGS: LazyLock<RwLock<HashMap<String, ErrorConfig>>> =
43 LazyLock::new(|| RwLock::new(HashMap::new()));
44
45pub struct Driver {
47 pub cfg: ClusterConfig,
48 pub profile_name: String,
49}
50
51impl Driver {
52 #[must_use]
54 pub fn new(cfg: ClusterConfig, profile_name: String) -> Self {
55 Self { cfg, profile_name }
56 }
57
58 fn configured_error(
59 &self,
60 pick: impl Fn(&ErrorConfig) -> &Option<DriverError>,
61 ) -> Option<DriverError> {
62 ERROR_CONFIGS
63 .read()
64 .unwrap_or_else(std::sync::PoisonError::into_inner)
65 .get(&self.profile_name)
66 .and_then(|cfg| pick(cfg).clone())
67 }
68}
69
70impl DriverTrait for Driver {
71 fn name(&self) -> &str {
72 DRIVER_NAME
73 }
74
75 fn start(&self) -> Result<(), DriverError> {
76 if let Some(err) = self.configured_error(|c| &c.start_error) {
77 return Err(err);
78 }
79
80 let mut state = GLOBAL_STATE
81 .write()
82 .unwrap_or_else(std::sync::PoisonError::into_inner);
83 let entry = state.entry(self.profile_name.clone()).or_default();
84 entry.start_call_count += 1;
85
86 if entry.state == Some(State::Ready) {
87 return Ok(());
88 }
89
90 entry.state = Some(State::Ready);
91 entry.kubernetes_version = MOCK_KUBERNETES_VERSION.to_string();
92 entry.ip_address = MOCK_IP_ADDRESS.to_string();
93
94 Ok(())
95 }
96
97 fn stop(&self) -> Result<(), DriverError> {
98 if let Some(err) = self.configured_error(|c| &c.stop_error) {
99 return Err(err);
100 }
101
102 let mut state = GLOBAL_STATE
103 .write()
104 .unwrap_or_else(std::sync::PoisonError::into_inner);
105 let entry = state.entry(self.profile_name.clone()).or_default();
106 entry.stop_call_count += 1;
107
108 if entry.state == Some(State::Stopped) {
109 return Ok(());
110 }
111
112 entry.state = Some(State::Stopped);
113
114 Ok(())
115 }
116
117 fn destroy(&self) -> Result<(), DriverError> {
118 if let Some(err) = self.configured_error(|c| &c.destroy_error) {
119 return Err(err);
120 }
121
122 let mut state = GLOBAL_STATE
123 .write()
124 .unwrap_or_else(std::sync::PoisonError::into_inner);
125 if !state.contains_key(&self.profile_name) {
126 return Ok(());
127 }
128 state.remove(&self.profile_name);
129
130 Ok(())
131 }
132
133 fn status(&self) -> Result<Status, DriverError> {
134 if let Some(err) = self.configured_error(|c| &c.status_error) {
135 return Err(err);
136 }
137
138 let mut state = GLOBAL_STATE
139 .write()
140 .unwrap_or_else(std::sync::PoisonError::into_inner);
141 let kube_context = format!("mock-{}", self.profile_name);
142
143 let Some(entry) = state.get_mut(&self.profile_name) else {
144 return Ok(Status {
145 driver: DRIVER_NAME.to_string(),
146 state: Some(State::Stopped),
147 kube_context,
148 ..Default::default()
149 });
150 };
151
152 entry.status_call_count += 1;
153
154 Ok(Status {
155 driver: DRIVER_NAME.to_string(),
156 state: entry.state,
157 kubernetes_version: entry.kubernetes_version.clone(),
158 ip_address: entry.ip_address.clone(),
159 host_ip: entry.ip_address.clone(),
160 kube_context,
161 exists: false,
162 })
163 }
164
165 fn get_kubeconfig(&self) -> Result<String, DriverError> {
166 if let Some(err) = self.configured_error(|c| &c.get_kubeconfig_error) {
167 return Err(err);
168 }
169
170 let state = GLOBAL_STATE
171 .read()
172 .unwrap_or_else(std::sync::PoisonError::into_inner);
173 Ok(state
174 .get(&self.profile_name)
175 .map(|s| s.kubeconfig.clone())
176 .unwrap_or_default())
177 }
178}
179
180pub fn reset_global_state() {
183 GLOBAL_STATE
184 .write()
185 .unwrap_or_else(std::sync::PoisonError::into_inner)
186 .clear();
187 ERROR_CONFIGS
188 .write()
189 .unwrap_or_else(std::sync::PoisonError::into_inner)
190 .clear();
191}
192
193pub fn set_error_config(profile_name: &str, err_cfg: ErrorConfig) {
195 ERROR_CONFIGS
196 .write()
197 .unwrap_or_else(std::sync::PoisonError::into_inner)
198 .insert(profile_name.to_string(), err_cfg);
199}
200
201pub fn clear_error_config(profile_name: &str) {
203 ERROR_CONFIGS
204 .write()
205 .unwrap_or_else(std::sync::PoisonError::into_inner)
206 .remove(profile_name);
207}
208
209pub fn get_state(profile_name: &str) -> Option<ClusterState> {
211 GLOBAL_STATE
212 .read()
213 .unwrap_or_else(std::sync::PoisonError::into_inner)
214 .get(profile_name)
215 .cloned()
216}
217
218pub fn profile_exists(profile_name: &str) -> bool {
220 GLOBAL_STATE
221 .read()
222 .unwrap_or_else(std::sync::PoisonError::into_inner)
223 .contains_key(profile_name)
224}
225
226pub fn set_kubeconfig(profile_name: &str, kubeconfig_yaml: &str) {
228 let mut state = GLOBAL_STATE
229 .write()
230 .unwrap_or_else(std::sync::PoisonError::into_inner);
231 let entry = state
232 .entry(profile_name.to_string())
233 .or_insert_with(|| ClusterState {
234 state: Some(State::Ready),
235 kubernetes_version: MOCK_KUBERNETES_VERSION.to_string(),
236 ..Default::default()
237 });
238 entry.kubeconfig = kubeconfig_yaml.to_string();
239}
240
241pub fn set_cluster_state(profile_name: &str, state: State) {
243 GLOBAL_STATE
244 .write()
245 .unwrap_or_else(std::sync::PoisonError::into_inner)
246 .insert(
247 profile_name.to_string(),
248 ClusterState {
249 state: Some(state),
250 kubernetes_version: MOCK_KUBERNETES_VERSION.to_string(),
251 ip_address: MOCK_IP_ADDRESS.to_string(),
252 ..Default::default()
253 },
254 );
255}