Merge pull request #9258 from sstrigler/master

Re-UP fix(emqx_gateway_api): don't crash on unknown status
This commit is contained in:
Zaiming (Stone) Shi 2022-10-28 22:18:10 +02:00 committed by GitHub
commit a0cd344752
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 65 additions and 13 deletions

View File

@ -367,11 +367,13 @@ parameters(Params, Module) ->
Required = hocon_schema:field_schema(Type, required),
Default = hocon_schema:field_schema(Type, default),
HoconType = hocon_schema:field_schema(Type, type),
SchemaExtras = hocon_extract_map([enum, default], Type),
Meta = init_meta(Default),
{ParamType, Refs} = hocon_schema_to_spec(HoconType, Module),
Schema = maps:merge(maps:merge(ParamType, Meta), SchemaExtras),
Spec0 = init_prop(
[required | ?DEFAULT_FIELDS],
#{schema => maps:merge(ParamType, Meta), name => Name, in => In},
#{schema => Schema, name => Name, in => In},
Type
),
Spec1 = trans_required(Spec0, Required, In),
@ -384,6 +386,18 @@ parameters(Params, Module) ->
),
{lists:reverse(SpecList), AllRefs}.
hocon_extract_map(Keys, Type) ->
lists:foldl(
fun(K, M) ->
case hocon_schema:field_schema(Type, K) of
undefined -> M;
V -> M#{K => V}
end
end,
#{},
Keys
).
init_meta(undefined) -> #{};
init_meta(Default) -> #{default => Default}.

View File

