logstash-output-elasticsearch 6.1.0-java → 6.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f8df743661ac7aed2fb52dddaf677ce1705a0612
4
- data.tar.gz: 10bcb6b88076eafe00aea65c6d9e01d4d3fd8648
3
+ metadata.gz: 8d8fa5b44c2bf968c6460d25f27caf4f1b814467
4
+ data.tar.gz: 3225315b016f698fcb2a29f48f180d79f8ae15ab
5
5
  SHA512:
6
- metadata.gz: 605c1958b1b4d22e51132e71932174c86c3d1696b80a7f35e07ec147301072dec9befeb64fae5bd240cff7c38f791fa3ede8bfa8a4781cd705a956d4a6e5b6b4
7
- data.tar.gz: 69fae6a096cfa00b41037800d7a09737d0fec46b9722796f746d2aa1074be49147b3d2e8f2ec9ca39fdabf35130a2d603f8f512f771bceb09b1afdc1ffa6d0e8
6
+ metadata.gz: 55d2b2af8b3e15a814cfc2e592251488eadb8325a6b075976af4199f98df79b0e8d70ba3c7e27352a6f69c7e741255fd3b46b523efbbb1cd6c32a3f4e07847bb
7
+ data.tar.gz: 18268aa5143178e89467b90f81c278cd449f49ba8b5e03d2a00ec7a4e3f5a05885ccba70252de25c4ebfc3e8137e9e28b3792a6af71b3de4cbf4665d0a642308
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ ## 6.2.0
2
+ - Add version number / version conflict support
3
+
1
4
  ## 6.1.0
2
5
  - Add option to use an absolute healthcheck path
3
6
 
@@ -6,6 +6,13 @@ module LogStash; module Outputs; class ElasticSearch;
6
6
 
7
7
  RETRYABLE_CODES = [429, 503]
8
8
  SUCCESS_CODES = [200, 201]
9
+ CONFLICT_CODE = 409
10
+
11
+ # When you use external versioning, you are communicating that you want
12
+ # to ignore conflicts. More obviously, since an external version is a
13
+ # constant part of the incoming document, we should not retry, as retrying
14
+ # will never succeed.
15
+ VERSION_TYPES_PERMITTING_CONFLICT = ["external", "external_gt", "external_gte"]
9
16
 
10
17
  def register
11
18
  @stopping = Concurrent::AtomicBoolean.new(false)
@@ -120,9 +127,13 @@ module LogStash; module Outputs; class ElasticSearch;
120
127
  status = action_props["status"]
121
128
  failure = action_props["error"]
122
129
  action = actions[idx]
130
+ action_params = action[1]
123
131
 
124
132
  if SUCCESS_CODES.include?(status)
125
133
  next
134
+ elsif CONFLICT_CODE == status && VERSION_TYPES_PERMITTING_CONFLICT.include?(action_params[:version_type])
135
+ @logger.debug "Ignoring external version conflict: status[#{status}] failure[#{failure}] version[#{action_params[:version]}] version_type[#{action_params[:version_type]}]"
136
+ next
126
137
  elsif RETRYABLE_CODES.include?(status)
127
138
  @logger.info "retrying failed action with response code: #{status} (#{failure})"
128
139
  actions_to_retry << action
@@ -159,6 +170,14 @@ module LogStash; module Outputs; class ElasticSearch;
159
170
  params[:_retry_on_conflict] = @retry_on_conflict
160
171
  end
161
172
 
173
+ if @version
174
+ params[:version] = event.sprintf(@version)
175
+ end
176
+
177
+ if @version_type
178
+ params[:version_type] = event.sprintf(@version_type)
179
+ end
180
+
162
181
  params
163
182
  end
164
183
 
@@ -61,6 +61,15 @@ module LogStash; module Outputs; class ElasticSearch
61
61
  # Elasticsearch with the same ID.
62
62
  mod.config :document_id, :validate => :string
63
63
 
