|
|
@@ -28,10 +28,14 @@
|
|
|
fields/1,
|
|
|
desc/1,
|
|
|
host_opts/0,
|
|
|
- ssl_client_opts_fields/0
|
|
|
+ ssl_client_opts_fields/0,
|
|
|
+ producer_opts/0
|
|
|
]).
|
|
|
|
|
|
--export([kafka_producer_converter/2, producer_strategy_key_validator/1]).
|
|
|
+-export([
|
|
|
+ kafka_producer_converter/2,
|
|
|
+ producer_strategy_key_validator/1
|
|
|
+]).
|
|
|
|
|
|
%% -------------------------------------------------------------------------------------------------
|
|
|
%% api
|
|
|
@@ -251,15 +255,13 @@ fields("get_" ++ Type) ->
|
|
|
fields("config_bridge_v2") ->
|
|
|
fields(kafka_producer_action);
|
|
|
fields("config_connector") ->
|
|
|
- fields(kafka_connector);
|
|
|
+ connector_config_fields();
|
|
|
fields("config_producer") ->
|
|
|
fields(kafka_producer);
|
|
|
fields("config_consumer") ->
|
|
|
fields(kafka_consumer);
|
|
|
-fields(kafka_connector) ->
|
|
|
- fields("config");
|
|
|
fields(kafka_producer) ->
|
|
|
- fields("config") ++ fields(producer_opts);
|
|
|
+ connector_config_fields() ++ producer_opts();
|
|
|
fields(kafka_producer_action) ->
|
|
|
[
|
|
|
{enable, mk(boolean(), #{desc => ?DESC("config_enable"), default => true})},
|
|
|
@@ -268,49 +270,9 @@ fields(kafka_producer_action) ->
|
|
|
desc => ?DESC(emqx_connector_schema, "connector_field"), required => true
|
|
|
})},
|
|
|
{description, emqx_schema:description_schema()}
|
|
|
- ] ++ fields(producer_opts);
|
|
|
+ ] ++ producer_opts();
|
|
|
fields(kafka_consumer) ->
|
|
|
- fields("config") ++ fields(consumer_opts);
|
|
|
-fields("config") ->
|
|
|
- [
|
|
|
- {enable, mk(boolean(), #{desc => ?DESC("config_enable"), default => true})},
|
|
|
- {description, emqx_schema:description_schema()},
|
|
|
- {bootstrap_hosts,
|
|
|
- mk(
|
|
|
- binary(),
|
|
|
- #{
|
|
|
- required => true,
|
|
|
- desc => ?DESC(bootstrap_hosts),
|
|
|
- validator => emqx_schema:servers_validator(
|
|
|
- host_opts(), _Required = true
|
|
|
- )
|
|
|
- }
|
|
|
- )},
|
|
|
- {connect_timeout,
|
|
|
- mk(emqx_schema:timeout_duration_ms(), #{
|
|
|
- default => <<"5s">>,
|
|
|
- desc => ?DESC(connect_timeout)
|
|
|
- })},
|
|
|
- {min_metadata_refresh_interval,
|
|
|
- mk(
|
|
|
- emqx_schema:timeout_duration_ms(),
|
|
|
- #{
|
|
|
- default => <<"3s">>,
|
|
|
- desc => ?DESC(min_metadata_refresh_interval)
|
|
|
- }
|
|
|
- )},
|
|
|
- {metadata_request_timeout,
|
|
|
- mk(emqx_schema:timeout_duration_ms(), #{
|
|
|
- default => <<"5s">>,
|
|
|
- desc => ?DESC(metadata_request_timeout)
|
|
|
- })},
|
|
|
- {authentication,
|
|
|
- mk(hoconsc:union([none, ref(auth_username_password), ref(auth_gssapi_kerberos)]), #{
|
|
|
- default => none, desc => ?DESC("authentication")
|
|
|
- })},
|
|
|
- {socket_opts, mk(ref(socket_opts), #{required => false, desc => ?DESC(socket_opts)})},
|
|
|
- {ssl, mk(ref(ssl_client_opts), #{})}
|
|
|
- ];
|
|
|
+ connector_config_fields() ++ fields(consumer_opts);
|
|
|
fields(ssl_client_opts) ->
|
|
|
ssl_client_opts_fields();
|
|
|
fields(auth_username_password) ->
|
|
|
@@ -369,20 +331,6 @@ fields(socket_opts) ->
|
|
|
validator => fun emqx_schema:validate_tcp_keepalive/1
|
|
|
})}
|
|
|
];
|
|
|
-fields(producer_opts) ->
|
|
|
- [
|
|
|
- %% Note: there's an implicit convention in `emqx_bridge' that,
|
|
|
- %% for egress bridges with this config, the published messages
|
|
|
- %% will be forwarded to such bridges.
|
|
|
- {local_topic, mk(binary(), #{required => false, desc => ?DESC(mqtt_topic)})},
|
|
|
- {kafka,
|
|
|
- mk(ref(producer_kafka_opts), #{
|
|
|
- required => true,
|
|
|
- desc => ?DESC(producer_kafka_opts),
|
|
|
- validator => fun producer_strategy_key_validator/1
|
|
|
- })},
|
|
|
- {resource_opts, mk(ref(resource_opts), #{default => #{}, desc => ?DESC(resource_opts)})}
|
|
|
- ];
|
|
|
fields(producer_kafka_opts) ->
|
|
|
[
|
|
|
{topic, mk(string(), #{required => true, desc => ?DESC(kafka_topic)})},
|
|
|
@@ -580,7 +528,7 @@ fields(resource_opts) ->
|
|
|
CreationOpts = emqx_resource_schema:create_opts(_Overrides = []),
|
|
|
lists:filter(fun({Field, _}) -> lists:member(Field, SupportedFields) end, CreationOpts).
|
|
|
|
|
|
-desc("config") ->
|
|
|
+desc("config_connector") ->
|
|
|
?DESC("desc_config");
|
|
|
desc(resource_opts) ->
|
|
|
?DESC(emqx_resource_schema, "resource_opts");
|
|
|
@@ -599,34 +547,86 @@ desc("post_" ++ Type) when
|
|
|
desc(kafka_producer_action) ->
|
|
|
?DESC("kafka_producer_action");
|
|
|
desc(Name) ->
|
|
|
- lists:member(Name, struct_names()) orelse throw({missing_desc, Name}),
|
|
|
?DESC(Name).
|
|
|
|
|
|
-struct_names() ->
|
|
|
+connector_config_fields() ->
|
|
|
[
|
|
|
- auth_gssapi_kerberos,
|
|
|
- auth_username_password,
|
|
|
- kafka_message,
|
|
|
- kafka_producer,
|
|
|
- kafka_consumer,
|
|
|
- producer_buffer,
|
|
|
- producer_kafka_opts,
|
|
|
- socket_opts,
|
|
|
- producer_opts,
|
|
|
- consumer_opts,
|
|
|
- consumer_kafka_opts,
|
|
|
- consumer_topic_mapping,
|
|
|
- producer_kafka_ext_headers,
|
|
|
- ssl_client_opts
|
|
|
+ {enable, mk(boolean(), #{desc => ?DESC("config_enable"), default => true})},
|
|
|
+ {description, emqx_schema:description_schema()},
|
|
|
+ {bootstrap_hosts,
|
|
|
+ mk(
|
|
|
+ binary(),
|
|
|
+ #{
|
|
|
+ required => true,
|
|
|
+ desc => ?DESC(bootstrap_hosts),
|
|
|
+ validator => emqx_schema:servers_validator(
|
|
|
+ host_opts(), _Required = true
|
|
|
+ )
|
|
|
+ }
|
|
|
+ )},
|
|
|
+ {connect_timeout,
|
|
|
+ mk(emqx_schema:timeout_duration_ms(), #{
|
|
|
+ default => <<"5s">>,
|
|
|
+ desc => ?DESC(connect_timeout)
|
|
|
+ })},
|
|
|
+ {min_metadata_refresh_interval,
|
|
|
+ mk(
|
|
|
+ emqx_schema:timeout_duration_ms(),
|
|
|
+ #{
|
|
|
+ default => <<"3s">>,
|
|
|
+ desc => ?DESC(min_metadata_refresh_interval)
|
|
|
+ }
|
|
|
+ )},
|
|
|
+ {metadata_request_timeout,
|
|
|
+ mk(emqx_schema:timeout_duration_ms(), #{
|
|
|
+ default => <<"5s">>,
|
|
|
+ desc => ?DESC(metadata_request_timeout)
|
|
|
+ })},
|
|
|
+ {authentication,
|
|
|
+ mk(hoconsc:union([none, ref(auth_username_password), ref(auth_gssapi_kerberos)]), #{
|
|
|
+ default => none, desc => ?DESC("authentication")
|
|
|
+ })},
|
|
|
+ {socket_opts, mk(ref(socket_opts), #{required => false, desc => ?DESC(socket_opts)})},
|
|
|
+ {ssl, mk(ref(ssl_client_opts), #{})}
|
|
|
].
|
|
|
|
|
|
+producer_opts() ->
|
|
|
+ [
|
|
|
+ %% Note: there's an implicit convention in `emqx_bridge' that,
|
|
|
+ %% for egress bridges with this config, the published messages
|
|
|
+ %% will be forwarded to such bridges.
|
|
|
+ {local_topic, mk(binary(), #{required => false, desc => ?DESC(mqtt_topic)})},
|
|
|
+ parameters_field(),
|
|
|
+ {resource_opts, mk(ref(resource_opts), #{default => #{}, desc => ?DESC(resource_opts)})}
|
|
|
+ ].
|
|
|
+
|
|
|
+%% Since e5.3.1, we want to rename the field 'kafka' to 'parameters'
|
|
|
+%% Hoever we need to keep it backward compatible for generated schema json (version 0.1.0)
|
|
|
+%% since schema is data for the 'schemas' API.
|
|
|
+parameters_field() ->
|
|
|
+ {Name, Alias} =
|
|
|
+ case get(emqx_bridge_schema_version) of
|
|
|
+ <<"0.1.0">> ->
|
|
|
+ {kafka, parameters};
|
|
|
+ _ ->
|
|
|
+ {parameters, kafka}
|
|
|
+ end,
|
|
|
+ {Name,
|
|
|
+ mk(ref(producer_kafka_opts), #{
|
|
|
+ required => true,
|
|
|
+ aliases => [Alias],
|
|
|
+ desc => ?DESC(producer_kafka_opts),
|
|
|
+ validator => fun producer_strategy_key_validator/1
|
|
|
+ })}.
|
|
|
+
|
|
|
%% -------------------------------------------------------------------------------------------------
|
|
|
%% internal
|
|
|
type_field(BridgeV2Type) when BridgeV2Type =:= "connector"; BridgeV2Type =:= "bridge_v2" ->
|
|
|
{type, mk(enum([kafka_producer]), #{required => true, desc => ?DESC("desc_type")})};
|
|
|
type_field(_) ->
|
|
|
{type,
|
|
|
- mk(enum([kafka_consumer, kafka, kafka_producer]), #{
|
|
|
+ %% 'kafka' is kept for backward compatibility
|
|
|
+ mk(enum([kafka, kafka_producer, kafka_consumer]), #{
|
|
|
required => true, desc => ?DESC("desc_type")
|
|
|
})}.
|
|
|
|
|
|
@@ -641,17 +641,23 @@ kafka_producer_converter(undefined, _HoconOpts) ->
|
|
|
kafka_producer_converter(
|
|
|
#{<<"producer">> := OldOpts0, <<"bootstrap_hosts">> := _} = Config0, _HoconOpts
|
|
|
) ->
|
|
|
- %% old schema
|
|
|
+ %% prior to e5.0.2
|
|
|
MQTTOpts = maps:get(<<"mqtt">>, OldOpts0, #{}),
|
|
|
LocalTopic = maps:get(<<"topic">>, MQTTOpts, undefined),
|
|
|
KafkaOpts = maps:get(<<"kafka">>, OldOpts0),
|
|
|
Config = maps:without([<<"producer">>], Config0),
|
|
|
case LocalTopic =:= undefined of
|
|
|
true ->
|
|
|
- Config#{<<"kafka">> => KafkaOpts};
|
|
|
+ Config#{<<"parameters">> => KafkaOpts};
|
|
|
false ->
|
|
|
- Config#{<<"kafka">> => KafkaOpts, <<"local_topic">> => LocalTopic}
|
|
|
+ Config#{<<"parameters">> => KafkaOpts, <<"local_topic">> => LocalTopic}
|
|
|
end;
|
|
|
+kafka_producer_converter(
|
|
|
+ #{<<"kafka">> := _} = Config0, _HoconOpts
|
|
|
+) ->
|
|
|
+ %% from e5.0.2 to e5.3.0
|
|
|
+ {KafkaOpts, Config} = maps:take(<<"kafka">>, Config0),
|
|
|
+ Config#{<<"parameters">> => KafkaOpts};
|
|
|
kafka_producer_converter(Config, _HoconOpts) ->
|
|
|
%% new schema
|
|
|
Config.
|