feat(plugin): add plugin http api

This commit is contained in:
zhongwencool 2022-01-24 17:52:56 +08:00 committed by Zhongwen Deng
parent dcc0ff673f
commit 7160bc06b3
3 changed files with 53 additions and 8 deletions

View File

@ -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) ->

View File

@ -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.

View File

@ -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.