64
+ # The version to use for indexing. Use sprintf syntax like `%{my_version}` to use a field value here.
65
+ # See https://www.elastic.co/blog/elasticsearch-versioning-support.
66
+ mod.config :version, :validate => :string
67
+
68
+ # The version_type to use for indexing.
69
+ # See https://www.elastic.co/blog/elasticsearch-versioning-support.
70
+ # See also https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html#_version_types
71
+ mod.config :version_type, :validate => ["internal", 'external', "external_gt", "external_gte", "force"]
72
+
64
73
  # A routing override to be applied to all processed events.
65
74
  # This can be dynamic using the `%{foo}` syntax.
66
75
  mod.config :routing, :validate => :string
@@ -36,6 +36,20 @@ module LogStash; module Outputs; class ElasticSearch;
36
36
  client_settings.merge! setup_ssl(logger, params)
37
37
  common_options.merge! setup_basic_auth(logger, params)
38
38
 
39
+ external_version_types = ["external", "external_gt", "external_gte"]
40
+ # External Version validation
41
+ raise(
42
+ LogStash::ConfigurationError,
43
+ "External versioning requires the presence of a version number."
44
+ ) if external_version_types.include?(params.fetch('version_type', '')) and params.fetch("version", nil) == nil
45
+
46
+
47
+ # Create API setup
48
+ raise(
49
+ LogStash::ConfigurationError,
50
+ "External versioning is not supported by the create action."
51
+ ) if params['action'] == 'create' and external_version_types.include?(params.fetch('version_type', ''))
52
+
39
53
  # Update API setup
40
54
  raise( LogStash::ConfigurationError,
41
55
  "doc_as_upsert and scripted_upsert are mutually exclusive."
@@ -46,6 +60,11 @@ module LogStash; module Outputs; class ElasticSearch;
46
60
  "Specifying action => 'update' needs a document_id."
47
61
  ) if params['action'] == 'update' and params.fetch('document_id', '') == ''
48
62
 
63
+ raise(
64
+ LogStash::ConfigurationError,
65
+ "External versioning is not supported by the update action. See https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-update.html."
66
+ ) if params['action'] == 'update' and external_version_types.include?(params.fetch('version_type', ''))
67
+
49
68
  # Update API setup
