meepo 1.5.2

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.
Files changed (108) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +16 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +29 -0
  6. data/.travis.yml +10 -0
  7. data/Dockerfile +7 -0
  8. data/Gemfile +13 -0
  9. data/MIT-LICENSE +20 -0
  10. data/Rakefile +15 -0
  11. data/TODO +5 -0
  12. data/bin/invoker +7 -0
  13. data/contrib/completion/invoker-completion.bash +70 -0
  14. data/contrib/completion/invoker-completion.zsh +62 -0
  15. data/examples/hello_sinatra.rb +26 -0
  16. data/examples/sample.ini +3 -0
  17. data/invoker.gemspec +43 -0
  18. data/lib/invoker.rb +152 -0
  19. data/lib/invoker/cli.rb +159 -0
  20. data/lib/invoker/cli/pinger.rb +23 -0
  21. data/lib/invoker/cli/question.rb +15 -0
  22. data/lib/invoker/cli/tail.rb +34 -0
  23. data/lib/invoker/cli/tail_watcher.rb +34 -0
  24. data/lib/invoker/command_worker.rb +60 -0
  25. data/lib/invoker/commander.rb +95 -0
  26. data/lib/invoker/daemon.rb +126 -0
  27. data/lib/invoker/dns_cache.rb +23 -0
  28. data/lib/invoker/errors.rb +17 -0
  29. data/lib/invoker/event/manager.rb +79 -0
  30. data/lib/invoker/ipc.rb +45 -0
  31. data/lib/invoker/ipc/add_command.rb +12 -0
  32. data/lib/invoker/ipc/add_http_command.rb +10 -0
  33. data/lib/invoker/ipc/base_command.rb +24 -0
  34. data/lib/invoker/ipc/client_handler.rb +26 -0
  35. data/lib/invoker/ipc/dns_check_command.rb +17 -0
  36. data/lib/invoker/ipc/list_command.rb +11 -0
  37. data/lib/invoker/ipc/message.rb +170 -0
  38. data/lib/invoker/ipc/message/list_response.rb +35 -0
  39. data/lib/invoker/ipc/message/tail_response.rb +10 -0
  40. data/lib/invoker/ipc/ping_command.rb +10 -0
  41. data/lib/invoker/ipc/reload_command.rb +12 -0
  42. data/lib/invoker/ipc/remove_command.rb +12 -0
  43. data/lib/invoker/ipc/server.rb +26 -0
  44. data/lib/invoker/ipc/tail_command.rb +11 -0
  45. data/lib/invoker/ipc/unix_client.rb +60 -0
  46. data/lib/invoker/logger.rb +13 -0
  47. data/lib/invoker/parsers/config.rb +184 -0
  48. data/lib/invoker/parsers/procfile.rb +86 -0
  49. data/lib/invoker/power/balancer.rb +131 -0
  50. data/lib/invoker/power/config.rb +77 -0
  51. data/lib/invoker/power/dns.rb +38 -0
  52. data/lib/invoker/power/http_parser.rb +68 -0
  53. data/lib/invoker/power/http_response.rb +81 -0
  54. data/lib/invoker/power/pf_migrate.rb +64 -0
  55. data/lib/invoker/power/port_finder.rb +49 -0
  56. data/lib/invoker/power/power.rb +3 -0
  57. data/lib/invoker/power/powerup.rb +29 -0
  58. data/lib/invoker/power/setup.rb +90 -0
  59. data/lib/invoker/power/setup/distro/arch.rb +15 -0
  60. data/lib/invoker/power/setup/distro/base.rb +57 -0
  61. data/lib/invoker/power/setup/distro/debian.rb +11 -0
  62. data/lib/invoker/power/setup/distro/mint.rb +10 -0
  63. data/lib/invoker/power/setup/distro/opensuse.rb +11 -0
  64. data/lib/invoker/power/setup/distro/redhat.rb +11 -0
  65. data/lib/invoker/power/setup/distro/ubuntu.rb +10 -0
  66. data/lib/invoker/power/setup/files/invoker_forwarder.sh.erb +17 -0
  67. data/lib/invoker/power/setup/files/socat_invoker.service +12 -0
  68. data/lib/invoker/power/setup/linux_setup.rb +105 -0
  69. data/lib/invoker/power/setup/osx_setup.rb +137 -0
  70. data/lib/invoker/power/templates/400.html +40 -0
  71. data/lib/invoker/power/templates/404.html +40 -0
  72. data/lib/invoker/power/templates/503.html +40 -0
  73. data/lib/invoker/power/url_rewriter.rb +40 -0
  74. data/lib/invoker/process_manager.rb +198 -0
  75. data/lib/invoker/process_printer.rb +43 -0
  76. data/lib/invoker/reactor.rb +37 -0
  77. data/lib/invoker/reactor/reader.rb +54 -0
  78. data/lib/invoker/version.rb +47 -0
  79. data/readme.md +25 -0
  80. data/spec/invoker/cli/pinger_spec.rb +22 -0
  81. data/spec/invoker/cli/tail_watcher_spec.rb +39 -0
  82. data/spec/invoker/cli_spec.rb +27 -0
  83. data/spec/invoker/command_worker_spec.rb +45 -0
  84. data/spec/invoker/commander_spec.rb +152 -0
  85. data/spec/invoker/config_spec.rb +361 -0
  86. data/spec/invoker/daemon_spec.rb +34 -0
  87. data/spec/invoker/event/manager_spec.rb +67 -0
  88. data/spec/invoker/invoker_spec.rb +71 -0
  89. data/spec/invoker/ipc/client_handler_spec.rb +54 -0
  90. data/spec/invoker/ipc/dns_check_command_spec.rb +32 -0
  91. data/spec/invoker/ipc/message/list_response_spec.rb +24 -0
  92. data/spec/invoker/ipc/message_spec.rb +49 -0
  93. data/spec/invoker/ipc/unix_client_spec.rb +29 -0
  94. data/spec/invoker/power/balancer_spec.rb +22 -0
  95. data/spec/invoker/power/config_spec.rb +18 -0
  96. data/spec/invoker/power/http_parser_spec.rb +32 -0
  97. data/spec/invoker/power/http_response_spec.rb +34 -0
  98. data/spec/invoker/power/pf_migrate_spec.rb +87 -0
  99. data/spec/invoker/power/port_finder_spec.rb +16 -0
  100. data/spec/invoker/power/setup/linux_setup_spec.rb +103 -0
  101. data/spec/invoker/power/setup/osx_setup_spec.rb +105 -0
  102. data/spec/invoker/power/setup_spec.rb +4 -0
  103. data/spec/invoker/power/url_rewriter_spec.rb +70 -0
  104. data/spec/invoker/power/web_sockets_spec.rb +61 -0
  105. data/spec/invoker/process_manager_spec.rb +130 -0
  106. data/spec/invoker/reactor_spec.rb +6 -0
  107. data/spec/spec_helper.rb +43 -0
  108. metadata +389 -0
