logstash-input-beats 3.1.24-java → 5.1.9-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.
Files changed (36) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +111 -14
  3. data/Gemfile +3 -2
  4. data/LICENSE +1 -1
  5. data/VERSION +1 -1
  6. data/docs/index.asciidoc +74 -41
  7. data/lib/logstash/inputs/beats/event_transform_common.rb +1 -0
  8. data/lib/logstash/inputs/beats/message_listener.rb +63 -5
  9. data/lib/logstash/inputs/beats.rb +31 -21
  10. data/lib/logstash-input-beats_jars.rb +9 -9
  11. data/logstash-input-beats.gemspec +2 -2
  12. data/spec/inputs/beats/message_listener_spec.rb +103 -12
  13. data/spec/inputs/beats_spec.rb +15 -26
  14. data/spec/integration/logstash_forwarder_spec.rb +0 -1
  15. data/spec/support/client_process_helpers.rb +6 -4
  16. data/spec/support/helpers.rb +8 -1
  17. data/spec/support/shared_examples.rb +111 -16
  18. data/vendor/jar-dependencies/com/fasterxml/jackson/core/jackson-annotations/2.9.9/jackson-annotations-2.9.9.jar +0 -0
  19. data/vendor/jar-dependencies/com/fasterxml/jackson/core/jackson-core/2.9.9/jackson-core-2.9.9.jar +0 -0
  20. data/vendor/jar-dependencies/com/fasterxml/jackson/core/jackson-databind/2.9.9.3/jackson-databind-2.9.9.3.jar +0 -0
  21. data/vendor/jar-dependencies/com/fasterxml/jackson/module/jackson-module-afterburner/2.9.9/jackson-module-afterburner-2.9.9.jar +0 -0
  22. data/vendor/jar-dependencies/io/netty/netty-all/4.1.30.Final/netty-all-4.1.30.Final.jar +0 -0
  23. data/vendor/jar-dependencies/io/netty/netty-tcnative-boringssl-static/2.0.12.Final/netty-tcnative-boringssl-static-2.0.12.Final.jar +0 -0
  24. data/vendor/jar-dependencies/org/apache/logging/log4j/log4j-api/2.11.1/log4j-api-2.11.1.jar +0 -0
  25. data/vendor/jar-dependencies/org/javassist/javassist/3.24.0-GA/javassist-3.24.0-GA.jar +0 -0
  26. data/vendor/jar-dependencies/org/logstash/beats/logstash-input-beats/5.1.9/logstash-input-beats-5.1.9.jar +0 -0
  27. metadata +22 -14
  28. data/vendor/jar-dependencies/com/fasterxml/jackson/core/jackson-annotations/2.7.5/jackson-annotations-2.7.5.jar +0 -0
  29. data/vendor/jar-dependencies/com/fasterxml/jackson/core/jackson-core/2.7.5/jackson-core-2.7.5.jar +0 -0
  30. data/vendor/jar-dependencies/com/fasterxml/jackson/core/jackson-databind/2.7.5/jackson-databind-2.7.5.jar +0 -0
  31. data/vendor/jar-dependencies/com/fasterxml/jackson/module/jackson-module-afterburner/2.7.5/jackson-module-afterburner-2.7.5.jar +0 -0
  32. data/vendor/jar-dependencies/io/netty/netty-all/4.1.3.Final/netty-all-4.1.3.Final.jar +0 -0
  33. data/vendor/jar-dependencies/io/netty/netty-tcnative-boringssl-static/1.1.33.Fork23/netty-tcnative-boringssl-static-1.1.33.Fork23.jar +0 -0
  34. data/vendor/jar-dependencies/org/apache/logging/log4j/log4j-api/2.6.2/log4j-api-2.6.2.jar +0 -0
  35. data/vendor/jar-dependencies/org/javassist/javassist/3.20.0-GA/javassist-3.20.0-GA.jar +0 -0
  36. data/vendor/jar-dependencies/org/logstash/beats/logstash-input-beats/3.1.24/logstash-input-beats-3.1.24.jar +0 -0
@@ -2,7 +2,6 @@
2
2
  require "logstash/inputs/base"
3
3
  require "logstash/namespace"
4
4
  require "logstash/timestamp"
