Explorar o código

feat(plugin): add plugin http api

zhongwencool %!s(int64=4) %!d(string=hai) anos
pai
achega
7160bc06b3

+ 7 - 1
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) ->

+ 9 - 3
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.

+ 37 - 4
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}) ->
+            <<Name/binary, "-", Vsn/binary>>
+                  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.