invoker 1.0.2 → 1.0.3
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 +6 -14
- data/.gitignore +2 -0
- data/.rspec +2 -0
- data/Rakefile +7 -5
- data/invoker.gemspec +3 -3
- data/lib/invoker.rb +2 -0
- data/lib/invoker/commander.rb +12 -9
- data/lib/invoker/errors.rb +1 -0
- data/lib/invoker/parsers/config.rb +49 -14
- data/lib/invoker/parsers/option_parser.rb +1 -1
- data/lib/invoker/parsers/procfile.rb +86 -0
- data/lib/invoker/power.rb +1 -0
- data/lib/invoker/power/balancer.rb +16 -1
- data/lib/invoker/power/http_response.rb +81 -0
- data/lib/invoker/power/setup.rb +13 -1
- data/lib/invoker/power/templates/404.html +40 -0
- data/lib/invoker/power/templates/503.html +40 -0
- data/lib/invoker/runner.rb +6 -0
- data/lib/invoker/version.rb +1 -1
- data/spec/invoker/command_listener/client_spec.rb +1 -1
- data/spec/invoker/command_worker_spec.rb +1 -1
- data/spec/invoker/commander_spec.rb +10 -10
- data/spec/invoker/config_spec.rb +55 -17
- data/spec/invoker/event/manager_spec.rb +13 -18
- data/spec/invoker/invoker_spec.rb +5 -5
- data/spec/invoker/power/config_spec.rb +4 -4
- data/spec/invoker/power/http_response_spec.rb +34 -0
- data/spec/invoker/power/port_finder_spec.rb +2 -2
- data/spec/invoker/power/setup_spec.rb +22 -30
- data/spec/spec_helper.rb +58 -8
- metadata +26 -19
data/lib/invoker/power/setup.rb
CHANGED
@@ -4,6 +4,8 @@ module Invoker
|
|
4
4
|
module Power
|
5
5
|
class Setup
|
6
6
|
RESOLVER_FILE = "/etc/resolver/dev"
|
7
|
+
RESOLVER_DIR = "/etc/resolver"
|
8
|
+
|
7
9
|
FIREWALL_PLIST_FILE = "/Library/LaunchDaemons/com.codemancers.invoker.firewall.plist"
|
8
10
|
def self.install
|
9
11
|
installer = new
|
@@ -75,7 +77,7 @@ module Invoker
|
|
75
77
|
end
|
76
78
|
|
77
79
|
def install_resolver(dns_port)
|
78
|
-
|
80
|
+
open_resolver_for_write { |fl|
|
79
81
|
fl.write(resolve_string(dns_port))
|
80
82
|
}
|
81
83
|
rescue Errno::EACCES
|
@@ -169,6 +171,16 @@ port #{dns_port}
|
|
169
171
|
end
|
170
172
|
replace_resolver_flag
|
171
173
|
end
|
174
|
+
|
175
|
+
private
|
176
|
+
def open_resolver_for_write
|
177
|
+
FileUtils.mkdir(RESOLVER_DIR) unless Dir.exists?(RESOLVER_DIR)
|
178
|
+
fl = File.open(RESOLVER_FILE, "w")
|
179
|
+
yield fl
|
180
|
+
ensure
|
181
|
+
fl && fl.close()
|
182
|
+
end
|
183
|
+
|
172
184
|
end
|
173
185
|
end
|
174
186
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<title>Invoker</title>
|
6
|
+
<style>
|
7
|
+
body {
|
8
|
+
margin: 0;
|
9
|
+
padding: 0;
|
10
|
+
background: #fff;
|
11
|
+
line-height: 18px;
|
12
|
+
}
|
13
|
+
div.page {
|
14
|
+
padding: 36px 90px;
|
15
|
+
}
|
16
|
+
h1, h2, p, li {
|
17
|
+
font-family: Helvetica, sans-serif;
|
18
|
+
font-size: 13px;
|
19
|
+
}
|
20
|
+
h1 {
|
21
|
+
line-height: 45px;
|
22
|
+
font-size: 36px;
|
23
|
+
margin: 0;
|
24
|
+
}
|
25
|
+
h2 {
|
26
|
+
line-height: 27px;
|
27
|
+
font-size: 18px;
|
28
|
+
font-weight: normal;
|
29
|
+
margin: 0;
|
30
|
+
}
|
31
|
+
</style>
|
32
|
+
</head>
|
33
|
+
<body class="">
|
34
|
+
<div class="page">
|
35
|
+
<h1>Application not found</h1>
|
36
|
+
<hr>
|
37
|
+
<h2>Invoker could not find the application. Please check the configuration file.<h2>
|
38
|
+
</div>
|
39
|
+
</body>
|
40
|
+
</html>
|
@@ -0,0 +1,40 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<title>Invoker</title>
|
6
|
+
<style>
|
7
|
+
body {
|
8
|
+
margin: 0;
|
9
|
+
padding: 0;
|
10
|
+
background: #fff;
|
11
|
+
line-height: 18px;
|
12
|
+
}
|
13
|
+
div.page {
|
14
|
+
padding: 36px 90px;
|
15
|
+
}
|
16
|
+
h1, h2, p, li {
|
17
|
+
font-family: Helvetica, sans-serif;
|
18
|
+
font-size: 13px;
|
19
|
+
}
|
20
|
+
h1 {
|
21
|
+
line-height: 45px;
|
22
|
+
font-size: 36px;
|
23
|
+
margin: 0;
|
24
|
+
}
|
25
|
+
h2 {
|
26
|
+
line-height: 27px;
|
27
|
+
font-size: 18px;
|
28
|
+
font-weight: normal;
|
29
|
+
margin: 0;
|
30
|
+
}
|
31
|
+
</style>
|
32
|
+
</head>
|
33
|
+
<body class="">
|
34
|
+
<div class="page">
|
35
|
+
<h1>Application not running</h1>
|
36
|
+
<hr>
|
37
|
+
<h2>Invoker did not get any response. Please check if the application is running.<h2>
|
38
|
+
</div>
|
39
|
+
</body>
|
40
|
+
</html>
|
data/lib/invoker/runner.rb
CHANGED
@@ -14,6 +14,8 @@ module Invoker
|
|
14
14
|
def self.run_command(selected_command)
|
15
15
|
return unless selected_command
|
16
16
|
case selected_command.command
|
17
|
+
when 'version'
|
18
|
+
emit_version
|
17
19
|
when 'setup'
|
18
20
|
setup_pow(selected_command)
|
19
21
|
when 'uninstall'
|
@@ -33,6 +35,10 @@ module Invoker
|
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
38
|
+
def self.emit_version
|
39
|
+
Invoker::Logger.puts Invoker::VERSION
|
40
|
+
end
|
41
|
+
|
36
42
|
def self.setup_pow(selected_command)
|
37
43
|
Invoker::Power::Setup.install()
|
38
44
|
end
|
data/lib/invoker/version.rb
CHANGED
@@ -6,7 +6,7 @@ describe Invoker::CommandListener::Client do
|
|
6
6
|
@client_socket = mock()
|
7
7
|
@client = Invoker::CommandListener::Client.new(@client_socket)
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
it "should run if read from socket" do
|
11
11
|
invoker_commander.expects(:on_next_tick).with("foo")
|
12
12
|
@client_socket.expects(:gets).returns("add foo\n")
|
@@ -10,9 +10,9 @@ describe "Invoker::Commander" do
|
|
10
10
|
it "should throw error" do
|
11
11
|
invoker_config.stubs(:processes).returns([])
|
12
12
|
|
13
|
-
|
13
|
+
expect {
|
14
14
|
@commander.start_manager()
|
15
|
-
}.
|
15
|
+
}.to raise_error(Invoker::Errors::InvalidConfig)
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
@@ -40,14 +40,14 @@ describe "Invoker::Commander" do
|
|
40
40
|
describe "if a signal is specified" do
|
41
41
|
it "should use that signal to kill the worker" do
|
42
42
|
@commander.expects(:process_kill).with("bogus", "HUP").returns(true)
|
43
|
-
@commander.remove_command("resque", "HUP").
|
43
|
+
expect(@commander.remove_command("resque", "HUP")).to be_true
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
47
|
describe "if no signal is specified" do
|
48
48
|
it "should use INT signal" do
|
49
49
|
@commander.expects(:process_kill).with("bogus", "INT").returns(true)
|
50
|
-
@commander.remove_command("resque", nil).
|
50
|
+
expect(@commander.remove_command("resque", nil)).to be_true
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
@@ -91,17 +91,17 @@ describe "Invoker::Commander" do
|
|
91
91
|
it "should populate workers and open_pipes" do
|
92
92
|
@commander.expects(:start_event_loop)
|
93
93
|
@commander.start_manager()
|
94
|
-
@commander.open_pipes.
|
95
|
-
@commander.workers.
|
94
|
+
expect(@commander.open_pipes).not_to be_empty
|
95
|
+
expect(@commander.workers).not_to be_empty
|
96
96
|
|
97
97
|
worker = @commander.workers['sleep']
|
98
98
|
|
99
|
-
worker.
|
100
|
-
worker.command_label.
|
101
|
-
worker.color.
|
99
|
+
expect(worker).not_to be_nil
|
100
|
+
expect(worker.command_label).to eq('sleep')
|
101
|
+
expect(worker.color).to eq(:green)
|
102
102
|
|
103
103
|
pipe_end_worker = @commander.open_pipes[worker.pipe_end.fileno]
|
104
|
-
pipe_end_worker.
|
104
|
+
expect(pipe_end_worker).not_to be_nil
|
105
105
|
end
|
106
106
|
end
|
107
107
|
|
data/spec/invoker/config_spec.rb
CHANGED
@@ -6,7 +6,7 @@ describe "Invoker::Config" do
|
|
6
6
|
describe "with invalid directory" do
|
7
7
|
it "should raise error during startup" do
|
8
8
|
begin
|
9
|
-
file = Tempfile.new("invalid_config.ini")
|
9
|
+
file = Tempfile.new(["invalid_config", ".ini"])
|
10
10
|
|
11
11
|
config_data =<<-EOD
|
12
12
|
[try_sleep]
|
@@ -15,9 +15,9 @@ command = ruby try_sleep.rb
|
|
15
15
|
EOD
|
16
16
|
file.write(config_data)
|
17
17
|
file.close
|
18
|
-
|
18
|
+
expect {
|
19
19
|
Invoker::Parsers::Config.new(file.path, 9000)
|
20
|
-
}.
|
20
|
+
}.to raise_error(Invoker::Errors::InvalidConfig)
|
21
21
|
ensure
|
22
22
|
file.unlink()
|
23
23
|
end
|
@@ -27,7 +27,7 @@ command = ruby try_sleep.rb
|
|
27
27
|
describe "for ports" do
|
28
28
|
it "should replace port in commands" do
|
29
29
|
begin
|
30
|
-
file = Tempfile.new("invalid_config.ini")
|
30
|
+
file = Tempfile.new(["invalid_config", ".ini"])
|
31
31
|
|
32
32
|
config_data =<<-EOD
|
33
33
|
[try_sleep]
|
@@ -48,17 +48,17 @@ command = ls
|
|
48
48
|
config = Invoker::Parsers::Config.new(file.path, 9000)
|
49
49
|
command1 = config.processes.first
|
50
50
|
|
51
|
-
command1.port.
|
52
|
-
command1.cmd.
|
51
|
+
expect(command1.port).to eq(9001)
|
52
|
+
expect(command1.cmd).to match(/9001/)
|
53
53
|
|
54
54
|
command2 = config.processes[1]
|
55
55
|
|
56
|
-
command2.port.
|
57
|
-
command2.cmd.
|
56
|
+
expect(command2.port).to eq(9002)
|
57
|
+
expect(command2.cmd).to match(/9002/)
|
58
58
|
|
59
59
|
command2 = config.processes[2]
|
60
60
|
|
61
|
-
command2.port.
|
61
|
+
expect(command2.port).to be_nil
|
62
62
|
ensure
|
63
63
|
file.unlink()
|
64
64
|
end
|
@@ -66,7 +66,7 @@ command = ls
|
|
66
66
|
|
67
67
|
it "should use port from separate option" do
|
68
68
|
begin
|
69
|
-
file = Tempfile.new("invalid_config.ini")
|
69
|
+
file = Tempfile.new(["invalid_config", ".ini"])
|
70
70
|
config_data =<<-EOD
|
71
71
|
[try_sleep]
|
72
72
|
directory = /tmp
|
@@ -87,16 +87,16 @@ command = ls
|
|
87
87
|
config = Invoker::Parsers::Config.new(file.path, 9000)
|
88
88
|
command1 = config.processes.first
|
89
89
|
|
90
|
-
command1.port.
|
91
|
-
command1.cmd.
|
90
|
+
expect(command1.port).to eq(9001)
|
91
|
+
expect(command1.cmd).to match(/9001/)
|
92
92
|
|
93
93
|
command2 = config.processes[1]
|
94
94
|
|
95
|
-
command2.port.
|
95
|
+
expect(command2.port).to eq(3000)
|
96
96
|
|
97
97
|
command2 = config.processes[2]
|
98
98
|
|
99
|
-
command2.port.
|
99
|
+
expect(command2.port).to be_nil
|
100
100
|
ensure
|
101
101
|
file.unlink()
|
102
102
|
end
|
@@ -105,7 +105,7 @@ command = ls
|
|
105
105
|
|
106
106
|
describe "loading power config" do
|
107
107
|
before do
|
108
|
-
@file = Tempfile.new("config.ini")
|
108
|
+
@file = Tempfile.new(["config", ".ini"])
|
109
109
|
end
|
110
110
|
|
111
111
|
it "does not load config if platform is not darwin" do
|
@@ -116,16 +116,54 @@ command = ls
|
|
116
116
|
|
117
117
|
it "does not load config if platform is darwin but there is no power config file" do
|
118
118
|
Invoker.expects(:darwin?).returns(true)
|
119
|
-
File.expects(:exists?).with(Invoker::Power::Config::CONFIG_LOCATION).returns(false)
|
120
119
|
Invoker::Power::Config.expects(:load_config).never
|
121
120
|
Invoker::Parsers::Config.new(@file.path, 9000)
|
122
121
|
end
|
123
122
|
|
124
123
|
it "loads config if platform is darwin and power config file exists" do
|
125
124
|
Invoker.expects(:darwin?).returns(true)
|
126
|
-
File.
|
125
|
+
File.open(Invoker::Power::Config::CONFIG_LOCATION, "w") { |fl| fl.puts "sample" }
|
127
126
|
Invoker::Power::Config.expects(:load_config).once
|
128
127
|
Invoker::Parsers::Config.new(@file.path, 9000)
|
129
128
|
end
|
130
129
|
end
|
130
|
+
|
131
|
+
describe "Procfile" do
|
132
|
+
it "should load Procfiles and create config object" do
|
133
|
+
begin
|
134
|
+
File.open("/tmp/Procfile", "w") {|fl|
|
135
|
+
fl.write <<-EOD
|
136
|
+
web: bundle exec rails s -p $PORT
|
137
|
+
EOD
|
138
|
+
}
|
139
|
+
config = Invoker::Parsers::Config.new("/tmp/Procfile", 9000)
|
140
|
+
command1 = config.processes.first
|
141
|
+
|
142
|
+
expect(command1.port).to eq(9001)
|
143
|
+
expect(command1.cmd).to match(/bundle exec rails/)
|
144
|
+
ensure
|
145
|
+
File.delete("/tmp/Procfile")
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should load environment variables from .env file" do
|
150
|
+
begin
|
151
|
+
env_file = File.new("#{ENV['PWD']}/.env", "w")
|
152
|
+
env_data =<<-EOD
|
153
|
+
TEST="test env"
|
154
|
+
EOD
|
155
|
+
env_file.write(env_data)
|
156
|
+
env_file.close()
|
157
|
+
File.open("/tmp/Procfile", "w") {|fl|
|
158
|
+
fl.write <<-EOD
|
159
|
+
web: bundle exec rails s -p $PORT
|
160
|
+
EOD
|
161
|
+
}
|
162
|
+
config = Invoker::Parsers::Config.new("/tmp/Procfile", 9000)
|
163
|
+
expect(ENV["TEST"]).to eq("test env")
|
164
|
+
ensure
|
165
|
+
File.delete("#{ENV['PWD']}/.env")
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
131
169
|
end
|
@@ -11,11 +11,11 @@ describe Invoker::Event::Manager do
|
|
11
11
|
@event_manager.trigger("foo", :exit)
|
12
12
|
|
13
13
|
@event_manager.run_scheduled_events do |event|
|
14
|
-
event.block.call.
|
14
|
+
expect(event.block.call).to eq("exit foo")
|
15
15
|
end
|
16
16
|
|
17
|
-
@event_manager.scheduled_events.
|
18
|
-
@event_manager.triggered_events.
|
17
|
+
expect(@event_manager.scheduled_events).to be_empty
|
18
|
+
expect(@event_manager.triggered_events).to be_empty
|
19
19
|
end
|
20
20
|
|
21
21
|
it "should remove triggrered and scheduld events on run" do
|
@@ -25,22 +25,17 @@ describe Invoker::Event::Manager do
|
|
25
25
|
@event_manager.trigger("baz", :exit)
|
26
26
|
|
27
27
|
@event_manager.run_scheduled_events do |event|
|
28
|
-
event.block.call.
|
28
|
+
expect(event.block.call).to eq("exit foo")
|
29
29
|
end
|
30
30
|
|
31
|
-
@event_manager.scheduled_events.
|
32
|
-
@event_manager.triggered_events.
|
31
|
+
expect(@event_manager.scheduled_events).not_to be_empty
|
32
|
+
expect(@event_manager.triggered_events).not_to be_empty
|
33
33
|
|
34
|
-
baz_containing_event =
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
bar_containing_scheduled_event = lambda do |events|
|
39
|
-
events.keys.detect {|event_key| event_key == "bar" }
|
40
|
-
end
|
34
|
+
baz_containing_event = @event_manager.triggered_events.map(&:command_label)
|
35
|
+
expect(baz_containing_event).to include("baz")
|
41
36
|
|
42
|
-
@event_manager.
|
43
|
-
|
37
|
+
bar_containing_scheduled_event = @event_manager.scheduled_events.keys
|
38
|
+
expect(bar_containing_scheduled_event).to include("bar")
|
44
39
|
end
|
45
40
|
|
46
41
|
it "should handle multiple events for same command" do
|
@@ -54,8 +49,8 @@ describe Invoker::Event::Manager do
|
|
54
49
|
@event_manager.schedule_event("foo", :exit) { 'exit foo' }
|
55
50
|
@event_manager.trigger("foo", :exit)
|
56
51
|
|
57
|
-
@event_manager.scheduled_events.
|
58
|
-
@event_manager.triggered_events.
|
52
|
+
expect(@event_manager.scheduled_events).not_to be_empty
|
53
|
+
expect(@event_manager.triggered_events).not_to be_empty
|
59
54
|
end
|
60
55
|
|
61
56
|
it "should not run unmatched events" do
|
@@ -66,7 +61,7 @@ describe Invoker::Event::Manager do
|
|
66
61
|
@event_manager.run_scheduled_events do |event|
|
67
62
|
events_ran = true
|
68
63
|
end
|
69
|
-
events_ran.
|
64
|
+
expect(events_ran).to be_false
|
70
65
|
end
|
71
66
|
end
|
72
67
|
end
|
@@ -4,12 +4,12 @@ describe "Invoker" do
|
|
4
4
|
describe "#darwin?" do
|
5
5
|
it "should return true on osx" do
|
6
6
|
Invoker.expects(:ruby_platform).returns("x86_64-darwin12.4.0")
|
7
|
-
Invoker.darwin
|
7
|
+
expect(Invoker.darwin?).to be_true
|
8
8
|
end
|
9
9
|
|
10
10
|
it "should return false on linux" do
|
11
11
|
Invoker.expects(:ruby_platform).returns("i686-linux")
|
12
|
-
Invoker.darwin
|
12
|
+
expect(Invoker.darwin?).to be_false
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
@@ -26,12 +26,12 @@ describe "Invoker" do
|
|
26
26
|
|
27
27
|
it "should return false if setup command was not run on osx" do
|
28
28
|
Invoker.expects(:ruby_platform).returns("x86_64-darwin12.4.0")
|
29
|
-
Invoker.can_run_balancer
|
29
|
+
expect(Invoker.can_run_balancer?).to be_false
|
30
30
|
end
|
31
31
|
|
32
32
|
it "should return false if platform is not osx" do
|
33
33
|
Invoker.expects(:ruby_platform).returns("i686-linux")
|
34
|
-
Invoker.can_run_balancer
|
34
|
+
expect(Invoker.can_run_balancer?).to be_false
|
35
35
|
end
|
36
36
|
|
37
37
|
it "should return true if setup was run properly" do
|
@@ -40,7 +40,7 @@ describe "Invoker" do
|
|
40
40
|
fl.write("hello")
|
41
41
|
}
|
42
42
|
|
43
|
-
Invoker.can_run_balancer
|
43
|
+
expect(Invoker.can_run_balancer?).to be_true
|
44
44
|
end
|
45
45
|
|
46
46
|
it "should not print warning if setup is not run when flag is false" do
|