From 5729ea0426537597433b50531913e810f6676d72 Mon Sep 17 00:00:00 2001 From: Zhongwen Deng Date: Wed, 31 May 2023 18:15:48 +0800 Subject: [PATCH] feat: api_key conf support hot conf --- .../emqx_bridge_kafka_impl_producer_SUITE.erl | 8 ---- .../src/emqx_dashboard_schema.erl | 5 +-- .../src/emqx_management.app.src | 2 +- apps/emqx_management/src/emqx_mgmt_app.erl | 2 + apps/emqx_management/src/emqx_mgmt_auth.erl | 21 ++++++---- .../test/emqx_mgmt_api_api_keys_SUITE.erl | 39 ++++++++----------- .../test/emqx_mgmt_cli_SUITE.erl | 13 +------ 7 files changed, 37 insertions(+), 53 deletions(-) diff --git a/apps/emqx_bridge_kafka/test/emqx_bridge_kafka_impl_producer_SUITE.erl b/apps/emqx_bridge_kafka/test/emqx_bridge_kafka_impl_producer_SUITE.erl index ad41c9904..378dda543 100644 --- a/apps/emqx_bridge_kafka/test/emqx_bridge_kafka_impl_producer_SUITE.erl +++ b/apps/emqx_bridge_kafka/test/emqx_bridge_kafka_impl_producer_SUITE.erl @@ -115,14 +115,6 @@ end_per_testcase(_TestCase, _Config) -> delete_all_bridges(), 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) -> emqx_dashboard_api_test_helpers:set_default_config(), ok; diff --git a/apps/emqx_dashboard/src/emqx_dashboard_schema.erl b/apps/emqx_dashboard/src/emqx_dashboard_schema.erl index 28bfb709a..e2b02edab 100644 --- a/apps/emqx_dashboard/src/emqx_dashboard_schema.erl +++ b/apps/emqx_dashboard/src/emqx_dashboard_schema.erl @@ -62,9 +62,8 @@ fields("dashboard") -> #{ desc => ?DESC(bootstrap_users_file), required => false, - importance => ?IMPORTANCE_HIDDEN, - default => <<>> - %% deprecated => {since, "5.1.0"} + default => <<>>, + deprecated => {since, "5.1.0"} } )} ]; diff --git a/apps/emqx_management/src/emqx_management.app.src b/apps/emqx_management/src/emqx_management.app.src index 31c719a33..4ee7dea10 100644 --- a/apps/emqx_management/src/emqx_management.app.src +++ b/apps/emqx_management/src/emqx_management.app.src @@ -2,7 +2,7 @@ {application, emqx_management, [ {description, "EMQX Management API and CLI"}, % strict semver, bump manually! - {vsn, "5.0.23"}, + {vsn, "5.0.24"}, {modules, []}, {registered, [emqx_management_sup]}, {applications, [kernel, stdlib, emqx_plugins, minirest, emqx, emqx_ctl]}, diff --git a/apps/emqx_management/src/emqx_mgmt_app.erl b/apps/emqx_management/src/emqx_mgmt_app.erl index b4cf9091a..2d48ed662 100644 --- a/apps/emqx_management/src/emqx_mgmt_app.erl +++ b/apps/emqx_management/src/emqx_mgmt_app.erl @@ -31,10 +31,12 @@ start(_Type, _Args) -> ok = mria_rlog:wait_for_shards([?MANAGEMENT_SHARD], infinity), case emqx_mgmt_auth:init_bootstrap_file() of ok -> + emqx_conf:add_handler([api_key], emqx_mgmt_auth), emqx_mgmt_sup:start_link(); {error, Reason} -> {error, Reason} end. stop(_State) -> + emqx_conf:remove_handler([api_key]), ok. diff --git a/apps/emqx_management/src/emqx_mgmt_auth.erl b/apps/emqx_management/src/emqx_mgmt_auth.erl index 12a7a6641..ffb41179f 100644 --- a/apps/emqx_management/src/emqx_mgmt_auth.erl +++ b/apps/emqx_management/src/emqx_mgmt_auth.erl @@ -20,6 +20,7 @@ %% API -export([mnesia/1]). -boot_mnesia({mnesia, [boot]}). +-behaviour(emqx_config_handler). -export([ create/4, @@ -31,6 +32,7 @@ ]). -export([authorize/3]). +-export([post_config_update/5]). %% Internal exports (RPC) -export([ @@ -65,6 +67,17 @@ mnesia(boot) -> {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, _}. init_bootstrap_file() -> File = bootstrap_file(), @@ -230,13 +243,7 @@ generate_api_secret() -> emqx_base62:encode(Random). bootstrap_file() -> - case emqx:get_config([api_key, bootstrap_file], <<>>) of - %% For compatible remove until 5.1.0 - <<>> -> - emqx:get_config([dashboard, bootstrap_users_file], <<>>); - File -> - File - end. + emqx:get_config([api_key, bootstrap_file], <<>>). init_bootstrap_file(<<>>) -> ok; diff --git a/apps/emqx_management/test/emqx_mgmt_api_api_keys_SUITE.erl b/apps/emqx_management/test/emqx_mgmt_api_api_keys_SUITE.erl index 1a396d795..2a78f76fc 100644 --- a/apps/emqx_management/test/emqx_mgmt_api_api_keys_SUITE.erl +++ b/apps/emqx_management/test/emqx_mgmt_api_api_keys_SUITE.erl @@ -29,19 +29,18 @@ groups() -> ]. 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. 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(_) -> TestPath = <<"/api/v5/status">>, Bin = <<"test-1:secret-1\ntest-2:secret-2">>, File = "./bootstrap_api_keys.txt", ok = file:write_file(File, Bin), - emqx:update_config([api_key, bootstrap_file], File), - ok = emqx_mgmt_auth:init_bootstrap_file(), + update_file(File), ?assertEqual(ok, emqx_mgmt_auth:authorize(TestPath, <<"test-1">>, <<"secret-1">>)), ?assertEqual(ok, emqx_mgmt_auth:authorize(TestPath, <<"test-2">>, <<"secret-2">>)), ?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. Bin1 = <<"test-1:new-secret-1\ntest-2:new-secret-2">>, 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-2">>, <<"secret-2">>)), ?assertEqual(ok, emqx_mgmt_auth:authorize(TestPath, <<"test-1">>, <<"new-secret-1">>)), ?assertEqual(ok, emqx_mgmt_auth:authorize(TestPath, <<"test-2">>, <<"new-secret-2">>)), - %% Compatibility - Bin2 = <<"test-3:new-secret-3\ntest-4:new-secret-4">>, - ok = file:write_file(File, Bin2), - emqx:update_config([api_key, bootstrap_file], <<>>), - emqx:update_config([dashboard, bootstrap_users_file], File), - ok = emqx_mgmt_auth:init_bootstrap_file(), - ?assertMatch(ok, emqx_mgmt_auth:authorize(TestPath, <<"test-1">>, <<"new-secret-1">>)), - ?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()), + %% not error when bootstrap_file is empty + update_file(<<>>), + update_file("./bootstrap_apps_not_exist.txt"), + ?assertMatch({error, _}, emqx_mgmt_auth:authorize(TestPath, <<"test-1">>, <<"secret-1">>)), + ?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-2">>, <<"new-secret-2">>)), %% bad format BadBin = <<"test-1:secret-11\ntest-2 secret-12">>, 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()), ?assertEqual(ok, emqx_mgmt_auth:authorize(TestPath, <<"test-1">>, <<"secret-11">>)), ?assertMatch({error, _}, emqx_mgmt_auth:authorize(TestPath, <<"test-2">>, <<"secret-12">>)), - emqx:update_config([api_key, bootstrap_file], <<>>), - emqx:update_config([dashboard, bootstrap_users_file], <<>>), + update_file(<<>>), ok. +update_file(File) -> + ?assertMatch({ok, _}, emqx:update_config([<<"api_key">>], #{<<"bootstrap_file">> => File})). + t_create(_Config) -> Name = <<"EMQX-API-KEY-1">>, {ok, Create} = create_app(Name), diff --git a/apps/emqx_management/test/emqx_mgmt_cli_SUITE.erl b/apps/emqx_management/test/emqx_mgmt_cli_SUITE.erl index f49663682..33292e54e 100644 --- a/apps/emqx_management/test/emqx_mgmt_cli_SUITE.erl +++ b/apps/emqx_management/test/emqx_mgmt_cli_SUITE.erl @@ -24,20 +24,11 @@ all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Config) -> - mria:start(), - ok = emqx_common_test_helpers:start_apps([emqx_management]), - emqx_common_test_helpers:start_apps([] ++ [emqx_dashboard], fun set_special_configs/1), + emqx_mgmt_api_test_util:init_suite([emqx_conf, emqx_management]), Config. end_per_suite(_) -> - emqx_common_test_helpers:stop_apps([emqx_management] ++ [emqx_dashboard]), - 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. + emqx_mgmt_api_test_util:end_suite([emqx_management, emqx_conf]). t_status(_Config) -> emqx_ctl:run_command([]),