Expand description
Provides a client for remote configuration.
Configuration assigned to this client arrives through polling the Datadog Agent, which fetches it from the Datadog
backend. A subscriber supplies a ProductDecoder that names a product and decodes its payloads, then receives
typed snapshots through a Subscription. The crate keeps the client’s identity, its protocol cursor (the last
targets version), the cached paths it reports to the Agent, configuration path structure, and numeric apply states
private.
§Testing
With the test-util feature enabled, [TestPublisher] creates a Subscription that a test publishes into by
hand, either with finished snapshots and rejections or by running a decoder over payloads exactly as the client
does. A component that takes a Subscription can therefore be tested without an Agent.
§Trust
The client performs no TUF signature verification. It trusts the Agent, reached over an authenticated local IPC channel, to have verified already. It does validate that each payload matches the length and SHA-256 hash published in the accompanying targets metadata, which guards against a bug in delivery.
§Examples
A decoder for a product whose payload is a message, a consumer of its subscription, and a test of both through
[TestPublisher]:
use datadog_agent_remote_config::{ConfigId, ProductDecoder, RemoteConfigurationClient, Subscription, TestPublisher};
#[derive(Debug)]
struct Example {
message: String,
}
/// Keeps the last valid message in ascending configuration ID order.
#[derive(Default)]
struct ExampleDecoder {
message: Option<String>,
}
impl ProductDecoder for ExampleDecoder {
const PRODUCT: &'static str = "EXAMPLE_PRODUCT";
type Snapshot = Example;
type Error = String;
fn decode(&mut self, _id: &ConfigId, payload: &[u8]) -> Result<(), Self::Error> {
let message = std::str::from_utf8(payload).map_err(|_| "Message is not UTF-8.".to_owned())?;
self.message = Some(message.to_owned());
Ok(())
}
fn build(self) -> Result<Self::Snapshot, Self::Error> {
let message = self.message.ok_or_else(|| "No message was assigned.".to_owned())?;
Ok(Example { message })
}
}
/// Subscribes once where the application is wired together, and hands the subscription to its consumer.
fn wire(rc_client: &RemoteConfigurationClient) -> datadog_agent_remote_config::Result<()> {
let subscription = rc_client.subscribe::<ExampleDecoder>()?;
tokio::spawn(consume(subscription));
Ok(())
}
async fn consume(mut subscription: Subscription<Example>) {
// A snapshot accepted before the subscription was created is not announced by `changed`, so read it first.
if let Some(example) = subscription.current() {
println!("{}", example.message);
}
loop {
match subscription.changed().await {
Ok(example) => println!("{}", example.message),
// The client reports the rejection to the Agent; `current` still returns the last accepted snapshot.
Err(error) => eprintln!("{error}"),
}
}
}
// In a test, `TestPublisher` runs the decoder over payloads exactly as the client does.
let (publisher, mut subscription) = TestPublisher::<Example>::new();
publisher.assign::<ExampleDecoder>([("greeting.v1", "hello"), ("greeting.v2", "hi")]);
assert_eq!(subscription.changed().await.unwrap().message, "hi");
// A rejection keeps the last accepted snapshot. This decoder rejects an empty assignment only to show that; a real
// decoder must build from one, or an expired Agent cache leaves its last snapshot live.
publisher.assign::<ExampleDecoder>(Vec::<(&str, &str)>::new());
assert_eq!(*subscription.changed().await.unwrap_err(), "No message was assigned.");
assert_eq!(subscription.current().unwrap().message, "hi");Structs§
- Agent
Identity - What an
Agentclient reports. - Config
Id - Identifies one configuration assigned to a product.
- Json
Error - A payload that
decode_jsoncould not deserialize. - RcClient
Configuration - Settings for a
RemoteConfigurationClient. - Remote
Configuration Client - A cloneable handle for subscribing to Remote Configuration products.
- Remote
Configuration Worker - Drives polling and delivery for a
RemoteConfigurationClient. - Subscription
- A handle that observes one product’s configuration as the client publishes it.
Enums§
- Client
Kind - The kind of client the Agent sees, and the details that kind reports.
- Error
- An error produced by the remote configuration client.
Traits§
- Apply
Error - Converts a subscriber’s decoding error into a rejection message for the Agent.
- Product
Decoder - Decodes one product’s assigned configurations into a snapshot.
Functions§
- decode_
json - Deserializes a JSON payload, for a
decodeimplementation to call.
Type Aliases§
- Result
- A result produced by the remote configuration client.