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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fa4450798ae34f2e3d086e2468afaae71f2d26a0
4
- data.tar.gz: 024ad272f37c82f91dd1c25e4636e6837dbc97b7
3
+ metadata.gz: 31a45d07d1d55ba2247ea058ca57be461f7773d9
4
+ data.tar.gz: c45f5e22b868918990ef27f5c2d2b1682f7ad93e
5
5
  SHA512:
6
- metadata.gz: e9b0b212a751b10ff9de9bc8d16695777ea53a4dfe5de72b91b3aa31c54f5ad7ce4a44da2e089d5d5b70d6f8c531e9dfdbf8696fcf81349f7b3f6ab40ca57dcf
7
- data.tar.gz: 1e3bb81b19480cae9370046f728d81feed5afc54eed8a58f81e865eb760a2090618f300052573c5bd66821f2c6c5790d7b81e490fcce5a68f7ead633658aeb87
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
 
@@ -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 AES256 server side encryption. Defaults to false.
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 ? :aes256 : nil,
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
- ::FileUtils.rm_rf(@temp_path, :secure => true)
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
- include ::LogStash::Util::Loggable
11
-
12
- def self.valid?(bucket_resource)
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 self.upload_test_file(bucket_resource)
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}"
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'logstash-output-s3'
3
- s.version = '4.0.3'
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(1) # the periodic check should have kick int
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)
@@ -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
- allow(LogStash::Outputs::S3::WriteBucketPermissionValidator).to receive(:valid?).with(mock_bucket).and_return(true)
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
- expect(LogStash::Outputs::S3::WriteBucketPermissionValidator).not_to receive(:valid?).with(any_args)
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.3
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-05 00:00:00.000000000 Z
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