diff --git a/apps/emqx_management/src/emqx_management.app.src b/apps/emqx_management/src/emqx_management.app.src index f16156c35..0951bee35 100644 --- a/apps/emqx_management/src/emqx_management.app.src +++ b/apps/emqx_management/src/emqx_management.app.src @@ -2,7 +2,7 @@ {application, emqx_management, [ {description, "EMQX Management API and CLI"}, % strict semver, bump manually! - {vsn, "5.0.29"}, + {vsn, "5.0.30"}, {modules, []}, {registered, [emqx_management_sup]}, {applications, [kernel, stdlib, emqx_plugins, minirest, emqx, emqx_ctl, emqx_bridge_http]}, diff --git a/apps/emqx_management/src/emqx_mgmt_api_clients.erl b/apps/emqx_management/src/emqx_mgmt_api_clients.erl index d9b6d9bd5..6b4793b1c 100644 --- a/apps/emqx_management/src/emqx_mgmt_api_clients.erl +++ b/apps/emqx_management/src/emqx_mgmt_api_clients.erl @@ -647,7 +647,7 @@ set_keepalive(put, #{bindings := #{clientid := ClientID}, body := Body}) -> error -> {400, 'BAD_REQUEST', "Interval Not Found"}; {ok, Interval} -> - case emqx_mgmt:set_keepalive(emqx_mgmt_util:urldecode(ClientID), Interval) of + case emqx_mgmt:set_keepalive(ClientID, Interval) of ok -> lookup(#{clientid => ClientID}); {error, not_found} -> {404, ?CLIENTID_NOT_FOUND}; {error, Reason} -> {400, #{code => 'PARAMS_ERROR', message => Reason}} diff --git a/apps/emqx_rule_engine/src/emqx_rule_actions.erl b/apps/emqx_rule_engine/src/emqx_rule_actions.erl index ce74203a4..276f8d0e0 100644 --- a/apps/emqx_rule_engine/src/emqx_rule_actions.erl +++ b/apps/emqx_rule_engine/src/emqx_rule_actions.erl @@ -45,11 +45,15 @@ %%-------------------------------------------------------------------- parse_action(#{function := ActionFunc} = Action) -> {Mod, Func} = parse_action_func(ActionFunc), - #{ - mod => Mod, - func => Func, - args => pre_process_args(Mod, Func, maps:get(args, Action, #{})) - }. + Res = #{mod => Mod, func => Func}, + %% builtin_action_console don't have args field. + %% Attempting to save args to the console action config could cause validation issues + case Action of + #{args := Args} -> + Res#{args => pre_process_args(Mod, Func, Args)}; + _ -> + Res + end. %%-------------------------------------------------------------------- %% callbacks of emqx_rule_action diff --git a/apps/emqx_rule_engine/src/emqx_rule_engine.app.src b/apps/emqx_rule_engine/src/emqx_rule_engine.app.src index 3a88a3e57..04ba60378 100644 --- a/apps/emqx_rule_engine/src/emqx_rule_engine.app.src +++ b/apps/emqx_rule_engine/src/emqx_rule_engine.app.src @@ -2,7 +2,7 @@ {application, emqx_rule_engine, [ {description, "EMQX Rule Engine"}, % strict semver, bump manually! - {vsn, "5.0.25"}, + {vsn, "5.0.26"}, {modules, []}, {registered, [emqx_rule_engine_sup, emqx_rule_engine]}, {applications, [kernel, stdlib, rulesql, getopt, emqx_ctl, uuid]}, diff --git a/apps/emqx_rule_engine/src/emqx_rule_engine_api.erl b/apps/emqx_rule_engine/src/emqx_rule_engine_api.erl index 79be197aa..cb177630b 100644 --- a/apps/emqx_rule_engine/src/emqx_rule_engine_api.erl +++ b/apps/emqx_rule_engine/src/emqx_rule_engine_api.erl @@ -525,6 +525,10 @@ do_format_action(#{mod := Mod, func := Func, args := Args}) -> #{ function => printable_function_name(Mod, Func), args => maps:remove(preprocessed_tmpl, Args) + }; +do_format_action(#{mod := Mod, func := Func}) -> + #{ + function => printable_function_name(Mod, Func) }. printable_function_name(emqx_rule_actions, Func) -> diff --git a/apps/emqx_rule_engine/src/emqx_rule_engine_schema.erl b/apps/emqx_rule_engine/src/emqx_rule_engine_schema.erl index ba4056421..d0019a1c5 100644 --- a/apps/emqx_rule_engine/src/emqx_rule_engine_schema.erl +++ b/apps/emqx_rule_engine/src/emqx_rule_engine_schema.erl @@ -98,10 +98,26 @@ fields("builtin_action_republish") -> ]; fields("builtin_action_console") -> [ - {function, ?HOCON(console, #{desc => ?DESC("console_function")})} + {function, ?HOCON(console, #{desc => ?DESC("console_function")})}, %% we may support some args for the console action in the future - %, {args, sc(map(), #{desc => "The arguments of the built-in 'console' action", - % default => #{}})} + + %% "args" needs to be a reserved/ignored field in the schema + %% to maintain compatibility with rule data that may contain + %% it due to a validation bug in previous versions. + + %% The "args" field was not validated by the HOCON schema before 5.2.0, + %% which allowed rules to be created with invalid "args" data. + %% In 5.2.1 the validation was added, + %% so existing rules saved with invalid "args" would now fail validation + %% To maintain backward compatibility for existing rule data that may contain invalid "args", + %% the field needs to be included in the schema even though it is not a valid field. + {args, + ?HOCON(map(), #{ + deprecated => true, + importance => ?IMPORTANCE_HIDDEN, + desc => "The arguments of the built-in 'console' action", + default => #{} + })} ]; fields("user_provided_function") -> [ diff --git a/apps/emqx_rule_engine/test/emqx_rule_engine_schema_tests.erl b/apps/emqx_rule_engine/test/emqx_rule_engine_schema_tests.erl index 27dbafdc8..e3cff53e9 100644 --- a/apps/emqx_rule_engine/test/emqx_rule_engine_schema_tests.erl +++ b/apps/emqx_rule_engine/test/emqx_rule_engine_schema_tests.erl @@ -30,7 +30,7 @@ rule_engine.rules.my_rule { metadata = {created_at = 1693918992079} sql = \"select * from \\\"t/topic\\\" \" actions = [ - {function = console} + {function = console, args = {test = 1}} { function = republish args = { payload = \"${.}\"