Переглянути джерело

fix(authn): transfer chain tab to emqx_authentication_sup

To preserve configuration after emqx_authentication crashes.
Ilya Averyanov 4 роки тому
батько
коміт
c86887491c

+ 23 - 3
apps/emqx/src/emqx_authentication.erl

@@ -401,9 +401,7 @@ list_users(ChainName, AuthenticatorID, Params) ->
 %%--------------------------------------------------------------------
 
 init(_Opts) ->
-    _ = ets:new(?CHAINS_TAB, [ named_table, set, public
-                             , {keypos, #chain.name}
-                             , {read_concurrency, true}]),
+    ok = create_chain_table(),
     ok = emqx_config_handler:add_handler([authentication], ?MODULE),
     ok = emqx_config_handler:add_handler([listeners, '?', '?', authentication], ?MODULE),
     {ok, #{hooked => false, providers => #{}}}.
@@ -578,6 +576,28 @@ code_change(_OldVsn, State, _Extra) ->
 reply(Reply, State) ->
     {reply, Reply, State}.
 
+%%--------------------------------------------------------------------
+%% Internal functions
+%%--------------------------------------------------------------------
+
+create_chain_table() ->
+    Status = try
+                 _ = ets:new(?CHAINS_TAB, [named_table, set, public,
+                                           {keypos, #chain.name},
+                                           {read_concurrency, true}]),
+                 created
+             catch
+                 error:badarg -> already_exists
+             end,
+
+    case Status of
+        created ->
+            ets:give_away(?CHAINS_TAB, whereis(emqx_authentication_sup), undefined),
+            ok;
+        already_exists ->
+            ok
+    end.
+
 global_chain(mqtt) ->
     'mqtt:global';
 global_chain('mqtt-sn') ->

+ 16 - 0
apps/emqx/test/emqx_authentication_SUITE.erl

@@ -258,6 +258,22 @@ t_update_config({'end', Config}) ->
     ?AUTHN:deregister_providers([?config("auth1"), ?config("auth2")]),
     ok.
 
+t_restart({'init', Config}) -> Config;
+t_restart(Config) when is_list(Config) ->
+    ?assertEqual({ok, []}, ?AUTHN:list_chain_names()),
+
+    ?AUTHN:create_chain(test_chain),
+    ?assertEqual({ok, [test_chain]}, ?AUTHN:list_chain_names()),
+
+    ok = supervisor:terminate_child(emqx_authentication_sup, ?AUTHN),
+    {ok, _} = supervisor:restart_child(emqx_authentication_sup, ?AUTHN),
+
+    ?assertEqual({ok, [test_chain]}, ?AUTHN:list_chain_names());
+
+t_restart({'end', Config}) ->
+    ?AUTHN:delete_chain(test_chain),
+    ok.
+
 t_convert_certs({_, Config}) -> Config;
 t_convert_certs(Config) when is_list(Config) ->
     Global = <<"mqtt:global">>,

+ 32 - 8
apps/emqx_authn/src/emqx_authn_app.erl

@@ -34,12 +34,11 @@
 start(_StartType, _StartArgs) ->
     ok = mria_rlog:wait_for_shards([?AUTH_SHARD], infinity),
     {ok, Sup} = emqx_authn_sup:start_link(),
-    ok = ?AUTHN:register_providers(emqx_authn:providers()),
     ok = initialize(),
     {ok, Sup}.
 
 stop(_State) ->
-    ok = ?AUTHN:deregister_providers(provider_types()),
+    ok = deinitialize(),
     ok.
 
 %%------------------------------------------------------------------------------
@@ -47,12 +46,37 @@ stop(_State) ->
 %%------------------------------------------------------------------------------
 
 initialize() ->
-    RawConfigs = emqx:get_raw_config([authentication], []),
-    Config = emqx_authn:check_configs(RawConfigs),
-    ?AUTHN:initialize_authentication(?GLOBAL, Config),
-    lists:foreach(fun({ListenerID, ListenerConfig}) ->
-                      ?AUTHN:initialize_authentication(ListenerID, maps:get(authentication, ListenerConfig, []))
-                  end, emqx_listeners:list()).
+    ok = ?AUTHN:register_providers(emqx_authn:providers()),
+
+    lists:foreach(
+      fun({ChainName, RawAuthConfigs}) ->
+              AuthConfig = emqx_authn:check_configs(RawAuthConfigs),
+              ?AUTHN:initialize_authentication(
+                 ChainName,
+                 AuthConfig)
+      end,
+      chain_configs()).
+
+deinitialize() ->
+    ok = ?AUTHN:deregister_providers(provider_types()).
+
+chain_configs() ->
+    [global_chain_config() | listener_chain_configs()].
+
+global_chain_config() ->
+    {?GLOBAL, emqx:get_raw_config([<<"authentication">>], [])}.
+
+listener_chain_configs() ->
+    lists:map(
+     fun({ListenerID, _}) ->
+        {ListenerID, emqx:get_raw_config(auth_config_path(ListenerID), [])}
+     end,
+     emqx_listeners:list()).
+
+auth_config_path(ListenerID) ->
+    [<<"listeners">>]
+    ++ binary:split(atom_to_binary(ListenerID), <<":">>)
+    ++ [<<"authentication">>].
 
 provider_types() ->
     lists:map(fun({Type, _Module}) -> Type end, emqx_authn:providers()).