emqx_rule_api_schema.erl 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. %%--------------------------------------------------------------------
  2. %% Copyright (c) 2022-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
  3. %%
  4. %% Licensed under the Apache License, Version 2.0 (the "License");
  5. %% you may not use this file except in compliance with the License.
  6. %% You may obtain a copy of the License at
  7. %%
  8. %% http://www.apache.org/licenses/LICENSE-2.0
  9. %%
  10. %% Unless required by applicable law or agreed to in writing, software
  11. %% distributed under the License is distributed on an "AS IS" BASIS,
  12. %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. %% See the License for the specific language governing permissions and
  14. %% limitations under the License.
  15. %%--------------------------------------------------------------------
  16. -module(emqx_rule_api_schema).
  17. -behaviour(hocon_schema).
  18. -include_lib("typerefl/include/types.hrl").
  19. -include_lib("hocon/include/hoconsc.hrl").
  20. -include_lib("emqx/include/logger.hrl").
  21. -export([check_params/2]).
  22. -export([roots/0, fields/1]).
  23. -type tag() :: rule_creation | rule_test | rule_engine.
  24. -spec check_params(map(), tag()) -> {ok, map()} | {error, term()}.
  25. check_params(Params, Tag) ->
  26. BTag = atom_to_binary(Tag),
  27. Opts = #{atom_key => true, required => false},
  28. try hocon_tconf:check_plain(?MODULE, #{BTag => Params}, Opts, [Tag]) of
  29. #{Tag := Checked} -> {ok, Checked}
  30. catch
  31. throw:Reason ->
  32. ?SLOG(error, #{
  33. msg => "check_rule_params_failed",
  34. reason => Reason
  35. }),
  36. {error, Reason}
  37. end.
  38. %%======================================================================================
  39. %% Hocon Schema Definitions
  40. roots() ->
  41. [
  42. {"rule_engine", sc(ref("rule_engine"), #{desc => ?DESC("root_rule_engine")})},
  43. {"rule_creation", sc(ref("rule_creation"), #{desc => ?DESC("root_rule_creation")})},
  44. {"rule_info", sc(ref("rule_info"), #{desc => ?DESC("root_rule_info")})},
  45. {"rule_events", sc(ref("rule_events"), #{desc => ?DESC("root_rule_events")})},
  46. {"rule_test", sc(ref("rule_test"), #{desc => ?DESC("root_rule_test")})}
  47. ].
  48. fields("rule_engine") ->
  49. emqx_rule_engine_schema:rule_engine_settings();
  50. fields("rule_creation") ->
  51. emqx_rule_engine_schema:fields("rules");
  52. fields("rule_info") ->
  53. [
  54. rule_id(),
  55. {"from",
  56. sc(
  57. hoconsc:array(binary()),
  58. #{desc => ?DESC("ri_from"), example => "t/#"}
  59. )},
  60. {"created_at",
  61. sc(
  62. binary(),
  63. #{
  64. desc => ?DESC("ri_created_at"),
  65. example => "2021-12-01T15:00:43.153+08:00"
  66. }
  67. )}
  68. ] ++ fields("rule_creation");
  69. fields("rule_metrics") ->
  70. [
  71. rule_id(),
  72. {"metrics", sc(ref("metrics"), #{desc => ?DESC("ri_metrics")})},
  73. {"node_metrics",
  74. sc(
  75. hoconsc:array(ref("node_metrics")),
  76. #{desc => ?DESC("ri_node_metrics")}
  77. )}
  78. ];
  79. %% TODO: we can delete this API if the Dashboard not depends on it
  80. fields("rule_events") ->
  81. ETopics = emqx_rule_events:event_topics_enum(),
  82. [
  83. {"event", sc(hoconsc:enum(ETopics), #{desc => ?DESC("rs_event"), required => true})},
  84. {"title", sc(binary(), #{desc => ?DESC("rs_title"), example => "some title"})},
  85. {"description", sc(binary(), #{desc => ?DESC("rs_description"), example => "some desc"})},
  86. {"columns", sc(map(), #{desc => ?DESC("rs_columns")})},
  87. {"test_columns", sc(map(), #{desc => ?DESC("rs_test_columns")})},
  88. {"sql_example", sc(binary(), #{desc => ?DESC("rs_sql_example")})}
  89. ];
  90. fields("rule_test") ->
  91. [
  92. {"context",
  93. sc(
  94. hoconsc:union([
  95. ref("ctx_pub"),
  96. ref("ctx_sub"),
  97. ref("ctx_unsub"),
  98. ref("ctx_delivered"),
  99. ref("ctx_acked"),
  100. ref("ctx_dropped"),
  101. ref("ctx_connected"),
  102. ref("ctx_disconnected"),
  103. ref("ctx_connack"),
  104. ref("ctx_check_authz_complete"),
  105. ref("ctx_bridge_mqtt")
  106. ]),
  107. #{
  108. desc => ?DESC("test_context"),
  109. default => #{}
  110. }
  111. )},
  112. {"sql", sc(binary(), #{desc => ?DESC("test_sql"), required => true})}
  113. ];
  114. fields("metrics") ->
  115. [
  116. {"matched",
  117. sc(non_neg_integer(), #{
  118. desc => ?DESC("metrics_sql_matched")
  119. })},
  120. {"matched.rate", sc(float(), #{desc => ?DESC("metrics_sql_matched_rate")})},
  121. {"matched.rate.max", sc(float(), #{desc => ?DESC("metrics_sql_matched_rate_max")})},
  122. {"matched.rate.last5m",
  123. sc(
  124. float(),
  125. #{desc => ?DESC("metrics_sql_matched_rate_last5m")}
  126. )},
  127. {"passed", sc(non_neg_integer(), #{desc => ?DESC("metrics_sql_passed")})},
  128. {"failed", sc(non_neg_integer(), #{desc => ?DESC("metrics_sql_failed")})},
  129. {"failed.exception",
  130. sc(non_neg_integer(), #{
  131. desc => ?DESC("metrics_sql_failed_exception")
  132. })},
  133. {"failed.unknown",
  134. sc(non_neg_integer(), #{
  135. desc => ?DESC("metrics_sql_failed_unknown")
  136. })},
  137. {"actions.total",
  138. sc(non_neg_integer(), #{
  139. desc => ?DESC("metrics_actions_total")
  140. })},
  141. {"actions.success",
  142. sc(non_neg_integer(), #{
  143. desc => ?DESC("metrics_actions_success")
  144. })},
  145. {"actions.failed",
  146. sc(non_neg_integer(), #{
  147. desc => ?DESC("metrics_actions_failed")
  148. })},
  149. {"actions.failed.out_of_service",
  150. sc(non_neg_integer(), #{
  151. desc => ?DESC("metrics_actions_failed_out_of_service")
  152. })},
  153. {"actions.failed.unknown",
  154. sc(non_neg_integer(), #{
  155. desc => ?DESC("metrics_actions_failed_unknown")
  156. })}
  157. ];
  158. fields("node_metrics") ->
  159. [{"node", sc(binary(), #{desc => ?DESC("node_node"), example => "emqx@127.0.0.1"})}] ++
  160. fields("metrics");
  161. fields("ctx_pub") ->
  162. [
  163. {"event_type", event_type_sc(message_publish)},
  164. {"id", sc(binary(), #{desc => ?DESC("event_id")})}
  165. | msg_event_common_fields()
  166. ];
  167. fields("ctx_sub") ->
  168. [
  169. {"event_type", event_type_sc(session_subscribed)}
  170. | msg_event_common_fields()
  171. ];
  172. fields("ctx_unsub") ->
  173. [
  174. {"event_type", event_type_sc(session_unsubscribed)}
  175. | proplists:delete("event_type", fields("ctx_sub"))
  176. ];
  177. fields("ctx_delivered") ->
  178. [
  179. {"event_type", event_type_sc(message_delivered)},
  180. {"id", sc(binary(), #{desc => ?DESC("event_id")})},
  181. {"from_clientid", sc(binary(), #{desc => ?DESC("event_from_clientid")})},
  182. {"from_username", sc(binary(), #{desc => ?DESC("event_from_username")})}
  183. | msg_event_common_fields()
  184. ];
  185. fields("ctx_acked") ->
  186. [
  187. {"event_type", event_type_sc(message_acked)}
  188. | proplists:delete("event_type", fields("ctx_delivered"))
  189. ];
  190. fields("ctx_dropped") ->
  191. [
  192. {"event_type", event_type_sc(message_dropped)},
  193. {"id", sc(binary(), #{desc => ?DESC("event_id")})},
  194. {"reason", sc(binary(), #{desc => ?DESC("event_ctx_dropped")})}
  195. | msg_event_common_fields()
  196. ];
  197. fields("ctx_connected") ->
  198. [
  199. {"event_type", event_type_sc(client_connected)},
  200. {"clientid", sc(binary(), #{desc => ?DESC("event_clientid")})},
  201. {"username", sc(binary(), #{desc => ?DESC("event_username")})},
  202. {"mountpoint", sc(binary(), #{desc => ?DESC("event_mountpoint")})},
  203. {"peername", sc(binary(), #{desc => ?DESC("event_peername")})},
  204. {"sockname", sc(binary(), #{desc => ?DESC("event_sockname")})},
  205. {"proto_name", sc(binary(), #{desc => ?DESC("event_proto_name")})},
  206. {"proto_ver", sc(binary(), #{desc => ?DESC("event_proto_ver")})},
  207. {"keepalive", sc(integer(), #{desc => ?DESC("event_keepalive")})},
  208. {"clean_start", sc(boolean(), #{desc => ?DESC("event_clean_start"), default => true})},
  209. {"expiry_interval", sc(integer(), #{desc => ?DESC("event_expiry_interval")})},
  210. {"is_bridge", sc(boolean(), #{desc => ?DESC("event_is_bridge"), default => false})},
  211. {"connected_at",
  212. sc(integer(), #{
  213. desc => ?DESC("event_connected_at")
  214. })}
  215. ];
  216. fields("ctx_disconnected") ->
  217. [
  218. {"event_type", event_type_sc(client_disconnected)},
  219. {"clientid", sc(binary(), #{desc => ?DESC("event_clientid")})},
  220. {"username", sc(binary(), #{desc => ?DESC("event_username")})},
  221. {"reason", sc(binary(), #{desc => ?DESC("event_ctx_disconnected_reason")})},
  222. {"peername", sc(binary(), #{desc => ?DESC("event_peername")})},
  223. {"sockname", sc(binary(), #{desc => ?DESC("event_sockname")})},
  224. {"disconnected_at",
  225. sc(integer(), #{
  226. desc => ?DESC("event_ctx_disconnected_da")
  227. })}
  228. ];
  229. fields("ctx_connack") ->
  230. [
  231. {"event_type", event_type_sc(client_connack)},
  232. {"reason_code", sc(binary(), #{desc => ?DESC("event_ctx_connack_reason_code")})},
  233. {"clientid", sc(binary(), #{desc => ?DESC("event_clientid")})},
  234. {"clean_start", sc(boolean(), #{desc => ?DESC("event_clean_start"), default => true})},
  235. {"username", sc(binary(), #{desc => ?DESC("event_username")})},
  236. {"peername", sc(binary(), #{desc => ?DESC("event_peername")})},
  237. {"sockname", sc(binary(), #{desc => ?DESC("event_sockname")})},
  238. {"proto_name", sc(binary(), #{desc => ?DESC("event_proto_name")})},
  239. {"proto_ver", sc(binary(), #{desc => ?DESC("event_proto_ver")})},
  240. {"keepalive", sc(integer(), #{desc => ?DESC("event_keepalive")})},
  241. {"expiry_interval", sc(integer(), #{desc => ?DESC("event_expiry_interval")})},
  242. {"connected_at",
  243. sc(integer(), #{
  244. desc => ?DESC("event_connected_at")
  245. })}
  246. ];
  247. fields("ctx_check_authz_complete") ->
  248. [
  249. {"event_type", event_type_sc(client_check_authz_complete)},
  250. {"clientid", sc(binary(), #{desc => ?DESC("event_clientid")})},
  251. {"username", sc(binary(), #{desc => ?DESC("event_username")})},
  252. {"peerhost", sc(binary(), #{desc => ?DESC("event_peerhost")})},
  253. {"topic", sc(binary(), #{desc => ?DESC("event_topic")})},
  254. {"action", sc(binary(), #{desc => ?DESC("event_action")})},
  255. {"authz_source", sc(binary(), #{desc => ?DESC("event_authz_source")})},
  256. {"result", sc(binary(), #{desc => ?DESC("event_result")})}
  257. ];
  258. fields("ctx_bridge_mqtt") ->
  259. [
  260. {"event_type", event_type_sc('$bridges/mqtt:*')},
  261. {"id", sc(binary(), #{desc => ?DESC("event_id")})},
  262. {"payload", sc(binary(), #{desc => ?DESC("event_payload")})},
  263. {"topic", sc(binary(), #{desc => ?DESC("event_topic")})},
  264. {"server", sc(binary(), #{desc => ?DESC("event_server")})},
  265. {"dup", sc(binary(), #{desc => ?DESC("event_dup")})},
  266. {"retain", sc(binary(), #{desc => ?DESC("event_retain")})},
  267. {"message_received_at", publish_received_at_sc()},
  268. qos()
  269. ].
  270. qos() ->
  271. {"qos", sc(emqx_schema:qos(), #{desc => ?DESC("event_qos")})}.
  272. rule_id() ->
  273. {"id",
  274. sc(
  275. binary(),
  276. #{
  277. desc => ?DESC("rule_id"),
  278. required => true,
  279. example => "293fb66f"
  280. }
  281. )}.
  282. sc(Type, Meta) -> hoconsc:mk(Type, Meta).
  283. ref(Field) -> hoconsc:ref(?MODULE, Field).
  284. event_type_sc(Event) ->
  285. sc(Event, #{desc => ?DESC("event_event_type"), required => true}).
  286. publish_received_at_sc() ->
  287. sc(integer(), #{desc => ?DESC("event_publish_received_at")}).
  288. msg_event_common_fields() ->
  289. [
  290. {"clientid", sc(binary(), #{desc => ?DESC("event_clientid")})},
  291. {"username", sc(binary(), #{desc => ?DESC("event_username")})},
  292. {"payload", sc(binary(), #{desc => ?DESC("event_payload")})},
  293. {"peerhost", sc(binary(), #{desc => ?DESC("event_peerhost")})},
  294. {"topic", sc(binary(), #{desc => ?DESC("event_topic")})},
  295. {"publish_received_at", publish_received_at_sc()},
  296. qos()
  297. ].