fluent-plugin-opensearch 1.1.4 → 1.1.5

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: 578e5c63061d5f1cb3f3729dee4ea630564dc60d82f6b047c8e4b23830fdf16a
4
- data.tar.gz: a502d46eb5a3a59c5c4f65f9009623ff32fde1de4cfda7e181437a8720bdbda1
3
+ metadata.gz: d0a251b65daac387b7520c49475a881440181bbe44da46849d8bdee61b9a4374
4
+ data.tar.gz: ec313c1dba6a723a4c5fd4cf672abaf7e1be9785e29176c31f419b253949f539
5
5
  SHA512:
6
- metadata.gz: 77b3373041396440cf8debaea8fd2ab95b94df950cbfe6105f65d45cce7092a6f89bd019b38d4022051c651541d3d21918625ea1b9939f58108101eae90a027f
7
- data.tar.gz: 2e746cd797f5d24f08dbb386ea42b9bff506831c56f9f4b92dcf99dde321b9b613c7473cbad39bd1f6d338ae6dd094a87f838141306111ab49b5a76886346918
6
+ metadata.gz: 1e40ac1b0816b42fa6d84a3cfd72eb3219ce688a80e15e110670e32a6ee7dd97a20542dd6d056a443f92d173e16f3a29b614a249e64ba2babb18243d3ad4ba7f
7
+ data.tar.gz: 342f988468e7fb9a47ef2111e88a474b9d7a97d310b3112173e1ca7dc510dea3c1a0ddf6f0c7515c5769e389a01a68f761540576e0856f718e06e2e83ab0f712
@@ -5,7 +5,7 @@ about: Suggest an idea for this project
5
5
  ---
6
6
 
7
7
  (check apply)
