Skip to content

Commit

Permalink
Optionally block enabling certain feature flags via Management UI/API
Browse files Browse the repository at this point in the history
Useful to avoid accidentally enabling for example experiemental
feature flags from the Management UI on sensitive clusters.
  • Loading branch information
gomoripeti committed Mar 5, 2024
1 parent 8e0f5d3 commit 852eb34
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -646,3 +646,10 @@ end}.
{datatype, {enum, [true, false]}},
{include_default, false}
]}.

%% Block enabling certain feature flags over API

{mapping, "management.restrictions.feature_flag_blocked.$name", "rabbitmq_management.restrictions.feature_flag_blocked", [
{datatype, [string, {enum, [false]}]},
{include_default, false}
]}.
8 changes: 8 additions & 0 deletions deps/rabbitmq_management/src/rabbit_mgmt_features.erl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

-export([is_op_policy_updating_disabled/0,
is_qq_replica_operations_disabled/0,
is_feature_flag_blocked/1,
are_stats_enabled/0]).

is_qq_replica_operations_disabled() ->
Expand All @@ -20,6 +21,13 @@ is_op_policy_updating_disabled() ->
_ -> false
end.

-spec is_feature_flag_blocked(rabbit_feature_flags:feature_name()) -> {true, string()} | false.
is_feature_flag_blocked(FeatureFlag) ->
case get_restriction([feature_flag_blocked, FeatureFlag]) of
Msg when is_list(Msg) -> {true, Msg};
_ -> false
end.

are_stats_enabled() ->
DisabledFromConf = application:get_env(
rabbitmq_management, disable_management_stats, false),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
-export([variances/2]).

-include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl").
-include_lib("rabbit_common/include/rabbit.hrl").

%%--------------------------------------------------------------------

Expand All @@ -38,13 +37,18 @@ accept_content(ReqData, #context{} = Context) ->
NameS = rabbit_mgmt_util:id(name, ReqData),
try
Name = list_to_existing_atom(binary_to_list(NameS)),
case rabbit_feature_flags:enable(Name) of
ok ->
{true, ReqData, Context};
{error, Reason1} ->
FormattedReason1 = rabbit_ff_extra:format_error(Reason1),
rabbit_mgmt_util:bad_request(
list_to_binary(FormattedReason1), ReqData, Context)
case rabbit_mgmt_features:is_feature_flag_blocked(Name) of
{true, Message} ->
rabbit_mgmt_util:method_not_allowed(Message, ReqData, Context);
false ->
case rabbit_feature_flags:enable(Name) of
ok ->
{true, ReqData, Context};
{error, Reason1} ->
FormattedReason1 = rabbit_ff_extra:format_error(Reason1),
rabbit_mgmt_util:bad_request(
list_to_binary(FormattedReason1), ReqData, Context)
end
end
catch
_:badarg ->
Expand Down
28 changes: 28 additions & 0 deletions deps/rabbitmq_management/test/rabbit_mgmt_http_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ all_tests() -> [
user_limit_set_test,
config_environment_test,
disabled_qq_replica_opers_test,
feature_flag_blocked_test,
list_deprecated_features_test,
list_used_deprecated_features_test
].
Expand Down Expand Up @@ -242,6 +243,21 @@ init_per_testcase(Testcase = disabled_qq_replica_opers_test, Config) ->
rabbit_ct_broker_helpers:rpc_all(Config,
application, set_env, [rabbitmq_management, restrictions, Restrictions]),
rabbit_ct_helpers:testcase_started(Config, Testcase);
init_per_testcase(Testcase = feature_flag_blocked_test, Config) ->
Desc = "This is an experimental feature",
DocUrl = "https://rabbitmq.com/",
FeatureFlags = #{Testcase =>
#{provided_by => ?MODULE,
desc => Desc,
doc_url => DocUrl}},
ok = rabbit_ct_broker_helpers:rpc(Config, 0, rabbit_feature_flags,
inject_test_feature_flags,
[FeatureFlags]),

Restrictions = [{feature_flag_blocked, [{Testcase, "This feature flag is blocked"}]}],
rabbit_ct_broker_helpers:rpc_all(Config,
application, set_env, [rabbitmq_management, restrictions, Restrictions]),
rabbit_ct_helpers:testcase_started(Config, Testcase);
init_per_testcase(queues_detailed_test, Config) ->
IsEnabled = rabbit_ct_broker_helpers:is_feature_flag_enabled(
Config, detailed_queues_endpoint),
Expand Down Expand Up @@ -308,6 +324,13 @@ end_per_testcase0(disabled_operator_policy_test, Config) ->
end_per_testcase0(disabled_qq_replica_opers_test, Config) ->
rpc(Config, application, unset_env, [rabbitmq_management, restrictions]),
Config;
end_per_testcase0(feature_flag_blocked_test, Config) ->
rabbit_ct_broker_helpers:rpc(Config, 0, application, unset_env,
[rabbitmq_management, restrictions]),
ok = rabbit_ct_broker_helpers:rpc(Config, 0, rabbit_feature_flags,
clear_injected_test_feature_flags,
[]),
Config;
end_per_testcase0(Testcase, Config)
when Testcase == list_deprecated_features_test;
Testcase == list_used_deprecated_features_test ->
Expand Down Expand Up @@ -3770,6 +3793,11 @@ disabled_qq_replica_opers_test(Config) ->
http_delete(Config, "/queues/quorum/replicas/on/" ++ Nodename ++ "/shrink", ?METHOD_NOT_ALLOWED),
passed.

feature_flag_blocked_test(Config) ->
Body = "",
http_put(Config, "/feature-flags/" ++ atom_to_list(?FUNCTION_NAME) ++ "/enable", Body, ?METHOD_NOT_ALLOWED),
passed.

list_deprecated_features_test(Config) ->
Desc = "This is a deprecated feature",
DocUrl = "https://rabbitmq.com/",
Expand Down

0 comments on commit 852eb34

Please sign in to comment.