feat(API): add a general API to update configs

This commit is contained in:
Shawn 2021-08-04 20:56:54 +08:00
parent 990c383e01
commit 2738815af9
2 changed files with 44 additions and 32 deletions

View File

@ -23,8 +23,6 @@
-export([ config/2 -export([ config/2
]). ]).
-define(CONFIG_NAMES, [log, rpc, broker, zones, sysmon, alarm]).
-define(PARAM_CONF_PATH, [#{ -define(PARAM_CONF_PATH, [#{
name => conf_path, name => conf_path,
in => query, in => query,
@ -33,30 +31,34 @@
schema => #{type => string, default => <<".">>} schema => #{type => string, default => <<".">>}
}]). }]).
api_spec() -> -define(TEXT_BODY(DESCR), #{
{config_apis(), config_schemas()}. description => list_to_binary(DESCR),
content => #{
<<"text/plain">> => #{
schema => #{}
}
}
}).
config_schemas() -> api_spec() ->
[#{RootName => #{type => object}} %% TODO: generate this from hocon schema {config_apis(), []}.
|| RootName <- ?CONFIG_NAMES].
config_apis() -> config_apis() ->
[config_api(RootName) || RootName <- ?CONFIG_NAMES]. [config_api()].
config_api(RootName) when is_atom(RootName) -> config_api() ->
RootNameStr = atom_to_list(RootName),
Descr = fun(Prefix) -> list_to_binary(Prefix ++ " " ++ RootNameStr) end,
Metadata = #{ Metadata = #{
get => #{ get => #{
description => Descr("Get configs for"), description => <<"Get configs">>,
parameters => ?PARAM_CONF_PATH, parameters => ?PARAM_CONF_PATH,
responses => #{ responses => #{
<<"200">> => emqx_mgmt_util:response_schema(<<"The config value for log">>, <<"200">> => ?TEXT_BODY("Get configs successfully"),
RootName) <<"404">> => emqx_mgmt_util:response_error_schema(
<<"Config not found">>, ['NOT_FOUND'])
} }
}, },
delete => #{ delete => #{
description => Descr("Remove configs for"), description => <<"Remove configs for">>,
parameters => ?PARAM_CONF_PATH, parameters => ?PARAM_CONF_PATH,
responses => #{ responses => #{
<<"200">> => emqx_mgmt_util:response_schema(<<"Remove configs successfully">>), <<"200">> => emqx_mgmt_util:response_schema(<<"Remove configs successfully">>),
@ -65,45 +67,47 @@ config_api(RootName) when is_atom(RootName) ->
} }
}, },
put => #{ put => #{
description => Descr("Update configs for"), description => <<"Update configs for">>,
'requestBody' => emqx_mgmt_util:request_body_schema(RootName), parameters => ?PARAM_CONF_PATH,
'requestBody' => ?TEXT_BODY("The format of the request body is depend on the 'conf_path' parameter in the query string"),
responses => #{ responses => #{
<<"200">> => emqx_mgmt_util:response_schema(<<"Update configs successfully">>, <<"200">> => ?TEXT_BODY("Update configs successfully"),
RootName),
<<"400">> => emqx_mgmt_util:response_error_schema( <<"400">> => emqx_mgmt_util:response_error_schema(
<<"Update configs failed">>, ['UPDATE_FAILED']) <<"Update configs failed">>, ['UPDATE_FAILED'])
} }
} }
}, },
{"/configs/" ++ RootNameStr, Metadata, config}. {"/configs", Metadata, config}.
%%%============================================================================================== %%%==============================================================================================
%% parameters trans %% parameters trans
config(get, Req) -> config(get, Req) ->
%% TODO: query the config specified by the query string param 'conf_path' %% TODO: query the config specified by the query string param 'conf_path'
Conf = emqx_config:get_raw([root_name_from_path(Req) | conf_path_from_querystr(Req)]), case emqx_config:find_raw(conf_path_from_querystr(Req)) of
{200, Conf}; {ok, Conf} ->
{200, Conf};
{not_found, _, _} ->
{404, #{code => 'NOT_FOUND', message => <<"Config cannot found">>}}
end;
config(delete, Req) -> config(delete, Req) ->
%% TODO: remove the config specified by the query string param 'conf_path' %% TODO: remove the config specified by the query string param 'conf_path'
emqx_config:remove([root_name_from_path(Req) | conf_path_from_querystr(Req)]), emqx_config:remove(conf_path_from_querystr(Req)),
{200}; {200};
config(put, Req) -> config(put, Req) ->
RootName = root_name_from_path(Req), Path = [binary_to_atom(Key, latin1) || Key <- conf_path_from_querystr(Req)],
ok = emqx_config:update([RootName], http_body(Req)), ok = emqx_config:update(Path, http_body(Req)),
{200, emqx_config:get_raw([RootName])}. {201, emqx_config:get_raw(Path)}.
root_name_from_path(Req) ->
<<"/api/v5/configs/", RootName/binary>> = cowboy_req:path(Req),
string:trim(RootName, trailing, "/").
conf_path_from_querystr(Req) -> conf_path_from_querystr(Req) ->
case proplists:get_value(<<"conf_path">>, cowboy_req:parse_qs(Req)) of case proplists:get_value(<<"conf_path">>, cowboy_req:parse_qs(Req)) of
undefined -> []; undefined -> [];
Path -> [string:lexemes(Path, ". ")] Path -> string:lexemes(Path, ". ")
end. end.
http_body(Req) -> http_body(Req) ->
{ok, Body, _} = cowboy_req:read_body(Req), {ok, Body, _} = cowboy_req:read_body(Req),
Body. try jsx:decode(Body, [{return_maps, true}])
catch error:badarg -> Body
end.

View File

@ -48,6 +48,14 @@ start_listener({Proto, Port, Options}) ->
openapi => "3.0.0", openapi => "3.0.0",
info => #{title => "EMQ X API", version => "5.0.0"}, info => #{title => "EMQ X API", version => "5.0.0"},
servers => [#{url => ?BASE_PATH}], servers => [#{url => ?BASE_PATH}],
tags => [#{
name => configs,
description => <<"The query string parameter `conf_path` is of jq format.">>,
externalDocs => #{
description => "Find out more about the path syntax in jq",
url => "https://stedolan.github.io/jq/manual/"
}
}],
components => #{ components => #{
schemas => #{}, schemas => #{},
securitySchemes => #{ securitySchemes => #{