50
69
  update_options = {
51
70
  :doc_as_upsert => params["doc_as_upsert"],
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
 
3
3
  s.name = 'logstash-output-elasticsearch'
4
- s.version = '6.1.0'
4
+ s.version = '6.2.0'
5
5
  s.licenses = ['apache-2.0']
6
6
  s.summary = "Logstash Output to Elasticsearch"
7
7
  s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
25
25
  s.add_development_dependency 'ftw', '~> 0.0.42'
26
26
  s.add_development_dependency 'addressable', "~> 2.3.0" # used by FTW. V 2.5.0 is ruby 2.0 only.
27
27
  s.add_development_dependency 'logstash-codec-plain'
28
+ s.add_development_dependency 'json' # used by spec/unit/outputs/elasticsearch/http_client/pool_spec.rb
28
29
 
29
30
  if RUBY_PLATFORM == 'java'
30
31
  s.platform = RUBY_PLATFORM
@@ -3,7 +3,7 @@ require_relative "../../../spec/es_spec_helper"
3
3
  describe "client create actions", :integration => true do
4
4
  require "logstash/outputs/elasticsearch"
5
5
 
6
- def get_es_output(action, id)
6
+ def get_es_output(action, id, version=nil, version_type=nil)
7
7
  settings = {
8
8
  "manage_template" => true,
9
9
  "index" => "logstash-create",
@@ -12,6 +12,8 @@ describe "client create actions", :integration => true do
12
12
  "action" => action
13
13
  }
14
14
  settings['document_id'] = id
15
+ settings['version'] = version if version
16
+ settings['version_type'] = version_type if version_type
15
17
  LogStash::Outputs::ElasticSearch.new(settings)
16
18
  end
17
19
 
@@ -36,5 +38,30 @@ describe "client create actions", :integration => true do
36
38
  insist { r["hits"]["total"] } == 1
37
39
  end
38
40
  end
41
+
42
+ it "should allow default (internal) version" do
43
+ subject = get_es_output("create", "id123", 43)
44
+ subject.register
45
+ end
46
+
47
+ it "should allow internal version" do
48
+ subject = get_es_output("create", "id123", 43, "internal")
49
+ subject.register
50
+ end
51
+
52
+ it "should not allow external version" do
53
+ subject = get_es_output("create", "id123", 43, "external")
54
+ expect { subject.register }.to raise_error(LogStash::ConfigurationError)
55
+ end
56
+
57
+ it "should not allow external_gt version" do
58
+ subject = get_es_output("create", "id123", 43, "external_gt")
59
+ expect { subject.register }.to raise_error(LogStash::ConfigurationError)
60
+ end
61
+
62
+ it "should not allow external_gte version" do
63
+ subject = get_es_output("create", "id123", 43, "external_gte")
64
+ expect { subject.register }.to raise_error(LogStash::ConfigurationError)
65
+ end
39
66
  end
40
67
  end
@@ -0,0 +1,63 @@
1
+ require_relative "../../../spec/es_spec_helper"
2
+ require "logstash/outputs/elasticsearch"
3
+
4
+
5
+ describe "Versioned delete", :integration => true, :version_greater_than_equal_to_2x => true do
6
+ require "logstash/outputs/elasticsearch"
7
+
8
+ let(:es) { get_client }
9
+
10
+ before :each do
11
+ # Delete all templates first.
12
+ # Clean ES of data before we start.
13
+ es.indices.delete_template(:name => "*")
14
+ # This can fail if there are no indexes, ignore failure.
15
+ es.indices.delete(:index => "*") rescue nil
16
+ es.indices.refresh
17
+ end
18
+
19
+ context "when delete only" do
20
+ subject { LogStash::Outputs::ElasticSearch.new(settings) }
21
+
22
+ before do
23
+ subject.register
24
+ end
25
+
26
+ let(:settings) do
27
+ {
28
+ "manage_template" => true,
29
+ "index" => "logstash-delete",
30
+ "template_overwrite" => true,
31
+ "hosts" => get_host_port(),
32
+ "document_id" => "%{my_id}",
33
+ "version" => "%{my_version}",
34
+ "version_type" => "external",
35
+ "action" => "%{my_action}"
36
+ }
37
+ end
38
+
39
+ it "should ignore non-monotonic external version updates" do
40
+ id = "ev2"
41
+ subject.multi_receive([LogStash::Event.new("my_id" => id, "my_action" => "index", "message" => "foo", "my_version" => 99)])
42
+ r = es.get(:index => 'logstash-delete', :type => 'logs', :id => id, :refresh => true)
43
+ expect(r['_version']).to eq(99)
44
+ expect(r['_source']['message']).to eq('foo')
45
+
46
+ subject.multi_receive([LogStash::Event.new("my_id" => id, "my_action" => "delete", "message" => "foo", "my_version" => 98)])
47
+ r2 = es.get(:index => 'logstash-delete', :type => 'logs', :id => id, :refresh => true)
48
+ expect(r2['_version']).to eq(99)
49
+ expect(r2['_source']['message']).to eq('foo')
50
+ end
51
+
52
+ it "should commit monotonic external version updates" do
53
+ id = "ev3"
54
+ subject.multi_receive([LogStash::Event.new("my_id" => id, "my_action" => "index", "message" => "foo", "my_version" => 99)])
55
+ r = es.get(:index => 'logstash-delete', :type => 'logs', :id => id, :refresh => true)
56
+ expect(r['_version']).to eq(99)
57
+ expect(r['_source']['message']).to eq('foo')
58
+
59
+ subject.multi_receive([LogStash::Event.new("my_id" => id, "my_action" => "delete", "message" => "foo", "my_version" => 100)])
60
+ expect { es.get(:index => 'logstash-delete', :type => 'logs', :id => id, :refresh => true) }.to raise_error(Elasticsearch::Transport::Transport::Errors::NotFound)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,101 @@
1
+ require_relative "../../../spec/es_spec_helper"
2
+ require "logstash/outputs/elasticsearch"
3
+
4
+
5
+ describe "Versioned indexing", :integration => true, :version_greater_than_equal_to_2x => true do
6
+ require "logstash/outputs/elasticsearch"
7
+
8
+ let(:es) { get_client }
9
+
10
+ before :each do
11
+ # Delete all templates first.
12
+ # Clean ES of data before we start.
13
+ es.indices.delete_template(:name => "*")
14
+ # This can fail if there are no indexes, ignore failure.
15
+ es.indices.delete(:index => "*") rescue nil
16
+ es.indices.refresh
17
+ end
18
+
19
+ context "when index only" do
20
+ subject { LogStash::Outputs::ElasticSearch.new(settings) }
21
+
22
+ before do
23
+ subject.register
24
+ end
25
+
26
+ describe "unversioned output" do
27
+ let(:settings) do
28
+ {
29
+ "manage_template" => true,
30
+ "index" => "logstash-index",
31
+ "template_overwrite" => true,
32
+ "hosts" => get_host_port(),
33
+ "action" => "index",
34
+ "script_lang" => "groovy",
35
+ "document_id" => "%{my_id}"
36
+ }
37
+ end
38
+
39
+ it "should default to ES version" do
40
+ subject.multi_receive([LogStash::Event.new("my_id" => "123", "message" => "foo")])
41
+ r = es.get(:index => 'logstash-index', :type => 'logs', :id => "123", :refresh => true)
42
+ expect(r["_version"]).to eq(1)
43
+ expect(r["_source"]["message"]).to eq('foo')
44
+ subject.multi_receive([LogStash::Event.new("my_id" => "123", "message" => "foobar")])
45
+ r2 = es.get(:index => 'logstash-index', :type => 'logs', :id => "123", :refresh => true)
46
+ expect(r2["_version"]).to eq(2)
47
+ expect(r2["_source"]["message"]).to eq('foobar')
48
+ end
49
+ end
50
+
51
+ describe "versioned output" do
52
+ let(:settings) do
53
+ {
54
+ "manage_template" => true,
55
+ "index" => "logstash-index",
56
+ "template_overwrite" => true,
57
+ "hosts" => get_host_port(),
58
+ "action" => "index",
59
+ "script_lang" => "groovy",
60
+ "document_id" => "%{my_id}",
61
+ "version" => "%{my_version}",
62
+ "version_type" => "external",
63
+ }
64
+ end
65
+
66
+ it "should respect the external version" do
67
+ id = "ev1"
68
+ subject.multi_receive([LogStash::Event.new("my_id" => id, "my_version" => "99", "message" => "foo")])
69
+ r = es.get(:index => 'logstash-index', :type => 'logs', :id => id, :refresh => true)
70
+ expect(r["_version"]).to eq(99)
71
+ expect(r["_source"]["message"]).to eq('foo')
72
+ end
73
+
74
+ it "should ignore non-monotonic external version updates" do
75
+ id = "ev2"
76
+ subject.multi_receive([LogStash::Event.new("my_id" => id, "my_version" => "99", "message" => "foo")])
77
+ r = es.get(:index => 'logstash-index', :type => 'logs', :id => id, :refresh => true)
78
+ expect(r["_version"]).to eq(99)
79
+ expect(r["_source"]["message"]).to eq('foo')
80
+
81
+ subject.multi_receive([LogStash::Event.new("my_id" => id, "my_version" => "98", "message" => "foo")])
82
+ r2 = es.get(:index => 'logstash-index', :type => 'logs', :id => id, :refresh => true)
83
+ expect(r2["_version"]).to eq(99)
84
+ expect(r2["_source"]["message"]).to eq('foo')
85
+ end
86
+
87
+ it "should commit monotonic external version updates" do
88
+ id = "ev3"
89
+ subject.multi_receive([LogStash::Event.new("my_id" => id, "my_version" => "99", "message" => "foo")])
90
+ r = es.get(:index => 'logstash-index', :type => 'logs', :id => id, :refresh => true)
91
+ expect(r["_version"]).to eq(99)
92
+ expect(r["_source"]["message"]).to eq('foo')
93
+
94
+ subject.multi_receive([LogStash::Event.new("my_id" => id, "my_version" => "100", "message" => "foo")])
95
+ r2 = es.get(:index => 'logstash-index', :type => 'logs', :id => id, :refresh => true)
96
+ expect(r2["_version"]).to eq(100)
97
+ expect(r2["_source"]["message"]).to eq('foo')
98
+ end
99
+ end
100
+ end
101
+ end
@@ -62,6 +62,32 @@ describe "Update actions", :integration => true, :version_greater_than_equal_to_
62
62
  insist { r["_source"]["data"] } == 'updated message here'
63
63
  insist { r["_source"]["message"] } == 'foo'
64
64
  end
65
+
66
+ it "should allow default (internal) version" do
67
+ subject = get_es_output({ 'document_id' => "123", "version" => "99" })
68
+ subject.register
69
+ end
70
+
71
+ it "should allow internal version" do
72
+ subject = get_es_output({ 'document_id' => "123", "version" => "99", "version_type" => "internal" })
73
+ subject.register
74
+ end
75
+
76
+ it "should not allow external version" do
77
+ subject = get_es_output({ 'document_id' => "123", "version" => "99", "version_type" => "external" })
78
+ expect { subject.register }.to raise_error(LogStash::ConfigurationError)
79
+ end
80
+
81
+ it "should not allow external_gt version" do
82
+ subject = get_es_output({ 'document_id' => "123", "version" => "99", "version_type" => "external_gt" })
83
+ expect { subject.register }.to raise_error(LogStash::ConfigurationError)
84
+ end
85
+
86
+ it "should not allow external_gte version" do
87
+ subject = get_es_output({ 'document_id' => "123", "version" => "99", "version_type" => "external_gte" })
88
+ expect { subject.register }.to raise_error(LogStash::ConfigurationError)
89
+ end
90
+
65
91
  end
66
92
 
67
93
  context "when using script" do
@@ -154,6 +180,11 @@ describe "Update actions", :integration => true, :version_greater_than_equal_to_
154
180
  insist { r["_source"]["message"] } == 'sample message here'
155
181
  end
156
182
 
183
+ it "should fail on documents with event/doc as upsert at external version" do
184
+ subject = get_es_output({ 'document_id' => "456", 'doc_as_upsert' => true, 'version' => 999, "version_type" => "external" })
185
+ expect { subject.register }.to raise_error(LogStash::ConfigurationError)
186
+ end
187
+
157
188
  context "when using script" do
158
189
  it "should create new documents with upsert content" do
159
190
  subject = get_es_output({ 'document_id' => "456", 'script' => 'scripted_update', 'upsert' => '{"message": "upsert message"}', 'script_type' => 'file' })
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-output-elasticsearch
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.1.0
4
+ version: 6.2.0
5
5
  platform: java
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-12-27 00:00:00.000000000 Z
11
+ date: 2017-01-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -106,6 +106,20 @@ dependencies:
106
106
  - - ">="
107
107
  - !ruby/object:Gem::Version
108
108
  version: '0'
109
+ - !ruby/object:Gem::Dependency
110
+ requirement: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ name: json
116
+ prerelease: false
117
+ type: :development
118
+ version_requirements: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
109
123
  - !ruby/object:Gem::Dependency
110
124
  requirement: !ruby/object:Gem::Requirement
111
125
  requirements:
@@ -196,7 +210,9 @@ files:
196
210
  - spec/fixtures/scripts/scripted_update_nested.groovy
197
211
  - spec/fixtures/scripts/scripted_upsert.groovy
198
212
  - spec/integration/outputs/create_spec.rb
213
+ - spec/integration/outputs/delete_spec.rb
199
214
  - spec/integration/outputs/index_spec.rb
215
+ - spec/integration/outputs/index_version_spec.rb
200
216
  - spec/integration/outputs/parent_spec.rb
201
217
  - spec/integration/outputs/pipeline_spec.rb
202
218
  - spec/integration/outputs/retry_spec.rb
@@ -247,7 +263,9 @@ test_files:
247
263
  - spec/fixtures/scripts/scripted_update_nested.groovy
248
264
  - spec/fixtures/scripts/scripted_upsert.groovy
249
265
  - spec/integration/outputs/create_spec.rb
266
+ - spec/integration/outputs/delete_spec.rb
250
267
  - spec/integration/outputs/index_spec.rb
268
+ - spec/integration/outputs/index_version_spec.rb
251
269
  - spec/integration/outputs/parent_spec.rb
252
270
  - spec/integration/outputs/pipeline_spec.rb
253
271
  - spec/integration/outputs/retry_spec.rb