datadog_agent_runtime/env/
mod.rs1use std::{future::Future, num::NonZeroUsize, path::PathBuf, time::Duration};
8
9use datadog_agent_commons::ipc::config::RemoteAgentClientConfiguration;
10use saluki_core::accounting::ComponentRegistry;
11use saluki_core::health::HealthRegistry;
12use saluki_core::runtime::Supervisor;
13use saluki_core::support::SubsystemIdentifier;
14use saluki_env::{
15 autodiscovery::providers::BoxedAutodiscoveryProvider,
16 host::providers::{BoxedHostProvider, FixedHostProvider},
17 EnvironmentProvider,
18};
19use saluki_error::{generic_error, GenericError};
20use tracing::warn;
21
22use crate::facade::AuthoritativeConfiguration;
23
24mod autodiscovery;
25pub use self::autodiscovery::RemoteAgentAutodiscoveryProvider;
26
27mod host;
28pub use self::host::RemoteAgentHostProvider;
29
30mod workload;
31pub use self::workload::RemoteAgentWorkloadProvider;
32
33const DEFAULT_STRING_INTERNER_SIZE_BYTES: NonZeroUsize = NonZeroUsize::new(512 * 1024).unwrap();
35const DEFAULT_CONTAINERD_CONNECTION_TIMEOUT: Duration = Duration::from_secs(1);
36const DEFAULT_CONTAINERD_QUERY_TIMEOUT: Duration = Duration::from_secs(5);
37
38pub(crate) fn root_provider_id() -> SubsystemIdentifier {
39 SubsystemIdentifier::from_segments(["env_provider"])
40}
41
42#[derive(Clone, Debug, Default)]
44#[non_exhaustive]
45pub struct HostSettings {
46 pub hostname: Option<String>,
51}
52
53#[derive(Clone, Debug)]
55#[non_exhaustive]
56pub struct WorkloadSettings {
57 pub string_interner_size_bytes: NonZeroUsize,
62
63 pub containerd_socket_path: Option<PathBuf>,
67
68 pub containerd_connection_timeout: Duration,
70
71 pub containerd_query_timeout: Duration,
73
74 pub proc_root: Option<PathBuf>,
78
79 pub cgroup_root: Option<PathBuf>,
83}
84
85impl WorkloadSettings {
86 pub fn new(string_interner_size_bytes: NonZeroUsize) -> Self {
88 Self {
89 string_interner_size_bytes,
90 ..Self::default()
91 }
92 }
93}
94
95impl Default for WorkloadSettings {
96 fn default() -> Self {
97 Self {
98 string_interner_size_bytes: DEFAULT_STRING_INTERNER_SIZE_BYTES,
99 containerd_socket_path: None,
100 containerd_connection_timeout: DEFAULT_CONTAINERD_CONNECTION_TIMEOUT,
101 containerd_query_timeout: DEFAULT_CONTAINERD_QUERY_TIMEOUT,
102 proc_root: None,
103 cgroup_root: None,
104 }
105 }
106}
107
108#[derive(Clone)]
121pub struct RemoteAgentEnvironmentProvider {
122 client_config: Option<RemoteAgentClientConfiguration>,
123 host_provider: BoxedHostProvider,
124 workload_provider: Option<RemoteAgentWorkloadProvider>,
125 autodiscovery_provider: Option<BoxedAutodiscoveryProvider>,
126 health_registry: HealthRegistry,
127}
128
129impl RemoteAgentEnvironmentProvider {
130 pub async fn from_authoritative<C>(
142 config: &C, component_registry: &ComponentRegistry, health_registry: &HealthRegistry,
143 ) -> Result<(Self, Option<Supervisor>), GenericError>
144 where
145 C: AuthoritativeConfiguration,
146 {
147 if config.is_standalone() {
148 let env = Self::standalone(&config.host(), health_registry)?;
149 Ok((env, None))
150 } else {
151 let client_config = config.client_configuration()?;
152 let (env, env_supervisor) =
153 Self::connected(&config.workload(), client_config, component_registry, health_registry).await?;
154 Ok((env, Some(env_supervisor)))
155 }
156 }
157
158 fn standalone(settings: &HostSettings, health_registry: &HealthRegistry) -> Result<Self, GenericError> {
159 warn!("Running in standalone mode. Origin detection/enrichment and other features dependent upon the Datadog Agent will not be available.");
160
161 let hostname = match &settings.hostname {
162 Some(hostname) if !hostname.is_empty() => hostname.clone(),
163 _ => {
164 return Err(generic_error!(
165 "A non-empty hostname must be configured (`hostname`) when running in standalone mode."
166 ))
167 }
168 };
169
170 Ok(Self {
171 client_config: None,
172 host_provider: BoxedHostProvider::from_provider(FixedHostProvider::new(hostname)),
173 workload_provider: None,
174 autodiscovery_provider: None,
175 health_registry: health_registry.clone(),
176 })
177 }
178
179 async fn connected(
180 settings: &WorkloadSettings, client_config: RemoteAgentClientConfiguration,
181 component_registry: &ComponentRegistry, health_registry: &HealthRegistry,
182 ) -> Result<(Self, Supervisor), GenericError> {
183 let mut env_supervisor = Supervisor::new("env-provider")?;
184
185 let host_provider = RemoteAgentHostProvider::new(&client_config, component_registry).await?;
186
187 let (workload_provider, workload_supervisor) =
188 RemoteAgentWorkloadProvider::new(settings, &client_config, component_registry, health_registry).await?;
189 env_supervisor.add_worker(workload_supervisor);
190
191 let (autodiscovery_provider, autodiscovery_supervisor) =
192 RemoteAgentAutodiscoveryProvider::new(&client_config).await?;
193 env_supervisor.add_worker(autodiscovery_supervisor);
194
195 let env = Self {
196 client_config: Some(client_config),
197 host_provider: BoxedHostProvider::from_provider(host_provider),
198 workload_provider: Some(workload_provider),
199 autodiscovery_provider: Some(BoxedAutodiscoveryProvider::from_provider(autodiscovery_provider)),
200 health_registry: health_registry.clone(),
201 };
202
203 Ok((env, env_supervisor))
204 }
205
206 pub fn client_configuration(&self) -> Option<&RemoteAgentClientConfiguration> {
208 self.client_config.as_ref()
209 }
210
211 pub fn wait_for_ready(&self) -> impl Future<Output = ()> + Send + 'static {
217 let health_registry = self.health_registry.clone();
218 let has_workload_provider = self.workload_provider.is_some();
219 async move {
220 if has_workload_provider {
221 health_registry.all_ready_under(root_provider_id()).await;
222 }
223 }
224 }
225}
226
227impl EnvironmentProvider for RemoteAgentEnvironmentProvider {
228 type Host = BoxedHostProvider;
229 type Workload = Option<RemoteAgentWorkloadProvider>;
230 type AutodiscoveryProvider = Option<BoxedAutodiscoveryProvider>;
231
232 fn host(&self) -> &Self::Host {
233 &self.host_provider
234 }
235
236 fn workload(&self) -> &Self::Workload {
237 &self.workload_provider
238 }
239
240 fn autodiscovery(&self) -> &Self::AutodiscoveryProvider {
241 &self.autodiscovery_provider
242 }
243}