fix(gateway): improve gateway schema modules
1. enhances the gateway name as an enum 2. make the schema more flexible and extensible without some hardcode
This commit is contained in:
parent
5e314d4ef1
commit
30a72f557f
|
@ -93,10 +93,9 @@ gateways(get, Request) ->
|
|||
|
||||
gateway(get, #{bindings := #{name := Name}}) ->
|
||||
try
|
||||
GwName = gw_name(Name),
|
||||
case emqx_gateway:lookup(GwName) of
|
||||
case emqx_gateway:lookup(Name) of
|
||||
undefined ->
|
||||
{200, #{name => GwName, status => unloaded}};
|
||||
{200, #{name => Name, status => unloaded}};
|
||||
Gateway ->
|
||||
GwConf = emqx_gateway_conf:gateway(Name),
|
||||
GwInfo0 = emqx_gateway_utils:unix_ts_to_rfc3339(
|
||||
|
@ -125,15 +124,14 @@ gateway(put, #{
|
|||
}) ->
|
||||
GwConf = maps:without([<<"name">>], GwConf0),
|
||||
try
|
||||
GwName = gw_name(Name),
|
||||
LoadOrUpdateF =
|
||||
case emqx_gateway:lookup(GwName) of
|
||||
case emqx_gateway:lookup(Name) of
|
||||
undefined ->
|
||||
fun emqx_gateway_conf:load_gateway/2;
|
||||
_ ->
|
||||
fun emqx_gateway_conf:update_gateway/2
|
||||
end,
|
||||
case LoadOrUpdateF(GwName, GwConf) of
|
||||
case LoadOrUpdateF(Name, GwConf) of
|
||||
{ok, _} ->
|
||||
{204};
|
||||
{error, Reason} ->
|
||||
|
@ -148,12 +146,11 @@ gateway(put, #{
|
|||
|
||||
gateway_enable(put, #{bindings := #{name := Name, enable := Enable}}) ->
|
||||
try
|
||||
GwName = gw_name(Name),
|
||||
case emqx_gateway:lookup(GwName) of
|
||||
case emqx_gateway:lookup(Name) of
|
||||
undefined ->
|
||||
return_http_error(404, <<"NOT FOUND">>);
|
||||
_Gateway ->
|
||||
{ok, _} = emqx_gateway_conf:update_gateway(GwName, #{<<"enable">> => Enable}),
|
||||
{ok, _} = emqx_gateway_conf:update_gateway(Name, #{<<"enable">> => Enable}),
|
||||
{204}
|
||||
end
|
||||
catch
|
||||
|
@ -161,15 +158,6 @@ gateway_enable(put, #{bindings := #{name := Name, enable := Enable}}) ->
|
|||
return_http_error(404, <<"NOT FOUND">>)
|
||||
end.
|
||||
|
||||
-spec gw_name(binary()) -> stomp | coap | lwm2m | mqttsn | exproto | gbt32960 | no_return().
|
||||
gw_name(<<"stomp">>) -> stomp;
|
||||
gw_name(<<"coap">>) -> coap;
|
||||
gw_name(<<"lwm2m">>) -> lwm2m;
|
||||
gw_name(<<"mqttsn">>) -> mqttsn;
|
||||
gw_name(<<"exproto">>) -> exproto;
|
||||
gw_name(<<"gbt32960">>) -> gbt32960;
|
||||
gw_name(_Else) -> throw(not_found).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Swagger defines
|
||||
%%--------------------------------------------------------------------
|
||||
|
@ -250,7 +238,7 @@ params_gateway_name_in_path() ->
|
|||
[
|
||||
{name,
|
||||
mk(
|
||||
binary(),
|
||||
hoconsc:enum(emqx_gateway_schema:gateway_names()),
|
||||
#{
|
||||
in => path,
|
||||
desc => ?DESC(gateway_name_in_qs),
|
||||
|
@ -450,33 +438,30 @@ fields(gateway_stats) ->
|
|||
[{key, mk(binary(), #{})}].
|
||||
|
||||
schema_load_or_update_gateways_conf() ->
|
||||
Names = emqx_gateway_schema:gateway_names(),
|
||||
emqx_dashboard_swagger:schema_with_examples(
|
||||
hoconsc:union([
|
||||
ref(?MODULE, stomp),
|
||||
ref(?MODULE, mqttsn),
|
||||
ref(?MODULE, coap),
|
||||
ref(?MODULE, lwm2m),
|
||||
ref(?MODULE, exproto),
|
||||
ref(?MODULE, update_stomp),
|
||||
ref(?MODULE, update_mqttsn),
|
||||
ref(?MODULE, update_coap),
|
||||
ref(?MODULE, update_lwm2m),
|
||||
ref(?MODULE, update_exproto),
|
||||
ref(?MODULE, update_gbt32960)
|
||||
]),
|
||||
hoconsc:union(
|
||||
[
|
||||
ref(?MODULE, Name)
|
||||
|| Name <-
|
||||
Names ++
|
||||
[
|
||||
erlang:list_to_existing_atom("update_" ++ erlang:atom_to_list(Name))
|
||||
|| Name <- Names
|
||||
]
|
||||
]
|
||||
),
|
||||
examples_update_gateway_confs()
|
||||
).
|
||||
|
||||
schema_gateways_conf() ->
|
||||
emqx_dashboard_swagger:schema_with_examples(
|
||||
hoconsc:union([
|
||||
ref(?MODULE, stomp),
|
||||
ref(?MODULE, mqttsn),
|
||||
ref(?MODULE, coap),
|
||||
ref(?MODULE, lwm2m),
|
||||
ref(?MODULE, exproto),
|
||||
ref(?MODULE, gbt32960)
|
||||
]),
|
||||
hoconsc:union(
|
||||
[
|
||||
ref(?MODULE, Name)
|
||||
|| Name <- emqx_gateway_schema:gateway_names()
|
||||
]
|
||||
),
|
||||
examples_gateway_confs()
|
||||
).
|
||||
|
||||
|
|
|
@ -327,7 +327,7 @@ params_gateway_name_in_path() ->
|
|||
[
|
||||
{name,
|
||||
mk(
|
||||
binary(),
|
||||
hoconsc:enum(emqx_gateway_schema:gateway_names()),
|
||||
#{
|
||||
in => path,
|
||||
desc => ?DESC(emqx_gateway_api, gateway_name_in_qs),
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
%%--------------------------------------------------------------------
|
||||
|
||||
api_spec() ->
|
||||
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => false}).
|
||||
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true, translate_body => true}).
|
||||
|
||||
paths() ->
|
||||
[
|
||||
|
@ -157,7 +157,7 @@ params_gateway_name_in_path() ->
|
|||
[
|
||||
{name,
|
||||
mk(
|
||||
binary(),
|
||||
hoconsc:enum(emqx_gateway_schema:gateway_names()),
|
||||
#{
|
||||
in => path,
|
||||
desc => ?DESC(emqx_gateway_api, gateway_name_in_qs),
|
||||
|
|
|
@ -700,7 +700,7 @@ params_gateway_name_in_path() ->
|
|||
[
|
||||
{name,
|
||||
mk(
|
||||
binary(),
|
||||
hoconsc:enum(emqx_gateway_schema:gateway_names()),
|
||||
#{
|
||||
in => path,
|
||||
desc => ?DESC(emqx_gateway_api, gateway_name)
|
||||
|
|
|
@ -609,7 +609,7 @@ params_gateway_name_in_path() ->
|
|||
[
|
||||
{name,
|
||||
mk(
|
||||
binary(),
|
||||
hoconsc:enum(emqx_gateway_schema:gateway_names()),
|
||||
#{
|
||||
in => path,
|
||||
desc => ?DESC(emqx_gateway_api, gateway_name_in_qs),
|
||||
|
|
|
@ -513,29 +513,23 @@ codestr(501) -> 'NOT_IMPLEMENTED'.
|
|||
fmtstr(Fmt, Args) ->
|
||||
lists:flatten(io_lib:format(Fmt, Args)).
|
||||
|
||||
-spec with_authn(binary(), function()) -> any().
|
||||
-spec with_authn(atom(), function()) -> any().
|
||||
with_authn(GwName0, Fun) ->
|
||||
with_gateway(GwName0, fun(GwName, _GwConf) ->
|
||||
Authn = emqx_gateway_http:authn(GwName),
|
||||
Fun(GwName, Authn)
|
||||
end).
|
||||
|
||||
-spec with_listener_authn(binary(), binary(), function()) -> any().
|
||||
-spec with_listener_authn(atom(), binary(), function()) -> any().
|
||||
with_listener_authn(GwName0, Id, Fun) ->
|
||||
with_gateway(GwName0, fun(GwName, _GwConf) ->
|
||||
Authn = emqx_gateway_http:authn(GwName, Id),
|
||||
Fun(GwName, Authn)
|
||||
end).
|
||||
|
||||
-spec with_gateway(binary(), function()) -> any().
|
||||
with_gateway(GwName0, Fun) ->
|
||||
-spec with_gateway(atom(), function()) -> any().
|
||||
with_gateway(GwName, Fun) ->
|
||||
try
|
||||
GwName =
|
||||
try
|
||||
binary_to_existing_atom(GwName0)
|
||||
catch
|
||||
_:_ -> error(badname)
|
||||
end,
|
||||
case emqx_gateway:lookup(GwName) of
|
||||
undefined ->
|
||||
return_http_error(404, "Gateway not loaded");
|
||||
|
|
|
@ -48,12 +48,13 @@
|
|||
ip_port/0
|
||||
]).
|
||||
-elvis([{elvis_style, dont_repeat_yourself, disable}]).
|
||||
-elvis([{elvis_style, invalid_dynamic_call, disable}]).
|
||||
|
||||
-export([namespace/0, roots/0, fields/1, desc/1, tags/0]).
|
||||
|
||||
-export([proxy_protocol_opts/0]).
|
||||
|
||||
-export([mountpoint/0, mountpoint/1, gateway_common_options/0, gateway_schema/1]).
|
||||
-export([mountpoint/0, mountpoint/1, gateway_common_options/0, gateway_schema/1, gateway_names/0]).
|
||||
|
||||
namespace() -> gateway.
|
||||
|
||||
|
@ -337,13 +338,21 @@ proxy_protocol_opts() ->
|
|||
%% dynamic schemas
|
||||
|
||||
%% FIXME: don't hardcode the gateway names
|
||||
gateway_schema(stomp) -> emqx_stomp_schema:fields(stomp);
|
||||
gateway_schema(mqttsn) -> emqx_mqttsn_schema:fields(mqttsn);
|
||||
gateway_schema(coap) -> emqx_coap_schema:fields(coap);
|
||||
gateway_schema(lwm2m) -> emqx_lwm2m_schema:fields(lwm2m);
|
||||
gateway_schema(exproto) -> emqx_exproto_schema:fields(exproto);
|
||||
gateway_schema(gbt32960) -> emqx_gbt32960_schema:fields(gbt32960).
|
||||
gateway_schema(Name) ->
|
||||
case emqx_gateway_utils:find_gateway_definition(Name) of
|
||||
{ok, #{config_schema_module := SchemaMod}} ->
|
||||
SchemaMod:fields(Name);
|
||||
{error, _} = Error ->
|
||||
throw(Error)
|
||||
end.
|
||||
|
||||
gateway_names() ->
|
||||
Definations = emqx_gateway_utils:find_gateway_definitions(),
|
||||
[
|
||||
Name
|
||||
|| #{name := Name} = Defination <- Definations,
|
||||
emqx_gateway_utils:check_gateway_edition(Defination)
|
||||
].
|
||||
%%--------------------------------------------------------------------
|
||||
%% helpers
|
||||
|
||||
|
|
|
@ -45,8 +45,10 @@
|
|||
global_chain/1,
|
||||
listener_chain/3,
|
||||
find_gateway_definitions/0,
|
||||
find_gateway_definition/1,
|
||||
plus_max_connections/2,
|
||||
random_clientid/1
|
||||
random_clientid/1,
|
||||
check_gateway_edition/1
|
||||
]).
|
||||
|
||||
-export([stringfy/1]).
|
||||
|
@ -538,6 +540,32 @@ find_gateway_definitions() ->
|
|||
)
|
||||
).
|
||||
|
||||
-spec find_gateway_definition(atom()) -> {ok, map()} | {error, term()}.
|
||||
find_gateway_definition(Name) ->
|
||||
ensure_gateway_loaded(),
|
||||
find_gateway_definition(Name, ignore_lib_apps(application:loaded_applications())).
|
||||
|
||||
-dialyzer({no_match, [find_gateway_definition/2]}).
|
||||
find_gateway_definition(Name, [App | T]) ->
|
||||
Attrs = find_attrs(App, gateway),
|
||||
SearchFun = fun({_App, _Mod, #{name := GwName}}) ->
|
||||
GwName =:= Name
|
||||
end,
|
||||
case lists:search(SearchFun, Attrs) of
|
||||
{value, {_App, _Mod, Defination}} ->
|
||||
case check_gateway_edition(Defination) of
|
||||
true ->
|
||||
{ok, Defination};
|
||||
_ ->
|
||||
{error, invalid_edition}
|
||||
end;
|
||||
false ->
|
||||
find_gateway_definition(Name, T)
|
||||
end;
|
||||
find_gateway_definition(_Name, []) ->
|
||||
{error, not_found}.
|
||||
|
||||
-dialyzer({no_match, [gateways/1]}).
|
||||
gateways([]) ->
|
||||
[];
|
||||
gateways([
|
||||
|
@ -550,7 +578,20 @@ gateways([
|
|||
}}
|
||||
| More
|
||||
]) when is_atom(Name), is_atom(CbMod), is_atom(SchemaMod) ->
|
||||
[Defination | gateways(More)].
|
||||
case check_gateway_edition(Defination) of
|
||||
true ->
|
||||
[Defination | gateways(More)];
|
||||
_ ->
|
||||
gateways(More)
|
||||
end.
|
||||
|
||||
-if(?EMQX_RELEASE_EDITION == ee).
|
||||
check_gateway_edition(_Defination) ->
|
||||
true.
|
||||
-else.
|
||||
check_gateway_edition(Defination) ->
|
||||
ce == maps:get(edition, Defination, ce).
|
||||
-endif.
|
||||
|
||||
find_attrs(App, Def) ->
|
||||
[
|
||||
|
|
|
@ -96,10 +96,8 @@ t_gateways(_) ->
|
|||
ok.
|
||||
|
||||
t_gateway(_) ->
|
||||
{404, GwNotFoundReq1} = request(get, "/gateways/not_a_known_atom"),
|
||||
assert_not_found(GwNotFoundReq1),
|
||||
{404, GwNotFoundReq2} = request(get, "/gateways/undefined"),
|
||||
assert_not_found(GwNotFoundReq2),
|
||||
?assertMatch({400, #{code := <<"BAD_REQUEST">>}}, request(get, "/gateways/not_a_known_atom")),
|
||||
?assertMatch({400, #{code := <<"BAD_REQUEST">>}}, request(get, "/gateways/undefined")),
|
||||
{204, _} = request(put, "/gateways/stomp", #{}),
|
||||
{200, StompGw} = request(get, "/gateways/stomp"),
|
||||
assert_fields_exist(
|
||||
|
@ -110,7 +108,7 @@ t_gateway(_) ->
|
|||
{200, #{enable := true}} = request(get, "/gateways/stomp"),
|
||||
{204, _} = request(put, "/gateways/stomp", #{enable => false}),
|
||||
{200, #{enable := false}} = request(get, "/gateways/stomp"),
|
||||
{404, _} = request(put, "/gateways/undefined", #{}),
|
||||
?assertMatch({400, #{code := <<"BAD_REQUEST">>}}, request(put, "/gateways/undefined", #{})),
|
||||
{400, _} = request(put, "/gateways/stomp", #{bad_key => "foo"}),
|
||||
ok.
|
||||
|
||||
|
@ -129,8 +127,14 @@ t_gateway_enable(_) ->
|
|||
{200, #{enable := NotEnable}} = request(get, "/gateways/stomp"),
|
||||
{204, _} = request(put, "/gateways/stomp/enable/" ++ atom_to_list(Enable), undefined),
|
||||
{200, #{enable := Enable}} = request(get, "/gateways/stomp"),
|
||||
{404, _} = request(put, "/gateways/undefined/enable/true", undefined),
|
||||
{404, _} = request(put, "/gateways/not_a_known_atom/enable/true", undefined),
|
||||
?assertMatch(
|
||||
{400, #{code := <<"BAD_REQUEST">>}},
|
||||
request(put, "/gateways/undefined/enable/true", undefined)
|
||||
),
|
||||
?assertMatch(
|
||||
{400, #{code := <<"BAD_REQUEST">>}},
|
||||
request(put, "/gateways/not_a_known_atom/enable/true", undefined)
|
||||
),
|
||||
{404, _} = request(put, "/gateways/coap/enable/true", undefined),
|
||||
ok.
|
||||
|
||||
|
|
|
@ -12,7 +12,8 @@
|
|||
-gateway(#{
|
||||
name => gbt32960,
|
||||
callback_module => ?MODULE,
|
||||
config_schema_module => emqx_gbt32960_schema
|
||||
config_schema_module => emqx_gbt32960_schema,
|
||||
edition => ee
|
||||
}).
|
||||
|
||||
%% callback_module must implement the emqx_gateway_impl behaviour
|
||||
|
|
|
@ -37,8 +37,7 @@ gateway_name.desc:
|
|||
"""Gateway Name"""
|
||||
|
||||
gateway_name_in_qs.desc:
|
||||
"""Gateway Name.<br/>
|
||||
It's enum with `stomp`, `mqttsn`, `coap`, `lwm2m`, `exproto`, `gbt32960`"""
|
||||
"""Gateway Name"""
|
||||
|
||||
gateway_node_status.desc:
|
||||
"""The status of the gateway on each node in the cluster"""
|
||||
|
|
Loading…
Reference in New Issue