fluent-plugin-s3 0.6.6 → 0.6.7
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
- data/ChangeLog +6 -0
- data/README.md +10 -0
- data/VERSION +1 -1
- data/fluent-plugin-s3.gemspec +1 -0
- data/lib/fluent/plugin/out_s3.rb +11 -0
- data/test/test_out_s3.rb +67 -43
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cc5bd6dc0616525d3beb069168b7f59bc985b188
|
4
|
+
data.tar.gz: 5021dbf9b12861ee087ad2b5a1800d9430e79874
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f0c104943d41ecaacefcf35565d3bf3de8ff8c0301d3edb02994f8425cfcc81f43833c1eed478dfc8fd2965017068da32d43a590644e82bbd1cd98277f3888bd
|
7
|
+
data.tar.gz: 4580b5c87c33db7fc7ba65c250c3c2e1330c10be6e75bde2144175df41276cfe929031379df785dba68b5d8196890e6ba51b8fbd5081e8e769ea96b24718c6ae
|
data/ChangeLog
CHANGED
data/README.md
CHANGED
@@ -293,6 +293,16 @@ AWS SDK uses MD5 for API request/response by default. On FIPS enabled environmen
|
|
293
293
|
OpenSSL returns an error because MD5 is disabled. If you want to use
|
294
294
|
this plugin on FIPS enabled environment, set `compute_checksums false`.
|
295
295
|
|
296
|
+
**signature_version**
|
297
|
+
|
298
|
+
Signature version for API request. `s3` means signature version 2 and
|
299
|
+
`v4` means signature version 4. Default is `nil` (Following SDK's default).
|
300
|
+
It would be useful when you use S3 compatible storage that accepts only signature version 2.
|
301
|
+
|
302
|
+
**warn_for_delay**
|
303
|
+
|
304
|
+
Given a threshold to treat events as delay, output warning logs if delayed events were put into s3.
|
305
|
+
|
296
306
|
### assume_role_credentials
|
297
307
|
|
298
308
|
Typically, you use AssumeRole for cross-account access or federation.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.6.
|
1
|
+
0.6.7
|
data/fluent-plugin-s3.gemspec
CHANGED
data/lib/fluent/plugin/out_s3.rb
CHANGED
@@ -105,6 +105,10 @@ module Fluent
|
|
105
105
|
config_param :ssekms_key_id, :string, :default => nil, :secret => true
|
106
106
|
desc "AWS SDK uses MD5 for API request/response by default"
|
107
107
|
config_param :compute_checksums, :bool, :default => nil # use nil to follow SDK default configuration
|
108
|
+
desc "Signature version for API Request (s3,v4)"
|
109
|
+
config_param :signature_version, :string, :default => nil # use nil to follow SDK default configuration
|
110
|
+
desc "Given a threshold to treat events as delay, output warning logs if delayed events were put into s3"
|
111
|
+
config_param :warn_for_delay, :time, :default => nil
|
108
112
|
|
109
113
|
attr_reader :bucket
|
110
114
|
|
@@ -159,6 +163,7 @@ module Fluent
|
|
159
163
|
options[:http_proxy] = @proxy_uri if @proxy_uri
|
160
164
|
options[:force_path_style] = @force_path_style
|
161
165
|
options[:compute_checksums] = @compute_checksums unless @compute_checksums.nil?
|
166
|
+
options[:signature_version] = @signature_version unless @signature_version.nil?
|
162
167
|
|
163
168
|
s3_client = Aws::S3::Client.new(options)
|
164
169
|
@s3 = Aws::S3::Resource.new(:client => s3_client)
|
@@ -227,6 +232,12 @@ module Fluent
|
|
227
232
|
@bucket.object(s3path).put(put_options)
|
228
233
|
|
229
234
|
@values_for_s3_object_chunk.delete(chunk.unique_id)
|
235
|
+
|
236
|
+
if @warn_for_delay
|
237
|
+
if Time.strptime(chunk.key, @time_slice_format) < Time.now - @warn_for_delay
|
238
|
+
log.warn { "out_s3: delayed events were put to s3://#{@s3_bucket}/#{s3path}" }
|
239
|
+
end
|
240
|
+
end
|
230
241
|
ensure
|
231
242
|
tmp.close(true) rescue nil
|
232
243
|
end
|
data/test/test_out_s3.rb
CHANGED
@@ -4,6 +4,7 @@ require 'fluent/plugin/out_s3'
|
|
4
4
|
require 'test/unit/rr'
|
5
5
|
require 'zlib'
|
6
6
|
require 'fileutils'
|
7
|
+
require 'timecop'
|
7
8
|
|
8
9
|
class S3OutputTest < Test::Unit::TestCase
|
9
10
|
def setup
|
@@ -50,6 +51,7 @@ class S3OutputTest < Test::Unit::TestCase
|
|
50
51
|
assert_equal 'application/x-gzip', d.instance.instance_variable_get(:@compressor).content_type
|
51
52
|
assert_equal false, d.instance.force_path_style
|
52
53
|
assert_equal nil, d.instance.compute_checksums
|
54
|
+
assert_equal nil, d.instance.signature_version
|
53
55
|
end
|
54
56
|
|
55
57
|
def test_s3_endpoint_with_valid_endpoint
|
@@ -274,19 +276,8 @@ class S3OutputTest < Test::Unit::TestCase
|
|
274
276
|
def test_write_with_custom_s3_object_key_format
|
275
277
|
# Partial mock the S3Bucket, not to make an actual connection to Amazon S3
|
276
278
|
setup_mocks(true)
|
277
|
-
|
278
|
-
|
279
|
-
s3obj = stub(Aws::S3::Object.new(:bucket_name => "test_bucket",
|
280
|
-
:key => "test",
|
281
|
-
:client => @s3_client))
|
282
|
-
s3obj.exists? { false }
|
283
|
-
s3_test_file_path = "/tmp/s3-test.txt"
|
284
|
-
tempfile = File.new(s3_test_file_path, "w")
|
285
|
-
mock(Tempfile).new("s3-") { tempfile }
|
286
|
-
s3obj.put(:body => tempfile,
|
287
|
-
:content_type => "application/x-gzip",
|
288
|
-
:storage_class => "STANDARD")
|
289
|
-
@s3_bucket.object("log/events/ts=20110102-13/events_0-testing.node.local.gz") { s3obj }
|
279
|
+
s3_local_file_path = "/tmp/s3-test.txt"
|
280
|
+
setup_s3_object_mocks(s3_local_file_path: s3_local_file_path)
|
290
281
|
|
291
282
|
# We must use TimeSlicedOutputTestDriver instead of BufferedOutputTestDriver,
|
292
283
|
# to make assertions on chunks' keys
|
@@ -298,13 +289,13 @@ class S3OutputTest < Test::Unit::TestCase
|
|
298
289
|
|
299
290
|
# Finally, the instance of S3Output is initialized and then invoked
|
300
291
|
d.run
|
301
|
-
Zlib::GzipReader.open(
|
292
|
+
Zlib::GzipReader.open(s3_local_file_path) do |gz|
|
302
293
|
data = gz.read
|
303
294
|
assert_equal %[2011-01-02T13:14:15Z\ttest\t{"a":1}\n] +
|
304
295
|
%[2011-01-02T13:14:15Z\ttest\t{"a":2}\n],
|
305
296
|
data
|
306
297
|
end
|
307
|
-
FileUtils.rm_f(
|
298
|
+
FileUtils.rm_f(s3_local_file_path)
|
308
299
|
end
|
309
300
|
|
310
301
|
def test_write_with_custom_s3_object_key_format_containing_uuid_flush_placeholder
|
@@ -314,18 +305,9 @@ class S3OutputTest < Test::Unit::TestCase
|
|
314
305
|
uuid = "5755e23f-9b54-42d8-8818-2ea38c6f279e"
|
315
306
|
stub(UUIDTools::UUID).random_create{ uuid }
|
316
307
|
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
:client => @s3_client))
|
321
|
-
s3obj.exists? { false }
|
322
|
-
s3_test_file_path = "/tmp/s3-test.txt"
|
323
|
-
tempfile = File.new(s3_test_file_path, "w")
|
324
|
-
mock(Tempfile).new("s3-") { tempfile }
|
325
|
-
s3obj.put(:body => tempfile,
|
326
|
-
:content_type => "application/x-gzip",
|
327
|
-
:storage_class => "STANDARD")
|
328
|
-
@s3_bucket.object("log/events/ts=20110102-13/events_0-#{uuid}.gz") { s3obj }
|
308
|
+
s3_local_file_path = "/tmp/s3-test.txt"
|
309
|
+
s3path = "log/events/ts=20110102-13/events_0-#{uuid}.gz"
|
310
|
+
setup_s3_object_mocks(s3_local_file_path: s3_local_file_path, s3path: s3path)
|
329
311
|
|
330
312
|
# We must use TimeSlicedOutputTestDriver instead of BufferedOutputTestDriver,
|
331
313
|
# to make assertions on chunks' keys
|
@@ -338,13 +320,13 @@ class S3OutputTest < Test::Unit::TestCase
|
|
338
320
|
|
339
321
|
# Finally, the instance of S3Output is initialized and then invoked
|
340
322
|
d.run
|
341
|
-
Zlib::GzipReader.open(
|
323
|
+
Zlib::GzipReader.open(s3_local_file_path) do |gz|
|
342
324
|
data = gz.read
|
343
325
|
assert_equal %[2011-01-02T13:14:15Z\ttest\t{"a":1}\n] +
|
344
326
|
%[2011-01-02T13:14:15Z\ttest\t{"a":2}\n],
|
345
327
|
data
|
346
328
|
end
|
347
|
-
FileUtils.rm_f(
|
329
|
+
FileUtils.rm_f(s3_local_file_path)
|
348
330
|
Dir.glob('tmp/*').each {|file| FileUtils.rm_f(file) }
|
349
331
|
end
|
350
332
|
|
@@ -375,18 +357,9 @@ class S3OutputTest < Test::Unit::TestCase
|
|
375
357
|
# Partial mock the S3Bucket, not to make an actual connection to Amazon S3
|
376
358
|
setup_mocks(true)
|
377
359
|
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
:client => @s3_client))
|
382
|
-
s3obj.exists? { false }
|
383
|
-
s3_test_file_path = "/tmp/s3-test.txt"
|
384
|
-
tempfile = File.new(s3_test_file_path, "w")
|
385
|
-
mock(Tempfile).new("s3-") { tempfile }
|
386
|
-
s3obj.put(:body => tempfile,
|
387
|
-
:content_type => "application/x-gzip",
|
388
|
-
:storage_class => "STANDARD")
|
389
|
-
@s3_bucket.object("log/events/ts=20110102-13/events_0-#{hex}.gz") { s3obj }
|
360
|
+
s3path = "log/events/ts=20110102-13/events_0-#{hex}.gz"
|
361
|
+
s3_local_file_path = "/tmp/s3-test.txt"
|
362
|
+
setup_s3_object_mocks(s3_local_file_path: s3_local_file_path, s3path: s3path)
|
390
363
|
|
391
364
|
d = create_time_sliced_driver(config)
|
392
365
|
|
@@ -396,13 +369,13 @@ class S3OutputTest < Test::Unit::TestCase
|
|
396
369
|
|
397
370
|
# Finally, the instance of S3Output is initialized and then invoked
|
398
371
|
d.run
|
399
|
-
Zlib::GzipReader.open(
|
372
|
+
Zlib::GzipReader.open(s3_local_file_path) do |gz|
|
400
373
|
data = gz.read
|
401
374
|
assert_equal %[2011-01-02T13:14:15Z\ttest\t{"a":1}\n] +
|
402
375
|
%[2011-01-02T13:14:15Z\ttest\t{"a":2}\n],
|
403
376
|
data
|
404
377
|
end
|
405
|
-
FileUtils.rm_f(
|
378
|
+
FileUtils.rm_f(s3_local_file_path)
|
406
379
|
end
|
407
380
|
|
408
381
|
def setup_mocks(exists_return = false)
|
@@ -420,6 +393,25 @@ class S3OutputTest < Test::Unit::TestCase
|
|
420
393
|
@s3_resource.bucket(anything) { @s3_bucket }
|
421
394
|
end
|
422
395
|
|
396
|
+
def setup_s3_object_mocks(params = {})
|
397
|
+
s3path = params[:s3path] || "log/events/ts=20110102-13/events_0-testing.node.local.gz"
|
398
|
+
s3_local_file_path = params[:s3_local_file_path] || "/tmp/s3-test.txt"
|
399
|
+
|
400
|
+
# Assert content of event logs which are being sent to S3
|
401
|
+
s3obj = stub(Aws::S3::Object.new(:bucket_name => "test_bucket",
|
402
|
+
:key => "test",
|
403
|
+
:client => @s3_client))
|
404
|
+
s3obj.exists? { false }
|
405
|
+
|
406
|
+
tempfile = File.new(s3_local_file_path, "w")
|
407
|
+
stub(Tempfile).new("s3-") { tempfile }
|
408
|
+
s3obj.put(:body => tempfile,
|
409
|
+
:content_type => "application/x-gzip",
|
410
|
+
:storage_class => "STANDARD")
|
411
|
+
|
412
|
+
@s3_bucket.object(s3path) { s3obj }
|
413
|
+
end
|
414
|
+
|
423
415
|
def test_auto_create_bucket_false_with_non_existence_bucket
|
424
416
|
setup_mocks
|
425
417
|
|
@@ -534,4 +526,36 @@ class S3OutputTest < Test::Unit::TestCase
|
|
534
526
|
credentials = client.config.credentials
|
535
527
|
assert_equal(expected_credentials, credentials)
|
536
528
|
end
|
529
|
+
|
530
|
+
def test_signature_version
|
531
|
+
config = [CONFIG, 'signature_version s3'].join("\n")
|
532
|
+
d = create_driver(config)
|
533
|
+
|
534
|
+
signature_version = d.instance.instance_variable_get(:@signature_version)
|
535
|
+
assert_equal("s3", signature_version)
|
536
|
+
end
|
537
|
+
|
538
|
+
def test_warn_for_delay
|
539
|
+
setup_mocks(true)
|
540
|
+
s3_local_file_path = "/tmp/s3-test.txt"
|
541
|
+
setup_s3_object_mocks(s3_local_file_path: s3_local_file_path)
|
542
|
+
|
543
|
+
config = CONFIG_TIME_SLICE + 'warn_for_delay 1d'
|
544
|
+
d = create_time_sliced_driver(config)
|
545
|
+
|
546
|
+
delayed_time = Time.parse("2011-01-02 13:14:15 UTC")
|
547
|
+
now = delayed_time + 86000 + 1
|
548
|
+
Timecop.freeze(now)
|
549
|
+
|
550
|
+
d.emit({"a"=>1}, delayed_time.to_i)
|
551
|
+
d.emit({"a"=>2}, delayed_time.to_i)
|
552
|
+
|
553
|
+
d.run
|
554
|
+
|
555
|
+
logs = d.instance.log.logs
|
556
|
+
assert_true logs.any? {|log| log.include?('[warn]: out_s3: delayed events were put') }
|
557
|
+
|
558
|
+
Timecop.return
|
559
|
+
FileUtils.rm_f(s3_local_file_path)
|
560
|
+
end
|
537
561
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-s3
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sadayuki Furuhashi
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-03-
|
12
|
+
date: 2016-03-31 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: fluentd
|
@@ -115,6 +115,20 @@ dependencies:
|
|
115
115
|
- - ">="
|
116
116
|
- !ruby/object:Gem::Version
|
117
117
|
version: 1.0.3
|
118
|
+
- !ruby/object:Gem::Dependency
|
119
|
+
name: timecop
|
120
|
+
requirement: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
type: :development
|
126
|
+
prerelease: false
|
127
|
+
version_requirements: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
118
132
|
description: Amazon S3 output plugin for Fluentd event collector
|
119
133
|
email: frsyuki@gmail.com
|
120
134
|
executables: []
|