Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be73e8500f | ||
|
|
d26ca669a1 | ||
|
|
a3e758ab6c | ||
|
|
5dc232a7b1 | ||
|
|
4191cb7b9c | ||
|
|
90d4dffb82 | ||
|
|
823f307abc | ||
|
|
ed44a11e21 | ||
|
|
5719f4fc72 | ||
|
|
91edac3197 | ||
|
|
20e598abcc | ||
|
|
ec7f4a480d | ||
|
|
51376058d4 | ||
|
|
f7542083dd | ||
|
|
23124afc7e | ||
|
|
c948858f45 | ||
|
|
f358d897fa | ||
|
|
ec1b06abb5 | ||
|
|
75d4fc562d | ||
|
|
1cbb295b0d | ||
|
|
60fb125b51 | ||
|
|
69d596bb8b | ||
|
|
cbd5a6344c | ||
|
|
4230455859 | ||
|
|
b25dfee62d | ||
|
|
b73da71c9c | ||
|
|
43558758fc | ||
|
|
6da8aca609 | ||
|
|
9df93a64cc | ||
|
|
8fd9b753f4 | ||
|
|
7fc6d02e7b | ||
|
|
ddcaac8749 | ||
|
|
9db97abb10 | ||
|
|
21a041527c |
14
.gitignore
vendored
14
.gitignore
vendored
@@ -1,8 +1,8 @@
|
||||
.bundle
|
||||
coverage
|
||||
example/log/*
|
||||
man/*.html
|
||||
man/*.markdown
|
||||
pkg
|
||||
tags
|
||||
/.bundle
|
||||
/coverage
|
||||
/example/log/*
|
||||
/man/*.html
|
||||
/man/*.markdown
|
||||
/pkg
|
||||
/tags
|
||||
|
||||
|
||||
12
Gemfile
12
Gemfile
@@ -1,3 +1,15 @@
|
||||
source "http://rubygems.org"
|
||||
|
||||
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
|
||||
|
||||
13
Gemfile.lock
13
Gemfile.lock
@@ -1,13 +1,18 @@
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
foreman (0.20.0)
|
||||
foreman (0.24.0)
|
||||
term-ansicolor (~> 1.0.5)
|
||||
thor (>= 0.13.6)
|
||||
|
||||
GEM
|
||||
remote: http://rubygems.org/
|
||||
specs:
|
||||
aws-s3 (0.6.2)
|
||||
builder
|
||||
mime-types
|
||||
xml-simple
|
||||
builder (3.0.0)
|
||||
crack (0.1.8)
|
||||
diff-lcs (1.1.2)
|
||||
fakefs (0.2.1)
|
||||
@@ -18,7 +23,7 @@ GEM
|
||||
crack
|
||||
rest-client
|
||||
thor
|
||||
rake (0.8.7)
|
||||
rake (0.9.2)
|
||||
rcov (0.9.8)
|
||||
rdiscount (1.6.5)
|
||||
rest-client (1.6.1)
|
||||
@@ -36,13 +41,16 @@ GEM
|
||||
rspec-expectations (2.6.0)
|
||||
diff-lcs (~> 1.1.2)
|
||||
rspec-mocks (2.6.0)
|
||||
rubyzip (0.9.4)
|
||||
term-ansicolor (1.0.6)
|
||||
thor (0.14.6)
|
||||
xml-simple (1.0.15)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
aws-s3
|
||||
fakefs (~> 0.2.1)
|
||||
foreman!
|
||||
parka
|
||||
@@ -51,3 +59,4 @@ DEPENDENCIES
|
||||
ronn
|
||||
rr (~> 1.0.2)
|
||||
rspec (~> 2.6.0)
|
||||
rubyzip
|
||||
|
||||
@@ -2,8 +2,18 @@
|
||||
|
||||
## Installation
|
||||
|
||||
* Rubygems
|
||||
|
||||
gem install foreman
|
||||
|
||||
* OSX
|
||||
|
||||
http://assets.foreman.io/foreman/foreman.pkg
|
||||
|
||||
* Standalone Tarball
|
||||
|
||||
http://assets.foreman.io/foreman/foreman.tgz
|
||||
|
||||
## Description
|
||||
|
||||
http://blog.daviddollar.org/2011/05/06/introducing-foreman.html
|
||||
@@ -19,11 +29,20 @@ Created by David Dollar
|
||||
Patches contributed by:
|
||||
|
||||
* Adam Wiggins
|
||||
* clifff
|
||||
* Dan Peterson
|
||||
* Hunter Nield
|
||||
* Jay Zeschin
|
||||
* Keith Rarick
|
||||
* Khaja Minhajuddin
|
||||
* Matt Haynes
|
||||
* Michael van Rooijen
|
||||
* Mike Javorski
|
||||
* Nathan L Smith
|
||||
* Nick Zadrozny
|
||||
* Ricardo Chimal, Jr
|
||||
* Thom May
|
||||
* clifff
|
||||
* Greg Reinacker
|
||||
|
||||
## License
|
||||
|
||||
|
||||
112
Rakefile
112
Rakefile
@@ -54,3 +54,115 @@ task :pages => "man:commit" do
|
||||
git checkout master
|
||||
}
|
||||
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
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
exec ARGV.join(" ")
|
||||
@@ -1,2 +1,2 @@
|
||||
ticker: ./ticker $PORT
|
||||
error : ./error
|
||||
ticker: ruby ./ticker $PORT
|
||||
error: ruby ./error
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
$stdout.sync = true
|
||||
|
||||
puts "will error in 10s"
|
||||
sleep 5
|
||||
raise "Dying"
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
%w( SIGINT SIGTERM SIGHUP ).each do |signal|
|
||||
$stdout.sync = true
|
||||
|
||||
%w( SIGINT SIGTERM ).each do |signal|
|
||||
trap(signal) do
|
||||
puts "received #{signal} but i'm ignoring it!"
|
||||
end
|
||||
|
||||
27
data/export/bluepill/master.pill.erb
Normal file
27
data/export/bluepill/master.pill.erb
Normal 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.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
|
||||
@@ -2,4 +2,4 @@ start on starting <%= app %>-<%= process.name %>
|
||||
stop on stopping <%= app %>-<%= process.name %>
|
||||
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
dist/gem.rake
vendored
Normal file
14
dist/gem.rake
vendored
Normal 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
dist/pkg.rake
vendored
Normal file
52
dist/pkg.rake
vendored
Normal 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
dist/resources/pkg/Distribution.erb
vendored
Normal file
23
dist/resources/pkg/Distribution.erb
vendored
Normal 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
dist/resources/pkg/PackageInfo.erb
vendored
Normal file
7
dist/resources/pkg/PackageInfo.erb
vendored
Normal 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
dist/resources/pkg/foreman
vendored
Normal file
15
dist/resources/pkg/foreman
vendored
Normal 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
dist/resources/pkg/postinstall
vendored
Normal file
2
dist/resources/pkg/postinstall
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
ln -sf /usr/local/foreman/bin/foreman /usr/bin/foreman
|
||||
15
dist/resources/tgz/foreman
vendored
Normal file
15
dist/resources/tgz/foreman
vendored
Normal 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
dist/tgz.rake
vendored
Normal file
24
dist/tgz.rake
vendored
Normal 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
|
||||
@@ -18,12 +18,4 @@ Gem::Specification.new do |gem|
|
||||
|
||||
gem.add_dependency 'term-ansicolor', '~> 1.0.5'
|
||||
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
|
||||
|
||||
@@ -18,9 +18,9 @@ class Foreman::CLI < Thor
|
||||
check_procfile!
|
||||
|
||||
if process
|
||||
engine.execute(process, options)
|
||||
engine.execute(process)
|
||||
else
|
||||
engine.start(options)
|
||||
engine.start
|
||||
end
|
||||
end
|
||||
|
||||
@@ -40,6 +40,7 @@ class Foreman::CLI < Thor
|
||||
formatter = case format
|
||||
when "inittab" then Foreman::Export::Inittab
|
||||
when "upstart" then Foreman::Export::Upstart
|
||||
when "bluepill" then Foreman::Export::Bluepill
|
||||
else error "Unknown export format: #{format}."
|
||||
end
|
||||
|
||||
@@ -52,9 +53,8 @@ class Foreman::CLI < Thor
|
||||
desc "check", "Validate your application's Procfile"
|
||||
|
||||
def check
|
||||
processes = engine.processes_in_order.map { |p| p.first }
|
||||
error "no processes defined" unless processes.length > 0
|
||||
display "valid procfile detected (#{processes.join(', ')})"
|
||||
error "no processes defined" unless engine.processes.length > 0
|
||||
display "valid procfile detected (#{engine.processes.map(&:name).join(', ')})"
|
||||
end
|
||||
|
||||
private ######################################################################
|
||||
@@ -64,7 +64,7 @@ private ######################################################################
|
||||
end
|
||||
|
||||
def engine
|
||||
@engine ||= Foreman::Engine.new(procfile)
|
||||
@engine ||= Foreman::Engine.new(procfile, options)
|
||||
end
|
||||
|
||||
def procfile
|
||||
|
||||
9
lib/foreman/distribution.rb
Normal file
9
lib/foreman/distribution.rb
Normal 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
|
||||
@@ -1,5 +1,6 @@
|
||||
require "foreman"
|
||||
require "foreman/process"
|
||||
require "foreman/procfile"
|
||||
require "foreman/utils"
|
||||
require "pty"
|
||||
require "tempfile"
|
||||
@@ -11,89 +12,65 @@ class Foreman::Engine
|
||||
|
||||
attr_reader :procfile
|
||||
attr_reader :directory
|
||||
attr_reader :environment
|
||||
attr_reader :options
|
||||
|
||||
extend Term::ANSIColor
|
||||
|
||||
COLORS = [ cyan, yellow, green, magenta, red ]
|
||||
|
||||
def initialize(procfile)
|
||||
@procfile = read_procfile(procfile)
|
||||
def initialize(procfile, options={})
|
||||
@procfile = Foreman::Procfile.new(procfile)
|
||||
@directory = File.expand_path(File.dirname(procfile))
|
||||
@options = options
|
||||
@environment = read_environment_files(options[:env])
|
||||
end
|
||||
|
||||
def start
|
||||
proctitle "ruby: foreman master"
|
||||
|
||||
processes.each do |process|
|
||||
process.color = next_color
|
||||
fork process
|
||||
end
|
||||
|
||||
trap("TERM") { puts "SIGTERM received"; terminate_gracefully }
|
||||
trap("INT") { puts "SIGINT received"; terminate_gracefully }
|
||||
|
||||
watch_for_termination
|
||||
end
|
||||
|
||||
def execute(name)
|
||||
fork procfile[name]
|
||||
|
||||
trap("TERM") { puts "SIGTERM received"; terminate_gracefully }
|
||||
trap("INT") { puts "SIGINT received"; terminate_gracefully }
|
||||
|
||||
watch_for_termination
|
||||
end
|
||||
|
||||
def processes
|
||||
@processes ||= begin
|
||||
@order = []
|
||||
procfile.split("\n").inject({}) do |hash, line|
|
||||
next hash if line.strip == ""
|
||||
name, command = line.split(/ *: +/, 2)
|
||||
unless command
|
||||
warn_deprecated_procfile!
|
||||
name, command = line.split(/ +/, 2)
|
||||
end
|
||||
process = Foreman::Process.new(name, command)
|
||||
process.color = next_color
|
||||
@order << process.name
|
||||
hash.update(process.name => process)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def process_order
|
||||
processes
|
||||
@order.uniq
|
||||
end
|
||||
|
||||
def processes_in_order
|
||||
process_order.map do |name|
|
||||
[name, processes[name]]
|
||||
end
|
||||
end
|
||||
|
||||
def start(options={})
|
||||
environment = read_environment(options[:env])
|
||||
|
||||
proctitle "ruby: foreman master"
|
||||
|
||||
processes_in_order.each do |name, process|
|
||||
fork process, options, environment
|
||||
end
|
||||
|
||||
trap("TERM") { puts "SIGTERM received"; terminate_gracefully }
|
||||
trap("INT") { puts "SIGINT received"; terminate_gracefully }
|
||||
|
||||
watch_for_termination
|
||||
end
|
||||
|
||||
def execute(name, options={})
|
||||
environment = read_environment(options[:env])
|
||||
|
||||
fork processes[name], options, environment
|
||||
|
||||
trap("TERM") { puts "SIGTERM received"; terminate_gracefully }
|
||||
trap("INT") { puts "SIGINT received"; terminate_gracefully }
|
||||
|
||||
watch_for_termination
|
||||
procfile.processes
|
||||
end
|
||||
|
||||
def port_for(process, num, base_port=nil)
|
||||
base_port ||= 5000
|
||||
offset = processes_in_order.map { |p| p.first }.index(process.name) * 100
|
||||
offset = procfile.process_names.index(process.name) * 100
|
||||
base_port.to_i + offset + num - 1
|
||||
end
|
||||
|
||||
private ######################################################################
|
||||
|
||||
def fork(process, options={}, environment={})
|
||||
concurrency = Foreman::Utils.parse_concurrency(options[:concurrency])
|
||||
def fork(process)
|
||||
concurrency = Foreman::Utils.parse_concurrency(@options[:concurrency])
|
||||
|
||||
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
|
||||
|
||||
def fork_individual(process, num, port, environment)
|
||||
environment.each { |k,v| ENV[k] = v }
|
||||
def fork_individual(process, num, port)
|
||||
@environment.each { |k,v| ENV[k] = v }
|
||||
|
||||
ENV["PORT"] = port.to_s
|
||||
ENV["PS"] = "#{process.name}.#{num}"
|
||||
@@ -112,7 +89,7 @@ private ######################################################################
|
||||
|
||||
begin
|
||||
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) }
|
||||
until stdin.eof?
|
||||
info stdin.gets, process
|
||||
@@ -133,6 +110,24 @@ private ######################################################################
|
||||
end
|
||||
end
|
||||
|
||||
def terminate_gracefully
|
||||
info "sending SIGTERM to all processes"
|
||||
kill_all "SIGTERM"
|
||||
Timeout.timeout(3) { Process.waitall }
|
||||
rescue Timeout::Error
|
||||
info "sending SIGKILL to all processes"
|
||||
kill_all "SIGKILL"
|
||||
end
|
||||
|
||||
def watch_for_termination
|
||||
pid, status = Process.wait2
|
||||
process = running_processes.delete(pid)
|
||||
info "process terminated", process
|
||||
terminate_gracefully
|
||||
kill_all
|
||||
rescue Errno::ECHILD
|
||||
end
|
||||
|
||||
def info(message, process=nil)
|
||||
print process.color if process
|
||||
print "#{Time.now.strftime("%H:%M:%S")} #{pad_process_name(process)} | "
|
||||
@@ -148,7 +143,7 @@ private ######################################################################
|
||||
|
||||
def longest_process_name
|
||||
@longest_process_name ||= begin
|
||||
longest = processes.keys.map { |name| name.length }.sort.last
|
||||
longest = procfile.process_names.map { |name| name.length }.sort.last
|
||||
longest = 6 if longest < 6 # system
|
||||
longest
|
||||
end
|
||||
@@ -159,30 +154,10 @@ private ######################################################################
|
||||
name.ljust(longest_process_name + 3) # add 3 for process number padding
|
||||
end
|
||||
|
||||
def print_info
|
||||
info "currently running processes:"
|
||||
running_processes.each do |pid, process|
|
||||
info "pid #{pid}", process
|
||||
end
|
||||
end
|
||||
|
||||
def proctitle(title)
|
||||
$0 = title
|
||||
end
|
||||
|
||||
def read_procfile(procfile)
|
||||
File.read(procfile)
|
||||
end
|
||||
|
||||
def watch_for_termination
|
||||
pid, status = Process.wait2
|
||||
process = running_processes.delete(pid)
|
||||
info "process terminated", process
|
||||
terminate_gracefully
|
||||
kill_all
|
||||
rescue Errno::ECHILD
|
||||
end
|
||||
|
||||
def running_processes
|
||||
@running_processes ||= {}
|
||||
end
|
||||
@@ -193,41 +168,27 @@ private ######################################################################
|
||||
@current_color >= COLORS.length ? "" : COLORS[@current_color]
|
||||
end
|
||||
|
||||
def warn_deprecated_procfile!
|
||||
return if @already_warned_deprecated
|
||||
@already_warned_deprecated = true
|
||||
puts "!!! This format of Procfile is deprecated, and will not work starting in v0.12"
|
||||
puts "!!! Use a colon to separate the process name from the command"
|
||||
puts "!!! e.g. web: thin start"
|
||||
end
|
||||
|
||||
def read_environment(filename)
|
||||
error "No such file: #{filename}" if filename && !File.exists?(filename)
|
||||
filename ||= ".env"
|
||||
def read_environment_files(filenames)
|
||||
environment = {}
|
||||
|
||||
if File.exists?(filename)
|
||||
File.read(filename).split("\n").each do |line|
|
||||
if line =~ /\A([A-Za-z_]+)=(.*)\z/
|
||||
environment[$1] = $2
|
||||
end
|
||||
end
|
||||
(filenames || "").split(",").map(&:strip).each do |filename|
|
||||
error "No such file: #{filename}" unless File.exists?(filename)
|
||||
environment.merge!(read_environment(filename))
|
||||
end
|
||||
|
||||
environment.merge!(read_environment(".env")) unless filenames
|
||||
environment
|
||||
end
|
||||
|
||||
def runner
|
||||
File.expand_path("../../../bin/foreman-runner", __FILE__)
|
||||
end
|
||||
def read_environment(filename)
|
||||
return {} unless File.exists?(filename)
|
||||
|
||||
def terminate_gracefully
|
||||
info "sending SIGTERM to all processes"
|
||||
kill_all "SIGTERM"
|
||||
Timeout.timeout(3) { Process.waitall }
|
||||
rescue Timeout::Error
|
||||
info "sending SIGKILL to all processes"
|
||||
kill_all "SIGKILL"
|
||||
File.read(filename).split("\n").inject({}) do |hash, line|
|
||||
if line =~ /\A([A-Za-z_]+)=(.*)\z/
|
||||
hash[$1] = $2
|
||||
end
|
||||
hash
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -7,3 +7,4 @@ end
|
||||
require "foreman/export/base"
|
||||
require "foreman/export/inittab"
|
||||
require "foreman/export/upstart"
|
||||
require "foreman/export/bluepill"
|
||||
|
||||
29
lib/foreman/export/bluepill.rb
Normal file
29
lib/foreman/export/bluepill.rb
Normal 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
|
||||
@@ -26,7 +26,7 @@ class Foreman::Export::Upstart < Foreman::Export::Base
|
||||
|
||||
process_template = export_template("upstart", "process.conf.erb", template_root)
|
||||
|
||||
engine.processes.values.each do |process|
|
||||
engine.processes.each do |process|
|
||||
process_master_template = export_template("upstart", "process_master.conf.erb", template_root)
|
||||
process_master_config = ERB.new(process_master_template).result(binding)
|
||||
write_file "#{location}/#{app}-#{process.name}.conf", process_master_config
|
||||
|
||||
37
lib/foreman/procfile.rb
Normal file
37
lib/foreman/procfile.rb
Normal file
@@ -0,0 +1,37 @@
|
||||
require "foreman"
|
||||
|
||||
# A valid Procfile entry is captured by this regex.
|
||||
# All other lines are ignored.
|
||||
#
|
||||
# /^([A-Za-z0-9_]+):\s*(.+)$/
|
||||
#
|
||||
# $1 = name
|
||||
# $2 = command
|
||||
#
|
||||
class Foreman::Procfile
|
||||
|
||||
attr_reader :processes
|
||||
|
||||
def initialize(filename)
|
||||
@processes = parse_procfile(filename)
|
||||
end
|
||||
|
||||
def process_names
|
||||
processes.map(&:name)
|
||||
end
|
||||
|
||||
def [](name)
|
||||
processes.detect { |process| process.name == name }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def parse_procfile(filename)
|
||||
File.read(filename).split("\n").map do |line|
|
||||
if line =~ /^([A-Za-z0-9_]+):\s*(.+)$/
|
||||
Foreman::Process.new($1, $2)
|
||||
end
|
||||
end.compact
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,5 +1,5 @@
|
||||
module Foreman
|
||||
|
||||
VERSION = "0.20.0"
|
||||
VERSION = "0.24.0"
|
||||
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.\" generated with Ronn/v0.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"
|
||||
\fBforeman\fR \- manage Procfile\-based applications
|
||||
@@ -69,7 +69,7 @@ These options control all modes of foreman\'s operation\.
|
||||
.
|
||||
.TP
|
||||
\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
|
||||
\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:
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
bluepill
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
inittab
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
@@ -162,7 +165,7 @@ If a \fB\.foreman\fR file exists in the current directory, default options will
|
||||
.
|
||||
.nf
|
||||
|
||||
concurrency: alpha=0
|
||||
concurrency: alpha=0,bravo=1
|
||||
port: 15000
|
||||
.
|
||||
.fi
|
||||
|
||||
@@ -67,7 +67,8 @@ The following options control how the application is run:
|
||||
These options control all modes of foreman's operation.
|
||||
|
||||
* `-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`:
|
||||
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:
|
||||
|
||||
* bluepill
|
||||
|
||||
* inittab
|
||||
|
||||
* 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
|
||||
name as keys. Example:
|
||||
|
||||
concurrency: alpha=0
|
||||
concurrency: alpha=0,bravo=1
|
||||
port: 15000
|
||||
|
||||
## EXAMPLES
|
||||
|
||||
@@ -19,7 +19,7 @@ describe "Foreman::CLI" do
|
||||
|
||||
it "runs successfully" do
|
||||
dont_allow(subject).error
|
||||
mock.instance_of(Foreman::Engine).start({})
|
||||
mock.instance_of(Foreman::Engine).start
|
||||
subject.start
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,7 +2,7 @@ require "spec_helper"
|
||||
require "foreman/engine"
|
||||
|
||||
describe "Foreman::Engine" do
|
||||
subject { Foreman::Engine.new("Procfile") }
|
||||
subject { Foreman::Engine.new("Procfile", {}) }
|
||||
|
||||
describe "initialize" do
|
||||
describe "without an existing Procfile" do
|
||||
@@ -15,21 +15,8 @@ describe "Foreman::Engine" do
|
||||
before { write_procfile }
|
||||
|
||||
it "reads the processes" do
|
||||
subject.processes["alpha"].command.should == "./alpha"
|
||||
subject.processes["bravo"].command.should == "./bravo"
|
||||
end
|
||||
end
|
||||
|
||||
describe "with a deprecated Procfile" do
|
||||
before do
|
||||
File.open("Procfile", "w") do |file|
|
||||
file.puts "name command"
|
||||
end
|
||||
end
|
||||
|
||||
it "should print a deprecation warning" do
|
||||
mock(subject).warn_deprecated_procfile!
|
||||
subject.processes.length.should == 1
|
||||
subject.procfile["alpha"].command.should == "./alpha"
|
||||
subject.procfile["bravo"].command.should == "./bravo"
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -37,26 +24,27 @@ describe "Foreman::Engine" do
|
||||
describe "start" do
|
||||
it "forks the processes" do
|
||||
write_procfile
|
||||
mock(subject).fork(subject.processes["alpha"], {}, {})
|
||||
mock(subject).fork(subject.processes["bravo"], {}, {})
|
||||
mock(subject).fork(subject.procfile["alpha"])
|
||||
mock(subject).fork(subject.procfile["bravo"])
|
||||
mock(subject).watch_for_termination
|
||||
subject.start
|
||||
end
|
||||
|
||||
it "handles concurrency" do
|
||||
write_procfile
|
||||
mock(subject).fork_individual(subject.processes["alpha"], 1, 5000, {})
|
||||
mock(subject).fork_individual(subject.processes["alpha"], 2, 5001, {})
|
||||
mock(subject).fork_individual(subject.processes["bravo"], 1, 5100, {})
|
||||
mock(subject).watch_for_termination
|
||||
subject.start(:concurrency => "alpha=2")
|
||||
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(engine).watch_for_termination
|
||||
engine.start
|
||||
end
|
||||
end
|
||||
|
||||
describe "execute" do
|
||||
it "runs the processes" do
|
||||
write_procfile
|
||||
mock(subject).fork(subject.processes["alpha"], {}, {})
|
||||
mock(subject).fork(subject.procfile["alpha"])
|
||||
mock(subject).watch_for_termination
|
||||
subject.execute("alpha")
|
||||
end
|
||||
@@ -66,24 +54,40 @@ describe "Foreman::Engine" do
|
||||
before(:each) do
|
||||
write_procfile
|
||||
stub(Process).fork
|
||||
stub(subject).info
|
||||
mock(subject).watch_for_termination
|
||||
end
|
||||
|
||||
it "should read if specified" do
|
||||
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
|
||||
|
||||
it "should fail if specified and doesnt exist" do
|
||||
mock(subject).error("No such file: /tmp/env")
|
||||
subject.execute("alpha", :env => "/tmp/env")
|
||||
mock.instance_of(Foreman::Engine).error("No such file: /tmp/env")
|
||||
engine = Foreman::Engine.new("Procfile", :env => "/tmp/env")
|
||||
end
|
||||
|
||||
it "should read .env if none specified" do
|
||||
File.open(".env", "w") { |f| f.puts("FOO=qoo") }
|
||||
mock(subject).fork_individual(anything, anything, anything, { "FOO" => "qoo" })
|
||||
subject.execute("bravo")
|
||||
engine = Foreman::Engine.new("Procfile")
|
||||
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
|
||||
|
||||
20
spec/foreman/export/bluepill_spec.rb
Normal file
20
spec/foreman/export/bluepill_spec.rb
Normal 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
spec/resources/export/bluepill/app.pill
Normal file
65
spec/resources/export/bluepill/app.pill
Normal 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
|
||||
@@ -28,7 +28,7 @@ def write_procfile(procfile="Procfile")
|
||||
File.open(procfile, "w") do |file|
|
||||
file.puts "alpha: ./alpha"
|
||||
file.puts "\n"
|
||||
file.puts "bravo: ./bravo"
|
||||
file.puts "bravo:\t./bravo"
|
||||
end
|
||||
File.expand_path(procfile)
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user