refactor(gw): simplify code structure

1. Add the management API for listener's authn
2. Clarify responsed error messages
This commit is contained in:
JianBo He 2021-09-23 10:21:02 +08:00
parent 5ad1a8c232
commit 791408cd99
3 changed files with 159 additions and 61 deletions

View File

@ -34,6 +34,9 @@
%% http handlers
-export([authn/2]).
%% internal export for emqx_gateway_api_listeners module
-export([schema_authn/0]).
%%--------------------------------------------------------------------
%% minirest behaviour callbacks
%%--------------------------------------------------------------------
@ -50,42 +53,27 @@ apis() ->
authn(get, #{bindings := #{name := Name0}}) ->
with_gateway(Name0, fun(GwName, _) ->
case emqx_gateway_http:authn(GwName) of
undefined ->
return_http_error(404, "No Authentication");
Auth ->
{200, Auth}
end
{200, emqx_gateway_http:authn(GwName)}
end);
authn(put, #{bindings := #{name := Name0},
body := Body}) ->
with_gateway(Name0, fun(GwName, _) ->
case emqx_gateway_http:update_authn(GwName, Body) of
ok ->
{204};
{error, Reason} ->
return_http_error(500, Reason)
end
ok = emqx_gateway_http:update_authn(GwName, Body),
{204}
end);
authn(post, #{bindings := #{name := Name0},
body := Body}) ->
with_gateway(Name0, fun(GwName, _) ->
case emqx_gateway_http:add_authn(GwName, Body) of
ok -> {204};
{error, Reason} ->
return_http_error(500, Reason)
end
ok = emqx_gateway_http:add_authn(GwName, Body),
{204}
end);
authn(delete, #{bindings := #{name := Name0}}) ->
with_gateway(Name0, fun(GwName, _) ->
case emqx_gateway_http:remove_authn(GwName) of
ok -> {204};
{error, Reason} ->
return_http_error(500, Reason)
end
ok = emqx_gateway_http:remove_authn(GwName),
{204}
end).
%%--------------------------------------------------------------------

View File

@ -28,12 +28,15 @@
, checks/2
]).
-import(emqx_gateway_api_authn, [schema_authn/0]).
%% minirest behaviour callbacks
-export([api_spec/0]).
%% http handlers
-export([ listeners/2
, listeners_insta/2
, listeners_insta_authn/2
]).
%%--------------------------------------------------------------------
@ -46,6 +49,7 @@ api_spec() ->
apis() ->
[ {"/gateway/:name/listeners", listeners}
, {"/gateway/:name/listeners/:id", listeners_insta}
, {"/gateway/:name/listeners/:id/authentication", listeners_insta_authn}
].
%%--------------------------------------------------------------------
@ -70,27 +74,18 @@ listeners(post, #{bindings := #{name := Name0}, body := LConf}) ->
undefined ->
ListenerId = emqx_gateway_utils:listener_id(
GwName, Type, LName),
case emqx_gateway_http:add_listener(ListenerId, LConf) of
ok ->
ok = emqx_gateway_http:add_listener(ListenerId, LConf),
{204};
{error, Reason} ->
return_http_error(500, Reason)
end;
_ ->
return_http_error(400, "Listener name has occupied")
end
end).
%% FIXME: not working
listeners_insta(delete, #{bindings := #{name := Name0, id := ListenerId0}}) ->
ListenerId = emqx_mgmt_util:urldecode(ListenerId0),
with_gateway(Name0, fun(_GwName, _) ->
case emqx_gateway_http:remove_listener(ListenerId) of
ok -> {204};
{error, not_found} -> {204};
{error, Reason} ->
return_http_error(500, Reason)
end
ok = emqx_gateway_http:remove_listener(ListenerId),
{204}
end);
listeners_insta(get, #{bindings := #{name := Name0, id := ListenerId0}}) ->
ListenerId = emqx_mgmt_util:urldecode(ListenerId0),
@ -109,12 +104,38 @@ listeners_insta(put, #{body := LConf,
}) ->
ListenerId = emqx_mgmt_util:urldecode(ListenerId0),
with_gateway(Name0, fun(_GwName, _) ->
case emqx_gateway_http:update_listener(ListenerId, LConf) of
ok ->
{204};
{error, Reason} ->
return_http_error(500, Reason)
end
ok = emqx_gateway_http:update_listener(ListenerId, LConf),
{204}
end).
listeners_insta_authn(get, #{bindings := #{name := Name0,
id := ListenerId0}}) ->
ListenerId = emqx_mgmt_util:urldecode(ListenerId0),
with_gateway(Name0, fun(GwName, _) ->
{200, emqx_gateway_http:authn(GwName, ListenerId)}
end);
listeners_insta_authn(post, #{body := Conf,
bindings := #{name := Name0,
id := ListenerId0}}) ->
ListenerId = emqx_mgmt_util:urldecode(ListenerId0),
with_gateway(Name0, fun(GwName, _) ->
ok = emqx_gateway_http:add_authn(GwName, ListenerId, Conf),
{204}
end);
listeners_insta_authn(put, #{body := Conf,
bindings := #{name := Name0,
id := ListenerId0}}) ->
ListenerId = emqx_mgmt_util:urldecode(ListenerId0),
with_gateway(Name0, fun(GwName, _) ->
ok = emqx_gateway_http:update_authn(GwName, ListenerId, Conf),
{204}
end);
listeners_insta_authn(delete, #{bindings := #{name := Name0,
id := ListenerId0}}) ->
ListenerId = emqx_mgmt_util:urldecode(ListenerId0),
with_gateway(Name0, fun(GwName, _) ->
ok = emqx_gateway_http:remove_authn(GwName, ListenerId),
{204}
end).
%%--------------------------------------------------------------------
@ -191,6 +212,52 @@ swagger("/gateway/:name/listeners/:id", put) ->
, <<"500">> => schema_internal_error()
, <<"200">> => schema_no_content()
}
};
swagger("/gateway/:name/listeners/:id/authentication", get) ->
#{ description => <<"Get the listener's authentication info">>
, parameters => params_gateway_name_in_path()
++ params_listener_id_in_path()
, responses =>
#{ <<"400">> => schema_bad_request()
, <<"404">> => schema_not_found()
, <<"500">> => schema_internal_error()
, <<"200">> => schema_authn()
}
};
swagger("/gateway/:name/listeners/:id/authentication", post) ->
#{ description => <<"Add authentication for the listener">>
, parameters => params_gateway_name_in_path()
++ params_listener_id_in_path()
, requestBody => schema_authn()
, responses =>
#{ <<"400">> => schema_bad_request()
, <<"404">> => schema_not_found()
, <<"500">> => schema_internal_error()
, <<"204">> => schema_no_content()
}
};
swagger("/gateway/:name/listeners/:id/authentication", put) ->
#{ description => <<"Update authentication for the listener">>
, parameters => params_gateway_name_in_path()
++ params_listener_id_in_path()
, requestBody => schema_authn()
, responses =>
#{ <<"400">> => schema_bad_request()
, <<"404">> => schema_not_found()
, <<"500">> => schema_internal_error()
, <<"204">> => schema_no_content()
}
};
swagger("/gateway/:name/listeners/:id/authentication", delete) ->
#{ description => <<"Remove authentication for the listener">>
, parameters => params_gateway_name_in_path()
++ params_listener_id_in_path()
, responses =>
#{ <<"400">> => schema_bad_request()
, <<"404">> => schema_not_found()
, <<"500">> => schema_internal_error()
, <<"204">> => schema_no_content()
}
}.
%%--------------------------------------------------------------------

