manta_shared/common/config/
types.rs1use std::collections::HashMap;
9
10use crate::common::audit::Auditor;
11
12use manta_backend_dispatcher::types::K8sDetails;
13use serde::{Deserialize, Serialize};
14
15#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
17#[serde(rename_all = "lowercase")]
18pub enum BackendTechnology {
19 Csm,
21 Ochami,
23}
24
25impl BackendTechnology {
26 pub fn as_str(&self) -> &'static str {
28 match self {
29 Self::Csm => "csm",
30 Self::Ochami => "ochami",
31 }
32 }
33}
34
35#[derive(Serialize, Deserialize, Debug)]
36pub struct Site {
44 pub backend: BackendTechnology,
46 pub socks5_proxy: Option<String>,
49 pub shasta_base_url: String,
51 pub k8s: Option<K8sDetails>,
54 pub root_ca_cert_file: String,
57}
58
59#[derive(Serialize, Deserialize, Debug)]
65pub struct CliConfiguration {
66 pub log: String,
69 pub audit_file: String,
71 pub site: String,
76 pub parent_hsm_group: String,
79 pub manta_server_url: String,
83 pub socks5_proxy: Option<String>,
86 #[serde(default)]
95 pub request_timeout_secs: Option<u64>,
96}
97
98#[derive(Serialize, Deserialize, Debug)]
101pub struct ServerSettings {
102 #[serde(default)]
106 pub listen_address: Option<String>,
107 #[serde(default)]
113 pub port: Option<u16>,
114 pub cert: Option<String>,
116 pub key: Option<String>,
118 pub console_inactivity_timeout_secs: u64,
121 pub auth_rate_limit_per_minute: Option<u32>,
125 #[serde(default = "default_request_timeout_secs")]
130 pub request_timeout_secs: u64,
131}
132
133impl ServerSettings {
134 pub const DEFAULT_LISTEN_ADDRESS: &'static str = "0.0.0.0";
137
138 pub fn default_port(has_tls: bool) -> u16 {
143 if has_tls { 8443 } else { 8080 }
144 }
145}
146
147fn default_request_timeout_secs() -> u64 {
150 60
151}
152
153#[derive(Serialize, Deserialize, Debug)]
158pub struct ServerConfiguration {
159 pub log: String,
161 pub audit_file: String,
163 pub server: ServerSettings,
165 pub sites: HashMap<String, Site>,
168 pub auditor: Option<Auditor>,
171}
172
173#[cfg(test)]
174mod tests {
175 use super::*;
176
177 #[test]
178 fn site_deserialize_missing_backend_fails() {
179 let bad_toml = r#"
180 shasta_base_url = "https://api.example.com"
181 root_ca_cert_file = "cert.pem"
182 # missing backend
183 "#;
184 let result = toml::from_str::<Site>(bad_toml);
185 assert!(result.is_err());
186 }
187
188 #[test]
189 fn backend_technology_as_str() {
190 assert_eq!(BackendTechnology::Csm.as_str(), "csm");
191 assert_eq!(BackendTechnology::Ochami.as_str(), "ochami");
192 }
193
194 #[test]
195 fn backend_technology_roundtrip_toml() {
196 #[derive(Serialize, Deserialize)]
198 struct Wrapper {
199 backend: BackendTechnology,
200 }
201 let w = Wrapper {
202 backend: BackendTechnology::Csm,
203 };
204 let s = toml::to_string(&w).unwrap();
205 assert!(s.contains("\"csm\"") || s.contains("csm"));
206 let parsed: Wrapper = toml::from_str(&s).unwrap();
207 assert_eq!(parsed.backend, BackendTechnology::Csm);
208 }
209
210 fn make_minimal_site() -> Site {
211 Site {
212 backend: BackendTechnology::Csm,
213 socks5_proxy: None,
214 shasta_base_url: "https://api.example.com".to_string(),
215 k8s: None,
216 root_ca_cert_file: "cert.pem".to_string(),
217 }
218 }
219
220 #[test]
221 fn cli_configuration_roundtrip_toml_minimal() {
222 let cfg = CliConfiguration {
223 log: "info".to_string(),
224 audit_file: "/tmp/cli-audit.log".to_string(),
225 site: "alps".to_string(),
226 parent_hsm_group: "nodes_free".to_string(),
227 manta_server_url: "https://manta-server.cscs.ch:8443".to_string(),
228 socks5_proxy: Some("socks5h://127.0.0.1:1080".to_string()),
229 request_timeout_secs: None,
230 };
231 let toml_str = toml::to_string(&cfg).unwrap();
232 let parsed: CliConfiguration = toml::from_str(&toml_str).unwrap();
233 assert_eq!(parsed.site, "alps");
234 assert_eq!(parsed.parent_hsm_group, "nodes_free");
235 assert_eq!(parsed.manta_server_url, "https://manta-server.cscs.ch:8443");
236 assert_eq!(
237 parsed.socks5_proxy.as_deref(),
238 Some("socks5h://127.0.0.1:1080")
239 );
240 }
241
242 #[test]
243 fn cli_configuration_socks5_proxy_optional() {
244 let toml_str = r#"
245 log = "info"
246 audit_file = "/tmp/cli-audit.log"
247 site = "alps"
248 parent_hsm_group = ""
249 manta_server_url = "https://manta-server.cscs.ch:8443"
250 "#;
251 let parsed: CliConfiguration = toml::from_str(toml_str).unwrap();
252 assert!(parsed.socks5_proxy.is_none());
253 }
254
255 #[test]
256 fn cli_configuration_missing_manta_server_url_fails() {
257 let bad_toml = r#"
258 log = "info"
259 audit_file = "/tmp/cli-audit.log"
260 site = "alps"
261 parent_hsm_group = ""
262 # missing manta_server_url
263 "#;
264 let result = toml::from_str::<CliConfiguration>(bad_toml);
265 assert!(result.is_err());
266 }
267
268 #[test]
269 fn server_configuration_roundtrip_toml_minimal() {
270 let mut sites = HashMap::new();
271 sites.insert("alps".to_string(), make_minimal_site());
272 let cfg = ServerConfiguration {
273 log: "info".to_string(),
274 audit_file: "/var/log/manta/server-audit.log".to_string(),
275 server: ServerSettings {
276 listen_address: Some("0.0.0.0".to_string()),
277 port: Some(8443),
278 cert: Some("/etc/manta/tls/server.crt".to_string()),
279 key: Some("/etc/manta/tls/server.key".to_string()),
280 console_inactivity_timeout_secs: 1800,
281 auth_rate_limit_per_minute: Some(60),
282 request_timeout_secs: 60,
283 },
284 sites,
285 auditor: None,
286 };
287 let toml_str = toml::to_string(&cfg).unwrap();
288 let parsed: ServerConfiguration = toml::from_str(&toml_str).unwrap();
289 assert_eq!(parsed.server.port, Some(8443));
290 assert_eq!(parsed.server.listen_address.as_deref(), Some("0.0.0.0"));
291 assert_eq!(parsed.server.console_inactivity_timeout_secs, 1800);
292 assert_eq!(parsed.server.request_timeout_secs, 60);
293 assert_eq!(
294 parsed.server.cert.as_deref(),
295 Some("/etc/manta/tls/server.crt")
296 );
297 }
298
299 #[test]
303 fn server_settings_default_port_depends_on_tls() {
304 assert_eq!(ServerSettings::default_port(true), 8443);
305 assert_eq!(ServerSettings::default_port(false), 8080);
306 }
307
308 #[test]
312 fn server_settings_request_timeout_secs_defaults_to_60() {
313 let toml_str = r#"
314 listen_address = "0.0.0.0"
315 port = 8443
316 console_inactivity_timeout_secs = 1800
317 "#;
318 let parsed: ServerSettings = toml::from_str(toml_str).unwrap();
319 assert_eq!(parsed.request_timeout_secs, 60);
320 }
321
322 #[test]
327 fn server_settings_listen_address_and_port_default_to_none() {
328 let toml_str = r#"
329 console_inactivity_timeout_secs = 1800
330 "#;
331 let parsed: ServerSettings = toml::from_str(toml_str).unwrap();
332 assert!(parsed.listen_address.is_none());
333 assert!(parsed.port.is_none());
334 }
335
336 #[test]
339 fn server_settings_request_timeout_field_defaults_when_omitted() {
340 let toml_str = r#"
341 listen_address = "0.0.0.0"
342 port = 8443
343 console_inactivity_timeout_secs = 1800
344 "#;
345 let parsed: ServerSettings = toml::from_str(toml_str).unwrap();
346 assert_eq!(parsed.request_timeout_secs, 60);
347 }
348
349 #[test]
350 fn server_configuration_deserialize_missing_server_section_fails() {
351 let bad_toml = r#"
352 log = "info"
353 audit_file = "/tmp/server.log"
354 [sites]
355 "#;
356 let result = toml::from_str::<ServerConfiguration>(bad_toml);
357 assert!(result.is_err());
358 }
359
360 #[test]
361 fn server_settings_optional_tls_paths() {
362 let toml_str = r#"
365 listen_address = "0.0.0.0"
366 port = 8443
367 console_inactivity_timeout_secs = 1800
368 "#;
369 let parsed: ServerSettings = toml::from_str(toml_str).unwrap();
370 assert!(parsed.cert.is_none());
371 assert!(parsed.key.is_none());
372 }
373}