5
- require "logstash/codecs/identity_map_codec"
6
5
  require "logstash/codecs/multiline"
7
6
  require "logstash/util"
8
7
  require "logstash-input-beats_jars"
@@ -40,8 +39,7 @@ require_relative "beats/patch"
40
39
  # IMPORTANT: If you are shipping events that span multiple lines, you need to
41
40
  # use the configuration options available in Filebeat to handle multiline events
42
41
  # before sending the event data to Logstash. You cannot use the
43
- # <<plugins-codecs-multiline>> codec to handle multiline events. Doing so may
44
- # result in the mixing of streams and corrupted event data.
42
+ # <<plugins-codecs-multiline>> codec to handle multiline events.
45
43
  #
46
44
  class LogStash::Inputs::Beats < LogStash::Inputs::Base
47
45
  require "logstash/inputs/beats/codec_callback_listener"
@@ -84,6 +82,10 @@ class LogStash::Inputs::Beats < LogStash::Inputs::Base
84
82
  #
85
83
  config :ssl_certificate_authorities, :validate => :array, :default => []
86
84
 
85
+ # Flag to determine whether to add host information (provided by the beat in the 'hostname' field) to the event
86
+ config :add_hostname, :validate => :boolean, :default => true, :deprecated => 'Host field will not be automatically populated by future version of the Beats input'
87
+
88
+
87
89
  # By default the server doesn't do any client verification.
88
90
  #
89
91
  # `peer` will make the server ask the client to provide a certificate.
@@ -95,6 +97,10 @@ class LogStash::Inputs::Beats < LogStash::Inputs::Base
95
97
  # This option needs to be used with `ssl_certificate_authorities` and a defined list of CAs.
96
98
  config :ssl_verify_mode, :validate => ["none", "peer", "force_peer"], :default => "none"
97
99
 
100
+ # Enables storing client certificate information in event's metadata. You need
101
+ # to configure the `ssl_verify_mode` to `peer` or `force_peer` to enable this.
102
+ config :ssl_peer_metadata, :validate => :boolean, :default => false
103
+
98
104
  config :include_codec_tag, :validate => :boolean, :default => true
99
105
 
100
106
  # Time in milliseconds for an incomplete ssl handshake to timeout
@@ -102,10 +108,10 @@ class LogStash::Inputs::Beats < LogStash::Inputs::Base
102
108
 
103
109
  # The number of seconds before we raise a timeout.
104
110
  # This option is useful to control how much time to wait if something is blocking the pipeline.
105
- config :congestion_threshold, :validate => :number, :default => 5, :deprecated => "This option is now deprecated since congestion control is done automatically"
111
+ config :congestion_threshold, :validate => :number, :obsolete => "This option is obsolete since congestion control is done automatically"
106
112
 
107
113
  # This is the default field to which the specified codec will be applied.
108
- config :target_field_for_codec, :validate => :string, :default => "message", :deprecated => "This option is now deprecated, the plugin is now compatible with Filebeat and Logstash-Forwarder"
114
+ config :target_field_for_codec, :validate => :string, :obsolete => "This option is obsolete"
109
115
 
110
116
  # The minimum TLS version allowed for the encrypted connections. The value must be one of the following:
111
117
  # 1.0 for TLS 1.0, 1.1 for TLS 1.1, 1.2 for TLS 1.2
@@ -121,6 +127,9 @@ class LogStash::Inputs::Beats < LogStash::Inputs::Base
121
127
  # Close Idle clients after X seconds of inactivity.
122
128
  config :client_inactivity_timeout, :validate => :number, :default => 60
123
129
 
130
+ # Beats handler executor thread
131
+ config :executor_threads, :validate => :number, :default => LogStash::Config::CpuCoreStrategy.maximum
132
+
124
133
  def register
125
134
  # For Logstash 2.4 we need to make sure that the logger is correctly set for the
126
135
  # java classes before actually loading them.
@@ -147,26 +156,22 @@ class LogStash::Inputs::Beats < LogStash::Inputs::Base
147
156
  raise LogStash::ConfigurationError, "Using `verify_mode` set to PEER or FORCE_PEER, requires the configuration of `certificate_authorities`"
148
157
  end
149
158
 
