azure_client 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/.rvmrc +48 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +43 -0
- data/azure_client.gemspec +24 -0
- data/lib/azure_client/blob.rb +24 -0
- data/lib/azure_client/blob_lease.rb +58 -0
- data/lib/azure_client/buffered_queue.rb +52 -0
- data/lib/azure_client/buffered_queue_factory.rb +19 -0
- data/lib/azure_client/buffered_queue_message.rb +51 -0
- data/lib/azure_client/client.rb +45 -0
- data/lib/azure_client/container.rb +81 -0
- data/lib/azure_client/exponential_retry_policy.rb +26 -0
- data/lib/azure_client/linear_retry_policy.rb +30 -0
- data/lib/azure_client/message.rb +37 -0
- data/lib/azure_client/queue.rb +33 -0
- data/lib/azure_client/table.rb +45 -0
- data/lib/azure_client/table_entity.rb +15 -0
- data/lib/azure_client/version.rb +3 -0
- data/lib/azure_client.rb +8 -0
- metadata +129 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
# This is an RVM Project .rvmrc file, used to automatically load the ruby
|
4
|
+
# development environment upon cd'ing into the directory
|
5
|
+
|
6
|
+
# First we specify our desired <ruby>[@<gemset>], the @gemset name is optional,
|
7
|
+
# Only full ruby name is supported here, for short names use:
|
8
|
+
# echo "rvm use 1.9.3" > .rvmrc
|
9
|
+
environment_id="ruby-1.9.3-p327@azure_client"
|
10
|
+
|
11
|
+
# Uncomment the following lines if you want to verify rvm version per project
|
12
|
+
# rvmrc_rvm_version="1.17.3 (stable)" # 1.10.1 seams as a safe start
|
13
|
+
# eval "$(echo ${rvm_version}.${rvmrc_rvm_version} | awk -F. '{print "[[ "$1*65536+$2*256+$3" -ge "$4*65536+$5*256+$6" ]]"}' )" || {
|
14
|
+
# echo "This .rvmrc file requires at least RVM ${rvmrc_rvm_version}, aborting loading."
|
15
|
+
# return 1
|
16
|
+
# }
|
17
|
+
|
18
|
+
# First we attempt to load the desired environment directly from the environment
|
19
|
+
# file. This is very fast and efficient compared to running through the entire
|
20
|
+
# CLI and selector. If you want feedback on which environment was used then
|
21
|
+
# insert the word 'use' after --create as this triggers verbose mode.
|
22
|
+
if [[ -d "${rvm_path:-$HOME/.rvm}/environments"
|
23
|
+
&& -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
|
24
|
+
then
|
25
|
+
\. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
|
26
|
+
[[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]] &&
|
27
|
+
\. "${rvm_path:-$HOME/.rvm}/hooks/after_use" || true
|
28
|
+
else
|
29
|
+
# If the environment file has not yet been created, use the RVM CLI to select.
|
30
|
+
rvm --create "$environment_id" || {
|
31
|
+
echo "Failed to create RVM environment '${environment_id}'."
|
32
|
+
return 1
|
33
|
+
}
|
34
|
+
fi
|
35
|
+
|
36
|
+
# If you use bundler, this might be useful to you:
|
37
|
+
# if [[ -s Gemfile ]] && {
|
38
|
+
# ! builtin command -v bundle >/dev/null ||
|
39
|
+
# builtin command -v bundle | GREP_OPTIONS= \grep $rvm_path/bin/bundle >/dev/null
|
40
|
+
# }
|
41
|
+
# then
|
42
|
+
# printf "%b" "The rubygem 'bundler' is not installed. Installing it now.\n"
|
43
|
+
# gem install bundler
|
44
|
+
# fi
|
45
|
+
# if [[ -s Gemfile ]] && builtin command -v bundle >/dev/null
|
46
|
+
# then
|
47
|
+
# bundle install | GREP_OPTIONS= \grep -vE '^Using|Your bundle is complete'
|
48
|
+
# fi
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
azure_client (0.0.9)
|
5
|
+
rest-client
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
azure (0.5.0)
|
11
|
+
json
|
12
|
+
mime-types (~> 1.0)
|
13
|
+
nokogiri (~> 1.5)
|
14
|
+
uuid
|
15
|
+
diff-lcs (1.2.4)
|
16
|
+
json (1.8.0)
|
17
|
+
macaddr (1.6.1)
|
18
|
+
systemu (~> 2.5.0)
|
19
|
+
mime-types (1.23)
|
20
|
+
nokogiri (1.5.9)
|
21
|
+
rake (10.0.4)
|
22
|
+
rest-client (1.6.7)
|
23
|
+
mime-types (>= 1.16)
|
24
|
+
rspec (2.13.0)
|
25
|
+
rspec-core (~> 2.13.0)
|
26
|
+
rspec-expectations (~> 2.13.0)
|
27
|
+
rspec-mocks (~> 2.13.0)
|
28
|
+
rspec-core (2.13.1)
|
29
|
+
rspec-expectations (2.13.0)
|
30
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
31
|
+
rspec-mocks (2.13.1)
|
32
|
+
systemu (2.5.2)
|
33
|
+
uuid (2.3.7)
|
34
|
+
macaddr (~> 1.0)
|
35
|
+
|
36
|
+
PLATFORMS
|
37
|
+
ruby
|
38
|
+
|
39
|
+
DEPENDENCIES
|
40
|
+
azure
|
41
|
+
azure_client!
|
42
|
+
rake
|
43
|
+
rspec
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'azure_client/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "azure_client"
|
8
|
+
gem.version = AzureClient::VERSION
|
9
|
+
gem.authors = ["Karl Skucha"]
|
10
|
+
gem.email = ["kskucha@yammer-inc.com"]
|
11
|
+
gem.description = %q{Encapsulate the API's of Azure SDK}
|
12
|
+
gem.summary = %q{}
|
13
|
+
gem.homepage = ""
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency 'rest-client'
|
21
|
+
gem.add_development_dependency 'azure'
|
22
|
+
gem.add_development_dependency 'rspec'
|
23
|
+
gem.add_development_dependency 'rake'
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module AzureClient
|
2
|
+
class Blob
|
3
|
+
|
4
|
+
def initialize(name, azure_blob, content, container_name, blob_service, retry_policy)
|
5
|
+
@name = name
|
6
|
+
@azure_blob = azure_blob
|
7
|
+
@content = content
|
8
|
+
@container_name = container_name
|
9
|
+
@blob_service = blob_service
|
10
|
+
@retry_policy = retry_policy
|
11
|
+
end
|
12
|
+
|
13
|
+
def get_content
|
14
|
+
@content
|
15
|
+
end
|
16
|
+
|
17
|
+
def delete(retry_policy = @retry_policy)
|
18
|
+
retry_policy.retry {
|
19
|
+
@blob_service.delete_blob(@container_name, @name)
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module AzureClient
|
2
|
+
class BlobLease
|
3
|
+
RENEW_MARGIN = 10
|
4
|
+
|
5
|
+
attr_reader :lease_id, :duration, :start_time, :container, :blob_name
|
6
|
+
alias_method :name, :lease_id
|
7
|
+
alias_method :to_s, :name
|
8
|
+
|
9
|
+
def initialize(container, blob_name, blob_service, retry_policy, options = {})
|
10
|
+
@container = container
|
11
|
+
@blob_name = blob_name
|
12
|
+
@blob_service = blob_service
|
13
|
+
@retry_policy = retry_policy
|
14
|
+
|
15
|
+
options[:duration] ||= 60 # NO default to infinity
|
16
|
+
retry_policy.retry {
|
17
|
+
tries = 0
|
18
|
+
begin
|
19
|
+
@lease_id = @blob_service.acquire_lease(container, blob_name, options)
|
20
|
+
rescue Azure::Core::Http::HTTPError => e
|
21
|
+
if tries < 1 and e.status_code == 404 then
|
22
|
+
@blob_service.create_block_blob(container, blob_name, '')
|
23
|
+
tries += 1
|
24
|
+
retry
|
25
|
+
else
|
26
|
+
raise
|
27
|
+
end
|
28
|
+
end
|
29
|
+
}
|
30
|
+
@start_time = Time.now
|
31
|
+
@duration = options[:duration]
|
32
|
+
end
|
33
|
+
|
34
|
+
def change(new_lease_id, retry_policy = @retry_policy)
|
35
|
+
retry_policy.retry {
|
36
|
+
@blob_service.change_lease(container, blob_name, "#{new_lease_id}", lease_id)
|
37
|
+
@lease_id = new_lease_id
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
def renew(retry_policy = @retry_policy)
|
42
|
+
retry_policy.retry {
|
43
|
+
@blob_service.renew_lease(container, blob_name, lease_id)
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
def renew_if_necessary(retry_policy = nil)
|
48
|
+
age = Time.now - start_time
|
49
|
+
renew(retry_policy) if duration - age <= RENEW_MARGIN
|
50
|
+
end
|
51
|
+
|
52
|
+
def release(retry_policy = @retry_policy)
|
53
|
+
retry_policy.retry {
|
54
|
+
@blob_service.release_lease(container, blob_name, lease_id)
|
55
|
+
}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module AzureClient
|
2
|
+
class BufferedQueue
|
3
|
+
attr_accessor :name
|
4
|
+
|
5
|
+
def initialize(queues, container, retry_policy = ExponentialRetryPolicy.new(5,1,2))
|
6
|
+
@queues = queues.kind_of?(Array) ? queues : [queues]
|
7
|
+
@name = @queues[0].name
|
8
|
+
@container = container
|
9
|
+
@retry_policy = retry_policy
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_message(content, metadata = "", retry_policy = @retry_policy)
|
13
|
+
payload = {"content" => content, "metadata" => metadata}.to_json
|
14
|
+
queue = select_queue
|
15
|
+
if is_allowed_payload_size(payload)
|
16
|
+
queue.add_message(payload, retry_policy)
|
17
|
+
else
|
18
|
+
#pick random blob name
|
19
|
+
blob_name = name + (0...9).map{ ('a'..'z').to_a[rand(26)] }.join
|
20
|
+
reference = {"type" => "azure_blob_reference", "name" => blob_name, "metadata" => metadata}
|
21
|
+
@container.store_blob(blob_name, content, {}, retry_policy)
|
22
|
+
queue.add_message(reference.to_json, retry_policy)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
#default to one try
|
27
|
+
def get_message(retry_policy = LinearRetryPolicy.new(1,1))
|
28
|
+
queue = select_queue
|
29
|
+
message = queue.get_message(retry_policy)
|
30
|
+
message ? BufferedQueueMessage.new(message, @container, @retry_policy) : nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def delete(retry_policy = @retry_policy)
|
34
|
+
@queues.each do |queue|
|
35
|
+
queue.delete(retry_policy)
|
36
|
+
end
|
37
|
+
@container.delete(retry_policy)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def is_allowed_payload_size(payload)
|
43
|
+
#leave a 1kb margin
|
44
|
+
return payload.bytesize <= 63 * 1024 / 4 * 3
|
45
|
+
end
|
46
|
+
|
47
|
+
def select_queue
|
48
|
+
@queues.sample
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module AzureClient
|
2
|
+
class BufferedQueueFactory
|
3
|
+
|
4
|
+
def self.get_buffered_queue(container, queues, storage, retryPolicy = ExponentialRetryPolicy.new(5,1,2))
|
5
|
+
buffered_queue = AzureClient::BufferedQueue.new(get_queues(queues, storage), storage.get_container(container), retryPolicy)
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def self.get_queues(queues, storage)
|
11
|
+
result = []
|
12
|
+
queues.each do |queue|
|
13
|
+
result << storage.get_queue(queue)
|
14
|
+
end
|
15
|
+
result
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module AzureClient
|
2
|
+
class BufferedQueueMessage
|
3
|
+
|
4
|
+
def initialize(message, container, retry_policy = ExponentialRetryPolicy.new(5,1,2))
|
5
|
+
@message = message
|
6
|
+
@parsed_message = parse
|
7
|
+
@container = container
|
8
|
+
@retry_policy = retry_policy
|
9
|
+
@blob = get_blob
|
10
|
+
end
|
11
|
+
|
12
|
+
def get_content
|
13
|
+
if @blob
|
14
|
+
@blob.get_content
|
15
|
+
else
|
16
|
+
@parsed_message["content"]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_metadata
|
21
|
+
@parsed_message["metadata"]
|
22
|
+
end
|
23
|
+
|
24
|
+
def delete(retry_policy = @retry_policy)
|
25
|
+
if @blob
|
26
|
+
@blob.delete(@retry_policy)
|
27
|
+
else
|
28
|
+
@message.delete(@retry_policy)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def get_blob
|
35
|
+
if @parsed_message && @parsed_message["type"] == "azure_blob_reference"
|
36
|
+
blob_name = @parsed_message["name"]
|
37
|
+
return @container.get_blob(blob_name)
|
38
|
+
end
|
39
|
+
return nil
|
40
|
+
end
|
41
|
+
|
42
|
+
def parse
|
43
|
+
begin
|
44
|
+
JSON.parse(@message.get_content)
|
45
|
+
rescue
|
46
|
+
return nil
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module AzureClient
|
2
|
+
class Client
|
3
|
+
|
4
|
+
def initialize(account_name, access_key)
|
5
|
+
Azure.configure do |config|
|
6
|
+
config.storage_account_name = account_name
|
7
|
+
config.storage_access_key = access_key
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def get_queue(name, retry_policy = ExponentialRetryPolicy.new(5,1,2))
|
12
|
+
queue_service.create_queue(name)
|
13
|
+
return Queue.new(name, queue_service, retry_policy)
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_container(name, retry_policy = ExponentialRetryPolicy.new(5,1,2))
|
17
|
+
if !(blob_service.list_containers.map {|container| container.name}.include?(name))
|
18
|
+
blob_service.create_container(name)
|
19
|
+
end
|
20
|
+
return Container.new(name, blob_service, retry_policy)
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_table(name, retry_policy = ExponentialRetryPolicy.new(2,1,2))
|
24
|
+
if !(table_service.query_tables.map {|hash| hash[:properties]["TableName"]}.include?(name))
|
25
|
+
table_service.create_table(name)
|
26
|
+
end
|
27
|
+
return Table.new(name, table_service, retry_policy)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def blob_service
|
33
|
+
@blob_service || Azure::BlobService.new
|
34
|
+
end
|
35
|
+
|
36
|
+
def queue_service
|
37
|
+
@queue_service || Azure::QueueService.new
|
38
|
+
end
|
39
|
+
|
40
|
+
def table_service
|
41
|
+
@table_service || Azure::TableService.new
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module AzureClient
|
2
|
+
class Container
|
3
|
+
attr_reader :name
|
4
|
+
|
5
|
+
def initialize(name, blob_service, retry_policy)
|
6
|
+
@name = name
|
7
|
+
@blob_service = blob_service
|
8
|
+
@retry_policy = retry_policy
|
9
|
+
end
|
10
|
+
|
11
|
+
#will overwrite content if blob with same name already exists
|
12
|
+
def store_blob(blob_name, content, options = {}, retry_policy = @retry_policy)
|
13
|
+
retry_policy.retry {
|
14
|
+
@blob_service.create_block_blob(name, blob_name, content, options)
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
#throws exception if no blob found
|
19
|
+
def get_blob(blob_name, options = {}, retry_policy = @retry_policy)
|
20
|
+
retry_policy.retry {
|
21
|
+
azure_blob, content = @blob_service.get_blob(name, blob_name, options)
|
22
|
+
Blob.new(blob_name, azure_blob, content, name, @blob_service, @retry_policy)
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_blob_lease(blob_name, retry_policy = @retry_policy, options = {})
|
27
|
+
BlobLease.new(@name, blob_name, @blob_service, retry_policy, options)
|
28
|
+
end
|
29
|
+
|
30
|
+
def get_blob_properties(blob_name, retry_policy = @retry_policy)
|
31
|
+
retry_policy.retry {
|
32
|
+
@blob_service.get_blob_properties(@name, blob_name)
|
33
|
+
}.properties
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_blob_metadata(blob_name, retry_policy = @retry_policy)
|
37
|
+
retry_policy.retry {
|
38
|
+
@blob_service.get_blob_metadata(@name, blob_name).metadata
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def set_blob_metadata(blob_name, metadata, retry_policy = @retry_policy)
|
43
|
+
retry_policy.retry {
|
44
|
+
@blob_service.set_blob_metadata(@name, blob_name, metadata)
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
def delete(retry_policy = @retry_policy)
|
49
|
+
retry_policy.retry {
|
50
|
+
@blob_service.delete_container(@name)
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
def delete_blob(blob_name, retry_policy = @retry_policy)
|
55
|
+
retry_policy.retry {
|
56
|
+
@blob_service.delete_blob(name, blob_name)
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
def poll_blob(blob_name, key, val, timeout = 10800)
|
61
|
+
time = 0
|
62
|
+
#create blob if it does not exist
|
63
|
+
begin
|
64
|
+
blob = get_blob(blob_name)
|
65
|
+
rescue
|
66
|
+
store_blob(blob_name,"")
|
67
|
+
end
|
68
|
+
loop do
|
69
|
+
sleep(5)
|
70
|
+
time += 5;
|
71
|
+
puts "*** polling Azure blob #{blob_name} for #{time} seconds"
|
72
|
+
metadata = get_blob_metadata(blob_name)
|
73
|
+
return val if metadata && metadata[key] == val
|
74
|
+
if time > timeout
|
75
|
+
raise "Polling blob #{blob_name} took more than #{timeout} seconds to run. Time out."
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module AzureClient
|
2
|
+
class ExponentialRetryPolicy
|
3
|
+
|
4
|
+
def initialize(num_retries, initial_timeout, multiplier)
|
5
|
+
@num_retries = num_retries
|
6
|
+
@initial_timeout = initial_timeout
|
7
|
+
@multiplier = multiplier
|
8
|
+
end
|
9
|
+
|
10
|
+
def retry
|
11
|
+
@num_retries.times do |count|
|
12
|
+
begin
|
13
|
+
return yield
|
14
|
+
rescue StandardError => e
|
15
|
+
if count == @num_retries - 1
|
16
|
+
raise e
|
17
|
+
else
|
18
|
+
sleep((@multiplier**count) * @initial_timeout)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module AzureClient
|
2
|
+
class LinearRetryPolicy
|
3
|
+
|
4
|
+
def initialize(num_retries, timeout)
|
5
|
+
@num_retries = num_retries
|
6
|
+
@timeout = timeout
|
7
|
+
end
|
8
|
+
|
9
|
+
def retry
|
10
|
+
@num_retries.times do |count|
|
11
|
+
begin
|
12
|
+
return yield
|
13
|
+
rescue StandardError => e
|
14
|
+
if count == @num_retries - 1
|
15
|
+
raise e
|
16
|
+
else
|
17
|
+
sleep(@timeout)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module AzureClient
|
2
|
+
class Message
|
3
|
+
|
4
|
+
def initialize(azure_message, queue_name, queue_service, retry_policy)
|
5
|
+
@azure_message = azure_message
|
6
|
+
@queue_name = queue_name
|
7
|
+
@queue_service = queue_service
|
8
|
+
@retry_policy = retry_policy
|
9
|
+
end
|
10
|
+
|
11
|
+
def get_content
|
12
|
+
content = @azure_message.message_text
|
13
|
+
begin
|
14
|
+
Base64.decode64(content)
|
15
|
+
rescue
|
16
|
+
raise $!, "Failed to decode content of azure queue message, check to make sure message is encoded, exception: #{$!}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def id
|
21
|
+
@azure_message.id
|
22
|
+
end
|
23
|
+
|
24
|
+
def delete(retry_policy = @retry_policy)
|
25
|
+
retry_policy.retry {
|
26
|
+
@queue_service.delete_message(@queue_name, id, pop_receipt)
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def pop_receipt
|
33
|
+
@azure_message.pop_receipt
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module AzureClient
|
2
|
+
class Queue
|
3
|
+
attr_accessor :name
|
4
|
+
|
5
|
+
def initialize(name, queue_service, retry_policy = ExponentialRetryPolicy.new(5,1,2))
|
6
|
+
@name = name
|
7
|
+
@queue_service = queue_service
|
8
|
+
@retry_policy = retry_policy
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_message(content, retry_policy = @retry_policy)
|
12
|
+
retry_policy.retry {
|
13
|
+
encoded = Base64.encode64(content)
|
14
|
+
@queue_service.create_message(name, encoded)
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
#default to only one try
|
19
|
+
def get_message(retry_policy = LinearRetryPolicy.new(1,1))
|
20
|
+
retry_policy.retry {
|
21
|
+
azure_message = @queue_service.list_messages(name, 30).first
|
22
|
+
azure_message ? Message.new(azure_message, name, @queue_service, @retry_policy) : nil
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
def delete(retry_policy = @retry_policy)
|
27
|
+
retry_policy.retry {
|
28
|
+
@queue_service.delete_queue(name)
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module AzureClient
|
2
|
+
class Table
|
3
|
+
attr_reader :name
|
4
|
+
|
5
|
+
def initialize(name, table_service, retry_policy)
|
6
|
+
@name = name
|
7
|
+
@table_service = table_service
|
8
|
+
@retry_policy = retry_policy
|
9
|
+
end
|
10
|
+
|
11
|
+
def store_entity(entity, retry_policy = @retry_policy)
|
12
|
+
retry_policy.retry {
|
13
|
+
entity_hash = {"PartitionKey" => entity.partition_key, "RowKey" => entity.row_key}.merge(entity.content_hash)
|
14
|
+
@table_service.insert_or_replace_entity(name, entity_hash)
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
def get_entity(partition_key, row_key, retry_policy = @retry_policy)
|
20
|
+
retry_policy.retry {
|
21
|
+
entity_hash = @table_service.get_entity(name, partition_key, row_key).properties
|
22
|
+
TableEntity.new(entity_hash["PartitionKey"], entity_hash["RowKey"], entity_hash["TimeStamp"], entity_hash.tap { |h| h.delete(:PartitionKey); h.delete(:RowKey)})
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
def delete(retry_policy = @retry_policy)
|
27
|
+
retry_policy.retry {
|
28
|
+
@table_service.delete_table(name)
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def delete_entity(partition_key, row_key, retry_policy = @retry_policy)
|
33
|
+
retry_policy.retry {
|
34
|
+
@table_service.delete_entity(name, partition_key, row_key)
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
def query(query_hash, retry_policy = @retry_policy)
|
39
|
+
retry_policy.retry {
|
40
|
+
@table_service.query_entities(name, query_hash)
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module AzureClient
|
2
|
+
class TableEntity
|
3
|
+
attr_accessor :partition_key, :row_key, :content_hash
|
4
|
+
|
5
|
+
def initialize(partition_key, row_key, timestamp = nil, content_hash)
|
6
|
+
@partition_key = partition_key
|
7
|
+
@row_key = row_key
|
8
|
+
@timestamp = timestamp
|
9
|
+
@content_hash = content_hash
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
|
data/lib/azure_client.rb
ADDED
metadata
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: azure_client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Karl Skucha
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-07-31 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rest-client
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: azure
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rake
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
description: Encapsulate the API's of Azure SDK
|
79
|
+
email:
|
80
|
+
- kskucha@yammer-inc.com
|
81
|
+
executables: []
|
82
|
+
extensions: []
|
83
|
+
extra_rdoc_files: []
|
84
|
+
files:
|
85
|
+
- .gitignore
|
86
|
+
- .rvmrc
|
87
|
+
- Gemfile
|
88
|
+
- Gemfile.lock
|
89
|
+
- azure_client.gemspec
|
90
|
+
- lib/azure_client.rb
|
91
|
+
- lib/azure_client/blob.rb
|
92
|
+
- lib/azure_client/blob_lease.rb
|
93
|
+
- lib/azure_client/buffered_queue.rb
|
94
|
+
- lib/azure_client/buffered_queue_factory.rb
|
95
|
+
- lib/azure_client/buffered_queue_message.rb
|
96
|
+
- lib/azure_client/client.rb
|
97
|
+
- lib/azure_client/container.rb
|
98
|
+
- lib/azure_client/exponential_retry_policy.rb
|
99
|
+
- lib/azure_client/linear_retry_policy.rb
|
100
|
+
- lib/azure_client/message.rb
|
101
|
+
- lib/azure_client/queue.rb
|
102
|
+
- lib/azure_client/table.rb
|
103
|
+
- lib/azure_client/table_entity.rb
|
104
|
+
- lib/azure_client/version.rb
|
105
|
+
homepage: ''
|
106
|
+
licenses: []
|
107
|
+
post_install_message:
|
108
|
+
rdoc_options: []
|
109
|
+
require_paths:
|
110
|
+
- lib
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
none: false
|
113
|
+
requirements:
|
114
|
+
- - ! '>='
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
|
+
none: false
|
119
|
+
requirements:
|
120
|
+
- - ! '>='
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
requirements: []
|
124
|
+
rubyforge_project:
|
125
|
+
rubygems_version: 1.8.24
|
126
|
+
signing_key:
|
127
|
+
specification_version: 3
|
128
|
+
summary: ''
|
129
|
+
test_files: []
|