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

Sign up to get free protection for your applications and to get access to all the features.
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