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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/COMPATIBILITY.md +27 -0
- data/CONTRIBUTING.md +27 -5
- data/DEVELOPER_GUIDE.md +16 -7
- data/Gemfile +1 -1
- data/MAINTAINERS.md +3 -0
- data/NOTICE +9 -2
- data/README.md +75 -5
- data/lib/logstash/outputs/opensearch/http_client/manticore_adapter.rb +101 -4
- data/lib/logstash/outputs/opensearch/http_client/pool.rb +3 -16
- data/lib/logstash/outputs/opensearch/http_client.rb +12 -23
- data/lib/logstash/outputs/opensearch/http_client_builder.rb +5 -2
- data/lib/logstash/outputs/opensearch/templates/ecs-disabled/2x.json +44 -0
- data/lib/logstash/outputs/opensearch/templates/ecs-v8/1x.json +5252 -0
- data/lib/logstash/outputs/opensearch/templates/ecs-v8/2x.json +5252 -0
- data/lib/logstash/outputs/opensearch/templates/ecs-v8/7x.json +5252 -0
- data/lib/logstash/outputs/opensearch.rb +4 -5
- data/lib/logstash/plugin_mixins/opensearch/api_configs.rb +26 -0
- data/lib/logstash/plugin_mixins/opensearch/common.rb +2 -2
- data/logstash-output-opensearch.gemspec +20 -4
- data/spec/integration/outputs/compressed_indexing_spec.rb +11 -5
- 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 +54 -12
- data/spec/integration/outputs/index_version_spec.rb +11 -11
- data/spec/integration/outputs/ingest_pipeline_spec.rb +3 -4
- 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 +2 -2
- 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 +74 -4
- data/spec/unit/outputs/opensearch/http_client/pool_spec.rb +4 -87
- data/spec/unit/outputs/opensearch/http_client_spec.rb +6 -5
- data/spec/unit/outputs/opensearch/template_manager_spec.rb +23 -4
- data/spec/unit/outputs/opensearch_spec.rb +18 -2
- data.tar.gz.sig +0 -0
- metadata +75 -19
- metadata.gz.sig +0 -0
- data/lib/logstash/outputs/opensearch/distribution_checker.rb +0 -44
- 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://
|
|
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
|
|
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
|
|
28
|
-
|
|
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.
|
|
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(:
|
|
37
|
-
let(:index_url) {"#{
|
|
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("#{
|
|
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
|
-
|
|
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", "
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(:
|
|
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
|
-
|
|
22
|
+
client.indices.delete_template(:name => "*")
|
|
23
23
|
# This can fail if there are no indexes, ignore failure.
|
|
24
|
-
|
|
25
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 {
|
|
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 "
|
|
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(:
|
|
67
|
-
let(:index_url) {"#{
|
|
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("#{
|
|
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
|
-
|
|
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 => {"
|
|
103
|
+
expected_manticore_opts = {:headers => {"content-type" => "application/json"}, :body => anything}
|
|
99
104
|
if secure
|
|
100
105
|
expected_manticore_opts = {
|
|
101
|
-
:headers => {"
|
|
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(:
|
|
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(:
|
|
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
|
-
|
|
21
|
+
client.indices.delete_template(:name => "*")
|
|
22
22
|
# This can fail if there are no indexes, ignore failure.
|
|
23
|
-
|
|
24
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 => {"
|
|
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)
|
|
@@ -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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
{"
|
|
28
|
+
{"content-type" => "application/json"}
|
|
29
29
|
}
|
|
30
30
|
subject { LogStash::Outputs::OpenSearch.new(config) }
|
|
31
31
|
|