logstash-output-elasticsearch 12.1.3-java → 12.1.6-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
  SHA256:
3
- metadata.gz: 295ebf9ba0c0c79766056646cba92ea6f037d2adf61379a53c9f7d080de34c1d
4
- data.tar.gz: 26e45497d1b2e77894ebd0ccdd9b3f55492f18a2932ef938dabd95065007f37c
3
+ metadata.gz: 1cdbd34639c856955089e567feefe731b38ca8c6990207f5eb23bf4b82e7b655
4
+ data.tar.gz: 6f6faff70fc33714ae9ae49b44d046abcbf45d51cf3d986d03580d63f104d859
5
5
  SHA512:
6
- metadata.gz: 8c1afa9504cb9ec4a7e15aab9068456185cf54d2b1bd7b323c43462a721747a2aeb329ed68e0d3e519a7322554c155e1c32b4501ff854558c25bea3eed612c82
7
- data.tar.gz: 2c617369a30a0d485d510ad460e9b6a4e55b8d7265795e24129a6472c7d688de0ef9562238f7bda0621cad54277d65199e6826ce8f76f70b94e057e7671f237a
6
+ metadata.gz: c78e7bb0162c33b4ec4ae39ceb9a9fe16f16a8f3c3ef6cda426ceaf9adf2a5d415bea2398a1d2e20ec414dab258c3d95135666f3dbfffa532a455c3ffeb91f32
7
+ data.tar.gz: 620d9d85ab8425dffbdc89f8dfa45d5b65b741ab29aca914d6039ea9619e1706893a2b6dc4b7f301a3a631f4842ce1681c3cbb024352c6e31f0429b4118cee16
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## 12.1.6
2
+ - Fix serverless compatibility: nil params in pool requests and unsupported template settings [#1276](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/1276)
3
+
4
+ ## 12.1.5
5
+ - Support Elastic Cloud API keys in the `api_key` option, which now accepts an `id:api_key` pair, its base64-encoded form, or an `essu_` Cloud API key, and rejects an unrecognized format at startup [#1274](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/1274)
6
+
7
+ ## 12.1.4
8
+ - [Doc] Add note for index option [#1269](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/1269)
9
+
1
10
  ## 12.1.3
2
11
  - Improves the logging experience when DLQ used [#1253](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/1253)
3
12
 
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Logstash Plugin
2
2
 
3
- [![Unit Tests](https://github.com/logstash-plugins/logstash-output-elasticsearch/actions/workflows/tests.yml/badge.svg)](https://github.com/logstash-plugins/logstash-output-elasticsearch/actions/workflows/tests.yml)
3
+ [![Unit Tests](https://github.com/logstash-plugins/logstash-output-elasticsearch/actions/workflows/unit-tests.yml/badge.svg)](https://github.com/logstash-plugins/logstash-output-elasticsearch/actions/workflows/unit-tests.yml)
4
4
  [![Secure Integration Tests](https://github.com/logstash-plugins/logstash-output-elasticsearch/actions/workflows/secure-integration-tests.yml/badge.svg)](https://github.com/logstash-plugins/logstash-output-elasticsearch/actions/workflows/secure-integration-tests.yml)
5
5
  [![Integration Tests](https://github.com/logstash-plugins/logstash-output-elasticsearch/actions/workflows/integration-tests.yml/badge.svg)](https://github.com/logstash-plugins/logstash-output-elasticsearch/actions/workflows/integration-tests.yml)
6
6
 
data/docs/index.asciidoc CHANGED
@@ -467,8 +467,11 @@ For more details on actions, check out the {ref}/docs-bulk.html[Elasticsearch bu
467
467
  Authenticate using Elasticsearch API key.
468
468
  Note that this option also requires SSL/TLS, which can be enabled by supplying a <<plugins-{type}s-{plugin}-cloud_id>>, a list of HTTPS <<plugins-{type}s-{plugin}-hosts>>, or by setting <<plugins-{type}s-{plugin}-ssl_enabled,`ssl_enabled => true`>>.
469
469
 
470
- Format is `id:api_key` where `id` and `api_key` are as returned by the
471
- Elasticsearch {ref}/security-api-create-api-key.html[Create API key API].
470
+ The format is `id:api_key`, where `id` and `api_key` are as returned by the
471
+ Elasticsearch {ref}/security-api-create-api-key.html[Create API key API]. The
472
+ base64-encoded form of that pair is also accepted, as is an
473
+ https://www.elastic.co/docs/deploy-manage/api-keys/elastic-cloud-api-keys[Elastic Cloud API key]
474
+ (prefixed with `essu_`), which is used as-is.
472
475
 
473
476
  [id="plugins-{type}s-{plugin}-bulk_path"]
474
477
  ===== `bulk_path`
@@ -842,10 +845,15 @@ NOTE: `ilm_rollover_alias` does NOT support dynamic variable substitution as
842
845
  The indexing target to write events to.
843
846
  Can point to an {ref}/index-mgmt.html[index], {ref}/aliases.html[alias], or {ref}/data-streams.html[data stream].
844
847
  This can be dynamic using the `%{foo}` syntax.
848
+
849
+ NOTE: When using dynamic syntax, verify that the resolved index names align with your cluster index templates and Index Lifecycle Management (ILM) configuration.
850
+
851
+ WARNING: Date math (e.g. `%{+yyyy.MM.dd}`) is not recommended for use with aliases or data streams.
852
+
845
853
  The default value will partition your indices by day so you can more easily
846
854
  delete old data or only search specific date ranges.
847
855
  Indexes may not contain uppercase characters.
848
- For weekly indexes ISO 8601 format is recommended, eg. logstash-%{+xxxx.ww}.
856
+ For weekly indexes ISO 8601 format is recommended, eg. `logstash-%{+xxxx.ww}`.
849
857
  Logstash uses
850
858
  http://www.joda.org/joda-time/apidocs/org/joda/time/format/DateTimeFormat.html[Joda
851
859
  formats] and the `@timestamp` field of each event is being used as source for the date.
@@ -350,6 +350,7 @@ module LogStash; module Outputs; class ElasticSearch; class HttpClient;
350
350
  end
351
351
 
352
352
  def perform_request_to_url(url, method, path, params={}, body=nil)
353
+ params ||= {}
353
354
  params[:headers] = DEFAULT_EAV_HEADER.merge(params[:headers] || {}) if serverless?
354
355
  @adapter.perform_request(url, method, path, params, body)
355
356
  end
@@ -433,7 +433,7 @@ module LogStash; module Outputs; class ElasticSearch;
433
433
  def template_put(template_endpoint, name, template)
434
434
  path = "#{template_endpoint}/#{name}"
435
435
  logger.info("Installing Elasticsearch template", name: name)
436
- @pool.put(path, nil, LogStash::Json.dump(template))
436
+ @pool.put(path, {}, LogStash::Json.dump(template))
437
437
  rescue ::LogStash::Outputs::ElasticSearch::HttpClient::Pool::BadResponseCodeError => e
438
438
  raise e unless e.response_code == 404
439
439
  end
@@ -447,7 +447,7 @@ module LogStash; module Outputs; class ElasticSearch;
447
447
 
448
448
  # Create a new rollover alias
449
449
  def rollover_alias_put(alias_name, alias_definition)
450
- @pool.put(CGI::escape(alias_name), nil, LogStash::Json.dump(alias_definition))
450
+ @pool.put(CGI::escape(alias_name), {}, LogStash::Json.dump(alias_definition))
451
451
  logger.info("Created rollover alias", name: alias_name)
452
452
  # If the rollover alias already exists, ignore the error that comes back from Elasticsearch
453
453
  rescue ::LogStash::Outputs::ElasticSearch::HttpClient::Pool::BadResponseCodeError => e
@@ -473,7 +473,7 @@ module LogStash; module Outputs; class ElasticSearch;
473
473
  def ilm_policy_put(name, policy)
474
474
  path = "_ilm/policy/#{name}"
475
475
  logger.info("Installing ILM policy #{policy}", name: name)
476
- @pool.put(path, nil, LogStash::Json.dump(policy))
476
+ @pool.put(path, {}, LogStash::Json.dump(policy))
477
477
  end
478
478
 
479
479
 
@@ -190,8 +190,7 @@ module LogStash; module Outputs; class ElasticSearch;
190
190
 
191
191
  return {} unless (api_key&.value)
192
192
 
193
- value = is_base64?(api_key.value) ? api_key.value : Base64.strict_encode64(api_key.value)
194
-
193
+ value = resolve_api_key(api_key.value)
195
194
  { "Authorization" => "ApiKey #{value}" }
196
195
  end
197
196
 
@@ -212,6 +211,28 @@ module LogStash; module Outputs; class ElasticSearch;
212
211
  url.match?(/\?[^\s#]+/) ? '&' : '?'
213
212
  end
214
213
 
214
+ # Resolves the `api_key` value into the credential used in the
215
+ # `Authorization: ApiKey` header. An already base64-encoded key and an
216
+ # Elastic Cloud API key are used as-is; a raw `id:api_key` pair is
217
+ # base64-encoded. An unrecognized value is rejected so a malformed key
218
+ # surfaces at startup rather than as a later authentication failure.
219
+ def resolve_api_key(key_value)
220
+ if is_base64?(key_value) || cloud_api_key?(key_value)
221
+ key_value
222
+ elsif key_value.match?(/\A[^:]+:[^:]+\z/)
223
+ Base64.strict_encode64(key_value)
224
+ else
225
+ raise LogStash::ConfigurationError, "Invalid api_key format. Expected a base64-encoded key, an 'id:api_key' pair, or a Cloud API key (essu_ prefix)."
226
+ end
227
+ end
228
+
229
+ # Elastic Cloud API keys (such as the unified Serverless keys) are opaque
230
+ # tokens prefixed with `essu_` that Elasticsearch accepts verbatim in the
231
+ # `Authorization: ApiKey` header, with no base64 encoding.
232
+ def cloud_api_key?(string)
233
+ string.match?(/\Aessu_.+/)
234
+ end
235
+
215
236
  def is_base64?(string)
216
237
  begin
217
238
  string == Base64.strict_encode64(Base64.strict_decode64(string))
@@ -28,6 +28,7 @@ module LogStash; module Outputs; class ElasticSearch
28
28
  end
29
29
 
30
30
  add_ilm_settings_to_template(plugin, template) if plugin.ilm_in_use?
31
+ strip_serverless_incompatible_settings(template) if plugin.serverless?
31
32
  plugin.logger.debug("Attempting to install template", template: template)
32
33
  install(plugin.client, template_endpoint(plugin), template_name(plugin), template, plugin.template_overwrite)
33
34
  end
@@ -129,5 +130,19 @@ module LogStash; module Outputs; class ElasticSearch
129
130
  end
130
131
  end
131
132
 
133
+ SERVERLESS_INCOMPATIBLE_SETTINGS = %w[
134
+ number_of_shards
135
+ index.number_of_shards
136
+ number_of_replicas
137
+ index.number_of_replicas
138
+ ].freeze
139
+
140
+ def self.strip_serverless_incompatible_settings(template)
141
+ settings = template.dig('template', 'settings') || template['settings']
142
+ return unless settings
143
+
144
+ SERVERLESS_INCOMPATIBLE_SETTINGS.each { |s| settings.delete(s) }
145
+ end
146
+
132
147
  end
133
148
  end end end
@@ -16,7 +16,8 @@ module LogStash; module PluginMixins; module ElasticSearch
16
16
  :password => { :validate => :password },
17
17
 
18
18
  # Authenticate using Elasticsearch API key.
19
- # format is id:api_key (as returned by https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html[Create API key])
19
+ # Format is either the `id:api_key` pair (as returned by https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html[Create API key]),
20
+ # its base64-encoded form, or an https://www.elastic.co/docs/deploy-manage/api-keys/elastic-cloud-api-keys[Elastic Cloud API key] (prefixed with `essu_`) can be used.
20
21
  :api_key => { :validate => :password },
21
22
 
22
23
  # Cloud authentication string ("<username>:<password>" format) is an alternative for the `user`/`password` configuration.
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'logstash-output-elasticsearch'
3
- s.version = '12.1.3'
3
+ s.version = ::File.read('version').split("\n").first
4
4
  s.licenses = ['apache-2.0']
5
5
  s.summary = "Stores logs in Elasticsearch"
6
6
  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"
@@ -12,7 +12,7 @@ Gem::Specification.new do |s|
12
12
  s.platform = RUBY_PLATFORM
13
13
 
14
14
  # Files
15
- s.files = Dir["lib/**/*","spec/**/*","*.gemspec","*.md","CONTRIBUTORS","Gemfile","LICENSE","NOTICE.TXT", "vendor/jar-dependencies/**/*.jar", "vendor/jar-dependencies/**/*.rb", "VERSION", "docs/**/*"]
15
+ s.files = Dir["lib/**/*","spec/**/*","*.gemspec","*.md","CONTRIBUTORS","Gemfile","LICENSE","NOTICE.TXT", "vendor/jar-dependencies/**/*.jar", "vendor/jar-dependencies/**/*.rb", "VERSION", "version", "docs/**/*"]
16
16
 
17
17
  # Tests
18
18
  s.test_files = s.files.grep(%r{^(test|spec|features)/})
@@ -62,6 +62,40 @@ describe LogStash::Outputs::ElasticSearch::HttpClientBuilder do
62
62
  expect(api_key_header["Authorization"]).to eql(expected)
63
63
  end
64
64
  end
65
+
66
+ context "when api-key is an Elastic Cloud API key (essu_ prefix)" do
67
+ # The suffix is intentionally not canonical base64: a Cloud key is opaque
68
+ # and must be forwarded verbatim regardless of its payload encoding.
69
+ let(:api_key) { "essu_VFZGblZreFhTekJ4ZDB4M2NHUnZRMEU2YzNWd1pYSnpaV055WlhRPQ==AAAAAAAA" }
70
+ let(:api_key_secured) do
71
+ secured = double("api_key")
72
+ allow(secured).to receive(:value).and_return(api_key)
73
+ secured
74
+ end
75
+ let(:options) { { "api_key" => api_key_secured } }
76
+ let(:logger) { double("logger") }
77
+ let(:api_key_header) { klass.setup_api_key(logger, options) }
78
+
79
+ it "returns the cloud api-key header verbatim without re-encoding" do
80
+ expected = "ApiKey #{api_key}"
81
+ expect(api_key_header["Authorization"]).to eql(expected)
82
+ end
83
+ end
84
+
85
+ context "when api-key has an unrecognized format" do
86
+ let(:api_key) { "not-a-valid-key" }
87
+ let(:api_key_secured) do
88
+ secured = double("api_key")
89
+ allow(secured).to receive(:value).and_return(api_key)
90
+ secured
91
+ end
92
+ let(:options) { { "api_key" => api_key_secured } }
93
+ let(:logger) { double("logger") }
94
+
95
+ it "raises a configuration error" do
96
+ expect { klass.setup_api_key(logger, options) }.to raise_error(LogStash::ConfigurationError, /Invalid api_key format/)
97
+ end
98
+ end
65
99
  end
66
100
 
67
101
  describe "customizing action paths" do
@@ -181,4 +181,75 @@ describe LogStash::Outputs::ElasticSearch::TemplateManager do
181
181
 
182
182
  end
183
183
  end
184
+
185
+ describe ".strip_serverless_incompatible_settings" do
186
+ context "with composable template (template.settings)" do
187
+ let(:template) do
188
+ {
189
+ "template" => {
190
+ "settings" => {
191
+ "index.refresh_interval" => "5s",
192
+ "number_of_shards" => 1,
193
+ "number_of_replicas" => 0
194
+ }
195
+ }
196
+ }
197
+ end
198
+
199
+ it "removes number_of_shards and number_of_replicas" do
200
+ described_class.strip_serverless_incompatible_settings(template)
201
+ expect(template["template"]["settings"]).not_to have_key("number_of_shards")
202
+ expect(template["template"]["settings"]).not_to have_key("number_of_replicas")
203
+ end
204
+
205
+ it "preserves compatible settings" do
206
+ described_class.strip_serverless_incompatible_settings(template)
207
+ expect(template["template"]["settings"]["index.refresh_interval"]).to eq("5s")
208
+ end
209
+ end
210
+
211
+ context "with index-prefixed setting keys" do
212
+ let(:template) do
213
+ {
214
+ "template" => {
215
+ "settings" => {
216
+ "index.number_of_shards" => 1,
217
+ "index.number_of_replicas" => 0
218
+ }
219
+ }
220
+ }
221
+ end
222
+
223
+ it "removes index-prefixed variants" do
224
+ described_class.strip_serverless_incompatible_settings(template)
225
+ expect(template["template"]["settings"]).not_to have_key("index.number_of_shards")
226
+ expect(template["template"]["settings"]).not_to have_key("index.number_of_replicas")
227
+ end
228
+ end
229
+
230
+ context "with legacy template (top-level settings)" do
231
+ let(:template) do
232
+ {
233
+ "settings" => {
234
+ "index.refresh_interval" => "5s",
235
+ "number_of_shards" => 1
236
+ }
237
+ }
238
+ end
239
+
240
+ it "removes incompatible settings from top-level settings" do
241
+ described_class.strip_serverless_incompatible_settings(template)
242
+ expect(template["settings"]).not_to have_key("number_of_shards")
243
+ expect(template["settings"]["index.refresh_interval"]).to eq("5s")
244
+ end
245
+ end
246
+
247
+ context "with no settings" do
248
+ let(:template) { { "mappings" => {} } }
249
+
250
+ it "does not raise" do
251
+ expect { described_class.strip_serverless_incompatible_settings(template) }.not_to raise_error
252
+ end
253
+ end
254
+ end
184
255
  end
data/version ADDED
@@ -0,0 +1 @@
1
+ 12.1.6
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-output-elasticsearch
3
3
  version: !ruby/object:Gem::Version
4
- version: 12.1.3
4
+ version: 12.1.6
5
5
  platform: java
6
6
  authors:
7
7
  - Elastic
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-04-17 00:00:00.000000000 Z
10
+ date: 2026-07-06 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: manticore
@@ -334,6 +334,7 @@ files:
334
334
  - spec/unit/outputs/elasticsearch_ssl_spec.rb
335
335
  - spec/unit/outputs/error_whitelist_spec.rb
336
336
  - spec/unit/outputs/license_check_spec.rb
337
+ - version
337
338
  homepage: https://www.elastic.co/guide/en/logstash/current/index.html
338
339
  licenses:
339
340
  - apache-2.0