159
+ if client_authentication_metadata? && !require_certificate_authorities?
160
+ raise LogStash::ConfigurationError, "Enabling `peer_metadata` requires using `verify_mode` set to PEER or FORCE_PEER"
161
+ end
162
+
163
+ # Logstash 6.x breaking change (introduced with 4.0.0 of this gem)
150
164
  if @codec.kind_of? LogStash::Codecs::Multiline
151
- @logger.warn("WARNING! - Multiline codec with beats input has been deprecated. Support for this configuration will be removed in a future version. Please refer to the beats documentation for how to best manage multiline data. See https://www.elastic.co/guide/en/beats/filebeat/current/multiline-examples.html")
165
+ raise LogStash::ConfigurationError, "Multiline codec with beats input is not supported. Please refer to the beats documentation for how to best manage multiline data. See https://www.elastic.co/guide/en/beats/filebeat/current/multiline-examples.html"
152
166
  end
153
167
 
154
168
  @logger.info("Beats inputs: Starting input listener", :address => "#{@host}:#{@port}")
155
169
 
156
- # wrap the configured codec to support identity stream
157
- # from the producers if running with the multiline codec.
158
- #
159
- # If they dont need an identity map, codec are stateless and can be reused
160
- # accross multiples connections.
161
- if need_identity_map?
162
- @codec = LogStash::Codecs::IdentityMapCodec.new(@codec)
163
- end
164
-
165
170
  @server = create_server
166
171
  end # def register
167
172
 
168
173
  def create_server
169
- server = org.logstash.beats.Server.new(@host, @port, @client_inactivity_timeout)
174
+ server = org.logstash.beats.Server.new(@host, @port, @client_inactivity_timeout, @executor_threads)
170
175
  if @ssl
171
176
 
172
177
  begin
@@ -182,13 +187,14 @@ class LogStash::Inputs::Beats < LogStash::Inputs::Base
182
187
  if client_authentification?
183
188
  if @ssl_verify_mode.upcase == "FORCE_PEER"
184
189
  ssl_builder.setVerifyMode(org.logstash.netty.SslSimpleBuilder::SslClientVerifyMode::FORCE_PEER)
190
+ elsif @ssl_verify_mode.upcase == "PEER"
191
+ ssl_builder.setVerifyMode(org.logstash.netty.SslSimpleBuilder::SslClientVerifyMode::VERIFY_PEER)
185
192
  end
186
193
  ssl_builder.setCertificateAuthorities(@ssl_certificate_authorities)
187
194
  end
188
195
 
189
196
  server.enableSSL(ssl_builder)
190
197
  end
191
-
192
198
  server
193
199
  end
194
200
 
@@ -210,14 +216,18 @@ class LogStash::Inputs::Beats < LogStash::Inputs::Base
210
216
  @server.stop unless @server.nil?
211
217
  end
212
218
 
213
- def need_identity_map?
214
- @codec.kind_of?(LogStash::Codecs::Multiline)
215
- end
216
-
217
219
  def client_authentification?
218
220
  @ssl_certificate_authorities && @ssl_certificate_authorities.size > 0
219
221
  end
220
222
 
223
+ def client_authentication_metadata?
224
+ @ssl_peer_metadata && ssl_configured? && client_authentification?
225
+ end
226
+
227
+ def client_authentication_required?
228
+ @ssl_verify_mode == "force_peer"
229
+ end
230
+
221
231
  def require_certificate_authorities?
222
232
  @ssl_verify_mode == "force_peer" || @ssl_verify_mode == "peer"
223
233
  end
@@ -1,12 +1,12 @@
1
1
  # AUTOGENERATED BY THE GRADLE SCRIPT. DO NOT EDIT.
2
2
 
3
3
  require 'jar_dependencies'
