From 1a8e9818828fa900e70741b4bdbdbe18a4645183 Mon Sep 17 00:00:00 2001 From: Carlos V Date: Tue, 8 Oct 2024 20:11:22 +0000 Subject: [PATCH 1/2] feat: Make it possible to have a shared env var for srvice and tap --- config/src/config.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/config/src/config.rs b/config/src/config.rs index 795c382fe..405e85752 100644 --- a/config/src/config.rs +++ b/config/src/config.rs @@ -61,10 +61,10 @@ pub enum ConfigPrefix { } impl ConfigPrefix { - fn get_prefix(&self) -> &'static str { + fn get_prefixes(&self) -> Vec<&'static str> { match self { - Self::Tap => "TAP_AGENT_", - Self::Service => "INDEXER_SERVICE_", + Self::Tap => vec!["TAP_AGENT_", "INDEXER_"], + Self::Service => vec!["INDEXER_SERVICE_", "INDEXER_"], } } } @@ -81,11 +81,11 @@ impl Config { config_content = Self::substitute_env_vars(config_content)?; figment_config = figment_config.merge(Toml::string(&config_content)); } + for prefix_str in prefix.get_prefixes() { + figment_config = figment_config.merge(Env::prefixed(prefix_str).split("__")); + } - let config: ConfigWrapper = figment_config - .merge(Env::prefixed(prefix.get_prefix()).split("__")) - .extract() - .map_err(|e| e.to_string())?; + let config: ConfigWrapper = figment_config.extract().map_err(|e| e.to_string())?; config.0.validate()?; Ok(config.0) } From d8760b519803daec25a7a4ccfed7f9013a624eb7 Mon Sep 17 00:00:00 2001 From: Carlos V Date: Wed, 9 Oct 2024 17:33:34 +0000 Subject: [PATCH 2/2] feat: Simplify shared env var logic and add unit tests --- config/src/config.rs | 60 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 7 deletions(-) diff --git a/config/src/config.rs b/config/src/config.rs index 405e85752..8235d0030 100644 --- a/config/src/config.rs +++ b/config/src/config.rs @@ -22,6 +22,8 @@ use url::Url; use crate::NonZeroGRT; +const SHARED_PREFIX: &str = "INDEXER_"; + #[derive(Debug, Deserialize)] #[cfg_attr(test, derive(PartialEq))] pub struct Config { @@ -61,10 +63,10 @@ pub enum ConfigPrefix { } impl ConfigPrefix { - fn get_prefixes(&self) -> Vec<&'static str> { + fn get_prefix(&self) -> &'static str { match self { - Self::Tap => vec!["TAP_AGENT_", "INDEXER_"], - Self::Service => vec!["INDEXER_SERVICE_", "INDEXER_"], + Self::Tap => "TAP_AGENT_", + Self::Service => "INDEXER_SERVICE_", } } } @@ -81,11 +83,12 @@ impl Config { config_content = Self::substitute_env_vars(config_content)?; figment_config = figment_config.merge(Toml::string(&config_content)); } - for prefix_str in prefix.get_prefixes() { - figment_config = figment_config.merge(Env::prefixed(prefix_str).split("__")); - } + let config: ConfigWrapper = figment_config + .merge(Env::prefixed(prefix.get_prefix()).split("__")) + .merge(Env::prefixed(SHARED_PREFIX).split("__")) + .extract() + .map_err(|e| e.to_string())?; - let config: ConfigWrapper = figment_config.extract().map_err(|e| e.to_string())?; config.0.validate()?; Ok(config.0) } @@ -674,4 +677,47 @@ mod tests { "postgres://postgres@postgres/postgres" ); } + + // Test that we can fill in mandatory config fields missing from the config file with + // environment variables + #[sealed_test(files = ["minimal-config-example.toml"])] + fn test_fill_in_missing_with_shared_env() { + let mut minimal_config: toml::Value = toml::from_str( + fs::read_to_string("minimal-config-example.toml") + .unwrap() + .as_str(), + ) + .unwrap(); + // Remove the database.postgres_url field from minimal config + minimal_config + .get_mut("database") + .unwrap() + .as_table_mut() + .unwrap() + .remove("postgres_url"); + + // Save the modified minimal config to a named temporary file using tempfile + let temp_minimal_config_path = tempfile::NamedTempFile::new().unwrap(); + fs::write( + temp_minimal_config_path.path(), + toml::to_string(&minimal_config).unwrap(), + ) + .unwrap(); + + // No need to parse since from another test we know parsing at this point it will fail + + let test_value = "postgres://postgres@postgres:5432/postgres"; + env::set_var("INDEXER_DATABASE__POSTGRES_URL", test_value); + + let config = Config::parse( + ConfigPrefix::Service, + Some(PathBuf::from(temp_minimal_config_path.path())).as_ref(), + ) + .unwrap(); + + assert_eq!( + config.database.get_formated_postgres_url().as_str(), + test_value + ); + } }