sunshine 1.0.3 → 1.1.0
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/History.txt +22 -2
- data/Manifest.txt +7 -0
- data/README.txt +333 -57
- data/Rakefile +1 -1
- data/lib/commands/add.rb +2 -2
- data/lib/commands/default.rb +15 -8
- data/lib/commands/list.rb +5 -3
- data/lib/commands/restart.rb +2 -2
- data/lib/commands/rm.rb +2 -2
- data/lib/commands/run.rb +2 -2
- data/lib/commands/start.rb +2 -2
- data/lib/commands/stop.rb +2 -2
- data/lib/sunshine.rb +117 -132
- data/lib/sunshine/app.rb +116 -10
- data/lib/sunshine/crontab.rb +11 -2
- data/lib/sunshine/daemon.rb +60 -46
- data/lib/sunshine/daemons/apache.rb +10 -2
- data/lib/sunshine/daemons/ar_sendmail.rb +0 -6
- data/lib/sunshine/daemons/delayed_job.rb +2 -0
- data/lib/sunshine/daemons/mongrel_rails.rb +32 -0
- data/lib/sunshine/daemons/nginx.rb +3 -0
- data/lib/sunshine/daemons/rainbows.rb +2 -0
- data/lib/sunshine/daemons/server.rb +51 -24
- data/lib/sunshine/daemons/server_cluster.rb +47 -0
- data/lib/sunshine/daemons/thin.rb +36 -0
- data/lib/sunshine/daemons/unicorn.rb +4 -1
- data/lib/sunshine/dependencies.rb +10 -3
- data/lib/sunshine/healthcheck.rb +2 -2
- data/lib/sunshine/remote_shell.rb +11 -2
- data/lib/sunshine/repo.rb +1 -1
- data/lib/sunshine/repos/rsync_repo.rb +1 -0
- data/templates/apache/apache.conf.erb +25 -18
- data/templates/mongrel_rails/mongrel_rails.conf.erb +9 -0
- data/templates/nginx/nginx.conf.erb +12 -9
- data/templates/thin/thin.conf.erb +12 -0
- data/test/helper_methods.rb +161 -0
- data/test/unit/test_daemon.rb +1 -8
- data/test/unit/test_nginx.rb +1 -1
- data/test/unit/test_server.rb +16 -0
- data/test/unit/test_server_cluster.rb +46 -0
- data/test/unit/test_sunshine.rb +18 -12
- metadata +14 -11
@@ -3,31 +3,48 @@ module Sunshine
|
|
3
3
|
##
|
4
4
|
# An abstract class to wrap simple server software setup and start/stop.
|
5
5
|
#
|
6
|
-
# Child classes are expected to at least provide a
|
7
|
-
# by either overloading the start_cmd
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
6
|
+
# Child classes are expected to at least provide a start_cmd bash script
|
7
|
+
# by either overloading the start_cmd method, or by setting @start_cmd.
|
8
|
+
# A restart_cmd and stop_cmd method or attribute may also be specified
|
9
|
+
# if restart requires more functionality than simply calling
|
10
|
+
# start_cmd && stop_cmd.
|
11
11
|
|
12
12
|
class Server < Daemon
|
13
13
|
|
14
|
+
##
|
15
|
+
# Creates a server cluster object:
|
16
|
+
# Mongrel.new_cluster 3, app, :port => 5000
|
17
|
+
# #=> [<# mongrel_5000 >, <# mongrel_5001 >, <# mongrel_5002 >]
|
18
|
+
|
19
|
+
def self.new_cluster count, app, options={}
|
20
|
+
ServerCluster.new self, count, app, options
|
21
|
+
end
|
22
|
+
|
23
|
+
|
14
24
|
def self.binder_methods
|
15
|
-
[:server_name, :port].concat super
|
25
|
+
[:server_name, :port, :target, :connections].concat super
|
16
26
|
end
|
17
27
|
|
18
28
|
|
19
|
-
attr_reader :server_name, :port
|
20
|
-
|
29
|
+
attr_reader :server_name, :port, :target, :connections
|
30
|
+
|
31
|
+
attr_accessor :sigkill, :cluster
|
21
32
|
|
22
33
|
|
23
34
|
# Server objects need only an App object to be instantiated.
|
24
35
|
# All Daemon init options are supported plus the following:
|
25
36
|
#
|
26
|
-
# :
|
27
|
-
#
|
37
|
+
# :connections:: num - Number of connections allowed per server;
|
38
|
+
# defaults to 1024.
|
39
|
+
#
|
40
|
+
# :point_to:: app|server - An app or server to point to,
|
41
|
+
# defaults to the passed app. If a server object is given, will
|
42
|
+
# act as a proxy. (Only valid on front-end servers - Nginx, Apache)
|
28
43
|
#
|
29
|
-
# :
|
30
|
-
#
|
44
|
+
# :port:: port_num - The port to run the server on defaults to 80.
|
45
|
+
#
|
46
|
+
# :server_name:: myserver.com - Host name used by server
|
47
|
+
# defaults to the individual remote host.
|
31
48
|
#
|
32
49
|
# By default, servers also assign the option :role => :web.
|
33
50
|
|
@@ -36,20 +53,25 @@ module Sunshine
|
|
36
53
|
|
37
54
|
super app, options
|
38
55
|
|
39
|
-
@
|
40
|
-
@
|
56
|
+
@connections = options[:connections] || 1024
|
57
|
+
@port = options[:port] || 80
|
41
58
|
@server_name = options[:server_name]
|
42
|
-
@
|
43
|
-
@
|
59
|
+
# Setting @sudo to nil will let the server apps' shells handle sudo
|
60
|
+
@sudo = options[:sudo] || @port < 1024 || nil
|
61
|
+
@target = options[:point_to] || @app
|
62
|
+
|
63
|
+
@supports_rack = false
|
64
|
+
@supports_passenger = false
|
44
65
|
end
|
45
66
|
|
46
67
|
|
47
68
|
##
|
48
69
|
# Check if passenger is required to run the application.
|
49
|
-
# Returns true if the server's target is a Sunshine::App
|
70
|
+
# Returns true if the server's target is a Sunshine::App and if
|
71
|
+
# the server explicitely supports passenger.
|
50
72
|
|
51
73
|
def use_passenger?
|
52
|
-
Sunshine::App === @target && !supports_rack?
|
74
|
+
Sunshine::App === @target && supports_passenger? && !supports_rack?
|
53
75
|
end
|
54
76
|
|
55
77
|
|
@@ -68,7 +90,7 @@ module Sunshine
|
|
68
90
|
|
69
91
|
|
70
92
|
##
|
71
|
-
#
|
93
|
+
# Adds passenger information to the binder at setup time.
|
72
94
|
|
73
95
|
def setup
|
74
96
|
super do |server_app, binder|
|
@@ -85,11 +107,10 @@ module Sunshine
|
|
85
107
|
|
86
108
|
|
87
109
|
##
|
88
|
-
#
|
110
|
+
# Defines if this server has passenger support.
|
89
111
|
|
90
|
-
def
|
91
|
-
|
92
|
-
"rm -f #{@pid} || echo 'No #{@name} process to stop for #{@app.name}';"
|
112
|
+
def supports_passenger?
|
113
|
+
@supports_passenger
|
93
114
|
end
|
94
115
|
|
95
116
|
|
@@ -108,6 +129,12 @@ module Sunshine
|
|
108
129
|
|
109
130
|
binder.set :server_name, (@server_name || shell.host)
|
110
131
|
|
132
|
+
binder.set :proxy_name, "#{@app.name}_proxy"
|
133
|
+
|
134
|
+
binder.set :target_server do
|
135
|
+
target.server_name || server_name
|
136
|
+
end
|
137
|
+
|
111
138
|
binder
|
112
139
|
end
|
113
140
|
|
@@ -116,7 +143,7 @@ module Sunshine
|
|
116
143
|
super
|
117
144
|
|
118
145
|
@app.after_user_script do |app|
|
119
|
-
next unless @port
|
146
|
+
next unless @port && has_setup?
|
120
147
|
|
121
148
|
each_server_app do |sa|
|
122
149
|
sa.info[:ports][@pid] = @port
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Sunshine
|
2
|
+
|
3
|
+
##
|
4
|
+
# The ServerCluster is simply a fancy Array that conveniently forwards
|
5
|
+
# some method calls to each server in the array, namely:
|
6
|
+
# Server#setup, Server#start, Server#stop, Server#restart,
|
7
|
+
# Server#has_setup?, Server#status.
|
8
|
+
|
9
|
+
class ServerCluster < Array
|
10
|
+
|
11
|
+
##
|
12
|
+
# ServerClusters get initialized just like any server class with the
|
13
|
+
# additional svr_class (Unicorn, Thin, Mongrel) and the number of
|
14
|
+
# server instances you would like:
|
15
|
+
#
|
16
|
+
# ServerCluster.new Mongrel, 3, app, :port => 5000
|
17
|
+
# #=> [<# mongrel_5000 >, <# mongrel_5001 >, <# mongrel_5002 >]
|
18
|
+
#
|
19
|
+
# ServerClusters can also be created from any Server class:
|
20
|
+
#
|
21
|
+
# Mongrel.new_cluster 3, app, :port => 5000
|
22
|
+
|
23
|
+
def initialize svr_class, count, app, options={}
|
24
|
+
count.times do |num|
|
25
|
+
port = (options[:port] || 80) + num
|
26
|
+
name = (options[:name] || svr_class.short_name) + ".#{port}"
|
27
|
+
|
28
|
+
self << svr_class.new(app, options.merge(:name => name, :port => port))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
[:setup, :start, :stop, :restart].each do |method|
|
34
|
+
define_method method do
|
35
|
+
each{|server| server.send method }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
[:has_setup?, :status].each do |method|
|
41
|
+
define_method method do
|
42
|
+
each{|server| return false unless server.send method}
|
43
|
+
true
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Sunshine
|
2
|
+
|
3
|
+
##
|
4
|
+
# Simple server wrapper for Thin setup and control.
|
5
|
+
# Thin is considered a backend server and therefore does not support
|
6
|
+
# the :point_to proxying option.
|
7
|
+
#
|
8
|
+
# Note: Thin only supports a single log file. The default stdout file is used.
|
9
|
+
#
|
10
|
+
# Note: Thin manipulates the passed pid filepath to:
|
11
|
+
# path/[basename].[port].pid
|
12
|
+
# Sunshine::Thin will adjust the @pid attribute value accordingly.
|
13
|
+
|
14
|
+
class Thin < Server
|
15
|
+
|
16
|
+
def initialize app, options={}
|
17
|
+
super
|
18
|
+
|
19
|
+
@start_pid = @pid
|
20
|
+
|
21
|
+
pid_name = File.basename(@pid, ".pid")
|
22
|
+
@pid = File.join File.dirname(@pid), "#{pid_name}.#{@port}.pid"
|
23
|
+
|
24
|
+
@timeout = options[:timeout] || 3
|
25
|
+
|
26
|
+
@supports_rack = true
|
27
|
+
@supports_passenger = false
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def start_cmd
|
32
|
+
"cd #{@app.current_path} && "+
|
33
|
+
"#{@bin} start -C #{self.config_file_path} -P #{@start_pid};"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -2,6 +2,8 @@ module Sunshine
|
|
2
2
|
|
3
3
|
##
|
4
4
|
# Simple server wrapper for Unicorn setup and control.
|
5
|
+
# Unicorn is strictly a backend server and therefore does not support
|
6
|
+
# the :point_to proxying option.
|
5
7
|
|
6
8
|
class Unicorn < Server
|
7
9
|
|
@@ -10,7 +12,8 @@ module Sunshine
|
|
10
12
|
|
11
13
|
@timeout = options[:timeout] || 3.0
|
12
14
|
|
13
|
-
@supports_rack
|
15
|
+
@supports_rack = true
|
16
|
+
@supports_passenger = false
|
14
17
|
end
|
15
18
|
|
16
19
|
|
@@ -10,6 +10,9 @@ Sunshine.dependencies.instance_eval do
|
|
10
10
|
apt 'git', :pkg => 'git-core'
|
11
11
|
yum 'git', :pkg => 'git-core'
|
12
12
|
|
13
|
+
apt 'rsync'
|
14
|
+
yum 'rsync'
|
15
|
+
|
13
16
|
yum 'httpd-devel'
|
14
17
|
|
15
18
|
apt 'apache2', :pkg => 'apache2-mpm-prefork'
|
@@ -30,10 +33,10 @@ Sunshine.dependencies.instance_eval do
|
|
30
33
|
apt 'irb'
|
31
34
|
yum 'irb', :pkg => 'ruby-irb'
|
32
35
|
|
33
|
-
apt 'rubygems'
|
36
|
+
apt 'rubygems' do
|
34
37
|
requires 'ruby', 'ruby-devel'
|
35
38
|
end
|
36
|
-
yum 'rubygems'
|
39
|
+
yum 'rubygems' do
|
37
40
|
requires 'ruby', 'ruby-devel'
|
38
41
|
end
|
39
42
|
|
@@ -111,7 +114,7 @@ Sunshine.dependencies.instance_eval do
|
|
111
114
|
|
112
115
|
|
113
116
|
##
|
114
|
-
# Define gems used by Sunshine
|
117
|
+
# Define gems used by Sunshine remotely
|
115
118
|
|
116
119
|
gem 'bundler', :version => ">=0.9"
|
117
120
|
|
@@ -121,6 +124,10 @@ Sunshine.dependencies.instance_eval do
|
|
121
124
|
|
122
125
|
gem 'geminstaller', :version => ">=0.5"
|
123
126
|
|
127
|
+
gem 'mongrel', :version => ">=1.1.5"
|
128
|
+
|
129
|
+
gem 'thin', :version => ">=1.2.7"
|
130
|
+
|
124
131
|
gem 'unicorn', :version => ">=0.9"
|
125
132
|
|
126
133
|
gem 'rainbows', :version => ">=0.90.2"
|
data/lib/sunshine/healthcheck.rb
CHANGED
@@ -17,8 +17,8 @@ module Sunshine
|
|
17
17
|
# :uri_path:: The path that healthcheck will be used on.
|
18
18
|
# :health_file:: The file to check for health.
|
19
19
|
#
|
20
|
-
# use
|
21
|
-
#
|
20
|
+
# use Sunshine::Health, :uri_path => "/health.txt",
|
21
|
+
# :health_file => "health.txt"
|
22
22
|
|
23
23
|
class Healthcheck
|
24
24
|
|
@@ -51,7 +51,7 @@ module Sunshine
|
|
51
51
|
# The constructor also supports the following options:
|
52
52
|
# :env:: hash - hash of environment variables to set for the ssh session
|
53
53
|
# :password:: string - password for ssh login; if missing the deploy server
|
54
|
-
#
|
54
|
+
# will attempt to prompt the user for a password.
|
55
55
|
|
56
56
|
def initialize host, options={}
|
57
57
|
super $stdout, options
|
@@ -78,7 +78,7 @@ module Sunshine
|
|
78
78
|
|
79
79
|
##
|
80
80
|
# Runs a command via SSH. Optional block is passed the
|
81
|
-
# stream(stderr, stdout) and string data
|
81
|
+
# stream(stderr, stdout) and string data.
|
82
82
|
|
83
83
|
def call command_str, options={}, &block
|
84
84
|
Sunshine.logger.info @host, "Running: #{command_str}" do
|
@@ -204,6 +204,9 @@ module Sunshine
|
|
204
204
|
|
205
205
|
private
|
206
206
|
|
207
|
+
##
|
208
|
+
# Figure out which rsync flags to use.
|
209
|
+
|
207
210
|
def build_rsync_flags options
|
208
211
|
flags = @rsync_flags.dup
|
209
212
|
|
@@ -222,12 +225,18 @@ module Sunshine
|
|
222
225
|
end
|
223
226
|
|
224
227
|
|
228
|
+
##
|
229
|
+
# Creates an rsync command.
|
230
|
+
|
225
231
|
def rsync_cmd from_path, to_path, options={}
|
226
232
|
cmd = ["rsync", build_rsync_flags(options), from_path, to_path]
|
227
233
|
cmd.flatten.compact.join(" ")
|
228
234
|
end
|
229
235
|
|
230
236
|
|
237
|
+
##
|
238
|
+
# Wraps the command in an ssh call.
|
239
|
+
|
231
240
|
def ssh_cmd string, options=nil
|
232
241
|
options ||= {}
|
233
242
|
|
data/lib/sunshine/repo.rb
CHANGED
@@ -4,28 +4,29 @@ LoadModule authz_host_module modules/mod_authz_host.so
|
|
4
4
|
ErrorLog <%= expand_path log_file(:stderr) %>
|
5
5
|
TransferLog <%= expand_path log_file(:stdout) %>
|
6
6
|
|
7
|
-
<% if use_passenger?
|
7
|
+
<% if use_passenger? -%>
|
8
8
|
LoadModule passenger_module <%= passenger_root %>/ext/apache2/mod_passenger.so
|
9
9
|
|
10
10
|
PassengerRuby <%= shell.call "which ruby" %>
|
11
11
|
PassengerRoot <%= passenger_root %>
|
12
12
|
PassengerMaxPoolSize <%= processes %>
|
13
|
-
<% end
|
13
|
+
<% end -%>
|
14
14
|
|
15
|
-
<% unless
|
16
|
-
LoadModule proxy_module
|
17
|
-
LoadModule proxy_connect_module
|
18
|
-
LoadModule proxy_http_module
|
19
|
-
|
15
|
+
<% unless App === target -%>
|
16
|
+
LoadModule proxy_module modules/mod_proxy.so
|
17
|
+
LoadModule proxy_connect_module modules/mod_proxy_connect.so
|
18
|
+
LoadModule proxy_http_module modules/mod_proxy_http.so
|
19
|
+
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
|
20
|
+
<% end -%>
|
20
21
|
|
21
22
|
|
22
23
|
PidFile <%= expand_path pid %>
|
23
|
-
MaxClients <%=
|
24
|
+
MaxClients <%= connections %>
|
24
25
|
|
25
|
-
<% if sudo == true || sudo == 'root'
|
26
|
+
<% if sudo == true || sudo == 'root' -%>
|
26
27
|
User nobody
|
27
28
|
Group nobody
|
28
|
-
<% end
|
29
|
+
<% end -%>
|
29
30
|
|
30
31
|
Listen <%= port %>
|
31
32
|
|
@@ -36,19 +37,25 @@ NameVirtualHost *:<%= port %>
|
|
36
37
|
ServerName <%= server_name %>
|
37
38
|
ServerAlias www.<%= server_name %>
|
38
39
|
|
39
|
-
<% if Sunshine::App === target %>
|
40
|
-
|
41
40
|
DocumentRoot <%= expand_path app.current_path %>/public
|
42
41
|
|
43
42
|
<Directory <%= app.current_path %>/public>
|
44
|
-
|
45
|
-
|
43
|
+
Allow from all
|
44
|
+
Options -MultiViews
|
46
45
|
</Directory>
|
47
46
|
|
48
|
-
<%
|
47
|
+
<% unless App === target -%>
|
49
48
|
|
50
|
-
|
51
|
-
|
49
|
+
<Proxy balancer://<%= proxy_name %>>
|
50
|
+
<% [*target].each do |server| %>
|
51
|
+
BalancerMember http://0.0.0.0:<%= server.port %>
|
52
|
+
<% end -%>
|
53
|
+
</Proxy>
|
52
54
|
|
53
|
-
|
55
|
+
# Using / after the proxy target is essential to the public dir.
|
56
|
+
ProxyPass / balancer://<%= proxy_name %>/ timeout=<%= timeout %>
|
57
|
+
ProxyPassReverse / balancer://<%= proxy_name %>/
|
58
|
+
ProxyPreserveHost On
|
59
|
+
|
60
|
+
<% end -%>
|
54
61
|
</VirtualHost>
|