Compare commits

...
32 Commits
Author SHA1 Message Date
David Dollar a3e758ab6c 0.23.1 2011-10-04 09:56:39 -04:00
David Dollar 5dc232a7b1 Merge pull request #79 from fdr/runner-dead-code
Eliminate dead code
2011-10-04 05:14:50 -07:00
Dan Farina 4191cb7b9c Eliminate dead code
An oversight; this code should probably have been pruned in
20e598abcc.

Signed-off-by: Dan Farina <drfarina@acm.org>
2011-10-04 00:19:04 -07:00
David Dollar 90d4dffb82 tweak docs 2011-09-16 18:46:10 -04:00
David Dollar 823f307abc doc updates 2011-09-16 18:42:57 -04:00
David Dollar ed44a11e21 0.23.0 2011-09-16 18:25:02 -04:00
David Dollar 5719f4fc72 allow multiple environment files to be specified 2011-09-16 18:24:38 -04:00
David Dollar 91edac3197 0.22.0 2011-09-12 20:30:19 -04:00
David Dollar 20e598abcc dont use the runner, not needed 2011-09-12 20:30:01 -04:00
David Dollar ec7f4a480d fix pkg bin 2011-09-12 19:07:25 -04:00
David Dollar 51376058d4 fix procfile to be compatible with non-unix 2011-09-12 19:07:14 -04:00
David Dollar f7542083dd Merge pull request #69 from greinacker/whitespace
Whitespace in Procfile
2011-09-12 11:39:10 -07:00
David Dollar 23124afc7e fix gitignore 2011-09-12 12:55:37 -04:00
David Dollar c948858f45 store objects in s3, list them in readme 2011-09-12 11:11:36 -04:00
David Dollar f358d897fa set up distribution mechanisms 2011-09-12 10:58:35 -04:00
Greg Reinacker ec1b06abb5 update authors list 2011-09-11 17:03:07 -06:00
Greg Reinacker 75d4fc562d accept any whitespace around : in Procfile 2011-09-11 17:01:31 -06:00
David Dollar 1cbb295b0d update authors 2011-09-09 17:06:07 -04:00
David Dollar 60fb125b51 update manual 2011-09-09 16:59:19 -04:00
David Dollar 69d596bb8b add bluepill export to docs 2011-09-09 16:59:09 -04:00
David Dollar cbd5a6344c 0.21.0 2011-09-09 16:59:01 -04:00
David Dollar 4230455859 Merge branch 'master' of github.com:ddollar/foreman 2011-09-09 16:56:32 -04:00
David Dollar b25dfee62d Merge pull request #59 from hunter/bluepill
Bluepill export
2011-09-09 13:56:02 -07:00
David Dollar b73da71c9c update rake 2011-09-09 16:54:37 -04:00
David Dollar 43558758fc Merge pull request #67 from thommay/env-for-upstart
Env for upstart
2011-09-09 13:52:32 -07:00
Thom May 6da8aca609 foreman erb doesn't have the -%> extension enabled. 2011-09-07 15:40:33 +01:00
Thom May 9df93a64cc Export environment to upstart jobs 2011-09-07 15:40:17 +01:00
Thom May 8fd9b753f4 Actually test that the environment is set correctly 2011-09-06 15:59:26 +01:00
Thom May 7fc6d02e7b Read environment at initialisation
This allows us to expose the environment attribute from the engine
object and utilise it to build exported startup files.
2011-09-01 17:26:50 +01:00
Thom May ddcaac8749 Move options into class initialisation 2011-09-01 17:06:37 +01:00
Hunter Nield 9db97abb10 Updates to get Bluepill export working & tweaks to output 2011-08-25 21:17:00 +10:00
Hunter Nield 21a041527c Added basic support for Bluepill 2011-08-22 21:24:34 +10:00
33 changed files with 555 additions and 77 deletions
+7 -7
View File
@@ -1,8 +1,8 @@
.bundle /.bundle
coverage /coverage
example/log/* /example/log/*
man/*.html /man/*.html
man/*.markdown /man/*.markdown
pkg /pkg
tags /tags
+12
View File
@@ -1,3 +1,15 @@
source "http://rubygems.org" source "http://rubygems.org"
gemspec gemspec
group :development do
gem 'parka'
gem 'rake'
gem 'ronn'
gem 'fakefs', '~> 0.2.1'
gem 'rcov', '~> 0.9.8'
gem 'rr', '~> 1.0.2'
gem 'rspec', '~> 2.6.0'
gem 'aws-s3'
gem "rubyzip"
end
+11 -2
View File
@@ -1,13 +1,18 @@
PATH PATH
remote: . remote: .
specs: specs:
foreman (0.20.0) foreman (0.23.1)
term-ansicolor (~> 1.0.5) term-ansicolor (~> 1.0.5)
thor (>= 0.13.6) thor (>= 0.13.6)
GEM GEM
remote: http://rubygems.org/ remote: http://rubygems.org/
specs: specs:
aws-s3 (0.6.2)
builder
mime-types
xml-simple
builder (3.0.0)
crack (0.1.8) crack (0.1.8)
diff-lcs (1.1.2) diff-lcs (1.1.2)
fakefs (0.2.1) fakefs (0.2.1)
@@ -18,7 +23,7 @@ GEM
crack crack
rest-client rest-client
thor thor
rake (0.8.7) rake (0.9.2)
rcov (0.9.8) rcov (0.9.8)
rdiscount (1.6.5) rdiscount (1.6.5)
rest-client (1.6.1) rest-client (1.6.1)
@@ -36,13 +41,16 @@ GEM
rspec-expectations (2.6.0) rspec-expectations (2.6.0)
diff-lcs (~> 1.1.2) diff-lcs (~> 1.1.2)
rspec-mocks (2.6.0) rspec-mocks (2.6.0)
rubyzip (0.9.4)
term-ansicolor (1.0.6) term-ansicolor (1.0.6)
thor (0.14.6) thor (0.14.6)
xml-simple (1.0.15)
PLATFORMS PLATFORMS
ruby ruby
DEPENDENCIES DEPENDENCIES
aws-s3
fakefs (~> 0.2.1) fakefs (~> 0.2.1)
foreman! foreman!
parka parka
@@ -51,3 +59,4 @@ DEPENDENCIES
ronn ronn
rr (~> 1.0.2) rr (~> 1.0.2)
rspec (~> 2.6.0) rspec (~> 2.6.0)
rubyzip
+20 -1
View File
@@ -2,8 +2,18 @@
## Installation ## Installation
* Rubygems
gem install foreman gem install foreman
* OSX
http://assets.foreman.io/foreman/foreman.pkg
* Standalone Tarball
http://assets.foreman.io/foreman/foreman.tgz
## Description ## Description
http://blog.daviddollar.org/2011/05/06/introducing-foreman.html http://blog.daviddollar.org/2011/05/06/introducing-foreman.html
@@ -19,11 +29,20 @@ Created by David Dollar
Patches contributed by: Patches contributed by:
* Adam Wiggins * Adam Wiggins
* clifff
* Dan Peterson * Dan Peterson
* Hunter Nield
* Jay Zeschin * Jay Zeschin
* Keith Rarick * Keith Rarick
* Khaja Minhajuddin
* Matt Haynes
* Michael van Rooijen
* Mike Javorski
* Nathan L Smith
* Nick Zadrozny
* Ricardo Chimal, Jr * Ricardo Chimal, Jr
* Thom May
* clifff
* Greg Reinacker
## License ## License
+112
View File
@@ -54,3 +54,115 @@ task :pages => "man:commit" do
git checkout master git checkout master
} }
end end
## dist
require "erb"
require "fileutils"
require "tmpdir"
def assemble(source, target, perms=0644)
FileUtils.mkdir_p(File.dirname(target))
File.open(target, "w") do |f|
f.puts ERB.new(File.read(source)).result(binding)
end
File.chmod(perms, target)
end
def assemble_distribution(target_dir=Dir.pwd)
distribution_files.each do |source|
target = source.gsub(/^#{project_root}/, target_dir)
FileUtils.mkdir_p(File.dirname(target))
FileUtils.cp(source, target)
end
end
GEM_BLACKLIST = %w( bundler foreman )
def assemble_gems(target_dir=Dir.pwd)
lines = %x{ bundle show }.strip.split("\n")
raise "error running bundler" unless $?.success?
%x{ env BUNDLE_WITHOUT="development:test" bundle show }.split("\n").each do |line|
if line =~ /^ \* (.*?) \((.*?)\)/
next if GEM_BLACKLIST.include?($1)
puts "vendoring: #{$1}-#{$2}"
gem_dir = %x{ bundle show #{$1} }.strip
FileUtils.mkdir_p "#{target_dir}/vendor/gems"
%x{ cp -R "#{gem_dir}" "#{target_dir}/vendor/gems" }
end
end.compact
end
def beta?
Foreman::VERSION.to_s =~ /pre/
end
def clean(file)
rm file if File.exists?(file)
end
def distribution_files
require "foreman/distribution"
Foreman::Distribution.files
end
def mkchdir(dir)
FileUtils.mkdir_p(dir)
Dir.chdir(dir) do |dir|
yield(File.expand_path(dir))
end
end
def pkg(filename)
File.expand_path("../pkg/#{filename}", __FILE__)
end
def project_root
File.dirname(__FILE__)
end
def resource(name)
File.expand_path("../dist/resources/#{name}", __FILE__)
end
def s3_connect
return if @s3_connected
require "aws/s3"
unless ENV["DAVID_RELEASE_ACCESS"] && ENV["DAVID_RELEASE_SECRET"]
puts "please set DAVID_RELEASE_ACCESS and DAVID_RELEASE_SECRET in your environment"
exit 1
end
AWS::S3::Base.establish_connection!(
:access_key_id => ENV["DAVID_RELEASE_ACCESS"],
:secret_access_key => ENV["DAVID_RELEASE_SECRET"]
)
@s3_connected = true
end
def store(package_file, filename, bucket="assets.foreman.io")
s3_connect
puts "storing: #{filename}"
AWS::S3::S3Object.store(filename, File.open(package_file), bucket, :access => :public_read)
end
def tempdir
Dir.mktmpdir do |dir|
Dir.chdir(dir) do
yield(dir)
end
end
end
def version
require "foreman/version"
Foreman::VERSION
end
Dir[File.expand_path("../dist/**/*.rake", __FILE__)].each do |rake|
import rake
end
-2
View File
@@ -1,2 +0,0 @@
#!/usr/bin/env ruby
exec ARGV.join(" ")
+2 -2
View File
@@ -1,2 +1,2 @@
ticker: ./ticker $PORT ticker: ruby ./ticker $PORT
error : ./error error : ruby ./error
+2
View File
@@ -1,5 +1,7 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
$stdout.sync = true
puts "will error in 10s" puts "will error in 10s"
sleep 5 sleep 5
raise "Dying" raise "Dying"
+3 -1
View File
@@ -1,6 +1,8 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
%w( SIGINT SIGTERM SIGHUP ).each do |signal| $stdout.sync = true
%w( SIGINT SIGTERM ).each do |signal|
trap(signal) do trap(signal) do
puts "received #{signal} but i'm ignoring it!" puts "received #{signal} but i'm ignoring it!"
end end
+27
View File
@@ -0,0 +1,27 @@
Bluepill.application("<%= app %>", :foreground => false, :log_file => "/var/log/bluepill.log") do |app|
app.uid = "<%= user %>"
app.gid = "<%= user %>"
<% engine.processes.values.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|
process.start_command = "<%= process.command.gsub("$PORT", port.to_s) %>"
process.working_dir = "<%= engine.directory %>"
process.daemonize = true
process.environment = {"PORT" => "<%= port %>"}
process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
process.stdout = process.stderr = "<%= log_root %>/<%= app %>-<%= process.name %>-<%=num%>.log"
process.monitor_children do |children|
children.stop_command "kill -QUIT {{PID}}"
end
process.group = "<%= app %>-<%= process.name %>"
end
<% end %>
<% end %>
end
+1 -1
View File
@@ -2,4 +2,4 @@ start on starting <%= app %>-<%= process.name %>
stop on stopping <%= app %>-<%= process.name %> stop on stopping <%= app %>-<%= process.name %>
respawn respawn
exec su - <%= user %> -c 'cd <%= engine.directory %>; export PORT=<%= port %>; <%= process.command %> >> <%= log_root %>/<%=process.name%>-<%=num%>.log 2>&1' exec su - <%= user %> -c 'cd <%= engine.directory %>; export PORT=<%= port %>;<% engine.environment.each_pair do |var,env| %> export <%= var.upcase %>=<%= env %>; <% end %> <%= process.command %> >> <%= log_root %>/<%=process.name%>-<%=num%>.log 2>&1'
+14
View File
@@ -0,0 +1,14 @@
file pkg("foreman-#{version}.gem") => distribution_files do |t|
sh "gem build foreman.gemspec"
sh "mv foreman-#{version}.gem #{t.name}"
end
task "gem:build" => pkg("foreman-#{version}.gem")
task "gem:clean" do
clean pkg("foreman-#{version}.gem")
end
task "gem:release" => "gem:build" do |t|
sh "parka push -f #{pkg("foreman-#{version}.gem")}"
end
+52
View File
@@ -0,0 +1,52 @@
require "erb"
file pkg("foreman-#{version}.pkg") => distribution_files do |t|
tempdir do |dir|
mkchdir("foreman") do
assemble_distribution
assemble_gems
assemble resource("pkg/foreman"), "bin/foreman", 0755
end
kbytes = %x{ du -ks foreman | cut -f 1 }
num_files = %x{ find foreman | wc -l }
mkdir_p "pkg"
mkdir_p "pkg/Resources"
mkdir_p "pkg/foreman-#{version}.pkg"
dist = File.read(resource("pkg/Distribution.erb"))
dist = ERB.new(dist).result(binding)
File.open("pkg/Distribution", "w") { |f| f.puts dist }
dist = File.read(resource("pkg/PackageInfo.erb"))
dist = ERB.new(dist).result(binding)
File.open("pkg/foreman-#{version}.pkg/PackageInfo", "w") { |f| f.puts dist }
mkdir_p "pkg/foreman-#{version}.pkg/Scripts"
cp resource("pkg/postinstall"), "pkg/foreman-#{version}.pkg/Scripts/postinstall"
chmod 0755, "pkg/foreman-#{version}.pkg/Scripts/postinstall"
sh %{ mkbom -s foreman pkg/foreman-#{version}.pkg/Bom }
Dir.chdir("foreman") do
sh %{ pax -wz -x cpio . > ../pkg/foreman-#{version}.pkg/Payload }
end
sh %{ pkgutil --flatten pkg foreman-#{version}.pkg }
cp_r "foreman-#{version}.pkg", t.name
end
end
task "pkg:build" => pkg("foreman-#{version}.pkg")
task "pkg:clean" do
clean pkg("foreman-#{version}.pkg")
end
task "pkg:release" => "pkg:build" do |t|
store pkg("foreman-#{version}.pkg"), "foreman/foreman-#{version}.pkg"
store pkg("foreman-#{version}.pkg"), "foreman/foreman-beta.pkg" if beta?
store pkg("foreman-#{version}.pkg"), "foreman/foreman.pkg" unless beta?
end
+23
View File
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<installer-script minSpecVersion="1.000000" authoringTool="org.ruby-lang.rake" authoringToolVersion="0.8.7">
<title>Foreman</title>
<options customize="never" allow-external-scripts="no"/>
<domains enable_localSystem="true"/>
<script><![CDATA[
function needs_git() {
return (system.compareVersion(system.version.ProductVersion, "10.7.0") < 0);
}
]]></script>
<choices-outline>
<line choice="git"/>
<line choice="foreman-<%= version %>"/>
</choices-outline>
<choice id="git" title="git" start_selected="false" start_enabled="false" selected="needs_git()" enabled="needs_git()">
<pkg-ref id="git.pkg" />
</choice>
<choice id="foreman-<%= version %>" title="foreman">
<pkg-ref id="io.foreman.installer"/>
</choice>
<pkg-ref id="io.foreman.installer" installKBytes="<%= kbytes %>" version="<%= version %>" auth="Root">#foreman-<%= version %>.pkg</pkg-ref>
</installer-script>
+7
View File
@@ -0,0 +1,7 @@
<pkg-info format-version="2" identifier="io.foreman.installer" version="<%= version %>" install-location="/usr/local/foreman" auth="root">
<payload installKBytes="<%= kbytes %>" numberOfFiles="<%= num_files %>"/>
<scripts>
<postinstall file="./postinstall"/>
</scripts>
</pkg-info>
+15
View File
@@ -0,0 +1,15 @@
#!/usr/bin/ruby
require "pathname"
bin_file = Pathname.new(__FILE__).realpath
gem_dir = File.expand_path("../../vendor/gems", bin_file)
Dir["#{gem_dir}/**/lib"].each do |libdir|
$:.unshift libdir
end
$:.unshift File.expand_path("../../lib", bin_file)
require "foreman/cli"
Foreman::CLI.start
+2
View File
@@ -0,0 +1,2 @@
#!/bin/sh
ln -sf /usr/local/foreman/bin/foreman /usr/bin/foreman
+15
View File
@@ -0,0 +1,15 @@
#!/usr/bin/env ruby
require "pathname"
bin_file = Pathname.new(__FILE__).realpath
gem_dir = File.expand_path("../vendor/gems", bin_file)
Dir["#{gem_dir}/**/lib"].each do |libdir|
$:.unshift libdir
end
$:.unshift File.expand_path("../lib", bin_file)
require "foreman/cli"
Foreman::CLI.start
+24
View File
@@ -0,0 +1,24 @@
file pkg("foreman-#{version}.tgz") => distribution_files do |t|
tempdir do |dir|
mkchdir("foreman") do
assemble_distribution
assemble_gems
rm_rf "bin"
assemble resource("tgz/foreman"), "foreman", 0755
end
sh "tar czvf #{t.name} foreman"
end
end
task "tgz:build" => pkg("foreman-#{version}.tgz")
task "tgz:clean" do
clean pkg("foreman-#{version}.tgz")
end
task "tgz:release" => "tgz:build" do |t|
store pkg("foreman-#{version}.tgz"), "foreman/foreman-#{version}.tgz"
store pkg("foreman-#{version}.tgz"), "foreman/foreman-beta.tgz" if beta?
store pkg("foreman-#{version}.tgz"), "foreman/foreman.tgz" unless beta?
end
-8
View File
@@ -18,12 +18,4 @@ Gem::Specification.new do |gem|
gem.add_dependency 'term-ansicolor', '~> 1.0.5' gem.add_dependency 'term-ansicolor', '~> 1.0.5'
gem.add_dependency 'thor', '>= 0.13.6' gem.add_dependency 'thor', '>= 0.13.6'
gem.add_development_dependency 'parka'
gem.add_development_dependency 'rake'
gem.add_development_dependency 'ronn'
gem.add_development_dependency 'fakefs', '~> 0.2.1'
gem.add_development_dependency 'rcov', '~> 0.9.8'
gem.add_development_dependency 'rr', '~> 1.0.2'
gem.add_development_dependency 'rspec', '~> 2.6.0'
end end
+4 -3
View File
@@ -18,9 +18,9 @@ class Foreman::CLI < Thor
check_procfile! check_procfile!
if process if process
engine.execute(process, options) engine.execute(process)
else else
engine.start(options) engine.start
end end
end end
@@ -40,6 +40,7 @@ class Foreman::CLI < Thor
formatter = case format formatter = case format
when "inittab" then Foreman::Export::Inittab when "inittab" then Foreman::Export::Inittab
when "upstart" then Foreman::Export::Upstart when "upstart" then Foreman::Export::Upstart
when "bluepill" then Foreman::Export::Bluepill
else error "Unknown export format: #{format}." else error "Unknown export format: #{format}."
end end
@@ -64,7 +65,7 @@ private ######################################################################
end end
def engine def engine
@engine ||= Foreman::Engine.new(procfile) @engine ||= Foreman::Engine.new(procfile, options)
end end
def procfile def procfile
+9
View File
@@ -0,0 +1,9 @@
module Foreman
module Distribution
def self.files
Dir[File.expand_path("../../../{bin,data,lib}/**/*", __FILE__)].select do |file|
File.file?(file)
end
end
end
end
+30 -26
View File
@@ -11,14 +11,18 @@ class Foreman::Engine
attr_reader :procfile attr_reader :procfile
attr_reader :directory attr_reader :directory
attr_reader :environment
attr_reader :options
extend Term::ANSIColor extend Term::ANSIColor
COLORS = [ cyan, yellow, green, magenta, red ] COLORS = [ cyan, yellow, green, magenta, red ]
def initialize(procfile) def initialize(procfile, options={})
@procfile = read_procfile(procfile) @procfile = read_procfile(procfile)
@directory = File.expand_path(File.dirname(procfile)) @directory = File.expand_path(File.dirname(procfile))
@options = options
@environment = read_environment_files(options[:env])
end end
def processes def processes
@@ -26,7 +30,7 @@ class Foreman::Engine
@order = [] @order = []
procfile.split("\n").inject({}) do |hash, line| procfile.split("\n").inject({}) do |hash, line|
next hash if line.strip == "" next hash if line.strip == ""
name, command = line.split(/ *: +/, 2) name, command = line.split(/\s*:\s+/, 2)
unless command unless command
warn_deprecated_procfile! warn_deprecated_procfile!
name, command = line.split(/ +/, 2) name, command = line.split(/ +/, 2)
@@ -50,13 +54,11 @@ class Foreman::Engine
end end
end end
def start(options={}) def start
environment = read_environment(options[:env])
proctitle "ruby: foreman master" proctitle "ruby: foreman master"
processes_in_order.each do |name, process| processes_in_order.each do |name, process|
fork process, options, environment fork process
end end
trap("TERM") { puts "SIGTERM received"; terminate_gracefully } trap("TERM") { puts "SIGTERM received"; terminate_gracefully }
@@ -65,10 +67,9 @@ class Foreman::Engine
watch_for_termination watch_for_termination
end end
def execute(name, options={}) def execute(name)
environment = read_environment(options[:env])
fork processes[name], options, environment fork processes[name]
trap("TERM") { puts "SIGTERM received"; terminate_gracefully } trap("TERM") { puts "SIGTERM received"; terminate_gracefully }
trap("INT") { puts "SIGINT received"; terminate_gracefully } trap("INT") { puts "SIGINT received"; terminate_gracefully }
@@ -84,16 +85,16 @@ class Foreman::Engine
private ###################################################################### private ######################################################################
def fork(process, options={}, environment={}) def fork(process)
concurrency = Foreman::Utils.parse_concurrency(options[:concurrency]) concurrency = Foreman::Utils.parse_concurrency(@options[:concurrency])
1.upto(concurrency[process.name]) do |num| 1.upto(concurrency[process.name]) do |num|
fork_individual(process, num, port_for(process, num, options[:port]), environment) fork_individual(process, num, port_for(process, num, @options[:port]))
end end
end end
def fork_individual(process, num, port, environment) def fork_individual(process, num, port)
environment.each { |k,v| ENV[k] = v } @environment.each { |k,v| ENV[k] = v }
ENV["PORT"] = port.to_s ENV["PORT"] = port.to_s
ENV["PS"] = "#{process.name}.#{num}" ENV["PS"] = "#{process.name}.#{num}"
@@ -112,7 +113,7 @@ private ######################################################################
begin begin
Dir.chdir directory do Dir.chdir directory do
PTY.spawn(runner, process.command) do |stdin, stdout, pid| PTY.spawn(process.command) do |stdin, stdout, pid|
trap("SIGTERM") { Process.kill("SIGTERM", pid) } trap("SIGTERM") { Process.kill("SIGTERM", pid) }
until stdin.eof? until stdin.eof?
info stdin.gets, process info stdin.gets, process
@@ -201,24 +202,27 @@ private ######################################################################
puts "!!! e.g. web: thin start" puts "!!! e.g. web: thin start"
end end
def read_environment(filename) def read_environment_files(filenames)
error "No such file: #{filename}" if filename && !File.exists?(filename)
filename ||= ".env"
environment = {} environment = {}
if File.exists?(filename) (filenames || "").split(",").map(&:strip).each do |filename|
File.read(filename).split("\n").each do |line| error "No such file: #{filename}" unless File.exists?(filename)
if line =~ /\A([A-Za-z_]+)=(.*)\z/ environment.merge!(read_environment(filename))
environment[$1] = $2
end
end
end end
environment.merge!(read_environment(".env")) unless filenames
environment environment
end end
def runner def read_environment(filename)
File.expand_path("../../../bin/foreman-runner", __FILE__) return {} unless File.exists?(filename)
File.read(filename).split("\n").inject({}) do |hash, line|
if line =~ /\A([A-Za-z_]+)=(.*)\z/
hash[$1] = $2
end
hash
end
end end
def terminate_gracefully def terminate_gracefully
+1
View File
@@ -7,3 +7,4 @@ end
require "foreman/export/base" require "foreman/export/base"
require "foreman/export/inittab" require "foreman/export/inittab"
require "foreman/export/upstart" require "foreman/export/upstart"
require "foreman/export/bluepill"
+29
View File
@@ -0,0 +1,29 @@
require "erb"
require "foreman/export"
class Foreman::Export::Bluepill < Foreman::Export::Base
def export(location, options={})
error("Must specify a location") unless location
FileUtils.mkdir_p location
app = options[:app] || File.basename(engine.directory)
user = options[:user] || app
log_root = options[:log] || "/var/log/#{app}"
template_root = options[:template]
Dir["#{location}/#{app}.pill"].each do |file|
say "cleaning up: #{file}"
FileUtils.rm(file)
end
concurrency = Foreman::Utils.parse_concurrency(options[:concurrency])
master_template = export_template("bluepill", "master.pill.erb", template_root)
master_config = ERB.new(master_template).result(binding)
write_file "#{location}/#{app}.pill", master_config
end
end
+1 -1
View File
@@ -1,5 +1,5 @@
module Foreman module Foreman
VERSION = "0.20.0" VERSION = "0.23.1"
end end
+6 -3
View File
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "FOREMAN" "1" "August 2011" "Foreman 0.19.0" "Foreman Manual" .TH "FOREMAN" "1" "September 2011" "Foreman 0.23.0" "Foreman Manual"
. .
.SH "NAME" .SH "NAME"
\fBforeman\fR \- manage Procfile\-based applications \fBforeman\fR \- manage Procfile\-based applications
@@ -69,7 +69,7 @@ These options control all modes of foreman\'s operation\.
. .
.TP .TP
\fB\-e\fR, \fB\-\-env\fR \fB\-e\fR, \fB\-\-env\fR
Specify an alternate environment file\. Specify an alternate environment file\. You can specify more than one file by using: \fB\-\-env file1,file2\fR\.
. .
.TP .TP
\fB\-f\fR, \fB\-\-procfile\fR \fB\-f\fR, \fB\-\-procfile\fR
@@ -79,6 +79,9 @@ Specify an alternate location for the application\'s Procfile\. This file\'s con
foreman currently supports the following output formats: foreman currently supports the following output formats:
. .
.IP "\(bu" 4 .IP "\(bu" 4
bluepill
.
.IP "\(bu" 4
inittab inittab
. .
.IP "\(bu" 4 .IP "\(bu" 4
@@ -162,7 +165,7 @@ If a \fB\.foreman\fR file exists in the current directory, default options will
. .
.nf .nf
concurrency: alpha=0 concurrency: alpha=0,bravo=1
port: 15000 port: 15000
. .
.fi .fi
+5 -2
View File
@@ -67,7 +67,8 @@ The following options control how the application is run:
These options control all modes of foreman's operation. These options control all modes of foreman's operation.
* `-e`, `--env`: * `-e`, `--env`:
Specify an alternate environment file. Specify an alternate environment file. You can specify more than one
file by using: `--env file1,file2`.
* `-f`, `--procfile`: * `-f`, `--procfile`:
Specify an alternate location for the application's Procfile. This file's Specify an alternate location for the application's Procfile. This file's
@@ -78,6 +79,8 @@ These options control all modes of foreman's operation.
foreman currently supports the following output formats: foreman currently supports the following output formats:
* bluepill
* inittab * inittab
* upstart * upstart
@@ -129,7 +132,7 @@ If a `.foreman` file exists in the current directory, default options will
be read from it. This file should be in YAML format with the long option be read from it. This file should be in YAML format with the long option
name as keys. Example: name as keys. Example:
concurrency: alpha=0 concurrency: alpha=0,bravo=1
port: 15000 port: 15000
## EXAMPLES ## EXAMPLES
+1 -1
View File
@@ -19,7 +19,7 @@ describe "Foreman::CLI" do
it "runs successfully" do it "runs successfully" do
dont_allow(subject).error dont_allow(subject).error
mock.instance_of(Foreman::Engine).start({}) mock.instance_of(Foreman::Engine).start
subject.start subject.start
end end
end end
+34 -16
View File
@@ -2,7 +2,7 @@ require "spec_helper"
require "foreman/engine" require "foreman/engine"
describe "Foreman::Engine" do describe "Foreman::Engine" do
subject { Foreman::Engine.new("Procfile") } subject { Foreman::Engine.new("Procfile", {}) }
describe "initialize" do describe "initialize" do
describe "without an existing Procfile" do describe "without an existing Procfile" do
@@ -37,53 +37,71 @@ 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.processes["alpha"], {}, {}) mock(subject).fork(subject.processes["alpha"])
mock(subject).fork(subject.processes["bravo"], {}, {}) mock(subject).fork(subject.processes["bravo"])
mock(subject).watch_for_termination mock(subject).watch_for_termination
subject.start subject.start
end end
it "handles concurrency" do it "handles concurrency" do
write_procfile write_procfile
mock(subject).fork_individual(subject.processes["alpha"], 1, 5000, {}) engine = Foreman::Engine.new("Procfile",:concurrency => "alpha=2")
mock(subject).fork_individual(subject.processes["alpha"], 2, 5001, {}) mock(engine).fork_individual(engine.processes["alpha"], 1, 5000)
mock(subject).fork_individual(subject.processes["bravo"], 1, 5100, {}) mock(engine).fork_individual(engine.processes["alpha"], 2, 5001)
mock(subject).watch_for_termination mock(engine).fork_individual(engine.processes["bravo"], 1, 5100)
subject.start(:concurrency => "alpha=2") mock(engine).watch_for_termination
engine.start
end end
end end
describe "execute" do describe "execute" do
it "runs the processes" do it "runs the processes" do
write_procfile write_procfile
mock(subject).fork(subject.processes["alpha"], {}, {}) mock(subject).fork(subject.processes["alpha"])
mock(subject).watch_for_termination mock(subject).watch_for_termination
subject.execute("alpha") subject.execute("alpha")
end end
end end
describe "environment" do describe "environment" do
before(:each) do before(:each) do
write_procfile write_procfile
stub(Process).fork stub(Process).fork
stub(subject).info
mock(subject).watch_for_termination
end end
it "should read if specified" do it "should read if specified" do
File.open("/tmp/env", "w") { |f| f.puts("FOO=baz") } File.open("/tmp/env", "w") { |f| f.puts("FOO=baz") }
subject.execute("alpha", :env => "/tmp/env") engine = Foreman::Engine.new("Procfile", :env => "/tmp/env")
stub(engine).info
mock(engine).watch_for_termination
engine.environment.should == {"FOO"=>"baz"}
engine.execute("alpha")
end
it "should read more than one if specified" do
File.open("/tmp/env1", "w") { |f| f.puts("FOO=bar") }
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).watch_for_termination
engine.environment.should == { "FOO"=>"bar", "BAZ"=>"qux" }
engine.execute("alpha")
end end
it "should fail if specified and doesnt exist" do it "should fail if specified and doesnt exist" do
mock(subject).error("No such file: /tmp/env") mock.instance_of(Foreman::Engine).error("No such file: /tmp/env")
subject.execute("alpha", :env => "/tmp/env") engine = Foreman::Engine.new("Procfile", :env => "/tmp/env")
end end
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") }
mock(subject).fork_individual(anything, anything, anything, { "FOO" => "qoo" }) engine = Foreman::Engine.new("Procfile")
subject.execute("bravo") stub(engine).info
mock(engine).watch_for_termination
mock(engine).fork_individual(anything, anything, anything)
engine.environment.should == {"FOO"=>"qoo"}
engine.execute("bravo")
end end
end end
end end
+20
View File
@@ -0,0 +1,20 @@
require "spec_helper"
require "foreman/engine"
require "foreman/export/bluepill"
require "tmpdir"
describe Foreman::Export::Bluepill do
let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
let(:engine) { Foreman::Engine.new(procfile) }
let(:bluepill) { Foreman::Export::Bluepill.new(engine) }
before(:each) { load_export_templates_into_fakefs("bluepill") }
before(:each) { stub(bluepill).say }
it "exports to the filesystem" do
bluepill.export("/tmp/init")
File.read("/tmp/init/app.pill").should == example_export_file("bluepill/app.pill")
end
end
+65
View File
@@ -0,0 +1,65 @@
Bluepill.application("app", :foreground => false, :log_file => "/var/log/bluepill.log") do |app|
app.uid = "app"
app.gid = "app"
app.process("alpha-1") do |process|
process.start_command = "./alpha"
process.working_dir = "/tmp/app"
process.daemonize = true
process.environment = {"PORT" => "5000"}
process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
process.stdout = process.stderr = "/var/log/app/app-alpha-1.log"
process.monitor_children do |children|
children.stop_command "kill -QUIT {{PID}}"
end
process.group = "app-alpha"
end
app.process("alpha-2") do |process|
process.start_command = "./alpha"
process.working_dir = "/tmp/app"
process.daemonize = true
process.environment = {"PORT" => "5001"}
process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
process.stdout = process.stderr = "/var/log/app/app-alpha-2.log"
process.monitor_children do |children|
children.stop_command "kill -QUIT {{PID}}"
end
process.group = "app-alpha"
end
app.process("bravo-1") do |process|
process.start_command = "./bravo"
process.working_dir = "/tmp/app"
process.daemonize = true
process.environment = {"PORT" => "5100"}
process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
process.stdout = process.stderr = "/var/log/app/app-bravo-1.log"
process.monitor_children do |children|
children.stop_command "kill -QUIT {{PID}}"
end
process.group = "app-bravo"
end
end
+1 -1
View File
@@ -28,7 +28,7 @@ def write_procfile(procfile="Procfile")
File.open(procfile, "w") do |file| File.open(procfile, "w") do |file|
file.puts "alpha: ./alpha" file.puts "alpha: ./alpha"
file.puts "\n" file.puts "\n"
file.puts "bravo: ./bravo" file.puts "bravo:\t./bravo"
end end
File.expand_path(procfile) File.expand_path(procfile)
end end