dnslib/vendors/pangolin/
mod.rs1pub mod client;
2pub mod mapping;
3pub mod responses;
4pub mod service;
5
6use std::env;
7
8use crate::control_plane::config::{self as app_config, DnsServerConfig};
9use crate::core::error::{Error, Result};
10use crate::core::secret::ApiToken;
11use crate::vendors::runtime::ClientOverrides;
12
13pub fn client_from_server(
14 server: &DnsServerConfig,
15 overrides: ClientOverrides<'_>,
16) -> Result<client::PangolinClient> {
17 let base_url = overrides
18 .base_url
19 .map(ToOwned::to_owned)
20 .or_else(|| env::var("DNSYNC_PANGOLIN_BASE_URL").ok())
21 .or_else(|| server.base_url_env.as_ref().and_then(|k| env::var(k).ok()))
22 .or_else(|| server.base_url.clone())
23 .unwrap_or_else(|| app_config::PANGOLIN_DEFAULT_BASE_URL.to_string());
24 let token = overrides
25 .token
26 .map(ToOwned::to_owned)
27 .or_else(|| env::var("DNSYNC_PANGOLIN_API_TOKEN").ok())
28 .or_else(|| server.token_env.as_ref().and_then(|k| env::var(k).ok()))
29 .or_else(|| server.token.clone())
30 .ok_or_else(|| {
31 Error::parse(
32 "Pangolin API token is required from --token, DNSYNC_PANGOLIN_API_TOKEN, token_env, or config token",
33 )
34 })
35 .map(ApiToken::new)?;
36 let org_id = env::var("DNSYNC_PANGOLIN_ORG_ID")
37 .ok()
38 .or_else(|| server.org_id.clone())
39 .ok_or_else(|| {
40 Error::parse("Pangolin org ID is required from DNSYNC_PANGOLIN_ORG_ID or config org_id")
41 })?;
42 client::PangolinClient::new(base_url, token, org_id)
43}
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48
49 static ENV_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
50
51 fn clear_pangolin_env() {
52 unsafe {
54 std::env::remove_var("DNSYNC_PANGOLIN_BASE_URL");
55 std::env::remove_var("DNSYNC_PANGOLIN_API_TOKEN");
56 std::env::remove_var("DNSYNC_PANGOLIN_ORG_ID");
57 }
58 }
59
60 #[test]
61 fn client_uses_default_base_url_from_config() {
62 let _guard = ENV_LOCK.lock().unwrap();
63 clear_pangolin_env();
64 let app_config: app_config::AppConfig = toml::from_str(
65 r#"
66 [[servers]]
67 id = "cloud"
68 vendor = "pangolin"
69 token = "pangolin-token"
70 org_id = "org_123"
71 "#,
72 )
73 .unwrap();
74 let server = app_config.selected_server(Some("cloud")).unwrap();
75
76 let client = client_from_server(server, ClientOverrides::default()).unwrap();
77
78 assert_eq!(client.base_url(), app_config::PANGOLIN_DEFAULT_BASE_URL);
79 assert_eq!(client.org_id, "org_123");
80 }
81
82 #[test]
83 fn client_from_server_uses_vendor_env_without_overrides() {
84 let _guard = ENV_LOCK.lock().unwrap();
85 clear_pangolin_env();
86 unsafe {
88 std::env::set_var("DNSYNC_PANGOLIN_BASE_URL", "https://pangolin.example/v1");
89 std::env::set_var("DNSYNC_PANGOLIN_API_TOKEN", "pangolin-env-token");
90 std::env::set_var("DNSYNC_PANGOLIN_ORG_ID", "env-org");
91 }
92 let app_config: app_config::AppConfig = toml::from_str(
93 r#"
94 [[servers]]
95 id = "cloud"
96 vendor = "pangolin"
97 "#,
98 )
99 .unwrap();
100 let server = app_config.selected_server(Some("cloud")).unwrap();
101
102 let client = client_from_server(server, ClientOverrides::default()).unwrap();
103
104 assert_eq!(client.base_url(), "https://pangolin.example/v1");
105 assert_eq!(client.org_id, "env-org");
106
107 clear_pangolin_env();
109 }
110}