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

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 (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