logstash-output-opensearch 1.1.0-java → 2.0.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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/COMPATIBILITY.md +5 -3
- data/CONTRIBUTING.md +26 -0
- data/DEVELOPER_GUIDE.md +9 -0
- data/Gemfile +1 -1
- data/MAINTAINERS.md +3 -0
- data/README.md +90 -3
- data/docs/ecs_compatibility.md +42 -0
- data/lib/logstash/outputs/opensearch/http_client/manticore_adapter.rb +122 -10
- data/lib/logstash/outputs/opensearch/http_client/pool.rb +11 -2
- data/lib/logstash/outputs/opensearch/http_client.rb +22 -25
- data/lib/logstash/outputs/opensearch/http_client_builder.rb +9 -3
- data/lib/logstash/outputs/opensearch/template_manager.rb +6 -5
- data/lib/logstash/outputs/opensearch/templates/ecs-disabled/1x_index.json +66 -0
- data/lib/logstash/outputs/opensearch/templates/ecs-disabled/2x.json +44 -0
- data/lib/logstash/outputs/opensearch/templates/ecs-disabled/2x_index.json +66 -0
- data/lib/logstash/outputs/opensearch/templates/ecs-disabled/7x_index.json +66 -0
- data/lib/logstash/outputs/opensearch/templates/ecs-v1/1x.json +3629 -0
- data/lib/logstash/outputs/opensearch/templates/ecs-v1/1x_index.json +3631 -0
- data/lib/logstash/outputs/opensearch/templates/ecs-v1/2x.json +3629 -0
- data/lib/logstash/outputs/opensearch/templates/ecs-v1/2x_index.json +3631 -0
- data/lib/logstash/outputs/opensearch/templates/ecs-v1/7x.json +3629 -0
- data/lib/logstash/outputs/opensearch/templates/ecs-v1/7x_index.json +3631 -0
- data/lib/logstash/outputs/opensearch/templates/ecs-v8/1x.json +5252 -0
- data/lib/logstash/outputs/opensearch/templates/ecs-v8/1x_index.json +5254 -0
- data/lib/logstash/outputs/opensearch/templates/ecs-v8/2x.json +5252 -0
- data/lib/logstash/outputs/opensearch/templates/ecs-v8/2x_index.json +5254 -0
- data/lib/logstash/outputs/opensearch/templates/ecs-v8/7x.json +5252 -0
- data/lib/logstash/outputs/opensearch/templates/ecs-v8/7x_index.json +5254 -0
- data/lib/logstash/outputs/opensearch.rb +10 -3
- data/lib/logstash/plugin_mixins/opensearch/api_configs.rb +26 -0
- data/logstash-output-opensearch.gemspec +19 -3
- data/spec/integration/outputs/compressed_indexing_spec.rb +10 -4
- data/spec/integration/outputs/create_spec.rb +7 -7
- data/spec/integration/outputs/delete_spec.rb +8 -8
- data/spec/integration/outputs/index_spec.rb +52 -10
- data/spec/integration/outputs/index_version_spec.rb +11 -11
- data/spec/integration/outputs/ingest_pipeline_spec.rb +2 -3
- data/spec/integration/outputs/metrics_spec.rb +0 -2
- data/spec/integration/outputs/no_opensearch_on_startup_spec.rb +0 -1
- data/spec/integration/outputs/painless_update_spec.rb +10 -10
- data/spec/integration/outputs/parent_spec.rb +1 -1
- data/spec/integration/outputs/retry_spec.rb +2 -2
- data/spec/integration/outputs/sniffer_spec.rb +2 -2
- data/spec/integration/outputs/templates_spec.rb +83 -59
- data/spec/integration/outputs/update_spec.rb +14 -14
- data/spec/opensearch_spec_helper.rb +12 -2
- data/spec/unit/outputs/opensearch/http_client/manticore_adapter_spec.rb +86 -3
- data/spec/unit/outputs/opensearch/http_client_spec.rb +26 -5
- data/spec/unit/outputs/opensearch/template_manager_spec.rb +11 -4
- data/spec/unit/outputs/opensearch_spec.rb +18 -2
- data.tar.gz.sig +0 -0
- metadata +74 -9
- metadata.gz.sig +0 -0
|
@@ -10,8 +10,12 @@
|
|
|
10
10
|
require_relative "../../../spec/opensearch_spec_helper"
|
|
11
11
|
|
|
12
12
|
describe "index template expected behavior", :integration => true do
|
|
13
|
+
let(:ecs_compatibility) { fail('spec group does not define `ecs_compatibility`!') }
|
|
14
|
+
|
|
13
15
|
subject! do
|
|
14
16
|
require "logstash/outputs/opensearch"
|
|
17
|
+
allow_any_instance_of(LogStash::Outputs::OpenSearch).to receive(:ecs_compatibility).and_return(ecs_compatibility)
|
|
18
|
+
|
|
15
19
|
settings = {
|
|
16
20
|
"manage_template" => true,
|
|
17
21
|
"template_overwrite" => true,
|
|
@@ -21,8 +25,6 @@ describe "index template expected behavior", :integration => true do
|
|
|
21
25
|
end
|
|
22
26
|
|
|
23
27
|
before :each do
|
|
24
|
-
# Delete all templates first.
|
|
25
|
-
require "elasticsearch"
|
|
26
28
|
|
|
27
29
|
# Clean OpenSearch of data before we start.
|
|
28
30
|
@client = get_client
|
|
@@ -31,75 +33,97 @@ describe "index template expected behavior", :integration => true do
|
|
|
31
33
|
# This can fail if there are no indexes, ignore failure.
|
|
32
34
|
@client.indices.delete(:index => "*") rescue nil
|
|
33
35
|
|
|
34
|
-
subject.register
|
|
35
|
-
|
|
36
|
-
subject.multi_receive([
|
|
37
|
-
LogStash::Event.new("message" => "sample message here"),
|
|
38
|
-
LogStash::Event.new("somemessage" => { "message" => "sample nested message here" }),
|
|
39
|
-
LogStash::Event.new("somevalue" => 100),
|
|
40
|
-
LogStash::Event.new("somevalue" => 10),
|
|
41
|
-
LogStash::Event.new("somevalue" => 1),
|
|
42
|
-
LogStash::Event.new("country" => "us"),
|
|
43
|
-
LogStash::Event.new("country" => "at"),
|
|
44
|
-
LogStash::Event.new("geoip" => { "location" => [ 0.0, 0.0 ] })
|
|
45
|
-
])
|
|
46
|
-
|
|
47
|
-
@client.indices.refresh
|
|
48
|
-
|
|
49
|
-
# Wait or fail until everything's indexed.
|
|
50
|
-
Stud::try(20.times) do
|
|
51
|
-
r = @client.search(index: 'logstash-*')
|
|
52
|
-
expect(r).to have_hits(8)
|
|
53
|
-
end
|
|
54
36
|
end
|
|
55
37
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
38
|
+
context 'with ecs_compatibility => disabled' do
|
|
39
|
+
let(:ecs_compatibility) { :disabled }
|
|
40
|
+
|
|
41
|
+
before :each do
|
|
42
|
+
subject.register
|
|
43
|
+
|
|
44
|
+
subject.multi_receive([
|
|
45
|
+
LogStash::Event.new("message" => "sample message here"),
|
|
46
|
+
LogStash::Event.new("somemessage" => { "message" => "sample nested message here" }),
|
|
47
|
+
LogStash::Event.new("somevalue" => 100),
|
|
48
|
+
LogStash::Event.new("somevalue" => 10),
|
|
49
|
+
LogStash::Event.new("somevalue" => 1),
|
|
50
|
+
LogStash::Event.new("country" => "us"),
|
|
51
|
+
LogStash::Event.new("country" => "at"),
|
|
52
|
+
LogStash::Event.new("geoip" => { "location" => [ 0.0, 0.0 ] })
|
|
53
|
+
])
|
|
54
|
+
|
|
55
|
+
@client.indices.refresh
|
|
56
|
+
|
|
57
|
+
# Wait or fail until everything's indexed.
|
|
58
|
+
Stud::try(20.times) do
|
|
59
|
+
r = @client.search(index: 'logstash-*')
|
|
60
|
+
expect(r).to have_hits(8)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
61
63
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
64
|
+
it "permits phrase searching on string fields" do
|
|
65
|
+
results = @client.search(:q => "message:\"sample message\"")
|
|
66
|
+
expect(results).to have_hits(1)
|
|
67
|
+
expect(results["hits"]["hits"][0]["_source"]["message"]).to eq("sample message here")
|
|
68
|
+
end
|
|
65
69
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
expect(values).to_not include(1)
|
|
70
|
-
end
|
|
70
|
+
it "numbers dynamically map to a numeric type and permit range queries" do
|
|
71
|
+
results = @client.search(:q => "somevalue:[5 TO 105]")
|
|
72
|
+
expect(results).to have_hits(2)
|
|
71
73
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
values = results["hits"]["hits"].collect { |r| r["_source"]["somevalue"] }
|
|
75
|
+
expect(values).to include(10)
|
|
76
|
+
expect(values).to include(100)
|
|
77
|
+
expect(values).to_not include(1)
|
|
78
|
+
end
|
|
76
79
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
it "does not create .keyword field for top-level message field" do
|
|
81
|
+
results = @client.search(:q => "message.keyword:\"sample message here\"")
|
|
82
|
+
expect(results).to have_hits(0)
|
|
83
|
+
end
|
|
81
84
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
it "creates .keyword field for nested message fields" do
|
|
86
|
+
results = @client.search(:q => "somemessage.message.keyword:\"sample nested message here\"")
|
|
87
|
+
expect(results).to have_hits(1)
|
|
88
|
+
end
|
|
86
89
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
90
|
+
it "creates .keyword field from any string field which is not_analyzed" do
|
|
91
|
+
results = @client.search(:q => "country.keyword:\"us\"")
|
|
92
|
+
expect(results).to have_hits(1)
|
|
93
|
+
expect(results["hits"]["hits"][0]["_source"]["country"]).to eq("us")
|
|
94
|
+
|
|
95
|
+
# partial or terms should not work.
|
|
96
|
+
results = @client.search(:q => "country.keyword:\"u\"")
|
|
97
|
+
expect(results).to have_hits(0)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "make [geoip][location] a geo_point" do
|
|
101
|
+
expect(field_properties_from_template("logstash", "geoip")["location"]["type"]).to eq("geo_point")
|
|
102
|
+
end
|
|
91
103
|
|
|
92
|
-
|
|
93
|
-
|
|
104
|
+
it "aggregate .keyword results correctly " do
|
|
105
|
+
results = @client.search(:body => { "aggregations" => { "my_agg" => { "terms" => { "field" => "country.keyword" } } } })["aggregations"]["my_agg"]
|
|
106
|
+
terms = results["buckets"].collect { |b| b["key"] }
|
|
107
|
+
|
|
108
|
+
expect(terms).to include("us")
|
|
109
|
+
|
|
110
|
+
# 'at' is a stopword, make sure stopwords are not ignored.
|
|
111
|
+
expect(terms).to include("at")
|
|
112
|
+
end
|
|
94
113
|
end
|
|
95
114
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
terms = results["buckets"].collect { |b| b["key"] }
|
|
115
|
+
context 'with ECS enabled' do
|
|
116
|
+
let(:ecs_compatibility) { :v1 }
|
|
99
117
|
|
|
100
|
-
|
|
118
|
+
before(:each) do
|
|
119
|
+
subject.register # should load template?
|
|
120
|
+
subject.multi_receive([LogStash::Event.new("message" => "sample message here")])
|
|
121
|
+
end
|
|
101
122
|
|
|
102
|
-
|
|
103
|
-
|
|
123
|
+
it 'loads the templates' do
|
|
124
|
+
aggregate_failures do
|
|
125
|
+
expect(@client.indices.exists_template(name: 'ecs-logstash')).to be_truthy
|
|
126
|
+
end
|
|
127
|
+
end
|
|
104
128
|
end
|
|
105
129
|
end
|
|
@@ -12,7 +12,7 @@ require_relative "../../../spec/opensearch_spec_helper"
|
|
|
12
12
|
describe "Update actions without scripts", :integration => true do
|
|
13
13
|
require "logstash/outputs/opensearch"
|
|
14
14
|
|
|
15
|
-
def
|
|
15
|
+
def get_output( options={} )
|
|
16
16
|
settings = {
|
|
17
17
|
"manage_template" => true,
|
|
18
18
|
"index" => "logstash-update",
|
|
@@ -40,20 +40,20 @@ describe "Update actions without scripts", :integration => true do
|
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
it "should fail without a document_id" do
|
|
43
|
-
subject =
|
|
43
|
+
subject = get_output
|
|
44
44
|
expect { subject.register }.to raise_error(LogStash::ConfigurationError)
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
context "when update only" do
|
|
48
48
|
it "should not create new document" do
|
|
49
|
-
subject =
|
|
49
|
+
subject = get_output({ 'document_id' => "456" } )
|
|
50
50
|
subject.register
|
|
51
51
|
subject.multi_receive([LogStash::Event.new("message" => "sample message here")])
|
|
52
|
-
expect {@client.get(:index => 'logstash-update', :type => doc_type, :id => "456", :refresh => true)}.to raise_error(
|
|
52
|
+
expect {@client.get(:index => 'logstash-update', :type => doc_type, :id => "456", :refresh => true)}.to raise_error(OpenSearch::Transport::Transport::Errors::NotFound)
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
it "should update existing document" do
|
|
56
|
-
subject =
|
|
56
|
+
subject = get_output({ 'document_id' => "123" })
|
|
57
57
|
subject.register
|
|
58
58
|
subject.multi_receive([LogStash::Event.new("message" => "updated message here")])
|
|
59
59
|
r = @client.get(:index => 'logstash-update', :type => doc_type, :id => "123", :refresh => true)
|
|
@@ -63,7 +63,7 @@ describe "Update actions without scripts", :integration => true do
|
|
|
63
63
|
# The es ruby client treats the data field differently. Make sure this doesn't
|
|
64
64
|
# raise an exception
|
|
65
65
|
it "should update an existing document that has a 'data' field" do
|
|
66
|
-
subject =
|
|
66
|
+
subject = get_output({ 'document_id' => "123" })
|
|
67
67
|
subject.register
|
|
68
68
|
subject.multi_receive([LogStash::Event.new("data" => "updated message here", "message" => "foo")])
|
|
69
69
|
r = @client.get(:index => 'logstash-update', :type => doc_type, :id => "123", :refresh => true)
|
|
@@ -72,27 +72,27 @@ describe "Update actions without scripts", :integration => true do
|
|
|
72
72
|
end
|
|
73
73
|
|
|
74
74
|
it "should allow default (internal) version" do
|
|
75
|
-
subject =
|
|
75
|
+
subject = get_output({ 'document_id' => "123", "version" => "99" })
|
|
76
76
|
subject.register
|
|
77
77
|
end
|
|
78
78
|
|
|
79
79
|
it "should allow internal version" do
|
|
80
|
-
subject =
|
|
80
|
+
subject = get_output({ 'document_id' => "123", "version" => "99", "version_type" => "internal" })
|
|
81
81
|
subject.register
|
|
82
82
|
end
|
|
83
83
|
|
|
84
84
|
it "should not allow external version" do
|
|
85
|
-
subject =
|
|
85
|
+
subject = get_output({ 'document_id' => "123", "version" => "99", "version_type" => "external" })
|
|
86
86
|
expect { subject.register }.to raise_error(LogStash::ConfigurationError)
|
|
87
87
|
end
|
|
88
88
|
|
|
89
89
|
it "should not allow external_gt version" do
|
|
90
|
-
subject =
|
|
90
|
+
subject = get_output({ 'document_id' => "123", "version" => "99", "version_type" => "external_gt" })
|
|
91
91
|
expect { subject.register }.to raise_error(LogStash::ConfigurationError)
|
|
92
92
|
end
|
|
93
93
|
|
|
94
94
|
it "should not allow external_gte version" do
|
|
95
|
-
subject =
|
|
95
|
+
subject = get_output({ 'document_id' => "123", "version" => "99", "version_type" => "external_gte" })
|
|
96
96
|
expect { subject.register }.to raise_error(LogStash::ConfigurationError)
|
|
97
97
|
end
|
|
98
98
|
|
|
@@ -100,7 +100,7 @@ describe "Update actions without scripts", :integration => true do
|
|
|
100
100
|
|
|
101
101
|
context "when update with upsert" do
|
|
102
102
|
it "should create new documents with provided upsert" do
|
|
103
|
-
subject =
|
|
103
|
+
subject = get_output({ 'document_id' => "456", 'upsert' => '{"message": "upsert message"}' })
|
|
104
104
|
subject.register
|
|
105
105
|
subject.multi_receive([LogStash::Event.new("message" => "sample message here")])
|
|
106
106
|
r = @client.get(:index => 'logstash-update', :type => doc_type, :id => "456", :refresh => true)
|
|
@@ -108,7 +108,7 @@ describe "Update actions without scripts", :integration => true do
|
|
|
108
108
|
end
|
|
109
109
|
|
|
110
110
|
it "should create new documents with event/doc as upsert" do
|
|
111
|
-
subject =
|
|
111
|
+
subject = get_output({ 'document_id' => "456", 'doc_as_upsert' => true })
|
|
112
112
|
subject.register
|
|
113
113
|
subject.multi_receive([LogStash::Event.new("message" => "sample message here")])
|
|
114
114
|
r = @client.get(:index => 'logstash-update', :type => doc_type, :id => "456", :refresh => true)
|
|
@@ -116,7 +116,7 @@ describe "Update actions without scripts", :integration => true do
|
|
|
116
116
|
end
|
|
117
117
|
|
|
118
118
|
it "should fail on documents with event/doc as upsert at external version" do
|
|
119
|
-
subject =
|
|
119
|
+
subject = get_output({ 'document_id' => "456", 'doc_as_upsert' => true, 'version' => 999, "version_type" => "external" })
|
|
120
120
|
expect { subject.register }.to raise_error(LogStash::ConfigurationError)
|
|
121
121
|
end
|
|
122
122
|
end
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
require_relative './spec_helper'
|
|
11
11
|
|
|
12
|
-
require '
|
|
12
|
+
require 'opensearch'
|
|
13
13
|
|
|
14
14
|
require 'json'
|
|
15
15
|
require 'cabin'
|
|
@@ -24,7 +24,7 @@ module OpenSearchHelper
|
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def get_client
|
|
27
|
-
|
|
27
|
+
OpenSearch::Client.new(:hosts => [get_host_port])
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def doc_type
|
|
@@ -49,6 +49,16 @@ module OpenSearchHelper
|
|
|
49
49
|
RSpec.configuration.filter[:version]
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
+
def self.check_version?(*requirement)
|
|
53
|
+
version = self.version
|
|
54
|
+
if version.nil? || version.empty?
|
|
55
|
+
puts "version tag isn't set. Returning false from 'check_version?`."
|
|
56
|
+
return false
|
|
57
|
+
end
|
|
58
|
+
release_version = Gem::Version.new(version).release
|
|
59
|
+
Gem::Requirement.new(requirement).satisfied_by?(release_version)
|
|
60
|
+
end
|
|
61
|
+
|
|
52
62
|
RSpec::Matchers.define :have_hits do |expected|
|
|
53
63
|
match do |actual|
|
|
54
64
|
expected == actual['hits']['total']['value']
|
|
@@ -25,13 +25,13 @@ describe LogStash::Outputs::OpenSearch::HttpClient::ManticoreAdapter do
|
|
|
25
25
|
it "should implement host unreachable exceptions" do
|
|
26
26
|
expect(subject.host_unreachable_exceptions).to be_a(Array)
|
|
27
27
|
end
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
describe "auth" do
|
|
30
30
|
let(:user) { "myuser" }
|
|
31
31
|
let(:password) { "mypassword" }
|
|
32
32
|
let(:noauth_uri) { clone = uri.clone; clone.user=nil; clone.password=nil; clone }
|
|
33
33
|
let(:uri) { ::LogStash::Util::SafeURI.new("http://#{user}:#{password}@localhost:9200") }
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
it "should convert the auth to params" do
|
|
36
36
|
resp = double("response")
|
|
37
37
|
allow(resp).to receive(:call)
|
|
@@ -39,7 +39,7 @@ describe LogStash::Outputs::OpenSearch::HttpClient::ManticoreAdapter do
|
|
|
39
39
|
|
|
40
40
|
expected_uri = noauth_uri.clone
|
|
41
41
|
expected_uri.path = "/"
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
expect(subject.manticore).to receive(:get).
|
|
44
44
|
with(expected_uri.to_s, {
|
|
45
45
|
:headers => {"content-type" => "application/json"},
|
|
@@ -54,6 +54,89 @@ describe LogStash::Outputs::OpenSearch::HttpClient::ManticoreAdapter do
|
|
|
54
54
|
end
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
+
describe "aws_iam" do
|
|
58
|
+
let(:options) { {
|
|
59
|
+
:auth_type => {
|
|
60
|
+
"type"=>"aws_iam",
|
|
61
|
+
"aws_access_key_id"=>"AAAAAAAAAAAAAAAAAAAA",
|
|
62
|
+
"aws_secret_access_key"=>"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"}
|
|
63
|
+
} }
|
|
64
|
+
let(:options_svc) { {
|
|
65
|
+
:auth_type => {
|
|
66
|
+
"type"=>"aws_iam",
|
|
67
|
+
"aws_access_key_id"=>"AAAAAAAAAAAAAAAAAAAA",
|
|
68
|
+
"aws_secret_access_key"=>"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
|
69
|
+
"service_name"=>"svc_test"}
|
|
70
|
+
} }
|
|
71
|
+
subject { described_class.new(logger, options) }
|
|
72
|
+
let(:uri) { ::LogStash::Util::SafeURI.new("http://localhost:9200") }
|
|
73
|
+
let(:sign_aws_request) { }
|
|
74
|
+
|
|
75
|
+
it "should validate AWS IAM credentials initialization" do
|
|
76
|
+
expect(subject.aws_iam_auth_initialization(options)).not_to be_nil
|
|
77
|
+
expect(subject.get_service_name).to eq("es")
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "should validate AWS IAM service_name config" do
|
|
81
|
+
expect(subject.aws_iam_auth_initialization(options_svc)).not_to be_nil
|
|
82
|
+
expect(subject.get_service_name).to eq("svc_test")
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "should validate signing aws request" do
|
|
86
|
+
resp = double("response")
|
|
87
|
+
allow(resp).to receive(:call)
|
|
88
|
+
allow(resp).to receive(:code).and_return(200)
|
|
89
|
+
allow(subject).to receive(:sign_aws_request).with(any_args).and_return(sign_aws_request)
|
|
90
|
+
|
|
91
|
+
expected_uri = uri.clone
|
|
92
|
+
expected_uri.path = "/"
|
|
93
|
+
|
|
94
|
+
expect(subject.manticore).to receive(:get).
|
|
95
|
+
with(expected_uri.to_s, {
|
|
96
|
+
:headers => {"content-type"=> "application/json"}
|
|
97
|
+
}
|
|
98
|
+
).and_return resp
|
|
99
|
+
|
|
100
|
+
expect(subject).to receive(:sign_aws_request)
|
|
101
|
+
subject.perform_request(uri, :get, "/")
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
describe "basic_auth" do
|
|
106
|
+
let(:options) { {
|
|
107
|
+
:auth_type => {
|
|
108
|
+
"type"=>"basic",
|
|
109
|
+
"user" => "myuser",
|
|
110
|
+
"password" => "mypassword"}
|
|
111
|
+
} }
|
|
112
|
+
subject { described_class.new(logger, options) }
|
|
113
|
+
let(:user) {options[:auth_type]["user"]}
|
|
114
|
+
let(:password) {options[:auth_type]["password"]}
|
|
115
|
+
let(:noauth_uri) { clone = uri.clone; clone.user=nil; clone.password=nil; clone }
|
|
116
|
+
let(:uri) { ::LogStash::Util::SafeURI.new("http://localhost:9200") }
|
|
117
|
+
|
|
118
|
+
it "should validate master credentials with type as 'basic_auth'" do
|
|
119
|
+
resp = double("response")
|
|
120
|
+
allow(resp).to receive(:call)
|
|
121
|
+
allow(resp).to receive(:code).and_return(200)
|
|
122
|
+
|
|
123
|
+
expected_uri = noauth_uri.clone
|
|
124
|
+
expected_uri.path = "/"
|
|
125
|
+
|
|
126
|
+
expect(subject.manticore).to receive(:get).
|
|
127
|
+
with(expected_uri.to_s, {
|
|
128
|
+
:headers => {"content-type" => "application/json"},
|
|
129
|
+
:auth => {
|
|
130
|
+
:user => user,
|
|
131
|
+
:password => password,
|
|
132
|
+
:eager => true
|
|
133
|
+
}
|
|
134
|
+
}).and_return resp
|
|
135
|
+
|
|
136
|
+
subject.perform_request(uri, :get, "/")
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
57
140
|
describe "bad response codes" do
|
|
58
141
|
let(:uri) { ::LogStash::Util::SafeURI.new("http://localhost:9200") }
|
|
59
142
|
|
|
@@ -17,6 +17,7 @@ describe LogStash::Outputs::OpenSearch::HttpClient do
|
|
|
17
17
|
opts = {
|
|
18
18
|
:hosts => [::LogStash::Util::SafeURI.new("127.0.0.1")],
|
|
19
19
|
:logger => Cabin::Channel.get,
|
|
20
|
+
:target_bulk_bytes => 9_000_000,
|
|
20
21
|
:metric => ::LogStash::Instrument::NullMetric.new(:dummy).namespace(:alsodummy)
|
|
21
22
|
}
|
|
22
23
|
|
|
@@ -156,11 +157,31 @@ describe LogStash::Outputs::OpenSearch::HttpClient do
|
|
|
156
157
|
}
|
|
157
158
|
|
|
158
159
|
it "should call index template" do
|
|
159
|
-
expect(subject.pool).to receive(:put).with("_template/#{template_name}", nil, anything).and_return(get_response)
|
|
160
|
+
expect(subject.pool).to receive(:put).with("/_template/#{template_name}", nil, anything).and_return(get_response)
|
|
160
161
|
subject.template_put(template_name, template)
|
|
161
162
|
end
|
|
162
163
|
end
|
|
163
164
|
|
|
165
|
+
describe "legacy_template" do
|
|
166
|
+
let(:template_name) { "logstash" }
|
|
167
|
+
let(:template) { {} }
|
|
168
|
+
let(:get_response) {
|
|
169
|
+
double("response", :body => {}, :code => 404)
|
|
170
|
+
}
|
|
171
|
+
[true, false].each do |legacy_template|
|
|
172
|
+
context "when legacy_template => #{legacy_template}" do
|
|
173
|
+
let(:base_options) { super().merge(:client_settings => {:legacy_template => legacy_template}) }
|
|
174
|
+
subject { described_class.new(base_options) }
|
|
175
|
+
endpoint = legacy_template ? "_template" : "_index_template"
|
|
176
|
+
it "should call template_endpoint #{endpoint}" do
|
|
177
|
+
expect(subject.pool).to receive(:head).with("/#{endpoint}/#{template_name}").and_return(get_response)
|
|
178
|
+
expect(subject.pool).to receive(:put).with("/#{endpoint}/#{template_name}", nil, anything).and_return(get_response)
|
|
179
|
+
subject.template_install(template_name, template)
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
164
185
|
describe "join_bulk_responses" do
|
|
165
186
|
subject { described_class.new(base_options) }
|
|
166
187
|
|
|
@@ -226,8 +247,8 @@ describe LogStash::Outputs::OpenSearch::HttpClient do
|
|
|
226
247
|
end
|
|
227
248
|
end
|
|
228
249
|
|
|
229
|
-
context "if a message is over
|
|
230
|
-
let(:target_bulk_bytes) {
|
|
250
|
+
context "if a message is over target_bulk_bytes" do
|
|
251
|
+
let(:target_bulk_bytes) { subject.target_bulk_bytes }
|
|
231
252
|
let(:message) { "a" * (target_bulk_bytes + 1) }
|
|
232
253
|
|
|
233
254
|
it "should be handled properly" do
|
|
@@ -256,8 +277,8 @@ describe LogStash::Outputs::OpenSearch::HttpClient do
|
|
|
256
277
|
s = subject.send(:bulk, actions)
|
|
257
278
|
end
|
|
258
279
|
|
|
259
|
-
context "if one exceeds
|
|
260
|
-
let(:target_bulk_bytes) {
|
|
280
|
+
context "if one exceeds target_bulk_bytes" do
|
|
281
|
+
let(:target_bulk_bytes) { subject.target_bulk_bytes }
|
|
261
282
|
let(:message1) { "a" * (target_bulk_bytes + 1) }
|
|
262
283
|
it "executes two bulk_send operations" do
|
|
263
284
|
allow(subject).to receive(:join_bulk_responses)
|
|
@@ -13,9 +13,16 @@ require "logstash/outputs/opensearch/template_manager"
|
|
|
13
13
|
describe LogStash::Outputs::OpenSearch::TemplateManager do
|
|
14
14
|
|
|
15
15
|
describe ".default_template_path" do
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
[7, 1, 2].each do |major_version|
|
|
17
|
+
[:disabled, :v1, :v8].each do |ecs_ver|
|
|
18
|
+
[true, false].each do |legacy_template|
|
|
19
|
+
context "when ECS is #{ecs_ver} with OpenSearch #{major_version}.x legacy_template:#{legacy_template}" do
|
|
20
|
+
suffix = legacy_template ? "" : "_index"
|
|
21
|
+
it 'resolves' do
|
|
22
|
+
expect(described_class.default_template_path(major_version, ecs_ver, legacy_template)).to end_with("/templates/ecs-#{ecs_ver}/#{major_version}x#{suffix}.json")
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
19
26
|
end
|
|
20
27
|
end
|
|
21
28
|
end
|
|
@@ -33,4 +40,4 @@ describe LogStash::Outputs::OpenSearch::TemplateManager do
|
|
|
33
40
|
end
|
|
34
41
|
end
|
|
35
42
|
end
|
|
36
|
-
end
|
|
43
|
+
end
|
|
@@ -12,6 +12,7 @@ require "base64"
|
|
|
12
12
|
require "flores/random"
|
|
13
13
|
require 'concurrent/atomic/count_down_latch'
|
|
14
14
|
require "logstash/outputs/opensearch"
|
|
15
|
+
require 'logstash/plugin_mixins/ecs_compatibility_support/spec_helper'
|
|
15
16
|
|
|
16
17
|
describe LogStash::Outputs::OpenSearch do
|
|
17
18
|
subject(:opensearch_output_instance) { described_class.new(options) }
|
|
@@ -325,7 +326,7 @@ describe LogStash::Outputs::OpenSearch do
|
|
|
325
326
|
end
|
|
326
327
|
|
|
327
328
|
context '413 errors' do
|
|
328
|
-
let(:payload_size) {
|
|
329
|
+
let(:payload_size) { subject.client.target_bulk_bytes + 1024 }
|
|
329
330
|
let(:event) { ::LogStash::Event.new("message" => ("a" * payload_size ) ) }
|
|
330
331
|
|
|
331
332
|
let(:logger_stub) { double("logger").as_null_object }
|
|
@@ -357,7 +358,7 @@ describe LogStash::Outputs::OpenSearch do
|
|
|
357
358
|
|
|
358
359
|
expect(logger_stub).to have_received(:warn)
|
|
359
360
|
.with(a_string_matching(/413 Payload Too Large/),
|
|
360
|
-
hash_including(:action_count => 1, :content_length => a_value >
|
|
361
|
+
hash_including(:action_count => 1, :content_length => a_value > subject.client.target_bulk_bytes))
|
|
361
362
|
end
|
|
362
363
|
end
|
|
363
364
|
|
|
@@ -784,6 +785,21 @@ describe LogStash::Outputs::OpenSearch do
|
|
|
784
785
|
end
|
|
785
786
|
end
|
|
786
787
|
|
|
788
|
+
describe 'ecs_compatibility support', :ecs_compatibility_support do
|
|
789
|
+
[:disabled, :v1, :v8].each do |ecs_compatibility|
|
|
790
|
+
context "when `ecs_compatibility => #{ecs_compatibility}`" do
|
|
791
|
+
let(:options) { Hash.new }
|
|
792
|
+
subject(:output) { described_class.new(options.merge("ecs_compatibility" => "#{ecs_compatibility}")) }
|
|
793
|
+
context 'when registered' do
|
|
794
|
+
before(:each) { output.register }
|
|
795
|
+
it 'has the correct effective ECS compatibility setting' do
|
|
796
|
+
expect(output.ecs_compatibility).to eq(ecs_compatibility)
|
|
797
|
+
end
|
|
798
|
+
end
|
|
799
|
+
end
|
|
800
|
+
end
|
|
801
|
+
end
|
|
802
|
+
|
|
787
803
|
@private
|
|
788
804
|
|
|
789
805
|
def stub_manticore_client!(manticore_double = nil)
|
data.tar.gz.sig
CHANGED
|
Binary file
|