Skip to content

Commit fe95fbe

Browse files
authored
aix: populate datadog.yaml from env vars in the config script (#54767)
<!--Please give us some feedback on your experience writing this PR ! https://app.datadoghq.com/forms/43db4c02-6837-400c-8083-692e141b1b88 !--> ### What does this PR do? Seeds `datadog.yaml` from `DD_API_KEY`/`DD_SITE`/`DD_HOSTNAME`/`DD_TAGS`/`DD_ENV`/`DD_INFRASTRUCTURE_MODE`/proxy env vars on first install, mirroring the Linux install script. ### Motivation installp has no mechanism to pass parameters at install time, so this is the only way to configure the agent unattended on AIX. ### Describe how you validated your changes Ran all creation/skip/`DD_INSTALL_ONLY` scenarios in a sandbox on a real AIX 7.3 host and confirmed the resulting YAML and file permissions. ### Additional Notes Co-authored-by: pierre.gimalac <pierre.gimalac@datadoghq.com>
1 parent eafd80b commit fe95fbe

5 files changed

Lines changed: 133 additions & 5 deletions

File tree

CHANGELOG-AIX.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
## Unreleased
1010

1111
<!-- Add entries here for changes not yet in a release. -->
12+
13+
- Populate `datadog.yaml` automatically on first install from `DD_API_KEY`, `DD_SITE`, `DD_HOSTNAME`, `DD_TAGS`, `DD_ENV`, `DD_INFRASTRUCTURE_MODE`, and proxy (`DD_PROXY_HTTP`/`DD_PROXY_HTTPS`/`DD_PROXY_NO_PROXY`, or generic `HTTP_PROXY`/`HTTPS_PROXY`/`NO_PROXY`) environment variables, mirroring the Linux install script; set `DD_INSTALL_ONLY` to skip starting the Agent.
1214
- Fix uninstallation: `unconfig` now uses `rmssys` only to deregister SRC subsystems, dropping the preceding `odmdelete` calls that left stale entries in the live srcmstr daemon
1315
- Set `NLSPATH` in the agent wrapper so the IBM MQ client library can locate its own message catalogs. Previously, `ibm_mq` check errors and other MQ client errors rendered as unreadable generic text (e.g. `AMQ9211E: Failed to find error message id`) instead of the real message, because the agent process only had AIX's default `NLSPATH` (`/usr/lib/nls/msg/...`), which doesn't include MQ's catalog directory.
1416
- Bump the embedded Python from 3.13.12 to 3.13.15, matching the version used by the Linux omnibus/bazel build

packaging/aix/package-scripts/config

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,48 @@
11
#!/bin/sh
2+
CONFIG_DIR=/etc/datadog-agent
3+
CONFIG_FILE="$CONFIG_DIR/datadog.yaml"
4+
EXAMPLE_FILE="$CONFIG_DIR/datadog.yaml.example"
5+
PYTHON=/opt/datadog-agent/embedded/bin/python3
6+
RENDER_SCRIPT=/opt/datadog-agent/embedded/share/installp/render-datadog-config.py
7+
8+
# installp has no mechanism to pass parameters/env vars at install time, so
9+
# this is the only way to configure the agent unattended on AIX (mirrors
10+
# https://github.com/DataDog/agent-linux-install-script). Only runs on a
11+
# fresh install: an existing datadog.yaml is left untouched.
12+
if [ ! -f "$CONFIG_FILE" ] && [ -n "$DD_API_KEY" ] && [ -f "$EXAMPLE_FILE" ] && [ -x "$PYTHON" ] && [ -f "$RENDER_SCRIPT" ]; then
13+
echo "Populating $CONFIG_FILE from environment variables..."
14+
# Rendered on a root-only (umask 077) staging file, only chowned/chmoded
15+
# and moved into place once done, so the real datadog.yaml never exists
16+
# readable by anyone but root.
17+
STAGING_FILE="$CONFIG_FILE.tmp.$$"
18+
19+
if (umask 077 && cp "$EXAMPLE_FILE" "$STAGING_FILE"); then
20+
"$PYTHON" "$RENDER_SCRIPT" "$STAGING_FILE"
21+
22+
if chown dd-agent:dd-agent "$STAGING_FILE" 2>/dev/null && chmod 640 "$STAGING_FILE" 2>/dev/null; then
23+
mv "$STAGING_FILE" "$CONFIG_FILE" 2>/dev/null
24+
fi
25+
fi
26+
rm -f "$STAGING_FILE" 2>/dev/null || true
27+
fi
28+
229
chown -R dd-agent:dd-agent /etc/datadog-agent \
330
/var/log/datadog \
431
/var/run/datadog \
532
/opt/datadog-agent 2>/dev/null || true
633

7-
if [ -f /etc/datadog-agent/datadog.yaml ]; then
8-
startsrc -s datadog-agent
9-
startsrc -s datadog-trace-agent
10-
startsrc -s datadog-agent-data-plane
34+
if [ -f "$CONFIG_FILE" ]; then
35+
if [ -z "$DD_INSTALL_ONLY" ]; then
36+
echo "Starting Datadog Agent services..."
37+
startsrc -s datadog-agent
38+
startsrc -s datadog-trace-agent
39+
startsrc -s datadog-agent-data-plane
40+
else
41+
echo ""
42+
echo "DD_INSTALL_ONLY is set: the Datadog Agent was not started."
43+
echo "Start it with: startsrc -s datadog-agent && startsrc -s datadog-trace-agent && startsrc -s datadog-agent-data-plane"
44+
echo ""
45+
fi
1146
else
1247
echo ""
1348
echo "Datadog Agent installed."

packaging/aix/package-scripts/postinst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ mkssys -s datadog-agent-data-plane \
6565
# Start (or restart) the agent if datadog.yaml exists.
6666
# On a fresh install this starts the agent for the first time.
6767
# On an upgrade the preinst stopped the services; this brings them back up.
68-
if [ -f /etc/datadog-agent/datadog.yaml ]; then
68+
# Skipped when DD_INSTALL_ONLY is set
69+
if [ -f /etc/datadog-agent/datadog.yaml ] && [ -z "$DD_INSTALL_ONLY" ]; then
6970
startsrc -s datadog-agent 2>/dev/null || true
7071
startsrc -s datadog-trace-agent 2>/dev/null || true
7172
startsrc -s datadog-agent-data-plane 2>/dev/null || true
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#!/opt/datadog-agent/embedded/bin/python3
2+
# Populates a copy of datadog.yaml.example from DD_* environment variables.
3+
# Invoked by the "config" installp script; see that script for why this is a
4+
# separate file (AIX sed has no -i, and interpolating env values into an
5+
# eval'd script is a code-injection risk) and why edits are staged rather
6+
# than applied to the real datadog.yaml directly (permissions).
7+
import os
8+
import sys
9+
10+
import yaml
11+
12+
13+
def env(*names, allow_empty=False):
14+
# allow_empty=True matches os.LookupEnv semantics (used by LoadProxyFromEnv
15+
# in pkg/config/setup/config.go): an explicit DD_PROXY_HTTP="" must
16+
# suppress a lower-priority HTTP_PROXY rather than fall through to it.
17+
for name in names:
18+
if allow_empty:
19+
if name in os.environ:
20+
return os.environ[name]
21+
elif os.environ.get(name):
22+
return os.environ[name]
23+
return None
24+
25+
26+
def split_list(value):
27+
# DD_TAGS and DD_PROXY_NO_PROXY both accept space or comma as separators.
28+
return [v for v in value.replace(",", " ").split() if v]
29+
30+
31+
path = sys.argv[1]
32+
with open(path) as f:
33+
lines = f.readlines()
34+
35+
# api_key is the only field with a real, uncommented line in the template;
36+
# the rest below ship commented out. Duplicate YAML keys resolve last-wins,
37+
# so it must be edited in place -- appending it instead would get
38+
# overridden by the template's own empty "api_key:" line.
39+
api_key = env("DD_API_KEY")
40+
for i, line in enumerate(lines):
41+
if line.startswith("api_key:"):
42+
value_yaml = yaml.safe_dump(api_key, default_flow_style=True).splitlines()[0]
43+
lines[i] = "api_key: " + value_yaml + "\n"
44+
break
45+
46+
extra = {}
47+
if site := env("DD_SITE"):
48+
extra["site"] = site
49+
if hostname := env("DD_HOSTNAME"):
50+
extra["hostname"] = hostname
51+
if environment := env("DD_ENV"):
52+
extra["env"] = environment
53+
if infrastructure_mode := env("DD_INFRASTRUCTURE_MODE"):
54+
extra["infrastructure_mode"] = infrastructure_mode
55+
if tags := env("DD_TAGS"):
56+
extra["tags"] = split_list(tags)
57+
58+
# DD_PROXY_* takes precedence over the generic HTTP_PROXY/HTTPS_PROXY/NO_PROXY
59+
# vars, matching the Agent's own env var resolution (LoadProxyFromEnv).
60+
proxy = {}
61+
if http_proxy := env("DD_PROXY_HTTP", "HTTP_PROXY", "http_proxy", allow_empty=True):
62+
proxy["http"] = http_proxy
63+
if https_proxy := env("DD_PROXY_HTTPS", "HTTPS_PROXY", "https_proxy", allow_empty=True):
64+
proxy["https"] = https_proxy
65+
if no_proxy := env("DD_PROXY_NO_PROXY", "NO_PROXY", "no_proxy", allow_empty=True):
66+
# DD_PROXY_NO_PROXY accepts space or comma; generic NO_PROXY is comma-only.
67+
if "DD_PROXY_NO_PROXY" in os.environ:
68+
proxy["no_proxy"] = split_list(no_proxy)
69+
else:
70+
proxy["no_proxy"] = [p for p in no_proxy.split(",") if p]
71+
if proxy:
72+
extra["proxy"] = proxy
73+
74+
with open(path, "w") as f:
75+
if extra:
76+
f.write(yaml.safe_dump(extra, default_flow_style=False) + "\n")
77+
f.writelines(lines)

packaging/aix/stages/11-assemble.sh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,19 @@ for script in preinst postinst config unconfig prerm; do
170170
done
171171
log "All package lifecycle scripts installed"
172172

173+
# render-datadog-config.py is a helper invoked by the "config" script above
174+
# (not a lifecycle script itself), staged alongside them for the same reason:
175+
# it must exist at its final installed path for "config" to find it at
176+
# install time.
177+
RENDER_SCRIPT_SRC="$PKGSCRIPTS_SRC/render-datadog-config.py"
178+
if [ ! -f "$RENDER_SCRIPT_SRC" ]; then
179+
log "ERROR: render-datadog-config.py not found: $RENDER_SCRIPT_SRC"
180+
exit 1
181+
fi
182+
cp "$RENDER_SCRIPT_SRC" "$SCRIPTS_DIR/render-datadog-config.py"
183+
cp "$RENDER_SCRIPT_SRC" "$SCRIPTS_INSTALLED/render-datadog-config.py"
184+
log "render-datadog-config.py installed to $SCRIPTS_DIR and $SCRIPTS_INSTALLED"
185+
173186
# ─── Step 5: Set correct ownership ────────────────────────────────────────────
174187
#
175188
# mkinstallp records the owning uid:gid of every file and directory in the

0 commit comments

Comments
 (0)