Skip to content

Commit 532bb8a

Browse files
Merge pull request #13341 from rabbitmq/mergify/bp/v4.0.x/pr-13337
Follow-up: finish 'rabbitmqctl clear_auth_backend_cache' plus add tests (backport #13325) (backport #13337)
2 parents fca6f1a + eb994a5 commit 532bb8a

8 files changed

+176
-6
lines changed

deps/rabbitmq_auth_backend_cache/src/rabbit_auth_backend_cache.erl

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
-export([user_login_authentication/2, user_login_authorization/2,
1515
check_vhost_access/3, check_resource_access/4, check_topic_access/4,
16-
expiry_timestamp/1]).
16+
expiry_timestamp/1, clear_cache_cluster_wide/0, clear_cache/0]).
1717

1818
%% API
1919

@@ -66,6 +66,17 @@ expiry_timestamp(_) -> never.
6666
%% Implementation
6767
%%
6868

69+
clear_cache_cluster_wide() ->
70+
Nodes = rabbit_nodes:list_running(),
71+
rabbit_log:warning("Clearing auth_backend_cache in all nodes : ~p", [Nodes]),
72+
rabbit_misc:append_rpc_all_nodes(Nodes, ?MODULE, clear_cache, []).
73+
74+
clear_cache() ->
75+
{ok, AuthCache} = application:get_env(rabbitmq_auth_backend_cache,
76+
cache_module),
77+
rabbit_log:warning("Clearing auth_backend_cache"),
78+
AuthCache:clear().
79+
6980
with_cache(BackendType, {F, A}, Fun) ->
7081
{ok, AuthCache} = application:get_env(rabbitmq_auth_backend_cache,
7182
cache_module),
@@ -105,3 +116,5 @@ should_cache(Result, Fun) ->
105116
{refusal, true} -> true;
106117
_ -> false
107118
end.
119+
120+

deps/rabbitmq_auth_backend_cache/src/rabbit_auth_cache.erl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
-callback delete(term()) -> ok.
1717

18+
-callback clear() -> ok.
19+
1820
expiration(TTL) ->
1921
erlang:system_time(milli_seconds) + TTL.
2022

deps/rabbitmq_auth_backend_cache/src/rabbit_auth_cache_dict.erl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
-include("rabbit_auth_backend_cache.hrl").
1616

1717
-export([start_link/0,
18-
get/1, put/3, delete/1]).
18+
get/1, put/3, delete/1, clear/0]).
1919

2020
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
2121
terminate/2, code_change/3]).
@@ -28,6 +28,8 @@ put(Key, Value, TTL) -> gen_server:cast(?MODULE, {put, Key, Value, TTL}).
2828

2929
delete(Key) -> gen_server:call(?MODULE, {delete, Key}, ?CACHE_OPERATION_TIMEOUT).
3030

31+
clear() -> gen_server:cast(?MODULE, clear).
32+
3133
init(_Args) -> {ok, nostate}.
3234

3335
handle_call({get, Key}, _From, nostate) ->
@@ -40,6 +42,10 @@ handle_call({delete, Key}, _From, nostate) ->
4042
do_delete(Key),
4143
{reply, ok, nostate}.
4244

45+
handle_cast(clear, nostate) ->
46+
_ = erlang:erase(),
47+
{noreply, nostate};
48+
4349
handle_cast({put, Key, Value, TTL}, nostate) ->
4450
erlang:put({items, Key}, Value),
4551
{ok, TRef} = timer:apply_after(TTL, rabbit_auth_cache_dict, delete, [Key]),

deps/rabbitmq_auth_backend_cache/src/rabbit_auth_cache_ets.erl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
-behaviour(rabbit_auth_cache).
1616

1717
-export([start_link/0,
18-
get/1, put/3, delete/1]).
18+
get/1, put/3, delete/1, clear/0]).
1919

2020
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
2121
terminate/2, code_change/3]).
@@ -36,6 +36,8 @@ put(Key, Value, TTL) ->
3636

3737
delete(Key) -> gen_server:call(?MODULE, {delete, Key}, ?CACHE_OPERATION_TIMEOUT).
3838

