fix(mgmt): avoid 500 error when hocon syntax error

This commit is contained in:
zmstone 2024-04-27 21:02:09 +02:00
parent a3320ab51b
commit 5f4215b333
3 changed files with 36 additions and 18 deletions

View File

@ -32,7 +32,7 @@
-export([format/2]). -export([format/2]).
%% For CLI HTTP API outputs %% For CLI HTTP API outputs
-export([best_effort_json/1, best_effort_json/2]). -export([best_effort_json/1, best_effort_json/2, best_effort_json_obj/1]).
-ifdef(TEST). -ifdef(TEST).
-include_lib("proper/include/proper.hrl"). -include_lib("proper/include/proper.hrl").
@ -65,10 +65,13 @@
best_effort_json(Input) -> best_effort_json(Input) ->
best_effort_json(Input, [pretty, force_utf8]). best_effort_json(Input, [pretty, force_utf8]).
best_effort_json(Input, Opts) -> best_effort_json(Input, Opts) ->
Config = #{depth => unlimited, single_line => true, chars_limit => unlimited}, JsonReady = best_effort_json_obj(Input),
JsonReady = best_effort_json_obj(Input, Config),
emqx_utils_json:encode(JsonReady, Opts). emqx_utils_json:encode(JsonReady, Opts).
best_effort_json_obj(Input) ->
Config = #{depth => unlimited, single_line => true, chars_limit => unlimited},
best_effort_json_obj(Input, Config).
-spec format(logger:log_event(), config()) -> iodata(). -spec format(logger:log_event(), config()) -> iodata().
format(#{level := Level, msg := Msg, meta := Meta}, Config0) when is_map(Config0) -> format(#{level := Level, msg := Msg, meta := Meta}, Config0) when is_map(Config0) ->
Config = add_default_config(Config0), Config = add_default_config(Config0),

View File

@ -366,11 +366,8 @@ configs(put, #{body := Conf, query_string := #{<<"mode">> := Mode}}, _Req) ->
ok -> ok ->
{200}; {200};
%% bad hocon format %% bad hocon format
{error, MsgList = [{_, _} | _]} -> {error, Errors} ->
JsonFun = fun(K, V) -> {K, emqx_utils_maps:binary_string(V)} end, Msg = emqx_logger_jsonfmt:best_effort_json_obj(#{errors => Errors}),
JsonMap = emqx_utils_maps:jsonable_map(maps:from_list(MsgList), JsonFun),
{400, #{<<"content-type">> => <<"text/plain">>}, JsonMap};
{error, Msg} ->
{400, #{<<"content-type">> => <<"text/plain">>}, Msg} {400, #{<<"content-type">> => <<"text/plain">>}, Msg}
end. end.

View File

@ -336,13 +336,15 @@ t_configs_key(_Config) ->
BadLog = emqx_utils_maps:deep_put([<<"log">>, <<"console">>, <<"level">>], Log, <<"erro1r">>), BadLog = emqx_utils_maps:deep_put([<<"log">>, <<"console">>, <<"level">>], Log, <<"erro1r">>),
{error, Error} = update_configs_with_binary(iolist_to_binary(hocon_pp:do(BadLog, #{}))), {error, Error} = update_configs_with_binary(iolist_to_binary(hocon_pp:do(BadLog, #{}))),
ExpectError = #{ ExpectError = #{
<<"log">> => <<"errors">> => #{
#{ <<"log">> =>
<<"kind">> => <<"validation_error">>, #{
<<"path">> => <<"log.console.level">>, <<"kind">> => <<"validation_error">>,
<<"reason">> => <<"unable_to_convert_to_enum_symbol">>, <<"path">> => <<"log.console.level">>,
<<"value">> => <<"erro1r">> <<"reason">> => <<"unable_to_convert_to_enum_symbol">>,
} <<"value">> => <<"erro1r">>
}
}
}, },
?assertEqual(ExpectError, emqx_utils_json:decode(Error, [return_maps])), ?assertEqual(ExpectError, emqx_utils_json:decode(Error, [return_maps])),
ReadOnlyConf = #{ ReadOnlyConf = #{
@ -355,7 +357,7 @@ t_configs_key(_Config) ->
}, },
ReadOnlyBin = iolist_to_binary(hocon_pp:do(ReadOnlyConf, #{})), ReadOnlyBin = iolist_to_binary(hocon_pp:do(ReadOnlyConf, #{})),
{error, ReadOnlyError} = update_configs_with_binary(ReadOnlyBin), {error, ReadOnlyError} = update_configs_with_binary(ReadOnlyBin),
?assertEqual(<<"Cannot update read-only key 'cluster'.">>, ReadOnlyError), ?assertEqual(<<"{\"errors\":\"Cannot update read-only key 'cluster'.\"}">>, ReadOnlyError),
ok. ok.
t_get_configs_in_different_accept(_Config) -> t_get_configs_in_different_accept(_Config) ->
@ -487,6 +489,22 @@ t_create_webhook_v1_bridges_api(Config) ->
?assertEqual(#{<<"webhook">> => #{}}, emqx_conf:get_raw([<<"bridges">>])), ?assertEqual(#{<<"webhook">> => #{}}, emqx_conf:get_raw([<<"bridges">>])),
ok. ok.
t_config_update_parse_error(_Config) ->
?assertMatch(
{error, <<"{\"errors\":\"{parse_error,", _/binary>>},
update_configs_with_binary(<<"not an object">>)
),
?assertMatch(
{error, <<"{\"errors\":\"{parse_error,", _/binary>>},
update_configs_with_binary(<<"a = \"tlsv1\"\"\"3e-01">>)
).
t_config_update_unknown_root(_Config) ->
?assertMatch(
{error, <<"{\"errors\":{\"a\":\"{root_key_not_found,", _/binary>>},
update_configs_with_binary(<<"a = \"tlsv1.3\"">>)
).
%% Helpers %% Helpers
get_config(Name) -> get_config(Name) ->
@ -547,10 +565,10 @@ update_configs_with_binary(Bin) ->
Code >= 200 andalso Code =< 299 Code >= 200 andalso Code =< 299
-> ->
Body; Body;
{ok, {{"HTTP/1.1", _Code, _}, _Headers, Body}} -> {ok, {{"HTTP/1.1", 400, _}, _Headers, Body}} ->
{error, Body}; {error, Body};
Error -> Error ->
Error error({unexpected, Error})
end. end.
update_config(Name, Change) -> update_config(Name, Change) ->