foreman 0.3.2 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +11 -0
- data/lib/foreman.rb +1 -1
- data/lib/foreman/cli.rb +36 -24
- data/lib/foreman/engine.rb +2 -2
- data/lib/foreman/export.rb +1 -0
- data/lib/foreman/export/base.rb +48 -0
- data/lib/foreman/export/upstart.rb +27 -44
- data/spec/foreman/cli_spec.rb +6 -49
- metadata +6 -5
data/Rakefile
CHANGED
|
@@ -6,6 +6,7 @@ $:.unshift File.expand_path("../lib", __FILE__)
|
|
|
6
6
|
require "foreman"
|
|
7
7
|
|
|
8
8
|
task :default => :spec
|
|
9
|
+
task :release => :man
|
|
9
10
|
|
|
10
11
|
desc "Run all specs"
|
|
11
12
|
Rspec::Core::RakeTask.new(:spec) do |t|
|
|
@@ -23,6 +24,16 @@ Rspec::Core::RakeTask.new("rcov:build") do |t|
|
|
|
23
24
|
t.rcov_opts = [ "--exclude", Gem.default_dir , "--exclude", "spec" ]
|
|
24
25
|
end
|
|
25
26
|
|
|
27
|
+
desc 'Build the manual'
|
|
28
|
+
task :man do
|
|
29
|
+
require 'ronn'
|
|
30
|
+
ENV['RONN_MANUAL'] = "Foreman Manual"
|
|
31
|
+
ENV['RONN_ORGANIZATION'] = "Foreman #{Foreman::VERSION}"
|
|
32
|
+
sh "ronn -w -s toc -r5 --markdown man/*.ronn"
|
|
33
|
+
sh "git add man/*.?"
|
|
34
|
+
sh "git commit -m \"updating man pages\""
|
|
35
|
+
end
|
|
36
|
+
|
|
26
37
|
######################################################
|
|
27
38
|
|
|
28
39
|
begin
|
data/lib/foreman.rb
CHANGED
data/lib/foreman/cli.rb
CHANGED
|
@@ -6,46 +6,58 @@ require "thor"
|
|
|
6
6
|
|
|
7
7
|
class Foreman::CLI < Thor
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
class_option :procfile, :type => :string, :aliases => "-p", :desc => "Default: ./Procfile"
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
error "#{procfile} does not exist." unless procfile_exists?(procfile)
|
|
13
|
-
Foreman::Engine.new(procfile).start
|
|
14
|
-
end
|
|
11
|
+
desc "start [PROCESS]", "Start the application, or a specific process"
|
|
15
12
|
|
|
16
|
-
|
|
13
|
+
method_option :screen, :type => :boolean, :aliases => "-s"
|
|
17
14
|
|
|
18
|
-
def
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
def start(process=nil)
|
|
16
|
+
check_procfile!
|
|
17
|
+
|
|
18
|
+
if process
|
|
19
|
+
engine.execute(process)
|
|
20
|
+
elsif options[:screen]
|
|
21
|
+
engine.screen
|
|
22
|
+
else
|
|
23
|
+
engine.start
|
|
24
|
+
end
|
|
21
25
|
end
|
|
22
26
|
|
|
23
|
-
desc "
|
|
27
|
+
desc "export FORMAT LOCATION", "Export the application to another process management format"
|
|
24
28
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
end
|
|
29
|
+
method_option :app, :type => :string, :aliases => "-a"
|
|
30
|
+
method_option :concurrency, :type => :string, :aliases => "-c",
|
|
31
|
+
:banner => '"alpha=5,bar=3"'
|
|
29
32
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def export(app, procfile="Procfile", format="upstart")
|
|
33
|
-
error "#{procfile} does not exist." unless procfile_exists?(procfile)
|
|
33
|
+
def export(format, location=nil)
|
|
34
|
+
check_procfile!
|
|
34
35
|
|
|
35
36
|
formatter = case format
|
|
36
37
|
when "upstart" then Foreman::Export::Upstart
|
|
37
38
|
else error "Unknown export format: #{format}."
|
|
38
39
|
end
|
|
39
40
|
|
|
40
|
-
formatter.new(
|
|
41
|
+
formatter.new(engine).export(location,
|
|
42
|
+
:name => options[:app],
|
|
43
|
+
:concurrency => options[:concurrency]
|
|
44
|
+
)
|
|
45
|
+
rescue Foreman::Export::Exception => ex
|
|
46
|
+
error ex.message
|
|
41
47
|
end
|
|
42
48
|
|
|
43
|
-
|
|
49
|
+
private ######################################################################
|
|
50
|
+
|
|
51
|
+
def check_procfile!
|
|
52
|
+
error("Procfile does not exist.") unless File.exist?(procfile)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def engine
|
|
56
|
+
@engine ||= Foreman::Engine.new(procfile)
|
|
57
|
+
end
|
|
44
58
|
|
|
45
|
-
def
|
|
46
|
-
|
|
47
|
-
error "No such process: #{process}." unless config.processes[process]
|
|
48
|
-
config.scale(process, amount)
|
|
59
|
+
def procfile
|
|
60
|
+
options[:procfile] || "./Procfile"
|
|
49
61
|
end
|
|
50
62
|
|
|
51
63
|
private ######################################################################
|
data/lib/foreman/engine.rb
CHANGED
data/lib/foreman/export.rb
CHANGED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require "foreman/configuration"
|
|
2
|
+
require "foreman/export"
|
|
3
|
+
|
|
4
|
+
class Foreman::Export::Base
|
|
5
|
+
|
|
6
|
+
attr_reader :engine
|
|
7
|
+
|
|
8
|
+
def initialize(engine)
|
|
9
|
+
@engine = engine
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def export
|
|
13
|
+
raise "export method must be overridden"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private ######################################################################
|
|
17
|
+
|
|
18
|
+
def error(message)
|
|
19
|
+
raise Foreman::Export::Exception.new(message)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def say(message)
|
|
23
|
+
puts "[foreman export] %s" % message
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def export_template(name)
|
|
27
|
+
File.read(File.expand_path("../../../../export/#{name}", __FILE__))
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def parse_concurrency(concurrency)
|
|
31
|
+
@concurrency ||= begin
|
|
32
|
+
pairs = concurrency.to_s.gsub(/\s/, "").split(",")
|
|
33
|
+
pairs.inject(Hash.new(1)) do |hash, pair|
|
|
34
|
+
process, amount = pair.split("=")
|
|
35
|
+
hash.update(process => amount.to_i)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def write_file(filename, contents)
|
|
41
|
+
say "writing: #{filename}"
|
|
42
|
+
|
|
43
|
+
File.open(filename, "w") do |file|
|
|
44
|
+
file.puts contents
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
@@ -1,51 +1,42 @@
|
|
|
1
|
+
require "erb"
|
|
1
2
|
require "foreman/configuration"
|
|
2
|
-
require "foreman/export"
|
|
3
|
+
require "foreman/export/base"
|
|
3
4
|
|
|
4
|
-
class Foreman::Export::Upstart
|
|
5
|
+
class Foreman::Export::Upstart < Foreman::Export::Base
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
def export(location, options={})
|
|
8
|
+
error("Must specify a location") unless location
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
@engine = engine
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def export(app)
|
|
13
|
-
FileUtils.mkdir_p "/etc/foreman"
|
|
14
|
-
FileUtils.mkdir_p "/etc/init"
|
|
15
|
-
|
|
16
|
-
config = Foreman::Configuration.new(app)
|
|
10
|
+
FileUtils.mkdir_p location
|
|
17
11
|
|
|
18
|
-
|
|
19
|
-
pre-start script
|
|
12
|
+
app = options[:app] || File.basename(engine.directory)
|
|
20
13
|
|
|
21
|
-
|
|
22
|
-
|
|
14
|
+
Dir["#{location}/#{app}*.conf"].each do |file|
|
|
15
|
+
say "cleaning up: #{file}"
|
|
16
|
+
FileUtils.rm(file)
|
|
17
|
+
end
|
|
23
18
|
|
|
24
|
-
|
|
25
|
-
source /etc/foreman/#{app}.conf
|
|
26
|
-
fi
|
|
19
|
+
concurrency = parse_concurrency(options[:concurrency])
|
|
27
20
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
21
|
+
master_template = export_template("upstart/master.conf.erb")
|
|
22
|
+
master_config = ERB.new(master_template).result(binding)
|
|
23
|
+
write_file "#{location}/#{app}.conf", master_config
|
|
31
24
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
25
|
+
process_template = export_template("upstart/process.conf.erb")
|
|
26
|
+
|
|
27
|
+
engine.processes.values.each do |process|
|
|
28
|
+
1.upto(concurrency[process.name]) do |num|
|
|
29
|
+
process_config = ERB.new(process_template).result(binding)
|
|
30
|
+
write_file "#{location}/#{app}-#{process.name}-#{num}.conf", process_config
|
|
31
|
+
end
|
|
32
|
+
end
|
|
37
33
|
|
|
38
|
-
|
|
34
|
+
return
|
|
35
|
+
write_file "#{location}/#{app}.conf", <<-UPSTART_MASTER
|
|
39
36
|
UPSTART_MASTER
|
|
40
37
|
|
|
41
|
-
engine.processes.
|
|
42
|
-
write_file
|
|
43
|
-
instance $NUM
|
|
44
|
-
stop on stopping #{app}
|
|
45
|
-
respawn
|
|
46
|
-
|
|
47
|
-
chdir #{engine.directory}
|
|
48
|
-
exec #{process.command} >>/var/log/#{app}/#{process.name}.log 2>&1
|
|
38
|
+
engine.processes.each do |process|
|
|
39
|
+
write_file process_conf, <<-UPSTART_CHILD
|
|
49
40
|
UPSTART_CHILD
|
|
50
41
|
end
|
|
51
42
|
|
|
@@ -55,12 +46,4 @@ exec #{process.command} >>/var/log/#{app}/#{process.name}.log 2>&1
|
|
|
55
46
|
config.write
|
|
56
47
|
end
|
|
57
48
|
|
|
58
|
-
private ######################################################################
|
|
59
|
-
|
|
60
|
-
def write_file(filename, contents)
|
|
61
|
-
File.open(filename, "w") do |file|
|
|
62
|
-
file.puts contents
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
|
|
66
49
|
end
|
data/spec/foreman/cli_spec.rb
CHANGED
|
@@ -25,27 +25,6 @@ describe "Foreman::CLI" do
|
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
describe "execute" do
|
|
29
|
-
describe "with a non-existent Procfile" do
|
|
30
|
-
it "prints an error" do
|
|
31
|
-
mock_error(subject, "Procfile does not exist.") do
|
|
32
|
-
dont_allow.instance_of(Foreman::Engine).start
|
|
33
|
-
subject.execute("alpha")
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
describe "with a Procfile" do
|
|
39
|
-
before(:each) { write_procfile }
|
|
40
|
-
|
|
41
|
-
it "runs successfully" do
|
|
42
|
-
dont_allow(subject).error
|
|
43
|
-
mock.instance_of(Foreman::Engine).execute("alpha")
|
|
44
|
-
subject.execute("alpha")
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
28
|
describe "export" do
|
|
50
29
|
describe "with a non-existent Procfile" do
|
|
51
30
|
it "prints an error" do
|
|
@@ -62,7 +41,7 @@ describe "Foreman::CLI" do
|
|
|
62
41
|
describe "with an invalid formatter" do
|
|
63
42
|
it "prints an error" do
|
|
64
43
|
mock_error(subject, "Unknown export format: invalidformatter.") do
|
|
65
|
-
subject.export("
|
|
44
|
+
subject.export("invalidformatter")
|
|
66
45
|
end
|
|
67
46
|
end
|
|
68
47
|
end
|
|
@@ -72,33 +51,11 @@ describe "Foreman::CLI" do
|
|
|
72
51
|
|
|
73
52
|
it "runs successfully" do
|
|
74
53
|
dont_allow(subject).error
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
describe "scale" do
|
|
82
|
-
describe "without an existing configuration" do
|
|
83
|
-
it "displays an error" do
|
|
84
|
-
mock_error(subject, "No such process: alpha.") do
|
|
85
|
-
subject.scale("testapp", "alpha", "2")
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
describe "with an existing configuration" do
|
|
91
|
-
before(:each) { write_foreman_config("testapp") }
|
|
92
|
-
|
|
93
|
-
it "scales a process that exists" do
|
|
94
|
-
mock.instance_of(Foreman::Configuration).scale("alpha", "2")
|
|
95
|
-
subject.scale("testapp", "alpha", "2")
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
it "errors if a process that does not exist is specified" do
|
|
99
|
-
mock_error(subject, "No such process: invalidprocess.") do
|
|
100
|
-
dont_allow.instance_of(Foreman::Configuration).scale
|
|
101
|
-
subject.scale("testapp", "invalidprocess", "2")
|
|
54
|
+
mock.instance_of(Foreman::Export::Upstart).export("/tmp/foo", {
|
|
55
|
+
:concurrency => nil,
|
|
56
|
+
:name => nil
|
|
57
|
+
})
|
|
58
|
+
subject.export("upstart", "/tmp/foo")
|
|
102
59
|
end
|
|
103
60
|
end
|
|
104
61
|
end
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: foreman
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
hash:
|
|
4
|
+
hash: 13
|
|
5
5
|
prerelease: false
|
|
6
6
|
segments:
|
|
7
7
|
- 0
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
version: 0.
|
|
8
|
+
- 4
|
|
9
|
+
- 1
|
|
10
|
+
version: 0.4.1
|
|
11
11
|
platform: ruby
|
|
12
12
|
authors:
|
|
13
13
|
- David Dollar
|
|
@@ -15,7 +15,7 @@ autorequire:
|
|
|
15
15
|
bindir: bin
|
|
16
16
|
cert_chain: []
|
|
17
17
|
|
|
18
|
-
date: 2010-06-
|
|
18
|
+
date: 2010-06-23 00:00:00 -04:00
|
|
19
19
|
default_executable: foreman
|
|
20
20
|
dependencies:
|
|
21
21
|
- !ruby/object:Gem::Dependency
|
|
@@ -146,6 +146,7 @@ files:
|
|
|
146
146
|
- lib/foreman/configuration.rb
|
|
147
147
|
- lib/foreman/engine.rb
|
|
148
148
|
- lib/foreman/export.rb
|
|
149
|
+
- lib/foreman/export/base.rb
|
|
149
150
|
- lib/foreman/export/upstart.rb
|
|
150
151
|
- lib/foreman/process.rb
|
|
151
152
|
- spec/foreman/cli_spec.rb
|