Compare commits

...
67 Commits
Author SHA1 Message Date
David Dollar 1905a7c310 Merge pull request #388 from brixen/patch-1
Update README.md
2013-09-04 16:49:36 -07:00
Brian Shirai 134b31f599 Update README.md 2013-09-04 16:47:09 -07:00
David Dollar 2b97cb458a Merge pull request #366 from wfarr/tgz-install-foreman-to-bin
Install tgz/foreman to bin/foreman in tgz package
2013-05-27 14:06:42 -07:00
Will Farrington 03d76d4254 Install tgz/foreman to bin/foreman in tgz package 2013-05-26 07:49:18 -07:00
David Dollar 133228f247 Merge pull request #305 from marclennox/master
Add start-stop-daemon export support with upstart
2013-05-03 13:27:54 -07:00
David Dollar bfba2cad71 Merge pull request #360 from kjwierenga/feature/require-posix-spawn
Feature/require posix spawn
2013-05-03 12:55:16 -07:00
Klaas Jan Wierenga e245026f65 Fail with an error on Ruby 1.8 when posix-spawn is not present. 2013-05-03 21:44:57 +02:00
Klaas Jan Wierenga ffc73366b2 Require and use 'posix/spawn' when running ruby 1.8 without using Foreman.ruby_18? (which is the subject under test). 2013-05-03 21:29:17 +02:00
Marc Lennox 284503899a Added start-stop-daemon support. 2013-05-03 12:54:08 -04:00
David Dollar 144be02bbd Merge pull request #353 from austiniam/master
added support for directories with single quote
2013-05-03 07:29:17 -07:00
Austin Cherry 9734a2ed65 fixed conflicts 2013-05-03 07:25:56 -07:00
AustinandAustin Cherry 0fff148fe0 modified to use shellescape instead of gsub 2013-05-03 07:23:25 -07:00
AustinandAustin Cherry d19a9aa043 added support for directories with single quotes. fixes #315 2013-05-03 07:22:16 -07:00
David Dollar c3abaad353 kill the children, not self 2013-05-03 09:54:20 -04:00
David Dollar b1f91d4505 fix docs, thanks to @Invizory 2013-05-03 09:49:31 -04:00
David Dollar 0c7b8ddd79 not sure how this snuck in, not in the exporter format 2013-05-03 09:44:25 -04:00
David Dollar 189b751d9f update docs 2013-05-03 09:44:25 -04:00
David Dollar 619bd03bb8 Merge pull request #340 from ldmosquera/set_env_var_with_process_name
Set FOREMAN_PROCESS_NAME env var for spawned procs
2013-05-03 06:42:04 -07:00
David Dollar fd836b46c0 Merge pull request #355 from JoeyButler/fix_typo_in_man
Fix typo in manual page.
2013-05-03 06:38:42 -07:00
David Dollar 2379259b33 Merge pull request #359 from kjwierenga/feature/make-ruby-18-compatible
Fix specs that were broken on ruby 1.8. Use POSIX::Spawn.spawn to make foreman robust on ruby 1.8.7.
2013-05-03 06:32:01 -07:00
Klaas Jan Wierenga baf842cdd4 The wrapped_command has spaces which triggers Ruby to fork a system shell (with /bin/sh -c). This causes orphaned processes on some systems (i.e. Linux). Fix this by splitting the command using String#shellsplit and using ruby's splat operator (*) to pass discrete arguments to spawn. 2013-05-02 16:30:39 +02:00
Klaas Jan Wierenga 5c06aaaa57 Enable ruby 1.8.7 building on Travis. All specs should pass now on ruby 1.8.7. 2013-05-02 12:49:05 +02:00
Klaas Jan Wierenga 75b782b664 Use POSIX::Spawn to make foreman ruby 1.8 compatible and have all specs passing. 2013-05-02 12:39:23 +02:00
Klaas Jan Wierenga 9b4bd10cdb Use pipe factory method to handle 1.8 incompatible signature for IO.pipe. 2013-05-02 12:37:06 +02:00
Klaas Jan Wierenga fff82dc685 Ruby 1.8 doesn't have the concept of string encodings. Compare to the string as is. 2013-05-02 11:00:47 +02:00
David Dollar da0a9f2de3 Merge pull request #294 from bfulton/master
add systemd export
2013-04-22 20:37:39 -07:00
Bright Fulton 7d77d8ff1a updated systemd export spec after rebasing included 5ef8bbdb 2013-04-20 13:48:27 -04:00
Joey Butler 51e181da29 Fix typo in manual page. 2013-04-17 10:47:03 -07:00
Leonardo Mosquera 9866a341ca Add unit test for PS env var 2013-04-16 22:31:34 -03:00
Leonardo Mosquera 90848e7dea Change FOREMAN_PROCESS_NAME to just PS 2013-04-16 22:31:15 -03:00
David Dollar a92e24b17c changelog 2013-04-15 15:35:21 -04:00
David Dollar 0da42cf7d2 0.63.0 2013-04-15 15:33:51 -04:00
David Dollar 23561b963c fix dotenv dependency 2013-04-15 15:32:27 -04:00
David Dollar cc51ab2cb1 fix up tests 2013-04-15 15:32:22 -04:00
David Dollar 403d40b277 Revert "Merge pull request #292 from andrewsmedina/master"
Does not pass tests

This reverts commit 17a8a316b8, reversing
changes made to 9e1d590734.
2013-04-15 15:31:38 -04:00
Bright Fulton 669a920c1e fix spec after d4ab495 2013-04-15 14:43:02 -04:00
Bright Fulton d357197718 better default for things which intentionally daemonize child processes, the default KillMode is control-group which survives daemonization 2013-04-15 14:43:02 -04:00
bfulton f6b57d7b92 rough draft for systemd export support
http://0pointer.de/blog/projects/systemd.html

This adds support for exporting systemd targets and services.  The
structure is based on the existing upstart support.

Quality is draft and expected to refine in the coming weeks.

One Foremanism that is not respected by these export templates is the
usual log output location, instead stdout and stderr go to syslog.
2013-04-15 14:43:02 -04:00
Austin e79588fd40 modified to use shellescape instead of gsub 2013-04-15 08:01:24 -07:00
David Dollar f1c2347680 Merge pull request #317 from andymorris/fix_deleted_upstart_files
Prevent upstart export from deleting similarly named upstart files
2013-04-14 08:45:21 -07:00
David Dollar 80f8242b11 Merge pull request #316 from avtobiff/add-mit-license
Add MIT license text
2013-04-14 08:43:41 -07:00
David Dollar 383276bb79 Merge pull request #343 from steakknife/fix__issue_341__profile_not_found
Fixes #341 . .profile not found error
2013-04-14 08:41:58 -07:00
David Dollar 5a7692ff2c Merge pull request #326 from pje/patch-1
Update man/foreman.1
2013-04-14 08:40:50 -07:00
David Dollar 405a85bc86 Merge pull request #351 from GreenplumChorus/master
Remove posix-spawn dependency for JRuby
2013-04-14 08:40:10 -07:00
David Dollar bff554d554 Merge pull request #347 from bkeepers/dotenv
Replace Foreman::Env with dotenv
2013-04-14 08:37:31 -07:00
David Dollar eaed989c75 Merge pull request #329 from kentaro/permit-underscore-in-procfile
Permit hyphen for command name in Procfile
2013-04-14 08:32:24 -07:00
David Dollar 93daebbf1b Merge pull request #323 from dplummer/remove-tmux-from-man
Remove tmux option from man page
2013-04-14 08:31:40 -07:00
David Dollar 17a8a316b8 Merge pull request #292 from andrewsmedina/master
circus support
2013-04-14 08:30:17 -07:00
David Dollar 9e1d590734 Merge pull request #266 from messick/master
Use runlevels in upstart config so app starts after boot in Ubuntu 12.03
2013-04-14 08:28:08 -07:00
Austin 6611d818b1 third time is the charm. :) 2013-04-11 09:14:01 -07:00
Austin ad4d59ae14 fixes #315 2013-04-11 08:49:36 -07:00
Austin 434f30fe42 added support for directories with single quotes. fixes #315 2013-04-11 08:44:16 -07:00
David Dollar 1cb1c8812a Merge pull request #352 from john-griffin/master
Restore ability to trap crtl+c
2013-04-11 07:59:52 -07:00
John Griffin 6786f4df39 Revert "Ensure foreman is the process group leader"
This reverts commit 44726e377e.

Conflicts:

	lib/foreman/engine.rb
2013-04-09 17:05:16 +01:00
Andrew Brown & Corey Downing 0be08a0651 remove posix-spawn dependency as it does not work in jruby 1.7.3 2013-04-04 17:27:31 -07:00
Brandon Keepers 3abe10e5ab Replace Foreman::Env with dotenv 2013-03-22 10:38:58 -04:00
Barry Allard 66ab0f08e7 [foreman-runner] fix sourcing as . is rarely in PATH 2013-03-16 00:04:57 -07:00
Leonardo Mosquera 95a1d49e9d Set FOREMAN_PROCESS_NAME env var for spawned procs
This way, processes can identify themselves to metrics logging systems.
2013-03-14 21:34:39 -03:00
David Dollar 7be4375168 changelog 2013-03-08 14:53:56 -05:00
Kentaro Kuribayashi 8d1e3a849f Fixed specs to pass. 2013-02-21 11:52:37 +09:00
Kentaro Kuribayashi 5ef8bbdbe3 Permit underscore for command name in Procfile. 2013-02-21 11:30:59 +09:00
Patrick Ellis 8cf5896c3e Update man/foreman.1
fix man example typo: Procfile flag is `-f`, not `-p`
2013-02-05 16:29:38 -08:00
Donald Plummer 5f8032cac8 Remove tmux option from man page
Not well supported at this time. See issue #242
2013-01-30 09:29:16 -08:00
Andy Morris 9f3b903085 Prevent upstart export from deleting similarly named upstart files 2013-01-25 00:24:04 -06:00
Per Andersson 69d278d864 Add MIT license text 2013-01-22 10:10:41 +01:00
Andrews Medina 9325f2ca6d add circus support 2012-11-29 00:15:01 -02:00
Nick Messick 9a91e5df44 use "start|stop\ on runlevel [x]" for upstart config 2012-09-24 18:18:05 -07:00
54 changed files with 667 additions and 152 deletions
+1 -1
View File
@@ -2,7 +2,6 @@ script: bundle exec rake spec
matrix: matrix:
allow_failures: allow_failures:
- rvm: 1.8.7
- rvm: jruby - rvm: jruby
- rvm: rbx - rvm: rbx
- rvm: ree - rvm: ree
@@ -16,6 +15,7 @@ notifications:
- http://dx-helper.herokuapp.com/travis - http://dx-helper.herokuapp.com/travis
rvm: rvm:
- 1.8.7
- 1.9.2 - 1.9.2
- 1.9.3 - 1.9.3
- 2.0.0 - 2.0.0
+26 -1
View File
@@ -1,6 +1,31 @@
## 0.63.0 (2013-04-15)
* Revert "Ensure foreman is the process group leader" [John Griffin]
* remove posix-spawn dependency as it does not work in jruby 1.7.3 [Andrew Brown & Corey Downing]
* Replace Foreman::Env with dotenv [Brandon Keepers]
* [foreman-runner] fix sourcing as . is rarely in PATH [Barry Allard]
* Fixed specs to pass. [Kentaro Kuribayashi]
* Permit underscore for command name in Procfile. [Kentaro Kuribayashi]
* Update man/foreman.1 [Patrick Ellis]
* Remove tmux option from man page [Donald Plummer]
* Prevent upstart export from deleting similarly named upstart files [Andy Morris]
* Add MIT license text [Per Andersson]
* use "start|stop\ on runlevel [x]" for upstart config [Nick Messick]
## 0.62.0 (2013-03-08)
* Merge pull request #334 from ged/reentrant_signal_handlers [David Dollar]
* Merge pull request #335 from ged/20_encoding_fix [David Dollar]
* Try to allow children to shut down gracefully [Michael Granger]
* Add deferred signal-handling (fixes #332). [Michael Granger]
* Fix spec encoding problem under Ruby 2.0.0. [Michael Granger]
* add ruby 2.0 to travis [David Dollar]
* Merge pull request #327 from patheticpat/master [David Dollar]
* Fixed a typo in cli options description [Michael Kaiser]
* handled by mingw now [David Dollar]
## 0.61.0 (2013-01-14) ## 0.61.0 (2013-01-14)
* 0.61.0 [David Dollar]
* Fix bug in color definitons [nseo] * Fix bug in color definitons [nseo]
* Fix for high CPU load when processes close output [Pavel Forkert] * Fix for high CPU load when processes close output [Pavel Forkert]
* Ensure foreman is the process group leader [Christos Trochalakis] * Ensure foreman is the process group leader [Christos Trochalakis]
+1 -1
View File
@@ -6,7 +6,7 @@ platform :mingw do
gem "win32console", "~> 1.3.0" gem "win32console", "~> 1.3.0"
end end
platform :jruby do platform :jruby, :ruby_18 do
gem "posix-spawn", "~> 0.3.6" gem "posix-spawn", "~> 0.3.6"
end end
+3 -1
View File
@@ -1,7 +1,8 @@
PATH PATH
remote: . remote: .
specs: specs:
foreman (0.62.0) foreman (0.63.0)
dotenv (>= 0.7)
thor (>= 0.13.6) thor (>= 0.13.6)
GEM GEM
@@ -13,6 +14,7 @@ GEM
xml-simple xml-simple
builder (3.0.0) builder (3.0.0)
diff-lcs (1.1.3) diff-lcs (1.1.3)
dotenv (0.7.0)
fakefs (0.3.2) fakefs (0.3.2)
hpricot (0.8.6) hpricot (0.8.6)
hpricot (0.8.6-java) hpricot (0.8.6-java)
+19
View File
@@ -0,0 +1,19 @@
Copyright (c) 2012 David Dollar
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+4 -1
View File
@@ -32,6 +32,7 @@ Manage Procfile-based applications
* [shoreman](https://github.com/hecticjeff/shoreman) - shell * [shoreman](https://github.com/hecticjeff/shoreman) - shell
* [honcho](https://github.com/nickstenning/honcho) - python * [honcho](https://github.com/nickstenning/honcho) - python
* [norman](https://github.com/josh/norman) - node.js * [norman](https://github.com/josh/norman) - node.js
* [forego](https://github.com/ddollar/forego) - Go
## Authors ## Authors
@@ -43,4 +44,6 @@ David Dollar
## License ## License
MIT Foreman is licensed under the MIT license.
See LICENSE for the full license text.
+1 -1
View File
@@ -34,7 +34,7 @@ shift $((OPTIND-1))
if [ "$read_profile" = "1" ]; then if [ "$read_profile" = "1" ]; then
if [ -f .profile ]; then if [ -f .profile ]; then
. .profile . ./.profile
fi fi
fi fi
+14
View File
@@ -0,0 +1,14 @@
pre-start script
bash << "EOF"
mkdir -p <%= log %>
chown -R <%= user %> <%= log %>
mkdir -p <%= run %>
chown -R <%= user %> <%= run %>
EOF
end script
start on runlevel [2345]
stop on runlevel [016]
+8
View File
@@ -0,0 +1,8 @@
start on starting <%= app %>-<%= name.gsub('_', '-') %>
stop on stopping <%= app %>-<%= name.gsub('_', '-') %>
respawn
env PORT=<%= port %><% engine.env.each_pair do |var, env| %>
env <%= var.upcase %>=<%= env %><% end %>
exec start-stop-daemon --start --chuid <%= user %> --chdir <%= engine.root %> --make-pidfile --pidfile <%= run %>/<%= app %>-<%= name %>-<%= num %>.pid --exec <%= executable %><%= arguments %> >> <%= log %>/<%= app %>-<%= name %>-<%= num %>.log 2>&1
@@ -0,0 +1,2 @@
start on starting <%= app %>
stop on stopping <%= app %>
+1
View File
@@ -0,0 +1 @@
[Unit]
+18
View File
@@ -0,0 +1,18 @@
[Unit]
StopWhenUnneeded=true
[Service]
User=<%= user %>
WorkingDirectory=<%= engine.root %>
Environment=PORT=<%= port %><% engine.env.each_pair do |var,env| %>
Environment=<%= var.upcase %>=<%= env %><% end %>
ExecStart=/bin/bash -lc '<%= process.command %>'
Restart=always
StandardInput=null
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=%n
KillMode=process
[Install]
WantedBy=<%= app %>-<%= name %>.target
@@ -0,0 +1,5 @@
[Unit]
StopWhenUnneeded=true
[Install]
WantedBy=<%= app %>.target
+2 -6
View File
@@ -7,10 +7,6 @@ EOF
end script end script
start on (started network-interface start on runlevel [2345]
or started network-manager
or started networking)
stop on (stopping network-interface stop on runlevel [016]
or stopping network-manager
or stopping networking)
+1 -1
View File
@@ -4,7 +4,7 @@ file pkg("foreman-#{version}.tgz") => distribution_files do |t|
assemble_distribution assemble_distribution
assemble_gems assemble_gems
rm_f "bin/foreman" rm_f "bin/foreman"
assemble resource("tgz/foreman"), "foreman", 0755 assemble resource("tgz/foreman"), "bin/foreman", 0755
end end
sh "tar czvf #{t.name} foreman" sh "tar czvf #{t.name} foreman"
+1 -1
View File
@@ -18,9 +18,9 @@ Gem::Specification.new do |gem|
gem.files << "man/foreman.1" gem.files << "man/foreman.1"
gem.add_dependency 'thor', '>= 0.13.6' gem.add_dependency 'thor', '>= 0.13.6'
gem.add_dependency 'dotenv', '>= 0.7'
if ENV["PLATFORM"] == "java" if ENV["PLATFORM"] == "java"
gem.add_dependency "posix-spawn", "~> 0.3.6"
gem.platform = Gem::Platform.new("java") gem.platform = Gem::Platform.new("java")
end end
-54
View File
@@ -1,54 +0,0 @@
if defined?(Capistrano)
Capistrano::Configuration.instance(:must_exist).load do
namespace :foreman do
desc <<-DESC
Export the Procfile to upstart. Will use sudo if available.
You can override any of these defaults by setting the variables shown below.
set :foreman_format, "upstart"
set :foreman_location, "/etc/init"
set :foreman_procfile, "Procfile"
set :foreman_app, application
set :foreman_user, user
set :foreman_log, 'shared_path/log'
set :foreman_concurrency, false
DESC
task :export, :roles => :app do
bundle_cmd = fetch(:bundle_cmd, "bundle")
foreman_format = fetch(:foreman_format, "upstart")
foreman_location = fetch(:foreman_location, "/etc/init")
foreman_procfile = fetch(:foreman_procfile, "Procfile")
foreman_app = fetch(:foreman_app, application)
foreman_user = fetch(:foreman_user, user)
foreman_log = fetch(:foreman_log, "#{shared_path}/log")
foreman_concurrency = fetch(:foreman_concurrency, false)
args = ["#{foreman_format} #{foreman_location}"]
args << "-f #{foreman_procfile}"
args << "-a #{foreman_app}"
args << "-u #{foreman_user}"
args << "-l #{foreman_log}"
args << "-c #{foreman_concurrency}" if foreman_concurrency
run "cd #{release_path} && #{sudo} #{bundle_cmd} exec foreman export #{args.join(' ')}"
end
desc "Start the application services"
task :start, :roles => :app do
run "#{sudo} start #{application}"
end
desc "Stop the application services"
task :stop, :roles => :app do
run "#{sudo} stop #{application}"
end
desc "Restart the application services"
task :restart, :roles => :app do
run "#{sudo} start #{application} || #{sudo} restart #{application}"
end
end
end
end
+10
View File
@@ -34,6 +34,7 @@ class Foreman::CLI < Thor
end end
def start(process=nil) def start(process=nil)
require_posix_spawn_for_ruby_18!
check_procfile! check_procfile!
load_environment! load_environment!
engine.load_procfile(procfile) engine.load_procfile(procfile)
@@ -45,6 +46,7 @@ class Foreman::CLI < Thor
method_option :app, :type => :string, :aliases => "-a" method_option :app, :type => :string, :aliases => "-a"
method_option :log, :type => :string, :aliases => "-l" method_option :log, :type => :string, :aliases => "-l"
method_option :run, :type => :string, :aliases => "-r", :desc => "Specify the pid file directory, defaults to /var/run/<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 :user, :type => :string, :aliases => "-u" method_option :user, :type => :string, :aliases => "-u"
@@ -137,6 +139,14 @@ private ######################################################################
end end
end end
def require_posix_spawn_for_ruby_18!
begin
Kernel.require 'posix/spawn' # Use Kernel explicitly so we can mock the require call in the spec
rescue LoadError
error "foreman requires gem `posix-spawn` on Ruby #{RUBY_VERSION}. Please `gem install posix-spawn`."
end if Foreman.ruby_18?
end
def procfile def procfile
case case
when options[:procfile] then options[:procfile] when options[:procfile] then options[:procfile]
+10 -10
View File
@@ -1,7 +1,7 @@
require "foreman" require "foreman"
require "foreman/env"
require "foreman/process" require "foreman/process"
require "foreman/procfile" require "foreman/procfile"
require "dotenv"
require "tempfile" require "tempfile"
require "timeout" require "timeout"
require "fileutils" require "fileutils"
@@ -52,9 +52,6 @@ class Foreman::Engine
# Start the processes registered to this +Engine+ # Start the processes registered to this +Engine+
# #
def start def start
# Make sure foreman is the process group leader.
Process.setpgrp unless Foreman.windows?
register_signal_handlers register_signal_handlers
startup startup
spawn_processes spawn_processes
@@ -172,9 +169,7 @@ class Foreman::Engine
# @param [String] filename A .env file to load into the environment # @param [String] filename A .env file to load into the environment
# #
def load_env(filename) def load_env(filename)
Foreman::Env.new(filename).entries do |name, value| @env.update Dotenv::Environment.new(filename)
@env[name] = value
end
end end
# Send a signal to all processes started by this +Engine+ # Send a signal to all processes started by this +Engine+
@@ -207,7 +202,7 @@ class Foreman::Engine
kill_children(signal) kill_children(signal)
else else
begin begin
Process.kill "-#{signal}", Process.getpgrp Process.kill "-#{signal}", Process.pid
rescue Errno::ESRCH, Errno::EPERM rescue Errno::ESRCH, Errno::EPERM
end end
end end
@@ -307,6 +302,10 @@ private
def name_for(pid) def name_for(pid)
process, index = @running[pid] process, index = @running[pid]
name_for_index(process, index)
end
def name_for_index(process, index)
[ @names[process], index.to_s ].compact.join(".") [ @names[process], index.to_s ].compact.join(".")
end end
@@ -355,7 +354,8 @@ private
reader, writer = create_pipe reader, writer = create_pipe
begin begin
pid = process.run(:output => writer, :env => { pid = process.run(:output => writer, :env => {
"PORT" => port_for(process, n).to_s "PORT" => port_for(process, n).to_s,
"PS" => name_for_index(process, n)
}) })
writer.puts "started with pid #{pid}" writer.puts "started with pid #{pid}"
rescue Errno::ENOENT rescue Errno::ENOENT
@@ -427,7 +427,7 @@ private
end end
rescue Timeout::Error rescue Timeout::Error
system "sending SIGKILL to all processes" system "sending SIGKILL to all processes"
killall "SIGKILL" kill_children "SIGKILL"
end end
end end
-29
View File
@@ -1,29 +0,0 @@
require "foreman"
class Foreman::Env
attr_reader :entries
def initialize(filename)
@entries = File.read(filename).gsub("\r\n","\n").split("\n").inject({}) do |ax, line|
if line =~ /\A([A-Za-z_0-9]+)=(.*)\z/
key = $1
case val = $2
# Remove single quotes
when /\A'(.*)'\z/ then ax[key] = $1
# Remove double quotes and unescape string preserving newline characters
when /\A"(.*)"\z/ then ax[key] = $1.gsub('\n', "\n").gsub(/\\(.)/, '\1')
else ax[key] = val
end
end
ax
end
end
def entries
@entries.each do |key, value|
yield key, value
end
end
end
+2
View File
@@ -28,7 +28,9 @@ 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/daemon"
require "foreman/export/bluepill" require "foreman/export/bluepill"
require "foreman/export/runit" require "foreman/export/runit"
require "foreman/export/supervisord" require "foreman/export/supervisord"
require "foreman/export/launchd" require "foreman/export/launchd"
require "foreman/export/systemd"
+6
View File
@@ -47,7 +47,9 @@ class Foreman::Export::Base
error("Must specify a location") unless location error("Must specify a location") unless location
FileUtils.mkdir_p(location) rescue error("Could not create: #{location}") FileUtils.mkdir_p(location) rescue error("Could not create: #{location}")
FileUtils.mkdir_p(log) rescue error("Could not create: #{log}") FileUtils.mkdir_p(log) rescue error("Could not create: #{log}")
FileUtils.mkdir_p(run) rescue error("Could not create: #{run}")
FileUtils.chown(user, nil, log) rescue error("Could not chown #{log} to #{user}") FileUtils.chown(user, nil, log) rescue error("Could not chown #{log} to #{user}")
FileUtils.chown(user, nil, run) rescue error("Could not chown #{run} to #{user}")
end end
def app def app
@@ -58,6 +60,10 @@ class Foreman::Export::Base
options[:log] || "/var/log/#{app}" options[:log] || "/var/log/#{app}"
end end
def run
options[:run] || "/var/run/#{app}"
end
def user def user
options[:user] || app options[:user] || app
end end
+28
View File
@@ -0,0 +1,28 @@
require "erb"
require "foreman/export"
class Foreman::Export::Daemon < Foreman::Export::Base
def export
super
(Dir["#{location}/#{app}-*.conf"] << "#{location}/#{app}.conf").each do |file|
clean file
end
write_template "daemon/master.conf.erb", "#{app}.conf", binding
engine.each_process do |name, process|
next if engine.formation[name] < 1
write_template "daemon/process_master.conf.erb", "#{app}-#{name}.conf", binding
1.upto(engine.formation[name]) do |num|
port = engine.port_for(process, num)
arguments = process.command.split(" ")
executable = arguments.slice!(0)
arguments = arguments.size > 0 ? " -- #{arguments.join(' ')}" : ""
write_template "daemon/process.conf.erb", "#{app}-#{name}-#{num}.conf", binding
end
end
end
end
+25
View File
@@ -0,0 +1,25 @@
require "erb"
require "foreman/export"
class Foreman::Export::Systemd < Foreman::Export::Base
def export
super
Dir["#{location}/#{app}*.target"].concat(Dir["#{location}/#{app}*.service"]).each do |file|
clean file
end
write_template "systemd/master.target.erb", "#{app}.target", binding
engine.each_process do |name, process|
next if engine.formation[name] < 1
write_template "systemd/process_master.target.erb", "#{app}-#{name}.target", binding
1.upto(engine.formation[name]) do |num|
port = engine.port_for(process, num)
write_template "systemd/process.service.erb", "#{app}-#{name}-#{num}.service", binding
end
end
end
end
+1 -1
View File
@@ -6,7 +6,7 @@ class Foreman::Export::Upstart < Foreman::Export::Base
def export def export
super super
Dir["#{location}/#{app}*.conf"].each do |file| (Dir["#{location}/#{app}-*.conf"] << "#{location}/#{app}.conf").each do |file|
clean file clean file
end end
+16 -12
View File
@@ -1,4 +1,5 @@
require "foreman" require "foreman"
require "shellwords"
class Foreman::Process class Foreman::Process
@@ -47,25 +48,18 @@ class Foreman::Process
def run(options={}) def run(options={})
env = @options[:env].merge(options[:env] || {}) env = @options[:env].merge(options[:env] || {})
output = options[:output] || $stdout output = options[:output] || $stdout
runner = "#{Foreman.runner}".shellescape
if Foreman.windows? if Foreman.windows?
Dir.chdir(cwd) do Dir.chdir(cwd) do
Process.spawn env, expanded_command(env), :out => output, :err => output Process.spawn env, expanded_command(env), :out => output, :err => output
end end
elsif Foreman.jruby_18? elsif Foreman.jruby_18? || Foreman.ruby_18?
require "posix/spawn" require "posix/spawn"
wrapped_command = "#{Foreman.runner} -d '#{cwd}' -p -- #{command}" wrapped_command = "#{runner} -d '#{cwd.shellescape}' -p -- #{expanded_command(env)}"
POSIX::Spawn.spawn env, wrapped_command, :out => output, :err => output POSIX::Spawn.spawn(*spawn_args(env, wrapped_command.shellsplit, {:out => output, :err => output}))
elsif Foreman.ruby_18?
fork do
$stdout.reopen output
$stderr.reopen output
env.each { |k,v| ENV[k] = v }
wrapped_command = "#{Foreman.runner} -d '#{cwd}' -p -- #{command}"
Kernel.exec wrapped_command
end
else else
wrapped_command = "#{Foreman.runner} -d '#{cwd}' -p -- #{command}" wrapped_command = "#{runner} -d '#{cwd.shellescape}' -p -- #{command}"
Process.spawn env, wrapped_command, :out => output, :err => output Process.spawn env, wrapped_command, :out => output, :err => output
end end
end end
@@ -122,4 +116,14 @@ class Foreman::Process
File.expand_path(@options[:cwd] || ".") File.expand_path(@options[:cwd] || ".")
end end
private
def spawn_args(env, argv, options)
args = []
args << env
args += argv
args << options
args
end
end end
+1 -1
View File
@@ -83,7 +83,7 @@ private
def parse(filename) def parse(filename)
File.read(filename).gsub("\r\n","\n").split("\n").map do |line| File.read(filename).gsub("\r\n","\n").split("\n").map do |line|
if line =~ /^([A-Za-z0-9_]+):\s*(.+)$/ if line =~ /^([A-Za-z0-9_-]+):\s*(.+)$/
[$1, $2] [$1, $2]
end end
end.compact end.compact
+1 -1
View File
@@ -1,5 +1,5 @@
module Foreman module Foreman
VERSION = "0.62.0" VERSION = "0.63.0"
end end
+24 -7
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" "January 2013" "Foreman 0.61.0" "Foreman Manual" .TH "FOREMAN" "1" "May 2013" "Foreman 0.63.0" "Foreman Manual"
. .
.SH "NAME" .SH "NAME"
\fBforeman\fR \- manage Procfile\-based applications \fBforeman\fR \- manage Procfile\-based applications
@@ -46,10 +46,6 @@ Specify an alternate Procfile to load, implies \fB\-d\fR at the Procfile root\.
\fB\-p\fR, \fB\-\-port\fR \fB\-p\fR, \fB\-\-port\fR
Specify which port to use as the base for this application\. Should be a multiple of 1000\. Specify which port to use as the base for this application\. Should be a multiple of 1000\.
. .
.TP
\fB\-t\fR, \fB\-\-tmux\fR
Runs the processes in a tmux session\. Creates one window for each process and an extra window containing the output of each window (requires gawk)\.
.
.P .P
\fBforeman run\fR is used to run one\-off commands using the same environment as your defined processes\. \fBforeman run\fR is used to run one\-off commands using the same environment as your defined processes\.
. .
@@ -111,9 +107,18 @@ bluepill
inittab inittab
. .
.IP "\(bu" 4 .IP "\(bu" 4
launchd
.
.IP "\(bu" 4
runit runit
. .
.IP "\(bu" 4 .IP "\(bu" 4
supervisord
.
.IP "\(bu" 4
systemd
.
.IP "\(bu" 4
upstart upstart
. .
.IP "" 0 .IP "" 0
@@ -134,6 +139,18 @@ EX02:4:respawn:/bin/su \- example \-c \'PORT=5100 bundle exec rake jobs:work >>
. .
.IP "" 0 .IP "" 0
. .
.SH "SYSTEMD EXPORT"
Will create a series of systemd scripts in the location you specify\. Scripts will be structured to make the following commands valid:
.
.P
\fBsystemctl start appname\.target\fR
.
.P
\fBsystemctl stop appname\-processname\.target\fR
.
.P
\fBsystemctl restart appname\-processname\-3\.service\fR
.
.SH "UPSTART EXPORT" .SH "UPSTART EXPORT"
Will create a series of upstart scripts in the location you specify\. Scripts will be structured to make the following commands valid: Will create a series of upstart scripts in the location you specify\. Scripts will be structured to make the following commands valid:
. .
@@ -161,7 +178,7 @@ job: bundle exec rake jobs:work
.IP "" 0 .IP "" 0
. .
.P .P
A process name may contain letters, numbers amd the underscore character\. You can validate your Procfile format using the \fBcheck\fR command: A process name may contain letters, numbers and the underscore character\. You can validate your Procfile format using the \fBcheck\fR command:
. .
.IP "" 4 .IP "" 4
. .
@@ -234,7 +251,7 @@ Run one process type from the application defined in a specific Procfile:
. .
.nf .nf
$ foreman start alpha \-p ~/myapp/Procfile $ foreman start alpha \-f ~/myapp/Procfile
. .
.fi .fi
. .
+19 -6
View File
@@ -40,10 +40,6 @@ The following options control how the application is run:
Specify which port to use as the base for this application. Should be Specify which port to use as the base for this application. Should be
a multiple of 1000. a multiple of 1000.
* `-t`, `--tmux`:
Runs the processes in a tmux session. Creates one window for each process
and an extra window containing the output of each window (requires gawk).
`foreman run` is used to run one-off commands using the same environment `foreman run` is used to run one-off commands using the same environment
as your defined processes. as your defined processes.
@@ -105,8 +101,14 @@ foreman currently supports the following output formats:
* inittab * inittab
* launchd
* runit * runit
* supervisord
* systemd
* upstart * upstart
## INITTAB EXPORT ## INITTAB EXPORT
@@ -118,6 +120,17 @@ Will export a chunk of inittab-compatible configuration:
EX02:4:respawn:/bin/su - example -c 'PORT=5100 bundle exec rake jobs:work >> /var/log/job-1.log 2>&1' EX02:4:respawn:/bin/su - example -c 'PORT=5100 bundle exec rake jobs:work >> /var/log/job-1.log 2>&1'
# ----- end foreman example processes ----- # ----- end foreman example processes -----
## SYSTEMD EXPORT
Will create a series of systemd scripts in the location you specify. Scripts
will be structured to make the following commands valid:
`systemctl start appname.target`
`systemctl stop appname-processname.target`
`systemctl restart appname-processname-3.service`
## UPSTART EXPORT ## UPSTART EXPORT
Will create a series of upstart scripts in the location you specify. Scripts Will create a series of upstart scripts in the location you specify. Scripts
@@ -137,7 +150,7 @@ to run it.
web: bundle exec thin start web: bundle exec thin start
job: bundle exec rake jobs:work job: bundle exec rake jobs:work
A process name may contain letters, numbers amd the underscore character. A process name may contain letters, numbers and the underscore character.
You can validate your Procfile format using the `check` command: You can validate your Procfile format using the `check` command:
$ foreman check $ foreman check
@@ -172,7 +185,7 @@ Export the application in upstart format:
Run one process type from the application defined in a specific Procfile: Run one process type from the application defined in a specific Procfile:
$ foreman start alpha -p ~/myapp/Procfile $ foreman start alpha -f ~/myapp/Procfile
## COPYRIGHT ## COPYRIGHT
+16 -1
View File
@@ -44,13 +44,20 @@ describe "Foreman::CLI", :fakefs do
output.should =~ /test.1 \| testing/ output.should =~ /test.1 \| testing/
end end
end end
it "sets PS variable with the process name" do
without_fakefs do
output = foreman("start -f #{resource_path("Procfile")}")
output.should =~ /ps.1 \| PS env var is ps.1/
end
end
end end
end end
describe "check" do describe "check" do
it "with a valid Procfile displays the jobs" do it "with a valid Procfile displays the jobs" do
write_procfile write_procfile
foreman("check").should == "valid procfile detected (alpha, bravo)\n" foreman("check").should == "valid procfile detected (alpha, bravo, foo_bar, foo-bar)\n"
end end
it "with a blank Procfile displays an error" do it "with a blank Procfile displays an error" do
@@ -93,4 +100,12 @@ describe "Foreman::CLI", :fakefs do
end end
end end
describe "when posix-spawn is not present on ruby 1.8" do
it "should fail with an error" do
mock(Kernel).require('posix/spawn') { raise LoadError }
output = foreman("start -f #{resource_path("Procfile")}")
output.should == "ERROR: foreman requires gem `posix-spawn` on Ruby #{RUBY_VERSION}. Please `gem install posix-spawn`.\n"
end
end if running_ruby_18?
end end
+97
View File
@@ -0,0 +1,97 @@
require "spec_helper"
require "foreman/engine"
require "foreman/export/daemon"
require "tmpdir"
describe Foreman::Export::Daemon, :fakefs do
let(:procfile) { write_procfile("/tmp/app/Procfile") }
let(:formation) { nil }
let(:engine) { Foreman::Engine.new(:formation => formation).load_procfile(procfile) }
let(:options) { Hash.new }
let(:daemon) { Foreman::Export::Daemon.new("/tmp/init", engine, options) }
before(:each) { load_export_templates_into_fakefs("daemon") }
before(:each) { stub(daemon).say }
it "exports to the filesystem" do
daemon.export
File.read("/tmp/init/app.conf").should == example_export_file("daemon/app.conf")
File.read("/tmp/init/app-alpha.conf").should == example_export_file("daemon/app-alpha.conf")
File.read("/tmp/init/app-alpha-1.conf").should == example_export_file("daemon/app-alpha-1.conf")
File.read("/tmp/init/app-bravo.conf").should == example_export_file("daemon/app-bravo.conf")
File.read("/tmp/init/app-bravo-1.conf").should == example_export_file("daemon/app-bravo-1.conf")
end
it "cleans up if exporting into an existing dir" do
mock(FileUtils).rm("/tmp/init/app.conf")
mock(FileUtils).rm("/tmp/init/app-alpha.conf")
mock(FileUtils).rm("/tmp/init/app-alpha-1.conf")
mock(FileUtils).rm("/tmp/init/app-bravo.conf")
mock(FileUtils).rm("/tmp/init/app-bravo-1.conf")
mock(FileUtils).rm("/tmp/init/app-foo-bar.conf")
mock(FileUtils).rm("/tmp/init/app-foo-bar-1.conf")
mock(FileUtils).rm("/tmp/init/app-foo_bar.conf")
mock(FileUtils).rm("/tmp/init/app-foo_bar-1.conf")
daemon.export
daemon.export
end
it "does not delete exported files for similarly named applications" do
FileUtils.mkdir_p "/tmp/init"
["app2", "app2-alpha", "app2-alpha-1"].each do |name|
path = "/tmp/init/#{name}.conf"
FileUtils.touch(path)
dont_allow(FileUtils).rm(path)
end
daemon.export
end
context "with a formation" do
let(:formation) { "alpha=2" }
it "exports to the filesystem with concurrency" do
daemon.export
File.read("/tmp/init/app.conf").should == example_export_file("daemon/app.conf")
File.read("/tmp/init/app-alpha.conf").should == example_export_file("daemon/app-alpha.conf")
File.read("/tmp/init/app-alpha-1.conf").should == example_export_file("daemon/app-alpha-1.conf")
File.read("/tmp/init/app-alpha-2.conf").should == example_export_file("daemon/app-alpha-2.conf")
File.exists?("/tmp/init/app-bravo-1.conf").should == false
end
end
context "with alternate templates" do
let(:template) { "/tmp/alternate" }
let(:options) { { :app => "app", :template => template } }
before do
FileUtils.mkdir_p template
File.open("#{template}/master.conf.erb", "w") { |f| f.puts "alternate_template" }
end
it "can export with alternate template files" do
daemon.export
File.read("/tmp/init/app.conf").should == "alternate_template\n"
end
end
context "with alternate templates from home dir" do
before do
FileUtils.mkdir_p File.expand_path("~/.foreman/templates/daemon")
File.open(File.expand_path("~/.foreman/templates/daemon/master.conf.erb"), "w") do |file|
file.puts "default_alternate_template"
end
end
it "can export with alternate template files" do
daemon.export
File.read("/tmp/init/app.conf").should == "default_alternate_template\n"
end
end
end
+91
View File
@@ -0,0 +1,91 @@
require "spec_helper"
require "foreman/engine"
require "foreman/export/systemd"
require "tmpdir"
describe Foreman::Export::Systemd, :fakefs do
let(:procfile) { write_procfile("/tmp/app/Procfile") }
let(:formation) { nil }
let(:engine) { Foreman::Engine.new(:formation => formation).load_procfile(procfile) }
let(:options) { Hash.new }
let(:systemd) { Foreman::Export::Systemd.new("/tmp/init", engine, options) }
before(:each) { load_export_templates_into_fakefs("systemd") }
before(:each) { stub(systemd).say }
it "exports to the filesystem" do
systemd.export
File.read("/tmp/init/app.target").should == example_export_file("systemd/app.target")
File.read("/tmp/init/app-alpha.target").should == example_export_file("systemd/app-alpha.target")
File.read("/tmp/init/app-alpha-1.service").should == example_export_file("systemd/app-alpha-1.service")
File.read("/tmp/init/app-bravo.target").should == example_export_file("systemd/app-bravo.target")
File.read("/tmp/init/app-bravo-1.service").should == example_export_file("systemd/app-bravo-1.service")
end
it "cleans up if exporting into an existing dir" do
mock(FileUtils).rm("/tmp/init/app.target")
mock(FileUtils).rm("/tmp/init/app-alpha.target")
mock(FileUtils).rm("/tmp/init/app-alpha-1.service")
mock(FileUtils).rm("/tmp/init/app-bravo.target")
mock(FileUtils).rm("/tmp/init/app-bravo-1.service")
mock(FileUtils).rm("/tmp/init/app-foo-bar.target")
mock(FileUtils).rm("/tmp/init/app-foo-bar-1.service")
mock(FileUtils).rm("/tmp/init/app-foo_bar.target")
mock(FileUtils).rm("/tmp/init/app-foo_bar-1.service")
systemd.export
systemd.export
end
it "includes environment variables" do
engine.env['KEY'] = 'some "value"'
systemd.export
File.read("/tmp/init/app-alpha-1.service").should =~ /KEY=some "value"$/
end
context "with a formation" do
let(:formation) { "alpha=2" }
it "exports to the filesystem with concurrency" do
systemd.export
File.read("/tmp/init/app.target").should == example_export_file("systemd/app.target")
File.read("/tmp/init/app-alpha.target").should == example_export_file("systemd/app-alpha.target")
File.read("/tmp/init/app-alpha-1.service").should == example_export_file("systemd/app-alpha-1.service")
File.read("/tmp/init/app-alpha-2.service").should == example_export_file("systemd/app-alpha-2.service")
File.exists?("/tmp/init/app-bravo-1.service").should == false
end
end
context "with alternate templates" do
let(:template) { "/tmp/alternate" }
let(:options) { { :app => "app", :template => template } }
before do
FileUtils.mkdir_p template
File.open("#{template}/master.target.erb", "w") { |f| f.puts "alternate_template" }
end
it "can export with alternate template files" do
systemd.export
File.read("/tmp/init/app.target").should == "alternate_template\n"
end
end
context "with alternate templates from home dir" do
before do
FileUtils.mkdir_p File.expand_path("~/.foreman/templates/systemd")
File.open(File.expand_path("~/.foreman/templates/systemd/master.target.erb"), "w") do |file|
file.puts "default_alternate_template"
end
end
it "can export with alternate template files" do
systemd.export
File.read("/tmp/init/app.target").should == "default_alternate_template\n"
end
end
end
+16
View File
@@ -29,11 +29,27 @@ describe Foreman::Export::Upstart, :fakefs do
mock(FileUtils).rm("/tmp/init/app-alpha-1.conf") mock(FileUtils).rm("/tmp/init/app-alpha-1.conf")
mock(FileUtils).rm("/tmp/init/app-bravo.conf") mock(FileUtils).rm("/tmp/init/app-bravo.conf")
mock(FileUtils).rm("/tmp/init/app-bravo-1.conf") mock(FileUtils).rm("/tmp/init/app-bravo-1.conf")
mock(FileUtils).rm("/tmp/init/app-foo-bar.conf")
mock(FileUtils).rm("/tmp/init/app-foo-bar-1.conf")
mock(FileUtils).rm("/tmp/init/app-foo_bar.conf")
mock(FileUtils).rm("/tmp/init/app-foo_bar-1.conf")
upstart.export upstart.export
upstart.export upstart.export
end end
it "does not delete exported files for similarly named applications" do
FileUtils.mkdir_p "/tmp/init"
["app2", "app2-alpha", "app2-alpha-1"].each do |name|
path = "/tmp/init/#{name}.conf"
FileUtils.touch(path)
dont_allow(FileUtils).rm(path)
end
upstart.export
end
it "quotes and escapes environment variables" do it "quotes and escapes environment variables" do
engine.env['KEY'] = 'd"\|d' engine.env['KEY'] = 'd"\|d'
upstart.export upstart.export
+1 -1
View File
@@ -41,7 +41,7 @@ describe Foreman::Process do
it "should output utf8 properly" do it "should output utf8 properly" do
process = Foreman::Process.new(resource_path("bin/utf8")) process = Foreman::Process.new(resource_path("bin/utf8"))
run(process).should == "\xFF\x03\n".force_encoding('binary') run(process).should == (Foreman.ruby_18? ? "\xFF\x03\n" : "\xFF\x03\n".force_encoding('binary'))
end end
end end
+4 -2
View File
@@ -16,8 +16,10 @@ describe Foreman::Procfile, :fakefs do
it "loads a passed-in Procfile" do it "loads a passed-in Procfile" do
write_procfile write_procfile
procfile = Foreman::Procfile.new("Procfile") procfile = Foreman::Procfile.new("Procfile")
procfile["alpha"].should == "./alpha" procfile["alpha"].should == "./alpha"
procfile["bravo"].should == "./bravo" procfile["bravo"].should == "./bravo"
procfile["foo-bar"].should == "./foo-bar"
procfile["foo_bar"].should == "./foo_bar"
end end
it "can have a process appended to it" do it "can have a process appended to it" do
+1
View File
@@ -2,3 +2,4 @@ echo: bin/echo echoing
env: bin/env FOO env: bin/env FOO
test: bin/test test: bin/test
utf8: bin/utf8 utf8: bin/utf8
ps: bin/echo PS env var is $PS
+35
View File
@@ -42,5 +42,40 @@ Bluepill.application("app", :foreground => false, :log_file => "/var/log/bluepil
process.group = "app-bravo" process.group = "app-bravo"
end end
app.process("foo_bar-1") do |process|
process.start_command = "./foo_bar"
process.working_dir = "/tmp/app"
process.daemonize = true
process.environment = {"PORT"=>"5200"}
process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
process.stop_grace_time = 45.seconds
process.stdout = process.stderr = "/var/log/app/app-foo_bar-1.log"
process.monitor_children do |children|
children.stop_command "kill {{PID}}"
end
process.group = "app-foo_bar"
end
app.process("foo-bar-1") do |process|
process.start_command = "./foo-bar"
process.working_dir = "/tmp/app"
process.daemonize = true
process.environment = {"PORT"=>"5300"}
process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
process.stop_grace_time = 45.seconds
process.stdout = process.stderr = "/var/log/app/app-foo-bar-1.log"
process.monitor_children do |children|
children.stop_command "kill {{PID}}"
end
process.group = "app-foo-bar"
end
end end
@@ -0,0 +1,7 @@
start on starting app-alpha
stop on stopping app-alpha
respawn
env PORT=5000
exec start-stop-daemon --start --chuid app --chdir /tmp/app --make-pidfile --pidfile /var/run/app/app-alpha-1.pid --exec ./alpha >> /var/log/app/app-alpha-1.log 2>&1
@@ -0,0 +1,7 @@
start on starting app-alpha
stop on stopping app-alpha
respawn
env PORT=5001
exec start-stop-daemon --start --chuid app --chdir /tmp/app --make-pidfile --pidfile /var/run/app/app-alpha-2.pid --exec ./alpha >> /var/log/app/app-alpha-2.log 2>&1
@@ -0,0 +1,2 @@
start on starting app
stop on stopping app
@@ -0,0 +1,7 @@
start on starting app-bravo
stop on stopping app-bravo
respawn
env PORT=5100
exec start-stop-daemon --start --chuid app --chdir /tmp/app --make-pidfile --pidfile /var/run/app/app-bravo-1.pid --exec ./bravo >> /var/log/app/app-bravo-1.log 2>&1
@@ -0,0 +1,2 @@
start on starting app
stop on stopping app
+14
View File
@@ -0,0 +1,14 @@
pre-start script
bash << "EOF"
mkdir -p /var/log/app
chown -R app /var/log/app
mkdir -p /var/run/app
chown -R app /var/run/app
EOF
end script
start on runlevel [2345]
stop on runlevel [016]
@@ -1,4 +1,6 @@
# ----- foreman app processes ----- # ----- foreman app processes -----
AP01:4:respawn:/bin/su - app -c 'cd /tmp/app;export PORT=5000;./alpha >> /var/log/app/alpha-1.log 2>&1' AP01:4:respawn:/bin/su - app -c 'cd /tmp/app;export PORT=5000;./alpha >> /var/log/app/alpha-1.log 2>&1'
AP02:4:respawn:/bin/su - app -c 'cd /tmp/app;export PORT=5100;./bravo >> /var/log/app/bravo-1.log 2>&1' AP02:4:respawn:/bin/su - app -c 'cd /tmp/app;export PORT=5100;./bravo >> /var/log/app/bravo-1.log 2>&1'
AP03:4:respawn:/bin/su - app -c 'cd /tmp/app;export PORT=5200;./foo_bar >> /var/log/app/foo_bar-1.log 2>&1'
AP04:4:respawn:/bin/su - app -c 'cd /tmp/app;export PORT=5300;./foo-bar >> /var/log/app/foo-bar-1.log 2>&1'
# ----- end foreman app processes ----- # ----- end foreman app processes -----
@@ -19,6 +19,26 @@ stderr_logfile=/var/log/app/bravo-1.error.log
user=app user=app
directory=/tmp/app directory=/tmp/app
environment=PORT=5100 environment=PORT=5100
[program:app-foo_bar-1]
command=./foo_bar
autostart=true
autorestart=true
stopsignal=QUIT
stdout_logfile=/var/log/app/foo_bar-1.log
stderr_logfile=/var/log/app/foo_bar-1.error.log
user=app
directory=/tmp/app
environment=PORT=5200
[program:app-foo-bar-1]
command=./foo-bar
autostart=true
autorestart=true
stopsignal=QUIT
stdout_logfile=/var/log/app/foo-bar-1.log
stderr_logfile=/var/log/app/foo-bar-1.error.log
user=app
directory=/tmp/app
environment=PORT=5300
[group:app] [group:app]
programs=app-alpha-1,app-bravo-1 programs=app-alpha-1,app-bravo-1,app-foo_bar-1,app-foo-bar-1
@@ -0,0 +1,17 @@
[Unit]
StopWhenUnneeded=true
[Service]
User=app
WorkingDirectory=/tmp/app
Environment=PORT=5000
ExecStart=/bin/bash -lc './alpha'
Restart=always
StandardInput=null
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=%n
KillMode=process
[Install]
WantedBy=app-alpha.target
@@ -0,0 +1,17 @@
[Unit]
StopWhenUnneeded=true
[Service]
User=app
WorkingDirectory=/tmp/app
Environment=PORT=5001
ExecStart=/bin/bash -lc './alpha'
Restart=always
StandardInput=null
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=%n
KillMode=process
[Install]
WantedBy=app-alpha.target
@@ -0,0 +1,5 @@
[Unit]
StopWhenUnneeded=true
[Install]
WantedBy=app.target
@@ -0,0 +1,17 @@
[Unit]
StopWhenUnneeded=true
[Service]
User=app
WorkingDirectory=/tmp/app
Environment=PORT=5100
ExecStart=/bin/bash -lc './bravo'
Restart=always
StandardInput=null
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=%n
KillMode=process
[Install]
WantedBy=app-bravo.target
@@ -0,0 +1,5 @@
[Unit]
StopWhenUnneeded=true
[Install]
WantedBy=app.target
+1
View File
@@ -0,0 +1 @@
[Unit]
+2 -6
View File
@@ -7,10 +7,6 @@ EOF
end script end script
start on (started network-interface start on runlevel [2345]
or started network-manager
or started networking)
stop on (stopping network-interface stop on runlevel [016]
or stopping network-manager
or stopping networking)
+29 -5
View File
@@ -10,6 +10,15 @@ require "fakefs/spec_helpers"
$:.unshift File.expand_path("../../lib", __FILE__) $:.unshift File.expand_path("../../lib", __FILE__)
begin
def running_ruby_18?
defined?(RUBY_VERSION) and RUBY_VERSION =~ /^1\.8\.\d+/
end
require 'posix/spawn' if running_ruby_18?
rescue LoadError
STDERR.puts "WARNING: foreman requires gem `posix-spawn` on Ruby #{RUBY_VERSION}. Please `gem install posix-spawn`."
end
def mock_export_error(message) def mock_export_error(message)
lambda { yield }.should raise_error(Foreman::Export::Exception, message) lambda { yield }.should raise_error(Foreman::Export::Exception, message)
end end
@@ -21,6 +30,10 @@ def mock_error(subject, message)
end end
end end
def make_pipe
IO.method(:pipe).arity.zero? ? IO.pipe : IO.pipe("BINARY")
end
def foreman(args) def foreman(args)
capture_stdout do capture_stdout do
begin begin
@@ -31,14 +44,18 @@ def foreman(args)
end end
def forked_foreman(args) def forked_foreman(args)
rd, wr = IO.pipe("BINARY") rd, wr = make_pipe
Process.spawn("bundle exec bin/foreman #{args}", :out => wr, :err => wr) if running_ruby_18?
POSIX::Spawn.spawn({}, "bundle exec bin/foreman #{args}", :out => wr, :err => wr)
else
Process.spawn("bundle exec bin/foreman #{args}", :out => wr, :err => wr)
end
wr.close wr.close
rd.read rd.read
end end
def fork_and_capture(&blk) def fork_and_capture(&blk)
rd, wr = IO.pipe("BINARY") rd, wr = make_pipe
pid = fork do pid = fork do
rd.close rd.close
wr.sync = true wr.sync = true
@@ -57,7 +74,11 @@ def fork_and_capture(&blk)
end end
def fork_and_get_exitstatus(args) def fork_and_get_exitstatus(args)
pid = Process.spawn("bundle exec bin/foreman #{args}", :out => "/dev/null", :err => "/dev/null") pid = if running_ruby_18?
POSIX::Spawn.spawn({}, "bundle exec bin/foreman #{args}", :out => "/dev/null", :err => "/dev/null")
else
Process.spawn("bundle exec bin/foreman #{args}", :out => "/dev/null", :err => "/dev/null")
end
Process.wait(pid) Process.wait(pid)
$?.exitstatus $?.exitstatus
end end
@@ -79,6 +100,8 @@ def write_procfile(procfile="Procfile", alpha_env="")
file.puts "alpha: ./alpha" + " #{alpha_env}".rstrip file.puts "alpha: ./alpha" + " #{alpha_env}".rstrip
file.puts "\n" file.puts "\n"
file.puts "bravo:\t./bravo" file.puts "bravo:\t./bravo"
file.puts "foo_bar:\t./foo_bar"
file.puts "foo-bar:\t./foo-bar"
end end
File.expand_path(procfile) File.expand_path(procfile)
end end
@@ -139,7 +162,7 @@ end
def capture_stdout def capture_stdout
old_stdout = $stdout.dup old_stdout = $stdout.dup
rd, wr = IO.method(:pipe).arity.zero? ? IO.pipe : IO.pipe("BINARY") rd, wr = make_pipe
$stdout = wr $stdout = wr
yield yield
wr.close wr.close
@@ -154,4 +177,5 @@ RSpec.configure do |config|
config.order = 'rand' config.order = 'rand'
config.include FakeFS::SpecHelpers, :fakefs config.include FakeFS::SpecHelpers, :fakefs
config.mock_with :rr config.mock_with :rr
config.backtrace_clean_patterns = []
end end