logstash-integration-logstash 0.0.5-java → 1.0.1-java

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