Skip to content

Commit d20f382

Browse files
committed
rabbit_deprecated_features: New module to manage deprecated features (!)
[TBW]
1 parent 60e20fc commit d20f382

9 files changed

+667
-101
lines changed

deps/rabbit/BUILD.bazel

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,11 @@ rabbitmq_integration_suite(
379379
size = "medium",
380380
)
381381

382+
rabbitmq_integration_suite(
383+
name = "deprecated_features_SUITE",
384+
size = "medium",
385+
)
386+
382387
rabbitmq_integration_suite(
383388
name = "disconnect_detected_during_alarm_SUITE",
384389
size = "medium",

deps/rabbit/priv/schema/rabbit.schema

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2081,6 +2081,23 @@ end}.
20812081
{datatype, integer}
20822082
]}.
20832083

2084+
%%
2085+
%% Feature flags and deprecated features
2086+
%% =====================================
2087+
%%
2088+
2089+
{mapping, "deprecated_features.$name", "rabbit.deprecated_features", [
2090+
{datatype, {enum, [true, false]}}
2091+
]}.
2092+
2093+
{translation, "rabbit.deprecated_features",
2094+
fun(Conf) ->
2095+
Settings = cuttlefish_variable:filter_by_prefix(
2096+
"deprecated_features", Conf),
2097+
[{list_to_atom(FeatureName), State}
2098+
|| {["deprecated_features", FeatureName], State} <- Settings]
2099+
end}.
2100+
20842101
% ==========================
20852102
% Kernel section
20862103
% ==========================
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
%% This Source Code Form is subject to the terms of the Mozilla Public
2+
%% License, v. 2.0. If a copy of the MPL was not distributed with this
3+
%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
%%
5+
%% Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved.
6+
%%
7+
8+
%% @author The RabbitMQ team
9+
%% @copyright 2023 VMware, Inc. or its affiliates.
10+
%%
11+
%% @doc
12+
%% This module provides an API to manage deprecated features in RabbitMQ. It
13+
%% is built on top of the Feature flags subsystem.
14+
15+
-module(rabbit_deprecated_features).
16+
17+
-include_lib("kernel/include/logger.hrl").
18+
-include_lib("stdlib/include/assert.hrl").
19+
20+
-include_lib("rabbit_common/include/logging.hrl").
21+
22+
-include("src/rabbit_feature_flags.hrl").
23+
24+
-export([is_permitted/1,
25+
get_phase/1,
26+
get_warning/1]).
27+
-export([extend_properties/2,
28+
should_be_permitted/2]).
29+
30+
is_permitted(FeatureName) ->
31+
Permitted = not rabbit_feature_flags:is_enabled(FeatureName),
32+
maybe_log_warning(FeatureName, Permitted),
33+
Permitted.
34+
35+
get_phase(FeatureName) when is_atom(FeatureName) ->
36+
case rabbit_ff_registry:get(FeatureName) of
37+
undefined -> undefined;
38+
FeatureProps -> get_phase(FeatureProps)
39+
end;
40+
get_phase(FeatureProps) when is_map(FeatureProps) ->
41+
?assert(?IS_DEPRECATION(FeatureProps)),
42+
maps:get(deprecation_phase, FeatureProps).
43+
44+
get_warning(FeatureName) when is_atom(FeatureName) ->
45+
case rabbit_ff_registry:get(FeatureName) of
46+
undefined -> undefined;
47+
FeatureProps -> get_warning(FeatureProps)
48+
end;
49+
get_warning(FeatureProps) when is_map(FeatureProps) ->
50+
?assert(?IS_DEPRECATION(FeatureProps)),
51+
maps:get(warning, FeatureProps).
52+
53+
extend_properties(_FeatureName, #{warning := _} = FeatureProps)
54+
when ?IS_DEPRECATION(FeatureProps) ->
55+
FeatureProps;
56+
extend_properties(FeatureName, FeatureProps)
57+
when ?IS_DEPRECATION(FeatureProps) ->
58+
Warning = case get_phase(FeatureProps) of
59+
optout ->
60+
rabbit_misc:format(
61+
"Feature `~ts` is deprecated; "
62+
"it is disabled explicitly from configuration",
63+
[FeatureName]);
64+
optin ->
65+
rabbit_misc:format(
66+
"Feature `~ts` is deprecated; "
67+
"it is disabled by default, except if configured "
68+
"otherwise",
69+
[FeatureName]);
70+
disconnected ->
71+
rabbit_misc:format(
72+
"Feature `~ts` is deprecated; "
73+
"it is disabled and can't be turned back on",
74+
[FeatureName]);
75+
removed ->
76+
rabbit_misc:format(
77+
"Feature `~ts` is removed; "
78+
"the deprecation period ended and it can't be turned "
79+
"back on",
80+
[FeatureName])
81+
end,
82+
FeatureProps#{warning => Warning}.
83+
84+
should_be_permitted(FeatureName, FeatureProps) ->
85+
case get_phase(FeatureProps) of
86+
optout -> is_permitted_in_configuration(FeatureName, true);
87+
optin -> is_permitted_in_configuration(FeatureName, false);
88+
_ -> false
89+
end.
90+
91+
is_permitted_in_configuration(FeatureName, Default) ->
92+
Settings = application:get_env(rabbit, deprecated_features, []),
93+
case proplists:get_value(FeatureName, Settings) of
94+
undefined ->
95+
Default;
96+
Default ->
97+
PermittedStr = case Default of
98+
true -> "permitted";
99+
false -> "not permitted"
100+
end,
101+
?LOG_DEBUG(
102+
"Deprecated features: `~ts`: ~ts in configuration, same as "
103+
"default",
104+
[FeatureName, PermittedStr],
105+
#{domain => ?RMQLOG_DOMAIN_FEAT_FLAGS}),
106+
Default;
107+
Permitted ->
108+
PermittedStr = case Permitted of
109+
true -> "permitted";
110+
false -> "not permitted"
111+
end,
112+
?LOG_DEBUG(
113+
"Deprecated features: `~ts`: ~ts in configuration, overrides "
114+
"default",
115+
[FeatureName, PermittedStr],
116+
#{domain => ?RMQLOG_DOMAIN_FEAT_FLAGS}),
117+
?assert(is_boolean(Permitted)),
118+
Permitted
119+
end.
120+
121+
maybe_log_warning(FeatureName, Permitted) ->
122+
case should_log_warning(FeatureName) of
123+
false ->
124+
ok;
125+
true ->
126+
Warning = get_warning(FeatureName),
127+
FormatStr = "Deprecated features: `~ts`: ~ts",
128+
FormatArgs = [FeatureName, Warning],
129+
case Permitted of
130+
true ->
131+
?LOG_WARNING(
132+
FormatStr, FormatArgs,
133+
#{domain => ?RMQLOG_DOMAIN_FEAT_FLAGS});
134+
false ->
135+
?LOG_ERROR(
136+
FormatStr, FormatArgs,
137+
#{domain => ?RMQLOG_DOMAIN_FEAT_FLAGS})
138+
end
139+
end.
140+
141+
-define(PT_DEPRECATION_WARNING_TS(FeatureName), {?MODULE, FeatureName}).
142+
143+
should_log_warning(FeatureName) ->
144+
Key = ?PT_DEPRECATION_WARNING_TS(FeatureName),
145+
Now = erlang:timestamp(),
146+
try
147+
Last = persistent_term:get(Key),
148+
Diff = timer:now_diff(Now, Last),
149+
if
150+
Diff >= 24 * 60 * 60 * 1000 * 1000 ->
151+
persistent_term:put(Key, Now),
152+
true;
153+
true ->
154+
false
155+
end
156+
catch
157+
error:badarg ->
158+
persistent_term:put(Key, Now),
159+
true
160+
end.

0 commit comments

Comments
 (0)