feat(emqx_config): support fetching the entire config map

This commit is contained in:
Shawn 2021-08-04 20:55:49 +08:00
parent c05e92a7cc
commit 990c383e01
2 changed files with 49 additions and 10 deletions

View File

@ -32,6 +32,7 @@
-export([ get/1 -export([ get/1
, get/2 , get/2
, find/1 , find/1
, find_raw/1
, put/1 , put/1
, put/2 , put/2
]). ]).
@ -62,7 +63,7 @@
-define(CONF, conf). -define(CONF, conf).
-define(RAW_CONF, raw_conf). -define(RAW_CONF, raw_conf).
-define(PERSIS_KEY(TYPE, ROOT), {?MODULE, TYPE, bin(ROOT)}). -define(PERSIS_KEY(TYPE, ROOT), {?MODULE, TYPE, ROOT}).
-define(ZONE_CONF_PATH(ZONE, PATH), [zones, ZONE | PATH]). -define(ZONE_CONF_PATH(ZONE, PATH), [zones, ZONE | PATH]).
-define(LISTENER_CONF_PATH(ZONE, LISTENER, PATH), [zones, ZONE, listeners, LISTENER | PATH]). -define(LISTENER_CONF_PATH(ZONE, LISTENER, PATH), [zones, ZONE, listeners, LISTENER | PATH]).
@ -101,10 +102,29 @@ get(KeyPath, Default) -> do_get(?CONF, KeyPath, Default).
-spec find(emqx_map_lib:config_key_path()) -> -spec find(emqx_map_lib:config_key_path()) ->
{ok, term()} | {not_found, emqx_map_lib:config_key_path(), term()}. {ok, term()} | {not_found, emqx_map_lib:config_key_path(), term()}.
find([]) ->
Ref = make_ref(),
Res = do_get(?CONF, [], Ref),
case Res =:= Ref of
true -> {not_found, []};
false -> {ok, Res}
end;
find(KeyPath) -> find(KeyPath) ->
?ATOM_CONF_PATH(KeyPath, emqx_map_lib:deep_find(AtomKeyPath, get_root(KeyPath)), ?ATOM_CONF_PATH(KeyPath, emqx_map_lib:deep_find(AtomKeyPath, get_root(KeyPath)),
{not_found, KeyPath}). {not_found, KeyPath}).
-spec find_raw(emqx_map_lib:config_key_path()) ->
{ok, term()} | {not_found, emqx_map_lib:config_key_path(), term()}.
find_raw([]) ->
Ref = make_ref(),
Res = do_get(?RAW_CONF, [], Ref),
case Res =:= Ref of
true -> {not_found, []};
false -> {ok, Res}
end;
find_raw(KeyPath) ->
emqx_map_lib:deep_find([bin(Key) || Key <- KeyPath], get_root_raw(KeyPath)).
-spec get_zone_conf(atom(), emqx_map_lib:config_key_path()) -> term(). -spec get_zone_conf(atom(), emqx_map_lib:config_key_path()) -> term().
get_zone_conf(Zone, KeyPath) -> get_zone_conf(Zone, KeyPath) ->
?MODULE:get(?ZONE_CONF_PATH(Zone, KeyPath)). ?MODULE:get(?ZONE_CONF_PATH(Zone, KeyPath)).
@ -279,16 +299,30 @@ do_get(Type, KeyPath) ->
false -> Res false -> Res
end. end.
do_get(Type, [], Default) ->
AllConf = lists:foldl(fun
({?PERSIS_KEY(Type0, RootName), Conf}, AccIn) when Type0 == Type ->
AccIn#{RootName => Conf};
(_, AccIn) -> AccIn
end, #{}, persistent_term:get()),
case map_size(AllConf) == 0 of
true -> Default;
false -> AllConf
end;
do_get(Type, [RootName], Default) -> do_get(Type, [RootName], Default) ->
persistent_term:get(?PERSIS_KEY(Type, RootName), Default); persistent_term:get(?PERSIS_KEY(Type, bin(RootName)), Default);
do_get(Type, [RootName | KeyPath], Default) -> do_get(Type, [RootName | KeyPath], Default) ->
RootV = persistent_term:get(?PERSIS_KEY(Type, RootName), #{}), RootV = persistent_term:get(?PERSIS_KEY(Type, bin(RootName)), #{}),
do_deep_get(Type, KeyPath, RootV, Default). do_deep_get(Type, KeyPath, RootV, Default).
do_put(Type, [], DeepValue) ->
maps:fold(fun(RootName, Value, _Res) ->
do_put(Type, [RootName], Value)
end, ok, DeepValue);
do_put(Type, [RootName | KeyPath], DeepValue) -> do_put(Type, [RootName | KeyPath], DeepValue) ->
OldValue = do_get(Type, [RootName], #{}), OldValue = do_get(Type, [RootName], #{}),
NewValue = do_deep_put(Type, KeyPath, OldValue, DeepValue), NewValue = do_deep_put(Type, KeyPath, OldValue, DeepValue),
persistent_term:put(?PERSIS_KEY(Type, RootName), NewValue). persistent_term:put(?PERSIS_KEY(Type, bin(RootName)), NewValue).
do_deep_get(?CONF, KeyPath, Map, Default) -> do_deep_get(?CONF, KeyPath, Map, Default) ->
?ATOM_CONF_PATH(KeyPath, emqx_map_lib:deep_get(AtomKeyPath, Map, Default), ?ATOM_CONF_PATH(KeyPath, emqx_map_lib:deep_get(AtomKeyPath, Map, Default),

View File

@ -28,7 +28,7 @@
-define(PARAM_CONF_PATH, [#{ -define(PARAM_CONF_PATH, [#{
name => conf_path, name => conf_path,
in => query, in => query,
description => <<"The config path in jq syntax">>, description => <<"The config path separated by '.' character">>,
required => false, required => false,
schema => #{type => string, default => <<".">>} schema => #{type => string, default => <<".">>}
}]). }]).
@ -81,23 +81,28 @@ config_api(RootName) when is_atom(RootName) ->
%% 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 = emqx_config:get_raw([root_name_from_path(Req) | conf_path_from_querystr(Req)]),
{200, Conf}; {200, Conf};
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([binary_to_existing_atom(root_name_from_path(Req), latin1)]), emqx_config:remove([root_name_from_path(Req) | conf_path_from_querystr(Req)]),
{200}; {200};
config(put, Req) -> config(put, Req) ->
RootName = root_name_from_path(Req), RootName = root_name_from_path(Req),
AtomRootName = binary_to_existing_atom(RootName, latin1), ok = emqx_config:update([RootName], http_body(Req)),
ok = emqx_config:update([AtomRootName], http_body(Req)),
{200, emqx_config:get_raw([RootName])}. {200, emqx_config:get_raw([RootName])}.
root_name_from_path(Req) -> root_name_from_path(Req) ->
<<"/api/v5/configs/", RootName/binary>> = cowboy_req:path(Req), <<"/api/v5/configs/", RootName/binary>> = cowboy_req:path(Req),
RootName. string:trim(RootName, trailing, "/").
conf_path_from_querystr(Req) ->
case proplists:get_value(<<"conf_path">>, cowboy_req:parse_qs(Req)) of
undefined -> [];
Path -> [string:lexemes(Path, ". ")]
end.
http_body(Req) -> http_body(Req) ->
{ok, Body, _} = cowboy_req:read_body(Req), {ok, Body, _} = cowboy_req:read_body(Req),