fluent-plugin-azure-storage-append-blob-lts 0.6.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 24eb19ac68cd42369ff7f147be24635945aad7c003f4ed789bcb4189d5f9a96e
4
- data.tar.gz: f293437b177cf4f7fc7a02694150f03f479c70749a3973d2ffc45a19377b7784
3
+ metadata.gz: 4e900def94ba82e3cb4e29b5ce37beed5b3801b951e5f68b1a1bc1e5a84ebfc1
4
+ data.tar.gz: 64780e024de8bb93023c7c42c5aff1d26ae461f51a769aae3ef74697fb607264
5
5
  SHA512:
6
- metadata.gz: 7be9b8cf563a7c2cf5b10667a8d037ea5a17d84a78ab3a782a937f5c06e0f850804985fef3b5b6eff795e965c4eefa0d690ddd737485929fa4882df416e420c0
7
- data.tar.gz: d4bb668e69155459e1b69ce954f9b8434a9dfa5e92dbf5e1324e9a1d50514c2e7b6b34e513f5fcb3621f5ba7b2b2dee5d7dea1cf37788ffe198869f5d7a3a0a4
6
+ metadata.gz: d7da2a55760e6221520198ccb54632892bfc3293d68bd78f0b088260f2d6ca2ff49b014caaff7427fa99de6731a52f642167be9df96e930323ffce7eb54d70e0
7
+ data.tar.gz: bc0cacd9e1bc4fb6a2e425a0556d8c9737fc2f35cd4530399bb3e95f62fa1b55804b118f4ec7550dadc549e29a3c7767eb2c61a3f7d84fca1bb24969084ea3dd
@@ -1,29 +1,28 @@
1
+ ---
2
+ jobs:
3
+ build:
4
+ name: Build + Publish
5
+ runs-on: ubuntu-latest
6
+ steps:
7
+ - uses: actions/checkout@v3
8
+ - name: Set up Ruby
9
+ uses: actions/setup-ruby@v1
10
+ with:
11
+ ruby-version: "3.1"
12
+ - env:
13
+ RUBYGEMS_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
14
+ name: Publish to RubyGems
15
+ run: |
16
+ mkdir -p $HOME/.gem
17
+ touch $HOME/.gem/credentials
18
+ chmod 0600 $HOME/.gem/credentials
19
+ printf -- "---\n:rubygems_api_key: ${RUBYGEMS_API_KEY}\n" > $HOME/.gem/credentials
20
+ gem build *.gemspec
21
+ gem push *.gem --otp ${{ github.event.inputs.otp }}
1
22
  name: Publish Ruby Gem
2
-
3
23
  on:
4
24
  workflow_dispatch:
5
25
  inputs:
6
26
  otp:
7
- description: 'One Time Password'
27
+ description: "One Time Password"
8
28
  required: true
9
-
10
- jobs:
11
- build:
12
- name: Build + Publish
13
- runs-on: ubuntu-latest
14
- steps:
15
- - uses: actions/checkout@v2
16
- - name: Set up Ruby 2.6
17
- uses: actions/setup-ruby@v1
18
- with:
19
- ruby-version: 2.6.x
20
- - name: Publish to RubyGems
21
- run: |
22
- mkdir -p $HOME/.gem
23
- touch $HOME/.gem/credentials
24
- chmod 0600 $HOME/.gem/credentials
25
- printf -- "---\n:rubygems_api_key: ${RUBYGEMS_API_KEY}\n" > $HOME/.gem/credentials
26
- gem build *.gemspec
27
- gem push *.gem --otp ${{ github.event.inputs.otp }}
28
- env:
29
- RUBYGEMS_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
@@ -1,21 +1,20 @@
1
- name: Test
2
-
3
- on:
4
- push:
5
- branches: [ master ]
6
- pull_request:
7
- branches: [ master ]
8
-
1
+ ---
9
2
  jobs:
