Skip to main content

datadog_agent_runtime/env/
host.rs

1use async_trait::async_trait;
2use datadog_agent_commons::ipc::{client::RemoteAgentClient, config::RemoteAgentClientConfiguration};
3use saluki_core::accounting::{ComponentRegistry, MemoryBounds, MemoryBoundsBuilder};
4use saluki_env::HostProvider;
5use saluki_error::GenericError;
6use tokio::sync::OnceCell;
7
8use crate::env::root_provider_id;
9
10/// Datadog Agent-based host provider.
11///
12/// This provider is based on the internal gRPC API exposed by the Datadog Agent which exposes a way to get the hostname
13/// as detected by the Datadog Agent.
14#[derive(Clone)]
15pub struct RemoteAgentHostProvider {
16    client: RemoteAgentClient,
17    cached_hostname: OnceCell<String>,
18}
19
20impl RemoteAgentHostProvider {
21    /// Creates a new `RemoteAgentHostProvider` from the given configuration.
22    ///
23    /// # Errors
24    ///
25    /// If the Agent gRPC client can't be created (invalid API endpoint, missing authentication token, etc), or if the
26    /// authentication token is invalid, an error will be returned.
27    pub async fn new(
28        client_config: &RemoteAgentClientConfiguration, component_registry: &ComponentRegistry,
29    ) -> Result<Self, GenericError> {
30        let client = RemoteAgentClient::connect(client_config).await?;
31
32        let host_provider = Self {
33            client,
34            cached_hostname: OnceCell::new(),
35        };
36
37        let host_provider_id = root_provider_id().child("host").child("remote_agent");
38        let mut bounds_builder = component_registry.bounds_builder(&host_provider_id);
39        host_provider.specify_bounds(&mut bounds_builder);
40
41        Ok(host_provider)
42    }
43
44    async fn get_or_fetch_hostname(&self) -> Result<String, GenericError> {
45        self.cached_hostname
46            .get_or_try_init(|| {
47                let mut client = self.client.clone();
48                async move { client.get_hostname().await }
49            })
50            .await
51            .cloned()
52    }
53}
54
55#[async_trait]
56impl HostProvider for RemoteAgentHostProvider {
57    type Error = GenericError;
58
59    async fn get_hostname(&self) -> Result<String, Self::Error> {
60        self.get_or_fetch_hostname().await
61    }
62}
63
64impl MemoryBounds for RemoteAgentHostProvider {
65    fn specify_bounds(&self, builder: &mut MemoryBoundsBuilder) {
66        builder.minimum().with_single_value::<Self>("component struct");
67    }
68}