Skip to content

Commit a9ce872

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 RAM nodes can be turned off anytime, there are no conditions to do that. 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. The `change_cluster_node_type` CLI command will reject a change to a RAM node with an error. 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 a9ce872

File tree

2 files changed

+155
-8
lines changed

2 files changed

+155
-8
lines changed

deps/rabbit/src/rabbit_mnesia.erl

+46-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,17 @@ 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+
case is_node_type_permitted(NodeType) of
104+
false ->
105+
rabbit_log:info(
106+
"RAM nodes are deprecated and not permitted. This "
107+
"node will be converted to a disc node."),
108+
init_db_and_upgrade(cluster_nodes(all), disc,
109+
true, _Retry = true);
110+
true ->
111+
init_db_and_upgrade(cluster_nodes(all), NodeType,
112+
NodeType =:= ram, _Retry = true)
113+
end,
99114
rabbit_peer_discovery:maybe_init(),
100115
rabbit_peer_discovery:maybe_register()
101116
end,
@@ -180,9 +195,13 @@ run_peer_discovery_with_retries(RetriesLeft, DelayInterval) ->
180195
"Enabling debug logging might help troubleshoot."),
181196
init_db_and_upgrade([node()], disc, false, _Retry = true);
182197
_ ->
198+
NodeType1 = case is_node_type_permitted(NodeType) of
199+
false -> disc;
200+
true -> NodeType
201+
end,
183202
rabbit_log:info("Peer nodes we can cluster with: ~ts",
184203
[rabbit_peer_discovery:format_discovered_nodes(Peers)]),
185-
join_discovered_peers(Peers, NodeType)
204+
join_discovered_peers(Peers, NodeType1)
186205
end.
187206

188207
%% Attempts to join discovered,
@@ -250,10 +269,15 @@ join_cluster(DiscoveryNode, NodeType) ->
250269
%% of resetting the node from the user.
251270
reset_gracefully(),
252271

272+
NodeType1 = case is_node_type_permitted(NodeType) of
273+
false -> disc;
274+
true -> NodeType
275+
end,
276+
253277
%% Join the cluster
254278
rabbit_log:info("Clustering with ~tp as ~tp node",
255-
[ClusterNodes, NodeType]),
256-
ok = init_db_with_mnesia(ClusterNodes, NodeType,
279+
[ClusterNodes, NodeType1]),
280+
ok = init_db_with_mnesia(ClusterNodes, NodeType1,
257281
true, true, _Retry = true),
258282
rabbit_node_monitor:notify_joined_cluster(),
259283
ok;
@@ -320,6 +344,7 @@ wipe() ->
320344
-spec change_cluster_node_type(rabbit_db_cluster:node_type()) -> 'ok'.
321345

322346
change_cluster_node_type(Type) ->
347+
ensure_node_type_is_permitted(Type),
323348
ensure_mnesia_not_running(),
324349
ensure_mnesia_dir(),
325350
case is_clustered() of
@@ -549,6 +574,20 @@ node_type() ->
549574
false -> ram
550575
end.
551576

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

554593
dir() -> mnesia:system_info(directory).
@@ -562,6 +601,8 @@ dir() -> mnesia:system_info(directory).
562601
%% nodes in the cluster already. It also updates the cluster status
563602
%% file.
564603
init_db(ClusterNodes, NodeType, CheckOtherNodes) ->
604+
ensure_node_type_is_permitted(NodeType),
605+
565606
NodeIsVirgin = is_virgin_node(),
566607
rabbit_log:debug("Does data directory looks like that of a blank (uninitialised) node? ~tp", [NodeIsVirgin]),
567608
%% 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)