10
3
  test:
11
4
  runs-on: ubuntu-latest
12
5
  steps:
13
- - uses: actions/checkout@v2
14
- - name: Set up Ruby
15
- uses: ruby/setup-ruby@v1
16
- with:
17
- ruby-version: 2.6
18
- - name: Install dependencies
19
- run: bundle install
20
- - name: Run tests
21
- run: bundle exec rake test
6
+ - uses: actions/checkout@v3
7
+ - name: Set up Ruby
8
+ uses: ruby/setup-ruby@v1
9
+ with:
10
+ ruby-version: "3.1"
11
+ - name: Install dependencies
12
+ run: bundle install
13
+ - name: Run tests
14
+ run: bundle exec rake test
15
+ name: Test
16
+ on:
17
+ pull_request:
18
+ branches: [master]
19
+ push:
20
+ branches: [master]
data/Dockerfile CHANGED
@@ -1,4 +1,4 @@
1
- FROM ruby:2.7
1
+ FROM ruby:3.1.4
2
2
 
3
3
  WORKDIR /plugin
4
4
 
data/README.md CHANGED
@@ -29,6 +29,7 @@ And then execute:
29
29
  type azure-storage-append-blob
30
30
 
31
31
  azure_cloud <azure cloud environment>
32
+ azure_storage_dns_suffix <your azure storage dns suffix> # only used for Azure Stack Cloud
32
33
  azure_storage_account <your azure storage account>
33
34
  azure_storage_access_key <your azure storage access key> # leave empty to use MSI
34
35
  azure_storage_connection_string <your azure storage connection string> # leave empty to use MSI
@@ -41,6 +42,7 @@ And then execute:
41
42
  path logs/
42
43
  azure_object_key_format %{path}%{time_slice}_%{index}.log
43
44
  time_slice_format %Y%m%d-%H
45
+ compress false
44
46
  compute_checksums true
45
47
  # if you want to use %{tag} or %Y/%m/%d/ like syntax in path / azure_blob_name_format,
46
48
  # need to specify tag for %{tag} and time for %Y/%m/%d in <buffer> argument.
@@ -59,6 +61,12 @@ Default: `AZUREPUBLICCLOUD`
59
61
 
