From 7160bc06b36fb8d7c8d3aee517e535fe471af176 Mon Sep 17 00:00:00 2001 From: zhongwencool Date: Mon, 24 Jan 2022 17:52:56 +0800 Subject: [PATCH] feat(plugin): add plugin http api --- .../src/emqx_mgmt_api_plugins.erl | 8 +++- apps/emqx_plugins/src/emqx_plugins.erl | 12 ++++-- apps/emqx_plugins/test/emqx_plugins_SUITE.erl | 41 +++++++++++++++++-- 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/apps/emqx_management/src/emqx_mgmt_api_plugins.erl b/apps/emqx_management/src/emqx_mgmt_api_plugins.erl index 657565c93..8646d286b 100644 --- a/apps/emqx_management/src/emqx_mgmt_api_plugins.erl +++ b/apps/emqx_management/src/emqx_mgmt_api_plugins.erl @@ -199,7 +199,7 @@ fields(position) -> #{ desc => """ Enable auto-boot at position in the boot list, where Position could be - 'top', 'bottom', or 'before:other-vsn' to specify a relative position. + 'top', 'bottom', or 'before:other-vsn', 'after:other-vsn' to specify a relative position. """, nullable => true })}]; @@ -227,6 +227,10 @@ move_request_body() -> move_to_before => #{ summary => <<"move plugin before other plugins">>, value => #{position => <<"before:emqx_plugin_demo-5.1-rc.2">>} + }, + move_to_after => #{ + summary => <<"move plugin after other plugins">>, + value => #{position => <<"after:emqx_plugin_demo-5.1-rc.2">>} } }). @@ -354,7 +358,9 @@ return(_, {error, Reason}) -> parse_position(#{<<"position">> := <<"top">>}, _) -> front; parse_position(#{<<"position">> := <<"bottom">>}, _) -> rear; parse_position(#{<<"position">> := <<"before:", Name/binary>>}, Name) -> {error, <<"Can't before:self">>}; +parse_position(#{<<"position">> := <<"after:", Name/binary>>}, Name) -> {error, <<"Can't after:self">>}; parse_position(#{<<"position">> := <<"before:", Before/binary>>}, _Name) -> {before, binary_to_list(Before)}; +parse_position(#{<<"position">> := <<"after:", After/binary>>}, _Name) -> {behind, binary_to_list(After)}; parse_position(Position, _) -> {error, iolist_to_binary(io_lib:format("~p", [Position]))}. format_plugins(List) -> diff --git a/apps/emqx_plugins/src/emqx_plugins.erl b/apps/emqx_plugins/src/emqx_plugins.erl index d5d5b4c1a..0e54b8450 100644 --- a/apps/emqx_plugins/src/emqx_plugins.erl +++ b/apps/emqx_plugins/src/emqx_plugins.erl @@ -59,7 +59,7 @@ -type name_vsn() :: binary() | string(). %% "my_plugin-0.1.0" -type plugin() :: map(). %% the parse result of the JSON info file --type position() :: no_move | front | rear | {before, name_vsn()}. +-type position() :: no_move | front | rear | {before, name_vsn()} | {behind, name_vsn()}. %%-------------------------------------------------------------------- %% APIs @@ -170,7 +170,7 @@ add_new_configured(Configured, front, Item) -> [Item | Configured]; add_new_configured(Configured, rear, Item) -> Configured ++ [Item]; -add_new_configured(Configured, {before, NameVsn}, Item) -> +add_new_configured(Configured, {Action, NameVsn}, Item) -> SplitFun = fun(#{name_vsn := Nv}) -> bin(Nv) =/= bin(NameVsn) end, {Front, Rear} = lists:splitwith(SplitFun, Configured), Rear =:= [] andalso @@ -178,7 +178,13 @@ add_new_configured(Configured, {before, NameVsn}, Item) -> hint => "maybe_install_and_configure", name_vsn => NameVsn }), - Front ++ [Item | Rear]. + case Action of + before -> Front ++ [Item | Rear]; + behind -> + [Anchor | Rear0] = Rear, + Front ++ [Anchor, Item | Rear0] + end. + %% @doc Delete the package file. -spec delete_package(name_vsn()) -> ok. diff --git a/apps/emqx_plugins/test/emqx_plugins_SUITE.erl b/apps/emqx_plugins/test/emqx_plugins_SUITE.erl index 7fb778b2f..afccd84e3 100644 --- a/apps/emqx_plugins/test/emqx_plugins_SUITE.erl +++ b/apps/emqx_plugins/test/emqx_plugins_SUITE.erl @@ -115,8 +115,8 @@ t_demo_install_start_stop_uninstall(Config) -> ok = emqx_plugins:ensure_installed(NameVsn), %% idempotent ok = emqx_plugins:ensure_installed(NameVsn), - {ok, Info} = emqx_plugins:read_plugin(NameVsn), - ?assertEqual([Info], emqx_plugins:list()), + {ok, Info} = emqx_plugins:describe(NameVsn), + ?assertEqual([maps:without([readme], Info)], emqx_plugins:list()), %% start ok = emqx_plugins:ensure_started(NameVsn), ok = assert_app_running(emqx_plugin_template, true), @@ -158,6 +158,39 @@ write_info_file(Config, NameVsn, Content) -> ok = filelib:ensure_dir(InfoFile), ok = file:write_file(InfoFile, Content). +t_position({init, Config}) -> + Package = build_demo_plugin_package(), + NameVsn = filename:basename(Package, ?PACKAGE_SUFFIX), + [{name_vsn, NameVsn} | Config]; +t_position({'end', _Config}) -> ok; +t_position(Config) -> + NameVsn = proplists:get_value(name_vsn, Config), + ok = emqx_plugins:ensure_installed(NameVsn), + ok = emqx_plugins:ensure_enabled(NameVsn), + FakeInfo = "name=position, rel_vsn=\"2\", rel_apps=[\"position-9\"]," + "description=\"desc fake position app\"", + PosApp2 = <<"position-2">>, + ok = write_info_file(Config, PosApp2, FakeInfo), + %% fake a disabled plugin in config + ok = emqx_plugins:ensure_state(PosApp2, {before, NameVsn}, false), + ListFun = fun() -> + lists:map(fun( + #{<<"name">> := Name, <<"rel_vsn">> := Vsn}) -> + <> + end, emqx_plugins:list()) + end, + ?assertEqual([PosApp2, list_to_binary(NameVsn)], ListFun()), + emqx_plugins:ensure_enabled(PosApp2, {behind, NameVsn}), + ?assertEqual([list_to_binary(NameVsn), PosApp2], ListFun()), + + ok = emqx_plugins:ensure_stopped(), + ok = emqx_plugins:ensure_disabled(NameVsn), + ok = emqx_plugins:ensure_disabled(PosApp2), + ok = emqx_plugins:ensure_uninstalled(NameVsn), + ok = emqx_plugins:ensure_uninstalled(PosApp2), + ?assertEqual([], emqx_plugins:list()), + ok. + t_start_restart_and_stop({init, Config}) -> #{package := Package} = build_demo_plugin_package(), NameVsn = filename:basename(Package, ?PACKAGE_SUFFIX), @@ -283,12 +316,12 @@ t_bad_info_json(Config) -> ?assertMatch({error, #{error := "bad_info_file", return := {parse_error, _} }}, - emqx_plugins:read_plugin(NameVsn)), + emqx_plugins:describe(NameVsn)), ok = write_info_file(Config, NameVsn, "{\"bad\": \"obj\"}"), ?assertMatch({error, #{error := "bad_info_file_content", mandatory_fields := _ }}, - emqx_plugins:read_plugin(NameVsn)), + emqx_plugins:describe(NameVsn)), ?assertEqual([], emqx_plugins:list()), emqx_plugins:purge(NameVsn), ok.