logstash-output-opensearch 1.0.0-java → 1.3.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/COMPATIBILITY.md +27 -0
  4. data/CONTRIBUTING.md +27 -5
  5. data/DEVELOPER_GUIDE.md +16 -7
  6. data/Gemfile +1 -1
  7. data/MAINTAINERS.md +3 -0
  8. data/NOTICE +9 -2
  9. data/README.md +75 -5
  10. data/lib/logstash/outputs/opensearch/http_client/manticore_adapter.rb +101 -4
  11. data/lib/logstash/outputs/opensearch/http_client/pool.rb +3 -16
  12. data/lib/logstash/outputs/opensearch/http_client.rb +12 -23
  13. data/lib/logstash/outputs/opensearch/http_client_builder.rb +5 -2
  14. data/lib/logstash/outputs/opensearch/templates/ecs-disabled/2x.json +44 -0
  15. data/lib/logstash/outputs/opensearch/templates/ecs-v8/1x.json +5252 -0
  16. data/lib/logstash/outputs/opensearch/templates/ecs-v8/2x.json +5252 -0
  17. data/lib/logstash/outputs/opensearch/templates/ecs-v8/7x.json +5252 -0
  18. data/lib/logstash/outputs/opensearch.rb +4 -5
  19. data/lib/logstash/plugin_mixins/opensearch/api_configs.rb +26 -0
  20. data/lib/logstash/plugin_mixins/opensearch/common.rb +2 -2
  21. data/logstash-output-opensearch.gemspec +20 -4
  22. data/spec/integration/outputs/compressed_indexing_spec.rb +11 -5
  23. data/spec/integration/outputs/create_spec.rb +7 -7
  24. data/spec/integration/outputs/delete_spec.rb +8 -8
  25. data/spec/integration/outputs/index_spec.rb +54 -12
  26. data/spec/integration/outputs/index_version_spec.rb +11 -11
  27. data/spec/integration/outputs/ingest_pipeline_spec.rb +3 -4
  28. data/spec/integration/outputs/metrics_spec.rb +0 -2
  29. data/spec/integration/outputs/no_opensearch_on_startup_spec.rb +0 -1
  30. data/spec/integration/outputs/painless_update_spec.rb +10 -10
  31. data/spec/integration/outputs/parent_spec.rb +2 -2
  32. data/spec/integration/outputs/retry_spec.rb +2 -2
  33. data/spec/integration/outputs/sniffer_spec.rb +2 -2
  34. data/spec/integration/outputs/templates_spec.rb +83 -59
  35. data/spec/integration/outputs/update_spec.rb +14 -14
  36. data/spec/opensearch_spec_helper.rb +12 -2
  37. data/spec/unit/outputs/opensearch/http_client/manticore_adapter_spec.rb +74 -4
  38. data/spec/unit/outputs/opensearch/http_client/pool_spec.rb +4 -87
  39. data/spec/unit/outputs/opensearch/http_client_spec.rb +6 -5
  40. data/spec/unit/outputs/opensearch/template_manager_spec.rb +23 -4
  41. data/spec/unit/outputs/opensearch_spec.rb +18 -2
  42. data.tar.gz.sig +0 -0
  43. metadata +75 -19
  44. metadata.gz.sig +0 -0
  45. data/lib/logstash/outputs/opensearch/distribution_checker.rb +0 -44
  46. data/lib/logstash/plugin_mixins/opensearch/noop_distribution_checker.rb +0 -18
@@ -68,7 +68,6 @@ require "forwardable"
68
68
  class LogStash::Outputs::OpenSearch < LogStash::Outputs::Base
69
69
  declare_threadsafe!
70
70
 
71
- require "logstash/outputs/opensearch/distribution_checker"
72
71
  require "logstash/outputs/opensearch/http_client"
73
72
  require "logstash/outputs/opensearch/http_client_builder"
74
73
  require "logstash/plugin_mixins/opensearch/api_configs"
@@ -79,7 +78,7 @@ class LogStash::Outputs::OpenSearch < LogStash::Outputs::Base
79
78
  include(LogStash::PluginMixins::OpenSearch::Common)
80
79
 
81
80
  # ecs_compatibility option, provided by Logstash core or the support adapter.
82
- include(LogStash::PluginMixins::ECSCompatibilitySupport)
81
+ include(LogStash::PluginMixins::ECSCompatibilitySupport(:disabled, :v1, :v8))
83
82
 
84
83
  # Generic/API config options that any document indexer output needs
85
84
  include(LogStash::PluginMixins::OpenSearch::APIConfigs)
@@ -96,7 +95,7 @@ class LogStash::Outputs::OpenSearch < LogStash::Outputs::Base
96
95
  # - A sprintf style string to change the action based on the content of the event. The value `%{[foo]}`
97
96
  # would use the foo field for the action
98
97
  #