39+
clear() -> gen_server:cast(?MODULE, clear).
40+
3941
init([]) ->
4042
{ok, #state{cache = ets:new(?MODULE, [set, private]),
4143
timers = ets:new(auth_cache_ets_timers, [set, private])}}.
@@ -53,6 +55,10 @@ handle_call({delete, Key}, _From, State = #state{cache = Table, timers = Timers}
5355
do_delete(Key, Table, Timers),
5456
{reply, ok, State}.
5557

58+
handle_cast(clear, State = #state{cache = Table}) ->
59+
ets:delete_all_objects(Table),
60+
{noreply, State};
61+
5662
handle_cast({put, Key, Value, TTL, Expiration},
5763
State = #state{cache = Table, timers = Timers}) ->
5864
do_delete(Key, Table, Timers),

deps/rabbitmq_auth_backend_cache/src/rabbit_auth_cache_ets_segmented.erl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
-behaviour(rabbit_auth_cache).
1111

1212
-export([start_link/1,
13-
get/1, put/3, delete/1]).
13+
get/1, put/3, delete/1, clear/0]).
1414
-export([gc/0]).
1515

1616
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
@@ -43,6 +43,11 @@ delete(Key) ->
4343
|| Table <- gen_server:call(?MODULE, get_segment_tables, ?CACHE_OPERATION_TIMEOUT)],
4444
ok.
4545

46+
clear() ->
47+
_ = [ets:delete_all_objects(Table)
48+
|| Table <- gen_server:call(?MODULE, get_segment_tables, ?CACHE_OPERATION_TIMEOUT)],
49+
ok.
50+
4651
gc() ->
4752
case whereis(?MODULE) of
4853
undefined -> ok;

deps/rabbitmq_auth_backend_cache/src/rabbit_auth_cache_ets_segmented_stateless.erl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
-include("rabbit_auth_backend_cache.hrl").
1313

1414
-export([start_link/1,
15-
get/1, put/3, delete/1]).
15+
get/1, put/3, delete/1, clear/0]).
1616
-export([gc/0]).
1717

1818
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
@@ -47,6 +47,11 @@ delete(Key) ->
4747
|| Table <- get_all_segment_tables()],
4848
ok.
4949

50+
clear() ->
51+
_ = [ets:delete_all_objects(Table)
52+
|| Table <- get_all_segment_tables()],
53+
ok.
54+
5055
gc() ->
5156
case whereis(?MODULE) of
5257
undefined -> ok;

deps/rabbitmq_auth_backend_cache/test/rabbit_auth_cache_SUITE.erl

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,14 @@ all() ->
1919
].
2020

