erlnixify 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +20 -0
- data/CONTRIBUTING.md +139 -0
- data/Gemfile +4 -0
- data/LICENSE.md +194 -0
- data/README.md +226 -0
- data/Rakefile +22 -0
- data/erlnixify.gemspec +35 -0
- data/features/node.feature +35 -0
- data/features/settings.feature +20 -0
- data/features/step_definitions/node_steps.rb +108 -0
- data/features/step_definitions/settings_steps.rb +63 -0
- data/features/test_data/settings_config.yml +7 -0
- data/lib/erlnixify/exceptions.rb +6 -0
- data/lib/erlnixify/node.rb +135 -0
- data/lib/erlnixify/opts.rb +45 -0
- data/lib/erlnixify/settings.rb +127 -0
- data/lib/erlnixify/version.rb +3 -0
- data/lib/erlnixify.rb +24 -0
- data/reek.yml +8 -0
- data/settings.feature +20 -0
- metadata +158 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
Feature: Node
|
2
|
+
In order to manage a running erlang node
|
3
|
+
As a developer
|
4
|
+
I want to be able to bring it up and shut it down
|
5
|
+
and regularly check to see if its still running as expected
|
6
|
+
|
7
|
+
Scenario: Basic startup
|
8
|
+
Given a valid configuration
|
9
|
+
And the erlang node is started
|
10
|
+
When the node is brought up
|
11
|
+
Then no errors or problems occur
|
12
|
+
|
13
|
+
Scenario: Startup failure
|
14
|
+
Given a valid configuration with invalid command
|
15
|
+
And the erlang node is started
|
16
|
+
When the node fails
|
17
|
+
Then an exception occures
|
18
|
+
|
19
|
+
Scenario: Check failure
|
20
|
+
Given a valid configuration with invalid check command
|
21
|
+
And the erlang node is started
|
22
|
+
When the check fails
|
23
|
+
And the erlang node is halted
|
24
|
+
|
25
|
+
Scenario: Check Timeout
|
26
|
+
Given a valid configuration with a long running check comamnd
|
27
|
+
And the erlang node is started
|
28
|
+
When the check command times out
|
29
|
+
Then the erlang node is halted
|
30
|
+
|
31
|
+
Scenario: Signal TERM
|
32
|
+
Given a valid configuration
|
33
|
+
And the erlang node is started
|
34
|
+
When a term signal is recieved
|
35
|
+
Then the erlang node is halted
|
@@ -0,0 +1,20 @@
|
|
1
|
+
Feature: Settings
|
2
|
+
In order to provide a 'templatable' settings file
|
3
|
+
As a developer
|
4
|
+
I want to be able to provide a settings file
|
5
|
+
and have the system warn me when I get settings wrong
|
6
|
+
|
7
|
+
Scenario: A basic yaml settings file
|
8
|
+
Given a settings file
|
9
|
+
When I load that settings file
|
10
|
+
Then the settings should be available in the settings object
|
11
|
+
|
12
|
+
Scenario: Command line options override config
|
13
|
+
Given an options object that contains config values
|
14
|
+
When a new settings file is loaded up using that options
|
15
|
+
Then the command line options override the file options
|
16
|
+
|
17
|
+
Scenario: Reasonable Default Settings
|
18
|
+
Given a lack of a config file and command line options
|
19
|
+
When a settings are loaded
|
20
|
+
Then that settings object contains sane defaults
|
@@ -0,0 +1,108 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
Given(/^a valid configuration$/) do
|
4
|
+
hostname = `hostname -f`.strip
|
5
|
+
@opts = Erlnixify::Opts.new(["--cookie", "fubachu",
|
6
|
+
"--startuptimeout", "10",
|
7
|
+
"--checkinterval", "10",
|
8
|
+
"--name", "foo",
|
9
|
+
"--command", "erl -noshell -setcookie fubachu -name foo@#{hostname}"
|
10
|
+
])
|
11
|
+
@settings = Erlnixify::Settings.new(@opts)
|
12
|
+
end
|
13
|
+
|
14
|
+
Then(/^no errors or problems occur$/) do
|
15
|
+
assert @node.is_running?
|
16
|
+
@node.halt_nicely
|
17
|
+
sleep @settings[:startuptimeout]
|
18
|
+
assert (not @node.is_running?)
|
19
|
+
end
|
20
|
+
|
21
|
+
Given(/^the erlang node is started$/) do
|
22
|
+
@node = Erlnixify::Node.new @settings
|
23
|
+
Thread.new do
|
24
|
+
begin
|
25
|
+
@node.start
|
26
|
+
rescue Erlnixify::NodeError => node_error
|
27
|
+
@node_start_error = node_error
|
28
|
+
rescue Exception => e
|
29
|
+
assert_fail "Other exception should not occur #{e.message}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
sleep (@settings[:startuptimeout] + 30)
|
33
|
+
end
|
34
|
+
|
35
|
+
When(/^the node is brought up$/) do
|
36
|
+
assert @node.is_running?
|
37
|
+
end
|
38
|
+
|
39
|
+
Given(/^a valid configuration with invalid command$/) do
|
40
|
+
hostname = `hostname -f`.strip
|
41
|
+
@opts = Erlnixify::Opts.new(["--cookie", "fubachu",
|
42
|
+
"--startuptimeout", "10",
|
43
|
+
"--checkinterval", "10",
|
44
|
+
"--name", "foo",
|
45
|
+
"--command", "this should fail"
|
46
|
+
])
|
47
|
+
@settings = Erlnixify::Settings.new(@opts)
|
48
|
+
end
|
49
|
+
|
50
|
+
When(/^the node fails$/) do
|
51
|
+
assert @node_start_error != nil, "An NodeError was expected to be thrown"
|
52
|
+
assert @node.is_running? == false, "Node is still running"
|
53
|
+
end
|
54
|
+
|
55
|
+
Then(/^an exception occures$/) do
|
56
|
+
assert @node_start_error != nil, "An NodeError was expected to be thrown"
|
57
|
+
end
|
58
|
+
|
59
|
+
Given(/^a valid configuration with invalid check command$/) do
|
60
|
+
hostname = `hostname -f`.strip
|
61
|
+
@opts = Erlnixify::Opts.new(["--cookie", "fubachu",
|
62
|
+
"--startuptimeout", "10",
|
63
|
+
"--checkinterval", "10",
|
64
|
+
"--name", "foo",
|
65
|
+
"--command", "erl -noshell -setcookie fubachu -name foo@#{hostname}",
|
66
|
+
"--check", "invalid check",
|
67
|
+
|
68
|
+
])
|
69
|
+
@settings = Erlnixify::Settings.new(@opts)
|
70
|
+
end
|
71
|
+
|
72
|
+
When(/^the check fails$/) do
|
73
|
+
assert @node_start_error.message == "Node check failed"
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
When(/^the erlang node is halted$/) do
|
78
|
+
assert false == @node.is_running?, "The node is running when it should not be"
|
79
|
+
end
|
80
|
+
|
81
|
+
Given(/^a valid configuration with a long running check comamnd$/) do
|
82
|
+
check_time = 60 * 1000 # 60 seconds in milliseconds
|
83
|
+
hostname = `hostname -f`.strip
|
84
|
+
@opts = Erlnixify::Opts.new(["--cookie", "fubachu",
|
85
|
+
"--startuptimeout", "10",
|
86
|
+
"--checkinterval", "10",
|
87
|
+
"--name", "foo",
|
88
|
+
"--command", "erl -noshell -setcookie fubachu -name foo@#{hostname}",
|
89
|
+
"--check", "timer sleep [#{check_time}]",
|
90
|
+
|
91
|
+
])
|
92
|
+
@settings = Erlnixify::Settings.new(@opts)
|
93
|
+
end
|
94
|
+
|
95
|
+
When(/^the check command times out$/) do
|
96
|
+
sleep 60 # should be a enough given the timeout
|
97
|
+
|
98
|
+
assert @node_start_error.message == "Check command timeout occurred", "Timeout did not occur"
|
99
|
+
end
|
100
|
+
|
101
|
+
When(/^a term signal is recieved$/) do
|
102
|
+
begin
|
103
|
+
Process.kill("TERM", $$)
|
104
|
+
assert_fail "Did not recieve error"
|
105
|
+
rescue Erlnixify::NodeError => e
|
106
|
+
assert e.message == "SIGTERM recieved, shutting down"
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require "erlnixify"
|
2
|
+
|
3
|
+
Before do
|
4
|
+
end
|
5
|
+
|
6
|
+
After do
|
7
|
+
end
|
8
|
+
|
9
|
+
Given(/^a settings file$/) do
|
10
|
+
file = File.dirname(__FILE__) + '/../test_data/settings_config.yml'
|
11
|
+
@opts = Erlnixify::Opts.new(["--config", file])
|
12
|
+
end
|
13
|
+
|
14
|
+
When(/^I load that settings file$/) do
|
15
|
+
@settings = Erlnixify::Settings.new(@opts)
|
16
|
+
end
|
17
|
+
|
18
|
+
Then(/^the settings should be available in the settings object$/) do
|
19
|
+
assert_equal 60, @settings[:startuptimeout]
|
20
|
+
assert_equal "/some/place", @settings[:release]
|
21
|
+
assert_equal "/some/root/file", @settings[:erlang]
|
22
|
+
assert_equal "mynode", @settings[:name]
|
23
|
+
assert_equal "sleep 10", @settings[:command]
|
24
|
+
assert_equal "testcookie!", @settings[:cookie]
|
25
|
+
assert_equal 30, @settings[:checkinterval]
|
26
|
+
end
|
27
|
+
|
28
|
+
Given(/^an options object that contains config values$/) do
|
29
|
+
file = File.dirname(__FILE__) + '/../test_data/settings_config.yml'
|
30
|
+
@opts = Erlnixify::Opts.new(["--config", file,
|
31
|
+
"--checkinterval", "100",
|
32
|
+
"--startuptimeout", "500",
|
33
|
+
"--cookie", "fubachu"])
|
34
|
+
end
|
35
|
+
|
36
|
+
When(/^a new settings file is loaded up using that options$/) do
|
37
|
+
@settings = Erlnixify::Settings.new(@opts)
|
38
|
+
end
|
39
|
+
|
40
|
+
Then(/^the command line options override the file options$/) do
|
41
|
+
assert_equal 500, @settings[:startuptimeout]
|
42
|
+
assert_equal "/some/place", @settings[:release]
|
43
|
+
assert_equal "/some/root/file", @settings[:erlang]
|
44
|
+
assert_equal "mynode", @settings[:name]
|
45
|
+
assert_equal "sleep 10", @settings[:command]
|
46
|
+
assert_equal "fubachu", @settings[:cookie]
|
47
|
+
assert_equal 100, @settings[:checkinterval]
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
Given(/^a lack of a config file and command line options$/) do
|
52
|
+
@opts = Erlnixify::Opts.new([])
|
53
|
+
end
|
54
|
+
|
55
|
+
When(/^a settings are loaded$/) do
|
56
|
+
@settings = Erlnixify::Settings.new(@opts)
|
57
|
+
end
|
58
|
+
|
59
|
+
Then(/^that settings object contains sane defaults$/) do
|
60
|
+
assert_equal 60, @settings[:startuptimeout]
|
61
|
+
assert_equal ENV["HOME"], @settings[:home]
|
62
|
+
assert_equal 30, @settings[:checkinterval]
|
63
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'erlnixify/exceptions'
|
3
|
+
|
4
|
+
module Erlnixify
|
5
|
+
COMMAND_WRAPPER = "%{erl_interface}/bin/erl_call -n %{fullnode} \
|
6
|
+
-c '%{cookie}' -a '%{cmd}'"
|
7
|
+
|
8
|
+
SHUTDOWN_COMMAND = "init stop"
|
9
|
+
|
10
|
+
BRUTAL_SHUTDOWN_COMMAND = "erlang halt 127"
|
11
|
+
|
12
|
+
# The process class owns the Running erlang process. It knows how to
|
13
|
+
# query it if its active, and kill it if something goes long. This
|
14
|
+
# class is the guts of erlnixify
|
15
|
+
class Node
|
16
|
+
def initialize(settings)
|
17
|
+
@settings = settings
|
18
|
+
@command = @settings[:command] % settings.settings
|
19
|
+
@check_command = self.interpolate_cmd(@settings[:check])
|
20
|
+
@halt_command = self.interpolate_cmd(SHUTDOWN_COMMAND)
|
21
|
+
@brutal_halt_command = self.interpolate_cmd(BRUTAL_SHUTDOWN_COMMAND)
|
22
|
+
@checkregex = Regexp.new @settings[:checkregex]
|
23
|
+
|
24
|
+
@log = Logger.new(STDOUT)
|
25
|
+
@log.level = Logger::DEBUG
|
26
|
+
|
27
|
+
Signal.trap("TERM") do
|
28
|
+
self.halt_nicely
|
29
|
+
raise NodeError, "SIGTERM recieved, shutting down"
|
30
|
+
end
|
31
|
+
|
32
|
+
Signal.trap("INT") do
|
33
|
+
self.halt_nicely
|
34
|
+
raise NodeError, "SIGINT recieved, shutting down"
|
35
|
+
end
|
36
|
+
|
37
|
+
at_exit { self.external_kill }
|
38
|
+
end
|
39
|
+
|
40
|
+
def start
|
41
|
+
@log.debug "starting process"
|
42
|
+
env = {}
|
43
|
+
env["HOME"] = @settings[:home] if @settings[:home]
|
44
|
+
|
45
|
+
begin
|
46
|
+
@log.debug "spawning command '#{@command}' with #{env}"
|
47
|
+
@pid = Process.spawn(env, @command)
|
48
|
+
rescue Errno::ENOENT
|
49
|
+
@log.debug "Invalid command provided, raising error"
|
50
|
+
raise NodeError, "Command does not exist"
|
51
|
+
end
|
52
|
+
|
53
|
+
@log.debug "waiting for #{@settings[:startuptimeout]} seconds for startup"
|
54
|
+
sleep @settings[:startuptimeout]
|
55
|
+
self.monitor
|
56
|
+
end
|
57
|
+
|
58
|
+
def monitor
|
59
|
+
@log.debug "starting monitor of Pid #{@pid}"
|
60
|
+
loop do
|
61
|
+
if is_running?
|
62
|
+
self.check
|
63
|
+
sleep @settings[:checkinterval]
|
64
|
+
else
|
65
|
+
raise NodeError, "Node not running"
|
66
|
+
end
|
67
|
+
break if @stop
|
68
|
+
@log.debug "Node responded correctly, continuing check"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def check
|
73
|
+
begin
|
74
|
+
Timeout.timeout(@settings[:checktimeout]) do
|
75
|
+
self.raw_check
|
76
|
+
end
|
77
|
+
rescue Timeout::Error
|
78
|
+
self.halt_nicely
|
79
|
+
raise NodeError, "Check command timeout occurred"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def raw_check
|
84
|
+
@log.debug "Checking the status of Pid #{@pid}"
|
85
|
+
@log.debug "#{@check_command} =~ #{@checkregex}"
|
86
|
+
result = `#{@check_command}`
|
87
|
+
@log.debug "got #{result}"
|
88
|
+
if not (result =~ @checkregex)
|
89
|
+
@log.debug "Check failed, halting system"
|
90
|
+
self.halt_nicely
|
91
|
+
raise NodeError, "Node check failed"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def is_running?
|
96
|
+
@log.debug "Checking if Pid (#{@pid}) is running"
|
97
|
+
if @pid
|
98
|
+
begin
|
99
|
+
Process.getpgid(@pid)
|
100
|
+
true
|
101
|
+
rescue Errno::ESRCH
|
102
|
+
false
|
103
|
+
end
|
104
|
+
else
|
105
|
+
false
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def halt_nicely
|
110
|
+
`#{@halt_command}`
|
111
|
+
sleep @settings[:checkinterval]
|
112
|
+
if self.is_running?
|
113
|
+
self.halt_brutally
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def halt_brutally
|
118
|
+
`#{@brutal_halt_command}`
|
119
|
+
sleep @settings[:checkinterval]
|
120
|
+
if self.is_running?
|
121
|
+
self.external_kill
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def external_kill
|
126
|
+
Process.kill("KILL", @pid) if @pid
|
127
|
+
end
|
128
|
+
|
129
|
+
def interpolate_cmd(cmd)
|
130
|
+
local_settings = @settings.settings.clone
|
131
|
+
local_settings[:cmd] = cmd % local_settings
|
132
|
+
COMMAND_WRAPPER % local_settings
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'slop'
|
2
|
+
|
3
|
+
module Erlnixify
|
4
|
+
|
5
|
+
# The Opts class provides options parsing support for erlnixify. It
|
6
|
+
# is similar to settings with the exception that it is designed to
|
7
|
+
# get its values from the command line.
|
8
|
+
#
|
9
|
+
class Opts
|
10
|
+
|
11
|
+
attr_reader :options
|
12
|
+
|
13
|
+
def initialize(args)
|
14
|
+
opts = Slop.parse(args) do
|
15
|
+
|
16
|
+
banner = "Usage: erlnixify [options]"
|
17
|
+
|
18
|
+
on :b, :release=, 'Release Root Directory'
|
19
|
+
on :e, :erlang=, 'Erlang Root Directory'
|
20
|
+
on :o, :home=, "The home directory to explicitly set"
|
21
|
+
on :n, :name=, "The short name of the node to be managed"
|
22
|
+
on :fullnode=, "The fully qualified node name"
|
23
|
+
on :m, :command=, "The command to run to start the release"
|
24
|
+
on :k, :check=, "The command to check if the release is active"
|
25
|
+
on :r, :checkregex=, "The regex that must match to the output of check command"
|
26
|
+
on :x, :cookiefile=, "A file that contains the erlang cookie, not needed if cookie is set"
|
27
|
+
on :i, :cookie=, "The cookie itself, not needed if cookie-file is set"
|
28
|
+
on(:t, :startuptimeout=,
|
29
|
+
"The amount of time to let the system startup in seconds",
|
30
|
+
as: Integer)
|
31
|
+
on(:a, :checkinterval=,
|
32
|
+
"How often erlnixify should check to see if the system is still running",
|
33
|
+
as: Integer)
|
34
|
+
on(:w, :checktimeout=,
|
35
|
+
"The longest time a check can run, defaults to 30 seconds",
|
36
|
+
as: Integer)
|
37
|
+
on :c, :config=, "A file that contains the YAML based config for this system"
|
38
|
+
on :v, :version, "Show the Version"
|
39
|
+
end
|
40
|
+
|
41
|
+
@options = opts.to_hash
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Erlnixify
|
4
|
+
|
5
|
+
# Provides a library for settings to be accessed from accross the
|
6
|
+
# system
|
7
|
+
class Settings
|
8
|
+
attr_accessor :settings
|
9
|
+
attr_accessor :options
|
10
|
+
|
11
|
+
STARTUP_TIMEOUT = 60
|
12
|
+
CHECK_INTERVAL = 30
|
13
|
+
CHECK_TIMEOUT = 30
|
14
|
+
CHECK_COMMAND = "erlang statistics [reductions]"
|
15
|
+
CHECK_REGEX = "^{\\d+, \\d+}$"
|
16
|
+
|
17
|
+
def initialize(opts)
|
18
|
+
@options = opts
|
19
|
+
config = @options.options[:config]
|
20
|
+
|
21
|
+
@settings = self.default_settings
|
22
|
+
|
23
|
+
self.load! config if config
|
24
|
+
self.merge(@options.options)
|
25
|
+
self.post_settings_setup
|
26
|
+
end
|
27
|
+
|
28
|
+
def default_settings
|
29
|
+
defaults = {release: nil,
|
30
|
+
erlang: nil,
|
31
|
+
home: ENV["HOME"],
|
32
|
+
name: nil,
|
33
|
+
fullnode: nil,
|
34
|
+
command: nil,
|
35
|
+
check: CHECK_COMMAND,
|
36
|
+
checkregex: CHECK_REGEX,
|
37
|
+
cookiefile: nil,
|
38
|
+
cookie: nil,
|
39
|
+
startuptimeout: STARTUP_TIMEOUT,
|
40
|
+
checkinterval: CHECK_INTERVAL,
|
41
|
+
checktimeout: CHECK_TIMEOUT,
|
42
|
+
config: nil}
|
43
|
+
defaults
|
44
|
+
end
|
45
|
+
|
46
|
+
def load!(filename, options = {})
|
47
|
+
newsets = YAML::load_file(filename)
|
48
|
+
|
49
|
+
env = options[:env].to_sym if options[:env]
|
50
|
+
|
51
|
+
if env
|
52
|
+
newsets = newsets[env] if newsets[env]
|
53
|
+
end
|
54
|
+
|
55
|
+
self.merge(newsets)
|
56
|
+
end
|
57
|
+
|
58
|
+
def [](key)
|
59
|
+
return @settings[key]
|
60
|
+
end
|
61
|
+
|
62
|
+
def merge(data)
|
63
|
+
@settings = @settings.inject({}) do |newhash, (key, value)|
|
64
|
+
symkey = key.to_sym
|
65
|
+
data_value = data[symkey]
|
66
|
+
data_value = data[key.to_s] unless data_value
|
67
|
+
if data_value
|
68
|
+
newhash[symkey] = data_value
|
69
|
+
else
|
70
|
+
newhash[symkey] = value
|
71
|
+
end
|
72
|
+
newhash
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def post_settings_setup
|
77
|
+
@settings[:erlang] = self.find_erlang_root
|
78
|
+
@settings[:cookie] = self.find_cookie
|
79
|
+
@settings[:erl_interface] = self.find_erl_interface
|
80
|
+
@settings[:fullnode] = self.find_full_node
|
81
|
+
end
|
82
|
+
|
83
|
+
def find_erlang_root
|
84
|
+
if @settings[:erlang]
|
85
|
+
@settings[:erlang]
|
86
|
+
elsif File.directory? "/usr/local/lib/erlang"
|
87
|
+
"/usr/local/lib/erlang"
|
88
|
+
elsif File.directory? "/usr/lib/erlang"
|
89
|
+
"/usr/lib/erlang"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
def find_cookie
|
95
|
+
cookie_file = @settings[:cookiefile]
|
96
|
+
if @settings[:cookie]
|
97
|
+
@settings[:cookie]
|
98
|
+
elsif cookie_file
|
99
|
+
if File.exists? cookie_file
|
100
|
+
IO.read cookie_file
|
101
|
+
else
|
102
|
+
raise RuntimeError, "Cookie file does not exist"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def find_full_node
|
108
|
+
if @settings[:fullnode]
|
109
|
+
@settings[:fullnode]
|
110
|
+
else
|
111
|
+
hostname = `hostname -f`.strip
|
112
|
+
node = @settings[:name]
|
113
|
+
"#{node}@#{hostname}"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def find_erl_interface
|
118
|
+
erlang_root = @settings[:erlang]
|
119
|
+
release_root = @settings[:release]
|
120
|
+
if erlang_root && (File.directory? erlang_root)
|
121
|
+
Dir.glob("#{erlang_root}/lib/erl_interface-*").first
|
122
|
+
elsif release_root && (File.directory? release_root)
|
123
|
+
Dir.glob("#{release_root}/lib/erl_interface-*").first
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
data/lib/erlnixify.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require "erlnixify/version"
|
2
|
+
require "erlnixify/opts"
|
3
|
+
require "erlnixify/settings"
|
4
|
+
require "erlnixify/node"
|
5
|
+
|
6
|
+
module Erlnixify
|
7
|
+
|
8
|
+
def main(args)
|
9
|
+
@opts = Opts.new(args)
|
10
|
+
|
11
|
+
if opts.version?
|
12
|
+
puts Erlnixify::VERSION
|
13
|
+
exit 0
|
14
|
+
end
|
15
|
+
|
16
|
+
@settings = Settings.new(opts)
|
17
|
+
@process = Process.new(@settings)
|
18
|
+
begin
|
19
|
+
@process.start
|
20
|
+
rescue Erlnixify::NodeError
|
21
|
+
exit 127
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/reek.yml
ADDED
data/settings.feature
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Feature: Settings
|
2
|
+
In order to provide a 'templatable' settings file
|
3
|
+
As a developer
|
4
|
+
I want to be able to provide a settings file
|
5
|
+
and have the system warn me when I get settings wrong
|
6
|
+
|
7
|
+
Scenario: A basic yaml settings file
|
8
|
+
Given a settings file
|
9
|
+
When I load that settings file
|
10
|
+
Then the settings should be available in the settings object
|
11
|
+
|
12
|
+
Scenario: Command line options override config
|
13
|
+
Given an options object that contains config values
|
14
|
+
When a new settings file is loaded up using that options
|
15
|
+
Then the command line options override the file options
|
16
|
+
|
17
|
+
Scenario: Reasonable Default Settings
|
18
|
+
Given a lack of a config file and command line options
|
19
|
+
When a settings are loaded
|
20
|
+
Then that settings object contains sane defaults
|