4
- require_jar('io.netty', 'netty-all', '4.1.3.Final')
5
- require_jar('io.netty', 'netty-tcnative-boringssl-static', '1.1.33.Fork23')
6
- require_jar('org.javassist', 'javassist', '3.20.0-GA')
7
- require_jar('com.fasterxml.jackson.core', 'jackson-core', '2.7.5')
8
- require_jar('com.fasterxml.jackson.core', 'jackson-annotations', '2.7.5')
9
- require_jar('com.fasterxml.jackson.core', 'jackson-databind', '2.7.5')
10
- require_jar('com.fasterxml.jackson.module', 'jackson-module-afterburner', '2.7.5')
11
- require_jar('org.apache.logging.log4j', 'log4j-api', '2.6.2')
12
- require_jar('org.logstash.beats', 'logstash-input-beats', '3.1.24')
4
+ require_jar('io.netty', 'netty-all', '4.1.30.Final')
5
+ require_jar('io.netty', 'netty-tcnative-boringssl-static', '2.0.12.Final')
6
+ require_jar('org.javassist', 'javassist', '3.24.0-GA')
7
+ require_jar('com.fasterxml.jackson.core', 'jackson-core', '2.9.9')
8
+ require_jar('com.fasterxml.jackson.core', 'jackson-annotations', '2.9.9')
9
+ require_jar('com.fasterxml.jackson.core', 'jackson-databind', '2.9.9.3')
10
+ require_jar('com.fasterxml.jackson.module', 'jackson-module-afterburner', '2.9.9')
11
+ require_jar('org.apache.logging.log4j', 'log4j-api', '2.11.1')
12
+ require_jar('org.logstash.beats', 'logstash-input-beats', '5.1.9')
@@ -4,7 +4,7 @@ Gem::Specification.new do |s|
4
4
  s.name = "logstash-input-beats"
5
5
  s.version = BEATS_VERSION
6
6
  s.licenses = ["Apache License (2.0)"]
7
- s.summary = "Receive events using the lumberjack protocol."
7
+ s.summary = "Receives events from the Elastic Beats framework"
8
8
  s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
9
9
  s.authors = ["Elastic"]
10
10
  s.email = "info@elastic.co"
@@ -26,7 +26,7 @@ Gem::Specification.new do |s|
26
26
  s.add_runtime_dependency "concurrent-ruby", "~> 1.0"
27
27
  s.add_runtime_dependency "thread_safe", "~> 0.3.5"
28
28
  s.add_runtime_dependency "logstash-codec-multiline", ">= 2.0.5"
29
- s.add_runtime_dependency 'jar-dependencies', '~> 0.3.4'
29
+ s.add_runtime_dependency 'jar-dependencies', '~> 0.3', '>= 0.3.4'
30
30
 
31
31
  s.add_development_dependency "flores", "~>0.0.6"
32
32
  s.add_development_dependency "rspec"
@@ -6,7 +6,10 @@ require "logstash/inputs/beats/message_listener"
6
6
  require "logstash/instrument/namespaced_null_metric"
7
7
  require "thread"
8
8
 
9
+ java_import java.util.HashMap
10
+
9
11
  class MockMessage
12
+
10
13
  def initialize(identity_stream, data = {})
11
14
  @identity_stream = identity_stream
12
15
  @data = data
@@ -21,6 +24,22 @@ class MockMessage
21
24
  end
22
25
  end
23
26
 
27
+ # General purpose single method mock class. Will keep generating mocks until requested method name (no args) is found.
28
+ class OngoingMethodMock
29
+ def initialize(method_name, return_value)
30
+ @method_name = method_name
31
+ @return_value = return_value
32
+ end
33
+
34
+ def method_missing(method)
35
+ if(method.to_s.eql? @method_name)
36
+ return @return_value
37
+ else
38
+ return OngoingMethodMock.new(@method_name, @return_value)
39
+ end
40
+ end
41
+ end
42
+
24
43
  class DummyCodec < LogStash::Codecs::Base
25
44
  DUMMY_EVENT = LogStash::Event.new
26
45
 
@@ -37,7 +56,11 @@ describe LogStash::Inputs::Beats::MessageListener do
37
56
  let(:queue) { Queue.new }
38
57
  let(:codec) { DummyCodec.new }
39
58
  let(:input) { LogStash::Inputs::Beats.new({ "port" => 5555, "codec" => codec }) }
40
- let(:ctx) { double("ChannelHandlerContext") }
59
+
60
+ let(:ip_address) { "10.0.0.1" }
61
+ let(:remote_address) { OngoingMethodMock.new("getHostAddress", ip_address) }
62
+ let(:ctx) {OngoingMethodMock.new("remoteAddress", remote_address)}
63
+
41
64
  let(:message) { MockMessage.new("abc", { "message" => "hello world"}) }