@ -6,7 +6,7 @@
-export([paths/0, api_spec/0, schema/1, fields/1]).
-export([init_per_suite/1, end_per_suite/1]).
-export([t_in_path/1, t_in_query/1, t_in_mix/1, t_without_in/1, t_ref/1, t_public_ref/1]).
-export([t_require/1, t_nullable/1, t_method/1, t_api_spec/1]).
-export([t_require/1, t_query_enum/1, t_nullable/1, t_method/1, t_api_spec/1]).
-export([t_in_path_trans/1, t_in_query_trans/1, t_in_mix_trans/1, t_ref_trans/1]).
-export([t_in_path_trans_error/1, t_in_query_trans_error/1, t_in_mix_trans_error/1]).
-export([all/0, suite/0, groups/0]).
@ -30,6 +30,7 @@ groups() ->
t_in_mix,
t_without_in,
t_require,
t_query_enum,
t_nullable,
t_method,
t_public_ref
@ -226,6 +227,17 @@ t_require(_Config) ->
validate("/required/false", ExpectSpec),
ok.
t_query_enum(_Config) ->
ExpectSpec = [
#{
in => query,
name => userid,
schema => #{type => string, enum => [<<"a">>], default => <<"a">>}
}
],
validate("/query/enum", ExpectSpec),
ok.
t_nullable(_Config) ->
NullableFalse = [
#{
@ -528,6 +540,8 @@ schema("/test/without/in") ->
};
schema("/required/false") ->
to_schema([{'userid', mk(binary(), #{in => query, required => false})}]);
schema("/query/enum") ->
to_schema([{'userid', mk(binary(), #{in => query, enum => [<<"a">>], default => <<"a">>})}]);
schema("/nullable/false") ->
to_schema([{'userid', mk(binary(), #{in => query, required => true})}]);
schema("/nullable/true") ->

View File

@ -1,7 +1,7 @@
%% -*- mode: erlang -*-
{application, emqx_gateway, [
{description, "The Gateway management application"},
{vsn, "0.1.6"},
{vsn, "0.1.7"},
{registered, []},
{mod, {emqx_gateway_app, []}},
{applications, [kernel, stdlib, grpc, emqx, emqx_authn]},

View File

@ -53,6 +53,8 @@
gateway_insta/2
]).
-define(KNOWN_GATEWAY_STATUSES, [<<"running">>, <<"stopped">>, <<"unloaded">>]).
%%--------------------------------------------------------------------
%% minirest behaviour callbacks
%%--------------------------------------------------------------------
@ -71,12 +73,22 @@ paths() ->
gateway(get, Request) ->
Params = maps:get(query_string, Request, #{}),
Status =
case maps:get(<<"status">>, Params, undefined) of
undefined -> all;
S0 -> binary_to_existing_atom(S0, utf8)
end,
{200, emqx_gateway_http:gateways(Status)};
Status = maps:get(<<"status">>, Params, <<"all">>),
case lists:member(Status, [<<"all">> | ?KNOWN_GATEWAY_STATUSES]) of
true ->
{200, emqx_gateway_http:gateways(binary_to_existing_atom(Status, utf8))};
false ->
return_http_error(
400,
[
"Unknown gateway status in query: ",
Status,
"\n",
"Values allowed: ",
lists:join(", ", ?KNOWN_GATEWAY_STATUSES)
]
)
end;
gateway(post, Request) ->
Body = maps:get(body, Request, #{}),
try
@ -241,16 +253,16 @@ params_gateway_name_in_path() ->
].
params_gateway_status_in_qs() ->
%% FIXME: enum in swagger ??
[
{status,
mk(
binary(),
#{
in => query,
enum => ?KNOWN_GATEWAY_STATUSES,
required => false,
desc => ?DESC(gateway_status_in_qs),
example => <<"">>
example => <<"running">>
}
)}
].

View File

@ -62,8 +62,16 @@ end_per_suite(Conf) ->
t_gateway(_) ->
{200, Gateways} = request(get, "/gateways"),
lists:foreach(fun assert_gw_unloaded/1, Gateways),
{400, BadReq} = request(get, "/gateways/uname_gateway"),
assert_bad_request(BadReq),
{200, UnloadedGateways} = request(get, "/gateways?status=unloaded"),
lists:foreach(fun assert_gw_unloaded/1, UnloadedGateways),
{200, NoRunningGateways} = request(get, "/gateways?status=running"),
?assertEqual([], NoRunningGateways),
{400, BadReqUnknownGw} = request(get, "/gateways/unknown_gateway"),
assert_bad_request(BadReqUnknownGw),
{400, BadReqInvalidStatus} = request(get, "/gateways?status=invalid_status"),
assert_bad_request(BadReqInvalidStatus),
{400, BadReqUCStatus} = request(get, "/gateways?status=UNLOADED"),
assert_bad_request(BadReqUCStatus),
{201, _} = request(post, "/gateways", #{name => <<"stomp">>}),
{200, StompGw1} = request(get, "/gateways/stomp"),
assert_feilds_apperence(

View File

@ -20,6 +20,8 @@
- Fix error log message when `mechanism` is missing in authentication config [#8924](https://github.com/emqx/emqx/pull/8924).
- Fix HTTP 500 issue when unknown `status` parameter is used in `/gateway` API call [#9225](https://github.com/emqx/emqx/pull/9225).
- Fixed the HTTP response status code for the `/status` endpoint [#9211](https://github.com/emqx/emqx/pull/9211).
Before the fix, it always returned `200` even if the EMQX application was not running. Now it returns `503` in that case.

View File

@ -19,6 +19,8 @@
- 优化认认证配置中 `mechanism` 字段缺失情况下的错误日志 [#8924](https://github.com/emqx/emqx/pull/8924)。
- 修复未知 `status` 参数导致 `/gateway` API 发生 HTTP 500 错误的问题 [#9225](https://github.com/emqx/emqx/pull/9225)。
- 修正了 `/status` 端点的响应状态代码 [#9211](https://github.com/emqx/emqx/pull/9211)。
在此修复前,它总是返回 HTTP 状态码 `200`,即使 EMQX 没有完成启动或正在重启。 现在它在这些情况下会返回状态码 `503`