right_agent 1.0.1 → 2.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +10 -8
- data/Rakefile +31 -5
- data/lib/right_agent.rb +6 -1
- data/lib/right_agent/actor.rb +4 -20
- data/lib/right_agent/actors/agent_manager.rb +1 -1
- data/lib/right_agent/agent.rb +357 -144
- data/lib/right_agent/agent_config.rb +7 -6
- data/lib/right_agent/agent_identity.rb +13 -11
- data/lib/right_agent/agent_tag_manager.rb +60 -64
- data/{spec/results_mock.rb → lib/right_agent/clients.rb} +10 -24
- data/lib/right_agent/clients/api_client.rb +383 -0
- data/lib/right_agent/clients/auth_client.rb +247 -0
- data/lib/right_agent/clients/balanced_http_client.rb +369 -0
- data/lib/right_agent/clients/base_retry_client.rb +495 -0
- data/lib/right_agent/clients/right_http_client.rb +279 -0
- data/lib/right_agent/clients/router_client.rb +493 -0
- data/lib/right_agent/command/command_io.rb +4 -4
- data/lib/right_agent/command/command_parser.rb +2 -2
- data/lib/right_agent/command/command_runner.rb +1 -1
- data/lib/right_agent/connectivity_checker.rb +179 -0
- data/lib/right_agent/core_payload_types/secure_document_location.rb +2 -2
- data/lib/right_agent/dispatcher.rb +12 -10
- data/lib/right_agent/enrollment_result.rb +16 -12
- data/lib/right_agent/exceptions.rb +34 -20
- data/lib/right_agent/history.rb +10 -5
- data/lib/right_agent/log.rb +5 -5
- data/lib/right_agent/minimal.rb +1 -0
- data/lib/right_agent/multiplexer.rb +1 -1
- data/lib/right_agent/offline_handler.rb +270 -0
- data/lib/right_agent/packets.rb +7 -7
- data/lib/right_agent/payload_formatter.rb +1 -1
- data/lib/right_agent/pending_requests.rb +128 -0
- data/lib/right_agent/platform.rb +1 -1
- data/lib/right_agent/protocol_version_mixin.rb +69 -0
- data/lib/right_agent/{idempotent_request.rb → retryable_request.rb} +7 -7
- data/lib/right_agent/scripts/agent_controller.rb +28 -26
- data/lib/right_agent/scripts/agent_deployer.rb +37 -22
- data/lib/right_agent/scripts/common_parser.rb +10 -3
- data/lib/right_agent/secure_identity.rb +1 -1
- data/lib/right_agent/sender.rb +299 -785
- data/lib/right_agent/serialize/secure_serializer.rb +3 -1
- data/lib/right_agent/serialize/secure_serializer_initializer.rb +2 -2
- data/lib/right_agent/serialize/serializable.rb +8 -3
- data/right_agent.gemspec +49 -18
- data/spec/agent_config_spec.rb +7 -7
- data/spec/agent_identity_spec.rb +7 -4
- data/spec/agent_spec.rb +43 -7
- data/spec/agent_tag_manager_spec.rb +72 -83
- data/spec/clients/api_client_spec.rb +423 -0
- data/spec/clients/auth_client_spec.rb +272 -0
- data/spec/clients/balanced_http_client_spec.rb +576 -0
- data/spec/clients/base_retry_client_spec.rb +635 -0
- data/spec/clients/router_client_spec.rb +594 -0
- data/spec/clients/spec_helper.rb +111 -0
- data/spec/command/command_io_spec.rb +1 -1
- data/spec/command/command_parser_spec.rb +1 -1
- data/spec/connectivity_checker_spec.rb +83 -0
- data/spec/dispatcher_spec.rb +3 -2
- data/spec/enrollment_result_spec.rb +2 -2
- data/spec/history_spec.rb +51 -39
- data/spec/offline_handler_spec.rb +340 -0
- data/spec/pending_requests_spec.rb +136 -0
- data/spec/{idempotent_request_spec.rb → retryable_request_spec.rb} +73 -73
- data/spec/sender_spec.rb +835 -1052
- data/spec/serialize/secure_serializer_spec.rb +3 -2
- data/spec/spec_helper.rb +54 -1
- metadata +71 -12
@@ -76,11 +76,11 @@ module RightScale
|
|
76
76
|
# true:: Always return true
|
77
77
|
#
|
78
78
|
# === Raise
|
79
|
-
# (
|
80
|
-
# (
|
81
|
-
# (
|
79
|
+
# (ArgumentError):: If block is missing
|
80
|
+
# (Exceptions::Application):: If +listen+ has already been called and +stop+ hasn't since
|
81
|
+
# (Exceptions::Application):: If port is already bound
|
82
82
|
def listen(socket_port, &block)
|
83
|
-
raise
|
83
|
+
raise ArgumentError, 'Missing listener block' unless block_given?
|
84
84
|
raise Exceptions::Application, 'Already listening' if listening
|
85
85
|
begin
|
86
86
|
@conn = EM.start_server('127.0.0.1', socket_port, ServerInputHandler, block)
|
@@ -31,9 +31,9 @@ module RightScale
|
|
31
31
|
# Block that will get called back whenever a command is successfully parsed
|
32
32
|
#
|
33
33
|
# === Raise
|
34
|
-
# (
|
34
|
+
# (ArgumentError): If block is missing
|
35
35
|
def initialize &block
|
36
|
-
raise
|
36
|
+
raise ArgumentError, 'Missing handler block' unless block
|
37
37
|
@callback = block
|
38
38
|
@buildup = ''
|
39
39
|
end
|
@@ -55,7 +55,7 @@ module RightScale
|
|
55
55
|
# cmd_options[:listen_port](Integer):: Command server listen port
|
56
56
|
#
|
57
57
|
# === Raise
|
58
|
-
# (
|
58
|
+
# (Exceptions::Application):: If +start+ has already been called and +stop+ hasn't since
|
59
59
|
def self.start(socket_port, identity, commands, fiber_pool = nil)
|
60
60
|
cmd_options = nil
|
61
61
|
@listen_port = socket_port
|
@@ -0,0 +1,179 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2009-2013 RightScale Inc
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
|
23
|
+
module RightScale
|
24
|
+
|
25
|
+
# Broker connectivity checker
|
26
|
+
# Checks connectivity when requested
|
27
|
+
class ConnectivityChecker
|
28
|
+
|
29
|
+
# Minimum number of seconds between restarts of the inactivity timer
|
30
|
+
MIN_RESTART_INACTIVITY_TIMER_INTERVAL = 60
|
31
|
+
|
32
|
+
# Number of seconds to wait for ping response from a RightNet router when checking connectivity
|
33
|
+
PING_TIMEOUT = 30
|
34
|
+
|
35
|
+
# Default maximum number of consecutive ping timeouts before attempt to reconnect
|
36
|
+
MAX_PING_TIMEOUTS = 3
|
37
|
+
|
38
|
+
# (EM::Timer) Timer while waiting for RightNet router ping response
|
39
|
+
attr_accessor :ping_timer
|
40
|
+
|
41
|
+
def initialize(sender, check_interval, ping_stats, exception_stats)
|
42
|
+
@sender = sender
|
43
|
+
@check_interval = check_interval
|
44
|
+
@ping_timeouts = {}
|
45
|
+
@ping_timer = nil
|
46
|
+
@ping_stats = ping_stats
|
47
|
+
@exception_stats = exception_stats
|
48
|
+
@last_received = Time.now
|
49
|
+
@message_received_callbacks = []
|
50
|
+
restart_inactivity_timer if @check_interval > 0
|
51
|
+
end
|
52
|
+
|
53
|
+
# Update the time this agent last received a request or response message
|
54
|
+
# and restart the inactivity timer thus deferring the next connectivity check
|
55
|
+
# Also forward this message receipt notification to any callbacks that have registered
|
56
|
+
#
|
57
|
+
# === Block
|
58
|
+
# Optional block without parameters that is activated when a message is received
|
59
|
+
#
|
60
|
+
# === Return
|
61
|
+
# true:: Always return true
|
62
|
+
def message_received(&callback)
|
63
|
+
if block_given?
|
64
|
+
@message_received_callbacks << callback
|
65
|
+
else
|
66
|
+
@message_received_callbacks.each { |c| c.call }
|
67
|
+
if @check_interval > 0
|
68
|
+
now = Time.now
|
69
|
+
if (now - @last_received) > MIN_RESTART_INACTIVITY_TIMER_INTERVAL
|
70
|
+
@last_received = now
|
71
|
+
restart_inactivity_timer
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
true
|
76
|
+
end
|
77
|
+
|
78
|
+
# Check whether broker connection is usable by pinging a router via that broker
|
79
|
+
# Attempt to reconnect if ping does not respond in PING_TIMEOUT seconds and
|
80
|
+
# if have reached timeout limit
|
81
|
+
# Ignore request if already checking a connection
|
82
|
+
#
|
83
|
+
# === Parameters
|
84
|
+
# id(String):: Identity of specific broker to use to send ping, defaults to any
|
85
|
+
# currently connected broker
|
86
|
+
# max_ping_timeouts(Integer):: Maximum number of ping timeouts before attempt
|
87
|
+
# to reconnect, defaults to MAX_PING_TIMEOUTS
|
88
|
+
#
|
89
|
+
# === Return
|
90
|
+
# true:: Always return true
|
91
|
+
def check(id = nil, max_ping_timeouts = MAX_PING_TIMEOUTS)
|
92
|
+
unless @terminating || @ping_timer || (id && !@sender.client.connected?(id))
|
93
|
+
@ping_id = id
|
94
|
+
@ping_timer = EM::Timer.new(PING_TIMEOUT) do
|
95
|
+
if @ping_id
|
96
|
+
begin
|
97
|
+
@ping_stats.update("timeout")
|
98
|
+
@ping_timer = nil
|
99
|
+
@ping_timeouts[@ping_id] = (@ping_timeouts[@ping_id] || 0) + 1
|
100
|
+
if @ping_timeouts[@ping_id] >= max_ping_timeouts
|
101
|
+
Log.error("Mapper ping via broker #{@ping_id} timed out after #{PING_TIMEOUT} seconds and now " +
|
102
|
+
"reached maximum of #{max_ping_timeouts} timeout#{max_ping_timeouts > 1 ? 's' : ''}, " +
|
103
|
+
"attempting to reconnect")
|
104
|
+
host, port, index, priority = @sender.client.identity_parts(@ping_id)
|
105
|
+
@sender.agent.connect(host, port, index, priority, force = true)
|
106
|
+
else
|
107
|
+
Log.warning("Mapper ping via broker #{@ping_id} timed out after #{PING_TIMEOUT} seconds")
|
108
|
+
end
|
109
|
+
rescue Exception => e
|
110
|
+
Log.error("Failed to reconnect to broker #{@ping_id}", e, :trace)
|
111
|
+
@exception_stats.track("ping timeout", e)
|
112
|
+
end
|
113
|
+
else
|
114
|
+
@ping_timer = nil
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
handler = lambda do |_|
|
119
|
+
begin
|
120
|
+
if @ping_timer
|
121
|
+
@ping_stats.update("success")
|
122
|
+
@ping_timer.cancel
|
123
|
+
@ping_timer = nil
|
124
|
+
@ping_timeouts[@ping_id] = 0
|
125
|
+
@ping_id = nil
|
126
|
+
end
|
127
|
+
rescue Exception => e
|
128
|
+
Log.error("Failed to cancel router ping", e, :trace)
|
129
|
+
@exception_stats.track("cancel ping", e)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
request = Request.new("/router/ping", nil, {:from => @sender.identity, :token => AgentIdentity.generate})
|
133
|
+
@sender.pending_requests[request.token] = PendingRequest.new(Request, Time.now, handler)
|
134
|
+
ids = [@ping_id] if @ping_id
|
135
|
+
@ping_id = @sender.send(:publish, request, ids).first
|
136
|
+
end
|
137
|
+
true
|
138
|
+
end
|
139
|
+
|
140
|
+
# Prepare for agent termination
|
141
|
+
#
|
142
|
+
# === Return
|
143
|
+
# true:: Always return true
|
144
|
+
def terminate
|
145
|
+
@terminating = true
|
146
|
+
@check_interval = 0
|
147
|
+
if @ping_timer
|
148
|
+
@ping_timer.cancel
|
149
|
+
@ping_timer = nil
|
150
|
+
end
|
151
|
+
if @inactivity_timer
|
152
|
+
@inactivity_timer.cancel
|
153
|
+
@inactivity_timer = nil
|
154
|
+
end
|
155
|
+
true
|
156
|
+
end
|
157
|
+
|
158
|
+
protected
|
159
|
+
|
160
|
+
# Start timer that waits for inactive messaging period to end before checking connectivity
|
161
|
+
#
|
162
|
+
# === Return
|
163
|
+
# true:: Always return true
|
164
|
+
def restart_inactivity_timer
|
165
|
+
@inactivity_timer.cancel if @inactivity_timer
|
166
|
+
@inactivity_timer = EM::Timer.new(@check_interval) do
|
167
|
+
begin
|
168
|
+
check(id = nil, max_ping_timeouts = 1)
|
169
|
+
rescue Exception => e
|
170
|
+
Log.error("Failed connectivity check", e, :trace)
|
171
|
+
@exception_stats.track("check connectivity", e)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
true
|
175
|
+
end
|
176
|
+
|
177
|
+
end # ConnectivityChecker
|
178
|
+
|
179
|
+
end # RightScale
|
@@ -40,10 +40,10 @@ module RightScale
|
|
40
40
|
# (String):: Access token that should be used to fetch the document
|
41
41
|
attr_accessor :ticket
|
42
42
|
|
43
|
-
# Array(String)::
|
43
|
+
# Array(String):: Identities of RightNet agents capable of providing the document.
|
44
44
|
# If nil, then no target should be specified when sending RightNet requests;
|
45
45
|
# this is used to route requests to "trusted infrastructure" nodes at the
|
46
|
-
# discretion of the
|
46
|
+
# discretion of the RightNet router.
|
47
47
|
attr_accessor :targets
|
48
48
|
|
49
49
|
# Initialize fields from given arguments
|
@@ -25,6 +25,8 @@ module RightScale
|
|
25
25
|
# Dispatching of payload to specified actor
|
26
26
|
class Dispatcher
|
27
27
|
|
28
|
+
include ProtocolVersionMixin
|
29
|
+
|
28
30
|
class InvalidRequestType < Exception; end
|
29
31
|
class DuplicateRequest < Exception; end
|
30
32
|
|
@@ -85,10 +87,10 @@ module RightScale
|
|
85
87
|
token = request.token
|
86
88
|
actor, method, idempotent = route(request)
|
87
89
|
received_at = @request_stats.update(method, (token if request.is_a?(Request)))
|
88
|
-
if dup = duplicate?(request, method, idempotent)
|
90
|
+
if (dup = duplicate?(request, method, idempotent))
|
89
91
|
raise DuplicateRequest.new(dup)
|
90
92
|
end
|
91
|
-
unless result = expired?(request, method)
|
93
|
+
unless (result = expired?(request, method))
|
92
94
|
result = perform(request, actor, method, idempotent)
|
93
95
|
end
|
94
96
|
if request.is_a?(Request)
|
@@ -140,7 +142,7 @@ module RightScale
|
|
140
142
|
@reject_stats = RightSupport::Stats::Activity.new
|
141
143
|
@request_stats = RightSupport::Stats::Activity.new
|
142
144
|
@dispatch_failure_stats = RightSupport::Stats::Activity.new
|
143
|
-
@exception_stats = RightSupport::Stats::Exceptions.new(@agent)
|
145
|
+
@exception_stats = RightSupport::Stats::Exceptions.new(@agent, @agent.exception_callback)
|
144
146
|
true
|
145
147
|
end
|
146
148
|
|
@@ -157,10 +159,10 @@ module RightScale
|
|
157
159
|
@reject_stats.update("expired (#{method})")
|
158
160
|
Log.info("REJECT EXPIRED <#{request.token}> from #{request.from} TTL #{RightSupport::Stats.elapsed(now - expires_at)} ago")
|
159
161
|
# For agents that do not know about non-delivery, use error result
|
160
|
-
if request.recv_version
|
161
|
-
OperationResult.error("Could not deliver request (#{OperationResult::TTL_EXPIRATION})")
|
162
|
-
else
|
162
|
+
if can_handle_non_delivery_result?(request.recv_version)
|
163
163
|
OperationResult.non_delivery(OperationResult::TTL_EXPIRATION)
|
164
|
+
else
|
165
|
+
OperationResult.error("Could not deliver request (#{OperationResult::TTL_EXPIRATION})")
|
164
166
|
end
|
165
167
|
end
|
166
168
|
end
|
@@ -176,11 +178,11 @@ module RightScale
|
|
176
178
|
# (String|nil):: Messaging describing who already serviced request if it is a duplicate, otherwise nil
|
177
179
|
def duplicate?(request, method, idempotent)
|
178
180
|
if !idempotent && @dispatched_cache
|
179
|
-
if serviced_by = @dispatched_cache.serviced_by(request.token)
|
181
|
+
if (serviced_by = @dispatched_cache.serviced_by(request.token))
|
180
182
|
from_retry = ""
|
181
183
|
else
|
182
184
|
from_retry = "retry "
|
183
|
-
request.tries.each { |t| break if serviced_by = @dispatched_cache.serviced_by(t) }
|
185
|
+
request.tries.each { |t| break if (serviced_by = @dispatched_cache.serviced_by(t)) }
|
184
186
|
end
|
185
187
|
if serviced_by
|
186
188
|
@reject_stats.update("#{from_retry}duplicate (#{method})")
|
@@ -225,9 +227,9 @@ module RightScale
|
|
225
227
|
def perform(request, actor, method, idempotent)
|
226
228
|
@dispatched_cache.store(request.token) if @dispatched_cache && !idempotent
|
227
229
|
if actor.method(method).arity.abs == 1
|
228
|
-
actor.
|
230
|
+
actor.send(method, request.payload)
|
229
231
|
else
|
230
|
-
actor.
|
232
|
+
actor.send(method, request.payload, request)
|
231
233
|
end
|
232
234
|
rescue Exception => e
|
233
235
|
@dispatch_failure_stats.update("#{request.type}->#{e.class.name}")
|
@@ -6,7 +6,7 @@ require 'openssl'
|
|
6
6
|
require 'base64'
|
7
7
|
require 'json'
|
8
8
|
|
9
|
-
# A response to a RightNet enrollment request containing the
|
9
|
+
# A response to a RightNet enrollment request containing the router's X509 cert,
|
10
10
|
# the instance (or other) agent's identity cert, and the agent's private key.
|
11
11
|
# Responses are encrypted using a secret key shared between the instance and
|
12
12
|
# the Certifying Authority (aka the RightScale core site) and integrity-protected
|
@@ -14,35 +14,39 @@ require 'json'
|
|
14
14
|
module RightScale
|
15
15
|
|
16
16
|
class EnrollmentResult
|
17
|
+
|
18
|
+
include ProtocolVersionMixin
|
19
|
+
|
17
20
|
# Versions 5 and above use an identical format for the enrollment result
|
18
21
|
SUPPORTED_VERSIONS = 5..AgentConfig.protocol_version
|
19
22
|
|
20
23
|
class IntegrityFailure < Exception; end
|
21
24
|
class VersionError < Exception; end
|
22
25
|
|
23
|
-
attr_reader :r_s_version, :timestamp, :
|
26
|
+
attr_reader :r_s_version, :timestamp, :router_cert, :id_cert, :id_key
|
24
27
|
|
25
28
|
# Create a new instance of this class
|
26
29
|
#
|
27
30
|
# === Parameters
|
28
31
|
# timestamp(Time):: Timestamp associated with this result
|
29
|
-
#
|
32
|
+
# router_cert(String):: Arbitrary string
|
30
33
|
# id_cert(String):: Arbitrary string
|
31
34
|
# id_key(String):: Arbitrary string
|
32
35
|
# secret(String):: Shared secret with which the result is encrypted
|
33
36
|
#
|
34
|
-
def initialize(r_s_version, timestamp,
|
37
|
+
def initialize(r_s_version, timestamp, router_cert, id_cert, id_key, secret)
|
35
38
|
@r_s_version = r_s_version
|
36
39
|
@timestamp = timestamp.utc
|
37
|
-
@
|
40
|
+
@router_cert = router_cert
|
38
41
|
@id_cert = id_cert
|
39
42
|
@id_key = id_key
|
40
|
-
@serializer = Serializer.new((
|
43
|
+
@serializer = Serializer.new(can_handle_msgpack_result?(r_s_version) ? :msgpack : :json)
|
41
44
|
|
45
|
+
cert_name = can_handle_http?(r_s_version) ? 'router_cert' : 'mapper_cert'
|
42
46
|
msg = @serializer.dump({
|
43
|
-
|
44
|
-
'id_cert'
|
45
|
-
'id_key'
|
47
|
+
cert_name => @router_cert.to_s,
|
48
|
+
'id_cert' => @id_cert,
|
49
|
+
'id_key' => @id_key
|
46
50
|
})
|
47
51
|
|
48
52
|
key = EnrollmentResult.derive_key(secret, @timestamp.to_i.to_s)
|
@@ -90,7 +94,7 @@ module RightScale
|
|
90
94
|
# true|false:: Whether the objects' pertinent fields are identical
|
91
95
|
#
|
92
96
|
def ==(o)
|
93
|
-
self.
|
97
|
+
self.router_cert == o.router_cert &&
|
94
98
|
self.id_cert == o.id_cert &&
|
95
99
|
self.id_key == o.id_key &&
|
96
100
|
self.timestamp.to_i == o.timestamp.to_i
|
@@ -164,11 +168,11 @@ module RightScale
|
|
164
168
|
raise IntegrityFailure.new("MAC mismatch: expected #{my_mac}, got #{mac}") unless (mac == my_mac)
|
165
169
|
|
166
170
|
msg = serializer.load(plaintext)
|
167
|
-
|
171
|
+
router_cert = msg['router_cert'] || msg['mapper_cert']
|
168
172
|
id_cert = msg['id_cert']
|
169
173
|
id_key = msg['id_key']
|
170
174
|
|
171
|
-
self.new(r_s_version, timestamp,
|
175
|
+
self.new(r_s_version, timestamp, router_cert, id_cert, id_key, secret)
|
172
176
|
end
|
173
177
|
|
174
178
|
protected
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (c) 2009-
|
2
|
+
# Copyright (c) 2009-2013 RightScale Inc
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining
|
5
5
|
# a copy of this software and associated documentation files (the
|
@@ -21,21 +21,22 @@
|
|
21
21
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
22
|
|
23
23
|
module RightScale
|
24
|
+
|
24
25
|
class Exceptions
|
25
|
-
# Capability not currently supported
|
26
|
-
class NotSupported < Exception; end
|
27
26
|
|
28
|
-
#
|
29
|
-
class
|
27
|
+
# Base exception for use in nesting exceptions
|
28
|
+
class NestedException < StandardError
|
30
29
|
attr_reader :nested_exception
|
30
|
+
|
31
|
+
# Exception message and optional nested exception or string
|
31
32
|
def initialize(message, nested_exception = nil)
|
32
33
|
@nested_exception = nested_exception
|
33
34
|
super(message)
|
34
35
|
end
|
35
36
|
end
|
36
37
|
|
37
|
-
#
|
38
|
-
class
|
38
|
+
# Internal application error
|
39
|
+
class Application < StandardError; end
|
39
40
|
|
40
41
|
# Agent command IO error
|
41
42
|
class IO < RuntimeError; end
|
@@ -43,30 +44,43 @@ module RightScale
|
|
43
44
|
# Agent compute platform error
|
44
45
|
class PlatformError < StandardError; end
|
45
46
|
|
46
|
-
#
|
47
|
-
class
|
48
|
-
|
47
|
+
# Terminating service
|
48
|
+
class Terminating < RuntimeError; end
|
49
|
+
|
50
|
+
# Not authorized to make request
|
51
|
+
class Unauthorized < NestedException
|
49
52
|
def initialize(message, nested_exception = nil)
|
50
|
-
|
51
|
-
|
53
|
+
super(message, nested_exception)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Cannot connect to service, lost connection to it, or it is out of service or too busy to respond
|
58
|
+
class ConnectivityFailure < NestedException
|
59
|
+
def initialize(message, nested_exception = nil)
|
60
|
+
super(message, nested_exception)
|
52
61
|
end
|
53
62
|
end
|
54
63
|
|
55
64
|
# Request failed but potentially will succeed if retried
|
56
|
-
class RetryableError <
|
57
|
-
attr_reader :nested_exception
|
65
|
+
class RetryableError < NestedException
|
58
66
|
def initialize(message, nested_exception = nil)
|
59
|
-
|
60
|
-
super(message)
|
67
|
+
super(message, nested_exception)
|
61
68
|
end
|
62
69
|
end
|
63
70
|
|
64
71
|
# Database query failed
|
65
|
-
class QueryFailure <
|
66
|
-
attr_reader :nested_exception
|
72
|
+
class QueryFailure < NestedException
|
67
73
|
def initialize(message, nested_exception = nil)
|
68
|
-
|
69
|
-
|
74
|
+
super(message, nested_exception)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Error internal to specified server
|
79
|
+
class InternalServerError < NestedException
|
80
|
+
attr_reader :server
|
81
|
+
def initialize(message, server, nested_exception = nil)
|
82
|
+
@server = server
|
83
|
+
super(message, nested_exception)
|
70
84
|
end
|
71
85
|
end
|
72
86
|
end
|