wip
This commit is contained in:
1 parent
c9411cd2b1
commit
5436b68cf1
12 files changed
+52
-59
No files matched your search
@@ -1,5 +1,2 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
echo "command[$*][$1]"
|
|
||||||
|
|
||||||
exec $1 2>&1
|
exec $1 2>&1
|
||||||
@@ -3,7 +3,7 @@ Bluepill.application("<%= app %>", :foreground => false, :log_file => "/var/log/
|
|||||||
app.uid = "<%= user %>"
|
app.uid = "<%= user %>"
|
||||||
app.gid = "<%= user %>"
|
app.gid = "<%= user %>"
|
||||||
|
|
||||||
<% engine.processes.each do |process| %>
|
<% engine.procfile.entries.each do |process| %>
|
||||||
<% 1.upto(concurrency[process.name]) do |num| %>
|
<% 1.upto(concurrency[process.name]) do |num| %>
|
||||||
<% port = engine.port_for(process, num, options[:port]) %>
|
<% port = engine.port_for(process, num, options[:port]) %>
|
||||||
app.process("<%= process.name %>-<%=num%>") do |process|
|
app.process("<%= process.name %>-<%=num%>") do |process|
|
||||||
|
|||||||
@@ -9,5 +9,10 @@ module Foreman
|
|||||||
require 'foreman/engine'
|
require 'foreman/engine'
|
||||||
Foreman::Engine.load_env!(env_file)
|
Foreman::Engine.load_env!(env_file)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.runner
|
||||||
|
File.expand_path("../../bin/runner", __FILE__)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
+5
-10
@@ -8,20 +8,15 @@ class Foreman::CLI < Thor
|
|||||||
|
|
||||||
class_option :procfile, :type => :string, :aliases => "-f", :desc => "Default: Procfile"
|
class_option :procfile, :type => :string, :aliases => "-f", :desc => "Default: Procfile"
|
||||||
|
|
||||||
desc "start [PROCESS]", "Start the application, or a specific process"
|
desc "start", "Start the application"
|
||||||
|
|
||||||
method_option :env, :type => :string, :aliases => "-e", :desc => "Specify an environment file to load, defaults to .env"
|
method_option :env, :type => :string, :aliases => "-e", :desc => "Specify an environment file to load, defaults to .env"
|
||||||
method_option :port, :type => :numeric, :aliases => "-p"
|
method_option :port, :type => :numeric, :aliases => "-p"
|
||||||
method_option :concurrency, :type => :string, :aliases => "-c", :banner => '"alpha=5,bar=3"'
|
method_option :concurrency, :type => :string, :aliases => "-c", :banner => '"alpha=5,bar=3"'
|
||||||
|
|
||||||
def start(process=nil)
|
def start
|
||||||
check_procfile!
|
check_procfile!
|
||||||
|
engine.start
|
||||||
if process
|
|
||||||
engine.execute(process)
|
|
||||||
else
|
|
||||||
engine.start
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "export FORMAT LOCATION", "Export the application to another process management format"
|
desc "export FORMAT LOCATION", "Export the application to another process management format"
|
||||||
@@ -55,8 +50,8 @@ class Foreman::CLI < Thor
|
|||||||
desc "check", "Validate your application's Procfile"
|
desc "check", "Validate your application's Procfile"
|
||||||
|
|
||||||
def check
|
def check
|
||||||
error "no processes defined" unless engine.processes.length > 0
|
error "no processes defined" unless engine.procfile.entries.length > 0
|
||||||
display "valid procfile detected (#{engine.processes.map(&:name).join(', ')})"
|
display "valid procfile detected (#{engine.procfile.process_names.join(', ')})"
|
||||||
end
|
end
|
||||||
|
|
||||||
private ######################################################################
|
private ######################################################################
|
||||||
|
|||||||
@@ -57,16 +57,19 @@ private ######################################################################
|
|||||||
|
|
||||||
procfile.entries.each do |entry|
|
procfile.entries.each do |entry|
|
||||||
reader, writer = IO.pipe
|
reader, writer = IO.pipe
|
||||||
entry.spawn(concurrency[entry.name], writer, @directory, @environment).each do |process|
|
entry.spawn(concurrency[entry.name], writer, @directory, @environment, base_port).each do |process|
|
||||||
running_processes[process.pid] = process
|
running_processes[process.pid] = process
|
||||||
readers[process] = reader
|
readers[process] = reader
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def base_port
|
||||||
|
options[:port] || 5000
|
||||||
|
end
|
||||||
|
|
||||||
def kill_all(signal="SIGTERM")
|
def kill_all(signal="SIGTERM")
|
||||||
running_processes.each do |pid, process|
|
running_processes.each do |pid, process|
|
||||||
p [:killing, pid]
|
|
||||||
Process.kill(signal, pid) rescue Errno::ESRCH
|
Process.kill(signal, pid) rescue Errno::ESRCH
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class Foreman::Export::Inittab < Foreman::Export::Base
|
|||||||
inittab = []
|
inittab = []
|
||||||
inittab << "# ----- foreman #{app} processes -----"
|
inittab << "# ----- foreman #{app} processes -----"
|
||||||
|
|
||||||
engine.processes.inject(1) do |index, process|
|
engine.procfile.entries.inject(1) do |index, process|
|
||||||
1.upto(concurrency[process.name]) do |num|
|
1.upto(concurrency[process.name]) do |num|
|
||||||
id = app.slice(0, 2).upcase + sprintf("%02d", index)
|
id = app.slice(0, 2).upcase + sprintf("%02d", index)
|
||||||
port = engine.port_for(process, num, options[:port])
|
port = engine.port_for(process, num, options[:port])
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class Foreman::Export::Runit < Foreman::Export::Base
|
|||||||
run_template = export_template('runit', 'run.erb', template_root)
|
run_template = export_template('runit', 'run.erb', template_root)
|
||||||
log_run_template = export_template('runit', 'log_run.erb', template_root)
|
log_run_template = export_template('runit', 'log_run.erb', template_root)
|
||||||
|
|
||||||
engine.processes.each do |process|
|
engine.procfile.entries.each do |process|
|
||||||
1.upto(concurrency[process.name]) do |num|
|
1.upto(concurrency[process.name]) do |num|
|
||||||
process_directory = "#{location}/#{app}-#{process.name}-#{num}"
|
process_directory = "#{location}/#{app}-#{process.name}-#{num}"
|
||||||
process_env_directory = "#{process_directory}/env"
|
process_env_directory = "#{process_directory}/env"
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class Foreman::Export::Upstart < Foreman::Export::Base
|
|||||||
|
|
||||||
process_template = export_template("upstart", "process.conf.erb", template_root)
|
process_template = export_template("upstart", "process.conf.erb", template_root)
|
||||||
|
|
||||||
engine.processes.each do |process|
|
engine.procfile.entries.each do |process|
|
||||||
next if (conc = concurrency[process.name]) < 1
|
next if (conc = concurrency[process.name]) < 1
|
||||||
process_master_template = export_template("upstart", "process_master.conf.erb", template_root)
|
process_master_template = export_template("upstart", "process_master.conf.erb", template_root)
|
||||||
process_master_config = ERB.new(process_master_template).result(binding)
|
process_master_config = ERB.new(process_master_template).result(binding)
|
||||||
|
|||||||
+19
-12
@@ -5,24 +5,18 @@ class Foreman::Process
|
|||||||
attr_reader :entry
|
attr_reader :entry
|
||||||
attr_reader :num
|
attr_reader :num
|
||||||
attr_reader :pid
|
attr_reader :pid
|
||||||
|
attr_reader :port
|
||||||
|
|
||||||
def initialize(entry, num)
|
def initialize(entry, num, port)
|
||||||
@entry = entry
|
@entry = entry
|
||||||
@num = num
|
@num = num
|
||||||
|
@port = port
|
||||||
end
|
end
|
||||||
|
|
||||||
def run(pipe, basedir, environment)
|
def run(pipe, basedir, environment)
|
||||||
Dir.chdir(basedir) do
|
Dir.chdir(basedir) do
|
||||||
with_environment(environment) do
|
with_environment(environment.merge("PORT" => port.to_s)) do
|
||||||
io = IO.popen(["/Users/david/Code/foreman/bin/runner", "#{entry.command}"], "w+")
|
run_process entry.command
|
||||||
@pid = io.pid
|
|
||||||
trap("SIGTERM") { "got sigterm for %d" % @pid }
|
|
||||||
output pipe, "started with pid %d" % @pid
|
|
||||||
Thread.new do
|
|
||||||
until io.eof?
|
|
||||||
output pipe, io.gets
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -33,11 +27,24 @@ class Foreman::Process
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def run_process(command)
|
||||||
|
io = IO.popen([Foreman.runner, replace_command_env(command)], "w+")
|
||||||
|
@pid = io.pid
|
||||||
|
trap("SIGTERM") { "got sigterm for %d" % @pid }
|
||||||
|
output pipe, "started with pid %d" % @pid
|
||||||
|
Thread.new do
|
||||||
|
until io.eof?
|
||||||
|
output pipe, io.gets
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def output(pipe, message)
|
def output(pipe, message)
|
||||||
pipe.puts "%s,%s" % [ name, message ]
|
pipe.puts "%s,%s" % [ name, message ]
|
||||||
end
|
end
|
||||||
|
|
||||||
def replace_command
|
def replace_command_env(command)
|
||||||
|
command.gsub(/\$(\w+)/) { |e| ENV[e[1..-1]] }
|
||||||
end
|
end
|
||||||
|
|
||||||
def with_environment(environment)
|
def with_environment(environment)
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ class Foreman::ProcfileEntry
|
|||||||
@command = command
|
@command = command
|
||||||
end
|
end
|
||||||
|
|
||||||
def spawn(num, pipe, basedir, environment)
|
def spawn(num, pipe, basedir, environment, base_port)
|
||||||
(1..num).to_a.map do |n|
|
(1..num).to_a.map do |n|
|
||||||
process = Foreman::Process.new(self, n)
|
process = Foreman::Process.new(self, n, base_port + (n-1))
|
||||||
process.run(pipe, basedir, environment)
|
process.run(pipe, basedir, environment)
|
||||||
process
|
process
|
||||||
end
|
end
|
||||||
|
|||||||
+12
-25
@@ -24,8 +24,9 @@ describe "Foreman::Engine" do
|
|||||||
describe "start" do
|
describe "start" do
|
||||||
it "forks the processes" do
|
it "forks the processes" do
|
||||||
write_procfile
|
write_procfile
|
||||||
mock(subject).fork(subject.procfile["alpha"])
|
mock.instance_of(Foreman::Process).run_process("./alpha")
|
||||||
mock(subject).fork(subject.procfile["bravo"])
|
mock.instance_of(Foreman::Process).run_process("./bravo")
|
||||||
|
mock(subject).watch_for_output
|
||||||
mock(subject).watch_for_termination
|
mock(subject).watch_for_termination
|
||||||
subject.start
|
subject.start
|
||||||
end
|
end
|
||||||
@@ -33,29 +34,14 @@ describe "Foreman::Engine" do
|
|||||||
it "handles concurrency" do
|
it "handles concurrency" do
|
||||||
write_procfile
|
write_procfile
|
||||||
engine = Foreman::Engine.new("Procfile",:concurrency => "alpha=2")
|
engine = Foreman::Engine.new("Procfile",:concurrency => "alpha=2")
|
||||||
mock(engine).fork_individual(engine.procfile["alpha"], 1, 5000)
|
mock.instance_of(Foreman::Process).run_process("./alpha").twice
|
||||||
mock(engine).fork_individual(engine.procfile["alpha"], 2, 5001)
|
mock.instance_of(Foreman::Process).run_process("./bravo")
|
||||||
mock(engine).fork_individual(engine.procfile["bravo"], 1, 5100)
|
mock(engine).watch_for_output
|
||||||
mock(engine).watch_for_termination
|
mock(engine).watch_for_termination
|
||||||
engine.start
|
engine.start
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "execute" do
|
|
||||||
it "runs the processes" do
|
|
||||||
write_procfile
|
|
||||||
mock(subject).fork(subject.procfile["alpha"])
|
|
||||||
mock(subject).watch_for_termination
|
|
||||||
subject.execute("alpha")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "shows an error running a process that doesnt exist" do
|
|
||||||
write_procfile
|
|
||||||
mock(subject).puts("ERROR: no such process: foo")
|
|
||||||
lambda { subject.execute("foo") }.should raise_error(SystemExit)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "environment" do
|
describe "environment" do
|
||||||
before(:each) do
|
before(:each) do
|
||||||
write_procfile
|
write_procfile
|
||||||
@@ -66,9 +52,10 @@ describe "Foreman::Engine" do
|
|||||||
File.open("/tmp/env", "w") { |f| f.puts("FOO=baz") }
|
File.open("/tmp/env", "w") { |f| f.puts("FOO=baz") }
|
||||||
engine = Foreman::Engine.new("Procfile", :env => "/tmp/env")
|
engine = Foreman::Engine.new("Procfile", :env => "/tmp/env")
|
||||||
stub(engine).info
|
stub(engine).info
|
||||||
|
mock(engine).spawn_processes
|
||||||
mock(engine).watch_for_termination
|
mock(engine).watch_for_termination
|
||||||
engine.environment.should == {"FOO"=>"baz"}
|
engine.environment.should == {"FOO"=>"baz"}
|
||||||
engine.execute("alpha")
|
engine.start
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should read more than one if specified" do
|
it "should read more than one if specified" do
|
||||||
@@ -76,9 +63,10 @@ describe "Foreman::Engine" do
|
|||||||
File.open("/tmp/env2", "w") { |f| f.puts("BAZ=qux") }
|
File.open("/tmp/env2", "w") { |f| f.puts("BAZ=qux") }
|
||||||
engine = Foreman::Engine.new("Procfile", :env => "/tmp/env1,/tmp/env2")
|
engine = Foreman::Engine.new("Procfile", :env => "/tmp/env1,/tmp/env2")
|
||||||
stub(engine).info
|
stub(engine).info
|
||||||
|
mock(engine).spawn_processes
|
||||||
mock(engine).watch_for_termination
|
mock(engine).watch_for_termination
|
||||||
engine.environment.should == { "FOO"=>"bar", "BAZ"=>"qux" }
|
engine.environment.should == { "FOO"=>"bar", "BAZ"=>"qux" }
|
||||||
engine.execute("alpha")
|
engine.start
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should fail if specified and doesnt exist" do
|
it "should fail if specified and doesnt exist" do
|
||||||
@@ -89,11 +77,10 @@ describe "Foreman::Engine" do
|
|||||||
it "should read .env if none specified" do
|
it "should read .env if none specified" do
|
||||||
File.open(".env", "w") { |f| f.puts("FOO=qoo") }
|
File.open(".env", "w") { |f| f.puts("FOO=qoo") }
|
||||||
engine = Foreman::Engine.new("Procfile")
|
engine = Foreman::Engine.new("Procfile")
|
||||||
stub(engine).info
|
mock(engine).spawn_processes
|
||||||
mock(engine).watch_for_termination
|
mock(engine).watch_for_termination
|
||||||
mock(engine).fork_individual(anything, anything, anything)
|
|
||||||
engine.environment.should == {"FOO"=>"qoo"}
|
engine.environment.should == {"FOO"=>"qoo"}
|
||||||
engine.execute("bravo")
|
engine.start
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -13,7 +13,6 @@ describe Foreman::Export::Bluepill do
|
|||||||
|
|
||||||
it "exports to the filesystem" do
|
it "exports to the filesystem" do
|
||||||
bluepill.export("/tmp/init", :concurrency => "alpha=2")
|
bluepill.export("/tmp/init", :concurrency => "alpha=2")
|
||||||
|
|
||||||
File.read("/tmp/init/app.pill").should == example_export_file("bluepill/app.pill")
|
File.read("/tmp/init/app.pill").should == example_export_file("bluepill/app.pill")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user