smith 0.5.13.1 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/agency +19 -7
- data/bin/pry-smith +11 -0
- data/bin/smithctl +19 -21
- data/lib/smith/acl_compiler.rb +101 -56
- data/lib/smith/acl_parser.rb +75 -0
- data/lib/smith/agent.rb +28 -43
- data/lib/smith/agent_cache.rb +43 -17
- data/lib/smith/agent_monitoring.rb +1 -1
- data/lib/smith/agent_process.rb +148 -53
- data/lib/smith/application/agency.rb +44 -54
- data/lib/smith/bootstrap.rb +31 -17
- data/lib/smith/cache.rb +4 -0
- data/lib/smith/command.rb +1 -3
- data/lib/smith/commands/agency/kill.rb +22 -5
- data/lib/smith/commands/agency/list.rb +9 -4
- data/lib/smith/commands/agency/logger.rb +25 -12
- data/lib/smith/commands/agency/object_count.rb +19 -8
- data/lib/smith/commands/agency/start.rb +7 -10
- data/lib/smith/commands/agency/stop.rb +30 -12
- data/lib/smith/commands/common.rb +1 -1
- data/lib/smith/commands/smithctl/acl.rb +6 -3
- data/lib/smith/commands/smithctl/dump.rb +79 -0
- data/lib/smith/commands/smithctl/firehose.rb +2 -1
- data/lib/smith/commands/smithctl/push.rb +27 -12
- data/lib/smith/commands/smithctl/status.rb +27 -0
- data/lib/smith/config.rb +140 -28
- data/lib/smith/daemon.rb +16 -3
- data/lib/smith/exceptions.rb +6 -3
- data/lib/smith/logger.rb +12 -24
- data/lib/smith/messaging/acl/agent_keepalive.proto +2 -2
- data/lib/smith/messaging/acl/agent_lifecycle.proto +15 -9
- data/lib/smith/messaging/acl/agent_stats.proto +6 -5
- data/lib/smith/messaging/acl/default.rb +2 -7
- data/lib/smith/messaging/acl_type_cache.rb +77 -0
- data/lib/smith/messaging/factory.rb +29 -0
- data/lib/smith/messaging/queue.rb +12 -10
- data/lib/smith/messaging/queue_definition.rb +21 -4
- data/lib/smith/messaging/receiver.rb +55 -62
- data/lib/smith/messaging/requeue.rb +1 -5
- data/lib/smith/messaging/sender.rb +48 -43
- data/lib/smith/messaging/util.rb +0 -10
- data/lib/smith/queue_definitions.rb +7 -4
- data/lib/smith/version.rb +1 -1
- data/lib/smith.rb +57 -56
- metadata +77 -128
- data/lib/smith/messaging/payload.rb +0 -100
data/lib/smith/agent_process.rb
CHANGED
@@ -1,43 +1,53 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
require 'pp'
|
3
2
|
require 'state_machine'
|
4
|
-
require '
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
require 'protobuf/message'
|
5
6
|
|
6
7
|
module Smith
|
7
8
|
|
8
9
|
class AgentProcess
|
9
10
|
|
10
|
-
include Logger
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
11
|
+
include Smith::Logger
|
12
|
+
extend Forwardable
|
13
|
+
|
14
|
+
class AgentState < ::Protobuf::Message
|
15
|
+
required ::Protobuf::Field::StringField, :_state, 0
|
16
|
+
required ::Protobuf::Field::StringField, :name, 2
|
17
|
+
required ::Protobuf::Field::StringField, :uuid, 3
|
18
|
+
optional ::Protobuf::Field::Int32Field, :pid, 4
|
19
|
+
optional ::Protobuf::Field::Int32Field, :started_at, 5
|
20
|
+
optional ::Protobuf::Field::Int32Field, :last_keep_alive, 6
|
21
|
+
optional ::Protobuf::Field::BoolField, :singleton, 7
|
22
|
+
optional ::Protobuf::Field::StringField, :metadata, 8
|
23
|
+
optional ::Protobuf::Field::BoolField, :monitor, 9
|
24
|
+
end
|
25
|
+
|
26
|
+
def_delegators :@agent_state, :name, :uuid, :pid, :last_keep_alive, :metadata, :monitor, :singleton
|
27
|
+
def_delegators :@agent_state, :name=, :uuid=, :pid=, :last_keep_alive=, :metadata=, :monitor=, :singleton=
|
28
|
+
|
29
|
+
state_machine :initial => lambda {|o| o.send(:_state)}, :action => :save do
|
30
|
+
|
31
|
+
before_transition do |_, transition|
|
28
32
|
logger.debug { "Transition [#{name}]: :#{transition.from} -> :#{transition.to}" }
|
29
33
|
end
|
30
34
|
|
31
|
-
after_failure do |transition|
|
35
|
+
after_failure do |_, transition|
|
32
36
|
logger.debug { "Illegal state change [#{name}]: :#{transition.from} -> :#{transition.event}" }
|
33
37
|
end
|
34
38
|
|
35
|
-
event :
|
36
|
-
transition [:null] => :
|
39
|
+
event :start do
|
40
|
+
transition [:null] => :checked
|
37
41
|
end
|
38
42
|
|
39
|
-
|
40
|
-
|
43
|
+
# I'm not terribly keen on this. On the one hand it means that the code
|
44
|
+
# for checking the existance of the agent is contained here on the other
|
45
|
+
# hand if the agent does not exist the state is checked which is not very
|
46
|
+
# indicative that a failure has occurred! It does work but not very nice.
|
47
|
+
# FIXME
|
48
|
+
|
49
|
+
event :check do
|
50
|
+
transition [:checked] => :starting
|
41
51
|
end
|
42
52
|
|
43
53
|
event :acknowledge_start do
|
@@ -49,7 +59,11 @@ module Smith
|
|
49
59
|
end
|
50
60
|
|
51
61
|
event :acknowledge_stop do
|
52
|
-
transition [:stopping] => :
|
62
|
+
transition [:stopping] => :null
|
63
|
+
end
|
64
|
+
|
65
|
+
event :null do
|
66
|
+
transition [:check, :stopped] => :null
|
53
67
|
end
|
54
68
|
|
55
69
|
event :no_process_running do
|
@@ -65,13 +79,25 @@ module Smith
|
|
65
79
|
end
|
66
80
|
end
|
67
81
|
|
82
|
+
def started_at
|
83
|
+
Time.at(@agent_state.started_at)
|
84
|
+
end
|
85
|
+
|
86
|
+
def started_at=(time)
|
87
|
+
@agent_state.started_at = time.to_i
|
88
|
+
end
|
89
|
+
|
68
90
|
def add_callback(state, &blk)
|
69
91
|
AgentProcess.state_machine do
|
70
|
-
puts "changing callback"
|
92
|
+
puts "changing callback: :on => #{state}, :do => #{blk}"
|
71
93
|
after_transition :on => state, :do => blk
|
72
94
|
end
|
73
95
|
end
|
74
96
|
|
97
|
+
def delete
|
98
|
+
@db.delete(@agent_state.uuid)
|
99
|
+
end
|
100
|
+
|
75
101
|
# Check to see if the agent is alive.
|
76
102
|
def alive?
|
77
103
|
if self.pid
|
@@ -87,24 +113,64 @@ module Smith
|
|
87
113
|
end
|
88
114
|
|
89
115
|
# Return the agent control queue.
|
90
|
-
def
|
91
|
-
|
116
|
+
def control_queue_def
|
117
|
+
QueueDefinitions::Agent_control.call(uuid)
|
118
|
+
end
|
119
|
+
|
120
|
+
def initialize(db, attributes={})
|
121
|
+
@db = db
|
122
|
+
if attributes.is_a?(String)
|
123
|
+
@agent_state = AgentState.new.parse_from_string(attributes)
|
124
|
+
else
|
125
|
+
raise ArgumentError, "missing uuid option" if attributes[:uuid].nil?
|
126
|
+
attr = attributes.merge(:_state => 'null')
|
127
|
+
@agent_state = AgentState.new(attr)
|
128
|
+
end
|
129
|
+
|
130
|
+
super()
|
131
|
+
end
|
132
|
+
|
133
|
+
def exists?
|
134
|
+
Smith.agent_paths.detect do |path|
|
135
|
+
Pathname.new(path).join("#{name.snake_case}.rb").exist?
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def to_s
|
140
|
+
@agent_state.to_hash.tap do |h|
|
141
|
+
h[:state] = h.delete(:_state)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
private
|
146
|
+
|
147
|
+
def _state
|
148
|
+
@agent_state._state || "null"
|
149
|
+
end
|
150
|
+
|
151
|
+
def save
|
152
|
+
@agent_state._state = state
|
153
|
+
# TODO This *must* change to uuid when I've worked out how to manage them.
|
154
|
+
@db[uuid] = @agent_state.to_s
|
92
155
|
end
|
93
156
|
end
|
94
157
|
|
95
|
-
|
158
|
+
module AgentProcessObserver
|
96
159
|
|
97
160
|
include Logger
|
98
|
-
include DataMapper::Observer
|
99
161
|
|
100
|
-
|
162
|
+
def self.start(agent_process)
|
163
|
+
if agent_process.exists?
|
164
|
+
agent_process.check
|
165
|
+
else
|
166
|
+
agent_process.delete
|
167
|
+
end
|
168
|
+
end
|
101
169
|
|
102
170
|
# Start an agent. This forks and execs the bootstrapper class
|
103
171
|
# which then becomes responsible for managing the agent process.
|
104
|
-
def self.
|
105
|
-
|
106
|
-
agent_process.pid = fork do
|
107
|
-
|
172
|
+
def self.start_process(agent_process)
|
173
|
+
fork do
|
108
174
|
# Detach from the controlling terminal
|
109
175
|
unless Process.setsid
|
110
176
|
raise 'Cannot detach from controlling terminal'
|
@@ -113,7 +179,7 @@ module Smith
|
|
113
179
|
# Close all file descriptors apart from stdin, stdout, stderr
|
114
180
|
ObjectSpace.each_object(IO) do |io|
|
115
181
|
unless [STDIN, STDOUT, STDERR].include?(io)
|
116
|
-
io.close
|
182
|
+
io.close unless io.closed?
|
117
183
|
end
|
118
184
|
end
|
119
185
|
|
@@ -122,23 +188,26 @@ module Smith
|
|
122
188
|
STDIN.reopen("/dev/null")
|
123
189
|
STDERR.reopen(STDOUT)
|
124
190
|
|
125
|
-
bootstrapper =
|
191
|
+
bootstrapper = Pathname.new(__FILE__).dirname.join('bootstrap.rb').expand_path
|
126
192
|
|
127
|
-
|
193
|
+
binary = Smith.config.ruby[agent_process.name]
|
194
|
+
logger.debug { "Launching #{agent_process.name} with: #{binary}" }
|
195
|
+
exec(binary, bootstrapper.to_s, agent_process.name, agent_process.uuid)
|
128
196
|
end
|
129
197
|
|
130
198
|
# We don't want any zombies.
|
131
199
|
Process.detach(agent_process.pid)
|
132
200
|
end
|
133
201
|
|
134
|
-
def self.acknowledge_start(agent_process)
|
202
|
+
def self.acknowledge_start(agent_process, &blk)
|
203
|
+
logger.info { "Agent started: #{agent_process.uuid}" }
|
135
204
|
end
|
136
205
|
|
137
206
|
def self.stop(agent_process)
|
138
|
-
Messaging::Sender.new(agent_process.
|
207
|
+
Messaging::Sender.new(agent_process.control_queue_def) do |sender|
|
139
208
|
sender.consumer_count do |count|
|
140
209
|
if count > 0
|
141
|
-
sender.publish(ACL::
|
210
|
+
sender.publish(ACL::AgentCommand.new(:command => 'stop'))
|
142
211
|
else
|
143
212
|
logger.warn { "Agent is not listening. Setting state to dead." }
|
144
213
|
agent_process.no_process_running
|
@@ -147,21 +216,35 @@ module Smith
|
|
147
216
|
end
|
148
217
|
end
|
149
218
|
|
219
|
+
def self.no_process_running(agent_process)
|
220
|
+
agent_process.delete
|
221
|
+
end
|
222
|
+
|
223
|
+
|
150
224
|
def self.acknowledge_stop(agent_process)
|
151
|
-
|
225
|
+
agent_process.delete
|
226
|
+
logger.info { "Agent stopped: #{agent_process.uuid}" }
|
152
227
|
end
|
153
228
|
|
229
|
+
# This needs to use the PID class to verify if an agent is still running.
|
230
|
+
# FIXME
|
154
231
|
def self.kill(agent_process)
|
155
232
|
if agent_process.pid
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
logger.
|
233
|
+
if agent_process.pid == 0
|
234
|
+
logger.info { "Agent's pid is 0. The agent probably didn't start correctly. Cleaning up." }
|
235
|
+
agent_process.delete
|
236
|
+
else
|
237
|
+
logger.info { "Sending kill signal: #{agent_process.pid}: #{agent_process.uuid}" }
|
238
|
+
begin
|
239
|
+
Process.kill('TERM', agent_process.pid)
|
240
|
+
rescue
|
241
|
+
logger.error { "Process does not exist. PID is stale: #{agent_process.pid}: #{agent_process.uuid}" }
|
242
|
+
end
|
161
243
|
end
|
162
244
|
else
|
163
|
-
logger.error { "Not sending kill signal, agent pid is not set: #{agent_process.
|
245
|
+
logger.error { "Not sending kill signal, agent pid is not set: #{agent_process.uuid}" }
|
164
246
|
end
|
247
|
+
agent_process.delete
|
165
248
|
end
|
166
249
|
|
167
250
|
# If an agent is in an unknown state then this will check to see
|
@@ -170,19 +253,31 @@ module Smith
|
|
170
253
|
# quite worked out what I'm going to do with it so I'll leave it
|
171
254
|
# as is
|
172
255
|
def self.reap_agent(agent_process)
|
173
|
-
logger.info { "Reaping agent: #{agent_process.
|
256
|
+
logger.info { "Reaping agent: #{agent_process.uuid}" }
|
174
257
|
if Pathname.new('/proc').join(agent_process.pid.to_s).exist?
|
175
|
-
logger.warn { "Agent is still alive: #{agent_process.
|
258
|
+
logger.warn { "Agent is still alive: #{agent_process.uuid}" }
|
176
259
|
else
|
177
|
-
logger.warn { "Agent is already dead: #{agent_process.
|
260
|
+
logger.warn { "Agent is already dead: #{agent_process.uuid}" }
|
178
261
|
end
|
179
262
|
end
|
180
263
|
end
|
181
264
|
|
182
|
-
|
265
|
+
module LoggeMethods
|
266
|
+
include Logger
|
267
|
+
end
|
268
|
+
|
269
|
+
AgentProcess.state_machine do |state_machine|
|
270
|
+
# Make sure the state machine gets a logger.
|
271
|
+
# This doesn't work with JRuby.
|
272
|
+
state_machine.extend LoggeMethods
|
273
|
+
|
183
274
|
after_transition :on => :start, :do => AgentProcessObserver.method(:start)
|
275
|
+
after_transition :on => :check, :do => AgentProcessObserver.method(:start_process)
|
184
276
|
after_transition :on => :stop, :do => AgentProcessObserver.method(:stop)
|
185
277
|
after_transition :on => :kill, :do => AgentProcessObserver.method(:kill)
|
186
278
|
after_transition :on => :not_responding, :do => AgentProcessObserver.method(:reap_agent)
|
279
|
+
after_transition :on => :acknowledge_start, :do => AgentProcessObserver.method(:acknowledge_start)
|
280
|
+
after_transition :on => :acknowledge_stop, :do => AgentProcessObserver.method(:acknowledge_stop)
|
281
|
+
after_transition :on => :no_process_running, :do => AgentProcessObserver.method(:no_process_running)
|
187
282
|
end
|
188
283
|
end
|
@@ -1,5 +1,10 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
2
|
+
|
3
|
+
require 'daemons/pidfile'
|
4
|
+
|
5
|
+
require 'smith/agent_process'
|
6
|
+
require 'smith/agent_monitoring'
|
7
|
+
require 'smith/command'
|
3
8
|
|
4
9
|
module Smith
|
5
10
|
class Agency
|
@@ -9,19 +14,17 @@ module Smith
|
|
9
14
|
attr_reader :agents, :agent_processes
|
10
15
|
|
11
16
|
def initialize(opts={})
|
12
|
-
|
13
|
-
|
14
|
-
@agent_processes = AgentCache.new(:paths => opts.delete(:paths))
|
17
|
+
@agent_processes = AgentCache.new
|
15
18
|
end
|
16
19
|
|
17
20
|
def setup_queues
|
18
|
-
Messaging::Receiver.new(QueueDefinitions::Agency_control) do |receiver|
|
21
|
+
Messaging::Receiver.new(QueueDefinitions::Agency_control, :auto_ack => false) do |receiver|
|
19
22
|
receiver.subscribe do |payload, responder|
|
20
23
|
|
21
24
|
completion = EM::Completion.new.tap do |c|
|
22
25
|
c.completion do |value|
|
23
|
-
|
24
|
-
responder.reply(Smith::ACL::
|
26
|
+
responder.ack
|
27
|
+
responder.reply(Smith::ACL::AgencyCommandResponse.new(:response => value))
|
25
28
|
end
|
26
29
|
end
|
27
30
|
|
@@ -35,12 +38,12 @@ module Smith
|
|
35
38
|
|
36
39
|
Messaging::Receiver.new(QueueDefinitions::Agent_lifecycle) do |receiver|
|
37
40
|
receiver.subscribe do |payload, r|
|
38
|
-
case payload
|
39
|
-
when
|
41
|
+
case payload
|
42
|
+
when Smith::ACL::AgentDead
|
40
43
|
dead(payload)
|
41
|
-
when
|
44
|
+
when Smith::ACL::AgentAcknowledgeStart
|
42
45
|
acknowledge_start(payload)
|
43
|
-
when
|
46
|
+
when Smith::ACL::AgentAcknowledgeStop
|
44
47
|
acknowledge_stop(payload)
|
45
48
|
else
|
46
49
|
logger.warn { "Unknown command received on #{QueueDefinitions::Agent_lifecycle.name} queue: #{payload.state}" }
|
@@ -56,8 +59,8 @@ module Smith
|
|
56
59
|
end
|
57
60
|
|
58
61
|
def start_monitoring
|
59
|
-
@agent_monitor = AgentMonitoring.new(@agent_processes)
|
60
|
-
@agent_monitor.start_monitoring
|
62
|
+
# @agent_monitor = AgentMonitoring.new(@agent_processes)
|
63
|
+
# @agent_monitor.start_monitoring
|
61
64
|
end
|
62
65
|
|
63
66
|
# Stop the agency. This will wait for one second to ensure
|
@@ -73,61 +76,48 @@ module Smith
|
|
73
76
|
private
|
74
77
|
|
75
78
|
def acknowledge_start(agent_data)
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
logger.error { "Agent reports different pid during acknowledge_start: #{agent_data.name}" }
|
84
|
-
end
|
79
|
+
agent_exists?(agent_data.uuid) do |agent_process|
|
80
|
+
agent_process.pid = agent_data.pid
|
81
|
+
agent_process.started_at = agent_data.started_at
|
82
|
+
agent_process.singleton = agent_data.singleton
|
83
|
+
agent_process.monitor = agent_data.monitor
|
84
|
+
agent_process.metadata = agent_data.metadata
|
85
|
+
agent_process.acknowledge_start
|
85
86
|
end
|
86
87
|
end
|
87
88
|
|
88
89
|
def acknowledge_stop(agent_data)
|
89
|
-
|
90
|
-
|
91
|
-
agent_process.pid = nil
|
92
|
-
agent_process.monitor = nil
|
93
|
-
agent_process.singleton = nil
|
94
|
-
agent_process.started_at = nil
|
95
|
-
agent_process.last_keep_alive = nil
|
96
|
-
agent_process.acknowledge_stop
|
97
|
-
else
|
98
|
-
if agent_process.pid
|
99
|
-
logger.error { "Agent reports different pid during acknowledge_stop: #{agent_data.name}" }
|
100
|
-
end
|
101
|
-
end
|
90
|
+
agent_exists?(agent_data.uuid) do |agent_process|
|
91
|
+
agent_process.acknowledge_stop
|
102
92
|
end
|
103
93
|
end
|
104
94
|
|
105
95
|
def dead(agent_data)
|
106
|
-
|
107
|
-
|
96
|
+
agent_exists?(agent_data.uuid, ->{}) do |agent_process|
|
97
|
+
if agent_process.no_process_running
|
98
|
+
logger.fatal { "Agent is dead: #{agent_data.uuid}" }
|
99
|
+
end
|
100
|
+
end
|
108
101
|
end
|
109
102
|
|
110
103
|
def keep_alive(agent_data)
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
agent_process.save
|
119
|
-
else
|
120
|
-
if agent_process.pid
|
121
|
-
logger.error { "Agent reports different pid during acknowledge_stop: #{agent_data.name}" }
|
122
|
-
end
|
123
|
-
end
|
104
|
+
agent_exists?(agent_data.uuid) do |agent_process|
|
105
|
+
agent_process.last_keep_alive = agent_data.time
|
106
|
+
logger.verbose { "Agent keep alive: #{agent_data.uuid}: #{agent_data.time}" }
|
107
|
+
|
108
|
+
# We need to call save explicitly here as the keep alive is not part of
|
109
|
+
# the state_machine which is the thing that writes the state to disc.
|
110
|
+
agent_process.save
|
124
111
|
end
|
125
112
|
end
|
126
113
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
114
|
+
def agent_exists?(uuid, error_proc=nil, &blk)
|
115
|
+
agent = @agent_processes[uuid]
|
116
|
+
if agent
|
117
|
+
blk.call(agent)
|
118
|
+
else
|
119
|
+
error_proc.call
|
120
|
+
end
|
131
121
|
end
|
132
122
|
end
|
133
123
|
end
|
data/lib/smith/bootstrap.rb
CHANGED
@@ -3,7 +3,8 @@
|
|
3
3
|
# This should never be run directly it should only ever be run by
|
4
4
|
# the agency.
|
5
5
|
|
6
|
-
|
6
|
+
require 'pathname'
|
7
|
+
$:.unshift(Pathname.new(__FILE__).dirname.parent.expand_path)
|
7
8
|
|
8
9
|
require 'smith'
|
9
10
|
require 'smith/agent'
|
@@ -15,31 +16,44 @@ module Smith
|
|
15
16
|
|
16
17
|
include Logger
|
17
18
|
|
18
|
-
def initialize(
|
19
|
+
def initialize(name, uuid)
|
20
|
+
Dir.chdir('/')
|
21
|
+
|
19
22
|
# FIXME
|
20
23
|
# This doesn't do what I think it should. If an exception is
|
21
24
|
# thrown in setup_control_queue, for example, it just kills
|
22
25
|
# the agent without it actually raising the exception.
|
23
26
|
Thread.abort_on_exception = true
|
24
|
-
@agent_name =
|
25
|
-
@
|
27
|
+
@agent_name = name
|
28
|
+
@agent_uuid = uuid
|
29
|
+
@agent_filename = agent_path(name)
|
26
30
|
end
|
27
31
|
|
28
32
|
def signal_handlers
|
29
33
|
logger.debug { "Installing default signal handlers" }
|
30
34
|
%w{TERM INT QUIT}.each do |sig|
|
31
35
|
@agent.install_signal_handler(sig) do |sig|
|
32
|
-
logger.error { "Agent received: signal #{sig}: #{agent.name}" }
|
36
|
+
logger.error { "Agent received: signal #{sig}: #{agent.name} (#{agent.uuid})" }
|
33
37
|
terminate!
|
34
38
|
end
|
35
39
|
end
|
36
40
|
end
|
37
41
|
|
38
42
|
def load_agent
|
43
|
+
@agent_filename = agent_path(@agent_name)
|
39
44
|
logger.debug { "Loading #{@agent_name} from: #{@agent_filename.dirname}" }
|
40
45
|
add_agent_load_path
|
41
46
|
load @agent_filename
|
42
|
-
@agent = Kernel.const_get(@agent_name).new
|
47
|
+
@agent = Kernel.const_get(@agent_name).new(@agent_uuid)
|
48
|
+
end
|
49
|
+
|
50
|
+
def agent_path(name)
|
51
|
+
file_name = "#{name.snake_case}.rb"
|
52
|
+
Smith.agent_paths.each do |path|
|
53
|
+
p = Pathname.new(path).join(file_name)
|
54
|
+
return p if p.exist?
|
55
|
+
end
|
56
|
+
return nil
|
43
57
|
end
|
44
58
|
|
45
59
|
def start!
|
@@ -53,7 +67,7 @@ module Smith
|
|
53
67
|
# See the note at the in main.
|
54
68
|
def terminate!(exception=nil)
|
55
69
|
logger.error { format_exception(exception) } if exception
|
56
|
-
logger.error { "Terminating: #{@
|
70
|
+
logger.error { "Terminating: #{@agent_uuid}." }
|
57
71
|
|
58
72
|
if Smith.running?
|
59
73
|
send_dead_message
|
@@ -78,14 +92,14 @@ module Smith
|
|
78
92
|
private
|
79
93
|
|
80
94
|
def write_pid_file
|
81
|
-
@pid = Daemons::PidFile.new(Daemons::Pid.dir(:normal, Dir::tmpdir, nil), ".rubymas-#{@
|
95
|
+
@pid = Daemons::PidFile.new(Daemons::Pid.dir(:normal, Dir::tmpdir, nil), ".rubymas-#{@agent_uuid.snake_case}", true)
|
82
96
|
@pid.pid = Process.pid
|
83
97
|
end
|
84
98
|
|
85
99
|
def send_dead_message
|
86
|
-
logger.debug { "Sending dead message to agency: #{@agent_name}" }
|
100
|
+
logger.debug { "Sending dead message to agency: #{@agent_name} (#{@agent_uuid})" }
|
87
101
|
Messaging::Sender.new(QueueDefinitions::Agent_lifecycle) do |sender|
|
88
|
-
sender.publish(ACL::
|
102
|
+
sender.publish(ACL::AgentDead.new(:uuid => @agent_uuid))
|
89
103
|
end
|
90
104
|
end
|
91
105
|
|
@@ -124,18 +138,18 @@ module Smith
|
|
124
138
|
end
|
125
139
|
end
|
126
140
|
|
127
|
-
|
128
|
-
|
141
|
+
name = ARGV[0]
|
142
|
+
uuid = ARGV[1]
|
129
143
|
|
130
|
-
exit 1 if
|
144
|
+
exit 1 if name.nil? || uuid.nil?
|
131
145
|
|
132
146
|
# Set the running instance name to the name of the agent.
|
133
|
-
$0 = "#{
|
147
|
+
$0 = "#{name}"
|
134
148
|
|
135
|
-
#
|
136
|
-
Smith.
|
149
|
+
# Compile acls
|
150
|
+
Smith.compile_acls
|
137
151
|
|
138
|
-
bootstrapper = Smith::AgentBootstrap.new(
|
152
|
+
bootstrapper = Smith::AgentBootstrap.new(name, uuid)
|
139
153
|
|
140
154
|
# I've tried putting the exception handling in the main reactor log
|
141
155
|
# but it doesn't do anything. I know there's a reason for this but I
|
data/lib/smith/cache.rb
CHANGED
data/lib/smith/command.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
|
3
3
|
require 'trollop'
|
4
|
+
require 'smith/command_base'
|
4
5
|
|
5
6
|
module Smith
|
6
7
|
class Command
|
@@ -21,10 +22,7 @@ module Smith
|
|
21
22
|
|
22
23
|
clazz = Commands.const_get(Extlib::Inflection.camelize(command)).new
|
23
24
|
|
24
|
-
logger.debug { "#{(Command.agency?) ? 'Agency' : 'Smithctl'} command: #{command}#{(args.empty?) ? '' : " #{args.join(', ')}"}." }
|
25
|
-
|
26
25
|
begin
|
27
|
-
|
28
26
|
clazz.parse_options(args)
|
29
27
|
|
30
28
|
vars.each do |k,v|
|
@@ -3,18 +3,35 @@ module Smith
|
|
3
3
|
module Commands
|
4
4
|
class Kill < CommandBase
|
5
5
|
def execute
|
6
|
-
work = ->(
|
7
|
-
agents
|
8
|
-
|
6
|
+
work = ->(acc, uuid, iter) do
|
7
|
+
if agents.exist?(uuid)
|
8
|
+
agents[uuid].kill
|
9
|
+
else
|
10
|
+
acc << uuid
|
11
|
+
end
|
12
|
+
|
13
|
+
iter.return(acc)
|
9
14
|
end
|
10
15
|
|
11
|
-
done = -> { responder.succeed(
|
16
|
+
done = ->(errors) { responder.succeed(format_error_message(errors)) }
|
12
17
|
|
13
|
-
EM::Iterator.new(target).
|
18
|
+
EM::Iterator.new(target).inject([], work, done)
|
14
19
|
end
|
15
20
|
|
16
21
|
private
|
17
22
|
|
23
|
+
def format_error_message(errors)
|
24
|
+
errors = errors.compact
|
25
|
+
case errors.size
|
26
|
+
when 0
|
27
|
+
''
|
28
|
+
when 1
|
29
|
+
"Agent does not exist: #{errors.first}"
|
30
|
+
else
|
31
|
+
"Agents do not exist: #{errors.join(", ")}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
18
35
|
def options_spec
|
19
36
|
banner "Kill an agent/agents."
|
20
37
|
end
|
@@ -3,7 +3,12 @@ module Smith
|
|
3
3
|
module Commands
|
4
4
|
class List < CommandBase
|
5
5
|
def execute
|
6
|
-
|
6
|
+
if target.size > 0
|
7
|
+
selected_agents = agents.find_by_name(target)
|
8
|
+
else
|
9
|
+
selected_agents = (options[:all]) ? agents.to_a : agents.state(:running)
|
10
|
+
end
|
11
|
+
|
7
12
|
responder.succeed((selected_agents.empty?) ? '' : format(selected_agents, options[:long]))
|
8
13
|
end
|
9
14
|
|
@@ -22,16 +27,16 @@ module Smith
|
|
22
27
|
|
23
28
|
def long_format(a)
|
24
29
|
a.map do |a|
|
25
|
-
[a.state, a.pid, (a.started_at) ? format_time(a.started_at) : '', (!(a.stopped? || a.null?) && !a.alive?) ? '(agent dead)' : "", a.name]
|
30
|
+
[a.state, a.uuid, a.pid, (a.started_at) ? format_time(a.started_at) : '', (!(a.stopped? || a.null?) && !a.alive?) ? '(agent dead)' : "", a.name]
|
26
31
|
end
|
27
32
|
end
|
28
33
|
|
29
34
|
def short_format(a, sep=' ')
|
30
|
-
a.map
|
35
|
+
a.map { |a| [a.uuid] }.join(sep)
|
31
36
|
end
|
32
37
|
|
33
38
|
def format_time(t)
|
34
|
-
(t) ?
|
39
|
+
(t) ? t.strftime("%Y/%m/%d %H:%M:%S") : ''
|
35
40
|
end
|
36
41
|
|
37
42
|
def tabulate(a, opts={})
|