right_agent 1.0.1 → 2.0.7
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/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
|