42
65
 
43
66
  subject { described_class.new(queue, input) }
@@ -47,28 +70,54 @@ describe LogStash::Inputs::Beats::MessageListener do
47
70
  end
48
71
 
49
72
  context "onNewConnection" do
50
- it "register the connection to the connection list" do
51
- expect { subject.onNewConnection(double("ChannelHandlerContext")) }.to change { subject.connections_list.count }.by(1)
73
+ let(:second_ip_address) { "10.0.0.2" }
74
+ let(:second_ctx) {OngoingMethodMock.new("getHostAddress", second_ip_address)}
75
+
76
+ shared_examples 'a valid new connection' do
77
+ it "register the connection to the connection list" do
78
+ expect { subject.onNewConnection(second_ctx) }.to change { subject.connections_list.count }.by(1)
79
+ end
80
+ end
81
+
82
+ it_behaves_like 'a valid new connection'
83
+
84
+ context 'with a nil remote address' do
85
+ let(:second_ip_address) { nil}
86
+
87
+ it_behaves_like 'a valid new connection'
88
+ end
89
+
90
+ context 'when the channel throws retrieving remote address' do
91
+ before do
92
+ allow(second_ctx).to receive(:channel).and_raise('nope')
93
+ end
94
+
95
+ it_behaves_like 'a valid new connection'
52
96
  end
53
97
 
54
98
  describe "metrics" do
55
99
  it "new connection should increment connection count" do
56
100
  expect(subject).to receive(:increment_connection_count).once
57
- subject.onNewConnection(double("ChannelHandlerContext"))
101
+ subject.onNewConnection(second_ctx)
58
102
  end
59
103
 
60
104
  describe "peak connections" do
105
+ let (:ctxes) { [1, 2, 3, 4].inject([]) do |result, element|
106
+ result << OngoingMethodMock.new("getHostAddress", "10.0.0.#{element}")
107
+ result
108
+ end
109
+ }
61
110
  it "closing and open connections should keep highest count" do
62
111
  expect(subject.instance_eval("@peak_connection_count").value).to eq(1)
63
- subject.onNewConnection(1)
112
+ subject.onNewConnection(ctxes[0])
64
113
  expect(subject.instance_eval("@peak_connection_count").value).to eq(2)
65
- subject.onNewConnection(2)
114
+ subject.onNewConnection(ctxes[1])
66
115
  expect(subject.instance_eval("@peak_connection_count").value).to eq(3)
67
- subject.onConnectionClose(2)
116
+ subject.onConnectionClose(ctxes[1])
68
117
  expect(subject.instance_eval("@peak_connection_count").value).to eq(3)
69
- subject.onNewConnection(3)
118
+ subject.onNewConnection(ctxes[2])
70
119
  expect(subject.instance_eval("@peak_connection_count").value).to eq(3)
71
- subject.onNewConnection(4)
120
+ subject.onNewConnection(ctxes[3])
72
121
  expect(subject.instance_eval("@peak_connection_count").value).to eq(4)
73
122
  end
74
123
  end
@@ -78,7 +127,7 @@ describe LogStash::Inputs::Beats::MessageListener do
78
127
 
79
128
  context "onNewMessage" do
80
129
  context "when the message is from filebeat" do
81
- let(:message) { MockMessage.new("abc", { "message" => "hello world" } )}
130
+ let(:message) { MockMessage.new("abc", { "message" => "hello world", "@metadata" => {} } )}
82
131
 
83
132
  it "extract the event" do
84
133
  subject.onNewMessage(ctx, message)
@@ -88,7 +137,7 @@ describe LogStash::Inputs::Beats::MessageListener do
88
137
  end
89
138
 
90
139
  context "when the message is from LSF" do
91
- let(:message) { MockMessage.new("abc", { "line" => "hello world" } )}
140
+ let(:message) { MockMessage.new("abc", { "line" => "hello world", '@metadata' => {} } )}
92
141
 
93
142
  it "extract the event" do
94
143
  subject.onNewMessage(ctx, message)
@@ -98,7 +147,16 @@ describe LogStash::Inputs::Beats::MessageListener do
98
147
  end
99
148
 
100
149
  context "when the message is from any libbeat" do
