foreman 0.57.0 → 0.58.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,14 +4,25 @@
4
4
  <dict>
5
5
  <key>Label</key>
6
6
  <string><%= "#{app}-#{name}-#{num}" %></string>
7
+ <key>EnvironmentVariables</key>
8
+ <dict>
9
+ <%- engine.env.merge("PORT" => port).each_pair do |var,env| -%>
10
+ <key><%= var.upcase %></key>
11
+ <string><%= env %></string>
12
+ <%- end -%>
13
+ </dict>
7
14
  <key>ProgramArguments</key>
8
15
  <array>
9
- <string><%= process.command %></string>
16
+ <%- command_args.each do |command| -%>
17
+ <string><%= command %></string>
18
+ <%- end -%>
10
19
  </array>
11
20
  <key>KeepAlive</key>
12
21
  <true/>
13
22
  <key>RunAtLoad</key>
14
23
  <true/>
24
+ <key>StandardOutPath</key>
25
+ <string><%= log %>/<%= app %>-<%= name %>-<%=num%>.log</string>
15
26
  <key>StandardErrorPath</key>
16
27
  <string><%= log %>/<%= app %>-<%= name %>-<%=num%>.log</string>
17
28
  <key>UserName</key>
@@ -0,0 +1,54 @@
1
+ if defined?(Capistrano)
2
+ Capistrano::Configuration.instance(:must_exist).load do
3
+
4
+ namespace :foreman do
5
+ desc <<-DESC
6
+ Export the Procfile to upstart. Will use sudo if available.
7
+
8
+ You can override any of these defaults by setting the variables shown below.
9
+
10
+ set :foreman_format, "upstart"
11
+ set :foreman_location, "/etc/init"
12
+ set :foreman_procfile, "Procfile"
13
+ set :foreman_app, application
14
+ set :foreman_user, user
15
+ set :foreman_log, "#{shared_path}/log"
16
+ set :foreman_concurrency, false
17
+ DESC
18
+ task :export, :roles => :app do
19
+ bundle_cmd = fetch(:bundle_cmd, "bundle")
20
+ foreman_format = fetch(:foreman_format, "upstart")
21
+ foreman_location = fetch(:foreman_location, "/etc/init")
22
+ foreman_procfile = fetch(:foreman_procfile, "Procfile")
23
+ foreman_app = fetch(:foreman_app, application)
24
+ foreman_user = fetch(:foreman_user, user)
25
+ foreman_log = fetch(:foreman_log, "#{shared_path}/log")
26
+ foreman_concurrency = fetch(:foreman_concurrency, false)
27
+
28
+ args = ["#{foreman_format} #{foreman_location}"]
29
+ args << "-f #{foreman_procfile}"
30
+ args << "-a #{foreman_app}"
31
+ args << "-u #{foreman_user}"
32
+ args << "-l #{foreman_log}"
33
+ args << "-c #{foreman_concurrency}" if foreman_concurrency
34
+ run "cd #{release_path} && #{sudo} #{bundle_cmd} exec foreman export #{args.join(' ')}"
35
+ end
36
+
37
+ desc "Start the application services"
38
+ task :start, :roles => :app do
39
+ run "#{sudo} start #{application}"
40
+ end
41
+
42
+ desc "Stop the application services"
43
+ task :stop, :roles => :app do
44
+ run "#{sudo} stop #{application}"
45
+ end
46
+
47
+ desc "Restart the application services"
48
+ task :restart, :roles => :app do
49
+ run "#{sudo} start #{application} || #{sudo} restart #{application}"
50
+ end
51
+
52
+ end
53
+ end
54
+ end
data/lib/foreman/cli.rb CHANGED
@@ -86,6 +86,7 @@ class Foreman::CLI < Thor
86
86
  end
87
87
  end
88
88
  Process.wait(pid)
89
+ exit $?.exitstatus
89
90
  end
90
91
 
91
92
  desc "version", "Display Foreman gem version"
@@ -129,7 +130,7 @@ private ######################################################################
129
130
  def procfile
130
131
  case
131
132
  when options[:procfile] then options[:procfile]
