smith 0.6.12 → 0.7.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.
- checksums.yaml +4 -4
- data/config/smithrc.toml +62 -0
- data/lib/smith.rb +14 -29
- data/lib/smith/acl_compiler.rb +5 -5
- data/lib/smith/agent.rb +1 -1
- data/lib/smith/agent_cache.rb +9 -2
- data/lib/smith/agent_process.rb +2 -2
- data/lib/smith/bootstrap.rb +2 -1
- data/lib/smith/commands/agency/agents.rb +2 -2
- data/lib/smith/commands/agency/list.rb +11 -6
- data/lib/smith/commands/common.rb +1 -1
- data/lib/smith/commands/smithctl/acl.rb +7 -7
- data/lib/smith/config.rb +127 -121
- data/lib/smith/daemon.rb +6 -12
- data/lib/smith/messaging/receiver.rb +16 -1
- data/lib/smith/utils.rb +9 -2
- data/lib/smith/version.rb +1 -1
- metadata +17 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8f1a64e720f6d09734b66a3bf1f39b56ec81aed8
|
4
|
+
data.tar.gz: baafcf0aa8e1f048ea9ef250adc8475d8aa53408
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: afca0d267739a592b25876133fa70fd0f2f03f962e22a3a4af35efa67b28cb9b47068526142e707db7afa7a496734c8f396c8b884ec0d3295c1706a5f7ab7f94
|
7
|
+
data.tar.gz: 0365407a67ab65dc32d41bbf91b316db1dde05851f6191df1a49bfcba611246efc09291f06abba2286c499f60f0807c484226ec5314b6fc315d773b712279a41
|
data/config/smithrc.toml
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
[smith]
|
2
|
+
timeout = 8
|
3
|
+
namespace = "smith"
|
4
|
+
|
5
|
+
[agent]
|
6
|
+
monitor = false
|
7
|
+
singleton = true
|
8
|
+
metadata = ""
|
9
|
+
prefetch = 1
|
10
|
+
|
11
|
+
# Specify the VM that an agent should use.
|
12
|
+
[vm]
|
13
|
+
agent_default = "ruby"
|
14
|
+
|
15
|
+
[eventmachine]
|
16
|
+
epoll = true
|
17
|
+
kqueue = true
|
18
|
+
|
19
|
+
[agency]
|
20
|
+
# The the agency pid path. This can be overriden on the command line.
|
21
|
+
pid_directory = "~/.smith/run"
|
22
|
+
cache_directory = "~/.smith/cache"
|
23
|
+
|
24
|
+
# It would be better to use inline tables here but there is a bug in
|
25
|
+
# toml-rb: https://github.com/emancu/toml-rb/issues/57.
|
26
|
+
# TODO: Change these to inline tables when this bug is fixed.
|
27
|
+
[amqp.exchange]
|
28
|
+
durable = true
|
29
|
+
auto_delete = false
|
30
|
+
|
31
|
+
[amqp.queue]
|
32
|
+
durable = true
|
33
|
+
auto_delete = false
|
34
|
+
|
35
|
+
[amqp.pop]
|
36
|
+
ack = true
|
37
|
+
|
38
|
+
[amqp.publish.headers]
|
39
|
+
# headers = {}},
|
40
|
+
|
41
|
+
[amqp.subscribe]
|
42
|
+
ack = true
|
43
|
+
|
44
|
+
# Change according to your local broker.
|
45
|
+
[amqp.broker]
|
46
|
+
host = "localhost"
|
47
|
+
port = 5672
|
48
|
+
user = "guest"
|
49
|
+
password = "guest"
|
50
|
+
vhost = "/"
|
51
|
+
|
52
|
+
[logging]
|
53
|
+
trace = true
|
54
|
+
level = "debug"
|
55
|
+
|
56
|
+
# Log pattern. Note you need to escape backslashes.
|
57
|
+
default_pattern = "%d [%5p] %7l - %34c:%-3L - %m\n"
|
58
|
+
default_date_pattern = "%Y/%m/%d %H:%M:%S.%3N"
|
59
|
+
|
60
|
+
# This can be either: stderr, stdout, file, rollingfile or syslog
|
61
|
+
[logging.appender]
|
62
|
+
type = "stderr"
|
data/lib/smith.rb
CHANGED
@@ -1,9 +1,4 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
3
|
-
$LOAD_PATH.delete_if { |p| p.to_s =~ /eventmachine-\d/ }
|
4
|
-
|
5
|
-
require 'eventmachine-le'
|
6
|
-
|
7
2
|
require 'amqp'
|
8
3
|
require 'tmpdir'
|
9
4
|
require "socket"
|
@@ -17,9 +12,10 @@ require 'extlib/string'
|
|
17
12
|
require 'extlib/inflection'
|
18
13
|
require 'daemons/pidfile'
|
19
14
|
|
20
|
-
|
21
|
-
|
22
|
-
|
15
|
+
require 'smith/config'
|
16
|
+
require 'smith/utils'
|
17
|
+
require 'smith/logger'
|
18
|
+
require 'smith/acl_compiler'
|
23
19
|
|
24
20
|
MultiJson.use(:oj)
|
25
21
|
|
@@ -49,8 +45,8 @@ module Smith
|
|
49
45
|
Pathname.new(__FILE__).dirname.parent.expand_path
|
50
46
|
end
|
51
47
|
|
52
|
-
def
|
53
|
-
|
48
|
+
def agent_directories
|
49
|
+
config.agency.agent_directories
|
54
50
|
end
|
55
51
|
|
56
52
|
# Convenience method to get the hostname
|
@@ -58,17 +54,17 @@ module Smith
|
|
58
54
|
Socket.gethostname
|
59
55
|
end
|
60
56
|
|
61
|
-
def
|
62
|
-
|
57
|
+
def acl_directories
|
58
|
+
config.agency.acl_directories
|
63
59
|
end
|
64
60
|
|
65
|
-
def
|
66
|
-
|
61
|
+
def cache_directory
|
62
|
+
Utils.check_and_create_directory(config.agency.cache_directory)
|
67
63
|
end
|
68
64
|
|
69
65
|
# Return the acl cache path.
|
70
|
-
def
|
71
|
-
|
66
|
+
def acl_cache_directory
|
67
|
+
cache_directory.join('acl').tap do |path|
|
72
68
|
check_path(path, true)
|
73
69
|
end
|
74
70
|
end
|
@@ -94,8 +90,6 @@ module Smith
|
|
94
90
|
EM.kqueue
|
95
91
|
end
|
96
92
|
|
97
|
-
EM.set_descriptor_table_size(Smith.config.eventmachine.file_descriptors)
|
98
|
-
|
99
93
|
connection_settings = config.amqp.broker.merge(
|
100
94
|
:on_tcp_connection_failure => method(:tcp_connection_failure_handler),
|
101
95
|
:on_possible_authentication_failure => method(:authentication_failure_handler))
|
@@ -185,14 +179,6 @@ module Smith
|
|
185
179
|
EM.stop
|
186
180
|
end
|
187
181
|
|
188
|
-
def path_to_pathnames(path)
|
189
|
-
path ||= []
|
190
|
-
path.split(':').map do |path|
|
191
|
-
p = Pathname.new(path)
|
192
|
-
((p.absolute?) ? p : root_path.join(p)).tap { |path| check_path(path) }
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
182
|
def broker_identifier(connection)
|
197
183
|
broker = connection.broker.properties
|
198
184
|
"#{connection.broker_endpoint}, (#{broker['product']}/v#{broker['version']})"
|
@@ -202,10 +188,10 @@ module Smith
|
|
202
188
|
unless path.exist?
|
203
189
|
error_message = "Path does not exist: #{path}"
|
204
190
|
if create
|
205
|
-
logger.info { "
|
191
|
+
logger.info { "#{error_message}. Creating" }
|
206
192
|
path.mkpath
|
207
193
|
else
|
208
|
-
logger.warn {
|
194
|
+
logger.warn { error_message }
|
209
195
|
end
|
210
196
|
end
|
211
197
|
end
|
@@ -213,7 +199,6 @@ module Smith
|
|
213
199
|
end
|
214
200
|
end
|
215
201
|
|
216
|
-
require 'smith/utils'
|
217
202
|
require 'smith/self_pipe'
|
218
203
|
require 'smith/amqp_errors'
|
219
204
|
require 'smith/object_count'
|
data/lib/smith/acl_compiler.rb
CHANGED
@@ -15,9 +15,9 @@ module Smith
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def compile
|
18
|
-
$LOAD_PATH << Smith.
|
18
|
+
$LOAD_PATH << Smith.acl_cache_directory
|
19
19
|
|
20
|
-
Smith.
|
20
|
+
Smith.acl_directories.each do |path|
|
21
21
|
$LOAD_PATH << path
|
22
22
|
|
23
23
|
acl_files = path_glob(path)
|
@@ -41,7 +41,7 @@ module Smith
|
|
41
41
|
|
42
42
|
unless acls.empty?
|
43
43
|
Dir.chdir(path) do
|
44
|
-
cmd = %Q{sh -c 'protoc --ruby_out=#{Smith.
|
44
|
+
cmd = %Q{sh -c 'protoc --ruby_out=#{Smith.acl_cache_directory} -I #{path} #{out_of_date_acls.map(&:to_s).join(' ')} 2>&1'}
|
45
45
|
protoc = IO.popen(cmd)
|
46
46
|
output = protoc.read
|
47
47
|
protoc.close
|
@@ -62,7 +62,7 @@ module Smith
|
|
62
62
|
|
63
63
|
# Returns true if the .proto file is newer that the .pb.rb file
|
64
64
|
def should_compile?(file)
|
65
|
-
cached_file = Smith.
|
65
|
+
cached_file = Smith.acl_cache_directory.join(file.basename).sub_ext(".pb.rb")
|
66
66
|
if cached_file.exist?
|
67
67
|
file.mtime > cached_file.mtime
|
68
68
|
else
|
@@ -109,7 +109,7 @@ module Smith
|
|
109
109
|
end
|
110
110
|
|
111
111
|
def acl_compiled_path(path)
|
112
|
-
"#{Smith.
|
112
|
+
"#{Smith.acl_cache_directory.join(path.basename('.proto'))}.pb.rb"
|
113
113
|
end
|
114
114
|
end
|
115
115
|
end
|
data/lib/smith/agent.rb
CHANGED
data/lib/smith/agent_cache.rb
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'gdbm'
|
5
|
+
rescue LoadError => e
|
6
|
+
STDERR.puts "\nYou instance of ruby wasn't compiled with gdbm support.\nSee: https://github.com/filterfish/smith2/wiki/gdbm\n\n"
|
7
|
+
raise
|
8
|
+
end
|
9
|
+
|
3
10
|
require 'securerandom'
|
4
11
|
|
5
12
|
module Smith
|
@@ -10,7 +17,7 @@ module Smith
|
|
10
17
|
attr_accessor :path
|
11
18
|
|
12
19
|
def initialize(opts={})
|
13
|
-
@db = GDBM.new(Smith.
|
20
|
+
@db = GDBM.new(Smith.cache_directory.join('agent_state.gdbm').to_s, 0600, GDBM::WRCREAT | GDBM::SYNC)
|
14
21
|
end
|
15
22
|
|
16
23
|
def create(name)
|
data/lib/smith/agent_process.rb
CHANGED
@@ -133,7 +133,7 @@ module Smith
|
|
133
133
|
end
|
134
134
|
|
135
135
|
def exists?
|
136
|
-
|
136
|
+
agent_directories(name)
|
137
137
|
end
|
138
138
|
|
139
139
|
def to_s
|
@@ -190,7 +190,7 @@ module Smith
|
|
190
190
|
|
191
191
|
bootstrapper = Pathname.new(__FILE__).dirname.join('bootstrap.rb').expand_path
|
192
192
|
|
193
|
-
binary = Smith.config.
|
193
|
+
binary = Smith.config.vm[agent_process.name.snake_case.to_sym] || Smith.config.vm.agent_default
|
194
194
|
logger.debug { "Launching #{agent_process.name} with: #{binary}" }
|
195
195
|
exec(binary, bootstrapper.to_s, agent_process.name, agent_process.uuid)
|
196
196
|
end
|
data/lib/smith/bootstrap.rb
CHANGED
@@ -40,7 +40,7 @@ module Smith
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def load_agent
|
43
|
-
path =
|
43
|
+
path = agent_directories(@agent_name)
|
44
44
|
logger.debug { "Loading #{@agent_name} from: #{path.dirname}" }
|
45
45
|
add_agent_load_path(path)
|
46
46
|
load path
|
@@ -92,6 +92,7 @@ module Smith
|
|
92
92
|
|
93
93
|
private
|
94
94
|
|
95
|
+
# FIXME This really should be using Smith::Daemon
|
95
96
|
def write_pid_file
|
96
97
|
@pid = Daemons::PidFile.new(Daemons::Pid.dir(:normal, Dir::tmpdir, nil), ".smith-#{@agent_uuid}", true)
|
97
98
|
@pid.pid = Process.pid
|
@@ -10,10 +10,10 @@ module Smith
|
|
10
10
|
# FIXME make sure that if the path doesn't exist don't blow up.
|
11
11
|
separator = (options[:one_column]) ? "\n" : " "
|
12
12
|
|
13
|
-
Smith.
|
13
|
+
Smith.agent_directories.inject([]) do |path_acc, path|
|
14
14
|
path_acc.tap do |a|
|
15
15
|
if path.exist?
|
16
|
-
a << path.each_child.inject([]) do |agent_acc,p|
|
16
|
+
a << path.each_child.inject([]) do |agent_acc, p|
|
17
17
|
agent_acc.tap do |b|
|
18
18
|
b << Extlib::Inflection.camelize(p.basename('.rb')) if p.file? && p.basename('.rb').to_s.end_with?("agent")
|
19
19
|
end
|
@@ -29,8 +29,8 @@ module Smith
|
|
29
29
|
a = (target.empty?) ? a : a.select {|z| target.detect {|y| z.name == y } }.flatten
|
30
30
|
if options[:long_given]
|
31
31
|
tabulate(long_format(a), :header => "total #{a.count}")
|
32
|
-
elsif options[:
|
33
|
-
|
32
|
+
elsif options[:name_only]
|
33
|
+
name_only(a, "\n")
|
34
34
|
else
|
35
35
|
short_format(a)
|
36
36
|
end
|
@@ -46,6 +46,11 @@ module Smith
|
|
46
46
|
a.map { |a| [a.uuid] }.join(sep)
|
47
47
|
end
|
48
48
|
|
49
|
+
|
50
|
+
def name_only(a, sep=' ')
|
51
|
+
a.map { |a| [a.name] }.join(sep)
|
52
|
+
end
|
53
|
+
|
49
54
|
def format_time(t)
|
50
55
|
(t) ? t.strftime("%Y/%m/%d %H:%M:%S") : ''
|
51
56
|
end
|
@@ -61,12 +66,12 @@ module Smith
|
|
61
66
|
def options_spec
|
62
67
|
banner "List the running agents."
|
63
68
|
|
64
|
-
opt :long, "
|
69
|
+
opt :long, "shows full details of running agents", :short => :l
|
65
70
|
opt :group, "list only agents in this group", :type => :string, :short => :g
|
66
|
-
opt :
|
67
|
-
opt :all, "
|
71
|
+
opt :name_only, "list on the agents' name", :short => :n
|
72
|
+
opt :all, "list all agents in all states", :short => :a
|
68
73
|
|
69
|
-
conflicts :
|
74
|
+
conflicts :name_only, :long
|
70
75
|
end
|
71
76
|
end
|
72
77
|
end
|
@@ -3,7 +3,7 @@ module Smith
|
|
3
3
|
module Commands
|
4
4
|
module Common
|
5
5
|
def agent_group(group)
|
6
|
-
agents = Smith.
|
6
|
+
agents = Smith.agent_directories.map do |path|
|
7
7
|
group_dir = path.join(group)
|
8
8
|
if group_dir.exist? && group_dir.directory?
|
9
9
|
agents = Pathname.glob(group_dir.join("*_agent.rb"))
|
@@ -17,9 +17,9 @@ module Smith
|
|
17
17
|
else
|
18
18
|
target.map do |acl|
|
19
19
|
if options[:source_given]
|
20
|
-
acls = find_acl(Smith.
|
20
|
+
acls = find_acl(Smith.acl_cache_directory, acl, 'pb.rb')
|
21
21
|
else
|
22
|
-
acls = find_acl(Smith.
|
22
|
+
acls = find_acl(Smith.acl_directories, acl, 'proto')
|
23
23
|
end
|
24
24
|
|
25
25
|
case acls.length
|
@@ -37,7 +37,7 @@ module Smith
|
|
37
37
|
end.join("\n")
|
38
38
|
end
|
39
39
|
elsif options[:clean_given]
|
40
|
-
Pathname.glob(Smith.
|
40
|
+
Pathname.glob(Smith.acl_cache_directory.join("*.pb.rb")).each {|p| p.unlink}
|
41
41
|
""
|
42
42
|
elsif options[:compile_given]
|
43
43
|
Pathname.glob(Smith.compile_acls)
|
@@ -46,7 +46,7 @@ module Smith
|
|
46
46
|
join_string = (options[:long]) ? "\n" : " "
|
47
47
|
acl_type_cache.dump_types.keys.map(&:to_s).sort.join(join_string)
|
48
48
|
|
49
|
-
# Pathname.glob(Smith.
|
49
|
+
# Pathname.glob(Smith.acl_directories.map {|p| "#{p}#{File::SEPARATOR}*"}).map do |p|
|
50
50
|
# p.basename(".proto")
|
51
51
|
# end.sort.join(join_string)
|
52
52
|
end
|
@@ -54,10 +54,10 @@ module Smith
|
|
54
54
|
|
55
55
|
private
|
56
56
|
|
57
|
-
def find_acl(
|
58
|
-
[
|
57
|
+
def find_acl(directories, acl, ext)
|
58
|
+
[directories].flatten.inject([]) do |a, directory|
|
59
59
|
a.tap do |acc|
|
60
|
-
acl_file =
|
60
|
+
acl_file = directory.join("#{acl.snake_case}.#{ext}")
|
61
61
|
acc << acl_file if acl_file.exist?
|
62
62
|
end
|
63
63
|
end
|
data/lib/smith/config.rb
CHANGED
@@ -1,44 +1,22 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# -*- encoding: utf-8 -*-
|
3
3
|
|
4
|
+
require 'toml'
|
5
|
+
require 'fileutils'
|
4
6
|
require 'pathname'
|
7
|
+
require 'hashie/extensions/coercion'
|
8
|
+
require 'hashie/extensions/deep_merge'
|
9
|
+
require 'hashie/extensions/method_access'
|
10
|
+
require 'hashie/extensions/merge_initializer'
|
5
11
|
|
6
12
|
module Smith
|
7
13
|
|
8
14
|
class ConfigNotFoundError < IOError; end
|
15
|
+
class MissingConfigItemError < StandardError; end
|
9
16
|
|
10
17
|
class Config
|
11
18
|
|
12
|
-
CONFIG_FILENAME = '
|
13
|
-
|
14
|
-
attr_accessor :agent, :agency, :amqp, :logging, :smith, :eventmachine, :smith, :ruby
|
15
|
-
|
16
|
-
to_hash = proc do
|
17
|
-
def to_hash
|
18
|
-
Hash[*members.zip(values).flatten]
|
19
|
-
end
|
20
|
-
|
21
|
-
def merge(h)
|
22
|
-
to_hash.merge(h)
|
23
|
-
end
|
24
|
-
|
25
|
-
def has_key?(k)
|
26
|
-
to_hash.has_key?(k)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
Struct.new("Agent", :monitor, :singleton, :metadata, :prefetch, &to_hash)
|
31
|
-
Struct.new("Agency", :cache_path, :agent_path, :acl_path, :acl_cache_path, :pid_dir, &to_hash)
|
32
|
-
Struct.new("AmqpOpts", :durable, :auto_delete, &to_hash)
|
33
|
-
Struct.new("Broker", :host, :port, :user, :password, :vhost, &to_hash)
|
34
|
-
Struct.new("Subscribe", :ack, &to_hash)
|
35
|
-
Struct.new("Pop", :ack, &to_hash)
|
36
|
-
Struct.new("Publish", :headers, &to_hash)
|
37
|
-
Struct.new("Amqp", :broker, :exchange, :queue, :publish, :subscribe, :pop, &to_hash)
|
38
|
-
Struct.new("Appender", :type, :filename, &to_hash)
|
39
|
-
Struct.new("Logging", :trace, :level, :default_pattern, :default_date_pattern, :appender, :filetype, :vhost, &to_hash)
|
40
|
-
Struct.new("Smith", :namespace, :timeout, &to_hash)
|
41
|
-
Struct.new("Eventmachine", :file_descriptors, :epoll, :kqueue, &to_hash)
|
19
|
+
CONFIG_FILENAME = 'smithrc'
|
42
20
|
|
43
21
|
def initialize
|
44
22
|
load_config
|
@@ -48,123 +26,151 @@ module Smith
|
|
48
26
|
@config = Config.new
|
49
27
|
end
|
50
28
|
|
51
|
-
def to_hash
|
52
|
-
{:agent => @agent, :agency => @agency, :amqp => @amqp, :eventmachine => @eventmachine, :logging => @logging, :smith => @smith, :ruby => @ruby}
|
53
|
-
end
|
54
|
-
|
55
29
|
def path
|
56
30
|
@config_file
|
57
31
|
end
|
58
32
|
|
33
|
+
def method_missing(method, *args)
|
34
|
+
@config.send(method, *args)
|
35
|
+
end
|
36
|
+
|
59
37
|
def self.get
|
60
38
|
@config ||= Config.new
|
61
39
|
end
|
62
40
|
|
63
41
|
private
|
64
42
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
true
|
73
|
-
elsif v == 'false'
|
74
|
-
false
|
75
|
-
else
|
76
|
-
raise ArgumentError, "#{k} must be true or false, #{v} given."
|
77
|
-
end
|
78
|
-
end
|
43
|
+
class ConfigHash < Hash
|
44
|
+
include Hashie::Extensions::Coercion
|
45
|
+
include Hashie::Extensions::DeepMerge
|
46
|
+
include Hashie::Extensions::MethodReader
|
47
|
+
include Hashie::Extensions::MergeInitializer
|
48
|
+
|
49
|
+
coerce_value Hash, ConfigHash
|
79
50
|
end
|
80
51
|
|
81
|
-
def
|
82
|
-
|
52
|
+
def load_config
|
53
|
+
@config_file = find_config_file
|
54
|
+
@config = load_tomls(default_config_file, @config_file)
|
55
|
+
coerce_directories!
|
83
56
|
end
|
84
57
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
end
|
58
|
+
# Make sure the non-default direcotires are set.
|
59
|
+
# @raise [MissingConfigItemError<Array<String>>] the config items that are not set.
|
60
|
+
def check_directories
|
61
|
+
errors = []
|
62
|
+
errors << "agncy.acl_directories" if @config.agency[:acl_directories].empty?
|
63
|
+
errors << "agncy.agent_directories" if @config.agency[:agent_directories].empty?
|
64
|
+
|
65
|
+
unless errors.empty?
|
66
|
+
raise MissingConfigItemError, errors
|
95
67
|
end
|
96
68
|
end
|
97
69
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
appender = Struct::Appender.new(config[:logging_appender_type], config[:logging_appender_filename])
|
107
|
-
|
108
|
-
@agent = Struct::Agent.new(set_as_boolean(config, :agent_monitor), set_as_boolean(config, :agent_singleton), '', set_as_integer(config, :agent_prefetch))
|
109
|
-
@agency = Struct::Agency.new(cache_path, config[:agent_path], acl_path, cache_path.join('acl'), config[:agency_pid_dir])
|
110
|
-
@amqp = Struct::Amqp.new(broker, amqp_opts, amqp_opts, Struct::Publish.new({}), Struct::Subscribe.new(true), Struct::Pop.new(true))
|
111
|
-
@eventmachine = Struct::Eventmachine.new(set_as_integer(config, :file_descriptors, 1024), set_as_boolean(config, :epoll, true), set_as_boolean(config, :kqueue, true))
|
112
|
-
@logging = Struct::Logging.new(config[:logging_trace], config[:logging_level], config[:logging_pattern], config[:logging_date_pattern], appender)
|
113
|
-
@smith = Struct::Smith.new(config[:smith_namespace], set_as_integer(config, :smith_timeout))
|
114
|
-
|
115
|
-
# Set the default ruby runtime. This will use the ruby that is in the path.
|
116
|
-
@ruby = Hash.new(config[:default_vm] || 'ruby')
|
117
|
-
|
118
|
-
config[:agent_vm] && config[:agent_vm].split(/\s+/).each do |vm_spec|
|
119
|
-
agent, vm = vm_spec.split(/:/)
|
120
|
-
@ruby[agent] = vm
|
70
|
+
# Check appropriate env vars and convert the string representation to Pathname
|
71
|
+
# @return [ConfigHash] the config with coerced paths.
|
72
|
+
def coerce_directories!
|
73
|
+
@config.tap do |c|
|
74
|
+
c.agency[:pid_directory] = path_from_env('SMITH_PID_DIRECTORY', c.agency[:pid_directory])
|
75
|
+
c.agency[:cache_directory] = path_from_env('SMITH_CACHE_DIRECTORY', c.agency[:cache_directory])
|
76
|
+
c.agency[:acl_directories] = paths_from_env('SMITH_ACL_DIRECTORIES', c.agency[:acl_directories])
|
77
|
+
c.agency[:agent_directories] = paths_from_env('SMITH_AGENT_DIRECTORIES', c.agency[:agent_directories])
|
121
78
|
end
|
122
79
|
|
123
|
-
|
80
|
+
check_directories
|
81
|
+
@config.agency[:acl_directories] = @config.agency[:acl_directories] + [smith_acl_directory]
|
124
82
|
end
|
125
83
|
|
126
|
-
#
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
84
|
+
# Find the config file. This checks the following paths before raising an
|
85
|
+
# exception:
|
86
|
+
#
|
87
|
+
# * ./.smithrc
|
88
|
+
# * $HOME/.smithrc
|
89
|
+
# * /etc/smithrc
|
90
|
+
# * /etc/smith/smithrc
|
91
|
+
#
|
92
|
+
# @return the config file path
|
93
|
+
def find_config_file
|
94
|
+
if ENV["SMITH_CONFIG"]
|
95
|
+
to_pathname(ENV["SMITH_CONFIG"]).tap do |path|
|
96
|
+
raise ConfigNotFoundError, "Cannot find a config file name: #{path}" unless path.exist?
|
136
97
|
end
|
98
|
+
else
|
99
|
+
user = ["./.#{CONFIG_FILENAME}", "#{ENV['HOME']}/.#{CONFIG_FILENAME}"].map { |p| to_pathname(p) }
|
100
|
+
system = ["/etc/#{CONFIG_FILENAME}", "/etc/smith/#{CONFIG_FILENAME}"].map { |p| to_pathname(p) }
|
101
|
+
default = [default_config_file]
|
102
|
+
|
103
|
+
(user + system + default).detect { |path| path.exist? }
|
137
104
|
end
|
138
105
|
end
|
139
106
|
|
140
|
-
#
|
141
|
-
# until it reaches the user home directory. If it gets to the home
|
142
|
-
# directory without finding a config file it will read /etc/smithrc and
|
143
|
-
# then /etc/smith/config. If that fails give up and raise a
|
144
|
-
# ConfigNotFoundError exception.
|
107
|
+
# Convert a string to a path
|
145
108
|
#
|
146
|
-
# path
|
147
|
-
#
|
148
|
-
def
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
109
|
+
# @param path [String] the string to convert
|
110
|
+
# @return [Pathname]
|
111
|
+
def to_pathname(path)
|
112
|
+
Pathname.new(path).expand_path
|
113
|
+
end
|
114
|
+
|
115
|
+
# Returns a path from the environment variable passed in. If the
|
116
|
+
# environment variable is not set it returns nil.
|
117
|
+
#
|
118
|
+
# @param env_var [String] the name of the environment variable
|
119
|
+
# @param default [String] the value to use if the environment variable is not set
|
120
|
+
# @return [Pathname]
|
121
|
+
def path_from_env(env_var, default)
|
122
|
+
to_pathname(ENV.fetch(env_var, default))
|
123
|
+
end
|
124
|
+
|
125
|
+
# Returns an array of path from the environment variable passed in. If the
|
126
|
+
# environment variable is not set it returns an empty array.
|
127
|
+
#
|
128
|
+
# @param env_var [String] the name of the environment variable
|
129
|
+
# @param default [String] the value to use if the environment variable is not set
|
130
|
+
# @return [Array<Pathnmae>]
|
131
|
+
def paths_from_env(env_var, default)
|
132
|
+
split_paths(ENV.fetch(env_var, default))
|
133
|
+
end
|
134
|
+
|
135
|
+
# Splits a string using PATH_SEPARATOR.
|
136
|
+
#
|
137
|
+
# @param paths to split
|
138
|
+
# @return [Array<Pathnmae>]
|
139
|
+
def split_paths(paths)
|
140
|
+
(paths || '').split(File::PATH_SEPARATOR).map { |p| to_pathname(p) }
|
141
|
+
end
|
142
|
+
|
143
|
+
# @return [Pathnmae]
|
144
|
+
def smith_acl_directory
|
145
|
+
Pathname.new(__FILE__).dirname.join('messaging').join('acl').expand_path
|
146
|
+
end
|
147
|
+
|
148
|
+
# @return [Pathnmae]
|
149
|
+
def default_config_file
|
150
|
+
gem_root.join('config', 'smithrc.toml')
|
151
|
+
end
|
152
|
+
|
153
|
+
# Loads and merges multiple toml files.
|
154
|
+
#
|
155
|
+
# @params [String] the default toml file
|
156
|
+
# @params [String] the user supplied toml file
|
157
|
+
# @return [ConfigHash] the merge toml files.
|
158
|
+
def load_tomls(default, main)
|
159
|
+
load_toml(default).deep_merge(load_toml(main))
|
160
|
+
end
|
161
|
+
|
162
|
+
# Load the toml file specified
|
163
|
+
#
|
164
|
+
# @param [Pathname] the path of the toml file
|
165
|
+
# @return [ConfigHash] the toml file
|
166
|
+
def load_toml(path)
|
167
|
+
ConfigHash.new(TOML.parse(path.read, :symbolize_keys => true))
|
168
|
+
end
|
169
|
+
|
170
|
+
# Returns the gem root. We can't use Smith.root_path here as it hasn't
|
171
|
+
# been initialised yet.
|
172
|
+
def gem_root
|
173
|
+
Pathname.new(__FILE__).dirname.parent.parent.expand_path
|
168
174
|
end
|
169
175
|
end
|
170
176
|
end
|
data/lib/smith/daemon.rb
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
require 'daemons/daemonize'
|
4
4
|
require 'daemons/pidfile'
|
5
5
|
|
6
|
+
require 'smith/utils'
|
7
|
+
|
6
8
|
module Smith
|
7
9
|
class Daemon
|
8
10
|
|
@@ -11,7 +13,7 @@ module Smith
|
|
11
13
|
def initialize(name, daemonise, dir=nil)
|
12
14
|
@name = name
|
13
15
|
@daemonise = daemonise
|
14
|
-
@pid = Daemons::PidFile.new(
|
16
|
+
@pid = Daemons::PidFile.new(pid_directory(dir), @name)
|
15
17
|
end
|
16
18
|
|
17
19
|
# Daemonise the process if the daemonise option is true, otherwise do nothing.
|
@@ -57,7 +59,7 @@ module Smith
|
|
57
59
|
def unlink_pid_file
|
58
60
|
p = Pathname.new(@pid.filename)
|
59
61
|
if p.exist?
|
60
|
-
logger.verbose { "Removing pid file." }
|
62
|
+
logger.verbose { "Removing pid file: #{p.to_s}" }
|
61
63
|
p.unlink
|
62
64
|
end
|
63
65
|
end
|
@@ -66,16 +68,8 @@ module Smith
|
|
66
68
|
|
67
69
|
# Get the pid directory. This checks for the command line option,
|
68
70
|
# then the config and finally use the tmp directory.
|
69
|
-
def
|
70
|
-
|
71
|
-
dir
|
72
|
-
else
|
73
|
-
if Smith.config.agency.to_hash.has_key?(:pid_dir)
|
74
|
-
Smith.config.agency.pid_dir
|
75
|
-
else
|
76
|
-
Dir.tmpdir
|
77
|
-
end
|
78
|
-
end
|
71
|
+
def pid_directory(dir)
|
72
|
+
dir || Utils.check_and_create_directory(Smith.config.agency.pid_directory)
|
79
73
|
end
|
80
74
|
end
|
81
75
|
end
|
@@ -81,7 +81,10 @@ module Smith
|
|
81
81
|
# Subscribes to a queue and passes the headers and payload into the
|
82
82
|
# block. +subscribe+ will automatically acknowledge the message unless
|
83
83
|
# the options sets :ack to false.
|
84
|
-
def subscribe(&blk)
|
84
|
+
def subscribe(handler=nil, &blk)
|
85
|
+
|
86
|
+
blk = handler || blk
|
87
|
+
|
85
88
|
@queue_completion.completion do |queue|
|
86
89
|
@requeue_options_completion.completion do |requeue_options|
|
87
90
|
if !queue.subscribed?
|
@@ -253,6 +256,18 @@ module Smith
|
|
253
256
|
def ack(multiple=false)
|
254
257
|
@metadata.ack(multiple)
|
255
258
|
end
|
259
|
+
alias :call :ack
|
260
|
+
|
261
|
+
# Make #call invoke ack. This makes the following idiom possible:
|
262
|
+
#
|
263
|
+
# receiver('queue').subscribe do |payload, receiver|
|
264
|
+
# blah(payload, &receiver)
|
265
|
+
# end
|
266
|
+
#
|
267
|
+
# which will ensure that #ack is called properly.
|
268
|
+
def to_proc
|
269
|
+
proc { |obj| ack(obj) }
|
270
|
+
end
|
256
271
|
|
257
272
|
# reject the message. Optionally requeuing it.
|
258
273
|
def reject(opts={})
|
data/lib/smith/utils.rb
CHANGED
@@ -6,8 +6,8 @@ module Smith
|
|
6
6
|
#
|
7
7
|
# @param name [String] the name of the agent.
|
8
8
|
# @return [Pathname] the path of the agent.
|
9
|
-
def
|
10
|
-
Smith.
|
9
|
+
def agent_directories(name)
|
10
|
+
Smith.agent_directories.each do |path|
|
11
11
|
p = path_from_class(path, name)
|
12
12
|
return p if p.exist?
|
13
13
|
end
|
@@ -38,5 +38,12 @@ module Smith
|
|
38
38
|
def class_from_name(name)
|
39
39
|
name.to_s.split(/::/).inject(Kernel) { |acc, t| acc.const_get(t) }
|
40
40
|
end
|
41
|
+
|
42
|
+
def check_and_create_directory(dir)
|
43
|
+
dir.tap do
|
44
|
+
dir.exist? || dir.mkpath
|
45
|
+
end
|
46
|
+
end
|
47
|
+
module_function :check_and_create_directory
|
41
48
|
end
|
42
49
|
end
|
data/lib/smith/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smith
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Heycock
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-04-
|
11
|
+
date: 2015-04-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: oj
|
@@ -65,19 +65,19 @@ dependencies:
|
|
65
65
|
- !ruby/object:Gem::Version
|
66
66
|
version: '1.1'
|
67
67
|
- !ruby/object:Gem::Dependency
|
68
|
-
name: eventmachine
|
68
|
+
name: eventmachine
|
69
69
|
requirement: !ruby/object:Gem::Requirement
|
70
70
|
requirements:
|
71
71
|
- - "~>"
|
72
72
|
- !ruby/object:Gem::Version
|
73
|
-
version: '1.
|
73
|
+
version: '1.0'
|
74
74
|
type: :runtime
|
75
75
|
prerelease: false
|
76
76
|
version_requirements: !ruby/object:Gem::Requirement
|
77
77
|
requirements:
|
78
78
|
- - "~>"
|
79
79
|
- !ruby/object:Gem::Version
|
80
|
-
version: '1.
|
80
|
+
version: '1.0'
|
81
81
|
- !ruby/object:Gem::Dependency
|
82
82
|
name: extlib
|
83
83
|
requirement: !ruby/object:Gem::Requirement
|
@@ -191,33 +191,33 @@ dependencies:
|
|
191
191
|
- !ruby/object:Gem::Version
|
192
192
|
version: 0.1.4
|
193
193
|
- !ruby/object:Gem::Dependency
|
194
|
-
name:
|
194
|
+
name: curses
|
195
195
|
requirement: !ruby/object:Gem::Requirement
|
196
196
|
requirements:
|
197
|
-
- -
|
197
|
+
- - '='
|
198
198
|
- !ruby/object:Gem::Version
|
199
|
-
version:
|
199
|
+
version: 1.0.1
|
200
200
|
type: :runtime
|
201
201
|
prerelease: false
|
202
202
|
version_requirements: !ruby/object:Gem::Requirement
|
203
203
|
requirements:
|
204
|
-
- -
|
204
|
+
- - '='
|
205
205
|
- !ruby/object:Gem::Version
|
206
|
-
version:
|
206
|
+
version: 1.0.1
|
207
207
|
- !ruby/object:Gem::Dependency
|
208
|
-
name:
|
208
|
+
name: toml-rb
|
209
209
|
requirement: !ruby/object:Gem::Requirement
|
210
210
|
requirements:
|
211
|
-
- -
|
211
|
+
- - "~>"
|
212
212
|
- !ruby/object:Gem::Version
|
213
|
-
version:
|
213
|
+
version: '0.3'
|
214
214
|
type: :runtime
|
215
215
|
prerelease: false
|
216
216
|
version_requirements: !ruby/object:Gem::Requirement
|
217
217
|
requirements:
|
218
|
-
- -
|
218
|
+
- - "~>"
|
219
219
|
- !ruby/object:Gem::Version
|
220
|
-
version:
|
220
|
+
version: '0.3'
|
221
221
|
description: Simple multi-agent framework. It uses AMQP for it's messaging layer.
|
222
222
|
email: rgh@filterfish.org
|
223
223
|
executables:
|
@@ -230,6 +230,7 @@ files:
|
|
230
230
|
- bin/agency
|
231
231
|
- bin/pry-smith
|
232
232
|
- bin/smithctl
|
233
|
+
- config/smithrc.toml
|
233
234
|
- lib/smith.rb
|
234
235
|
- lib/smith/acl_compiler.rb
|
235
236
|
- lib/smith/acl_parser.rb
|
@@ -317,7 +318,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
317
318
|
version: '0'
|
318
319
|
requirements: []
|
319
320
|
rubyforge_project: smith
|
320
|
-
rubygems_version: 2.
|
321
|
+
rubygems_version: 2.4.5
|
321
322
|
signing_key:
|
322
323
|
specification_version: 4
|
323
324
|
summary: Multi-agent framework
|