99
- # For more details on actions, check out the https://docs-beta.opensearch.org/opensearch/rest-api/bulk/[OpenSearch bulk API documentation]
98
+ # For more details on actions, check out the https://opensearch.org/docs/opensearch/rest-api/document-apis/bulk/[OpenSearch bulk API documentation]
100
99
  config :action, :validate => :string, :default => "index"
101
100
 
102
101
  # The index to write events to. This can be dynamic using the `%{foo}` syntax.
@@ -218,7 +217,7 @@ class LogStash::Outputs::OpenSearch < LogStash::Outputs::Base
218
217
 
219
218
  @logger.info("New OpenSearch output", :class => self.class.name, :hosts => @hosts.map(&:sanitized).map(&:to_s))
220
219
 
221
- @client = build_client(DistributionChecker.new(@logger))
220
+ @client = build_client
222
221
 
223
222
  @after_successful_connection_thread = after_successful_connection do
224
223
  begin
@@ -420,7 +419,7 @@ class LogStash::Outputs::OpenSearch < LogStash::Outputs::Base
420
419
  when :disabled
421
420
  @default_index = "logstash-%{+yyyy.MM.dd}"
422
421
  @default_template_name = 'logstash'
423
- when :v1
422
+ when :v1, :v8
424
423
  @default_index = "ecs-logstash-%{+yyyy.MM.dd}"
425
424
  @default_template_name = 'ecs-logstash'
426
425
  else
@@ -20,6 +20,18 @@ module LogStash; module PluginMixins; module OpenSearch
20
20
  # Password to authenticate to a secure OpenSearch cluster
21
21
  :password => { :validate => :password },
22
22
 
23
+ # if auth_type is "aws_iam" then
24
+ # Credential resolution logic works as follows :
25
+ #
26
+ # - User passed aws_access_key_id and aws_secret_access_key in opensearch configuration
27
+ # - Environment Variables - AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
28
+ # (RECOMMENDED since they are recognized by all the AWS SDKs and CLI except for .NET),
29
+ # or AWS_ACCESS_KEY and AWS_SECRET_KEY (only recognized by Java SDK)
30
+ # - Credential profiles file at the default location (~/.aws/credentials) shared by all AWS SDKs and the AWS CLI
31
+ # - Instance profile credentials delivered through the Amazon EC2 metadata service
32
+ # - type in auth_type specifies the type of authentication
33
+ :auth_type => { },
34
+
23
35
  # The document ID for the index. Useful for overwriting existing entries in
24
36
  # OpenSearch with the same ID.
25
37
  :document_id => { :validate => :string },
@@ -34,6 +46,20 @@ module LogStash; module PluginMixins; module OpenSearch
34
46
  # this defaults to a concatenation of the path parameter and "_bulk"
35
47
  :bulk_path => { :validate => :string },
36
48
 
49
+ # Maximum number of bytes in bulk requests
50
+ # The criteria for deciding the default value of target_bulk_bytes is:
51
+ # 1. We need a number that's less than 10MiB because OpenSearch is commonly
52
+ # configured (particular in AWS Opensearch Service) to not accept
53
+ # bulks larger than that.
54
+ # 2. It must be large enough to amortize the connection constant
55
+ # across multiple requests.
56
+ # 3. It must be small enough that even if multiple threads hit this size
57
+ # we won't use a lot of heap.
58
+ :target_bulk_bytes => {
59
+ :validate => :number,
60
+ :default => 9 * 1024 * 1024 # 9MiB
61
+ },
62
+
37
63
  # Pass a set of key value pairs as the URL query string. This query string is added
38
64
  # to every host listed in the 'hosts' configuration. If the 'hosts' list contains
39
65
  # urls that already have query strings, the one specified here will be appended.
@@ -24,8 +24,8 @@ module LogStash; module PluginMixins; module OpenSearch
24
24
  # Perform some OpenSearch options validations and Build the HttpClient.
25
25
  # Note that this methods may sets the @user, @password, @hosts and @client ivars as a side effect.
26
26
  # @return [HttpClient] the new http client
27
- def build_client(distribution_checker=nil)
28
- params["distribution_checker"] = distribution_checker
27
+ def build_client
28
+
29
29
  # the following 3 options validation & setup methods are called inside build_client
30
30
  # because they must be executed prior to building the client and logstash
31
31
  # monitoring and management rely on directly calling build_client
@@ -1,6 +1,17 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ #
3
+ # The OpenSearch Contributors require contributions made to
4
+ # this file be licensed under the Apache-2.0 license or a
5
+ # compatible open source license.
6
+ #
7
+ # Modifications Copyright OpenSearch Contributors. See
8
+ # GitHub history for details.
9
+
10
+ signing_key_path = "gem-private_key.pem"
11
+
1
12
  Gem::Specification.new do |s|
2
13
  s.name = 'logstash-output-opensearch'
3
- s.version = '1.0.0'
14
+ s.version = '1.3.0'
4
15
 
5
16
  s.licenses = ['Apache-2.0']
6
17
  s.summary = "Stores logs in OpenSearch"