132
- when options[:root] then File.expand_path(File.join(options[:app_root], "Procfile"))
133
+ when options[:root] then File.expand_path(File.join(options[:root], "Procfile"))
133
134
  else "Procfile"
134
135
  end
135
136
  end
@@ -257,7 +257,6 @@ private
257
257
  reader, writer = create_pipe
258
258
  begin
259
259
  pid = process.run(:output => writer, :env => {
260
- "HOME" => process.cwd,
261
260
  "PORT" => port_for(process, n).to_s
262
261
  })
263
262
  writer.puts "started with pid #{pid}"
data/lib/foreman/env.rb CHANGED
@@ -9,8 +9,10 @@ class Foreman::Env
9
9
  if line =~ /\A([A-Za-z_0-9]+)=(.*)\z/
10
10
  key = $1
11
11
  case val = $2
12
+ # Remove single quotes
12
13
  when /\A'(.*)'\z/ then ax[key] = $1
13
- when /\A"(.*)"\z/ then ax[key] = $1.gsub(/\\(.)/, '\1')
14
+ # Remove double quotes and unescape string preserving newline characters
15
+ when /\A"(.*)"\z/ then ax[key] = $1.gsub('\n', "\n").gsub(/\\(.)/, '\1')
14
16
  else ax[key] = val
15
17
  end
16
18
  end
@@ -119,7 +119,7 @@ private ######################################################################
119
119
  end
120
120
 
121
121
  def write_template(name, target, binding)
122
- compiled = ERB.new(export_template(name)).result(binding)
122
+ compiled = ERB.new(export_template(name), nil, '-').result(binding)
123
123
  write_file target, compiled
124
124
  end
125
125
 
@@ -13,7 +13,16 @@ class Foreman::Export::Inittab < Foreman::Export::Base
13
13
  1.upto(engine.formation[name]) do |num|
14
14
  id = app.slice(0, 2).upcase + sprintf("%02d", index)
15
15
  port = engine.port_for(process, num)
16
- inittab << "#{id}:4:respawn:/bin/su - #{user} -c 'PORT=#{port} #{process.command} >> #{log}/#{name}-#{num}.log 2>&1'"
16
+
17
+ commands = []
18
+ commands << "cd #{engine.root}"
19
+ commands << "export PORT=#{port}"
20
+ engine.env.each_pair do |var, env|
21
+ commands << "export #{var.upcase}=#{shell_quote(env)}"
22
+ end
23
+ commands << "#{process.command} >> #{log}/#{name}-#{num}.log 2>&1"
24
+
25
+ inittab << "#{id}:4:respawn:/bin/su - #{user} -c '#{commands.join(";")}'"
17
26
  index += 1
18
27
  end
19
28
  end
@@ -7,6 +7,8 @@ class Foreman::Export::Launchd < Foreman::Export::Base
7
7
  super
8
8
  engine.each_process do |name, process|
9
9
  1.upto(engine.formation[name]) do |num|
10
+ port = engine.port_for(process, num)
11
+ command_args = process.command.split(" ")
10
12
  write_template "launchd/launchd.plist.erb", "#{app}-#{name}-#{num}.plist", binding
11
13
  end
12
14
  end
@@ -1,5 +1,5 @@
1
1
  module Foreman
2
2
 
3
- VERSION = "0.57.0"
3
+ VERSION = "0.58.0"
4
4
 
5
5
  end
data/man/foreman.1 CHANGED
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "FOREMAN" "1" "July 2012" "Foreman 0.51.0" "Foreman Manual"
4
+ .TH "FOREMAN" "1" "July 2012" "Foreman 0.57.0" "Foreman Manual"
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBforeman\fR \- manage Procfile\-based applications
@@ -72,6 +72,11 @@ describe "Foreman::CLI", :fakefs do
72
72
  it "includes the environment" do
73
73
  forked_foreman("run #{resource_path("bin/env FOO")} -e #{resource_path(".env")}").should == "bar\n"
74
74
  end
75
+
76
+ it "exits with the same exit code as the command" do
77
+ fork_and_get_exitstatus("run echo 1").should == 0
78
+ fork_and_get_exitstatus("run date 'invalid_date'").should == 1
79
+ end
75
80
  end
