rightscale-nanite 0.4.1.10 → 0.4.1.22
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/Rakefile +5 -7
- data/lib/nanite.rb +1 -1
- data/lib/nanite/actor.rb +8 -2
- data/lib/nanite/agent.rb +13 -3
- data/lib/nanite/cluster.rb +57 -34
- data/lib/nanite/local_state.rb +18 -14
- data/lib/nanite/mapper.rb +6 -4
- data/lib/nanite/mapper_proxy.rb +12 -0
- data/lib/nanite/packets.rb +50 -14
- data/lib/nanite/redis_tag_store.rb +7 -21
- data/lib/nanite/security/certificate.rb +3 -1
- data/lib/nanite/security/secure_serializer.rb +16 -19
- data/lib/nanite/serializer.rb +1 -1
- data/lib/nanite/state.rb +4 -14
- metadata +11 -12
data/Rakefile
CHANGED
@@ -11,10 +11,10 @@ require 'rake/clean'
|
|
11
11
|
require 'lib/nanite'
|
12
12
|
|
13
13
|
GEM = "rightscale-nanite"
|
14
|
-
AUTHOR = "
|
15
|
-
EMAIL = "
|
16
|
-
HOMEPAGE = "http://github.com/
|
17
|
-
SUMMARY = "
|
14
|
+
AUTHOR = "RightScale, Inc."
|
15
|
+
EMAIL = "support@rightscale.com"
|
16
|
+
HOMEPAGE = "http://github.com/rightscale/nanite"
|
17
|
+
SUMMARY = "Self-assembling fabric of ruby daemons; fork of ezmobius/nanite."
|
18
18
|
|
19
19
|
Dir.glob('tasks/*.rake').each { |r| Rake.application.add_import r }
|
20
20
|
|
@@ -73,6 +73,4 @@ task :docs => :rdoc do
|
|
73
73
|
else
|
74
74
|
sh 'firefox rdoc/index.html'
|
75
75
|
end
|
76
|
-
end
|
77
|
-
|
78
|
-
require 'rightscale-nanite.rb'
|
76
|
+
end
|
data/lib/nanite.rb
CHANGED
@@ -39,7 +39,7 @@ require 'nanite/security/static_certificate_store'
|
|
39
39
|
require 'nanite/serializer'
|
40
40
|
|
41
41
|
module Nanite
|
42
|
-
VERSION = '0.4.1.
|
42
|
+
VERSION = '0.4.1.22' unless defined?(Nanite::VERSION)
|
43
43
|
|
44
44
|
class MapperNotRunning < StandardError; end
|
45
45
|
|
data/lib/nanite/actor.rb
CHANGED
@@ -57,15 +57,21 @@ module Nanite
|
|
57
57
|
end # ClassMethods
|
58
58
|
|
59
59
|
module InstanceMethods
|
60
|
-
#
|
60
|
+
# Send nanite request to another agent (through the mapper)
|
61
61
|
def request(*args, &blk)
|
62
62
|
MapperProxy.instance.request(*args, &blk)
|
63
63
|
end
|
64
64
|
|
65
|
+
# Send nanite push to another agent (through the mapper)
|
65
66
|
def push(*args)
|
66
67
|
MapperProxy.instance.push(*args)
|
67
68
|
end
|
69
|
+
|
70
|
+
# Send nanite tag query to mapper
|
71
|
+
def query_tags(*args, &blk)
|
72
|
+
MapperProxy.instance.query_tags(*args, &blk)
|
73
|
+
end
|
68
74
|
end # InstanceMethods
|
69
75
|
|
70
76
|
end # Actor
|
71
|
-
end # Nanite
|
77
|
+
end # Nanite
|
data/lib/nanite/agent.rb
CHANGED
@@ -5,7 +5,7 @@ module Nanite
|
|
5
5
|
include ConsoleHelper
|
6
6
|
include DaemonizeHelper
|
7
7
|
|
8
|
-
attr_reader :identity, :options, :serializer, :dispatcher, :registry, :amq, :tags
|
8
|
+
attr_reader :identity, :options, :serializer, :dispatcher, :registry, :amq, :tags, :callbacks
|
9
9
|
attr_accessor :status_proc
|
10
10
|
|
11
11
|
DEFAULT_OPTIONS = COMMON_DEFAULT_OPTIONS.merge({
|
@@ -74,6 +74,10 @@ module Nanite
|
|
74
74
|
# this defaults to 5672, port used by some widely
|
75
75
|
# used AMQP brokers (RabbitMQ and ZeroMQ)
|
76
76
|
#
|
77
|
+
# callback : Hash of proc objects defining well known callbacks
|
78
|
+
# Currently only the :exception callback is supported
|
79
|
+
# This block gets called whenever a packet generates an exception
|
80
|
+
#
|
77
81
|
# On start Nanite reads config.yml, so it is common to specify
|
78
82
|
# options in the YAML file. However, when both Ruby code options
|
79
83
|
# and YAML file specify option, Ruby code options take precedence.
|
@@ -95,7 +99,7 @@ module Nanite
|
|
95
99
|
Log.init(@identity, @options[:log_path])
|
96
100
|
Log.level = @options[:log_level] if @options[:log_level]
|
97
101
|
@serializer = Serializer.new(@options[:format])
|
98
|
-
@status_proc
|
102
|
+
@status_proc ||= lambda { parse_uptime(`uptime 2> /dev/null`) rescue 'no status' }
|
99
103
|
pid_file = PidFile.new(@identity, @options)
|
100
104
|
pid_file.check
|
101
105
|
if @options[:daemonize]
|
@@ -159,7 +163,12 @@ module Nanite
|
|
159
163
|
if @options[:daemonize]
|
160
164
|
@options[:log_path] = (@options[:log_dir] || @options[:root] || Dir.pwd)
|
161
165
|
end
|
162
|
-
|
166
|
+
|
167
|
+
@callbacks = opts[:callbacks]
|
168
|
+
@status_proc = opts[:status_proc]
|
169
|
+
|
170
|
+
# note the return statement in case of identity being known; ensure all
|
171
|
+
# needed configurations occur before the the following line.
|
163
172
|
return @identity = "nanite-#{@options[:identity]}" if @options[:identity]
|
164
173
|
token = Identity.generate
|
165
174
|
@identity = "nanite-#{token}"
|
@@ -224,6 +233,7 @@ module Nanite
|
|
224
233
|
receive(serializer.load(msg))
|
225
234
|
rescue Exception => e
|
226
235
|
Nanite::Log.error("RECV #{e.message}")
|
236
|
+
callbacks[:exception].call(e, msg, self) rescue nil if callbacks && callbacks[:exception]
|
227
237
|
end
|
228
238
|
end
|
229
239
|
end
|
data/lib/nanite/cluster.rb
CHANGED
@@ -18,9 +18,9 @@ module Nanite
|
|
18
18
|
end
|
19
19
|
|
20
20
|
# determine which nanites should receive the given request
|
21
|
-
def targets_for(request)
|
21
|
+
def targets_for(request, include_timed_out)
|
22
22
|
return [request.target] if request.target
|
23
|
-
__send__(request.selector, request
|
23
|
+
__send__(request.selector, request, include_timed_out)
|
24
24
|
end
|
25
25
|
|
26
26
|
# adds nanite to nanites map: key is nanite's identity
|
@@ -33,7 +33,7 @@ module Nanite
|
|
33
33
|
Nanite::Log.info("RECV #{reg.to_s}")
|
34
34
|
nanites[reg.identity] = { :services => reg.services, :status => reg.status, :tags => reg.tags, :timestamp => Time.now.utc.to_i }
|
35
35
|
reaper.register(reg.identity, agent_timeout + 1) { nanite_timed_out(reg.identity) }
|
36
|
-
callbacks[:register].call(reg.identity, mapper) if callbacks[:register]
|
36
|
+
callbacks[:register].call(reg.identity, mapper) if callbacks && callbacks[:register]
|
37
37
|
else
|
38
38
|
Nanite::Log.warn("RECV NOT AUTHORIZED #{reg.to_s}")
|
39
39
|
end
|
@@ -41,7 +41,7 @@ module Nanite
|
|
41
41
|
Nanite::Log.info("RECV #{reg.to_s}")
|
42
42
|
reaper.unregister(reg.identity)
|
43
43
|
nanites.delete(reg.identity)
|
44
|
-
callbacks[:unregister].call(reg.identity, mapper) if callbacks[:unregister]
|
44
|
+
callbacks[:unregister].call(reg.identity, mapper) if callbacks && callbacks[:unregister]
|
45
45
|
when TagUpdate
|
46
46
|
Nanite::Log.info("RECV #{reg.to_s}")
|
47
47
|
nanites.update_tags(reg.identity, reg.new_tags, reg.obsolete_tags)
|
@@ -55,7 +55,7 @@ module Nanite
|
|
55
55
|
if nanite && timed_out?(nanite)
|
56
56
|
Nanite::Log.info("Nanite #{token} timed out")
|
57
57
|
nanite = nanites.delete(token)
|
58
|
-
callbacks[:timeout].call(token, mapper) if callbacks[:timeout]
|
58
|
+
callbacks[:timeout].call(token, mapper) if callbacks && callbacks[:timeout]
|
59
59
|
true
|
60
60
|
end
|
61
61
|
end
|
@@ -71,10 +71,10 @@ module Nanite
|
|
71
71
|
old_target = request.target
|
72
72
|
request.target = target unless target == 'mapper-offline'
|
73
73
|
if @security.authorize_request(request)
|
74
|
-
Nanite::Log.info("SEND #{request.to_s([:from, :
|
74
|
+
Nanite::Log.info("SEND #{request.to_s([:from, :scope, :tags, :target])}")
|
75
75
|
amq.queue(target).publish(serializer.dump(request), :persistent => request.persistent)
|
76
76
|
else
|
77
|
-
Nanite::Log.
|
77
|
+
Nanite::Log.error("RECV NOT AUTHORIZED #{request.to_s}")
|
78
78
|
end
|
79
79
|
ensure
|
80
80
|
request.target = old_target
|
@@ -100,12 +100,14 @@ module Nanite
|
|
100
100
|
|
101
101
|
# forward request coming from agent
|
102
102
|
def handle_request(request)
|
103
|
-
Nanite::Log.info("RECV #{request.to_s([:from, :
|
103
|
+
Nanite::Log.info("RECV #{request.to_s([:from, :scope, :target, :tags])}") unless Nanite::Log.level == :debug
|
104
104
|
Nanite::Log.debug("RECV #{request.to_s}")
|
105
105
|
case request
|
106
106
|
when Push
|
107
|
-
mapper.send_push(request)
|
108
|
-
|
107
|
+
if mapper.send_push(request) == false
|
108
|
+
Nanite::Log.info("RECV - No target found for #{request.to_s}")
|
109
|
+
end
|
110
|
+
when Request
|
109
111
|
intm_handler = lambda do |result, job|
|
110
112
|
result = IntermediateMessage.new(request.token, job.request.from, mapper.identity, nil, result)
|
111
113
|
forward_response(result, request.persistent)
|
@@ -118,8 +120,23 @@ module Nanite
|
|
118
120
|
end
|
119
121
|
|
120
122
|
if ok == false
|
123
|
+
Nanite::Log.info("RECV - No target found for #{request.to_s}")
|
121
124
|
forward_response(result, request.persistent)
|
122
125
|
end
|
126
|
+
when TagQuery
|
127
|
+
results = {}
|
128
|
+
results = nanites.nanites_for(request) if request.tags && !request.tags.empty?
|
129
|
+
if request.agent_ids && !request.agent_ids.empty?
|
130
|
+
request.agent_ids.each do |nanite_id|
|
131
|
+
if !results.include?(nanite_id)
|
132
|
+
if nanite = nanites[nanite_id]
|
133
|
+
results[nanite_id] = nanite
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
result = Result.new(request.token, request.from, results, mapper.identity)
|
139
|
+
forward_response(result, request.persistent)
|
123
140
|
end
|
124
141
|
end
|
125
142
|
|
@@ -130,37 +147,38 @@ module Nanite
|
|
130
147
|
end
|
131
148
|
|
132
149
|
# returns least loaded nanite that provides given service
|
133
|
-
def least_loaded(
|
134
|
-
candidates = nanites_providing(
|
150
|
+
def least_loaded(request, include_timed_out)
|
151
|
+
candidates = nanites_providing(request, include_timed_out)
|
135
152
|
return [] if candidates.empty?
|
136
|
-
|
137
|
-
[
|
153
|
+
res = candidates.to_a.min { |a, b| a[1][:status] <=> b[1][:status] }
|
154
|
+
[res[0]]
|
138
155
|
end
|
139
156
|
|
140
157
|
# returns all nanites that provide given service
|
141
|
-
|
142
|
-
|
158
|
+
# potentially including timed out agents
|
159
|
+
def all(request, include_timed_out)
|
160
|
+
nanites_providing(request, include_timed_out).keys
|
143
161
|
end
|
144
162
|
|
145
163
|
# returns a random nanite
|
146
|
-
def random(
|
147
|
-
candidates = nanites_providing(
|
164
|
+
def random(request, include_timed_out)
|
165
|
+
candidates = nanites_providing(request, include_timed_out)
|
148
166
|
return [] if candidates.empty?
|
149
|
-
|
150
|
-
[candidates[rand(candidates.size)]]
|
167
|
+
[candidates.keys[rand(candidates.size)]]
|
151
168
|
end
|
152
169
|
|
153
170
|
# selects next nanite that provides given service
|
154
171
|
# using round robin rotation
|
155
|
-
def rr(
|
172
|
+
def rr(request, include_timed_out)
|
156
173
|
@last ||= {}
|
174
|
+
service = request.type
|
157
175
|
@last[service] ||= 0
|
158
|
-
candidates = nanites_providing(
|
176
|
+
candidates = nanites_providing(request, include_timed_out)
|
159
177
|
return [] if candidates.empty?
|
160
178
|
@last[service] = 0 if @last[service] >= candidates.size
|
161
|
-
|
179
|
+
key = candidates.keys[@last[service]]
|
162
180
|
@last[service] += 1
|
163
|
-
[
|
181
|
+
[key]
|
164
182
|
end
|
165
183
|
|
166
184
|
def timed_out?(nanite)
|
@@ -168,13 +186,18 @@ module Nanite
|
|
168
186
|
end
|
169
187
|
|
170
188
|
# returns all nanites that provide the given service
|
171
|
-
def nanites_providing(
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
189
|
+
def nanites_providing(request, include_timed_out)
|
190
|
+
# FIXME: Not filtering out results for now to alleviate issue with
|
191
|
+
# overloaded agents not pinging in a timely fashion
|
192
|
+
# Put that code back once agents behave properly
|
193
|
+
nanites.nanites_for(request)
|
194
|
+
|
195
|
+
# nanites.nanites_for(request).delete_if do |nanite, info|
|
196
|
+
# if res = !include_timed_out && timed_out?(info)
|
197
|
+
# Nanite::Log.debug("Ignoring timed out nanite #{nanite} in target selection - last seen at #{info[:timestamp]}")
|
198
|
+
# end
|
199
|
+
# res
|
200
|
+
# end
|
178
201
|
end
|
179
202
|
|
180
203
|
def setup_queues
|
@@ -191,7 +214,7 @@ module Nanite
|
|
191
214
|
handle_ping(ping)
|
192
215
|
rescue Exception => e
|
193
216
|
Nanite::Log.error("RECV [ping] #{e.message}")
|
194
|
-
callbacks[:exception].call(e,
|
217
|
+
callbacks[:exception].call(e, ping, mapper) rescue nil if callbacks && callbacks[:exception]
|
195
218
|
end
|
196
219
|
end
|
197
220
|
hb_fanout = amq.fanout('heartbeat', :durable => true)
|
@@ -208,7 +231,7 @@ module Nanite
|
|
208
231
|
register(serializer.load(msg))
|
209
232
|
rescue Exception => e
|
210
233
|
Nanite::Log.error("RECV [register] #{e.message}")
|
211
|
-
callbacks[:exception].call(e, msg, mapper) rescue nil if callbacks[:exception]
|
234
|
+
callbacks[:exception].call(e, msg, mapper) rescue nil if callbacks && callbacks[:exception]
|
212
235
|
end
|
213
236
|
end
|
214
237
|
reg_fanout = amq.fanout('registration', :durable => true)
|
@@ -225,7 +248,7 @@ module Nanite
|
|
225
248
|
handle_request(serializer.load(msg))
|
226
249
|
rescue Exception => e
|
227
250
|
Nanite::Log.error("RECV [request] #{e.message}")
|
228
|
-
callbacks[:exception].call(e, msg, mapper) rescue nil if callbacks[:exception]
|
251
|
+
callbacks[:exception].call(e, msg, mapper) rescue nil if callbacks && callbacks[:exception]
|
229
252
|
end
|
230
253
|
end
|
231
254
|
req_fanout = amq.fanout('request', :durable => true)
|
data/lib/nanite/local_state.rb
CHANGED
@@ -6,28 +6,32 @@ module Nanite
|
|
6
6
|
end
|
7
7
|
end
|
8
8
|
|
9
|
-
def
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
9
|
+
def nanites_for(request)
|
10
|
+
tags = request.tags
|
11
|
+
service = request.type
|
12
|
+
if service
|
13
|
+
nanites = reject { |_, state| !state[:services].include?(service) }
|
14
|
+
else
|
15
|
+
nanites = self
|
16
|
+
end
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
nanites = select { |name, state| state[:services].include?(service) }
|
20
|
-
unless tags.empty?
|
21
|
-
nanites.select { |a, b| !(b[:tags] & tags).empty? }
|
18
|
+
if tags.nil? || tags.empty?
|
19
|
+
service ? nanites : {}
|
22
20
|
else
|
23
|
-
nanites
|
24
|
-
end
|
21
|
+
nanites.reject { |_, state| (state[:tags] & tags).empty? }
|
22
|
+
end
|
25
23
|
end
|
26
24
|
|
27
25
|
def update_status(name, status)
|
28
26
|
self[name].update(:status => status, :timestamp => Time.now.utc.to_i)
|
29
27
|
end
|
30
28
|
|
29
|
+
def update_tags(name, new_tags, obsolete_tags)
|
30
|
+
prev_tags = self[name] && self[name][:tags]
|
31
|
+
updated_tags = (new_tags || []) + (prev_tags || []) - (obsolete_tags || [])
|
32
|
+
self[name].update(:tags => updated_tags.uniq)
|
33
|
+
end
|
34
|
+
|
31
35
|
private
|
32
36
|
|
33
37
|
def all(key)
|
data/lib/nanite/mapper.rb
CHANGED
@@ -195,7 +195,7 @@ module Nanite
|
|
195
195
|
def send_request(request, opts = {}, &blk)
|
196
196
|
request.reply_to = identity
|
197
197
|
intm_handler = opts.delete(:intermediate_handler)
|
198
|
-
targets = cluster.targets_for(request)
|
198
|
+
targets = cluster.targets_for(request, include_timed_out=false)
|
199
199
|
if !targets.empty?
|
200
200
|
job = job_warden.new_job(request, targets, intm_handler, blk)
|
201
201
|
cluster.route(request, job.targets)
|
@@ -235,7 +235,8 @@ module Nanite
|
|
235
235
|
end
|
236
236
|
|
237
237
|
def send_push(push, opts = {})
|
238
|
-
|
238
|
+
include_timed_out = push.selector == :all
|
239
|
+
targets = cluster.targets_for(push, include_timed_out)
|
239
240
|
if !targets.empty?
|
240
241
|
cluster.route(push, targets)
|
241
242
|
true
|
@@ -270,7 +271,8 @@ module Nanite
|
|
270
271
|
offline_queue = amq.queue('mapper-offline', :durable => true)
|
271
272
|
offline_queue.subscribe(:ack => true) do |info, deliverable|
|
272
273
|
deliverable = serializer.load(deliverable)
|
273
|
-
|
274
|
+
include_timed_out = deliverable.is_a?(Push) && deliverable.selector == :all
|
275
|
+
targets = cluster.targets_for(deliverable, include_timed_out)
|
274
276
|
unless targets.empty?
|
275
277
|
info.ack
|
276
278
|
if deliverable.kind_of?(Request)
|
@@ -297,7 +299,7 @@ module Nanite
|
|
297
299
|
job_warden.process(msg)
|
298
300
|
rescue Exception => e
|
299
301
|
Nanite::Log.error("RECV [result] #{e.message}")
|
300
|
-
callbacks[:exception].call(e, msg, mapper) rescue nil if callbacks[:exception]
|
302
|
+
callbacks[:exception].call(e, msg, mapper) rescue nil if callbacks && callbacks[:exception]
|
301
303
|
end
|
302
304
|
end
|
303
305
|
end
|
data/lib/nanite/mapper_proxy.rb
CHANGED
@@ -41,6 +41,7 @@ module Nanite
|
|
41
41
|
amqp.fanout('request', :no_declare => options[:secure]).publish(serializer.dump(request))
|
42
42
|
end
|
43
43
|
|
44
|
+
# Send push to given agent through the mapper
|
44
45
|
def push(type, payload = '', opts = {})
|
45
46
|
raise "Mapper proxy not initialized" unless identity && options
|
46
47
|
push = Push.new(type, payload, opts)
|
@@ -51,6 +52,17 @@ module Nanite
|
|
51
52
|
amqp.fanout('request', :no_declare => options[:secure]).publish(serializer.dump(push))
|
52
53
|
end
|
53
54
|
|
55
|
+
# Send tag query to mapper
|
56
|
+
def query_tags(opts, &blk)
|
57
|
+
raise "Mapper proxy not initialized" unless identity && options
|
58
|
+
tag_query = TagQuery.new(identity, opts)
|
59
|
+
tag_query.token = Identity.generate
|
60
|
+
tag_query.persistent = opts.key?(:persistent) ? opts[:persistent] : options[:persistent]
|
61
|
+
pending_requests[tag_query.token] = { :result_handler => blk }
|
62
|
+
Nanite::Log.info("SEND #{tag_query.to_s}")
|
63
|
+
amqp.fanout('request', :no_declare => options[:secure]).publish(serializer.dump(tag_query))
|
64
|
+
end
|
65
|
+
|
54
66
|
# Update tags registered by mapper for agent
|
55
67
|
def update_tags(new_tags, obsolete_tags)
|
56
68
|
raise "Mapper proxy not initialized" unless identity && options
|
data/lib/nanite/packets.rb
CHANGED
@@ -113,7 +113,7 @@ module Nanite
|
|
113
113
|
#
|
114
114
|
# Options:
|
115
115
|
# from is sender identity
|
116
|
-
#
|
116
|
+
# scope define behavior that should be used to resolve tag based routing
|
117
117
|
# token is a generated request id that mapper uses to identify replies
|
118
118
|
# reply_to is identity of the node actor replies to, usually a mapper itself
|
119
119
|
# selector is the selector used to route the request
|
@@ -121,7 +121,7 @@ module Nanite
|
|
121
121
|
# persistent signifies if this request should be saved to persistent storage by the AMQP broker
|
122
122
|
class Request < Packet
|
123
123
|
|
124
|
-
attr_accessor :from, :
|
124
|
+
attr_accessor :from, :scope, :payload, :type, :token, :reply_to, :selector, :target, :persistent, :tags
|
125
125
|
|
126
126
|
DEFAULT_OPTIONS = {:selector => :least_loaded}
|
127
127
|
|
@@ -131,7 +131,7 @@ module Nanite
|
|
131
131
|
@payload = payload
|
132
132
|
@size = size
|
133
133
|
@from = opts[:from]
|
134
|
-
@
|
134
|
+
@scope = opts[:scope]
|
135
135
|
@token = opts[:token]
|
136
136
|
@reply_to = opts[:reply_to]
|
137
137
|
@selector = opts[:selector]
|
@@ -142,9 +142,9 @@ module Nanite
|
|
142
142
|
|
143
143
|
def self.json_create(o)
|
144
144
|
i = o['data']
|
145
|
-
new(i['type'], i['payload'], { :from
|
146
|
-
:token => i['token'], :reply_to => i['reply_to'],
|
147
|
-
:selector => i['selector'], :target => i['target'],
|
145
|
+
new(i['type'], i['payload'], { :from => i['from'], :scope => i['scope'],
|
146
|
+
:token => i['token'], :reply_to => i['reply_to'],
|
147
|
+
:selector => i['selector'], :target => i['target'],
|
148
148
|
:persistent => i['persistent'], :tags => i['tags'] },
|
149
149
|
o['size'])
|
150
150
|
end
|
@@ -152,7 +152,7 @@ module Nanite
|
|
152
152
|
def to_s(filter=nil)
|
153
153
|
log_msg = "#{super} <#{token}> #{type}"
|
154
154
|
log_msg += " from #{id_to_s(from)}" if filter.nil? || filter.include?(:from)
|
155
|
-
log_msg += "
|
155
|
+
log_msg += " with scope #{scope}" if scope && (filter.nil? || filter.include?(:scope))
|
156
156
|
log_msg += " to #{id_to_s(target)}" if target && (filter.nil? || filter.include?(:target))
|
157
157
|
log_msg += ", reply_to #{id_to_s(reply_to)}" if reply_to && (filter.nil? || filter.include?(:reply_to))
|
158
158
|
log_msg += ", tags #{tags.inspect}" if tags && !tags.empty? && (filter.nil? || filter.include?(:tags))
|
@@ -170,14 +170,14 @@ module Nanite
|
|
170
170
|
#
|
171
171
|
# Options:
|
172
172
|
# from is sender identity
|
173
|
-
#
|
173
|
+
# scope define behavior that should be used to resolve tag based routing
|
174
174
|
# token is a generated request id that mapper uses to identify replies
|
175
175
|
# selector is the selector used to route the request
|
176
176
|
# target is the target nanite for the request
|
177
177
|
# persistent signifies if this request should be saved to persistent storage by the AMQP broker
|
178
178
|
class Push < Packet
|
179
179
|
|
180
|
-
attr_accessor :from, :
|
180
|
+
attr_accessor :from, :scope, :payload, :type, :token, :selector, :target, :persistent, :tags
|
181
181
|
|
182
182
|
DEFAULT_OPTIONS = {:selector => :least_loaded}
|
183
183
|
|
@@ -187,7 +187,7 @@ module Nanite
|
|
187
187
|
@payload = payload
|
188
188
|
@size = size
|
189
189
|
@from = opts[:from]
|
190
|
-
@
|
190
|
+
@scope = opts[:scope]
|
191
191
|
@token = opts[:token]
|
192
192
|
@selector = opts[:selector]
|
193
193
|
@target = opts[:target]
|
@@ -197,9 +197,9 @@ module Nanite
|
|
197
197
|
|
198
198
|
def self.json_create(o)
|
199
199
|
i = o['data']
|
200
|
-
new(i['type'], i['payload'], { :from => i['from'], :
|
201
|
-
:token => i['token'], :selector => i['selector'],
|
202
|
-
:target => i['target'], :persistent => i['persistent'],
|
200
|
+
new(i['type'], i['payload'], { :from => i['from'], :scope => i['scope'],
|
201
|
+
:token => i['token'], :selector => i['selector'],
|
202
|
+
:target => i['target'], :persistent => i['persistent'],
|
203
203
|
:tags => i['tags'] },
|
204
204
|
o['size'])
|
205
205
|
end
|
@@ -207,7 +207,7 @@ module Nanite
|
|
207
207
|
def to_s(filter=nil)
|
208
208
|
log_msg = "#{super} <#{token}> #{type}"
|
209
209
|
log_msg += " from #{id_to_s(from)}" if filter.nil? || filter.include?(:from)
|
210
|
-
log_msg += "
|
210
|
+
log_msg += " with scope #{scope}" if scope && (filter.nil? || filter.include?(:scope))
|
211
211
|
log_msg += ", target #{id_to_s(target)}" if target && (filter.nil? || filter.include?(:target))
|
212
212
|
log_msg += ", tags #{tags.inspect}" if tags && !tags.empty? && (filter.nil? || filter.include?(:tags))
|
213
213
|
log_msg += ", payload #{payload.inspect}" if filter.nil? || filter.include?(:payload)
|
@@ -215,6 +215,42 @@ module Nanite
|
|
215
215
|
end
|
216
216
|
end
|
217
217
|
|
218
|
+
# Tag query: retrieve agent ids with associated tags that match given tags
|
219
|
+
#
|
220
|
+
# Options:
|
221
|
+
# from is sender identity
|
222
|
+
# opts Hash of options, two options are supported, at least one must be set:
|
223
|
+
# :tags is an array of tags defining a query that returned agents tags must match
|
224
|
+
# :agent_ids is an array of agents whose tags should be returned
|
225
|
+
class TagQuery < Packet
|
226
|
+
|
227
|
+
attr_accessor :from, :token, :agent_ids, :tags, :persistent
|
228
|
+
|
229
|
+
def initialize(from, opts, size=nil)
|
230
|
+
@from = from
|
231
|
+
@token = opts[:token]
|
232
|
+
@agent_ids = opts[:agent_ids]
|
233
|
+
@tags = opts[:tags]
|
234
|
+
@persistent = opts[:persistent]
|
235
|
+
@size = size
|
236
|
+
end
|
237
|
+
|
238
|
+
def self.json_create(o)
|
239
|
+
i = o['data']
|
240
|
+
new(i['from'], { :token => i['token'], :agent_ids => i['agent_ids'],
|
241
|
+
:tags => i['tags'], :persistent => i['persistent'] },
|
242
|
+
o['size'])
|
243
|
+
end
|
244
|
+
|
245
|
+
def to_s(filter=nil)
|
246
|
+
log_msg = "#{super} <#{token}>"
|
247
|
+
log_msg += " from #{id_to_s(from)}" if filter.nil? || filter.include?(:from)
|
248
|
+
log_msg += " agent_ids #{agent_ids.inspect}"
|
249
|
+
log_msg += " tags: #{tags.inspect}"
|
250
|
+
log_msg
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
218
254
|
# packet that means a work result notification sent from actor to mapper
|
219
255
|
#
|
220
256
|
# from is sender identity
|
@@ -68,27 +68,13 @@ module Nanite
|
|
68
68
|
@redis.set_members("tg-#{nanite}")
|
69
69
|
end
|
70
70
|
|
71
|
-
# Retrieve all agents services
|
72
|
-
def all_services
|
73
|
-
log_redis_error do
|
74
|
-
@redis.set_members('naniteservices')
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
# Retrieve all agents tags
|
79
|
-
def all_tags
|
80
|
-
log_redis_error do
|
81
|
-
@redis.set_members('nanitetags')
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
71
|
# Retrieve nanites implementing given service and exposing given tags
|
86
|
-
def
|
87
|
-
keys = tags
|
88
|
-
keys <<
|
89
|
-
|
90
|
-
|
91
|
-
|
72
|
+
def nanites_ids_for(request)
|
73
|
+
keys = request.tags ? request.tags.dup : []
|
74
|
+
keys << request.type if request.type
|
75
|
+
keys.compact!
|
76
|
+
return {} if keys.empty?
|
77
|
+
log_redis_error { @redis.set_intersect(keys) }
|
92
78
|
end
|
93
79
|
|
94
80
|
private
|
@@ -138,4 +124,4 @@ module Nanite
|
|
138
124
|
end
|
139
125
|
|
140
126
|
end
|
141
|
-
end
|
127
|
+
end
|
@@ -28,13 +28,14 @@ module Nanite
|
|
28
28
|
end
|
29
29
|
|
30
30
|
# Serialize message and sign it using X.509 certificate
|
31
|
-
def self.dump(obj)
|
31
|
+
def self.dump(obj, encrypt=nil)
|
32
32
|
raise "Missing certificate identity" unless @identity
|
33
33
|
raise "Missing certificate" unless @cert
|
34
34
|
raise "Missing certificate key" unless @key
|
35
35
|
raise "Missing certificate store" unless @store || !@encrypt
|
36
|
+
must_encrypt = encrypt.nil? ? @encrypt : encrypt
|
36
37
|
json = obj.to_json
|
37
|
-
if
|
38
|
+
if must_encrypt
|
38
39
|
certs = @store.get_recipients(obj)
|
39
40
|
json = EncryptedDocument.new(json, certs).encrypted_data if certs
|
40
41
|
end
|
@@ -44,24 +45,20 @@ module Nanite
|
|
44
45
|
|
45
46
|
# Unserialize data using certificate store
|
46
47
|
def self.load(json)
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
60
|
-
JSON.load(jsn) if jsn
|
61
|
-
rescue Exception => e
|
62
|
-
Nanite::Log.error("Loading of secure packet failed: #{e.message}\n#{e.backtrace.join("\n")}")
|
63
|
-
raise
|
48
|
+
raise "Missing certificate store" unless @store
|
49
|
+
raise "Missing certificate" unless @cert || !@encrypt
|
50
|
+
raise "Missing certificate key" unless @key || !@encrypt
|
51
|
+
data = JSON.load(json)
|
52
|
+
sig = Signature.from_data(data['signature'])
|
53
|
+
certs = @store.get_signer(data['id'])
|
54
|
+
raise "Could not find a cert for signer #{data['id']}" unless certs
|
55
|
+
certs = [ certs ] unless certs.respond_to?(:any?)
|
56
|
+
raise "Failed to check signature for signer #{data['id']}" unless certs.any? { |c| sig.match?(c) }
|
57
|
+
jsn = data['data']
|
58
|
+
if jsn && @encrypt && data['encrypted']
|
59
|
+
jsn = EncryptedDocument.from_data(jsn).decrypted_data(@key, @cert)
|
64
60
|
end
|
61
|
+
JSON.load(jsn) if jsn
|
65
62
|
end
|
66
63
|
|
67
64
|
end
|
data/lib/nanite/serializer.rb
CHANGED
@@ -6,7 +6,7 @@ module Nanite
|
|
6
6
|
def initialize(action, packet, serializers, msg = nil)
|
7
7
|
@action, @packet = action, packet
|
8
8
|
msg = ":\n#{msg}" if msg && !msg.empty?
|
9
|
-
super("Could not #{action}
|
9
|
+
super("Could not #{action} packet using #{serializers.inspect}: #{msg}")
|
10
10
|
end
|
11
11
|
end # SerializationError
|
12
12
|
|
data/lib/nanite/state.rb
CHANGED
@@ -66,16 +66,6 @@ module Nanite
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
-
# Return all services exposed by all agents
|
70
|
-
def all_services
|
71
|
-
@tag_store.all_services
|
72
|
-
end
|
73
|
-
|
74
|
-
# Return all tags exposed by all agents
|
75
|
-
def all_tags
|
76
|
-
@tag_store.all_tags
|
77
|
-
end
|
78
|
-
|
79
69
|
# Update status and timestamp for given agent
|
80
70
|
def update_status(name, status)
|
81
71
|
log_redis_error do
|
@@ -111,11 +101,11 @@ module Nanite
|
|
111
101
|
|
112
102
|
# Return agents that implement given service and expose
|
113
103
|
# all given tags
|
114
|
-
def nanites_for(
|
115
|
-
res =
|
116
|
-
@tag_store.
|
104
|
+
def nanites_for(request)
|
105
|
+
res = {}
|
106
|
+
@tag_store.nanites_ids_for(request).each do |nanite_id|
|
117
107
|
if nanite = self[nanite_id]
|
118
|
-
res
|
108
|
+
res[nanite_id] = nanite
|
119
109
|
end
|
120
110
|
end
|
121
111
|
res
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rightscale-nanite
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.1.
|
4
|
+
version: 0.4.1.22
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- RightScale, Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2010-01-12 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -22,8 +22,8 @@ dependencies:
|
|
22
22
|
- !ruby/object:Gem::Version
|
23
23
|
version: 0.6.0
|
24
24
|
version:
|
25
|
-
description:
|
26
|
-
email:
|
25
|
+
description: Self-assembling fabric of ruby daemons; fork of ezmobius/nanite.
|
26
|
+
email: support@rightscale.com
|
27
27
|
executables:
|
28
28
|
- nanite-agent
|
29
29
|
- nanite-mapper
|
@@ -39,7 +39,6 @@ files:
|
|
39
39
|
- README.rdoc
|
40
40
|
- Rakefile
|
41
41
|
- TODO
|
42
|
-
- lib/nanite
|
43
42
|
- lib/nanite/actor.rb
|
44
43
|
- lib/nanite/actor_registry.rb
|
45
44
|
- lib/nanite/admin.rb
|
@@ -52,7 +51,6 @@ files:
|
|
52
51
|
- lib/nanite/identity.rb
|
53
52
|
- lib/nanite/job.rb
|
54
53
|
- lib/nanite/local_state.rb
|
55
|
-
- lib/nanite/log
|
56
54
|
- lib/nanite/log/formatter.rb
|
57
55
|
- lib/nanite/log.rb
|
58
56
|
- lib/nanite/mapper.rb
|
@@ -62,7 +60,6 @@ files:
|
|
62
60
|
- lib/nanite/pid_file.rb
|
63
61
|
- lib/nanite/reaper.rb
|
64
62
|
- lib/nanite/redis_tag_store.rb
|
65
|
-
- lib/nanite/security
|
66
63
|
- lib/nanite/security/cached_certificate_store_proxy.rb
|
67
64
|
- lib/nanite/security/certificate.rb
|
68
65
|
- lib/nanite/security/certificate_cache.rb
|
@@ -82,7 +79,9 @@ files:
|
|
82
79
|
- bin/nanite-agent
|
83
80
|
- bin/nanite-mapper
|
84
81
|
has_rdoc: true
|
85
|
-
homepage: http://github.com/
|
82
|
+
homepage: http://github.com/rightscale/nanite
|
83
|
+
licenses: []
|
84
|
+
|
86
85
|
post_install_message:
|
87
86
|
rdoc_options: []
|
88
87
|
|
@@ -103,9 +102,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
103
102
|
requirements: []
|
104
103
|
|
105
104
|
rubyforge_project:
|
106
|
-
rubygems_version: 1.3.
|
105
|
+
rubygems_version: 1.3.5
|
107
106
|
signing_key:
|
108
|
-
specification_version:
|
109
|
-
summary:
|
107
|
+
specification_version: 3
|
108
|
+
summary: Self-assembling fabric of ruby daemons; fork of ezmobius/nanite.
|
110
109
|
test_files: []
|
111
110
|
|