Skip to content

Commit e4393c2

Browse files
committed
Refine agentless configuration source contract
1 parent 82e864f commit e4393c2

9 files changed

Lines changed: 42 additions & 231 deletions

File tree

dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java

Lines changed: 2 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@
7272
import java.net.URL;
7373
import java.security.CodeSource;
7474
import java.util.EnumSet;
75-
import java.util.Locale;
7675
import java.util.concurrent.TimeUnit;
7776
import java.util.concurrent.atomic.AtomicBoolean;
7877
import java.util.regex.PatternSyntaxException;
@@ -136,7 +135,7 @@ private enum AgentFeature {
136135
APP_LOGS_COLLECTION(GeneralConfig.APP_LOGS_COLLECTION_ENABLED, false),
137136
LLMOBS(LlmObsConfig.LLMOBS_ENABLED, false),
138137
LLMOBS_AGENTLESS(LlmObsConfig.LLMOBS_AGENTLESS_ENABLED, false),
139-
FEATURE_FLAGGING(FeatureFlaggingConfig.FEATURE_FLAGS_ENABLED, false);
138+
FEATURE_FLAGGING(FeatureFlaggingConfig.FLAGGING_PROVIDER_ENABLED, false);
140139

141140
private final String configKey;
142141
private final String systemProp;
@@ -283,7 +282,7 @@ public static void start(
283282
agentlessLogSubmissionEnabled = isFeatureEnabled(AgentFeature.AGENTLESS_LOG_SUBMISSION);
284283
appLogsCollectionEnabled = isFeatureEnabled(AgentFeature.APP_LOGS_COLLECTION);
285284
llmObsEnabled = isFeatureEnabled(AgentFeature.LLMOBS);
286-
featureFlaggingEnabled = isFeatureFlaggingEnabled();
285+
featureFlaggingEnabled = isFeatureEnabled(AgentFeature.FEATURE_FLAGGING);
287286

288287
// setup writers when llmobs is enabled to accomodate apm and llmobs
289288
if (llmObsEnabled) {
@@ -1632,53 +1631,6 @@ private static boolean isFeatureEnabled(AgentFeature feature) {
16321631
}
16331632
}
16341633

1635-
private static boolean isFeatureFlaggingEnabled() {
1636-
final String enabled = getConfiguredValue(FeatureFlaggingConfig.FEATURE_FLAGS_ENABLED);
1637-
if ("false".equalsIgnoreCase(enabled) || "0".equals(enabled)) {
1638-
return false;
1639-
}
1640-
if ("true".equalsIgnoreCase(enabled) || "1".equals(enabled)) {
1641-
return true;
1642-
}
1643-
1644-
final String oldEnabled = getConfiguredValue(FeatureFlaggingConfig.FLAGGING_PROVIDER_ENABLED);
1645-
if ("false".equalsIgnoreCase(oldEnabled) || "0".equals(oldEnabled)) {
1646-
return false;
1647-
}
1648-
if ("true".equalsIgnoreCase(oldEnabled) || "1".equals(oldEnabled)) {
1649-
return true;
1650-
}
1651-
1652-
return isFeatureFlaggingConfigurationSourceAutoEnabled();
1653-
}
1654-
1655-
private static boolean isFeatureFlaggingConfigurationSourceAutoEnabled() {
1656-
final String configurationSource =
1657-
getConfiguredValue(FeatureFlaggingConfig.FEATURE_FLAGS_CONFIGURATION_SOURCE);
1658-
if (configurationSource == null) {
1659-
return true;
1660-
}
1661-
final String normalized = configurationSource.trim().toLowerCase(Locale.ROOT);
1662-
return "agentless".equals(normalized)
1663-
|| "remote_config".equals(normalized)
1664-
|| "offline".equals(normalized);
1665-
}
1666-
1667-
private static String getConfiguredValue(final String configKey) {
1668-
final String systemProp = propertyNameToSystemPropertyName(configKey);
1669-
String settingValue = getNullIfEmpty(SystemProperties.get(systemProp));
1670-
if (settingValue == null) {
1671-
settingValue = getNullIfEmpty(getStableConfig(FLEET, configKey));
1672-
}
1673-
if (settingValue == null) {
1674-
settingValue = getNullIfEmpty(ddGetEnv(systemProp));
1675-
}
1676-
if (settingValue == null) {
1677-
settingValue = getNullIfEmpty(getStableConfig(LOCAL, configKey));
1678-
}
1679-
return settingValue;
1680-
}
1681-
16821634
/**
16831635
* @see datadog.trace.api.ProductActivation#fromString(String)
16841636
*/

dd-trace-api/src/main/java/datadog/trace/api/config/FeatureFlaggingConfig.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,14 @@
22

33
public class FeatureFlaggingConfig {
44

5-
public static final String FEATURE_FLAGS_ENABLED = "feature.flags.enabled";
65
public static final String FLAGGING_PROVIDER_ENABLED = "experimental.flagging.provider.enabled";
76

87
public static final String FEATURE_FLAGS_CONFIGURATION_SOURCE =
98
"feature.flags.configuration.source";
10-
public static final String FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_BASE_URL =
11-
"feature.flags.configuration.source.agentless.base.url";
129
public static final String FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_POLL_INTERVAL_SECONDS =
1310
"feature.flags.configuration.source.agentless.poll.interval.seconds";
1411
public static final String FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_REQUEST_TIMEOUT_SECONDS =
1512
"feature.flags.configuration.source.agentless.request.timeout.seconds";
16-
public static final String FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_EXTRA_HEADERS =
17-
"feature.flags.configuration.source.agentless.extra.headers";
1813

1914
private FeatureFlaggingConfig() {}
2015
}

internal-api/src/main/java/datadog/trace/api/Config.java

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -365,8 +365,6 @@
365365
import static datadog.trace.api.config.DebuggerConfig.THIRD_PARTY_INCLUDES;
366366
import static datadog.trace.api.config.DebuggerConfig.THIRD_PARTY_SHADING_IDENTIFIERS;
367367
import static datadog.trace.api.config.FeatureFlaggingConfig.FEATURE_FLAGS_CONFIGURATION_SOURCE;
368-
import static datadog.trace.api.config.FeatureFlaggingConfig.FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_BASE_URL;
369-
import static datadog.trace.api.config.FeatureFlaggingConfig.FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_EXTRA_HEADERS;
370368
import static datadog.trace.api.config.FeatureFlaggingConfig.FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_POLL_INTERVAL_SECONDS;
371369
import static datadog.trace.api.config.FeatureFlaggingConfig.FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_REQUEST_TIMEOUT_SECONDS;
372370
import static datadog.trace.api.config.GeneralConfig.AGENTLESS_LOG_SUBMISSION_LEVEL;
@@ -1222,10 +1220,8 @@ public static String getHostName() {
12221220
private final int remoteConfigMaxExtraServices;
12231221

12241222
private final String featureFlaggingConfigurationSource;
1225-
private final String featureFlaggingConfigurationSourceBaseUrl;
12261223
private final double featureFlaggingConfigurationSourcePollIntervalSeconds;
12271224
private final double featureFlaggingConfigurationSourceRequestTimeoutSeconds;
1228-
private final Map<String, String> featureFlaggingConfigurationSourceExtraHeaders;
12291225

12301226
private final boolean dbmInjectSqlBaseHash;
12311227
private final String dbmPropagationMode;
@@ -2853,9 +2849,6 @@ PROFILING_DATADOG_PROFILER_ENABLED, isDatadogProfilerSafeInCurrentEnvironment())
28532849
normalizeFeatureFlaggingConfigurationSource(
28542850
configProvider.getString(
28552851
FEATURE_FLAGS_CONFIGURATION_SOURCE, DEFAULT_FEATURE_FLAGGING_CONFIGURATION_SOURCE));
2856-
featureFlaggingConfigurationSourceBaseUrl =
2857-
configProvider.getStringNotEmpty(
2858-
FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_BASE_URL, null);
28592852
featureFlaggingConfigurationSourcePollIntervalSeconds =
28602853
configProvider.getDouble(
28612854
FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_POLL_INTERVAL_SECONDS,
@@ -2864,9 +2857,6 @@ PROFILING_DATADOG_PROFILER_ENABLED, isDatadogProfilerSafeInCurrentEnvironment())
28642857
configProvider.getDouble(
28652858
FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_REQUEST_TIMEOUT_SECONDS,
28662859
DEFAULT_FEATURE_FLAGGING_CONFIGURATION_SOURCE_REQUEST_TIMEOUT_SECONDS);
2867-
featureFlaggingConfigurationSourceExtraHeaders =
2868-
configProvider.getMergedMap(
2869-
FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_EXTRA_HEADERS, '=');
28702860

28712861
dynamicInstrumentationEnabled =
28722862
configProvider.getBoolean(
@@ -4699,10 +4689,6 @@ public String getFeatureFlaggingConfigurationSource() {
46994689
return featureFlaggingConfigurationSource;
47004690
}
47014691

4702-
public String getFeatureFlaggingConfigurationSourceBaseUrl() {
4703-
return featureFlaggingConfigurationSourceBaseUrl;
4704-
}
4705-
47064692
public double getFeatureFlaggingConfigurationSourcePollIntervalSeconds() {
47074693
return featureFlaggingConfigurationSourcePollIntervalSeconds;
47084694
}
@@ -4711,10 +4697,6 @@ public double getFeatureFlaggingConfigurationSourceRequestTimeoutSeconds() {
47114697
return featureFlaggingConfigurationSourceRequestTimeoutSeconds;
47124698
}
47134699

4714-
public Map<String, String> getFeatureFlaggingConfigurationSourceExtraHeaders() {
4715-
return featureFlaggingConfigurationSourceExtraHeaders;
4716-
}
4717-
47184700
public boolean isDynamicInstrumentationEnabled() {
47194701
return dynamicInstrumentationEnabled;
47204702
}
@@ -6549,14 +6531,10 @@ public String toString() {
65496531
+ remoteConfigIntegrityCheckEnabled
65506532
+ ", featureFlaggingConfigurationSource="
65516533
+ featureFlaggingConfigurationSource
6552-
+ ", featureFlaggingConfigurationSourceBaseUrl="
6553-
+ featureFlaggingConfigurationSourceBaseUrl
65546534
+ ", featureFlaggingConfigurationSourcePollIntervalSeconds="
65556535
+ featureFlaggingConfigurationSourcePollIntervalSeconds
65566536
+ ", featureFlaggingConfigurationSourceRequestTimeoutSeconds="
65576537
+ featureFlaggingConfigurationSourceRequestTimeoutSeconds
6558-
+ ", featureFlaggingConfigurationSourceExtraHeaderNames="
6559-
+ featureFlaggingConfigurationSourceExtraHeaders.keySet()
65606538
+ ", debuggerEnabled="
65616539
+ dynamicInstrumentationEnabled
65626540
+ ", debuggerUploadTimeout="

metadata/supported-configurations.json

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1505,22 +1505,6 @@
15051505
"aliases": []
15061506
}
15071507
],
1508-
"DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_BASE_URL": [
1509-
{
1510-
"version": "A",
1511-
"type": "string",
1512-
"default": null,
1513-
"aliases": []
1514-
}
1515-
],
1516-
"DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_EXTRA_HEADERS": [
1517-
{
1518-
"version": "A",
1519-
"type": "map",
1520-
"default": null,
1521-
"aliases": []
1522-
}
1523-
],
15241508
"DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_POLL_INTERVAL_SECONDS": [
15251509
{
15261510
"version": "A",
@@ -1537,14 +1521,6 @@
15371521
"aliases": []
15381522
}
15391523
],
1540-
"DD_FEATURE_FLAGS_ENABLED": [
1541-
{
1542-
"version": "A",
1543-
"type": "boolean",
1544-
"default": "true",
1545-
"aliases": ["DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED"]
1546-
}
1547-
],
15481524
"DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED": [
15491525
{
15501526
"version": "A",

products/feature-flagging/feature-flagging-agent/src/main/java/com/datadog/featureflag/FeatureFlaggingSystem.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ static ConfigurationSourceService createConfigurationSourceService(
4141
}
4242
return new RemoteConfigServiceImpl(sco, config);
4343
case AGENTLESS:
44-
return new UfcHttpConfigService(config);
44+
return new AgentlessConfigurationSource(config);
4545
case OFFLINE:
4646
LOGGER.debug(
4747
"Feature Flagging offline configuration source selected; no config service started");

products/feature-flagging/feature-flagging-agent/src/test/java/com/datadog/featureflag/FeatureFlaggingSystemTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ void testThatRemoteConfigIsRequired() {
7272
@WithConfig(key = REMOTE_CONFIGURATION_ENABLED, value = "false")
7373
void agentlessConfigurationSourceUsesHttpServiceWithoutRemoteConfig() {
7474
assertInstanceOf(
75-
UfcHttpConfigService.class,
75+
AgentlessConfigurationSource.class,
7676
FeatureFlaggingSystem.createConfigurationSourceService(
7777
sharedCommunicationObjects(), Config.get()));
7878
}

products/feature-flagging/feature-flagging-api/README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,5 +85,7 @@ OTEL_EXPORTER_OTLP_PROTOCOL=grpc
8585
## Requirements
8686

8787
- Java 11+
88-
- Feature Flags provider enabled with `DD_FEATURE_FLAGS_ENABLED=true`, or left unset
89-
for the default `agentless` configuration source.
88+
- `DD_FEATURE_FLAGS_CONFIGURATION_SOURCE=agentless` uses the Datadog agentless
89+
backend. `remote_config` uses the existing Agent Remote Configuration path.
90+
`offline` is reserved for startup-provided UFC bytes; until those bytes are
91+
implemented, no network source starts and evaluations use defaults.

products/feature-flagging/feature-flagging-lib/src/main/java/com/datadog/featureflag/UfcHttpConfigService.java renamed to products/feature-flagging/feature-flagging-lib/src/main/java/com/datadog/featureflag/AgentlessConfigurationSource.java

Lines changed: 11 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import java.io.IOException;
1010
import java.net.HttpURLConnection;
1111
import java.net.URLEncoder;
12-
import java.util.Collections;
1312
import java.util.HashMap;
1413
import java.util.Locale;
1514
import java.util.Map;
@@ -27,16 +26,16 @@
2726
import org.slf4j.Logger;
2827
import org.slf4j.LoggerFactory;
2928

30-
final class UfcHttpConfigService implements ConfigurationSourceService {
31-
private static final Logger LOGGER = LoggerFactory.getLogger(UfcHttpConfigService.class);
29+
final class AgentlessConfigurationSource implements ConfigurationSourceService {
30+
private static final Logger LOGGER = LoggerFactory.getLogger(AgentlessConfigurationSource.class);
3231

32+
// TODO before merge: confirm the final backend route with the server-distribution API owners.
3333
private static final String DATADOG_API_SERVER_DISTRIBUTION_PATH =
3434
"/api/v2/feature-flagging/config/server-distribution";
3535
private static final int MAX_ATTEMPTS = 3;
3636

3737
private final HttpUrl endpoint;
3838
private final Config config;
39-
private final Map<String, String> extraHeaders;
4039
private final long pollIntervalMillis;
4140
private final UfcHttpClient client;
4241
private final ScheduledExecutorService executor;
@@ -45,11 +44,11 @@ final class UfcHttpConfigService implements ConfigurationSourceService {
4544
private volatile ScheduledFuture<?> scheduledPoll;
4645
private volatile String etag;
4746

48-
UfcHttpConfigService(final Config config) {
47+
AgentlessConfigurationSource(final Config config) {
4948
this(config, endpoint(config));
5049
}
5150

52-
private UfcHttpConfigService(final Config config, final HttpUrl endpoint) {
51+
private AgentlessConfigurationSource(final Config config, final HttpUrl endpoint) {
5352
this(
5453
endpoint,
5554
config,
@@ -61,18 +60,14 @@ private UfcHttpConfigService(final Config config, final HttpUrl endpoint) {
6160
Executors.newSingleThreadScheduledExecutor(new UfcHttpThreadFactory()));
6261
}
6362

64-
UfcHttpConfigService(
63+
AgentlessConfigurationSource(
6564
final HttpUrl endpoint,
6665
final Config config,
6766
final long pollIntervalMillis,
6867
final UfcHttpClient client,
6968
final ScheduledExecutorService executor) {
7069
this.endpoint = endpoint;
7170
this.config = config;
72-
final Map<String, String> configuredExtraHeaders =
73-
config.getFeatureFlaggingConfigurationSourceExtraHeaders();
74-
this.extraHeaders =
75-
configuredExtraHeaders == null ? Collections.emptyMap() : configuredExtraHeaders;
7671
this.pollIntervalMillis = pollIntervalMillis;
7772
this.client = client;
7873
this.executor = executor;
@@ -120,7 +115,7 @@ private void pollOnceSafely() {
120115
private boolean fetchAndApply() {
121116
for (int attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
122117
try {
123-
final UfcHttpResponse response = client.fetch(endpoint, config, extraHeaders, etag);
118+
final UfcHttpResponse response = client.fetch(endpoint, config, etag);
124119
if (isRetryableStatus(response.status) && attempt < MAX_ATTEMPTS) {
125120
continue;
126121
}
@@ -176,11 +171,7 @@ private void updateEtag(final String nextEtag) {
176171
}
177172

178173
static HttpUrl endpoint(final Config config) {
179-
final String configuredBaseUrl = config.getFeatureFlaggingConfigurationSourceBaseUrl();
180-
final String endpoint =
181-
configuredBaseUrl == null
182-
? datadogApiServerDistributionEndpoint(config)
183-
: endpointFromConfiguredUrl(configuredBaseUrl);
174+
final String endpoint = datadogApiServerDistributionEndpoint(config);
184175
final HttpUrl parsed = HttpUrl.parse(endpoint);
185176
if (parsed == null) {
186177
throw new IllegalArgumentException(
@@ -189,26 +180,6 @@ static HttpUrl endpoint(final Config config) {
189180
return parsed;
190181
}
191182

192-
private static String endpointFromConfiguredUrl(final String configuredUrl) {
193-
final HttpUrl parsed = HttpUrl.parse(configuredUrl.trim());
194-
if (parsed == null) {
195-
throw new IllegalArgumentException(
196-
"Invalid Feature Flagging HTTP configuration source URL: " + configuredUrl);
197-
}
198-
if (isRootPath(parsed)) {
199-
return parsed
200-
.newBuilder()
201-
.addPathSegments(datadogApiServerDistributionPath())
202-
.build()
203-
.toString();
204-
}
205-
return parsed.toString();
206-
}
207-
208-
private static boolean isRootPath(final HttpUrl url) {
209-
return "/".equals(url.encodedPath()) || url.encodedPath().isEmpty();
210-
}
211-
212183
private static String datadogApiServerDistributionEndpoint(final Config config) {
213184
final StringBuilder endpoint =
214185
new StringBuilder("https://api.")
@@ -221,10 +192,6 @@ private static String datadogApiServerDistributionEndpoint(final Config config)
221192
return endpoint.toString();
222193
}
223194

224-
private static String datadogApiServerDistributionPath() {
225-
return DATADOG_API_SERVER_DISTRIBUTION_PATH.substring(1);
226-
}
227-
228195
private static String urlEncode(final String value) {
229196
try {
230197
return URLEncoder.encode(value, "UTF-8");
@@ -238,9 +205,7 @@ static long millis(final double seconds) {
238205
}
239206

240207
interface UfcHttpClient {
241-
UfcHttpResponse fetch(
242-
HttpUrl endpoint, Config config, Map<String, String> extraHeaders, String etag)
243-
throws IOException;
208+
UfcHttpResponse fetch(HttpUrl endpoint, Config config, String etag) throws IOException;
244209
}
245210

246211
static final class UfcHttpResponse {
@@ -263,13 +228,9 @@ private OkHttpUfcHttpClient(final OkHttpClient httpClient) {
263228
}
264229

265230
@Override
266-
public UfcHttpResponse fetch(
267-
final HttpUrl endpoint,
268-
final Config config,
269-
final Map<String, String> extraHeaders,
270-
final String etag)
231+
public UfcHttpResponse fetch(final HttpUrl endpoint, final Config config, final String etag)
271232
throws IOException {
272-
final Map<String, String> headers = new HashMap<>(extraHeaders);
233+
final Map<String, String> headers = new HashMap<>();
273234
if (etag != null) {
274235
headers.put("If-None-Match", etag);
275236
}

0 commit comments

Comments
 (0)