parent
473a3c0b35
commit
c4e279bb76
|
@ -11,35 +11,30 @@ emqx_dashboard {
|
|||
token_expired_time = 60m
|
||||
listeners = [
|
||||
{
|
||||
protocol = http
|
||||
num_acceptors = 4
|
||||
max_connections = 512
|
||||
protocol = http
|
||||
port = 18083
|
||||
backlog = 512
|
||||
send_timeout = 15s
|
||||
send_timeout_close = true
|
||||
send_timeout = 5s
|
||||
inet6 = false
|
||||
ipv6_v6only = false
|
||||
}
|
||||
## ,
|
||||
## {
|
||||
## protocol: https
|
||||
## port: 18084
|
||||
## acceptors: 2
|
||||
## backlog: 512
|
||||
## send_timeout: 15s
|
||||
## send_timeout_close: true
|
||||
## inet6: false
|
||||
## ipv6_v6only: false
|
||||
## certfile = "etc/certs/cert.pem"
|
||||
## keyfile = "etc/certs/key.pem"
|
||||
## cacertfile = "etc/certs/cacert.pem"
|
||||
## verify = verify_peer
|
||||
## tls_versions = "tlsv1.3,tlsv1.2,tlsv1.1,tlsv1"
|
||||
## ciphers = "TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256,TLS_CHACHA20_POLY1305_SHA256,TLS_AES_128_CCM_SHA256,TLS_AES_128_CCM_8_SHA256,ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-AES256-SHA384,ECDHE-RSA-AES256-SHA384,ECDHE-ECDSA-DES-CBC3-SHA,ECDH-ECDSA-AES256-GCM-SHA384,ECDH-RSA-AES256-GCM-SHA384,ECDH-ECDSA-AES256-SHA384,ECDH-RSA-AES256-SHA384,DHE-DSS-AES256-GCM-SHA384,DHE-DSS-AES256-SHA256,AES256-GCM-SHA384,AES256-SHA256,ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-AES128-SHA256,ECDHE-RSA-AES128-SHA256,ECDH-ECDSA-AES128-GCM-SHA256,ECDH-RSA-AES128-GCM-SHA256,ECDH-ECDSA-AES128-SHA256,ECDH-RSA-AES128-SHA256,DHE-DSS-AES128-GCM-SHA256,DHE-DSS-AES128-SHA256,AES128-GCM-SHA256,AES128-SHA256,ECDHE-ECDSA-AES256-SHA,ECDHE-RSA-AES256-SHA,DHE-DSS-AES256-SHA,ECDH-ECDSA-AES256-SHA,ECDH-RSA-AES256-SHA,AES256-SHA,ECDHE-ECDSA-AES128-SHA,ECDHE-RSA-AES128-SHA,DHE-DSS-AES128-SHA,ECDH-ECDSA-AES128-SHA,ECDH-RSA-AES128-SHA,AES128-SHA"
|
||||
## fail_if_no_peer_cert = true
|
||||
## inet6 = false
|
||||
## ipv6_v6only = false
|
||||
## }
|
||||
# ,
|
||||
# {
|
||||
# protocol = https
|
||||
# port = 18084
|
||||
# num_acceptors = 2
|
||||
# backlog = 512
|
||||
# send_timeout = 5s
|
||||
# inet6 = false
|
||||
# ipv6_v6only = false
|
||||
# certfile = "etc/certs/cert.pem"
|
||||
# keyfile = "etc/certs/key.pem"
|
||||
# cacertfile = "etc/certs/cacert.pem"
|
||||
# verify = verify_peer
|
||||
# versions = ["tlsv1.3","tlsv1.2","tlsv1.1","tlsv1"]
|
||||
# ciphers = ["TLS_AES_256_GCM_SHA384","TLS_AES_128_GCM_SHA256","TLS_CHACHA20_POLY1305_SHA256","TLS_AES_128_CCM_SHA256","TLS_AES_128_CCM_8_SHA256","ECDHE-ECDSA-AES256-GCM-SHA384","ECDHE-RSA-AES256-GCM-SHA384","ECDHE-ECDSA-AES256-SHA384","ECDHE-RSA-AES256-SHA384","ECDHE-ECDSA-DES-CBC3-SHA","ECDH-ECDSA-AES256-GCM-SHA384","ECDH-RSA-AES256-GCM-SHA384","ECDH-ECDSA-AES256-SHA384","ECDH-RSA-AES256-SHA384","DHE-DSS-AES256-GCM-SHA384","DHE-DSS-AES256-SHA256","AES256-GCM-SHA384","AES256-SHA256","ECDHE-ECDSA-AES128-GCM-SHA256","ECDHE-RSA-AES128-GCM-SHA256","ECDHE-ECDSA-AES128-SHA256","ECDHE-RSA-AES128-SHA256","ECDH-ECDSA-AES128-GCM-SHA256","ECDH-RSA-AES128-GCM-SHA256","ECDH-ECDSA-AES128-SHA256","ECDH-RSA-AES128-SHA256","DHE-DSS-AES128-GCM-SHA256","DHE-DSS-AES128-SHA256","AES128-GCM-SHA256","AES128-SHA256","ECDHE-ECDSA-AES256-SHA","ECDHE-RSA-AES256-SHA","DHE-DSS-AES256-SHA","ECDH-ECDSA-AES256-SHA","ECDH-RSA-AES256-SHA","AES256-SHA","ECDHE-ECDSA-AES128-SHA","ECDHE-RSA-AES128-SHA","DHE-DSS-AES128-SHA","ECDH-ECDSA-AES128-SHA","ECDH-RSA-AES128-SHA","AES128-SHA"]
|
||||
# }
|
||||
]
|
||||
}
|
||||
|
|
|
@ -20,9 +20,7 @@
|
|||
|
||||
|
||||
-export([ start_listeners/0
|
||||
, stop_listeners/0
|
||||
, start_listener/1
|
||||
, stop_listener/1]).
|
||||
, stop_listeners/0]).
|
||||
|
||||
%% Authorization
|
||||
-export([authorize_appid/1]).
|
||||
|
@ -36,15 +34,8 @@
|
|||
%%--------------------------------------------------------------------
|
||||
|
||||
start_listeners() ->
|
||||
lists:foreach(fun start_listener/1, listeners()).
|
||||
|
||||
stop_listeners() ->
|
||||
lists:foreach(fun stop_listener/1, listeners()).
|
||||
|
||||
start_listener({Proto, Port, Options}) ->
|
||||
{ok, _} = application:ensure_all_started(minirest),
|
||||
Authorization = {?MODULE, authorize_appid},
|
||||
RanchOptions = ranch_opts(Port, Options),
|
||||
GlobalSpec = #{
|
||||
openapi => "3.0.0",
|
||||
info => #{title => "EMQ X Dashboard API", version => "5.0.0"},
|
||||
|
@ -56,20 +47,33 @@ start_listener({Proto, Port, Options}) ->
|
|||
type => apiKey,
|
||||
name => "authorization",
|
||||
in => header}}}},
|
||||
Dispatch = [{"/", cowboy_static, {priv_file, emqx_dashboard, "www/index.html"}},
|
||||
{"/static/[...]", cowboy_static, {priv_dir, emqx_dashboard, "www/static"}},
|
||||
{'_', cowboy_static, {priv_file, emqx_dashboard, "www/index.html"}}],
|
||||
Minirest = #{
|
||||
protocol => Proto,
|
||||
Dispatch = [
|
||||
{"/", cowboy_static, {priv_file, emqx_dashboard, "www/index.html"}},
|
||||
{"/static/[...]", cowboy_static, {priv_dir, emqx_dashboard, "www/static"}},
|
||||
{'_', cowboy_static, {priv_file, emqx_dashboard, "www/index.html"}}
|
||||
],
|
||||
BaseMinirest = #{
|
||||
base_path => ?BASE_PATH,
|
||||
modules => minirest_api:find_api_modules(apps()),
|
||||
authorization => Authorization,
|
||||
security => [#{application => []}],
|
||||
swagger_global_spec => GlobalSpec,
|
||||
dispatch => Dispatch},
|
||||
MinirestOptions = maps:merge(Minirest, RanchOptions),
|
||||
{ok, _} = minirest:start(listener_name(Proto), MinirestOptions),
|
||||
?ULOG("Start ~p listener on ~p successfully.~n", [listener_name(Proto), Port]).
|
||||
dispatch => Dispatch
|
||||
},
|
||||
[begin
|
||||
Minirest = maps:put(protocol, Protocol, BaseMinirest),
|
||||
{ok, _} = minirest:start(Name, RanchOptions, Minirest),
|
||||
?ULOG("Start listener ~s on ~p successfully.~n", [Name, Port])
|
||||
end || {Name, Protocol, Port, RanchOptions} <- listeners()].
|
||||
|
||||
stop_listeners() ->
|
||||
[begin
|
||||
ok = minirest:stop(Name),
|
||||
?ULOG("Stop listener ~s on ~p successfully.~n", [Name, Port])
|
||||
end || {Name, _, Port, _} <- listeners()].
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% internal
|
||||
|
||||
apps() ->
|
||||
[App || {App, _, _} <- application:loaded_applications(),
|
||||
|
@ -78,30 +82,48 @@ apps() ->
|
|||
_ -> false
|
||||
end].
|
||||
|
||||
ranch_opts(Port, Options0) ->
|
||||
Options = lists:foldl(
|
||||
fun
|
||||
({K, _V}, Acc) when K =:= max_connections orelse K =:= num_acceptors -> Acc;
|
||||
({inet6, true}, Acc) -> [inet6 | Acc];
|
||||
({inet6, false}, Acc) -> Acc;
|
||||
({ipv6_v6only, true}, Acc) -> [{ipv6_v6only, true} | Acc];
|
||||
({ipv6_v6only, false}, Acc) -> Acc;
|
||||
({K, V}, Acc)->
|
||||
[{K, V} | Acc]
|
||||
end, [], Options0),
|
||||
maps:from_list([{port, Port} | Options]).
|
||||
|
||||
stop_listener({Proto, Port, _}) ->
|
||||
?ULOG("Stop dashboard listener on ~s successfully.~n", [format(Port)]),
|
||||
minirest:stop(listener_name(Proto)).
|
||||
|
||||
listeners() ->
|
||||
[{Protocol, Port, maps:to_list(maps:without([protocol, port], Map))}
|
||||
|| Map = #{protocol := Protocol,port := Port}
|
||||
<- emqx:get_config([emqx_dashboard, listeners], [])].
|
||||
[begin
|
||||
Protocol = maps:get(protocol, ListenerOptions, http),
|
||||
Port = maps:get(port, ListenerOptions, 18083),
|
||||
Name = listener_name(Protocol, Port),
|
||||
RanchOptions = ranch_opts(maps:without([protocol], ListenerOptions)),
|
||||
{Name, Protocol, Port, RanchOptions}
|
||||
end || ListenerOptions <- emqx_config:get([emqx_dashboard, listeners], [])].
|
||||
|
||||
listener_name(Proto) ->
|
||||
list_to_atom(atom_to_list(Proto) ++ ":dashboard").
|
||||
ranch_opts(RanchOptions) ->
|
||||
Keys = [ {ack_timeout, handshake_timeout}
|
||||
, connection_type
|
||||
, max_connections
|
||||
, num_acceptors
|
||||
, shutdown
|
||||
, socket],
|
||||
{S, R} = lists:foldl(fun key_take/2, {RanchOptions, #{}}, Keys),
|
||||
R#{socket_opts => maps:fold(fun key_only/3, [], S)}.
|
||||
|
||||
|
||||
key_take({K, K1}, {All, R}) ->
|
||||
case maps:get(K, All, undefined) of
|
||||
undefined ->
|
||||
{All, R};
|
||||
V ->
|
||||
{maps:remove(K, All), R#{K1 => V}}
|
||||
end;
|
||||
key_take(K, {All, R}) ->
|
||||
case maps:get(K, All, undefined) of
|
||||
undefined ->
|
||||
{All, R};
|
||||
V ->
|
||||
{maps:remove(K, All), R#{K => V}}
|
||||
end.
|
||||
|
||||
key_only(K , true , S) -> [K | S];
|
||||
key_only(_K, false, S) -> S;
|
||||
key_only(K , V , S) -> [{K, V} | S].
|
||||
|
||||
listener_name(Protocol, Port) ->
|
||||
Name = "dashboard:" ++ atom_to_list(Protocol) ++ ":" ++ integer_to_list(Port),
|
||||
list_to_atom(Name).
|
||||
|
||||
authorize_appid(Req) ->
|
||||
case cowboy_req:parse_header(<<"authorization">>, Req) of
|
||||
|
@ -127,10 +149,3 @@ authorize_appid(Req) ->
|
|||
#{code => <<"UNAUTHORIZED">>,
|
||||
message => <<"POST '/login'">>}}
|
||||
end.
|
||||
|
||||
format(Port) when is_integer(Port) ->
|
||||
io_lib:format("0.0.0.0:~w", [Port]);
|
||||
format({Addr, Port}) when is_list(Addr) ->
|
||||
io_lib:format("~s:~w", [Addr, Port]);
|
||||
format({Addr, Port}) when is_tuple(Addr) ->
|
||||
io_lib:format("~s:~w", [inet:ntoa(Addr), Port]).
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
start(_StartType, _StartArgs) ->
|
||||
{ok, Sup} = emqx_dashboard_sup:start_link(),
|
||||
ok = ekka_rlog:wait_for_shards([?DASHBOARD_SHARD], infinity),
|
||||
emqx_dashboard:start_listeners(),
|
||||
_ = emqx_dashboard:start_listeners(),
|
||||
emqx_dashboard_cli:load(),
|
||||
ok = emqx_dashboard_admin:add_default_user(),
|
||||
{ok, Sup}.
|
||||
|
|
|
@ -37,14 +37,13 @@ fields("http") ->
|
|||
, {"num_acceptors", emqx_schema:t(integer(), undefined, 4)}
|
||||
, {"max_connections", emqx_schema:t(integer(), undefined, 512)}
|
||||
, {"backlog", emqx_schema:t(integer(), undefined, 1024)}
|
||||
, {"send_timeout", emqx_schema:t(emqx_schema:duration(), undefined, "15s")}
|
||||
, {"send_timeout_close", emqx_schema:t(boolean(), undefined, true)}
|
||||
, {"send_timeout", emqx_schema:t(emqx_schema:duration(), undefined, "5s")}
|
||||
, {"inet6", emqx_schema:t(boolean(), undefined, false)}
|
||||
, {"ipv6_v6only", emqx_schema:t(boolean(), undefined, false)}
|
||||
];
|
||||
|
||||
fields("https") ->
|
||||
emqx_schema:ssl(#{enable => true}) ++ fields("http").
|
||||
proplists:delete("fail_if_no_peer_cert", emqx_schema:ssl(#{})) ++ fields("http").
|
||||
|
||||
default_username(type) -> string();
|
||||
default_username(default) -> "admin";
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
, {esockd, {git, "https://github.com/emqx/esockd", {tag, "5.8.2"}}}
|
||||
, {ekka, {git, "https://github.com/emqx/ekka", {tag, "0.10.8"}}}
|
||||
, {gen_rpc, {git, "https://github.com/emqx/gen_rpc", {tag, "2.5.1"}}}
|
||||
, {minirest, {git, "https://github.com/emqx/minirest", {tag, "1.2.0"}}}
|
||||
, {minirest, {git, "https://github.com/emqx/minirest", {tag, "1.2.1"}}}
|
||||
, {ecpool, {git, "https://github.com/emqx/ecpool", {tag, "0.5.1"}}}
|
||||
, {replayq, "0.3.3"}
|
||||
, {pbkdf2, {git, "https://github.com/emqx/erlang-pbkdf2.git", {tag, "2.0.4"}}}
|
||||
|
|
Loading…
Reference in New Issue