azure 0.0.0 → 0.1.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.
- data/Gemfile +3 -0
- data/Gemfile.lock +36 -0
- data/README.md +3 -0
- data/Rakefile +81 -0
- data/azure.gemspec +20 -9
- data/lib/azure.rb +4 -0
- data/lib/azure/atom.rb +170 -0
- data/lib/azure/auth.rb +29 -0
- data/lib/azure/blobs.rb +620 -0
- data/lib/azure/blobs/blob.rb +360 -0
- data/lib/azure/blobs/container.rb +209 -0
- data/lib/azure/blobs/service.rb +396 -0
- data/lib/azure/blobs/shared_access_signature.rb +84 -0
- data/lib/azure/blobs/uri.rb +60 -0
- data/lib/azure/configuration.rb +121 -0
- data/lib/azure/core/auth/shared_key.rb +95 -0
- data/lib/azure/core/auth/shared_key_lite.rb +34 -0
- data/lib/azure/core/collection.rb +118 -0
- data/lib/azure/core/service.rb +43 -0
- data/lib/azure/core/signer.rb +32 -0
- data/lib/azure/core/utils/interval.rb +97 -0
- data/lib/azure/core/utils/queryable.rb +74 -0
- data/lib/azure/core/utils/storage_service_properties.rb +83 -0
- data/lib/azure/core/utils/string.rb +59 -0
- data/lib/azure/error.rb +72 -0
- data/lib/azure/queues.rb +272 -0
- data/lib/azure/queues/message.rb +174 -0
- data/lib/azure/queues/queue.rb +187 -0
- data/lib/azure/queues/service.rb +263 -0
- data/lib/azure/queues/service_properties.rb +152 -0
- data/lib/azure/queues/uri.rb +78 -0
- data/lib/azure/request.rb +102 -0
- data/lib/azure/response.rb +93 -0
- data/lib/azure/service_bus.rb +4 -0
- data/lib/azure/service_bus/auth/authorizer.rb +22 -0
- data/lib/azure/service_bus/auth/uri.rb +52 -0
- data/lib/azure/service_bus/auth/wrap.rb +37 -0
- data/lib/azure/service_bus/auth/wrap_service.rb +76 -0
- data/lib/azure/service_bus/auth/wrap_token.rb +45 -0
- data/lib/azure/service_bus/auth/wrap_token_manager.rb +46 -0
- data/lib/azure/service_bus/brokered_message.rb +139 -0
- data/lib/azure/service_bus/brokered_message_serializer.rb +113 -0
- data/lib/azure/service_bus/queues.rb +194 -0
- data/lib/azure/service_bus/queues/queue.rb +100 -0
- data/lib/azure/service_bus/queues/queue_serializer.rb +51 -0
- data/lib/azure/service_bus/queues/service.rb +154 -0
- data/lib/azure/service_bus/queues/uri.rb +80 -0
- data/lib/azure/service_bus/rules.rb +110 -0
- data/lib/azure/service_bus/rules/rule.rb +97 -0
- data/lib/azure/service_bus/rules/service.rb +122 -0
- data/lib/azure/service_bus/rules/uri.rb +39 -0
- data/lib/azure/service_bus/service_bus_service.rb +22 -0
- data/lib/azure/service_bus/subscriptions.rb +170 -0
- data/lib/azure/service_bus/subscriptions/service.rb +133 -0
- data/lib/azure/service_bus/subscriptions/subscription.rb +164 -0
- data/lib/azure/service_bus/subscriptions/subscription_serializer.rb +74 -0
- data/lib/azure/service_bus/subscriptions/uri.rb +71 -0
- data/lib/azure/service_bus/topics.rb +120 -0
- data/lib/azure/service_bus/topics/service.rb +98 -0
- data/lib/azure/service_bus/topics/topic.rb +122 -0
- data/lib/azure/service_bus/topics/topic_serializer.rb +44 -0
- data/lib/azure/service_bus/topics/uri.rb +58 -0
- data/lib/azure/service_runtime/client/goal_state_pipe_monitor.rb +21 -0
- data/lib/azure/service_runtime/client/goal_state_protocol.rb +18 -0
- data/lib/azure/service_runtime/client/runtime_client.rb +135 -0
- data/lib/azure/service_runtime/deployment.rb +24 -0
- data/lib/azure/service_runtime/local_resource.rb +15 -0
- data/lib/azure/service_runtime/role.rb +17 -0
- data/lib/azure/service_runtime/role_environment.rb +206 -0
- data/lib/azure/service_runtime/role_environment_change.rb +32 -0
- data/lib/azure/service_runtime/role_instance.rb +35 -0
- data/lib/azure/service_runtime/role_instance_endpoint.rb +14 -0
- data/lib/azure/tables.rb +215 -0
- data/lib/azure/tables/auth/shared_key.rb +71 -0
- data/lib/azure/tables/auth/shared_key_lite.rb +30 -0
- data/lib/azure/tables/entities_collection.rb +66 -0
- data/lib/azure/tables/entity.rb +127 -0
- data/lib/azure/tables/service.rb +211 -0
- data/lib/azure/tables/table.rb +129 -0
- data/lib/azure/tables/tables_collection.rb +62 -0
- data/lib/azure/tables/types.rb +65 -0
- data/lib/azure/tables/uri.rb +62 -0
- data/test/fixtures/32px-fulls-black.jpg +0 -0
- data/test/fixtures/all_containers.xml +20 -0
- data/test/fixtures/all_tables.xml +22 -0
- data/test/fixtures/create_table_response_entry.xml +15 -0
- data/test/fixtures/error.xml +5 -0
- data/test/fixtures/insert_entity_response_entry.xml +25 -0
- data/test/fixtures/messages.xml +12 -0
- data/test/fixtures/query_entities_empty_response.xml +7 -0
- data/test/fixtures/query_entities_response.xml +45 -0
- data/test/fixtures/queue_service_properties.xml +22 -0
- data/test/fixtures/queue_service_properties_original.xml +19 -0
- data/test/fixtures/queues.xml +16 -0
- data/test/fixtures/sb_default_create_queue_response.xml +23 -0
- data/test/fixtures/sb_default_create_topic_response.xml +18 -0
- data/test/fixtures/sb_get_access_token_response.txt +1 -0
- data/test/fixtures/sb_queues_runtime_peek_message_response_headers.txt +9 -0
- data/test/integration/blobs/auth_test.rb +19 -0
- data/test/integration/blobs/blob_test.rb +61 -0
- data/test/integration/blobs/clear_page_range_test.rb +19 -0
- data/test/integration/blobs/copy_test.rb +33 -0
- data/test/integration/blobs/create_blobs_test.rb +51 -0
- data/test/integration/blobs/create_container_test.rb +13 -0
- data/test/integration/blobs/create_snapshot_test.rb +17 -0
- data/test/integration/blobs/delete_blob_snapshots_test.rb +19 -0
- data/test/integration/blobs/delete_blobs_test.rb +25 -0
- data/test/integration/blobs/delete_container_test.rb +24 -0
- data/test/integration/blobs/delete_snapshot_test.rb +17 -0
- data/test/integration/blobs/get_blob_snapshot_test.rb +18 -0
- data/test/integration/blobs/get_blobs_test.rb +31 -0
- data/test/integration/blobs/get_page_range_test.rb +19 -0
- data/test/integration/blobs/list_blobs_test.rb +39 -0
- data/test/integration/blobs/list_containers_test.rb +28 -0
- data/test/integration/blobs/manage_blob_leases_test.rb +45 -0
- data/test/integration/blobs/manage_blob_metadata_test.rb +51 -0
- data/test/integration/blobs/manage_blob_properties_test.rb +25 -0
- data/test/integration/blobs/manage_blob_service_properties_test.rb +38 -0
- data/test/integration/blobs/manage_container_metadata_test.rb +46 -0
- data/test/integration/blobs/manage_container_permissions_test.rb +17 -0
- data/test/integration/blobs/update_page_range_test.rb +20 -0
- data/test/integration/queues/clear_messages_test.rb +22 -0
- data/test/integration/queues/create_queue_test.rb +13 -0
- data/test/integration/queues/delete_message_test.rb +42 -0
- data/test/integration/queues/delete_queue_test.rb +24 -0
- data/test/integration/queues/get_messages_test.rb +39 -0
- data/test/integration/queues/list_queues_test.rb +43 -0
- data/test/integration/queues/manage_queue_metadata_test.rb +45 -0
- data/test/integration/queues/manage_queue_service_properties_test.rb +27 -0
- data/test/integration/queues/peek_messages_test.rb +55 -0
- data/test/integration/queues/put_message_test.rb +31 -0
- data/test/integration/queues/update_message_test.rb +46 -0
- data/test/integration/service_bus/auth_test.rb +18 -0
- data/test/integration/service_bus/queues/create_queue_test.rb +25 -0
- data/test/integration/service_bus/queues/delete_message_from_queue_test.rb +29 -0
- data/test/integration/service_bus/queues/delete_queue_test.rb +25 -0
- data/test/integration/service_bus/queues/get_queue_test.rb +23 -0
- data/test/integration/service_bus/queues/list_queues_test.rb +39 -0
- data/test/integration/service_bus/queues/peek_message_from_queue_test.rb +34 -0
- data/test/integration/service_bus/queues/read_and_delete_message_from_queue_test.rb +31 -0
- data/test/integration/service_bus/queues/send_message_to_queue_test.rb +22 -0
- data/test/integration/service_bus/queues/unlock_message_from_queue_test.rb +36 -0
- data/test/integration/service_bus/rules/create_rule_test.rb +19 -0
- data/test/integration/service_bus/rules/delete_rule_test.rb +17 -0
- data/test/integration/service_bus/rules/get_rule_test.rb +21 -0
- data/test/integration/service_bus/rules/list_rules_test.rb +24 -0
- data/test/integration/service_bus/rules/rule_test.rb +16 -0
- data/test/integration/service_bus/subscriptions/create_subscription_test.rb +25 -0
- data/test/integration/service_bus/subscriptions/delete_message_from_subscription_test.rb +31 -0
- data/test/integration/service_bus/subscriptions/delete_subscription_test.rb +30 -0
- data/test/integration/service_bus/subscriptions/fetch_subscription_test.rb +28 -0
- data/test/integration/service_bus/subscriptions/list_subscriptions_test.rb +23 -0
- data/test/integration/service_bus/subscriptions/peek_lock_message_from_subscription_test.rb +42 -0
- data/test/integration/service_bus/subscriptions/read_delete_message_from_subscription_test.rb +36 -0
- data/test/integration/service_bus/subscriptions/subscription_test.rb +31 -0
- data/test/integration/service_bus/subscriptions/unlock_message_from_subscription_test.rb +43 -0
- data/test/integration/service_bus/topics/create_topic_test.rb +25 -0
- data/test/integration/service_bus/topics/delete_topic_test.rb +25 -0
- data/test/integration/service_bus/topics/get_topic_test.rb +23 -0
- data/test/integration/service_bus/topics/list_topics_test.rb +39 -0
- data/test/integration/service_bus/topics/send_message_to_topic_test.rb +23 -0
- data/test/integration/tables/auth_test.rb +29 -0
- data/test/integration/tables/creating_tables_test.rb +16 -0
- data/test/integration/tables/delete_entity_test.rb +39 -0
- data/test/integration/tables/deleting_table_test.rb +22 -0
- data/test/integration/tables/insert_entity_test.rb +23 -0
- data/test/integration/tables/merge_entity_test.rb +28 -0
- data/test/integration/tables/query_entities_test.rb +131 -0
- data/test/integration/tables/query_tables_test.rb +63 -0
- data/test/integration/tables/update_entity_test.rb +54 -0
- data/test/integration/test_helper.rb +14 -0
- data/test/support/blobs.rb +12 -0
- data/test/support/env.rb +5 -0
- data/test/support/fixtures.rb +22 -0
- data/test/support/stubs.rb +28 -0
- data/test/support/table_names.rb +44 -0
- data/test/test_helper.rb +10 -0
- data/test/unit/atom_test.rb +58 -0
- data/test/unit/auth_test.rb +24 -0
- data/test/unit/blobs/blob_test.rb +5 -0
- data/test/unit/blobs/container_test.rb +67 -0
- data/test/unit/blobs/service_test.rb +17 -0
- data/test/unit/blobs/shared_access_signature_test.rb +66 -0
- data/test/unit/blobs_test.rb +156 -0
- data/test/unit/core/service_test.rb +57 -0
- data/test/unit/core/utils/interval_test.rb +70 -0
- data/test/unit/core/utils/queryable_test.rb +69 -0
- data/test/unit/core/utils/storage_service_properties_test.rb +66 -0
- data/test/unit/error_test.rb +39 -0
- data/test/unit/queues/message_test.rb +40 -0
- data/test/unit/queues/queue_test.rb +64 -0
- data/test/unit/queues/service_properties.rb +35 -0
- data/test/unit/request_test.rb +38 -0
- data/test/unit/response_test.rb +43 -0
- data/test/unit/service_bus/auth/authorizer_test.rb +27 -0
- data/test/unit/service_bus/auth/wrap_token_test.rb +28 -0
- data/test/unit/service_bus/queues/queue_test.rb +38 -0
- data/test/unit/service_bus/topics/topic_test.rb +33 -0
- data/test/unit/service_runtime/data/goalstate.xml +9 -0
- data/test/unit/service_runtime/data/roleenvironmentdata.xml +29 -0
- data/test/unit/service_runtime/data/runtime.xml +6 -0
- data/test/unit/service_runtime/role_environment_test.rb +144 -0
- data/test/unit/tables/auth/shared_key_lite_test.rb +39 -0
- data/test/unit/tables/auth/shared_key_test.rb +45 -0
- data/test/unit/tables/entities_collection_test.rb +39 -0
- data/test/unit/tables/entity_test.rb +72 -0
- data/test/unit/tables/table_test.rb +57 -0
- data/test/unit/tables_test.rb +302 -0
- data/test/unit/types_test.rb +67 -0
- metadata +310 -47
- data/LICENSE +0 -0
- data/README +0 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
azure (0.1.0)
|
|
5
|
+
mime-types (~> 1.0)
|
|
6
|
+
nokogiri (~> 1.5)
|
|
7
|
+
ratom (~> 0.6)
|
|
8
|
+
uuid (~> 2.0)
|
|
9
|
+
|
|
10
|
+
GEM
|
|
11
|
+
remote: http://rubygems.org/
|
|
12
|
+
specs:
|
|
13
|
+
em-minitest-spec (1.1.1)
|
|
14
|
+
eventmachine
|
|
15
|
+
eventmachine (0.12.10)
|
|
16
|
+
libxml-ruby (2.3.2)
|
|
17
|
+
macaddr (1.6.1)
|
|
18
|
+
systemu (~> 2.5.0)
|
|
19
|
+
mime-types (1.18)
|
|
20
|
+
minitest (3.1.0)
|
|
21
|
+
nokogiri (1.5.4)
|
|
22
|
+
rake (0.9.2.2)
|
|
23
|
+
ratom (0.7.0)
|
|
24
|
+
libxml-ruby (~> 2.3.2)
|
|
25
|
+
systemu (2.5.1)
|
|
26
|
+
uuid (2.3.5)
|
|
27
|
+
macaddr (~> 1.0)
|
|
28
|
+
|
|
29
|
+
PLATFORMS
|
|
30
|
+
ruby
|
|
31
|
+
|
|
32
|
+
DEPENDENCIES
|
|
33
|
+
azure!
|
|
34
|
+
em-minitest-spec
|
|
35
|
+
minitest (~> 3.0)
|
|
36
|
+
rake
|
data/README.md
ADDED
data/Rakefile
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
require "rake/testtask"
|
|
2
|
+
require "rubygems/package_task"
|
|
3
|
+
|
|
4
|
+
gem_spec = eval(File.read("./azure.gemspec"))
|
|
5
|
+
Gem::PackageTask.new(gem_spec) do |pkg|
|
|
6
|
+
pkg.need_zip = false
|
|
7
|
+
pkg.need_tar = false
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
namespace :test do
|
|
11
|
+
Rake::TestTask.new :unit do |t|
|
|
12
|
+
t.pattern = "test/unit/**/*_test.rb"
|
|
13
|
+
t.verbose = true
|
|
14
|
+
t.libs = ["lib", "test"]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
Rake::TestTask.new :integration do |t|
|
|
18
|
+
t.pattern = "test/integration/**/*_test.rb"
|
|
19
|
+
t.verbose = true
|
|
20
|
+
t.libs = ["lib", "test"]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
namespace :integration do
|
|
24
|
+
def component_task(component)
|
|
25
|
+
Rake::TestTask.new component do |t|
|
|
26
|
+
t.pattern = "test/integration/#{component}/**/*_test.rb"
|
|
27
|
+
t.verbose = true
|
|
28
|
+
t.libs = ["lib", "test"]
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
component_task :tables
|
|
33
|
+
component_task :blobs
|
|
34
|
+
component_task :queues
|
|
35
|
+
component_task :service_bus
|
|
36
|
+
|
|
37
|
+
task :conditionally do
|
|
38
|
+
name = ENV.fetch("AZURE_ACCOUNT_NAME", nil)
|
|
39
|
+
key = ENV.fetch("AZURE_ACCESS_KEY", nil)
|
|
40
|
+
t_host = ENV.fetch("AZURE_TABLE_HOST", nil)
|
|
41
|
+
b_host = ENV.fetch("AZURE_BLOB_HOST", nil)
|
|
42
|
+
q_host = ENV.fetch("AZURE_QUEUE_HOST", nil)
|
|
43
|
+
acs_namespace = ENV.fetch("AZURE_ACS_NAMESPACE", nil)
|
|
44
|
+
sb_access_key = ENV.fetch("AZURE_SB_ACCESS_KEY", nil)
|
|
45
|
+
sb_issuer = ENV.fetch("AZURE_SB_ISSUER", nil)
|
|
46
|
+
|
|
47
|
+
if name && key && t_host && b_host && q_host && acs_namespace && sb_access_key && sb_issuer
|
|
48
|
+
Rake::Task["test:integration"].invoke
|
|
49
|
+
else
|
|
50
|
+
warn "[WARNING] Configure your environment to run the integration tests"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
Rake::TestTask.new :cleanup do |t|
|
|
56
|
+
$:.unshift "lib"
|
|
57
|
+
require 'azure'
|
|
58
|
+
|
|
59
|
+
Azure.configure do |config|
|
|
60
|
+
config.access_key = ENV.fetch("AZURE_ACCESS_KEY")
|
|
61
|
+
config.account_name = ENV.fetch("AZURE_ACCOUNT_NAME")
|
|
62
|
+
config.table_host = ENV.fetch("AZURE_TABLE_HOST")
|
|
63
|
+
config.blob_host = ENV.fetch("AZURE_BLOB_HOST")
|
|
64
|
+
config.queue_host = ENV.fetch("AZURE_QUEUE_HOST")
|
|
65
|
+
|
|
66
|
+
config.acs_namespace = ENV.fetch("AZURE_ACS_NAMESPACE")
|
|
67
|
+
config.sb_access_key = ENV.fetch("AZURE_SB_ACCESS_KEY")
|
|
68
|
+
config.sb_issuer = ENV.fetch("AZURE_SB_ISSUER")
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
Azure::Tables.all.map(&:delete)
|
|
72
|
+
Azure::Blobs.containers.map(&:delete)
|
|
73
|
+
Azure::Queues.all.map(&:delete)
|
|
74
|
+
Azure::ServiceBus::Queues.list.map(&:delete)
|
|
75
|
+
Azure::ServiceBus::Topics.list.map(&:delete)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
task :test => ["test:unit", "test:integration:conditionally"]
|
|
80
|
+
|
|
81
|
+
task default: :test
|
data/azure.gemspec
CHANGED
|
@@ -1,12 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
require "date"
|
|
2
2
|
|
|
3
3
|
Gem::Specification.new do |s|
|
|
4
|
-
s.name
|
|
5
|
-
s.version
|
|
6
|
-
s.
|
|
7
|
-
|
|
8
|
-
s.authors = ["
|
|
9
|
-
s.email = "
|
|
10
|
-
s.
|
|
11
|
-
s.
|
|
4
|
+
s.name = "azure"
|
|
5
|
+
s.version = "0.1.0"
|
|
6
|
+
s.date = Date.today.iso8601
|
|
7
|
+
|
|
8
|
+
s.authors = ["Microsoft"]
|
|
9
|
+
s.email = "azure@microsoft.com"
|
|
10
|
+
s.description = "Services and ruby SDKs to access the Windows Azure platform."
|
|
11
|
+
s.summary = "Implementation of several Windows Azure SDKs in ruby."
|
|
12
|
+
s.homepage = "http://azure.com"
|
|
13
|
+
s.files = `git ls-files | grep -v "^examples/"`.split("\n")
|
|
14
|
+
|
|
15
|
+
s.add_runtime_dependency("uuid", "~> 2.0")
|
|
16
|
+
s.add_runtime_dependency("ratom", "~> 0.6")
|
|
17
|
+
s.add_runtime_dependency("nokogiri", "~> 1.5")
|
|
18
|
+
s.add_runtime_dependency("mime-types", "~> 1.0")
|
|
19
|
+
|
|
20
|
+
s.add_development_dependency("rake")
|
|
21
|
+
s.add_development_dependency("minitest", "~> 3.0")
|
|
22
|
+
s.add_development_dependency("em-minitest-spec")
|
|
12
23
|
end
|
data/lib/azure.rb
ADDED
data/lib/azure/atom.rb
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
require "atom"
|
|
2
|
+
require "azure/tables/types"
|
|
3
|
+
|
|
4
|
+
module Azure
|
|
5
|
+
# Collection of XML::Node extensions for generating Atom feeds.
|
|
6
|
+
module Atom
|
|
7
|
+
Entry = ::Atom::Entry
|
|
8
|
+
Feed = ::Atom::Feed
|
|
9
|
+
|
|
10
|
+
# Generates a Data Property, making sure that it's in the correct namespace
|
|
11
|
+
# (dataservices).
|
|
12
|
+
class Property < XML::Node
|
|
13
|
+
|
|
14
|
+
# Public: Set up the property.
|
|
15
|
+
#
|
|
16
|
+
# name - The property name, without the namespace qualification.
|
|
17
|
+
# value - The property's value.
|
|
18
|
+
def initialize(name, value)
|
|
19
|
+
super("d:#{name}")
|
|
20
|
+
self << value
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Public: Set the property's value, and sets the content type based on the
|
|
24
|
+
# value's type.
|
|
25
|
+
#
|
|
26
|
+
# value - The value of the property.
|
|
27
|
+
#
|
|
28
|
+
# Returns self.
|
|
29
|
+
def <<(value)
|
|
30
|
+
self["m:type"] = Azure::Tables::Types.type_of(value)
|
|
31
|
+
super(value)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def to_xml(*)
|
|
35
|
+
self
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Represent a list of properties in the proper namespace
|
|
40
|
+
# (dataservices/metadata).
|
|
41
|
+
class PropertyList < XML::Node
|
|
42
|
+
include ::Atom::Xml::Parseable
|
|
43
|
+
|
|
44
|
+
add_extension_namespace "d", "http://schemas.microsoft.com/ado/2007/08/dataservices"
|
|
45
|
+
|
|
46
|
+
# Public: Initialize the property list.
|
|
47
|
+
#
|
|
48
|
+
# Yields the PropertyList.
|
|
49
|
+
def initialize(o=nil)
|
|
50
|
+
super("m:properties")
|
|
51
|
+
|
|
52
|
+
if o && o.is_a?(LibXML::XML::Reader)
|
|
53
|
+
o.node.children.each do |node|
|
|
54
|
+
self << node.copy(true) unless node.blank?
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
yield self if block_given?
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Public: Add several properties at the same time.
|
|
62
|
+
#
|
|
63
|
+
# properties - A Hash of property name => property value pairs.
|
|
64
|
+
#
|
|
65
|
+
# Returns the passed properties.
|
|
66
|
+
def merge(properties)
|
|
67
|
+
properties.each do |name, value|
|
|
68
|
+
self[name] = value
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Public: Add a property to this list. This will internally store a
|
|
73
|
+
# Atom::Nodes::Property object.
|
|
74
|
+
#
|
|
75
|
+
# property - The name of the property to be included.
|
|
76
|
+
# value - The value of the property.
|
|
77
|
+
#
|
|
78
|
+
# Returns nothing.
|
|
79
|
+
def []=(property, value)
|
|
80
|
+
self << Property.new(property, value)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def to_xml(*)
|
|
84
|
+
self
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Represent an entry's <content/> tag, ensuring it has the correct content
|
|
89
|
+
# type and that it conforms to the Atom::Content interface so it can be used
|
|
90
|
+
# seamlessly with Atom::Entry objects.
|
|
91
|
+
class Content < XML::Node
|
|
92
|
+
include ::Atom::Xml::Parseable
|
|
93
|
+
|
|
94
|
+
add_extension_namespace "m", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
|
|
95
|
+
|
|
96
|
+
element "m:properties", class: Azure::Atom::PropertyList
|
|
97
|
+
|
|
98
|
+
# Public: Initialize the content node.
|
|
99
|
+
#
|
|
100
|
+
# Yields self.
|
|
101
|
+
def initialize(o=nil)
|
|
102
|
+
super("content")
|
|
103
|
+
self["type"] = "application/xml"
|
|
104
|
+
|
|
105
|
+
if o && o.is_a?(LibXML::XML::Reader)
|
|
106
|
+
o.read_inner_xml
|
|
107
|
+
o.read
|
|
108
|
+
parse o
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
yield self if block_given?
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Public: Cast this object into something Atom::Entry can understand as
|
|
115
|
+
# content. By returning itself (as a Node) the Entry won't try to escape
|
|
116
|
+
# this as CDATA.
|
|
117
|
+
#
|
|
118
|
+
# Returns self.
|
|
119
|
+
def to_xml(*)
|
|
120
|
+
self
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# FIXME: The rAtom gem doesn't play well when you extend your classes, raising
|
|
127
|
+
# weird errors, so we're monkeypatching their classes. This *sucks*.
|
|
128
|
+
module Atom
|
|
129
|
+
# Public: An Atom feed, that understands the Microsoft ADO namespaces for Data
|
|
130
|
+
# services.
|
|
131
|
+
class Feed
|
|
132
|
+
add_extension_namespace "d", "http://schemas.microsoft.com/ado/2007/08/dataservices"
|
|
133
|
+
add_extension_namespace "m", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Public: An Atom entry, that understands the Microsoft ADO namespaces for Data
|
|
137
|
+
# services.
|
|
138
|
+
class Entry
|
|
139
|
+
add_extension_namespace "d", "http://schemas.microsoft.com/ado/2007/08/dataservices"
|
|
140
|
+
add_extension_namespace "m", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
|
|
141
|
+
|
|
142
|
+
element "content", class: Azure::Atom::Content
|
|
143
|
+
|
|
144
|
+
# Public: Generate a list of data properties to include in this Entry's
|
|
145
|
+
# content.
|
|
146
|
+
# FIXME: This method isn't very confident as getter, use content.m_properties instead.
|
|
147
|
+
#
|
|
148
|
+
# Yields a Nodes::PropertyList.
|
|
149
|
+
#
|
|
150
|
+
# Example:
|
|
151
|
+
#
|
|
152
|
+
# entry.properties do |props|
|
|
153
|
+
# props["one"] = 1
|
|
154
|
+
# props["two"] = 2
|
|
155
|
+
# end
|
|
156
|
+
#
|
|
157
|
+
# Returns the XML node for entry's <m_properties/>.
|
|
158
|
+
def properties(&block)
|
|
159
|
+
if !@content
|
|
160
|
+
@content = Azure::Atom::Content.new
|
|
161
|
+
@m_properties = Azure::Atom::PropertyList.new
|
|
162
|
+
@content << @m_properties
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
yield @m_properties if block_given?
|
|
166
|
+
|
|
167
|
+
@m_properties
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
data/lib/azure/auth.rb
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require "azure/configuration"
|
|
2
|
+
|
|
3
|
+
module Azure
|
|
4
|
+
class Auth
|
|
5
|
+
# The account name.
|
|
6
|
+
attr :account_name
|
|
7
|
+
|
|
8
|
+
# Public: Initialize the Auth object.
|
|
9
|
+
#
|
|
10
|
+
# account_name - A String with the Azure account's name. Defaults to the one
|
|
11
|
+
# in the global configuration.
|
|
12
|
+
def initialize(account_name=Azure.config.account_name)
|
|
13
|
+
@account_name = account_name
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Public: Signs an HTTP request before it's made, by adding the
|
|
17
|
+
# Authorization header.
|
|
18
|
+
#
|
|
19
|
+
# request - An Azure::Request that hasn't been signed.
|
|
20
|
+
# signer - A signing strategy, such as Azure::Table::Auth::SharedKey.
|
|
21
|
+
#
|
|
22
|
+
# Returns the modified request.
|
|
23
|
+
def sign(request, signer)
|
|
24
|
+
signature = signer.sign(request.method, request.uri, request.headers)
|
|
25
|
+
request.headers["Authorization"] = "#{signer.name} #{account_name}:#{signature}"
|
|
26
|
+
request
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
data/lib/azure/blobs.rb
ADDED
|
@@ -0,0 +1,620 @@
|
|
|
1
|
+
require "nokogiri"
|
|
2
|
+
require "uri"
|
|
3
|
+
require "azure/blobs/service"
|
|
4
|
+
require "azure/blobs/container"
|
|
5
|
+
require "azure/blobs/blob"
|
|
6
|
+
require "azure/blobs/uri"
|
|
7
|
+
|
|
8
|
+
module Azure
|
|
9
|
+
module Blobs
|
|
10
|
+
# Public: Get a list of Containers from the server.
|
|
11
|
+
#
|
|
12
|
+
# service - The backend service to implement this (optional).
|
|
13
|
+
#
|
|
14
|
+
# Returns an Array of Container elements.
|
|
15
|
+
def self.containers(service=Azure::Blobs::Services::ListContainers.new)
|
|
16
|
+
response = service.call
|
|
17
|
+
document = Nokogiri::XML(response.body)
|
|
18
|
+
(document / "//Containers/Container").map do |node|
|
|
19
|
+
Container.from_node(node)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Public: Try to create a new container. If the operation is unsuccessful,
|
|
24
|
+
# the resulting Container object will have the error accessible through the
|
|
25
|
+
# #error method.
|
|
26
|
+
#
|
|
27
|
+
# name - The name of the container.
|
|
28
|
+
# metadata - User defined metadata for this container (optional).
|
|
29
|
+
# visibility - One of Container::PRIVATE, Container::CONTAINER, or
|
|
30
|
+
# Container::BLOB, specifying the level of visibility for
|
|
31
|
+
# anonymouse requests to this container. (optional, defaults to
|
|
32
|
+
# Container::PRIVATE).
|
|
33
|
+
# service - The backend service to implement this (optional).
|
|
34
|
+
#
|
|
35
|
+
# Returns a Container.
|
|
36
|
+
def self.create_container(name, metadata={}, visibility=Container::PRIVATE, service=Azure::Blobs::Services::CreateContainer.new)
|
|
37
|
+
response = service.call(name, metadata, visibility)
|
|
38
|
+
|
|
39
|
+
if response.success?
|
|
40
|
+
Container.new(name) do |container|
|
|
41
|
+
container.visibility = visibility
|
|
42
|
+
end
|
|
43
|
+
else
|
|
44
|
+
Container.from_error(response.error)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Public: Obtain the metadata of a container. This updates the container and
|
|
49
|
+
# changes the metadata internally if successful. If the operation fails, the
|
|
50
|
+
# container's metadata does not change, and the container is invalidated.
|
|
51
|
+
#
|
|
52
|
+
# container - An Azure::Blobs::Container.
|
|
53
|
+
# service - The backend service to implement this (optional).
|
|
54
|
+
#
|
|
55
|
+
# Returns a Hash.
|
|
56
|
+
def self.load_container_metadata(container, service=Azure::Blobs::Services::GetContainerMetadata.new)
|
|
57
|
+
response = service.call(container.name)
|
|
58
|
+
|
|
59
|
+
if response.success?
|
|
60
|
+
container.extract_metadata(response.headers)
|
|
61
|
+
else
|
|
62
|
+
container.error = response.error
|
|
63
|
+
|
|
64
|
+
{}
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Public: Save the current metadata of a container in the storage service.
|
|
69
|
+
# If the operation fails, the container is invalidated.
|
|
70
|
+
#
|
|
71
|
+
# container - An Azure::Blobs::Container.
|
|
72
|
+
# metadata - User defined metadata for this container (optional).
|
|
73
|
+
# service - The backend service to implement this (optional).
|
|
74
|
+
#
|
|
75
|
+
# Returns true|false to indicate success.
|
|
76
|
+
def self.save_container_metadata(container, service=Azure::Blobs::Services::SetContainerMetadata.new)
|
|
77
|
+
response = service.call(container.name, container.metadata)
|
|
78
|
+
container.error = response.error unless response.success?
|
|
79
|
+
response.success?
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Public: Delete a Container from the server. If the delete operation fails,
|
|
83
|
+
# the container is invalidated. Otherwise it's frozen.
|
|
84
|
+
#
|
|
85
|
+
# container - An Azure::Blobs::Container.
|
|
86
|
+
# service - The backend service to implement this (optional).
|
|
87
|
+
#
|
|
88
|
+
# Returns true|false to indicate success.
|
|
89
|
+
def self.delete_container(container, service=Azure::Blobs::Services::DeleteContainer.new)
|
|
90
|
+
response = service.call(container.name)
|
|
91
|
+
|
|
92
|
+
if response.success?
|
|
93
|
+
container.freeze
|
|
94
|
+
else
|
|
95
|
+
container.error = response.error
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
response.success?
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Public: Creates a new Block Blob, or updates an existent one. If the
|
|
102
|
+
# request is unsuccessful, the resulting blob is invalidated.
|
|
103
|
+
#
|
|
104
|
+
# container - An Azure::Blobs::Container instance.
|
|
105
|
+
# blob_name - A String representing the Blob name.
|
|
106
|
+
# filename - String representing a file in the file system. 64mb limit.
|
|
107
|
+
# metadata - A Hash representing blob metadata as :name => value.
|
|
108
|
+
# service - The backend service to implement this (optional).
|
|
109
|
+
#
|
|
110
|
+
# Returns an instance of Azure::Blobs::BlockBlob.
|
|
111
|
+
def self.create_block_blob(container, blob_name, filename, metadata={}, service=Azure::Blobs::Services::CreateBlockBlob.new)
|
|
112
|
+
|
|
113
|
+
response = service.call(container.name, blob_name, filename, metadata)
|
|
114
|
+
|
|
115
|
+
if response.success?
|
|
116
|
+
Azure::Blobs::BlockBlob.new(blob_name, container) do |blob|
|
|
117
|
+
blob.metadata.replace(metadata)
|
|
118
|
+
blob.extract_properties(response.headers)
|
|
119
|
+
end
|
|
120
|
+
else
|
|
121
|
+
Azure::Blobs::BlockBlob.from_error(response.error)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Public: Creates a new Page Blob, or updates an existent one. If the
|
|
126
|
+
# request is unsuccessful, the resulting blob is invalidated.
|
|
127
|
+
#
|
|
128
|
+
# container - An Azure::Blobs::Container instance.
|
|
129
|
+
# blob_name - A String representing the Blob name.
|
|
130
|
+
# size - Size must be aligned to a 512-byte boundary. 1 TB max.
|
|
131
|
+
# metadata - A Hash representing blob metadata as :name => value.
|
|
132
|
+
# headers - A Hash to be passed as headers.
|
|
133
|
+
# service - The backend service to implement this (optional).
|
|
134
|
+
#
|
|
135
|
+
# Returns an instance of Azure::Blobs::PageBlob.
|
|
136
|
+
def self.create_page_blob(container, blob_name, size=nil, metadata={}, headers={}, service=Azure::Blobs::Services::CreatePageBlob.new)
|
|
137
|
+
|
|
138
|
+
response = service.call(container.name, blob_name, size, metadata, headers)
|
|
139
|
+
|
|
140
|
+
if response.success?
|
|
141
|
+
uri = Blobs::URI.blob(container.name, blob_name)
|
|
142
|
+
Azure::Blobs::PageBlob.new(blob_name) do |blob|
|
|
143
|
+
blob.container = container
|
|
144
|
+
blob.extract_properties(response.headers)
|
|
145
|
+
end
|
|
146
|
+
else
|
|
147
|
+
Azure::Blobs::PageBlob.from_error(response.error)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Public: List blobs in the given container.
|
|
152
|
+
#
|
|
153
|
+
# container - An Azure::Blobs::Container instance.
|
|
154
|
+
# service - The backend service to implement this (optional).
|
|
155
|
+
#
|
|
156
|
+
# Returns Array.
|
|
157
|
+
def self.blobs(container, service=Azure::Blobs::Services::ListBlobs.new)
|
|
158
|
+
response = service.call(container.name)
|
|
159
|
+
|
|
160
|
+
document = Nokogiri.parse(response.body)
|
|
161
|
+
(document / "//Blobs/Blob").map do |node|
|
|
162
|
+
Blob.from_node(node) { |b| b.container = container }
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Public: Delete a blob or snapshot blob in the given container. If the operation is
|
|
167
|
+
# unsuccessful, the blob is invalidated. If not, it will be frozen.
|
|
168
|
+
#
|
|
169
|
+
# blob - An Azure::Blobs::Blob instance.
|
|
170
|
+
# service - The backend service to implement this (optional).
|
|
171
|
+
# snapshots - Boolean indicating if the snapshots will be deleted. False by default, which means
|
|
172
|
+
# you will get an error if the blob has snapshots.
|
|
173
|
+
# headers - A Hash representing user defined headers (optional).
|
|
174
|
+
#
|
|
175
|
+
# Returns true|false indicating success.
|
|
176
|
+
def self.delete_blob(blob, snapshots=false, headers={}, service=Azure::Blobs::Services::DeleteBlob.new)
|
|
177
|
+
headers["x-ms-delete-snapshots"] = "include"
|
|
178
|
+
headers["x-ms-lease-id"] = blob.lease_id if blob.lease_id
|
|
179
|
+
|
|
180
|
+
response = service.call(blob.container.name, blob.name, nil, headers)
|
|
181
|
+
|
|
182
|
+
if response.success?
|
|
183
|
+
blob.freeze
|
|
184
|
+
else
|
|
185
|
+
blob.error = response.error
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
response.success?
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# Public: Get a blob from the given container. If the operation is
|
|
192
|
+
# unsuccessful, invalidates the blob.
|
|
193
|
+
#
|
|
194
|
+
# container - An Azure::Blobs::Container instance.
|
|
195
|
+
# blob_name - String representing the name of the blob to be deleted.
|
|
196
|
+
# service - The backend service to implement this (optional).
|
|
197
|
+
#
|
|
198
|
+
# Returns an instance of Azure::Blobs::Blob.
|
|
199
|
+
def self.get_blob(container, blob_name, service=Azure::Blobs::Services::GetBlob.new)
|
|
200
|
+
response = service.call(container.name, blob_name)
|
|
201
|
+
|
|
202
|
+
if response.success?
|
|
203
|
+
Azure::Blobs::Blob.new(blob_name, container, response.body) do |blob|
|
|
204
|
+
blob.extract_metadata(response.headers)
|
|
205
|
+
blob.extract_properties(response.headers)
|
|
206
|
+
end
|
|
207
|
+
else
|
|
208
|
+
Azure::Blobs::Blob.from_error(response.error)
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# Get Properties of a Blob.
|
|
213
|
+
#
|
|
214
|
+
# blob - An Azure::Blobs::Blob instance.
|
|
215
|
+
# headers - A Hash representing user defined headers (optional).
|
|
216
|
+
# service - The backend service to implement this (optional).
|
|
217
|
+
#
|
|
218
|
+
# Returns a Hash.
|
|
219
|
+
def self.load_blob_properties(blob, headers={}, service=Azure::Blobs::Services::GetBlobProperties.new)
|
|
220
|
+
headers["x-ms-lease-id"] = blob.lease_id if blob.lease_id
|
|
221
|
+
response = service.call(blob.container.name, blob.name, headers)
|
|
222
|
+
|
|
223
|
+
if response.success?
|
|
224
|
+
blob.extract_properties(response.headers)
|
|
225
|
+
blob.properties
|
|
226
|
+
else
|
|
227
|
+
blob.error = response.error
|
|
228
|
+
{}
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# Set Properties of a Block or Page Blob.
|
|
233
|
+
#
|
|
234
|
+
# blob - An Azure::Blobs::Blob instance.
|
|
235
|
+
# headers - A Hash representing user defined headers (optional).
|
|
236
|
+
# service - The backend service to implement this (optional).
|
|
237
|
+
#
|
|
238
|
+
# Returns boolean indicating success. Invalidate blob if operation fails.
|
|
239
|
+
def self.save_blob_properties(blob, headers={}, service=Azure::Blobs::Services::SetBlobProperties.new)
|
|
240
|
+
headers.merge(blob.properties.select {|prop, value| prop.match(/x-ms-/)})
|
|
241
|
+
headers["x-ms-lease-id"] = blob.lease_id if blob.lease_id
|
|
242
|
+
response = service.call(blob.container.name, blob.name, headers)
|
|
243
|
+
blob.error = response.error unless response.success?
|
|
244
|
+
response.success?
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# Public: Replaces the blob's metadata with the metadata on the server. If
|
|
248
|
+
# the operation is unsuccessful, invalidates the blob.
|
|
249
|
+
#
|
|
250
|
+
# See http://msdn.microsoft.com/en-us/library/windowsazure/dd179350
|
|
251
|
+
#
|
|
252
|
+
# blob - An Azure::Blobs::Blob instance.
|
|
253
|
+
# service - The backend service to implement this (optional).
|
|
254
|
+
#
|
|
255
|
+
# Returns a Hash.
|
|
256
|
+
def self.load_blob_metadata(blob, service=Azure::Blobs::Services::GetBlobMetadata.new)
|
|
257
|
+
response = service.call(blob.container.name, blob.name, blob.lease_id)
|
|
258
|
+
|
|
259
|
+
if response.success?
|
|
260
|
+
blob.extract_metadata(response.headers)
|
|
261
|
+
else
|
|
262
|
+
blob.error = response.error
|
|
263
|
+
{}
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
# Public: Saves the current blob's metadata to the server, replacing any
|
|
268
|
+
# existing metadata there. If the operation is unsuccessful, invalidates the
|
|
269
|
+
# blob.
|
|
270
|
+
#
|
|
271
|
+
# See http://msdn.microsoft.com/en-us/library/windowsazure/dd179414
|
|
272
|
+
#
|
|
273
|
+
# blob - An Azure::Blobs::Blob instance.
|
|
274
|
+
# headers - A Hash representing user defined headers (optional).
|
|
275
|
+
# service - The backend service to implement this (optional).
|
|
276
|
+
#
|
|
277
|
+
# Returns true|false to indicate success.
|
|
278
|
+
def self.save_blob_metadata(blob, service=Azure::Blobs::Services::SetBlobMetadata.new)
|
|
279
|
+
headers["x-ms-lease-id"] = blob.lease_id if blob.lease_id
|
|
280
|
+
response = service.call(blob.container.name, blob.name, blob.metadata, headers={})
|
|
281
|
+
blob.error = response.error unless response.success?
|
|
282
|
+
response.success?
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# Public: Put a Block in a given Blob.
|
|
286
|
+
#
|
|
287
|
+
# http://msdn.microsoft.com/en-us/library/windowsazure/dd135726
|
|
288
|
+
def self.put_block(blob, block_string, blockid, headers={}, service=Azure::Blobs::Services::PutBlock.new)
|
|
289
|
+
headers["x-ms-lease-id"] = blob.lease_id if blob.lease_id
|
|
290
|
+
response = service.call(blob.container.name, blob.name, ::URI.encode(blockid), block_string)
|
|
291
|
+
blob.error = response.error if !response.success?
|
|
292
|
+
response.success?
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
# Public: Put Block List. Invalidates the blob if the operation fails.
|
|
296
|
+
#
|
|
297
|
+
# blob - An instance of Azure::Blobs::Blob.
|
|
298
|
+
# block_ids - An Array with block ids to be commited.
|
|
299
|
+
# headers - A Hash representing user defined headers (optional).
|
|
300
|
+
#
|
|
301
|
+
# http://msdn.microsoft.com/en-us/library/windowsazure/dd179467
|
|
302
|
+
#
|
|
303
|
+
# Returns the blob.
|
|
304
|
+
def self.put_block_list(blob, block_ids, headers={}, service=Azure::Blobs::Services::PutBlockList.new)
|
|
305
|
+
|
|
306
|
+
headers["x-ms-blob-content-type"] = blob.content_type
|
|
307
|
+
headers["x-ms-lease-id"] = blob.lease_id if blob.lease_id
|
|
308
|
+
|
|
309
|
+
blob.metadata.each do |name, value|
|
|
310
|
+
headers["x-ms-meta-#{name}"] = value
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
blob.properties.each do |name, value|
|
|
314
|
+
headers[name] = value unless ["etag", "last-modified", "content-md5"].include?(name)
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
response = service.call(blob.container.name, blob.name, block_ids, headers)
|
|
318
|
+
|
|
319
|
+
if response.success?
|
|
320
|
+
blob.properties["etag"] = response.headers["etag"]
|
|
321
|
+
blob.properties["last-modified"] = response.headers["last-modified"]
|
|
322
|
+
else
|
|
323
|
+
blob.error = response.error
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
response.success?
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
# Public: Update a set of bytes for the given page blob.
|
|
330
|
+
#
|
|
331
|
+
# blob - An instance of Azure::Blobs::PageBlob.
|
|
332
|
+
# start_byte - Integer byte where start operation.
|
|
333
|
+
# end_byte - Integer byte where end operation.
|
|
334
|
+
# stream - String or IO.
|
|
335
|
+
# headers - A Hash representing request headers.
|
|
336
|
+
#
|
|
337
|
+
# http://msdn.microsoft.com/en-us/library/windowsazure/ee691975
|
|
338
|
+
#
|
|
339
|
+
# Returns boolean indicating success.
|
|
340
|
+
def self.update_page_range(blob, start_byte, end_byte, stream, headers={}, service=Azure::Blobs::Services::PutPage.new)
|
|
341
|
+
|
|
342
|
+
headers["x-ms-page-write"] = "update"
|
|
343
|
+
headers["x-ms-lease-id"] = blob.lease_id if blob.lease_id
|
|
344
|
+
|
|
345
|
+
response = service.call(blob.container.name, blob.name, start_byte, end_byte, stream, headers)
|
|
346
|
+
if response.success?
|
|
347
|
+
blob.extract_properties(response.headers)
|
|
348
|
+
true
|
|
349
|
+
else
|
|
350
|
+
blob.error = response.error
|
|
351
|
+
false
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
# Public: Clear Page range.
|
|
356
|
+
#
|
|
357
|
+
# blob - An instance of Azure::Blobs::PageBlob.
|
|
358
|
+
# start_byte - Integer byte where start operation.
|
|
359
|
+
# end_byte - Integer byte where end operation.
|
|
360
|
+
# headers - A Hash representing request headers.
|
|
361
|
+
#
|
|
362
|
+
# http://msdn.microsoft.com/en-us/library/windowsazure/ee691975
|
|
363
|
+
#
|
|
364
|
+
# Returns boolean indicating success.
|
|
365
|
+
def self.clear_page_range(blob, start_byte, end_byte, headers={}, service=Azure::Blobs::Services::PutPage.new)
|
|
366
|
+
|
|
367
|
+
headers["x-ms-page-write"] = "clear"
|
|
368
|
+
headers["x-ms-lease-id"] = blob.lease_id if blob.lease_id
|
|
369
|
+
|
|
370
|
+
response = service.call(blob.container.name, blob.name, start_byte, end_byte, nil, headers)
|
|
371
|
+
if response.success?
|
|
372
|
+
blob.extract_properties(response.headers)
|
|
373
|
+
true
|
|
374
|
+
else
|
|
375
|
+
blob.error = response.error
|
|
376
|
+
false
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
# Public: Get Page Range. Returns an Array with Range instances.
|
|
381
|
+
#
|
|
382
|
+
# blob - An instance of Azure::Blobs::PageBlob.
|
|
383
|
+
# start_byte - Integer byte where start operation. (optional)
|
|
384
|
+
# end_byte - Integer byte where end operation. (optional)
|
|
385
|
+
# headers - A Hash representing request headers. (optional)
|
|
386
|
+
#
|
|
387
|
+
# http://msdn.microsoft.com/en-us/library/windowsazure/ee691973
|
|
388
|
+
#
|
|
389
|
+
# Returns Array of Range instances.
|
|
390
|
+
def self.get_page_range(blob, start_byte=nil, end_byte=nil, headers={}, service=Azure::Blobs::Services::GetPage.new)
|
|
391
|
+
response = service.call(blob.container.name, blob.name, start_byte, end_byte, headers)
|
|
392
|
+
|
|
393
|
+
if response.success?
|
|
394
|
+
document = Nokogiri::XML(response.body)
|
|
395
|
+
(document / "//PageList/PageRange").map do |node|
|
|
396
|
+
Range.new((node / "Start").text.to_i, (node / "End").text.to_i)
|
|
397
|
+
end
|
|
398
|
+
else
|
|
399
|
+
blob.error = response.error
|
|
400
|
+
false
|
|
401
|
+
end
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
# Public: Creates a snapshot from a given blob.
|
|
405
|
+
#
|
|
406
|
+
# blob - An instance of Azure::Blobs::Blob.
|
|
407
|
+
# metadata - User defined metadata for this container (optional).
|
|
408
|
+
# headers - A Hash representing request headers. (optional)
|
|
409
|
+
#
|
|
410
|
+
# Returns an Azure::Blobs::Snapshot instance.
|
|
411
|
+
def self.create_snapshot(blob, metadata={}, headers={}, service=Azure::Blobs::Services::CreateSnapshot.new)
|
|
412
|
+
|
|
413
|
+
headers["x-ms-lease-id"] = blob.lease_id if blob.lease_id
|
|
414
|
+
|
|
415
|
+
response = service.call(blob.container.name, blob.name, metadata, headers)
|
|
416
|
+
|
|
417
|
+
if response.success?
|
|
418
|
+
Azure::Blobs::Snapshot.new(blob.name, blob.container) do |blob|
|
|
419
|
+
blob.metadata.replace(metadata)
|
|
420
|
+
blob.extract_properties(response.headers)
|
|
421
|
+
end
|
|
422
|
+
else
|
|
423
|
+
nil
|
|
424
|
+
end
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
# Public: Get a blob Snapshot from the given container. If the operation is
|
|
428
|
+
# unsuccessful, invalidates the blob.
|
|
429
|
+
#
|
|
430
|
+
# container - An Azure::Blobs::Container instance.
|
|
431
|
+
# blob_name - String representing the name of the blob to be deleted.
|
|
432
|
+
# snapshot_id - String representing the datetime uniq id of the snapshot.
|
|
433
|
+
# service - The backend service to implement this (optional).
|
|
434
|
+
#
|
|
435
|
+
# Returns an instance of Azure::Blobs::Snapshot.
|
|
436
|
+
def self.get_snapshot(container, blob_name, snapshot_id, service=Azure::Blobs::Services::GetBlob.new)
|
|
437
|
+
response = service.call(container.name, blob_name)
|
|
438
|
+
|
|
439
|
+
if response.success?
|
|
440
|
+
Azure::Blobs::Snapshot.new(blob_name, container, response.body) do |blob|
|
|
441
|
+
blob.extract_metadata(response.headers)
|
|
442
|
+
blob.extract_properties(response.headers)
|
|
443
|
+
end
|
|
444
|
+
else
|
|
445
|
+
Azure::Blobs::Snapshot.from_error(response.error)
|
|
446
|
+
end
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
# Public: Delete a blob snapshot in the given container. If the operation is
|
|
450
|
+
# unsuccessful, the blob is invalidated. If not, it will be frozen.
|
|
451
|
+
#
|
|
452
|
+
# snapshot - An Azure::Blobs::Snapshot instance. Representing a Blob Snapshot.
|
|
453
|
+
# headers - User defined headers for this operation. (optional).
|
|
454
|
+
# service - The backend service to implement this (optional).
|
|
455
|
+
#
|
|
456
|
+
# Returns true|false indicating success.
|
|
457
|
+
def self.delete_snapshot(snapshot, headers={}, service=Azure::Blobs::Services::DeleteBlob.new)
|
|
458
|
+
headers["x-ms-lease-id"] = snapshot.lease_id if snapshot.lease_id
|
|
459
|
+
|
|
460
|
+
response = service.call(snapshot.container.name, snapshot.name, snapshot.id, headers)
|
|
461
|
+
|
|
462
|
+
if response.success?
|
|
463
|
+
snapshot.freeze
|
|
464
|
+
else
|
|
465
|
+
snapshot.error = response.error
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
response.success?
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
# Public: Delete a snapshots of a blob in the given container.
|
|
472
|
+
#
|
|
473
|
+
# blob - An Azure::Blobs::Blob instance.
|
|
474
|
+
# service - The backend service to implement this (optional).
|
|
475
|
+
# headers - User defined headers for this operation. (optional).
|
|
476
|
+
#
|
|
477
|
+
# Returns true|false indicating success.
|
|
478
|
+
def self.delete_blob_snapshots(blob, headers={}, service=Azure::Blobs::Services::DeleteBlob.new)
|
|
479
|
+
headers["x-ms-delete-snapshots"] = "only"
|
|
480
|
+
headers["x-ms-lease-id"] = blob.lease_id if blob.lease_id
|
|
481
|
+
|
|
482
|
+
response = service.call(blob.container.name, blob.name, nil, headers)
|
|
483
|
+
response.success?
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
# Public: Copy a Blob or Snapshot.
|
|
487
|
+
#
|
|
488
|
+
# source - An instance of Azure::Blobs::Blob or Azure::Blobs::Snapshot
|
|
489
|
+
# destination - An instance of Azure::Blobs::Container representing destination.
|
|
490
|
+
# name - A string of the blob where source will be copied.
|
|
491
|
+
# metadata - User defined metadata for the copied blob (optional).
|
|
492
|
+
# headers - User defined headers for this operation. (optional).
|
|
493
|
+
#
|
|
494
|
+
# Returns an instance of Azure::Blobs::BlockBlob or PageBlob depending on the source.
|
|
495
|
+
def self.copy(source, destination, name, metadata={}, headers={}, service=Azure::Blobs::Services::CopyBlob.new)
|
|
496
|
+
|
|
497
|
+
headers["x-ms-lease-id"] = source.lease_id if source.lease_id
|
|
498
|
+
|
|
499
|
+
snapshot_id = source.is_a?(Azure::Blobs::Snapshot) ? source.id : nil
|
|
500
|
+
|
|
501
|
+
response = service.call(source.container.name,
|
|
502
|
+
source.name,
|
|
503
|
+
destination.name,
|
|
504
|
+
name,
|
|
505
|
+
snapshot_id,
|
|
506
|
+
metadata,
|
|
507
|
+
headers)
|
|
508
|
+
|
|
509
|
+
blob_class = Azure::Blobs::Blob
|
|
510
|
+
|
|
511
|
+
if source.is_a?(Azure::Blobs::PageBlob) || source.properties["x-ms-blob-type"] == "PageBlob"
|
|
512
|
+
blob_class = Azure::Blobs::PageBlob
|
|
513
|
+
elsif source.is_a?(Azure::Blobs::BlockBlob) || source.properties["x-ms-blob-type"] == "BlockBlob"
|
|
514
|
+
blob_class = Azure::Blobs::BlockBlob
|
|
515
|
+
end
|
|
516
|
+
|
|
517
|
+
if response.success?
|
|
518
|
+
blob_class.new(name, destination) do |blob|
|
|
519
|
+
blob.metadata.replace(metadata)
|
|
520
|
+
blob.extract_properties(response.headers)
|
|
521
|
+
end
|
|
522
|
+
else
|
|
523
|
+
blob_class.from_error(response.error)
|
|
524
|
+
end
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
# Public: Updates the content of a given Block Blob.
|
|
528
|
+
#
|
|
529
|
+
# blob - An Azure::Blobs::Blob instance.
|
|
530
|
+
# io - IO. String representing the resource on the filesystem.
|
|
531
|
+
# byte_partition - Optional. Integer representing the size of the chunks to be uploaded.
|
|
532
|
+
#
|
|
533
|
+
# Returns an array with the ids of the uploaded blocks.
|
|
534
|
+
def self.update_block_blob_content(blob, io, byte_partition=nil)
|
|
535
|
+
byte_partition ||= 4194304
|
|
536
|
+
block_ids = []
|
|
537
|
+
|
|
538
|
+
while chunk = io.read(byte_partition)
|
|
539
|
+
block_ids << Base64.strict_encode64(Digest::MD5.digest(chunk))
|
|
540
|
+
break if !self.put_block(blob, chunk, block_ids.last)
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
block_ids
|
|
544
|
+
end
|
|
545
|
+
|
|
546
|
+
# Public: Set Blob Service properties.
|
|
547
|
+
#
|
|
548
|
+
# properties - A hash representing the desired properties configuration for blob storage service.
|
|
549
|
+
# {
|
|
550
|
+
# "Logging" => {
|
|
551
|
+
# "Version" => "1.0",
|
|
552
|
+
# "Delete" => "true",
|
|
553
|
+
# "Read" => "true",
|
|
554
|
+
# "Write" => "true",
|
|
555
|
+
# "RetentionPolicy" => {
|
|
556
|
+
# "Enabled" => true,
|
|
557
|
+
# "Days" => 7
|
|
558
|
+
# }
|
|
559
|
+
# },
|
|
560
|
+
# "Metrics"=> {
|
|
561
|
+
# "Version" => "1.0",
|
|
562
|
+
# "Enabled" => "true",
|
|
563
|
+
# "IncludeAPIs" => "false",
|
|
564
|
+
# "RetentionPolicy" => {
|
|
565
|
+
# "Enabled" => true,
|
|
566
|
+
# "Days" => 7
|
|
567
|
+
# }
|
|
568
|
+
# }
|
|
569
|
+
# }
|
|
570
|
+
#
|
|
571
|
+
# http://msdn.microsoft.com/en-us/library/windowsazure/hh452235
|
|
572
|
+
#
|
|
573
|
+
# Returns boolean indicating success.
|
|
574
|
+
def self.set_service_properties(properties, service=Azure::Blobs::Services::SetBlobServiceProperties.new)
|
|
575
|
+
xml_body = Azure::Core::Utils::StorageServiceProperties.hash_to_xml_string(properties)
|
|
576
|
+
response = service.call(xml_body)
|
|
577
|
+
response.success?
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
# Public: Get Blob Service properties.
|
|
581
|
+
#
|
|
582
|
+
# http://msdn.microsoft.com/en-us/library/windowsazure/hh452239
|
|
583
|
+
#
|
|
584
|
+
# Returns a hash with Service properties or nil if the operation fail.
|
|
585
|
+
def self.get_service_properties(service=Azure::Blobs::Services::GetBlobServiceProperties.new)
|
|
586
|
+
response = service.call
|
|
587
|
+
|
|
588
|
+
if response.success?
|
|
589
|
+
Azure::Core::Utils::StorageServiceProperties.xml_string_to_hash(response.body)
|
|
590
|
+
else
|
|
591
|
+
nil
|
|
592
|
+
end
|
|
593
|
+
end
|
|
594
|
+
|
|
595
|
+
# Public: Lease a Blob.
|
|
596
|
+
#
|
|
597
|
+
# blob - An instance of Azure::Blobs::Blob.
|
|
598
|
+
# action - symbol included in [:acquire, :renew, :release, :break]
|
|
599
|
+
#
|
|
600
|
+
# http://msdn.microsoft.com/en-us/library/windowsazure/ee691972
|
|
601
|
+
#
|
|
602
|
+
# Returns blob if success and blob invalidated if the operation fails.
|
|
603
|
+
def self.lease(blob, action, service=Azure::Blobs::Services::Lease.new)
|
|
604
|
+
|
|
605
|
+
lease_actions = [:acquire, :renew, :release, :break]
|
|
606
|
+
|
|
607
|
+
if !lease_actions.include?(action)
|
|
608
|
+
raise ArgumentError, "action not in the list [:acquire, :renew, :release, :break]"
|
|
609
|
+
end
|
|
610
|
+
|
|
611
|
+
response = service.call(blob.container.name, blob.name, action, blob.lease_id)
|
|
612
|
+
|
|
613
|
+
if response.success?
|
|
614
|
+
blob.extract_properties(response.headers)
|
|
615
|
+
else
|
|
616
|
+
blob.error = response.error
|
|
617
|
+
end
|
|
618
|
+
end
|
|
619
|
+
end
|
|
620
|
+
end
|