From 2738815af98d136f8651edbc34beabbe37aabe3e Mon Sep 17 00:00:00 2001 From: Shawn <506895667@qq.com> Date: Wed, 4 Aug 2021 20:56:54 +0800 Subject: [PATCH] feat(API): add a general API to update configs --- .../src/emqx_mgmt_api_configs.erl | 68 ++++++++++--------- apps/emqx_management/src/emqx_mgmt_http.erl | 8 +++ 2 files changed, 44 insertions(+), 32 deletions(-) diff --git a/apps/emqx_management/src/emqx_mgmt_api_configs.erl b/apps/emqx_management/src/emqx_mgmt_api_configs.erl index eab0c78ad..488a4e467 100644 --- a/apps/emqx_management/src/emqx_mgmt_api_configs.erl +++ b/apps/emqx_management/src/emqx_mgmt_api_configs.erl @@ -23,8 +23,6 @@ -export([ config/2 ]). --define(CONFIG_NAMES, [log, rpc, broker, zones, sysmon, alarm]). - -define(PARAM_CONF_PATH, [#{ name => conf_path, in => query, @@ -33,30 +31,34 @@ schema => #{type => string, default => <<".">>} }]). -api_spec() -> - {config_apis(), config_schemas()}. +-define(TEXT_BODY(DESCR), #{ + description => list_to_binary(DESCR), + content => #{ + <<"text/plain">> => #{ + schema => #{} + } + } +}). -config_schemas() -> - [#{RootName => #{type => object}} %% TODO: generate this from hocon schema - || RootName <- ?CONFIG_NAMES]. +api_spec() -> + {config_apis(), []}. config_apis() -> - [config_api(RootName) || RootName <- ?CONFIG_NAMES]. + [config_api()]. -config_api(RootName) when is_atom(RootName) -> - RootNameStr = atom_to_list(RootName), - Descr = fun(Prefix) -> list_to_binary(Prefix ++ " " ++ RootNameStr) end, +config_api() -> Metadata = #{ get => #{ - description => Descr("Get configs for"), + description => <<"Get configs">>, parameters => ?PARAM_CONF_PATH, responses => #{ - <<"200">> => emqx_mgmt_util:response_schema(<<"The config value for log">>, - RootName) + <<"200">> => ?TEXT_BODY("Get configs successfully"), + <<"404">> => emqx_mgmt_util:response_error_schema( + <<"Config not found">>, ['NOT_FOUND']) } }, delete => #{ - description => Descr("Remove configs for"), + description => <<"Remove configs for">>, parameters => ?PARAM_CONF_PATH, responses => #{ <<"200">> => emqx_mgmt_util:response_schema(<<"Remove configs successfully">>), @@ -65,45 +67,47 @@ config_api(RootName) when is_atom(RootName) -> } }, put => #{ - description => Descr("Update configs for"), - 'requestBody' => emqx_mgmt_util:request_body_schema(RootName), + description => <<"Update configs for">>, + 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 => #{ - <<"200">> => emqx_mgmt_util:response_schema(<<"Update configs successfully">>, - RootName), + <<"200">> => ?TEXT_BODY("Update configs successfully"), <<"400">> => emqx_mgmt_util:response_error_schema( <<"Update configs failed">>, ['UPDATE_FAILED']) } } }, - {"/configs/" ++ RootNameStr, Metadata, config}. + {"/configs", Metadata, config}. %%%============================================================================================== %% parameters trans config(get, Req) -> %% 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)]), - {200, Conf}; + case emqx_config:find_raw(conf_path_from_querystr(Req)) of + {ok, Conf} -> + {200, Conf}; + {not_found, _, _} -> + {404, #{code => 'NOT_FOUND', message => <<"Config cannot found">>}} + end; config(delete, Req) -> %% 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}; config(put, Req) -> - RootName = root_name_from_path(Req), - ok = emqx_config:update([RootName], http_body(Req)), - {200, emqx_config:get_raw([RootName])}. - -root_name_from_path(Req) -> - <<"/api/v5/configs/", RootName/binary>> = cowboy_req:path(Req), - string:trim(RootName, trailing, "/"). + Path = [binary_to_atom(Key, latin1) || Key <- conf_path_from_querystr(Req)], + ok = emqx_config:update(Path, http_body(Req)), + {201, emqx_config:get_raw(Path)}. conf_path_from_querystr(Req) -> case proplists:get_value(<<"conf_path">>, cowboy_req:parse_qs(Req)) of undefined -> []; - Path -> [string:lexemes(Path, ". ")] + Path -> string:lexemes(Path, ". ") end. http_body(Req) -> {ok, Body, _} = cowboy_req:read_body(Req), - Body. + try jsx:decode(Body, [{return_maps, true}]) + catch error:badarg -> Body + end. diff --git a/apps/emqx_management/src/emqx_mgmt_http.erl b/apps/emqx_management/src/emqx_mgmt_http.erl index 8c7b0d7c5..c795e1de7 100644 --- a/apps/emqx_management/src/emqx_mgmt_http.erl +++ b/apps/emqx_management/src/emqx_mgmt_http.erl @@ -48,6 +48,14 @@ start_listener({Proto, Port, Options}) -> openapi => "3.0.0", info => #{title => "EMQ X API", version => "5.0.0"}, 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 => #{ schemas => #{}, securitySchemes => #{