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

fix: allow put plugin config without schema

JimMoen 1 год назад
Родитель
Сommit
25a9aa1797

+ 16 - 5
apps/emqx_management/src/emqx_mgmt_api_plugins.erl

@@ -20,6 +20,7 @@
 -include_lib("typerefl/include/types.hrl").
 -include_lib("emqx/include/logger.hrl").
 -include_lib("emqx_plugins/include/emqx_plugins.hrl").
+-include_lib("erlavro/include/erlavro.hrl").
 
 -dialyzer({no_match, [format_plugin_avsc_and_i18n/1]}).
 
@@ -506,14 +507,20 @@ plugin_config(get, #{bindings := #{name := NameVsn}}) ->
             {404, plugin_not_found_msg()}
     end;
 plugin_config(put, #{bindings := #{name := NameVsn}, body := AvroJsonMap}) ->
+    Nodes = emqx:running_nodes(),
     case emqx_plugins:describe(NameVsn) of
         {ok, _} ->
             case emqx_plugins:decode_plugin_config_map(NameVsn, AvroJsonMap) of
-                {ok, AvroValueConfig} ->
-                    Nodes = emqx:running_nodes(),
+                {ok, ?plugin_without_config_schema} ->
+                    %% no plugin avro schema, just put the json map it as-is
+                    _Res = emqx_mgmt_api_plugins_proto_v3:update_plugin_config(
+                        Nodes, NameVsn, AvroJsonMap, ?plugin_without_config_schema
+                    ),
+                    {204};
+                {ok, AvroValue} ->
                     %% cluster call with config in map (binary key-value)
                     _Res = emqx_mgmt_api_plugins_proto_v3:update_plugin_config(
-                        Nodes, NameVsn, AvroJsonMap, AvroValueConfig
+                        Nodes, NameVsn, AvroJsonMap, AvroValue
                     ),
                     {204};
                 {error, Reason} ->
@@ -604,9 +611,13 @@ ensure_action(Name, restart) ->
     ok.
 
 %% for RPC plugin avro encoded config update
-do_update_plugin_config(NameVsn, AvroJsonMap, PluginConfigMap) ->
+-spec do_update_plugin_config(
+    name_vsn(), map(), avro_value() | ?plugin_without_config_schema
+) ->
+    ok.
+do_update_plugin_config(NameVsn, AvroJsonMap, AvroValue) ->
     %% TODO: maybe use `PluginConfigMap` to validate config
-    emqx_plugins:put_config(NameVsn, AvroJsonMap, PluginConfigMap).
+    emqx_plugins:put_config(NameVsn, AvroJsonMap, AvroValue).
 
 %%--------------------------------------------------------------------
 %% Helper functions

+ 4 - 3
apps/emqx_management/src/proto/emqx_mgmt_api_plugins_proto_v3.erl

@@ -28,6 +28,7 @@
 ]).
 
 -include_lib("emqx/include/bpapi.hrl").
+-include_lib("emqx_plugins/include/emqx_plugins.hrl").
 
 introduced_in() ->
     "5.7.0".
@@ -56,14 +57,14 @@ ensure_action(Name, Action) ->
     [node()],
     binary() | string(),
     binary(),
-    map()
+    map() | ?plugin_without_config_schema
 ) ->
     emqx_rpc:multicall_result().
-update_plugin_config(Nodes, NameVsn, AvroJsonMap, PluginConfig) ->
+update_plugin_config(Nodes, NameVsn, AvroJsonMap, MaybeAvroValue) ->
     rpc:multicall(
         Nodes,
         emqx_mgmt_api_plugins,
         do_update_plugin_config,
-        [NameVsn, AvroJsonMap, PluginConfig],
+        [NameVsn, AvroJsonMap, MaybeAvroValue],
         10000
     ).

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

@@ -25,6 +25,7 @@
 -define(CONFIG_FORMAT_MAP, config_format_map).
 
 -define(plugin_conf_not_found, plugin_conf_not_found).
+-define(plugin_without_config_schema, plugin_without_config_schema).
 
 -type schema_name() :: binary().
 -type avsc_path() :: string().

+ 36 - 14
apps/emqx_plugins/src/emqx_plugins.erl

