Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/library_config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }
Expand Down
118 changes: 88 additions & 30 deletions crates/library_config/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::collections::HashMap;

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
Expand All @@ -9,6 +7,43 @@ pub struct JsConfigurator {
args: Vec<String>,
}

#[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)]
Expand All @@ -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<String, JsValue> {
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<String, JsValue> {
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<JsValue, JsValue> {
let envp: Vec<&[u8]> = self
.envp
.iter()
.map(|s| s.as_bytes())
.collect();
config_string_local: String,
config_string_managed: String,
) -> Result<Vec<ConfigEntry>, JsValue> {
let envp: Vec<Vec<u8>> = 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<Vec<u8>> = 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<String, String> = 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<ConfigEntry> = 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
Expand Down
2 changes: 1 addition & 1 deletion test/wasm/library_config/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Libconfig example

## How to run
## How to run
From repository root
```bash
yarn build-wasm
Expand Down
2 changes: 2 additions & 0 deletions test/wasm/library_config/config_local_phase1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
apm_configuration_default:
DD_RUNTIME_METRICS_ENABLED: true
2 changes: 2 additions & 0 deletions test/wasm/library_config/config_local_phase2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
apm_configuration_default:
DD_RUNTIME_METRICS_ENABLED: true
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ rules:
- nodejs
operator: equals
configuration:
DD_SERVICE: my-service
DD_SERVICE: my-service_butremote
config_id: abc
57 changes: 46 additions & 11 deletions test/wasm/library_config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();