initial commit

This commit is contained in:
David Dollar
2010-05-17 01:36:30 -04:00
commit 2dbd3e6be5
11 changed files with 233 additions and 0 deletions

7
bin/foreman Executable file
View File

@@ -0,0 +1,7 @@
#!/usr/bin/env ruby
$:.unshift File.expand_path("../../lib", __FILE__)
require "foreman/cli"
Foreman::CLI.start

3
example/Procfile Normal file
View File

@@ -0,0 +1,3 @@
neverdie ./never_die
diealot ./die_alot
error ./error

4
example/die_alot Executable file
View File

@@ -0,0 +1,4 @@
#!/usr/bin/env ruby
sleep 2
exit 0

4
example/error Executable file
View File

@@ -0,0 +1,4 @@
#!/usr/bin/env ruby
sleep 10
raise "Dying"

5
example/never_die Executable file
View File

@@ -0,0 +1,5 @@
#!/usr/bin/env ruby
while true
sleep 5
end

6
lib/foreman.rb Normal file
View File

@@ -0,0 +1,6 @@
module Foreman
VERSION = "0.0.1"
end

35
lib/foreman/cli.rb Normal file
View File

@@ -0,0 +1,35 @@
require "foreman"
require "foreman/engine"
require "foreman/export"
require "thor"
class Foreman::CLI < Thor
desc "start [PROCFILE]", "Run the app described in PROCFILE"
def start(procfile="Procfile")
error "#{procfile} does not exist." unless File.exist?(procfile)
Foreman::Engine.new(procfile).start
end
desc "export NAME [PROCFILE] [FORMAT]", "Export the app described in PROCFILE as NAME to another FORMAT"
def export(name, procfile="Procfile", format="upstart")
error "#{procfile} does not exist." unless File.exist?(procfile)
formatter = case format
when "upstart" then Foreman::Export::Upstart
else error "Unknown export format: #{format}"
end
formatter.new(Foreman::Engine.new(procfile)).export(name)
end
private ######################################################################
def error(message)
puts "ERROR: #{message}"
exit 1
end
end

87
lib/foreman/engine.rb Normal file
View File

@@ -0,0 +1,87 @@
require "foreman"
require "foreman/process"
class Foreman::Engine
attr_reader :procfile
attr_reader :directory
def initialize(procfile)
@procfile = File.read(procfile)
@directory = File.expand_path(File.dirname(procfile))
end
def processes
@processes ||= begin
procfile.split("\n").inject({}) do |hash, line|
next if line.strip == ""
process = Foreman::Process.new(*line.split(" ", 2))
hash.update(process.name => process)
end
end
end
def start
proctitle "ruby: foreman master"
processes.each do |name, process|
fork process
end
trap("TERM") { kill_and_exit("TERM") }
trap("INT") { kill_and_exit("INT") }
trap("INFO") { print_info }
while true
pid, status = Process.wait2
process = running_processes.delete(pid)
info "exited with code #{status}", process
fork process
end
end
private ######################################################################
def fork(process)
pid = Process.fork do
proctitle "ruby: foreman #{process.name}"
Dir.chdir directory do
system process.command
exit $?.exitstatus || 255
end
end
info "started with pid #{pid}", process
running_processes[pid] = process
end
def kill_and_exit(signal="TERM")
info "termination requested"
running_processes.each do |pid, process|
info "killing pid #{pid}", process
Process.kill(signal, pid)
end
exit 0
end
def info(message, process=nil)
puts "[foreman] [#{Time.now.utc}] [#{process ? process.name : "system"}] #{message}"
end
def print_info
info "currently running processes:"
running_processes.each do |pid, process|
info "pid #{pid}", process
end
end
def running_processes
@running_processes ||= {}
end
def proctitle(title)
$0 = title
end
end

6
lib/foreman/export.rb Normal file
View File

@@ -0,0 +1,6 @@
require "foreman"
module Foreman::Export
end
require "foreman/export/upstart"

View File

@@ -0,0 +1,63 @@
require "foreman/export"
class Foreman::Export::Upstart
attr_reader :engine
def initialize(engine)
@engine = engine
end
def export(name)
FileUtils.mkdir_p "/etc/foreman"
FileUtils.mkdir_p "/etc/init"
write_file "/etc/foreman/#{name}.conf", <<-UPSTART_CONFIG
#{name}_processes="#{engine.processes.keys.join(' ')}"
#{engine.processes.keys.map { |k| "#{name}_#{k}=\"1\"" }.join("\n")}
UPSTART_CONFIG
write_file "/etc/init/#{name}.conf", <<-UPSTART_MASTER
pre-start script
bash << "EOF"
mkdir -p /var/log/#{name}
if [ -f /etc/foreman/#{name}.conf ]; then
source /etc/foreman/#{name}.conf
fi
for process in $( echo "$#{name}_processes" ); do
process_count_config="#{name}_$process"
process_count=${!process_count_config}
for ((i=1; i<=${process_count:=1}; i+=1)); do
start #{name}-$process NUM=$i
done
done
EOF
end script
UPSTART_MASTER
engine.processes.values.each do |process|
write_file "/etc/init/#{name}-#{process.name}.conf", <<-UPSTART_CHILD
instance $NUM
stop on stopping #{name}
respawn
chdir #{engine.directory}
exec #{process.command} 2>&1 > /var/log/#{name}/#{process.name}.log
UPSTART_CHILD
end
end
private
def write_file(filename, contents)
File.open(filename, "w") do |file|
file.puts contents
end
end
end

13
lib/foreman/process.rb Normal file
View File

@@ -0,0 +1,13 @@
require "foreman"
class Foreman::Process
attr_reader :name
attr_reader :command
def initialize(name, command)
@name = name
@command = command
end
end