Merge pull request #10896 from zhongwencool/api-keys-hot-conf-update

feat: api_key conf support hot conf
This commit is contained in:
zhongwencool 2023-06-02 15:58:45 +08:00 committed by GitHub
commit 8d8efe449e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 36 additions and 52 deletions

View File

@ -115,14 +115,6 @@ end_per_testcase(_TestCase, _Config) ->
delete_all_bridges(), delete_all_bridges(),
ok. ok.
set_special_configs(emqx_management) ->
Listeners = #{http => #{port => 8081}},
Config = #{
listeners => Listeners,
applications => [#{id => "admin", secret => "public"}]
},
emqx_config:put([emqx_management], Config),
ok;
set_special_configs(emqx_dashboard) -> set_special_configs(emqx_dashboard) ->
emqx_dashboard_api_test_helpers:set_default_config(), emqx_dashboard_api_test_helpers:set_default_config(),
ok; ok;

View File

@ -62,9 +62,8 @@ fields("dashboard") ->
#{ #{
desc => ?DESC(bootstrap_users_file), desc => ?DESC(bootstrap_users_file),
required => false, required => false,
importance => ?IMPORTANCE_HIDDEN, default => <<>>,
default => <<>> deprecated => {since, "5.1.0"}
%% deprecated => {since, "5.1.0"}
} }
)} )}
]; ];

View File

@ -31,10 +31,12 @@ start(_Type, _Args) ->
ok = mria_rlog:wait_for_shards([?MANAGEMENT_SHARD], infinity), ok = mria_rlog:wait_for_shards([?MANAGEMENT_SHARD], infinity),
case emqx_mgmt_auth:init_bootstrap_file() of case emqx_mgmt_auth:init_bootstrap_file() of
ok -> ok ->
emqx_conf:add_handler([api_key], emqx_mgmt_auth),
emqx_mgmt_sup:start_link(); emqx_mgmt_sup:start_link();
{error, Reason} -> {error, Reason} ->
{error, Reason} {error, Reason}
end. end.
stop(_State) -> stop(_State) ->
emqx_conf:remove_handler([api_key]),
ok. ok.

View File

