fluent-plugin-azure-storage-append-blob-lts 0.5.0 → 0.6.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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0d55d827bbb8aa8906536f7593257e42abf9c6b24e5aa485176cd5aa15284732
|
4
|
+
data.tar.gz: ff055bb2b5585ee3a38b2ed18b75ac1aa8ba6a20654be97b13a920a6566472e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ea451b6605f9126c9af9e697cacccac03145631926684ac7d001eb6c18ca22755ec13cd647eb3b016cbed48678b890a61ff829644cfd041ef4c88a7495cf215c
|
7
|
+
data.tar.gz: e50e9381970ce666d3bc6337526be2e5620d6eced418b9df02a26d6f80f13ce0fb31a45e0cdef3a55090afc6276c328a660b66137005d17b1756948d77ac7491
|
data/Dockerfile
CHANGED
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.
|
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 <
|
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
|
-
"#{!
|
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
|
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(
|
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
|
-
|
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
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
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(
|
127
|
+
def append_blob_block(_container, _path, data, options={})
|
126
128
|
@blocks.append(data)
|
127
129
|
end
|
128
130
|
|
129
|
-
def get_container_properties(
|
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.
|
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-
|
11
|
+
date: 2021-02-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|