From bebd7a4d093d61f14d94888066afc7135ff367c7 Mon Sep 17 00:00:00 2001 From: Kyle-Neale Date: Fri, 8 May 2026 12:53:55 -0400 Subject: [PATCH] feat(base): add get_agent_embedded_path helper Resolve paths under the agent's `embedded` directory by reading `run_path` from the agent config instead of assuming the install sits at `/opt/datadog-agent`. Works for both standard installs and Remote-Management installs at `/opt/datadog-packages/datadog-agent/`. Returns `None` when `run_path` is unset so callers can decide whether the miss is fatal (raise) or skip a fallback. Refs: AI-5681 Follow-up to #20574 which inlined this lookup in glusterfs. Co-Authored-By: Claude Opus 4.7 (1M context) --- datadog_checks_base/changelog.d/23487.fixed | 1 + .../datadog_checks/base/utils/agent/common.py | 22 +++++++++ .../tests/base/utils/test_agent_common.py | 49 +++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 datadog_checks_base/changelog.d/23487.fixed create mode 100644 datadog_checks_base/tests/base/utils/test_agent_common.py diff --git a/datadog_checks_base/changelog.d/23487.fixed b/datadog_checks_base/changelog.d/23487.fixed new file mode 100644 index 0000000000000..c420621b3d3a1 --- /dev/null +++ b/datadog_checks_base/changelog.d/23487.fixed @@ -0,0 +1 @@ +Add `get_agent_embedded_path` helper to resolve paths under the agent's embedded directory regardless of install location. \ No newline at end of file diff --git a/datadog_checks_base/datadog_checks/base/utils/agent/common.py b/datadog_checks_base/datadog_checks/base/utils/agent/common.py index 18a15fb62727d..39912ae810b93 100644 --- a/datadog_checks_base/datadog_checks/base/utils/agent/common.py +++ b/datadog_checks_base/datadog_checks/base/utils/agent/common.py @@ -1,5 +1,27 @@ # (C) Datadog, Inc. 2019-present # All rights reserved # Licensed under a 3-clause BSD style license (see LICENSE) +import os + +try: + import datadog_agent +except ImportError: + from datadog_checks.base.stubs import datadog_agent + METRIC_NAMESPACE_METRICS = 'datadog.agent.metrics' METRIC_NAMESPACE_PROFILE = 'datadog.agent.profile' + + +def get_agent_embedded_path(*parts: str) -> str | None: + """Resolve a path under the agent's `embedded` directory from the agent's `run_path` config. + + Returns ``None`` when ``run_path`` is unset so callers can decide whether the + miss is fatal or merely skips a fallback. Works for both the standard install + (``/opt/datadog-agent/run``) and Remote-Management installs + (``/opt/datadog-packages/datadog-agent//run``). + """ + run_path = datadog_agent.get_config('run_path') + if not run_path: + return None + install_path = run_path[:-4] if run_path.endswith('/run') else run_path + return os.path.join(install_path, 'embedded', *parts) diff --git a/datadog_checks_base/tests/base/utils/test_agent_common.py b/datadog_checks_base/tests/base/utils/test_agent_common.py new file mode 100644 index 0000000000000..09ce0c9f21c95 --- /dev/null +++ b/datadog_checks_base/tests/base/utils/test_agent_common.py @@ -0,0 +1,49 @@ +# (C) Datadog, Inc. 2026-present +# All rights reserved +# Licensed under a 3-clause BSD style license (see LICENSE) +import mock + +from datadog_checks.base.utils.agent.common import get_agent_embedded_path + + +class TestGetAgentEmbeddedPath: + def test_standard_install(self): + with mock.patch( + 'datadog_checks.base.utils.agent.common.datadog_agent.get_config', + return_value='/opt/datadog-agent/run', + ): + assert get_agent_embedded_path('sbin', 'gstatus') == '/opt/datadog-agent/embedded/sbin/gstatus' + + def test_remote_management_install(self): + with mock.patch( + 'datadog_checks.base.utils.agent.common.datadog_agent.get_config', + return_value='/opt/datadog-packages/datadog-agent/7.79.0/run', + ): + assert ( + get_agent_embedded_path('sbin', 'gstatus') + == '/opt/datadog-packages/datadog-agent/7.79.0/embedded/sbin/gstatus' + ) + + def test_missing_run_path_returns_none(self): + with mock.patch( + 'datadog_checks.base.utils.agent.common.datadog_agent.get_config', + return_value='', + ): + assert get_agent_embedded_path('sbin', 'gstatus') is None + + def test_run_path_without_trailing_run(self): + with mock.patch( + 'datadog_checks.base.utils.agent.common.datadog_agent.get_config', + return_value='/custom/agent/dir', + ): + assert ( + get_agent_embedded_path('ssl', 'certs', 'cacert.pem') + == '/custom/agent/dir/embedded/ssl/certs/cacert.pem' + ) + + def test_no_parts_returns_embedded_dir(self): + with mock.patch( + 'datadog_checks.base.utils.agent.common.datadog_agent.get_config', + return_value='/opt/datadog-agent/run', + ): + assert get_agent_embedded_path() == '/opt/datadog-agent/embedded'