fluent-plugin-azure-storage-append-blob-lts 0.5.0 → 0.6.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: e1dca8c31f6ec0f0383d24637d3c0b6225d92e8505387a5c1a422d85057f0340
4
- data.tar.gz: 240d435415a53386a245d3449d092eb2d71a85c2e08e989b841ec71b7a20a9f5
3
+ metadata.gz: 0d55d827bbb8aa8906536f7593257e42abf9c6b24e5aa485176cd5aa15284732
4
+ data.tar.gz: ff055bb2b5585ee3a38b2ed18b75ac1aa8ba6a20654be97b13a920a6566472e5
5
5
  SHA512:
6
- metadata.gz: 7744655dfad7169b43df0db53a20c781276d8dba8a83c2858e1809cb281008e9b401b6755ec6fb0efa4eff0311c2e76fc2d2e60164ffd373ef0087b81fabc9cf
7
- data.tar.gz: 046e1e69571d6502d6c06d52d49c3e97234f4b2a44e15210122941d6787bac825769b40f2c1e70cff926f8d5a6ca9cf916ee2aac42b06a82367c7b9c0f410279
6
+ metadata.gz: ea451b6605f9126c9af9e697cacccac03145631926684ac7d001eb6c18ca22755ec13cd647eb3b016cbed48678b890a61ff829644cfd041ef4c88a7495cf215c
7
+ data.tar.gz: e50e9381970ce666d3bc6337526be2e5620d6eced418b9df02a26d6f80f13ce0fb31a45e0cdef3a55090afc6276c328a660b66137005d17b1756948d77ac7491
data/Dockerfile CHANGED
@@ -1,8 +1,8 @@
1
- FROM ruby:latest
1
+ FROM ruby:2.7
2
2
 
3
3
  WORKDIR /plugin
4
4
 
5
- ADD . /plugin
5
+ COPY . /plugin
6
6
 
7
7
  RUN gem install bundler && \
8
8
  gem install fluentd --no-doc && \
data/README.md CHANGED
@@ -24,6 +24,7 @@ And then execute:
24
24
  <match pattern>
25
25
  type azure-storage-append-blob
26
26
 
27
+ azure_cloud <azure cloud environment>
27
28
  azure_storage_account <your azure storage account>
28
29
  azure_storage_access_key <your azure storage access key> # leave empty to use MSI
29
30
  azure_storage_connection_string <your azure storage connection string> # leave empty to use MSI
@@ -36,6 +37,7 @@ And then execute:
36
37
  path logs/
37
38
  azure_object_key_format %{path}%{time_slice}_%{index}.log
38
39
  time_slice_format %Y%m%d-%H
40
+ calculate_checksums true
39
41
  # if you want to use %{tag} or %Y/%m/%d/ like syntax in path / azure_blob_name_format,
40
42
  # need to specify tag for %{tag} and time for %Y/%m/%d in <buffer> argument.
41
43
  <buffer tag,time>
@@ -47,6 +49,12 @@ And then execute:
47
49
  </buffer>
48
50
  </match>
49
51
 
52
+ ### `azure_cloud` (Optional)
53
+
54
+ Default: `AZUREPUBLICCLOUD`
55
+
56
+ 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).
57
+
50
58
  ### `azure_storage_account` (Required)
51
59
 
52
60
  Your Azure Storage Account Name. This can be retrieved from Azure Management portal.
@@ -60,7 +68,7 @@ If all are empty, the plugin will use the local Managed Identity endpoint to obt
60
68
 
61
69
  ### `azure_imds_api_version` (Optional, only for MSI)
62
70
 
63
- Default: 2019-08-15
71
+ Default: `2019-08-15`
64
72
 
65
73
  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.
66
74
 
