Просмотр исходного кода

Merge pull request #11229 from thalesmg/fix-plugin-load-conf-master

fix(plugins): start/stop plugins when loading config from CLI
Thales Macedo Garitezi 2 лет назад
Родитель
Сommit
0d1abf7d8a

+ 1 - 1
apps/emqx_plugins/src/emqx_plugins.app.src

@@ -1,7 +1,7 @@
 %% -*- mode: erlang -*-
 {application, emqx_plugins, [
     {description, "EMQX Plugin Management"},
-    {vsn, "0.1.4"},
+    {vsn, "0.1.5"},
     {modules, []},
     {mod, {emqx_plugins_app, []}},
     {applications, [kernel, stdlib, emqx]},

+ 29 - 0
apps/emqx_plugins/src/emqx_plugins.erl

@@ -51,6 +51,11 @@
     get_tar/1
 ]).
 
+%% `emqx_config_handler' API
+-export([
+    post_config_update/5
+]).
+
 %% internal
 -export([do_ensure_started/1]).
 -export([
@@ -857,3 +862,27 @@ running_apps() ->
         end,
         application:which_applications(infinity)
     ).
+
+%%--------------------------------------------------------------------
+%% `emqx_config_handler' API
+%%--------------------------------------------------------------------
+
+post_config_update([?CONF_ROOT], _Req, #{states := NewStates}, #{states := OldStates}, _Envs) ->
+    NewStatesIndex = maps:from_list([{NV, S} || S = #{name_vsn := NV} <- NewStates]),
+    OldStatesIndex = maps:from_list([{NV, S} || S = #{name_vsn := NV} <- OldStates]),
+    #{changed := Changed} = emqx_utils_maps:diff_maps(NewStatesIndex, OldStatesIndex),
+    maps:foreach(fun enable_disable_plugin/2, Changed),
+    ok;
+post_config_update(_Path, _Req, _NewConf, _OldConf, _Envs) ->
+    ok.
+
+enable_disable_plugin(NameVsn, {#{enable := true}, #{enable := false}}) ->
+    %% errors are already logged in this fn
+    _ = ensure_stopped(NameVsn),
+    ok;
+enable_disable_plugin(NameVsn, {#{enable := false}, #{enable := true}}) ->
+    %% errors are already logged in this fn
+    _ = ensure_started(NameVsn),
+    ok;
+enable_disable_plugin(_NameVsn, _Diff) ->
+    ok.

+ 4 - 0
apps/emqx_plugins/src/emqx_plugins_app.erl

@@ -18,6 +18,8 @@
 
 -behaviour(application).
 
+-include("emqx_plugins.hrl").
+
 -export([
     start/2,
     stop/1
@@ -27,7 +29,9 @@ start(_Type, _Args) ->
     %% load all pre-configured
     ok = emqx_plugins:ensure_started(),
     {ok, Sup} = emqx_plugins_sup:start_link(),
+    ok = emqx_config_handler:add_handler([?CONF_ROOT], emqx_plugins),
     {ok, Sup}.
 
 stop(_State) ->
+    ok = emqx_config_handler:remove_handler([?CONF_ROOT]),
     ok.

+ 61 - 2
apps/emqx_plugins/test/emqx_plugins_SUITE.erl

@@ -65,7 +65,7 @@ init_per_suite(Config) ->
     WorkDir = proplists:get_value(data_dir, Config),
     filelib:ensure_path(WorkDir),
     OrigInstallDir = emqx_plugins:get_config(install_dir, undefined),
-    emqx_common_test_helpers:start_apps([emqx_conf]),
+    emqx_common_test_helpers:start_apps([emqx_conf, emqx_plugins]),
     emqx_plugins:put_config(install_dir, WorkDir),
     [{orig_install_dir, OrigInstallDir} | Config].
 
@@ -77,7 +77,7 @@ end_per_suite(Config) ->
         undefined -> ok;
         OrigInstallDir -> emqx_plugins:put_config(install_dir, OrigInstallDir)
     end,
-    emqx_common_test_helpers:stop_apps([emqx_conf]),
+    emqx_common_test_helpers:stop_apps([emqx_plugins, emqx_conf]),
     ok.
 
 init_per_testcase(TestCase, Config) ->
@@ -505,6 +505,65 @@ t_elixir_plugin(Config) ->
     ?assertEqual([], emqx_plugins:list()),
     ok.
 
+t_load_config_from_cli({init, Config}) ->
+    #{package := Package} = get_demo_plugin_package(),
+    NameVsn = filename:basename(Package, ?PACKAGE_SUFFIX),
+    [{name_vsn, NameVsn} | Config];
+t_load_config_from_cli({'end', Config}) ->
+    NameVsn = ?config(name_vsn, Config),
+    ok = emqx_plugins:ensure_stopped(NameVsn),
+    ok = emqx_plugins:ensure_uninstalled(NameVsn),
+    ok;
+t_load_config_from_cli(Config) when is_list(Config) ->
+    NameVsn = ?config(name_vsn, Config),
+    ok = emqx_plugins:ensure_installed(NameVsn),
+    ?assertEqual([], emqx_plugins:configured()),
+    ok = emqx_plugins:ensure_enabled(NameVsn),
+    ok = emqx_plugins:ensure_started(NameVsn),
+    Params0 = unused,
+    ?assertMatch(
+        {200, [#{running_status := [#{status := running}]}]},
+        emqx_mgmt_api_plugins:list_plugins(get, Params0)
+    ),
+
+    %% Now we disable it via CLI loading
+    Conf0 = emqx_config:get([plugins]),
+    ?assertMatch(
+        #{states := [#{enable := true}]},
+        Conf0
+    ),
+    #{states := [Plugin0]} = Conf0,
+    Conf1 = Conf0#{states := [Plugin0#{enable := false}]},
+    Filename = filename:join(["/tmp", [?FUNCTION_NAME, ".hocon"]]),
+    ok = file:write_file(Filename, hocon_pp:do(#{plugins => Conf1}, #{})),
+    ok = emqx_conf_cli:conf(["load", Filename]),
+
+    Conf2 = emqx_config:get([plugins]),
+    ?assertMatch(
+        #{states := [#{enable := false}]},
+        Conf2
+    ),
+    ?assertMatch(
+        {200, [#{running_status := [#{status := stopped}]}]},
+        emqx_mgmt_api_plugins:list_plugins(get, Params0)
+    ),
+
+    %% Re-enable it via CLI loading
+    ok = file:write_file(Filename, hocon_pp:do(#{plugins => Conf0}, #{})),
+    ok = emqx_conf_cli:conf(["load", Filename]),
+
+    Conf3 = emqx_config:get([plugins]),
+    ?assertMatch(
+        #{states := [#{enable := true}]},
+        Conf3
+    ),
+    ?assertMatch(
+        {200, [#{running_status := [#{status := running}]}]},
+        emqx_mgmt_api_plugins:list_plugins(get, Params0)
+    ),
+
+    ok.
+
 group_t_copy_plugin_to_a_new_node({init, Config}) ->
     WorkDir = proplists:get_value(data_dir, Config),
     FromInstallDir = filename:join(WorkDir, atom_to_list(plugins_copy_from)),

+ 1 - 0
changes/ce/fix-11229.en.md

@@ -0,0 +1 @@
+Fixed an issue preventing plugins from starting/stopping after changing configuration via `emqx ctl conf load`.