fix(emqx_gateway_api): don't crash on unknown status

This commit is contained in:
Stefan Strigler 2022-10-25 16:24:20 +02:00
parent dc3c0094f0
commit ef5687d465
8 changed files with 66 additions and 14 deletions

View File

@ -2,7 +2,7 @@
{application, emqx_dashboard, [ {application, emqx_dashboard, [
{description, "EMQX Web Dashboard"}, {description, "EMQX Web Dashboard"},
% strict semver, bump manually! % strict semver, bump manually!
{vsn, "5.0.6"}, {vsn, "5.0.7"},
{modules, []}, {modules, []},
{registered, [emqx_dashboard_sup]}, {registered, [emqx_dashboard_sup]},
{applications, [kernel, stdlib, mnesia, minirest, emqx]}, {applications, [kernel, stdlib, mnesia, minirest, emqx]},

View File

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

View File

@ -6,7 +6,7 @@
-export([paths/0, api_spec/0, schema/1, fields/1]). -export([paths/0, api_spec/0, schema/1, fields/1]).
-export([init_per_suite/1, end_per_suite/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_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/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([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]). -export([all/0, suite/0, groups/0]).
@ -30,6 +30,7 @@ groups() ->
t_in_mix, t_in_mix,
t_without_in, t_without_in,
t_require, t_require,
t_query_enum,
t_nullable, t_nullable,
t_method, t_method,
t_public_ref t_public_ref
@ -226,6 +227,17 @@ t_require(_Config) ->
validate("/required/false", ExpectSpec), validate("/required/false", ExpectSpec),
ok. 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) -> t_nullable(_Config) ->
NullableFalse = [ NullableFalse = [
#{ #{
@ -528,6 +540,8 @@ schema("/test/without/in") ->
}; };
schema("/required/false") -> schema("/required/false") ->
to_schema([{'userid', mk(binary(), #{in => query, 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") -> schema("/nullable/false") ->
to_schema([{'userid', mk(binary(), #{in => query, required => true})}]); to_schema([{'userid', mk(binary(), #{in => query, required => true})}]);
schema("/nullable/true") -> schema("/nullable/true") ->

View File

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

View File

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

View File

@ -62,8 +62,16 @@ end_per_suite(Conf) ->
t_gateway(_) -> t_gateway(_) ->
{200, Gateways} = request(get, "/gateways"), {200, Gateways} = request(get, "/gateways"),
lists:foreach(fun assert_gw_unloaded/1, Gateways), lists:foreach(fun assert_gw_unloaded/1, Gateways),
{400, BadReq} = request(get, "/gateways/uname_gateway"), {200, UnloadedGateways} = request(get, "/gateways?status=unloaded"),
assert_bad_request(BadReq), 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">>}), {201, _} = request(post, "/gateways", #{name => <<"stomp">>}),
{200, StompGw1} = request(get, "/gateways/stomp"), {200, StompGw1} = request(get, "/gateways/stomp"),
assert_feilds_apperence( assert_feilds_apperence(

View File

@ -11,3 +11,5 @@
## Bug fixes ## Bug fixes
- Fix error log message when `mechanism` is missing in authentication config [#8924](https://github.com/emqx/emqx/pull/8924). - 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 [#7794](https://github.com/emqx/emqx/pull/9225).

View File

@ -11,3 +11,5 @@
## Bug fixes ## Bug fixes
- 优化认认证配置中 `mechanism` 字段缺失情况下的错误日志 [#8924](https://github.com/emqx/emqx/pull/8924)。 - 优化认认证配置中 `mechanism` 字段缺失情况下的错误日志 [#8924](https://github.com/emqx/emqx/pull/8924)。
- 修复未知 `status` 参数导致 `/gateway` API 发生 HTTP 500 错误的问题 [#7794](https://github.com/emqx/emqx/pull/9225) [#7794](https://github.com/emqx/emqx/pull/9225).