@@ -68,7 +76,7 @@ See [here](https://docs.microsoft.com/en-us/azure/virtual-machines/linux/instanc
68
76
 
69
77
  ### `azure_token_refresh_interval` (Optional, only for MSI)
70
78
 
71
- Default: 60 (1 hour)
79
+ Default: `60` (1 hour)
72
80
 
73
81
  When using MSI, the initial access token needs to be refreshed periodically.
74
82
 
@@ -82,8 +90,9 @@ Azure Identity Client ID to use for accessing Azure Blob service.
82
90
 
83
91
  ### `auto_create_container`
84
92
 
93
+ Default: `true`
94
+
85
95
  This plugin creates the Azure container if it does not already exist exist when you set 'auto_create_container' to true.
86
- The default value is `true`
87
96
 
88
97
  ### `azure_object_key_format`
89
98
 
@@ -127,6 +136,14 @@ The [fluent-mixin-config-placeholders](https://github.com/tagomoris/fluent-mixin
127
136
 
128
137
  Format of the time used in the file name. Default is '%Y%m%d'. Use '%Y%m%d%H' to split files hourly.
129
138
 
139
+ ### `calculate_checksums`
140
+
141
+ Default: `true`
142
+
143
+ Whether to calculate MD5 checksum of the blob contents during append operation and provide it in a header for the blob service.
144
+
145
+ You want to set it to `false` in FIPS-enabled environments.
146
+
130
147
  ### Run tests
131
148
 
132
149
  gem install bundler
@@ -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.5.0'
6
+ spec.version = '0.6.0'
7
7
  spec.authors = ['Jonas-Taha El Sesiy']
8
8
  spec.email = ['github@elsesiy.com']
9
9
 
@@ -11,7 +11,7 @@ require 'json'
11
11
 
12
12
  module Fluent
13
13
  module Plugin
14
- class AzureStorageAppendBlobOut < Fluent::Plugin::Output
14
+ class AzureStorageAppendBlobOut < Output
15
15
  Fluent::Plugin.register_output('azure-storage-append-blob', self)
16
16
 
17
17
  helpers :formatter, :inject
@@ -19,18 +19,32 @@ module Fluent
19
19
  DEFAULT_FORMAT_TYPE = 'out_file'.freeze
20
20
  AZURE_BLOCK_SIZE_LIMIT = 4 * 1024 * 1024 - 1
21
21
 
22
+ def initialize
23
+ super
24
+ @use_msi = false
25
+
26
+ # Storage endpoint suffixes for various environments, see https://github.com/Azure/go-autorest/blob/master/autorest/azure/environments.go
27
+ @storage_endpoint_mapping = {
28
+ 'AZURECHINACLOUD' => 'core.chinacloudapi.cn',
29
+ 'AZUREGERMANCLOUD' => 'core.cloudapi.de',
30
+ 'AZUREPUBLICCLOUD' => 'core.windows.net',
31
+ 'AZUREUSGOVERNMENTCLOUD' => 'core.usgovcloudapi.net'
32
+ }
33
+ end
34
+
22
35
  config_param :path, :string, default: ''
23
36
  config_param :azure_storage_account, :string, default: nil
24
37
  config_param :azure_storage_access_key, :string, default: nil, secret: true
25
- config_param :azure_storage_sas_token, :string, default: nil, secret: true
26
38
  config_param :azure_storage_connection_string, :string, default: nil, secret: true
39
+ config_param :azure_storage_sas_token, :string, default: nil, secret: true
40
+ config_param :azure_cloud, :string, default: 'AZUREPUBLICCLOUD'
27
41
  config_param :azure_msi_client_id, :string, default: nil
28
42
  config_param :azure_container, :string, default: nil
29
43
  config_param :azure_imds_api_version, :string, default: '2019-08-15'
30
44
  config_param :azure_token_refresh_interval, :integer, default: 60
31
- config_param :use_msi, :bool, default: false
32
45
  config_param :azure_object_key_format, :string, default: '%{path}%{time_slice}-%{index}.log'
33
46
  config_param :auto_create_container, :bool, default: true
47
+ config_param :calculate_checksums, :bool, default: true
34
48
  config_param :format, :string, default: DEFAULT_FORMAT_TYPE
35
49
  config_param :time_slice_format, :string, default: '%Y%m%d'
36
50
  config_param :localtime, :bool, default: false
@@ -61,6 +75,11 @@ module Fluent
61
75
  end
62
76
  end
63
77
 
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
+ end
82
+
64
83
  if (@azure_storage_access_key.nil? || @azure_storage_access_key.empty?) &&
65
84
  (@azure_storage_sas_token.nil? || @azure_storage_sas_token.empty?) &&
66
85
  (@azure_storage_connection_string.nil? || @azure_storage_connection_string.empty?)
@@ -70,6 +89,12 @@ module Fluent
70
89
  raise ConfigError, 'azure_storage_account needs to be specified' if @azure_storage_account.nil?
71
90
  raise ConfigError, 'azure_container needs to be specified' if @azure_container.nil?
72
91
  end
92
+
93
+ @blob_options = {}
94
+
95
+ if !@calculate_checksums
96
+ @blob_options[:content_md5] = ''
97
+ end
73
98
  end
74
99
 
75
100
  def multi_workers_ready?
@@ -80,13 +105,13 @@ module Fluent
80
105
  access_key_request = Faraday.new('http://169.254.169.254/metadata/identity/oauth2/token?' \
81
106
  "api-version=#{@azure_imds_api_version}" \
82
107
  '&resource=https://storage.azure.com/' \
83
- "#{! azure_msi_client_id.nil? ? "&client_id=#{azure_msi_client_id}" : ''}",
108
+ "#{!azure_msi_client_id.nil? ? "&client_id=#{azure_msi_client_id}" : ''}",
84
109
  headers: { 'Metadata' => 'true' }).get
85
110
 
86
111
  if access_key_request.status == 200
87
112
  JSON.parse(access_key_request.body)['access_token']
88
113
  else
89
- raise "Access token request was not sucssessful. Possibly due to missing azure_msi_client_id config parameter."
114
+ raise 'Access token request was not sucssessful. Possibly due to missing azure_msi_client_id config parameter.'
90
115
  end
91
116
  end
92
117
 
@@ -95,7 +120,11 @@ module Fluent
95
120
  if @use_msi
96
121
  token_credential = Azure::Storage::Common::Core::TokenCredential.new get_access_token
97
122
  token_signer = Azure::Storage::Common::Core::Auth::TokenSigner.new token_credential
98
- @bs = Azure::Storage::Blob::BlobService.new(storage_account_name: @azure_storage_account, signer: token_signer)
123
+ @bs = Azure::Storage::Blob::BlobService.new(
124
+ storage_account_name: @azure_storage_account,
125
+ storage_dns_suffix: @azure_storage_dns_suffix,
126
+ signer: token_signer
127
+ )
99
128
 
100
129
  refresh_interval = @azure_token_refresh_interval * 60
101
130
  cancelled = false
@@ -112,7 +141,7 @@ module Fluent
112
141
  elsif !@azure_storage_connection_string.nil? && !@azure_storage_connection_string.empty?
113
142
  @bs = Azure::Storage::Blob::BlobService.create_from_connection_string(@azure_storage_connection_string)
114
143
  else
115
- @bs_params = { storage_account_name: @azure_storage_account }
144
+ @bs_params = { storage_account_name: @azure_storage_account, storage_dns_suffix: @azure_storage_dns_suffix }
116
145
 
117
146
  if !@azure_storage_access_key.nil? && !@azure_storage_access_key.empty?
118
147
  @bs_params.merge!({ storage_access_key: @azure_storage_access_key })
@@ -152,7 +181,11 @@ module Fluent
152
181
  append_blob(content, metadata)
153
182
  @last_azure_storage_path = @azure_storage_path
154
183
  ensure
155
- tmp.close(true) rescue nil
184
+ begin
185
+ tmp.close(true)
186
+ rescue StandardError
187
+ nil
188
+ end
156
189
  end
157
190
  end
158
191
 
@@ -202,34 +235,32 @@ module Fluent
202
235
  position = 0
203
236
  log.debug "azure_storage_append_blob: append_blob.start: Content size: #{content.length}"
204
237
  loop do
205
- begin
206
- size = [content.length - position, AZURE_BLOCK_SIZE_LIMIT].min
207
- log.debug "azure_storage_append_blob: append_blob.chunk: content[#{position}..#{position + size}]"
208
- @bs.append_blob_block(@azure_container, @azure_storage_path, content[position..position + size - 1])
209
- position += size
210
- break if position >= content.length
211
- rescue Azure::Core::Http::HTTPError => e
212
- status_code = e.status_code
213
-
214
- if status_code == 409 # exceeds azure block limit
215
- @current_index += 1
216
- old_azure_storage_path = @azure_storage_path
217
- generate_log_name(metadata, @current_index)
218
-
219
- # If index is not a part of format, rethrow exception.
220
- if old_azure_storage_path == @azure_storage_path
221
- log.warn 'azure_storage_append_blob: append_blob: blocks limit reached, you need to use %{index} for the format.'
222
- raise
223
- end
224
-
225
- log.debug "azure_storage_append_blob: append_blob: blocks limit reached, creating new blob #{@azure_storage_path}."
226
- @bs.create_append_blob(@azure_container, @azure_storage_path)
227
- elsif status_code == 404 # blob not found
228
- log.debug "azure_storage_append_blob: append_blob: #{@azure_storage_path} blob doesn't exist, creating new blob."
229
- @bs.create_append_blob(@azure_container, @azure_storage_path)
230
- else
238
+ size = [content.length - position, AZURE_BLOCK_SIZE_LIMIT].min
239
+ log.debug "azure_storage_append_blob: append_blob.chunk: content[#{position}..#{position + size}]"
240
+ @bs.append_blob_block(@azure_container, @azure_storage_path, content[position..position + size - 1], options=@blob_options)
241
+ position += size
242
+ break if position >= content.length
243
+ rescue Azure::Core::Http::HTTPError => e
244
+ status_code = e.status_code
245
+
246
+ if status_code == 409 # exceeds azure block limit
247
+ @current_index += 1
248
+ old_azure_storage_path = @azure_storage_path
249
+ generate_log_name(metadata, @current_index)
250
+
251
+ # If index is not a part of format, rethrow exception.
252
+ if old_azure_storage_path == @azure_storage_path
253
+ log.warn 'azure_storage_append_blob: append_blob: blocks limit reached, you need to use %{index} for the format.'
231
254
  raise
232
255
  end
256
+
257
+ log.debug "azure_storage_append_blob: append_blob: blocks limit reached, creating new blob #{@azure_storage_path}."
258
+ @bs.create_append_blob(@azure_container, @azure_storage_path)
259
+ elsif status_code == 404 # blob not found
260
+ log.debug "azure_storage_append_blob: append_blob: #{@azure_storage_path} blob doesn't exist, creating new blob."
261
+ @bs.create_append_blob(@azure_container, @azure_storage_path)
262
+ else
263
+ raise
233
264
  end
234
265
  end
235
266
  log.debug 'azure_storage_append_blob: append_blob.complete'
@@ -11,6 +11,7 @@ class AzureStorageAppendBlobOutTest < Test::Unit::TestCase
11
11
  end
12
12
 
13
13
  CONFIG = %(
14
+ azure_cloud AZUREGERMANCLOUD
14
15
  azure_storage_account test_storage_account
15
16
  azure_storage_access_key MY_FAKE_SECRET
16
17
  azure_container test_container
@@ -55,6 +56,7 @@ class AzureStorageAppendBlobOutTest < Test::Unit::TestCase
55
56
 
56
57
  test 'config with access key should set instance variables' do
57
58
  d = create_driver
59
+ assert_equal 'core.cloudapi.de', d.instance.instance_variable_get(:@azure_storage_dns_suffix)
58
60
  assert_equal 'test_storage_account', d.instance.azure_storage_account
59
61
  assert_equal 'MY_FAKE_SECRET', d.instance.azure_storage_access_key
60
62
  assert_equal 'test_container', d.instance.azure_container
@@ -66,7 +68,7 @@ class AzureStorageAppendBlobOutTest < Test::Unit::TestCase
66
68
  d = create_driver conf: MSI_CONFIG
67
69
  assert_equal 'test_storage_account', d.instance.azure_storage_account
68
70
  assert_equal 'test_container', d.instance.azure_container
69
- assert_equal true, d.instance.use_msi
71
+ assert_equal true, d.instance.instance_variable_get(:@use_msi)
70
72
  assert_equal true, d.instance.auto_create_container
71
73
  assert_equal '%{path}%{time_slice}-%{index}.log', d.instance.azure_object_key_format
72
74
  assert_equal 120, d.instance.azure_token_refresh_interval
@@ -76,7 +78,7 @@ class AzureStorageAppendBlobOutTest < Test::Unit::TestCase
76
78
  test 'config with connection string should set instance variables' do
77
79
  d = create_driver conf: CONNSTR_CONFIG
78
80
  assert_equal 'https://test', d.instance.azure_storage_connection_string
79
- assert_equal false, d.instance.use_msi
81
+ assert_equal false, d.instance.instance_variable_get(:@use_msi)
80
82
  assert_equal true, d.instance.auto_create_container
81
83
  end
82
84
  end
@@ -122,11 +124,11 @@ class AzureStorageAppendBlobOutTest < Test::Unit::TestCase
122
124
  end
123
125
  attr_reader :blocks
124
126
 
125
- def append_blob_block(container, path, data)
127
+ def append_blob_block(_container, _path, data, options={})
126
128
  @blocks.append(data)
127
129
  end
128
130
 
129
- def get_container_properties(container)
131
+ def get_container_properties(_container)
130
132
  unless @response.status_code == 200
131
133
  raise Azure::Core::Http::HTTPError.new(@response)
132
134
  end
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.5.0
4
+ version: 0.6.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-01-31 00:00:00.000000000 Z
11
+ date: 2021-02-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler