Skip to content

Commit bca75fa

Browse files
committed
fix(openfeature): preserve source compatibility settings
1 parent 289d4a0 commit bca75fa

4 files changed

Lines changed: 72 additions & 7 deletions

File tree

products/feature-flagging/feature-flagging-api/src/main/java/datadog/trace/api/openfeature/Provider.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,8 @@ public static class Options {
281281

282282
private long timeout = 30;
283283
private TimeUnit unit = SECONDS;
284+
Boolean providerEnabled;
285+
Boolean legacyProviderEnabled;
284286
String configurationSource;
285287
String cdnBaseUrl;
286288
String apiKey;
@@ -300,6 +302,11 @@ public Options configurationSource(final String configurationSource) {
300302
return this;
301303
}
302304

305+
public Options enabled(final boolean enabled) {
306+
this.providerEnabled = enabled;
307+
return this;
308+
}
309+
303310
public Options cdnBaseUrl(final String cdnBaseUrl) {
304311
this.cdnBaseUrl = cdnBaseUrl;
305312
return this;

products/feature-flagging/feature-flagging-api/src/main/java/datadog/trace/api/openfeature/ProviderRuntime.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ private ProviderRuntime() {}
1717

1818
static Handle acquire(
1919
final RuntimeConfiguration configuration, final Consumer<ConfigurationSnapshot> listener) {
20+
if (configuration.source == RuntimeConfiguration.Source.DISABLED) {
21+
throw new IllegalStateException("Datadog OpenFeature provider is disabled by configuration");
22+
}
2023
synchronized (LOCK) {
2124
if (shared == null) {
2225
shared = new SharedRuntime(configuration);

products/feature-flagging/feature-flagging-api/src/main/java/datadog/trace/api/openfeature/RuntimeConfiguration.java

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ final class RuntimeConfiguration {
1313

1414
enum Source {
1515
CDN,
16-
REMOTE_CONFIG
16+
REMOTE_CONFIG,
17+
DISABLED
1718
}
1819

1920
final Source source;
@@ -25,13 +26,23 @@ private RuntimeConfiguration(final Source source, final HttpConfigurationOptions
2526
}
2627

2728
static RuntimeConfiguration resolve(final Provider.Options options) {
29+
final Boolean providerEnabled =
30+
options.providerEnabled != null
31+
? options.providerEnabled
32+
: booleanSetting("dd.feature.flags.enabled", "DD_FEATURE_FLAGS_ENABLED");
2833
final String sourceValue =
2934
first(
3035
options.configurationSource,
3136
setting(
3237
"dd.feature.flags.configuration.source", "DD_FEATURE_FLAGS_CONFIGURATION_SOURCE"));
33-
final Source source = parseSource(sourceValue);
34-
if (source == Source.REMOTE_CONFIG) {
38+
final Boolean legacyProviderEnabled =
39+
options.legacyProviderEnabled != null
40+
? options.legacyProviderEnabled
41+
: booleanSetting(
42+
"dd.experimental.flagging.provider.enabled",
43+
"DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED");
44+
final Source source = resolveSource(providerEnabled, sourceValue, legacyProviderEnabled);
45+
if (source != Source.CDN) {
3546
return new RuntimeConfiguration(source, null);
3647
}
3748

@@ -72,19 +83,28 @@ static RuntimeConfiguration resolve(final Provider.Options options) {
7283
.build());
7384
}
7485

75-
private static Source parseSource(final String value) {
76-
if (value == null || value.trim().isEmpty()) {
86+
private static Source resolveSource(
87+
final Boolean providerEnabled,
88+
final String sourceValue,
89+
final Boolean legacyProviderEnabled) {
90+
if (Boolean.FALSE.equals(providerEnabled)) {
91+
return Source.DISABLED;
92+
}
93+
if (sourceValue == null || sourceValue.trim().isEmpty()) {
94+
if (legacyProviderEnabled != null) {
95+
return legacyProviderEnabled ? Source.REMOTE_CONFIG : Source.DISABLED;
96+
}
7797
return Source.CDN;
7898
}
79-
final String normalized = value.trim().toLowerCase(Locale.ROOT);
99+
final String normalized = sourceValue.trim().toLowerCase(Locale.ROOT);
80100
if ("agentless".equals(normalized) || "cdn".equals(normalized)) {
81101
return Source.CDN;
82102
}
83103
if ("remote_config".equals(normalized)) {
84104
return Source.REMOTE_CONFIG;
85105
}
86106
throw new IllegalArgumentException(
87-
"Unsupported Feature Flagging configuration source: " + value);
107+
"Unsupported Feature Flagging configuration source: " + sourceValue);
88108
}
89109

90110
private static Duration seconds(final String value, final long defaultValue) {
@@ -105,6 +125,11 @@ private static String setting(final String property, final String environment) {
105125
return propertyValue != null ? propertyValue : System.getenv(environment);
106126
}
107127

128+
private static Boolean booleanSetting(final String property, final String environment) {
129+
final String value = setting(property, environment);
130+
return value == null ? null : Boolean.valueOf(value);
131+
}
132+
108133
private static String first(final String... values) {
109134
for (final String value : values) {
110135
if (value != null && !value.isEmpty()) {

products/feature-flagging/feature-flagging-api/src/test/java/datadog/trace/api/openfeature/ProviderTest.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,36 @@ void selectsCdnByDefaultAndRemoteConfigExplicitly() {
5050
.source);
5151
}
5252

53+
@Test
54+
void preservesStableAndLegacySourceSelection() {
55+
assertEquals(
56+
RuntimeConfiguration.Source.DISABLED,
57+
RuntimeConfiguration.resolve(new Provider.Options().enabled(false)).source);
58+
59+
final Provider.Options legacyEnabled = new Provider.Options();
60+
legacyEnabled.legacyProviderEnabled = true;
61+
assertEquals(
62+
RuntimeConfiguration.Source.REMOTE_CONFIG,
63+
RuntimeConfiguration.resolve(legacyEnabled).source);
64+
65+
final Provider.Options legacyDisabled = new Provider.Options();
66+
legacyDisabled.legacyProviderEnabled = false;
67+
assertEquals(
68+
RuntimeConfiguration.Source.DISABLED, RuntimeConfiguration.resolve(legacyDisabled).source);
69+
assertEquals(
70+
RuntimeConfiguration.Source.CDN,
71+
RuntimeConfiguration.resolve(legacyDisabled.configurationSource("agentless")).source);
72+
}
73+
74+
@Test
75+
void disabledProviderDoesNotStartConfigurationSource() {
76+
first = new Provider(new Provider.Options().enabled(false).initTimeout(10, MILLISECONDS));
77+
78+
final FatalError error =
79+
assertThrows(FatalError.class, () -> first.initialize(new MutableContext()));
80+
assertTrue(error.getMessage().contains("disabled by configuration"));
81+
}
82+
5383
@Test
5484
void providerOwnsCdnLifecycleWithoutAgent() throws Exception {
5585
final AtomicInteger requests = new AtomicInteger();

0 commit comments

Comments
 (0)