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