Merge pull request #6427 from zmstone/feat-add-emqx-plugins-app
feat(plugins): add emqx_plugins skeleton
This commit is contained in:
commit
56804ef733
|
@ -175,9 +175,10 @@ restart_listener(Type, ListenerName, Conf) ->
|
||||||
restart_listener(Type, ListenerName, Conf, Conf).
|
restart_listener(Type, ListenerName, Conf, Conf).
|
||||||
|
|
||||||
restart_listener(Type, ListenerName, OldConf, NewConf) ->
|
restart_listener(Type, ListenerName, OldConf, NewConf) ->
|
||||||
case stop_listener(Type, ListenerName, OldConf) of
|
case do_stop_listener(Type, ListenerName, OldConf) of
|
||||||
ok -> start_listener(Type, ListenerName, NewConf);
|
ok -> start_listener(Type, ListenerName, NewConf);
|
||||||
Error -> Error
|
{error, not_found} -> start_listener(Type, ListenerName, NewConf);
|
||||||
|
{error, Reason} -> {error, Reason}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% @doc Stop all listeners.
|
%% @doc Stop all listeners.
|
||||||
|
|
|
@ -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"),
|
||||||
#{})}
|
#{})}
|
||||||
|
@ -800,13 +797,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()]),
|
||||||
|
|
|
@ -120,6 +120,7 @@ all(Suite) ->
|
||||||
string:substr(atom_to_list(F), 1, 2) == "t_"
|
string:substr(atom_to_list(F), 1, 2) == "t_"
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
%% set emqx app boot modules
|
||||||
-spec(boot_modules(all|list(atom())) -> ok).
|
-spec(boot_modules(all|list(atom())) -> ok).
|
||||||
boot_modules(Mods) ->
|
boot_modules(Mods) ->
|
||||||
application:set_env(emqx, boot_modules, Mods).
|
application:set_env(emqx, boot_modules, Mods).
|
||||||
|
@ -162,8 +163,7 @@ app_schema(App) ->
|
||||||
mustache_vars(App) ->
|
mustache_vars(App) ->
|
||||||
[{platform_data_dir, app_path(App, "data")},
|
[{platform_data_dir, app_path(App, "data")},
|
||||||
{platform_etc_dir, app_path(App, "etc")},
|
{platform_etc_dir, app_path(App, "etc")},
|
||||||
{platform_log_dir, app_path(App, "log")},
|
{platform_log_dir, app_path(App, "log")}
|
||||||
{platform_plugins_dir, app_path(App, "plugins")}
|
|
||||||
].
|
].
|
||||||
|
|
||||||
start_app(App, Schema, ConfigFile, SpecAppConfig) ->
|
start_app(App, Schema, ConfigFile, SpecAppConfig) ->
|
||||||
|
|
|
@ -132,8 +132,7 @@ render_config_file() ->
|
||||||
mustache_vars() ->
|
mustache_vars() ->
|
||||||
[{platform_data_dir, local_path(["data"])},
|
[{platform_data_dir, local_path(["data"])},
|
||||||
{platform_etc_dir, local_path(["etc"])},
|
{platform_etc_dir, local_path(["etc"])},
|
||||||
{platform_log_dir, local_path(["log"])},
|
{platform_log_dir, local_path(["log"])}
|
||||||
{platform_plugins_dir, local_path(["plugins"])}
|
|
||||||
].
|
].
|
||||||
|
|
||||||
generate_config() ->
|
generate_config() ->
|
||||||
|
@ -144,10 +143,6 @@ generate_config() ->
|
||||||
set_app_env({App, Lists}) ->
|
set_app_env({App, Lists}) ->
|
||||||
lists:foreach(fun({authz_file, _Var}) ->
|
lists:foreach(fun({authz_file, _Var}) ->
|
||||||
application:set_env(App, authz_file, local_path(["etc", "authz.conf"]));
|
application:set_env(App, authz_file, local_path(["etc", "authz.conf"]));
|
||||||
({plugins_loaded_file, _Var}) ->
|
|
||||||
application:set_env(App,
|
|
||||||
plugins_loaded_file,
|
|
||||||
local_path(["test", "emqx_SUITE_data","loaded_plugins"]));
|
|
||||||
({Par, Var}) ->
|
({Par, Var}) ->
|
||||||
application:set_env(App, Par, Var)
|
application:set_env(App, Par, Var)
|
||||||
end, Lists).
|
end, Lists).
|
||||||
|
|
|
@ -160,9 +160,6 @@ init_per_group(gc_tests, Config) ->
|
||||||
init_per_suite(Config) ->
|
init_per_suite(Config) ->
|
||||||
Config.
|
Config.
|
||||||
|
|
||||||
set_special_confs(emqx) ->
|
|
||||||
Path = emqx_common_test_helpers:deps_path(emqx, "test/emqx_SUITE_data/loaded_plugins"),
|
|
||||||
application:set_env(emqx, plugins_loaded_file, Path);
|
|
||||||
set_special_confs(_) ->
|
set_special_confs(_) ->
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
plugins {
|
||||||
|
prebuilt {
|
||||||
|
}
|
||||||
|
external {
|
||||||
|
}
|
||||||
|
install_dir = "{{ platform_plugins_dir }}"
|
||||||
|
}
|
|
@ -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, []}
|
||||||
|
]}.
|
|
@ -0,0 +1,8 @@
|
||||||
|
%% -*- mode: erlang -*-
|
||||||
|
{"0.1.0",
|
||||||
|
[ {<<".*">>, []}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{<<".*">>, []}
|
||||||
|
]
|
||||||
|
}.
|
|
@ -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()}).
|
|
@ -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.
|
|
@ -0,0 +1,99 @@
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% 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 in a location specified by
|
||||||
|
<code>install_dir</code> config key
|
||||||
|
<br>
|
||||||
|
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>.
|
||||||
|
<br>
|
||||||
|
NOTE: For security reasons, this directory should **NOT** be writable
|
||||||
|
by anyone expect for <code>emqx</code> (or any user which runs EMQ X)
|
||||||
|
""".
|
||||||
|
|
||||||
|
%% 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".
|
|
@ -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}}.
|
|
@ -42,12 +42,14 @@ 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.
|
||||||
|
|
||||||
end_per_suite(_Config) ->
|
end_per_suite(_Config) ->
|
||||||
emqx_common_test_helpers:stop_apps([]).
|
emqx_common_test_helpers:boot_modules(all),
|
||||||
|
emqx_common_test_helpers:stop_apps([]),
|
||||||
|
emqx_config:erase(plugins).
|
||||||
|
|
||||||
t_load(_) ->
|
t_load(_) ->
|
||||||
?assertEqual(ok, emqx_plugins:load()),
|
?assertEqual(ok, emqx_plugins:load()),
|
||||||
|
@ -57,7 +59,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:erase(plugins).
|
||||||
|
|
||||||
t_load_ext_plugin(_) ->
|
t_load_ext_plugin(_) ->
|
||||||
?assertError({plugin_app_file_not_found, _},
|
?assertError({plugin_app_file_not_found, _},
|
|
@ -55,6 +55,7 @@ init_per_suite(Config) ->
|
||||||
|
|
||||||
end_per_suite(_Config) ->
|
end_per_suite(_Config) ->
|
||||||
emqx_common_test_helpers:stop_apps([emqx_retainer]).
|
emqx_common_test_helpers:stop_apps([emqx_retainer]).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Test Cases
|
%% Test Cases
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
|
@ -257,7 +257,7 @@ overlay_vars_pkg(pkg) ->
|
||||||
, {platform_etc_dir, "/etc/emqx"}
|
, {platform_etc_dir, "/etc/emqx"}
|
||||||
, {platform_lib_dir, ""}
|
, {platform_lib_dir, ""}
|
||||||
, {platform_log_dir, "/var/log/emqx"}
|
, {platform_log_dir, "/var/log/emqx"}
|
||||||
, {platform_plugins_dir, "/var/lib/enqx/plugins"}
|
, {platform_plugins_dir, "/var/lib/emqx/plugins"}
|
||||||
, {runner_root_dir, "/usr/lib/emqx"}
|
, {runner_root_dir, "/usr/lib/emqx"}
|
||||||
, {runner_bin_dir, "/usr/bin"}
|
, {runner_bin_dir, "/usr/bin"}
|
||||||
, {runner_etc_dir, "/etc/emqx"}
|
, {runner_etc_dir, "/etc/emqx"}
|
||||||
|
@ -306,6 +306,7 @@ relx_apps(ReleaseType, Edition) ->
|
||||||
, emqx_prometheus
|
, emqx_prometheus
|
||||||
, emqx_psk
|
, emqx_psk
|
||||||
, emqx_slow_subs
|
, emqx_slow_subs
|
||||||
|
, emqx_plugins
|
||||||
]
|
]
|
||||||
++ [quicer || is_quicer_supported()]
|
++ [quicer || is_quicer_supported()]
|
||||||
%++ [emqx_license || is_enterprise(Edition)]
|
%++ [emqx_license || is_enterprise(Edition)]
|
||||||
|
|
Loading…
Reference in New Issue