fluent-plugin-azure-queue 0.0.6.pre → 0.0.8.pre

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
  SHA1:
3
- metadata.gz: b9216faa1348ea85dd618fcc498b31efea22eac1
4
- data.tar.gz: 18989b0f648643a7f29d06f51c4b2d49b3850132
3
+ metadata.gz: 7dec8e5dd6a0f5973f5741702060efb40cc04b22
4
+ data.tar.gz: 0b1fb55a244ccc5a8a1ad390d09f1950eaf3e22c
5
5
  SHA512:
6
- metadata.gz: 9e721814bfb21da863ae2ec607743967a398c79719ba03330b7842f65cd8b27eb7e7968e685dabcd710528f5df3bcad3a2ef508507f481002aa51ebe860ed0a2
7
- data.tar.gz: 3d2ce94dcd4f395a27e76c2bc7fa1605978914def55ee44d18b113cdbd204e31e70ad17396b38742e7ee65b2f1565a236ec7739e61abee605113ca108271702f
6
+ metadata.gz: d4cf9f3f62e6213c4aeb421741bcde86fc4ecffef9a0b0b3efa0c0002390cb58e398c8187d698bab9b9f0babd01c531ea5a0273877cfbad7bbdb74cf505e4555
7
+ data.tar.gz: 6092c42d2fba01796c75085c1692e4f94696f37ba7314fdf38273d3cc309d6187fcf4562b44a46df7203f7b9f3dc865e0bb304248f0fa39d3bc9c568eb378e98
data/README.md CHANGED
@@ -76,6 +76,7 @@ public static void Run(string[] hubMessages, ICollector<string> outputQueue, Tra
76
76
  }
77
77
  }
