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,133 @@
1
+ require_relative "../../../spec/es_spec_helper"
2
+
3
+ describe "index template expected behavior", :integration => true do
4
+ let(:ecs_compatibility) { fail('spec group does not define `ecs_compatibility`!') }
5
+
6
+ subject! do
7
+ require "logstash/outputs/elasticsearch"
8
+ allow_any_instance_of(LogStash::Outputs::ElasticSearch).to receive(:ecs_compatibility).and_return(ecs_compatibility)
9
+
10
+ settings = {
11
+ "manage_template" => true,
12
+ "template_overwrite" => true,
13
+ "hosts" => "#{get_host_port()}"
14
+ }
15
+ next LogStash::Outputs::ElasticSearch.new(settings)
16
+ end
17
+
18
+ let(:elasticsearch_client) { get_client }
19
+
20
+ before(:each) do
21
+ # delete indices and templates
22
+ require "elasticsearch"
23
+
24
+ elasticsearch_client.indices.delete_template(:name => '*')
25
+ # This can fail if there are no indexes, ignore failure.
26
+ elasticsearch_client.indices.delete(:index => '*') rescue puts("DELETE INDICES ERROR: #{$!}")
27
+ # Since we are pinned to ES client 7.x, we need to delete data streams the hard way...
28
+ elasticsearch_client.perform_request("DELETE", "/_data_stream/*") rescue puts("DELETE DATA STREAMS ERROR: #{$!}")
29
+ end
30
+
31
+ context 'with ecs_compatibility => disabled' do
32
+ let(:ecs_compatibility) { :disabled }
33
+ before :each do
34
+ @es = elasticsearch_client # cache as ivar for tests...
35
+
36
+ subject.register
37
+
38
+ subject.multi_receive([
39
+ LogStash::Event.new("message" => "sample message here"),
40
+ LogStash::Event.new("somemessage" => { "message" => "sample nested message here" }),
41
+ LogStash::Event.new("somevalue" => 100),
42
+ LogStash::Event.new("somevalue" => 10),
43
+ LogStash::Event.new("somevalue" => 1),
44
+ LogStash::Event.new("country" => "us"),
45
+ LogStash::Event.new("country" => "at"),
46
+ LogStash::Event.new("geoip" => { "location" => [ 0.0, 0.0 ] })
47
+ ])
48
+
49
+ @es.indices.refresh
50
+
51
+ # Wait or fail until everything's indexed.
52
+ Stud::try(20.times) do
53
+ r = @es.search(index: 'logstash*')
54
+ expect(r).to have_hits(8)
55
+ end
56
+ end
57
+
58
+ it "permits phrase searching on string fields" do
59
+ results = @es.search(index: 'logstash*', q: "message:\"sample message\"")
60
+ expect(results).to have_hits(1)
61
+ expect(results["hits"]["hits"][0]["_source"]["message"]).to eq("sample message here")
62
+ end
63
+
64
+ it "numbers dynamically map to a numeric type and permit range queries" do
65
+ results = @es.search(index: 'logstash*', q: "somevalue:[5 TO 105]")
66
+ expect(results).to have_hits(2)
67
+
68
+ values = results["hits"]["hits"].collect { |r| r["_source"]["somevalue"] }
69
+ expect(values).to include(10)
70
+ expect(values).to include(100)
71
+ expect(values).to_not include(1)
72
+ end
73
+
74
+ it "does not create .keyword field for top-level message field" do
75
+ results = @es.search(index: 'logstash*', q: "message.keyword:\"sample message here\"")
76
+ expect(results).to have_hits(0)
77
+ end
78
+
79
+ it "creates .keyword field for nested message fields" do
80
+ results = @es.search(index: 'logstash*', q: "somemessage.message.keyword:\"sample nested message here\"")
81
+ expect(results).to have_hits(1)
82
+ end
83
+
84
+ it "creates .keyword field from any string field which is not_analyzed" do
85
+ results = @es.search(index: 'logstash*', q: "country.keyword:\"us\"")
86
+ expect(results).to have_hits(1)
87
+ expect(results["hits"]["hits"][0]["_source"]["country"]).to eq("us")
88
+
89
+ # partial or terms should not work.
90
+ results = @es.search(index: 'logstash*', q: "country.keyword:\"u\"")
91
+ expect(results).to have_hits(0)
92
+ end
93
+
94
+ it "make [geoip][location] a geo_point" do
95
+ expect(field_properties_from_template("logstash", "geoip")["location"]["type"]).to eq("geo_point")
96
+ end
97
+
98
+ it "aggregate .keyword results correctly " do
99
+ results = @es.search(index: 'logstash*', body: { "aggregations" => { "my_agg" => { "terms" => { "field" => "country.keyword" } } } })["aggregations"]["my_agg"]
100
+ terms = results["buckets"].collect { |b| b["key"] }
101
+
102
+ expect(terms).to include("us")
103
+
104
+ # 'at' is a stopword, make sure stopwords are not ignored.
105
+ expect(terms).to include("at")
106
+ end
107
+ end
108
+
109
+ context 'with ECS enabled' do
110
+ let(:ecs_compatibility) { :v1 }
111
+
112
+ before(:each) do
113
+ subject.register # should load template?
114
+ subject.multi_receive([LogStash::Event.new("message" => "sample message here")])
115
+ end
116
+
117
+ let(:elasticsearch_cluster_major_version) do
118
+ elasticsearch_client.info&.dig("version", "number" )&.split('.')&.map(&:to_i)&.first
119
+ end
120
+
121
+ it 'loads the templates' do
122
+ aggregate_failures do
123
+ if elasticsearch_cluster_major_version >= 8
124
+ # In ES 8+ we use the _index_template API
125
+ expect(elasticsearch_client.indices.exists_index_template(name: 'ecs-logstash')).to be_truthy
126
+ else
127
+ # Otherwise, we used the legacy _template API
128
+ expect(elasticsearch_client.indices.exists_template(name: 'ecs-logstash')).to be_truthy
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,75 @@
1
+ require_relative "../../../spec/es_spec_helper"
2
+
3
+ describe "Unsupported actions testing...", :integration => true do
4
+ require "logstash/outputs/elasticsearch"
5
+
6
+ INDEX = "logstash-unsupported-actions-rejected"
7
+
8
+ def get_es_output( options={} )
9
+ settings = {
10
+ "manage_template" => true,
11
+ "index" => INDEX,
12
+ "template_overwrite" => true,
13
+ "hosts" => get_host_port(),
14
+ "action" => "%{action_field}",
15
+ "document_id" => "%{doc_id}",
16
+ "ecs_compatibility" => "disabled"
17
+ }
18
+ LogStash::Outputs::ElasticSearch.new(settings.merge!(options))
19
+ end
20
+
21
+ before :each do
22
+ @es = get_client
23
+ # Delete all templates first.
24
+ # Clean ES of data before we start.
25
+ @es.indices.delete_template(:name => "*")
26
+ # This can fail if there are no indexes, ignore failure.
27
+ @es.indices.delete(:index => "*") rescue nil
28
+ # index single doc for update purpose
29
+ @es.index(
30
+ :index => INDEX,
31
+ :type => doc_type,
32
+ :id => "2",
33
+ :body => { :message => 'Test to doc indexing', :counter => 1 }
34
+ )
35
+ @es.index(
36
+ :index => INDEX,
37
+ :type => doc_type,
38
+ :id => "3",
39
+ :body => { :message => 'Test to doc deletion', :counter => 2 }
40
+ )
41
+ @es.indices.refresh
42
+ end
43
+
44
+ context "multiple actions include unsupported action" do
45
+ let(:events) {[
46
+ LogStash::Event.new("action_field" => "index", "doc_id" => 1, "message"=> "hello"),
47
+ LogStash::Event.new("action_field" => "update", "doc_id" => 2, "message"=> "hi"),
48
+ LogStash::Event.new("action_field" => "delete", "doc_id" => 3),
49
+ LogStash::Event.new("action_field" => "unsupported_action", "doc_id" => 4, "message"=> "world!")
50
+ ]}
51
+
52
+ it "should reject unsupported doc" do
53
+ subject = get_es_output
54
+ subject.register
55
+ subject.multi_receive(events)
56
+
57
+ index_or_update = proc do |event|
58
+ action = event.get("action_field")
59
+ action.eql?("index") || action.eql?("update")
60
+ end
61
+
62
+ indexed_events = events.select { |event| index_or_update.call(event) }
63
+ rejected_events = events.select { |event| !index_or_update.call(event) }
64
+
65
+ indexed_events.each do |event|
66
+ response = @es.get(:index => INDEX, :type => doc_type, :id => event.get("doc_id"), :refresh => true)
67
+ expect(response['_source']['message']).to eq(event.get("message"))
68
+ end
69
+
70
+ rejected_events.each do |event|
71
+ expect {@es.get(:index => INDEX, :type => doc_type, :id => event.get("doc_id"), :refresh => true)}.to raise_error(Elasticsearch::Transport::Transport::Errors::NotFound)
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,114 @@
1
+ require_relative "../../../spec/es_spec_helper"
2
+
3
+ describe "Update actions without scripts", :integration => true do
4
+ require "logstash/outputs/elasticsearch"
5
+
6
+ def get_es_output( options={} )
7
+ settings = {
8
+ "manage_template" => true,
9
+ "index" => "logstash-update",
10
+ "template_overwrite" => true,
11
+ "hosts" => get_host_port(),
12
+ "action" => "update"
13
+ }
14
+ LogStash::Outputs::ElasticSearch.new(settings.merge!(options))
15
+ end
16
+
17
+ before :each do
18
+ @es = get_client
19
+ # Delete all templates first.
20
+ # Clean ES of data before we start.
21
+ @es.indices.delete_template(:name => "*")
22
+ # This can fail if there are no indexes, ignore failure.
23
+ @es.indices.delete(:index => "*") rescue nil
24
+ @es.index(
25
+ :index => 'logstash-update',
26
+ :type => doc_type,
27
+ :id => "123",
28
+ :body => { :message => 'Test', :counter => 1 }
29
+ )
30
+ @es.indices.refresh
31
+ end
32
+
33
+ it "should fail without a document_id" do
34
+ subject = get_es_output
35
+ expect { subject.register }.to raise_error(LogStash::ConfigurationError)
36
+ end
37
+
38
+ context "when update only" do
39
+ it "should not create new document" do
40
+ subject = get_es_output({ 'document_id' => "456" } )
41
+ subject.register
42
+ subject.multi_receive([LogStash::Event.new("message" => "sample message here")])
43
+ expect {@es.get(:index => 'logstash-update', :type => doc_type, :id => "456", :refresh => true)}.to raise_error(Elasticsearch::Transport::Transport::Errors::NotFound)
44
+ end
45
+
46
+ it "should update existing document" do
47
+ subject = get_es_output({ 'document_id' => "123" })
48
+ subject.register
49
+ subject.multi_receive([LogStash::Event.new("message" => "updated message here")])
50
+ r = @es.get(:index => 'logstash-update', :type => doc_type, :id => "123", :refresh => true)
51
+ expect(r["_source"]["message"]).to eq('updated message here')
52
+ end
53
+
54
+ # The es ruby client treats the data field differently. Make sure this doesn't
55
+ # raise an exception
56
+ it "should update an existing document that has a 'data' field" do
57
+ subject = get_es_output({ 'document_id' => "123" })
58
+ subject.register
59
+ subject.multi_receive([LogStash::Event.new("data" => "updated message here", "message" => "foo")])
60
+ r = @es.get(:index => 'logstash-update', :type => doc_type, :id => "123", :refresh => true)
61
+ expect(r["_source"]["data"]).to eq('updated message here')
62
+ expect(r["_source"]["message"]).to eq('foo')
63
+ end
64
+
65
+ it "should allow default (internal) version" do
66
+ subject = get_es_output({ 'document_id' => "123", "version" => "99" })
67
+ subject.register
68
+ end
69
+
70
+ it "should allow internal version" do
71
+ subject = get_es_output({ 'document_id' => "123", "version" => "99", "version_type" => "internal" })
72
+ subject.register
73
+ end
74
+
75
+ it "should not allow external version" do
76
+ subject = get_es_output({ 'document_id' => "123", "version" => "99", "version_type" => "external" })
77
+ expect { subject.register }.to raise_error(LogStash::ConfigurationError)
78
+ end
79
+
80
+ it "should not allow external_gt version" do
81
+ subject = get_es_output({ 'document_id' => "123", "version" => "99", "version_type" => "external_gt" })
82
+ expect { subject.register }.to raise_error(LogStash::ConfigurationError)
83
+ end
84
+
85
+ it "should not allow external_gte version" do
86
+ subject = get_es_output({ 'document_id' => "123", "version" => "99", "version_type" => "external_gte" })
87
+ expect { subject.register }.to raise_error(LogStash::ConfigurationError)
88
+ end
89
+
90
+ end
91
+
92
+ context "when update with upsert" do
93
+ it "should create new documents with provided upsert" do
94
+ subject = get_es_output({ 'document_id' => "456", 'upsert' => '{"message": "upsert message"}' })
95
+ subject.register
96
+ subject.multi_receive([LogStash::Event.new("message" => "sample message here")])
97
+ r = @es.get(:index => 'logstash-update', :type => doc_type, :id => "456", :refresh => true)
98
+ expect(r["_source"]["message"]).to eq('upsert message')
99
+ end
100
+
101
+ it "should create new documents with event/doc as upsert" do
102
+ subject = get_es_output({ 'document_id' => "456", 'doc_as_upsert' => true })
103
+ subject.register
104
+ subject.multi_receive([LogStash::Event.new("message" => "sample message here")])
105
+ r = @es.get(:index => 'logstash-update', :type => doc_type, :id => "456", :refresh => true)
106
+ expect(r["_source"]["message"]).to eq('sample message here')
107
+ end
108
+
109
+ it "should fail on documents with event/doc as upsert at external version" do
110
+ subject = get_es_output({ 'document_id' => "456", 'doc_as_upsert' => true, 'version' => 999, "version_type" => "external" })
111
+ expect { subject.register }.to raise_error(LogStash::ConfigurationError)
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,10 @@
1
+ require "logstash/devutils/rspec/spec_helper"
2
+
3
+ require "logstash/outputs/elasticsearch"
4
+
5
+ module LogStash::Outputs::ElasticSearch::SpecHelper
6
+ end
7
+
8
+ RSpec.configure do |config|
9
+ config.include LogStash::Outputs::ElasticSearch::SpecHelper
10
+ end
@@ -0,0 +1,19 @@
1
+ # Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
2
+ # or more contributor license agreements. Licensed under the Elastic License;
3
+ # you may not use this file except in compliance with the Elastic License.
4
+
5
+ module Elasticsearch
6
+ module API
7
+ module Actions
8
+
9
+ # Update the password of the specified user
10
+ def delete_ilm_policy(arguments={})
11
+ method = HTTP_DELETE
12
+ path = Utils.__pathify '_ilm/policy/',
13
+ Utils.__escape(arguments[:name])
14
+ params = {}
15
+ perform_request(method, path, params, nil).body
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,18 @@
1
+ # Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
2
+ # or more contributor license agreements. Licensed under the Elastic License;
3
+ # you may not use this file except in compliance with the Elastic License.
4
+
5
+ module Elasticsearch
6
+ module API
7
+ module Actions
8
+
9
+ # Retrieve the list of index lifecycle management policies
10
+ def get_alias(arguments={})
11
+ method = HTTP_GET
12
+ path = Utils.__pathify '_alias', Utils.__escape(arguments[:name])
13
+ params = {}
14
+ perform_request(method, path, params, nil).body
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
2
+ # or more contributor license agreements. Licensed under the Elastic License;
3
+ # you may not use this file except in compliance with the Elastic License.
4
+
5
+ module Elasticsearch
6
+ module API
7
+ module Actions
8
+
9
+ # Retrieve the list of index lifecycle management policies
10
+ def get_ilm_policy(arguments={})
11
+ method = HTTP_GET
12
+ path = Utils.__pathify '_ilm/policy', Utils.__escape(arguments[:name])
13
+ params = {}
14
+ perform_request(method, path, params, nil).body
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,24 @@
1
+ # Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
2
+ # or more contributor license agreements. Licensed under the Elastic License;
3
+ # you may not use this file except in compliance with the Elastic License.
4
+
5
+ module Elasticsearch
6
+ module API
7
+ module Actions
8
+
9
+ # @option arguments [String] :name The name of the alias (*Required*)
10
+ # @option arguments [Hash] :The alias definition(*Required*)
11
+
12
+ def put_alias(arguments={})
13
+ raise ArgumentError, "Required argument 'name' missing" unless arguments[:name]
14
+ raise ArgumentError, "Required argument 'body' missing" unless arguments[:body]
15
+ method = HTTP_PUT
16
+ path = Utils.__pathify Utils.__escape(arguments[:name])
17
+
18
+ params = Utils.__validate_and_extract_params arguments
19
+ body = arguments[:body]
20
+ perform_request(method, path, params, body.to_json).body
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,25 @@
1
+ # Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
2
+ # or more contributor license agreements. Licensed under the Elastic License;
3
+ # you may not use this file except in compliance with the Elastic License.
4
+
5
+ module Elasticsearch
6
+ module API
7
+ module Actions
8
+
9
+ # @option arguments [String] :name The name of the policy (*Required*)
10
+ # @option arguments [Hash] :body The policy definition (*Required*)
11
+
12
+ def put_ilm_policy(arguments={})
13
+ raise ArgumentError, "Required argument 'name' missing" unless arguments[:name]
14
+ raise ArgumentError, "Required argument 'body' missing" unless arguments[:body]
15
+ method = HTTP_PUT
16
+ path = Utils.__pathify '_ilm/policy/', Utils.__escape(arguments[:name])
17
+
18
+ params = Utils.__validate_and_extract_params arguments
19
+
20
+ body = arguments[:body]
21
+ perform_request(method, path, params, body.to_json).body
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,185 @@
1
+ require "logstash/devutils/rspec/spec_helper"
2
+ require "logstash/outputs/elasticsearch"
3
+ require "logstash/outputs/elasticsearch/http_client"
4
+ require "logstash/outputs/elasticsearch/http_client_builder"
5
+
6
+ describe LogStash::Outputs::ElasticSearch::HttpClientBuilder do
7
+ describe "auth setup with url encodable passwords" do
8
+ let(:klass) { LogStash::Outputs::ElasticSearch::HttpClientBuilder }
9
+ let(:user) { "foo@bar"}
10
+ let(:password) {"baz@blah" }
11
+ let(:password_secured) do
12
+ secured = double("password")
13
+ allow(secured).to receive(:value).and_return(password)
14
+ secured
15
+ end
16
+ let(:options) { {"user" => user, "password" => password} }
17
+ let(:logger) { mock("logger") }
18
+ let(:auth_setup) { klass.setup_basic_auth(double("logger"), {"user" => user, "password" => password_secured}) }
19
+
20
+ it "should return the user escaped" do
21
+ expect(auth_setup[:user]).to eql(CGI.escape(user))
22
+ end
23
+
24
+ it "should return the password escaped" do
25
+ expect(auth_setup[:password]).to eql(CGI.escape(password))
26
+ end
27
+ end
28
+
29
+ describe "customizing action paths" do
30
+ let(:hosts) { [ ::LogStash::Util::SafeURI.new("http://localhost:9200") ] }
31
+ let(:options) { {"hosts" => hosts } }
32
+ let(:logger) { double("logger") }
33
+ before :each do
34
+ [:debug, :debug?, :info?, :info, :warn].each do |level|
35
+ allow(logger).to receive(level)
36
+ end
37
+ end
38
+
39
+ describe "healthcheck_path" do
40
+
41
+ context "when setting bulk_path" do
42
+ let(:bulk_path) { "/meh" }
43
+ let(:options) { super().merge("bulk_path" => bulk_path) }
44
+
45
+ context "when using path" do
46
+ let(:options) { super().merge("path" => "/path") }
47
+ it "ignores the path setting" do
48
+ expect(described_class).to receive(:create_http_client) do |options|
49
+ expect(options[:bulk_path]).to eq(bulk_path)
50
+ end
51
+ described_class.build(logger, hosts, options)
52
+ end
53
+ end
54
+ context "when not using path" do
55
+
56
+ it "uses the bulk_path setting" do
57
+ expect(described_class).to receive(:create_http_client) do |options|
58
+ expect(options[:bulk_path]).to eq(bulk_path)
59
+ end
60
+ described_class.build(logger, hosts, options)
61
+ end
62
+ end
63
+ end
64
+
65
+ context "when not setting bulk_path" do
66
+
67
+ context "when using path" do
68
+ let(:path) { "/meh" }
69
+ let(:options) { super().merge("path" => path) }
70
+ it "sets bulk_path to path+_bulk" do
71
+ expect(described_class).to receive(:create_http_client) do |options|
72
+ expect(options[:bulk_path]).to eq("#{path}/_bulk")
73
+ end
74
+ described_class.build(logger, hosts, options)
75
+ end
76
+ end
77
+
78
+ context "when not using path" do
79
+ it "sets the bulk_path to _bulk" do
80
+ expect(described_class).to receive(:create_http_client) do |options|
81
+ expect(options[:bulk_path]).to eq("/_bulk")
82
+ end
83
+ described_class.build(logger, hosts, options)
84
+ end
85
+ end
86
+ end
87
+ end
88
+ describe "healthcheck_path" do
89
+ context "when setting healthcheck_path" do
90
+ let(:healthcheck_path) { "/meh" }
91
+ let(:options) { super().merge("healthcheck_path" => healthcheck_path) }
92
+
93
+ context "when using path" do
94
+ let(:options) { super().merge("path" => "/path") }
95
+ it "ignores the path setting" do
96
+ expect(described_class).to receive(:create_http_client) do |options|
97
+ expect(options[:healthcheck_path]).to eq(healthcheck_path)
98
+ end
99
+ described_class.build(logger, hosts, options)
100
+ end
101
+ end
102
+ context "when not using path" do
103
+
104
+ it "uses the healthcheck_path setting" do
105
+ expect(described_class).to receive(:create_http_client) do |options|
106
+ expect(options[:healthcheck_path]).to eq(healthcheck_path)
107
+ end
108
+ described_class.build(logger, hosts, options)
109
+ end
110
+ end
111
+ end
112
+
113
+ context "when not setting healthcheck_path" do
114
+
115
+ context "when using path" do
116
+ let(:path) { "/meh" }
117
+ let(:options) { super().merge("path" => path) }
118
+ it "sets healthcheck_path to path" do
119
+ expect(described_class).to receive(:create_http_client) do |options|
120
+ expect(options[:healthcheck_path]).to eq(path)
121
+ end
122
+ described_class.build(logger, hosts, options)
123
+ end
124
+ end
125
+
126
+ context "when not using path" do
127
+ it "sets the healthcheck_path to root" do
128
+ expect(described_class).to receive(:create_http_client) do |options|
129
+ expect(options[:healthcheck_path]).to eq("/")
130
+ end
131
+ described_class.build(logger, hosts, options)
132
+ end
133
+ end
134
+ end
135
+ end
136
+ describe "sniffing_path" do
137
+ context "when setting sniffing_path" do
138
+ let(:sniffing_path) { "/meh" }
139
+ let(:options) { super().merge("sniffing_path" => sniffing_path) }
140
+
141
+ context "when using path" do
142
+ let(:options) { super().merge("path" => "/path") }
143
+ it "ignores the path setting" do
144
+ expect(described_class).to receive(:create_http_client) do |options|
145
+ expect(options[:sniffing_path]).to eq(sniffing_path)
146
+ end
147
+ described_class.build(logger, hosts, options)
148
+ end
149
+ end
150
+ context "when not using path" do
151
+
152
+ it "uses the sniffing_path setting" do
153
+ expect(described_class).to receive(:create_http_client) do |options|
154
+ expect(options[:sniffing_path]).to eq(sniffing_path)
155
+ end
156
+ described_class.build(logger, hosts, options)
157
+ end
158
+ end
159
+ end
160
+
161
+ context "when not setting sniffing_path" do
162
+
163
+ context "when using path" do
164
+ let(:path) { "/meh" }
165
+ let(:options) { super().merge("path" => path) }
166
+ it "sets sniffing_path to path+_nodes/http" do
167
+ expect(described_class).to receive(:create_http_client) do |options|
168
+ expect(options[:sniffing_path]).to eq("#{path}/_nodes/http")
169
+ end
170
+ described_class.build(logger, hosts, options)
171
+ end
172
+ end
173
+
174
+ context "when not using path" do
175
+ it "sets the sniffing_path to _nodes/http" do
176
+ expect(described_class).to receive(:create_http_client) do |options|
177
+ expect(options[:sniffing_path]).to eq("/_nodes/http")
178
+ end
179
+ described_class.build(logger, hosts, options)
180
+ end
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end