2121
groups() ->
22-
CommonTests = [get_empty, get_put, get_expired, put_replace, get_deleted, random_timing],
22+
CommonTests = [
23+
get_empty,
24+
get_put,
25+
get_expired,
26+
put_replace,
27+
get_deleted,
28+
random_timing,
29+
clear],
2330
[
2431
{rabbit_auth_cache_dict, [sequence], CommonTests},
2532
{rabbit_auth_cache_ets, [sequence], CommonTests},
@@ -153,6 +160,20 @@ get_deleted(Config) ->
153160
AuthCacheModule:delete(Key),
154161
{error, not_found} = AuthCacheModule:get(Key).
155162

163+
clear(Config) ->
164+
AuthCacheModule = ?config(auth_cache_module, Config),
165+
Key1 = some_key1,
166+
Key2 = some_key2,
167+
TTL = ?config(current_ttl, Config),
168+
{error, not_found} = AuthCacheModule:get(Key1),
169+
{error, not_found} = AuthCacheModule:get(Key2),
170+
ok = AuthCacheModule:put(Key1, some_value, TTL),
171+
ok = AuthCacheModule:put(Key2, some_value, TTL),
172+
{ok, some_value} = AuthCacheModule:get(Key1),
173+
{ok, some_value} = AuthCacheModule:get(Key2),
174+
AuthCacheModule:clear(),
175+
{error, not_found} = AuthCacheModule:get(Key1),
176+
{error, not_found} = AuthCacheModule:get(Key2).
156177

157178
random_timing(Config) ->
158179
random_timing(Config, 15000, 1000).
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
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) 2007-2025 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved.
6+
%%
7+
8+
-module(rabbit_auth_clear_cache_command_SUITE).
9+
10+
-include_lib("stdlib/include/assert.hrl").
11+
12+
-compile(export_all).
13+
14+
-define(CLEAR_CACHE_CMD, 'Elixir.RabbitMQ.CLI.Ctl.Commands.ClearAuthBackendCacheCommand').
15+
16+
all() ->
17+
[
18+
{group, non_parallel_tests},
19+
{group, cluster_size_2}
20+
].
21+
22+
groups() ->
23+
[
24+
{non_parallel_tests, [], [
25+
clear_cache
26+
]},
27+
{cluster_size_2, [], [
28+
clear_cache
29+
]}
30+
].
31+
32+
%% -------------------------------------------------------------------
33+
%% Testsuite setup/teardown.
34+
%% -------------------------------------------------------------------
35+
36+
init_per_suite(Config) ->
37+
rabbit_ct_helpers:log_environment(),
38+
rabbit_ct_helpers:run_setup_steps(Config).
39+
40+
41+
setup_env(Config, Nodename) ->
42+
rpc(Config, Nodename, application, set_env,
43+
[rabbit, auth_backends, [rabbit_auth_backend_cache]]),
44+
Config.
45+
46+
end_per_suite(Config) ->
47+
rabbit_ct_helpers:run_teardown_steps(Config).
48+
49+
init_per_group(cluster_size_2, Config) ->
50+
case rabbit_ct_helpers:is_mixed_versions() of
51+
true -> {skip, "cluster size 2 isn't mixed versions compatible"};
52+
false -> init_per_multinode_group(cluster_size_2, Config, 2)
53+
end;
54+
init_per_group(Group, Config) ->
55+
init_per_multinode_group(Group, Config, 1).
56+
57+
init_per_multinode_group(_Group, Config, NodeCount) ->
58+
Suffix = rabbit_ct_helpers:testcase_absname(Config, "", "-"),
59+
Config1 = rabbit_ct_helpers:set_config(Config, [
60+
{rmq_nodes_count, NodeCount},
61+
{rmq_nodename_suffix, Suffix}
62+
]),
63+
rabbit_ct_helpers:run_steps(Config1,
64+
rabbit_ct_broker_helpers:setup_steps() ++
65+
rabbit_ct_client_helpers:setup_steps()).
66+
67+
end_per_group(_Group, Config) ->
68+
rabbit_ct_helpers:run_steps(Config,
69+
rabbit_ct_client_helpers:teardown_steps() ++
70+
rabbit_ct_broker_helpers:teardown_steps()).
71+
72+
init_per_testcase(Testcase, Config) ->
73+
rabbit_ct_helpers:testcase_started(Config, Testcase).
74+
75+
end_per_testcase(Testcase, Config) ->
76+
rabbit_ct_helpers:testcase_finished(Config, Testcase).
77+
78+
%% -------------------------------------------------------------------
79+
%% Testcases.
80+
%% -------------------------------------------------------------------
81+
82+
83+
clear_cache(Config) ->
84+
F = user_login_authentication,
85+
A = [<<"guest">>, [{password, <<"guest">>}]],
86+
Nodes = rabbit_ct_broker_helpers:get_node_configs(Config, nodename),
87+
[ setup_env(Config, Nodename) || Nodename <- Nodes],
88+
89+
[ ok = ensure_cache_entries(Config, Node, {F, A}) || Node <- Nodes],
90+
?CLEAR_CACHE_CMD:run([], #{node => lists:last(Nodes)}),
91+
[ rabbit_ct_helpers:await_condition_with_retries(fun () ->
92+
case has_cache_entry(Config, Node, {F, A}) of
93+
{error, not_found} -> true;
94+
_ -> false
95+
end
96+
end, 20) || Node <- Nodes].
97+
98+
ensure_cache_entries(Config, Nodename, {F, A}) ->
99+
{ok, AuthRespOk} = rpc(Config, Nodename, rabbit_auth_backend_internal, F, A),
100+
{ok, AuthRespOk} = rpc(Config, Nodename, rabbit_auth_backend_cache, F, A),
101+
ok = has_cache_entry(Config, Nodename, {F, A}).
102+
103+
rpc(Config, N, M, F, A) ->
104+
rabbit_ct_broker_helpers:rpc(Config, N, M, F, A).
105+
106+
has_cache_entry(Config, Node, {F, A}) ->
107+
{ok, AuthCache} = rpc(Config, Node, application, get_env,
108+
[rabbitmq_auth_backend_cache, cache_module]),
109+
case rpc(Config, Node, AuthCache, get, [{F, A}]) of
110+
{ok, _} -> ok;
111+
{error, not_found} = E -> E
112+
end.

0 commit comments

Comments
 (0)