101
- let(:message) { MockMessage.new("abc", { "metric" => 1, "name" => "super-stats"} )}
150
+ #Requires data modeled as Java, not Ruby since the actual code pulls from Java backed (Netty) object
151
+ let(:data) do
152
+ d = HashMap.new
153
+ d.put('@metadata', HashMap.new)
154
+ d.put('metric', 1)
155
+ d.put('name', "super-stats")
156
+ d
157
+ end
158
+
159
+ let(:message) { MockMessage.new("abc", data)}
102
160
 
103
161
  it "extract the event" do
104
162
  subject.onNewMessage(ctx, message)
@@ -106,7 +164,40 @@ describe LogStash::Inputs::Beats::MessageListener do
106
164
  expect(event.get("message")).to be_nil
107
165
  expect(event.get("metric")).to eq(1)
108
166
  expect(event.get("name")).to eq("super-stats")
167
+ expect(event.get("[@metadata][ip_address]")).to eq(ip_address)
109
168
  end
169
+
170
+ context 'when the remote address is nil' do
171
+ let(:ctx) { OngoingMethodMock.new("remoteAddress", nil)}
172
+
173
+ it 'extracts the event' do
174
+ subject.onNewMessage(ctx, message)
175
+ event = queue.pop
176
+ expect(event.get("message")).to be_nil
177
+ expect(event.get("metric")).to eq(1)
178
+ expect(event.get("name")).to eq("super-stats")
179
+ expect(event.get("[@metadata][ip_address]")).to eq(nil)
180
+ end
181
+ end
182
+
183
+ context 'when getting the remote address raises' do
184
+ let(:raising_ctx) { double("context")}
185
+
186
+ before do
187
+ allow(raising_ctx).to receive(:channel).and_raise("nope")
188
+ subject.onNewConnection(raising_ctx)
189
+ end
190
+
191
+ it 'extracts the event' do
192
+ subject.onNewMessage(raising_ctx, message)
193
+ event = queue.pop
194
+ expect(event.get("message")).to be_nil
195
+ expect(event.get("metric")).to eq(1)
196
+ expect(event.get("name")).to eq("super-stats")
197
+ expect(event.get("[@metadata][ip_address]")).to eq(nil)
198
+ end
199
+ end
200
+
110
201
  end
111
202
  end
112
203
 
@@ -16,43 +16,20 @@ describe LogStash::Inputs::Beats do
16
16
 
17
17
  context "#register" do
18
18
  context "host related configuration" do
19
- let(:config) { super.merge!({ "host" => host, "port" => port, "client_inactivity_timeout" => client_inactivity_timeout }) }
19
+ let(:config) { super.merge!({ "host" => host, "port" => port, "client_inactivity_timeout" => client_inactivity_timeout, "executor_threads" => threads }) }
20
20
  let(:host) { "192.168.1.20" }
21
21
  let(:port) { 9000 }
22
22
  let(:client_inactivity_timeout) { 400 }
23
+ let(:threads) { 10 }
23
24
 
24
25
  subject(:plugin) { LogStash::Inputs::Beats.new(config) }
25
26
 
26
27
  it "sends the required options to the server" do
27
- expect(org.logstash.beats.Server).to receive(:new).with(host, port, client_inactivity_timeout)
28
+ expect(org.logstash.beats.Server).to receive(:new).with(host, port, client_inactivity_timeout, threads)
28
29
  subject.register
29
30
  end
30
31
  end
31
32
 
32
- context "identity map" do
33
- subject(:plugin) { LogStash::Inputs::Beats.new(config) }
34
- before { plugin.register }
35
-
36
- context "when using the multiline codec" do
37
- let(:codec) { LogStash::Codecs::Multiline.new("pattern" => '^2015',
38
- "what" => "previous",
39
- "negate" => true) }
40
- let(:config) { super.merge({ "codec" => codec }) }
41
-
42
- it "wraps the codec with the identity_map" do
43
- expect(plugin.codec).to be_kind_of(LogStash::Codecs::IdentityMapCodec)
44
- end
45
- end
46
-
47
- context "when using non buffered codecs" do
48
- let(:config) { super.merge({ "codec" => "json" }) }
49
-
50
- it "doesnt wrap the codec with the identity map" do
51
- expect(plugin.codec).to be_kind_of(LogStash::Codecs::JSON)
52
- end
53
- end
54
- end
55
-
56
33
  it "raise no exception" do
