Skip to content

Commit b8b5bb9

Browse files
committed
Mark RAM node type as deprecated
[Why] RAM nodes provide no safety at all and they lost interest with recent fast storage solutions. [How] RAM nodes are marked as deprecated in the code using the Deprecated features subsystem (based on feature flags). See pull request #7390 for a description of that subsystem. To test RabbitMQ behavior as if the feature was removed, the following configuration setting can be used: deprecated_features.permit.ram_node_type = false To turn off RAM nodes, there must be no RAM nodes in the cluster. Once RAM nodes are turned off, an existing node previously created as a RAM node will change itself to a disc node during boot. If a new node is added to the cluster using peer discovery or the CLI, it will be as a disc node and a warning will be logged if the requested node type is RAM. Note that given the marketing calendar, the deprecated feature will go directly from "permitted by default" to "removed" in RabbitMQ 4.0. It won't go through the gradual deprecation process.
1 parent aa8a6f5 commit b8b5bb9

File tree

2 files changed

+156
-8
lines changed

2 files changed

+156
-8
lines changed

deps/rabbit/src/rabbit_mnesia.erl

+47-5
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@
7979
%% Main interface
8080
%%----------------------------------------------------------------------------
8181

82+
-rabbit_deprecated_feature(
83+
{ram_node_type,
84+
#{deprecation_phase => permitted_by_default,
85+
doc_url => "https://blog.rabbitmq.com/posts/2021/08/4.0-deprecation-announcements/#removal-of-ram-nodes"
86+
}}).
87+
8288
-spec init() -> 'ok'.
8389

8490
init() ->
@@ -94,8 +100,18 @@ init() ->
94100
init_with_lock();
95101
false ->
96102
NodeType = node_type(),
97-
init_db_and_upgrade(cluster_nodes(all), NodeType,
98-
NodeType =:= ram, _Retry = true),
103+
NodeTypeConvNeeded = not is_node_type_permitted(NodeType),
104+
case NodeTypeConvNeeded of
105+
false ->
106+
init_db_and_upgrade(cluster_nodes(all), NodeType,
107+
NodeType =:= ram, _Retry = true);
108+
true ->
109+
rabbit_log:info(
110+
"RAM nodes are deprecated and not permitted. This "
111+
"node will be converted to a disc node."),
112+
init_db_and_upgrade(cluster_nodes(all), disc,
113+
true, _Retry = true)
114+
end,
99115
rabbit_peer_discovery:maybe_init(),
100116
rabbit_peer_discovery:maybe_register()
101117
end,
@@ -180,9 +196,13 @@ run_peer_discovery_with_retries(RetriesLeft, DelayInterval) ->
180196
"Enabling debug logging might help troubleshoot."),
181197
init_db_and_upgrade([node()], disc, false, _Retry = true);
182198
_ ->
199+
NodeType1 = case is_node_type_permitted(NodeType) of
200+
false -> disc;
201+
true -> NodeType
202+
end,
183203
rabbit_log:info("Peer nodes we can cluster with: ~ts",
184204
[rabbit_peer_discovery:format_discovered_nodes(Peers)]),
185-
join_discovered_peers(Peers, NodeType)
205+
join_discovered_peers(Peers, NodeType1)
186206
end.
187207

188208
%% Attempts to join discovered,
@@ -250,10 +270,15 @@ join_cluster(DiscoveryNode, NodeType) ->
250270
%% of resetting the node from the user.
251271
reset_gracefully(),
252272

273+
NodeType1 = case is_node_type_permitted(NodeType) of
274+
false -> disc;
275+
true -> NodeType
276+
end,
277+
253278
%% Join the cluster
254279
rabbit_log:info("Clustering with ~tp as ~tp node",
255-
[ClusterNodes, NodeType]),
256-
ok = init_db_with_mnesia(ClusterNodes, NodeType,
280+
[ClusterNodes, NodeType1]),
281+
ok = init_db_with_mnesia(ClusterNodes, NodeType1,
257282
true, true, _Retry = true),
258283
rabbit_node_monitor:notify_joined_cluster(),
259284
ok;
@@ -320,6 +345,7 @@ wipe() ->
320345
-spec change_cluster_node_type(rabbit_db_cluster:node_type()) -> 'ok'.
321346

322347
change_cluster_node_type(Type) ->
348+
ensure_node_type_is_permitted(Type),
323349
ensure_mnesia_not_running(),
324350
ensure_mnesia_dir(),
325351
case is_clustered() of
@@ -549,6 +575,20 @@ node_type() ->
549575
false -> ram
550576
end.
551577

