Merge pull request #7279 from zhongwencool/hot-conf-global-zone
feat: Hot conf global zone
This commit is contained in:
commit
59b10fc80b
|
@ -38,9 +38,7 @@
|
|||
-type bar_separated_list() :: list().
|
||||
-type ip_port() :: tuple().
|
||||
-type cipher() :: map().
|
||||
-type qos() :: integer().
|
||||
|
||||
-typerefl_from_string({qos/0, emqx_schema, to_qos}).
|
||||
-typerefl_from_string({duration/0, emqx_schema, to_duration}).
|
||||
-typerefl_from_string({duration_s/0, emqx_schema, to_duration_s}).
|
||||
-typerefl_from_string({duration_ms/0, emqx_schema, to_duration_ms}).
|
||||
|
@ -59,12 +57,14 @@
|
|||
, validations/0
|
||||
]).
|
||||
|
||||
-export([ qos/0]).
|
||||
|
||||
% workaround: prevent being recognized as unused functions
|
||||
-export([to_duration/1, to_duration_s/1, to_duration_ms/1,
|
||||
mk_duration/2, to_bytesize/1, to_wordsize/1,
|
||||
to_percent/1, to_comma_separated_list/1,
|
||||
to_bar_separated_list/1, to_ip_port/1,
|
||||
to_erl_cipher_suite/1, to_qos/1,
|
||||
to_erl_cipher_suite/1,
|
||||
to_comma_separated_atoms/1
|
||||
]).
|
||||
|
||||
|
@ -73,7 +73,7 @@
|
|||
-reflect_type([ duration/0, duration_s/0, duration_ms/0,
|
||||
bytesize/0, wordsize/0, percent/0, file/0,
|
||||
comma_separated_list/0, bar_separated_list/0, ip_port/0,
|
||||
cipher/0, qos/0,
|
||||
cipher/0,
|
||||
comma_separated_atoms/0
|
||||
]).
|
||||
|
||||
|
@ -1558,12 +1558,6 @@ to_comma_separated_atoms(Str) ->
|
|||
to_bar_separated_list(Str) ->
|
||||
{ok, string:tokens(Str, "| ")}.
|
||||
|
||||
to_qos(Str) ->
|
||||
case string:to_integer(Str) of
|
||||
{Num, []} when Num >= 0 andalso Num =< 2 -> {ok, Num};
|
||||
_ -> {error, Str}
|
||||
end.
|
||||
|
||||
to_ip_port(Str) ->
|
||||
case string:tokens(Str, ": ") of
|
||||
[Ip, Port] ->
|
||||
|
@ -1688,3 +1682,7 @@ When authenticating a login (username, client ID, etc.) the authenticators are c
|
|||
in the configured order.<br>
|
||||
"""])
|
||||
}.
|
||||
|
||||
-spec qos() -> typerefl:type().
|
||||
qos() ->
|
||||
typerefl:alias("qos", typerefl:union([0, 1, 2])).
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
namespace() -> zone.
|
||||
|
||||
%% this shcema module is not used at root level.
|
||||
%% this schema module is not used at root level.
|
||||
%% roots are added only for document generation.
|
||||
roots() -> ["mqtt", "stats", "flapping_detect", "force_shutdown",
|
||||
"conn_congestion", "force_gc",
|
||||
|
|
|
@ -17,12 +17,17 @@
|
|||
-module(emqx_mgmt_api_configs).
|
||||
|
||||
-include_lib("hocon/include/hoconsc.hrl").
|
||||
-include_lib("emqx/include/logger.hrl").
|
||||
-behaviour(minirest_api).
|
||||
|
||||
-export([api_spec/0, namespace/0]).
|
||||
-export([paths/0, schema/1, fields/1]).
|
||||
|
||||
-export([config/3, config_reset/3, configs/3, get_full_config/0]).
|
||||
-export([ config/3
|
||||
, config_reset/3
|
||||
, configs/3
|
||||
, get_full_config/0
|
||||
, global_zone_configs/3]).
|
||||
|
||||
-export([gen_schema/1]).
|
||||
|
||||
|
@ -51,7 +56,8 @@
|
|||
<<"event_message">>,
|
||||
<<"prometheus">>,
|
||||
<<"telemetry">>
|
||||
]).
|
||||
] ++ global_zone_roots()
|
||||
).
|
||||
|
||||
api_spec() ->
|
||||
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}).
|
||||
|
@ -59,7 +65,7 @@ api_spec() ->
|
|||
namespace() -> "configuration".
|
||||
|
||||
paths() ->
|
||||
["/configs", "/configs_reset/:rootname"] ++
|
||||
["/configs", "/configs_reset/:rootname", "/configs/global_zone"] ++
|
||||
lists:map(fun({Name, _Type}) -> ?PREFIX ++ binary_to_list(Name) end, config_list()).
|
||||
|
||||
schema("/configs") ->
|
||||
|
@ -104,6 +110,25 @@ schema("/configs_reset/:rootname") ->
|
|||
}
|
||||
}
|
||||
};
|
||||
schema("/configs/global_zone") ->
|
||||
Schema = global_zone_schema(),
|
||||
#{
|
||||
'operationId' => global_zone_configs,
|
||||
get => #{
|
||||
tags => [conf],
|
||||
description => <<"Get the global zone configs">>,
|
||||
responses => #{200 => Schema}
|
||||
},
|
||||
put => #{
|
||||
tags => [conf],
|
||||
description => <<"Update globbal zone configs">>,
|
||||
'requestBody' => Schema,
|
||||
responses => #{
|
||||
200 => Schema,
|
||||
400 => emqx_dashboard_swagger:error_codes(['UPDATE_FAILED'])
|
||||
}
|
||||
}
|
||||
};
|
||||
schema(Path) ->
|
||||
{RootKey, {_Root, Schema}} = find_schema(Path),
|
||||
#{
|
||||
|
@ -159,6 +184,28 @@ config(put, #{body := Body}, Req) ->
|
|||
{400, #{code => 'UPDATE_FAILED', message => ?ERR_MSG(Reason)}}
|
||||
end.
|
||||
|
||||
global_zone_configs(get, _Params, _Req) ->
|
||||
Paths = global_zone_roots(),
|
||||
Zones = lists:foldl(fun(Path, Acc) -> Acc#{Path => get_config_with_default([Path])} end,
|
||||
#{}, Paths),
|
||||
{200, Zones};
|
||||
global_zone_configs(put, #{body := Body}, _Req) ->
|
||||
Res =
|
||||
maps:fold(fun(Path, Value, Acc) ->
|
||||
case emqx:update_config([Path], Value, #{rawconf_with_defaults => true}) of
|
||||
{ok, #{raw_config := RawConf}} ->
|
||||
Acc#{Path => RawConf};
|
||||
{error, Reason} ->
|
||||
?SLOG(error, #{msg => "update global zone failed", reason => Reason,
|
||||
path => Path, value => Value}),
|
||||
Acc
|
||||
end
|
||||
end, #{}, Body),
|
||||
case maps:size(Res) =:= maps:size(Body) of
|
||||
true -> {200, Res};
|
||||
false -> {400, #{code => 'UPDATE_FAILED'}}
|
||||
end.
|
||||
|
||||
config_reset(post, _Params, Req) ->
|
||||
%% reset the config specified by the query string param 'conf_path'
|
||||
Path = conf_path_reset(Req) ++ conf_path_from_querystr(Req),
|
||||
|
@ -196,6 +243,9 @@ get_full_config() ->
|
|||
maps:without(?EXCLUDES,
|
||||
emqx:get_raw_config([]))).
|
||||
|
||||
get_config_with_default(Path) ->
|
||||
emqx_config:fill_defaults(emqx:get_raw_config(Path)).
|
||||
|
||||
conf_path_from_querystr(Req) ->
|
||||
case proplists:get_value(<<"conf_path">>, cowboy_req:parse_qs(Req)) of
|
||||
undefined -> [];
|
||||
|
@ -235,3 +285,10 @@ gen_schema(_Conf) ->
|
|||
|
||||
with_default_value(Type, Value) ->
|
||||
Type#{example => emqx_map_lib:binary_string(Value)}.
|
||||
|
||||
global_zone_roots() ->
|
||||
lists:map(fun({K, _}) -> K end, global_zone_schema()).
|
||||
|
||||
global_zone_schema() ->
|
||||
Roots = hocon_schema:roots(emqx_zone_schema),
|
||||
lists:map(fun({RootKey, {_Root, Schema}}) -> {RootKey, Schema} end, Roots).
|
||||
|
|
|
@ -68,6 +68,35 @@ t_update(_Config) ->
|
|||
?assertMatch(#{<<"vm">> := #{<<"busy_port">> := false}}, SysMon4),
|
||||
ok.
|
||||
|
||||
t_zones(_Config) ->
|
||||
{ok, Zones} = get_zones(),
|
||||
ZonesKeys = lists:map(fun({K, _}) -> K end, hocon_schema:roots(emqx_zone_schema)),
|
||||
?assertEqual(lists:usort(ZonesKeys), lists:usort(maps:keys(Zones))),
|
||||
?assertEqual(emqx_config:get_zone_conf(no_default, [mqtt, max_qos_allowed]),
|
||||
emqx_map_lib:deep_get([<<"mqtt">>, <<"max_qos_allowed">>], Zones)),
|
||||
NewZones = emqx_map_lib:deep_put([<<"mqtt">>, <<"max_qos_allowed">>], Zones, 1),
|
||||
{ok, #{}} = update_zones(NewZones),
|
||||
?assertEqual(1, emqx_config:get_zone_conf(no_default, [mqtt, max_qos_allowed])),
|
||||
|
||||
BadZones = emqx_map_lib:deep_put([<<"mqtt">>, <<"max_qos_allowed">>], Zones, 3),
|
||||
?assertMatch({error, {"HTTP/1.1", 400, _}}, update_zones(BadZones)),
|
||||
ok.
|
||||
|
||||
get_zones() ->
|
||||
Path = emqx_mgmt_api_test_util:api_path(["configs", "global_zone"]),
|
||||
case emqx_mgmt_api_test_util:request_api(get, Path) of
|
||||
{ok, Res} -> {ok, emqx_json:decode(Res, [return_maps])};
|
||||
Error -> Error
|
||||
end.
|
||||
|
||||
update_zones(Change) ->
|
||||
AuthHeader = emqx_mgmt_api_test_util:auth_header_(),
|
||||
UpdatePath = emqx_mgmt_api_test_util:api_path(["configs", "global_zone"]),
|
||||
case emqx_mgmt_api_test_util:request_api(put, UpdatePath, "", AuthHeader, Change) of
|
||||
{ok, Update} -> {ok, emqx_json:decode(Update, [return_maps])};
|
||||
Error -> Error
|
||||
end.
|
||||
|
||||
get_config(Name) ->
|
||||
Path = emqx_mgmt_api_test_util:api_path(["configs", Name]),
|
||||
case emqx_mgmt_api_test_util:request_api(get, Path) of
|
||||
|
|
Loading…
Reference in New Issue