feat(dashboard): support bind specific ip(port or ip:port).
This commit is contained in:
parent
0cde9e6ecf
commit
ec5d1b1463
|
@ -14,7 +14,7 @@ dashboard {
|
||||||
protocol = http
|
protocol = http
|
||||||
num_acceptors = 4
|
num_acceptors = 4
|
||||||
max_connections = 512
|
max_connections = 512
|
||||||
port = 18083
|
bind = 18083
|
||||||
backlog = 512
|
backlog = 512
|
||||||
send_timeout = 5s
|
send_timeout = 5s
|
||||||
inet6 = false
|
inet6 = false
|
||||||
|
@ -23,7 +23,7 @@ dashboard {
|
||||||
# ,
|
# ,
|
||||||
# {
|
# {
|
||||||
# protocol = https
|
# protocol = https
|
||||||
# port = 18084
|
# bind = "127.0.0.1:18084"
|
||||||
# num_acceptors = 2
|
# num_acceptors = 2
|
||||||
# backlog = 512
|
# backlog = 512
|
||||||
# send_timeout = 5s
|
# send_timeout = 5s
|
||||||
|
|
|
@ -61,15 +61,26 @@ start_listeners() ->
|
||||||
dispatch => Dispatch,
|
dispatch => Dispatch,
|
||||||
middlewares => [cowboy_router, ?EMQX_MIDDLE, cowboy_handler]
|
middlewares => [cowboy_router, ?EMQX_MIDDLE, cowboy_handler]
|
||||||
},
|
},
|
||||||
[begin
|
Res =
|
||||||
Minirest = maps:put(protocol, Protocol, BaseMinirest),
|
lists:foldl(fun({Name, Protocol, Port, RanchOptions}, Acc) ->
|
||||||
{ok, _} = minirest:start(Name, RanchOptions, Minirest),
|
Minirest = BaseMinirest#{protocol => Protocol},
|
||||||
?ULOG("Start listener ~ts on ~p successfully.~n", [Name, Port])
|
case minirest:start(Name, RanchOptions, Minirest) of
|
||||||
end || {Name, Protocol, Port, RanchOptions} <- listeners()].
|
{ok, _} ->
|
||||||
|
?ULOG("Start listener ~ts on ~p successfully.~n", [Name, Port]),
|
||||||
|
Acc;
|
||||||
|
{error, _Reason} ->
|
||||||
|
%% Don't record the reason because minirest already does(too much logs noise).
|
||||||
|
[Name | Acc]
|
||||||
|
end
|
||||||
|
end, [], listeners()),
|
||||||
|
case Res of
|
||||||
|
[] -> ok;
|
||||||
|
_ -> {error, Res}
|
||||||
|
end.
|
||||||
|
|
||||||
stop_listeners() ->
|
stop_listeners() ->
|
||||||
[begin
|
[begin
|
||||||
ok = minirest:stop(Name),
|
_ = minirest:stop(Name),
|
||||||
?ULOG("Stop listener ~ts on ~p successfully.~n", [Name, Port])
|
?ULOG("Stop listener ~ts on ~p successfully.~n", [Name, Port])
|
||||||
end || {Name, _, Port, _} <- listeners()].
|
end || {Name, _, Port, _} <- listeners()].
|
||||||
|
|
||||||
|
@ -85,12 +96,19 @@ apps() ->
|
||||||
|
|
||||||
listeners() ->
|
listeners() ->
|
||||||
[begin
|
[begin
|
||||||
Protocol = maps:get(protocol, ListenerOptions, http),
|
Protocol = maps:get(protocol, ListenerOption0, http),
|
||||||
Port = maps:get(port, ListenerOptions, 18083),
|
{ListenerOption, Port} = ip_port(ListenerOption0),
|
||||||
Name = listener_name(Protocol, Port),
|
Name = listener_name(Protocol, ListenerOption),
|
||||||
RanchOptions = ranch_opts(maps:without([protocol], ListenerOptions)),
|
RanchOptions = ranch_opts(maps:without([protocol], ListenerOption)),
|
||||||
{Name, Protocol, Port, RanchOptions}
|
{Name, Protocol, Port, RanchOptions}
|
||||||
end || ListenerOptions <- emqx_conf:get([dashboard, listeners], [])].
|
end || ListenerOption0 <- emqx_conf:get([dashboard, listeners], [])].
|
||||||
|
|
||||||
|
ip_port(Opts) -> ip_port(maps:take(bind, Opts), Opts).
|
||||||
|
|
||||||
|
ip_port(error, Opts) -> {Opts#{port => 18083}, 18083};
|
||||||
|
ip_port({Port, Opts}, _) when is_integer(Port) -> {Opts#{port => Port}, Port};
|
||||||
|
ip_port({{IP, Port}, Opts}, _) -> {Opts#{port => Port, ip => IP}, Port}.
|
||||||
|
|
||||||
|
|
||||||
ranch_opts(RanchOptions) ->
|
ranch_opts(RanchOptions) ->
|
||||||
Keys = [ {ack_timeout, handshake_timeout}
|
Keys = [ {ack_timeout, handshake_timeout}
|
||||||
|
@ -119,8 +137,16 @@ key_only(K , true , S) -> [K | S];
|
||||||
key_only(_K, false, S) -> S;
|
key_only(_K, false, S) -> S;
|
||||||
key_only(K , V , S) -> [{K, V} | S].
|
key_only(K , V , S) -> [{K, V} | S].
|
||||||
|
|
||||||
listener_name(Protocol, Port) ->
|
listener_name(Protocol, #{port := Port, ip := IP}) ->
|
||||||
Name = "dashboard:" ++ atom_to_list(Protocol) ++ ":" ++ integer_to_list(Port),
|
Name = "dashboard:"
|
||||||
|
++ atom_to_list(Protocol) ++ ":"
|
||||||
|
++ inet:ntoa(IP) ++ ":"
|
||||||
|
++ integer_to_list(Port),
|
||||||
|
list_to_atom(Name);
|
||||||
|
listener_name(Protocol, #{port := Port}) ->
|
||||||
|
Name = "dashboard:"
|
||||||
|
++ atom_to_list(Protocol) ++ ":"
|
||||||
|
++ integer_to_list(Port),
|
||||||
list_to_atom(Name).
|
list_to_atom(Name).
|
||||||
|
|
||||||
authorize(Req) ->
|
authorize(Req) ->
|
||||||
|
|
|
@ -27,10 +27,13 @@
|
||||||
start(_StartType, _StartArgs) ->
|
start(_StartType, _StartArgs) ->
|
||||||
{ok, Sup} = emqx_dashboard_sup:start_link(),
|
{ok, Sup} = emqx_dashboard_sup:start_link(),
|
||||||
ok = mria_rlog:wait_for_shards([?DASHBOARD_SHARD], infinity),
|
ok = mria_rlog:wait_for_shards([?DASHBOARD_SHARD], infinity),
|
||||||
_ = emqx_dashboard:start_listeners(),
|
case emqx_dashboard:start_listeners() of
|
||||||
emqx_dashboard_cli:load(),
|
ok ->
|
||||||
{ok, _Result} = emqx_dashboard_admin:add_default_user(),
|
emqx_dashboard_cli:load(),
|
||||||
{ok, Sup}.
|
{ok, _Result} = emqx_dashboard_admin:add_default_user(),
|
||||||
|
{ok, Sup};
|
||||||
|
{error, Reason} -> {error, Reason}
|
||||||
|
end.
|
||||||
|
|
||||||
stop(_State) ->
|
stop(_State) ->
|
||||||
emqx_dashboard_cli:unload(),
|
emqx_dashboard_cli:unload(),
|
||||||
|
|
|
@ -25,8 +25,18 @@ namespace() -> <<"dashboard">>.
|
||||||
roots() -> ["dashboard"].
|
roots() -> ["dashboard"].
|
||||||
|
|
||||||
fields("dashboard") ->
|
fields("dashboard") ->
|
||||||
[ {listeners, hoconsc:array(hoconsc:union([hoconsc:ref(?MODULE, "http"),
|
[ {listeners,
|
||||||
hoconsc:ref(?MODULE, "https")]))}
|
sc(hoconsc:array(hoconsc:union([hoconsc:ref(?MODULE, "http"),
|
||||||
|
hoconsc:ref(?MODULE, "https")])),
|
||||||
|
#{ desc =>
|
||||||
|
"""HTTP(s) listeners identified by their protocol type,
|
||||||
|
is used to serve dashboard UI and restful HTTP API.<br>
|
||||||
|
Listeners must have a unique combination of port number and IP address.<br>
|
||||||
|
For example, an HTTP listener can listen on all configured IP addresses
|
||||||
|
on a given port for a machine by specifying the IP address 0.0.0.0.<br>
|
||||||
|
Alternatively, the HTTP listener can specify a unique IP address for each listener,
|
||||||
|
but use the same port.
|
||||||
|
""" })}
|
||||||
, {default_username, fun default_username/1}
|
, {default_username, fun default_username/1}
|
||||||
, {default_password, fun default_password/1}
|
, {default_password, fun default_password/1}
|
||||||
, {sample_interval, sc(emqx_schema:duration_s(), #{default => "10s"})}
|
, {sample_interval, sc(emqx_schema:duration_s(), #{default => "10s"})}
|
||||||
|
@ -35,11 +45,23 @@ fields("dashboard") ->
|
||||||
];
|
];
|
||||||
|
|
||||||
fields("http") ->
|
fields("http") ->
|
||||||
[ {"protocol", hoconsc:enum([http, https])}
|
[ {"protocol", sc(
|
||||||
, {"port", hoconsc:mk(integer(), #{default => 18083})}
|
hoconsc:enum([http, https]),
|
||||||
, {"num_acceptors", sc(integer(), #{default => 4})}
|
#{ desc => "HTTP/HTTPS protocol."
|
||||||
|
, nullable => false
|
||||||
|
, default => http})}
|
||||||
|
, {"bind", fun bind/1}
|
||||||
|
, {"num_acceptors", sc(
|
||||||
|
integer(),
|
||||||
|
#{ default => 4
|
||||||
|
, desc => "Socket acceptor pool for TCP protocols."
|
||||||
|
})}
|
||||||
, {"max_connections", sc(integer(), #{default => 512})}
|
, {"max_connections", sc(integer(), #{default => 512})}
|
||||||
, {"backlog", sc(integer(), #{default => 1024})}
|
, {"backlog", sc(
|
||||||
|
integer(),
|
||||||
|
#{ default => 1024
|
||||||
|
, desc => "Defines the maximum length that the queue of pending connections can grow to."
|
||||||
|
})}
|
||||||
, {"send_timeout", sc(emqx_schema:duration(), #{default => "5s"})}
|
, {"send_timeout", sc(emqx_schema:duration(), #{default => "5s"})}
|
||||||
, {"inet6", sc(boolean(), #{default => false})}
|
, {"inet6", sc(boolean(), #{default => false})}
|
||||||
, {"ipv6_v6only", sc(boolean(), #{default => false})}
|
, {"ipv6_v6only", sc(boolean(), #{default => false})}
|
||||||
|
@ -50,6 +72,12 @@ fields("https") ->
|
||||||
proplists:delete("fail_if_no_peer_cert",
|
proplists:delete("fail_if_no_peer_cert",
|
||||||
emqx_schema:server_ssl_opts_schema(#{}, true)).
|
emqx_schema:server_ssl_opts_schema(#{}, true)).
|
||||||
|
|
||||||
|
bind(type) -> hoconsc:union([non_neg_integer(), emqx_schema:ip_port()]);
|
||||||
|
bind(default) -> 18083;
|
||||||
|
bind(nullable) -> false;
|
||||||
|
bind(desc) -> "Port without IP(18083) or port with specified IP(127.0.0.1:18083).";
|
||||||
|
bind(_) -> undefined.
|
||||||
|
|
||||||
default_username(type) -> string();
|
default_username(type) -> string();
|
||||||
default_username(default) -> "admin";
|
default_username(default) -> "admin";
|
||||||
default_username(nullable) -> false;
|
default_username(nullable) -> false;
|
||||||
|
@ -67,6 +95,10 @@ default_password(_) -> undefined.
|
||||||
cors(type) -> boolean();
|
cors(type) -> boolean();
|
||||||
cors(default) -> false;
|
cors(default) -> false;
|
||||||
cors(nullable) -> true;
|
cors(nullable) -> true;
|
||||||
|
cors(desc) ->
|
||||||
|
"""Support Cross-Origin Resource Sharing (CORS).
|
||||||
|
Allows a server to indicate any origins (domain, scheme, or port) other than
|
||||||
|
its own from which a browser should permit loading resources.""";
|
||||||
cors(_) -> undefined.
|
cors(_) -> undefined.
|
||||||
|
|
||||||
sc(Type, Meta) -> hoconsc:mk(Type, Meta).
|
sc(Type, Meta) -> hoconsc:mk(Type, Meta).
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
%% FIXME: tag this as v3.1.3
|
%% FIXME: tag this as v3.1.3
|
||||||
{prometheus, {git, "https://github.com/emqx/prometheus.erl", {ref, "9994c76adca40d91a2545102230ccce2423fd8a7"}}},
|
{prometheus, {git, "https://github.com/emqx/prometheus.erl", {ref, "9994c76adca40d91a2545102230ccce2423fd8a7"}}},
|
||||||
{hocon, {git, "https://github.com/emqx/hocon.git", {tag, "0.23.0"}}},
|
{hocon, {git, "https://github.com/emqx/hocon.git", {tag, "0.23.0"}}},
|
||||||
{minirest, {git, "https://github.com/emqx/minirest", {tag, "1.2.10"}}}
|
{minirest, {git, "https://github.com/emqx/minirest", {tag, "1.2.11"}}}
|
||||||
]}.
|
]}.
|
||||||
|
|
||||||
{edoc_opts, [{preprocess, true}]}.
|
{edoc_opts, [{preprocess, true}]}.
|
||||||
|
|
|
@ -56,7 +56,7 @@
|
||||||
, {mria, {git, "https://github.com/emqx/mria", {tag, "0.1.5"}}}
|
, {mria, {git, "https://github.com/emqx/mria", {tag, "0.1.5"}}}
|
||||||
, {ekka, {git, "https://github.com/emqx/ekka", {tag, "0.11.3"}}}
|
, {ekka, {git, "https://github.com/emqx/ekka", {tag, "0.11.3"}}}
|
||||||
, {gen_rpc, {git, "https://github.com/emqx/gen_rpc", {tag, "2.8.0"}}}
|
, {gen_rpc, {git, "https://github.com/emqx/gen_rpc", {tag, "2.8.0"}}}
|
||||||
, {minirest, {git, "https://github.com/emqx/minirest", {tag, "1.2.10"}}}
|
, {minirest, {git, "https://github.com/emqx/minirest", {tag, "1.2.11"}}}
|
||||||
, {ecpool, {git, "https://github.com/emqx/ecpool", {tag, "0.5.2"}}}
|
, {ecpool, {git, "https://github.com/emqx/ecpool", {tag, "0.5.2"}}}
|
||||||
, {replayq, "0.3.3"}
|
, {replayq, "0.3.3"}
|
||||||
, {pbkdf2, {git, "https://github.com/emqx/erlang-pbkdf2.git", {tag, "2.0.4"}}}
|
, {pbkdf2, {git, "https://github.com/emqx/erlang-pbkdf2.git", {tag, "2.0.4"}}}
|
||||||
|
|
Loading…
Reference in New Issue