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

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: 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