smith 0.5.12 → 0.5.13.1
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/smithctl +16 -19
- data/lib/smith.rb +25 -41
- data/lib/smith/agent.rb +96 -66
- data/lib/smith/agent_monitoring.rb +3 -4
- data/lib/smith/agent_process.rb +16 -9
- data/lib/smith/amqp_errors.rb +53 -0
- data/lib/smith/application/agency.rb +23 -20
- data/lib/smith/bootstrap.rb +3 -3
- data/lib/smith/command.rb +2 -2
- data/lib/smith/command_base.rb +4 -0
- data/lib/smith/commands/agency/agents.rb +19 -19
- data/lib/smith/commands/agency/kill.rb +6 -2
- data/lib/smith/commands/agency/list.rb +2 -4
- data/lib/smith/commands/agency/logger.rb +27 -28
- data/lib/smith/commands/agency/metadata.rb +1 -5
- data/lib/smith/commands/agency/object_count.rb +13 -11
- data/lib/smith/commands/agency/restart.rb +18 -9
- data/lib/smith/commands/agency/start.rb +34 -25
- data/lib/smith/commands/agency/stop.rb +58 -41
- data/lib/smith/commands/agency/version.rb +10 -10
- data/lib/smith/commands/common.rb +7 -4
- data/lib/smith/commands/smithctl/acl.rb +46 -37
- data/lib/smith/commands/smithctl/commands.rb +1 -1
- data/lib/smith/commands/smithctl/firehose.rb +30 -0
- data/lib/smith/commands/smithctl/pop.rb +39 -32
- data/lib/smith/commands/smithctl/push.rb +70 -51
- data/lib/smith/commands/smithctl/rm.rb +32 -9
- data/lib/smith/commands/smithctl/subscribe.rb +36 -0
- data/lib/smith/commands/smithctl/top.rb +1 -1
- data/lib/smith/exceptions.rb +2 -0
- data/lib/smith/messaging/acl/agency_command.proto +4 -0
- data/lib/smith/messaging/acl/default.rb +8 -1
- data/lib/smith/messaging/amqp_options.rb +2 -2
- data/lib/smith/messaging/message_counter.rb +21 -0
- data/lib/smith/messaging/payload.rb +47 -49
- data/lib/smith/messaging/queue.rb +50 -0
- data/lib/smith/messaging/queue_definition.rb +18 -0
- data/lib/smith/messaging/queue_factory.rb +20 -29
- data/lib/smith/messaging/receiver.rb +211 -173
- data/lib/smith/messaging/requeue.rb +91 -0
- data/lib/smith/messaging/sender.rb +184 -28
- data/lib/smith/messaging/util.rb +72 -0
- data/lib/smith/queue_definitions.rb +11 -0
- data/lib/smith/version.rb +1 -1
- metadata +18 -10
- data/lib/smith/messaging/endpoint.rb +0 -116
@@ -9,7 +9,12 @@ module Smith
|
|
9
9
|
include Common
|
10
10
|
|
11
11
|
def execute
|
12
|
+
start do |value|
|
13
|
+
responder.succeed(value)
|
14
|
+
end
|
15
|
+
end
|
12
16
|
|
17
|
+
def start(&blk)
|
13
18
|
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
14
19
|
#!!!!!!!!!!!! See note about target at end of this file !!!!!!!!!!!!!!
|
15
20
|
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
@@ -20,41 +25,45 @@ module Smith
|
|
20
25
|
begin
|
21
26
|
agents_to_start = agent_group(options[:group])
|
22
27
|
if agents_to_start.empty?
|
23
|
-
|
24
|
-
|
28
|
+
blk.call("Agent group is empty. No agents started: #{options[:group]}")
|
29
|
+
else
|
30
|
+
start_agents(agents_to_start, &blk)
|
25
31
|
end
|
26
32
|
rescue RuntimeError => e
|
27
|
-
|
28
|
-
return
|
33
|
+
blk.call(e.message)
|
29
34
|
end
|
30
35
|
else
|
31
|
-
|
36
|
+
start_agents(target, &blk)
|
32
37
|
end
|
38
|
+
end
|
33
39
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
agents[
|
45
|
-
nil
|
46
|
-
else
|
47
|
-
"Unknown agent: #{agents[agent].name}".tap do |m|
|
48
|
-
logger.error { m }
|
49
|
-
end
|
40
|
+
private
|
41
|
+
|
42
|
+
def start_agents(agents_to_start, &blk)
|
43
|
+
if agents_to_start.empty?
|
44
|
+
blk.call("Start what? No agent specified.")
|
45
|
+
else
|
46
|
+
worker = ->(agent_name, iter) do
|
47
|
+
agents[agent_name].name = agent_name
|
48
|
+
if agents[agent_name].path
|
49
|
+
if options[:kill]
|
50
|
+
agents[agent_name].kill
|
50
51
|
end
|
51
|
-
|
52
|
+
agents[agent_name].start
|
53
|
+
iter.return(agent_name)
|
54
|
+
else
|
55
|
+
iter.return("Unknown agent: #{agents[agent_name].name}")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
done = ->(started_agents) do
|
60
|
+
blk.call(started_agents.compact.join("\n"))
|
52
61
|
end
|
62
|
+
|
63
|
+
EM::Iterator.new(agents_to_start).map(worker, done)
|
53
64
|
end
|
54
65
|
end
|
55
66
|
|
56
|
-
private
|
57
|
-
|
58
67
|
def options_spec
|
59
68
|
banner "Start an agent/agents or group of agents."
|
60
69
|
|
@@ -70,6 +79,6 @@ end
|
|
70
79
|
#
|
71
80
|
# Target is a method and if you assign something to it strange things happen --
|
72
81
|
# even if the code doesn't get run! I'm not strictly sure what's going on but I
|
73
|
-
# think it's something to do with
|
82
|
+
# think it's something to do with variable aliasing a method of the same
|
74
83
|
# name. So even though the code isn't being run it gets compiled and that
|
75
84
|
# somehow aliases the method. This looks like a bug in yarv to me.
|
@@ -9,65 +9,82 @@ module Smith
|
|
9
9
|
include Common
|
10
10
|
|
11
11
|
def execute
|
12
|
+
if target.first == 'agency' || target.first == 'all'
|
13
|
+
send("stop_#{target.first}") { |ret| responder.succeed(ret) }
|
14
|
+
else
|
15
|
+
stop_agent { |ret| responder.succeed(ret) }
|
16
|
+
end
|
17
|
+
end
|
12
18
|
|
13
|
-
|
14
|
-
#!!!!!!!!!!!! See note about target at end of this file !!!!!!!!!!!!!!
|
15
|
-
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
19
|
+
private
|
16
20
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
21
|
+
def stop_agency(&blk)
|
22
|
+
running_agents = agents.state(:running)
|
23
|
+
if running_agents.empty?
|
24
|
+
logger.info { "Agency shutting down." }
|
25
|
+
blk.call('')
|
26
|
+
Smith.stop
|
27
|
+
else
|
28
|
+
if options[:force]
|
29
|
+
blk.call('')
|
22
30
|
Smith.stop
|
23
|
-
responder.value
|
24
31
|
else
|
25
32
|
logger.warn { "Agents are still running: #{running_agents.map(&:name).join(", ")}." }
|
26
33
|
logger.info { "Agency not shutting down. Use force_stop if you really want to shut it down." }
|
27
|
-
|
34
|
+
blk.call("Not shutting down, agents are still running: #{running_agents.map(&:name).join(", ")}.")
|
28
35
|
end
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def stop_all(&blk)
|
40
|
+
agents.state(:running).each do |agent|
|
41
|
+
agent.stop
|
42
|
+
end
|
43
|
+
blk.call('')
|
44
|
+
end
|
45
|
+
|
46
|
+
def stop_agent(&blk)
|
47
|
+
|
48
|
+
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
49
|
+
#!!!!!!!!!!!! See note about target at end of this file !!!!!!!!!!!!!!
|
50
|
+
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
51
|
+
|
52
|
+
# Sort out any groups. If the group option is set it will override
|
53
|
+
# any other specified agents.
|
54
|
+
if options[:group]
|
55
|
+
begin
|
56
|
+
agents_to_stop = agent_group(options[:group])
|
57
|
+
if agents_to_stop.empty?
|
58
|
+
blk.call("There are no agents in group: #{options[:group]}")
|
47
59
|
end
|
48
|
-
|
49
|
-
|
60
|
+
rescue RuntimeError => e
|
61
|
+
return blk.call(e.message)
|
50
62
|
end
|
63
|
+
else
|
64
|
+
agents_to_stop = target
|
65
|
+
end
|
51
66
|
|
52
|
-
|
53
|
-
|
54
|
-
agents[agent_name].stop
|
55
|
-
nil
|
56
|
-
else
|
57
|
-
logger.warn { "Agent not running: #{agent_name}" }
|
58
|
-
agent_name
|
59
|
-
end
|
60
|
-
end
|
61
|
-
responder.value((ret.compact.empty?) ? nil : "Agent(s) not running: #{ret.compact.join(", ")}")
|
67
|
+
ret = agents_to_stop.inject([]) do |acc,agent_name|
|
68
|
+
acc << stop_if_running(agents[agent_name])
|
62
69
|
end
|
70
|
+
blk.call((ret.compact.empty?) ? '' : "Agent(s) not running: #{ret.compact.join(", ")}")
|
63
71
|
end
|
64
72
|
|
65
|
-
|
73
|
+
def stop_if_running(agent)
|
74
|
+
if agent.running?
|
75
|
+
agent.stop
|
76
|
+
nil
|
77
|
+
else
|
78
|
+
logger.warn { "Agent not running: #{agent.name}" }
|
79
|
+
agent.name
|
80
|
+
end
|
81
|
+
end
|
66
82
|
|
67
83
|
def options_spec
|
68
84
|
banner "Stop an agent/agents."
|
69
85
|
|
70
86
|
opt :group, "Stop everything in the specified group", :type => :string, :short => :g
|
87
|
+
opt :force, "If stopping the agency and there are agents running stop anyway"
|
71
88
|
end
|
72
89
|
end
|
73
90
|
end
|
@@ -3,19 +3,19 @@ module Smith
|
|
3
3
|
module Commands
|
4
4
|
class Version < CommandBase
|
5
5
|
def execute
|
6
|
-
|
6
|
+
version do |v|
|
7
|
+
responder.succeed(v)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def version(&blk)
|
7
12
|
if options[:git]
|
8
|
-
EM.system
|
9
|
-
|
10
|
-
|
11
|
-
output.strip
|
12
|
-
else
|
13
|
-
'The agency is not running in a git repo.'
|
14
|
-
end
|
15
|
-
end
|
13
|
+
# EM.system doesn't do any shell expansion so do it ourselves.
|
14
|
+
EM.system("sh -c 'git describe 2> /dev/null'") do |output,status|
|
15
|
+
blk.call((status.exitstatus == 0) ? output.strip : 'The agency is not running in a git repo.')
|
16
16
|
end
|
17
17
|
else
|
18
|
-
|
18
|
+
blk.call(Smith::VERSION)
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -3,15 +3,18 @@ module Smith
|
|
3
3
|
module Commands
|
4
4
|
module Common
|
5
5
|
def agent_group(group)
|
6
|
-
Smith.agent_paths.map do |path|
|
6
|
+
agents = Smith.agent_paths.map do |path|
|
7
7
|
group_dir = path.join(group)
|
8
8
|
if group_dir.exist? && group_dir.directory?
|
9
9
|
agents = Pathname.glob("#{path.join(group)}/*_agent.rb")
|
10
|
-
|
10
|
+
agents.map {|a| Extlib::Inflection.camelize(a.basename(".rb").to_s)}
|
11
11
|
else
|
12
|
-
|
12
|
+
nil
|
13
13
|
end
|
14
|
-
end
|
14
|
+
end.uniq
|
15
|
+
|
16
|
+
raise RuntimeError, "Group does not exist: #{group}" if agents == [nil]
|
17
|
+
agents.compact.flatten
|
15
18
|
end
|
16
19
|
end
|
17
20
|
end
|
@@ -6,52 +6,60 @@ module Smith
|
|
6
6
|
module Commands
|
7
7
|
class Acl < CommandBase
|
8
8
|
def execute
|
9
|
-
responder.
|
10
|
-
|
11
|
-
if target.empty?
|
12
|
-
"You must supply an ACL file name."
|
13
|
-
else
|
14
|
-
target.map do |acl|
|
15
|
-
acls = Smith.acl_path.inject([]) do |a,path|
|
16
|
-
a.tap do |acc|
|
17
|
-
acl_file = path.join("#{acl.snake_case}.proto")
|
18
|
-
if acl_file.exist?
|
19
|
-
acc << acl_file
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
9
|
+
responder.succeed(_acl)
|
10
|
+
end
|
23
11
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
12
|
+
def _acl
|
13
|
+
if options[:show]
|
14
|
+
if target.empty?
|
15
|
+
"You must supply an ACL file name."
|
16
|
+
else
|
17
|
+
target.map do |acl|
|
18
|
+
if options[:source_given]
|
19
|
+
acls = find_acl(Smith.acl_cache_path, acl, 'pb.rb')
|
20
|
+
else
|
21
|
+
acls = find_acl(Smith.acl_path, acl, 'proto')
|
22
|
+
end
|
23
|
+
|
24
|
+
case acls.length
|
25
|
+
when 0
|
26
|
+
"ACL file does not exist."
|
27
|
+
when 1
|
28
|
+
if target.length == 1
|
29
|
+
"\n#{indent_acl(acls.first.read)}\n"
|
33
30
|
else
|
34
|
-
"
|
31
|
+
"\n#{acl} ->\n#{indent_acl(acls.first.read)}"
|
35
32
|
end
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
""
|
41
|
-
elsif options[:compile_given]
|
42
|
-
Pathname.glob(Smith.compile_acls)
|
43
|
-
""
|
44
|
-
else
|
45
|
-
join_string = (options[:long]) ? "\n" : " "
|
46
|
-
Pathname.glob(Smith.acl_path.map {|p| "#{p}#{File::SEPARATOR}*"}).map do |p|
|
47
|
-
p.basename(".proto")
|
48
|
-
end.sort.join(join_string)
|
33
|
+
else
|
34
|
+
"There are multiple ACLs with the name: #{target}"
|
35
|
+
end
|
36
|
+
end.join("\n")
|
49
37
|
end
|
38
|
+
elsif options[:clean_given]
|
39
|
+
Pathname.glob(Smith.acl_cache_path.join("*.pb.rb")).each {|p| p.unlink}
|
40
|
+
""
|
41
|
+
elsif options[:compile_given]
|
42
|
+
Pathname.glob(Smith.compile_acls)
|
43
|
+
""
|
44
|
+
else
|
45
|
+
join_string = (options[:long]) ? "\n" : " "
|
46
|
+
Pathname.glob(Smith.acl_path.map {|p| "#{p}#{File::SEPARATOR}*"}).map do |p|
|
47
|
+
p.basename(".proto")
|
48
|
+
end.sort.join(join_string)
|
50
49
|
end
|
51
50
|
end
|
52
51
|
|
53
52
|
private
|
54
53
|
|
54
|
+
def find_acl(path, acl, ext)
|
55
|
+
[path].flatten.inject([]) do |a,path|
|
56
|
+
a.tap do |acc|
|
57
|
+
acl_file = path.join("#{acl.snake_case}.#{ext}")
|
58
|
+
acc << acl_file if acl_file.exist?
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
55
63
|
def indent_acl(acl)
|
56
64
|
acl.split("\n").map { |l| l.sub(/^/, " ") }.join("\n")
|
57
65
|
end
|
@@ -61,6 +69,7 @@ module Smith
|
|
61
69
|
|
62
70
|
opt :long, "format the listing", :short => :l
|
63
71
|
opt :show, "show the contents of the acl file", :short => :s
|
72
|
+
opt :source, "show the contents of the generated acl file", :depends => :show
|
64
73
|
opt :clean, "remove all compiled acls", :short => :none
|
65
74
|
opt :compile, "compile all acls", :short => :none
|
66
75
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module Smith
|
4
|
+
module Commands
|
5
|
+
class Firehose < CommandBase
|
6
|
+
def execute
|
7
|
+
queue_name = target.first
|
8
|
+
AMQP::Channel.new(Smith.connection) do |channel,ok|
|
9
|
+
channel.topic('amq.rabbitmq.trace', :durable => true) do |exchange|
|
10
|
+
channel.queue('smith.firehose', :durable => true) do |queue|
|
11
|
+
queue.bind(exchange, :routing_key => "publish.#{Smith.config.smith.namespace}.#{queue_name}").subscribe do |m,p|
|
12
|
+
message = ACL::Payload.decode(p, m.headers['properties']['type'])
|
13
|
+
puts (options[:json_given]) ? message.to_json : message.inspect
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def options_spec
|
21
|
+
b = ["Listens to the rabbitmq firehose for the named queue and prints decoded message to stdout.",
|
22
|
+
" Be warned it can produce vast amounts of outpu.\n",
|
23
|
+
" You _must_ run 'rabbitmqctl trace_on' for this to work."]
|
24
|
+
banner b.join("\n")
|
25
|
+
|
26
|
+
opt :json , "return the JSON representation of the message", :short => :j
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -1,60 +1,67 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
require 'yajl'
|
3
3
|
|
4
|
+
require 'smith/messaging/queue'
|
5
|
+
|
4
6
|
module Smith
|
5
7
|
module Commands
|
6
8
|
class Pop < CommandBase
|
7
9
|
def execute
|
10
|
+
pop
|
11
|
+
end
|
12
|
+
|
13
|
+
def pop
|
8
14
|
case target.size
|
9
15
|
when 0
|
10
|
-
|
16
|
+
"No queue specified. Please specify a queue."
|
11
17
|
when 1
|
12
18
|
|
13
19
|
queue = target.first
|
14
20
|
|
15
|
-
|
16
|
-
Smith.on_error do |ch,channel_close|
|
17
|
-
case channel_close.reply_code
|
18
|
-
when 404
|
19
|
-
responder.value("Queue does not exist: #{queue}")
|
20
|
-
else
|
21
|
-
responder.value("Unknown error: #{channel_close.reply_text}")
|
22
|
-
end
|
23
|
-
end
|
21
|
+
Messaging::Queue.number_of_messages(queue) do |queue_length|
|
24
22
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
if options[:remove]
|
30
|
-
r.ack
|
31
|
-
else
|
32
|
-
r.reject(:requeue => true)
|
33
|
-
end
|
23
|
+
# Number of messages on the queue.
|
24
|
+
number_to_remove = (options[:number] > queue_length) ? queue_length : options[:number]
|
25
|
+
|
26
|
+
Messaging::Receiver.new(queue, :auto_ack => false, :prefetch => number_to_remove, :passive => true) do |receiver|
|
34
27
|
|
35
|
-
|
36
|
-
|
28
|
+
receiver.on_error do |ch,channel_close|
|
29
|
+
case channel_close.reply_code
|
30
|
+
when 404
|
31
|
+
responder.succeed("Queue does not exist: #{queue}")
|
32
|
+
else
|
33
|
+
responder.succeed("Unknown error: #{channel_close.reply_text}")
|
34
|
+
end
|
35
|
+
end
|
37
36
|
|
37
|
+
worker = proc do |acc, n, iter|
|
38
|
+
receiver.pop do |payload,r|
|
39
|
+
if payload
|
40
|
+
acc[:result] << print_message(payload) if options[:print]
|
41
|
+
acc[:count] += 1
|
42
|
+
|
43
|
+
if n == number_to_remove - 1
|
44
|
+
if options[:remove]
|
45
|
+
r.ack(true)
|
46
|
+
else
|
47
|
+
r.reject(:requeue => true)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
38
51
|
iter.return(acc)
|
39
52
|
end
|
40
53
|
end
|
41
54
|
|
42
55
|
finished = proc do |acc|
|
43
|
-
|
44
|
-
|
45
|
-
acc[:result].join("\n")
|
46
|
-
end
|
56
|
+
logger.debug { "Removing #{acc[:count]} message from #{receiver.queue_name}" }
|
57
|
+
responder.succeed(acc[:result].join("\n"))
|
47
58
|
end
|
48
59
|
|
49
|
-
EM::Iterator.new(0
|
60
|
+
EM::Iterator.new(0...number_to_remove).inject({:count => 0, :result => [], :ack => nil}, worker, finished)
|
50
61
|
end
|
51
|
-
|
52
|
-
errback = proc {responder.value(nil)}
|
53
|
-
|
54
|
-
receiver.messages?(callback, errback)
|
55
62
|
end
|
56
63
|
else
|
57
|
-
|
64
|
+
"You can only specify one queue at a time"
|
58
65
|
end
|
59
66
|
end
|
60
67
|
|
@@ -62,7 +69,7 @@ module Smith
|
|
62
69
|
|
63
70
|
def print_message(message)
|
64
71
|
if options[:json]
|
65
|
-
message.
|
72
|
+
message.to_json
|
66
73
|
else
|
67
74
|
message.inspect
|
68
75
|
end
|