Skip to content

Commit e081df7

Browse files
authored
Merge pull request #8946 from rabbitmq/feature-flags-and-rabbit_db-improvements
Improvements to feature flags and `rabbit_db*`
2 parents 51b353f + 0a9e35d commit e081df7

File tree

4 files changed

+172
-11
lines changed

4 files changed

+172
-11
lines changed

deps/rabbit/src/rabbit_db_cluster.erl

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,7 @@ can_join(RemoteNode) ->
5858
#{domain => ?RMQLOG_DOMAIN_DB}),
5959
case rabbit_feature_flags:check_node_compatibility(RemoteNode) of
6060
ok ->
61-
rabbit_db:run(
62-
#{mnesia => fun() -> can_join_using_mnesia(RemoteNode) end});
61+
can_join_using_mnesia(RemoteNode);
6362
Error ->
6463
Error
6564
end.
@@ -79,16 +78,16 @@ join(RemoteNode, NodeType)
7978
when is_atom(RemoteNode) andalso ?IS_NODE_TYPE(NodeType) ->
8079
case can_join(RemoteNode) of
8180
{ok, ClusterNodes} when is_list(ClusterNodes) ->
82-
rabbit_db:reset(),
81+
ok = rabbit_db:reset(),
8382

8483
?LOG_INFO(
8584
"DB: joining cluster using remote nodes:~n~tp", [ClusterNodes],
8685
#{domain => ?RMQLOG_DOMAIN_DB}),
87-
Ret = rabbit_db:run(
88-
#{mnesia =>
89-
fun() -> join_using_mnesia(ClusterNodes, NodeType) end}),
86+
Ret = join_using_mnesia(ClusterNodes, NodeType),
9087
case Ret of
9188
ok ->
89+
rabbit_feature_flags:copy_feature_states_after_reset(
90+
RemoteNode),
9291
rabbit_node_monitor:notify_joined_cluster(),
9392
ok;
9493
{error, _} = Error ->

deps/rabbit/src/rabbit_feature_flags.erl

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@
120120
query_supported_feature_flags/0,
121121
does_enabled_feature_flags_list_file_exist/0,
122122
read_enabled_feature_flags_list/0,
123+
copy_feature_states_after_reset/1,
123124
uses_callbacks/1,
124125
reset_registry/0]).
125126

@@ -1122,10 +1123,13 @@ try_to_write_enabled_feature_flags_list(FeatureNames) ->
11221123
false -> [Name | Acc]
11231124
end
11241125
end, FeatureNames1, PreviouslyEnabled),
1125-
FeatureNames3 = lists:sort(FeatureNames2),
1126+
do_write_enabled_feature_flags_list(FeatureNames2).
1127+
1128+
do_write_enabled_feature_flags_list(EnabledFeatureNames) ->
1129+
EnabledFeatureNames1 = lists:sort(EnabledFeatureNames),
11261130

11271131
File = enabled_feature_flags_list_file(),
1128-
Content = io_lib:format("~tp.~n", [FeatureNames3]),
1132+
Content = io_lib:format("~tp.~n", [EnabledFeatureNames1]),
11291133
%% TODO: If we fail to write the the file, we should spawn a process
11301134
%% to retry the operation.
11311135
case file:write_file(File, Content) of
@@ -1152,6 +1156,24 @@ enabled_feature_flags_list_file() ->
11521156
undefined -> throw(feature_flags_file_not_set)
11531157
end.
11541158

