logstash-output-elasticsearch 6.1.0-java → 6.2.0-java

Sign up to get free protection for your applications and to get access to all the features.
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