From b8cd1c90203f8370ad510e4176962b8b46fe817e Mon Sep 17 00:00:00 2001 From: Thales Macedo Garitezi Date: Wed, 20 Mar 2024 14:59:32 -0300 Subject: [PATCH] feat(message validation api): add enable/disable HTTP API --- .../src/emqx_message_validation_http_api.erl | 68 ++++++++++++++++++- ...emqx_message_validation_http_api_SUITE.erl | 61 +++++++++++++++++ .../emqx_message_validation_http_api.hocon | 6 ++ 3 files changed, 133 insertions(+), 2 deletions(-) diff --git a/apps/emqx_message_validation/src/emqx_message_validation_http_api.erl b/apps/emqx_message_validation/src/emqx_message_validation_http_api.erl index b024ca09e..272abbbcf 100644 --- a/apps/emqx_message_validation/src/emqx_message_validation_http_api.erl +++ b/apps/emqx_message_validation/src/emqx_message_validation_http_api.erl @@ -23,7 +23,8 @@ -export([ '/message_validations'/2, '/message_validations/reorder'/2, - '/message_validations/validation/:name'/2 + '/message_validations/validation/:name'/2, + '/message_validations/validation/:name/enable/:enable'/2 ]). %%------------------------------------------------------------------------------------------------- @@ -45,7 +46,8 @@ paths() -> [ "/message_validations", "/message_validations/reorder", - "/message_validations/validation/:name" + "/message_validations/validation/:name", + "/message_validations/validation/:name/enable/:enable" ]. schema("/message_validations") -> @@ -170,6 +172,22 @@ schema("/message_validations/validation/:name") -> 404 => error_schema('NOT_FOUND', "Validation not found") } } + }; +schema("/message_validations/validation/:name/enable/:enable") -> + #{ + 'operationId' => '/message_validations/validation/:name/enable/:enable', + post => #{ + tags => ?TAGS, + summary => <<"Enable or disable validation">>, + description => ?DESC("enable_disable_validation"), + parameters => [param_path_name(), param_path_enable()], + responses => + #{ + 204 => <<"No content">>, + 404 => error_schema('NOT_FOUND', "Validation not found"), + 400 => error_schema('BAD_REQUEST', "Bad params") + } + } }. param_path_name() -> @@ -184,6 +202,17 @@ param_path_name() -> } )}. +param_path_enable() -> + {enable, + mk( + boolean(), + #{ + in => path, + required => true, + desc => ?DESC("param_path_enable") + } + )}. + fields(front) -> [{position, mk(front, #{default => front, required => true, in => body})}]; fields(rear) -> @@ -261,6 +290,15 @@ fields(reorder) -> '/message_validations/reorder'(post, #{body := #{<<"order">> := Order}}) -> do_reorder(Order). +'/message_validations/validation/:name/enable/:enable'(post, #{ + bindings := #{name := Name, enable := Enable} +}) -> + with_validation( + Name, + fun(Validation) -> do_enable_disable(Validation, Enable) end, + not_found() + ). + %%------------------------------------------------------------------------------------------------- %% Internal fns %%------------------------------------------------------------------------------------------------- @@ -328,6 +366,15 @@ do_reorder(Order) -> ?BAD_REQUEST(Error) end. +do_enable_disable(Validation, Enable) -> + RawValidation = make_serializable(Validation), + case emqx_message_validation:update(RawValidation#{<<"enable">> => Enable}) of + {ok, _} -> + ?NO_CONTENT; + {error, Reason} -> + ?BAD_REQUEST(Reason) + end. + with_validation(Name, FoundFn, NotFoundFn) -> case emqx_message_validation:lookup(Name) of {ok, Validation} -> @@ -345,3 +392,20 @@ return(Response) -> not_found() -> return(?NOT_FOUND(<<"Validation not found">>)). + +make_serializable(Validation) -> + Schema = emqx_message_validation_schema, + RawConfig = #{ + <<"message_validation">> => #{ + <<"validations">> => + [emqx_utils_maps:binary_key_map(Validation)] + } + }, + #{ + <<"message_validation">> := #{ + <<"validations">> := + [Serialized] + } + } = + hocon_tconf:make_serializable(Schema, RawConfig, #{}), + Serialized. diff --git a/apps/emqx_message_validation/test/emqx_message_validation_http_api_SUITE.erl b/apps/emqx_message_validation/test/emqx_message_validation_http_api_SUITE.erl index 141fc74af..8f052a147 100644 --- a/apps/emqx_message_validation/test/emqx_message_validation_http_api_SUITE.erl +++ b/apps/emqx_message_validation/test/emqx_message_validation_http_api_SUITE.erl @@ -182,6 +182,18 @@ reorder(Order) -> ct:pal("reorder result:\n ~p", [Res]), simplify_result(Res). +enable(Name) -> + Path = emqx_mgmt_api_test_util:api_path([api_root(), "validation", Name, "enable", "true"]), + Res = request(post, Path, _Params = []), + ct:pal("enable result:\n ~p", [Res]), + simplify_result(Res). + +disable(Name) -> + Path = emqx_mgmt_api_test_util:api_path([api_root(), "validation", Name, "enable", "false"]), + Res = request(post, Path, _Params = []), + ct:pal("disable result:\n ~p", [Res]), + simplify_result(Res). + connect(ClientId) -> connect(ClientId, _IsPersistent = false). @@ -600,6 +612,55 @@ t_action_ignore(_Config) -> ), ok. +t_enable_disable_via_api_endpoint(_Config) -> + Topic = <<"t">>, + + Name1 = <<"foo">>, + AlwaysFailCheck = sql_check(<<"select * where false">>), + Validation1 = validation(Name1, [AlwaysFailCheck], #{<<"topics">> => Topic}), + + {201, _} = insert(Validation1), + ?assertIndexOrder([Name1], Topic), + + C = connect(<<"c1">>), + {ok, _, [_]} = emqtt:subscribe(C, Topic), + + ok = publish(C, Topic, #{}), + ?assertNotReceive({publish, _}), + + %% already enabled + {204, _} = enable(Name1), + ?assertIndexOrder([Name1], Topic), + ?assertMatch({200, #{<<"enable">> := true}}, lookup(Name1)), + + ok = publish(C, Topic, #{}), + ?assertNotReceive({publish, _}), + + {204, _} = disable(Name1), + ?assertIndexOrder([], Topic), + ?assertMatch({200, #{<<"enable">> := false}}, lookup(Name1)), + + ok = publish(C, Topic, #{}), + ?assertReceive({publish, _}), + + %% already disabled + {204, _} = disable(Name1), + ?assertIndexOrder([], Topic), + ?assertMatch({200, #{<<"enable">> := false}}, lookup(Name1)), + + ok = publish(C, Topic, #{}), + ?assertReceive({publish, _}), + + %% Re-enable + {204, _} = enable(Name1), + ?assertIndexOrder([Name1], Topic), + ?assertMatch({200, #{<<"enable">> := true}}, lookup(Name1)), + + ok = publish(C, Topic, #{}), + ?assertNotReceive({publish, _}), + + ok. + %% Check the `all_pass' strategy t_all_pass(_Config) -> Name1 = <<"foo">>, diff --git a/rel/i18n/emqx_message_validation_http_api.hocon b/rel/i18n/emqx_message_validation_http_api.hocon index 6e549fe31..69a8ed78d 100644 --- a/rel/i18n/emqx_message_validation_http_api.hocon +++ b/rel/i18n/emqx_message_validation_http_api.hocon @@ -18,7 +18,13 @@ emqx_message_validation_http_api { reorder_validations.desc: """Reorder of all validations""" + enable_disable_validation.desc: + """Enable or disable a particular validation""" + param_path_name.desc: """Validation name""" + param_path_enable.desc: + """Enable or disable validation""" + }