parent
473a3c0b35
commit
c4e279bb76
|
@ -11,35 +11,30 @@ emqx_dashboard {
|
||||||
token_expired_time = 60m
|
token_expired_time = 60m
|
||||||
listeners = [
|
listeners = [
|
||||||
{
|
{
|
||||||
|
protocol = http
|
||||||
num_acceptors = 4
|
num_acceptors = 4
|
||||||
max_connections = 512
|
max_connections = 512
|
||||||
protocol = http
|
|
||||||
port = 18083
|
port = 18083
|
||||||
backlog = 512
|
backlog = 512
|
||||||
send_timeout = 15s
|
send_timeout = 5s
|
||||||
send_timeout_close = true
|
|
||||||
inet6 = false
|
inet6 = false
|
||||||
ipv6_v6only = false
|
ipv6_v6only = false
|
||||||
}
|
}
|
||||||
## ,
|
# ,
|
||||||
## {
|
# {
|
||||||
## protocol: https
|
# protocol = https
|
||||||
## port: 18084
|
# port = 18084
|
||||||
## acceptors: 2
|
# num_acceptors = 2
|
||||||
## backlog: 512
|
# backlog = 512
|
||||||
## send_timeout: 15s
|
# send_timeout = 5s
|
||||||
## send_timeout_close: true
|
# inet6 = false
|
||||||
## inet6: false
|
# ipv6_v6only = false
|
||||||
## ipv6_v6only: false
|
# certfile = "etc/certs/cert.pem"
|
||||||
## certfile = "etc/certs/cert.pem"
|
# keyfile = "etc/certs/key.pem"
|
||||||
## keyfile = "etc/certs/key.pem"
|
# cacertfile = "etc/certs/cacert.pem"
|
||||||
## cacertfile = "etc/certs/cacert.pem"
|
# verify = verify_peer
|
||||||
## verify = verify_peer
|
# versions = ["tlsv1.3","tlsv1.2","tlsv1.1","tlsv1"]
|
||||||
## 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"]
|
||||||
## 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
|
|
||||||
## }
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,7 @@
|
||||||
|
|
||||||
|
|
||||||
-export([ start_listeners/0
|
-export([ start_listeners/0
|
||||||
, stop_listeners/0
|
, stop_listeners/0]).
|
||||||
, start_listener/1
|
|
||||||
, stop_listener/1]).
|
|
||||||
|
|
||||||
%% Authorization
|
%% Authorization
|
||||||
-export([authorize_appid/1]).
|
-export([authorize_appid/1]).
|
||||||
|
@ -36,15 +34,8 @@
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
start_listeners() ->
|
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),
|
{ok, _} = application:ensure_all_started(minirest),
|
||||||
Authorization = {?MODULE, authorize_appid},
|
Authorization = {?MODULE, authorize_appid},
|
||||||
RanchOptions = ranch_opts(Port, Options),
|
|
||||||
GlobalSpec = #{
|
GlobalSpec = #{
|
||||||
openapi => "3.0.0",
|
openapi => "3.0.0",
|
||||||
info => #{title => "EMQ X Dashboard API", version => "5.0.0"},
|
info => #{title => "EMQ X Dashboard API", version => "5.0.0"},
|
||||||
|
@ -56,20 +47,33 @@ start_listener({Proto, Port, Options}) ->
|
||||||
type => apiKey,
|
type => apiKey,
|
||||||
name => "authorization",
|
name => "authorization",
|
||||||
in => header}}}},
|
in => header}}}},
|
||||||
Dispatch = [{"/", cowboy_static, {priv_file, emqx_dashboard, "www/index.html"}},
|
Dispatch = [
|
||||||
|
{"/", cowboy_static, {priv_file, emqx_dashboard, "www/index.html"}},
|
||||||
{"/static/[...]", cowboy_static, {priv_dir, emqx_dashboard, "www/static"}},
|
{"/static/[...]", cowboy_static, {priv_dir, emqx_dashboard, "www/static"}},
|
||||||
{'_', cowboy_static, {priv_file, emqx_dashboard, "www/index.html"}}],
|
{'_', cowboy_static, {priv_file, emqx_dashboard, "www/index.html"}}
|
||||||
Minirest = #{
|
],
|
||||||
protocol => Proto,
|
BaseMinirest = #{
|
||||||
base_path => ?BASE_PATH,
|
base_path => ?BASE_PATH,
|
||||||
modules => minirest_api:find_api_modules(apps()),
|
modules => minirest_api:find_api_modules(apps()),
|
||||||
authorization => Authorization,
|
authorization => Authorization,
|
||||||
security => [#{application => []}],
|
security => [#{application => []}],
|
||||||
swagger_global_spec => GlobalSpec,
|
swagger_global_spec => GlobalSpec,
|
||||||
dispatch => Dispatch},
|
dispatch => Dispatch
|
||||||
MinirestOptions = maps:merge(Minirest, RanchOptions),
|
},
|
||||||
{ok, _} = minirest:start(listener_name(Proto), MinirestOptions),
|
[begin
|
||||||
?ULOG("Start ~p listener on ~p successfully.~n", [listener_name(Proto), Port]).
|
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() ->
|
apps() ->
|
||||||
[App || {App, _, _} <- application:loaded_applications(),
|
[App || {App, _, _} <- application:loaded_applications(),
|
||||||
|
@ -78,30 +82,48 @@ apps() ->
|
||||||
_ -> false
|
_ -> false
|
||||||
end].
|
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() ->
|
listeners() ->
|
||||||
[{Protocol, Port, maps:to_list(maps:without([protocol, port], Map))}
|
[begin
|
||||||
|| Map = #{protocol := Protocol,port := Port}
|
Protocol = maps:get(protocol, ListenerOptions, http),
|
||||||
<- emqx:get_config([emqx_dashboard, listeners], [])].
|
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) ->
|
ranch_opts(RanchOptions) ->
|
||||||
list_to_atom(atom_to_list(Proto) ++ ":dashboard").
|
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) ->
|
authorize_appid(Req) ->
|
||||||
case cowboy_req:parse_header(<<"authorization">>, Req) of
|
case cowboy_req:parse_header(<<"authorization">>, Req) of
|
||||||
|
@ -127,10 +149,3 @@ authorize_appid(Req) ->
|
||||||
#{code => <<"UNAUTHORIZED">>,
|
#{code => <<"UNAUTHORIZED">>,
|
||||||
message => <<"POST '/login'">>}}
|
message => <<"POST '/login'">>}}
|
||||||
end.
|
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) ->
|
start(_StartType, _StartArgs) ->
|
||||||
{ok, Sup} = emqx_dashboard_sup:start_link(),
|
{ok, Sup} = emqx_dashboard_sup:start_link(),
|
||||||
ok = ekka_rlog:wait_for_shards([?DASHBOARD_SHARD], infinity),
|
ok = ekka_rlog:wait_for_shards([?DASHBOARD_SHARD], infinity),
|
||||||
emqx_dashboard:start_listeners(),
|
_ = emqx_dashboard:start_listeners(),
|
||||||
emqx_dashboard_cli:load(),
|
emqx_dashboard_cli:load(),
|
||||||
ok = emqx_dashboard_admin:add_default_user(),
|
ok = emqx_dashboard_admin:add_default_user(),
|
||||||
{ok, Sup}.
|
{ok, Sup}.
|
||||||
|
|
|
@ -37,14 +37,13 @@ fields("http") ->
|
||||||
, {"num_acceptors", emqx_schema:t(integer(), undefined, 4)}
|
, {"num_acceptors", emqx_schema:t(integer(), undefined, 4)}
|
||||||
, {"max_connections", emqx_schema:t(integer(), undefined, 512)}
|
, {"max_connections", emqx_schema:t(integer(), undefined, 512)}
|
||||||
, {"backlog", emqx_schema:t(integer(), undefined, 1024)}
|
, {"backlog", emqx_schema:t(integer(), undefined, 1024)}
|
||||||
, {"send_timeout", emqx_schema:t(emqx_schema:duration(), undefined, "15s")}
|
, {"send_timeout", emqx_schema:t(emqx_schema:duration(), undefined, "5s")}
|
||||||
, {"send_timeout_close", emqx_schema:t(boolean(), undefined, true)}
|
|
||||||
, {"inet6", emqx_schema:t(boolean(), undefined, false)}
|
, {"inet6", emqx_schema:t(boolean(), undefined, false)}
|
||||||
, {"ipv6_v6only", emqx_schema:t(boolean(), undefined, false)}
|
, {"ipv6_v6only", emqx_schema:t(boolean(), undefined, false)}
|
||||||
];
|
];
|
||||||
|
|
||||||
fields("https") ->
|
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(type) -> string();
|
||||||
default_username(default) -> "admin";
|
default_username(default) -> "admin";
|
||||||
|
|
|
@ -51,7 +51,7 @@
|
||||||
, {esockd, {git, "https://github.com/emqx/esockd", {tag, "5.8.2"}}}
|
, {esockd, {git, "https://github.com/emqx/esockd", {tag, "5.8.2"}}}
|
||||||
, {ekka, {git, "https://github.com/emqx/ekka", {tag, "0.10.8"}}}
|
, {ekka, {git, "https://github.com/emqx/ekka", {tag, "0.10.8"}}}
|
||||||
, {gen_rpc, {git, "https://github.com/emqx/gen_rpc", {tag, "2.5.1"}}}
|
, {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"}}}
|
, {ecpool, {git, "https://github.com/emqx/ecpool", {tag, "0.5.1"}}}
|
||||||
, {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