fluent-plugin-azurestorage-gen2 0.2.10 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +35 -0
- data/VERSION +1 -1
- data/lib/fluent/plugin/out_azurestorage_gen2.rb +112 -16
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: eeea9ef451a8996e41202f49defb227905aeec16aab55f6f208617517365b929
|
4
|
+
data.tar.gz: 0c2027d20716c613c35ee0a325694225d138f0712fc4ca638962beef9397edea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 65a5ffaea781a9e74f860f489e91f2fc0f0264a8998ffd694808688e48a826a5f3af5d02c1b07091565324c70ad7d6dcfbdfcbb7278d108eacd01089964cdf6c
|
7
|
+
data.tar.gz: 40f629211e74147a59dadf047809f1b743ef01437542b9c880b0a2fe51907dd182a2db49a90ba9c80c1aa3741a30b739d59452b31a195ffb839529559b6c3c70
|
data/README.md
CHANGED
@@ -31,6 +31,7 @@ $ gem install fluent-plugin-azurestorage-gen2
|
|
31
31
|
azure_storage_account mystorageabfs
|
32
32
|
azure_container mycontainer
|
33
33
|
azure_instance_msi /subscriptions/mysubscriptionid
|
34
|
+
azure_client_id <msi client id>
|
34
35
|
azure_object_key_format %{path}-%{index}.%{file_extension}
|
35
36
|
azure_oauth_refresh_interval 3600
|
36
37
|
time_slice_format %Y%m%d-%H
|
@@ -92,6 +93,14 @@ Your Azure Storage Access Key(Primary or Secondary). This also can be got from A
|
|
92
93
|
|
93
94
|
Your Azure Managed Service Identity ID. When storage key authentication is not used, the plugin uses OAuth2 to authenticate as given MSI. This authentication method only works on Azure VM. If the VM has only one MSI assigned, this parameter becomes optional and the only MSI will be used. Otherwise this parameter is required.
|
94
95
|
|
96
|
+
### azure_client_id
|
97
|
+
|
98
|
+
Azure AD client id is a specific explicit identity to use when authenticating to Azure AD. Mutually exclusive with azure_object_id and azure_instance_msi. (for now, you need to define next to `azure_instance_msi`)
|
99
|
+
|
100
|
+
### azure_object_id
|
101
|
+
|
102
|
+
Azure AD object id is a specific explicit identity to use when authenticating to Azure AD. Mutually exclusive with azure_client_id and azure_instance_msi. (for now, you need to define next to `azure_instance_msi`)
|
103
|
+
|
95
104
|
### azure_oauth_tenant_id (Preview)
|
96
105
|
|
97
106
|
Azure account tenant id from your Azure Directory. Required if OAuth based credential mechanism is used.
|
@@ -152,6 +161,7 @@ The format of Azure Storage object keys. You can use several built-in variables:
|
|
152
161
|
- %{time_slice}
|
153
162
|
- %{index}
|
154
163
|
- %{file_extension}
|
164
|
+
- %{upload_timestamp}
|
155
165
|
|
156
166
|
to decide keys dynamically.
|
157
167
|
|
@@ -159,6 +169,7 @@ to decide keys dynamically.
|
|
159
169
|
%{time_slice} is the time-slice in text that are formatted with *time_slice_format*.
|
160
170
|
%{index} is the sequential number starts from 0, increments when multiple files are uploaded to Azure Storage in the same time slice.
|
161
171
|
%{file_extention} is always "gz" for now.
|
172
|
+
%{upload_timestamp} is an upload timestamp in text that are formatted with *upload_timestamp_format*. Difference between time_slice and upload_timestamp is that the second one is the actual system timestamp (other one is from the metadata)
|
162
173
|
|
163
174
|
The default format is "%{path}%{time_slice}_%{index}.%{file_extension}".
|
164
175
|
|
@@ -283,10 +294,34 @@ Format of the time used as the file name. Default is '%Y%m%d'. Use '%Y%m%d%H' to
|
|
283
294
|
|
284
295
|
The time to wait old logs. Default is 10 minutes.
|
285
296
|
|
297
|
+
### upload_timestamp_format
|
298
|
+
|
299
|
+
Format of the upload timestamp used as the file name. Can be used instead of index in case of `write_only` option is enabled. Default value is '%H%M%S%L'.
|
300
|
+
|
286
301
|
### utc
|
287
302
|
|
288
303
|
Use UTC instead of local time.
|
289
304
|
|
305
|
+
### write_only
|
306
|
+
|
307
|
+
If that option is enabled, HEAD calls are skipped during blob operations. (so make sure to set the chunk limit to 4MB in order to avoid HEAD operation because of the append operation needs the last position of the uploaded blobs).
|
308
|
+
|
309
|
+
### proxy_url
|
310
|
+
|
311
|
+
Proxy URL for Azure endpoint.
|
312
|
+
|
313
|
+
### proxy_username
|
314
|
+
|
315
|
+
Proxy username for Azure proxy endpoint (used only if `proxy_url` is filled)
|
316
|
+
|
317
|
+
### proxy_password
|
318
|
+
|
319
|
+
Proxy password for Azure `proxy_username` (used only if `proxy_url` is filled)
|
320
|
+
|
321
|
+
### http_timeout_seconds
|
322
|
+
|
323
|
+
The time limit for HTTP request in seconds. Default: 120
|
324
|
+
|
290
325
|
## TODOs
|
291
326
|
|
292
327
|
- add storage key support
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.3
|
@@ -24,6 +24,8 @@ module Fluent::Plugin
|
|
24
24
|
config_param :azure_storage_account, :string, :default => nil
|
25
25
|
config_param :azure_storage_access_key, :string, :default => nil, :secret => true
|
26
26
|
config_param :azure_instance_msi, :string, :default => nil
|
27
|
+
config_param :azure_client_id, :string, :default => nil
|
28
|
+
config_param :azure_object_id, :string, :default => nil
|
27
29
|
config_param :azure_oauth_app_id, :string, :default => nil, :secret => true
|
28
30
|
config_param :azure_oauth_secret, :string, :default => nil, :secret => true
|
29
31
|
config_param :azure_oauth_tenant_id, :string, :default => nil
|
@@ -44,6 +46,12 @@ module Fluent::Plugin
|
|
44
46
|
config_param :time_slice_format, :string, :default => '%Y%m%d'
|
45
47
|
config_param :hex_random_length, :integer, default: 4
|
46
48
|
config_param :command_parameter, :string, :default => nil
|
49
|
+
config_param :proxy_url, :string, :default => nil
|
50
|
+
config_param :proxy_username, :string, :default => nil
|
51
|
+
config_param :proxy_password, :string, :default => nil, :secret => true
|
52
|
+
config_param :write_only, :bool, :default => false
|
53
|
+
config_param :upload_timestamp_format, :string, :default => '%H%M%S%L'
|
54
|
+
config_param :http_timeout_seconds, :integer, :default => 120
|
47
55
|
|
48
56
|
DEFAULT_FORMAT_TYPE = "out_file"
|
49
57
|
ACCESS_TOKEN_API_VERSION = "2018-02-01"
|
@@ -53,7 +61,7 @@ module Fluent::Plugin
|
|
53
61
|
config_section :format do
|
54
62
|
config_set_default :@type, DEFAULT_FORMAT_TYPE
|
55
63
|
end
|
56
|
-
|
64
|
+
|
57
65
|
config_section :buffer do
|
58
66
|
config_set_default :chunk_keys, ['time']
|
59
67
|
config_set_default :timekey, (60 * 60 * 24)
|
@@ -76,7 +84,7 @@ module Fluent::Plugin
|
|
76
84
|
end
|
77
85
|
|
78
86
|
@formatter = formatter_create
|
79
|
-
|
87
|
+
|
80
88
|
if @azure_container.nil?
|
81
89
|
raise Fluent::ConfigError, "azure_container is needed"
|
82
90
|
end
|
@@ -102,12 +110,20 @@ module Fluent::Plugin
|
|
102
110
|
if !@skip_container_check
|
103
111
|
if @failsafe_container_check
|
104
112
|
begin
|
105
|
-
|
113
|
+
if @write_only && @auto_create_container
|
114
|
+
create_container
|
115
|
+
else
|
116
|
+
ensure_container
|
117
|
+
end
|
106
118
|
rescue Exception => e
|
107
119
|
log.warn("#{e.message}, container list/create failsafe is enabled. Continue without those operations.")
|
108
120
|
end
|
109
121
|
else
|
110
|
-
|
122
|
+
if @write_only && @auto_create_container
|
123
|
+
create_container
|
124
|
+
else
|
125
|
+
ensure_container
|
126
|
+
end
|
111
127
|
end
|
112
128
|
end
|
113
129
|
super
|
@@ -158,11 +174,16 @@ module Fluent::Plugin
|
|
158
174
|
private
|
159
175
|
def upload_blob(content, chunk)
|
160
176
|
log.debug "azurestorage_gen2: Uploading blob: #{@azure_storage_path}"
|
161
|
-
|
162
|
-
if existing_content_length == 0
|
177
|
+
if @write_only
|
163
178
|
create_blob(@azure_storage_path)
|
179
|
+
append_blob(content, chunk, 0)
|
180
|
+
else
|
181
|
+
existing_content_length = get_blob_properties(@azure_storage_path)
|
182
|
+
if existing_content_length == 0
|
183
|
+
create_blob(@azure_storage_path)
|
184
|
+
end
|
185
|
+
append_blob(content, chunk, existing_content_length)
|
164
186
|
end
|
165
|
-
append_blob(content, chunk, existing_content_length)
|
166
187
|
end
|
167
188
|
|
168
189
|
private
|
@@ -175,8 +196,10 @@ module Fluent::Plugin
|
|
175
196
|
end
|
176
197
|
if @localtime
|
177
198
|
hms_slicer = Time.now.strftime("%H%M%S")
|
199
|
+
upload_timestamp = Time.now.strftime(@upload_timestamp_format)
|
178
200
|
else
|
179
201
|
hms_slicer = Time.now.utc.strftime("%H%M%S")
|
202
|
+
upload_timestamp = Time.now.utc.strftime(@upload_timestamp_format)
|
180
203
|
end
|
181
204
|
|
182
205
|
@values_for_object_chunk[chunk.unique_id] ||= {
|
@@ -186,7 +209,8 @@ module Fluent::Plugin
|
|
186
209
|
"%{path}" => @path,
|
187
210
|
"%{index}" => index,
|
188
211
|
"%{uuid_flush}" => uuid_random,
|
189
|
-
"%{file_extension}" => @final_file_extension
|
212
|
+
"%{file_extension}" => @final_file_extension,
|
213
|
+
"%{upload_timestamp}" => upload_timestamp,
|
190
214
|
}
|
191
215
|
values_for_object_key_post = {
|
192
216
|
"%{date_slice}" => time_slice,
|
@@ -255,7 +279,19 @@ module Fluent::Plugin
|
|
255
279
|
unless @azure_instance_msi.nil?
|
256
280
|
params[:msi_res_id] = @azure_instance_msi
|
257
281
|
end
|
258
|
-
|
282
|
+
unless @azure_client_id.nil?
|
283
|
+
params[:client_id] = @azure_client_id
|
284
|
+
end
|
285
|
+
unless @azure_object_id.nil?
|
286
|
+
params[:object_id] = @azure_object_id
|
287
|
+
end
|
288
|
+
req_opts = {
|
289
|
+
:params => params,
|
290
|
+
:headers => { Metadata: "true" },
|
291
|
+
:timeout => @http_timeout_seconds
|
292
|
+
}
|
293
|
+
add_proxy_options(req_opts)
|
294
|
+
request = Typhoeus::Request.new("http://169.254.169.254/metadata/identity/oauth2/token", req_opts)
|
259
295
|
request.on_complete do |response|
|
260
296
|
if response.success?
|
261
297
|
data = JSON.parse(response.body)
|
@@ -273,7 +309,14 @@ module Fluent::Plugin
|
|
273
309
|
params = { :"api-version" => ACCESS_TOKEN_API_VERSION, :resource => "#{@url_storage_resource}"}
|
274
310
|
headers = {:"Content-Type" => "application/x-www-form-urlencoded"}
|
275
311
|
content = "grant_type=client_credentials&client_id=#{@azure_oauth_app_id}&client_secret=#{@azure_oauth_secret}&resource=#{@url_storage_resource}"
|
276
|
-
|
312
|
+
req_opts = {
|
313
|
+
:params => params,
|
314
|
+
:body => content,
|
315
|
+
:headers => headers,
|
316
|
+
:timeout => @http_timeout_seconds
|
317
|
+
}
|
318
|
+
add_proxy_options(req_opts)
|
319
|
+
request = Typhoeus::Request.new("https://login.microsoftonline.com/#{@azure_oauth_tenant_id}/oauth2/token", req_opts)
|
277
320
|
request.on_complete do |response|
|
278
321
|
if response.success?
|
279
322
|
data = JSON.parse(response.body)
|
@@ -300,7 +343,14 @@ module Fluent::Plugin
|
|
300
343
|
params = {:resource => "filesystem" }
|
301
344
|
auth_header = create_auth_header("head", datestamp, "#{@azure_container}", headers, params)
|
302
345
|
headers[:Authorization] = auth_header
|
303
|
-
|
346
|
+
req_opts = {
|
347
|
+
:method => :head,
|
348
|
+
:params => params,
|
349
|
+
:headers => headers,
|
350
|
+
:timeout => @http_timeout_seconds
|
351
|
+
}
|
352
|
+
add_proxy_options(req_opts)
|
353
|
+
request = Typhoeus::Request.new("https://#{azure_storage_account}#{@url_domain_suffix}/#{@azure_container}", req_opts)
|
304
354
|
request.on_complete do |response|
|
305
355
|
if response.success?
|
306
356
|
log.info "azurestorage_gen2: Container '#{@azure_container}' exists."
|
@@ -327,7 +377,14 @@ module Fluent::Plugin
|
|
327
377
|
params = {:resource => "filesystem" }
|
328
378
|
auth_header = create_auth_header("put", datestamp, "#{@azure_container}", headers, params)
|
329
379
|
headers[:Authorization] = auth_header
|
330
|
-
|
380
|
+
req_opts = {
|
381
|
+
:method => :put,
|
382
|
+
:params => params,
|
383
|
+
:headers => headers,
|
384
|
+
:timeout => @http_timeout_seconds
|
385
|
+
}
|
386
|
+
add_proxy_options(req_opts)
|
387
|
+
request = Typhoeus::Request.new("https://#{azure_storage_account}#{@url_domain_suffix}/#{@azure_container}", req_opts)
|
331
388
|
request.on_complete do |response|
|
332
389
|
if response.success?
|
333
390
|
log.debug "azurestorage_gen2: Container '#{@azure_container}' created, response code: #{response.code}"
|
@@ -347,7 +404,14 @@ module Fluent::Plugin
|
|
347
404
|
params = {:resource => "file", :recursive => "false"}
|
348
405
|
auth_header = create_auth_header("put", datestamp, "#{@azure_container}#{blob_path}", headers, params)
|
349
406
|
headers[:Authorization] = auth_header
|
350
|
-
|
407
|
+
req_opts = {
|
408
|
+
:method => :put,
|
409
|
+
:params => params,
|
410
|
+
:headers => headers,
|
411
|
+
:timeout => @http_timeout_seconds
|
412
|
+
}
|
413
|
+
add_proxy_options(req_opts)
|
414
|
+
request = Typhoeus::Request.new("https://#{azure_storage_account}#{@url_domain_suffix}/#{@azure_container}#{blob_path}", req_opts)
|
351
415
|
request.on_complete do |response|
|
352
416
|
if response.success?
|
353
417
|
log.debug "azurestorage_gen2: Blob '#{blob_path}' has been created, response code: #{response.code}"
|
@@ -370,7 +434,15 @@ module Fluent::Plugin
|
|
370
434
|
params = {:action => "append", :position => "#{position}"}
|
371
435
|
auth_header = create_auth_header("patch", datestamp, "#{@azure_container}#{blob_path}", headers, params)
|
372
436
|
headers[:Authorization] = auth_header
|
373
|
-
|
437
|
+
req_opts = {
|
438
|
+
:method => :patch,
|
439
|
+
:params => params,
|
440
|
+
:headers => headers,
|
441
|
+
:body => content,
|
442
|
+
:timeout => @http_timeout_seconds
|
443
|
+
}
|
444
|
+
add_proxy_options(req_opts)
|
445
|
+
request = Typhoeus::Request.new("https://#{azure_storage_account}#{@url_domain_suffix}/#{@azure_container}#{blob_path}", req_opts)
|
374
446
|
request.on_complete do |response|
|
375
447
|
if response.success?
|
376
448
|
log.debug "azurestorage_gen2: Blob '#{blob_path}' has been appended, response code: #{response.code}"
|
@@ -395,7 +467,14 @@ module Fluent::Plugin
|
|
395
467
|
params = {:action => "flush", :position => "#{position}"}
|
396
468
|
auth_header = create_auth_header("patch", datestamp, "#{@azure_container}#{blob_path}",headers, params)
|
397
469
|
headers[:Authorization] = auth_header
|
398
|
-
|
470
|
+
req_opts = {
|
471
|
+
:method => :patch,
|
472
|
+
:params => params,
|
473
|
+
:headers => headers,
|
474
|
+
:timeout => @http_timeout_seconds
|
475
|
+
}
|
476
|
+
add_proxy_options(req_opts)
|
477
|
+
request = Typhoeus::Request.new("https://#{azure_storage_account}#{@url_domain_suffix}/#{@azure_container}#{blob_path}", req_opts)
|
399
478
|
request.on_complete do |response|
|
400
479
|
if response.success?
|
401
480
|
log.debug "azurestorage_gen2: Blob '#{blob_path}' flush was successful, response code: #{response.code}"
|
@@ -416,7 +495,14 @@ module Fluent::Plugin
|
|
416
495
|
content_length = -1
|
417
496
|
auth_header = create_auth_header("head", datestamp, "#{@azure_container}#{blob_path}", headers, params)
|
418
497
|
headers[:Authorization] = auth_header
|
419
|
-
|
498
|
+
req_opts = {
|
499
|
+
:method => :head,
|
500
|
+
:params => params,
|
501
|
+
:headers => headers,
|
502
|
+
:timeout => @http_timeout_seconds
|
503
|
+
}
|
504
|
+
add_proxy_options(req_opts)
|
505
|
+
request = Typhoeus::Request.new("https://#{azure_storage_account}#{@url_domain_suffix}/#{@azure_container}#{blob_path}", req_opts)
|
420
506
|
request.on_complete do |response|
|
421
507
|
if response.success?
|
422
508
|
log.debug "azurestorage_gen2: Get blob properties for '#{blob_path}', response headers: #{response.headers}"
|
@@ -484,6 +570,16 @@ module Fluent::Plugin
|
|
484
570
|
"SharedKey #{@azure_storage_account}:#{signed(method, datestamp, resource, headers, params)}"
|
485
571
|
end
|
486
572
|
end
|
573
|
+
|
574
|
+
private
|
575
|
+
def add_proxy_options(req_opts = {})
|
576
|
+
unless @proxy_url.nil?
|
577
|
+
req_opts[:proxy] = @proxy_url
|
578
|
+
unless @proxy_username.nil? || @proxy_password.nil?
|
579
|
+
req_opts[:proxyuserpwd] = "#{@proxy_username}:#{@proxy_password}"
|
580
|
+
end
|
581
|
+
end
|
582
|
+
end
|
487
583
|
|
488
584
|
private
|
489
585
|
def signed(method, datestamp, resource, headers, params)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-azurestorage-gen2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Oliver Szabo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-12-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fluentd
|
@@ -225,8 +225,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
225
225
|
- !ruby/object:Gem::Version
|
226
226
|
version: '0'
|
227
227
|
requirements: []
|
228
|
-
|
229
|
-
rubygems_version: 2.5.1
|
228
|
+
rubygems_version: 3.1.2
|
230
229
|
signing_key:
|
231
230
|
specification_version: 4
|
232
231
|
summary: Azure Storage output plugin for Fluentd event collector
|