logstash-output-elasticsearch-test 11.16.0-x86_64-linux

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 (88) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +649 -0
  3. data/CONTRIBUTORS +34 -0
  4. data/Gemfile +16 -0
  5. data/LICENSE +202 -0
  6. data/NOTICE.TXT +5 -0
  7. data/README.md +106 -0
  8. data/docs/index.asciidoc +1369 -0
  9. data/lib/logstash/outputs/elasticsearch/data_stream_support.rb +282 -0
  10. data/lib/logstash/outputs/elasticsearch/default-ilm-policy.json +14 -0
  11. data/lib/logstash/outputs/elasticsearch/http_client/manticore_adapter.rb +155 -0
  12. data/lib/logstash/outputs/elasticsearch/http_client/pool.rb +534 -0
  13. data/lib/logstash/outputs/elasticsearch/http_client.rb +497 -0
  14. data/lib/logstash/outputs/elasticsearch/http_client_builder.rb +201 -0
  15. data/lib/logstash/outputs/elasticsearch/ilm.rb +92 -0
  16. data/lib/logstash/outputs/elasticsearch/license_checker.rb +52 -0
  17. data/lib/logstash/outputs/elasticsearch/template_manager.rb +131 -0
  18. data/lib/logstash/outputs/elasticsearch/templates/ecs-disabled/elasticsearch-6x.json +45 -0
  19. data/lib/logstash/outputs/elasticsearch/templates/ecs-disabled/elasticsearch-7x.json +44 -0
  20. data/lib/logstash/outputs/elasticsearch/templates/ecs-disabled/elasticsearch-8x.json +50 -0
  21. data/lib/logstash/outputs/elasticsearch.rb +699 -0
  22. data/lib/logstash/plugin_mixins/elasticsearch/api_configs.rb +237 -0
  23. data/lib/logstash/plugin_mixins/elasticsearch/common.rb +409 -0
  24. data/lib/logstash/plugin_mixins/elasticsearch/noop_license_checker.rb +9 -0
  25. data/logstash-output-elasticsearch.gemspec +40 -0
  26. data/spec/es_spec_helper.rb +225 -0
  27. data/spec/fixtures/_nodes/6x.json +81 -0
  28. data/spec/fixtures/_nodes/7x.json +92 -0
  29. data/spec/fixtures/htpasswd +2 -0
  30. data/spec/fixtures/license_check/active.json +16 -0
  31. data/spec/fixtures/license_check/inactive.json +5 -0
  32. data/spec/fixtures/nginx_reverse_proxy.conf +22 -0
  33. data/spec/fixtures/scripts/painless/scripted_update.painless +2 -0
  34. data/spec/fixtures/scripts/painless/scripted_update_nested.painless +1 -0
  35. data/spec/fixtures/scripts/painless/scripted_upsert.painless +1 -0
  36. data/spec/fixtures/template-with-policy-es6x.json +48 -0
  37. data/spec/fixtures/template-with-policy-es7x.json +45 -0
  38. data/spec/fixtures/template-with-policy-es8x.json +50 -0
  39. data/spec/fixtures/test_certs/ca.crt +29 -0
  40. data/spec/fixtures/test_certs/ca.der.sha256 +1 -0
  41. data/spec/fixtures/test_certs/ca.key +51 -0
  42. data/spec/fixtures/test_certs/renew.sh +13 -0
  43. data/spec/fixtures/test_certs/test.crt +30 -0
  44. data/spec/fixtures/test_certs/test.der.sha256 +1 -0
  45. data/spec/fixtures/test_certs/test.key +51 -0
  46. data/spec/fixtures/test_certs/test.p12 +0 -0
  47. data/spec/fixtures/test_certs/test_invalid.crt +36 -0
  48. data/spec/fixtures/test_certs/test_invalid.key +51 -0
  49. data/spec/fixtures/test_certs/test_invalid.p12 +0 -0
  50. data/spec/fixtures/test_certs/test_self_signed.crt +32 -0
  51. data/spec/fixtures/test_certs/test_self_signed.key +54 -0
  52. data/spec/fixtures/test_certs/test_self_signed.p12 +0 -0
  53. data/spec/integration/outputs/compressed_indexing_spec.rb +70 -0
  54. data/spec/integration/outputs/create_spec.rb +67 -0
  55. data/spec/integration/outputs/data_stream_spec.rb +68 -0
  56. data/spec/integration/outputs/delete_spec.rb +63 -0
  57. data/spec/integration/outputs/ilm_spec.rb +534 -0
  58. data/spec/integration/outputs/index_spec.rb +421 -0
  59. data/spec/integration/outputs/index_version_spec.rb +98 -0
  60. data/spec/integration/outputs/ingest_pipeline_spec.rb +75 -0
  61. data/spec/integration/outputs/metrics_spec.rb +66 -0
  62. data/spec/integration/outputs/no_es_on_startup_spec.rb +78 -0
  63. data/spec/integration/outputs/painless_update_spec.rb +99 -0
  64. data/spec/integration/outputs/parent_spec.rb +94 -0
  65. data/spec/integration/outputs/retry_spec.rb +182 -0
  66. data/spec/integration/outputs/routing_spec.rb +61 -0
  67. data/spec/integration/outputs/sniffer_spec.rb +94 -0
  68. data/spec/integration/outputs/templates_spec.rb +133 -0
  69. data/spec/integration/outputs/unsupported_actions_spec.rb +75 -0
  70. data/spec/integration/outputs/update_spec.rb +114 -0
  71. data/spec/spec_helper.rb +10 -0
  72. data/spec/support/elasticsearch/api/actions/delete_ilm_policy.rb +19 -0
  73. data/spec/support/elasticsearch/api/actions/get_alias.rb +18 -0
  74. data/spec/support/elasticsearch/api/actions/get_ilm_policy.rb +18 -0
  75. data/spec/support/elasticsearch/api/actions/put_alias.rb +24 -0
  76. data/spec/support/elasticsearch/api/actions/put_ilm_policy.rb +25 -0
  77. data/spec/unit/http_client_builder_spec.rb +185 -0
  78. data/spec/unit/outputs/elasticsearch/data_stream_support_spec.rb +612 -0
  79. data/spec/unit/outputs/elasticsearch/http_client/manticore_adapter_spec.rb +151 -0
  80. data/spec/unit/outputs/elasticsearch/http_client/pool_spec.rb +501 -0
  81. data/spec/unit/outputs/elasticsearch/http_client_spec.rb +339 -0
  82. data/spec/unit/outputs/elasticsearch/template_manager_spec.rb +189 -0
  83. data/spec/unit/outputs/elasticsearch_proxy_spec.rb +103 -0
  84. data/spec/unit/outputs/elasticsearch_spec.rb +1573 -0
  85. data/spec/unit/outputs/elasticsearch_ssl_spec.rb +197 -0
  86. data/spec/unit/outputs/error_whitelist_spec.rb +56 -0
  87. data/spec/unit/outputs/license_check_spec.rb +57 -0
  88. metadata +423 -0