8
- - [ ] read [the contribution guideline](https://github.com/uken/fluent-plugin-elasticsearch/blob/master/CONTRIBUTING.md)
8
+ - [ ] read [the contribution guideline](https://github.com/fluent/fluent-plugin-opensearch/blob/master/CONTRIBUTING.md)
9
9
 
10
10
  **Is your feature request related to a problem? Please describe.**
11
11
 
@@ -22,5 +22,6 @@ jobs:
22
22
  CI: true
23
23
  run: |
24
24
  gem install bundler rake
25
+ bundle config set path 'vendor/bundle'
25
26
  bundle install --jobs 4 --retry 3
26
27
  bundle exec rake test
data/History.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  ### [Unreleased]
4
4
 
5
+ ### 1.1.5
6
+ - Fix bundle installation error on GitHub Action (#143)
7
+ - Prevent AWS credentials refresh from stopping on exception (#142)
8
+ - Added a retry logic and a service availability check function for high availability. (#136)
9
+ - out\_opensearch\_data\_stream: Early return on empty body (#131)
10
+ - Docs/cleanup issue templates (#119)
11
+ - pin dependency opensearch-ruby to 3.0.1 (#116)
12
+
5
13
  ### 1.1.4
6
14
  - test: remove minitest to correct misjudge of the framework by flexmock (#114)
7
15
  - Add logic to write method of out_opensearch_data_stream (#109)
@@ -24,6 +24,16 @@
24
24
  + [docinfo_fields](#docinfo_fields)
25
25
  + [docinfo_target](#docinfo_target)
26
26
  + [docinfo](#docinfo)
27
+ + [check_connection](#check_connection)
28
+ + [retry_forever](#retry_forever)
29
+ + [retry_timeout](#retry_timeout)
30
+ + [retry_max_times](#retry_max_times)
31
+ + [retry_type](#retry_type)
32
+ + [retry_wait](#retry_wait)
33
+ + [retry_exponential_backoff_base](#retry_exponential_backoff_base)
34
+ + [retry_max_interval](#retry_max_interval)
35
+ + [retry_randomize](#retry_randomize)
36
+
27
37
  * [Advanced Usage](#advanced-usage)
28
38
 
29
39
  ## Usage
@@ -274,6 +284,88 @@ This parameter specifies whether docinfo information including or not. The defau
274
284
  docinfo false
275
285
  ```
276
286
 
287
+ ### check_connection
288
+
289
+ The parameter for checking on connection availability with Elasticsearch or Opensearch hosts. The default value is `true`.
290
+
291
+ ```
292
+ check_connection true
293
+ ```
294
+ ### retry_forever
295
+
296
+ The parameter If true, plugin will ignore retry_timeout and retry_max_times options and retry forever. The default value is `true`.
297
+
298
+ ```
299
+ retry_forever true
300
+ ```
301
+
302
+ ### retry_timeout
303
+
304
+ The parameter maximum time (seconds) to retry again the failed try, until the plugin discards the retry.
305
+ If the next retry is going to exceed this time limit, the last retry will be made at exactly this time limit..
306
+ The default value is `72h`.
307
+ 72hours == 17 times with exponential backoff (not to change default behavior)
308
+
309
+ ```
310
+ retry_timeout 72 * 60 * 60
311
+ ```
312
+
313
+ ### retry_max_times
314
+
315
+ The parameter maximum number of times to retry the failed try. The default value is `5`
316
+
317
+ ```
318
+ retry_max_times 5
319
+ ```
320
+
321
+ ### retry_type
322
+
323
+ The parameter needs for how long need to wait (time in seconds) to retry again:
324
+ `exponential_backoff`: wait in seconds will become large exponentially per failure,
325
+ `periodic`: plugin will retry periodically with fixed intervals (configured via retry_wait). The default value is `:exponential_backoff`
326
+ Periodic -> fixed :retry_wait
327
+ Exponential backoff: k is number of retry times
328
+ c: constant factor, @retry_wait
329
+ b: base factor, @retry_exponential_backoff_base
330
+ k: times
331
+ total retry time: c + c * b^1 + (...) + c*b^k = c*b^(k+1) - 1
332
+
333
+ ```
334
+ retry_type exponential_backoff
335
+ ```
336
+
337
+ ### retry_wait
338
+
339
+ The parameter needs for wait in seconds before the next retry to again or constant factor of exponential backoff. The default value is `5`
340
+
341
+ ```
342
+ retry_wait 5
343
+ ```
344
+
345
+ ### retry_exponential_backoff_base
346
+
347
+ The parameter The base number of exponential backoff for retries. The default value is `2`
348
+
349
+ ```
350
+ retry_exponential_backoff_base 2
351
+ ```
352
+
353
+ ### retry_max_interval
354
+
355
+ The parameter maximum interval (seconds) for exponential backoff between retries while failing. The default value is `nil`
356
+
357
+ ```
358
+ retry_max_interval nil
359
+ ```
360
+
361
+ ### retry_randomize
362
+
363
+ The parameter If true, the plugin will retry after randomized interval not to do burst retries. The default value is `false`
364
+
365
+ ```
366
+ retry_randomize false
367
+ ```
368
+
277
369
  ## Advanced Usage
278
370
 
279
371
  OpenSearch Input plugin and OpenSearch output plugin can combine to transfer records into another cluster.
@@ -3,7 +3,7 @@ $:.push File.expand_path('../lib', __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = 'fluent-plugin-opensearch'
6
- s.version = '1.1.4'
6
+ s.version = '1.1.5'
7
7
  s.authors = ['Hiroshi Hatake']
8
8
  s.email = ['cosmo0920.wp@gmail.com']
9
9
  s.description = %q{Opensearch output plugin for Fluent event collector}
@@ -23,7 +23,7 @@ Gem::Specification.new do |s|
23
23
  s.required_ruby_version = Gem::Requirement.new(">= 2.3".freeze)
24
24
 
25
25
  s.add_runtime_dependency 'fluentd', '>= 0.14.22'
26
- s.add_runtime_dependency 'opensearch-ruby'
26
+ s.add_runtime_dependency 'opensearch-ruby', '>= 3.0.1'
27
27
  s.add_runtime_dependency "aws-sdk-core", "~> 3"
28
28
  s.add_runtime_dependency 'excon', '>= 0'
29
29
  s.add_runtime_dependency 'faraday', '>= 2.0.0'
@@ -32,7 +32,7 @@ Gem::Specification.new do |s|
32
32
 
33
33
  s.add_development_dependency 'rake', '>= 0'
34
34
  s.add_development_dependency 'webrick', '~> 1.7.0'
35
- s.add_development_dependency 'webmock', '~> 3'
35
+ s.add_development_dependency 'webmock', '~> 3.18.1'
36
36
  s.add_development_dependency 'test-unit', '~> 3.3.0'
37
37
  s.add_development_dependency 'minitest', '~> 5.8'
38
38
  s.add_development_dependency 'flexmock', '~> 2.0'
@@ -29,6 +29,7 @@ require 'opensearch'
29
29
  require 'faraday/excon'
30
30
  require 'fluent/log-ext'
31
31
  require 'fluent/plugin/input'
32
+ require 'fluent/plugin_helper'
32
33
  require_relative 'opensearch_constants'
33
34
 
34
35
  module Fluent::Plugin
@@ -39,7 +40,7 @@ module Fluent::Plugin
39
40
  DEFAULT_STORAGE_TYPE = 'local'
40
41
  METADATA = "@metadata".freeze
41
42
 
42
- helpers :timer, :thread
43
+ helpers :timer, :thread, :retry_state
43
44
 
44
45
  Fluent::Plugin.register_input('opensearch', self)
45
46
 
@@ -80,6 +81,23 @@ module Fluent::Plugin
80
81
  config_param :docinfo_fields, :array, :default => ['_index', '_type', '_id']
81
82
  config_param :docinfo_target, :string, :default => METADATA
82
83
  config_param :docinfo, :bool, :default => false
84
+ config_param :check_connection, :bool, :default => true
85
+ config_param :retry_forever, :bool, default: true, desc: 'If true, plugin will ignore retry_timeout and retry_max_times options and retry forever.'
86
+ config_param :retry_timeout, :time, default: 72 * 60 * 60, desc: 'The maximum seconds to retry'
87
+ # 72hours == 17 times with exponential backoff (not to change default behavior)
88
+ config_param :retry_max_times, :integer, default: 5, desc: 'The maximum number of times to retry'
89
+ # exponential backoff sequence will be initialized at the time of this threshold
90
+ config_param :retry_type, :enum, list: [:exponential_backoff, :periodic], default: :exponential_backoff
91
+ ### Periodic -> fixed :retry_wait
92
+ ### Exponential backoff: k is number of retry times
93
+ # c: constant factor, @retry_wait
94
+ # b: base factor, @retry_exponential_backoff_base
95
+ # k: times
96
+ # total retry time: c + c * b^1 + (...) + c*b^k = c*b^(k+1) - 1
97
+ config_param :retry_wait, :time, default: 5, desc: 'Seconds to wait before next retry , or constant factor of exponential backoff.'
98
+ config_param :retry_exponential_backoff_base, :float, default: 2, desc: 'The base number of exponential backoff for retries.'
99
+ config_param :retry_max_interval, :time, default: nil, desc: 'The maximum interval seconds for exponential backoff between retries while failing.'
100
+ config_param :retry_randomize, :bool, default: false, desc: 'If true, output plugin will retry after randomized interval not to do burst retries.'
83
101
 
84
102
  include Fluent::Plugin::OpenSearchConstants
85
103
 
@@ -92,6 +110,7 @@ module Fluent::Plugin
92
110
 
93
111
  @timestamp_parser = create_time_parser
94
112
  @backend_options = backend_options
113
+ @retry = nil
95
114
 
96
115
  raise Fluent::ConfigError, "`password` must be present if `user` is present" if @user && @password.nil?
97
116
 
@@ -138,6 +157,15 @@ module Fluent::Plugin
138
157
  raise Fluent::ConfigError, "You must install #{@http_backend} gem. Exception: #{ex}"
139
158
  end
140
159
 
160
+ def retry_state(randomize)
161
+ retry_state_create(
162
+ :input_retries, @retry_type, @retry_wait, @retry_timeout,
163
+ forever: @retry_forever, max_steps: @retry_max_times,
164
+ max_interval: @retry_max_interval, backoff_base: @retry_exponential_backoff_base,
165
+ randomize: randomize
166
+ )
167
+ end
168
+
141
169
  def get_escaped_userinfo(host_str)
142
170
  if m = host_str.match(/(?<scheme>.*)%{(?<user>.*)}:%{(?<password>.*)}(?<path>@.*)/)
143
171
  m["scheme"] +
@@ -176,12 +204,29 @@ module Fluent::Plugin
176
204
  host.merge!(user: @user, password: @password) if !host[:user] && @user
177
205
  host.merge!(path: @path) if !host[:path] && @path
178
206
  end
179
-
207
+ live_hosts = @check_connection ? hosts.select { |host| reachable_host?(host) } : hosts
180
208
  {
181
- hosts: hosts
209
+ hosts: live_hosts
182
210
  }
183
211
  end
184
212
 
213
+ def reachable_host?(host)
214
+ client = OpenSearch::Client.new(
215
+ host: ["#{host[:scheme]}://#{host[:host]}:#{host[:port]}"],
216
+ user: host[:user],
217
+ password: host[:password],
218
+ reload_connections: @reload_connections,
219
+ request_timeout: @request_timeout,
220
+ resurrect_after: @resurrect_after,
221
+ reload_on_failure: @reload_on_failure,
222
+ transport_options: { ssl: { verify: @ssl_verify, ca_file: @ca_file, version: @ssl_version } }
223
+ )
224
+ client.ping
225
+ rescue => e
226
+ log.warn "Failed to connect to #{host[:scheme]}://#{host[:host]}:#{host[:port]}: #{e.message}"
227
+ false
228
+ end
229
+
185
230
  def emit_error_label_event(&block)
186
231
  # If `emit_error_label_event` is specified as false, error event emittions are not occurred.
187
232
  if emit_error_label_event
@@ -292,6 +337,25 @@ module Fluent::Plugin
292
337
  return true
293
338
  end
294
339
 
340
+ def update_retry_state(error=nil)
341
+ if error
342
+ unless @retry
343
+ @retry = retry_state(@retry_randomize)
344
+ end
345
+ @retry.step
346
+ #Raise error if the retry limit has been reached
347
+ raise "Hit limit for retries. retry_times: #{@retry.steps}, error: #{error.message}" if @retry.limit?
348
+ #Retry if the limit hasn't been reached
349
+ log.warn("failed to connect or search.", retry_times: @retry.steps, next_retry_time: @retry.next_time.round, error: error.message)
350
+ sleep(@retry.next_time - Time.now)
351
+ else
352
+ unless @retry.nil?
353
+ log.debug("retry succeeded.")
354
+ @retry = nil
355
+ end
356
+ end
357
+ end
358
+
295
359
  def run
296
360
  return run_slice if @num_slices <= 1
297
361
 
@@ -302,6 +366,9 @@ module Fluent::Plugin
302
366
  run_slice(slice_id)
303
367
  end
304
368
  end
369
+ rescue Faraday::ConnectionFailed, OpenSearch::Transport::Transport::Error => error
370
+ update_retry_state(error)
371
+ retry
305
372
  end
306
373
 
307
374
  def run_slice(slice_id=nil)
@@ -321,7 +388,15 @@ module Fluent::Plugin
321
388
  end
322
389
 
323
390
  router.emit_stream(@tag, es)
391
+ clear_scroll(scroll_id)
392
+ update_retry_state
393
+ end
394
+
395
+ def clear_scroll(scroll_id)
324
396
  client.clear_scroll(scroll_id: scroll_id) if scroll_id
397
+ rescue => e
398
+ # ignore & log any clear_scroll errors
399
+ log.warn("Ignoring clear_scroll exception", message: e.message, exception: e.class)
325
400
  end
326
401
 
327
402
  def process_scroll_request(scroll_id)
@@ -350,7 +350,11 @@ module Fluent::Plugin
350
350
 
351
351
  @credential_mutex.synchronize do
352
352
  @_os = nil
353
- @_aws_credentials = aws_credentials(@endpoint)
353
+ begin
354
+ @_aws_credentials = aws_credentials(@endpoint)
355
+ rescue => e
356
+ log.error("Failed to get new AWS credentials: #{e}")
357
+ end
354
358
  end
355
359
  end
356
360
  end
@@ -201,6 +201,8 @@ module Fluent::Plugin
201
201
  end
202
202
  end
203
203
 
204
+ return if bulk_message.to_s.empty?
205
+
204
206
  params = {
205
207
  index: data_stream_name,
206
208
  body: bulk_message
@@ -39,6 +39,7 @@ class OpenSearchInputTest < Test::Unit::TestCase
39
39
  CONFIG = %[
40
40
  tag raw.opensearch
41
41
  interval 2
42
+ check_connection false
42
43
  ]
43
44
 
44
45
  def setup
@@ -190,6 +191,7 @@ class OpenSearchInputTest < Test::Unit::TestCase
190
191
  user john
191
192
  password doe
192
193
  tag raw.opensearch
194
+ check_connection false
193
195
  }
194
196
  instance = driver(config).instance
195
197
 
@@ -228,6 +230,7 @@ class OpenSearchInputTest < Test::Unit::TestCase
228
230
  user john
229
231
  password doe
230
232
  tag raw.opensearch
233
+ check_connection false
231
234
  }
232
235
  instance = driver(config).instance
233
236
 
@@ -249,6 +252,7 @@ class OpenSearchInputTest < Test::Unit::TestCase
249
252
  user %{j+hn}
250
253
  password %{d@e}
251
254
  tag raw.opensearch
255
+ check_connection false
252
256
  }
253
257
  instance = driver(config).instance
254
258
 
@@ -271,6 +275,7 @@ class OpenSearchInputTest < Test::Unit::TestCase
271
275
  path /es/
272
276
  port 123
273
277
  tag raw.opensearch
278
+ check_connection false
274
279
  }
275
280
  instance = driver(config).instance
276
281
 
@@ -295,6 +300,7 @@ class OpenSearchInputTest < Test::Unit::TestCase
295
300
  user default_user
296
301
  password default_password
297
302
  tag raw.opensearch
303
+ check_connection false
298
304
  }
299
305
  instance = driver(config).instance
300
306
 
@@ -323,6 +329,7 @@ class OpenSearchInputTest < Test::Unit::TestCase
323
329
  user default_user
324
330
  password default_password
325
331
  tag raw.opensearch
332
+ check_connection false
326
333
  }
327
334
  instance = driver(config).instance
328
335
 
@@ -3977,4 +3977,26 @@ class OpenSearchOutputTest < Test::Unit::TestCase
3977
3977
  end
3978
3978
  }
3979
3979
  end
3980
+
3981
+ def test_no_aws_credentials_refresh_exception
3982
+ # See https://github.com/fluent/fluent-plugin-opensearch/issues/129
3983
+ endpoint_config =
3984
+ Fluent::Config::Element.new('endpoint', '', {
3985
+ 'url' => "https://search-opensearch.aws.example.com/",
3986
+ 'region' => "local",
3987
+ 'access_key_id' => 'YOUR_AWESOME_KEY',
3988
+ 'secret_access_key' => 'YOUR_AWESOME_SECRET',
3989
+ 'refresh_credentials_interval' => '0',
3990
+ }, [])
3991
+ config = Fluent::Config::Element.new('ROOT', '**', { '@type' => 'opensearch' },
3992
+ [endpoint_config])
3993
+ # aws_credentials will be called twice in
3994
+ # OpenSearchOutput#configure call, and in the 2nd call was changed not
3995
+ # to emit exception. (instead, logging error) so check the error logs
3996
+ flexmock(Fluent::Plugin::OpenSearchOutput).new_instances.should_receive(:aws_credentials)
3997
+ .and_return(true).and_raise(::RuntimeError.new("No valid AWS credentials found."))
3998
+ d = driver(config)
3999
+ d.run
4000
+ assert { d.logs.any?(/\[error\]: Failed to get new AWS credentials: No valid AWS credentials found.\n/) }
4001
+ end
3980
4002
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-opensearch
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.4
4
+ version: 1.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hiroshi Hatake
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-21 00:00:00.000000000 Z
11
+ date: 2024-10-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fluentd
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: 3.0.1
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: 3.0.1
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: aws-sdk-core
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -142,14 +142,14 @@ dependencies:
142
142
  requirements:
143
143
  - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: '3'
145
+ version: 3.18.1
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
- version: '3'
152
+ version: 3.18.1
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: test-unit
155
155
  requirement: !ruby/object:Gem::Requirement
@@ -203,6 +203,7 @@ files:
203
203
  - ".editorconfig"
204
204
  - ".github/ISSUE_TEMPLATE/bug_report.md"
205
205
  - ".github/ISSUE_TEMPLATE/feature_request.md"
206
+ - ".github/PULL_REQUEST_TEMPLATE/pull_request_template.md"
206
207
  - ".github/workflows/coverage.yaml"
207
208
  - ".github/workflows/issue-auto-closer.yml"
208
209
  - ".github/workflows/linux.yml"
@@ -212,9 +213,7 @@ files:
212
213
  - CONTRIBUTING.md
213
214
  - Gemfile
214
215
  - History.md
215
- - ISSUE_TEMPLATE.md
216
216
  - LICENSE.txt
217
- - PULL_REQUEST_TEMPLATE.md
218
217
  - README.OpenSearchGenID.md
219
218
  - README.OpenSearchInput.md
220
219
  - README.Troubleshooting.md
data/ISSUE_TEMPLATE.md DELETED
@@ -1,26 +0,0 @@
1
- (check apply)
2
- - [ ] read [the contribution guideline](https://github.com/fluent/fluent-plugin-opensearch/blob/master/CONTRIBUTING.md)
3
-
4
- #### Problem
5
-
6
- ...
7
-
8
- #### Steps to replicate
9
-
10
- Provide example config and message
11
-
12
- #### Expected Behavior or What you need to ask
13
-
14
- ...
15
-
16
- #### Using Fluentd and OpenSearch plugin versions
17
-
18
- * OS version
19
- * Bare Metal or within Docker or Kubernetes or others?
20
- * Fluentd v1.0 or later
21
- * paste result of ``fluentd --version`` or ``td-agent --version``
22
- * OpenSearch plugin version
23
- * paste boot log of fluentd or td-agent
24
- * paste result of ``fluent-gem list``, ``td-agent-gem list`` or your Gemfile.lock
25
- * OpenSearch version (optional)
26
- * OpenSearch template(s) (optional)