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
@@ -0,0 +1,44 @@
1
+ require "nokogiri"
2
+
3
+ module Azure
4
+ module ServiceBus
5
+ module Topics
6
+ class TopicSerializer
7
+ attr_accessor :properties
8
+
9
+ PROPERTIES = [
10
+ 'MaxSizeInMegabytes',
11
+ 'SizeInBytes',
12
+ 'DefaultMessageTimeToLive',
13
+ 'RequiresDuplicateDetection',
14
+ 'DuplicateDetectionHistoryTimeWindow',
15
+ 'MaximumNumberOfSubscriptions',
16
+ 'EnableBatchedOperations',
17
+ 'DeadLetteringOnFilterEvaluationExceptions'
18
+ ].freeze
19
+
20
+ def initialize(properties={})
21
+ @properties = properties
22
+ yield self if block_given?
23
+ end
24
+
25
+ def to_xml(builder=Nokogiri::XML::Builder)
26
+ doc = builder.new do |xml|
27
+ xml.entry(:xmlns => 'http://www.w3.org/2005/Atom') {
28
+ xml.content(:type => 'application/xml') {
29
+ xml.TopicDescription('xmlns' => 'http://schemas.microsoft.com/netservices/2010/10/servicebus/connect', 'xmlns:i' => 'http://www.w3.org/2001/XMLSchema-instance') {
30
+ PROPERTIES.each do |p|
31
+ if prop = @properties.fetch(p, nil)
32
+ xml.send(p, prop)
33
+ end
34
+ end
35
+ }
36
+ }
37
+ }
38
+ end
39
+ doc.to_xml
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,58 @@
1
+ require "azure/configuration"
2
+ require "uri"
3
+
4
+ module Azure
5
+ module ServiceBus
6
+ module Topics
7
+ module URI
8
+ # Public: Generate the URI for a given topic.
9
+ #
10
+ # topic_name - The name of the topic.
11
+ # host - The host of the API.
12
+ #
13
+ # Returns a URI.
14
+ def self.topic(name, host=Azure.config.service_bus_host)
15
+ generate(host, name)
16
+ end
17
+
18
+ # Public: generate the URI for the topics collection.
19
+ #
20
+ # options - Options for this query (default: {}):
21
+ # :skip - Integer: number of entries to skip
22
+ # :top - Integer: number of entries to retrieve
23
+ # host - The host of the API.
24
+ #
25
+ # Returns a URI.
26
+ def self.collection(options={}, host=Azure.config.service_bus_host)
27
+ generate(host, "$Resources/Topics", options)
28
+ end
29
+
30
+ # Public: generate the URI for the given topic's messages
31
+ #
32
+ # topic_name - The topic name
33
+ # host - The host of the API.
34
+ #
35
+ # Returns a URI.
36
+ def self.messages(topic_name, host=Azure.config.service_bus_host)
37
+ generate(host, "#{topic_name}/messages")
38
+ end
39
+
40
+
41
+ #TODO: we need to move this method to other module to be mixedin here
42
+ #
43
+ # Utility method to generate the URI.
44
+ #
45
+ # host - A String with the URI's host.
46
+ # path - A String with the URI's path.
47
+ # query - A simple Hash with query parameters (default: {}).
48
+ #
49
+ # Returns a URI.
50
+ def self.generate(host, path, query={})
51
+ uri = ::URI.parse(File.join(host, path))
52
+ uri.query = ::URI.encode_www_form(query) unless query.empty?
53
+ uri
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,21 @@
1
+ require 'eventmachine'
2
+
3
+ module Azure
4
+ module ServiceRuntime
5
+ class GoalStatePipeMonitor < EM::Connection
6
+
7
+ # Public: Initializes a new monitor.
8
+ #
9
+ # callback - a lambda to invoke when a new message arraives
10
+ def initialize(new_message_callback)
11
+ @new_message_callback = new_message_callback
12
+ end
13
+
14
+ def notify_readable
15
+ state_message = GoalStateProtocol.read_message(@io)
16
+ @new_message_callback.call(state_message)
17
+ end
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ module Azure
2
+ module ServiceRuntime
3
+ class GoalStateProtocol
4
+
5
+ def self.read_message(channel)
6
+ message_header = ""
7
+ while ("\n" != char = channel.readchar)
8
+ message_header << char
9
+ end
10
+ size = message_header.to_i(16)
11
+ message = channel.read(size)
12
+
13
+ message
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,135 @@
1
+ require 'nokogiri'
2
+ require 'thread'
3
+ require 'uuid'
4
+ require 'eventmachine'
5
+ require 'azure/service_runtime/client/goal_state_protocol'
6
+ require 'azure/service_runtime/client/goal_state_pipe_monitor'
7
+
8
+ module Azure
9
+ module ServiceRuntime
10
+ class RuntimeClient
11
+
12
+ # Public: Defines the client id that is used when communicating with the runtime.
13
+ def client_id
14
+ @client_id = defined?(@client_id) ? @client_id : UUID.new.generate
15
+ end
16
+
17
+ def incarnation
18
+ @gs_incarnation
19
+ end
20
+
21
+ # Public: Initializes a new instance of the client, and reads the initial state synchronously.
22
+ # It also starts monitoring the pipe to receive status updates and automatically refresh the state
23
+ # and call the appropiate events.
24
+ def initialize(endpoint)
25
+ return unless @is_available = File.exists?(endpoint)
26
+
27
+ @gs_incarnation = 0
28
+
29
+ @changed_event = []
30
+ @changing_event = []
31
+ @stopping_event = []
32
+
33
+ goal_state_np = nil
34
+ File.open(endpoint, 0) do |runtime_np|
35
+ runtime_xml = Nokogiri::XML(runtime_np.read)
36
+ # read the initial state
37
+ File.open(runtime_xml.css('RuntimeServerEndpoint')[0]['path']) do |goalstate_np|
38
+ state_message = GoalStateProtocol.read_message(goalstate_np)
39
+ set_goal_state(state_message)
40
+ end
41
+ # open again to receive status changes
42
+ goal_state_np = File.open(runtime_xml.css('RuntimeServerEndpoint')[0]['path'])
43
+ end # close the runtime named pipe only
44
+
45
+ # start watching the pipe for changes
46
+ gspm = EM.watch goal_state_np, GoalStatePipeMonitor, ->(msg){ set_goal_state(msg) }
47
+ gspm.notify_readable = true
48
+ end
49
+
50
+ def is_available?
51
+ @is_available
52
+ end
53
+
54
+ def write(&block)
55
+ File.open(@gs_current_state_endpoint, "w") do |pipe|
56
+ block.call(pipe)
57
+ end
58
+
59
+ nil
60
+ end
61
+
62
+ def write_status(new_status)
63
+ write do |pipe|
64
+ builder = Nokogiri::XML::Builder.new do |xml|
65
+ xml.CurrentState {
66
+ xml.StatusLease(:ClientId => self.client_id) {
67
+ xml.Acquire {
68
+ xml.Incarnation self.incarnation
69
+ xml.Status new_status
70
+ xml.StatusDetail new_status
71
+ xml.Expiration "9999-12-31T23:59:59.999Z"
72
+ }
73
+ }
74
+ }
75
+ end
76
+ pipe.write(builder.to_xml)
77
+ end
78
+ end
79
+
80
+ def read(&block)
81
+ raise StandardError, "State not available" unless @gs_xml
82
+ block.call(@gs_xml)
83
+
84
+ nil
85
+ end
86
+
87
+ def on_changed(&block)
88
+ @changed_event << block
89
+ end
90
+
91
+ def on_changing(&block)
92
+ @changing_event << block
93
+ end
94
+
95
+ def on_stopping(&block)
96
+ @stopping_event << block
97
+ end
98
+
99
+ def set_goal_state(new_goal_state)
100
+ new_goal_state_xml = Nokogiri::XML(new_goal_state)
101
+ new_incarnation = new_goal_state_xml.css('Incarnation').size > 0 ? new_goal_state_xml.css('Incarnation')[0].content.to_i : 0
102
+ new_status = new_goal_state_xml.css('ExpectedState').size > 0 ? new_goal_state_xml.css('ExpectedState')[0].content : nil
103
+
104
+ case new_status
105
+ when 'Stopped'
106
+ @gs_xml = nil
107
+ @stopping_event.each {|block| block.call }
108
+ write_status('Stopped')
109
+
110
+ when 'Started'
111
+ return if @gs_incarnation >= new_incarnation
112
+
113
+ @gs_incarnation = new_incarnation
114
+ @gs_expected_state = new_status
115
+ @gs_current_state_endpoint ||= new_goal_state_xml.css('CurrentStateEndpoint').size > 0 ? new_goal_state_xml.css('CurrentStateEndpoint')[0].content : nil
116
+
117
+ if new_goal_state_xml.css('RoleEnvironmentPath').size > 0
118
+ File.open(new_goal_state_xml.css('RoleEnvironmentPath')[0].content) do |role_environment_file|
119
+ current_xml = @gs_xml ? Nokogiri::XML(@gs_xml) : nil
120
+ goal_xml = Nokogiri::XML(role_environment_file.read)
121
+
122
+ @changing_event.each {|block| block.call(current_xml, goal_xml) }
123
+ @gs_xml = goal_xml
124
+ @changed_event.each {|block| block.call(current_xml, goal_xml) }
125
+ end
126
+ else
127
+ @gs_xml = nil
128
+ @stopping_event.each {|block| block.call }
129
+ end
130
+ end
131
+ end
132
+
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,24 @@
1
+ module Azure
2
+ module ServiceRuntime
3
+ class Deployment
4
+ attr_accessor :name, :is_emulated
5
+ alias :is_emulated? :is_emulated
6
+
7
+ def initialize(node)
8
+ self.name = node["id"]
9
+ self.is_emulated = node["emulated"] == "true"
10
+ end
11
+
12
+ # Public: Retrieves the deployment identifier.
13
+ #
14
+ # Returns an integer that identifies the current deployment.
15
+ def id
16
+ if /\((?<deployment_id>\d+)\)/i =~ self.name
17
+ return deployment_id.to_i
18
+ end
19
+
20
+ nil
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,15 @@
1
+ module Azure
2
+ module ServiceRuntime
3
+ class LocalResource
4
+ attr_accessor :name, :path, :size
5
+ alias :maximumSizeInMegabytes :size
6
+ alias :root_path :path
7
+
8
+ def initialize(node)
9
+ self.name = node["name"]
10
+ self.path = node["path"]
11
+ self.size = node["sizeInMB"].to_i
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ module Azure
2
+ module ServiceRuntime
3
+ class Role
4
+ attr_accessor :name, :instances
5
+
6
+ def initialize(node)
7
+ self.name = node["name"]
8
+ self.instances = node.css('Instances > Instance').inject({}) do |hash, instance_xml|
9
+ role_instance = RoleInstance.new(instance_xml)
10
+ role_instance.role_name = self.name
11
+ hash[role_instance.id] = role_instance
12
+ hash
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,206 @@
1
+ require 'azure/service_runtime/role_instance'
2
+ require 'azure/service_runtime/role'
3
+ require 'azure/service_runtime/deployment'
4
+ require 'azure/service_runtime/client/runtime_client'
5
+ require 'nokogiri'
6
+ require 'uuid'
7
+
8
+ module Azure
9
+ module ServiceRuntime
10
+ class RoleEnvironment
11
+ VersionEndpointFixedPath = '\\\\.\\pipe\\WindowsAzureRuntime'
12
+ VersionEndpointEnvironmentName = 'WaRuntimeEndpoint'
13
+
14
+ # Public: Retrieves the resolved Service Runtime endpoint name.
15
+ #
16
+ # Returns a string with the endpoint name.
17
+ def self.endpoint
18
+ (defined?(@@endpoint) && @@endpoint) || ENV[VersionEndpointEnvironmentName] || VersionEndpointFixedPath
19
+ end
20
+
21
+ # Public: Allows to manually set an endpoint (used for testing).
22
+ def self.endpoint=(value)
23
+ @@endpoint = value
24
+ end
25
+
26
+ def self.client_id
27
+ @runtime ||= RuntimeClient.new(endpoint)
28
+ @runtime.client_id
29
+ end
30
+
31
+ # Public: Returns true if and only if the Service Runtime is available (ie, this
32
+ # is running in Azure or the emulator.
33
+ # This is a precondition for all of the other Service Runtime methods.
34
+ #
35
+ # Returns a boolean that is true if the Service Runtime is available.
36
+ def self.is_available?
37
+ @runtime ||= RuntimeClient.new(endpoint)
38
+ @runtime.is_available?
39
+ end
40
+
41
+ # Public: Retrieves the current deployment information.
42
+ #
43
+ # Returns a Deployment object.
44
+ def self.deployment(&block)
45
+ @runtime ||= RuntimeClient.new(endpoint)
46
+ @runtime.read do |data|
47
+ return Deployment.new(data.css('RoleEnvironment > Deployment')[0])
48
+ end
49
+ end
50
+
51
+ # Public: Retrieves a RoleInstance object that represents the role instance in which this code is running.
52
+ #
53
+ # Returns a RoleInstance object.
54
+ def self.current_role_instance(&block)
55
+ @runtime ||= RuntimeClient.new(endpoint)
56
+ @runtime.read do |data|
57
+ return build_current_role_instance(data)
58
+ end
59
+ end
60
+
61
+ # Public: Retrieves the Role objects defined for the hosted service.
62
+ #
63
+ # Returns a hash of Role objects.
64
+ def self.roles
65
+ @runtime ||= RuntimeClient.new(endpoint)
66
+ @runtime.read do |data|
67
+ return build_roles(data)
68
+ end
69
+ end
70
+
71
+ # Public: Requests that the current role instance be stopped and restarted.
72
+ def self.request_recycle
73
+ @runtime ||= RuntimeClient.new(endpoint)
74
+ @runtime.write_status("Recycle")
75
+ end
76
+
77
+ def self.set_status(new_status)
78
+ @runtime ||= RuntimeClient.new(endpoint)
79
+ new_runtime_status =
80
+ case new_status
81
+ when :busy, "busy"
82
+ "Busy"
83
+ when :ready, "ready"
84
+ "Started"
85
+ else
86
+ raise ArgumentError, "unknown state #{new_status}"
87
+ end
88
+
89
+ @runtime.write_status(new_runtime_status)
90
+ end
91
+
92
+ def self.on_changing(&block)
93
+ @runtime ||= RuntimeClient.new(endpoint)
94
+ @runtime.on_changing do |current_xml, goal_xml|
95
+ change_list = calculate_changes(current_xml, goal_xml)
96
+ block.call(change_list)
97
+ end
98
+ end
99
+
100
+ def self.on_changed(&block)
101
+ @runtime ||= RuntimeClient.new(endpoint)
102
+ @runtime.on_changed do |last_xml, current_xml|
103
+ change_list = calculate_changes(last_xml, current_xml)
104
+ block.call(change_list)
105
+ end
106
+ end
107
+
108
+ def self.on_stopping(&block)
109
+ @runtime ||= RuntimeClient.new(endpoint)
110
+ @runtime.on_stopping(&block)
111
+ end
112
+
113
+ private
114
+
115
+ def self.build_roles(state_xml)
116
+ state_xml.css('RoleEnvironment > Roles')[0].css('Role').inject({}) do |hash, role_xml|
117
+ role = Role.new(role_xml)
118
+ hash[role.name] = role
119
+ hash
120
+ end
121
+ end
122
+
123
+ def self.build_current_role_instance(state_xml)
124
+ RoleInstance.new(state_xml.css('RoleEnvironment > CurrentInstance')[0])
125
+ end
126
+
127
+ def self.calculate_changes(source, target)
128
+ if !source && !target
129
+ return [[],[]]
130
+ end
131
+
132
+ if !source && target
133
+ return [build_current_role_instance(target).configuration_settings.keys, build_roles(target).keys]
134
+ end
135
+
136
+ if source && !target
137
+ return [build_current_role_instance(source).configuration_settings.keys, build_roles(target).keys]
138
+ end
139
+
140
+ changed_settings = []
141
+ changed_roles = []
142
+
143
+ source_role_instance = build_current_role_instance(source)
144
+ target_role_instance = build_current_role_instance(target)
145
+
146
+ # find edited or removed settings
147
+ source_role_instance.configuration_settings.each do |name, value|
148
+ if !(target_value = target_role_instance.configuration_settings[setting.name]) || value != target_value
149
+ changed_settings << name
150
+ end
151
+ end
152
+
153
+ # find added settings
154
+ target_role_instance.configuration_settings.each do |name, value|
155
+ if !source_role_instance.configuration_settings[name]
156
+ changed_settings << name
157
+ end
158
+ end
159
+
160
+ source_roles = build_roles(source)
161
+ target_roles = build_roles(target)
162
+
163
+ # find edited or removed roles
164
+ source_roles.each do |source_role_name, source_role|
165
+ if target_role = target_roles[source_role_name]
166
+ source_role.instances.each do |source_instance_id, source_instance|
167
+ if target_instance = target_role.instances[source_instance_id]
168
+ if target_instance.fault_domain == source_instance.fault_domain &&
169
+ target_instance.update_domain == source_instance.update_domain
170
+
171
+ source_instance.endpoints.each do |source_endpoint_name, source_endpoint|
172
+ if target_endpoint = target_instance.endpoints[source_endpoint_name]
173
+ if target_endpoint.address != source_endpoint.address ||
174
+ target_endpoint.port != source_endpoint.port ||
175
+ target_endpoint.protocol != source_endpoint.protocol
176
+
177
+ changed_roles << source_role_name
178
+ end
179
+ else
180
+ changed_roles << source_role_name
181
+ end
182
+ end
183
+ else
184
+ changed_roles << source_role_name
185
+ end
186
+ else
187
+ changed_roles << source_role_name
188
+ end
189
+ end
190
+ else
191
+ changed_roles << source_role_name
192
+ end
193
+ end
194
+
195
+ # find added roles
196
+ target_roles.each do |target_role_name, target_role|
197
+ if !source_roles[target_role_name]
198
+ changed_roles << target_role_name
199
+ end
200
+ end
201
+
202
+ [changed_settings, changed_roles]
203
+ end
204
+ end
205
+ end
206
+ end