diff --git a/Cargo.lock b/Cargo.lock index 25049a6..211bf24 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -396,7 +396,7 @@ dependencies = [ [[package]] name = "datadog-library-config" version = "0.0.1" -source = "git+https://github.com/DataDog/libdatadog.git?tag=v15.0.0#0ef49864317b0728648b2b7f26fe2f1deeeeebc4" +source = "git+https://github.com/DataDog/libdatadog.git?tag=v16.0.2#52bd068269da43fb216e278a8576184bf6307177" dependencies = [ "anyhow", "serde", diff --git a/crates/library_config/Cargo.toml b/crates/library_config/Cargo.toml index c5459ee..459ace0 100644 --- a/crates/library_config/Cargo.toml +++ b/crates/library_config/Cargo.toml @@ -8,7 +8,7 @@ crate-type = ["cdylib", "rlib"] [dependencies] anyhow = "1" -datadog-library-config = { git = "https://github.com/DataDog/libdatadog.git", tag = "v15.0.0" } +datadog-library-config = { git = "https://github.com/DataDog/libdatadog.git", tag = "v16.0.2" } wasm-bindgen = "0.2.84" serde = { version = "1.0", features = ["derive"] } diff --git a/crates/library_config/src/lib.rs b/crates/library_config/src/lib.rs index 897885b..61c0712 100644 --- a/crates/library_config/src/lib.rs +++ b/crates/library_config/src/lib.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; - use wasm_bindgen::prelude::*; #[wasm_bindgen] @@ -9,6 +7,43 @@ pub struct JsConfigurator { args: Vec, } +#[wasm_bindgen] +pub struct ConfigEntry { + name: String, + value: String, + source: String, + config_id: String, +} + +#[wasm_bindgen] +impl ConfigEntry { + #[wasm_bindgen(constructor)] + pub fn new(name: String, value: String, source: String, config_id: String) -> ConfigEntry { + ConfigEntry { + name, + value, + source, + config_id, + } + } + #[wasm_bindgen(getter)] + pub fn name(&self) -> String { + self.name.clone() + } + #[wasm_bindgen(getter)] + pub fn value(&self) -> String { + self.value.clone() + } + #[wasm_bindgen(getter)] + pub fn source(&self) -> String { + self.source.clone() + } + #[wasm_bindgen(getter)] + pub fn config_id(&self) -> String { + self.config_id.clone() + } +} + #[wasm_bindgen] impl JsConfigurator { #[wasm_bindgen(constructor)] @@ -22,54 +57,77 @@ impl JsConfigurator { #[wasm_bindgen] pub fn set_envp(&mut self, envp: Box<[JsValue]>) -> Result<(), JsValue> { - self.envp = envp.iter() - .filter_map(|val| val.as_string()) - .collect(); + self.envp = envp.iter().filter_map(|val| val.as_string()).collect(); Ok(()) } #[wasm_bindgen] pub fn set_args(&mut self, args: Box<[JsValue]>) -> Result<(), JsValue> { - self.args = args.iter() - .filter_map(|val| val.as_string()) - .collect(); + self.args = args.iter().filter_map(|val| val.as_string()).collect(); Ok(()) } + #[wasm_bindgen] + pub fn get_config_local_path(&self, target: String) -> Result { + let target_enum = match target.as_str() { + "linux" => datadog_library_config::Target::Linux, + "win32" => datadog_library_config::Target::Windows, + "darwin" => datadog_library_config::Target::Macos, + _ => return Err(JsValue::from_str("Unsupported target")), + }; + Ok( + datadog_library_config::Configurator::local_stable_configuration_path(target_enum) + .to_string(), + ) + } + + #[wasm_bindgen] + pub fn get_config_managed_path(&self, target: String) -> Result { + let target_enum = match target.as_str() { + "linux" => datadog_library_config::Target::Linux, + "win32" => datadog_library_config::Target::Windows, + "darwin" => datadog_library_config::Target::Macos, + _ => return Err(JsValue::from_str("Unsupported target")), + }; + Ok( + datadog_library_config::Configurator::fleet_stable_configuration_path(target_enum) + .to_string(), + ) + } + #[wasm_bindgen] pub fn get_configuration( &self, - config_string: String, - ) -> Result { - let envp: Vec<&[u8]> = self - .envp - .iter() - .map(|s| s.as_bytes()) - .collect(); + config_string_local: String, + config_string_managed: String, + ) -> Result, JsValue> { + let envp: Vec> = self.envp.iter().map(|s| s.as_bytes().to_vec()).collect(); - let args: Vec<_> = self - .args - .iter() - .map(|s| s.as_bytes()) - .collect(); + let args: Vec> = self.args.iter().map(|s| s.as_bytes().to_vec()).collect(); let res_config = self.configurator.get_config_from_bytes( - config_string.as_bytes(), + config_string_local.as_bytes(), + config_string_managed.as_bytes(), datadog_library_config::ProcessInfo { - envp: &envp, - args: &args, - language: b"nodejs", + envp: envp, + args: args, + language: b"nodejs".to_vec(), }, ); match res_config { Ok(config) => { - let hashmap: HashMap = config.into_iter().map(|c| { - let key = c.name.to_str().to_owned(); - (key, c.value) - }).collect(); - Ok(serde_wasm_bindgen::to_value(&hashmap)?) - }, + let config_entries: Vec = config + .into_iter() + .map(|c| ConfigEntry { + name: c.name.to_str().into(), + value: c.value, + source: c.source.to_str().into(), + config_id: c.config_id.unwrap_or_default(), + }) + .collect(); + Ok(config_entries) + } Err(e) => Err(JsValue::from_str(&format!( "Failed to get configuration: {:?}", e diff --git a/test/wasm/library_config/README.md b/test/wasm/library_config/README.md index 4e58f07..ca98e96 100644 --- a/test/wasm/library_config/README.md +++ b/test/wasm/library_config/README.md @@ -1,6 +1,6 @@ # Libconfig example -## How to run +## How to run From repository root ```bash yarn build-wasm diff --git a/test/wasm/library_config/config_local_phase1.yaml b/test/wasm/library_config/config_local_phase1.yaml new file mode 100644 index 0000000..f9c6b62 --- /dev/null +++ b/test/wasm/library_config/config_local_phase1.yaml @@ -0,0 +1,2 @@ +apm_configuration_default: + DD_RUNTIME_METRICS_ENABLED: true diff --git a/test/wasm/library_config/config_local_phase2.yaml b/test/wasm/library_config/config_local_phase2.yaml new file mode 100644 index 0000000..f9c6b62 --- /dev/null +++ b/test/wasm/library_config/config_local_phase2.yaml @@ -0,0 +1,2 @@ +apm_configuration_default: + DD_RUNTIME_METRICS_ENABLED: true diff --git a/test/wasm/library_config/config.yaml b/test/wasm/library_config/config_managed_phase2.yaml similarity index 68% rename from test/wasm/library_config/config.yaml rename to test/wasm/library_config/config_managed_phase2.yaml index 0bdcd11..28c3302 100644 --- a/test/wasm/library_config/config.yaml +++ b/test/wasm/library_config/config_managed_phase2.yaml @@ -5,4 +5,5 @@ rules: - nodejs operator: equals configuration: - DD_SERVICE: my-service + DD_SERVICE: my-service_butremote +config_id: abc diff --git a/test/wasm/library_config/index.js b/test/wasm/library_config/index.js index a5283e8..64a60f8 100644 --- a/test/wasm/library_config/index.js +++ b/test/wasm/library_config/index.js @@ -6,17 +6,52 @@ const assert = require('assert'); const libconfig = loader.load('library_config'); assert(libconfig !== undefined); -const rawConfig = fs.readFileSync(path.join(__dirname, 'config.yaml')); -let configurator = new libconfig.JsConfigurator(); +// Test 1: phase 1 (host selection) +function test_host_wide() { + const rawConfigLocal = fs.readFileSync(path.join(__dirname, 'config_local_phase1.yaml')); + let configurator = new libconfig.JsConfigurator(); -configurator.set_envp(Object.entries(process.env).map(([key, value]) => `${key}=${value}`)) -configurator.set_args(process.argv) + configurator.set_envp(Object.entries(process.env).map(([key, value]) => `${key}=${value}`)) + configurator.set_args(process.argv) -// Apply each configuration as an environment variable -let values = {} -configurator.get_configuration(rawConfig.toString()).forEach((value, key, map) => { - values[key] = value - console.log(`Got ${key}=${value}`) -}); + let values = configurator.get_configuration(rawConfigLocal.toString(), "") + values.forEach((value, key, map) => { + console.log(`(phase 1) name: ${value.name}, value: ${value.value}, source: ${value.source}, config_id: ${value.config_id}`) + }); -assert.strictEqual(values['DD_SERVICE'], 'my-service') + assert.strictEqual(values.length, 1) + assert.strictEqual(values[0].name, 'DD_RUNTIME_METRICS_ENABLED') + assert.strictEqual(values[0].value, 'true') + assert.strictEqual(values[0].source, 'local_stable_config') +} + +// Test 2: managed > local, phase 2 (service selection) +function test_service_selector() { + const rawConfigLocal = fs.readFileSync(path.join(__dirname, 'config_local_phase2.yaml')); + const rawConfigManaged = fs.readFileSync(path.join(__dirname, 'config_managed_phase2.yaml')); + let configurator = new libconfig.JsConfigurator(); + + configurator.set_envp(Object.entries(process.env).map(([key, value]) => `${key}=${value}`)) + configurator.set_args(process.argv) + + values = configurator.get_configuration(rawConfigLocal.toString(), rawConfigManaged.toString()) + values.forEach((value, key, map) => { + console.log(`(phase 2) name: ${value.name}, value: ${value.value}, source: ${value.source}, config_id: ${value.config_id}`) + }); + + assert.strictEqual(values.length, 2) + assert.strictEqual(values[0].name, 'DD_RUNTIME_METRICS_ENABLED') + assert.strictEqual(values[0].value, 'true') + assert.strictEqual(values[0].source, 'local_stable_config') + + if (process.platform == 'linux') { + assert.strictEqual(configurator.get_config_local_path(process.platform), "/etc/datadog-agent/application_monitoring.yaml"); + } else if (process.platform == 'darwin') { + assert.strictEqual(configurator.get_config_local_path(process.platform), "/opt/datadog-agent/etc/application_monitoring.yaml"); + } else if (process.platform == 'win32') { + assert.strictEqual(configurator.get_config_local_path(process.platform), "C:\\ProgramData\\Datadog\\application_monitoring.yaml"); + } +} + +test_host_wide(); +test_service_selector();