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