View File

@ -34,9 +34,13 @@
]).
-export([ authn/1
, authn/2
, add_authn/2
, add_authn/3
, update_authn/2
, update_authn/3
, remove_authn/1
, remove_authn/2
]).
%% Mgmt APIs - clients
@ -205,47 +209,69 @@ bind2str(LConf = #{bind := Bind}) when is_binary(Bind) ->
bind2str(LConf = #{<<"bind">> := Bind}) when is_binary(Bind) ->
LConf.
-spec add_listener(atom() | binary(), map()) -> ok | {error, any()}.
-spec add_listener(atom() | binary(), map()) -> ok.
add_listener(ListenerId, NewConf0) ->
{GwName, Type, Name} = emqx_gateway_utils:parse_listener_id(ListenerId),
NewConf = maps:without([<<"id">>, <<"name">>,
<<"type">>, <<"running">>], NewConf0),
emqx_gateway_conf:add_listener(GwName, {Type, Name}, NewConf).
confexp(emqx_gateway_conf:add_listener(GwName, {Type, Name}, NewConf)).
-spec update_listener(atom() | binary(), map()) -> ok | {error, any()}.
-spec update_listener(atom() | binary(), map()) -> ok.
update_listener(ListenerId, NewConf0) ->
{GwName, Type, Name} = emqx_gateway_utils:parse_listener_id(ListenerId),
NewConf = maps:without([<<"id">>, <<"name">>,
<<"type">>, <<"running">>], NewConf0),
emqx_gateway_conf:update_listener(GwName, {Type, Name}, NewConf).
confexp(emqx_gateway_conf:update_listener(GwName, {Type, Name}, NewConf)).
-spec remove_listener(binary()) -> ok | {error, not_found} | {error, any()}.
-spec remove_listener(binary()) -> ok.
remove_listener(ListenerId) ->
{GwName, Type, Name} = emqx_gateway_utils:parse_listener_id(ListenerId),
emqx_gateway_conf:remove_listener(GwName, {Type, Name}).
confexp(emqx_gateway_conf:remove_listener(GwName, {Type, Name})).
-spec authn(gateway_name()) -> map() | undefined.
-spec authn(gateway_name()) -> map().
authn(GwName) ->
case emqx_map_lib:deep_get(
[authentication],
emqx:get_config([gateway, GwName]),
undefined) of
undefined -> undefined;
AuthConf -> emqx_map_lib:jsonable_map(AuthConf)
end.
Path = [gateway, GwName, authentication],
emqx_map_lib:jsonable_map(emqx:get_config(Path)).
-spec add_authn(gateway_name(), map()) -> ok | {error, any()}.
-spec authn(gateway_name(), binary()) -> map().
authn(GwName, ListenerId) ->
{_, Type, Name} = emqx_gateway_utils:parse_listener_id(ListenerId),
Path = [gateway, GwName, listeners, Type, Name, authentication],
emqx_map_lib:jsonable_map(emqx:get_config(Path)).
-spec add_authn(gateway_name(), map()) -> ok.
add_authn(GwName, AuthConf) ->
emqx_gateway_conf:add_authn(GwName, AuthConf).
confexp(emqx_gateway_conf:add_authn(GwName, AuthConf)).
-spec update_authn(gateway_name(), map()) -> ok | {error, any()}.
-spec add_authn(gateway_name(), binary(), map()) -> ok.
add_authn(GwName, ListenerId, AuthConf) ->
{_, Type, Name} = emqx_gateway_utils:parse_listener_id(ListenerId),
confexp(emqx_gateway_conf:add_authn(GwName, {Type, Name}, AuthConf)).
-spec update_authn(gateway_name(), map()) -> ok.
update_authn(GwName, AuthConf) ->
emqx_gateway_conf:update_authn(GwName, AuthConf).
confexp(emqx_gateway_conf:update_authn(GwName, AuthConf)).
-spec remove_authn(gateway_name()) -> ok | {error, any()}.
-spec update_authn(gateway_name(), binary(), map()) -> ok.
update_authn(GwName, ListenerId, AuthConf) ->
{_, Type, Name} = emqx_gateway_utils:parse_listener_id(ListenerId),
confexp(emqx_gateway_conf:update_authn(GwName, {Type, Name}, AuthConf)).
-spec remove_authn(gateway_name()) -> ok.
remove_authn(GwName) ->
emqx_gateway_conf:remove_authn(GwName).
confexp(emqx_gateway_conf:remove_authn(GwName)).
-spec remove_authn(gateway_name(), binary()) -> ok.
remove_authn(GwName, ListenerId) ->
{_, Type, Name} = emqx_gateway_utils:parse_listener_id(ListenerId),
confexp(emqx_gateway_conf:remove_authn(GwName, {Type, Name})).
confexp(ok) -> ok;
confexp({error, not_found}) ->
error({update_conf_error, not_found});
confexp({error, already_exist}) ->
error({update_conf_error, already_exist}).
%%--------------------------------------------------------------------
%% Mgmt APIs - clients
@ -365,10 +391,22 @@ with_gateway(GwName0, Fun) ->
catch
error : badname ->
return_http_error(404, "Bad gateway name");
%% Exceptions from: checks/2
error : {miss_param, K} ->
return_http_error(400, [K, " is required"]);
%% Exceptions from emqx_gateway_utils:parse_listener_id/1
error : {invalid_listener_id, Id} ->
return_http_error(400, ["invalid listener id: ", Id]);
%% Exceptions from: emqx:get_config/1
error : {config_not_found, Path0} ->
Path = lists:concat(
lists:join(".", lists:map(fun to_list/1, Path0))),
return_http_error(404, "Resource not found. path: " ++ Path);
%% Exceptions from: confexp/1
error : {update_conf_error, not_found} ->
return_http_error(404, "Resource not found");
error : {update_conf_error, already_exist} ->
return_http_error(400, "Resource already exist");
Class : Reason : Stk ->
?LOG(error, "Uncatched error: {~p, ~p}, stacktrace: ~0p",
[Class, Reason, Stk]),
@ -385,6 +423,11 @@ checks([K|Ks], Map) ->
error({miss_param, K})
end.
to_list(A) when is_atom(A) ->
atom_to_list(A);
to_list(B) when is_binary(B) ->
binary_to_list(B).
%%--------------------------------------------------------------------
%% common schemas