Skip to content

Commit 5d7bba2

Browse files
bojbrookrobertomonteromiguelquinna-hwantsui
authored
Add Origin Detection testing (#5310)
Co-authored-by: robertomonteromiguel <[email protected]> Co-authored-by: quinna-h <[email protected]> Co-authored-by: wantsui <[email protected]>
1 parent f338d34 commit 5d7bba2

File tree

6 files changed

+164
-14
lines changed

6 files changed

+164
-14
lines changed

tests/auto_inject/test_auto_inject_install.py

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,50 @@ def test_profiling(self):
5454
logger.info(f"Done test_install for : [{context.vm_name}]")
5555

5656

57+
@features.origin_detection
5758
@features.container_auto_installation_script
5859
@scenarios.container_auto_injection_install_script
5960
class TestContainerAutoInjectInstallScript(base.AutoInjectBaseTest):
61+
ruby_bug_platforms = [
62+
"AlamaLinux_9_amd64",
63+
"AlamaLinux_9_arm64",
64+
"Amazon_Linux_2022_amd64",
65+
"Amazon_Linux_2022_arm64",
66+
"Amazon_Linux_2023_amd64",
67+
"Amazon_Linux_2023_arm64",
68+
"Debian_11_amd64",
69+
"Debian_11_arm64",
70+
"Debian_12_amd64",
71+
"Debian_12_arm64",
72+
"OracleLinux_9_2_amd64",
73+
"OracleLinux_9_2_arm64",
74+
"OracleLinux_9_3_amd64",
75+
"OracleLinux_9_3_arm64",
76+
"RedHat_9_0_amd64",
77+
"RedHat_9_0_arm64",
78+
"RockyLinux_9_amd64",
79+
"RockyLinux_9_arm64",
80+
"Ubuntu_22_amd64",
81+
"Ubuntu_22_arm64",
82+
"Ubuntu_23_04_arm64",
83+
"Ubuntu_23_10_arm64",
84+
"Ubuntu_24_10_amd64",
85+
"Ubuntu_24_10_arm64",
86+
"Ubuntu_24_amd64",
87+
"Ubuntu_24_arm64",
88+
"Ubuntu_25_04_amd64",
89+
"Ubuntu_25_04_arm64",
90+
]
91+
92+
@missing_feature(
93+
context.vm_name in ruby_bug_platforms,
94+
library="ruby",
95+
reason="""Missing TCP cgroup2 support.
96+
See: https://datadoghq.atlassian.net/wiki/spaces/TS/pages/3189670032/Traces+missing+container+tags+with+cgroup+V2#Tracer-Side
97+
""",
98+
)
6099
def test_install(self):
61-
self._test_install(context.virtual_machine)
100+
self._test_install(context.virtual_machine, origin_detection=True)
62101

63102

64103
@features.container_auto_installation_script_profiling
@@ -200,6 +239,29 @@ def test_no_world_writeable(self):
200239
logger.info(f"Done test_no_world_writeable for : [{virtual_machine.name}]")
201240

202241

242+
@features.origin_detection
243+
@scenarios.simple_installer_auto_injection
244+
@scenarios.multi_installer_auto_injection
245+
class TestSimpleInstallerAutoInjectManualOriginDetection(base.AutoInjectBaseTest):
246+
@irrelevant(
247+
condition="container" not in context.weblog_variant and "alpine" not in context.weblog_variant,
248+
reason="Origin detection is not supported on host environments",
249+
)
250+
@irrelevant(
251+
context.library > "[email protected]" and context.installed_language_runtime < "3.8.0",
252+
reason="python 3.7 is not supported on ddtrace >= 3.x",
253+
)
254+
def test_origin_detection(self):
255+
virtual_machine = context.virtual_machine
256+
logger.info(
257+
f"Launching test_origin_detection for : [{virtual_machine.name}] [{virtual_machine.get_deployed_weblog().runtime_version}]..."
258+
)
259+
self._test_install(virtual_machine, origin_detection=True)
260+
logger.info(
261+
f"Done test_origin_detection for : [{virtual_machine.name}][{virtual_machine.get_deployed_weblog().runtime_version}]"
262+
)
263+
264+
203265
@features.auto_instrumentation_appsec
204266
@scenarios.simple_auto_injection_appsec
205267
class TestSimpleInstallerAutoInjectManualAppsec(base.AutoInjectBaseTest):

tests/auto_inject/utils.py

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,35 @@
77

88

99
class AutoInjectBaseTest:
10-
def _test_install(self, virtual_machine, *, profile: bool = False, appsec: bool = False):
10+
def _test_install(
11+
self, virtual_machine, *, profile: bool = False, appsec: bool = False, origin_detection: bool = False
12+
):
1113
"""If there is a multicontainer app, we need to make a request to each app"""
1214

1315
if virtual_machine.get_deployed_weblog().app_type == "multicontainer":
1416
for app in virtual_machine.get_deployed_weblog().multicontainer_apps:
1517
vm_context_url = (
1618
f"http://{virtual_machine.get_ip()}:{virtual_machine.deffault_open_port}{app.app_context_url}"
1719
)
18-
self._check_install(virtual_machine, vm_context_url, profile=profile, appsec=appsec)
20+
self._check_install(
21+
virtual_machine, vm_context_url, profile=profile, appsec=appsec, origin_detection=origin_detection
22+
)
1923

2024
else:
2125
vm_context_url = f"http://{virtual_machine.get_ip()}:{virtual_machine.deffault_open_port}{virtual_machine.get_deployed_weblog().app_context_url}"
22-
self._check_install(virtual_machine, vm_context_url, profile=profile, appsec=appsec)
26+
self._check_install(
27+
virtual_machine, vm_context_url, profile=profile, appsec=appsec, origin_detection=origin_detection
28+
)
2329

24-
def _check_install(self, virtual_machine, vm_context_url, *, profile: bool = False, appsec: bool = False):
30+
def _check_install(
31+
self,
32+
virtual_machine,
33+
vm_context_url,
34+
*,
35+
profile: bool = False,
36+
appsec: bool = False,
37+
origin_detection: bool = False,
38+
):
2539
"""We can easily install agent and lib injection software from agent installation script. Given a sample application we can enable tracing using local environment variables.
2640
After starting application we can see application HTTP requests traces in the backend.
2741
Using the agent installation script we can install different versions of the software (release or beta) in different OS.
@@ -49,6 +63,8 @@ def _check_install(self, virtual_machine, vm_context_url, *, profile: bool = Fal
4963
validator = None
5064
if appsec:
5165
validator = self._appsec_validator
66+
if origin_detection:
67+
validator = self._container_tags_validator
5268

5369
try:
5470
wait_backend_trace_id(request_uuid, profile=profile, validator=validator)
@@ -77,6 +93,21 @@ def _appsec_validator(self, _, trace_data):
7793

7894
return True
7995

96+
def _container_tags_validator(self, _, trace_data):
97+
root_id = trace_data["trace"]["root_id"]
98+
root_span = trace_data["trace"]["spans"][root_id]
99+
100+
# Check if container tags exist in the trace metadata
101+
meta = root_span.get("meta", {})
102+
container_tags = meta.get("_dd.tags.container")
103+
104+
if container_tags:
105+
logger.info(f"Found container tags: {container_tags}")
106+
return True
107+
else:
108+
logger.error(f"No container tags found in trace. Available meta keys: {list(meta.keys())}")
109+
return False
110+
80111
def _log_trace_debug_message(self, exc: Exception, request_uuid: str) -> None:
81112
logger.error(
82113
f"❌ Exception during trace in backend verification: {exc}\n"

utils/_features.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1921,6 +1921,16 @@ def host_auto_installation_script_profiling(test_object):
19211921
"""
19221922
return _mark_test_object(test_object, feature_id=306, owner=_Owner.auto_instrumentation)
19231923

1924+
@staticmethod
1925+
def origin_detection(test_object):
1926+
"""Origin Detection is a feature that allows the Agent to correctly detect and tag incoming custom
1927+
metrics or traces with their Origin (AKA container tags).
1928+
1929+
https://feature-parity.us1.prod.dog/#/?feature=362
1930+
1931+
"""
1932+
return _mark_test_object(test_object, feature_id=362, owner=_Owner.language_platform)
1933+
19241934
@staticmethod
19251935
def container_auto_installation_script_profiling(test_object):
19261936
"""Profiling works when enabled through the agent installer script in Container environments

utils/build/virtual_machine/provisions/auto-inject/auto-inject_installer_manual.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,39 @@
99
local_path: binaries/
1010

1111
remote-command: |
12+
# Check if Docker is installed and ensure it's running
13+
if command -v docker >/dev/null 2>&1; then
14+
echo "Docker is installed, ensuring service is enabled and running..."
15+
sudo systemctl enable docker.service docker.socket
16+
17+
if ! sudo systemctl is-active --quiet docker.service; then
18+
echo "Docker service is not running, starting it..."
19+
sudo systemctl start docker.service docker.socket
20+
21+
# Wait for Docker to be fully ready
22+
echo "Waiting for Docker service to be ready..."
23+
MAX_WAIT=20
24+
COUNTER=0
25+
while [ $COUNTER -lt $MAX_WAIT ]; do
26+
if sudo docker info >/dev/null 2>&1; then
27+
echo "Docker service is ready"
28+
break
29+
fi
30+
echo "Docker not ready yet, waiting... ($((COUNTER + 1))/$MAX_WAIT)"
31+
sleep 1
32+
((COUNTER++))
33+
done
34+
35+
if [ $COUNTER -eq $MAX_WAIT ]; then
36+
echo "WARNING: Docker service did not become ready after $MAX_WAIT seconds"
37+
fi
38+
else
39+
echo "Docker service is already running"
40+
fi
41+
else
42+
echo "Docker is not installed, skipping Docker service setup"
43+
fi
44+
1245
if [ "${DD_env}" == "dev" ]; then
1346
# To force the installer to pull from dev repositories -- agent config is set manually to datadoghq.com
1447
export DD_SITE="datad0g.com"
@@ -120,6 +153,12 @@
120153
sudo cp debug_config.yaml /etc/datadog-agent/inject/debug_config.yaml
121154
122155
for i in 1 2 3 4 5; do sudo datadog-installer apm instrument docker && break || sleep 1; done
156+
157+
# Add dd-agent user to docker group for docker socket access
158+
sudo usermod -aG docker dd-agent || echo "Warning: Could not add dd-agent to docker group"
159+
160+
# Restart datadog-agent so the new group membership takes effect
161+
sudo systemctl restart datadog-agent || echo "Warning: Could not restart datadog-agent"
123162
- os_type: windows
124163
copy_files:
125164
- name: copy-binaries

utils/build/virtual_machine/provisions/host-auto-inject-install-script/auto-inject_host_script.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
1818
DD_APM_INSTRUMENTATION_ENABLED=host bash execute_install_script.sh
1919
sudo cp debug_config.yaml /etc/datadog-agent/inject/debug_config.yaml
20-
20+
2121
- os_type: windows
2222
remote-command: |
2323
echo "TODO. Windows is not supported for installation script yet. TODO."

utils/onboarding/backend_interface.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,14 @@
1111

1212
def wait_backend_trace_id(trace_id, profile: bool = False, validator=None):
1313
logger.info(f"Waiting for backend trace with trace_id: {trace_id}")
14-
runtime_id = _query_for_trace_id(trace_id, validator=validator)
14+
results = _query_for_trace_id(trace_id, validator=validator)
15+
runtime_id = results["runtime_id"]
16+
if validator:
17+
validator_results = results["validator"]
18+
assert validator_results, f"{validator.__name__} failed to validate trace_id: {trace_id}"
19+
1520
assert runtime_id, f"Could not find runtime-id for trace_id: {trace_id}"
21+
1622
if profile:
1723
_query_for_profile(runtime_id)
1824

@@ -54,23 +60,25 @@ def _headers():
5460
def _query_for_trace_id(trace_id, validator=None):
5561
url = f"{API_HOST}/api/ui/trace/{trace_id}"
5662

63+
results = {}
64+
5765
trace_data = _make_request(url, headers=_headers())
5866
if validator:
5967
logger.info("Validating backend trace...")
60-
if not validator(trace_id, trace_data):
61-
logger.info("Backend trace is not valid")
62-
return None
63-
logger.info("Backend trace is valid")
68+
results["validator"] = validator(trace_id, trace_data)
69+
if not results["validator"]:
70+
logger.info("Validator failed")
6471

6572
root_id = trace_data["trace"]["root_id"]
6673
root_span = trace_data["trace"]["spans"][root_id]
6774
start_time = root_span["start"]
6875
start_date = datetime.fromtimestamp(start_time)
6976
if (datetime.now() - start_date).days > 1:
7077
logger.info("Backend trace is too old")
71-
return None
72-
73-
return root_span["meta"]["runtime-id"]
78+
results["runtime_id"] = None
79+
else:
80+
results["runtime_id"] = root_span["meta"]["runtime-id"]
81+
return results
7482

7583

7684
def _make_request(

0 commit comments

Comments
 (0)