azure 0.0.0 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +3 -0
- data/Gemfile.lock +36 -0
- data/README.md +3 -0
- data/Rakefile +81 -0
- data/azure.gemspec +20 -9
- data/lib/azure.rb +4 -0
- data/lib/azure/atom.rb +170 -0
- data/lib/azure/auth.rb +29 -0
- data/lib/azure/blobs.rb +620 -0
- data/lib/azure/blobs/blob.rb +360 -0
- data/lib/azure/blobs/container.rb +209 -0
- data/lib/azure/blobs/service.rb +396 -0
- data/lib/azure/blobs/shared_access_signature.rb +84 -0
- data/lib/azure/blobs/uri.rb +60 -0
- data/lib/azure/configuration.rb +121 -0
- data/lib/azure/core/auth/shared_key.rb +95 -0
- data/lib/azure/core/auth/shared_key_lite.rb +34 -0
- data/lib/azure/core/collection.rb +118 -0
- data/lib/azure/core/service.rb +43 -0
- data/lib/azure/core/signer.rb +32 -0
- data/lib/azure/core/utils/interval.rb +97 -0
- data/lib/azure/core/utils/queryable.rb +74 -0
- data/lib/azure/core/utils/storage_service_properties.rb +83 -0
- data/lib/azure/core/utils/string.rb +59 -0
- data/lib/azure/error.rb +72 -0
- data/lib/azure/queues.rb +272 -0
- data/lib/azure/queues/message.rb +174 -0
- data/lib/azure/queues/queue.rb +187 -0
- data/lib/azure/queues/service.rb +263 -0
- data/lib/azure/queues/service_properties.rb +152 -0
- data/lib/azure/queues/uri.rb +78 -0
- data/lib/azure/request.rb +102 -0
- data/lib/azure/response.rb +93 -0
- data/lib/azure/service_bus.rb +4 -0
- data/lib/azure/service_bus/auth/authorizer.rb +22 -0
- data/lib/azure/service_bus/auth/uri.rb +52 -0
- data/lib/azure/service_bus/auth/wrap.rb +37 -0
- data/lib/azure/service_bus/auth/wrap_service.rb +76 -0
- data/lib/azure/service_bus/auth/wrap_token.rb +45 -0
- data/lib/azure/service_bus/auth/wrap_token_manager.rb +46 -0
- data/lib/azure/service_bus/brokered_message.rb +139 -0
- data/lib/azure/service_bus/brokered_message_serializer.rb +113 -0
- data/lib/azure/service_bus/queues.rb +194 -0
- data/lib/azure/service_bus/queues/queue.rb +100 -0
- data/lib/azure/service_bus/queues/queue_serializer.rb +51 -0
- data/lib/azure/service_bus/queues/service.rb +154 -0
- data/lib/azure/service_bus/queues/uri.rb +80 -0
- data/lib/azure/service_bus/rules.rb +110 -0
- data/lib/azure/service_bus/rules/rule.rb +97 -0
- data/lib/azure/service_bus/rules/service.rb +122 -0
- data/lib/azure/service_bus/rules/uri.rb +39 -0
- data/lib/azure/service_bus/service_bus_service.rb +22 -0
- data/lib/azure/service_bus/subscriptions.rb +170 -0
- data/lib/azure/service_bus/subscriptions/service.rb +133 -0
- data/lib/azure/service_bus/subscriptions/subscription.rb +164 -0
- data/lib/azure/service_bus/subscriptions/subscription_serializer.rb +74 -0
- data/lib/azure/service_bus/subscriptions/uri.rb +71 -0
- data/lib/azure/service_bus/topics.rb +120 -0
- data/lib/azure/service_bus/topics/service.rb +98 -0
- data/lib/azure/service_bus/topics/topic.rb +122 -0
- data/lib/azure/service_bus/topics/topic_serializer.rb +44 -0
- data/lib/azure/service_bus/topics/uri.rb +58 -0
- data/lib/azure/service_runtime/client/goal_state_pipe_monitor.rb +21 -0
- data/lib/azure/service_runtime/client/goal_state_protocol.rb +18 -0
- data/lib/azure/service_runtime/client/runtime_client.rb +135 -0
- data/lib/azure/service_runtime/deployment.rb +24 -0
- data/lib/azure/service_runtime/local_resource.rb +15 -0
- data/lib/azure/service_runtime/role.rb +17 -0
- data/lib/azure/service_runtime/role_environment.rb +206 -0
- data/lib/azure/service_runtime/role_environment_change.rb +32 -0
- data/lib/azure/service_runtime/role_instance.rb +35 -0
- data/lib/azure/service_runtime/role_instance_endpoint.rb +14 -0
- data/lib/azure/tables.rb +215 -0
- data/lib/azure/tables/auth/shared_key.rb +71 -0
- data/lib/azure/tables/auth/shared_key_lite.rb +30 -0
- data/lib/azure/tables/entities_collection.rb +66 -0
- data/lib/azure/tables/entity.rb +127 -0
- data/lib/azure/tables/service.rb +211 -0
- data/lib/azure/tables/table.rb +129 -0
- data/lib/azure/tables/tables_collection.rb +62 -0
- data/lib/azure/tables/types.rb +65 -0
- data/lib/azure/tables/uri.rb +62 -0
- data/test/fixtures/32px-fulls-black.jpg +0 -0
- data/test/fixtures/all_containers.xml +20 -0
- data/test/fixtures/all_tables.xml +22 -0
- data/test/fixtures/create_table_response_entry.xml +15 -0
- data/test/fixtures/error.xml +5 -0
- data/test/fixtures/insert_entity_response_entry.xml +25 -0
- data/test/fixtures/messages.xml +12 -0
- data/test/fixtures/query_entities_empty_response.xml +7 -0
- data/test/fixtures/query_entities_response.xml +45 -0
- data/test/fixtures/queue_service_properties.xml +22 -0
- data/test/fixtures/queue_service_properties_original.xml +19 -0
- data/test/fixtures/queues.xml +16 -0
- data/test/fixtures/sb_default_create_queue_response.xml +23 -0
- data/test/fixtures/sb_default_create_topic_response.xml +18 -0
- data/test/fixtures/sb_get_access_token_response.txt +1 -0
- data/test/fixtures/sb_queues_runtime_peek_message_response_headers.txt +9 -0
- data/test/integration/blobs/auth_test.rb +19 -0
- data/test/integration/blobs/blob_test.rb +61 -0
- data/test/integration/blobs/clear_page_range_test.rb +19 -0
- data/test/integration/blobs/copy_test.rb +33 -0
- data/test/integration/blobs/create_blobs_test.rb +51 -0
- data/test/integration/blobs/create_container_test.rb +13 -0
- data/test/integration/blobs/create_snapshot_test.rb +17 -0
- data/test/integration/blobs/delete_blob_snapshots_test.rb +19 -0
- data/test/integration/blobs/delete_blobs_test.rb +25 -0
- data/test/integration/blobs/delete_container_test.rb +24 -0
- data/test/integration/blobs/delete_snapshot_test.rb +17 -0
- data/test/integration/blobs/get_blob_snapshot_test.rb +18 -0
- data/test/integration/blobs/get_blobs_test.rb +31 -0
- data/test/integration/blobs/get_page_range_test.rb +19 -0
- data/test/integration/blobs/list_blobs_test.rb +39 -0
- data/test/integration/blobs/list_containers_test.rb +28 -0
- data/test/integration/blobs/manage_blob_leases_test.rb +45 -0
- data/test/integration/blobs/manage_blob_metadata_test.rb +51 -0
- data/test/integration/blobs/manage_blob_properties_test.rb +25 -0
- data/test/integration/blobs/manage_blob_service_properties_test.rb +38 -0
- data/test/integration/blobs/manage_container_metadata_test.rb +46 -0
- data/test/integration/blobs/manage_container_permissions_test.rb +17 -0
- data/test/integration/blobs/update_page_range_test.rb +20 -0
- data/test/integration/queues/clear_messages_test.rb +22 -0
- data/test/integration/queues/create_queue_test.rb +13 -0
- data/test/integration/queues/delete_message_test.rb +42 -0
- data/test/integration/queues/delete_queue_test.rb +24 -0
- data/test/integration/queues/get_messages_test.rb +39 -0
- data/test/integration/queues/list_queues_test.rb +43 -0
- data/test/integration/queues/manage_queue_metadata_test.rb +45 -0
- data/test/integration/queues/manage_queue_service_properties_test.rb +27 -0
- data/test/integration/queues/peek_messages_test.rb +55 -0
- data/test/integration/queues/put_message_test.rb +31 -0
- data/test/integration/queues/update_message_test.rb +46 -0
- data/test/integration/service_bus/auth_test.rb +18 -0
- data/test/integration/service_bus/queues/create_queue_test.rb +25 -0
- data/test/integration/service_bus/queues/delete_message_from_queue_test.rb +29 -0
- data/test/integration/service_bus/queues/delete_queue_test.rb +25 -0
- data/test/integration/service_bus/queues/get_queue_test.rb +23 -0
- data/test/integration/service_bus/queues/list_queues_test.rb +39 -0
- data/test/integration/service_bus/queues/peek_message_from_queue_test.rb +34 -0
- data/test/integration/service_bus/queues/read_and_delete_message_from_queue_test.rb +31 -0
- data/test/integration/service_bus/queues/send_message_to_queue_test.rb +22 -0
- data/test/integration/service_bus/queues/unlock_message_from_queue_test.rb +36 -0
- data/test/integration/service_bus/rules/create_rule_test.rb +19 -0
- data/test/integration/service_bus/rules/delete_rule_test.rb +17 -0
- data/test/integration/service_bus/rules/get_rule_test.rb +21 -0
- data/test/integration/service_bus/rules/list_rules_test.rb +24 -0
- data/test/integration/service_bus/rules/rule_test.rb +16 -0
- data/test/integration/service_bus/subscriptions/create_subscription_test.rb +25 -0
- data/test/integration/service_bus/subscriptions/delete_message_from_subscription_test.rb +31 -0
- data/test/integration/service_bus/subscriptions/delete_subscription_test.rb +30 -0
- data/test/integration/service_bus/subscriptions/fetch_subscription_test.rb +28 -0
- data/test/integration/service_bus/subscriptions/list_subscriptions_test.rb +23 -0
- data/test/integration/service_bus/subscriptions/peek_lock_message_from_subscription_test.rb +42 -0
- data/test/integration/service_bus/subscriptions/read_delete_message_from_subscription_test.rb +36 -0
- data/test/integration/service_bus/subscriptions/subscription_test.rb +31 -0
- data/test/integration/service_bus/subscriptions/unlock_message_from_subscription_test.rb +43 -0
- data/test/integration/service_bus/topics/create_topic_test.rb +25 -0
- data/test/integration/service_bus/topics/delete_topic_test.rb +25 -0
- data/test/integration/service_bus/topics/get_topic_test.rb +23 -0
- data/test/integration/service_bus/topics/list_topics_test.rb +39 -0
- data/test/integration/service_bus/topics/send_message_to_topic_test.rb +23 -0
- data/test/integration/tables/auth_test.rb +29 -0
- data/test/integration/tables/creating_tables_test.rb +16 -0
- data/test/integration/tables/delete_entity_test.rb +39 -0
- data/test/integration/tables/deleting_table_test.rb +22 -0
- data/test/integration/tables/insert_entity_test.rb +23 -0
- data/test/integration/tables/merge_entity_test.rb +28 -0
- data/test/integration/tables/query_entities_test.rb +131 -0
- data/test/integration/tables/query_tables_test.rb +63 -0
- data/test/integration/tables/update_entity_test.rb +54 -0
- data/test/integration/test_helper.rb +14 -0
- data/test/support/blobs.rb +12 -0
- data/test/support/env.rb +5 -0
- data/test/support/fixtures.rb +22 -0
- data/test/support/stubs.rb +28 -0
- data/test/support/table_names.rb +44 -0
- data/test/test_helper.rb +10 -0
- data/test/unit/atom_test.rb +58 -0
- data/test/unit/auth_test.rb +24 -0
- data/test/unit/blobs/blob_test.rb +5 -0
- data/test/unit/blobs/container_test.rb +67 -0
- data/test/unit/blobs/service_test.rb +17 -0
- data/test/unit/blobs/shared_access_signature_test.rb +66 -0
- data/test/unit/blobs_test.rb +156 -0
- data/test/unit/core/service_test.rb +57 -0
- data/test/unit/core/utils/interval_test.rb +70 -0
- data/test/unit/core/utils/queryable_test.rb +69 -0
- data/test/unit/core/utils/storage_service_properties_test.rb +66 -0
- data/test/unit/error_test.rb +39 -0
- data/test/unit/queues/message_test.rb +40 -0
- data/test/unit/queues/queue_test.rb +64 -0
- data/test/unit/queues/service_properties.rb +35 -0
- data/test/unit/request_test.rb +38 -0
- data/test/unit/response_test.rb +43 -0
- data/test/unit/service_bus/auth/authorizer_test.rb +27 -0
- data/test/unit/service_bus/auth/wrap_token_test.rb +28 -0
- data/test/unit/service_bus/queues/queue_test.rb +38 -0
- data/test/unit/service_bus/topics/topic_test.rb +33 -0
- data/test/unit/service_runtime/data/goalstate.xml +9 -0
- data/test/unit/service_runtime/data/roleenvironmentdata.xml +29 -0
- data/test/unit/service_runtime/data/runtime.xml +6 -0
- data/test/unit/service_runtime/role_environment_test.rb +144 -0
- data/test/unit/tables/auth/shared_key_lite_test.rb +39 -0
- data/test/unit/tables/auth/shared_key_test.rb +45 -0
- data/test/unit/tables/entities_collection_test.rb +39 -0
- data/test/unit/tables/entity_test.rb +72 -0
- data/test/unit/tables/table_test.rb +57 -0
- data/test/unit/tables_test.rb +302 -0
- data/test/unit/types_test.rb +67 -0
- metadata +310 -47
- data/LICENSE +0 -0
- data/README +0 -0
|
@@ -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
|