waz-storage 0.5.7 → 0.5.8
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.
- data/lib/waz/blobs/blob_object.rb +14 -1
- data/lib/waz/blobs/container.rb +1 -0
- data/lib/waz/blobs/exceptions.rb +11 -0
- data/lib/waz/blobs/service.rb +12 -6
- data/lib/waz/queues/queue.rb +4 -3
- data/lib/waz/storage/core_service.rb +37 -35
- data/lib/waz/storage/validation_rules.rb +17 -0
- data/lib/waz/storage/version.rb +1 -1
- data/lib/waz-blobs.rb +1 -0
- data/lib/waz-storage.rb +1 -0
- data/rakefile +1 -1
- metadata +5 -3
@@ -35,7 +35,7 @@ module WAZ
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
attr_accessor :name, :url, :content_type
|
38
|
+
attr_accessor :name, :url, :content_type, :snapshot_date
|
39
39
|
|
40
40
|
# Creates a new instance of the Blob object. This constructor is internally used by the Container
|
41
41
|
# it's initialized thru a hash that's received as parameter. It has the following requirements:
|
@@ -48,6 +48,7 @@ module WAZ
|
|
48
48
|
self.name = options[:name]
|
49
49
|
self.url = options[:url]
|
50
50
|
self.content_type = options[:content_type]
|
51
|
+
self.snapshot_date = options[:snapshot_date]
|
51
52
|
end
|
52
53
|
|
53
54
|
# Returns the blob properties from Windows Azure. This properties always come as HTTP Headers and they include standard headers like
|
@@ -65,6 +66,7 @@ module WAZ
|
|
65
66
|
# Assigns the given value to the blob content. It also stores a local copy of it in order to avoid round trips
|
66
67
|
# on scenarios when you do Save and Display on the same context.
|
67
68
|
def value=(new_value)
|
69
|
+
raise WAZ::Blobs::InvalidOperation if self.snapshot_date
|
68
70
|
self.class.service_instance.put_blob(path, new_value, content_type, metadata)
|
69
71
|
@value = new_value
|
70
72
|
end
|
@@ -72,6 +74,7 @@ module WAZ
|
|
72
74
|
# Stores the blob properties. Those properties are sent as HTTP Headers it's really important that you name your custom
|
73
75
|
# properties with the <em>x-ms-meta</em> prefix, if not the won't be persisted by the Windows Azure Blob Storage API.
|
74
76
|
def put_properties!(properties = {})
|
77
|
+
raise WAZ::Blobs::InvalidOperation if self.snapshot_date
|
75
78
|
self.class.service_instance.set_blob_properties(path, properties)
|
76
79
|
end
|
77
80
|
|
@@ -92,6 +95,16 @@ module WAZ
|
|
92
95
|
:content_type => properties[:content_type])
|
93
96
|
end
|
94
97
|
|
98
|
+
# Creates and returns a read-only snapshot of a blob as it looked like in time.
|
99
|
+
def snapshot
|
100
|
+
date = self.class.service_instance.snapshot_blob(self.path)
|
101
|
+
properties = self.class.service_instance.get_blob_properties(self.path)
|
102
|
+
return BlobObject.new(:name => self.name,
|
103
|
+
:url => self.class.service_instance.generate_request_uri(self.path) + "?snapshot=#{date}",
|
104
|
+
:content_type => properties[:content_type],
|
105
|
+
:snapshot_date => date)
|
106
|
+
end
|
107
|
+
|
95
108
|
# Returns the blob path. This is specially important when simulating containers inside containers
|
96
109
|
# by enabling the API to point to the appropiated resource.
|
97
110
|
def path
|
data/lib/waz/blobs/container.rb
CHANGED
@@ -41,6 +41,7 @@ module WAZ
|
|
41
41
|
class << self
|
42
42
|
# Creates a new container with the given name.
|
43
43
|
def create(name)
|
44
|
+
raise WAZ::Storage::InvalidParameterValue, {:name => "name", :values => ["lower letters, numbers or - (hypen), and must not start or end with - (hyphen)"]} unless WAZ::Storage::ValidationRules.valid_name?(name)
|
44
45
|
service_instance.create_container(name)
|
45
46
|
return Container.new(:name => name)
|
46
47
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module WAZ
|
2
|
+
module Blobs
|
3
|
+
# This exception is raised when the user tries to perform an operation over a snapshoted blob. Since
|
4
|
+
# Snapshots are read-only copies of the original blob they cannot be modified
|
5
|
+
class InvalidOperation < WAZ::Storage::StorageException
|
6
|
+
def initialize()
|
7
|
+
super("A snapshoted blob cannot be modified.")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/lib/waz/blobs/service.rb
CHANGED
@@ -60,7 +60,7 @@ module WAZ
|
|
60
60
|
|
61
61
|
# Lists all the blobs inside the given container.
|
62
62
|
def list_blobs(container_name)
|
63
|
-
content = execute(:get, container_name, { :comp => 'list'
|
63
|
+
content = execute(:get, container_name, { :comp => 'list'})
|
64
64
|
doc = REXML::Document.new(content)
|
65
65
|
containers = []
|
66
66
|
REXML::XPath.each(doc, '//Blob/') do |item|
|
@@ -79,17 +79,18 @@ module WAZ
|
|
79
79
|
#
|
80
80
|
# metadata is a hash that stores all the properties that you want to add to the blob when creating it.
|
81
81
|
def put_blob(path, payload, content_type = "application/octet-stream", metadata = {})
|
82
|
-
|
82
|
+
default_headers = {"Content-Type" => content_type, :x_ms_version => "2009-09-19", :x_ms_blob_type => "BlockBlob"}
|
83
|
+
execute :put, path, nil, metadata.merge(default_headers), payload
|
83
84
|
end
|
84
85
|
|
85
86
|
# Retrieves a blob (content + headers) from the current path.
|
86
87
|
def get_blob(path, options = {})
|
87
|
-
execute :get, path, options
|
88
|
+
execute :get, path, options, {:x_ms_version => "2009-09-19"}
|
88
89
|
end
|
89
90
|
|
90
91
|
# Deletes the blob existing on the current path.
|
91
92
|
def delete_blob(path)
|
92
|
-
execute :delete, path
|
93
|
+
execute :delete, path, nil, {:x_ms_version => "2009-09-19"}
|
93
94
|
end
|
94
95
|
|
95
96
|
# Retrieves the properties associated with the blob at the given path.
|
@@ -104,7 +105,7 @@ module WAZ
|
|
104
105
|
|
105
106
|
# Copies a blob within the same account (not necessarily to the same container)
|
106
107
|
def copy_blob(source_path, dest_path)
|
107
|
-
execute :put, dest_path, nil, { :x_ms_version => "2009-
|
108
|
+
execute :put, dest_path, nil, { :x_ms_version => "2009-09-19", :x_ms_copy_source => canonicalize_message(source_path) }
|
108
109
|
end
|
109
110
|
|
110
111
|
# Adds a block to the block list of the given blob
|
@@ -114,7 +115,7 @@ module WAZ
|
|
114
115
|
|
115
116
|
# Retrieves the list of blocks associated with a single blob. The list is filtered (or not) by type of blob
|
116
117
|
def list_blocks(path, block_list_type = 'all')
|
117
|
-
raise WAZ::Storage::InvalidParameterValue , {:name => :
|
118
|
+
raise WAZ::Storage::InvalidParameterValue , {:name => :blocklisttype, :values => ['all', 'uncommitted', 'committed']} unless (block_list_type or "") =~ /all|committed|uncommitted/i
|
118
119
|
content = execute(:get, path, {:comp => 'blocklist'}.merge(:blocklisttype => block_list_type.downcase), { :x_ms_version => "2009-04-14" })
|
119
120
|
doc = REXML::Document.new(content)
|
120
121
|
blocks = []
|
@@ -125,6 +126,11 @@ module WAZ
|
|
125
126
|
end
|
126
127
|
return blocks
|
127
128
|
end
|
129
|
+
|
130
|
+
# Creates a read-only snapshot of a blob as it looked like in time.
|
131
|
+
def snapshot_blob(path)
|
132
|
+
execute(:put, path, { :comp => 'snapshot' }, {:x_ms_version => "2009-09-19"}).headers[:x_ms_snapshot]
|
133
|
+
end
|
128
134
|
end
|
129
135
|
end
|
130
136
|
end
|
data/lib/waz/queues/queue.rb
CHANGED
@@ -7,15 +7,15 @@ module WAZ
|
|
7
7
|
# WAZ::Queues::Queue.list
|
8
8
|
#
|
9
9
|
# # create a queue (here you can also send hashed metadata)
|
10
|
-
# WAZ::Queues::Queue.create('
|
10
|
+
# WAZ::Queues::Queue.create('test-queue')
|
11
11
|
#
|
12
12
|
# # get a specific queue
|
13
|
-
# queue = WAZ::Queues::
|
13
|
+
# queue = WAZ::Queues::Queue.find('test-queue')
|
14
14
|
#
|
15
15
|
# # get queue properties (including default headers)
|
16
16
|
# queue.metadata #=> hash containing beautified metadata (:x_ms_meta_name)
|
17
17
|
#
|
18
|
-
# # set
|
18
|
+
# # set queue properties (should follow x-ms-meta to be persisted)
|
19
19
|
# # if you specify the optional parameter overwrite, existing metadata
|
20
20
|
# # will be deleted else merged with new one.
|
21
21
|
# queue.put_properties!(:x_ms_meta_MyProperty => "my value")
|
@@ -55,6 +55,7 @@ module WAZ
|
|
55
55
|
# metadata to be stored on the queue. (Remember that metadata on the storage account must start with
|
56
56
|
# :x_ms_metadata_{yourCustomPropertyName}, if not it will not be persisted).
|
57
57
|
def create(queue_name, metadata = {})
|
58
|
+
raise WAZ::Storage::InvalidParameterValue, {:name => "name", :values => ["lower letters, numbers or - (hypen), and must not start or end with - (hyphen)"]} unless WAZ::Storage::ValidationRules.valid_name?(queue_name)
|
58
59
|
service_instance.create_queue(queue_name, metadata)
|
59
60
|
WAZ::Queues::Queue.new(:name => queue_name, :url => service_instance.generate_request_uri(queue_name))
|
60
61
|
end
|
@@ -3,13 +3,14 @@ module WAZ
|
|
3
3
|
# This module is imported by the specific services that use Shared Key authentication profile. On the current implementation
|
4
4
|
# this module is imported from WAZ::Queues::Service and WAZ::Blobs::Service.
|
5
5
|
module SharedKeyCoreService
|
6
|
-
attr_accessor :account_name, :access_key, :use_ssl, :base_url
|
6
|
+
attr_accessor :account_name, :access_key, :use_ssl, :base_url, :type_of_service
|
7
7
|
|
8
8
|
# Creates an instance of the implementor service (internally used by the API).
|
9
9
|
def initialize(options = {})
|
10
10
|
self.account_name = options[:account_name]
|
11
11
|
self.access_key = options[:access_key]
|
12
12
|
self.use_ssl = options[:use_ssl] or false
|
13
|
+
self.type_of_service = options[:type_of_service]
|
13
14
|
self.base_url = "#{options[:type_of_service] or "blobs"}.#{options[:base_url] or "core.windows.net"}"
|
14
15
|
end
|
15
16
|
|
@@ -19,11 +20,11 @@ module WAZ
|
|
19
20
|
def generate_request(verb, url, headers = {}, payload = nil)
|
20
21
|
http_headers = {}
|
21
22
|
headers.each{ |k, v| http_headers[k.to_s.gsub(/_/, '-')] = v} unless headers.nil?
|
22
|
-
|
23
|
-
|
24
|
-
request
|
25
|
-
request.
|
26
|
-
return request
|
23
|
+
http_headers.merge!("x-ms-Date" => Time.new.httpdate)
|
24
|
+
http_headers.merge!("Content-Length" => (payload or "").length)
|
25
|
+
request = {:headers => http_headers, :method => verb.to_s.downcase.to_sym, :url => url, :payload => payload}
|
26
|
+
request[:headers].merge!("Authorization" => "SharedKey #{account_name}:#{generate_signature(request)}")
|
27
|
+
return RestClient::Request.new(request)
|
27
28
|
end
|
28
29
|
|
29
30
|
# Generates the request uri based on the resource path, the protocol, the account name and the parameters passed
|
@@ -55,42 +56,43 @@ module WAZ
|
|
55
56
|
# Generates the signature based on Micosoft specs for the REST API. It includes some special headers,
|
56
57
|
# the canonicalized header line and the canonical form of the message, all of the joined by \n character. Encoded with
|
57
58
|
# Base64 and encrypted with SHA256 using the access_key as the seed.
|
58
|
-
def generate_signature(
|
59
|
-
return generate_signature20090919(
|
60
|
-
|
61
|
-
|
62
|
-
(
|
63
|
-
(
|
64
|
-
|
65
|
-
|
59
|
+
def generate_signature(options = {})
|
60
|
+
return generate_signature20090919(options) if options[:headers]["x-ms-version"] == "2009-09-19"
|
61
|
+
|
62
|
+
signature = options[:method].to_s.upcase + "\x0A" +
|
63
|
+
(options[:headers]["Content-MD5"] or "") + "\x0A" +
|
64
|
+
(options[:headers]["Content-Type"] or "") + "\x0A" +
|
65
|
+
(options[:headers]["Date"] or "")+ "\x0A"
|
66
|
+
|
67
|
+
signature += canonicalize_headers(options[:headers]) + "\x0A" unless self.type_of_service == 'table'
|
68
|
+
signature += canonicalize_message(options[:url])
|
66
69
|
|
67
|
-
|
70
|
+
Base64.encode64(HMAC::SHA256.new(Base64.decode64(self.access_key)).update(signature.toutf8).digest)
|
68
71
|
end
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
(
|
74
|
-
(
|
75
|
-
(
|
76
|
-
(
|
77
|
-
(
|
78
|
-
(
|
79
|
-
(
|
80
|
-
(
|
81
|
-
(
|
82
|
-
(
|
83
|
-
(
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
return Base64.encode64(HMAC::SHA256.new(Base64.decode64(self.access_key)).update(signature.toutf8).digest)
|
72
|
+
|
73
|
+
def generate_signature20090919(options = {})
|
74
|
+
signature = options[:method].to_s.upcase + "\x0A" +
|
75
|
+
(options[:headers]["Content-Encoding"] or "") + "\x0A" +
|
76
|
+
(options[:headers]["Content-Language"] or "") + "\x0A" +
|
77
|
+
(options[:headers]["Content-Length"] or "").to_s + "\x0A" +
|
78
|
+
(options[:headers]["Content-MD5"] or "") + "\x0A" +
|
79
|
+
(options[:headers]["Content-Type"] or "") + "\x0A" +
|
80
|
+
(options[:headers]["Date"] or "")+ "\x0A" +
|
81
|
+
(options[:headers]["If-Modified-Since"] or "")+ "\x0A" +
|
82
|
+
(options[:headers]["If-Match"] or "")+ "\x0A" +
|
83
|
+
(options[:headers]["If-None-Match"] or "")+ "\x0A" +
|
84
|
+
(options[:headers]["If-Unmodified-Since"] or "")+ "\x0A" +
|
85
|
+
(options[:headers]["Range"] or "")+ "\x0A" +
|
86
|
+
canonicalize_headers(options[:headers]) + "\x0A" +
|
87
|
+
canonicalize_message20090919(options[:url])
|
88
|
+
|
89
|
+
Base64.encode64(HMAC::SHA256.new(Base64.decode64(self.access_key)).update(signature.toutf8).digest)
|
88
90
|
end
|
89
91
|
|
90
92
|
def canonicalize_message20090919(url)
|
91
93
|
uri_component = url.gsub(/https?:\/\/[^\/]+\//i, '').gsub(/\?.*/i, '')
|
92
94
|
query_component = (url.scan(/\?(.*)/i).first() or []).first()
|
93
|
-
query_component = query_component.
|
95
|
+
query_component = query_component.split('&').sort{|a, b| a <=> b}.map{ |p| p.split('=').join(':') }.join("\n") if query_component
|
94
96
|
canonicalized_message = "/#{self.account_name}/#{uri_component}"
|
95
97
|
canonicalized_message << "\n#{query_component}" if query_component
|
96
98
|
return canonicalized_message
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module WAZ
|
2
|
+
module Storage
|
3
|
+
class ValidationRules
|
4
|
+
class << self
|
5
|
+
# Validates that the Container/Queue name given matches with the requirements of Windows Azure.
|
6
|
+
#
|
7
|
+
# -Container/Queue names must start with a letter or number, and can contain only letters, numbers, and the dash (-) character.
|
8
|
+
# -Every dash (-) character must be immediately preceded and followed by a letter or number.
|
9
|
+
# -All letters in a container name must be lowercase.
|
10
|
+
# -Container/Queue names must be from 3 through 63 characters long.
|
11
|
+
def valid_name?(name)
|
12
|
+
name =~ /^[a-z0-9][a-z0-9\-]{1,}[^-]$/ && name.length < 64
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/waz/storage/version.rb
CHANGED
data/lib/waz-blobs.rb
CHANGED
data/lib/waz-storage.rb
CHANGED
@@ -3,6 +3,7 @@ require 'waz/storage/base'
|
|
3
3
|
require 'waz/storage/core_service'
|
4
4
|
require 'waz/storage/exceptions'
|
5
5
|
require 'waz/storage/version'
|
6
|
+
require 'waz/storage/validation_rules'
|
6
7
|
|
7
8
|
# It will depende on which version of Ruby (or if you have Rails)
|
8
9
|
# but this method is required so we will add it the String class.
|
data/rakefile
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: waz-storage
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Johnny G. Halife
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2010-02-03 00:00:00 -03:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -20,7 +20,7 @@ dependencies:
|
|
20
20
|
requirements:
|
21
21
|
- - ">="
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version:
|
23
|
+
version: "0"
|
24
24
|
version:
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: ruby-hmac
|
@@ -44,6 +44,7 @@ files:
|
|
44
44
|
- rakefile
|
45
45
|
- lib/waz/blobs/blob_object.rb
|
46
46
|
- lib/waz/blobs/container.rb
|
47
|
+
- lib/waz/blobs/exceptions.rb
|
47
48
|
- lib/waz/blobs/service.rb
|
48
49
|
- lib/waz/queues/exceptions.rb
|
49
50
|
- lib/waz/queues/message.rb
|
@@ -52,6 +53,7 @@ files:
|
|
52
53
|
- lib/waz/storage/base.rb
|
53
54
|
- lib/waz/storage/core_service.rb
|
54
55
|
- lib/waz/storage/exceptions.rb
|
56
|
+
- lib/waz/storage/validation_rules.rb
|
55
57
|
- lib/waz/storage/version.rb
|
56
58
|
- lib/waz-blobs.rb
|
57
59
|
- lib/waz-queues.rb
|