578+
is_node_type_permitted(ram) ->
579+
rabbit_deprecated_features:is_permitted(ram_node_type);
580+
is_node_type_permitted(_NodeType) ->
581+
true.
582+
583+
ensure_node_type_is_permitted(NodeType) ->
584+
case is_node_type_permitted(NodeType) of
585+
true ->
586+
ok;
587+
false ->
588+
Warning = rabbit_deprecated_features:get_warning(ram_node_type),
589+
throw({error, Warning})
590+
end.
591+
552592
-spec dir() -> file:filename().
553593

554594
dir() -> mnesia:system_info(directory).
@@ -562,6 +602,8 @@ dir() -> mnesia:system_info(directory).
562602
%% nodes in the cluster already. It also updates the cluster status
563603
%% file.
564604
init_db(ClusterNodes, NodeType, CheckOtherNodes) ->
605+
ensure_node_type_is_permitted(NodeType),
606+
565607
NodeIsVirgin = is_virgin_node(),
566608
rabbit_log:debug("Does data directory looks like that of a blank (uninitialised) node? ~tp", [NodeIsVirgin]),
567609
%% We want to synchronize feature flags first before we wait for

deps/rabbit/test/rabbitmq_4_0_deprecations_SUITE.erl

+109-3
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,29 @@
2323
end_per_testcase/2,
2424

2525
when_global_qos_is_permitted_by_default/1,
26-
when_global_qos_is_not_permitted_from_conf/1
26+
when_global_qos_is_not_permitted_from_conf/1,
27+
28+
join_when_ram_node_type_is_permitted_by_default/1,
29+
join_when_ram_node_type_is_not_permitted_from_conf/1
2730
]).
2831

2932
suite() ->
3033
[{timetrap, {minutes, 5}}].
3134

3235
all() ->
3336
[
34-
{group, global_qos}
37+
{group, global_qos},
38+
{group, ram_node_type}
3539
].
3640

3741
groups() ->
3842
[
3943
{global_qos, [],
4044
[when_global_qos_is_permitted_by_default,
41-
when_global_qos_is_not_permitted_from_conf]}
45+
when_global_qos_is_not_permitted_from_conf]},
46+
{ram_node_type, [],
47+
[join_when_ram_node_type_is_permitted_by_default,
48+
join_when_ram_node_type_is_not_permitted_from_conf]}
4249
].
4350

4451
%% -------------------------------------------------------------------
@@ -57,6 +64,9 @@ end_per_suite(Config) ->
5764

5865
init_per_group(global_qos, Config) ->
5966
rabbit_ct_helpers:set_config(Config, {rmq_nodes_count, 1});
67+
init_per_group(ram_node_type, Config) ->
68+
rabbit_ct_helpers:set_config(Config, [{rmq_nodes_count, 2},
69+
{rmq_nodes_clustered, false}]);
6070
init_per_group(_Group, Config) ->
6171
Config.
6272