@@ -18,6 +29,11 @@ Gem::Specification.new do |s|
18
29
  # Tests
19
30
  s.test_files = s.files.grep(%r{^(test|spec|features)/})
20
31
 
32
+ if $PROGRAM_NAME.end_with?("gem") && ARGV == ["build", __FILE__] && File.exist?(signing_key_path)
33
+ s.signing_key = signing_key_path
34
+ s.cert_chain = ['certs/opensearch-rubygems.pem']
35
+ end
36
+
21
37
  # Special flag to let us know this is actually a logstash plugin
22
38
  s.metadata = {
23
39
  "logstash_plugin" => "true",
@@ -25,16 +41,16 @@ Gem::Specification.new do |s|
25
41
  "source_code_uri" => "https://github.com/opensearch-project/logstash-output-opensearch"
26
42
  }
27
43
 
28
- s.cert_chain = ['public.pem']
29
- s.signing_key = File.expand_path("private.pem") if $0 =~ /gem\z/
30
-
31
44
  s.add_runtime_dependency "manticore", '>= 0.5.4', '< 1.0.0'
32
45
  s.add_runtime_dependency 'stud', ['>= 0.0.17', '~> 0.0']
33
46
  s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
34
47
  s.add_runtime_dependency 'logstash-mixin-ecs_compatibility_support', '~>1.0'
48
+ s.add_runtime_dependency 'aws-sdk', '>= 2.11.632', '~> 2'
49
+ s.add_runtime_dependency 'json', '>= 2.3.0', '~> 2'
35
50
 
36
51
  s.add_development_dependency 'logstash-codec-plain'
37
52
  s.add_development_dependency 'logstash-devutils'
38
53
  s.add_development_dependency 'flores'
39
54
  s.add_development_dependency 'cabin', ['~> 0.6']
55
+ s.add_development_dependency 'opensearch-ruby', '~> 1'
40
56
  end
@@ -33,8 +33,8 @@ describe "indexing with http_compression turned on", :integration => true do
33
33
  }
34
34
  subject { LogStash::Outputs::OpenSearch.new(config) }
35
35
 
36
- let(:es_url) { "http://#{get_host_port}" }
37
- let(:index_url) {"#{es_url}/#{index}"}
36
+ let(:opensearch_url) { "http://#{get_host_port}" }
37
+ let(:index_url) {"#{opensearch_url}/#{index}"}
38
38
  let(:http_client_options) { {} }
39
39
  let(:http_client) do
40
40
  Manticore::Client.new(http_client_options)
@@ -49,7 +49,7 @@ describe "indexing with http_compression turned on", :integration => true do
49
49
  it "ships events" do
50
50
  subject.multi_receive(events)
51
51
 
52
- http_client.post("#{es_url}/_refresh").call
52
+ http_client.post("#{opensearch_url}/_refresh").call
53
53
 
54
54
  response = http_client.get("#{index_url}/_count?q=*")
55
55
  result = LogStash::Json.load(response.body)
@@ -59,7 +59,13 @@ describe "indexing with http_compression turned on", :integration => true do
59
59
  response = http_client.get("#{index_url}/_search?q=*&size=1000")
60
60
  result = LogStash::Json.load(response.body)
61
61
  result["hits"]["hits"].each do |doc|
62
- expect(doc["_type"]).to eq(type)
62
+ # FIXME This checks for OpenSearch 1.x or OpenDistro which has version 7.10.x
63
+ # need a cleaner way to check this.
64
+ if OpenSearchHelper.check_version?("< 2") || OpenSearchHelper.check_version?("> 7")
65
+ expect(doc["_type"]).to eq(type)
66
+ else
67
+ expect(doc).not_to include("_type")
68
+ end
63
69
  expect(doc["_index"]).to eq(index)
64
70
  end
65
71
  end
@@ -67,7 +73,7 @@ describe "indexing with http_compression turned on", :integration => true do
67
73
 
68
74
  it "sets the correct content-encoding header and body is compressed" do
69
75
  expect(subject.client.pool.adapter.client).to receive(:send).
70
- with(anything, anything, {:headers=>{"Content-Encoding"=>"gzip", "Content-Type"=>"application/json"}, :body => a_valid_gzip_encoded_string}).
76
+ with(anything, anything, {:headers=>{"Content-Encoding"=>"gzip", "content-type"=>"application/json"}, :body => a_valid_gzip_encoded_string}).
71
77
  and_call_original
72
78
  subject.multi_receive(events)
73
79
  end
@@ -12,7 +12,7 @@ require_relative "../../../spec/opensearch_spec_helper"
12
12
  describe "client create actions", :integration => true do
13
13
  require "logstash/outputs/opensearch"
14
14
 