1159+
copy_feature_states_after_reset(RemoteNode) ->
1160+
?assertEqual(undefined, erlang:whereis(rabbit_ff_controller)),
1161+
EnabledFeatureFlags = erpc:call(
1162+
RemoteNode, ?MODULE, list, [enabled], 60000),
1163+
EnabledFeatureNames = maps:keys(EnabledFeatureFlags),
1164+
?LOG_DEBUG(
1165+
"Feature flags: copy feature states from remote node `~ts` after "
1166+
"a reset of this node `~ts`; enabled feature flags:~n~p",
1167+
[RemoteNode, node(), EnabledFeatureNames],
1168+
#{domain => ?RMQLOG_DOMAIN_FEAT_FLAGS}),
1169+
case do_write_enabled_feature_flags_list(EnabledFeatureNames) of
1170+
ok ->
1171+
ok;
1172+
{error, Reason} ->
1173+
File = enabled_feature_flags_list_file(),
1174+
throw({feature_flags_file_copy_error, File, Reason})
1175+
end.
1176+
11551177
%% -------------------------------------------------------------------
11561178
%% Feature flags management: enabling.
11571179
%% -------------------------------------------------------------------

deps/rabbit/src/rabbit_ff_registry_factory.erl

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ maybe_initialize_registry(NewSupportedFeatureFlags,
258258
false ->
259259
NewFeatureStates
260260
end,
261-
FeatureStates =
261+
FeatureStates1 =
262262
maps:map(
263263
fun
264264
(FeatureName, FeatureProps) when ?IS_FEATURE_FLAG(FeatureProps) ->
@@ -308,6 +308,18 @@ maybe_initialize_registry(NewSupportedFeatureFlags,
308308
end
309309
end, AllFeatureFlags),
310310

311+
%% We don't record the state of deprecated features because it is
312+
%% controlled from configuration and they can be disabled (the deprecated
313+
%% feature can be turned back on) if the deprecated feature allows it.
314+
%%
315+
%% However, some feature flags may depend on deprecated features. If those
316+
%% feature flags are enabled, we need to enable the deprecated features
317+
%% (turn off the deprecated features) they depend on regardless of the
318+
%% configuration.
319+
FeatureStates =
320+
enable_deprecated_features_required_by_enabled_feature_flags(
321+
AllFeatureFlags, FeatureStates1),
322+
311323
%% The feature flags inventory is used by rabbit_ff_controller to query
312324
%% feature flags atomically. The inventory also contains the list of
313325
%% scanned applications: this is used to determine if an application is
@@ -400,6 +412,39 @@ does_registry_need_refresh(AllFeatureFlags,
400412
true
401413
end.
402414

415+
-spec enable_deprecated_features_required_by_enabled_feature_flags(
416+
FeatureFlags, FeatureStates) -> NewFeatureStates when
417+
FeatureFlags :: rabbit_feature_flags:feature_flags(),
418+
FeatureStates :: rabbit_feature_flags:feature_states(),
419+
NewFeatureStates :: rabbit_feature_flags:feature_states().
420+
421+
enable_deprecated_features_required_by_enabled_feature_flags(
422+
FeatureFlags, FeatureStates) ->
423+
FeatureStates1 =
424+
maps:map(
425+
fun
426+
(DependencyName, false) ->
427+
RequiredBy =
428+
maps:filter(
429+
fun
430+
(FeatureName, #{depends_on := DependsOn}) ->
431+
lists:member(DependencyName, DependsOn) andalso
432+
maps:get(FeatureName, FeatureStates) =:= true;
433+
(_FeatureName, _FeatureProps) ->
434+
false
435+
end, FeatureFlags),
436+
maps:size(RequiredBy) > 0;
437+
(_DependencyName, State) ->
438+
State
439+
end, FeatureStates),
440+
case FeatureStates1 of
441+
FeatureStates ->
442+
FeatureStates;
443+
_ ->
444+
enable_deprecated_features_required_by_enabled_feature_flags(
445+
FeatureFlags, FeatureStates1)
446+
end.
447+
403448
-spec do_initialize_registry(Vsn,
404449
FeatureFlags,
405450
FeatureStates,

deps/rabbit/test/deprecated_features_SUITE.erl

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
get_appropriate_warning_when_denied/1,
3636
get_appropriate_warning_when_disconnected/1,
3737
get_appropriate_warning_when_removed/1,
38+
deprecated_feature_enabled_if_feature_flag_depends_on_it/1,
3839

3940
feature_is_unused/1,
4041
feature_is_used/1
@@ -65,7 +66,8 @@ groups() ->
6566
get_appropriate_warning_when_permitted,
6667
get_appropriate_warning_when_denied,
6768
get_appropriate_warning_when_disconnected,
68-
get_appropriate_warning_when_removed
69+
get_appropriate_warning_when_removed,
70+
deprecated_feature_enabled_if_feature_flag_depends_on_it
6971
],
7072
[
7173
{cluster_size_1, [], Tests},
@@ -97,10 +99,14 @@ end_per_group(_Group, Config) ->
9799
Config.
98100

99101
init_per_testcase(Testcase, Config) ->
102+
NodesCount = ?config(nodes_count, Config),
103+
NodenamePrefix = list_to_atom(
104+
lists:flatten(
105+
io_lib:format("~s-cs~b", [Testcase, NodesCount]))),
100106
rabbit_ct_helpers:run_steps(
101107
Config,
102108
[fun(Cfg) ->
103-
feature_flags_v2_SUITE:start_slave_nodes(Cfg, Testcase)
109+
feature_flags_v2_SUITE:start_slave_nodes(Cfg, NodenamePrefix)
104110
end]).
105111

106112
end_per_testcase(_Testcase, Config) ->
@@ -631,3 +637,92 @@ get_appropriate_warning_when_removed(Config) ->
631637
ok
632638
end)
633639
|| Node <- AllNodes].
640+
641+
deprecated_feature_enabled_if_feature_flag_depends_on_it(Config) ->
642+
[FirstNode | _] = AllNodes = ?config(nodes, Config),
643+
feature_flags_v2_SUITE:connect_nodes(AllNodes),
644+
feature_flags_v2_SUITE:override_running_nodes(AllNodes),
645+
646+
FeatureName = ?FUNCTION_NAME,
647+
FeatureFlags = #{FeatureName =>
648+
#{provided_by => rabbit,
649+
deprecation_phase => permitted_by_default},
650+
651+
my_feature_flag =>
652+
#{provided_by => rabbit,
653+
stability => experimental,
654+
depends_on => [FeatureName]}},
655+
?assertEqual(
656+
ok,
657+
feature_flags_v2_SUITE:inject_on_nodes(AllNodes, FeatureFlags)),
658+
659+
_ = [ok =
660+
feature_flags_v2_SUITE:run_on_node(
661+
Node,
662+
fun() ->
663+
?assert(rabbit_feature_flags:is_supported(FeatureName)),
664+
?assertNot(rabbit_feature_flags:is_enabled(FeatureName)),
665+
?assert(
666+
rabbit_deprecated_features:is_permitted(FeatureName)),
667+
ok
668+
end)
669+
|| Node <- AllNodes],
670+
671+
ok = feature_flags_v2_SUITE:run_on_node(
672+
FirstNode,
673+
fun() ->
674+
?assertEqual(
675+
ok,
676+
rabbit_feature_flags:enable(my_feature_flag)),
677+
ok
678+
end),
679+
680+
_ = [ok =
681+
feature_flags_v2_SUITE:run_on_node(
682+
Node,
683+
fun() ->
684+
?assert(rabbit_feature_flags:is_enabled(my_feature_flag)),
685+
686+
?assert(rabbit_feature_flags:is_supported(FeatureName)),
687+
?assert(rabbit_feature_flags:is_enabled(FeatureName)),
688+
?assertNot(
689+
rabbit_deprecated_features:is_permitted(FeatureName)),
690+
ok
691+
end )
692+
|| Node <- AllNodes],
693+
694+
_ = [ok =
695+
feature_flags_v2_SUITE:run_on_node(
696+
Node,
697+
fun() ->
698+
?assertEqual(
699+
ok,
700+
rabbit_ff_registry_factory:reset_registry()),
701+
ok
702+
end )
703+
|| Node <- AllNodes],
704+
705+
_ = [ok =
706+
feature_flags_v2_SUITE:run_on_node(
707+
Node,
708+
fun() ->
709+
?assertEqual(
710+
ok,
711+
rabbit_ff_registry_factory:initialize_registry()),
712+
ok
713+
end )
714+
|| Node <- AllNodes],
715+
716+
_ = [ok =
717+
feature_flags_v2_SUITE:run_on_node(
718+
Node,
719+
fun() ->
720+
?assert(rabbit_feature_flags:is_enabled(my_feature_flag)),
721+
722+
?assert(rabbit_feature_flags:is_supported(FeatureName)),
723+
?assert(rabbit_feature_flags:is_enabled(FeatureName)),
724+
?assertNot(
725+
rabbit_deprecated_features:is_permitted(FeatureName)),
726+
ok
727+
end )
728+
|| Node <- AllNodes].

0 commit comments

Comments
 (0)