From 00fbd7699a68ea6e3b7c140b27fbf4add976c569 Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Fri, 11 Jul 2025 10:13:12 +0200 Subject: [PATCH] Backpropagate container tags hash coming from the info endpoint --- .../ddagent/DDAgentFeaturesDiscovery.java | 19 +++++++++--- .../communication/http/OkHttpUtils.java | 3 +- .../DDAgentFeaturesDiscoveryTest.groovy | 30 ++++++++++++++++++- .../common/container/ContainerInfo.java | 9 ++++++ 4 files changed, 55 insertions(+), 6 deletions(-) diff --git a/communication/src/main/java/datadog/communication/ddagent/DDAgentFeaturesDiscovery.java b/communication/src/main/java/datadog/communication/ddagent/DDAgentFeaturesDiscovery.java index 22f5f4603ac..9d87c1273e5 100644 --- a/communication/src/main/java/datadog/communication/ddagent/DDAgentFeaturesDiscovery.java +++ b/communication/src/main/java/datadog/communication/ddagent/DDAgentFeaturesDiscovery.java @@ -1,5 +1,7 @@ package datadog.communication.ddagent; +import static datadog.communication.http.OkHttpUtils.DATADOG_CONTAINER_ID; +import static datadog.communication.http.OkHttpUtils.DATADOG_CONTAINER_TAGS_HASH; import static datadog.communication.serialization.msgpack.MsgPackWriter.FIXARRAY; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; @@ -8,6 +10,7 @@ import com.squareup.moshi.JsonAdapter; import com.squareup.moshi.Moshi; import com.squareup.moshi.Types; +import datadog.common.container.ContainerInfo; import datadog.communication.http.OkHttpUtils; import datadog.communication.monitor.DDAgentStatsDClientManager; import datadog.communication.monitor.Monitoring; @@ -157,11 +160,15 @@ private void doDiscovery() { // 3. fallback if the endpoint couldn't be found or the response couldn't be parsed try (Recording recording = discoveryTimer.start()) { boolean fallback = true; - try (Response response = - client - .newCall(new Request.Builder().url(agentBaseUrl.resolve("info").url()).build()) - .execute()) { + final Request.Builder requestBuilder = + new Request.Builder().url(agentBaseUrl.resolve("info").url()); + final String containerId = ContainerInfo.get().getContainerId(); + if (containerId != null) { + requestBuilder.header(DATADOG_CONTAINER_ID, containerId); + } + try (Response response = client.newCall(requestBuilder.build()).execute()) { if (response.isSuccessful()) { + processInfoResponseHeaders(response); fallback = !processInfoResponse(response.body().string()); } } catch (Throwable error) { @@ -222,6 +229,10 @@ private String probeTracesEndpoint(String[] endpoints) { return V3_ENDPOINT; } + private void processInfoResponseHeaders(Response response) { + ContainerInfo.get().setContainerTagsHash(response.header(DATADOG_CONTAINER_TAGS_HASH)); + } + @SuppressWarnings("unchecked") private boolean processInfoResponse(String response) { try { diff --git a/communication/src/main/java/datadog/communication/http/OkHttpUtils.java b/communication/src/main/java/datadog/communication/http/OkHttpUtils.java index e74561f7277..63a8e613ba4 100644 --- a/communication/src/main/java/datadog/communication/http/OkHttpUtils.java +++ b/communication/src/main/java/datadog/communication/http/OkHttpUtils.java @@ -43,8 +43,9 @@ public final class OkHttpUtils { private static final String DATADOG_META_LANG_INTERPRETER = "Datadog-Meta-Lang-Interpreter"; private static final String DATADOG_META_LANG_INTERPRETER_VENDOR = "Datadog-Meta-Lang-Interpreter-Vendor"; - private static final String DATADOG_CONTAINER_ID = "Datadog-Container-ID"; + public static final String DATADOG_CONTAINER_ID = "Datadog-Container-ID"; private static final String DATADOG_ENTITY_ID = "Datadog-Entity-ID"; + public static final String DATADOG_CONTAINER_TAGS_HASH = "Datadog-Container-Tags-Hash"; private static final String DD_API_KEY = "DD-API-KEY"; diff --git a/communication/src/test/groovy/datadog/communication/ddagent/DDAgentFeaturesDiscoveryTest.groovy b/communication/src/test/groovy/datadog/communication/ddagent/DDAgentFeaturesDiscoveryTest.groovy index 51971e25b09..1ee382f5775 100644 --- a/communication/src/test/groovy/datadog/communication/ddagent/DDAgentFeaturesDiscoveryTest.groovy +++ b/communication/src/test/groovy/datadog/communication/ddagent/DDAgentFeaturesDiscoveryTest.groovy @@ -1,9 +1,11 @@ package datadog.communication.ddagent +import datadog.common.container.ContainerInfo import datadog.communication.monitor.Monitoring import datadog.trace.test.util.DDSpecification import datadog.trace.util.Strings import okhttp3.Call +import okhttp3.Headers import okhttp3.HttpUrl import okhttp3.MediaType import okhttp3.OkHttpClient @@ -19,6 +21,8 @@ import java.nio.file.Paths import static datadog.communication.ddagent.DDAgentFeaturesDiscovery.V01_DATASTREAMS_ENDPOINT import static datadog.communication.ddagent.DDAgentFeaturesDiscovery.V6_METRICS_ENDPOINT import static datadog.communication.ddagent.DDAgentFeaturesDiscovery.V7_CONFIG_ENDPOINT +import static datadog.communication.http.OkHttpUtils.DATADOG_CONTAINER_ID +import static datadog.communication.http.OkHttpUtils.DATADOG_CONTAINER_TAGS_HASH class DDAgentFeaturesDiscoveryTest extends DDSpecification { @@ -466,13 +470,37 @@ class DDAgentFeaturesDiscoveryTest extends DDSpecification { ) } - def infoResponse(Request request, String json) { + def "should send container id as header on the info request and parse the hash in the response"() { + setup: + OkHttpClient client = Mock(OkHttpClient) + DDAgentFeaturesDiscovery features = new DDAgentFeaturesDiscovery(client, monitoring, agentUrl, true, true) + def oldContainerId = ContainerInfo.get().getContainerId() + def oldContainerTagsHash = ContainerInfo.get().getContainerTagsHash() + ContainerInfo.get().setContainerId("test") + + when: "/info requested" + features.discover() + + then: + 1 * client.newCall(_) >> { Request request -> + assert request.header(DATADOG_CONTAINER_ID) == "test" + infoResponse(request, INFO_RESPONSE, Headers.of(DATADOG_CONTAINER_TAGS_HASH, "test-hash")) + } + and: + assert ContainerInfo.get().getContainerTagsHash() == "test-hash" + cleanup: + ContainerInfo.get().setContainerId(oldContainerId) + ContainerInfo.get().setContainerTagsHash(oldContainerTagsHash) + } + + def infoResponse(Request request, String json, Headers headers = new Headers.Builder().build()) { return Mock(Call) { it.execute() >> new Response.Builder() .code(200) .request(request) .protocol(Protocol.HTTP_1_1) .message("") + .headers(headers) .body(ResponseBody.create(MediaType.get("application/json"), json)) .build() } diff --git a/utils/container-utils/src/main/java/datadog/common/container/ContainerInfo.java b/utils/container-utils/src/main/java/datadog/common/container/ContainerInfo.java index 1d7c9c65655..df54d9d2a48 100644 --- a/utils/container-utils/src/main/java/datadog/common/container/ContainerInfo.java +++ b/utils/container-utils/src/main/java/datadog/common/container/ContainerInfo.java @@ -54,6 +54,7 @@ public class ContainerInfo { private static final String ENTITY_ID; public String containerId; + public String containerTagsHash; public String podId; public List cGroups = new ArrayList<>(); @@ -65,6 +66,14 @@ public void setContainerId(String containerId) { this.containerId = containerId; } + public String getContainerTagsHash() { + return containerTagsHash; + } + + public void setContainerTagsHash(String containerTagsHash) { + this.containerTagsHash = containerTagsHash; + } + public String getPodId() { return podId; }