76
81
 
77
82
  describe "version" do
@@ -90,6 +90,14 @@ describe "Foreman::Engine", :fakefs do
90
90
  subject.env["OTHER"].should == 'escaped"quote'
91
91
  end
92
92
 
93
+ it "should handle multiline strings" do
94
+ File.open("/tmp/env", "w") do |f|
95
+ f.puts 'FOO="bar\nbaz"'
96
+ end
97
+ subject.load_env "/tmp/env"
98
+ subject.env["FOO"].should == "bar\nbaz"
99
+ end
100
+
93
101
  it "should fail if specified and doesnt exist" do
94
102
  lambda { subject.load_env "/tmp/env" }.should raise_error(Errno::ENOENT)
95
103
  end
@@ -18,4 +18,14 @@ describe Foreman::Export::Launchd, :fakefs do
18
18
  File.read("/tmp/init/app-bravo-1.plist").should == example_export_file("launchd/launchd-b.default")
19
19
  end
20
20
 
21
+ context "with multiple command arguments" do
22
+ let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile", "charlie") }
23
+
24
+ it "splits each command argument" do
25
+ launchd.export
26
+ File.read("/tmp/init/app-alpha-1.plist").should == example_export_file("launchd/launchd-c.default")
27
+ end
28
+
29
+ end
30
+
21
31
  end
@@ -1,4 +1,4 @@
1
1
  # ----- foreman app processes -----
2
- AP01:4:respawn:/bin/su - app -c 'PORT=5000 ./alpha >> /var/log/app/alpha-1.log 2>&1'
3
- AP02:4:respawn:/bin/su - app -c 'PORT=5001 ./alpha >> /var/log/app/alpha-2.log 2>&1'
2
+ AP01:4:respawn:/bin/su - app -c 'cd /tmp/app;export PORT=5000;./alpha >> /var/log/app/alpha-1.log 2>&1'
3
+ AP02:4:respawn:/bin/su - app -c 'cd /tmp/app;export PORT=5001;./alpha >> /var/log/app/alpha-2.log 2>&1'
4
4
  # ----- end foreman app processes -----
@@ -1,4 +1,4 @@
1
1
  # ----- foreman app processes -----
2
- AP01:4:respawn:/bin/su - app -c 'PORT=5000 ./alpha >> /var/log/app/alpha-1.log 2>&1'
3
- AP02:4:respawn:/bin/su - app -c 'PORT=5100 ./bravo >> /var/log/app/bravo-1.log 2>&1'
2
+ AP01:4:respawn:/bin/su - app -c 'cd /tmp/app;export PORT=5000;./alpha >> /var/log/app/alpha-1.log 2>&1'
3
+ AP02:4:respawn:/bin/su - app -c 'cd /tmp/app;export PORT=5100;./bravo >> /var/log/app/bravo-1.log 2>&1'
4
4
  # ----- end foreman app processes -----
@@ -4,6 +4,11 @@
4
4
  <dict>
5
5
  <key>Label</key>
6
6
  <string>app-alpha-1</string>
7
+ <key>EnvironmentVariables</key>
8
+ <dict>
9
+ <key>PORT</key>
10
+ <string>5000</string>
11
+ </dict>
7
12
  <key>ProgramArguments</key>
8
13
  <array>
9
14
  <string>./alpha</string>
@@ -12,6 +17,8 @@
12
17
  <true/>
13
18
  <key>RunAtLoad</key>
14
19
  <true/>
20
+ <key>StandardOutPath</key>
21
+ <string>/var/log/app/app-alpha-1.log</string>
15
22
  <key>StandardErrorPath</key>
16
23
  <string>/var/log/app/app-alpha-1.log</string>
17
24
  <key>UserName</key>
@@ -4,6 +4,11 @@
4
4
  <dict>
5
5
  <key>Label</key>
6
6
  <string>app-bravo-1</string>
7
+ <key>EnvironmentVariables</key>
8
+ <dict>
9
+ <key>PORT</key>
10
+ <string>5100</string>
11
+ </dict>
7
12
  <key>ProgramArguments</key>
8
13
  <array>
9
14
  <string>./bravo</string>
