Compare commits
217 Commits
v0.48.0.pr
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 199e7de97c | |||
|
|
defc40b911 | ||
|
|
37dcba0e33 | ||
|
|
d205e3ba2e | ||
|
|
9905334f01 | ||
|
|
dd292ed7da | ||
|
|
67ffbe2aa2 | ||
|
|
da8bba5941 | ||
|
|
2aa1cbf94f | ||
|
|
34a1163fe9 | ||
|
|
2e5f610b76 | ||
|
|
20392d98a1 | ||
|
|
e8538d9f45 | ||
|
|
4a51a2aa8a | ||
|
|
1905a7c310 | ||
|
|
134b31f599 | ||
|
|
2b97cb458a | ||
|
|
03d76d4254 | ||
|
|
133228f247 | ||
|
|
bfba2cad71 | ||
|
|
e245026f65 | ||
|
|
ffc73366b2 | ||
|
|
284503899a | ||
|
|
144be02bbd | ||
|
|
9734a2ed65 | ||
|
|
0fff148fe0 | ||
|
|
d19a9aa043 | ||
|
|
c3abaad353 | ||
|
|
b1f91d4505 | ||
|
|
0c7b8ddd79 | ||
|
|
189b751d9f | ||
|
|
619bd03bb8 | ||
|
|
fd836b46c0 | ||
|
|
2379259b33 | ||
|
|
baf842cdd4 | ||
|
|
5c06aaaa57 | ||
|
|
75b782b664 | ||
|
|
9b4bd10cdb | ||
|
|
fff82dc685 | ||
|
|
da0a9f2de3 | ||
|
|
7d77d8ff1a | ||
|
|
51e181da29 | ||
|
|
9866a341ca | ||
|
|
90848e7dea | ||
|
|
a92e24b17c | ||
|
|
0da42cf7d2 | ||
|
|
23561b963c | ||
|
|
cc51ab2cb1 | ||
|
|
403d40b277 | ||
|
|
669a920c1e | ||
|
|
d357197718 | ||
|
|
f6b57d7b92 | ||
|
|
e79588fd40 | ||
|
|
f1c2347680 | ||
|
|
80f8242b11 | ||
|
|
383276bb79 | ||
|
|
5a7692ff2c | ||
|
|
405a85bc86 | ||
|
|
bff554d554 | ||
|
|
eaed989c75 | ||
|
|
93daebbf1b | ||
|
|
17a8a316b8 | ||
|
|
9e1d590734 | ||
|
|
6611d818b1 | ||
|
|
ad4d59ae14 | ||
|
|
434f30fe42 | ||
|
|
1cb1c8812a | ||
|
|
6786f4df39 | ||
|
|
0be08a0651 | ||
|
|
3abe10e5ab | ||
|
|
66ab0f08e7 | ||
|
|
95a1d49e9d | ||
|
|
7be4375168 | ||
|
|
2ebb33e049 | ||
|
|
9fe7ddb8bd | ||
|
|
f954a42ecb | ||
|
|
169188376b | ||
|
|
5ab08c608b | ||
|
|
0b5c1f919e | ||
|
|
c94aa13b06 | ||
|
|
8d1e3a849f | ||
|
|
5ef8bbdbe3 | ||
|
|
4e84b92536 | ||
|
|
6215f8b3db | ||
|
|
8cf5896c3e | ||
|
|
5f8032cac8 | ||
|
|
9f3b903085 | ||
|
|
69d278d864 | ||
|
|
ba9167152c | ||
|
|
f31ff18191 | ||
|
|
c42110e438 | ||
|
|
26bb0ed54e | ||
|
|
44002953f6 | ||
|
|
bb2c3a2d04 | ||
|
|
88cdaacc67 | ||
|
|
faf7b3c40f | ||
|
|
21dd610eaf | ||
|
|
fe65c7510d | ||
|
|
cd2c255296 | ||
|
|
92c1909217 | ||
|
|
af57bf3d52 | ||
|
|
443994d3b5 | ||
|
|
2faa3fb6ff | ||
|
|
0d53f6bd6c | ||
|
|
1d2bcdbc56 | ||
|
|
aceea1472a | ||
|
|
44726e377e | ||
|
|
61eca5a1d8 | ||
|
|
553ac7f81f | ||
|
|
6790cf02a9 | ||
|
|
9325f2ca6d | ||
|
|
7ad41da592 | ||
|
|
8ee7b7afdf | ||
|
|
2620b90808 | ||
|
|
89bdc3ab8e | ||
|
|
60a11eb981 | ||
|
|
61c222deb8 | ||
|
|
8fe86e98c8 | ||
|
|
5c1ffdb7dc | ||
|
|
8b49256175 | ||
|
|
37d777f224 | ||
|
|
73fc059634 | ||
|
|
f7b7029cc0 | ||
|
|
3a101ec7dd | ||
|
|
6c931ea15e | ||
|
|
d173570d98 | ||
|
|
0cd41fee7f | ||
|
|
9da4e38209 | ||
|
|
5d9dfd294e | ||
|
|
8998e9a47c | ||
|
|
8238a86942 | ||
|
|
1153fb0f0c | ||
|
|
f69c755d9a | ||
|
|
9a91e5df44 | ||
|
|
64f0749d16 | ||
|
|
6b77ca1e46 | ||
|
|
8fbee31a2d | ||
|
|
7b4eabf0c5 | ||
|
|
6a44dd3fd3 | ||
|
|
e99f3173ef | ||
|
|
6c04dab649 | ||
|
|
96e26e7412 | ||
|
|
a2c03cc402 | ||
|
|
803115c0c4 | ||
|
|
a4343187ad | ||
|
|
98af1f0943 | ||
|
|
af2d4762a8 | ||
|
|
1d06124457 | ||
|
|
698e6ae092 | ||
|
|
c617ddb3b2 | ||
|
|
f6d4badcd2 | ||
|
|
f29bf49a35 | ||
|
|
e06d36b27c | ||
|
|
85e62dfbeb | ||
|
|
574e852710 | ||
|
|
68f098c1d2 | ||
|
|
e8bdafdfc1 | ||
|
|
4abd3ebedb | ||
|
|
f765436dde | ||
|
|
b5c513b4b5 | ||
|
|
ee761ff098 | ||
|
|
27c22deb6c | ||
|
|
681a9f7e61 | ||
|
|
8335a2b1ba | ||
|
|
407425ca78 | ||
|
|
6ca505b4cd | ||
|
|
612eae5e21 | ||
|
|
497b5ea1eb | ||
|
|
cd384e0d59 | ||
|
|
8921cac35b | ||
|
|
7d6de5b2a7 | ||
|
|
cc4306492e | ||
|
|
6042783e82 | ||
|
|
b7b3a9f898 | ||
|
|
8b204db2f0 | ||
|
|
15643dcb3f | ||
|
|
5f0f2f5378 | ||
|
|
c1b57b59cf | ||
|
|
21d53818f2 | ||
|
|
359d6f1c34 | ||
|
|
584f251e4a | ||
|
|
7d9c2b2ac4 | ||
|
|
fba4d9beff | ||
|
|
0bde5fdab5 | ||
|
|
ebe160d425 | ||
|
|
1beab80c1f | ||
|
|
7b270f9f4a | ||
|
|
03e5342067 | ||
|
|
b1d57426fb | ||
|
|
06e5c52f35 | ||
|
|
64ca839c0b | ||
|
|
80aebda023 | ||
|
|
5dee2281a2 | ||
|
|
efb6d2f11d | ||
|
|
ac528d3b50 | ||
|
|
cefd4e351e | ||
|
|
9849f4558a | ||
|
|
4b53b42be1 | ||
|
|
219acaf690 | ||
|
|
f8118d7b40 | ||
|
|
7fdade277c | ||
|
|
1a0943c495 | ||
|
|
4a732abd77 | ||
|
|
3e71fea777 | ||
|
|
ae7aeabb63 | ||
|
|
0a61b1a62f | ||
|
|
9901b9f924 | ||
|
|
4c2d569810 | ||
|
|
26f9c8186d | ||
|
|
24ed8946f3 | ||
|
|
83b2a9cc50 | ||
|
|
a0228b9fa0 | ||
|
|
b1a2a4a0cd | ||
|
|
7774b7f150 | ||
|
|
b01355a093 | ||
|
|
8b18143281 | ||
|
|
e06886ed57 |
14
.travis.yml
14
.travis.yml
@@ -1,8 +1,8 @@
|
|||||||
script: bundle exec rake spec
|
script: bundle exec rake spec
|
||||||
|
|
||||||
rvm:
|
matrix:
|
||||||
- 1.9.2
|
allow_failures:
|
||||||
- 1.9.3
|
- rvm: jruby
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
email: false
|
email: false
|
||||||
@@ -11,3 +11,11 @@ notifications:
|
|||||||
on_failure: always
|
on_failure: always
|
||||||
urls:
|
urls:
|
||||||
- http://dx-helper.herokuapp.com/travis
|
- http://dx-helper.herokuapp.com/travis
|
||||||
|
|
||||||
|
rvm:
|
||||||
|
- 1.8.7
|
||||||
|
- 1.9.2
|
||||||
|
- 1.9.3
|
||||||
|
- 2.0.0
|
||||||
|
- 2.1.0
|
||||||
|
- jruby
|
||||||
|
|||||||
148
Changelog.md
148
Changelog.md
@@ -1,3 +1,151 @@
|
|||||||
|
## 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)
|
||||||
|
|
||||||
|
* Fix bug in color definitons [nseo]
|
||||||
|
* Fix for high CPU load when processes close output [Pavel Forkert]
|
||||||
|
* Ensure foreman is the process group leader [Christos Trochalakis]
|
||||||
|
* Don't ignore blank lines in the output [Matt Venables]
|
||||||
|
* Add license to gemspec [petedmarsh]
|
||||||
|
* Since JRuby 1.9 doesn't require posix/spawn, only follow that path if JRuby is loaded and running in 1.8 mode. [Adam Hutchison]
|
||||||
|
* Remove explicit requirement on rubygems. [Cyril Rohr]
|
||||||
|
* Dont use shared_path variable before multistage has a chance at it [Aditya Sanghi]
|
||||||
|
* Strip Windows Line Endings [Paul Morton]
|
||||||
|
* Fix man page: --directory is actually --root. [Evan Jones]
|
||||||
|
* Add timeout switch to CLI [Paulo Luis Franchini Casaretto]
|
||||||
|
* Remove expectation of double quotes around environment variables from test comparisons [Kevin McAllister]
|
||||||
|
* Remove explicit wrapping of Shellwords.escape in double quotes [Kevin McAllister]
|
||||||
|
|
||||||
|
## 0.60.2 (2012-10-08)
|
||||||
|
|
||||||
|
* Fix for nil value on io select loop, fixes #260 [Silvio Relli]
|
||||||
|
|
||||||
|
## 0.60.1 (2012-10-08)
|
||||||
|
|
||||||
|
* sleep on select() to avoid spinning the cpu [Silvio Relli]
|
||||||
|
|
||||||
|
## 0.60.0 (2012-09-25)
|
||||||
|
|
||||||
|
* foreman run can run things from the Procfile like heroku run. [Dan Peterson]
|
||||||
|
|
||||||
|
## 0.59.0 (2012-09-15)
|
||||||
|
|
||||||
|
* Use /bin/sh instead of bash for foreman-runner [Jeremy Evans]
|
||||||
|
|
||||||
|
## 0.58.0 (2012-09-14)
|
||||||
|
|
||||||
|
* dont set HOME [David Dollar]
|
||||||
|
* Add StandardOutPath to launchd export [Aaron Kalin]
|
||||||
|
* Add command argument string splitting [Aaron Kalin]
|
||||||
|
* Cleanup launchd exporter [Aaron Kalin]
|
||||||
|
* Enable trim_mode via '-' in ERB templates [Aaron Kalin]
|
||||||
|
* Add support for setting environment variables [Aaron Kalin]
|
||||||
|
* foreman run should exit with the same code as its command [Omar Khan]
|
||||||
|
* Handle multiline strings in .env file [Szymon Nowak]
|
||||||
|
* Use path and env variables in the inittab export [Indrek Juhkam]
|
||||||
|
* fixed the directory option [Arnaud Lachaume]
|
||||||
|
* Add capistrano export support [Daniel Farrell]
|
||||||
|
|
||||||
|
## 0.57.0 (2012-08-21)
|
||||||
|
|
||||||
|
* fix startup checks for upstart exporter [Aditya Sanghi]
|
||||||
|
|
||||||
|
## 0.56.0 (2012-08-19)
|
||||||
|
|
||||||
|
* read .profile, not .profile.d [David Dollar]
|
||||||
|
|
||||||
|
## 0.55.0 (2012-08-14)
|
||||||
|
|
||||||
|
* use a forked process to exec a run with environment [David Dollar]
|
||||||
|
|
||||||
|
## 0.54.0 (2012-08-14)
|
||||||
|
|
||||||
|
* use Foreman::Process to extract command running [David Dollar]
|
||||||
|
* changed to check env for bash [brntbeer]
|
||||||
|
|
||||||
|
## 0.53.0 (2012-07-24)
|
||||||
|
|
||||||
|
* put app root in $HOME [David Dollar]
|
||||||
|
|
||||||
|
## 0.52.0 (2012-07-24)
|
||||||
|
|
||||||
|
* wrap command in a runner that sources .profile.d scripts [David Dollar]
|
||||||
|
* fix upstart export specs [David Dollar]
|
||||||
|
* Make upstart export start/stop with network [Daniel Farrell]
|
||||||
|
|
||||||
|
## 0.51.0 (2012-07-11)
|
||||||
|
|
||||||
|
* dont try to colorize windows [David Dollar]
|
||||||
|
|
||||||
|
## 0.50.0 (2012-07-11)
|
||||||
|
|
||||||
|
* handle windows [David Dollar]
|
||||||
|
|
||||||
|
## 0.49.0 (2012-07-11)
|
||||||
|
|
||||||
|
* 1.8 compatibility [David Dollar]
|
||||||
|
* use one pgroup for all of foreman and kill that since ruby 1.8 sucks at pgroups [David Dollar]
|
||||||
|
* better debugging [David Dollar]
|
||||||
|
|
||||||
|
## 0.48.0 (2012-07-10)
|
||||||
|
|
||||||
|
* allow old exporter format to work, but with deprecation warning [David Dollar]
|
||||||
|
* remove debugging code [David Dollar]
|
||||||
|
* Merge pull request #219 from MarkDBlackwell/patch-1 [David Dollar]
|
||||||
|
* Avoid crash by verifying the existence of SIGHUP before accessing it. [Mark D. Blackwell]
|
||||||
|
* allow color to be forced on [David Dollar]
|
||||||
|
* terminate gracefully if stdout goes away [David Dollar]
|
||||||
|
* always flush output [David Dollar]
|
||||||
|
* Merge pull request #212 from morgoth/added-version-command [David Dollar]
|
||||||
|
* added command for displaying foreman version [Wojciech Wnętrzak]
|
||||||
|
* Merge pull request #211 from morgoth/fixed-yaml-usage [David Dollar]
|
||||||
|
* fixed using YAML [Wojciech Wnętrzak]
|
||||||
|
* test on more things, but don't fail [David Dollar]
|
||||||
|
* changelog [David Dollar]
|
||||||
|
* 0.48.0.pre1 [David Dollar]
|
||||||
|
* foreman doesn't work on ruby 1.8, may try to fix later [David Dollar]
|
||||||
|
* use bash [David Dollar]
|
||||||
|
* massive refactoring for programmatic control and stability [David Dollar]
|
||||||
|
* Merge pull request #164 from hsume2/master [David Dollar]
|
||||||
|
* Only run tmux specs if tmux is installed [Henry Hsu]
|
||||||
|
* Do not assume BUNDLE_GEMFILE [Henry Hsu]
|
||||||
|
* Add support for starting procfile in tmux session [Henry Hsu]
|
||||||
|
|
||||||
|
## 0.47.0 (2012-06-07)
|
||||||
|
|
||||||
|
* Fix multi-word argument handling in `foreman run`. [Daniel Brockman]
|
||||||
|
* Make 'PORT=5000 foreman start' work [Koen Van der Auwera]
|
||||||
|
* Terminate gracefully upon SIGHUP [Stefan Schüßler]
|
||||||
|
* Set port from .env if specified [Koen Van der Auwera]
|
||||||
|
* Updated bluepill exporter to use environment variables from .env [Aneeth]
|
||||||
|
* Added launchd exporter [Maxwell Swadling]
|
||||||
|
* Quote and escape environment variables in upstart templates [Matt Griffin]
|
||||||
|
* Added list of ports to other languages to README [elf Pavlik]
|
||||||
|
|
||||||
## 0.46.0 (2012-05-02)
|
## 0.46.0 (2012-05-02)
|
||||||
|
|
||||||
* Add Profile load/write/append API [Michael Granger]
|
* Add Profile load/write/append API [Michael Granger]
|
||||||
|
|||||||
6
Gemfile
6
Gemfile
@@ -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
|
||||||
|
|
||||||
@@ -18,6 +18,8 @@ group :development do
|
|||||||
gem 'rr', '~> 1.0.2'
|
gem 'rr', '~> 1.0.2'
|
||||||
gem 'rspec', '~> 2.0'
|
gem 'rspec', '~> 2.0'
|
||||||
gem "simplecov", :require => false
|
gem "simplecov", :require => false
|
||||||
gem 'timecop'
|
gem 'timecop', '0.6.1'
|
||||||
gem 'yard'
|
gem 'yard'
|
||||||
|
gem 'mime-types', '~> 1.25.1'
|
||||||
|
gem 'rdiscount', '~> 1.6.8'
|
||||||
end
|
end
|
||||||
|
|||||||
64
Gemfile.lock
64
Gemfile.lock
@@ -1,49 +1,53 @@
|
|||||||
PATH
|
PATH
|
||||||
remote: .
|
remote: .
|
||||||
specs:
|
specs:
|
||||||
foreman (0.48.0.pre1)
|
foreman (0.63.0)
|
||||||
|
dotenv (>= 0.7)
|
||||||
thor (>= 0.13.6)
|
thor (>= 0.13.6)
|
||||||
|
|
||||||
GEM
|
GEM
|
||||||
remote: http://rubygems.org/
|
remote: http://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
aws-s3 (0.6.2)
|
aws-s3 (0.6.3)
|
||||||
builder
|
builder
|
||||||
mime-types
|
mime-types
|
||||||
xml-simple
|
xml-simple
|
||||||
builder (3.0.0)
|
builder (3.2.2)
|
||||||
diff-lcs (1.1.3)
|
diff-lcs (1.2.5)
|
||||||
|
docile (1.1.3)
|
||||||
|
dotenv (0.10.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)
|
||||||
mime-types (1.16)
|
mime-types (1.25.1)
|
||||||
multi_json (1.0.4)
|
multi_json (1.9.0)
|
||||||
mustache (0.11.2)
|
mustache (0.99.5)
|
||||||
posix-spawn (0.3.6)
|
posix-spawn (0.3.8)
|
||||||
rake (0.9.2.2)
|
rake (10.1.1)
|
||||||
rdiscount (1.6.5)
|
rdiscount (1.6.8)
|
||||||
ronn (0.7.3)
|
ronn (0.7.3)
|
||||||
hpricot (>= 0.8.2)
|
hpricot (>= 0.8.2)
|
||||||
mustache (>= 0.7.0)
|
mustache (>= 0.7.0)
|
||||||
rdiscount (>= 1.5.8)
|
rdiscount (>= 1.5.8)
|
||||||
rr (1.0.2)
|
rr (1.0.5)
|
||||||
rspec (2.8.0)
|
rspec (2.14.1)
|
||||||
rspec-core (~> 2.8.0)
|
rspec-core (~> 2.14.0)
|
||||||
rspec-expectations (~> 2.8.0)
|
rspec-expectations (~> 2.14.0)
|
||||||
rspec-mocks (~> 2.8.0)
|
rspec-mocks (~> 2.14.0)
|
||||||
rspec-core (2.8.0)
|
rspec-core (2.14.8)
|
||||||
rspec-expectations (2.8.0)
|
rspec-expectations (2.14.5)
|
||||||
diff-lcs (~> 1.1.2)
|
diff-lcs (>= 1.1.3, < 2.0)
|
||||||
rspec-mocks (2.8.0)
|
rspec-mocks (2.14.6)
|
||||||
simplecov (0.5.4)
|
simplecov (0.8.2)
|
||||||
multi_json (~> 1.0.3)
|
docile (~> 1.1.0)
|
||||||
simplecov-html (~> 0.5.3)
|
multi_json
|
||||||
simplecov-html (0.5.3)
|
simplecov-html (~> 0.8.0)
|
||||||
thor (0.14.6)
|
simplecov-html (0.8.0)
|
||||||
timecop (0.3.5)
|
thor (0.18.1)
|
||||||
win32console (1.3.0-x86-mingw32)
|
timecop (0.6.1)
|
||||||
xml-simple (1.0.15)
|
win32console (1.3.2-x86-mingw32)
|
||||||
yard (0.8.2)
|
xml-simple (1.1.3)
|
||||||
|
yard (0.8.7.3)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
java
|
java
|
||||||
@@ -54,12 +58,14 @@ DEPENDENCIES
|
|||||||
aws-s3
|
aws-s3
|
||||||
fakefs (~> 0.3.2)
|
fakefs (~> 0.3.2)
|
||||||
foreman!
|
foreman!
|
||||||
|
mime-types (~> 1.25.1)
|
||||||
posix-spawn (~> 0.3.6)
|
posix-spawn (~> 0.3.6)
|
||||||
rake
|
rake
|
||||||
|
rdiscount (~> 1.6.8)
|
||||||
ronn
|
ronn
|
||||||
rr (~> 1.0.2)
|
rr (~> 1.0.2)
|
||||||
rspec (~> 2.0)
|
rspec (~> 2.0)
|
||||||
simplecov
|
simplecov
|
||||||
timecop
|
timecop (= 0.6.1)
|
||||||
win32console (~> 1.3.0)
|
win32console (~> 1.3.0)
|
||||||
yard
|
yard
|
||||||
|
|||||||
19
LICENSE
Normal file
19
LICENSE
Normal 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.
|
||||||
@@ -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,6 +1,6 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
#/ Usage: foreman-runner [-d <dir>] <command> [<args>...]
|
#/ Usage: foreman-runner [-d <dir>] [-p] <command> [<args>...]
|
||||||
#/
|
#/
|
||||||
#/ Run a command with exec, optionally changing directory first
|
#/ Run a command with exec, optionally changing directory first
|
||||||
|
|
||||||
@@ -16,9 +16,12 @@ usage() {
|
|||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
|
|
||||||
while getopts ":hd:" OPT; do
|
read_profile=""
|
||||||
|
|
||||||
|
while getopts ":hd:p" OPT; do
|
||||||
case $OPT in
|
case $OPT in
|
||||||
d) cd "$OPTARG" ;;
|
d) cd "$OPTARG" ;;
|
||||||
|
p) read_profile="1" ;;
|
||||||
h) usage ;;
|
h) usage ;;
|
||||||
\?) error "invalid option: -$OPTARG" ;;
|
\?) error "invalid option: -$OPTARG" ;;
|
||||||
:) error "option -$OPTARG requires an argument" ;;
|
:) error "option -$OPTARG requires an argument" ;;
|
||||||
@@ -29,4 +32,10 @@ shift $((OPTIND-1))
|
|||||||
|
|
||||||
[ -z "$1" ] && usage
|
[ -z "$1" ] && usage
|
||||||
|
|
||||||
|
if [ "$read_profile" = "1" ]; then
|
||||||
|
if [ -f .profile ]; then
|
||||||
|
. ./.profile
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
exec "$@"
|
exec "$@"
|
||||||
|
|||||||
2
data/example/.profile.d/foo.sh
Normal file
2
data/example/.profile.d/foo.sh
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
export FOO=bar
|
||||||
@@ -9,6 +9,6 @@ sigterm() {
|
|||||||
#trap sigterm SIGTERM
|
#trap sigterm SIGTERM
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
echo "$NAME: ping"
|
echo "$NAME: ping $$"
|
||||||
sleep 1
|
sleep 1
|
||||||
done
|
done
|
||||||
|
|||||||
14
data/export/daemon/master.conf.erb
Normal file
14
data/export/daemon/master.conf.erb
Normal 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
data/export/daemon/process.conf.erb
Normal file
8
data/export/daemon/process.conf.erb
Normal 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
|
||||||
2
data/export/daemon/process_master.conf.erb
Normal file
2
data/export/daemon/process_master.conf.erb
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
start on starting <%= app %>
|
||||||
|
stop on stopping <%= app %>
|
||||||
@@ -4,14 +4,25 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>Label</key>
|
<key>Label</key>
|
||||||
<string><%= "#{app}-#{name}-#{num}" %></string>
|
<string><%= "#{app}-#{name}-#{num}" %></string>
|
||||||
|
<key>EnvironmentVariables</key>
|
||||||
|
<dict>
|
||||||
|
<%- engine.env.merge("PORT" => port).each_pair do |var,env| -%>
|
||||||
|
<key><%= var.upcase %></key>
|
||||||
|
<string><%= env %></string>
|
||||||
|
<%- end -%>
|
||||||
|
</dict>
|
||||||
<key>ProgramArguments</key>
|
<key>ProgramArguments</key>
|
||||||
<array>
|
<array>
|
||||||
<string><%= process.command %></string>
|
<%- command_args.each do |command| -%>
|
||||||
|
<string><%= command %></string>
|
||||||
|
<%- end -%>
|
||||||
</array>
|
</array>
|
||||||
<key>KeepAlive</key>
|
<key>KeepAlive</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>RunAtLoad</key>
|
<key>RunAtLoad</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>StandardOutPath</key>
|
||||||
|
<string><%= log %>/<%= app %>-<%= name %>-<%=num%>.log</string>
|
||||||
<key>StandardErrorPath</key>
|
<key>StandardErrorPath</key>
|
||||||
<string><%= log %>/<%= app %>-<%= name %>-<%=num%>.log</string>
|
<string><%= log %>/<%= app %>-<%= name %>-<%=num%>.log</string>
|
||||||
<key>UserName</key>
|
<key>UserName</key>
|
||||||
|
|||||||
6
data/export/systemd/master.target.erb
Normal file
6
data/export/systemd/master.target.erb
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
[Unit]
|
||||||
|
StopWhenUnneeded=true
|
||||||
|
Wants=<%= process_master_names.join(' ') %>
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
15
data/export/systemd/process.service.erb
Normal file
15
data/export/systemd/process.service.erb
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
[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
|
||||||
3
data/export/systemd/process_master.target.erb
Normal file
3
data/export/systemd/process_master.target.erb
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[Unit]
|
||||||
|
StopWhenUnneeded=true
|
||||||
|
Wants=<%= process_names.join(' ') %>
|
||||||
@@ -6,3 +6,7 @@ bash << "EOF"
|
|||||||
EOF
|
EOF
|
||||||
|
|
||||||
end script
|
end script
|
||||||
|
|
||||||
|
start on runlevel [2345]
|
||||||
|
|
||||||
|
stop on runlevel [016]
|
||||||
|
|||||||
@@ -2,4 +2,4 @@ start on starting <%= app %>-<%= name %>
|
|||||||
stop on stopping <%= app %>-<%= name %>
|
stop on stopping <%= app %>-<%= name %>
|
||||||
respawn
|
respawn
|
||||||
|
|
||||||
exec su - <%= user %> -c 'cd <%= engine.root %>; export PORT=<%= port %>;<% engine.env.each_pair do |var,env| %> export <%= var.upcase %>=<%= shell_quote(env) %>; <% end %> <%= process.command %> >> <%= log %>/<%=name%>-<%=num%>.log 2>&1'
|
exec su - <%= user %> -s /bin/sh -c 'cd <%= engine.root %>; export PORT=<%= port %>;<% engine.env.each_pair do |var,env| %> export <%= var.upcase %>=<%= shell_quote(env) %>; <% end %> exec <%= process.command %> >> <%= log %>/<%=name%>-<%=num%>.log 2>&1'
|
||||||
|
|||||||
2
dist/tgz.rake
vendored
2
dist/tgz.rake
vendored
@@ -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"
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ require "foreman/version"
|
|||||||
|
|
||||||
Gem::Specification.new do |gem|
|
Gem::Specification.new do |gem|
|
||||||
gem.name = "foreman"
|
gem.name = "foreman"
|
||||||
|
gem.license = "MIT"
|
||||||
gem.version = Foreman::VERSION
|
gem.version = Foreman::VERSION
|
||||||
|
|
||||||
gem.author = "David Dollar"
|
gem.author = "David Dollar"
|
||||||
@@ -17,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
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,12 @@ module Foreman
|
|||||||
File.expand_path("../../bin/foreman-runner", __FILE__)
|
File.expand_path("../../bin/foreman-runner", __FILE__)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.jruby?
|
def self.jruby_18?
|
||||||
defined?(RUBY_PLATFORM) and RUBY_PLATFORM == "java"
|
defined?(RUBY_PLATFORM) and RUBY_PLATFORM == "java" and ruby_18?
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.ruby_18?
|
||||||
|
defined?(RUBY_VERSION) and RUBY_VERSION =~ /^1\.8\.\d+/
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.windows?
|
def self.windows?
|
||||||
|
|||||||
@@ -3,21 +3,27 @@ require "foreman/helpers"
|
|||||||
require "foreman/engine"
|
require "foreman/engine"
|
||||||
require "foreman/engine/cli"
|
require "foreman/engine/cli"
|
||||||
require "foreman/export"
|
require "foreman/export"
|
||||||
|
require "foreman/version"
|
||||||
require "shellwords"
|
require "shellwords"
|
||||||
|
require "yaml"
|
||||||
require "thor"
|
require "thor"
|
||||||
|
|
||||||
class Foreman::CLI < Thor
|
class Foreman::CLI < Thor
|
||||||
|
|
||||||
include Foreman::Helpers
|
include Foreman::Helpers
|
||||||
|
|
||||||
|
map ["-v", "--version"] => :version
|
||||||
|
|
||||||
class_option :procfile, :type => :string, :aliases => "-f", :desc => "Default: Procfile"
|
class_option :procfile, :type => :string, :aliases => "-f", :desc => "Default: Procfile"
|
||||||
class_option :root, :type => :string, :aliases => "-d", :desc => "Default: Procfile directory"
|
class_option :root, :type => :string, :aliases => "-d", :desc => "Default: Procfile directory"
|
||||||
|
|
||||||
desc "start [PROCESS]", "Start the application (or a specific PROCESS)"
|
desc "start [PROCESS]", "Start the application (or a specific PROCESS)"
|
||||||
|
|
||||||
|
method_option :color, :type => :boolean, :aliases => "-c", :desc => "Force color to be enabled"
|
||||||
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 :formation, :type => :string, :aliases => "-m", :banner => '"alpha=5,bar=3"'
|
method_option :formation, :type => :string, :aliases => "-m", :banner => '"alpha=5,bar=3"'
|
||||||
method_option :port, :type => :numeric, :aliases => "-p"
|
method_option :port, :type => :numeric, :aliases => "-p"
|
||||||
|
method_option :timeout, :type => :numeric, :aliases => "-t", :desc => "Specify the amount of time (in seconds) processes have to shutdown gracefully before receiving a SIGKILL, defaults to 5."
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
# Hackery. Take the run method away from Thor so that we can redefine it.
|
# Hackery. Take the run method away from Thor so that we can redefine it.
|
||||||
@@ -28,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)
|
||||||
@@ -39,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"
|
||||||
@@ -70,8 +78,18 @@ class Foreman::CLI < Thor
|
|||||||
|
|
||||||
def run(*args)
|
def run(*args)
|
||||||
load_environment!
|
load_environment!
|
||||||
|
|
||||||
|
if File.exist?(procfile)
|
||||||
|
engine.load_procfile(procfile)
|
||||||
|
end
|
||||||
|
|
||||||
begin
|
begin
|
||||||
exec engine.env, args.shelljoin
|
engine.env.each { |k,v| ENV[k] = v }
|
||||||
|
if args.size == 1 && process = engine.process(args.first)
|
||||||
|
process.exec(:env => engine.env)
|
||||||
|
else
|
||||||
|
exec args.shelljoin
|
||||||
|
end
|
||||||
rescue Errno::EACCES
|
rescue Errno::EACCES
|
||||||
error "not executable: #{args.first}"
|
error "not executable: #{args.first}"
|
||||||
rescue Errno::ENOENT
|
rescue Errno::ENOENT
|
||||||
@@ -79,15 +97,17 @@ class Foreman::CLI < Thor
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
desc "version", "Display Foreman gem version"
|
||||||
|
|
||||||
|
def version
|
||||||
|
puts Foreman::VERSION
|
||||||
|
end
|
||||||
|
|
||||||
no_tasks do
|
no_tasks do
|
||||||
def engine
|
def engine
|
||||||
@engine ||= begin
|
@engine ||= begin
|
||||||
engine_class = Foreman::Engine::CLI
|
engine_class = Foreman::Engine::CLI
|
||||||
engine = engine_class.new(
|
engine = engine_class.new(options)
|
||||||
:formation => options[:formation],
|
|
||||||
:port => options[:port],
|
|
||||||
:root => options[:root]
|
|
||||||
)
|
|
||||||
engine
|
engine
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -115,10 +135,18 @@ 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]
|
||||||
when options[:root] then File.expand_path(File.join(options[:app_root], "Procfile"))
|
when options[:root] then File.expand_path(File.join(options[:root], "Procfile"))
|
||||||
else "Procfile"
|
else "Procfile"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -126,7 +154,7 @@ private ######################################################################
|
|||||||
def options
|
def options
|
||||||
original_options = super
|
original_options = super
|
||||||
return original_options unless File.exists?(".foreman")
|
return original_options unless File.exists?(".foreman")
|
||||||
defaults = YAML::load_file(".foreman") || {}
|
defaults = ::YAML::load_file(".foreman") || {}
|
||||||
Thor::CoreExt::HashWithIndifferentAccess.new(defaults.merge(original_options))
|
Thor::CoreExt::HashWithIndifferentAccess.new(defaults.merge(original_options))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
@@ -9,6 +9,10 @@ require "thread"
|
|||||||
|
|
||||||
class Foreman::Engine
|
class Foreman::Engine
|
||||||
|
|
||||||
|
# The signals that the engine cares about.
|
||||||
|
#
|
||||||
|
HANDLED_SIGNALS = [ :TERM, :INT, :HUP ]
|
||||||
|
|
||||||
attr_reader :env
|
attr_reader :env
|
||||||
attr_reader :options
|
attr_reader :options
|
||||||
attr_reader :processes
|
attr_reader :processes
|
||||||
@@ -24,7 +28,8 @@ class Foreman::Engine
|
|||||||
def initialize(options={})
|
def initialize(options={})
|
||||||
@options = options.dup
|
@options = options.dup
|
||||||
|
|
||||||
@options[:formation] ||= "all=1"
|
@options[:formation] ||= (options[:concurrency] || "all=1")
|
||||||
|
@options[:timeout] ||= 5
|
||||||
|
|
||||||
@env = {}
|
@env = {}
|
||||||
@mutex = Mutex.new
|
@mutex = Mutex.new
|
||||||
@@ -32,15 +37,22 @@ class Foreman::Engine
|
|||||||
@processes = []
|
@processes = []
|
||||||
@running = {}
|
@running = {}
|
||||||
@readers = {}
|
@readers = {}
|
||||||
|
|
||||||
|
# Self-pipe for deferred signal-handling (ala djb: http://cr.yp.to/docs/selfpipe.html)
|
||||||
|
reader, writer = create_pipe
|
||||||
|
reader.close_on_exec = true if reader.respond_to?(:close_on_exec)
|
||||||
|
writer.close_on_exec = true if writer.respond_to?(:close_on_exec)
|
||||||
|
@selfpipe = { :reader => reader, :writer => writer }
|
||||||
|
|
||||||
|
# Set up a global signal queue
|
||||||
|
# http://blog.rubybestpractices.com/posts/ewong/016-Implementing-Signal-Handlers.html
|
||||||
|
Thread.main[:signal_queue] = []
|
||||||
end
|
end
|
||||||
|
|
||||||
# Start the processes registered to this +Engine+
|
# Start the processes registered to this +Engine+
|
||||||
#
|
#
|
||||||
def start
|
def start
|
||||||
trap("TERM") { puts "SIGTERM received"; terminate_gracefully }
|
register_signal_handlers
|
||||||
trap("INT") { puts "SIGINT received"; terminate_gracefully }
|
|
||||||
trap("HUP") { puts "SIGHUP received"; terminate_gracefully }
|
|
||||||
|
|
||||||
startup
|
startup
|
||||||
spawn_processes
|
spawn_processes
|
||||||
watch_for_output
|
watch_for_output
|
||||||
@@ -49,6 +61,74 @@ class Foreman::Engine
|
|||||||
shutdown
|
shutdown
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Set up deferred signal handlers
|
||||||
|
#
|
||||||
|
def register_signal_handlers
|
||||||
|
HANDLED_SIGNALS.each do |sig|
|
||||||
|
if ::Signal.list.include? sig.to_s
|
||||||
|
trap(sig) { Thread.main[:signal_queue] << sig ; notice_signal }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Unregister deferred signal handlers
|
||||||
|
#
|
||||||
|
def restore_default_signal_handlers
|
||||||
|
HANDLED_SIGNALS.each do |sig|
|
||||||
|
trap(sig, :DEFAULT) if ::Signal.list.include? sig.to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Wake the main thread up via the selfpipe when there's a signal
|
||||||
|
#
|
||||||
|
def notice_signal
|
||||||
|
@selfpipe[:writer].write_nonblock( '.' )
|
||||||
|
rescue Errno::EAGAIN
|
||||||
|
# Ignore writes that would block
|
||||||
|
rescue Errno::EINT
|
||||||
|
# Retry if another signal arrived while writing
|
||||||
|
retry
|
||||||
|
end
|
||||||
|
|
||||||
|
# Invoke the real handler for signal +sig+. This shouldn't be called directly
|
||||||
|
# by signal handlers, as it might invoke code which isn't re-entrant.
|
||||||
|
#
|
||||||
|
# @param [Symbol] sig the name of the signal to be handled
|
||||||
|
#
|
||||||
|
def handle_signal(sig)
|
||||||
|
case sig
|
||||||
|
when :TERM
|
||||||
|
handle_term_signal
|
||||||
|
when :INT
|
||||||
|
handle_interrupt
|
||||||
|
when :HUP
|
||||||
|
handle_hangup
|
||||||
|
else
|
||||||
|
system "unhandled signal #{sig}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Handle a TERM signal
|
||||||
|
#
|
||||||
|
def handle_term_signal
|
||||||
|
puts "SIGTERM received"
|
||||||
|
terminate_gracefully
|
||||||
|
end
|
||||||
|
|
||||||
|
# Handle an INT signal
|
||||||
|
#
|
||||||
|
def handle_interrupt
|
||||||
|
puts "SIGINT received"
|
||||||
|
terminate_gracefully
|
||||||
|
end
|
||||||
|
|
||||||
|
# Handle a HUP signal
|
||||||
|
#
|
||||||
|
def handle_hangup
|
||||||
|
puts "SIGHUP received"
|
||||||
|
terminate_gracefully
|
||||||
|
end
|
||||||
|
|
||||||
# Register a process to be run by this +Engine+
|
# Register a process to be run by this +Engine+
|
||||||
#
|
#
|
||||||
# @param [String] name A name for this process
|
# @param [String] name A name for this process
|
||||||
@@ -89,25 +169,33 @@ 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 processesstarted by this +Engine+
|
# Send a signal to all processes started by this +Engine+
|
||||||
#
|
#
|
||||||
# @param [String] signal The signal to send to each process
|
# @param [String] signal The signal to send to each process
|
||||||
#
|
#
|
||||||
def killall(signal="SIGTERM")
|
def kill_children( signal="SIGTERM" )
|
||||||
@running.each do |pid, (process, index)|
|
@running.each do |pid, (process, index)|
|
||||||
system "sending #{signal} to #{name_for(pid)} at pid #{pid}"
|
system "sending #{signal} to #{name_for(pid)} at pid #{pid}"
|
||||||
begin
|
begin
|
||||||
Process.kill(signal, -1 * pid)
|
Process.kill( signal, pid )
|
||||||
rescue Errno::ESRCH, Errno::EPERM
|
rescue Errno::ESRCH, Errno::EPERM => err
|
||||||
|
system " %p when sending signal %p to pid %d: %s" %
|
||||||
|
[ err.class, signal, pid, err.message ]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Send a signal to the whole process group.
|
||||||
|
#
|
||||||
|
# @param [String] signal The signal to send
|
||||||
|
#
|
||||||
|
def killall(signal="SIGTERM")
|
||||||
|
kill_children(signal)
|
||||||
|
end
|
||||||
|
|
||||||
# Get the process formation
|
# Get the process formation
|
||||||
#
|
#
|
||||||
# @returns [Fixnum] The formation count for the specified process
|
# @returns [Fixnum] The formation count for the specified process
|
||||||
@@ -154,11 +242,28 @@ class Foreman::Engine
|
|||||||
#
|
#
|
||||||
# @param [Foreman::Process] process A +Process+ associated with this engine
|
# @param [Foreman::Process] process A +Process+ associated with this engine
|
||||||
# @param [Fixnum] instance The instance of the process
|
# @param [Fixnum] instance The instance of the process
|
||||||
#
|
#
|
||||||
# @returns [Fixnum] port The port to use for this instance of this process
|
# @returns [Fixnum] port The port to use for this instance of this process
|
||||||
#
|
#
|
||||||
def port_for(process, instance)
|
def port_for(process, instance, base=nil)
|
||||||
base_port + (@processes.index(process) * 100) + (instance - 1)
|
if base
|
||||||
|
base + (@processes.index(process.process) * 100) + (instance - 1)
|
||||||
|
else
|
||||||
|
base_port + (@processes.index(process) * 100) + (instance - 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get the base port for this foreman instance
|
||||||
|
#
|
||||||
|
# @returns [Fixnum] port The base port
|
||||||
|
#
|
||||||
|
def base_port
|
||||||
|
(options[:port] || env["PORT"] || ENV["PORT"] || 5000).to_i
|
||||||
|
end
|
||||||
|
|
||||||
|
# deprecated
|
||||||
|
def environment
|
||||||
|
env
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
@@ -179,21 +284,21 @@ private
|
|||||||
|
|
||||||
## Helpers ##########################################################
|
## Helpers ##########################################################
|
||||||
|
|
||||||
def base_port
|
|
||||||
(options[:port] || env["PORT"] || ENV["PORT"] || 5000).to_i
|
|
||||||
end
|
|
||||||
|
|
||||||
def create_pipe
|
def create_pipe
|
||||||
IO.method(:pipe).arity.zero? ? IO.pipe : IO.pipe("BINARY")
|
IO.method(:pipe).arity.zero? ? IO.pipe : IO.pipe("BINARY")
|
||||||
end
|
end
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
def parse_formation(formation)
|
def parse_formation(formation)
|
||||||
pairs = @options[:formation].to_s.gsub(/\s/, "").split(",")
|
pairs = formation.to_s.gsub(/\s/, "").split(",")
|
||||||
|
|
||||||
pairs.inject(Hash.new(0)) do |ax, pair|
|
pairs.inject(Hash.new(0)) do |ax, pair|
|
||||||
process, amount = pair.split("=")
|
process, amount = pair.split("=")
|
||||||
@@ -236,7 +341,10 @@ private
|
|||||||
1.upto(formation[@names[process]]) do |n|
|
1.upto(formation[@names[process]]) do |n|
|
||||||
reader, writer = create_pipe
|
reader, writer = create_pipe
|
||||||
begin
|
begin
|
||||||
pid = process.run(:output => writer, :env => { "PORT" => port_for(process, n).to_s })
|
pid = process.run(:output => writer, :env => {
|
||||||
|
"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
|
||||||
writer.puts "unknown command: #{process.command}"
|
writer.puts "unknown command: #{process.command}"
|
||||||
@@ -251,9 +359,28 @@ private
|
|||||||
Thread.new do
|
Thread.new do
|
||||||
begin
|
begin
|
||||||
loop do
|
loop do
|
||||||
(IO.select(@readers.values).first || []).each do |reader|
|
io = IO.select([@selfpipe[:reader]] + @readers.values, nil, nil, 30)
|
||||||
data = reader.gets
|
|
||||||
output_with_mutex name_for(@readers.key(reader)), data
|
begin
|
||||||
|
@selfpipe[:reader].read_nonblock(11)
|
||||||
|
rescue Errno::EAGAIN, Errno::EINTR => err
|
||||||
|
# ignore
|
||||||
|
end
|
||||||
|
|
||||||
|
# Look for any signals that arrived and handle them
|
||||||
|
while sig = Thread.main[:signal_queue].shift
|
||||||
|
self.handle_signal(sig)
|
||||||
|
end
|
||||||
|
|
||||||
|
(io.nil? ? [] : io.first).each do |reader|
|
||||||
|
next if reader == @selfpipe[:reader]
|
||||||
|
|
||||||
|
if reader.eof?
|
||||||
|
@readers.delete_if { |key, value| value == reader }
|
||||||
|
else
|
||||||
|
data = reader.gets
|
||||||
|
output_with_mutex name_for(@readers.invert[reader]), data
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
rescue Exception => ex
|
rescue Exception => ex
|
||||||
@@ -274,15 +401,21 @@ private
|
|||||||
|
|
||||||
def terminate_gracefully
|
def terminate_gracefully
|
||||||
return if @terminating
|
return if @terminating
|
||||||
|
restore_default_signal_handlers
|
||||||
@terminating = true
|
@terminating = true
|
||||||
system "sending SIGTERM to all processes"
|
if Foreman.windows?
|
||||||
killall "SIGTERM"
|
system "sending SIGKILL to all processes"
|
||||||
Timeout.timeout(5) do
|
kill_children "SIGKILL"
|
||||||
|
else
|
||||||
|
system "sending SIGTERM to all processes"
|
||||||
|
kill_children "SIGTERM"
|
||||||
|
end
|
||||||
|
Timeout.timeout(options[:timeout]) do
|
||||||
watch_for_termination while @running.length > 0
|
watch_for_termination while @running.length > 0
|
||||||
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
|
||||||
|
|||||||
@@ -24,11 +24,14 @@ class Foreman::Engine::CLI < Foreman::Engine
|
|||||||
:bright_white => 37,
|
:bright_white => 37,
|
||||||
}
|
}
|
||||||
|
|
||||||
def self.enable(io)
|
def self.enable(io, force=false)
|
||||||
io.extend(self)
|
io.extend(self)
|
||||||
|
@@color_force = force
|
||||||
end
|
end
|
||||||
|
|
||||||
def color?
|
def color?
|
||||||
|
return true if @@color_force
|
||||||
|
return false if Foreman.windows?
|
||||||
return false unless self.respond_to?(:isatty)
|
return false unless self.respond_to?(:isatty)
|
||||||
self.isatty && ENV["TERM"]
|
self.isatty && ENV["TERM"]
|
||||||
end
|
end
|
||||||
@@ -41,24 +44,27 @@ class Foreman::Engine::CLI < Foreman::Engine
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
FOREMAN_COLORS = %w( cyan yellow green magenta red blue intense_cyan intense_yellow
|
FOREMAN_COLORS = %w( cyan yellow green magenta red blue bright_cyan bright_yellow
|
||||||
intense_green intense_magenta intense_red, intense_blue )
|
bright_green bright_magenta bright_red bright_blue )
|
||||||
|
|
||||||
def startup
|
def startup
|
||||||
@colors = map_colors
|
@colors = map_colors
|
||||||
proctitle "foreman: master"
|
proctitle "foreman: master" unless Foreman.windows?
|
||||||
|
Color.enable($stdout, options[:color])
|
||||||
end
|
end
|
||||||
|
|
||||||
def output(name, data)
|
def output(name, data)
|
||||||
data.to_s.chomp.split("\n").each do |message|
|
data.to_s.lines.map(&:chomp).each do |message|
|
||||||
Color.enable($stdout) unless $stdout.respond_to?(:color?)
|
|
||||||
output = ""
|
output = ""
|
||||||
output += $stdout.color(@colors[name.split(".").first].to_sym)
|
output += $stdout.color(@colors[name.split(".").first].to_sym)
|
||||||
output += "#{Time.now.strftime("%H:%M:%S")} #{pad_process_name(name)} | "
|
output += "#{Time.now.strftime("%H:%M:%S")} #{pad_process_name(name)} | "
|
||||||
output += $stdout.color(:reset)
|
output += $stdout.color(:reset)
|
||||||
output += message
|
output += message
|
||||||
$stdout.puts output
|
$stdout.puts output
|
||||||
|
$stdout.flush
|
||||||
end
|
end
|
||||||
|
rescue Errno::EPIPE
|
||||||
|
terminate_gracefully
|
||||||
end
|
end
|
||||||
|
|
||||||
def shutdown
|
def shutdown
|
||||||
@@ -83,7 +89,7 @@ private
|
|||||||
@names.values.each_with_index do |name, index|
|
@names.values.each_with_index do |name, index|
|
||||||
colors[name] = FOREMAN_COLORS[index % FOREMAN_COLORS.length]
|
colors[name] = FOREMAN_COLORS[index % FOREMAN_COLORS.length]
|
||||||
end
|
end
|
||||||
colors["system"] = "intense_white"
|
colors["system"] = "bright_white"
|
||||||
colors
|
colors
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
require "foreman"
|
|
||||||
|
|
||||||
class Foreman::Env
|
|
||||||
|
|
||||||
attr_reader :entries
|
|
||||||
|
|
||||||
def initialize(filename)
|
|
||||||
@entries = File.read(filename).split("\n").inject({}) do |ax, line|
|
|
||||||
if line =~ /\A([A-Za-z_0-9]+)=(.*)\z/
|
|
||||||
key = $1
|
|
||||||
case val = $2
|
|
||||||
when /\A'(.*)'\z/ then ax[key] = $1
|
|
||||||
when /\A"(.*)"\z/ then ax[key] = $1.gsub(/\\(.)/, '\1')
|
|
||||||
else ax[key] = val
|
|
||||||
end
|
|
||||||
end
|
|
||||||
ax
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def entries
|
|
||||||
@entries.each do |key, value|
|
|
||||||
yield key, value
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
require "foreman"
|
require "foreman"
|
||||||
require "foreman/helpers"
|
require "foreman/helpers"
|
||||||
|
require "pathname"
|
||||||
|
|
||||||
module Foreman::Export
|
module Foreman::Export
|
||||||
extend Foreman::Helpers
|
extend Foreman::Helpers
|
||||||
@@ -27,8 +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"
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
require "foreman/export"
|
require "foreman/export"
|
||||||
|
require "ostruct"
|
||||||
|
require "pathname"
|
||||||
require "shellwords"
|
require "shellwords"
|
||||||
|
|
||||||
class Foreman::Export::Base
|
class Foreman::Export::Base
|
||||||
@@ -8,18 +10,46 @@ class Foreman::Export::Base
|
|||||||
attr_reader :options
|
attr_reader :options
|
||||||
attr_reader :formation
|
attr_reader :formation
|
||||||
|
|
||||||
|
# deprecated
|
||||||
|
attr_reader :port
|
||||||
|
|
||||||
def initialize(location, engine, options={})
|
def initialize(location, engine, options={})
|
||||||
@location = location
|
@location = location
|
||||||
@engine = engine
|
@engine = engine
|
||||||
@options = options.dup
|
@options = options.dup
|
||||||
@formation = engine.formation
|
@formation = engine.formation
|
||||||
|
|
||||||
|
# deprecated
|
||||||
|
def port
|
||||||
|
Foreman::Export::Base.warn_deprecation!
|
||||||
|
engine.base_port
|
||||||
|
end
|
||||||
|
|
||||||
|
# deprecated
|
||||||
|
def template
|
||||||
|
Foreman::Export::Base.warn_deprecation!
|
||||||
|
options[:template]
|
||||||
|
end
|
||||||
|
|
||||||
|
# deprecated
|
||||||
|
def @engine.procfile
|
||||||
|
Foreman::Export::Base.warn_deprecation!
|
||||||
|
@processes.map do |process|
|
||||||
|
OpenStruct.new(
|
||||||
|
:name => @names[process],
|
||||||
|
:process => process
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def export
|
def export
|
||||||
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
|
||||||
@@ -30,12 +60,28 @@ 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
|
||||||
|
|
||||||
private ######################################################################
|
private ######################################################################
|
||||||
|
|
||||||
|
def self.warn_deprecation!
|
||||||
|
@@deprecation_warned ||= false
|
||||||
|
return if @@deprecation_warned
|
||||||
|
puts "WARNING: Using deprecated exporter interface. Please update your exporter"
|
||||||
|
puts "the interface shown in the upstart exporter:"
|
||||||
|
puts
|
||||||
|
puts "https://github.com/ddollar/foreman/blob/master/lib/foreman/export/upstart.rb"
|
||||||
|
puts "https://github.com/ddollar/foreman/blob/master/data/export/upstart/process.conf.erb"
|
||||||
|
puts
|
||||||
|
@@deprecation_warned = true
|
||||||
|
end
|
||||||
|
|
||||||
def error(message)
|
def error(message)
|
||||||
raise Foreman::Export::Exception.new(message)
|
raise Foreman::Export::Exception.new(message)
|
||||||
end
|
end
|
||||||
@@ -51,20 +97,35 @@ private ######################################################################
|
|||||||
end
|
end
|
||||||
|
|
||||||
def shell_quote(value)
|
def shell_quote(value)
|
||||||
'"' + Shellwords.escape(value) + '"'
|
Shellwords.escape(value)
|
||||||
end
|
end
|
||||||
|
|
||||||
def export_template(name)
|
# deprecated
|
||||||
name_without_first = name.split("/")[1..-1].join("/")
|
def old_export_template(exporter, file, template_root)
|
||||||
matchers = []
|
if template_root && File.exist?(file_path = File.join(template_root, file))
|
||||||
matchers << File.join(options[:template], name_without_first) if options[:template]
|
File.read(file_path)
|
||||||
matchers << File.expand_path("~/.foreman/templates/#{name}")
|
elsif File.exist?(file_path = File.expand_path(File.join("~/.foreman/templates", file)))
|
||||||
matchers << File.expand_path("../../../../data/export/#{name}", __FILE__)
|
File.read(file_path)
|
||||||
File.read(matchers.detect { |m| File.exists?(m) })
|
else
|
||||||
|
File.read(File.expand_path("../../../../data/export/#{exporter}/#{file}", __FILE__))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def export_template(name, file=nil, template_root=nil)
|
||||||
|
if file && template_root
|
||||||
|
old_export_template name, file, template_root
|
||||||
|
else
|
||||||
|
name_without_first = name.split("/")[1..-1].join("/")
|
||||||
|
matchers = []
|
||||||
|
matchers << File.join(options[:template], name_without_first) if options[:template]
|
||||||
|
matchers << File.expand_path("~/.foreman/templates/#{name}")
|
||||||
|
matchers << File.expand_path("../../../../data/export/#{name}", __FILE__)
|
||||||
|
File.read(matchers.detect { |m| File.exists?(m) })
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def write_template(name, target, binding)
|
def write_template(name, target, binding)
|
||||||
compiled = ERB.new(export_template(name)).result(binding)
|
compiled = ERB.new(export_template(name), nil, '-').result(binding)
|
||||||
write_file target, compiled
|
write_file target, compiled
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -81,7 +142,9 @@ private ######################################################################
|
|||||||
def write_file(filename, contents)
|
def write_file(filename, contents)
|
||||||
say "writing: #{filename}"
|
say "writing: #{filename}"
|
||||||
|
|
||||||
File.open(File.join(location, filename), "w") do |file|
|
filename = File.join(location, filename) unless Pathname.new(filename).absolute?
|
||||||
|
|
||||||
|
File.open(filename, "w") do |file|
|
||||||
file.puts contents
|
file.puts contents
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
28
lib/foreman/export/daemon.rb
Normal file
28
lib/foreman/export/daemon.rb
Normal 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
|
||||||
@@ -13,7 +13,16 @@ class Foreman::Export::Inittab < Foreman::Export::Base
|
|||||||
1.upto(engine.formation[name]) do |num|
|
1.upto(engine.formation[name]) do |num|
|
||||||
id = app.slice(0, 2).upcase + sprintf("%02d", index)
|
id = app.slice(0, 2).upcase + sprintf("%02d", index)
|
||||||
port = engine.port_for(process, num)
|
port = engine.port_for(process, num)
|
||||||
inittab << "#{id}:4:respawn:/bin/su - #{user} -c 'PORT=#{port} #{process.command} >> #{log}/#{name}-#{num}.log 2>&1'"
|
|
||||||
|
commands = []
|
||||||
|
commands << "cd #{engine.root}"
|
||||||
|
commands << "export PORT=#{port}"
|
||||||
|
engine.env.each_pair do |var, env|
|
||||||
|
commands << "export #{var.upcase}=#{shell_quote(env)}"
|
||||||
|
end
|
||||||
|
commands << "#{process.command} >> #{log}/#{name}-#{num}.log 2>&1"
|
||||||
|
|
||||||
|
inittab << "#{id}:4:respawn:/bin/su - #{user} -c '#{commands.join(";")}'"
|
||||||
index += 1
|
index += 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ class Foreman::Export::Launchd < Foreman::Export::Base
|
|||||||
super
|
super
|
||||||
engine.each_process do |name, process|
|
engine.each_process do |name, process|
|
||||||
1.upto(engine.formation[name]) do |num|
|
1.upto(engine.formation[name]) do |num|
|
||||||
|
port = engine.port_for(process, num)
|
||||||
|
command_args = process.command.split(" ")
|
||||||
write_template "launchd/launchd.plist.erb", "#{app}-#{name}-#{num}.plist", binding
|
write_template "launchd/launchd.plist.erb", "#{app}-#{name}-#{num}.plist", binding
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
32
lib/foreman/export/systemd.rb
Normal file
32
lib/foreman/export/systemd.rb
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
process_master_names = []
|
||||||
|
|
||||||
|
engine.each_process do |name, process|
|
||||||
|
next if engine.formation[name] < 1
|
||||||
|
|
||||||
|
process_names = []
|
||||||
|
|
||||||
|
1.upto(engine.formation[name]) do |num|
|
||||||
|
port = engine.port_for(process, num)
|
||||||
|
write_template "systemd/process.service.erb", "#{app}-#{name}-#{num}.service", binding
|
||||||
|
process_names << "#{app}-#{name}-#{num}.service"
|
||||||
|
end
|
||||||
|
|
||||||
|
write_template "systemd/process_master.target.erb", "#{app}-#{name}.target", binding
|
||||||
|
process_master_names << "#{app}-#{name}.target"
|
||||||
|
end
|
||||||
|
|
||||||
|
write_template "systemd/master.target.erb", "#{app}.target", binding
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
require "foreman"
|
require "foreman"
|
||||||
require "rubygems"
|
require "shellwords"
|
||||||
|
|
||||||
class Foreman::Process
|
class Foreman::Process
|
||||||
|
|
||||||
@@ -21,6 +21,21 @@ class Foreman::Process
|
|||||||
@options[:env] ||= {}
|
@options[:env] ||= {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Get environment-expanded command for a +Process+
|
||||||
|
#
|
||||||
|
# @param [Hash] custom_env ({}) Environment variables to merge with defaults
|
||||||
|
#
|
||||||
|
# @return [String] The expanded command
|
||||||
|
#
|
||||||
|
def expanded_command(custom_env={})
|
||||||
|
env = @options[:env].merge(custom_env)
|
||||||
|
expanded_command = command.dup
|
||||||
|
env.each do |key, val|
|
||||||
|
expanded_command.gsub!("$#{key}", val)
|
||||||
|
end
|
||||||
|
expanded_command
|
||||||
|
end
|
||||||
|
|
||||||
# Run a +Process+
|
# Run a +Process+
|
||||||
#
|
#
|
||||||
# @param [Hash] options
|
# @param [Hash] options
|
||||||
@@ -31,31 +46,48 @@ class Foreman::Process
|
|||||||
# @returns [Fixnum] pid The +pid+ of the process
|
# @returns [Fixnum] pid The +pid+ of the process
|
||||||
#
|
#
|
||||||
def run(options={})
|
def run(options={})
|
||||||
env = options[:env] ? @options[:env].merge(options[:env]) : @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, command, :out => output, :err => output, :new_pgroup => true
|
Process.spawn env, expanded_command(env), :out => output, :err => output
|
||||||
end
|
|
||||||
elsif Foreman.jruby?
|
|
||||||
Dir.chdir(cwd) do
|
|
||||||
require "posix/spawn"
|
|
||||||
POSIX::Spawn.spawn env, command, :out => output, :err => output, :pgroup => 0
|
|
||||||
end
|
end
|
||||||
|
elsif Foreman.jruby_18? || Foreman.ruby_18?
|
||||||
|
require "posix/spawn"
|
||||||
|
wrapped_command = "#{runner} -d '#{cwd.shellescape}' -p -- #{expanded_command(env)}"
|
||||||
|
POSIX::Spawn.spawn(*spawn_args(env, wrapped_command.shellsplit, {:out => output, :err => output}))
|
||||||
else
|
else
|
||||||
Dir.chdir(cwd) do
|
wrapped_command = "#{runner} -d '#{cwd.shellescape}' -p -- #{command}"
|
||||||
Process.spawn env, command, :out => output, :err => output, :pgroup => 0
|
Process.spawn env, wrapped_command, :out => output, :err => output
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Exec a +Process+
|
||||||
|
#
|
||||||
|
# @param [Hash] options
|
||||||
|
#
|
||||||
|
# @option options :env ({}) Environment variables to set for this execution
|
||||||
|
#
|
||||||
|
# @return Does not return
|
||||||
|
def exec(options={})
|
||||||
|
env = @options[:env].merge(options[:env] || {})
|
||||||
|
env.each { |k, v| ENV[k] = v }
|
||||||
|
Dir.chdir(cwd)
|
||||||
|
Kernel.exec expanded_command(env)
|
||||||
|
end
|
||||||
|
|
||||||
# Send a signal to this +Process+
|
# Send a signal to this +Process+
|
||||||
#
|
#
|
||||||
# @param [String] signal The signal to send
|
# @param [String] signal The signal to send
|
||||||
#
|
#
|
||||||
def kill(signal)
|
def kill(signal)
|
||||||
pid && Process.kill(signal, -1 * pid)
|
if Foreman.windows?
|
||||||
|
pid && Process.kill(signal, pid)
|
||||||
|
else
|
||||||
|
pid && Process.kill("-#{signal}", pid)
|
||||||
|
end
|
||||||
rescue Errno::ESRCH
|
rescue Errno::ESRCH
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
@@ -76,10 +108,22 @@ class Foreman::Process
|
|||||||
!alive?
|
!alive?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns the working directory for this +Process+
|
||||||
|
#
|
||||||
|
# @returns [String]
|
||||||
|
#
|
||||||
|
def cwd
|
||||||
|
File.expand_path(@options[:cwd] || ".")
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def cwd
|
def spawn_args(env, argv, options)
|
||||||
@options[:cwd] || "."
|
args = []
|
||||||
|
args << env
|
||||||
|
args += argv
|
||||||
|
args << options
|
||||||
|
args
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -82,8 +82,8 @@ class Foreman::Procfile
|
|||||||
private
|
private
|
||||||
|
|
||||||
def parse(filename)
|
def parse(filename)
|
||||||
File.read(filename).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,5 +1,5 @@
|
|||||||
module Foreman
|
module Foreman
|
||||||
|
|
||||||
VERSION = "0.48.0.pre1"
|
VERSION = "0.63.0"
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -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" "April 2012" "Foreman 0.46.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\.
|
||||||
.
|
.
|
||||||
@@ -90,7 +86,7 @@ Specify the user the application should be run as\. Defaults to the app name
|
|||||||
These options control all modes of foreman\'s operation\.
|
These options control all modes of foreman\'s operation\.
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
\fB\-d\fR, \fB\-\-directory\fR
|
\fB\-d\fR, \fB\-\-root\fR
|
||||||
Specify an alternate application root\. This defaults to the directory containing the Procfile\.
|
Specify an alternate application root\. This defaults to the directory containing the Procfile\.
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
@@ -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
|
||||||
.
|
.
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|
||||||
@@ -84,7 +80,7 @@ The following options control how the application is run:
|
|||||||
|
|
||||||
These options control all modes of foreman's operation.
|
These options control all modes of foreman's operation.
|
||||||
|
|
||||||
* `-d`, `--directory`:
|
* `-d`, `--root`:
|
||||||
Specify an alternate application root. This defaults to the directory
|
Specify an alternate application root. This defaults to the directory
|
||||||
containing the Procfile.
|
containing the Procfile.
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -72,6 +79,33 @@ describe "Foreman::CLI", :fakefs do
|
|||||||
it "includes the environment" do
|
it "includes the environment" do
|
||||||
forked_foreman("run #{resource_path("bin/env FOO")} -e #{resource_path(".env")}").should == "bar\n"
|
forked_foreman("run #{resource_path("bin/env FOO")} -e #{resource_path(".env")}").should == "bar\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "can run a command from the Procfile" do
|
||||||
|
forked_foreman("run -f #{resource_path("Procfile")} test").should == "testing\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "exits with the same exit code as the command" do
|
||||||
|
fork_and_get_exitstatus("run echo 1").should == 0
|
||||||
|
fork_and_get_exitstatus("run date 'invalid_date'").should == 1
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "version" do
|
||||||
|
it "displays gem version" do
|
||||||
|
foreman("version").chomp.should == Foreman::VERSION
|
||||||
|
end
|
||||||
|
|
||||||
|
it "displays gem version on shortcut command" do
|
||||||
|
foreman("-v").chomp.should == Foreman::VERSION
|
||||||
|
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
|
||||||
|
|||||||
@@ -90,6 +90,14 @@ describe "Foreman::Engine", :fakefs do
|
|||||||
subject.env["OTHER"].should == 'escaped"quote'
|
subject.env["OTHER"].should == 'escaped"quote'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "should handle multiline strings" do
|
||||||
|
File.open("/tmp/env", "w") do |f|
|
||||||
|
f.puts 'FOO="bar\nbaz"'
|
||||||
|
end
|
||||||
|
subject.load_env "/tmp/env"
|
||||||
|
subject.env["FOO"].should == "bar\nbaz"
|
||||||
|
end
|
||||||
|
|
||||||
it "should fail if specified and doesnt exist" do
|
it "should fail if specified and doesnt exist" do
|
||||||
lambda { subject.load_env "/tmp/env" }.should raise_error(Errno::ENOENT)
|
lambda { subject.load_env "/tmp/env" }.should raise_error(Errno::ENOENT)
|
||||||
end
|
end
|
||||||
|
|||||||
97
spec/foreman/export/daemon_spec.rb
Normal file
97
spec/foreman/export/daemon_spec.rb
Normal 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
|
||||||
@@ -18,4 +18,14 @@ describe Foreman::Export::Launchd, :fakefs do
|
|||||||
File.read("/tmp/init/app-bravo-1.plist").should == example_export_file("launchd/launchd-b.default")
|
File.read("/tmp/init/app-bravo-1.plist").should == example_export_file("launchd/launchd-b.default")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "with multiple command arguments" do
|
||||||
|
let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile", "charlie") }
|
||||||
|
|
||||||
|
it "splits each command argument" do
|
||||||
|
launchd.export
|
||||||
|
File.read("/tmp/init/app-alpha-1.plist").should == example_export_file("launchd/launchd-c.default")
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -31,6 +31,6 @@ describe Foreman::Export::Runit, :fakefs do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "creates a full path to the export directory" do
|
it "creates a full path to the export directory" do
|
||||||
expect { runit.export }.to_not raise_error(Errno::ENOENT)
|
expect { runit.export }.to_not raise_error
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
91
spec/foreman/export/systemd_spec.rb
Normal file
91
spec/foreman/export/systemd_spec.rb
Normal 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
|
||||||
@@ -29,16 +29,32 @@ 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
|
||||||
"foobarfoo".should include "bar"
|
"foobarfoo".should include "bar"
|
||||||
File.read("/tmp/init/app-alpha-1.conf").should =~ /KEY="d\\"\\\\\\\|d/
|
File.read("/tmp/init/app-alpha-1.conf").should =~ /KEY=d\\"\\\\\\\|d/
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with a formation" do
|
context "with a formation" do
|
||||||
|
|||||||
@@ -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"
|
run(process).should == (Foreman.ruby_18? ? "\xFF\x03\n" : "\xFF\x03\n".force_encoding('binary'))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
7
spec/resources/export/daemon/app-alpha-1.conf
Normal file
7
spec/resources/export/daemon/app-alpha-1.conf
Normal file
@@ -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
|
||||||
7
spec/resources/export/daemon/app-alpha-2.conf
Normal file
7
spec/resources/export/daemon/app-alpha-2.conf
Normal file
@@ -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
|
||||||
2
spec/resources/export/daemon/app-alpha.conf
Normal file
2
spec/resources/export/daemon/app-alpha.conf
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
start on starting app
|
||||||
|
stop on stopping app
|
||||||
7
spec/resources/export/daemon/app-bravo-1.conf
Normal file
7
spec/resources/export/daemon/app-bravo-1.conf
Normal file
@@ -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
|
||||||
2
spec/resources/export/daemon/app-bravo.conf
Normal file
2
spec/resources/export/daemon/app-bravo.conf
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
start on starting app
|
||||||
|
stop on stopping app
|
||||||
14
spec/resources/export/daemon/app.conf
Normal file
14
spec/resources/export/daemon/app.conf
Normal 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,4 @@
|
|||||||
# ----- foreman app processes -----
|
# ----- foreman app processes -----
|
||||||
AP01:4:respawn:/bin/su - app -c '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 'PORT=5001 ./alpha >> /var/log/app/alpha-2.log 2>&1'
|
AP02:4:respawn:/bin/su - app -c 'cd /tmp/app;export PORT=5001;./alpha >> /var/log/app/alpha-2.log 2>&1'
|
||||||
# ----- end foreman app processes -----
|
# ----- end foreman app processes -----
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
# ----- foreman app processes -----
|
# ----- foreman app processes -----
|
||||||
AP01:4:respawn:/bin/su - app -c '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 '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 -----
|
||||||
|
|||||||
@@ -4,6 +4,11 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>Label</key>
|
<key>Label</key>
|
||||||
<string>app-alpha-1</string>
|
<string>app-alpha-1</string>
|
||||||
|
<key>EnvironmentVariables</key>
|
||||||
|
<dict>
|
||||||
|
<key>PORT</key>
|
||||||
|
<string>5000</string>
|
||||||
|
</dict>
|
||||||
<key>ProgramArguments</key>
|
<key>ProgramArguments</key>
|
||||||
<array>
|
<array>
|
||||||
<string>./alpha</string>
|
<string>./alpha</string>
|
||||||
@@ -12,6 +17,8 @@
|
|||||||
<true/>
|
<true/>
|
||||||
<key>RunAtLoad</key>
|
<key>RunAtLoad</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>StandardOutPath</key>
|
||||||
|
<string>/var/log/app/app-alpha-1.log</string>
|
||||||
<key>StandardErrorPath</key>
|
<key>StandardErrorPath</key>
|
||||||
<string>/var/log/app/app-alpha-1.log</string>
|
<string>/var/log/app/app-alpha-1.log</string>
|
||||||
<key>UserName</key>
|
<key>UserName</key>
|
||||||
|
|||||||
@@ -4,6 +4,11 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>Label</key>
|
<key>Label</key>
|
||||||
<string>app-bravo-1</string>
|
<string>app-bravo-1</string>
|
||||||
|
<key>EnvironmentVariables</key>
|
||||||
|
<dict>
|
||||||
|
<key>PORT</key>
|
||||||
|
<string>5100</string>
|
||||||
|
</dict>
|
||||||
<key>ProgramArguments</key>
|
<key>ProgramArguments</key>
|
||||||
<array>
|
<array>
|
||||||
<string>./bravo</string>
|
<string>./bravo</string>
|
||||||
@@ -12,6 +17,8 @@
|
|||||||
<true/>
|
<true/>
|
||||||
<key>RunAtLoad</key>
|
<key>RunAtLoad</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>StandardOutPath</key>
|
||||||
|
<string>/var/log/app/app-bravo-1.log</string>
|
||||||
<key>StandardErrorPath</key>
|
<key>StandardErrorPath</key>
|
||||||
<string>/var/log/app/app-bravo-1.log</string>
|
<string>/var/log/app/app-bravo-1.log</string>
|
||||||
<key>UserName</key>
|
<key>UserName</key>
|
||||||
|
|||||||
30
spec/resources/export/launchd/launchd-c.default
Normal file
30
spec/resources/export/launchd/launchd-c.default
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>Label</key>
|
||||||
|
<string>app-alpha-1</string>
|
||||||
|
<key>EnvironmentVariables</key>
|
||||||
|
<dict>
|
||||||
|
<key>PORT</key>
|
||||||
|
<string>5000</string>
|
||||||
|
</dict>
|
||||||
|
<key>ProgramArguments</key>
|
||||||
|
<array>
|
||||||
|
<string>./alpha</string>
|
||||||
|
<string>charlie</string>
|
||||||
|
</array>
|
||||||
|
<key>KeepAlive</key>
|
||||||
|
<true/>
|
||||||
|
<key>RunAtLoad</key>
|
||||||
|
<true/>
|
||||||
|
<key>StandardOutPath</key>
|
||||||
|
<string>/var/log/app/app-alpha-1.log</string>
|
||||||
|
<key>StandardErrorPath</key>
|
||||||
|
<string>/var/log/app/app-alpha-1.log</string>
|
||||||
|
<key>UserName</key>
|
||||||
|
<string>app</string>
|
||||||
|
<key>WorkingDirectory</key>
|
||||||
|
<string>/tmp/app</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -8,7 +8,7 @@ stdout_logfile=/var/log/app/alpha-1.log
|
|||||||
stderr_logfile=/var/log/app/alpha-1.error.log
|
stderr_logfile=/var/log/app/alpha-1.error.log
|
||||||
user=app
|
user=app
|
||||||
directory=/tmp/app
|
directory=/tmp/app
|
||||||
environment=PORT="5000"
|
environment=PORT=5000
|
||||||
[program:app-bravo-1]
|
[program:app-bravo-1]
|
||||||
command=./bravo
|
command=./bravo
|
||||||
autostart=true
|
autostart=true
|
||||||
@@ -18,7 +18,27 @@ stdout_logfile=/var/log/app/bravo-1.log
|
|||||||
stderr_logfile=/var/log/app/bravo-1.error.log
|
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
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ stdout_logfile=/var/log/app/alpha-1.log
|
|||||||
stderr_logfile=/var/log/app/alpha-1.error.log
|
stderr_logfile=/var/log/app/alpha-1.error.log
|
||||||
user=app
|
user=app
|
||||||
directory=/tmp/app
|
directory=/tmp/app
|
||||||
environment=PORT="5000"
|
environment=PORT=5000
|
||||||
[program:app-alpha-2]
|
[program:app-alpha-2]
|
||||||
command=./alpha
|
command=./alpha
|
||||||
autostart=true
|
autostart=true
|
||||||
@@ -18,7 +18,7 @@ stdout_logfile=/var/log/app/alpha-2.log
|
|||||||
stderr_logfile=/var/log/app/alpha-2.error.log
|
stderr_logfile=/var/log/app/alpha-2.error.log
|
||||||
user=app
|
user=app
|
||||||
directory=/tmp/app
|
directory=/tmp/app
|
||||||
environment=PORT="5001"
|
environment=PORT=5001
|
||||||
|
|
||||||
[group:app]
|
[group:app]
|
||||||
programs=app-alpha-1,app-alpha-2
|
programs=app-alpha-1,app-alpha-2
|
||||||
|
|||||||
17
spec/resources/export/systemd/app-alpha-1.service
Normal file
17
spec/resources/export/systemd/app-alpha-1.service
Normal file
@@ -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
|
||||||
17
spec/resources/export/systemd/app-alpha-2.service
Normal file
17
spec/resources/export/systemd/app-alpha-2.service
Normal file
@@ -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
|
||||||
5
spec/resources/export/systemd/app-alpha.target
Normal file
5
spec/resources/export/systemd/app-alpha.target
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
[Unit]
|
||||||
|
StopWhenUnneeded=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=app.target
|
||||||
17
spec/resources/export/systemd/app-bravo-1.service
Normal file
17
spec/resources/export/systemd/app-bravo-1.service
Normal file
@@ -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
|
||||||
5
spec/resources/export/systemd/app-bravo.target
Normal file
5
spec/resources/export/systemd/app-bravo.target
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
[Unit]
|
||||||
|
StopWhenUnneeded=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=app.target
|
||||||
1
spec/resources/export/systemd/app.target
Normal file
1
spec/resources/export/systemd/app.target
Normal file
@@ -0,0 +1 @@
|
|||||||
|
[Unit]
|
||||||
@@ -6,3 +6,7 @@ bash << "EOF"
|
|||||||
EOF
|
EOF
|
||||||
|
|
||||||
end script
|
end script
|
||||||
|
|
||||||
|
start on runlevel [2345]
|
||||||
|
|
||||||
|
stop on runlevel [016]
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require "rubygems"
|
|
||||||
|
|
||||||
require "simplecov"
|
require "simplecov"
|
||||||
SimpleCov.start do
|
SimpleCov.start do
|
||||||
add_filter "/spec/"
|
add_filter "/spec/"
|
||||||
@@ -12,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
|
||||||
@@ -23,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
|
||||||
@@ -33,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
|
||||||
@@ -54,11 +69,20 @@ def fork_and_capture(&blk)
|
|||||||
Process.wait pid
|
Process.wait pid
|
||||||
buffer = ""
|
buffer = ""
|
||||||
until rd.eof?
|
until rd.eof?
|
||||||
p [:foo]
|
|
||||||
buffer += rd.gets
|
buffer += rd.gets
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def fork_and_get_exitstatus(args)
|
||||||
|
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)
|
||||||
|
$?.exitstatus
|
||||||
|
end
|
||||||
|
|
||||||
def mock_exit(&block)
|
def mock_exit(&block)
|
||||||
block.should raise_error(SystemExit)
|
block.should raise_error(SystemExit)
|
||||||
end
|
end
|
||||||
@@ -76,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
|
||||||
@@ -136,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
|
||||||
@@ -151,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_exclusion_patterns = []
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -32,10 +32,10 @@ def latest_release
|
|||||||
end
|
end
|
||||||
|
|
||||||
def newer_release
|
def newer_release
|
||||||
tags = %x{ git tag --contains v#{latest_release} }.split("\n").sort_by do |tag|
|
tags = %x{ git tag --contains v#{latest_release} | grep -v pre }.split("\n").sort_by do |tag|
|
||||||
Gem::Version.new(tag[1..-1])
|
Gem::Version.new(tag[1..-1])
|
||||||
end
|
end
|
||||||
tags.reject { |tag| Gem::Version.new(tag[1..-1]).prerelease? }[1]
|
tags[1]
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Generate a Changelog"
|
desc "Generate a Changelog"
|
||||||
@@ -60,7 +60,6 @@ end
|
|||||||
|
|
||||||
desc "Cut a release"
|
desc "Cut a release"
|
||||||
task :release do
|
task :release do
|
||||||
Rake::Task["authors"].invoke
|
|
||||||
Rake::Task["changelog"].invoke
|
Rake::Task["changelog"].invoke
|
||||||
Rake::Task["pages"].invoke
|
Rake::Task["pages"].invoke
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user