datadog_agent_commons/platform/linux_impl.rs
1//! Linux (and AIX) platform settings.
2//!
3//! Two filesystem layouts are supported, matching the Core Agent:
4//!
5//! - the FHS layout (the default), where configuration lives in `/etc/datadog-agent` and logs live in
6//! `/var/log/datadog`, and
7//! - the "common root" layout, selected by the `DD_COMMON_ROOT` environment variable, where every directory the Agent
8//! owns is collapsed under a single root: `{root}/etc`, `{root}/logs`, `{root}/run`, and so on.
9//!
10//! The common root layout exists to support installs where the root filesystem is read-only and the Agent cannot
11//! scatter writes across `/etc` and `/var`. The Core Agent implements it in `pkg/util/defaultpaths`
12//! (`commonRootOrPath`), and reads the environment variable during package initialization rather than from its own
13//! configuration, because the layout determines where the configuration file itself is found.
14//!
15//! We resolve it the same way, and for the same reason: the paths derived here (the configuration file, the IPC auth
16//! token, and the IPC certificate) are all needed during bootstrap, before ADP has registered with the Core Agent and
17//! can receive its resolved configuration. Paths that arrive over the configuration stream have already been resolved
18//! by the Core Agent against its own root, and must not be transformed again.
19
20use std::{
21 env,
22 ffi::OsStr,
23 path::{Path, PathBuf},
24 sync::OnceLock,
25};
26
27/// Default configuration directory for the Datadog Agent.
28///
29/// This is the FHS layout, used when the common root layout is not selected. It is deliberately private: callers must
30/// go through [`get_config_dir_path`] so that the common root is never circumvented.
31const DATADOG_AGENT_CONF_DIR: &str = "/etc/datadog-agent";
32
33/// Default log directory for the Datadog Agent.
34///
35/// This is the FHS layout, used when the common root layout is not selected. It is deliberately private: callers must
36/// go through [`get_log_dir_path`] so that the common root is never circumvented.
37const DATADOG_AGENT_LOG_DIR: &str = "/var/log/datadog";
38
39/// Default local syslog URI for the Datadog Agent.
40const DATADOG_AGENT_DEFAULT_SYSLOG_URI: &str = "unixgram:///dev/log";
41
42/// Environment variable that selects the common root layout.
43const COMMON_ROOT_ENV_VAR: &str = "DD_COMMON_ROOT";
44
45/// Common root used when `DD_COMMON_ROOT` is set but carries no value.
46const DEFAULT_COMMON_ROOT: &str = "/opt/datadog-agent";
47
48/// Configuration subdirectory of the common root.
49const COMMON_ROOT_CONF_SUBDIR: &str = "etc";
50
51/// Log subdirectory of the common root.
52const COMMON_ROOT_LOG_SUBDIR: &str = "logs";
53
54static CONFIG_DIR: OnceLock<PathBuf> = OnceLock::new();
55static LOG_DIR: OnceLock<PathBuf> = OnceLock::new();
56
57/// Returns the path to the default Datadog Agent configuration directory.
58pub fn get_config_dir_path() -> &'static Path {
59 CONFIG_DIR
60 .get_or_init(|| config_dir_for(common_root().as_deref()))
61 .as_path()
62}
63
64/// Returns the path to the default Datadog Agent log directory.
65pub fn get_log_dir_path() -> &'static Path {
66 LOG_DIR.get_or_init(|| log_dir_for(common_root().as_deref())).as_path()
67}
68
69/// Returns the default local syslog URI for the Datadog Agent.
70pub const fn get_default_syslog_uri() -> &'static str {
71 DATADOG_AGENT_DEFAULT_SYSLOG_URI
72}
73
74/// Reads the configured common root from the environment.
75fn common_root() -> Option<PathBuf> {
76 parse_common_root(env::var_os(COMMON_ROOT_ENV_VAR).as_deref())
77}
78
79/// Resolves the common root from the raw environment variable value.
80///
81/// An unset variable leaves the FHS layout in place. A variable that is set but empty selects the common root layout
82/// rooted at [`DEFAULT_COMMON_ROOT`], which matches the Core Agent and allows the layout to be switched on without
83/// having to name a location.
84fn parse_common_root(value: Option<&OsStr>) -> Option<PathBuf> {
85 match value {
86 None => None,
87 Some(value) if value.is_empty() => Some(PathBuf::from(DEFAULT_COMMON_ROOT)),
88 Some(value) => Some(PathBuf::from(value)),
89 }
90}
91
92/// Returns the configuration directory for the given common root, falling back to the FHS layout when unset.
93fn config_dir_for(common_root: Option<&Path>) -> PathBuf {
94 match common_root {
95 Some(root) => root.join(COMMON_ROOT_CONF_SUBDIR),
96 None => PathBuf::from(DATADOG_AGENT_CONF_DIR),
97 }
98}
99
100/// Returns the log directory for the given common root, falling back to the FHS layout when unset.
101fn log_dir_for(common_root: Option<&Path>) -> PathBuf {
102 match common_root {
103 Some(root) => root.join(COMMON_ROOT_LOG_SUBDIR),
104 None => PathBuf::from(DATADOG_AGENT_LOG_DIR),
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use std::{
111 ffi::OsStr,
112 path::{Path, PathBuf},
113 };
114
115 use super::{config_dir_for, log_dir_for, parse_common_root};
116
117 #[test]
118 fn common_root_is_unset_by_default() {
119 assert_eq!(parse_common_root(None), None);
120 }
121
122 #[test]
123 fn common_root_falls_back_to_the_default_root_when_set_but_empty() {
124 assert_eq!(
125 parse_common_root(Some(OsStr::new(""))),
126 Some(PathBuf::from("/opt/datadog-agent"))
127 );
128 }
129
130 #[test]
131 fn common_root_uses_the_configured_value() {
132 assert_eq!(
133 parse_common_root(Some(OsStr::new("/mnt/datadog"))),
134 Some(PathBuf::from("/mnt/datadog"))
135 );
136 }
137
138 #[test]
139 fn directories_use_the_fhs_layout_without_a_common_root() {
140 assert_eq!(config_dir_for(None), PathBuf::from("/etc/datadog-agent"));
141 assert_eq!(log_dir_for(None), PathBuf::from("/var/log/datadog"));
142 }
143
144 #[test]
145 fn directories_are_derived_from_the_common_root() {
146 let root = Path::new("/mnt/datadog");
147
148 assert_eq!(config_dir_for(Some(root)), PathBuf::from("/mnt/datadog/etc"));
149 assert_eq!(log_dir_for(Some(root)), PathBuf::from("/mnt/datadog/logs"));
150 }
151}