Skip to content

[BUG] Unable to flip feature flags defined in FeatureFlags.java #9564

@noCharger

Description

@noCharger

Describe the bug

A clear and concise description of what the bug is.

The feature flags used for experimental are defined here. This below example creates an setting static object with the feature flag name and default value.

    public static final Setting<Boolean> IDENTITY_SETTING = Setting.boolSetting(IDENTITY, false, Property.NodeScope);

However, if the feature flag is not specified as an env variable or written in the yml file, the FeatureFlags.isEnabled method does not read the value from these static settings and instead sets to 'false' by default.

    /**
     * Used to test feature flags whose values are expected to be booleans.
     * This method returns true if the value is "true" (case-insensitive),
     * and false otherwise.
     */
    public static boolean isEnabled(String featureFlagName) {
        if ("true".equalsIgnoreCase(System.getProperty(featureFlagName))) {
            // TODO: Remove the if condition once FeatureFlags are only supported via opensearch.yml
            return true;
        }

        return settings != null && settings.getAsBoolean(featureFlagName, false);
    }

Because these feature flag settings are never initialized / registered during node boostrap, it causes the difficulty when adding a static setting with the default value of true to keep the feature enabled but still gated behind the flag.

For example on node.java, if the default value on FeatureFlags.IDENTITY is set to true, the FeatureFlags.isEnabled will always return false.

    final Settings settings = pluginsService.updatedSettings();

    // Ensure to initialize Feature Flags via the settings from opensearch.yml
    FeatureFlags.initializeFeatureFlags(settings);

    final List<IdentityPlugin> identityPlugins = new ArrayList<>();
    if (FeatureFlags.isEnabled(FeatureFlags.IDENTITY)) {
        ...
       # this condition will never entered
    }

To Reproduce
Steps to reproduce the behavior:

  1. Set any feature flag (for example IDENTITY_SETTING) default value to true
    public static final Setting<Boolean> IDENTITY_SETTING = Setting.boolSetting(IDENTITY, false, Property.NodeScope);
  2. Add logs around FeatureFlags.isEnabled method usage during node bootstrap
    final Settings settings = pluginsService.updatedSettings();
    // Ensure to initialize Feature Flags via the settings from opensearch.yml
    FeatureFlags.initializeFeatureFlags(settings);
    final List<IdentityPlugin> identityPlugins = new ArrayList<>();
    if (FeatureFlags.isEnabled(FeatureFlags.IDENTITY)) {
    # Example logging
    logger.info("louis-feature-flag-test: " + FeatureFlags.IDENTITY + " value: " + settings.get(FeatureFlags.IDENTITY));
    if (FeatureFlags.isEnabled(FeatureFlags.IDENTITY)) {
        // If identity is enabled load plugins implementing the extension point
        logger.info("Identity on so found plugins implementing: " + pluginsService.filterPlugins(IdentityPlugin.class).toString());
        identityPlugins.addAll(pluginsService.filterPlugins(IdentityPlugin.class));
    }
  1. Start cluster
./gradlew run --debug-server-jvm --info 
  1. See error
[2023-08-25T12:46:29,937][INFO ][o.o.n.Node               ] [runTask-0] louis-feature-flag-test: opensearch.experimental.feature.identity.enabled value: null
[2023-08-25T12:46:29,938][INFO ][o.o.n.Node               ] [runTask-0] louis-feature-flag-test: opensearch.experimental.feature.extensions.enabled value: null

Expected behavior

A clear and concise description of what you expected to happen.

Some options here

  1. Disallow the use case of adding a static setting with the default value of 'true' in order to keep the feature enabled but still gated behind the flag: We could limit the feature flag's functionality by concealing the default_value during static setting construction. The default value is then set to always false. On public doc and java doc, we should explictly mention that flags are required to be removed when you want to enable the feature.
  2. FeatureFlags.isEnabled reads the setting object's real default_value.

Metadata

Metadata

Assignees

Labels

bugSomething isn't workinggood first issueGood for newcomers

Type

No type

Projects

Status

✅ Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions