wip
This commit is contained in:
@@ -1,5 +1,2 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "command[$*][$1]"
|
||||
|
||||
exec $1 2>&1
|
||||
|
||||
@@ -3,7 +3,7 @@ Bluepill.application("<%= app %>", :foreground => false, :log_file => "/var/log/
|
||||
app.uid = "<%= user %>"
|
||||
app.gid = "<%= user %>"
|
||||
|
||||
<% engine.processes.each do |process| %>
|
||||
<% engine.procfile.entries.each do |process| %>
|
||||
<% 1.upto(concurrency[process.name]) do |num| %>
|
||||
<% port = engine.port_for(process, num, options[:port]) %>
|
||||
app.process("<%= process.name %>-<%=num%>") do |process|
|
||||
@@ -19,7 +19,7 @@ Bluepill.application("<%= app %>", :foreground => false, :log_file => "/var/log/
|
||||
process.monitor_children do |children|
|
||||
children.stop_command "kill -QUIT {{PID}}"
|
||||
end
|
||||
|
||||
|
||||
process.group = "<%= app %>-<%= process.name %>"
|
||||
end
|
||||
<% end %>
|
||||
|
||||
@@ -9,5 +9,10 @@ module Foreman
|
||||
require 'foreman/engine'
|
||||
Foreman::Engine.load_env!(env_file)
|
||||
end
|
||||
|
||||
def self.runner
|
||||
File.expand_path("../../bin/runner", __FILE__)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -8,20 +8,15 @@ class Foreman::CLI < Thor
|
||||
|
||||
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 :port, :type => :numeric, :aliases => "-p"
|
||||
method_option :concurrency, :type => :string, :aliases => "-c", :banner => '"alpha=5,bar=3"'
|
||||
|
||||
def start(process=nil)
|
||||
def start
|
||||
check_procfile!
|
||||
|
||||
if process
|
||||
engine.execute(process)
|
||||
else
|
||||
engine.start
|
||||
end
|
||||
engine.start
|
||||
end
|
||||
|
||||
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"
|
||||
|
||||
def check
|
||||
error "no processes defined" unless engine.processes.length > 0
|
||||
display "valid procfile detected (#{engine.processes.map(&:name).join(', ')})"
|
||||
error "no processes defined" unless engine.procfile.entries.length > 0
|
||||
display "valid procfile detected (#{engine.procfile.process_names.join(', ')})"
|
||||
end
|
||||
|
||||
private ######################################################################
|
||||
|
||||
@@ -57,16 +57,19 @@ private ######################################################################
|
||||
|
||||
procfile.entries.each do |entry|
|
||||
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
|
||||
readers[process] = reader
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def base_port
|
||||
options[:port] || 5000
|
||||
end
|
||||
|
||||
def kill_all(signal="SIGTERM")
|
||||
running_processes.each do |pid, process|
|
||||
p [:killing, pid]
|
||||
Process.kill(signal, pid) rescue Errno::ESRCH
|
||||
end
|
||||
end
|
||||
|
||||
@@ -12,7 +12,7 @@ class Foreman::Export::Inittab < Foreman::Export::Base
|
||||
inittab = []
|
||||
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|
|
||||
id = app.slice(0, 2).upcase + sprintf("%02d", index)
|
||||
port = engine.port_for(process, num, options[:port])
|
||||
|
||||
@@ -3,58 +3,58 @@ require "foreman/export"
|
||||
|
||||
class Foreman::Export::Runit < Foreman::Export::Base
|
||||
ENV_VARIABLE_REGEX = /([a-zA-Z_]+[a-zA-Z0-9_]*)=(\S+)/
|
||||
|
||||
|
||||
def export(location, options={})
|
||||
error("Must specify a location") unless location
|
||||
|
||||
|
||||
app = options[:app] || File.basename(engine.directory)
|
||||
user = options[:user] || app
|
||||
log_root = options[:log] || "/var/log/#{app}"
|
||||
template_root = options[:template]
|
||||
|
||||
|
||||
concurrency = Foreman::Utils.parse_concurrency(options[:concurrency])
|
||||
|
||||
|
||||
run_template = export_template('runit', '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|
|
||||
process_directory = "#{location}/#{app}-#{process.name}-#{num}"
|
||||
process_env_directory = "#{process_directory}/env"
|
||||
process_log_directory = "#{process_directory}/log"
|
||||
|
||||
|
||||
create_directory process_directory
|
||||
create_directory process_env_directory
|
||||
create_directory process_log_directory
|
||||
|
||||
|
||||
run = ERB.new(run_template).result(binding)
|
||||
write_file "#{process_directory}/run", run
|
||||
|
||||
|
||||
port = engine.port_for(process, num, options[:port])
|
||||
environment_variables = {'PORT' => port}.
|
||||
merge(engine.environment).
|
||||
merge(inline_variables(process.command))
|
||||
|
||||
|
||||
environment_variables.each_pair do |var, env|
|
||||
write_file "#{process_env_directory}/#{var.upcase}", env
|
||||
end
|
||||
|
||||
|
||||
log_run = ERB.new(log_run_template).result(binding)
|
||||
write_file "#{process_log_directory}/run", log_run
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def create_directory(location)
|
||||
say "creating: #{location}"
|
||||
FileUtils.mkdir(location)
|
||||
end
|
||||
|
||||
|
||||
def inline_variables(command)
|
||||
variable_name_regex =
|
||||
variable_name_regex =
|
||||
Hash[*command.scan(ENV_VARIABLE_REGEX).flatten]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -26,7 +26,7 @@ class Foreman::Export::Upstart < Foreman::Export::Base
|
||||
|
||||
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
|
||||
process_master_template = export_template("upstart", "process_master.conf.erb", template_root)
|
||||
process_master_config = ERB.new(process_master_template).result(binding)
|
||||
|
||||
@@ -5,24 +5,18 @@ class Foreman::Process
|
||||
attr_reader :entry
|
||||
attr_reader :num
|
||||
attr_reader :pid
|
||||
attr_reader :port
|
||||
|
||||
def initialize(entry, num)
|
||||
def initialize(entry, num, port)
|
||||
@entry = entry
|
||||
@num = num
|
||||
@port = port
|
||||
end
|
||||
|
||||
def run(pipe, basedir, environment)
|
||||
Dir.chdir(basedir) do
|
||||
with_environment(environment) do
|
||||
io = IO.popen(["/Users/david/Code/foreman/bin/runner", "#{entry.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
|
||||
with_environment(environment.merge("PORT" => port.to_s)) do
|
||||
run_process entry.command
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -33,11 +27,24 @@ class Foreman::Process
|
||||
|
||||
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)
|
||||
pipe.puts "%s,%s" % [ name, message ]
|
||||
end
|
||||
|
||||
def replace_command
|
||||
def replace_command_env(command)
|
||||
command.gsub(/\$(\w+)/) { |e| ENV[e[1..-1]] }
|
||||
end
|
||||
|
||||
def with_environment(environment)
|
||||
|
||||
@@ -11,9 +11,9 @@ class Foreman::ProcfileEntry
|
||||
@command = command
|
||||
end
|
||||
|
||||
def spawn(num, pipe, basedir, environment)
|
||||
def spawn(num, pipe, basedir, environment, base_port)
|
||||
(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
|
||||
end
|
||||
|
||||
@@ -24,8 +24,9 @@ describe "Foreman::Engine" do
|
||||
describe "start" do
|
||||
it "forks the processes" do
|
||||
write_procfile
|
||||
mock(subject).fork(subject.procfile["alpha"])
|
||||
mock(subject).fork(subject.procfile["bravo"])
|
||||
mock.instance_of(Foreman::Process).run_process("./alpha")
|
||||
mock.instance_of(Foreman::Process).run_process("./bravo")
|
||||
mock(subject).watch_for_output
|
||||
mock(subject).watch_for_termination
|
||||
subject.start
|
||||
end
|
||||
@@ -33,29 +34,14 @@ describe "Foreman::Engine" do
|
||||
it "handles concurrency" do
|
||||
write_procfile
|
||||
engine = Foreman::Engine.new("Procfile",:concurrency => "alpha=2")
|
||||
mock(engine).fork_individual(engine.procfile["alpha"], 1, 5000)
|
||||
mock(engine).fork_individual(engine.procfile["alpha"], 2, 5001)
|
||||
mock(engine).fork_individual(engine.procfile["bravo"], 1, 5100)
|
||||
mock.instance_of(Foreman::Process).run_process("./alpha").twice
|
||||
mock.instance_of(Foreman::Process).run_process("./bravo")
|
||||
mock(engine).watch_for_output
|
||||
mock(engine).watch_for_termination
|
||||
engine.start
|
||||
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
|
||||
before(:each) do
|
||||
write_procfile
|
||||
@@ -66,9 +52,10 @@ describe "Foreman::Engine" do
|
||||
File.open("/tmp/env", "w") { |f| f.puts("FOO=baz") }
|
||||
engine = Foreman::Engine.new("Procfile", :env => "/tmp/env")
|
||||
stub(engine).info
|
||||
mock(engine).spawn_processes
|
||||
mock(engine).watch_for_termination
|
||||
engine.environment.should == {"FOO"=>"baz"}
|
||||
engine.execute("alpha")
|
||||
engine.start
|
||||
end
|
||||
|
||||
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") }
|
||||
engine = Foreman::Engine.new("Procfile", :env => "/tmp/env1,/tmp/env2")
|
||||
stub(engine).info
|
||||
mock(engine).spawn_processes
|
||||
mock(engine).watch_for_termination
|
||||
engine.environment.should == { "FOO"=>"bar", "BAZ"=>"qux" }
|
||||
engine.execute("alpha")
|
||||
engine.start
|
||||
end
|
||||
|
||||
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
|
||||
File.open(".env", "w") { |f| f.puts("FOO=qoo") }
|
||||
engine = Foreman::Engine.new("Procfile")
|
||||
stub(engine).info
|
||||
mock(engine).spawn_processes
|
||||
mock(engine).watch_for_termination
|
||||
mock(engine).fork_individual(anything, anything, anything)
|
||||
engine.environment.should == {"FOO"=>"qoo"}
|
||||
engine.execute("bravo")
|
||||
engine.start
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -13,8 +13,7 @@ describe Foreman::Export::Bluepill do
|
||||
|
||||
it "exports to the filesystem" do
|
||||
bluepill.export("/tmp/init", :concurrency => "alpha=2")
|
||||
|
||||
File.read("/tmp/init/app.pill").should == example_export_file("bluepill/app.pill")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,7 +19,7 @@ Bluepill.application("app", :foreground => false, :log_file => "/var/log/bluepil
|
||||
process.monitor_children do |children|
|
||||
children.stop_command "kill -QUIT {{PID}}"
|
||||
end
|
||||
|
||||
|
||||
process.group = "app-alpha"
|
||||
end
|
||||
|
||||
@@ -37,7 +37,7 @@ Bluepill.application("app", :foreground => false, :log_file => "/var/log/bluepil
|
||||
process.monitor_children do |children|
|
||||
children.stop_command "kill -QUIT {{PID}}"
|
||||
end
|
||||
|
||||
|
||||
process.group = "app-alpha"
|
||||
end
|
||||
|
||||
@@ -57,7 +57,7 @@ Bluepill.application("app", :foreground => false, :log_file => "/var/log/bluepil
|
||||
process.monitor_children do |children|
|
||||
children.stop_command "kill -QUIT {{PID}}"
|
||||
end
|
||||
|
||||
|
||||
process.group = "app-bravo"
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user