diff --git a/apps/emqx/rebar.config b/apps/emqx/rebar.config index 3626d0858..9953dd3fc 100644 --- a/apps/emqx/rebar.config +++ b/apps/emqx/rebar.config @@ -30,7 +30,7 @@ {esockd, {git, "https://github.com/emqx/esockd", {tag, "5.11.1"}}}, {ekka, {git, "https://github.com/emqx/ekka", {tag, "0.18.4"}}}, {gen_rpc, {git, "https://github.com/emqx/gen_rpc", {tag, "3.3.1"}}}, - {hocon, {git, "https://github.com/emqx/hocon.git", {tag, "0.40.4"}}}, + {hocon, {git, "https://github.com/emqx/hocon.git", {tag, "0.41.0"}}}, {emqx_http_lib, {git, "https://github.com/emqx/emqx_http_lib.git", {tag, "0.5.3"}}}, {pbkdf2, {git, "https://github.com/emqx/erlang-pbkdf2.git", {tag, "2.0.4"}}}, {recon, {git, "https://github.com/ferd/recon", {tag, "2.5.1"}}}, diff --git a/apps/emqx_auth/src/emqx_authn/emqx_authn_api.erl b/apps/emqx_auth/src/emqx_authn/emqx_authn_api.erl index 7f0413fbb..07584c76e 100644 --- a/apps/emqx_auth/src/emqx_authn/emqx_authn_api.erl +++ b/apps/emqx_auth/src/emqx_authn/emqx_authn_api.erl @@ -42,7 +42,8 @@ -export([ api_spec/0, paths/0, - schema/1 + schema/1, + namespace/0 ]). -export([ @@ -95,6 +96,8 @@ -elvis([{elvis_style, god_modules, disable}]). +namespace() -> undefined. + api_spec() -> emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}). diff --git a/apps/emqx_auth/src/emqx_authz/emqx_authz_api_sources.erl b/apps/emqx_auth/src/emqx_authz/emqx_authz_api_sources.erl index c2296f129..0af910d18 100644 --- a/apps/emqx_auth/src/emqx_authz/emqx_authz_api_sources.erl +++ b/apps/emqx_auth/src/emqx_authz/emqx_authz_api_sources.erl @@ -41,7 +41,8 @@ api_spec/0, paths/0, schema/1, - fields/1 + fields/1, + namespace/0 ]). -export([ @@ -56,6 +57,9 @@ -define(TAGS, [<<"Authorization">>]). +namespace() -> + undefined. + api_spec() -> emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}). diff --git a/apps/emqx_auth/src/emqx_authz/emqx_authz_schema.erl b/apps/emqx_auth/src/emqx_authz/emqx_authz_schema.erl index 426c7a9f6..5a73f5991 100644 --- a/apps/emqx_auth/src/emqx_authz/emqx_authz_schema.erl +++ b/apps/emqx_auth/src/emqx_authz/emqx_authz_schema.erl @@ -22,7 +22,8 @@ -export([ roots/0, fields/1, - desc/1 + desc/1, + namespace/0 ]). -export([ @@ -65,6 +66,8 @@ roots() -> []. +namespace() -> undefined. + fields(?CONF_NS) -> emqx_schema:authz_fields() ++ authz_fields(); fields("metrics_status_fields") -> diff --git a/apps/emqx_auth_mnesia/src/emqx_authz_api_mnesia.erl b/apps/emqx_auth_mnesia/src/emqx_authz_api_mnesia.erl index 5fc1ec280..cab596da3 100644 --- a/apps/emqx_auth_mnesia/src/emqx_authz_api_mnesia.erl +++ b/apps/emqx_auth_mnesia/src/emqx_authz_api_mnesia.erl @@ -35,7 +35,8 @@ api_spec/0, paths/0, schema/1, - fields/1 + fields/1, + namespace/0 ]). %% operation funs @@ -69,6 +70,8 @@ -define(PUT_MAP_EXAMPLE, in_put_requestBody). -define(POST_ARRAY_EXAMPLE, in_post_requestBody). +namespace() -> undefined. + api_spec() -> emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}). diff --git a/apps/emqx_bridge/src/schema/emqx_bridge_enterprise.erl b/apps/emqx_bridge/src/schema/emqx_bridge_enterprise.erl index cc4c6eb01..3822c7a34 100644 --- a/apps/emqx_bridge/src/schema/emqx_bridge_enterprise.erl +++ b/apps/emqx_bridge/src/schema/emqx_bridge_enterprise.erl @@ -13,7 +13,8 @@ examples/1, resource_type/1, bridge_impl_module/1, - fields/1 + fields/1, + namespace/0 ]). api_schemas(Method) -> @@ -139,6 +140,8 @@ bridge_impl_module(azure_event_hub_producer) -> bridge_impl_module(_BridgeType) -> undefined. +namespace() -> undefined. + fields(bridges) -> [ {hstreamdb, diff --git a/apps/emqx_bridge_cassandra/src/emqx_bridge_cassandra_connector.erl b/apps/emqx_bridge_cassandra/src/emqx_bridge_cassandra_connector.erl index 872ccb532..a84d3912b 100644 --- a/apps/emqx_bridge_cassandra/src/emqx_bridge_cassandra_connector.erl +++ b/apps/emqx_bridge_cassandra/src/emqx_bridge_cassandra_connector.erl @@ -14,7 +14,7 @@ -include_lib("snabbkaffe/include/snabbkaffe.hrl"). %% schema --export([roots/0, fields/1, desc/1]). +-export([roots/0, fields/1, desc/1, namespace/0]). %% callbacks of behaviour emqx_resource -export([ @@ -56,6 +56,8 @@ %%-------------------------------------------------------------------- %% schema +namespace() -> cassandra. + roots() -> [{config, #{type => hoconsc:ref(?MODULE, config)}}]. diff --git a/apps/emqx_bridge_clickhouse/src/emqx_bridge_clickhouse.app.src b/apps/emqx_bridge_clickhouse/src/emqx_bridge_clickhouse.app.src index 85c035be1..3288b83fd 100644 --- a/apps/emqx_bridge_clickhouse/src/emqx_bridge_clickhouse.app.src +++ b/apps/emqx_bridge_clickhouse/src/emqx_bridge_clickhouse.app.src @@ -1,6 +1,6 @@ {application, emqx_bridge_clickhouse, [ {description, "EMQX Enterprise ClickHouse Bridge"}, - {vsn, "0.2.4"}, + {vsn, "0.2.5"}, {registered, []}, {applications, [ kernel, diff --git a/apps/emqx_bridge_clickhouse/src/emqx_bridge_clickhouse_connector.erl b/apps/emqx_bridge_clickhouse/src/emqx_bridge_clickhouse_connector.erl index 8f575dd8d..0a6c504c7 100644 --- a/apps/emqx_bridge_clickhouse/src/emqx_bridge_clickhouse_connector.erl +++ b/apps/emqx_bridge_clickhouse/src/emqx_bridge_clickhouse_connector.erl @@ -23,7 +23,8 @@ -export([ roots/0, fields/1, - values/1 + values/1, + namespace/0 ]). %% callbacks for behaviour emqx_resource @@ -72,6 +73,8 @@ %% Configuration and default values %%===================================================================== +namespace() -> clickhouse. + roots() -> [{config, #{type => hoconsc:ref(?MODULE, config)}}]. diff --git a/apps/emqx_bridge_dynamo/src/emqx_bridge_dynamo.app.src b/apps/emqx_bridge_dynamo/src/emqx_bridge_dynamo.app.src index a4b372056..a0e8e2f19 100644 --- a/apps/emqx_bridge_dynamo/src/emqx_bridge_dynamo.app.src +++ b/apps/emqx_bridge_dynamo/src/emqx_bridge_dynamo.app.src @@ -1,6 +1,6 @@ {application, emqx_bridge_dynamo, [ {description, "EMQX Enterprise Dynamo Bridge"}, - {vsn, "0.1.4"}, + {vsn, "0.1.5"}, {registered, []}, {applications, [ kernel, diff --git a/apps/emqx_bridge_dynamo/src/emqx_bridge_dynamo_connector.erl b/apps/emqx_bridge_dynamo/src/emqx_bridge_dynamo_connector.erl index 9cdb8886c..0739df747 100644 --- a/apps/emqx_bridge_dynamo/src/emqx_bridge_dynamo_connector.erl +++ b/apps/emqx_bridge_dynamo/src/emqx_bridge_dynamo_connector.erl @@ -12,7 +12,7 @@ -include_lib("snabbkaffe/include/snabbkaffe.hrl"). -include_lib("hocon/include/hoconsc.hrl"). --export([roots/0, fields/1]). +-export([roots/0, fields/1, namespace/0]). %% `emqx_resource' API -export([ @@ -32,6 +32,9 @@ %%===================================================================== %% Hocon schema + +namespace() -> dynamodka. + roots() -> [{config, #{type => hoconsc:ref(?MODULE, config)}}]. diff --git a/apps/emqx_bridge_rocketmq/src/emqx_bridge_rocketmq.erl b/apps/emqx_bridge_rocketmq/src/emqx_bridge_rocketmq.erl index 22514dc5c..c40473ee5 100644 --- a/apps/emqx_bridge_rocketmq/src/emqx_bridge_rocketmq.erl +++ b/apps/emqx_bridge_rocketmq/src/emqx_bridge_rocketmq.erl @@ -115,7 +115,8 @@ action_values() -> %% ------------------------------------------------------------------------------------------------- %% Hocon Schema Definitions -namespace() -> "bridge_rocketmq". + +namespace() -> "rocketmq". roots() -> []. diff --git a/apps/emqx_bridge_rocketmq/src/emqx_bridge_rocketmq_connector.erl b/apps/emqx_bridge_rocketmq/src/emqx_bridge_rocketmq_connector.erl index c9a7ce177..a5bfa6437 100644 --- a/apps/emqx_bridge_rocketmq/src/emqx_bridge_rocketmq_connector.erl +++ b/apps/emqx_bridge_rocketmq/src/emqx_bridge_rocketmq_connector.erl @@ -12,7 +12,7 @@ -include_lib("snabbkaffe/include/snabbkaffe.hrl"). -include_lib("hocon/include/hoconsc.hrl"). --export([roots/0, fields/1]). +-export([roots/0, fields/1, namespace/0]). %% `emqx_resource' API -export([ @@ -36,6 +36,9 @@ %%===================================================================== %% Hocon schema + +namespace() -> rocketmq. + roots() -> [{config, #{type => hoconsc:ref(?MODULE, config)}}]. diff --git a/apps/emqx_bridge_sqlserver/src/emqx_bridge_sqlserver.app.src b/apps/emqx_bridge_sqlserver/src/emqx_bridge_sqlserver.app.src index 331f9c29f..bddf212e3 100644 --- a/apps/emqx_bridge_sqlserver/src/emqx_bridge_sqlserver.app.src +++ b/apps/emqx_bridge_sqlserver/src/emqx_bridge_sqlserver.app.src @@ -1,6 +1,6 @@ {application, emqx_bridge_sqlserver, [ {description, "EMQX Enterprise SQL Server Bridge"}, - {vsn, "0.1.5"}, + {vsn, "0.1.6"}, {registered, []}, {applications, [kernel, stdlib, emqx_resource, odbc]}, {env, []}, diff --git a/apps/emqx_bridge_sqlserver/src/emqx_bridge_sqlserver_connector.erl b/apps/emqx_bridge_sqlserver/src/emqx_bridge_sqlserver_connector.erl index a87e71e31..e9e77ba6b 100644 --- a/apps/emqx_bridge_sqlserver/src/emqx_bridge_sqlserver_connector.erl +++ b/apps/emqx_bridge_sqlserver/src/emqx_bridge_sqlserver_connector.erl @@ -24,7 +24,8 @@ %% Hocon config schema exports -export([ roots/0, - fields/1 + fields/1, + namespace/0 ]). %% callbacks for behaviour emqx_resource @@ -132,6 +133,8 @@ %% Configuration and default values %%==================================================================== +namespace() -> sqlserver. + roots() -> [{config, #{type => hoconsc:ref(?MODULE, config)}}]. diff --git a/apps/emqx_conf/src/emqx_conf.erl b/apps/emqx_conf/src/emqx_conf.erl index 0a8339ddd..0df5711e0 100644 --- a/apps/emqx_conf/src/emqx_conf.erl +++ b/apps/emqx_conf/src/emqx_conf.erl @@ -158,7 +158,6 @@ dump_schema(Dir, SchemaModule) -> ok = emqx_dashboard_desc_cache:init(), lists:foreach( fun(Lang) -> - ok = gen_config_md(Dir, SchemaModule, Lang), ok = gen_schema_json(Dir, SchemaModule, Lang) end, ["en", "zh"] @@ -468,14 +467,6 @@ bridge_schema_json() -> SchemaInfo = #{title => <<"EMQX Data Bridge API Schema">>, version => Version}, gen_api_schema_json_iodata(emqx_bridge_api, SchemaInfo). -%% TODO: remove it and also remove hocon_md.erl and friends. -%% markdown generation from schema is a failure and we are moving to an interactive -%% viewer like swagger UI. -gen_config_md(Dir, SchemaModule, Lang) -> - SchemaMdFile = filename:join([Dir, "config-" ++ Lang ++ ".md"]), - io:format(user, "===< Generating: ~s~n", [SchemaMdFile]), - ok = gen_doc(SchemaMdFile, SchemaModule, Lang). - %% @doc return the root schema module. -spec schema_module() -> module(). schema_module() -> @@ -515,19 +506,6 @@ make_desc_resolver(Lang) -> unicode:characters_to_binary(Desc) end. --spec gen_doc(file:name_all(), module(), string()) -> ok. -gen_doc(File, SchemaModule, Lang) -> - Version = emqx_release:version(), - Title = - "# " ++ emqx_release:description() ++ " Configuration\n\n" ++ - "", - BodyFile = filename:join([rel, "emqx_conf.template." ++ Lang ++ ".md"]), - {ok, Body} = file:read_file(BodyFile), - Resolver = make_desc_resolver(Lang), - Opts = #{title => Title, body => Body, desc_resolver => Resolver}, - Doc = hocon_schema_md:gen(SchemaModule, Opts), - file:write_file(File, Doc). - gen_api_schema_json_iodata(SchemaMod, SchemaInfo) -> emqx_dashboard_swagger:gen_api_schema_json_iodata( SchemaMod, diff --git a/apps/emqx_connector/src/emqx_connector_schema_lib.erl b/apps/emqx_connector/src/emqx_connector_schema_lib.erl index 76a06cb5a..609ba892d 100644 --- a/apps/emqx_connector/src/emqx_connector_schema_lib.erl +++ b/apps/emqx_connector/src/emqx_connector_schema_lib.erl @@ -44,12 +44,6 @@ password/0 ]). --export([roots/0, fields/1]). - -roots() -> []. - -fields(_) -> []. - ssl_fields() -> [ {ssl, #{ diff --git a/apps/emqx_connector/src/schema/emqx_connector_ee_schema.erl b/apps/emqx_connector/src/schema/emqx_connector_ee_schema.erl index f8800cc10..c0b0c365a 100644 --- a/apps/emqx_connector/src/schema/emqx_connector_ee_schema.erl +++ b/apps/emqx_connector/src/schema/emqx_connector_ee_schema.erl @@ -15,8 +15,8 @@ -export([ api_schemas/1, fields/1, - %%examples/1 - schema_modules/0 + schema_modules/0, + namespace/0 ]). resource_type(Type) when is_binary(Type) -> @@ -93,6 +93,8 @@ connector_impl_module(rabbitmq) -> connector_impl_module(_ConnectorType) -> undefined. +namespace() -> undefined. + fields(connectors) -> connector_structs(). diff --git a/apps/emqx_dashboard/src/emqx_dashboard_monitor_api.erl b/apps/emqx_dashboard/src/emqx_dashboard_monitor_api.erl index c36c6d0f3..97397056d 100644 --- a/apps/emqx_dashboard/src/emqx_dashboard_monitor_api.erl +++ b/apps/emqx_dashboard/src/emqx_dashboard_monitor_api.erl @@ -27,7 +27,8 @@ -export([ paths/0, schema/1, - fields/1 + fields/1, + namespace/0 ]). -export([ @@ -35,6 +36,8 @@ monitor_current/2 ]). +namespace() -> undefined. + api_spec() -> emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true, translate_body => true}). diff --git a/apps/emqx_dashboard/test/emqx_swagger_parameter_SUITE.erl b/apps/emqx_dashboard/test/emqx_swagger_parameter_SUITE.erl index 1e9e24755..d09490cc9 100644 --- a/apps/emqx_dashboard/test/emqx_swagger_parameter_SUITE.erl +++ b/apps/emqx_dashboard/test/emqx_swagger_parameter_SUITE.erl @@ -19,7 +19,7 @@ -behaviour(hocon_schema). %% API --export([paths/0, api_spec/0, schema/1, namespace/0, fields/1]). +-export([paths/0, api_spec/0, schema/1, roots/0, namespace/0, fields/1]). -export([init_per_suite/1, end_per_suite/1]). -export([t_in_path/1, t_in_query/1, t_in_mix/1, t_without_in/1, t_ref/1, t_public_ref/1]). -export([t_require/1, t_query_enum/1, t_nullable/1, t_method/1, t_api_spec/1]). @@ -563,6 +563,7 @@ schema("/method/error") -> #{operationId => test, bar => #{200 => <<"ok">>}}. namespace() -> undefined. +roots() -> []. fields(page) -> [ diff --git a/apps/emqx_dashboard/test/emqx_swagger_remote_schema.erl b/apps/emqx_dashboard/test/emqx_swagger_remote_schema.erl index dc9d54260..23573d612 100644 --- a/apps/emqx_dashboard/test/emqx_swagger_remote_schema.erl +++ b/apps/emqx_dashboard/test/emqx_swagger_remote_schema.erl @@ -17,9 +17,10 @@ -include_lib("typerefl/include/types.hrl"). --export([roots/0, fields/1]). +-export([namespace/0, roots/0, fields/1]). -import(hoconsc, [mk/2]). roots() -> ["root"]. +namespace() -> undefined. fields("root") -> [ diff --git a/apps/emqx_dashboard/test/emqx_swagger_requestBody_SUITE.erl b/apps/emqx_dashboard/test/emqx_swagger_requestBody_SUITE.erl index 0e1264aeb..13754579e 100644 --- a/apps/emqx_dashboard/test/emqx_swagger_requestBody_SUITE.erl +++ b/apps/emqx_dashboard/test/emqx_swagger_requestBody_SUITE.erl @@ -813,7 +813,8 @@ to_schema(Body) -> post => #{requestBody => Body, responses => #{200 => <<"ok">>}} }. -%% Don't warning hocon callback namespace/0 undef. +roots() -> []. + namespace() -> atom_to_list(?MODULE). fields(good_ref) -> diff --git a/apps/emqx_dashboard/test/emqx_swagger_response_SUITE.erl b/apps/emqx_dashboard/test/emqx_swagger_response_SUITE.erl index 5ccb01b3e..b9d7bf2e4 100644 --- a/apps/emqx_dashboard/test/emqx_swagger_response_SUITE.erl +++ b/apps/emqx_dashboard/test/emqx_swagger_response_SUITE.erl @@ -680,6 +680,7 @@ to_schema(Object) -> post => #{responses => #{200 => Object, 201 => Object}} }. +rotos() -> []. namespace() -> undefined. fields(good_ref) -> diff --git a/apps/emqx_gateway/src/emqx_gateway_api.erl b/apps/emqx_gateway/src/emqx_gateway_api.erl index bd0bcff8a..6c125cf22 100644 --- a/apps/emqx_gateway/src/emqx_gateway_api.erl +++ b/apps/emqx_gateway/src/emqx_gateway_api.erl @@ -36,7 +36,8 @@ -export([ api_spec/0, paths/0, - schema/1 + schema/1, + namespace/0 ]). -export([ @@ -59,6 +60,8 @@ %% minirest behaviour callbacks %%-------------------------------------------------------------------- +namespace() -> undefined. + api_spec() -> emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}). diff --git a/apps/emqx_gateway/src/emqx_gateway_api_clients.erl b/apps/emqx_gateway/src/emqx_gateway_api_clients.erl index 121cb4064..88c53d230 100644 --- a/apps/emqx_gateway/src/emqx_gateway_api_clients.erl +++ b/apps/emqx_gateway/src/emqx_gateway_api_clients.erl @@ -42,7 +42,8 @@ -export([ roots/0, - fields/1 + fields/1, + namespace/0 ]). %% http handlers @@ -775,6 +776,8 @@ schema_client() -> examples_client() ). +namespace() -> undefined. + roots() -> [ stomp_client, diff --git a/apps/emqx_gateway/src/emqx_gateway_api_listeners.erl b/apps/emqx_gateway/src/emqx_gateway_api_listeners.erl index 284576983..3072d8903 100644 --- a/apps/emqx_gateway/src/emqx_gateway_api_listeners.erl +++ b/apps/emqx_gateway/src/emqx_gateway_api_listeners.erl @@ -45,7 +45,8 @@ -export([ roots/0, - fields/1 + fields/1, + namespace/0 ]). %% http handlers @@ -651,6 +652,9 @@ params_paging_in_qs() -> %%-------------------------------------------------------------------- %% schemas +namespace() -> + undefined. + roots() -> [listener]. diff --git a/apps/emqx_gateway_jt808/src/emqx_jt808_schema.erl b/apps/emqx_gateway_jt808/src/emqx_jt808_schema.erl index d4b0a0b5e..97b01e5e8 100644 --- a/apps/emqx_gateway_jt808/src/emqx_jt808_schema.erl +++ b/apps/emqx_gateway_jt808/src/emqx_jt808_schema.erl @@ -9,10 +9,12 @@ -include_lib("typerefl/include/types.hrl"). -behaviour(hocon_schema). --export([namespace/0, fields/1, desc/1]). +-export([roots/0, namespace/0, fields/1, desc/1]). -define(NOT_EMPTY(MSG), emqx_resource_validator:not_empty(MSG)). +roots() -> []. + namespace() -> gateway. fields(jt808) -> diff --git a/apps/emqx_gcp_device/src/emqx_gcp_device.app.src b/apps/emqx_gcp_device/src/emqx_gcp_device.app.src index 7f1d81f14..b3a4407c0 100644 --- a/apps/emqx_gcp_device/src/emqx_gcp_device.app.src +++ b/apps/emqx_gcp_device/src/emqx_gcp_device.app.src @@ -1,6 +1,6 @@ {application, emqx_gcp_device, [ {description, "Application simplifying migration from GCP IoT Core"}, - {vsn, "0.1.3"}, + {vsn, "0.1.4"}, {registered, []}, {mod, {emqx_gcp_device_app, []}}, {applications, [ diff --git a/apps/emqx_gcp_device/src/emqx_gcp_device_api.erl b/apps/emqx_gcp_device/src/emqx_gcp_device_api.erl index a08e0af24..4e10092b8 100644 --- a/apps/emqx_gcp_device/src/emqx_gcp_device_api.erl +++ b/apps/emqx_gcp_device/src/emqx_gcp_device_api.erl @@ -22,7 +22,8 @@ api_spec/0, paths/0, schema/1, - fields/1 + fields/1, + namespace/0 ]). -export([ @@ -62,6 +63,9 @@ %% `minirest' and `minirest_trails' API %%------------------------------------------------------------------------------------------------- +namespace() -> + undefined. + api_spec() -> emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}). diff --git a/apps/emqx_management/src/emqx_mgmt_api_alarms.erl b/apps/emqx_management/src/emqx_mgmt_api_alarms.erl index d5965f019..ea88ba082 100644 --- a/apps/emqx_management/src/emqx_mgmt_api_alarms.erl +++ b/apps/emqx_management/src/emqx_mgmt_api_alarms.erl @@ -22,7 +22,7 @@ -include_lib("emqx/include/emqx.hrl"). -include_lib("typerefl/include/types.hrl"). --export([api_spec/0, paths/0, schema/1, fields/1]). +-export([api_spec/0, paths/0, schema/1, fields/1, namespace/0]). -export([alarms/2, format_alarm/2]). @@ -31,6 +31,9 @@ %% internal export (for query) -export([qs2ms/2]). +namespace() -> + undefined. + api_spec() -> emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}). diff --git a/apps/emqx_management/src/emqx_mgmt_api_banned.erl b/apps/emqx_management/src/emqx_mgmt_api_banned.erl index cf1ab3c49..4f2ba6c00 100644 --- a/apps/emqx_management/src/emqx_mgmt_api_banned.erl +++ b/apps/emqx_management/src/emqx_mgmt_api_banned.erl @@ -28,7 +28,8 @@ api_spec/0, paths/0, schema/1, - fields/1 + fields/1, + namespace/0 ]). -export([format/1]). @@ -44,6 +45,9 @@ -define(FORMAT_FUN, {?MODULE, format}). +namespace() -> + undefined. + api_spec() -> emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true, translate_body => true}). diff --git a/apps/emqx_management/src/emqx_mgmt_api_clients.erl b/apps/emqx_management/src/emqx_mgmt_api_clients.erl index 8965f4633..f5c799dd9 100644 --- a/apps/emqx_management/src/emqx_mgmt_api_clients.erl +++ b/apps/emqx_management/src/emqx_mgmt_api_clients.erl @@ -32,7 +32,8 @@ api_spec/0, paths/0, schema/1, - fields/1 + fields/1, + namespace/0 ]). -export([ @@ -83,6 +84,8 @@ message => <<"Client ID not found">> }). +namespace() -> undefined. + api_spec() -> emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true, translate_body => true}). diff --git a/apps/emqx_management/src/emqx_mgmt_api_data_backup.erl b/apps/emqx_management/src/emqx_mgmt_api_data_backup.erl index ef0b095cb..86fc8131d 100644 --- a/apps/emqx_management/src/emqx_mgmt_api_data_backup.erl +++ b/apps/emqx_management/src/emqx_mgmt_api_data_backup.erl @@ -21,7 +21,7 @@ -include_lib("emqx/include/logger.hrl"). -include_lib("hocon/include/hoconsc.hrl"). --export([api_spec/0, paths/0, schema/1, fields/1]). +-export([api_spec/0, paths/0, schema/1, fields/1, namespace/0]). -export([ data_export/2, @@ -48,6 +48,8 @@ })} ). +namespace() -> undefined. + api_spec() -> emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}). diff --git a/apps/emqx_management/src/emqx_mgmt_api_metrics.erl b/apps/emqx_management/src/emqx_mgmt_api_metrics.erl index 7ad0777c7..a4a27c0f4 100644 --- a/apps/emqx_management/src/emqx_mgmt_api_metrics.erl +++ b/apps/emqx_management/src/emqx_mgmt_api_metrics.erl @@ -27,7 +27,8 @@ -export([ api_spec/0, paths/0, - schema/1 + schema/1, + namespace/0 ]). -export([ @@ -42,6 +43,8 @@ %% minirest behaviour callbacks %%-------------------------------------------------------------------- +namespace() -> undefined. + api_spec() -> emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}). diff --git a/apps/emqx_management/src/emqx_mgmt_api_nodes.erl b/apps/emqx_management/src/emqx_mgmt_api_nodes.erl index 07d775f6e..9e9fad784 100644 --- a/apps/emqx_management/src/emqx_mgmt_api_nodes.erl +++ b/apps/emqx_management/src/emqx_mgmt_api_nodes.erl @@ -30,7 +30,8 @@ api_spec/0, schema/1, paths/0, - fields/1 + fields/1, + namespace/0 ]). %% API callbacks @@ -45,6 +46,8 @@ %% API spec funcs %%-------------------------------------------------------------------- +namespace() -> undefined. + api_spec() -> emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}). diff --git a/apps/emqx_management/src/emqx_mgmt_api_publish.erl b/apps/emqx_management/src/emqx_mgmt_api_publish.erl index f0834af96..c8c1a6e10 100644 --- a/apps/emqx_management/src/emqx_mgmt_api_publish.erl +++ b/apps/emqx_management/src/emqx_mgmt_api_publish.erl @@ -32,7 +32,8 @@ api_spec/0, paths/0, schema/1, - fields/1 + fields/1, + namespace/0 ]). -export([ @@ -40,6 +41,8 @@ publish_batch/2 ]). +namespace() -> undefined. + api_spec() -> emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true, translate_body => true}). diff --git a/apps/emqx_management/src/emqx_mgmt_api_stats.erl b/apps/emqx_management/src/emqx_mgmt_api_stats.erl index cddc2a7c3..cb07be6d2 100644 --- a/apps/emqx_management/src/emqx_mgmt_api_stats.erl +++ b/apps/emqx_management/src/emqx_mgmt_api_stats.erl @@ -34,11 +34,14 @@ api_spec/0, paths/0, schema/1, - fields/1 + fields/1, + namespace/0 ]). -export([list/2]). +namespace() -> undefined. + api_spec() -> emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}). diff --git a/apps/emqx_management/src/emqx_mgmt_api_subscriptions.erl b/apps/emqx_management/src/emqx_mgmt_api_subscriptions.erl index ca0a7a625..39dc639d5 100644 --- a/apps/emqx_management/src/emqx_mgmt_api_subscriptions.erl +++ b/apps/emqx_management/src/emqx_mgmt_api_subscriptions.erl @@ -28,7 +28,8 @@ api_spec/0, paths/0, schema/1, - fields/1 + fields/1, + namespace/0 ]). -export([subscriptions/2]). @@ -48,6 +49,9 @@ {<<"match_topic">>, binary} ]). +namespace() -> + undefined. + api_spec() -> emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}). diff --git a/apps/emqx_management/src/emqx_mgmt_api_topics.erl b/apps/emqx_management/src/emqx_mgmt_api_topics.erl index 02d4461e9..bffcc2f0c 100644 --- a/apps/emqx_management/src/emqx_mgmt_api_topics.erl +++ b/apps/emqx_management/src/emqx_mgmt_api_topics.erl @@ -28,7 +28,8 @@ api_spec/0, paths/0, schema/1, - fields/1 + fields/1, + namespace/0 ]). -export([ @@ -41,6 +42,8 @@ -define(TOPICS_QUERY_SCHEMA, [{<<"topic">>, binary}, {<<"node">>, atom}]). -define(TAGS, [<<"Topics">>]). +namespace() -> undefined. + api_spec() -> emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true, translate_body => true}). diff --git a/apps/emqx_modules/src/emqx_delayed_api.erl b/apps/emqx_modules/src/emqx_delayed_api.erl index f6ea99c12..37a79d8e0 100644 --- a/apps/emqx_modules/src/emqx_delayed_api.erl +++ b/apps/emqx_modules/src/emqx_delayed_api.erl @@ -34,7 +34,8 @@ -export([ paths/0, fields/1, - schema/1 + schema/1, + namespace/0 ]). %% for rpc @@ -55,6 +56,8 @@ -define(INVALID_TOPIC, 'INVALID_TOPIC_NAME'). -define(MESSAGE_NOT_FOUND, 'MESSAGE_NOT_FOUND'). +namespace() -> undefined. + api_spec() -> emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}). diff --git a/apps/emqx_modules/src/emqx_topic_metrics_api.erl b/apps/emqx_modules/src/emqx_topic_metrics_api.erl index 49b3071e0..982a4e710 100644 --- a/apps/emqx_modules/src/emqx_topic_metrics_api.erl +++ b/apps/emqx_modules/src/emqx_topic_metrics_api.erl @@ -47,7 +47,8 @@ api_spec/0, paths/0, schema/1, - fields/1 + fields/1, + namespace/0 ]). -define(EXCEED_LIMIT, 'EXCEED_LIMIT'). @@ -55,6 +56,8 @@ -define(TOPIC_NOT_FOUND, 'TOPIC_NOT_FOUND'). -define(BAD_REQUEST, 'BAD_REQUEST'). +namespace() -> undefined. + api_spec() -> emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}). diff --git a/apps/emqx_mysql/src/emqx_mysql.erl b/apps/emqx_mysql/src/emqx_mysql.erl index d33f313bc..cf937aeba 100644 --- a/apps/emqx_mysql/src/emqx_mysql.erl +++ b/apps/emqx_mysql/src/emqx_mysql.erl @@ -44,7 +44,7 @@ unprepare_sql/1 ]). --export([roots/0, fields/1]). +-export([roots/0, fields/1, namespace/0]). -export([do_get_status/1]). @@ -63,6 +63,9 @@ -export_type([state/0]). %%===================================================================== %% Hocon schema + +namespace() -> mysql. + roots() -> [{config, #{type => hoconsc:ref(?MODULE, config)}}]. diff --git a/apps/emqx_oracle/src/emqx_oracle_schema.erl b/apps/emqx_oracle/src/emqx_oracle_schema.erl index ba9904f19..a30ffca92 100644 --- a/apps/emqx_oracle/src/emqx_oracle_schema.erl +++ b/apps/emqx_oracle/src/emqx_oracle_schema.erl @@ -12,9 +12,12 @@ %% Hocon config schema exports -export([ roots/0, - fields/1 + fields/1, + namespace/0 ]). +namespace() -> oracle. + roots() -> [{config, #{type => hoconsc:ref(?REF_MODULE, config)}}]. diff --git a/apps/emqx_postgresql/src/emqx_postgresql.erl b/apps/emqx_postgresql/src/emqx_postgresql.erl index e77a88c57..c8f354df0 100644 --- a/apps/emqx_postgresql/src/emqx_postgresql.erl +++ b/apps/emqx_postgresql/src/emqx_postgresql.erl @@ -23,7 +23,7 @@ -include_lib("epgsql/include/epgsql.hrl"). -include_lib("snabbkaffe/include/snabbkaffe.hrl"). --export([roots/0, fields/1]). +-export([roots/0, fields/1, namespace/0]). -behaviour(emqx_resource). @@ -71,6 +71,8 @@ %%===================================================================== +namespace() -> postgres. + roots() -> [{config, #{type => hoconsc:ref(?MODULE, config)}}]. diff --git a/apps/emqx_prometheus/src/emqx_prometheus_api.erl b/apps/emqx_prometheus/src/emqx_prometheus_api.erl index 89bfa6e6a..432142775 100644 --- a/apps/emqx_prometheus/src/emqx_prometheus_api.erl +++ b/apps/emqx_prometheus/src/emqx_prometheus_api.erl @@ -34,7 +34,8 @@ api_spec/0, paths/0, schema/1, - fields/1 + fields/1, + namespace/0 ]). -export([ @@ -50,6 +51,8 @@ -define(IS_TRUE(Val), ((Val =:= true) orelse (Val =:= <<"true">>))). -define(IS_FALSE(Val), ((Val =:= false) orelse (Val =:= <<"false">>))). +namespace() -> undefined. + api_spec() -> emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}). diff --git a/apps/emqx_telemetry/src/emqx_telemetry_api.erl b/apps/emqx_telemetry/src/emqx_telemetry_api.erl index c90ad6b38..da18f761a 100644 --- a/apps/emqx_telemetry/src/emqx_telemetry_api.erl +++ b/apps/emqx_telemetry/src/emqx_telemetry_api.erl @@ -32,12 +32,15 @@ api_spec/0, paths/0, schema/1, - fields/1 + fields/1, + namespace/0 ]). -define(BAD_REQUEST, 'BAD_REQUEST'). -define(NOT_FOUND, 'NOT_FOUND'). +namespace() -> undefined. + api_spec() -> emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}). diff --git a/changes/ce/feat-12517.en.md b/changes/ce/feat-12517.en.md new file mode 100644 index 000000000..b26e3edc8 --- /dev/null +++ b/changes/ce/feat-12517.en.md @@ -0,0 +1,15 @@ +Congifuration files now support multi-line string values with indentation. + +Introduced the `"""~` and `~"""` to quote indented lines. For example: + +``` +rule_xlu4 { + sql = """~ + SELECT + * + FROM + "t/#" + ~""" +} +``` +See [HOCON 0.41.0](https://github.com/emqx/hocon/releases/tag/0.41.0) release note for more dtails. diff --git a/mix.exs b/mix.exs index b40ca2168..abbf5940c 100644 --- a/mix.exs +++ b/mix.exs @@ -72,7 +72,7 @@ defmodule EMQXUmbrella.MixProject do # in conflict by emqtt and hocon {:getopt, "1.0.2", override: true}, {:snabbkaffe, github: "kafka4beam/snabbkaffe", tag: "1.0.8", override: true}, - {:hocon, github: "emqx/hocon", tag: "0.40.4", override: true}, + {:hocon, github: "emqx/hocon", tag: "0.41.0", override: true}, {:emqx_http_lib, github: "emqx/emqx_http_lib", tag: "0.5.3", override: true}, {:esasl, github: "emqx/esasl", tag: "0.2.0"}, {:jose, github: "potatosalad/erlang-jose", tag: "1.11.2"}, diff --git a/rebar.config b/rebar.config index 5ebe9da15..88b32483e 100644 --- a/rebar.config +++ b/rebar.config @@ -97,7 +97,7 @@ {system_monitor, {git, "https://github.com/ieQu1/system_monitor", {tag, "3.0.3"}}}, {getopt, "1.0.2"}, {snabbkaffe, {git, "https://github.com/kafka4beam/snabbkaffe.git", {tag, "1.0.8"}}}, - {hocon, {git, "https://github.com/emqx/hocon.git", {tag, "0.40.4"}}}, + {hocon, {git, "https://github.com/emqx/hocon.git", {tag, "0.41.0"}}}, {emqx_http_lib, {git, "https://github.com/emqx/emqx_http_lib.git", {tag, "0.5.3"}}}, {esasl, {git, "https://github.com/emqx/esasl", {tag, "0.2.0"}}}, {jose, {git, "https://github.com/potatosalad/erlang-jose", {tag, "1.11.2"}}}, diff --git a/rel/emqx_conf.template.en.md b/rel/emqx_conf.template.en.md deleted file mode 100644 index 2dcb83896..000000000 --- a/rel/emqx_conf.template.en.md +++ /dev/null @@ -1,329 +0,0 @@ -EMQX configuration files are in [HOCON](https://github.com/emqx/hocon) format. -HOCON, or Human-Optimized Config Object Notation is a format for human-readable data, -and a superset of JSON. - -## Layered - -EMQX configuration consists of two layers. -From bottom up: - -1. Cluster-synced configs: `$EMQX_NODE__DATA_DIR/configs/cluster.hocon`. -2. Local node configs: `emqx.conf` + `EMQX_` prefixed environment variables. - -:::tip Tip -Prior to v5.0.23 and e5.0.3, the cluster-synced configs are stored in -`cluster-override.conf` which is applied on top of the local configs. - -If upgraded from an earlier version, as long as `cluster-override.conf` exists, -`cluster.hocon` will not be created, and `cluster-override.conf` will stay on -top of the overriding layers. -::: - -When environment variable `$EMQX_NODE__DATA_DIR` is not set, config `node.data_dir` -is used. - -The `cluster.hocon` file is overwritten at runtime when changes -are made from Dashboard, management HTTP API, or CLI. When clustered, -after EMQX restarts, it copies the file from the node which has the greatest `uptime`. - -:::tip Tip -To avoid confusion, don't add the same keys in both `cluster.hocon` and `emqx.conf`. -::: - -For detailed override rules, see [Config Overlay Rules](#config-overlay-rules). - -## Syntax - -In config file the values can be notated as JSON like objects, such as -``` -node { - name = "emqx@127.0.0.1" - cookie = "mysecret" -} -``` - -Another equivalent representation is flat, such as - -``` -node.name = "127.0.0.1" -node.cookie = "mysecret" -``` - -This flat format is almost backward compatible with EMQX's config file format -in 4.x series (the so called 'cuttlefish' format). - -It is not fully compatible because the often HOCON requires strings to be quoted, -while cuttlefish treats all characters to the right of the `=` mark as the value. - -e.g. cuttlefish: `node.name = emqx@127.0.0.1`, HOCON: `node.name = "emqx@127.0.0.1"`. - -Strings without special characters in them can be unquoted in HOCON too, -e.g. `foo`, `foo_bar` and `foo_bar_1`. - -For more HOCON syntax, please refer to the [specification](https://github.com/lightbend/config/blob/main/HOCON.md) - -## Schema - -To make the HOCON objects type-safe, EMQX introduced a schema for it. -The schema defines data types, and data fields' names and metadata for config value validation -and more. - -::: tip Tip -The configuration document you are reading now is generated from schema metadata. -::: - -### Complex Data Types - -There are 4 complex data types in EMQX's HOCON config: - -1. Struct: Named using an unquoted string, followed by a predefined list of fields. - Only lowercase letters and digits are allowed in struct and field names. - Alos, only underscore can be used as word separator. -1. Map: Map is like Struct, however the fields are not predefined. -1. Union: `MemberType1 | MemberType2 | ...` -1. Array: `[ElementType]` - -::: tip Tip -If map field name is a positive integer number, it is interpreted as an alternative representation of an `Array`. -For example: -``` -myarray.1 = 74 -myarray.2 = 75 -``` -will be interpreated as `myarray = [74, 75]`, which is handy when trying to override array elements. -::: - -### Primitive Data Types - -Complex types define data 'boxes' which may contain other complex data -or primitive values. -There are quite some different primitive types, to name a few: - -* `atom()`. -* `boolean()`. -* `string()`. -* `integer()`. -* `float()`. -* `number()`. -* `binary()`, another format of string(). -* `emqx_schema:duration()`, time duration, another format of integer() -* ... - -::: tip Tip -The primitive types are mostly self-describing, so there is usually not a lot to document. -For types that are not so clear by their names, the field description is to be used to find the details. -::: - -### Config Paths - -If we consider the whole EMQX config as a tree, -to reference a primitive value, we can use a dot-separated names form string for -the path from the tree-root (always a Struct) down to the primitive values at tree-leaves. - -Each segment of the dotted string is a Struct field name or Map key. -For Array elements, 1-based index is used. - -below are some examples - -``` -node.name = "emqx.127.0.0.1" -zone.zone1.max_packet_size = "10M" -authentication.1.enable = true -``` - -### Environment variables - -Environment variables can be used to define or override config values. - -Due to the fact that dots (`.`) are not allowed in environment variables, dots are -replaced with double-underscores (`__`). - -And the `EMQX_` prefix is used as the namespace. - -For example `node.name` can be represented as `EMQX_NODE__NAME` - -Environment variable values are parsed as HOCON values, this allows users -to even set complex values from environment variables. - -For example, this environment variable sets an array value. - -``` -export EMQX_LISTENERS__SSL__L1__AUTHENTICATION__SSL__CIPHERS='["TLS_AES_256_GCM_SHA384"]' -``` -However, this also means a string value should be quoted if it happens to contain special -characters such as `=` and `:`. - -For example, a string value `"localhost:1883"` would be -parsed into object (struct): `{"localhost": 1883}`. - -To keep it as a string, one should quote the value like below: - -``` -EMQX_BRIDGES__MQTT__MYBRIDGE__CONNECTOR_SERVER='"localhost:1883"' -``` - -::: tip Tip -Unknown root paths are silently discarded by EMQX, for example `EMQX_UNKNOWN_ROOT__FOOBAR` is -silently discarded because `unknown_root` is not a predefined root path. - -Unknown field names in environment variables are logged as a `warning` level log, for example: - -``` -[warning] unknown_env_vars: ["EMQX_AUTHENTICATION__ENABLED"] -``` - -because the field name is `enable`, not `enabled`. -::: - - -### Config Overlay Rules - -HOCON objects are overlaid, in general: - -- Within one file, objects defined 'later' recursively override objects defined 'earlier' -- When layered, 'later' (higher layer) objects override objects defined 'earlier' (lower layer) - -Below are more detailed rules. - -#### Struct Fields - -Later config values overwrites earlier values. -For example, in below config, the last line `debug` overwrites `error` for -console log handler's `level` config, but leaving `enable` unchanged. -``` -log { - console_handler{ - enable=true, - level=error - } -} - -## ... more configs ... - -log.console_handler.level=debug -``` - -#### Map Values - -Maps are like structs, only the files are user-defined rather than -the config schema. For instance, `zone1` in the example below. - -``` -zone { - zone1 { - mqtt.max_packet_size = 1M - } -} - -## The maximum packet size can be defined as above, -## then overridden as below - -zone.zone1.mqtt.max_packet_size = 10M -``` - -#### Array Elements - -Arrays in EMQX config have two different representations - -* list, such as: `[1, 2, 3]` -* indexed-map, such as: `{"1"=1, "2"=2, "3"=3}` - -Dot-separated paths with number in it are parsed to indexed-maps -e.g. `authentication.1={...}` is parsed as `authentication={"1": {...}}` - -This feature makes it easy to override array element values. For example: - -``` -authentication=[{enable=true, backend="built_in_database", mechanism="password_based"}] -# we can disable this authentication provider with: -authentication.1.enable=false -``` - -::: warning Warning -List arrays is a full-array override, but not a recursive merge, into indexed-map arrays. -e.g. - -``` -authentication=[{enable=true, backend="built_in_database", mechanism="password_based"}] -## below value will replace the whole array, but not to override just one field. -authentication=[{enable=true}] -``` -::: - -#### TLS/SSL ciphers - -Starting from v5.0.6, EMQX no longer pre-populates the ciphers list with a default -set of cipher suite names. -Instead, the default ciphers are applied at runtime when starting the listener -for servers, or when establishing a TLS connection as a client. - -Below are the default ciphers selected by EMQX. - -For tlsv1.3: -``` -ciphers = - [ "TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256", - "TLS_CHACHA20_POLY1305_SHA256", "TLS_AES_128_CCM_SHA256", - "TLS_AES_128_CCM_8_SHA256" - ] -``` - -For tlsv1.2 or earlier - -``` -ciphers = - [ "ECDHE-ECDSA-AES256-GCM-SHA384", - "ECDHE-RSA-AES256-GCM-SHA384", - "ECDHE-ECDSA-AES256-SHA384", - "ECDHE-RSA-AES256-SHA384", - "ECDH-ECDSA-AES256-GCM-SHA384", - "ECDH-RSA-AES256-GCM-SHA384", - "ECDH-ECDSA-AES256-SHA384", - "ECDH-RSA-AES256-SHA384", - "DHE-DSS-AES256-GCM-SHA384", - "DHE-DSS-AES256-SHA256", - "AES256-GCM-SHA384", - "AES256-SHA256", - "ECDHE-ECDSA-AES128-GCM-SHA256", - "ECDHE-RSA-AES128-GCM-SHA256", - "ECDHE-ECDSA-AES128-SHA256", - "ECDHE-RSA-AES128-SHA256", - "ECDH-ECDSA-AES128-GCM-SHA256", - "ECDH-RSA-AES128-GCM-SHA256", - "ECDH-ECDSA-AES128-SHA256", - "ECDH-RSA-AES128-SHA256", - "DHE-DSS-AES128-GCM-SHA256", - "DHE-DSS-AES128-SHA256", - "AES128-GCM-SHA256", - "AES128-SHA256", - "ECDHE-ECDSA-AES256-SHA", - "ECDHE-RSA-AES256-SHA", - "DHE-DSS-AES256-SHA", - "ECDH-ECDSA-AES256-SHA", - "ECDH-RSA-AES256-SHA", - "ECDHE-ECDSA-AES128-SHA", - "ECDHE-RSA-AES128-SHA", - "DHE-DSS-AES128-SHA", - "ECDH-ECDSA-AES128-SHA", - "ECDH-RSA-AES128-SHA" - ] -``` - -For PSK enabled listeners - -``` -ciphers = - [ "RSA-PSK-AES256-GCM-SHA384", - "RSA-PSK-AES256-CBC-SHA384", - "RSA-PSK-AES128-GCM-SHA256", - "RSA-PSK-AES128-CBC-SHA256", - "RSA-PSK-AES256-CBC-SHA", - "RSA-PSK-AES128-CBC-SHA", - "PSK-AES256-GCM-SHA384", - "PSK-AES128-GCM-SHA256", - "PSK-AES256-CBC-SHA384", - "PSK-AES256-CBC-SHA", - "PSK-AES128-CBC-SHA256", - "PSK-AES128-CBC-SHA" - ] -``` diff --git a/rel/emqx_conf.template.zh.md b/rel/emqx_conf.template.zh.md deleted file mode 100644 index a9df27f63..000000000 --- a/rel/emqx_conf.template.zh.md +++ /dev/null @@ -1,306 +0,0 @@ -EMQX的配置文件格式是 [HOCON](https://github.com/emqx/hocon) 。 -HOCON(Human-Optimized Config Object Notation)是一个JSON的超集,非常适用于易于人类读写的配置数据存储。 - -## 分层结构 - -EMQX的配置文件可分为二层,自底向上依次是: - -1. 集群同步配置:`$EMQX_NODE__DATA_DIR/configs/cluster.hocon`。 -2. 本地节点配置:`emqx.conf` 加上 `EMQX_` 前缀的环境变量。 - -:::tip Tip -在 v5.0.23 或 e5.0.3 之前,集群同步配置保存在文件 `cluster-override.conf` 中,并且它覆盖在配置的最上层。 - -如果从之前的版本升级上来,只要 `cluster-override.conf` 文件存在, -EMQX 就不会创建 `cluster.hocon`,并且 `cluster-override.conf` 会继续覆盖在配置的最上层。 -::: - -如果环境变量 `$EMQX_NODE__DATA_DIR` 没有设置,那么该目录会从 `emqx.conf` 的 `node.data_dir` 配置中读取。 - -配置文件 `cluster.hocon` 的内容会在运行时被EMQX重写。 -这些重写发生在 dashboard UI,管理HTTP API,或者CLI对集群配置进行修改时。 -当EMQX运行在集群中时,一个EMQX节点重启之后,会从集群中其他节点复制该文件内容到本地。 - -:::tip Tip -为避免歧义,应尽量避免让 `cluster.hocon` 和 `emqx.conf` 出现配置交集。 -::: - -更多的重载规则,请参考下文 [配置重载规则](#配置重载规则)。 - -## 配置文件语法 - -在配置文件中,值可以被记为类似JSON的对象,例如 - -``` -node { - name = "emqx@127.0.0.1" - cookie = "mysecret" -} -``` - -另一种等价的表示方法是扁平的,例如 - -``` -node.name = "127.0.0.1" -node.cookie = "mysecret" -``` - -这种扁平格式几乎与EMQX的配置文件格式向后兼容 -在4.x系列中(所谓的'cuttlefish'格式)。 - -它并不是完全兼容,因为HOCON经常要求字符串两端加上引号。 -而cuttlefish把`=`符右边的所有字符都视为值。 - -例如,cuttlefish:`node.name = emqx@127.0.0.1`,HOCON:`node.name = "emqx@127.0.0.1"`。 - -没有特殊字符的字符串在HOCON中也可以不加引号。 -例如:`foo`,`foo_bar`和`foo_bar_1`。 - -关于更多的HOCON语法,请参考[规范](https://github.com/lightbend/config/blob/main/HOCON.md) - -## Schema - -为了使HOCON对象类型安全,EMQX为它引入了一个schema。 -该schema定义了数据类型,以及数据字段的名称和元数据,用于配置值的类型检查等等。 - -::: tip Tip -当前阅读到配置文件的文档本身就是由模式元数据生成的。 -::: - -### 复杂数据类型 - -EMQX的配置文件中,有4中复杂数据结构类型,它们分别是: - -1. Struct:结构体都是有类型名称的,结构体中可以有任意多个字段。 - 结构体和字段的名称由不带特殊字符的全小些字母组成,名称中可以带数字,但不得以数字开头,多个单词可用下划线分隔。 -1. Map: Map 与 Struct(结构体)类似,但是内部的字段不是预先定义好的。 -1. Union: 联合 `MemberType1 | MemberType2 | ...`,可以理解为:“不是这个,就是那个” -1. Array: 数组 `[ElementType]` - -::: tip Tip -如果Map的字段名称是纯数字,它会被解释成一个数组。 -例如 -``` -myarray.1 = 74 -myarray.2 = 75 -``` -会被解析成 `myarray = [74, 75]`。这个用法在重载数组元素的值时候非常有用。 -::: - -### 原始数据类型 - -复杂类型定义了数据 "盒子",其中可能包含其他复杂数据或原始值。 -有很多不同的原始类型,仅举几个例子。 - -* 原子 `atom()`。 -* 布尔 `boolean()`。 -* 字符串 `string()`。 -* 整形 `integer()`。 -* 浮点数 `float()`。 -* 数值 `number()`。 -* 二进制编码的字符串 `binary()` 是 `string()` 的另一种格式。 -* 时间间隔 `emqx_schema:duration()` 是 `integer()` 的另一种格式。 -* ... - -::: tip Tip -原始类型的名称大多是自我描述的,所以不需要过多的注释。 -但是有一些不是那么直观的数据类型,则需要配合字段的描述文档进行理解。 -::: - - -### 配置路径 - -如果我们把EMQX的配置值理解成一个类似目录树的结构,那么类似于文件系统中使用斜杠或反斜杠进行层级分割, -EMQX使用的配置路径的层级分割符是 `'.'` - -被 `'.'` 号分割的每一段,则是 Struct(结构体)的字段,或 Map 的 key。 - -下面有几个例子: - -``` -node.name = "emqx.127.0.0.1" -zone.zone1.max_packet_size = "10M" -authentication.1.enable = true -``` - -### 环境变量重载 - -因为 `'.'` 分隔符不能使用于环境变量,所以我们需要使用另一个分割符。EMQX选用的是双下划线 `__`。 -为了与其他的环境变量有所区分,EMQX还增加了一个前缀 `EMQX_` 来用作环境变量命名空间。 - -例如 `node.name` 的重载变量名是 `EMQX_NODE__NAME`。 - -环境变量的值,是按 HOCON 值解析的,这也使得环境变量可以用来传递复杂数据类型的值。 - -例如,下面这个环境变量传入一个数组类型的值。 - -``` -export EMQX_LISTENERS__SSL__L1__AUTHENTICATION__SSL__CIPHERS='["TLS_AES_256_GCM_SHA384"]' -``` - -这也意味着有些带特殊字符(例如`:` 和 `=`),则需要用双引号对这个值包起来。 - -例如`localhost:1883` 会被解析成一个结构体 `{"localhost": 1883}`。 -想要把它当字符串使用时,就必需使用引号,如下: - -``` -EMQX_BRIDGES__MQTT__MYBRIDGE__CONNECTOR_SERVER='"localhost:1883"' -``` - - -::: tip Tip -未定义的根路径会被EMQX忽略,例如 `EMQX_UNKNOWN_ROOT__FOOBAR` 这个环境变量会被EMQX忽略, -因为 `UNKNOWN_ROOT` 不是预先定义好的根路径。 -对于已知的根路径,未知的字段名称将被记录为warning日志,比如下面这个例子。 - -``` -[warning] unknown_env_vars: ["EMQX_AUTHENTICATION__ENABLED"] -``` - -这是因为正确的字段名称是 `enable`,而不是 `enabled`。 -::: - -### 配置重载规则 - -HOCON的值是分层覆盖的,普遍规则如下: - -- 在同一个文件中,后(在文件底部)定义的值,覆盖前(在文件顶部)到值。 -- 当按层级覆盖时,高层级的值覆盖低层级的值。 - -结下来的文档将解释更详细的规则。 - -#### 结构体 - -合并覆盖规则。在如下配置中,最后一行的 `debug` 值会覆盖覆盖原先`level`字段的 `error` 值,但是 `enable` 字段保持不变。 -``` -log { - console_handler{ - enable=true, - level=error - } -} - -## 控制台日志打印先定义为 `error` 级,后被覆写成 `debug` 级 - -log.console_handler.level=debug -``` - -#### Map - -Map与结构体类似,也是合并覆盖规则。 -如下例子中,`zone1` 的 `max_packet_size` 可以在文件后面覆写。 - -``` -zone { - zone1 { - mqtt.max_packet_size = 1M - } -} - -## 报文大小限制最先被设置成1MB,后被覆写为10MB - -zone.zone1.mqtt.max_packet_size = 10M -``` - -#### 数组元素 - -如上面介绍过,EMQX配置中的数组有两种表达方式。 - -* 列表格式,例如: `[1, 2, 3]` -* 带下标的Map格式,例如: `{"1"=1, "2"=2, "3"=3}` - -点好(`'.'`)分隔到路径中的纯数字会被解析成数组下标。 -例如,`authentication.1={...}` 会被解析成 `authentication={"1": {...}}`,进而进一步解析成 `authentication=[{...}]` -有了这个特性,我们就可以轻松覆写数组某个元素的值,例如: - -``` -authentication=[{enable=true, backend="built_in_database", mechanism="password_based"}] -# 可以用下面的方式将第一个元素的 `enable` 字段覆写 -authentication.1.enable=false -``` - -::: warning Warning -使用列表格式是的数组将全量覆写原值,如下例: - -``` -authentication=[{enable=true, backend="built_in_database", mechanism="password_based"}] -## 下面这中方式会导致数组第一个元素的除了 `enable` 以外的其他字段全部丢失 -authentication=[{enable=true}] -``` -::: - -#### TLS/SSL ciphers - -从 v5.0.6 开始 EMQX 不在配置文件中详细列出所有默认的密码套件名称。 -而是在配置文件中使用一个空列表,然后在运行时替换成默认的密码套件。 - -下面这些密码套件是 EMQX 默认支持的: - -tlsv1.3: -``` -ciphers = - [ "TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256", - "TLS_CHACHA20_POLY1305_SHA256", "TLS_AES_128_CCM_SHA256", - "TLS_AES_128_CCM_8_SHA256" - ] -``` - -tlsv1.2 或更早 - -``` -ciphers = - [ "ECDHE-ECDSA-AES256-GCM-SHA384", - "ECDHE-RSA-AES256-GCM-SHA384", - "ECDHE-ECDSA-AES256-SHA384", - "ECDHE-RSA-AES256-SHA384", - "ECDH-ECDSA-AES256-GCM-SHA384", - "ECDH-RSA-AES256-GCM-SHA384", - "ECDH-ECDSA-AES256-SHA384", - "ECDH-RSA-AES256-SHA384", - "DHE-DSS-AES256-GCM-SHA384", - "DHE-DSS-AES256-SHA256", - "AES256-GCM-SHA384", - "AES256-SHA256", - "ECDHE-ECDSA-AES128-GCM-SHA256", - "ECDHE-RSA-AES128-GCM-SHA256", - "ECDHE-ECDSA-AES128-SHA256", - "ECDHE-RSA-AES128-SHA256", - "ECDH-ECDSA-AES128-GCM-SHA256", - "ECDH-RSA-AES128-GCM-SHA256", - "ECDH-ECDSA-AES128-SHA256", - "ECDH-RSA-AES128-SHA256", - "DHE-DSS-AES128-GCM-SHA256", - "DHE-DSS-AES128-SHA256", - "AES128-GCM-SHA256", - "AES128-SHA256", - "ECDHE-ECDSA-AES256-SHA", - "ECDHE-RSA-AES256-SHA", - "DHE-DSS-AES256-SHA", - "ECDH-ECDSA-AES256-SHA", - "ECDH-RSA-AES256-SHA", - "ECDHE-ECDSA-AES128-SHA", - "ECDHE-RSA-AES128-SHA", - "DHE-DSS-AES128-SHA", - "ECDH-ECDSA-AES128-SHA", - "ECDH-RSA-AES128-SHA" - ] -``` - -配置 PSK 认证的监听器 - -``` -ciphers = [ - [ "RSA-PSK-AES256-GCM-SHA384", - "RSA-PSK-AES256-CBC-SHA384", - "RSA-PSK-AES128-GCM-SHA256", - "RSA-PSK-AES128-CBC-SHA256", - "RSA-PSK-AES256-CBC-SHA", - "RSA-PSK-AES128-CBC-SHA", - "PSK-AES256-GCM-SHA384", - "PSK-AES128-GCM-SHA256", - "PSK-AES256-CBC-SHA384", - "PSK-AES256-CBC-SHA", - "PSK-AES128-CBC-SHA256", - "PSK-AES128-CBC-SHA" - ] -```