@ -20,6 +20,7 @@
%% API %% API
-export([mnesia/1]). -export([mnesia/1]).
-boot_mnesia({mnesia, [boot]}). -boot_mnesia({mnesia, [boot]}).
-behaviour(emqx_config_handler).
-export([ -export([
create/4, create/4,
@ -31,6 +32,7 @@
]). ]).
-export([authorize/3]). -export([authorize/3]).
-export([post_config_update/5]).
%% Internal exports (RPC) %% Internal exports (RPC)
-export([ -export([
@ -65,6 +67,17 @@ mnesia(boot) ->
{attributes, record_info(fields, ?APP)} {attributes, record_info(fields, ?APP)}
]). ]).
post_config_update([api_key], _Req, NewConf, _OldConf, _AppEnvs) ->
#{bootstrap_file := File} = NewConf,
case init_bootstrap_file(File) of
ok ->
?SLOG(debug, #{msg => "init_bootstrap_api_keys_from_file_ok", file => File});
{error, Reason} ->
Msg = "init_bootstrap_api_keys_from_file_failed",
?SLOG(error, #{msg => Msg, reason => Reason, file => File})
end,
ok.
-spec init_bootstrap_file() -> ok | {error, _}. -spec init_bootstrap_file() -> ok | {error, _}.
init_bootstrap_file() -> init_bootstrap_file() ->
File = bootstrap_file(), File = bootstrap_file(),
@ -230,13 +243,7 @@ generate_api_secret() ->
emqx_base62:encode(Random). emqx_base62:encode(Random).
bootstrap_file() -> bootstrap_file() ->
case emqx:get_config([api_key, bootstrap_file], <<>>) of emqx:get_config([api_key, bootstrap_file], <<>>).
%% For compatible remove until 5.1.0
<<>> ->
emqx:get_config([dashboard, bootstrap_users_file], <<>>);
File ->
File
end.
init_bootstrap_file(<<>>) -> init_bootstrap_file(<<>>) ->
ok; ok;

View File

@ -29,19 +29,18 @@ groups() ->
]. ].
init_per_suite(Config) -> init_per_suite(Config) ->
emqx_mgmt_api_test_util:init_suite([emqx_conf]), emqx_mgmt_api_test_util:init_suite([emqx_conf, emqx_management]),
Config. Config.
end_per_suite(_) -> end_per_suite(_) ->
emqx_mgmt_api_test_util:end_suite([emqx_conf]). emqx_mgmt_api_test_util:end_suite([emqx_conf, emqx_management]).
t_bootstrap_file(_) -> t_bootstrap_file(_) ->
TestPath = <<"/api/v5/status">>, TestPath = <<"/api/v5/status">>,
Bin = <<"test-1:secret-1\ntest-2:secret-2">>, Bin = <<"test-1:secret-1\ntest-2:secret-2">>,
File = "./bootstrap_api_keys.txt", File = "./bootstrap_api_keys.txt",
ok = file:write_file(File, Bin), ok = file:write_file(File, Bin),
emqx:update_config([api_key, bootstrap_file], File), update_file(File),
ok = emqx_mgmt_auth:init_bootstrap_file(),
?assertEqual(ok, emqx_mgmt_auth:authorize(TestPath, <<"test-1">>, <<"secret-1">>)), ?assertEqual(ok, emqx_mgmt_auth:authorize(TestPath, <<"test-1">>, <<"secret-1">>)),
?assertEqual(ok, emqx_mgmt_auth:authorize(TestPath, <<"test-2">>, <<"secret-2">>)), ?assertEqual(ok, emqx_mgmt_auth:authorize(TestPath, <<"test-2">>, <<"secret-2">>)),
?assertMatch({error, _}, emqx_mgmt_auth:authorize(TestPath, <<"test-2">>, <<"secret-1">>)), ?assertMatch({error, _}, emqx_mgmt_auth:authorize(TestPath, <<"test-2">>, <<"secret-1">>)),
@ -49,39 +48,33 @@ t_bootstrap_file(_) ->
%% relaunch to check if the table is changed. %% relaunch to check if the table is changed.
Bin1 = <<"test-1:new-secret-1\ntest-2:new-secret-2">>, Bin1 = <<"test-1:new-secret-1\ntest-2:new-secret-2">>,
ok = file:write_file(File, Bin1), ok = file:write_file(File, Bin1),
ok = emqx_mgmt_auth:init_bootstrap_file(), update_file(File),
?assertMatch({error, _}, emqx_mgmt_auth:authorize(TestPath, <<"test-1">>, <<"secret-1">>)), ?assertMatch({error, _}, emqx_mgmt_auth:authorize(TestPath, <<"test-1">>, <<"secret-1">>)),
?assertMatch({error, _}, emqx_mgmt_auth:authorize(TestPath, <<"test-2">>, <<"secret-2">>)), ?assertMatch({error, _}, emqx_mgmt_auth:authorize(TestPath, <<"test-2">>, <<"secret-2">>)),
?assertEqual(ok, emqx_mgmt_auth:authorize(TestPath, <<"test-1">>, <<"new-secret-1">>)), ?assertEqual(ok, emqx_mgmt_auth:authorize(TestPath, <<"test-1">>, <<"new-secret-1">>)),
?assertEqual(ok, emqx_mgmt_auth:authorize(TestPath, <<"test-2">>, <<"new-secret-2">>)), ?assertEqual(ok, emqx_mgmt_auth:authorize(TestPath, <<"test-2">>, <<"new-secret-2">>)),
%% Compatibility %% not error when bootstrap_file is empty
Bin2 = <<"test-3:new-secret-3\ntest-4:new-secret-4">>, update_file(<<>>),
ok = file:write_file(File, Bin2), update_file("./bootstrap_apps_not_exist.txt"),
emqx:update_config([api_key, bootstrap_file], <<>>), ?assertMatch({error, _}, emqx_mgmt_auth:authorize(TestPath, <<"test-1">>, <<"secret-1">>)),
emqx:update_config([dashboard, bootstrap_users_file], File), ?assertMatch({error, _}, emqx_mgmt_auth:authorize(TestPath, <<"test-2">>, <<"secret-2">>)),
ok = emqx_mgmt_auth:init_bootstrap_file(), ?assertEqual(ok, emqx_mgmt_auth:authorize(TestPath, <<"test-1">>, <<"new-secret-1">>)),
?assertMatch(ok, emqx_mgmt_auth:authorize(TestPath, <<"test-1">>, <<"new-secret-1">>)), ?assertEqual(ok, emqx_mgmt_auth:authorize(TestPath, <<"test-2">>, <<"new-secret-2">>)),
?assertMatch(ok, emqx_mgmt_auth:authorize(TestPath, <<"test-2">>, <<"new-secret-2">>)),
?assertEqual(ok, emqx_mgmt_auth:authorize(TestPath, <<"test-3">>, <<"new-secret-3">>)),
?assertEqual(ok, emqx_mgmt_auth:authorize(TestPath, <<"test-4">>, <<"new-secret-4">>)),
%% not found
NotFoundFile = "./bootstrap_apps_not_exist.txt",
emqx:update_config([api_key, bootstrap_file], NotFoundFile),
?assertMatch({error, "No such file or directory"}, emqx_mgmt_auth:init_bootstrap_file()),
%% bad format %% bad format
BadBin = <<"test-1:secret-11\ntest-2 secret-12">>, BadBin = <<"test-1:secret-11\ntest-2 secret-12">>,
ok = file:write_file(File, BadBin), ok = file:write_file(File, BadBin),
emqx:update_config([api_key, bootstrap_file], File), update_file(File),
?assertMatch({error, #{reason := "invalid_format"}}, emqx_mgmt_auth:init_bootstrap_file()), ?assertMatch({error, #{reason := "invalid_format"}}, emqx_mgmt_auth:init_bootstrap_file()),
?assertEqual(ok, emqx_mgmt_auth:authorize(TestPath, <<"test-1">>, <<"secret-11">>)), ?assertEqual(ok, emqx_mgmt_auth:authorize(TestPath, <<"test-1">>, <<"secret-11">>)),
?assertMatch({error, _}, emqx_mgmt_auth:authorize(TestPath, <<"test-2">>, <<"secret-12">>)), ?assertMatch({error, _}, emqx_mgmt_auth:authorize(TestPath, <<"test-2">>, <<"secret-12">>)),
emqx:update_config([api_key, bootstrap_file], <<>>), update_file(<<>>),
emqx:update_config([dashboard, bootstrap_users_file], <<>>),
ok. ok.
update_file(File) ->
?assertMatch({ok, _}, emqx:update_config([<<"api_key">>], #{<<"bootstrap_file">> => File})).
t_create(_Config) -> t_create(_Config) ->
Name = <<"EMQX-API-KEY-1">>, Name = <<"EMQX-API-KEY-1">>,
{ok, Create} = create_app(Name), {ok, Create} = create_app(Name),

View File

@ -24,20 +24,11 @@ all() ->
emqx_common_test_helpers:all(?MODULE). emqx_common_test_helpers:all(?MODULE).
init_per_suite(Config) -> init_per_suite(Config) ->
mria:start(), emqx_mgmt_api_test_util:init_suite([emqx_conf, emqx_management]),
ok = emqx_common_test_helpers:start_apps([emqx_management]),
emqx_common_test_helpers:start_apps([] ++ [emqx_dashboard], fun set_special_configs/1),
Config. Config.
end_per_suite(_) -> end_per_suite(_) ->
emqx_common_test_helpers:stop_apps([emqx_management] ++ [emqx_dashboard]), emqx_mgmt_api_test_util:end_suite([emqx_management, emqx_conf]).
emqx_config:delete_override_conf_files(),
ok.
set_special_configs(emqx_dashboard) ->
emqx_dashboard_api_test_helpers:set_default_config();
set_special_configs(_App) ->
ok.
t_status(_Config) -> t_status(_Config) ->
emqx_ctl:run_command([]), emqx_ctl:run_command([]),