@@ -70,6 +80,13 @@ init_per_testcase(
7080
{rabbit,
7181
[{permit_deprecated_features, #{global_qos => false}}]}),
7282
init_per_testcase1(Testcase, Config1);
83+
init_per_testcase(
84+
join_when_ram_node_type_is_not_permitted_from_conf = Testcase, Config) ->
85+
Config1 = rabbit_ct_helpers:merge_app_env(
86+
Config,
87+
{rabbit,
88+
[{permit_deprecated_features, #{ram_node_type => false}}]}),
89+
init_per_testcase1(Testcase, Config1);
7390
init_per_testcase(Testcase, Config) ->
7491
init_per_testcase1(Testcase, Config).
7592

@@ -152,6 +169,95 @@ is_prefetch_limited(ServerCh) ->
152169
LimiterState = element(3, ChState),
153170
element(3, LimiterState).
154171

172+
%% -------------------------------------------------------------------
173+
%% RAM node type.
174+
%% -------------------------------------------------------------------
175+
176+
join_when_ram_node_type_is_permitted_by_default(Config) ->
177+
[NodeA, NodeB] = rabbit_ct_broker_helpers:get_node_configs(
178+
Config, nodename),
179+
180+
ok = rabbit_control_helper:command(stop_app, NodeA),
181+
ok = rabbit_control_helper:command_with_output(
182+
join_cluster, NodeA,
183+
[atom_to_list(NodeB)], [{"--ram", true}]),
184+
ok = rabbit_control_helper:command(start_app, NodeA),
185+
186+
?assertEqual([NodeA, NodeB], get_all_nodes(Config, NodeA)),
187+
?assertEqual([NodeA, NodeB], get_all_nodes(Config, NodeB)),
188+
?assertEqual([NodeB], get_disc_nodes(Config, NodeA)),
189+
?assertEqual([NodeB], get_disc_nodes(Config, NodeB)),
190+
191+
?assert(
192+
log_file_contains_message(
193+
Config, NodeA,
194+
["Deprecated features: `ram_node_type`: Feature `ram_node_type` is deprecated",
195+
"By default, this feature can still be used for now."])),
196+
197+
%% Change the advanced configuration file to turn off RAM node type.
198+
ConfigFilename0 = rabbit_ct_broker_helpers:get_node_config(
199+
Config, NodeA, erlang_node_config_filename),
200+
ConfigFilename = ConfigFilename0 ++ ".config",
201+
{ok, [ConfigContent0]} = file:consult(ConfigFilename),
202+
ConfigContent1 = rabbit_ct_helpers:merge_app_env_in_erlconf(
203+
ConfigContent0,
204+
{rabbit, [{permit_deprecated_features,
205+
#{ram_node_type => false}}]}),
206+
ConfigContent2 = lists:flatten(io_lib:format("~p.~n", [ConfigContent1])),
207+
ok = file:write_file(ConfigFilename, ConfigContent2),
208+
?assertEqual({ok, [ConfigContent1]}, file:consult(ConfigFilename)),
209+
210+
%% Restart the node and see if it was correctly converted to a disc node.
211+
ok = rabbit_control_helper:command(stop_app, NodeA),
212+
Ret = rabbit_control_helper:command(start_app, NodeA),
213+
214+
case Ret of
215+
ok ->
216+
?assertEqual([NodeA, NodeB], get_all_nodes(Config, NodeA)),
217+
?assertEqual([NodeA, NodeB], get_all_nodes(Config, NodeB)),
218+
?assertEqual([NodeA, NodeB], get_disc_nodes(Config, NodeA)),
219+
?assertEqual([NodeA, NodeB], get_disc_nodes(Config, NodeB));
220+
{error, 69,
221+
<<"Error:\n{:rabbit, {:incompatible_feature_flags, ", _/binary>>} ->
222+
{skip, "Incompatible feature flags between nodes A and B"}
223+
end.
224+
225+
join_when_ram_node_type_is_not_permitted_from_conf(Config) ->
226+
[NodeA, NodeB] = rabbit_ct_broker_helpers:get_node_configs(
227+
Config, nodename),
228+
229+
ok = rabbit_control_helper:command(stop_app, NodeA),
230+
Ret = rabbit_control_helper:command_with_output(
231+
join_cluster, NodeA,
232+
[atom_to_list(NodeB)], [{"--ram", true}]),
233+
case Ret of
234+
ok ->
235+
ok = rabbit_control_helper:command(start_app, NodeA),
236+
237+
?assertEqual([NodeA, NodeB], get_all_nodes(Config, NodeA)),
238+
?assertEqual([NodeA, NodeB], get_all_nodes(Config, NodeB)),
239+
?assertEqual([NodeA, NodeB], get_disc_nodes(Config, NodeA)),
240+
?assertEqual([NodeA, NodeB], get_disc_nodes(Config, NodeB)),
241+
242+
?assert(
243+
log_file_contains_message(
244+
Config, NodeA,
245+
["Deprecated features: `ram_node_type`: Feature `ram_node_type` is deprecated",
246+
"Its use is not permitted per the configuration"]));
247+
{error, 69, <<"Error:\nincompatible_feature_flags">>} ->
248+
{skip, "Incompatible feature flags between nodes A and B"}
249+
end.
250+
251+
get_all_nodes(Config, Node) ->
252+
lists:sort(
253+
rabbit_ct_broker_helpers:rpc(
254+
Config, Node, rabbit_mnesia, cluster_nodes, [all])).
255+
256+
get_disc_nodes(Config, Node) ->
257+
lists:sort(
258+
rabbit_ct_broker_helpers:rpc(
259+
Config, Node, rabbit_mnesia, cluster_nodes, [disc])).
260+
155261
%% -------------------------------------------------------------------
156262
%% Helpers.
157263
%% -------------------------------------------------------------------

0 commit comments

Comments
 (0)