15
- def get_es_output(action, id, version=nil, version_type=nil)
15
+ def get_output(action, id, version=nil, version_type=nil)
16
16
  settings = {
17
17
  "manage_template" => true,
18
18
  "index" => "logstash-create",
@@ -37,7 +37,7 @@ describe "client create actions", :integration => true do
37
37
 
38
38
  context "when action => create" do
39
39
  it "should create new documents with or without id" do
40
- subject = get_es_output("create", "id123")
40
+ subject = get_output("create", "id123")
41
41
  subject.register
42
42
  subject.multi_receive([LogStash::Event.new("message" => "sample message here")])
43
43
  @client.indices.refresh
@@ -49,27 +49,27 @@ describe "client create actions", :integration => true do
49
49
  end
50
50
 
51
51
  it "should allow default (internal) version" do
52
- subject = get_es_output("create", "id123", 43)
52
+ subject = get_output("create", "id123", 43)
53
53
  subject.register
54
54
  end
55
55
 
56
56
  it "should allow internal version" do
57
- subject = get_es_output("create", "id123", 43, "internal")
57
+ subject = get_output("create", "id123", 43, "internal")
58
58
  subject.register
59
59
  end
60
60
 
61
61
  it "should not allow external version" do
62
- subject = get_es_output("create", "id123", 43, "external")
62
+ subject = get_output("create", "id123", 43, "external")
63
63
  expect { subject.register }.to raise_error(LogStash::ConfigurationError)
64
64
  end
65
65
 
66
66
  it "should not allow external_gt version" do
67
- subject = get_es_output("create", "id123", 43, "external_gt")
67
+ subject = get_output("create", "id123", 43, "external_gt")
68
68
  expect { subject.register }.to raise_error(LogStash::ConfigurationError)
69
69
  end
70
70
 
71
71
  it "should not allow external_gte version" do
72
- subject = get_es_output("create", "id123", 43, "external_gte")
72
+ subject = get_output("create", "id123", 43, "external_gte")
73
73
  expect { subject.register }.to raise_error(LogStash::ConfigurationError)
74
74
  end
75
75
  end
@@ -14,15 +14,15 @@ require "logstash/outputs/opensearch"
14
14
  describe "Versioned delete", :integration => true do
15
15
  require "logstash/outputs/opensearch"
16
16
 
17
- let(:es) { get_client }
17
+ let(:client) { get_client }
18
18
 
19
19
  before :each do
20
20
  # Delete all templates first.
21
21
  # Clean ES of data before we start.
22
- es.indices.delete_template(:name => "*")
22
+ client.indices.delete_template(:name => "*")
23
23
  # This can fail if there are no indexes, ignore failure.
24
- es.indices.delete(:index => "*") rescue nil
25
- es.indices.refresh
24
+ client.indices.delete(:index => "*") rescue nil
25
+ client.indices.refresh
26
26
  end
27
27
 
28
28
  context "when delete only" do
@@ -48,12 +48,12 @@ describe "Versioned delete", :integration => true do
48
48
  it "should ignore non-monotonic external version updates" do
49
49
  id = "ev2"
50
50
  subject.multi_receive([LogStash::Event.new("my_id" => id, "my_action" => "index", "message" => "foo", "my_version" => 99)])
51
- r = es.get(:index => 'logstash-delete', :type => doc_type, :id => id, :refresh => true)
51
+ r = client.get(:index => 'logstash-delete', :type => doc_type, :id => id, :refresh => true)
52
52
  expect(r['_version']).to eq(99)
53
53
  expect(r['_source']['message']).to eq('foo')
54
54
 
55
55
  subject.multi_receive([LogStash::Event.new("my_id" => id, "my_action" => "delete", "message" => "foo", "my_version" => 98)])
56
- r2 = es.get(:index => 'logstash-delete', :type => doc_type, :id => id, :refresh => true)
56
+ r2 = client.get(:index => 'logstash-delete', :type => doc_type, :id => id, :refresh => true)
57
57
  expect(r2['_version']).to eq(99)
58
58
  expect(r2['_source']['message']).to eq('foo')
59
59
  end
@@ -61,12 +61,12 @@ describe "Versioned delete", :integration => true do
61
61
  it "should commit monotonic external version updates" do
62
62
  id = "ev3"
63
63
  subject.multi_receive([LogStash::Event.new("my_id" => id, "my_action" => "index", "message" => "foo", "my_version" => 99)])
64
- r = es.get(:index => 'logstash-delete', :type => doc_type, :id => id, :refresh => true)
64
+ r = client.get(:index => 'logstash-delete', :type => doc_type, :id => id, :refresh => true)
65
65
  expect(r['_version']).to eq(99)
66
66
  expect(r['_source']['message']).to eq('foo')
67
67
 
68
68
  subject.multi_receive([LogStash::Event.new("my_id" => id, "my_action" => "delete", "message" => "foo", "my_version" => 100)])
69
- expect { es.get(:index => 'logstash-delete', :type => doc_type, :id => id, :refresh => true) }.to raise_error(Elasticsearch::Transport::Transport::Errors::NotFound)
69
+ expect { client.get(:index => 'logstash-delete', :type => doc_type, :id => id, :refresh => true) }.to raise_error(OpenSearch::Transport::Transport::Errors::NotFound)
70
70
  end
71
71
  end
72
72
  end
@@ -10,8 +10,7 @@
10
10
  require_relative "../../../spec/opensearch_spec_helper"
11
11
  require "logstash/outputs/opensearch"
12
12
 
13
- describe "TARGET_BULK_BYTES", :integration => true do
14
- let(:target_bulk_bytes) { LogStash::Outputs::OpenSearch::TARGET_BULK_BYTES }
13
+ describe "target_bulk_bytes", :integration => true do
15
14
  let(:event_count) { 1000 }
16
15
  let(:events) { event_count.times.map { event }.to_a }
17
16
  let(:config) {
@@ -32,11 +31,11 @@ describe "TARGET_BULK_BYTES", :integration => true do
32
31
  end
33
32
 
34
33
  describe "batches that are too large for one" do
35
- let(:event) { LogStash::Event.new("message" => "a " * (((target_bulk_bytes/2) / event_count)+1)) }
34
+ let(:event) { LogStash::Event.new("message" => "a " * (((subject.client.target_bulk_bytes/2) / event_count)+1)) }
36
35
 
37
36
  it "should send in two batches" do
38
37
  expect(subject.client).to have_received(:bulk_send).twice do |payload|
39
- expect(payload.size).to be <= target_bulk_bytes
38
+ expect(payload.size).to be <= subject.client.target_bulk_bytes
40
39
  end
41
40
  end
42
41
 
@@ -47,7 +46,7 @@ describe "TARGET_BULK_BYTES", :integration => true do
47
46
 
48
47
  it "should send in one batch" do
49
48
  expect(subject.client).to have_received(:bulk_send).once do |payload|
50
- expect(payload.size).to be <= target_bulk_bytes
49
+ expect(payload.size).to be <= subject.client.target_bulk_bytes
51
50
  end
52
51
  end
53
52
  end
@@ -63,8 +62,8 @@ describe "indexing" do
63
62
  let(:events) { event_count.times.map { event }.to_a }
64
63
  subject { LogStash::Outputs::OpenSearch.new(config) }
65
64
 
66
- let(:es_url) { "http://#{get_host_port}" }
67
- let(:index_url) {"#{es_url}/#{index}"}
65
+ let(:opensearch_url) { "http://#{get_host_port}" }
66
+ let(:index_url) {"#{opensearch_url}/#{index}"}
68
67
  let(:http_client_options) { {} }
69
68
  let(:http_client) do
70
69
  Manticore::Client.new(http_client_options)
@@ -79,7 +78,7 @@ describe "indexing" do
79
78
  it "ships events" do
80
79
  subject.multi_receive(events)
81
80
 
82
- http_client.post("#{es_url}/_refresh").call
81
+ http_client.post("#{opensearch_url}/_refresh").call
83
82
 
84
83
  response = http_client.get("#{index_url}/_count?q=*")
85
84
  result = LogStash::Json.load(response.body)
@@ -89,16 +88,22 @@ describe "indexing" do
89
88
  response = http_client.get("#{index_url}/_search?q=*&size=1000")
90
89
  result = LogStash::Json.load(response.body)
91
90
  result["hits"]["hits"].each do |doc|
92
- expect(doc["_type"]).to eq(type)
91
+ # FIXME This checks for OpenSearch 1.x or OpenDistro which has version 7.10.x
92
+ # need a cleaner way to check this.
93
+ if OpenSearchHelper.check_version?("< 2") || OpenSearchHelper.check_version?("> 7")
94
+ expect(doc["_type"]).to eq(type)
95
+ else
96
+ expect(doc).not_to include("_type")
97
+ end
93
98
  expect(doc["_index"]).to eq(index)
94
99
  end
95
100
  end
96
101
 
97
102
  it "sets the correct content-type header" do
98
- expected_manticore_opts = {:headers => {"Content-Type" => "application/json"}, :body => anything}
103
+ expected_manticore_opts = {:headers => {"content-type" => "application/json"}, :body => anything}
99
104
  if secure
100
105
  expected_manticore_opts = {
101
- :headers => {"Content-Type" => "application/json"},
106
+ :headers => {"content-type" => "application/json"},
102
107
  :body => anything,
103
108
  :auth => {
104
109
  :user => user,
@@ -136,7 +141,7 @@ describe "indexing" do
136
141
  describe "a secured indexer", :secure_integration => true do
137
142
  let(:user) { "admin" }
138
143
  let(:password) { "admin" }
139
- let(:es_url) {"https://integration:9200"}
144
+ let(:opensearch_url) {"https://integration:9200"}
140
145
  let(:config) do
141
146
  {
142
147
  "hosts" => ["integration:9200"],
@@ -161,4 +166,41 @@ describe "indexing" do
161
166
  end
162
167
  it_behaves_like("an indexer", true)
163
168
  end
169
+
170
+ describe "a basic auth secured indexer", :secure_integration => true do
171
+ let(:options) { {
172
+ :auth_type => {
173
+ "type"=>"basic",
174
+ "user" => "admin",
175
+ "password" => "admin"}
176
+ } }
177
+ let(:user) {options[:auth_type]["user"]}
178
+ let(:password) {options[:auth_type]["password"]}
179
+ let(:opensearch_url) {"https://integration:9200"}
180
+ let(:config) do
181
+ {
182
+ "hosts" => ["integration:9200"],
183
+ "auth_type" => {
184
+ "type"=>"basic",
185
+ "user" => user,
186
+ "password" => password},
187
+ "ssl" => true,
188
+ "ssl_certificate_verification" => false,
189
+ "index" => index
190
+ }
191
+ end
192
+ let(:http_client_options) do
193
+ {
194
+ :auth => {
195
+ :user => user,
196
+ :password => password
197
+ },
198
+ :ssl => {
199
+ :enabled => true,
200
+ :verify => false
201
+ }
202
+ }
203
+ end
204
+ it_behaves_like("an indexer", true)
205
+ end
164
206
  end
@@ -13,15 +13,15 @@ require "logstash/outputs/opensearch"
13
13
  describe "Versioned indexing", :integration => true do
14
14
  require "logstash/outputs/opensearch"
15
15
 
16
- let(:es) { get_client }
16
+ let(:client) { get_client }
17
17
 
18
18
  before :each do
19
19
  # Delete all templates first.
20
20
  # Clean OpenSearch of data before we start.
21
- es.indices.delete_template(:name => "*")
21
+ client.indices.delete_template(:name => "*")
22
22
  # This can fail if there are no indexes, ignore failure.
23
- es.indices.delete(:index => "*") rescue nil
24
- es.indices.refresh
23
+ client.indices.delete(:index => "*") rescue nil
24
+ client.indices.refresh
25
25
  end
26
26
 
27
27
  context "when index only" do
@@ -46,11 +46,11 @@ describe "Versioned indexing", :integration => true do
46
46
 
47
47
  it "should default to OpenSearch version" do
48
48
  subject.multi_receive([LogStash::Event.new("my_id" => "123", "message" => "foo")])
49
- r = es.get(:index => 'logstash-index', :type => doc_type, :id => "123", :refresh => true)
49
+ r = client.get(:index => 'logstash-index', :type => doc_type, :id => "123", :refresh => true)
50
50
  expect(r["_version"]).to eq(1)
51
51
  expect(r["_source"]["message"]).to eq('foo')
52
52
  subject.multi_receive([LogStash::Event.new("my_id" => "123", "message" => "foobar")])
53
- r2 = es.get(:index => 'logstash-index', :type => doc_type, :id => "123", :refresh => true)
53
+ r2 = client.get(:index => 'logstash-index', :type => doc_type, :id => "123", :refresh => true)
54
54
  expect(r2["_version"]).to eq(2)
55
55
  expect(r2["_source"]["message"]).to eq('foobar')
56
56
  end
@@ -74,7 +74,7 @@ describe "Versioned indexing", :integration => true do
74
74
  it "should respect the external version" do
75
75
  id = "ev1"
76
76
  subject.multi_receive([LogStash::Event.new("my_id" => id, "my_version" => "99", "message" => "foo")])
77
- r = es.get(:index => 'logstash-index', :type => doc_type, :id => id, :refresh => true)
77
+ r = client.get(:index => 'logstash-index', :type => doc_type, :id => id, :refresh => true)
78
78
  expect(r["_version"]).to eq(99)
79
79
  expect(r["_source"]["message"]).to eq('foo')
80
80
  end
@@ -82,12 +82,12 @@ describe "Versioned indexing", :integration => true do
82
82
  it "should ignore non-monotonic external version updates" do
83
83
  id = "ev2"
84
84
  subject.multi_receive([LogStash::Event.new("my_id" => id, "my_version" => "99", "message" => "foo")])
85
- r = es.get(:index => 'logstash-index', :type => doc_type, :id => id, :refresh => true)
85
+ r = client.get(:index => 'logstash-index', :type => doc_type, :id => id, :refresh => true)
86
86
  expect(r["_version"]).to eq(99)
87
87
  expect(r["_source"]["message"]).to eq('foo')
88
88
 
89
89
  subject.multi_receive([LogStash::Event.new("my_id" => id, "my_version" => "98", "message" => "foo")])
90
- r2 = es.get(:index => 'logstash-index', :type => doc_type, :id => id, :refresh => true)
90
+ r2 = client.get(:index => 'logstash-index', :type => doc_type, :id => id, :refresh => true)
91
91
  expect(r2["_version"]).to eq(99)
92
92
  expect(r2["_source"]["message"]).to eq('foo')
93
93
  end
@@ -95,12 +95,12 @@ describe "Versioned indexing", :integration => true do
95
95
  it "should commit monotonic external version updates" do
96
96
  id = "ev3"
97
97
  subject.multi_receive([LogStash::Event.new("my_id" => id, "my_version" => "99", "message" => "foo")])
98
- r = es.get(:index => 'logstash-index', :type => doc_type, :id => id, :refresh => true)
98
+ r = client.get(:index => 'logstash-index', :type => doc_type, :id => id, :refresh => true)
99
99
  expect(r["_version"]).to eq(99)
100
100
  expect(r["_source"]["message"]).to eq('foo')
101
101
 
102
102
  subject.multi_receive([LogStash::Event.new("my_id" => id, "my_version" => "100", "message" => "foo")])
103
- r2 = es.get(:index => 'logstash-index', :type => doc_type, :id => id, :refresh => true)
103
+ r2 = client.get(:index => 'logstash-index', :type => doc_type, :id => id, :refresh => true)
104
104
  expect(r2["_version"]).to eq(100)
105
105
  expect(r2["_source"]["message"]).to eq('foo')
106
106
  end
@@ -14,7 +14,8 @@ describe "Ingest pipeline execution behavior", :integration => true do
14
14
  require "logstash/outputs/opensearch"
15
15
  settings = {
16
16
  "hosts" => "#{get_host_port()}",
17
- "pipeline" => "apache-logs"
17
+ "pipeline" => "apache-logs",
18
+ "ecs_compatibility" => "disabled" # specs are tightly tied to non-ECS defaults
18
19
  }
19
20
  next LogStash::Outputs::OpenSearch.new(settings)
20
21
  end
@@ -37,8 +38,6 @@ describe "Ingest pipeline execution behavior", :integration => true do
37
38
 
38
39
  before :each do
39
40
  # Delete all templates first.
40
- require "elasticsearch"
41
-
42
41
  # Clean OpenSearch of data before we start.
43
42
  @client = get_client
44
43
  @client.indices.delete_template(:name => "*")
@@ -50,7 +49,7 @@ describe "Ingest pipeline execution behavior", :integration => true do
50
49
  http_client.delete(ingest_url).call
51
50
 
52
51
  # register pipeline
53
- http_client.put(ingest_url, :body => apache_logs_pipeline, :headers => {"Content-Type" => "application/json" }).call
52
+ http_client.put(ingest_url, :body => apache_logs_pipeline, :headers => {"content-type" => "application/json" }).call
54
53
 
55
54
  #TODO: Use esclient
56
55
  #@client.ingest.put_pipeline :id => 'apache_pipeline', :body => pipeline_defintion
@@ -24,8 +24,6 @@ describe "metrics", :integration => true do
24
24
  let(:document_level_metrics) { subject.instance_variable_get(:@document_level_metrics) }
25
25
 
26
26
  before :each do
27
- require "elasticsearch"
28
-
29
27
  # Clean OpenSearch of data before we start.
30
28
  @client = get_client
31
29
  clean(@client)
@@ -27,7 +27,6 @@ describe "opensearch is down on startup", :integration => true do
27
27
 
28
28
  before :each do
29
29
  # Delete all templates first.
30
- require "elasticsearch"
31
30
  allow(Stud).to receive(:stoppable_sleep)
32
31
 
33
32
  # Clean OpenSearch of data before we start.
@@ -12,7 +12,7 @@ require_relative "../../../spec/opensearch_spec_helper"
12
12
  describe "Update actions using painless scripts", :integration => true, :update_tests => 'painless' do
13
13
  require "logstash/outputs/opensearch"
14
14
 
15
- def get_es_output( options={} )
15
+ def get_output( options={} )
16
16
  settings = {
17
17
  "manage_template" => true,
18
18
  "index" => "logstash-update",
@@ -42,7 +42,7 @@ describe "Update actions using painless scripts", :integration => true, :update_
42
42
  context "scripted updates" do
43
43
 
44
44
  it "should increment a counter with event/doc 'count' variable with inline script" do
45
- subject = get_es_output({
45
+ subject = get_output({
46
46
  'document_id' => "123",
47
47
  'script' => 'ctx._source.counter += params.event.counter',
48
48
  'script_type' => 'inline'
@@ -54,7 +54,7 @@ describe "Update actions using painless scripts", :integration => true, :update_
54
54
  end
55
55
 
56
56
  it "should increment a counter with event/doc 'count' variable with event/doc as upsert and inline script" do
57
- subject = get_es_output({
57
+ subject = get_output({
58
58
  'document_id' => "123",
59
59
  'doc_as_upsert' => true,
60
60
  'script' => 'if( ctx._source.containsKey("counter") ){ ctx._source.counter += params.event.counter; } else { ctx._source.counter = params.event.counter; }',
@@ -67,7 +67,7 @@ describe "Update actions using painless scripts", :integration => true, :update_
67
67
  end
68
68
 
69
69
  it "should, with new doc, set a counter with event/doc 'count' variable with event/doc as upsert and inline script" do
70
- subject = get_es_output({
70
+ subject = get_output({
71
71
  'document_id' => "456",
72
72
  'doc_as_upsert' => true,
73
73
  'script' => 'if( ctx._source.containsKey("counter") ){ ctx._source.counter += params.event.counter; } else { ctx._source.counter = params.event.counter; }',
@@ -90,7 +90,7 @@ describe "Update actions using painless scripts", :integration => true, :update_
90
90
 
91
91
  plugin_parameters.merge!('script_lang' => '')
92
92
 
93
- subject = get_es_output(plugin_parameters)
93
+ subject = get_output(plugin_parameters)
94
94
  subject.register
95
95
  subject.multi_receive([LogStash::Event.new("count" => 4 )])
96
96
  r = @client.get(:index => 'logstash-update', :type => doc_type, :id => "123", :refresh => true)
@@ -101,7 +101,7 @@ describe "Update actions using painless scripts", :integration => true, :update_
101
101
 
102
102
  context "when update with upsert" do
103
103
  it "should create new documents with provided upsert" do
104
- subject = get_es_output({ 'document_id' => "456", 'upsert' => '{"message": "upsert message"}' })
104
+ subject = get_output({ 'document_id' => "456", 'upsert' => '{"message": "upsert message"}' })
105
105
  subject.register
106
106
  subject.multi_receive([LogStash::Event.new("message" => "sample message here")])
107
107
  r = @client.get(:index => 'logstash-update', :type => doc_type, :id => "456", :refresh => true)
@@ -109,7 +109,7 @@ describe "Update actions using painless scripts", :integration => true, :update_
109
109
  end
110
110
 
111
111
  it "should create new documents with event/doc as upsert" do
112
- subject = get_es_output({ 'document_id' => "456", 'doc_as_upsert' => true })
112
+ subject = get_output({ 'document_id' => "456", 'doc_as_upsert' => true })
113
113
  subject.register
114
114
  subject.multi_receive([LogStash::Event.new("message" => "sample message here")])
115
115
  r = @client.get(:index => 'logstash-update', :type => doc_type, :id => "456", :refresh => true)
@@ -117,7 +117,7 @@ describe "Update actions using painless scripts", :integration => true, :update_
117
117
  end
118
118
 
119
119
  it "should fail on documents with event/doc as upsert at external version" do
120
- subject = get_es_output({ 'document_id' => "456", 'doc_as_upsert' => true, 'version' => 999, "version_type" => "external" })
120
+ subject = get_output({ 'document_id' => "456", 'doc_as_upsert' => true, 'version' => 999, "version_type" => "external" })
121
121
  expect { subject.register }.to raise_error(LogStash::ConfigurationError)
122
122
  end
123
123
  end
@@ -126,7 +126,7 @@ describe "Update actions using painless scripts", :integration => true, :update_
126
126
 
127
127
  context 'with an inline script' do
128
128
  it "should create new documents with upsert content" do
129
- subject = get_es_output({ 'document_id' => "456", 'script' => 'ctx._source.counter = params.event.counter', 'upsert' => '{"message": "upsert message"}', 'script_type' => 'inline' })
129
+ subject = get_output({ 'document_id' => "456", 'script' => 'ctx._source.counter = params.event.counter', 'upsert' => '{"message": "upsert message"}', 'script_type' => 'inline' })
130
130
  subject.register
131
131
 
132
132
  subject.multi_receive([LogStash::Event.new("message" => "sample message here")])
@@ -135,7 +135,7 @@ describe "Update actions using painless scripts", :integration => true, :update_
135
135
  end
136
136
 
137
137
  it "should create new documents with event/doc as script params" do
138
- subject = get_es_output({ 'document_id' => "456", 'script' => 'ctx._source.counter = params.event.counter', 'scripted_upsert' => true, 'script_type' => 'inline' })
138
+ subject = get_output({ 'document_id' => "456", 'script' => 'ctx._source.counter = params.event.counter', 'scripted_upsert' => true, 'script_type' => 'inline' })
139
139
  subject.register
140
140
  subject.multi_receive([LogStash::Event.new("counter" => 1)])
141
141
  @client.indices.refresh
@@ -10,7 +10,7 @@
10
10
  require_relative "../../../spec/opensearch_spec_helper"
11
11
  require "logstash/outputs/opensearch"
12
12
 
13
- context "join field tests", :integration => true do
13
+ context "join field tests", :integration => true && OpenSearchHelper.check_version?("<2") do
14
14
 
15
15
  shared_examples "a join field based parent indexer" do
16
16
  let(:index) { 10.times.collect { rand(10).to_s }.join("") }
@@ -25,7 +25,7 @@ context "join field tests", :integration => true do
25
25
  let(:parent_relation) { "parent_type" }
26
26
  let(:child_relation) { "child_type" }
27
27
  let(:default_headers) {
28
- {"Content-Type" => "application/json"}
28
+ {"content-type" => "application/json"}
29
29
  }
30
30
  subject { LogStash::Outputs::OpenSearch.new(config) }
31
31