feat(plugins): add emqx_plugins skeleton

* added emqx_plugins app.
* emqx_plugins.erl is moved from emqx app to emqx_plugins app
  same for the test SUITE
This commit is contained in:
Zaiming (Stone) Shi 2021-12-11 20:22:32 +01:00
parent e5b11d48a2
commit 38ac10d3e2
23 changed files with 185 additions and 16 deletions

View File

@ -157,9 +157,6 @@ roots(low) ->
, {"quota", , {"quota",
sc(ref("quota"), sc(ref("quota"),
#{})} #{})}
, {"plugins", %% TODO: move to emqx_conf_schema
sc(ref("plugins"),
#{})}
, {"stats", , {"stats",
sc(ref("stats"), sc(ref("stats"),
#{})} #{})}
@ -797,13 +794,6 @@ fields("deflate_opts") ->
} }
]; ];
fields("plugins") ->
[ {"expand_plugins_dir",
sc(string(),
#{})
}
];
fields("broker") -> fields("broker") ->
[ {"sys_msg_interval", [ {"sys_msg_interval",
sc(hoconsc:union([disabled, duration()]), sc(hoconsc:union([disabled, duration()]),

View File

@ -50,6 +50,7 @@
, emqx_authz_schema , emqx_authz_schema
, emqx_auto_subscribe_schema , emqx_auto_subscribe_schema
, emqx_modules_schema , emqx_modules_schema
, emqx_plugins_schema
, emqx_dashboard_schema , emqx_dashboard_schema
, emqx_gateway_schema , emqx_gateway_schema
, emqx_prometheus_schema , emqx_prometheus_schema

View File

@ -0,0 +1,7 @@
plugins {
prebuilt {
}
external {
}
install_dir = "plugins"
}

View File

@ -0,0 +1,9 @@
%% -*- mode: erlang -*-
{application, emqx_plugins,
[{description, "EMQ X Plugin Management"},
{vsn, "0.1.0"},
{modules, []},
{mod, {emqx_plugins_app,[]}},
{applications, [kernel,stdlib,emqx]},
{env, []}
]}.

View File

@ -0,0 +1,8 @@
%% -*- mode: erlang -*-
{"0.1.0",
[ {<<".*">>, []}
],
[
{<<".*">>, []}
]
}.

View File

@ -16,9 +16,8 @@
-module(emqx_plugins). -module(emqx_plugins).
-include("emqx.hrl"). -include_lib("emqx/include/emqx.hrl").
-include("logger.hrl"). -include_lib("emqx/include/logger.hrl").
-export([ load/0 -export([ load/0
, load/1 , load/1
@ -41,7 +40,7 @@
%% @doc Load all plugins when the broker started. %% @doc Load all plugins when the broker started.
-spec(load() -> ok | ignore | {error, term()}). -spec(load() -> ok | ignore | {error, term()}).
load() -> load() ->
ok = load_ext_plugins(emqx:get_config([plugins, expand_plugins_dir], undefined)). ok = load_ext_plugins(emqx:get_config([plugins, install_dir], undefined)).
%% @doc Load a Plugin %% @doc Load a Plugin
-spec(load(atom()) -> ok | {error, term()}). -spec(load(atom()) -> ok | {error, term()}).

View File

@ -0,0 +1,30 @@
%%--------------------------------------------------------------------
%% Copyright (c) 2021 EMQ Technologies Co., Ltd. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%--------------------------------------------------------------------
-module(emqx_plugins_app).
-behaviour(application).
-export([ start/2
, stop/1
]).
start(_Type, _Args) ->
{ok, Sup} = emqx_plugins_sup:start_link(),
{ok, Sup}.
stop(_State) ->
ok.

View File

@ -0,0 +1,94 @@
%%--------------------------------------------------------------------
%% Copyright (c) 2021 EMQ Technologies Co., Ltd. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%--------------------------------------------------------------------
-module(emqx_plugins_schema).
-behaviour(hocon_schema).
-export([ roots/0
, fields/1
]).
-include_lib("typerefl/include/types.hrl").
roots() -> ["plugins"].
fields("plugins") ->
#{fields => fields(),
desc => """
Manage EMQ X plugins.
<br>
Plugins can be pre-built as a part of EMQ X package,
or installed as a standalone package to the specific directory.
The standalone-installed plugins are referred to as 'external' plugins.
"""
}.
fields() ->
[ {prebuilt, fun prebuilt/1}
, {external, fun external/1}
, {install_dir, fun install_dir/1}
].
prebuilt(type) -> hoconsc:map("name", boolean());
prebuilt(nullable) -> true;
prebuilt(T) when T=/= desc -> undefined;
prebuilt(desc) -> """
A map() from plugin name to a boolean (true | false) flag to indicate
whether or not to enable the prebuilt plugin.
<br>
Most of the prebuilt plugins from 4.x are converted into features since 5.0.
""" ++ prebuilt_plugins() ++
"""
<br>
Enabled plugins are loaded (started) as a part of EMQ X node's boot sequence.
Plugins can be loaded on the fly, and enabled from dashbaord UI and/or CLI.
<br>
Example config: <code>{emqx_foo_bar: true, emqx_bazz: false}</code>
""".
external(type) -> hoconsc:map("name", string());
external(nullable) -> true;
external(T) when T =/= desc -> undefined;
external(desc) ->
"""
A map from plugin name to a version number string for enabled ones.
To disable an external plugin, set the value to 'false'.
<br>
Enabled plugins are loaded (started) as a part of EMQ X node's boot sequence.
Plugins can be loaded on the fly, and enabled from dashbaord UI and/or CLI.
<br>
Example config: <code>{emqx_extplug1: \"0.1.0\", emqx_extplug2: false}</code>
""".
install_dir(type) -> string();
install_dir(nullable) -> true;
install_dir(default) -> "plugins"; %% runner's root dir
install_dir(T) when T =/= desc -> undefined;
install_dir(desc) -> """
In which directory are the external plugins installed.
The plugin beam files and configuration files should reside in
the sub-directory named as <code>emqx_foo_bar-0.1.0</code>.
""".
%% TODO: when we have some prebuilt plugins, change this function to:
%% """
%% The names should be one of
%% - name1
%% - name2
%% """
prebuilt_plugins() ->
"So far, we do not have any prebuilt plugins".

View File

@ -0,0 +1,30 @@
%%--------------------------------------------------------------------
%% Copyright (c) 2021 EMQ Technologies Co., Ltd. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%--------------------------------------------------------------------
-module(emqx_plugins_sup).
-behaviour(supervisor).
-export([start_link/0]).
-export([init/1]).
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([]) ->
Children = [],
{ok, {{one_for_one, 10, 10}, Children}}.

View File

@ -42,7 +42,7 @@ init_per_suite(Config) ->
emqx_common_test_helpers:boot_modules([]), emqx_common_test_helpers:boot_modules([]),
emqx_common_test_helpers:start_apps([]), emqx_common_test_helpers:start_apps([]),
emqx_config:put([plugins, expand_plugins_dir], DataPath), emqx_config:put([plugins, install_dir], DataPath),
?assertEqual(ok, emqx_plugins:load()), ?assertEqual(ok, emqx_plugins:load()),
Config. Config.
@ -57,7 +57,7 @@ t_load(_) ->
?assertEqual({error, not_started}, emqx_plugins:unload(emqx_mini_plugin)), ?assertEqual({error, not_started}, emqx_plugins:unload(emqx_mini_plugin)),
?assertEqual({error, not_started}, emqx_plugins:unload(emqx_hocon_plugin)), ?assertEqual({error, not_started}, emqx_plugins:unload(emqx_hocon_plugin)),
emqx_config:put([plugins, expand_plugins_dir], undefined). emqx_config:put([plugins, install_dir], undefined).
t_load_ext_plugin(_) -> t_load_ext_plugin(_) ->
?assertError({plugin_app_file_not_found, _}, ?assertError({plugin_app_file_not_found, _},

View File

@ -305,6 +305,7 @@ relx_apps(ReleaseType, Edition) ->
, emqx_statsd , emqx_statsd
, emqx_prometheus , emqx_prometheus
, emqx_psk , emqx_psk
, emqx_plugins
] ]
++ [quicer || is_quicer_supported()] ++ [quicer || is_quicer_supported()]
%++ [emqx_license || is_enterprise(Edition)] %++ [emqx_license || is_enterprise(Edition)]