57
34
  plugin = LogStash::Inputs::Beats.new(config)
58
35
  expect { plugin.register }.not_to raise_error
@@ -146,6 +123,18 @@ describe LogStash::Inputs::Beats do
146
123
  end
147
124
  end
148
125
  end
126
+
127
+ context "with multiline codec" do
128
+ let(:codec) { LogStash::Codecs::Multiline.new("pattern" => '^2015',
129
+ "what" => "previous",
130
+ "negate" => true) }
131
+ let(:config) { super.merge({ "codec" => codec }) }
132
+
133
+ it "raise a ConfigurationError when multiline codec is set" do
134
+ plugin = LogStash::Inputs::Beats.new(config)
135
+ expect {plugin.register}.to raise_error(LogStash::ConfigurationError, "Multiline codec with beats input is not supported. Please refer to the beats documentation for how to best manage multiline data. See https://www.elastic.co/guide/en/beats/filebeat/current/multiline-examples.html")
136
+ end
137
+ end
149
138
  end
150
139
 
151
140
  context "when interrupting the plugin" do
@@ -55,7 +55,6 @@ describe "Logstash-Forwarder", :integration => true do
55
55
  f.write(events.join("\n") + "\n")
56
56
  end
57
57
  sleep(1) # give some time to the clients to pick up the changes
58
- stop_client
59
58
  end
60
59
 
61
60
  after :each do
@@ -32,10 +32,12 @@ module ClientProcessHelpers
32
32
  end
33
33
 
34
34
  def stop_client
35
- begin
36
- @process.poll_for_exit(5)
37
- rescue ChildProcess::TimeoutError
38
- Process.kill("KILL", @process.pid)
35
+ unless @process.nil?
36
+ begin
37
+ @process.poll_for_exit(5)
38
+ rescue ChildProcess::TimeoutError
39
+ Process.kill("KILL", @process.pid)
40
+ end
39
41
  end
40
42
  end
41
43
  end
@@ -11,6 +11,13 @@ OPEN_SSL_TOPK8 = "openssl pkcs8 -nocrypt -topk8 -inform PEM -outform PEM"
11
11
  #
12
12
  def convert_to_pkcs8(key)
13
13
  out, e, s = Open3.capture3(OPEN_SSL_TOPK8, :stdin_data => key.to_s)
14
- raise e if e != ""
14
+ # attempt to address random failures by trying again
15
+ unless s.success?
16
+ sleep 1
17
+ out, e, s = Open3.capture3(OPEN_SSL_TOPK8, :stdin_data => key.to_s)
18
+ raise e if e != ""
19
+ out
20
+ end
21
+
15
22
  out
16
23
  end
@@ -25,31 +25,126 @@ shared_examples "Common Event Transformation" do
25
25
  expect(subject.get("tags")).to include(tag)
26
26
  end
27
27
 
28
- context "when the `beats.hostname` doesnt exist on the event" do
29
- let(:already_exist) { "already_exist" }
30
- let(:event_map) { super.merge({ "host" => already_exist }) }
28
+ context 'when add_hostname is true' do
29
+ let(:config) { super.merge({'add_hostname' => true})}
31
30
 
32
- it "doesnt change the value" do
33
- expect(subject.get("host")).to eq(already_exist)
31
+ context 'when a host is provided in beat.host.name' do
32
+ let(:already_exist) { "already_exist" }
33
+ let(:producer_host) { "newhost01" }
34
+ let(:event_map) { super.merge({ "beat" => { "host" => {"name" => producer_host }}}) }
35
+
36
+ context "when no `host` key already exists on the event" do
37
+ it "does not set the host value" do
38
+ expect(subject.get("host")).to be_nil
39
+ end
40
+ end
41
+
42
+ context "when `host` key exists on the event" do
43
+ let(:already_exist) { "already_exist" }
44
+ let(:event_map) { super.merge({ "host" => already_exist }) }
45
+
46
+ it "doesn't override it" do
47
+ expect(subject.get("host")).to eq(already_exist)
48
+ end
49
+ end
34
50
  end
35
- end
36
51
 
