azure 0.0.0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (212) hide show
  1. data/Gemfile +3 -0
  2. data/Gemfile.lock +36 -0
  3. data/README.md +3 -0
  4. data/Rakefile +81 -0
  5. data/azure.gemspec +20 -9
  6. data/lib/azure.rb +4 -0
  7. data/lib/azure/atom.rb +170 -0
  8. data/lib/azure/auth.rb +29 -0
  9. data/lib/azure/blobs.rb +620 -0
  10. data/lib/azure/blobs/blob.rb +360 -0
  11. data/lib/azure/blobs/container.rb +209 -0
  12. data/lib/azure/blobs/service.rb +396 -0
  13. data/lib/azure/blobs/shared_access_signature.rb +84 -0
  14. data/lib/azure/blobs/uri.rb +60 -0
  15. data/lib/azure/configuration.rb +121 -0
  16. data/lib/azure/core/auth/shared_key.rb +95 -0
  17. data/lib/azure/core/auth/shared_key_lite.rb +34 -0
  18. data/lib/azure/core/collection.rb +118 -0
  19. data/lib/azure/core/service.rb +43 -0
  20. data/lib/azure/core/signer.rb +32 -0
  21. data/lib/azure/core/utils/interval.rb +97 -0
  22. data/lib/azure/core/utils/queryable.rb +74 -0
  23. data/lib/azure/core/utils/storage_service_properties.rb +83 -0
  24. data/lib/azure/core/utils/string.rb +59 -0
  25. data/lib/azure/error.rb +72 -0
  26. data/lib/azure/queues.rb +272 -0
  27. data/lib/azure/queues/message.rb +174 -0
  28. data/lib/azure/queues/queue.rb +187 -0
  29. data/lib/azure/queues/service.rb +263 -0
  30. data/lib/azure/queues/service_properties.rb +152 -0
  31. data/lib/azure/queues/uri.rb +78 -0
  32. data/lib/azure/request.rb +102 -0
  33. data/lib/azure/response.rb +93 -0
  34. data/lib/azure/service_bus.rb +4 -0
  35. data/lib/azure/service_bus/auth/authorizer.rb +22 -0
  36. data/lib/azure/service_bus/auth/uri.rb +52 -0
  37. data/lib/azure/service_bus/auth/wrap.rb +37 -0
  38. data/lib/azure/service_bus/auth/wrap_service.rb +76 -0
  39. data/lib/azure/service_bus/auth/wrap_token.rb +45 -0
  40. data/lib/azure/service_bus/auth/wrap_token_manager.rb +46 -0
  41. data/lib/azure/service_bus/brokered_message.rb +139 -0
  42. data/lib/azure/service_bus/brokered_message_serializer.rb +113 -0
  43. data/lib/azure/service_bus/queues.rb +194 -0
  44. data/lib/azure/service_bus/queues/queue.rb +100 -0
  45. data/lib/azure/service_bus/queues/queue_serializer.rb +51 -0
  46. data/lib/azure/service_bus/queues/service.rb +154 -0
  47. data/lib/azure/service_bus/queues/uri.rb +80 -0
  48. data/lib/azure/service_bus/rules.rb +110 -0
  49. data/lib/azure/service_bus/rules/rule.rb +97 -0
  50. data/lib/azure/service_bus/rules/service.rb +122 -0
  51. data/lib/azure/service_bus/rules/uri.rb +39 -0
  52. data/lib/azure/service_bus/service_bus_service.rb +22 -0
  53. data/lib/azure/service_bus/subscriptions.rb +170 -0
  54. data/lib/azure/service_bus/subscriptions/service.rb +133 -0
  55. data/lib/azure/service_bus/subscriptions/subscription.rb +164 -0
  56. data/lib/azure/service_bus/subscriptions/subscription_serializer.rb +74 -0
  57. data/lib/azure/service_bus/subscriptions/uri.rb +71 -0
  58. data/lib/azure/service_bus/topics.rb +120 -0
  59. data/lib/azure/service_bus/topics/service.rb +98 -0
  60. data/lib/azure/service_bus/topics/topic.rb +122 -0
  61. data/lib/azure/service_bus/topics/topic_serializer.rb +44 -0
  62. data/lib/azure/service_bus/topics/uri.rb +58 -0
  63. data/lib/azure/service_runtime/client/goal_state_pipe_monitor.rb +21 -0
  64. data/lib/azure/service_runtime/client/goal_state_protocol.rb +18 -0
  65. data/lib/azure/service_runtime/client/runtime_client.rb +135 -0
  66. data/lib/azure/service_runtime/deployment.rb +24 -0
  67. data/lib/azure/service_runtime/local_resource.rb +15 -0
  68. data/lib/azure/service_runtime/role.rb +17 -0
  69. data/lib/azure/service_runtime/role_environment.rb +206 -0
  70. data/lib/azure/service_runtime/role_environment_change.rb +32 -0
  71. data/lib/azure/service_runtime/role_instance.rb +35 -0
  72. data/lib/azure/service_runtime/role_instance_endpoint.rb +14 -0
  73. data/lib/azure/tables.rb +215 -0
  74. data/lib/azure/tables/auth/shared_key.rb +71 -0
  75. data/lib/azure/tables/auth/shared_key_lite.rb +30 -0
  76. data/lib/azure/tables/entities_collection.rb +66 -0
  77. data/lib/azure/tables/entity.rb +127 -0
  78. data/lib/azure/tables/service.rb +211 -0
  79. data/lib/azure/tables/table.rb +129 -0
  80. data/lib/azure/tables/tables_collection.rb +62 -0
  81. data/lib/azure/tables/types.rb +65 -0
  82. data/lib/azure/tables/uri.rb +62 -0
  83. data/test/fixtures/32px-fulls-black.jpg +0 -0
  84. data/test/fixtures/all_containers.xml +20 -0
  85. data/test/fixtures/all_tables.xml +22 -0
  86. data/test/fixtures/create_table_response_entry.xml +15 -0
  87. data/test/fixtures/error.xml +5 -0
  88. data/test/fixtures/insert_entity_response_entry.xml +25 -0
  89. data/test/fixtures/messages.xml +12 -0
  90. data/test/fixtures/query_entities_empty_response.xml +7 -0
  91. data/test/fixtures/query_entities_response.xml +45 -0
  92. data/test/fixtures/queue_service_properties.xml +22 -0
  93. data/test/fixtures/queue_service_properties_original.xml +19 -0
  94. data/test/fixtures/queues.xml +16 -0
  95. data/test/fixtures/sb_default_create_queue_response.xml +23 -0
  96. data/test/fixtures/sb_default_create_topic_response.xml +18 -0
  97. data/test/fixtures/sb_get_access_token_response.txt +1 -0
  98. data/test/fixtures/sb_queues_runtime_peek_message_response_headers.txt +9 -0
  99. data/test/integration/blobs/auth_test.rb +19 -0
  100. data/test/integration/blobs/blob_test.rb +61 -0
  101. data/test/integration/blobs/clear_page_range_test.rb +19 -0
  102. data/test/integration/blobs/copy_test.rb +33 -0
  103. data/test/integration/blobs/create_blobs_test.rb +51 -0
  104. data/test/integration/blobs/create_container_test.rb +13 -0
  105. data/test/integration/blobs/create_snapshot_test.rb +17 -0
  106. data/test/integration/blobs/delete_blob_snapshots_test.rb +19 -0
  107. data/test/integration/blobs/delete_blobs_test.rb +25 -0
  108. data/test/integration/blobs/delete_container_test.rb +24 -0
  109. data/test/integration/blobs/delete_snapshot_test.rb +17 -0
  110. data/test/integration/blobs/get_blob_snapshot_test.rb +18 -0
  111. data/test/integration/blobs/get_blobs_test.rb +31 -0
  112. data/test/integration/blobs/get_page_range_test.rb +19 -0
  113. data/test/integration/blobs/list_blobs_test.rb +39 -0
  114. data/test/integration/blobs/list_containers_test.rb +28 -0
  115. data/test/integration/blobs/manage_blob_leases_test.rb +45 -0
  116. data/test/integration/blobs/manage_blob_metadata_test.rb +51 -0
  117. data/test/integration/blobs/manage_blob_properties_test.rb +25 -0
  118. data/test/integration/blobs/manage_blob_service_properties_test.rb +38 -0
  119. data/test/integration/blobs/manage_container_metadata_test.rb +46 -0
  120. data/test/integration/blobs/manage_container_permissions_test.rb +17 -0
  121. data/test/integration/blobs/update_page_range_test.rb +20 -0
  122. data/test/integration/queues/clear_messages_test.rb +22 -0
  123. data/test/integration/queues/create_queue_test.rb +13 -0
  124. data/test/integration/queues/delete_message_test.rb +42 -0
  125. data/test/integration/queues/delete_queue_test.rb +24 -0
  126. data/test/integration/queues/get_messages_test.rb +39 -0
  127. data/test/integration/queues/list_queues_test.rb +43 -0
  128. data/test/integration/queues/manage_queue_metadata_test.rb +45 -0
  129. data/test/integration/queues/manage_queue_service_properties_test.rb +27 -0
  130. data/test/integration/queues/peek_messages_test.rb +55 -0
  131. data/test/integration/queues/put_message_test.rb +31 -0
  132. data/test/integration/queues/update_message_test.rb +46 -0
  133. data/test/integration/service_bus/auth_test.rb +18 -0
  134. data/test/integration/service_bus/queues/create_queue_test.rb +25 -0
  135. data/test/integration/service_bus/queues/delete_message_from_queue_test.rb +29 -0
  136. data/test/integration/service_bus/queues/delete_queue_test.rb +25 -0
  137. data/test/integration/service_bus/queues/get_queue_test.rb +23 -0
  138. data/test/integration/service_bus/queues/list_queues_test.rb +39 -0
  139. data/test/integration/service_bus/queues/peek_message_from_queue_test.rb +34 -0
  140. data/test/integration/service_bus/queues/read_and_delete_message_from_queue_test.rb +31 -0
  141. data/test/integration/service_bus/queues/send_message_to_queue_test.rb +22 -0
  142. data/test/integration/service_bus/queues/unlock_message_from_queue_test.rb +36 -0
  143. data/test/integration/service_bus/rules/create_rule_test.rb +19 -0
  144. data/test/integration/service_bus/rules/delete_rule_test.rb +17 -0
  145. data/test/integration/service_bus/rules/get_rule_test.rb +21 -0
  146. data/test/integration/service_bus/rules/list_rules_test.rb +24 -0
  147. data/test/integration/service_bus/rules/rule_test.rb +16 -0
  148. data/test/integration/service_bus/subscriptions/create_subscription_test.rb +25 -0
  149. data/test/integration/service_bus/subscriptions/delete_message_from_subscription_test.rb +31 -0
  150. data/test/integration/service_bus/subscriptions/delete_subscription_test.rb +30 -0
  151. data/test/integration/service_bus/subscriptions/fetch_subscription_test.rb +28 -0
  152. data/test/integration/service_bus/subscriptions/list_subscriptions_test.rb +23 -0
  153. data/test/integration/service_bus/subscriptions/peek_lock_message_from_subscription_test.rb +42 -0
  154. data/test/integration/service_bus/subscriptions/read_delete_message_from_subscription_test.rb +36 -0
  155. data/test/integration/service_bus/subscriptions/subscription_test.rb +31 -0
  156. data/test/integration/service_bus/subscriptions/unlock_message_from_subscription_test.rb +43 -0
  157. data/test/integration/service_bus/topics/create_topic_test.rb +25 -0
  158. data/test/integration/service_bus/topics/delete_topic_test.rb +25 -0
  159. data/test/integration/service_bus/topics/get_topic_test.rb +23 -0
  160. data/test/integration/service_bus/topics/list_topics_test.rb +39 -0
  161. data/test/integration/service_bus/topics/send_message_to_topic_test.rb +23 -0
  162. data/test/integration/tables/auth_test.rb +29 -0
  163. data/test/integration/tables/creating_tables_test.rb +16 -0
  164. data/test/integration/tables/delete_entity_test.rb +39 -0
  165. data/test/integration/tables/deleting_table_test.rb +22 -0
  166. data/test/integration/tables/insert_entity_test.rb +23 -0
  167. data/test/integration/tables/merge_entity_test.rb +28 -0
  168. data/test/integration/tables/query_entities_test.rb +131 -0
  169. data/test/integration/tables/query_tables_test.rb +63 -0
  170. data/test/integration/tables/update_entity_test.rb +54 -0
  171. data/test/integration/test_helper.rb +14 -0
  172. data/test/support/blobs.rb +12 -0
  173. data/test/support/env.rb +5 -0
  174. data/test/support/fixtures.rb +22 -0
  175. data/test/support/stubs.rb +28 -0
  176. data/test/support/table_names.rb +44 -0
  177. data/test/test_helper.rb +10 -0
  178. data/test/unit/atom_test.rb +58 -0
  179. data/test/unit/auth_test.rb +24 -0
  180. data/test/unit/blobs/blob_test.rb +5 -0
  181. data/test/unit/blobs/container_test.rb +67 -0
  182. data/test/unit/blobs/service_test.rb +17 -0
  183. data/test/unit/blobs/shared_access_signature_test.rb +66 -0
  184. data/test/unit/blobs_test.rb +156 -0
  185. data/test/unit/core/service_test.rb +57 -0
  186. data/test/unit/core/utils/interval_test.rb +70 -0
  187. data/test/unit/core/utils/queryable_test.rb +69 -0
  188. data/test/unit/core/utils/storage_service_properties_test.rb +66 -0
  189. data/test/unit/error_test.rb +39 -0
  190. data/test/unit/queues/message_test.rb +40 -0
  191. data/test/unit/queues/queue_test.rb +64 -0
  192. data/test/unit/queues/service_properties.rb +35 -0
  193. data/test/unit/request_test.rb +38 -0
  194. data/test/unit/response_test.rb +43 -0
  195. data/test/unit/service_bus/auth/authorizer_test.rb +27 -0
  196. data/test/unit/service_bus/auth/wrap_token_test.rb +28 -0
  197. data/test/unit/service_bus/queues/queue_test.rb +38 -0
  198. data/test/unit/service_bus/topics/topic_test.rb +33 -0
  199. data/test/unit/service_runtime/data/goalstate.xml +9 -0
  200. data/test/unit/service_runtime/data/roleenvironmentdata.xml +29 -0
  201. data/test/unit/service_runtime/data/runtime.xml +6 -0
  202. data/test/unit/service_runtime/role_environment_test.rb +144 -0
  203. data/test/unit/tables/auth/shared_key_lite_test.rb +39 -0
  204. data/test/unit/tables/auth/shared_key_test.rb +45 -0
  205. data/test/unit/tables/entities_collection_test.rb +39 -0
  206. data/test/unit/tables/entity_test.rb +72 -0
  207. data/test/unit/tables/table_test.rb +57 -0
  208. data/test/unit/tables_test.rb +302 -0
  209. data/test/unit/types_test.rb +67 -0
  210. metadata +310 -47
  211. data/LICENSE +0 -0
  212. data/README +0 -0
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
@@ -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
@@ -0,0 +1,3 @@
1
+ Run "rake" to run all tests.
2
+
3
+ Run "gem build azure.gemspec" to build gem.
@@ -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
@@ -1,12 +1,23 @@
1
- files = ["README", "LICENSE", "azure.gemspec"].map {|f| Dir[f]}.flatten
1
+ require "date"
2
2
 
3
3
  Gem::Specification.new do |s|
4
- s.name = "azure"
5
- s.version = "0.0.0"
6
- s.summary = "Windows Azure SDK for Ruby."
7
- s.description = "Access Windows Azure storage and queue services."
8
- s.authors = ["Cubox"]
9
- s.email = "dev@cuboxlabs.com"
10
- s.files = files
11
- s.homepage = "https://github.com/cubox/azure-ruby"
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
@@ -0,0 +1,4 @@
1
+ require "azure/tables"
2
+ require "azure/blobs"
3
+ require "azure/queues"
4
+ require "azure/service_bus"
@@ -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
@@ -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
@@ -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