logstash-integration-kafka 10.5.3-java → 10.6.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/docs/input-kafka.asciidoc +46 -1
- data/lib/logstash-integration-kafka_jars.rb +13 -4
- data/lib/logstash/inputs/kafka.rb +29 -4
- data/lib/logstash/plugin_mixins/common.rb +92 -0
- data/logstash-integration-kafka.gemspec +1 -1
- data/spec/integration/inputs/kafka_spec.rb +186 -11
- data/spec/unit/inputs/avro_schema_fixture_payment.asvc +8 -0
- data/spec/unit/inputs/kafka_spec.rb +16 -0
- data/vendor/jar-dependencies/com/github/luben/zstd-jni/1.4.4-7/zstd-jni-1.4.4-7.jar +0 -0
- data/vendor/jar-dependencies/io/confluent/common-config/5.5.1/common-config-5.5.1.jar +0 -0
- data/vendor/jar-dependencies/io/confluent/common-utils/5.5.1/common-utils-5.5.1.jar +0 -0
- data/vendor/jar-dependencies/io/confluent/kafka-avro-serializer/5.5.1/kafka-avro-serializer-5.5.1.jar +0 -0
- data/vendor/jar-dependencies/io/confluent/kafka-schema-registry-client/5.5.1/kafka-schema-registry-client-5.5.1.jar +0 -0
- data/vendor/jar-dependencies/io/confluent/kafka-schema-serializer/5.5.1/kafka-schema-serializer-5.5.1.jar +0 -0
- data/vendor/jar-dependencies/javax/ws/rs/javax.ws.rs-api/2.1.1/javax.ws.rs-api-2.1.1.jar +0 -0
- data/vendor/jar-dependencies/org/apache/avro/avro/1.9.2/avro-1.9.2.jar +0 -0
- data/vendor/jar-dependencies/org/apache/kafka/kafka-clients/{2.4.1/kafka-clients-2.4.1.jar → 2.5.1/kafka-clients-2.5.1.jar} +0 -0
- data/vendor/jar-dependencies/org/apache/kafka/kafka_2.12/2.5.1/kafka_2.12-2.5.1.jar +0 -0
- data/vendor/jar-dependencies/org/glassfish/jersey/core/jersey-common/2.30/jersey-common-2.30.jar +0 -0
- data/vendor/jar-dependencies/org/lz4/lz4-java/1.7.1/lz4-java-1.7.1.jar +0 -0
- data/vendor/jar-dependencies/org/slf4j/slf4j-api/1.7.30/slf4j-api-1.7.30.jar +0 -0
- metadata +18 -6
- data/vendor/jar-dependencies/com/github/luben/zstd-jni/1.4.3-1/zstd-jni-1.4.3-1.jar +0 -0
- data/vendor/jar-dependencies/org/lz4/lz4-java/1.6.0/lz4-java-1.6.0.jar +0 -0
- data/vendor/jar-dependencies/org/slf4j/slf4j-api/1.7.28/slf4j-api-1.7.28.jar +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1d8b40d779e91e9c05dece65249660ab5c272b6833658cbca51b977d92936f42
|
|
4
|
+
data.tar.gz: 58323e216be645aede9f0b49c27824958b6627485bdf79a6774cd5f87b818245
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0f05eec028758745a2ab04b90d721128c088c46d0bb9a01923c389118c99a718a561d2ca2420fc2e206e4cf75e4e3695e1704a17d9eff9f4f18e66da3d3ccb85
|
|
7
|
+
data.tar.gz: 85e117a64d14d013674869ccadfb5487a04991ec83c6a9d6874496b862be200bf4e7203d3ac4fc779d67131ecbe82212fafd66884114337d17ed33dda7ad0963
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
## 10.6.0
|
|
2
|
+
- Added functionality to Kafka input to use Avro deserializer in retrieving data from Kafka. The schema is retrieved
|
|
3
|
+
from an instance of Confluent's Schema Registry service [#51](https://github.com/logstash-plugins/logstash-integration-kafka/pull/51)
|
|
4
|
+
|
|
1
5
|
## 10.5.3
|
|
2
6
|
- Fix: set (optional) truststore when endpoint id check disabled [#60](https://github.com/logstash-plugins/logstash-integration-kafka/pull/60).
|
|
3
7
|
Since **10.1.0** disabling server host-name verification (`ssl_endpoint_identification_algorithm => ""`) did not allow
|
data/docs/input-kafka.asciidoc
CHANGED
|
@@ -124,6 +124,10 @@ See the https://kafka.apache.org/{kafka_client_doc}/documentation for more detai
|
|
|
124
124
|
| <<plugins-{type}s-{plugin}-sasl_jaas_config>> |<<string,string>>|No
|
|
125
125
|
| <<plugins-{type}s-{plugin}-sasl_kerberos_service_name>> |<<string,string>>|No
|
|
126
126
|
| <<plugins-{type}s-{plugin}-sasl_mechanism>> |<<string,string>>|No
|
|
127
|
+
| <<plugins-{type}s-{plugin}-schema_registry_key>> |<<string,string>>|No
|
|
128
|
+
| <<plugins-{type}s-{plugin}-schema_registry_proxy>> |<<uri,uri>>|No
|
|
129
|
+
| <<plugins-{type}s-{plugin}-schema_registry_secret>> |<<string,string>>|No
|
|
130
|
+
| <<plugins-{type}s-{plugin}-schema_registry_url>> |<<uri,uri>>|No
|
|
127
131
|
| <<plugins-{type}s-{plugin}-security_protocol>> |<<string,string>>, one of `["PLAINTEXT", "SSL", "SASL_PLAINTEXT", "SASL_SSL"]`|No
|
|
128
132
|
| <<plugins-{type}s-{plugin}-send_buffer_bytes>> |<<number,number>>|No
|
|
129
133
|
| <<plugins-{type}s-{plugin}-session_timeout_ms>> |<<number,number>>|No
|
|
@@ -528,6 +532,44 @@ http://kafka.apache.org/documentation.html#security_sasl[SASL mechanism] used fo
|
|
|
528
532
|
This may be any mechanism for which a security provider is available.
|
|
529
533
|
GSSAPI is the default mechanism.
|
|
530
534
|
|
|
535
|
+
[id="plugins-{type}s-{plugin}-schema_registry_key"]
|
|
536
|
+
===== `schema_registry_key`
|
|
537
|
+
|
|
538
|
+
* Value type is <<string,string>>
|
|
539
|
+
* There is no default value for this setting.
|
|
540
|
+
|
|
541
|
+
Set the username for basic authorization to access remote Schema Registry.
|
|
542
|
+
|
|
543
|
+
[id="plugins-{type}s-{plugin}-schema_registry_proxy"]
|
|
544
|
+
===== `schema_registry_proxy`
|
|
545
|
+
|
|
546
|
+
* Value type is <<uri,uri>>
|
|
547
|
+
* There is no default value for this setting.
|
|
548
|
+
|
|
549
|
+
Set the address of a forward HTTP proxy. An empty string is treated as if proxy was not set.
|
|
550
|
+
|
|
551
|
+
[id="plugins-{type}s-{plugin}-schema_registry_secret"]
|
|
552
|
+
===== `schema_registry_secret`
|
|
553
|
+
|
|
554
|
+
* Value type is <<string,string>>
|
|
555
|
+
* There is no default value for this setting.
|
|
556
|
+
|
|
557
|
+
Set the password for basic authorization to access remote Schema Registry.
|
|
558
|
+
|
|
559
|
+
[id="plugins-{type}s-{plugin}-schema_registry_url"]
|
|
560
|
+
===== `schema_registry_url`
|
|
561
|
+
|
|
562
|
+
* Value type is <<uri,uri>>
|
|
563
|
+
|
|
564
|
+
The URI that points to an instance of the
|
|
565
|
+
https://docs.confluent.io/current/schema-registry/index.html[Schema Registry] service,
|
|
566
|
+
used to manage Avro schemas. Be sure that the Avro schemas for deserializing the data from
|
|
567
|
+
the specified topics have been uploaded to the Schema Registry service.
|
|
568
|
+
The schemas must follow a naming convention with the pattern <topic name>-value.
|
|
569
|
+
|
|
570
|
+
Use either the Schema Registry config option or the
|
|
571
|
+
<<plugins-{type}s-{plugin}-value_deserializer_class>> config option, but not both.
|
|
572
|
+
|
|
531
573
|
[id="plugins-{type}s-{plugin}-security_protocol"]
|
|
532
574
|
===== `security_protocol`
|
|
533
575
|
|
|
@@ -641,7 +683,10 @@ The topics configuration will be ignored when using this configuration.
|
|
|
641
683
|
* Value type is <<string,string>>
|
|
642
684
|
* Default value is `"org.apache.kafka.common.serialization.StringDeserializer"`
|
|
643
685
|
|
|
644
|
-
Java Class used to deserialize the record's value
|
|
686
|
+
Java Class used to deserialize the record's value.
|
|
687
|
+
A custom value deserializer can be used only if you are not using a Schema Registry.
|
|
688
|
+
Use either the value_deserializer_class config option or the
|
|
689
|
+
<<plugins-{type}s-{plugin}-schema_registry_url>> config option, but not both.
|
|
645
690
|
|
|
646
691
|
[id="plugins-{type}s-{plugin}-common-options"]
|
|
647
692
|
include::{include_path}/{type}.asciidoc[]
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
# AUTOGENERATED BY THE GRADLE SCRIPT. DO NOT EDIT.
|
|
2
2
|
|
|
3
3
|
require 'jar_dependencies'
|
|
4
|
-
require_jar('
|
|
5
|
-
require_jar('
|
|
6
|
-
require_jar('
|
|
7
|
-
require_jar('org.
|
|
4
|
+
require_jar('io.confluent', 'kafka-avro-serializer', '5.5.1')
|
|
5
|
+
require_jar('io.confluent', 'kafka-schema-serializer', '5.5.1')
|
|
6
|
+
require_jar('io.confluent', 'common-config', '5.5.1')
|
|
7
|
+
require_jar('org.apache.avro', 'avro', '1.9.2')
|
|
8
|
+
require_jar('io.confluent', 'kafka-schema-registry-client', '5.5.1')
|
|
9
|
+
require_jar('org.apache.kafka', 'kafka_2.12', '2.5.1')
|
|
10
|
+
require_jar('io.confluent', 'common-utils', '5.5.1')
|
|
11
|
+
require_jar('javax.ws.rs', 'javax.ws.rs-api', '2.1.1')
|
|
12
|
+
require_jar('org.glassfish.jersey.core', 'jersey-common', '2.30')
|
|
13
|
+
require_jar('org.apache.kafka', 'kafka-clients', '2.5.1')
|
|
14
|
+
require_jar('com.github.luben', 'zstd-jni', '1.4.4-7')
|
|
15
|
+
require_jar('org.slf4j', 'slf4j-api', '1.7.30')
|
|
16
|
+
require_jar('org.lz4', 'lz4-java', '1.7.1')
|
|
8
17
|
require_jar('org.xerial.snappy', 'snappy-java', '1.1.7.3')
|
|
@@ -4,6 +4,10 @@ require 'stud/interval'
|
|
|
4
4
|
require 'java'
|
|
5
5
|
require 'logstash-integration-kafka_jars.rb'
|
|
6
6
|
require 'logstash/plugin_mixins/kafka_support'
|
|
7
|
+
require "faraday"
|
|
8
|
+
require "json"
|
|
9
|
+
require "logstash/json"
|
|
10
|
+
require_relative '../plugin_mixins/common'
|
|
7
11
|
|
|
8
12
|
# This input will read events from a Kafka topic. It uses the 0.10 version of
|
|
9
13
|
# the consumer API provided by Kafka to read messages from the broker.
|
|
@@ -50,7 +54,10 @@ require 'logstash/plugin_mixins/kafka_support'
|
|
|
50
54
|
#
|
|
51
55
|
class LogStash::Inputs::Kafka < LogStash::Inputs::Base
|
|
52
56
|
|
|
57
|
+
DEFAULT_DESERIALIZER_CLASS = "org.apache.kafka.common.serialization.StringDeserializer"
|
|
58
|
+
|
|
53
59
|
include LogStash::PluginMixins::KafkaSupport
|
|
60
|
+
include ::LogStash::PluginMixins::KafkaAvroSchemaRegistry
|
|
54
61
|
|
|
55
62
|
config_name 'kafka'
|
|
56
63
|
|
|
@@ -167,7 +174,7 @@ class LogStash::Inputs::Kafka < LogStash::Inputs::Base
|
|
|
167
174
|
# and a rebalance operation is triggered for the group identified by `group_id`
|
|
168
175
|
config :session_timeout_ms, :validate => :number, :default => 10_000 # (10s) Kafka default
|
|
169
176
|
# Java Class used to deserialize the record's value
|
|
170
|
-
config :value_deserializer_class, :validate => :string, :default =>
|
|
177
|
+
config :value_deserializer_class, :validate => :string, :default => DEFAULT_DESERIALIZER_CLASS
|
|
171
178
|
# A list of topics to subscribe to, defaults to ["logstash"].
|
|
172
179
|
config :topics, :validate => :array, :default => ["logstash"]
|
|
173
180
|
# A topic regex pattern to subscribe to.
|
|
@@ -236,11 +243,11 @@ class LogStash::Inputs::Kafka < LogStash::Inputs::Base
|
|
|
236
243
|
# `timestamp`: The timestamp of this message
|
|
237
244
|
config :decorate_events, :validate => :boolean, :default => false
|
|
238
245
|
|
|
239
|
-
|
|
240
246
|
public
|
|
241
247
|
def register
|
|
242
248
|
@runner_threads = []
|
|
243
|
-
|
|
249
|
+
check_schema_registry_parameters
|
|
250
|
+
end
|
|
244
251
|
|
|
245
252
|
public
|
|
246
253
|
def run(logstash_queue)
|
|
@@ -278,6 +285,13 @@ class LogStash::Inputs::Kafka < LogStash::Inputs::Base
|
|
|
278
285
|
for record in records do
|
|
279
286
|
codec_instance.decode(record.value.to_s) do |event|
|
|
280
287
|
decorate(event)
|
|
288
|
+
if schema_registry_url
|
|
289
|
+
json = LogStash::Json.load(record.value.to_s)
|
|
290
|
+
json.each do |k, v|
|
|
291
|
+
event.set(k, v)
|
|
292
|
+
end
|
|
293
|
+
event.remove("message")
|
|
294
|
+
end
|
|
281
295
|
if @decorate_events
|
|
282
296
|
event.set("[@metadata][kafka][topic]", record.topic)
|
|
283
297
|
event.set("[@metadata][kafka][consumer_group]", @group_id)
|
|
@@ -337,7 +351,18 @@ class LogStash::Inputs::Kafka < LogStash::Inputs::Base
|
|
|
337
351
|
props.put(kafka::CLIENT_RACK_CONFIG, client_rack) unless client_rack.nil?
|
|
338
352
|
|
|
339
353
|
props.put("security.protocol", security_protocol) unless security_protocol.nil?
|
|
340
|
-
|
|
354
|
+
if schema_registry_url
|
|
355
|
+
props.put(kafka::VALUE_DESERIALIZER_CLASS_CONFIG, Java::io.confluent.kafka.serializers.KafkaAvroDeserializer.java_class)
|
|
356
|
+
serdes_config = Java::io.confluent.kafka.serializers.AbstractKafkaAvroSerDeConfig
|
|
357
|
+
props.put(serdes_config::SCHEMA_REGISTRY_URL_CONFIG, schema_registry_url.to_s)
|
|
358
|
+
if schema_registry_proxy && !schema_registry_proxy.empty?
|
|
359
|
+
props.put(serdes_config::PROXY_HOST, @schema_registry_proxy_host)
|
|
360
|
+
props.put(serdes_config::PROXY_PORT, @schema_registry_proxy_port)
|
|
361
|
+
end
|
|
362
|
+
if schema_registry_key && !schema_registry_key.empty?
|
|
363
|
+
props.put(serdes_config::USER_INFO_CONFIG, schema_registry_key + ":" + schema_registry_secret.value)
|
|
364
|
+
end
|
|
365
|
+
end
|
|
341
366
|
if security_protocol == "SSL"
|
|
342
367
|
set_trustore_keystore_config(props)
|
|
343
368
|
elsif security_protocol == "SASL_PLAINTEXT"
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
module LogStash
|
|
2
|
+
module PluginMixins
|
|
3
|
+
module KafkaAvroSchemaRegistry
|
|
4
|
+
|
|
5
|
+
def self.included(base)
|
|
6
|
+
base.extend(self)
|
|
7
|
+
base.setup_schema_registry_config
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def setup_schema_registry_config
|
|
11
|
+
# Option to set key to access Schema Registry.
|
|
12
|
+
config :schema_registry_key, :validate => :string
|
|
13
|
+
|
|
14
|
+
# Option to set secret to access Schema Registry.
|
|
15
|
+
config :schema_registry_secret, :validate => :password
|
|
16
|
+
|
|
17
|
+
# Option to set the endpoint of the Schema Registry.
|
|
18
|
+
# This option permit the usage of Avro Kafka deserializer which retrieve the schema of the Avro message from an
|
|
19
|
+
# instance of schema registry. If this option has value `value_deserializer_class` nor `topics_pattern` could be valued
|
|
20
|
+
config :schema_registry_url, :validate => :uri
|
|
21
|
+
|
|
22
|
+
# Option to set the proxy of the Schema Registry.
|
|
23
|
+
# This option permits to define a proxy to be used to reach the schema registry service instance.
|
|
24
|
+
config :schema_registry_proxy, :validate => :uri
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def check_schema_registry_parameters
|
|
28
|
+
if @schema_registry_url
|
|
29
|
+
check_for_schema_registry_conflicts
|
|
30
|
+
@schema_registry_proxy_host, @schema_registry_proxy_port = split_proxy_into_host_and_port(schema_registry_proxy)
|
|
31
|
+
check_for_key_and_secret
|
|
32
|
+
check_for_schema_registry_connectivity_and_subjects
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
def check_for_schema_registry_conflicts
|
|
38
|
+
if @value_deserializer_class != LogStash::Inputs::Kafka::DEFAULT_DESERIALIZER_CLASS
|
|
39
|
+
raise LogStash::ConfigurationError, 'Option schema_registry_url prohibit the customization of value_deserializer_class'
|
|
40
|
+
end
|
|
41
|
+
if @topics_pattern && !@topics_pattern.empty?
|
|
42
|
+
raise LogStash::ConfigurationError, 'Option schema_registry_url prohibit the customization of topics_pattern'
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
def check_for_schema_registry_connectivity_and_subjects
|
|
48
|
+
client = Faraday.new(@schema_registry_url.to_s) do |conn|
|
|
49
|
+
if schema_registry_proxy && !schema_registry_proxy.empty?
|
|
50
|
+
conn.proxy = schema_registry_proxy.to_s
|
|
51
|
+
end
|
|
52
|
+
if schema_registry_key and !schema_registry_key.empty?
|
|
53
|
+
conn.basic_auth(schema_registry_key, schema_registry_secret.value)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
begin
|
|
57
|
+
response = client.get('/subjects')
|
|
58
|
+
rescue Faraday::Error => e
|
|
59
|
+
raise LogStash::ConfigurationError.new("Schema registry service doesn't respond, error: #{e.message}")
|
|
60
|
+
end
|
|
61
|
+
registered_subjects = JSON.parse response.body
|
|
62
|
+
expected_subjects = @topics.map { |t| "#{t}-value"}
|
|
63
|
+
if (expected_subjects & registered_subjects).size != expected_subjects.size
|
|
64
|
+
undefined_topic_subjects = expected_subjects - registered_subjects
|
|
65
|
+
raise LogStash::ConfigurationError, "The schema registry does not contain definitions for required topic subjects: #{undefined_topic_subjects}"
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def split_proxy_into_host_and_port(proxy_uri)
|
|
70
|
+
return nil unless proxy_uri && !proxy_uri.empty?
|
|
71
|
+
|
|
72
|
+
port = proxy_uri.port
|
|
73
|
+
|
|
74
|
+
host_spec = ""
|
|
75
|
+
host_spec << proxy_uri.scheme || "http"
|
|
76
|
+
host_spec << "://"
|
|
77
|
+
host_spec << "#{proxy_uri.userinfo}@" if proxy_uri.userinfo
|
|
78
|
+
host_spec << proxy_uri.host
|
|
79
|
+
|
|
80
|
+
[host_spec, port]
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def check_for_key_and_secret
|
|
84
|
+
if schema_registry_key and !schema_registry_key.empty?
|
|
85
|
+
if !schema_registry_secret or schema_registry_secret.value.empty?
|
|
86
|
+
raise LogStash::ConfigurationError, "Setting `schema_registry_secret` is required when `schema_registry_key` is provided."
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Gem::Specification.new do |s|
|
|
2
2
|
s.name = 'logstash-integration-kafka'
|
|
3
|
-
s.version = '10.
|
|
3
|
+
s.version = '10.6.0'
|
|
4
4
|
s.licenses = ['Apache-2.0']
|
|
5
5
|
s.summary = "Integration with Kafka - input and output plugins"
|
|
6
6
|
s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline "+
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
require "logstash/devutils/rspec/spec_helper"
|
|
3
3
|
require "logstash/inputs/kafka"
|
|
4
4
|
require "rspec/wait"
|
|
5
|
+
require "stud/try"
|
|
6
|
+
require "faraday"
|
|
7
|
+
require "json"
|
|
5
8
|
|
|
6
9
|
# Please run kafka_test_setup.sh prior to executing this integration test.
|
|
7
10
|
describe "inputs/kafka", :integration => true do
|
|
@@ -120,20 +123,192 @@ describe "inputs/kafka", :integration => true do
|
|
|
120
123
|
end
|
|
121
124
|
end
|
|
122
125
|
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
private
|
|
129
|
+
|
|
130
|
+
def consume_messages(config, queue: Queue.new, timeout:, event_count:)
|
|
131
|
+
kafka_input = LogStash::Inputs::Kafka.new(config)
|
|
132
|
+
t = Thread.new { kafka_input.run(queue) }
|
|
133
|
+
begin
|
|
134
|
+
t.run
|
|
135
|
+
wait(timeout).for { queue.length }.to eq(event_count) unless timeout.eql?(false)
|
|
136
|
+
block_given? ? yield(queue, kafka_input) : queue
|
|
137
|
+
ensure
|
|
138
|
+
t.kill
|
|
139
|
+
t.join(30_000)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
describe "schema registry connection options" do
|
|
145
|
+
context "remote endpoint validation" do
|
|
146
|
+
it "should fail if not reachable" do
|
|
147
|
+
config = {'schema_registry_url' => 'http://localnothost:8081'}
|
|
148
|
+
kafka_input = LogStash::Inputs::Kafka.new(config)
|
|
149
|
+
expect { kafka_input.register }.to raise_error LogStash::ConfigurationError, /Schema registry service doesn't respond.*/
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
it "should fail if any topic is not matched by a subject on the schema registry" do
|
|
153
|
+
config = {
|
|
154
|
+
'schema_registry_url' => 'http://localhost:8081',
|
|
155
|
+
'topics' => ['temperature_stream']
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
kafka_input = LogStash::Inputs::Kafka.new(config)
|
|
159
|
+
expect { kafka_input.register }.to raise_error LogStash::ConfigurationError, /The schema registry does not contain definitions for required topic subjects: \["temperature_stream-value"\]/
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
context "register with subject present" do
|
|
163
|
+
SUBJECT_NAME = "temperature_stream-value"
|
|
164
|
+
|
|
165
|
+
before(:each) do
|
|
166
|
+
response = save_avro_schema_to_schema_registry(File.join(Dir.pwd, "spec", "unit", "inputs", "avro_schema_fixture_payment.asvc"), SUBJECT_NAME)
|
|
167
|
+
expect( response.status ).to be(200)
|
|
168
|
+
end
|
|
123
169
|
|
|
124
|
-
|
|
170
|
+
after(:each) do
|
|
171
|
+
schema_registry_client = Faraday.new('http://localhost:8081')
|
|
172
|
+
delete_remote_schema(schema_registry_client, SUBJECT_NAME)
|
|
173
|
+
end
|
|
125
174
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
t.kill
|
|
135
|
-
t.join(30_000)
|
|
175
|
+
it "should correctly complete registration phase" do
|
|
176
|
+
config = {
|
|
177
|
+
'schema_registry_url' => 'http://localhost:8081',
|
|
178
|
+
'topics' => ['temperature_stream']
|
|
179
|
+
}
|
|
180
|
+
kafka_input = LogStash::Inputs::Kafka.new(config)
|
|
181
|
+
kafka_input.register
|
|
182
|
+
end
|
|
136
183
|
end
|
|
137
184
|
end
|
|
185
|
+
end
|
|
138
186
|
|
|
187
|
+
def save_avro_schema_to_schema_registry(schema_file, subject_name)
|
|
188
|
+
raw_schema = File.readlines(schema_file).map(&:chomp).join
|
|
189
|
+
raw_schema_quoted = raw_schema.gsub('"', '\"')
|
|
190
|
+
response = Faraday.post("http://localhost:8081/subjects/#{subject_name}/versions",
|
|
191
|
+
'{"schema": "' + raw_schema_quoted + '"}',
|
|
192
|
+
"Content-Type" => "application/vnd.schemaregistry.v1+json")
|
|
193
|
+
response
|
|
139
194
|
end
|
|
195
|
+
|
|
196
|
+
def delete_remote_schema(schema_registry_client, subject_name)
|
|
197
|
+
expect(schema_registry_client.delete("/subjects/#{subject_name}").status ).to be(200)
|
|
198
|
+
expect(schema_registry_client.delete("/subjects/#{subject_name}?permanent=true").status ).to be(200)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# AdminClientConfig = org.alpache.kafka.clients.admin.AdminClientConfig
|
|
202
|
+
|
|
203
|
+
describe "Schema registry API", :integration => true do
|
|
204
|
+
|
|
205
|
+
let(:schema_registry) { Faraday.new('http://localhost:8081') }
|
|
206
|
+
|
|
207
|
+
context 'listing subject on clean instance' do
|
|
208
|
+
it "should return an empty set" do
|
|
209
|
+
subjects = JSON.parse schema_registry.get('/subjects').body
|
|
210
|
+
expect( subjects ).to be_empty
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
context 'send a schema definition' do
|
|
215
|
+
it "save the definition" do
|
|
216
|
+
response = save_avro_schema_to_schema_registry(File.join(Dir.pwd, "spec", "unit", "inputs", "avro_schema_fixture_payment.asvc"), "schema_test_1")
|
|
217
|
+
expect( response.status ).to be(200)
|
|
218
|
+
delete_remote_schema(schema_registry, "schema_test_1")
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
it "delete the schema just added" do
|
|
222
|
+
response = save_avro_schema_to_schema_registry(File.join(Dir.pwd, "spec", "unit", "inputs", "avro_schema_fixture_payment.asvc"), "schema_test_1")
|
|
223
|
+
expect( response.status ).to be(200)
|
|
224
|
+
|
|
225
|
+
expect( schema_registry.delete('/subjects/schema_test_1?permanent=false').status ).to be(200)
|
|
226
|
+
sleep(1)
|
|
227
|
+
subjects = JSON.parse schema_registry.get('/subjects').body
|
|
228
|
+
expect( subjects ).to be_empty
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
context 'use the schema to serialize' do
|
|
233
|
+
after(:each) do
|
|
234
|
+
expect( schema_registry.delete('/subjects/topic_avro-value').status ).to be(200)
|
|
235
|
+
sleep 1
|
|
236
|
+
expect( schema_registry.delete('/subjects/topic_avro-value?permanent=true').status ).to be(200)
|
|
237
|
+
|
|
238
|
+
Stud.try(3.times, [StandardError, RSpec::Expectations::ExpectationNotMetError]) do
|
|
239
|
+
wait(10).for do
|
|
240
|
+
subjects = JSON.parse schema_registry.get('/subjects').body
|
|
241
|
+
subjects.empty?
|
|
242
|
+
end.to be_truthy
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
let(:group_id_1) {rand(36**8).to_s(36)}
|
|
247
|
+
|
|
248
|
+
let(:avro_topic_name) { "topic_avro" }
|
|
249
|
+
|
|
250
|
+
let(:plain_config) do
|
|
251
|
+
{ 'schema_registry_url' => 'http://localhost:8081',
|
|
252
|
+
'topics' => [avro_topic_name],
|
|
253
|
+
'codec' => 'plain',
|
|
254
|
+
'group_id' => group_id_1,
|
|
255
|
+
'auto_offset_reset' => 'earliest' }
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def delete_topic_if_exists(topic_name)
|
|
259
|
+
props = java.util.Properties.new
|
|
260
|
+
props.put(Java::org.apache.kafka.clients.admin.AdminClientConfig::BOOTSTRAP_SERVERS_CONFIG, "localhost:9092")
|
|
261
|
+
|
|
262
|
+
admin_client = org.apache.kafka.clients.admin.AdminClient.create(props)
|
|
263
|
+
topics_list = admin_client.listTopics().names().get()
|
|
264
|
+
if topics_list.contains(topic_name)
|
|
265
|
+
result = admin_client.deleteTopics([topic_name])
|
|
266
|
+
result.values.get(topic_name).get()
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def write_some_data_to(topic_name)
|
|
271
|
+
props = java.util.Properties.new
|
|
272
|
+
config = org.apache.kafka.clients.producer.ProducerConfig
|
|
273
|
+
|
|
274
|
+
serdes_config = Java::io.confluent.kafka.serializers.AbstractKafkaAvroSerDeConfig
|
|
275
|
+
props.put(serdes_config::SCHEMA_REGISTRY_URL_CONFIG, "http://localhost:8081")
|
|
276
|
+
|
|
277
|
+
props.put(config::BOOTSTRAP_SERVERS_CONFIG, "localhost:9092")
|
|
278
|
+
props.put(config::KEY_SERIALIZER_CLASS_CONFIG, org.apache.kafka.common.serialization.StringSerializer.java_class)
|
|
279
|
+
props.put(config::VALUE_SERIALIZER_CLASS_CONFIG, Java::io.confluent.kafka.serializers.KafkaAvroSerializer.java_class)
|
|
280
|
+
|
|
281
|
+
parser = org.apache.avro.Schema::Parser.new()
|
|
282
|
+
user_schema = '''{"type":"record",
|
|
283
|
+
"name":"myrecord",
|
|
284
|
+
"fields":[
|
|
285
|
+
{"name":"str_field", "type": "string"},
|
|
286
|
+
{"name":"map_field", "type": {"type": "map", "values": "string"}}
|
|
287
|
+
]}'''
|
|
288
|
+
schema = parser.parse(user_schema)
|
|
289
|
+
avro_record = org.apache.avro.generic.GenericData::Record.new(schema)
|
|
290
|
+
avro_record.put("str_field", "value1")
|
|
291
|
+
avro_record.put("map_field", {"inner_field" => "inner value"})
|
|
292
|
+
|
|
293
|
+
producer = org.apache.kafka.clients.producer.KafkaProducer.new(props)
|
|
294
|
+
record = org.apache.kafka.clients.producer.ProducerRecord.new(topic_name, "avro_key", avro_record)
|
|
295
|
+
producer.send(record)
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
it "stored a new schema using Avro Kafka serdes" do
|
|
299
|
+
delete_topic_if_exists avro_topic_name
|
|
300
|
+
write_some_data_to avro_topic_name
|
|
301
|
+
|
|
302
|
+
subjects = JSON.parse schema_registry.get('/subjects').body
|
|
303
|
+
expect( subjects ).to contain_exactly("topic_avro-value")
|
|
304
|
+
|
|
305
|
+
num_events = 1
|
|
306
|
+
queue = consume_messages(plain_config, timeout: 30, event_count: num_events)
|
|
307
|
+
expect(queue.length).to eq(num_events)
|
|
308
|
+
elem = queue.pop
|
|
309
|
+
expect( elem.to_hash).not_to include("message")
|
|
310
|
+
expect( elem.get("str_field") ).to eq("value1")
|
|
311
|
+
expect( elem.get("map_field")["inner_field"] ).to eq("inner value")
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
end
|
|
@@ -37,6 +37,22 @@ describe LogStash::Inputs::Kafka do
|
|
|
37
37
|
expect { subject.register }.to_not raise_error
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
+
context "register parameter verification" do
|
|
41
|
+
let(:config) do
|
|
42
|
+
{ 'schema_registry_url' => 'http://localhost:8081', 'topics' => ['logstash'], 'consumer_threads' => 4 }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "schema_registry_url conflict with value_deserializer_class should fail" do
|
|
46
|
+
config['value_deserializer_class'] = 'my.fantasy.Deserializer'
|
|
47
|
+
expect { subject.register }.to raise_error LogStash::ConfigurationError, /Option schema_registry_url prohibit the customization of value_deserializer_class/
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "schema_registry_url conflict with topics_pattern should fail" do
|
|
51
|
+
config['topics_pattern'] = 'topic_.*'
|
|
52
|
+
expect { subject.register }.to raise_error LogStash::ConfigurationError, /Option schema_registry_url prohibit the customization of topics_pattern/
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
40
56
|
context 'with client_rack' do
|
|
41
57
|
let(:config) { super.merge('client_rack' => 'EU-R1') }
|
|
42
58
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
data/vendor/jar-dependencies/org/glassfish/jersey/core/jersey-common/2.30/jersey-common-2.30.jar
ADDED
|
Binary file
|
|
Binary file
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: logstash-integration-kafka
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 10.
|
|
4
|
+
version: 10.6.0
|
|
5
5
|
platform: java
|
|
6
6
|
authors:
|
|
7
7
|
- Elastic
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2020-10-
|
|
11
|
+
date: 2020-10-28 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -183,17 +183,28 @@ files:
|
|
|
183
183
|
- lib/logstash-integration-kafka_jars.rb
|
|
184
184
|
- lib/logstash/inputs/kafka.rb
|
|
185
185
|
- lib/logstash/outputs/kafka.rb
|
|
186
|
+
- lib/logstash/plugin_mixins/common.rb
|
|
186
187
|
- lib/logstash/plugin_mixins/kafka_support.rb
|
|
187
188
|
- logstash-integration-kafka.gemspec
|
|
188
189
|
- spec/fixtures/trust-store_stub.jks
|
|
189
190
|
- spec/integration/inputs/kafka_spec.rb
|
|
190
191
|
- spec/integration/outputs/kafka_spec.rb
|
|
192
|
+
- spec/unit/inputs/avro_schema_fixture_payment.asvc
|
|
191
193
|
- spec/unit/inputs/kafka_spec.rb
|
|
192
194
|
- spec/unit/outputs/kafka_spec.rb
|
|
193
|
-
- vendor/jar-dependencies/com/github/luben/zstd-jni/1.4.
|
|
194
|
-
- vendor/jar-dependencies/
|
|
195
|
-
- vendor/jar-dependencies/
|
|
196
|
-
- vendor/jar-dependencies/
|
|
195
|
+
- vendor/jar-dependencies/com/github/luben/zstd-jni/1.4.4-7/zstd-jni-1.4.4-7.jar
|
|
196
|
+
- vendor/jar-dependencies/io/confluent/common-config/5.5.1/common-config-5.5.1.jar
|
|
197
|
+
- vendor/jar-dependencies/io/confluent/common-utils/5.5.1/common-utils-5.5.1.jar
|
|
198
|
+
- vendor/jar-dependencies/io/confluent/kafka-avro-serializer/5.5.1/kafka-avro-serializer-5.5.1.jar
|
|
199
|
+
- vendor/jar-dependencies/io/confluent/kafka-schema-registry-client/5.5.1/kafka-schema-registry-client-5.5.1.jar
|
|
200
|
+
- vendor/jar-dependencies/io/confluent/kafka-schema-serializer/5.5.1/kafka-schema-serializer-5.5.1.jar
|
|
201
|
+
- vendor/jar-dependencies/javax/ws/rs/javax.ws.rs-api/2.1.1/javax.ws.rs-api-2.1.1.jar
|
|
202
|
+
- vendor/jar-dependencies/org/apache/avro/avro/1.9.2/avro-1.9.2.jar
|
|
203
|
+
- vendor/jar-dependencies/org/apache/kafka/kafka-clients/2.5.1/kafka-clients-2.5.1.jar
|
|
204
|
+
- vendor/jar-dependencies/org/apache/kafka/kafka_2.12/2.5.1/kafka_2.12-2.5.1.jar
|
|
205
|
+
- vendor/jar-dependencies/org/glassfish/jersey/core/jersey-common/2.30/jersey-common-2.30.jar
|
|
206
|
+
- vendor/jar-dependencies/org/lz4/lz4-java/1.7.1/lz4-java-1.7.1.jar
|
|
207
|
+
- vendor/jar-dependencies/org/slf4j/slf4j-api/1.7.30/slf4j-api-1.7.30.jar
|
|
197
208
|
- vendor/jar-dependencies/org/xerial/snappy/snappy-java/1.1.7.3/snappy-java-1.1.7.3.jar
|
|
198
209
|
homepage: http://www.elastic.co/guide/en/logstash/current/index.html
|
|
199
210
|
licenses:
|
|
@@ -227,5 +238,6 @@ test_files:
|
|
|
227
238
|
- spec/fixtures/trust-store_stub.jks
|
|
228
239
|
- spec/integration/inputs/kafka_spec.rb
|
|
229
240
|
- spec/integration/outputs/kafka_spec.rb
|
|
241
|
+
- spec/unit/inputs/avro_schema_fixture_payment.asvc
|
|
230
242
|
- spec/unit/inputs/kafka_spec.rb
|
|
231
243
|
- spec/unit/outputs/kafka_spec.rb
|
|
Binary file
|
|
Binary file
|
|
Binary file
|