37
- context "when the `beat.hostname` exist in the event" do
38
- let(:producer_host) { "newhost01" }
39
- let(:event_map) { super.merge({ "beat" => { "hostname" => producer_host }}) }
52
+ context "when a host is set in `beat.hostname`" do
53
+ let(:producer_host) { "newhost01" }
54
+ let(:event_map) { super.merge({ "beat" => { "hostname" => producer_host }}) }
40
55
 
41
- context "when `host` key doesn't exist on the event" do
42
- it "copy the `beat.hostname` to `host` or backward compatibility" do
43
- expect(subject.get("host")).to eq(producer_host)
56
+ context "when no `host` key already exists on the event" do
57
+ it "copies the value in `beat.hostname` to `host`" do
58
+ expect(subject.get("host")).to eq(producer_host)
59
+ end
60
+ end
61
+
62
+ context "when `host` key exists on the event" do
63
+ let(:already_exist) { "already_exist" }
64
+ let(:event_map) { super.merge({ "host" => already_exist }) }
65
+
66
+ it "doesn't override it" do
67
+ expect(subject.get("host")).to eq(already_exist)
68
+ end
69
+ end
70
+ end
71
+
72
+ context "when no host is provided in beat" do
73
+ context "when no `host` key already exists on the event" do
74
+ it "does not set the host" do
75
+ expect(subject.get("host")).to be_nil
76
+ end
77
+ end
78
+
79
+ context "when `host` key already exists on the event" do
80
+ let(:already_exist) { "already_exist" }
81
+ let(:event_map) { super.merge({ "host" => already_exist }) }
82
+
83
+ it "doesn't override it" do
84
+ expect(subject.get("host")).to eq(already_exist)
85
+ end
44
86
  end
45
87
  end
88
+ end
46
89
 
47
- context "when `host` key exists on the event" do
90
+ context 'when add hostname is false' do
91
+ let(:config) { super.merge({'add_hostname' => false})}
92
+
93
+ context 'when a host is provided in beat.host.name' do
48
94
  let(:already_exist) { "already_exist" }
49
- let(:event_map) { super.merge({ "host" => already_exist }) }
95
+ let(:producer_host) { "newhost01" }
96
+ let(:event_map) { super.merge({ "beat" => { "host" => {"name" => producer_host }}}) }
97
+
98
+ context "when no `host` key already exists on the event" do
99
+ it "does not set the host" do
100
+ expect(subject.get("host")).to be_nil
101
+ end
102
+ end
103
+
104
+ context "when `host` key already exists on the event" do
105
+ let(:already_exist) { "already_exist" }
106
+ let(:event_map) { super.merge({ "host" => already_exist }) }
107
+
108
+ it "doesn't override it" do
109
+ expect(subject.get("host")).to eq(already_exist)
110
+ end
111
+ end
112
+ end
113
+
114
+ context "when a host is provided in `beat.hostname`" do
115
+ let(:producer_host) { "newhost01" }
116
+ let(:event_map) { super.merge({ "beat" => { "hostname" => producer_host }}) }
117
+
118
+ context "when no `host` key already exists on the event" do
119
+ it "does not set the host" do
120
+ expect(subject.get("host")).to be_nil
121
+ end
122
+ end
123
+
124
+ context "when `host` key already exists on the event" do
125
+ let(:already_exist) { "already_exist" }
126
+ let(:event_map) { super.merge({ "host" => already_exist }) }
127
+
128
+ it "doesn't override it" do
129
+ expect(subject.get("host")).to eq(already_exist)
130
+ end
131
+ end
132
+ end
133
+
134
+ context "when no host is provided in beat" do
135
+ context "when no `host` key already exists on the event" do
136
+ it "does not set the host" do
137
+ expect(subject.get("host")).to be_nil
138
+ end
139
+ end
140
+
141
+ context "when `host` key already exists on the event" do
142
+ let(:already_exist) { "already_exist" }
143
+ let(:event_map) { super.merge({ "host" => already_exist }) }
50
144
 
51
- it "doesn't override it" do
52
- expect(subject.get("host")).to eq(already_exist)
145
+ it "doesn't override it" do
146
+ expect(subject.get("host")).to eq(already_exist)
147
+ end
53
148
  end
54
149
  end
55
150
  end