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.
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