Merge pull request #7797 from zmstone/0427-5.0-dashboard-add-listener-enable-disable-config

feat(dashboard): add listener enable/disable config toggle
This commit is contained in:
zhongwencool 2022-04-28 16:07:00 +08:00 committed by GitHub
commit 061d9198ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 131 additions and 57 deletions

View File

@ -74,8 +74,8 @@ Note: `sample_interval` should be a divisor of 60."""
} }
inet6 { inet6 {
desc { desc {
en: "Enable IPv6 support." en: "Enable IPv6 support, default is false, which means IPv4 only."
zh: "启用IPv6" zh: "启用IPv6 如果机器不支持IPv6请关闭此选项否则会导致仪表盘无法使用。"
} }
label { label {
en: "IPv6" en: "IPv6"
@ -85,7 +85,7 @@ Note: `sample_interval` should be a divisor of 60."""
ipv6_v6only { ipv6_v6only {
desc { desc {
en: "Disable IPv4-to-IPv6 mapping for the listener." en: "Disable IPv4-to-IPv6 mapping for the listener."
zh: "禁用IPv4-to-IPv6映射" zh: "当开启 inet6 功能的同时禁用 IPv4-to-IPv6 映射。该配置仅在 inet6 功能开启时有效。"
} }
label { label {
en: "IPv6 only" en: "IPv6 only"
@ -132,6 +132,16 @@ Note: `sample_interval` should be a divisor of 60."""
zh: "HTTPS" zh: "HTTPS"
} }
} }
listener_enable {
desc {
en: "Ignore or enable this listener"
zh: "忽略或启用该监听器配置"
}
label {
en: "Enable"
zh: "启用"
}
}
bind { bind {
desc { desc {
en: "Port without IP(18083) or port with specified IP(127.0.0.1:18083)." en: "Port without IP(18083) or port with specified IP(127.0.0.1:18083)."

View File

@ -153,10 +153,13 @@ apps() ->
]. ].
listeners(Listeners) -> listeners(Listeners) ->
lists:map( lists:filtermap(
fun({Protocol, Conf}) -> fun({Protocol, Conf}) ->
{Conf1, Bind} = ip_port(Conf), maps:get(enable, Conf) andalso
{listener_name(Protocol, Conf1), Protocol, Bind, ranch_opts(Conf1)} begin
{Conf1, Bind} = ip_port(Conf),
{true, {listener_name(Protocol, Conf1), Protocol, Bind, ranch_opts(Conf1)}}
end
end, end,
maps:to_list(Listeners) maps:to_list(Listeners)
). ).
@ -172,34 +175,34 @@ init_i18n() ->
Lang = emqx_conf:get([dashboard, i18n_lang], en), Lang = emqx_conf:get([dashboard, i18n_lang], en),
init_i18n(File, Lang). init_i18n(File, Lang).
ranch_opts(RanchOptions) -> ranch_opts(Options) ->
Keys = [ Keys = [
{ack_timeout, handshake_timeout}, handshake_timeout,
connection_type, connection_type,
max_connections, max_connections,
num_acceptors, num_acceptors,
shutdown, shutdown,
socket socket
], ],
{S, R} = lists:foldl(fun key_take/2, {RanchOptions, #{}}, Keys), RanchOpts = maps:with(Keys, Options),
R#{socket_opts => maps:fold(fun key_only/3, [], S)}. SocketOpts = maps:fold(
fun filter_false/3,
key_take(Key, {All, R}) -> [],
{K, KX} = maps:without([enable, inet6, ipv6_v6only | Keys], Options)
case Key of ),
{K1, K2} -> {K1, K2}; InetOpts =
_ -> {Key, Key} case Options of
#{inet6 := true, ipv6_v6only := true} ->
[inet6, {ipv6_v6only, true}];
#{inet6 := true, ipv6_v6only := false} ->
[inet6];
_ ->
[inet]
end, end,
case maps:get(K, All, undefined) of RanchOpts#{socket_opts => InetOpts ++ SocketOpts}.
undefined ->
{All, R};
V ->
{maps:remove(K, All), R#{KX => V}}
end.
key_only(K, true, S) -> [K | S]; filter_false(_K, false, S) -> S;
key_only(_K, false, S) -> S; filter_false(K, V, S) -> [{K, V} | S].
key_only(K, V, S) -> [{K, V} | S].
listener_name(Protocol, #{port := Port, ip := IP}) -> listener_name(Protocol, #{port := Port, ip := IP}) ->
Name = Name =

View File

@ -63,22 +63,42 @@ remove_handler() ->
ok. ok.
pre_config_update(_Path, UpdateConf0, RawConf) -> pre_config_update(_Path, UpdateConf0, RawConf) ->
UpdateConf = UpdateConf = remove_sensitive_data(UpdateConf0),
case UpdateConf0 of
#{<<"default_password">> := <<"******">>} ->
maps:remove(<<"default_password">>, UpdateConf0);
_ ->
UpdateConf0
end,
NewConf = emqx_map_lib:deep_merge(RawConf, UpdateConf), NewConf = emqx_map_lib:deep_merge(RawConf, UpdateConf),
{ok, NewConf}. {ok, NewConf}.
-define(SENSITIVE_PASSWORD, <<"******">>).
remove_sensitive_data(Conf0) ->
Conf1 =
case Conf0 of
#{<<"default_password">> := ?SENSITIVE_PASSWORD} ->
maps:remove(<<"default_password">>, Conf0);
_ ->
Conf0
end,
case Conf1 of
#{<<"listeners">> := #{<<"https">> := #{<<"password">> := ?SENSITIVE_PASSWORD}}} ->
emqx_map_lib:deep_remove([<<"listeners">>, <<"https">>, <<"password">>], Conf1);
_ ->
Conf1
end.
post_config_update(_, _Req, NewConf, OldConf, _AppEnvs) -> post_config_update(_, _Req, NewConf, OldConf, _AppEnvs) ->
#{listeners := NewListeners} = NewConf, #{listeners := #{http := NewHttp, https := NewHttps}} = NewConf,
#{listeners := OldListeners} = OldConf, #{listeners := #{http := OldHttp, https := OldHttps}} = OldConf,
_ = _ =
case NewListeners =:= OldListeners of case diff_listeners(OldHttp, NewHttp, OldHttps, NewHttps) of
true -> ok; identical -> ok;
false -> erlang:send_after(500, ?MODULE, {update_listeners, OldListeners, NewListeners}) {Stop, Start} -> erlang:send_after(500, ?MODULE, {update_listeners, Stop, Start})
end, end,
ok. ok.
diff_listeners(Http, Http, Https, Https) ->
identical;
diff_listeners(OldHttp, NewHttp, Https, Https) ->
{#{http => OldHttp}, #{http => NewHttp}};
diff_listeners(Http, Http, OldHttps, NewHttps) ->
{#{https => OldHttps}, #{https => NewHttps}};
diff_listeners(OldHttp, NewHttp, OldHttps, NewHttps) ->
{#{http => OldHttp, https => OldHttps}, #{http => NewHttp, https => NewHttps}}.

View File

@ -77,7 +77,32 @@ fields("listeners") ->
]; ];
fields("http") -> fields("http") ->
[ [
{"bind", fun bind/1}, enable(true),
bind(18803)
| common_listener_fields()
];
fields("https") ->
[
enable(false),
bind(18804)
| common_listener_fields() ++
exclude_fields(
["enable", "fail_if_no_peer_cert"],
emqx_schema:server_ssl_opts_schema(#{}, true)
)
].
exclude_fields([], Fields) ->
Fields;
exclude_fields([FieldName | Rest], Fields) ->
%% assert field exists
case lists:keytake(FieldName, 1, Fields) of
{value, _, New} -> exclude_fields(Rest, New);
false -> error({FieldName, Fields})
end.
common_listener_fields() ->
[
{"num_acceptors", {"num_acceptors",
sc( sc(
integer(), integer(),
@ -126,25 +151,40 @@ fields("http") ->
desc => ?DESC(ipv6_v6only) desc => ?DESC(ipv6_v6only)
} }
)} )}
]; ].
fields("https") ->
fields("http") ++
proplists:delete(
"fail_if_no_peer_cert",
emqx_schema:server_ssl_opts_schema(#{}, true)
).
desc("dashboard") -> ?DESC(desc_dashboard); enable(Bool) ->
desc("listeners") -> ?DESC(desc_listeners); {"enable",
desc("http") -> ?DESC(desc_http); sc(
desc("https") -> ?DESC(desc_https); boolean(),
desc(_) -> undefined. #{
default => Bool,
required => true,
desc => ?DESC(listener_enable)
}
)}.
bind(type) -> hoconsc:union([non_neg_integer(), emqx_schema:ip_port()]); bind(Port) ->
bind(default) -> 18083; {"bind",
bind(required) -> true; sc(
bind(desc) -> ?DESC(bind); hoconsc:union([non_neg_integer(), emqx_schema:ip_port()]),
bind(_) -> undefined. #{
default => Port,
required => true,
desc => ?DESC(bind)
}
)}.
desc("dashboard") ->
?DESC(desc_dashboard);
desc("listeners") ->
?DESC(desc_listeners);
desc("http") ->
?DESC(desc_http);
desc("https") ->
?DESC(desc_https);
desc(_) ->
undefined.
default_username(type) -> binary(); default_username(type) -> binary();
default_username(default) -> "admin"; default_username(default) -> "admin";

View File

@ -37,6 +37,7 @@ set_default_config(DefaultUsername) ->
Config = #{ Config = #{
listeners => #{ listeners => #{
http => #{ http => #{
enable => true,
port => 18083 port => 18083
} }
}, },

View File

@ -48,7 +48,7 @@ defmodule EMQXUmbrella.MixProject do
[ [
{:lc, github: "emqx/lc", tag: "0.2.1"}, {:lc, github: "emqx/lc", tag: "0.2.1"},
{:redbug, "2.0.7"}, {:redbug, "2.0.7"},
{:typerefl, github: "ieQu1/typerefl", tag: "0.9.0", override: true}, {:typerefl, github: "ieQu1/typerefl", tag: "0.9.1", override: true},
{:ehttpc, github: "emqx/ehttpc", tag: "0.1.12"}, {:ehttpc, github: "emqx/ehttpc", tag: "0.1.12"},
{:gproc, github: "uwiger/gproc", tag: "0.8.0", override: true}, {:gproc, github: "uwiger/gproc", tag: "0.8.0", override: true},
{:jiffy, github: "emqx/jiffy", tag: "1.0.5", override: true}, {:jiffy, github: "emqx/jiffy", tag: "1.0.5", override: true},

View File

@ -47,7 +47,7 @@
[ {lc, {git, "https://github.com/emqx/lc.git", {tag, "0.2.1"}}} [ {lc, {git, "https://github.com/emqx/lc.git", {tag, "0.2.1"}}}
, {redbug, "2.0.7"} , {redbug, "2.0.7"}
, {gpb, "4.11.2"} %% gpb only used to build, but not for release, pin it here to avoid fetching a wrong version due to rebar plugins scattered in all the deps , {gpb, "4.11.2"} %% gpb only used to build, but not for release, pin it here to avoid fetching a wrong version due to rebar plugins scattered in all the deps
, {typerefl, {git, "https://github.com/ieQu1/typerefl", {tag, "0.9.0"}}} , {typerefl, {git, "https://github.com/ieQu1/typerefl", {tag, "0.9.1"}}}
, {ehttpc, {git, "https://github.com/emqx/ehttpc", {tag, "0.1.12"}}} , {ehttpc, {git, "https://github.com/emqx/ehttpc", {tag, "0.1.12"}}}
, {gproc, {git, "https://github.com/uwiger/gproc", {tag, "0.8.0"}}} , {gproc, {git, "https://github.com/uwiger/gproc", {tag, "0.8.0"}}}
, {jiffy, {git, "https://github.com/emqx/jiffy", {tag, "1.0.5"}}} , {jiffy, {git, "https://github.com/emqx/jiffy", {tag, "1.0.5"}}}