@@ -0,0 +1,361 @@
1
+ require "spec_helper"
2
+
3
+ require "tempfile"
4
+
5
+ describe "Invoker::Config" do
6
+ describe "with invalid directory" do
7
+ it "should raise error during startup" do
8
+ begin
9
+ file = Tempfile.new(["invalid_config", ".ini"])
10
+
11
+ config_data =<<-EOD
12
+ [try_sleep]
13
+ directory = /Users/gnufied/foo
14
+ command = ruby try_sleep.rb
15
+ EOD
16
+ file.write(config_data)
17
+ file.close
18
+ expect {
19
+ Invoker::Parsers::Config.new(file.path, 9000)
20
+ }.to raise_error(Invoker::Errors::InvalidConfig)
21
+ ensure
22
+ file.unlink()
23
+ end
24
+ end
25
+ end
26
+
27
+ describe "with relative directory path" do
28
+ it "should expand path in commands" do
29
+ begin
30
+ file = Tempfile.new(["config", ".ini"])
31
+
32
+ config_data =<<-EOD
33
+ [pwd_home]
34
+ directory = ~
35
+ command = pwd
36
+
37
+ [pwd_parent]
38
+ directory = ../
39
+ command = pwd
40
+ EOD
41
+ file.write(config_data)
42
+ file.close
43
+
44
+ config = Invoker::Parsers::Config.new(file.path, 9000)
45
+ command1 = config.processes.first
46
+
47
+ expect(command1.dir).to match(File.expand_path('~'))
48
+
49
+ command2 = config.processes[1]
50
+
51
+ expect(command2.dir).to match(File.expand_path('..'))
52
+ ensure
53
+ file.unlink()
54
+ end
55
+ end
56
+ end
57
+
58
+ describe "for ports" do
59
+ it "should replace port in commands" do
60
+ begin
61
+ file = Tempfile.new(["invalid_config", ".ini"])
62
+
63
+ config_data =<<-EOD
64
+ [try_sleep]
65
+ directory = /tmp
66
+ command = ruby try_sleep.rb -p $PORT
67
+
68
+ [ls]
69
+ directory = /tmp
70
+ command = ls -p $PORT
71
+
72
+ [noport]
73
+ directory = /tmp
74
+ command = ls
75
+ EOD
76
+ file.write(config_data)
77
+ file.close
78
+
79
+ config = Invoker::Parsers::Config.new(file.path, 9000)
80
+ command1 = config.processes.first
81
+
82
+ expect(command1.port).to eq(9000)
83
+ expect(command1.cmd).to match(/9000/)
84
+
85
+ command2 = config.processes[1]
86
+
87
+ expect(command2.port).to eq(9001)
88
+ expect(command2.cmd).to match(/9001/)
89
+
90
+ command2 = config.processes[2]
91
+
92
+ expect(command2.port).to be_nil
93
+ ensure
94
+ file.unlink()
95
+ end
96
+ end
97
+
98
+ it "should use port from separate option" do
99
+ begin
100
+ file = Tempfile.new(["invalid_config", ".ini"])
101
+ config_data =<<-EOD
102
+ [try_sleep]
103
+ directory = /tmp
104
+ command = ruby try_sleep.rb -p $PORT
105
+
106
+ [ls]
107
+ directory = /tmp
108
+ port = 3000
109
+ command = pwd
110
+
111
+ [noport]
112
+ directory = /tmp
113
+ command = ls
114
+ EOD
115
+ file.write(config_data)
116
+ file.close
117
+
118
+ config = Invoker::Parsers::Config.new(file.path, 9000)
119
+ command1 = config.processes.first
120
+
121
+ expect(command1.port).to eq(9000)
122
+ expect(command1.cmd).to match(/9000/)
123
+
124
+ command2 = config.processes[1]
125
+
126
+ expect(command2.port).to eq(3000)
127
+
128
+ command2 = config.processes[2]
129
+
130
+ expect(command2.port).to be_nil
131
+ ensure
132
+ file.unlink()
133
+ end
134
+ end
135
+ end
136
+
137
+ describe "loading power config", fakefs: true do
138
+ before do
139
+ FileUtils.mkdir_p('/tmp')
140
+ FileUtils.mkdir_p(inv_conf_dir)
141
+ File.open("/tmp/foo.ini", "w") { |fl| fl.write("") }
142
+ end
143
+
144
+ it "does not load config if platform is darwin but there is no power config file" do
145
+ Invoker::Power::Config.expects(:load_config).never
146
+ Invoker::Parsers::Config.new("/tmp/foo.ini", 9000)
147
+ end
148
+
149
+ it "loads config if platform is darwin and power config file exists" do
150
+ File.open(Invoker::Power::Config.config_file, "w") { |fl| fl.puts "sample" }
151
+ Invoker::Power::Config.expects(:load_config).once
152
+ Invoker::Parsers::Config.new("/tmp/foo.ini", 9000)
153
+ end
154
+ end
155
+
156
+ describe "Procfile" do
157
+ it "should load Procfiles and create config object" do
158
+ File.open("/tmp/Procfile", "w") {|fl|
159
+ fl.write <<-EOD
160
+ web: bundle exec rails s -p $PORT
161
+ EOD
162
+ }
163
+ config = Invoker::Parsers::Config.new("/tmp/Procfile", 9000)
164
+ command1 = config.processes.first
165
+
166
+ expect(command1.port).to eq(9000)
167
+ expect(command1.cmd).to match(/bundle exec rails/)
168
+ end
169
+ end
170
+
171
+ describe "Copy of DNS information" do
172
+ it "should allow copy of DNS information" do
173
+ File.open("/tmp/Procfile", "w") {|fl|
174
+ fl.write <<-EOD
175
+ web: bundle exec rails s -p $PORT
176
+ EOD
177
+ }
178
+ Invoker.load_invoker_config("/tmp/Procfile", 9000)
179
+ dns_cache = Invoker::DNSCache.new(Invoker.config)
180
+
181
+ expect(dns_cache.dns_data).to_not be_empty
182
+ expect(dns_cache.dns_data['web']).to_not be_empty
183
+ expect(dns_cache.dns_data['web']['port']).to eql 9000
184
+ end
185
+ end
186
+
187
+ describe "#autorunnable_processes" do
188
+ it "returns a list of processes that can be autorun" do
189
+ begin
190
+ file = Tempfile.new(["config", ".ini"])
191
+ config_data =<<-EOD
192
+ [postgres]
193
+ command = postgres -D /usr/local/var/postgres
194
+
195
+ [redis]
196
+ command = redis-server /usr/local/etc/redis.conf
197
+ disable_autorun = true
198
+
199
+ [memcached]
200
+ command = /usr/local/opt/memcached/bin/memcached
201
+ disable_autorun = false
202
+
203
+ [panda-api]
204
+ command = bundle exec rails s
205
+ disable_autorun = true
206
+
207
+ [panda-auth]
208
+ command = bundle exec rails s -p $PORT
209
+ EOD
210
+ file.write(config_data)
211
+ file.close
212
+
213
+ config = Invoker::Parsers::Config.new(file.path, 9000)
214
+ expect(config.autorunnable_processes.map(&:label)).to eq(['postgres', 'memcached', 'panda-auth'])
215
+ ensure
216
+ file.unlink()
217
+ end
218
+ end
219
+
220
+ it "returns a list of processes that can by index" do
221
+ begin
222
+ file = Tempfile.new(["config", ".ini"])
223
+ config_data =<<-EOD
224
+ [postgres]
225
+ command = postgres -D /usr/local/var/postgres
226
+ index = 2
227
+ sleep = 5
228
+
229
+ [redis]
230
+ command = redis-server /usr/local/etc/redis.conf
231
+ disable_autorun = true
232
+ index = 3
233
+
234
+ [memcached]
235
+ command = /usr/local/opt/memcached/bin/memcached
236
+ disable_autorun = false
237
+ index = 5
238
+
239
+ [panda-api]
240
+ command = bundle exec rails s
241
+ disable_autorun = true
242
+ index = 4
243
+
244
+ [panda-auth]
245
+ command = bundle exec rails s -p $PORT
246
+ index = 1
247
+ EOD
248
+ file.write(config_data)
249
+ file.close
250
+
251
+ config = Invoker::Parsers::Config.new(file.path, 9000)
252
+ processes = config.autorunnable_processes
253
+ expect(processes.map(&:label)).to eq(['panda-auth', 'postgres', 'memcached'])
254
+ expect(processes[0].sleep_duration).to eq(1)
255
+ expect(processes[1].sleep_duration).to eq(5)
256
+ ensure
257
+ file.unlink()
258
+ end
259
+ end
260
+ end
261
+
262
+ describe "global config file" do
263
+ it "should use global config file if available" do
264
+ begin
265
+ FileUtils.mkdir_p(Invoker::Power::Config.config_dir)
266
+ filename = "#{Invoker::Power::Config.config_dir}/foo.ini"
267
+ file = File.open(filename, "w")
268
+ config_data =<<-EOD
269
+ [try_sleep]
270
+ directory = /tmp
271
+ command = ruby try_sleep.rb
272
+ EOD
273
+ file.write(config_data)
274
+ file.close
275
+ config = Invoker::Parsers::Config.new("foo", 9000)
276
+ expect(config.filename).to eql(filename)
277
+ ensure
278
+ File.unlink(filename)
279
+ end
280
+ end
281
+ end
282
+
283
+ describe "config file autodetection" do
284
+ context "no config file given" do
285
+
286
+ def create_invoker_ini
287
+ file = File.open("invoker.ini", "w")
288
+ config_data =<<-EOD
289
+ [some_process]
290
+ command = some_command
291
+ EOD
292
+ file.write(config_data)
293
+ file.close
294
+
295
+ file
296
+ end
297
+
298
+ def create_procfile
299
+ file = File.open("Procfile", "w")
300
+ config_data =<<-EOD
301
+ some_other_process: some_other_command
302
+ EOD
303
+ file.write(config_data)
304
+ file.close
305
+
306
+ file
307
+ end
308
+
309
+ context "directory has invoker.ini" do
310
+ it "autodetects invoker.ini" do
311
+ begin
312
+ file = create_invoker_ini
313
+
314
+ config = Invoker::Parsers::Config.new(nil, 9000)
315
+ expect(config.process("some_process").cmd).to eq("some_command")
316
+ ensure
317
+ File.delete(file)
318
+ end
319
+ end
320
+ end
321
+
322
+ context "directory has Procfile" do
323
+ it "autodetects Procfile" do
324
+ begin
325
+ file = create_procfile
326
+
327
+ config = Invoker::Parsers::Config.new(nil, 9000)
328
+ expect(config.process("some_other_process").cmd).to eq("some_other_command")
329
+ ensure
330
+ File.delete(file)
331
+ end
332
+ end
333
+ end
334
+
335
+ context "directory has both invoker.ini and Procfile" do
336
+ it "prioritizes invoker.ini" do
337
+ begin
338
+ invoker_ini = create_invoker_ini
339
+ procfile = create_procfile
340
+
341
+ config = Invoker::Parsers::Config.new(nil, 9000)
342
+ expect(config.process("some_process").cmd).to eq("some_command")
343
+ processes = config.autorunnable_processes
344
+ process_1 = processes[0]
345
+ expect(process_1.sleep_duration).to eq(1)
346
+ expect(process_1.index).to eq(0)
347
+ ensure
348
+ File.delete(invoker_ini)
349
+ File.delete(procfile)
350
+ end
351
+ end
352
+ end
353
+
354
+ context "directory doesn't have invoker.ini or Procfile" do
355
+ it "aborts" do
356
+ expect { Invoker::Parsers::Config.new(nil, 9000) }.to raise_error(SystemExit)
357
+ end
358
+ end
359
+ end
360
+ end
361
+ end
@@ -0,0 +1,34 @@
1
+ require "spec_helper"
2
+
3
+ describe Invoker::Daemon do
4
+ let(:daemon) { Invoker::Daemon.new}
5
+
6
+ describe "#start" do
7
+ context "when daemon is aleady running" do
8
+ it "exits without any error" do
9
+ daemon.expects(:running?).returns(true)
10
+ begin
11
+ daemon.start
12
+ rescue SystemExit => e
13
+ expect(e.status).to be(0)
14
+ end
15
+ end
16
+ end
17
+
18
+ context "when daemon is not running" do
19
+ it "starts the daemon" do
20
+ daemon.expects(:dead?).returns(false)
21
+ daemon.expects(:running?).returns(false)
22
+ daemon.expects(:daemonize)
23
+ daemon.start
24
+ end
25
+ end
26
+ end
27
+
28
+ describe "#stop" do
29
+ it "stops the daemon" do
30
+ daemon.expects(:kill_process)
31
+ daemon.stop
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,67 @@
1
+ require "spec_helper"
2
+
3
+ describe Invoker::Event::Manager do
4
+ describe "Run scheduled events" do
5
+ before do
6
+ @event_manager = Invoker::Event::Manager.new()
7
+ end
8
+
9
+ it "should run matched events" do
10
+ @event_manager.schedule_event("foo", :exit) { 'exit foo' }
11
+ @event_manager.trigger("foo", :exit)
12
+
13
+ @event_manager.run_scheduled_events do |event|
14
+ expect(event.block.call).to eq("exit foo")
15
+ end
16
+
17
+ expect(@event_manager.scheduled_events).to be_empty
18
+ expect(@event_manager.triggered_events).to be_empty
19
+ end
20
+
21
+ it "should remove triggrered and scheduld events on run" do
22
+ @event_manager.schedule_event("foo", :exit) { 'exit foo' }
23
+ @event_manager.schedule_event("bar", :entry) { "entry bar"}
24
+ @event_manager.trigger("foo", :exit)
25
+ @event_manager.trigger("baz", :exit)
26
+
27
+ @event_manager.run_scheduled_events do |event|
28
+ expect(event.block.call).to eq("exit foo")
29
+ end
30
+
31
+ expect(@event_manager.scheduled_events).not_to be_empty
32
+ expect(@event_manager.triggered_events).not_to be_empty
33
+
34
+ baz_containing_event = @event_manager.triggered_events.map(&:command_label)
35
+ expect(baz_containing_event).to include("baz")
36
+
37
+ bar_containing_scheduled_event = @event_manager.scheduled_events.keys
38
+ expect(bar_containing_scheduled_event).to include("bar")
39
+ end
40
+
41
+ it "should handle multiple events for same command" do
42
+ @event_manager.schedule_event("foo", :exit) { 'exit foo' }
43
+ @event_manager.schedule_event("foo", :entry) { "entry bar"}
44
+ @event_manager.trigger("foo", :exit)
45
+
46
+ @event_manager.run_scheduled_events { |event| }
47
+
48
+
49
+ @event_manager.schedule_event("foo", :exit) { 'exit foo' }
50
+ @event_manager.trigger("foo", :exit)
51
+
52
+ expect(@event_manager.scheduled_events).not_to be_empty
53
+ expect(@event_manager.triggered_events).not_to be_empty
54
+ end
55
+
56
+ it "should not run unmatched events" do
57
+ @event_manager.schedule_event("bar", :entry) { "entry bar"}
58
+ @event_manager.trigger("foo", :exit)
59
+
60
+ events_ran = false
61
+ @event_manager.run_scheduled_events do |event|
62
+ events_ran = true
63
+ end
64
+ expect(events_ran).to eql false
65
+ end
66
+ end
67
+ end