Просмотр исходного кода

feat: authz support merge sources

zhongwencool 2 лет назад
Родитель
Сommit
aac5b85d26
2 измененных файлов с 87 добавлено и 5 удалено
  1. 1 0
      apps/emqx_authz/include/emqx_authz.hrl
  2. 86 5
      apps/emqx_authz/src/emqx_authz.erl

+ 1 - 0
apps/emqx_authz/include/emqx_authz.hrl

@@ -37,6 +37,7 @@
 -define(CMD_PREPEND, prepend).
 -define(CMD_APPEND, append).
 -define(CMD_MOVE, move).
+-define(CMD_MERGE, merge).
 
 -define(CMD_MOVE_FRONT, front).
 -define(CMD_MOVE_REAR, rear).

+ 86 - 5
apps/emqx_authz/src/emqx_authz.erl

@@ -24,11 +24,6 @@
 -include_lib("emqx/include/emqx_hooks.hrl").
 -include_lib("snabbkaffe/include/snabbkaffe.hrl").
 
--ifdef(TEST).
--compile(export_all).
--compile(nowarn_export_all).
--endif.
-
 -export([
     register_metrics/0,
     init/0,
@@ -37,6 +32,7 @@
     lookup/1,
     move/2,
     update/2,
+    merge/1,
     authorize/5,
     %% for telemetry information
     get_enabled_authzs/0
@@ -45,6 +41,7 @@
 -export([post_config_update/5, pre_config_update/3]).
 
 -export([acl_conf_file/0]).
+-export([merge_sources/2, search/2]).
 
 %% Data backup
 -export([
@@ -128,6 +125,9 @@ lookup(Type) ->
     {Source, _Front, _Rear} = take(Type),
     Source.
 
+merge(NewConf) ->
+    emqx_authz_utils:update_config(?ROOT_KEY, {?CMD_MERGE, NewConf}).
+
 move(Type, ?CMD_MOVE_BEFORE(Before)) ->
     emqx_authz_utils:update_config(
         ?CONF_KEY_PATH, {?CMD_MOVE, type(Type), ?CMD_MOVE_BEFORE(type(Before))}
@@ -158,9 +158,16 @@ pre_config_update(Path, Cmd, Sources) ->
 
 do_pre_config_update(?CONF_KEY_PATH, Cmd, Sources) ->
     do_pre_config_update(Cmd, Sources);
+do_pre_config_update(?ROOT_KEY, {?CMD_MERGE, NewConf}, OldConf) ->
+    do_pre_config_merge(NewConf, OldConf);
 do_pre_config_update(?ROOT_KEY, NewConf, OldConf) ->
     do_pre_config_replace(NewConf, OldConf).
 
+do_pre_config_merge(NewConf, OldConf) ->
+    MergeConf0 = emqx_utils_maps:deep_merge(OldConf, NewConf),
+    NewSources = merge_sources(NewConf, OldConf),
+    do_pre_config_replace(MergeConf0#{<<"sources">> := NewSources}, OldConf).
+
 %% override the entire config when updating the root key
 %% emqx_conf:update(?ROOT_KEY, Conf);
 do_pre_config_replace(Conf, Conf) ->
@@ -629,3 +636,77 @@ check_acl_file_rules(Path, Rules) ->
     after
         _ = file:delete(TmpPath)
     end.
+
+merge_sources(OldConf, NewConf) ->
+    Default = [emqx_authz_schema:default_authz()],
+    NewSources0 = maps:get(<<"sources">>, NewConf, Default),
+    OriginSources0 = maps:get(<<"sources">>, OldConf, Default),
+    {OriginSource, NewSources} =
+        lists:foldl(
+            fun(Old = #{<<"type">> := Type}, {OriginAcc, NewAcc}) ->
+                case search(Type, NewAcc) of
+                    not_found ->
+                        {[Old | OriginAcc], NewAcc};
+                    {New, NewAcc1} ->
+                        MergeSource = emqx_utils_maps:deep_merge(Old, New),
+                        {[MergeSource | OriginAcc], NewAcc1}
+                end
+            end,
+            {[], NewSources0},
+            OriginSources0
+        ),
+    lists:reverse(OriginSource) ++ NewSources.
+
+search(Type, Sources) ->
+    case lists:splitwith(fun(T) -> type(T) =/= type(Type) end, Sources) of
+        {_Front, []} -> not_found;
+        {Front, [Target | Rear]} -> {Target, Front ++ Rear}
+    end.
+
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+-compile(nowarn_export_all).
+-compile(export_all).
+
+merge_sources_test() ->
+    Default = [emqx_authz_schema:default_authz()],
+    Http = #{<<"type">> => <<"http">>, <<"enable">> => true},
+    Mysql = #{<<"type">> => <<"mysql">>, <<"enable">> => true},
+    Mongo = #{<<"type">> => <<"mongodb">>, <<"enable">> => true},
+    Redis = #{<<"type">> => <<"redis">>, <<"enable">> => true},
+    HttpDisable = Http#{<<"enable">> => false},
+    MysqlDisable = Mysql#{<<"enable">> => false},
+    MongoDisable = Mongo#{<<"enable">> => false},
+
+    %% has default source
+    ?assertEqual(Default, merge_sources(#{}, #{})),
+    ?assertEqual([], merge_sources(#{<<"sources">> => []}, #{<<"sources">> => []})),
+    ?assertEqual(Default, merge_sources(#{}, #{<<"sources">> => []})),
+
+    %% add
+    ?assertEqual(
+        [Http, Mysql, Mongo, Redis],
+        merge_sources(
+            #{<<"sources">> => [Http, Mysql]},
+            #{<<"sources">> => [Mongo, Redis]}
+        )
+    ),
+    %% replace
+    ?assertEqual(
+        [HttpDisable, MysqlDisable],
+        merge_sources(
+            #{<<"sources">> => [Http, Mysql]},
+            #{<<"sources">> => [HttpDisable, MysqlDisable]}
+        )
+    ),
+    %% add + replace + change position
+    ?assertEqual(
+        [HttpDisable, Mysql, MongoDisable, Redis],
+        merge_sources(
+            #{<<"sources">> => [Http, Mysql, Mongo]},
+            #{<<"sources">> => [MongoDisable, HttpDisable, Redis]}
+        )
+    ),
+    ok.
+
+-endif.