logstash-output-s3 4.0.3 → 4.0.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 +4 -4
- data/CHANGELOG.md +9 -0
- data/lib/logstash/outputs/s3.rb +19 -3
- data/lib/logstash/outputs/s3/temporary_file.rb +2 -2
- data/lib/logstash/outputs/s3/uploader.rb +4 -1
- data/lib/logstash/outputs/s3/write_bucket_permission_validator.rb +9 -5
- data/logstash-output-s3.gemspec +1 -1
- data/spec/integration/time_based_rotation_with_stale_write_spec.rb +5 -1
- data/spec/outputs/s3/temporary_file_spec.rb +7 -0
- data/spec/outputs/s3/write_bucket_permission_validator_spec.rb +2 -1
- data/spec/outputs/s3_spec.rb +63 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 31a45d07d1d55ba2247ea058ca57be461f7773d9
|
4
|
+
data.tar.gz: c45f5e22b868918990ef27f5c2d2b1682f7ad93e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d05449f29cd48dbbf75372bae6a2b4a6722b23b34e3653f435f1edf49ee56caa473dc52972a4812888b600f8055c98b08ec4002f887cd38646941ffe05814887
|
7
|
+
data.tar.gz: 63ec9d6444fc8046aeaf05d81a7ea2a2e6e05b9d986538713d7e3357aa430ee1d3f6f49a7ae0ab15f1dd4950767aa8e13e8e1b8be72205167b132596f8348492
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
## 4.0.5
|
2
|
+
- Delete the file on disk after they are succesfully uploaded to S3 #122 #120
|
3
|
+
- Added logging when an exception occur in the Uploader's `on_complete` callback
|
4
|
+
|
5
|
+
## 4.0.4
|
6
|
+
- Add support for `storage_class` configuration
|
7
|
+
- Fix compatibility with Logstash 2.4
|
8
|
+
- Add support for `aws:kms` server side encryption #104
|
9
|
+
|
1
10
|
## 4.0.3
|
2
11
|
- When configuring the `canned_acl` options of the plugins the role was not applied correctly to the created object: #7
|
3
12
|
|
data/lib/logstash/outputs/s3.rb
CHANGED
@@ -127,9 +127,23 @@ class LogStash::Outputs::S3 < LogStash::Outputs::Base
|
|
127
127
|
config :canned_acl, :validate => ["private", "public_read", "public_read_write", "authenticated_read"],
|
128
128
|
:default => "private"
|
129
129
|
|
130
|
-
# Specifies wether or not to use S3's
|
130
|
+
# Specifies wether or not to use S3's server side encryption. Defaults to no encryption.
|
131
131
|
config :server_side_encryption, :validate => :boolean, :default => false
|
132
132
|
|
133
|
+
# Specifies what type of encryption to use when SSE is enabled.
|
134
|
+
config :server_side_encryption_algorithm, :validate => ["AES256", "aws:kms"], :default => "AES256"
|
135
|
+
|
136
|
+
# The key to use when specified along with server_side_encryption => aws:kms.
|
137
|
+
# If server_side_encryption => aws:kms is set but this is not default KMS key is used.
|
138
|
+
# http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingKMSEncryption.html
|
139
|
+
config :ssekms_key_id, :validate => :string
|
140
|
+
|
141
|
+
# Specifies what S3 storage class to use when uploading the file.
|
142
|
+
# More information about the different storage classes can be found:
|
143
|
+
# http://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html
|
144
|
+
# Defaults to STANDARD.
|
145
|
+
config :storage_class, :validate => ["STANDARD", "REDUCED_REDUNDANCY", "STANDARD_IA"], :default => "STANDARD"
|
146
|
+
|
133
147
|
# Set the directory where logstash will store the tmp files before sending it to S3
|
134
148
|
# default to the current OS temporary directory in linux /tmp/logstash
|
135
149
|
config :temporary_directory, :validate => :string, :default => File.join(Dir.tmpdir, "logstash")
|
@@ -183,7 +197,7 @@ class LogStash::Outputs::S3 < LogStash::Outputs::Base
|
|
183
197
|
raise LogStash::ConfigurationError, "Logstash must have the permissions to write to the temporary directory: #{@temporary_directory}"
|
184
198
|
end
|
185
199
|
|
186
|
-
if @validate_credentials_on_root_bucket && !WriteBucketPermissionValidator.valid?(bucket_resource)
|
200
|
+
if @validate_credentials_on_root_bucket && !WriteBucketPermissionValidator.new(@logger).valid?(bucket_resource)
|
187
201
|
raise LogStash::ConfigurationError, "Logstash must have the privileges to write to root bucket `#{@bucket}`, check you credentials or your permissions."
|
188
202
|
end
|
189
203
|
|
@@ -265,7 +279,9 @@ class LogStash::Outputs::S3 < LogStash::Outputs::Base
|
|
265
279
|
def upload_options
|
266
280
|
{
|
267
281
|
:acl => @canned_acl,
|
268
|
-
:server_side_encryption => @server_side_encryption ?
|
282
|
+
:server_side_encryption => @server_side_encryption ? @server_side_encryption_algorithm : nil,
|
283
|
+
:ssekms_key_id => @server_side_encryption_algorithm == "aws:kms" ? @ssekms_key_id : nil,
|
284
|
+
:storage_class => @storage_class,
|
269
285
|
:content_encoding => @encoding == "gzip" ? "gzip" : nil
|
270
286
|
}
|
271
287
|
end
|
@@ -50,8 +50,8 @@ module LogStash
|
|
50
50
|
# we delete the root of the UUID, using a UUID also remove the risk of deleting unwanted file, it acts as
|
51
51
|
# a sandbox.
|
52
52
|
def delete!
|
53
|
-
@fd.close
|
54
|
-
|
53
|
+
@fd.close rescue IOError # force close anyway
|
54
|
+
FileUtils.rm_r(@temp_path, :secure => true)
|
55
55
|
end
|
56
56
|
|
57
57
|
def empty?
|
@@ -42,11 +42,14 @@ module LogStash
|
|
42
42
|
#
|
43
43
|
# Thread might be stuck here, but I think its better than losing anything
|
44
44
|
# its either a transient errors or something bad really happened.
|
45
|
-
logger.error("Uploading failed, retrying", :exception => e, :path => file.path, :backtrace => e.backtrace)
|
45
|
+
logger.error("Uploading failed, retrying", :exception => e.class, :message => e.message, :path => file.path, :backtrace => e.backtrace)
|
46
46
|
retry
|
47
47
|
end
|
48
48
|
|
49
49
|
options[:on_complete].call(file) unless options[:on_complete].nil?
|
50
|
+
rescue => e
|
51
|
+
logger.error("An error occured in the `on_complete` uploader", :exception => e.class, :message => e.message, :path => file.path, :backtrace => e.backtrace)
|
52
|
+
raise e # reraise it since we don't deal with it now
|
50
53
|
end
|
51
54
|
|
52
55
|
def stop
|
@@ -7,14 +7,18 @@ module LogStash
|
|
7
7
|
module Outputs
|
8
8
|
class S3
|
9
9
|
class WriteBucketPermissionValidator
|
10
|
-
|
11
|
-
|
12
|
-
def
|
10
|
+
attr_reader :logger
|
11
|
+
|
12
|
+
def initialize(logger)
|
13
|
+
@logger = logger
|
14
|
+
end
|
15
|
+
|
16
|
+
def valid?(bucket_resource)
|
13
17
|
begin
|
14
18
|
upload_test_file(bucket_resource)
|
15
19
|
true
|
16
20
|
rescue StandardError => e
|
17
|
-
logger.error("Error validating bucket write permissions!",
|
21
|
+
logger.error("Error validating bucket write permissions!",
|
18
22
|
:message => e.message,
|
19
23
|
:class => e.class.name
|
20
24
|
)
|
@@ -23,7 +27,7 @@ module LogStash
|
|
23
27
|
end
|
24
28
|
|
25
29
|
private
|
26
|
-
def
|
30
|
+
def upload_test_file(bucket_resource)
|
27
31
|
generated_at = Time.now
|
28
32
|
|
29
33
|
key = "logstash-programmatic-access-test-object-#{generated_at}"
|
data/logstash-output-s3.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'logstash-output-s3'
|
3
|
-
s.version = '4.0.
|
3
|
+
s.version = '4.0.5'
|
4
4
|
s.licenses = ['Apache-2.0']
|
5
5
|
s.summary = "This plugin was created for store the logstash's events into Amazon Simple Storage Service (Amazon S3)"
|
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"
|
@@ -26,7 +26,7 @@ describe "File Time rotation with stale write", :integration => true do
|
|
26
26
|
clean_remote_files(prefix)
|
27
27
|
subject.register
|
28
28
|
subject.multi_receive_encoded(batch)
|
29
|
-
sleep(
|
29
|
+
sleep(5) # the periodic check should have kick in
|
30
30
|
end
|
31
31
|
|
32
32
|
after do
|
@@ -56,5 +56,9 @@ describe "File Time rotation with stale write", :integration => true do
|
|
56
56
|
try(20) do
|
57
57
|
expect(Dir.glob(File.join(download_directory, "**", "*.txt")).inject(0) { |sum, f| sum + IO.readlines(f).size }).to eq(number_of_events)
|
58
58
|
end
|
59
|
+
|
60
|
+
try(10) do
|
61
|
+
expect(Dir.glob(File.join(temporary_directory, "**", "*.txt")).size).to eq(1) # we should only have 1 file left, since we did a rotation
|
62
|
+
end
|
59
63
|
end
|
60
64
|
end
|
@@ -34,6 +34,13 @@ describe LogStash::Outputs::S3::TemporaryFile do
|
|
34
34
|
expect(File.exist?(subject.path)).to be_falsey
|
35
35
|
end
|
36
36
|
|
37
|
+
it "successfully delete a file already closed" do
|
38
|
+
subject.close
|
39
|
+
expect(File.exist?(subject.path)).to be_truthy
|
40
|
+
subject.delete!
|
41
|
+
expect(File.exist?(subject.path)).to be_falsey
|
42
|
+
end
|
43
|
+
|
37
44
|
it "returns the creation time" do
|
38
45
|
expect(subject.ctime).to be < Time.now + 0.5
|
39
46
|
end
|
@@ -4,12 +4,13 @@ require "logstash/outputs/s3/write_bucket_permission_validator"
|
|
4
4
|
require "aws-sdk"
|
5
5
|
|
6
6
|
describe LogStash::Outputs::S3::WriteBucketPermissionValidator do
|
7
|
+
let(:logger) { spy(:logger ) }
|
7
8
|
let(:bucket_name) { "foobar" }
|
8
9
|
let(:obj) { double("s3_object") }
|
9
10
|
let(:client) { Aws::S3::Client.new(stub_responses: true) }
|
10
11
|
let(:bucket) { Aws::S3::Bucket.new(bucket_name, :client => client) }
|
11
12
|
|
12
|
-
subject { described_class }
|
13
|
+
subject { described_class.new(logger) }
|
13
14
|
|
14
15
|
before do
|
15
16
|
expect(bucket).to receive(:object).with(any_args).and_return(obj)
|
data/spec/outputs/s3_spec.rb
CHANGED
@@ -25,7 +25,7 @@ describe LogStash::Outputs::S3 do
|
|
25
25
|
|
26
26
|
before do
|
27
27
|
allow(subject).to receive(:bucket_resource).and_return(mock_bucket)
|
28
|
-
|
28
|
+
allow_any_instance_of(LogStash::Outputs::S3::WriteBucketPermissionValidator).to receive(:valid?).with(mock_bucket).and_return(true)
|
29
29
|
end
|
30
30
|
|
31
31
|
context "#register configuration validation" do
|
@@ -61,6 +61,67 @@ describe LogStash::Outputs::S3 do
|
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
64
|
+
describe "Service Side Encryption" do
|
65
|
+
|
66
|
+
context "when configured" do
|
67
|
+
it "should be configure" do
|
68
|
+
s3 = described_class.new(options.merge({ "server_side_encryption" => true }))
|
69
|
+
expect(s3.upload_options).to include(:server_side_encryption => "AES256")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "when algorithm is configured" do
|
74
|
+
["AES256", "aws:kms"].each do |sse|
|
75
|
+
it "should return the configured SSE: #{sse}" do
|
76
|
+
s3 = described_class.new(options.merge({ "server_side_encryption" => true, "server_side_encryption_algorithm" => sse }))
|
77
|
+
expect(s3.upload_options).to include(:server_side_encryption => sse)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context "when using SSE with KMS and custom key" do
|
83
|
+
it "should return the configured KMS key" do
|
84
|
+
s3 = described_class.new(options.merge({ "server_side_encryption" => true, "server_side_encryption_algorithm" => "aws:kms", "ssekms_key_id" => "test"}))
|
85
|
+
expect(s3.upload_options).to include(:server_side_encryption => "aws:kms")
|
86
|
+
expect(s3.upload_options).to include(:ssekms_key_id => "test")
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "when using SSE with KMS but no custom key" do
|
91
|
+
it "should return the configured KMS key" do
|
92
|
+
s3 = described_class.new(options.merge({ "server_side_encryption" => true, "server_side_encryption_algorithm" => "aws:kms"}))
|
93
|
+
expect(s3.upload_options).to include(:server_side_encryption => "aws:kms")
|
94
|
+
expect(s3.upload_options).to include(:ssekms_key_id => nil)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context "when not configured" do
|
99
|
+
it "should not be configured" do
|
100
|
+
s3 = described_class.new(options)
|
101
|
+
expect(s3.upload_options).to include(:server_side_encryption => nil)
|
102
|
+
expect(s3.upload_options).to include(:ssekms_key_id => nil)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "Storage Class" do
|
108
|
+
context "when configured" do
|
109
|
+
["STANDARD", "REDUCED_REDUNDANCY", "STANDARD_IA"].each do |storage_class|
|
110
|
+
it "should return the configured storage class: #{storage_class}" do
|
111
|
+
s3 = described_class.new(options.merge({ "storage_class" => storage_class }))
|
112
|
+
expect(s3.upload_options).to include(:storage_class => storage_class)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context "when not configured" do
|
118
|
+
it "uses STANDARD as the default" do
|
119
|
+
s3 = described_class.new(options)
|
120
|
+
expect(s3.upload_options).to include(:storage_class => "STANDARD")
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
64
125
|
describe "temporary directory" do
|
65
126
|
let(:temporary_directory) { Stud::Temporary.pathname }
|
66
127
|
let(:options) { super.merge({ "temporary_directory" => temporary_directory }) }
|
@@ -84,7 +145,7 @@ describe LogStash::Outputs::S3 do
|
|
84
145
|
|
85
146
|
it "allow to not validate credentials" do
|
86
147
|
s3 = described_class.new(options.merge({"validate_credentials_on_root_bucket" => false}))
|
87
|
-
|
148
|
+
expect_any_instance_of(LogStash::Outputs::S3::WriteBucketPermissionValidator).not_to receive(:valid?).with(any_args)
|
88
149
|
s3.register
|
89
150
|
end
|
90
151
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-output-s3
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0.
|
4
|
+
version: 4.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Elastic
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-01-
|
11
|
+
date: 2017-01-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|