logstash-integration-logstash 0.0.5-java → 1.0.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 +3 -0
- data/VERSION +1 -1
- data/docs/index.asciidoc +8 -5
- data/docs/output-logstash.asciidoc +6 -6
- data/lib/logstash/outputs/logstash.rb +251 -127
- data/lib/logstash/utils/load_balancer.rb +81 -0
- data/logstash-integration-logstash.gemspec +2 -1
- data/spec/fixtures/certs/generated/client_from_root.jks +0 -0
- data/spec/fixtures/certs/generated/client_from_root.key.pem +50 -50
- data/spec/fixtures/certs/generated/client_from_root.key.pkcs8.pem +52 -52
- data/spec/fixtures/certs/generated/client_from_root.p12 +0 -0
- data/spec/fixtures/certs/generated/client_from_root.pem +28 -28
- data/spec/fixtures/certs/generated/client_from_untrusted.jks +0 -0
- data/spec/fixtures/certs/generated/client_from_untrusted.key.pem +50 -50
- data/spec/fixtures/certs/generated/client_from_untrusted.key.pkcs8.pem +52 -52
- data/spec/fixtures/certs/generated/client_from_untrusted.p12 +0 -0
- data/spec/fixtures/certs/generated/client_from_untrusted.pem +28 -28
- data/spec/fixtures/certs/generated/client_self_signed.jks +0 -0
- data/spec/fixtures/certs/generated/client_self_signed.key.pem +50 -50
- data/spec/fixtures/certs/generated/client_self_signed.key.pkcs8.pem +52 -52
- data/spec/fixtures/certs/generated/client_self_signed.p12 +0 -0
- data/spec/fixtures/certs/generated/client_self_signed.pem +28 -28
- data/spec/fixtures/certs/generated/root.key.pem +50 -50
- data/spec/fixtures/certs/generated/root.pem +28 -28
- data/spec/fixtures/certs/generated/server_from_root-key-pkcs8.pem +50 -50
- data/spec/fixtures/certs/generated/server_from_root.jks +0 -0
- data/spec/fixtures/certs/generated/server_from_root.key.pem +50 -50
- data/spec/fixtures/certs/generated/server_from_root.key.pkcs8.pem +52 -52
- data/spec/fixtures/certs/generated/server_from_root.p12 +0 -0
- data/spec/fixtures/certs/generated/server_from_root.pem +29 -29
- data/spec/fixtures/certs/generated/untrusted.key.pem +50 -50
- data/spec/fixtures/certs/generated/untrusted.pem +28 -28
- data/spec/unit/full_transmission_spec.rb +10 -2
- data/spec/unit/load_balancer_spec.rb +67 -0
- data/spec/unit/logstash_output_spec.rb +178 -17
- metadata +22 -5
@@ -9,6 +9,11 @@ describe LogStash::Outputs::Logstash do
|
|
9
9
|
let(:config) {{ "hosts" => "127.0.0.1" }}
|
10
10
|
|
11
11
|
subject(:plugin) { LogStash::Outputs::Logstash.new(config) }
|
12
|
+
let(:registered_plugin) { plugin.tap(&:register) }
|
13
|
+
|
14
|
+
let(:event) {
|
15
|
+
LogStash::Event.new({"message" => "Sending my hello to upstream input"})
|
16
|
+
}
|
12
17
|
|
13
18
|
describe "a plugin class" do
|
14
19
|
subject { described_class }
|
@@ -28,19 +33,22 @@ describe LogStash::Outputs::Logstash do
|
|
28
33
|
end
|
29
34
|
|
30
35
|
describe "plugin register" do
|
31
|
-
let(:registered_plugin) { plugin.tap(&:register) }
|
32
36
|
|
33
37
|
describe "construct host URI" do
|
34
38
|
|
35
39
|
it "applies default https scheme and 9800 port" do
|
36
|
-
|
40
|
+
normalized_hosts = registered_plugin.send(:normalize_host_uris)
|
41
|
+
expect(normalized_hosts).to have_attributes(:size => 1)
|
42
|
+
expect(normalized_hosts.first).to eql("https://127.0.0.1:9800")
|
37
43
|
end
|
38
44
|
|
39
45
|
describe "SSL disabled" do
|
40
46
|
let(:config) { super().merge("ssl_enabled" => false) }
|
41
47
|
|
42
48
|
it "causes HTTP scheme" do
|
43
|
-
|
49
|
+
normalized_hosts = registered_plugin.send(:normalize_host_uris)
|
50
|
+
expect(normalized_hosts).to have_attributes(:size => 1)
|
51
|
+
expect(normalized_hosts.first).to eql("http://127.0.0.1:9800")
|
44
52
|
end
|
45
53
|
end
|
46
54
|
|
@@ -48,7 +56,9 @@ describe LogStash::Outputs::Logstash do
|
|
48
56
|
let(:config) { super().merge("hosts" => "127.0.0.1:9808") }
|
49
57
|
|
50
58
|
it "will be applied" do
|
51
|
-
|
59
|
+
normalized_hosts = registered_plugin.send(:normalize_host_uris)
|
60
|
+
expect(normalized_hosts).to have_attributes(:size => 1)
|
61
|
+
expect(normalized_hosts.first).to eql("https://127.0.0.1:9808")
|
52
62
|
end
|
53
63
|
end
|
54
64
|
end
|
@@ -61,7 +71,7 @@ describe LogStash::Outputs::Logstash do
|
|
61
71
|
|
62
72
|
it "requires `password`" do
|
63
73
|
expected_message = "`password` is REQUIRED when `username` is provided"
|
64
|
-
expect{
|
74
|
+
expect{ registered_plugin }.to raise_error(LogStash::ConfigurationError).with_message(expected_message)
|
65
75
|
end
|
66
76
|
end
|
67
77
|
|
@@ -95,15 +105,15 @@ describe LogStash::Outputs::Logstash do
|
|
95
105
|
let(:config) { super().merge("ssl_certificate" => cert_fixture!('server_from_root.pem')) }
|
96
106
|
|
97
107
|
it "requires `ssl_key`" do
|
98
|
-
expected_message =
|
108
|
+
expected_message = "`ssl_key` is REQUIRED when `ssl_certificate` is provided"
|
99
109
|
expect{ registered_plugin }.to raise_error(LogStash::ConfigurationError).with_message(expected_message)
|
100
110
|
end
|
101
111
|
|
102
112
|
context "with keystore" do
|
103
|
-
let(:config) { super().merge("ssl_keystore_path" => cert_fixture!(
|
113
|
+
let(:config) { super().merge("ssl_keystore_path" => cert_fixture!("client_from_root.jks"), "ssl_key" => cert_fixture!("server_from_root.key.pem")) }
|
104
114
|
|
105
115
|
it "cannot be used together" do
|
106
|
-
expected_message =
|
116
|
+
expected_message = "SSL identity can be configured with EITHER `ssl_certificate` OR `ssl_keystore_*`, but not both"
|
107
117
|
expect{ registered_plugin }.to raise_error(LogStash::ConfigurationError).with_message(expected_message)
|
108
118
|
end
|
109
119
|
end
|
@@ -122,7 +132,7 @@ describe LogStash::Outputs::Logstash do
|
|
122
132
|
let(:config) { super().merge("ssl_keystore_path" => cert_fixture!('server_from_root.jks')) }
|
123
133
|
|
124
134
|
it "requires `ssl_keystore_password`" do
|
125
|
-
expected_message =
|
135
|
+
expected_message = "`ssl_keystore_password` is REQUIRED when `ssl_keystore_path` is provided"
|
126
136
|
expect{ registered_plugin }.to raise_error(LogStash::ConfigurationError).with_message(expected_message)
|
127
137
|
end
|
128
138
|
end
|
@@ -131,7 +141,7 @@ describe LogStash::Outputs::Logstash do
|
|
131
141
|
let(:config) { super().merge("ssl_keystore_password" => "pa$$w0rd") }
|
132
142
|
|
133
143
|
it "requires `ssl_keystore_path`" do
|
134
|
-
expected_message =
|
144
|
+
expected_message = "`ssl_keystore_password` is not allowed unless `ssl_keystore_path` is configured"
|
135
145
|
expect{ registered_plugin }.to raise_error(LogStash::ConfigurationError).with_message(expected_message)
|
136
146
|
end
|
137
147
|
end
|
@@ -141,22 +151,22 @@ describe LogStash::Outputs::Logstash do
|
|
141
151
|
let(:config) { super().merge("ssl_enabled" => true) }
|
142
152
|
|
143
153
|
context "with CA" do
|
144
|
-
let(:config) { super().merge("ssl_certificate_authorities" => cert_fixture!(
|
154
|
+
let(:config) { super().merge("ssl_certificate_authorities" => cert_fixture!("root.pem")) }
|
145
155
|
|
146
156
|
context "and `ssl_verification_mode` is 'none'" do
|
147
157
|
let(:config) { super().merge("ssl_verification_mode" => "none") }
|
148
158
|
|
149
159
|
it "not allowed" do
|
150
|
-
expected_message =
|
160
|
+
expected_message = "SSL Certificate Authorities cannot be configured when `ssl_verification_mode => none`"
|
151
161
|
expect{ registered_plugin }.to raise_error(LogStash::ConfigurationError).with_message(expected_message)
|
152
162
|
end
|
153
163
|
end
|
154
164
|
|
155
165
|
context "and truststore" do
|
156
|
-
let(:config) { super().merge("ssl_truststore_path" => cert_fixture!(
|
166
|
+
let(:config) { super().merge("ssl_truststore_path" => cert_fixture!("client_self_signed.jks")) }
|
157
167
|
|
158
168
|
it "not allowed" do
|
159
|
-
expected_message =
|
169
|
+
expected_message = "SSL trust can be configured with EITHER `ssl_certificate_authorities` OR `ssl_truststore_*`, but not both"
|
160
170
|
expect{ registered_plugin }.to raise_error(LogStash::ConfigurationError).with_message(expected_message)
|
161
171
|
end
|
162
172
|
end
|
@@ -166,7 +176,7 @@ describe LogStash::Outputs::Logstash do
|
|
166
176
|
let(:config) { super().merge("ssl_truststore_path" => cert_fixture!('client_self_signed.jks')) }
|
167
177
|
|
168
178
|
it "requires truststore password" do
|
169
|
-
expected_message =
|
179
|
+
expected_message = "`ssl_truststore_password` is REQUIRED when `ssl_truststore_path` is provided"
|
170
180
|
expect{ registered_plugin }.to raise_error(LogStash::ConfigurationError).with_message(expected_message)
|
171
181
|
end
|
172
182
|
|
@@ -174,7 +184,7 @@ describe LogStash::Outputs::Logstash do
|
|
174
184
|
let(:config) { super().merge("ssl_verification_mode" => "none") }
|
175
185
|
|
176
186
|
it "not allowed" do
|
177
|
-
expected_message =
|
187
|
+
expected_message = "SSL Truststore cannot be configured when `ssl_verification_mode => none`"
|
178
188
|
expect{ registered_plugin }.to raise_error(LogStash::ConfigurationError).with_message(expected_message)
|
179
189
|
end
|
180
190
|
end
|
@@ -184,10 +194,161 @@ describe LogStash::Outputs::Logstash do
|
|
184
194
|
let(:config) { super().merge("ssl_truststore_password" => "pa$$w0rd") }
|
185
195
|
|
186
196
|
it "not allowed" do
|
187
|
-
expected_message =
|
197
|
+
expected_message = "`ssl_truststore_password` not allowed unless `ssl_truststore_path` is configured"
|
188
198
|
expect{ registered_plugin }.to raise_error(LogStash::ConfigurationError).with_message(expected_message)
|
189
199
|
end
|
190
200
|
end
|
191
201
|
end
|
192
202
|
end
|
203
|
+
|
204
|
+
describe "#transmit" do
|
205
|
+
let(:normalized_host_uri) { "https://127.0.0.1:9800" }
|
206
|
+
|
207
|
+
let(:encoded_body) { "[]" }
|
208
|
+
let(:compressed_body) { "\x1F\xC3\xA3\b\x00\xE2\x80\xBA\xE2\x80\x9ACe\x00\x03\xC3\xA3\xC3\xA9\xC3\x82\x02\x00D\xE2\x80\x9Chp\x03\x00\x00\x00".b }
|
209
|
+
|
210
|
+
subject(:transmit_result) { registered_plugin.send(:transmit, encoded_body, compressed_body) }
|
211
|
+
|
212
|
+
context "successful transmission" do
|
213
|
+
before(:each) do
|
214
|
+
registered_plugin.http_client.stub(normalized_host_uri, body: "Response body", code: 200)
|
215
|
+
end
|
216
|
+
it "returns :done" do
|
217
|
+
expect(transmit_result).to eql :done
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
context "retriable HTTP errors" do
|
222
|
+
[429, 500].each do |retriable_response_code|
|
223
|
+
context "when http client emits #{retriable_response_code} retriable error response" do
|
224
|
+
before(:each) do
|
225
|
+
registered_plugin.http_client.stub(normalized_host_uri, body: "Response body", code: retriable_response_code)
|
226
|
+
end
|
227
|
+
it 'returns :retry' do
|
228
|
+
expect(transmit_result).to eql :retry
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
context "terminal HTTP errors" do
|
235
|
+
[301, 400, 404].each do |terminal_response_code|
|
236
|
+
context "when http client emits #{terminal_response_code} terminal error response" do
|
237
|
+
before(:each) do
|
238
|
+
registered_plugin.http_client.stub(normalized_host_uri, body: "Response body", code: terminal_response_code)
|
239
|
+
end
|
240
|
+
it 'returns :abort' do
|
241
|
+
expect(transmit_result).to eql :abort
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
context "retriable transmission exceptions" do
|
248
|
+
[
|
249
|
+
Manticore::Timeout.new,
|
250
|
+
Manticore::SocketException.new,
|
251
|
+
Manticore::ClientProtocolException.new,
|
252
|
+
Manticore::ResolutionFailure.new,
|
253
|
+
Manticore::SocketTimeout.new,
|
254
|
+
Manticore::UnknownException.new("Connection reset by peer"),
|
255
|
+
Manticore::UnknownException.new("Read Timed out"),
|
256
|
+
].each do |manticore_exception|
|
257
|
+
context "when http client raises retriable exception `#{manticore_exception}`" do
|
258
|
+
before(:each) do
|
259
|
+
expect(registered_plugin.http_client).to receive(:post).and_raise(manticore_exception)
|
260
|
+
end
|
261
|
+
it "returns :retry" do
|
262
|
+
expect(transmit_result).to eql :retry
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
describe '#multi_receive' do
|
270
|
+
let(:events) { [event] }
|
271
|
+
|
272
|
+
context "when first transmit succeeds" do
|
273
|
+
before(:each) do
|
274
|
+
allow(registered_plugin).to receive(:transmit).and_return(:abort).once
|
275
|
+
end
|
276
|
+
it "transmits once" do
|
277
|
+
registered_plugin.multi_receive(events)
|
278
|
+
expect(registered_plugin).to have_received(:transmit).once
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
context "when first transmit gets terminal failure" do
|
283
|
+
before(:each) do
|
284
|
+
allow(registered_plugin).to receive(:transmit).and_return(:abort).once
|
285
|
+
end
|
286
|
+
it "transmits once" do
|
287
|
+
registered_plugin.multi_receive(events)
|
288
|
+
expect(registered_plugin).to have_received(:transmit).once
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
context "when transmit indicates that a retry is required" do
|
293
|
+
# Configure a _sequence_ of `#transmit` responses
|
294
|
+
# emits :retry `retry_count` times, invoking `limit_met_hook` (if present) before the
|
295
|
+
# LAST normal retry, then emits `limit_met_next_action`.
|
296
|
+
# as a safeguard, this mock can be called AT MOST `retry_count + 1` times
|
297
|
+
let(:retry_count) { 3 }
|
298
|
+
let(:limit_met_hook) { nil }
|
299
|
+
let(:limit_met_next_action) { :retry }
|
300
|
+
before(:each) do
|
301
|
+
attempts_made = 0
|
302
|
+
next_action = :retry
|
303
|
+
allow(registered_plugin).to receive(:transmit).with(any_args) do
|
304
|
+
current_action = next_action
|
305
|
+
attempts_made += 1
|
306
|
+
if attempts_made == retry_count
|
307
|
+
limit_met_hook&.call
|
308
|
+
next_action = limit_met_next_action
|
309
|
+
end
|
310
|
+
current_action
|
311
|
+
end.at_most(retry_count + 1).times
|
312
|
+
end
|
313
|
+
|
314
|
+
context "and transmit eventually succeeds" do
|
315
|
+
let(:limit_met_next_action) { :done }
|
316
|
+
it "stops retrying" do
|
317
|
+
registered_plugin.multi_receive(events)
|
318
|
+
|
319
|
+
expect(registered_plugin).to have_received(:transmit).exactly(retry_count + 1).times
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
context "and transmit eventually gets terminal failure" do
|
324
|
+
let(:limit_met_next_action) { :abort }
|
325
|
+
it "stops retrying" do
|
326
|
+
registered_plugin.multi_receive(events)
|
327
|
+
|
328
|
+
expect(registered_plugin).to have_received(:transmit).exactly(retry_count + 1).times
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
context "and the pipeline shutdown is requested before transmission succeeds" do
|
333
|
+
let(:limit_met_hook) do
|
334
|
+
->() { expect(registered_plugin).to receive(:pipeline_shutdown_requested?).and_return(:true) }
|
335
|
+
end
|
336
|
+
let(:limit_met_next_action) { :retry }
|
337
|
+
|
338
|
+
if ::Gem::Version.create(LOGSTASH_VERSION) >= ::Gem::Version.create('8.8.0')
|
339
|
+
it 'aborts the batch' do
|
340
|
+
expect { registered_plugin.multi_receive(events) }.to raise_exception(org.logstash.execution.AbortedBatchException)
|
341
|
+
|
342
|
+
expect(registered_plugin).to have_received(:transmit).exactly(retry_count).times
|
343
|
+
end
|
344
|
+
else
|
345
|
+
it "stops retrying" do
|
346
|
+
registered_plugin.multi_receive(events)
|
347
|
+
|
348
|
+
expect(registered_plugin).to have_received(:transmit).exactly(retry_count).times
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
193
354
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-integration-logstash
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Elastic
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-11-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -72,6 +72,20 @@ dependencies:
|
|
72
72
|
- - "~>"
|
73
73
|
- !ruby/object:Gem::Version
|
74
74
|
version: '3.1'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
requirement: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - "~>"
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '7.3'
|
81
|
+
name: logstash-mixin-http_client
|
82
|
+
prerelease: false
|
83
|
+
type: :runtime
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '7.3'
|
75
89
|
- !ruby/object:Gem::Dependency
|
76
90
|
requirement: !ruby/object:Gem::Requirement
|
77
91
|
requirements:
|
@@ -91,15 +105,15 @@ dependencies:
|
|
91
105
|
requirements:
|
92
106
|
- - ">="
|
93
107
|
- !ruby/object:Gem::Version
|
94
|
-
version:
|
95
|
-
name:
|
108
|
+
version: '0'
|
109
|
+
name: stud
|
96
110
|
prerelease: false
|
97
111
|
type: :runtime
|
98
112
|
version_requirements: !ruby/object:Gem::Requirement
|
99
113
|
requirements:
|
100
114
|
- - ">="
|
101
115
|
- !ruby/object:Gem::Version
|
102
|
-
version:
|
116
|
+
version: '0'
|
103
117
|
- !ruby/object:Gem::Dependency
|
104
118
|
requirement: !ruby/object:Gem::Requirement
|
105
119
|
requirements:
|
@@ -161,6 +175,7 @@ files:
|
|
161
175
|
- docs/output-logstash.asciidoc
|
162
176
|
- lib/logstash/inputs/logstash.rb
|
163
177
|
- lib/logstash/outputs/logstash.rb
|
178
|
+
- lib/logstash/utils/load_balancer.rb
|
164
179
|
- logstash-integration-logstash.gemspec
|
165
180
|
- spec/fixtures/certs/generate.sh
|
166
181
|
- spec/fixtures/certs/generated/README.txt
|
@@ -192,6 +207,7 @@ files:
|
|
192
207
|
- spec/fixtures/certs/openssl.cnf
|
193
208
|
- spec/spec_helper.rb
|
194
209
|
- spec/unit/full_transmission_spec.rb
|
210
|
+
- spec/unit/load_balancer_spec.rb
|
195
211
|
- spec/unit/logstash_input_spec.rb
|
196
212
|
- spec/unit/logstash_output_spec.rb
|
197
213
|
homepage: https://www.elastic.co/logstash
|
@@ -253,5 +269,6 @@ test_files:
|
|
253
269
|
- spec/fixtures/certs/openssl.cnf
|
254
270
|
- spec/spec_helper.rb
|
255
271
|
- spec/unit/full_transmission_spec.rb
|
272
|
+
- spec/unit/load_balancer_spec.rb
|
256
273
|
- spec/unit/logstash_input_spec.rb
|
257
274
|
- spec/unit/logstash_output_spec.rb
|