@@ -0,0 +1,339 @@
1
+ require_relative "../../../../spec/spec_helper"
2
+ require "logstash/outputs/elasticsearch/http_client"
3
+ require "cabin"
4
+ require "webrick"
5
+ require "java"
6
+
7
+ describe LogStash::Outputs::ElasticSearch::HttpClient do
8
+ let(:ssl) { nil }
9
+ let(:base_options) do
10
+ opts = {
11
+ :hosts => [::LogStash::Util::SafeURI.new("127.0.0.1")],
12
+ :logger => Cabin::Channel.get,
13
+ :metric => ::LogStash::Instrument::NullMetric.new(:dummy).namespace(:alsodummy)
14
+ }
15
+
16
+ if !ssl.nil? # Shortcut to set this
17
+ opts[:client_settings] = {:ssl => {:enabled => ssl}}
18
+ end
19
+
20
+ opts
21
+ end
22
+
23
+ describe "Host/URL Parsing" do
24
+ subject { described_class.new(base_options) }
25
+
26
+ let(:true_hostname) { "my-dash.hostname" }
27
+ let(:ipv6_hostname) { "[::1]" }
28
+ let(:ipv4_hostname) { "127.0.0.1" }
29
+ let(:port) { 9202 }
30
+ let(:hostname_port) { "#{hostname}:#{port}" }
31
+ let(:hostname_port_uri) { ::LogStash::Util::SafeURI.new("//#{hostname_port}") }
32
+ let(:http_hostname_port) { ::LogStash::Util::SafeURI.new("http://#{hostname_port}") }
33
+ let(:https_hostname_port) { ::LogStash::Util::SafeURI.new("https://#{hostname_port}") }
34
+ let(:http_hostname_port_path) { ::LogStash::Util::SafeURI.new("http://#{hostname_port}/path") }
35
+
36
+ shared_examples("proper host handling") do
37
+ it "should properly transform a host:port string to a URL" do
38
+ expect(subject.host_to_url(hostname_port_uri).to_s).to eq(http_hostname_port.to_s + "/")
39
+ end
40
+
41
+ it "should not raise an error with a / for a path" do
42
+ expect(subject.host_to_url(::LogStash::Util::SafeURI.new("#{http_hostname_port}/"))).to eq(LogStash::Util::SafeURI.new("#{http_hostname_port}/"))
43
+ end
44
+
45
+ it "should parse full URLs correctly" do
46
+ expect(subject.host_to_url(http_hostname_port).to_s).to eq(http_hostname_port.to_s + "/")
47
+ end
48
+
49
+ describe "ssl" do
50
+ context "when SSL is true" do
51
+ let(:ssl) { true }
52
+ let(:base_options) { super().merge(:hosts => [http_hostname_port]) }
53
+
54
+ it "should refuse to handle an http url" do
55
+ expect {
56
+ subject.host_to_url(http_hostname_port)
57
+ }.to raise_error(LogStash::ConfigurationError)
58
+ end
59
+ end
60
+
61
+ context "when SSL is false" do
62
+ let(:ssl) { false }
63
+ let(:base_options) { super().merge(:hosts => [https_hostname_port]) }
64
+
65
+ it "should refuse to handle an https url" do
66
+ expect {
67
+ subject.host_to_url(https_hostname_port)
68
+ }.to raise_error(LogStash::ConfigurationError)
69
+ end
70
+ end
71
+
72
+ describe "ssl is nil" do
73
+ let(:base_options) { super().merge(:hosts => [https_hostname_port]) }
74
+ it "should handle an ssl url correctly when SSL is nil" do
75
+ subject
76
+ expect(subject.host_to_url(https_hostname_port).to_s).to eq(https_hostname_port.to_s + "/")
77
+ end
78
+ end
79
+ end
80
+
81
+ describe "path" do
82
+ let(:url) { http_hostname_port_path }
83
+ let(:base_options) { super().merge(:hosts => [url]) }
84
+
85
+ it "should allow paths in a url" do
86
+ expect(subject.host_to_url(url)).to eq(url)
87
+ end
88
+
89
+ context "with the path option set" do
90
+ let(:base_options) { super().merge(:client_settings => {:path => "/otherpath"}) }
91
+
92
+ it "should not allow paths in two places" do
93
+ expect {
94
+ subject.host_to_url(url)
95
+ }.to raise_error(LogStash::ConfigurationError)
96
+ end
97
+ end
98
+
99
+ context "with a path missing a leading /" do
100
+ let(:url) { http_hostname_port }
101
+ let(:base_options) { super().merge(:client_settings => {:path => "otherpath"}) }
102
+
103
+
104
+ it "should automatically insert a / in front of path overlays" do
105
+ expected = url.clone
106
+ expected.path = url.path + "/otherpath"
107
+ expect(subject.host_to_url(url)).to eq(expected)
108
+ end
109
+ end
110
+ end
111
+ end
112
+
113
+ describe "an regular hostname" do
114
+ let(:hostname) { true_hostname }
115
+ include_examples("proper host handling")
116
+ end
117
+
118
+ describe "an ipv4 host" do
119
+ let(:hostname) { ipv4_hostname }
120
+ include_examples("proper host handling")
121
+ end
122
+
123
+ describe "an ipv6 host" do
124
+ let(:hostname) { ipv6_hostname }
125
+ include_examples("proper host handling")
126
+ end
127
+ end
128
+
129
+ describe "get" do
130
+ subject { described_class.new(base_options) }
131
+ let(:body) { "foobar" }
132
+ let(:path) { "/hello-id" }
133
+ let(:get_response) {
134
+ double("response", :body => LogStash::Json::dump( { "body" => body }))
135
+ }
136
+
137
+ it "returns the hash response" do
138
+ expect(subject.pool).to receive(:get).with(path, nil).and_return(get_response)
139
+ expect(subject.get(path)["body"]).to eq(body)
140
+ end
141
+ end
142
+
143
+ describe "join_bulk_responses" do
144
+ subject { described_class.new(base_options) }
145
+
146
+ context "when items key is available" do
147
+ require "json"
148
+ let(:bulk_response) {
149
+ LogStash::Json.load ('[{
150
+ "items": [{
151
+ "delete": {
152
+ "_index": "website",
153
+ "_type": "blog",
154
+ "_id": "123",
155
+ "_version": 2,
156
+ "status": 200,
157
+ "found": true
158
+ }
159
+ }],
160
+ "errors": false
161
+ }]')
162
+ }
163
+ it "should be handled properly" do
164
+ s = subject.send(:join_bulk_responses, bulk_response)
165
+ expect(s["errors"]).to be false
166
+ expect(s["items"].size).to be 1
167
+ end
168
+ end
169
+
170
+ context "when items key is not available" do
171
+ require "json"
172
+ let(:bulk_response) {
173
+ JSON.parse ('[{
174
+ "took": 4,
175
+ "errors": false
176
+ }]')
177
+ }
178
+ it "should be handled properly" do
179
+ s = subject.send(:join_bulk_responses, bulk_response)
180
+ expect(s["errors"]).to be false
181
+ expect(s["items"].size).to be 0
182
+ end
183
+ end
184
+ end
185
+
186
+ describe "#bulk" do
187
+ subject(:http_client) { described_class.new(base_options) }
188
+
189
+ require "json"
190
+ let(:message) { "hey" }
191
+ let(:actions) { [
192
+ ["index", {:_id=>nil, :_index=>"logstash"}, {"message"=> message}],
193
+ ]}
194
+
195
+ [true,false].each do |http_compression_enabled|
196
+ context "with `http_compression => #{http_compression_enabled}`" do
197
+
198
+ let(:base_options) { super().merge(:client_settings => {:http_compression => http_compression_enabled}) }
199
+
200
+ before(:each) do
201
+ if http_compression_enabled
202
+ expect(http_client).to receive(:gzip_writer).at_least(:once).and_call_original
203
+ else
204
+ expect(http_client).to_not receive(:gzip_writer)
205
+ end
206
+ end
207
+
208
+ context "if a message is over TARGET_BULK_BYTES" do
209
+ let(:target_bulk_bytes) { LogStash::Outputs::ElasticSearch::TARGET_BULK_BYTES }
210
+ let(:message) { "a" * (target_bulk_bytes + 1) }
211
+
212
+ it "should be handled properly" do
213
+ allow(subject).to receive(:join_bulk_responses)
214
+ expect(subject).to receive(:bulk_send).once do |data|
215
+ if !http_compression_enabled
216
+ expect(data.size).to be > target_bulk_bytes
217
+ else
218
+ expect(Zlib::gunzip(data.string).size).to be > target_bulk_bytes
219
+ end
220
+ end
221
+ s = subject.send(:bulk, actions)
222
+ end
223
+ end
224
+
225
+ context "with two messages" do
226
+ let(:message1) { "hey" }
227
+ let(:message2) { "you" }
228
+ let(:actions) { [
229
+ ["index", {:_id=>nil, :_index=>"logstash"}, {"message"=> message1}],
230
+ ["index", {:_id=>nil, :_index=>"logstash"}, {"message"=> message2}],
231
+ ]}
232
+ it "executes one bulk_send operation" do
233
+ allow(subject).to receive(:join_bulk_responses)
234
+ expect(subject).to receive(:bulk_send).once
235
+ s = subject.send(:bulk, actions)
236
+ end
237
+
238
+ context "if one exceeds TARGET_BULK_BYTES" do
239
+ let(:target_bulk_bytes) { LogStash::Outputs::ElasticSearch::TARGET_BULK_BYTES }
240
+ let(:message1) { "a" * (target_bulk_bytes + 1) }
241
+ it "executes two bulk_send operations" do
242
+ allow(subject).to receive(:join_bulk_responses)
243
+ expect(subject).to receive(:bulk_send).twice
244
+ s = subject.send(:bulk, actions)
245
+ end
246
+ end
247
+ end
248
+
249
+ end
250
+ end
251
+ end
252
+
253
+ describe "sniffing" do
254
+ let(:client) { LogStash::Outputs::ElasticSearch::HttpClient.new(base_options.merge(client_opts)) }
255
+
256
+ context "with sniffing enabled" do
257
+ let(:client_opts) { {:sniffing => true, :sniffing_delay => 1 } }
258
+
259
+ it "should start the sniffer" do
260
+ expect(client.pool.sniffing).to be_truthy
261
+ end
262
+ end
263
+
264
+ context "with sniffing disabled" do
265
+ let(:client_opts) { {:sniffing => false} }
266
+
267
+ it "should not start the sniffer" do
268
+ expect(client.pool.sniffing).to be_falsey
269
+ end
270
+ end
271
+ end
272
+
273
+ class StoppableServer
274
+
275
+ attr_reader :port
276
+
277
+ def initialize()
278
+ queue = Queue.new
279
+ @first_req_waiter = java.util.concurrent.CountDownLatch.new(1)
280
+ @first_request = nil
281
+
282
+ @t = java.lang.Thread.new(
283
+ proc do
284
+ begin
285
+ @server = WEBrick::HTTPServer.new :Port => 0, :DocumentRoot => ".",
286
+ :Logger => Cabin::Channel.get, # silence WEBrick logging
287
+ :StartCallback => Proc.new {
288
+ queue.push("started")
289
+ }
290
+ @port = @server.config[:Port]
291
+ @server.mount_proc '/headers_check' do |req, res|
292
+ res.body = 'Hello, world from WEBrick mocking server!'
293
+ @first_request = req
294
+ @first_req_waiter.countDown()
295
+ end
296
+
297
+ @server.start
298
+ rescue => e
299
+ puts "Error in webserver thread #{e}"
300
+ # ignore
301
+ end
302
+ end
303
+ )
304
+ @t.daemon = true
305
+ @t.start
306
+ queue.pop # blocks until the server is up
307
+ end
308
+
309
+ def stop
310
+ @server.shutdown
311
+ end
312
+
313
+ def wait_receive_request
314
+ @first_req_waiter.await(2, java.util.concurrent.TimeUnit::SECONDS)
315
+ @first_request
316
+ end
317
+ end
318
+
319
+ describe "#build_adapter" do
320
+ let(:client) { LogStash::Outputs::ElasticSearch::HttpClient.new(base_options) }
321
+ let!(:webserver) { StoppableServer.new } # webserver must be started before the call, so no lazy "let"
322
+
323
+ after :each do
324
+ webserver.stop
325
+ end
326
+
327
+ context "the 'user-agent' header" do
328
+ it "contains the Logstash environment details" do
329
+ adapter = client.build_adapter(client.options)
330
+ adapter.perform_request(::LogStash::Util::SafeURI.new("http://localhost:#{webserver.port}"), :get, "/headers_check")
331
+
332
+ request = webserver.wait_receive_request
333
+
334
+ transmitted_user_agent = request.header['user-agent'][0]
335
+ expect(transmitted_user_agent).to match(/Logstash\/\d*\.\d*\.\d* \(OS=.*; JVM=.*\) logstash-output-elasticsearch\/\d*\.\d*\.\d*/)
336
+ end
337
+ end
338
+ end
339
+ end
@@ -0,0 +1,189 @@
1
+ require_relative "../../../../spec/spec_helper"
2
+ require "logstash/outputs/elasticsearch/template_manager"
3
+
4
+ describe LogStash::Outputs::ElasticSearch::TemplateManager do
5
+
6
+ describe ".default_template_path" do
7
+ context "elasticsearch 6.x" do
8
+ it "chooses the 6x template" do
9
+ expect(described_class.default_template_path(6)).to end_with("/templates/ecs-disabled/elasticsearch-6x.json")
10
+ end
11
+ end
12
+ context "elasticsearch 7.x" do
13
+ it "chooses the 7x template" do
14
+ expect(described_class.default_template_path(7)).to end_with("/templates/ecs-disabled/elasticsearch-7x.json")
15
+ end
16
+ end
17
+ context "elasticsearch 8.x" do
18
+ it "chooses the 8x template" do
19
+ expect(described_class.default_template_path(8)).to end_with("/templates/ecs-disabled/elasticsearch-8x.json")
20
+ end
21
+ end
22
+ end
23
+
24
+ context 'when ECS v1 is requested' do
25
+ it 'resolves' do
26
+ expect(described_class.default_template_path(7, :v1)).to end_with("/templates/ecs-v1/elasticsearch-7x.json")
27
+ end
28
+ end
29
+
30
+ context 'when ECS v8 is requested' do
31
+ it 'resolves' do
32
+ expect(described_class.default_template_path(7, :v8)).to end_with("/templates/ecs-v8/elasticsearch-7x.json")
33
+ end
34
+ end
35
+
36
+ context "index template with ilm settings" do
37
+ let(:plugin_settings) { {"manage_template" => true, "template_overwrite" => true} }
38
+ let(:plugin) { LogStash::Outputs::ElasticSearch.new(plugin_settings) }
39
+
40
+ describe "with custom template" do
41
+
42
+ describe "in version 8+" do
43
+ let(:file_path) { described_class.default_template_path(8) }
44
+ let(:template) { described_class.read_template_file(file_path)}
45
+
46
+ it "should update settings" do
47
+ expect(plugin).to receive(:maximum_seen_major_version).at_least(:once).and_return(8)
48
+ described_class.add_ilm_settings_to_template(plugin, template)
49
+ expect(template['template']['settings']['index.lifecycle.name']).not_to eq(nil)
50
+ expect(template['template']['settings']['index.lifecycle.rollover_alias']).not_to eq(nil)
51
+ expect(template.include?('settings')).to be_falsey
52
+ end
53
+ end
54
+
55
+ describe "in version < 8" do
56
+ let(:file_path) { described_class.default_template_path(7) }
57
+ let(:template) { described_class.read_template_file(file_path)}
58
+
59
+ it "should update settings" do
60
+ expect(plugin).to receive(:maximum_seen_major_version).at_least(:once).and_return(7)
61
+ described_class.add_ilm_settings_to_template(plugin, template)
62
+ expect(template['settings']['index.lifecycle.name']).not_to eq(nil)
63
+ expect(template['settings']['index.lifecycle.rollover_alias']).not_to eq(nil)
64
+ expect(template.include?('template')).to be_falsey
65
+ end
66
+ end
67
+ end
68
+
69
+ context "resolve template setting" do
70
+ let(:plugin_settings) { super().merge({"template_api" => template_api}) }
71
+
72
+ describe "with composable template API" do
73
+ let(:template_api) { "composable" }
74
+
75
+ it 'resolves composable index template API compatible setting' do
76
+ expect(plugin).to receive(:serverless?).and_return(false)
77
+ expect(plugin).to receive(:maximum_seen_major_version).at_least(:once).and_return(8) # required to log
78
+ template = {}
79
+ described_class.resolve_template_settings(plugin, template)
80
+ expect(template["template"]["settings"]).not_to eq(nil)
81
+ end
82
+ end
83
+
84
+ describe "with legacy template API" do
85
+ let(:template_api) { "legacy" }
86
+
87
+ it 'resolves legacy index template API compatible setting' do
88
+ expect(plugin).to receive(:serverless?).and_return(false)
89
+ expect(plugin).to receive(:maximum_seen_major_version).at_least(:once).and_return(7) # required to log
90
+ template = {}
91
+ described_class.resolve_template_settings(plugin, template)
92
+ expect(template["settings"]).not_to eq(nil)
93
+ end
94
+ end
95
+
96
+ describe "with `template_api => 'auto'`" do
97
+ let(:template_api) { "auto" }
98
+
99
+ describe "with ES < 8 versions" do
100
+
101
+ it 'resolves legacy index template API compatible setting' do
102
+ expect(plugin).to receive(:serverless?).and_return(false)
103
+ expect(plugin).to receive(:maximum_seen_major_version).at_least(:once).and_return(7)
104
+ template = {}
105
+ described_class.resolve_template_settings(plugin, template)
106
+ expect(template["settings"]).not_to eq(nil)
107
+ end
108
+ end
109
+
110
+ describe "with ES >= 8 versions" do
111
+ it 'resolves composable index template API compatible setting' do
112
+ expect(plugin).to receive(:serverless?).and_return(false)
113
+ expect(plugin).to receive(:maximum_seen_major_version).at_least(:once).and_return(8)
114
+ template = {}
115
+ described_class.resolve_template_settings(plugin, template)
116
+ expect(template["template"]["settings"]).not_to eq(nil)
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
122
+
123
+ describe "template endpoint" do
124
+ describe "template_api => 'auto'" do
125
+ let(:plugin_settings) { {"manage_template" => true, "template_api" => 'auto'} }
126
+ let(:plugin) { LogStash::Outputs::ElasticSearch.new(plugin_settings) }
127
+
128
+ describe "in version 8+" do
129
+ it "should use index template API" do
130
+ expect(plugin).to receive(:serverless?).and_return(false)
131
+ expect(plugin).to receive(:maximum_seen_major_version).at_least(:once).and_return(8)
132
+ endpoint = described_class.template_endpoint(plugin)
133
+ expect(endpoint).to be_equal(LogStash::Outputs::ElasticSearch::TemplateManager::INDEX_TEMPLATE_ENDPOINT)
134
+ end
135
+ end
136
+
137
+ describe "in version < 8" do
138
+ it "should use legacy template API" do
139
+ expect(plugin).to receive(:serverless?).and_return(false)
140
+ expect(plugin).to receive(:maximum_seen_major_version).at_least(:once).and_return(7)
141
+ endpoint = described_class.template_endpoint(plugin)
142
+ expect(endpoint).to be_equal(LogStash::Outputs::ElasticSearch::TemplateManager::LEGACY_TEMPLATE_ENDPOINT)
143
+ end
144
+ end
145
+ end
146
+
147
+ describe "template_api => 'legacy'" do
148
+ let(:plugin_settings) { {"manage_template" => true, "template_api" => 'legacy'} }
149
+ let(:plugin) { LogStash::Outputs::ElasticSearch.new(plugin_settings) }
150
+
151
+ describe "in version 8+" do
152
+ it "should use legacy template API" do
153
+ expect(plugin).to receive(:serverless?).and_return(false)
154
+ expect(plugin).to receive(:maximum_seen_major_version).never
155
+ endpoint = described_class.template_endpoint(plugin)
156
+ expect(endpoint).to be_equal(LogStash::Outputs::ElasticSearch::TemplateManager::LEGACY_TEMPLATE_ENDPOINT)
157
+ end
158
+ end
159
+ end
160
+
161
+ describe "template_api => 'composable'" do
162
+ let(:plugin_settings) { {"manage_template" => true, "template_api" => 'composable'} }
163
+ let(:plugin) { LogStash::Outputs::ElasticSearch.new(plugin_settings) }
164
+
165
+ describe "in version 8+" do
166
+ it "should use legacy template API" do
167
+ expect(plugin).to receive(:serverless?).and_return(false)
168
+ expect(plugin).to receive(:maximum_seen_major_version).never
169
+ endpoint = described_class.template_endpoint(plugin)
170
+ expect(endpoint).to be_equal(LogStash::Outputs::ElasticSearch::TemplateManager::INDEX_TEMPLATE_ENDPOINT)
171
+ end
172
+ end
173
+ end
174
+
175
+ describe "in serverless" do
176
+ [:auto, :composable, :legacy].each do |api|
177
+ let(:plugin_settings) { {"manage_template" => true, "template_api" => api.to_s} }
178
+ let(:plugin) { LogStash::Outputs::ElasticSearch.new(plugin_settings) }
179
+
180
+ it "use index template API when template_api set to #{api}" do
181
+ expect(plugin).to receive(:serverless?).and_return(true)
182
+ endpoint = described_class.template_endpoint(plugin)
183
+ expect(endpoint).to be_equal(LogStash::Outputs::ElasticSearch::TemplateManager::INDEX_TEMPLATE_ENDPOINT)
184
+ end
185
+ end
186
+
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,103 @@
1
+ require_relative "../../../spec/spec_helper"
2
+ require 'stud/temporary'
3
+ require 'manticore/client'
4
+
5
+ describe "Proxy option" do
6
+ let(:settings) { { "hosts" => "node01" } }
7
+ subject {
8
+ LogStash::Outputs::ElasticSearch.new(settings)
9
+ }
10
+
11
+ before do
12
+ allow(::Manticore::Client).to receive(:new).with(any_args).and_call_original
13
+ end
14
+
15
+ describe "valid configs" do
16
+ before do
17
+ subject.register
18
+ end
19
+
20
+ after do
21
+ subject.close
22
+ end
23
+
24
+ context "when specified as a URI" do
25
+ shared_examples("hash conversion") do |hash|
26
+ let(:settings) { super().merge("proxy" => proxy)}
27
+
28
+ it "should set the proxy to the correct hash value" do
29
+ expect(::Manticore::Client).to have_received(:new) do |options|
30
+ expect(options[:proxy]).to eq(hash)
31
+ end
32
+ end
33
+ end
34
+
35
+ describe "simple proxy" do
36
+ let(:proxy) { LogStash::Util::SafeURI.new("http://127.0.0.1:1234") }
37
+
38
+ include_examples("hash conversion",
39
+ {
40
+ :host => "127.0.0.1",
41
+ :scheme => "http",
42
+ :port => 1234
43
+ }
44
+ )
45
+ end
46
+
47
+
48
+ describe "a secure authed proxy" do
49
+ let(:proxy) { LogStash::Util::SafeURI.new("https://myuser:mypass@127.0.0.1:1234") }
50
+
51
+ include_examples("hash conversion",
52
+ {
53
+ :host => "127.0.0.1",
54
+ :scheme => "https",
55
+ :user => "myuser",
56
+ :password => "mypass",
57
+ :port => 1234
58
+ }
59
+ )
60
+ end
61
+ end
62
+
63
+ context "when not specified" do
64
+ it "should not send the proxy option to manticore" do
65
+ expect(::Manticore::Client).to have_received(:new) do |options|
66
+ expect(options).not_to include(:proxy)
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ context "when specified as ''" do
73
+ let(:settings) { super().merge("proxy" => "${A_MISSING_ENV_VARIABLE:}")}
74
+
75
+ it "should not send the proxy option to manticore" do
76
+ expect { subject.register }.not_to raise_error
77
+
78
+ expect(::Manticore::Client).to have_received(:new) do |options|
79
+ expect(options).not_to include(:proxy)
80
+ end
81
+
82
+ subject.close
83
+ end
84
+ end
85
+
86
+ context "when specified as invalid uri" do
87
+ let(:settings) { super().merge("proxy" => ":")}
88
+
89
+ it "should fail" do
90
+ # SafeURI isn't doing the proper exception wrapping for us, we can not simply :
91
+ # expect { subject.register }.to raise_error(ArgumentError, /URI is not valid/i)
92
+ begin
93
+ subject.register
94
+ rescue ArgumentError => e
95
+ expect(e.message).to match /URI is not valid/i
96
+ rescue java.net.URISyntaxException => e
97
+ expect(e.message).to match /scheme name/i
98
+ else
99
+ fail 'exception not raised'
100
+ end
101
+ end
102
+ end
103
+ end