smith 0.5.12 → 0.5.13.1
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/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
|