@@ -329,10 +329,11 @@ get_config_bin(NameVsn) ->
 
 %% @doc Update plugin's config.
 %% RPC call from Management API or CLI.
-%% the plugin config Json Map and plugin config ALWAYS be valid before calling this function.
-put_config(NameVsn, ConfigJsonMap, DecodedPluginConfig) when not is_binary(NameVsn) ->
-    put_config(bin(NameVsn), ConfigJsonMap, DecodedPluginConfig);
-put_config(NameVsn, ConfigJsonMap, _DecodedPluginConfig) ->
+%% The plugin config Json Map was valid by avro schema
+%% Or: if no and plugin config ALWAYS be valid before calling this function.
+put_config(NameVsn, ConfigJsonMap, AvroValue) when not is_binary(NameVsn) ->
+    put_config(bin(NameVsn), ConfigJsonMap, AvroValue);
+put_config(NameVsn, ConfigJsonMap, _AvroValue) ->
     HoconBin = hocon_pp:do(ConfigJsonMap, #{}),
     ok = backup_and_write_hocon_bin(NameVsn, HoconBin),
     %% TODO: callback in plugin's on_config_changed (config update by mgmt API)
@@ -370,10 +371,30 @@ list() ->
 %%--------------------------------------------------------------------
 %% Package utils
 
--spec decode_plugin_config_map(name_vsn(), map() | binary()) -> {ok, map()} | {error, any()}.
-decode_plugin_config_map(NameVsn, AvroJsonMap) when is_map(AvroJsonMap) ->
-    decode_plugin_config_map(NameVsn, emqx_utils_json:encode(AvroJsonMap));
-decode_plugin_config_map(NameVsn, AvroJsonBin) ->
+-spec decode_plugin_config_map(name_vsn(), map() | binary()) ->
+    {ok, map() | ?plugin_without_config_schema}
+    | {error, any()}.
+decode_plugin_config_map(NameVsn, AvroJsonMap) ->
+    case with_plugin_avsc(NameVsn) of
+        true ->
+            case emqx_plugins_serde:lookup_serde(NameVsn) of
+                {error, not_found} ->
+                    Reason = "plugin_config_schema_serde_not_found",
+                    ?SLOG(error, #{
+                        msg => Reason, name_vsn => NameVsn, plugin_with_avro_schema => true
+                    }),
+                    {error, Reason};
+                {ok, _Serde} ->
+                    do_decode_plugin_config_map(NameVsn, AvroJsonMap)
+            end;
+        false ->
+            ?SLOG(debug, #{name_vsn => NameVsn, plugin_with_avro_schema => false}),
+            {ok, ?plugin_without_config_schema}
+    end.
+
+do_decode_plugin_config_map(NameVsn, AvroJsonMap) when is_map(AvroJsonMap) ->
+    do_decode_plugin_config_map(NameVsn, emqx_utils_json:encode(AvroJsonMap));
+do_decode_plugin_config_map(NameVsn, AvroJsonBin) ->
     case emqx_plugins_serde:decode(NameVsn, AvroJsonBin) of
         {ok, Config} -> {ok, Config};
         {error, ReasonMap} -> {error, ReasonMap}
@@ -1205,14 +1226,15 @@ cp_default_config_file(NameVsn) ->
     end.
 
 ensure_config_map(NameVsn) ->
-    with_plugin_avsc(NameVsn) andalso
-        do_ensure_config_map(NameVsn).
-
-do_ensure_config_map(NameVsn) ->
     case read_plugin_hocon(NameVsn, #{read_mode => ?JSON_MAP}) of
         {ok, ConfigJsonMap} ->
-            {ok, Config} = decode_plugin_config_map(NameVsn, ConfigJsonMap),
-            put_config(NameVsn, ConfigJsonMap, Config);
+            case with_plugin_avsc(NameVsn) of
+                true ->
+                    {ok, AvroValue} = decode_plugin_config_map(NameVsn, ConfigJsonMap),
+                    put_config(NameVsn, ConfigJsonMap, AvroValue);
+                false ->
+                    put_config(NameVsn, ConfigJsonMap, ?plugin_without_config_schema)
+            end;
         _ ->
             ?SLOG(warning, #{msg => "failed_to_read_plugin_config_hocon", name_vsn => NameVsn}),
             ok