@@ -12,6 +17,8 @@
12
17
  <true/>
13
18
  <key>RunAtLoad</key>
14
19
  <true/>
20
+ <key>StandardOutPath</key>
21
+ <string>/var/log/app/app-bravo-1.log</string>
15
22
  <key>StandardErrorPath</key>
16
23
  <string>/var/log/app/app-bravo-1.log</string>
17
24
  <key>UserName</key>
@@ -0,0 +1,30 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>Label</key>
6
+ <string>app-alpha-1</string>
7
+ <key>EnvironmentVariables</key>
8
+ <dict>
9
+ <key>PORT</key>
10
+ <string>5000</string>
11
+ </dict>
12
+ <key>ProgramArguments</key>
13
+ <array>
14
+ <string>./alpha</string>
15
+ <string>charlie</string>
16
+ </array>
17
+ <key>KeepAlive</key>
18
+ <true/>
19
+ <key>RunAtLoad</key>
20
+ <true/>
21
+ <key>StandardOutPath</key>
22
+ <string>/var/log/app/app-alpha-1.log</string>
23
+ <key>StandardErrorPath</key>
24
+ <string>/var/log/app/app-alpha-1.log</string>
25
+ <key>UserName</key>
26
+ <string>app</string>
27
+ <key>WorkingDirectory</key>
28
+ <string>/tmp/app</string>
29
+ </dict>
30
+ </plist>
data/spec/spec_helper.rb CHANGED
@@ -58,6 +58,12 @@ def fork_and_capture(&blk)
58
58
  end
59
59
  end
60
60
 
61
+ def fork_and_get_exitstatus(args)
62
+ pid = Process.spawn("bundle exec bin/foreman #{args}", :out => "/dev/null", :err => "/dev/null")
63
+ Process.wait(pid)
64
+ $?.exitstatus
65
+ end
66
+
61
67
  def mock_exit(&block)
62
68
  block.should raise_error(SystemExit)
63
69
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.57.0
4
+ version: 0.58.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-21 00:00:00.000000000 Z
12
+ date: 2012-09-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: thor
16
- requirement: &70227591758760 !ruby/object:Gem::Requirement
16
+ requirement: &70177359356080 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: 0.13.6
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70227591758760
24
+ version_requirements: *70177359356080
25
25
  description: Process manager for applications with multiple components
26
26
  email: ddollar@gmail.com
27
27
  executables:
@@ -48,6 +48,7 @@ files:
48
48
  - data/export/upstart/master.conf.erb
49
49
  - data/export/upstart/process.conf.erb
50
50
  - data/export/upstart/process_master.conf.erb
51
+ - lib/foreman/capistrano.rb
51
52
  - lib/foreman/cli.rb
52
53
  - lib/foreman/distribution.rb
53
54
  - lib/foreman/engine/cli.rb
@@ -92,6 +93,7 @@ files:
92
93
  - spec/resources/export/inittab/inittab.default
93
94
  - spec/resources/export/launchd/launchd-a.default
94
95
  - spec/resources/export/launchd/launchd-b.default
96
+ - spec/resources/export/launchd/launchd-c.default
95
97
  - spec/resources/export/runit/app-alpha-1/log/run
96
98
  - spec/resources/export/runit/app-alpha-1/run
97
99
  - spec/resources/export/runit/app-alpha-2/log/run
@@ -121,18 +123,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
121
123
  - - ! '>='
122
124
  - !ruby/object:Gem::Version
123
125
  version: '0'
124
- segments:
125
- - 0
126
- hash: 1574791230196847546
127
126
  required_rubygems_version: !ruby/object:Gem::Requirement
128
127
  none: false
129
128
  requirements:
130
129
  - - ! '>='
131
130
  - !ruby/object:Gem::Version
132
131
  version: '0'
133
- segments:
134
- - 0
135
- hash: 1574791230196847546
136
132
  requirements: []
137
133
  rubyforge_project:
138
134
  rubygems_version: 1.8.11
@@ -140,4 +136,3 @@ signing_key:
140
136
  specification_version: 3
141
137
  summary: Process manager for applications with multiple components
142
138
  test_files: []
143
- has_rdoc: