right_agent 0.14.0 → 0.16.2
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 +2 -0
- data/lib/right_agent/actors/agent_manager.rb +1 -1
- data/lib/right_agent/agent.rb +28 -14
- data/lib/right_agent/agent_config.rb +1 -1
- data/lib/right_agent/agent_identity.rb +4 -5
- data/lib/right_agent/agent_tag_manager.rb +21 -24
- data/lib/right_agent/core_payload_types/executable_bundle.rb +1 -1
- data/lib/right_agent/core_payload_types/recipe_instantiation.rb +7 -0
- data/lib/right_agent/core_payload_types/right_script_instantiation.rb +20 -5
- data/lib/right_agent/exceptions.rb +44 -1
- data/lib/right_agent/history.rb +4 -1
- data/lib/right_agent/packets.rb +2 -1
- data/lib/right_agent/platform/darwin.rb +6 -0
- data/lib/right_agent/platform/linux.rb +5 -1
- data/lib/right_agent/platform/windows.rb +8 -4
- data/lib/right_agent/scripts/stats_manager.rb +3 -3
- data/lib/right_agent/security/cached_certificate_store_proxy.rb +27 -13
- data/lib/right_agent/security/encrypted_document.rb +1 -2
- data/lib/right_agent/security/static_certificate_store.rb +30 -14
- data/lib/right_agent/sender.rb +101 -47
- data/lib/right_agent/serialize/secure_serializer.rb +29 -27
- data/lib/right_agent/serialize/secure_serializer_initializer.rb +3 -3
- data/lib/right_agent/serialize/serializable.rb +1 -1
- data/lib/right_agent/serialize/serializer.rb +15 -6
- data/right_agent.gemspec +4 -5
- data/spec/agent_spec.rb +2 -2
- data/spec/agent_tag_manager_spec.rb +330 -0
- data/spec/core_payload_types/recipe_instantiation_spec.rb +81 -0
- data/spec/core_payload_types/right_script_instantiation_spec.rb +79 -0
- data/spec/security/cached_certificate_store_proxy_spec.rb +14 -8
- data/spec/security/static_certificate_store_spec.rb +13 -7
- data/spec/sender_spec.rb +114 -17
- data/spec/serialize/secure_serializer_spec.rb +78 -49
- data/spec/serialize/serializer_spec.rb +21 -2
- metadata +90 -36
data/README.rdoc
CHANGED
@@ -20,6 +20,8 @@ documentation.
|
|
20
20
|
Also use the built-in issues tracker (https://github.com/rightscale/right_agent/issues)
|
21
21
|
to report issues.
|
22
22
|
|
23
|
+
Maintained by the RightScale Teal Team
|
24
|
+
|
23
25
|
== Interface
|
24
26
|
|
25
27
|
A RightAgent exposes its services via actors and methods that are invoked by requests
|
@@ -81,7 +81,7 @@ class AgentManager
|
|
81
81
|
# === Return
|
82
82
|
# (OperationResult):: Empty success result or error result with message
|
83
83
|
def profile(options)
|
84
|
-
|
84
|
+
return error_result("The memprof gem is not available for profiling. Please install memprof 0.3 manually") unless require_succeeds?('memprof')
|
85
85
|
|
86
86
|
options = RightScale::SerializationHelper.symbolize_keys(options || {})
|
87
87
|
if options[:start]
|
data/lib/right_agent/agent.rb
CHANGED
@@ -38,8 +38,8 @@ module RightScale
|
|
38
38
|
# (Hash) Configuration options applied to the agent
|
39
39
|
attr_reader :options
|
40
40
|
|
41
|
-
# (
|
42
|
-
attr_reader :
|
41
|
+
# (Hash) Dispatcher for each queue for messages received
|
42
|
+
attr_reader :dispatchers
|
43
43
|
|
44
44
|
# (ActorRegistry) Registry for this agents actors
|
45
45
|
attr_reader :registry
|
@@ -373,7 +373,7 @@ module RightScale
|
|
373
373
|
def terminate(reason = nil, exception = nil, &block)
|
374
374
|
block ||= DEFAULT_TERMINATE_BLOCK
|
375
375
|
begin
|
376
|
-
@history.update("stop")
|
376
|
+
@history.update("stop") if @history
|
377
377
|
Log.error("[stop] Terminating because #{reason}", exception, :trace) if reason
|
378
378
|
if @terminating || @broker.nil?
|
379
379
|
@terminating = true
|
@@ -381,7 +381,7 @@ module RightScale
|
|
381
381
|
@termination_timer = nil
|
382
382
|
Log.info("[stop] Terminating immediately")
|
383
383
|
block.call
|
384
|
-
@history.update("graceful exit") if @broker.nil?
|
384
|
+
@history.update("graceful exit") if @history && @broker.nil?
|
385
385
|
else
|
386
386
|
@terminating = true
|
387
387
|
@check_status_timer.cancel if @check_status_timer
|
@@ -417,7 +417,7 @@ module RightScale
|
|
417
417
|
"version" => AgentConfig.protocol_version,
|
418
418
|
"brokers" => @broker.stats(reset),
|
419
419
|
"agent stats" => agent_stats(reset),
|
420
|
-
"receive stats" =>
|
420
|
+
"receive stats" => dispatcher_stats(reset),
|
421
421
|
"send stats" => @sender.stats(reset),
|
422
422
|
"last reset time" => @last_stat_reset_time.to_i,
|
423
423
|
"stat time" => now.to_i,
|
@@ -463,7 +463,7 @@ module RightScale
|
|
463
463
|
stats
|
464
464
|
end
|
465
465
|
|
466
|
-
# Reset
|
466
|
+
# Reset agent statistics
|
467
467
|
#
|
468
468
|
# === Return
|
469
469
|
# true:: Always return true
|
@@ -476,6 +476,14 @@ module RightScale
|
|
476
476
|
true
|
477
477
|
end
|
478
478
|
|
479
|
+
# Get dispatcher statistics
|
480
|
+
#
|
481
|
+
# === Return
|
482
|
+
# (Hash):: Current statistics
|
483
|
+
def dispatcher_stats(reset)
|
484
|
+
@dispatchers[@identity].stats(reset)
|
485
|
+
end
|
486
|
+
|
479
487
|
# Set the agent's configuration using the supplied options
|
480
488
|
#
|
481
489
|
# === Parameters
|
@@ -539,7 +547,7 @@ module RightScale
|
|
539
547
|
def start_service(&terminate_callback)
|
540
548
|
begin
|
541
549
|
@registry = ActorRegistry.new
|
542
|
-
@
|
550
|
+
@dispatchers = create_dispatchers
|
543
551
|
@sender = create_sender
|
544
552
|
load_actors
|
545
553
|
setup_traps
|
@@ -562,13 +570,14 @@ module RightScale
|
|
562
570
|
true
|
563
571
|
end
|
564
572
|
|
565
|
-
# Create dispatcher for handling incoming requests
|
573
|
+
# Create dispatcher per queue for use in handling incoming requests
|
566
574
|
#
|
567
575
|
# === Return
|
568
|
-
#
|
569
|
-
def
|
576
|
+
# [Hash]:: Dispatchers with queue name as key
|
577
|
+
def create_dispatchers
|
570
578
|
cache = DispatchedCache.new(@identity) if @options[:dup_check]
|
571
|
-
Dispatcher.new(self, cache)
|
579
|
+
dispatcher = Dispatcher.new(self, cache)
|
580
|
+
@queues.inject({}) { |dispatchers, queue| dispatchers[queue] = dispatcher; dispatchers }
|
572
581
|
end
|
573
582
|
|
574
583
|
# Create manager for outgoing requests
|
@@ -720,9 +729,14 @@ module RightScale
|
|
720
729
|
# true:: Always return true
|
721
730
|
def dispatch_request(request, queue)
|
722
731
|
begin
|
723
|
-
if
|
724
|
-
|
725
|
-
|
732
|
+
if (dispatcher = @dispatchers[queue])
|
733
|
+
if (result = dispatcher.dispatch(request))
|
734
|
+
exchange = {:type => :queue, :name => request.reply_to, :options => {:durable => true, :no_declare => @options[:secure]}}
|
735
|
+
@broker.publish(exchange, result, :persistent => true, :mandatory => true, :log_filter => [:request_from, :tries, :persistent, :duration])
|
736
|
+
end
|
737
|
+
else
|
738
|
+
Log.error("Failed to dispatch request #{request.trace} from queue #{queue} because no dispatcher configured")
|
739
|
+
@request_failure_stats.update("NoConfiguredDispatcher")
|
726
740
|
end
|
727
741
|
rescue Dispatcher::DuplicateRequest
|
728
742
|
rescue RightAMQP::HABrokerClient::NoConnectedBrokers => e
|
@@ -97,13 +97,12 @@ module RightScale
|
|
97
97
|
# (AgentIdentity):: Corresponding agent identity
|
98
98
|
#
|
99
99
|
# === Raise
|
100
|
-
# (RightScale::Exceptions::Argument):: Serialized agent identity is
|
100
|
+
# (RightScale::Exceptions::Argument):: Serialized agent identity is invalid
|
101
101
|
def self.parse(serialized_id)
|
102
|
-
|
103
|
-
|
104
|
-
raise RightScale::Exceptions::Argument, "Invalid agent identity token" unless prefix && agent_type && token && bid
|
102
|
+
prefix, agent_type, token, bid, separator = parts(self.compatible_serialized(serialized_id))
|
103
|
+
raise RightScale::Exceptions::Argument, "Invalid agent identity: #{serialized_id.inspect}" unless prefix && agent_type && token && bid
|
105
104
|
base_id = bid.to_i
|
106
|
-
raise RightScale::Exceptions::Argument, "Invalid agent identity
|
105
|
+
raise RightScale::Exceptions::Argument, "Invalid agent identity base ID: #{bid ? bid : bid.inspect}" unless base_id.to_s == bid
|
107
106
|
|
108
107
|
AgentIdentity.new(prefix, agent_type, base_id, token, separator)
|
109
108
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (c) 2009 RightScale Inc
|
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
|
@@ -20,7 +20,6 @@
|
|
20
20
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
21
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
22
|
|
23
|
-
|
24
23
|
module RightScale
|
25
24
|
|
26
25
|
# Agent tags management
|
@@ -43,7 +42,7 @@ module RightScale
|
|
43
42
|
#
|
44
43
|
# === Return
|
45
44
|
# true:: Always return true
|
46
|
-
def tags(options={})
|
45
|
+
def tags(options = {})
|
47
46
|
do_query(nil, @agent.identity, options) do |result|
|
48
47
|
if result.kind_of?(Hash)
|
49
48
|
yield(result.size == 1 ? result.values.first['tags'] : [])
|
@@ -57,7 +56,7 @@ module RightScale
|
|
57
56
|
# of the given tags.
|
58
57
|
#
|
59
58
|
# === Parameters
|
60
|
-
# tags(Array):: tags to query or empty
|
59
|
+
# tags(String, Array):: Tag or tags to query or empty
|
61
60
|
# options(Hash):: Request options
|
62
61
|
# :raw(Boolean):: true to yield raw tag response instead of deserialized tags
|
63
62
|
# :timeout(Integer):: timeout in seconds before giving up and yielding an error message
|
@@ -68,14 +67,8 @@ module RightScale
|
|
68
67
|
#
|
69
68
|
# === Return
|
70
69
|
# true:: Always return true
|
71
|
-
def query_tags(
|
72
|
-
|
73
|
-
tags = tags[0..-2]
|
74
|
-
options = tags.last
|
75
|
-
else
|
76
|
-
options = {}
|
77
|
-
end
|
78
|
-
|
70
|
+
def query_tags(tags, options = {})
|
71
|
+
tags = ensure_flat_array_value(tags) unless tags.nil? || tags.empty?
|
79
72
|
do_query(tags, nil, options) { |result| yield result }
|
80
73
|
end
|
81
74
|
|
@@ -83,7 +76,7 @@ module RightScale
|
|
83
76
|
# of the given tags. Yields the raw response (for responding locally).
|
84
77
|
#
|
85
78
|
# === Parameters
|
86
|
-
# tags(Array):: tags to query or empty
|
79
|
+
# tags(String, Array):: Tag or tags to query or empty
|
87
80
|
# agent_ids(Array):: agent IDs to query or empty or nil
|
88
81
|
# options(Hash):: Request options
|
89
82
|
# :timeout(Integer):: timeout in seconds before giving up and yielding an error message
|
@@ -93,15 +86,16 @@ module RightScale
|
|
93
86
|
#
|
94
87
|
# === Return
|
95
88
|
# true:: Always return true
|
96
|
-
def query_tags_raw(tags, agent_ids = nil, options={})
|
97
|
-
|
89
|
+
def query_tags_raw(tags, agent_ids = nil, options = {})
|
90
|
+
tags = ensure_flat_array_value(tags) unless tags.nil? || tags.empty?
|
91
|
+
options = options.merge(:raw => true)
|
98
92
|
do_query(tags, agent_ids, options) { |raw_response| yield raw_response }
|
99
93
|
end
|
100
94
|
|
101
95
|
# Add given tags to agent
|
102
96
|
#
|
103
97
|
# === Parameters
|
104
|
-
# new_tags(Array)::
|
98
|
+
# new_tags(String, Array):: Tag or tags to be added
|
105
99
|
#
|
106
100
|
# === Block
|
107
101
|
# A block is optional. If provided, should take one argument which will be set with the
|
@@ -109,14 +103,15 @@ module RightScale
|
|
109
103
|
#
|
110
104
|
# === Return
|
111
105
|
# true always return true
|
112
|
-
def add_tags(
|
106
|
+
def add_tags(new_tags)
|
107
|
+
new_tags = ensure_flat_array_value(new_tags) unless new_tags.nil? || new_tags.empty?
|
113
108
|
update_tags(new_tags, []) { |raw_response| yield raw_response if block_given? }
|
114
109
|
end
|
115
110
|
|
116
111
|
# Remove given tags from agent
|
117
112
|
#
|
118
113
|
# === Parameters
|
119
|
-
# old_tags(Array)::
|
114
|
+
# old_tags(String, Array):: Tag or tags to be removed
|
120
115
|
#
|
121
116
|
# === Block
|
122
117
|
# A block is optional. If provided, should take one argument which will be set with the
|
@@ -124,7 +119,8 @@ module RightScale
|
|
124
119
|
#
|
125
120
|
# === Return
|
126
121
|
# true always return true
|
127
|
-
def remove_tags(
|
122
|
+
def remove_tags(old_tags)
|
123
|
+
old_tags = ensure_flat_array_value(old_tags) unless old_tags.nil? || old_tags.empty?
|
128
124
|
update_tags([], old_tags) { |raw_response| yield raw_response if block_given? }
|
129
125
|
end
|
130
126
|
|
@@ -171,7 +167,7 @@ module RightScale
|
|
171
167
|
# === Return
|
172
168
|
# true::Always return true
|
173
169
|
def clear
|
174
|
-
update_tags([], tags) { |raw_response| yield raw_response }
|
170
|
+
update_tags([], @agent.tags) { |raw_response| yield raw_response }
|
175
171
|
end
|
176
172
|
|
177
173
|
private
|
@@ -183,10 +179,10 @@ module RightScale
|
|
183
179
|
# Runs a tag query with an optional list of tags.
|
184
180
|
#
|
185
181
|
# === Parameters
|
186
|
-
# tags(Array)::
|
187
|
-
# agent_ids(Array)::
|
182
|
+
# tags(Array):: Tags to query or empty or nil
|
183
|
+
# agent_ids(Array):: IDs of agents to query with empty or nil meaning all agents in deployment
|
188
184
|
# options(Hash):: Request options
|
189
|
-
# :raw(Boolean):: true to yield raw tag response instead of
|
185
|
+
# :raw(Boolean):: true to yield raw tag response instead of unserialized tags
|
190
186
|
# :timeout(Integer):: timeout in seconds before giving up and yielding an error message
|
191
187
|
#
|
192
188
|
# === Block
|
@@ -195,7 +191,7 @@ module RightScale
|
|
195
191
|
#
|
196
192
|
# === Return
|
197
193
|
# true:: Always return true
|
198
|
-
def do_query(tags = nil, agent_ids = nil, options={})
|
194
|
+
def do_query(tags = nil, agent_ids = nil, options = {})
|
199
195
|
raw = options[:raw] || false
|
200
196
|
timeout = options[:timeout]
|
201
197
|
|
@@ -241,4 +237,5 @@ module RightScale
|
|
241
237
|
# to the old typename
|
242
238
|
# TODO remove this alias for RightAgent 1.0
|
243
239
|
AgentTagsManager = AgentTagManager
|
240
|
+
|
244
241
|
end # RightScale
|
@@ -123,7 +123,7 @@ module RightScale
|
|
123
123
|
# === Return
|
124
124
|
# desc(String):: Auditable description
|
125
125
|
def to_s
|
126
|
-
desc = @executables.collect { |e| e.
|
126
|
+
desc = @executables.collect { |e| e.title }.join(', ') if @executables
|
127
127
|
desc ||= 'empty bundle'
|
128
128
|
end
|
129
129
|
end
|
@@ -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
|
@@ -41,7 +41,7 @@ module RightScale
|
|
41
41
|
# (Array) RightScript attachments URLs, array of RightScriptAttachment
|
42
42
|
attr_accessor :attachments
|
43
43
|
|
44
|
-
# (
|
44
|
+
# (String) RightScripts required packages as a space-delimited list of package names or empty
|
45
45
|
attr_accessor :packages
|
46
46
|
|
47
47
|
# (Integer) RightScript id
|
@@ -50,7 +50,7 @@ module RightScale
|
|
50
50
|
# (Boolean) Whether script inputs are ready
|
51
51
|
attr_accessor :ready
|
52
52
|
|
53
|
-
# (
|
53
|
+
# (Hash) a map of input names to CredentialLocations which must be retrieved by the instance or nil or empty
|
54
54
|
attr_accessor :external_inputs
|
55
55
|
|
56
56
|
# (Hash) nil or Hash of input name to flags (array of string tokens) indicating additional
|
@@ -58,6 +58,9 @@ module RightScale
|
|
58
58
|
# flag means true, absense means false.
|
59
59
|
attr_accessor :input_flags
|
60
60
|
|
61
|
+
# (String) Displayable version for RightScript (revision, etc.) or nil
|
62
|
+
attr_accessor :display_version
|
63
|
+
|
61
64
|
def initialize(*args)
|
62
65
|
@nickname = args[0] if args.size > 0
|
63
66
|
@source = args[1] if args.size > 1
|
@@ -68,12 +71,24 @@ module RightScale
|
|
68
71
|
@ready = args[6] if args.size > 6
|
69
72
|
@external_inputs = args[7] if args.size > 7
|
70
73
|
@input_flags = args[8] if args.size > 8
|
74
|
+
@display_version = args[9] if args.size > 9
|
71
75
|
end
|
72
76
|
|
73
77
|
# Array of serialized fields given to constructor
|
74
78
|
def serialized_members
|
75
|
-
[ @nickname, @source, @parameters, @attachments, @packages, @id, @ready, @external_inputs, @input_flags ]
|
79
|
+
[ @nickname, @source, @parameters, @attachments, @packages, @id, @ready, @external_inputs, @input_flags, @display_version ]
|
80
|
+
end
|
81
|
+
|
82
|
+
# Human readable title
|
83
|
+
#
|
84
|
+
# === Return
|
85
|
+
# @return [String] title for display
|
86
|
+
def title
|
87
|
+
if @display_version
|
88
|
+
"'#{nickname}' #{@display_version}"
|
89
|
+
else
|
90
|
+
nickname
|
91
|
+
end
|
76
92
|
end
|
77
|
-
|
78
93
|
end
|
79
94
|
end
|
@@ -22,9 +22,52 @@
|
|
22
22
|
|
23
23
|
module RightScale
|
24
24
|
class Exceptions
|
25
|
-
|
25
|
+
# Capability not currently supported
|
26
|
+
class NotSupported < Exception; end
|
27
|
+
|
28
|
+
# Internal application error
|
29
|
+
class Application < RuntimeError
|
30
|
+
attr_reader :nested_exception
|
31
|
+
def initialize(message, nested_exception = nil)
|
32
|
+
@nested_exception = nested_exception
|
33
|
+
super(message)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Invalid command or method argument
|
26
38
|
class Argument < RuntimeError; end
|
39
|
+
|
40
|
+
# Agent command IO error
|
27
41
|
class IO < RuntimeError; end
|
42
|
+
|
43
|
+
# Agent compute platform error
|
28
44
|
class PlatformError < StandardError; end
|
45
|
+
|
46
|
+
# Cannot connect or lost connection to external resource
|
47
|
+
class ConnectivityFailure < RuntimeError
|
48
|
+
attr_reader :nested_exception
|
49
|
+
def initialize(message, nested_exception = nil)
|
50
|
+
@nested_exception = nested_exception
|
51
|
+
super(message)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Request failed but potentially will succeed if retried
|
56
|
+
class RetryableError < RuntimeError
|
57
|
+
attr_reader :nested_exception
|
58
|
+
def initialize(message, nested_exception = nil)
|
59
|
+
@nested_exception = nested_exception
|
60
|
+
super(message)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Database query failed
|
65
|
+
class QueryFailure < RuntimeError
|
66
|
+
attr_reader :nested_exception
|
67
|
+
def initialize(message, nested_exception = nil)
|
68
|
+
@nested_exception = nested_exception
|
69
|
+
super(message)
|
70
|
+
end
|
71
|
+
end
|
29
72
|
end
|
30
73
|
end
|
data/lib/right_agent/history.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (c) 2009-
|
2
|
+
# Copyright (c) 2009-2012 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
|
@@ -20,6 +20,8 @@
|
|
20
20
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
21
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
22
|
|
23
|
+
require 'fileutils'
|
24
|
+
|
23
25
|
module RightScale
|
24
26
|
|
25
27
|
# Agent history manager
|
@@ -44,6 +46,7 @@ module RightScale
|
|
44
46
|
# true:: Always return true
|
45
47
|
def update(event)
|
46
48
|
@last_update = {:time => Time.now.to_i, :pid => @pid, :event => event}
|
49
|
+
FileUtils.mkdir_p(File.dirname(@history)) unless File.exists?(File.dirname(@history))
|
47
50
|
File.open(@history, "a") { |f| f.puts @last_update.to_json }
|
48
51
|
true
|
49
52
|
end
|