From 37771e42f00f3e93ffa9b885019bd313a8c37730 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Wed, 8 Jul 2026 15:36:17 -0700 Subject: [PATCH 1/3] add ability for the opamp client to use the x-sf-token header --- opamp/build.gradle.kts | 1 + .../opentelemetry/opamp/OpampActivator.java | 26 +++++++++-- .../opamp/OpampClientConfiguration.java | 13 ++++++ .../opamp/OpampActivatorTest.java | 3 ++ .../opamp/OpampClientConfigurationTest.java | 43 +++++++++++++++++++ 5 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 opamp/src/test/java/com/splunk/opentelemetry/opamp/OpampClientConfigurationTest.java diff --git a/opamp/build.gradle.kts b/opamp/build.gradle.kts index 1a37aff5e..fc9a0a80e 100644 --- a/opamp/build.gradle.kts +++ b/opamp/build.gradle.kts @@ -11,6 +11,7 @@ dependencies { compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi") compileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-extension-api") compileOnly("org.snakeyaml:snakeyaml-engine") + compileOnly("com.squareup.okhttp3:okhttp") annotationProcessor("com.google.auto.service:auto-service") compileOnly("com.google.auto.service:auto-service") diff --git a/opamp/src/main/java/com/splunk/opentelemetry/opamp/OpampActivator.java b/opamp/src/main/java/com/splunk/opentelemetry/opamp/OpampActivator.java index d98bd2a60..056a56fd3 100644 --- a/opamp/src/main/java/com/splunk/opentelemetry/opamp/OpampActivator.java +++ b/opamp/src/main/java/com/splunk/opentelemetry/opamp/OpampActivator.java @@ -38,8 +38,12 @@ import java.time.Duration; import java.time.Instant; import java.util.logging.Logger; +import okhttp3.Interceptor; +import okhttp3.OkHttpClient; +import okhttp3.Request; import opamp.proto.ComponentHealth; import opamp.proto.ServerErrorResponse; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @AutoService(AgentListener.class) @@ -125,10 +129,10 @@ static OpampClient startOpampClient( if (endpoint != null) { PeriodicDelay pollingDelay = PeriodicDelay.ofFixedDuration(Duration.ofMillis(pollingDurationMillis)); - OkHttpSender okhttp = OkHttpSender.create(endpoint); - HttpRequestService httpSender = + OkHttpSender okhttp = buildOkHttpSender(opampClientConfiguration); + HttpRequestService httpRequestService = HttpRequestService.create(okhttp, pollingDelay, DEFAULT_DELAY_BETWEEN_RETRIES); - builder.setRequestService(httpSender); + builder.setRequestService(httpRequestService); } OpampAgentAttributes agentAttributes = new OpampAgentAttributes(resource); @@ -141,6 +145,22 @@ static OpampClient startOpampClient( return builder.build(callbacks); } + @NotNull + private static OkHttpSender buildOkHttpSender(OpampClientConfiguration config) { + String token = config.getAccessToken(); + if (token == null) { + return OkHttpSender.create(config.getEndpoint()); + } + Interceptor tokenFlinger = + chain -> { + Request.Builder requestBuilder = chain.request().newBuilder(); + requestBuilder.addHeader("X-SF-TOKEN", token); + return chain.proceed(requestBuilder.build()); + }; + OkHttpClient okhttpClient = new OkHttpClient.Builder().addInterceptor(tokenFlinger).build(); + return OkHttpSender.create(config.getEndpoint(), okhttpClient); + } + private static ComponentHealth createInitialHealthReport() { Instant now = Instant.now(); long nowNanos = now.getEpochSecond() * 1_000_000_000L + now.getNano(); diff --git a/opamp/src/main/java/com/splunk/opentelemetry/opamp/OpampClientConfiguration.java b/opamp/src/main/java/com/splunk/opentelemetry/opamp/OpampClientConfiguration.java index a2bdf7487..7245abf12 100644 --- a/opamp/src/main/java/com/splunk/opentelemetry/opamp/OpampClientConfiguration.java +++ b/opamp/src/main/java/com/splunk/opentelemetry/opamp/OpampClientConfiguration.java @@ -19,6 +19,7 @@ public class OpampClientConfiguration { private boolean enabled; private String endpoint; + private String accessToken = null; private long pollingInterval; private OpampClientConfiguration() {} @@ -39,6 +40,10 @@ public long getPollingInterval() { return pollingInterval; } + public String getAccessToken() { + return accessToken; + } + @Override public String toString() { return "OpampClientConfiguration{" @@ -48,6 +53,9 @@ public String toString() { + ", endpoint='" + endpoint + '\'' + + ", accessToken='" + + (accessToken == null ? "" : "***redacted***") + + '\'' + ", pollingInterval=" + pollingInterval + '}'; @@ -73,6 +81,11 @@ public Builder withPollingInterval(long pollingInterval) { return this; } + public Builder withAccessToken(String accessToken) { + configuredInstance.accessToken = accessToken; + return this; + } + public OpampClientConfiguration build() { return configuredInstance; } diff --git a/opamp/src/test/java/com/splunk/opentelemetry/opamp/OpampActivatorTest.java b/opamp/src/test/java/com/splunk/opentelemetry/opamp/OpampActivatorTest.java index 689590a19..5c5cdbc60 100644 --- a/opamp/src/test/java/com/splunk/opentelemetry/opamp/OpampActivatorTest.java +++ b/opamp/src/test/java/com/splunk/opentelemetry/opamp/OpampActivatorTest.java @@ -138,6 +138,7 @@ void testOpamp() throws Exception { OpampClientConfiguration.builder() .withEnabled(true) .withEndpoint(server.httpUri().toString()) + .withAccessToken("test-access-token") .withPollingInterval(500) .build(); OpampClient client = @@ -177,6 +178,8 @@ public void onMessage(OpampClient opampClient, MessageData messageData) { assertThat(remoteConfig.config.config_map.get("test-key").body.utf8()).isEqualTo("test-value"); RecordedRequest recordedRequest = server.takeRequest(); + assertThat(recordedRequest.request().headers().get("X-SF-TOKEN")) + .isEqualTo("test-access-token"); byte[] body = recordedRequest.request().content().array(); AgentToServer agentToServer = AgentToServer.ADAPTER.decode(body); diff --git a/opamp/src/test/java/com/splunk/opentelemetry/opamp/OpampClientConfigurationTest.java b/opamp/src/test/java/com/splunk/opentelemetry/opamp/OpampClientConfigurationTest.java new file mode 100644 index 000000000..000490600 --- /dev/null +++ b/opamp/src/test/java/com/splunk/opentelemetry/opamp/OpampClientConfigurationTest.java @@ -0,0 +1,43 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.splunk.opentelemetry.opamp; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class OpampClientConfigurationTest { + + @Test + void shouldConfigureAccessToken() { + OpampClientConfiguration configuration = + OpampClientConfiguration.builder().withAccessToken("secret-token").build(); + + assertThat(configuration.getAccessToken()).isEqualTo("secret-token"); + assertThat(configuration.toString()) + .contains("accessToken='***redacted***'") + .doesNotContain("secret-token"); + } + + @Test + void shouldDefaultAccessTokenToNull() { + OpampClientConfiguration configuration = OpampClientConfiguration.builder().build(); + + assertThat(configuration.getAccessToken()).isNull(); + assertThat(configuration.toString()).contains("accessToken=''"); + } +} From 2fb3fc030df7dcf48fc23ac996fed75a36fb2ca6 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Thu, 9 Jul 2026 09:48:20 -0700 Subject: [PATCH 2/3] it is important to remain consistent. --- .../splunk/opentelemetry/opamp/OpampClientConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opamp/src/main/java/com/splunk/opentelemetry/opamp/OpampClientConfiguration.java b/opamp/src/main/java/com/splunk/opentelemetry/opamp/OpampClientConfiguration.java index 7245abf12..143fc260a 100644 --- a/opamp/src/main/java/com/splunk/opentelemetry/opamp/OpampClientConfiguration.java +++ b/opamp/src/main/java/com/splunk/opentelemetry/opamp/OpampClientConfiguration.java @@ -19,7 +19,7 @@ public class OpampClientConfiguration { private boolean enabled; private String endpoint; - private String accessToken = null; + private String accessToken; private long pollingInterval; private OpampClientConfiguration() {} From d0b476d2d95f0d9ce0c25825b76c4e0ca4005902 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Mon, 13 Jul 2026 14:26:39 -0700 Subject: [PATCH 3/3] address code review comment --- .../opentelemetry/opamp/OpampClientConfigurationFactory.java | 3 +++ .../opamp/OpampClientConfigurationFactoryTest.java | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/opamp/src/main/java/com/splunk/opentelemetry/opamp/OpampClientConfigurationFactory.java b/opamp/src/main/java/com/splunk/opentelemetry/opamp/OpampClientConfigurationFactory.java index 57692bfdf..bf7043df3 100644 --- a/opamp/src/main/java/com/splunk/opentelemetry/opamp/OpampClientConfigurationFactory.java +++ b/opamp/src/main/java/com/splunk/opentelemetry/opamp/OpampClientConfigurationFactory.java @@ -16,6 +16,7 @@ package com.splunk.opentelemetry.opamp; +import static com.splunk.opentelemetry.SplunkConfigurationCustomizer.SPLUNK_ACCESS_TOKEN; import static io.opentelemetry.opamp.client.internal.request.service.HttpRequestService.DEFAULT_DELAY_BETWEEN_REQUESTS; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; @@ -47,6 +48,7 @@ private static OpampClientConfiguration createConfigurationFromDeclarativeConfig builder.withEnabled(true); builder .withEndpoint(opampProperties.getString("endpoint")) + .withAccessToken(opampProperties.getString("access_token")) .withPollingInterval( opampProperties.getLong( "polling_interval", DEFAULT_DELAY_BETWEEN_REQUESTS.getNextDelay().toMillis())); @@ -59,6 +61,7 @@ private static OpampClientConfiguration createConfiguration(ConfigProperties con return OpampClientConfiguration.builder() .withEnabled(config.getBoolean("splunk.opamp.enabled", false)) .withEndpoint(config.getString("splunk.opamp.endpoint")) + .withAccessToken(config.getString(SPLUNK_ACCESS_TOKEN)) .withPollingInterval( config.getLong( "splunk.opamp.polling.interval", diff --git a/opamp/src/test/java/com/splunk/opentelemetry/opamp/OpampClientConfigurationFactoryTest.java b/opamp/src/test/java/com/splunk/opentelemetry/opamp/OpampClientConfigurationFactoryTest.java index 6dc723b76..e1d7b513f 100644 --- a/opamp/src/test/java/com/splunk/opentelemetry/opamp/OpampClientConfigurationFactoryTest.java +++ b/opamp/src/test/java/com/splunk/opentelemetry/opamp/OpampClientConfigurationFactoryTest.java @@ -46,6 +46,7 @@ void shouldCreateConfigurationFromEnvVars() { Map.of( "splunk.opamp.enabled", "true", "splunk.opamp.endpoint", "https://opamp.example.com", + "splunk.access.token", "env-token", "splunk.opamp.polling.interval", "3210")); // when @@ -55,6 +56,7 @@ void shouldCreateConfigurationFromEnvVars() { // then assertThat(configuration.isEnabled()).isTrue(); assertThat(configuration.getEndpoint()).isEqualTo("https://opamp.example.com"); + assertThat(configuration.getAccessToken()).isEqualTo("env-token"); assertThat(configuration.getPollingInterval()).isEqualTo(3210); } @@ -68,6 +70,7 @@ void shouldCreateConfigurationFromDeclarativeConfig(@TempDir Path tempDir) throw splunk: opamp/development: endpoint: http://some.opamp-host.com:3420/v1/opamp + access_token: declarative-token polling_interval: 4567 """; AutoConfiguredOpenTelemetrySdk sdk = @@ -80,6 +83,7 @@ void shouldCreateConfigurationFromDeclarativeConfig(@TempDir Path tempDir) throw // then assertThat(configuration.isEnabled()).isTrue(); assertThat(configuration.getEndpoint()).isEqualTo("http://some.opamp-host.com:3420/v1/opamp"); + assertThat(configuration.getAccessToken()).isEqualTo("declarative-token"); assertThat(configuration.getPollingInterval()).isEqualTo(4567); } @@ -95,6 +99,7 @@ void shouldUseDefaults() { // then assertThat(configuration.isEnabled()).isFalse(); assertThat(configuration.getEndpoint()).isNull(); + assertThat(configuration.getAccessToken()).isNull(); assertThat(configuration.getPollingInterval()) .isEqualTo(DEFAULT_DELAY_BETWEEN_REQUESTS.getNextDelay().toMillis()); }