erlnixify 0.0.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 +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
|