78
78
  ```
79
+
79
80
  ## azure_event_hub_capture Input Plugin
80
81
  This plugin is designed to work with blobs stored to a container via [Azure Event Hubs Capture](https://docs.microsoft.com/en-us/azure/event-hubs/event-hubs-capture-overview)
81
82
 
@@ -121,3 +122,37 @@ The time in seconds to sleep between fetching the blob list. Default 30
121
122
  **lease_duration**
122
123
 
123
124
  The time to lease the messages for. Default 60
125
+
126
+ **queue_lease_time**
127
+
128
+ The time to lease the queue message for. Default 60
129
+
130
+ **queue_name**
131
+
132
+ If set, get the blob names from a storage queue. Good if there are many blobs because listblobs is not reliable.
133
+
134
+ ## Integration with Azure Event Hub
135
+
136
+ Use this azure function if you want to ingest event hub capture blob names from a storage queue.
137
+
138
+ ```c#
139
+ // Blob trigger binding to a CloudBlockBlob
140
+ #r "Microsoft.WindowsAzure.Storage"
141
+
142
+ using Microsoft.WindowsAzure.Storage.Blob;
143
+
144
+ public static void Run(CloudBlockBlob myBlob, out BlobIdentifier outputQueueItem, TraceWriter log)
145
+ {
146
+ log.Info($"C# Blob trigger function Processed blob Name:{myBlob.Name} URI:{myBlob.StorageUri}");
147
+ BlobIdentifier blobId = new BlobIdentifier { Name = myBlob.Name, Container = myBlob.Container.Name };
148
+ //outputQueueItem.add(blobId);
149
+ outputQueueItem = blobId;
150
+ }
151
+
152
+
153
+ public class BlobIdentifier
154
+ {
155
+ public string Container { get; set; }
156
+ public string Name { get; set; }
157
+ }
158
+ ```
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.6.pre
1
+ 0.0.8.pre
@@ -20,6 +20,10 @@ module Fluent
20
20
  config_param :fetch_interval, :integer, default: 30
21
21
  desc 'The the lease duration on the blob in seconds'
22
22
  config_param :lease_duration, :integer, default: 60
23
+ desc 'The the lease time on the messages in seconds'
24
+ config_param :queue_lease_time, :integer, default: 60
25
+ desc 'If set, get the blob names from a queue rather than the "list blobs" operation'
26
+ config_param :queue_name, :string, default: nil
23
27
 
24
28
  def configure(conf)
25
29
  super
@@ -30,9 +34,9 @@ module Fluent
30
34
  if @lease_duration > 60 || @lease_duration < 15
31
35
  raise Fluent::ConfigError, "fluent-plugin-azure-queue: 'lease_duration' parameter must be between 15 and 60: #{@lease_duration}"
32
36
  end
33
- @blob_client = Azure::Storage::Client.create(
37
+ @azure_client = Azure::Storage::Client.create(
34
38
  :storage_account_name => @storage_account_name,
35
- :storage_access_key => @storage_access_key).blob_client
39
+ :storage_access_key => @storage_access_key)
36
40
  @running = true
37
41
  @containers = container_names.split(',').map { |c| c.strip }
38
42
 
@@ -55,19 +59,10 @@ module Fluent
55
59
  while @running
56
60
  if Time.now > @next_fetch_time
57
61
  @next_fetch_time = Time.now + @fetch_interval
58
- @containers.each do |container_name|
59
- begin
60
- blobs = @blob_client.list_blobs(container_name)
61
- blobs = blobs.select { |b| b.properties[:lease_status] == "unlocked" }
62
- log.info("Found #{blobs.count} unlocked blobs", container_name: container_name)
63
- # Blobs come back with oldest first
64
- blobs.each do |blob|
65
- ingest_blob(container_name, blob)
66
- end
67
- rescue => e
68
- log.warn(error: e)
69
- log.warn_backtrace(e.backtrace)
70
- end
62
+ if queue_name
63
+ ingest_from_queue
64
+ else
65
+ ingest_from_blob_list
71
66
  end
72
67
  else
73
68
  sleep(@next_fetch_time - Time.now)
@@ -75,25 +70,56 @@ module Fluent
75
70
  end
76
71
  end
77
72
 
78
- def ingest_blob(container_name, blob)
73
+ def ingest_from_blob_list
74
+ @containers.each do |container_name|
75
+ begin
76
+ blobs = @azure_client.blob_client.list_blobs(container_name)
77
+ blobs = blobs.select { |b| b.properties[:lease_status] == "unlocked" }
78
+ log.info("Found #{blobs.count} unlocked blobs", container_name: container_name)
79
+ # Blobs come back with oldest first
80
+ blobs.each do |blob|
81
+ ingest_blob(container_name, blob.name)
82
+ end
83
+ rescue => e
84
+ log.warn(error: e)
85
+ log.warn_backtrace(e.backtrace)
86
+ end
87
+ end
88
+ end
89
+
90
+ def ingest_from_queue
91
+ begin
92
+ blob_id_messages = @azure_client.queue_client.list_messages(@queue_name, @queue_lease_time, { number_of_messages: 32 })
93
+ blob_id_messages.each do |blob_id_message|
94
+ blob_id = JSON.parse(Base64.decode64(blob_id_message.message_text))
95
+ ingest_blob(blob_id["Container"], blob_id["Name"])
96
+ @azure_client.queue_client.delete_message(@queue_name, blob_id_message.id, blob_id_message.pop_receipt)
97
+ end
98
+ rescue => e
99
+ log.warn(error: e)
100
+ log.warn_backtrace(e.backtrace)
101
+ end
102
+ end
103
+
104
+ def ingest_blob(container_name, blob_name)
79
105
  begin
80
- lease_id = @blob_client.acquire_blob_lease(container_name, blob.name, duration: @lease_duration)
81
- log.info("Blob Leased", blob_name: blob.name)
82
- blob, blob_contents = @blob_client.get_blob(container_name, blob.name)
106
+ lease_id = @azure_client.blob_client.acquire_blob_lease(container_name, blob_name, duration: @lease_duration)
107
+ log.info("Blob Leased", blob_name: blob_name)
108
+ blob, blob_contents = @azure_client.blob_client.get_blob(container_name, blob_name)
83
109
  emit_blob_messages(blob_contents)
84
- log.trace("Done Ingest blob", blob_name: blob.name)
110
+ log.trace("Done Ingest blob", blob_name: blob_name)
85
111
  begin
86
112
  delete_blob(container_name, blob, lease_id)
87
- log.debug("Blob deleted", blob_name: blob.name)
113
+ log.debug("Blob deleted", blob_name: blob_name)
88
114
  rescue Exception => e
89
- log.warn("Records emmitted but blob not deleted", container_name: container_name, blob_name: blob.name, error: e)
115
+ log.warn("Records emmitted but blob not deleted", container_name: container_name, blob_name: blob_name, error: e)
90
116
  log.warn_backtrace(e.backtrace)
91
117
  end
92
118
  rescue Azure::Core::Http::HTTPError => e
93
119
  if e.status_code == 409
94
- log.trace("Blob already leased", blob_name: blob.name)
120
+ log.trace("Blob already leased", blob_name: blob_name)
95
121
  elsif e.status_code == 404
96
- log.trace("Blob already deleted", blob_name: blob.name)
122
+ log.trace("Blob already deleted", blob_name: blob_name)
97
123
  else
98
124
  log.warn("Error occurred while ingesting blob", error: e)
99
125
  log.warn_backtrace(e.backtrace)
@@ -127,7 +153,7 @@ module Fluent
127
153
  def delete_blob(container_name, blob, lease_id)
128
154
  # Hack because 'delete_blob' doesn't support lease_id yet
129
155
  Azure::Storage::Service::StorageService.register_request_callback { |headers| headers["x-ms-lease-id"] = lease_id }
130
- @blob_client.delete_blob(container_name, blob.name)
156
+ @azure_client.blob_client.delete_blob(container_name, blob.name)
131
157
  Azure::Storage::Service::StorageService.register_request_callback { |headers| headers }
132
158
  end
133
159
  end
@@ -11,7 +11,7 @@ class AzureEventHubCaptureInputTest < Test::Unit::TestCase
11
11
  end
12
12
  end
13
13
 
14
- CONFIG = %[
14
+ LIST_CONFIG = %[
15
15
  tag test_tag
16
16
  storage_account_name test_storage_account_name
17
17
  storage_access_key test_storage_access_key
@@ -19,13 +19,24 @@ class AzureEventHubCaptureInputTest < Test::Unit::TestCase
19
19
  fetch_interval 1
20
20
  ]
21
21
 
22
- def create_driver(conf = CONFIG)
22
+ QUEUE_CONFIG = %[
23
+ tag test_tag
24
+ storage_account_name test_storage_account_name
25
+ storage_access_key test_storage_access_key
26
+ container_names test_container_name
27
+ fetch_interval 1
28
+ queue_lease_time 30
29
+ queue_name test_queue_name
30
+ ]
31
+
32
+ def create_driver(conf = LIST_CONFIG)
23
33
  d = Fluent::Test::InputTestDriver.new(Fluent::AzureEventHubCaptureInput)
24
34
  d.configure(conf)
25
35
  d
26
36
  end
27
37
 
28
38
  Struct.new("Blob", :name, :properties)
39
+ Struct.new("QueueMessage", :id, :pop_receipt, :message_text)
29
40
 
30
41
  def test_configure
31
42
  d = create_driver
@@ -38,14 +49,15 @@ class AzureEventHubCaptureInputTest < Test::Unit::TestCase
38
49
 
39
50
  def setup_mocks(driver)
40
51
  blob_client = flexmock("blob_client")
41
- client = flexmock("client", :blob_client => blob_client)
52
+ queue_client = flexmock("queue_client")
53
+ client = flexmock("client", :blob_client => blob_client, :queue_client => queue_client)
42
54
  flexmock(Azure::Storage::Client, :create => client)
43
- blob_client
55
+ [blob_client, queue_client]
44
56
  end
45
57
 
46
- def test_no_blobs
58
+ def test_list_no_blobs
47
59
  d = create_driver
48
- blob_client = setup_mocks(d)
60
+ blob_client, queue_client = setup_mocks(d)
49
61
  blob_client.should_receive(:list_blobs).with(d.instance.container_names).and_return([]).once
50
62
  flexmock(d.instance).should_receive(:ingest_blob).never()
51
63
  d.run do
@@ -53,10 +65,10 @@ class AzureEventHubCaptureInputTest < Test::Unit::TestCase
53
65
  end
54
66
  end
55
67
 
56
- def test_two_blobs
68
+ def test_list_two_blobs
57
69
  d = create_driver
58
70
  blobs = [Struct::Blob.new("test1", lease_status: "unlocked"), Struct::Blob.new("test2", lease_status: "unlocked")]
59
- blob_client = setup_mocks(d)
71
+ blob_client, queue_client = setup_mocks(d)
60
72
  blob_client.should_receive(:list_blobs).with(d.instance.container_names).and_return(blobs).once
61
73
  plugin = flexmock(d.instance)
62
74
  plugin.should_receive(:ingest_blob).with(d.instance.container_names, blobs[0]).once()
@@ -66,10 +78,44 @@ class AzureEventHubCaptureInputTest < Test::Unit::TestCase
66
78
  end
67
79
  end
68
80
 
81
+ def test_queue_no_blobs
82
+ d = create_driver(QUEUE_CONFIG)
83
+ blob_client, queue_client = setup_mocks(d)
84
+ queue_client.should_receive(:list_messages).with(
85
+ d.instance.queue_name,
86
+ d.instance.queue_lease_time,
87
+ { number_of_messages: 32}).and_return([]).once
88
+ flexmock(d.instance).should_receive(:ingest_blob).never()
89
+ d.run do
90
+ sleep 1
91
+ end
92
+ end
93
+
94
+ def test_queue_two_blobs
95
+ d = create_driver(QUEUE_CONFIG)
96
+ blob_id1 = { "Name" => "test1", "Container" => "container1" }
97
+ blob_id2 = { "Name" => "test2", "Container" => "container2" }
98
+ blobs_id_messages = [ Struct::QueueMessage.new(1, 99, Base64.encode64(blob_id1.to_json)),
99
+ Struct::QueueMessage.new(2, 299, Base64.encode64(blob_id2.to_json))]
100
+ blob_client, queue_client = setup_mocks(d)
101
+ queue_client.should_receive(:list_messages).with(
102
+ d.instance.queue_name,
103
+ d.instance.queue_lease_time,
104
+ { number_of_messages: 32}).and_return(blobs_id_messages).once
105
+ plugin = flexmock(d.instance)
106
+ plugin.should_receive(:ingest_blob).with(blob_id1["Container"], blob_id1["Name"]).once()
107
+ plugin.should_receive(:ingest_blob).with(blob_id2["Container"], blob_id2["Name"]).once()
108
+ queue_client.should_receive(:delete_message).with(d.instance.queue_name, blobs_id_messages[0].id, blobs_id_messages[0].pop_receipt).once
109
+ queue_client.should_receive(:delete_message).with(d.instance.queue_name, blobs_id_messages[1].id, blobs_id_messages[1].pop_receipt).once
110
+ d.run do
111
+ sleep 1
112
+ end
113
+ end
114
+
69
115
  def test_ingest_blob
70
116
  d = create_driver
71
117
  blob = Struct::Blob.new("test1", lease_status: "unlocked")
72
- blob_client = setup_mocks(d)
118
+ blob_client, queue_client = setup_mocks(d)
73
119
  plugin = flexmock(d.instance)
74
120
  lease_id = "123"
75
121
  blob_client.should_receive(:acquire_blob_lease).with(d.instance.container_names, blob.name, duration: d.instance.lease_duration).and_return(lease_id).once
@@ -85,7 +131,7 @@ class AzureEventHubCaptureInputTest < Test::Unit::TestCase
85
131
 
86
132
  def test_emit_blob_messages
87
133
  d = create_driver
88
- setup_mocks(d)
134
+ blob_client, queue_client = setup_mocks(d)
89
135
  test_payload = flexmock("test_payload")
90
136
  buffer = flexmock("buffer")
91
137
  flexmock(StringIO).should_receive(:new).and_return(buffer)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-azure-queue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6.pre
4
+ version: 0.0.8.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Bonebrake
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-09-20 00:00:00.000000000 Z
11
+ date: 2017-10-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fluentd