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 pub auditor: Option<Auditor>,
99}
100
101#[derive(Serialize, Deserialize, Debug)]
104pub struct ServerSettings {
105 #[serde(default)]
109 pub listen_address: Option<String>,
110 #[serde(default)]
116 pub port: Option<u16>,
117 pub cert: Option<String>,
119 pub key: Option<String>,
121 pub console_inactivity_timeout_secs: u64,
124 pub auth_rate_limit_per_minute: Option<u32>,
128 #[serde(default = "default_request_timeout_secs")]
133 pub request_timeout_secs: u64,
134}
135
136impl ServerSettings {
137 pub const DEFAULT_LISTEN_ADDRESS: &'static str = "0.0.0.0";
140
141 pub fn default_port(has_tls: bool) -> u16 {
146 if has_tls { 8443 } else { 8080 }
147 }
148}
149
150fn default_request_timeout_secs() -> u64 {
153 60
154}
155
156#[derive(Serialize, Deserialize, Debug)]
161pub struct ServerConfiguration {
162 pub log: String,
164 pub audit_file: String,
166 pub server: ServerSettings,
168 pub sites: HashMap<String, Site>,
171 pub auditor: Option<Auditor>,
174}
175
176#[cfg(test)]
177mod tests {
178 use super::*;
179
180 #[test]
181 fn site_deserialize_missing_backend_fails() {
182 let bad_toml = r#"
183 shasta_base_url = "https://api.example.com"
184 root_ca_cert_file = "cert.pem"
185 # missing backend
186 "#;
187 let result = toml::from_str::<Site>(bad_toml);
188 assert!(result.is_err());
189 }
190
191 #[test]
192 fn backend_technology_as_str() {
193 assert_eq!(BackendTechnology::Csm.as_str(), "csm");
194 assert_eq!(BackendTechnology::Ochami.as_str(), "ochami");
195 }
196
197 #[test]
198 fn backend_technology_roundtrip_toml() {
199 #[derive(Serialize, Deserialize)]
201 struct Wrapper {
202 backend: BackendTechnology,
203 }
204 let w = Wrapper {
205 backend: BackendTechnology::Csm,
206 };
207 let s = toml::to_string(&w).unwrap();
208 assert!(s.contains("\"csm\"") || s.contains("csm"));
209 let parsed: Wrapper = toml::from_str(&s).unwrap();
210 assert_eq!(parsed.backend, BackendTechnology::Csm);
211 }
212
213 fn make_minimal_site() -> Site {
214 Site {
215 backend: BackendTechnology::Csm,
216 socks5_proxy: None,
217 shasta_base_url: "https://api.example.com".to_string(),
218 k8s: None,
219 root_ca_cert_file: "cert.pem".to_string(),
220 }
221 }
222
223 #[test]
224 fn cli_configuration_roundtrip_toml_minimal() {
225 let cfg = CliConfiguration {
226 log: "info".to_string(),
227 audit_file: "/tmp/cli-audit.log".to_string(),
228 site: "alps".to_string(),
229 parent_hsm_group: "nodes_free".to_string(),
230 manta_server_url: "https://manta-server.cscs.ch:8443".to_string(),
231 socks5_proxy: Some("socks5h://127.0.0.1:1080".to_string()),
232 request_timeout_secs: None,
233 auditor: None,
234 };
235 let toml_str = toml::to_string(&cfg).unwrap();
236 let parsed: CliConfiguration = toml::from_str(&toml_str).unwrap();
237 assert_eq!(parsed.site, "alps");
238 assert_eq!(parsed.parent_hsm_group, "nodes_free");
239 assert_eq!(parsed.manta_server_url, "https://manta-server.cscs.ch:8443");
240 assert_eq!(
241 parsed.socks5_proxy.as_deref(),
242 Some("socks5h://127.0.0.1:1080")
243 );
244 }
245
246 #[test]
247 fn cli_configuration_socks5_proxy_optional() {
248 let toml_str = r#"
249 log = "info"
250 audit_file = "/tmp/cli-audit.log"
251 site = "alps"
252 parent_hsm_group = ""
253 manta_server_url = "https://manta-server.cscs.ch:8443"
254 "#;
255 let parsed: CliConfiguration = toml::from_str(toml_str).unwrap();
256 assert!(parsed.socks5_proxy.is_none());
257 }
258
259 #[test]
260 fn cli_configuration_missing_manta_server_url_fails() {
261 let bad_toml = r#"
262 log = "info"
263 audit_file = "/tmp/cli-audit.log"
264 site = "alps"
265 parent_hsm_group = ""
266 # missing manta_server_url
267 "#;
268 let result = toml::from_str::<CliConfiguration>(bad_toml);
269 assert!(result.is_err());
270 }
271
272 #[test]
273 fn server_configuration_roundtrip_toml_minimal() {
274 let mut sites = HashMap::new();
275 sites.insert("alps".to_string(), make_minimal_site());
276 let cfg = ServerConfiguration {
277 log: "info".to_string(),
278 audit_file: "/var/log/manta/server-audit.log".to_string(),
279 server: ServerSettings {
280 listen_address: Some("0.0.0.0".to_string()),
281 port: Some(8443),
282 cert: Some("/etc/manta/tls/server.crt".to_string()),
283 key: Some("/etc/manta/tls/server.key".to_string()),
284 console_inactivity_timeout_secs: 1800,
285 auth_rate_limit_per_minute: Some(60),
286 request_timeout_secs: 60,
287 },
288 sites,
289 auditor: None,
290 };
291 let toml_str = toml::to_string(&cfg).unwrap();
292 let parsed: ServerConfiguration = toml::from_str(&toml_str).unwrap();
293 assert_eq!(parsed.server.port, Some(8443));
294 assert_eq!(parsed.server.listen_address.as_deref(), Some("0.0.0.0"));
295 assert_eq!(parsed.server.console_inactivity_timeout_secs, 1800);
296 assert_eq!(parsed.server.request_timeout_secs, 60);
297 assert_eq!(
298 parsed.server.cert.as_deref(),
299 Some("/etc/manta/tls/server.crt")
300 );
301 }
302
303 #[test]
307 fn server_settings_default_port_depends_on_tls() {
308 assert_eq!(ServerSettings::default_port(true), 8443);
309 assert_eq!(ServerSettings::default_port(false), 8080);
310 }
311
312 #[test]
316 fn server_settings_request_timeout_secs_defaults_to_60() {
317 let toml_str = r#"
318 listen_address = "0.0.0.0"
319 port = 8443
320 console_inactivity_timeout_secs = 1800
321 "#;
322 let parsed: ServerSettings = toml::from_str(toml_str).unwrap();
323 assert_eq!(parsed.request_timeout_secs, 60);
324 }
325
326 #[test]
331 fn server_settings_listen_address_and_port_default_to_none() {
332 let toml_str = r#"
333 console_inactivity_timeout_secs = 1800
334 "#;
335 let parsed: ServerSettings = toml::from_str(toml_str).unwrap();
336 assert!(parsed.listen_address.is_none());
337 assert!(parsed.port.is_none());
338 }
339
340 #[test]
343 fn server_settings_request_timeout_field_defaults_when_omitted() {
344 let toml_str = r#"
345 listen_address = "0.0.0.0"
346 port = 8443
347 console_inactivity_timeout_secs = 1800
348 "#;
349 let parsed: ServerSettings = toml::from_str(toml_str).unwrap();
350 assert_eq!(parsed.request_timeout_secs, 60);
351 }
352
353 #[test]
354 fn server_configuration_deserialize_missing_server_section_fails() {
355 let bad_toml = r#"
356 log = "info"
357 audit_file = "/tmp/server.log"
358 [sites]
359 "#;
360 let result = toml::from_str::<ServerConfiguration>(bad_toml);
361 assert!(result.is_err());
362 }
363
364 #[test]
365 fn server_settings_optional_tls_paths() {
366 let toml_str = r#"
369 listen_address = "0.0.0.0"
370 port = 8443
371 console_inactivity_timeout_secs = 1800
372 "#;
373 let parsed: ServerSettings = toml::from_str(toml_str).unwrap();
374 assert!(parsed.cert.is_none());
375 assert!(parsed.key.is_none());
376 }
377}