60
62
  Cloud environment used to determine the storage endpoint suffix to use, see [here](https://github.com/Azure/go-autorest/blob/master/autorest/azure/environments.go).
61
63
 
64
+ Use `AZURESTACKCLOUD` for Azure Stack Cloud.
65
+
66
+ ### `azure_storage_dns_suffix` (Required only for Azure Stack Cloud)
67
+
68
+ Your Azure Storage endpoint suffix. This can be retrieved from Azure Storage connection string, `EndpointSuffix` section.
69
+
62
70
  ### `azure_storage_account` (Required)
63
71
 
64
72
  Your Azure Storage Account Name. This can be retrieved from Azure Management portal.
@@ -72,11 +80,11 @@ If all are empty, the plugin will use the local Managed Identity endpoint to obt
72
80
 
73
81
  ### `azure_imds_api_version` (Optional, only for MSI)
74
82
 
75
- Default: `2019-08-15`
83
+ Default: `2020-12-01`
76
84
 
77
85
  The Instance Metadata Service is used during the OAuth flow to obtain an access token. This API is versioned and specifying the version is mandatory.
78
86
 
79
- See [here](https://docs.microsoft.com/en-us/azure/virtual-machines/linux/instance-metadata-service#versioning) for more details.
87
+ See [here](https://docs.microsoft.com/en-us/azure/virtual-machines/linux/instance-metadata-service?tabs=windows#versioning) for more details.
80
88
 
81
89
  ### `azure_token_refresh_interval` (Optional, only for MSI)
82
90
 
@@ -140,6 +148,20 @@ The [fluent-mixin-config-placeholders](https://github.com/tagomoris/fluent-mixin
140
148
 
141
149
  Format of the time used in the file name. Default is '%Y%m%d'. Use '%Y%m%d%H' to split files hourly.
142
150
 
151
+ ### `compress`
152
+
153
+ Default: `false`
154
+
155
+ If `true`, compress (gzip) the file prior to uploading it.
156
+
157
+ Note: If desired, set `.gz` suffix via `azure_object_key_format`.
158
+
159
+ Example:
160
+
161
+ ```
162
+ azure_object_key_format %{path}%{time_slice}-%{index}.log.gz
163
+ ```
164
+
143
165
  ### `compute_checksums`
144
166
 
145
167
  Default: `true`
@@ -3,7 +3,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
 
4
4
  Gem::Specification.new do |spec|
5
5
  spec.name = 'fluent-plugin-azure-storage-append-blob-lts'
6
- spec.version = '0.6.2'
6
+ spec.version = '0.7.0'
7
7
  spec.authors = ['Jonas-Taha El Sesiy']
8
8
  spec.email = ['github@elsesiy.com']
9
9
 
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.executables = files.grep(%r{^bin/}) { |f| File.basename(f) }
20
20
  spec.test_files = test_files
21
21
  spec.require_paths = ['lib']
22
- spec.required_ruby_version = '>= 2.6'
22
+ spec.required_ruby_version = '>= 3.1'
23
23
 
24
24
  spec.add_development_dependency 'bundler', '~> 2.0'
25
25
  spec.add_development_dependency 'rake', '~> 13.0'
@@ -8,6 +8,7 @@ require 'azure/storage/blob'
8
8
  require 'faraday'
9
9
  require 'fluent/plugin/output'
10
10
  require 'json'
11
+ require 'zlib'
11
12
 
12
13
  module Fluent
13
14
  module Plugin
@@ -36,15 +37,17 @@ module Fluent
36
37
  config_param :azure_storage_account, :string, default: nil
37
38
  config_param :azure_storage_access_key, :string, default: nil, secret: true
38
39
  config_param :azure_storage_connection_string, :string, default: nil, secret: true
40
+ config_param :azure_storage_dns_suffix, :string, default: nil
39
41
  config_param :azure_storage_sas_token, :string, default: nil, secret: true
40
42
  config_param :azure_cloud, :string, default: 'AZUREPUBLICCLOUD'
41
43
  config_param :azure_msi_client_id, :string, default: nil
42
44
  config_param :azure_container, :string, default: nil
43
- config_param :azure_imds_api_version, :string, default: '2019-08-15'
45
+ config_param :azure_imds_api_version, :string, default: '2020-12-01'
44
46
  config_param :azure_token_refresh_interval, :integer, default: 60
45
47
  config_param :azure_object_key_format, :string, default: '%{path}%{time_slice}-%{index}.log'
46
48
  config_param :auto_create_container, :bool, default: true
47
49
  config_param :compute_checksums, :bool, default: true
50
+ config_param :compress, :bool, default: false
48
51
  config_param :format, :string, default: DEFAULT_FORMAT_TYPE
49
52
  config_param :time_slice_format, :string, default: '%Y%m%d'
50
53
  config_param :localtime, :bool, default: false
@@ -75,9 +78,15 @@ module Fluent
75
78
  end
76
79
  end
77
80
 
78
- @azure_storage_dns_suffix = @storage_endpoint_mapping[@azure_cloud]
79
- if @azure_storage_dns_suffix.nil?
80
- raise ConfigError 'azure_cloud invalid, must be either of AZURECHINACLOUD, AZUREGERMANCLOUD, AZUREPUBLICCLOUD, AZUREUSGOVERNMENTCLOUD'
81
+ if @azure_cloud == 'AZURESTACKCLOUD'
82
+ if @azure_storage_dns_suffix.nil?
83
+ raise ConfigError, 'azure_storage_dns_suffix invalid, must not be empty for AZURESTACKCLOUD'
84
+ end
85
+ else
86
+ @azure_storage_dns_suffix = @storage_endpoint_mapping[@azure_cloud]
87
+ if @azure_storage_dns_suffix.nil?
88
+ raise ConfigError, 'azure_cloud invalid, must be either of AZURECHINACLOUD, AZUREGERMANCLOUD, AZUREPUBLICCLOUD, AZUREUSGOVERNMENTCLOUD, AZURESTACKCLOUD'
89
+ end
81
90
  end
82
91
 
83
92
  if (@azure_storage_access_key.nil? || @azure_storage_access_key.empty?) &&
@@ -117,7 +126,9 @@ module Fluent
117
126
 
118
127
  def start
119
128
  super
120
- if @use_msi
129
+ if @bs
130
+ # nop
131
+ elsif @use_msi
121
132
  token_credential = Azure::Storage::Common::Core::TokenCredential.new get_access_token
122
133
  token_signer = Azure::Storage::Common::Core::Auth::TokenSigner.new token_credential
123
134
  @bs = Azure::Storage::Blob::BlobService.new(
@@ -164,10 +175,49 @@ module Fluent
164
175
  @formatter.format(tag, time, r)
165
176
  end
166
177
 
178
+ def write_compress(chunk, tmp)
179
+ tmp.binmode
180
+ write_compress_helper(chunk, tmp)
181
+ tmp.rewind
182
+ end
183
+
184
+ # ref: https://github.com/fluent/fluent-plugin-s3/blob/master/lib/fluent/plugin/s3_compressor_gzip_command.rb
185
+ def write_compress_helper(chunk, tmp)
186
+ chunk_is_file = @buffer_type == 'file'
187
+ path = if chunk_is_file
188
+ chunk.path
189
+ else
190
+ w = Tempfile.new("chunk-gzip-tmp")
191
+ w.binmode
192
+ chunk.write_to(w)
193
+ w.close
194
+ w.path
195
+ end
196
+
197
+ res = system "gzip -c #{path} > #{tmp.path}"
198
+ unless res
199
+ log.warn "failed to execute gzip command. Fallback to GzipWriter. status = #{$?}"
200
+ begin
201
+ tmp.truncate(0)
202
+ gw = Zlib::GzipWriter.new(tmp)
203
+ chunk.write_to(gw)
204
+ gw.close
205
+ ensure
206
+ gw.close rescue nil
207
+ end
208
+ end
209
+ ensure
210
+ w.close(true) rescue nil
211
+ end
212
+
167
213
  def write(chunk)
168
214
  tmp = Tempfile.new('azure-')
169
215
  begin
170
- chunk.write_to(tmp)
216
+ if @compress
217
+ write_compress(chunk, tmp)
218
+ else
219
+ chunk.write_to(tmp)
220
+ end
171
221
 
172
222
  generate_log_name(chunk, @current_index)
173
223
  if @last_azure_storage_path != @azure_storage_path
@@ -2,6 +2,8 @@ require 'helper'
2
2
  require 'fluent/plugin/out_azure-storage-append-blob.rb'
3
3
  require 'azure/core/http/http_response'
4
4
  require 'azure/core/http/http_error'
5
+ require 'stringio'
6
+ require 'zlib'
5
7
 
6
8
  include Fluent::Test::Helpers
7
9
 
@@ -34,6 +36,16 @@ class AzureStorageAppendBlobOutTest < Test::Unit::TestCase
34
36
  path log
35
37
  ).freeze
36
38
 
39
+ AZURESTACKCLOUD_CONFIG = %(
40
+ azure_cloud AZURESTACKCLOUD
41
+ azure_storage_dns_suffix test.storage.dns.suffix
42
+ azure_storage_account test_storage_account
43
+ azure_storage_access_key MY_FAKE_SECRET
44
+ azure_container test_container
45
+ time_slice_format %Y%m%d-%H
46
+ path log
47
+ ).freeze
48
+
37
49
  def create_driver(conf: CONFIG, service: nil)
38
50
  d = Fluent::Test::Driver::Output.new(Fluent::Plugin::AzureStorageAppendBlobOut).configure(conf)
39
51
  d.instance.instance_variable_set(:@bs, service)
@@ -43,7 +55,7 @@ class AzureStorageAppendBlobOutTest < Test::Unit::TestCase
43
55
 
44
56
  sub_test_case 'test config' do
45
57
  test 'config should reject with no azure container' do
46
- assert_raise Fluent::ConfigError do
58
+ assert_raise Fluent::ConfigError.new('azure_container needs to be specified') do
47
59
  create_driver conf: %(
48
60
  azure_storage_account test_storage_account
49
61
  azure_storage_access_key MY_FAKE_SECRET
@@ -54,6 +66,22 @@ class AzureStorageAppendBlobOutTest < Test::Unit::TestCase
54
66
  end
55
67
  end
56
68
 
69
+ test 'config should reject for invalid cloud ' do
70
+ assert_raise Fluent::ConfigError.new('azure_cloud invalid, must be either of AZURECHINACLOUD, AZUREGERMANCLOUD, AZUREPUBLICCLOUD, AZUREUSGOVERNMENTCLOUD, AZURESTACKCLOUD') do
71
+ create_driver conf: %(
72
+ azure_cloud INVALIDCLOUD
73
+ )
74
+ end
75
+ end
76
+
77
+ test 'config should reject for Azure Stack Cloud with no azure storage dns suffix' do
78
+ assert_raise Fluent::ConfigError.new('azure_storage_dns_suffix invalid, must not be empty for AZURESTACKCLOUD') do
79
+ create_driver conf: %(
80
+ azure_cloud AZURESTACKCLOUD
81
+ )
82
+ end
83
+ end
84
+
57
85
  test 'config with access key should set instance variables' do
58
86
  d = create_driver
59
87
  assert_equal 'core.cloudapi.de', d.instance.instance_variable_get(:@azure_storage_dns_suffix)
@@ -81,6 +109,16 @@ class AzureStorageAppendBlobOutTest < Test::Unit::TestCase
81
109
  assert_equal false, d.instance.instance_variable_get(:@use_msi)
82
110
  assert_equal true, d.instance.auto_create_container
83
111
  end
112
+
113
+ test 'config for Azure Stack Cloud should set instance variables' do
114
+ d = create_driver conf: AZURESTACKCLOUD_CONFIG
115
+ assert_equal 'test.storage.dns.suffix', d.instance.instance_variable_get(:@azure_storage_dns_suffix)
116
+ assert_equal 'test_storage_account', d.instance.azure_storage_account
117
+ assert_equal 'MY_FAKE_SECRET', d.instance.azure_storage_access_key
118
+ assert_equal 'test_container', d.instance.azure_container
119
+ assert_equal true, d.instance.auto_create_container
120
+ assert_equal '%{path}%{time_slice}-%{index}.log', d.instance.azure_object_key_format
121
+ end
84
122
  end
85
123
 
86
124
  sub_test_case 'test path slicing' do
@@ -104,6 +142,18 @@ class AzureStorageAppendBlobOutTest < Test::Unit::TestCase
104
142
  end
105
143
  end
106
144
 
145
+ sub_test_case 'compress options' do
146
+ test 'compress default value' do
147
+ d = create_driver
148
+ assert_equal false, d.instance.instance_variable_get(:@compress)
149
+ end
150
+ test 'compress set true' do
151
+ config = CONFIG.clone + "\ncompress true\n"
152
+ d = create_driver conf: config
153
+ assert_equal true, d.instance.instance_variable_get(:@compress)
154
+ end
155
+ end
156
+
107
157
  # This class is used to create an Azure::Core::Http::HTTPError. HTTPError parses
108
158
  # a response object when it is created.
109
159
  class FakeResponse
@@ -116,6 +166,70 @@ class AzureStorageAppendBlobOutTest < Test::Unit::TestCase
116
166
  attr_reader :status, :body, :headers
117
167
  end
118
168
 
169
+ def uncompress_blocks(blocks)
170
+ gzip_data = blocks.join
171
+ uncompressed_data = ""
172
+ while gzip_data do
173
+ Zlib::GzipReader.wrap(StringIO.new(gzip_data.b)) do |gz|
174
+ uncompressed_data << gz.read
175
+ gzip_data = gz.unused
176
+ end
177
+ end
178
+ uncompressed_data
179
+ end
180
+
181
+ sub_test_case 'test append blob for compress' do
182
+ test 'compress 2 events 1 chunk' do
183
+ config = CONFIG.clone + %(
184
+ compress true
185
+ <buffer time>
186
+ timekey 5
187
+ timekey_wait 0
188
+ </buffer>
189
+ )
190
+
191
+ svc = FakeBlobService.new(200)
192
+ d = create_driver conf:config, service: svc
193
+
194
+ d.run(default_tag: 'test') do
195
+ d.feed(event_time("2011-01-02 13:14:15 UTC"), { :a => 1 })
196
+ d.feed(event_time("2011-01-02 13:14:15 UTC"), { :a => 2 })
197
+ end
198
+
199
+ uncompressed_data = uncompress_blocks(svc.blocks)
200
+
201
+ expected = "2011-01-02T13:14:15+00:00\ttest\t{\"a\":1}\n" +
202
+ "2011-01-02T13:14:15+00:00\ttest\t{\"a\":2}\n"
203
+ assert_equal(expected, uncompressed_data)
204
+ assert_equal(10, svc.blocks.size)
205
+ end
206
+
207
+ test 'compress 2 events 2 chunk' do
208
+ config = CONFIG.clone + %(
209
+ compress true
210
+ <buffer time>
211
+ timekey 5
212
+ timekey_wait 0
213
+ </buffer>
214
+ )
215
+
216
+ svc = FakeBlobService.new(200)
217
+ d = create_driver conf:config, service: svc
218
+
219
+ d.run(default_tag: 'test') do
220
+ d.feed(event_time("2011-01-02 13:14:00 UTC"), { :a => 1 })
221
+ d.feed(event_time("2011-01-02 13:14:15 UTC"), { :a => 2 }) # after 15 sec
222
+ end
223
+
224
+ uncompressed_data = uncompress_blocks(svc.blocks)
225
+
226
+ expected = "2011-01-02T13:14:00+00:00\ttest\t{\"a\":1}\n" +
227
+ "2011-01-02T13:14:15+00:00\ttest\t{\"a\":2}\n"
228
+ assert_equal(expected, uncompressed_data)
229
+ assert_equal(20, svc.blocks.size)
230
+ end
231
+ end
232
+
119
233
  # This class is used to test plugin functions which interact with the blob service
120
234
  class FakeBlobService
121
235
  def initialize(status)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-azure-storage-append-blob-lts
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonas-Taha El Sesiy
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-04 00:00:00.000000000 Z
11
+ date: 2023-05-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -120,14 +120,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
120
120
  requirements:
121
121
  - - ">="
122
122
  - !ruby/object:Gem::Version
123
- version: '2.6'
123
+ version: '3.1'
124
124
  required_rubygems_version: !ruby/object:Gem::Requirement
125
125
  requirements:
126
126
  - - ">="
127
127
  - !ruby/object:Gem::Version
128
128
  version: '0'
129
129
  requirements: []
130
- rubygems_version: 3.0.3
130
+ rubygems_version: 3.3.26
131
131
  signing_key:
132
132
  specification_version: 4
133
133
  summary: Azure Storage Append Blob output plugin for Fluentd event collector