sunshine 1.0.0.pre
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 +237 -0
- data/Manifest.txt +70 -0
- data/README.txt +277 -0
- data/Rakefile +46 -0
- data/bin/sunshine +5 -0
- data/examples/deploy.rb +61 -0
- data/examples/deploy_tasks.rake +112 -0
- data/examples/standalone_deploy.rb +31 -0
- data/lib/commands/add.rb +96 -0
- data/lib/commands/default.rb +169 -0
- data/lib/commands/list.rb +322 -0
- data/lib/commands/restart.rb +62 -0
- data/lib/commands/rm.rb +83 -0
- data/lib/commands/run.rb +151 -0
- data/lib/commands/start.rb +72 -0
- data/lib/commands/stop.rb +61 -0
- data/lib/sunshine/app.rb +876 -0
- data/lib/sunshine/binder.rb +70 -0
- data/lib/sunshine/crontab.rb +143 -0
- data/lib/sunshine/daemon.rb +380 -0
- data/lib/sunshine/daemons/ar_sendmail.rb +28 -0
- data/lib/sunshine/daemons/delayed_job.rb +30 -0
- data/lib/sunshine/daemons/nginx.rb +104 -0
- data/lib/sunshine/daemons/rainbows.rb +35 -0
- data/lib/sunshine/daemons/server.rb +66 -0
- data/lib/sunshine/daemons/unicorn.rb +26 -0
- data/lib/sunshine/dependencies.rb +103 -0
- data/lib/sunshine/dependency_lib.rb +200 -0
- data/lib/sunshine/exceptions.rb +54 -0
- data/lib/sunshine/healthcheck.rb +83 -0
- data/lib/sunshine/output.rb +131 -0
- data/lib/sunshine/package_managers/apt.rb +48 -0
- data/lib/sunshine/package_managers/dependency.rb +349 -0
- data/lib/sunshine/package_managers/gem.rb +54 -0
- data/lib/sunshine/package_managers/yum.rb +62 -0
- data/lib/sunshine/remote_shell.rb +241 -0
- data/lib/sunshine/repo.rb +128 -0
- data/lib/sunshine/repos/git_repo.rb +122 -0
- data/lib/sunshine/repos/rsync_repo.rb +29 -0
- data/lib/sunshine/repos/svn_repo.rb +78 -0
- data/lib/sunshine/server_app.rb +554 -0
- data/lib/sunshine/shell.rb +384 -0
- data/lib/sunshine.rb +391 -0
- data/templates/logrotate/logrotate.conf.erb +11 -0
- data/templates/nginx/nginx.conf.erb +109 -0
- data/templates/nginx/nginx_optimize.conf +23 -0
- data/templates/nginx/nginx_proxy.conf +13 -0
- data/templates/rainbows/rainbows.conf.erb +18 -0
- data/templates/tasks/sunshine.rake +114 -0
- data/templates/unicorn/unicorn.conf.erb +6 -0
- data/test/fixtures/app_configs/test_app.yml +11 -0
- data/test/fixtures/sunshine_test/test_upload +0 -0
- data/test/mocks/mock_object.rb +179 -0
- data/test/mocks/mock_open4.rb +117 -0
- data/test/test_helper.rb +188 -0
- data/test/unit/test_app.rb +489 -0
- data/test/unit/test_binder.rb +20 -0
- data/test/unit/test_crontab.rb +128 -0
- data/test/unit/test_git_repo.rb +26 -0
- data/test/unit/test_healthcheck.rb +70 -0
- data/test/unit/test_nginx.rb +107 -0
- data/test/unit/test_rainbows.rb +26 -0
- data/test/unit/test_remote_shell.rb +102 -0
- data/test/unit/test_repo.rb +42 -0
- data/test/unit/test_server.rb +324 -0
- data/test/unit/test_server_app.rb +425 -0
- data/test/unit/test_shell.rb +97 -0
- data/test/unit/test_sunshine.rb +157 -0
- data/test/unit/test_svn_repo.rb +55 -0
- data/test/unit/test_unicorn.rb +22 -0
- metadata +217 -0
@@ -0,0 +1,70 @@
|
|
1
|
+
module Sunshine
|
2
|
+
|
3
|
+
##
|
4
|
+
# Instantiated per deploy server and used to pass bindings to the config's
|
5
|
+
# ERB build method:
|
6
|
+
# binder.set :server_name, "blah.com"
|
7
|
+
# binder.forward :server_method, ...
|
8
|
+
# binder.get_binding
|
9
|
+
|
10
|
+
class Binder
|
11
|
+
|
12
|
+
def initialize target
|
13
|
+
@target = target
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
##
|
18
|
+
# Set the binding instance variable and accessor method.
|
19
|
+
|
20
|
+
def set key, value=nil, &block
|
21
|
+
value ||= block if block_given?
|
22
|
+
|
23
|
+
instance_variable_set("@#{key}", value)
|
24
|
+
|
25
|
+
eval_str = <<-STR
|
26
|
+
undef #{key} if defined?(#{key})
|
27
|
+
def #{key}(*args)
|
28
|
+
if Proc === @#{key}
|
29
|
+
@#{key}.call(*args)
|
30
|
+
else
|
31
|
+
@#{key}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
STR
|
35
|
+
|
36
|
+
instance_eval eval_str, __FILE__, __LINE__ + 1
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
##
|
41
|
+
# Takes a hash and assign each hash key/value as an attribute.
|
42
|
+
|
43
|
+
def import_hash hash
|
44
|
+
hash.each{|k, v| self.set(k, v)}
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
##
|
49
|
+
# Forward a method to the server instance.
|
50
|
+
|
51
|
+
def forward *method_names
|
52
|
+
method_names.each do |method_name|
|
53
|
+
instance_eval <<-STR, __FILE__, __LINE__ + 1
|
54
|
+
undef #{method_name} if defined?(#{method_name})
|
55
|
+
def #{method_name}(*args, &block)
|
56
|
+
@target.#{method_name}(*args, &block)
|
57
|
+
end
|
58
|
+
STR
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
##
|
64
|
+
# Retrieve the object's binding.
|
65
|
+
|
66
|
+
def get_binding
|
67
|
+
binding
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
module Sunshine
|
2
|
+
|
3
|
+
##
|
4
|
+
# A simple namespaced grouping of cron jobs that can be written
|
5
|
+
# to a deploy server.
|
6
|
+
|
7
|
+
class Crontab
|
8
|
+
|
9
|
+
attr_reader :name, :shell
|
10
|
+
|
11
|
+
def initialize name, shell
|
12
|
+
@name = name
|
13
|
+
@shell = shell
|
14
|
+
@jobs = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
##
|
19
|
+
# Get the jobs matching this crontab. Loads them from the crontab
|
20
|
+
# if @jobs hasn't been set yet.
|
21
|
+
|
22
|
+
def jobs
|
23
|
+
@jobs ||= parse read_crontab
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
##
|
28
|
+
# Build the crontab by replacing preexisting cron jobs and adding new ones.
|
29
|
+
|
30
|
+
def build crontab=""
|
31
|
+
crontab.strip!
|
32
|
+
|
33
|
+
jobs.each do |namespace, cron_job|
|
34
|
+
crontab = delete_jobs crontab, namespace
|
35
|
+
|
36
|
+
start_id, end_id = get_job_ids namespace
|
37
|
+
cron_str = "\n#{start_id}\n#{cron_job.chomp}\n#{end_id}\n\n"
|
38
|
+
|
39
|
+
crontab << cron_str
|
40
|
+
end
|
41
|
+
|
42
|
+
crontab
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
##
|
47
|
+
# Remove all cron jobs that reference crontab.name.
|
48
|
+
|
49
|
+
def delete!
|
50
|
+
crontab = read_crontab
|
51
|
+
crontab = delete_jobs crontab
|
52
|
+
|
53
|
+
write_crontab crontab
|
54
|
+
|
55
|
+
crontab
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
##
|
60
|
+
# Write the crontab on the given shell
|
61
|
+
|
62
|
+
def write!
|
63
|
+
return unless modified?
|
64
|
+
|
65
|
+
crontab = read_crontab
|
66
|
+
crontab = delete_jobs crontab
|
67
|
+
crontab = build crontab
|
68
|
+
|
69
|
+
write_crontab crontab
|
70
|
+
|
71
|
+
crontab
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
##
|
76
|
+
# Checks if the crontab was modified for crontab.name.
|
77
|
+
|
78
|
+
def modified?
|
79
|
+
!@jobs.nil?
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
##
|
84
|
+
# Load a crontab string and parse out jobs related to crontab.name.
|
85
|
+
# Returns a hash of namespace/jobs pairs.
|
86
|
+
|
87
|
+
def parse string
|
88
|
+
jobs = Hash.new
|
89
|
+
|
90
|
+
namespace = nil
|
91
|
+
|
92
|
+
string.each_line do |line|
|
93
|
+
if line =~ /^# sunshine #{@name}:(.*):begin/
|
94
|
+
namespace = $1
|
95
|
+
next
|
96
|
+
elsif line =~ /^# sunshine #{@name}:#{namespace}:end/
|
97
|
+
namespace = nil
|
98
|
+
end
|
99
|
+
|
100
|
+
if namespace
|
101
|
+
jobs[namespace] ||= String.new
|
102
|
+
jobs[namespace] << line
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
jobs
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
##
|
111
|
+
# Returns the shell's crontab as a string
|
112
|
+
|
113
|
+
def read_crontab
|
114
|
+
@shell.call("crontab -l") rescue ""
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
def write_crontab content
|
121
|
+
@shell.call("echo '#{content.gsub(/'/){|s| "'\\''"}}' | crontab")
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
def delete_jobs crontab, namespace=nil
|
126
|
+
start_id, end_id = get_job_ids namespace
|
127
|
+
|
128
|
+
crontab.gsub!(/^#{start_id}$(.*?)^#{end_id}$\n*/m, "")
|
129
|
+
|
130
|
+
crontab
|
131
|
+
end
|
132
|
+
|
133
|
+
|
134
|
+
def get_job_ids namespace=nil
|
135
|
+
namespace ||= "[^\n]*"
|
136
|
+
|
137
|
+
start_id = "# sunshine #{@name}:#{namespace}:begin"
|
138
|
+
end_id = "# sunshine #{@name}:#{namespace}:end"
|
139
|
+
|
140
|
+
return start_id, end_id
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,380 @@
|
|
1
|
+
module Sunshine
|
2
|
+
|
3
|
+
##
|
4
|
+
# An abstract class to wrap simple daemon software setup and start/stop.
|
5
|
+
#
|
6
|
+
# Child classes are expected to at least provide a start and stop bash script
|
7
|
+
# by either overloading the start_cmd and stop_cmd methods, or by setting
|
8
|
+
# @start_cmd and @stop_cmd. A restart_cmd method or @restart_cmd attribute
|
9
|
+
# may also be specified if restart requires more functionality than simply
|
10
|
+
# calling start_cmd && stop_cmd.
|
11
|
+
|
12
|
+
class Daemon
|
13
|
+
|
14
|
+
|
15
|
+
##
|
16
|
+
# Returns an array of method names to assign to the binder
|
17
|
+
# for template rendering.
|
18
|
+
|
19
|
+
def self.binder_methods
|
20
|
+
[:app, :name, :target, :bin, :pid, :port,
|
21
|
+
:processes, :config_path, :log_file, :timeout]
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
##
|
26
|
+
# Turn camelcase into underscore. Used for Daemon#name.
|
27
|
+
|
28
|
+
def self.underscore str
|
29
|
+
str.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
30
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').downcase
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
attr_reader :app, :name, :target
|
35
|
+
|
36
|
+
attr_accessor :bin, :pid, :processes, :timeout, :sudo, :server_apps
|
37
|
+
|
38
|
+
attr_accessor :config_template, :config_path, :config_file
|
39
|
+
|
40
|
+
attr_writer :start_cmd, :stop_cmd, :restart_cmd, :status_cmd
|
41
|
+
|
42
|
+
|
43
|
+
# Daemon objects need only an App object to be instantiated but many options
|
44
|
+
# are available for customization:
|
45
|
+
#
|
46
|
+
# :pid:: pid_path - set the pid; default: app.shared_path/pids/svr_name.pid
|
47
|
+
# defaults to app.shared_path/pids/svr_name.pid
|
48
|
+
#
|
49
|
+
# :bin:: bin_path - set the daemon app bin path (e.g. usr/local/nginx)
|
50
|
+
# defaults to svr_name
|
51
|
+
#
|
52
|
+
# :sudo:: bool|str - define if sudo should be used and with what user
|
53
|
+
#
|
54
|
+
# :timeout:: int|str - timeout to use for daemon config
|
55
|
+
# defaults to 1
|
56
|
+
#
|
57
|
+
# :processes:: prcss_num - number of processes daemon should run
|
58
|
+
# defaults to 0
|
59
|
+
#
|
60
|
+
# :config_template:: path - glob path to tempates to render and upload
|
61
|
+
# defaults to sunshine_path/templates/svr_name/*
|
62
|
+
#
|
63
|
+
# :config_path:: path - remote path daemon configs will be uploaded to
|
64
|
+
# defaults to app.current_path/daemons/svr_name
|
65
|
+
#
|
66
|
+
# :config_file:: name - remote file name the daemon should load
|
67
|
+
# defaults to svr_name.conf
|
68
|
+
#
|
69
|
+
# :log_path:: path - path to where the log files should be output
|
70
|
+
# defaults to app.log_path
|
71
|
+
#
|
72
|
+
# :point_to:: app|daemon - an abstract target to point to
|
73
|
+
# defaults to the passed app
|
74
|
+
#
|
75
|
+
# The Daemon constructor also supports any App#find options to narrow
|
76
|
+
# the server apps to use. Note: subclasses such as Server already have
|
77
|
+
# a default :role that can be overridden.
|
78
|
+
|
79
|
+
def initialize app, options={}
|
80
|
+
@options = options
|
81
|
+
|
82
|
+
@app = app
|
83
|
+
@target = options[:point_to] || @app
|
84
|
+
|
85
|
+
@short_class_name = self.class.underscore self.class.to_s.split("::").last
|
86
|
+
|
87
|
+
@name = options[:name] || @short_class_name
|
88
|
+
|
89
|
+
@pid = options[:pid] || "#{@app.shared_path}/pids/#{@name}.pid"
|
90
|
+
@bin = options[:bin] || @name
|
91
|
+
@sudo = options[:sudo]
|
92
|
+
@timeout = options[:timeout] || 0
|
93
|
+
@dep_name = options[:dep_name] || @name
|
94
|
+
@processes = options[:processes] || 1
|
95
|
+
|
96
|
+
@config_template = options[:config_template]
|
97
|
+
@config_template ||= "#{Sunshine::ROOT}/templates/#{@short_class_name}/*"
|
98
|
+
|
99
|
+
@config_path = options[:config_path] ||
|
100
|
+
"#{@app.current_path}/daemons/#{@name}"
|
101
|
+
@config_file = options[:config_file] || "#{@name}.conf"
|
102
|
+
|
103
|
+
log_path = options[:log_path] || @app.log_path
|
104
|
+
@log_files = {
|
105
|
+
:stderr => "#{log_path}/#{@name}_stderr.log",
|
106
|
+
:stdout => "#{log_path}/#{@name}_stdout.log"
|
107
|
+
}
|
108
|
+
|
109
|
+
@start_cmd = @stop_cmd = @restart_cmd = @status_cmd = nil
|
110
|
+
|
111
|
+
@setup_successful = nil
|
112
|
+
|
113
|
+
register_after_user_script
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
##
|
118
|
+
# Do something with each server app used by the daemon.
|
119
|
+
|
120
|
+
def each_server_app(&block)
|
121
|
+
@app.each(@options, &block)
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
##
|
126
|
+
# Setup the daemon, parse and upload config templates.
|
127
|
+
# If a dependency with the daemon name exists in Sunshine.dependencies,
|
128
|
+
# setup will attempt to install the dependency before uploading configs.
|
129
|
+
# If a block is given it will be passed each server_app and binder object
|
130
|
+
# which will be used for the building erb config templates.
|
131
|
+
# See the ConfigBinding class for more information.
|
132
|
+
|
133
|
+
def setup
|
134
|
+
Sunshine.logger.info @name, "Setting up #{@name} daemon" do
|
135
|
+
|
136
|
+
each_server_app do |server_app|
|
137
|
+
|
138
|
+
# Build erb binding
|
139
|
+
binder = config_binding server_app.shell
|
140
|
+
|
141
|
+
server_app.shell.call "mkdir -p #{remote_dirs.join(" ")}",
|
142
|
+
:sudo => binder.sudo
|
143
|
+
|
144
|
+
yield(server_app, binder) if block_given?
|
145
|
+
|
146
|
+
server_app.install_deps @dep_name if
|
147
|
+
Sunshine.dependencies.exist?(@dep_name)
|
148
|
+
|
149
|
+
upload_config_files(server_app.shell, binder.get_binding)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
@setup_successful = true
|
154
|
+
|
155
|
+
rescue => e
|
156
|
+
raise CriticalDeployError.new(e, "Could not setup #{@name}")
|
157
|
+
end
|
158
|
+
|
159
|
+
|
160
|
+
##
|
161
|
+
# Check if setup was run successfully.
|
162
|
+
|
163
|
+
def has_setup? force=false
|
164
|
+
return @setup_successful unless @setup_successful.nil? || force
|
165
|
+
|
166
|
+
each_server_app do |server_app|
|
167
|
+
|
168
|
+
unless server_app.shell.file? config_file_path
|
169
|
+
return @setup_successful = false
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
@setup_successful = true
|
174
|
+
end
|
175
|
+
|
176
|
+
|
177
|
+
##
|
178
|
+
# Start the daemon app after running setup.
|
179
|
+
|
180
|
+
def start
|
181
|
+
self.setup unless has_setup?
|
182
|
+
Sunshine.logger.info @name, "Starting #{@name} daemon" do
|
183
|
+
|
184
|
+
each_server_app do |server_app|
|
185
|
+
begin
|
186
|
+
server_app.shell.call start_cmd,
|
187
|
+
:sudo => pick_sudo(server_app.shell)
|
188
|
+
|
189
|
+
yield(server_app) if block_given?
|
190
|
+
rescue => e
|
191
|
+
raise CriticalDeployError.new(e, "Could not start #{@name}")
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
|
198
|
+
##
|
199
|
+
# Stop the daemon app.
|
200
|
+
|
201
|
+
def stop
|
202
|
+
Sunshine.logger.info @name, "Stopping #{@name} daemon" do
|
203
|
+
|
204
|
+
each_server_app do |server_app|
|
205
|
+
begin
|
206
|
+
server_app.shell.call stop_cmd,
|
207
|
+
:sudo => pick_sudo(server_app.shell)
|
208
|
+
|
209
|
+
yield(server_app) if block_given?
|
210
|
+
rescue => e
|
211
|
+
raise CriticalDeployError.new(e, "Could not stop #{@name}")
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
|
218
|
+
##
|
219
|
+
# Restarts the daemon using the restart_cmd attribute if provided.
|
220
|
+
# If restart_cmd is not provided, calls stop and start.
|
221
|
+
|
222
|
+
def restart
|
223
|
+
self.setup unless has_setup?
|
224
|
+
|
225
|
+
Sunshine.logger.info @name, "Restarting #{@name} daemon" do
|
226
|
+
each_server_app do |server_app|
|
227
|
+
begin
|
228
|
+
server_app.shell.call restart_cmd,
|
229
|
+
:sudo => pick_sudo(server_app.shell)
|
230
|
+
|
231
|
+
yield(server_app) if block_given?
|
232
|
+
rescue => e
|
233
|
+
raise CriticalDeployError.new(e, "Could not restart #{@name}")
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
|
240
|
+
##
|
241
|
+
# Gets the command that starts the daemon.
|
242
|
+
# Should be overridden by child classes.
|
243
|
+
|
244
|
+
def start_cmd
|
245
|
+
return @start_cmd ||
|
246
|
+
raise(CriticalDeployError, "@start_cmd undefined. Can't start #{@name}")
|
247
|
+
end
|
248
|
+
|
249
|
+
|
250
|
+
##
|
251
|
+
# Gets the command that stops the daemon.
|
252
|
+
# Should be overridden by child classes.
|
253
|
+
|
254
|
+
def stop_cmd
|
255
|
+
return @stop_cmd ||
|
256
|
+
raise(CriticalDeployError, "@stop_cmd undefined. Can't stop #{@name}")
|
257
|
+
end
|
258
|
+
|
259
|
+
|
260
|
+
##
|
261
|
+
# Gets the command that restarts the daemon.
|
262
|
+
|
263
|
+
def restart_cmd
|
264
|
+
@restart_cmd || [stop_cmd, start_cmd].map{|c| "(#{c})"}.join(" && ")
|
265
|
+
end
|
266
|
+
|
267
|
+
|
268
|
+
##
|
269
|
+
# Get the command to check if the daemon is running.
|
270
|
+
|
271
|
+
def status_cmd
|
272
|
+
@status_cmd || "test -f #{@pid}"
|
273
|
+
end
|
274
|
+
|
275
|
+
|
276
|
+
##
|
277
|
+
# Append or override daemon log file paths:
|
278
|
+
# daemon.log_files :stderr => "/all_logs/stderr.log"
|
279
|
+
|
280
|
+
def log_files(hash)
|
281
|
+
@log_files.merge!(hash)
|
282
|
+
end
|
283
|
+
|
284
|
+
|
285
|
+
##
|
286
|
+
# Get the path of a log file:
|
287
|
+
# daemon.log_file(:stderr)
|
288
|
+
# #=> "/all_logs/stderr.log"
|
289
|
+
|
290
|
+
def log_file(key)
|
291
|
+
@log_files[key]
|
292
|
+
end
|
293
|
+
|
294
|
+
|
295
|
+
##
|
296
|
+
# Get the file path to the daemon's config file.
|
297
|
+
|
298
|
+
def config_file_path
|
299
|
+
"#{@config_path}/#{@config_file}"
|
300
|
+
end
|
301
|
+
|
302
|
+
|
303
|
+
##
|
304
|
+
# Upload config files and run them through erb with the provided
|
305
|
+
# binding if necessary.
|
306
|
+
|
307
|
+
def upload_config_files(shell, setup_binding=binding)
|
308
|
+
config_template_files.each do |config_file|
|
309
|
+
|
310
|
+
if File.extname(config_file) == ".erb"
|
311
|
+
filename = File.basename(config_file[0..-5])
|
312
|
+
parsed_config = @app.build_erb(config_file, setup_binding)
|
313
|
+
shell.make_file "#{@config_path}/#{filename}", parsed_config
|
314
|
+
else
|
315
|
+
filename = File.basename(config_file)
|
316
|
+
shell.upload config_file, "#{@config_path}/#{filename}"
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
|
322
|
+
##
|
323
|
+
# Get the array of local config template files needed by the daemon.
|
324
|
+
|
325
|
+
def config_template_files
|
326
|
+
@config_template_files ||= Dir[@config_template].select{|f| File.file?(f)}
|
327
|
+
end
|
328
|
+
|
329
|
+
|
330
|
+
private
|
331
|
+
|
332
|
+
def config_binding shell
|
333
|
+
binder = Binder.new self
|
334
|
+
binder.forward(*self.class.binder_methods)
|
335
|
+
|
336
|
+
binder.set :shell, shell
|
337
|
+
|
338
|
+
binder_sudo = pick_sudo(shell)
|
339
|
+
binder.set :sudo, binder_sudo
|
340
|
+
|
341
|
+
binder.set :expand_path do |path|
|
342
|
+
shell.expand_path path
|
343
|
+
end
|
344
|
+
|
345
|
+
binder
|
346
|
+
end
|
347
|
+
|
348
|
+
|
349
|
+
def pick_sudo shell
|
350
|
+
case shell.sudo
|
351
|
+
when true
|
352
|
+
self.sudo || shell.sudo
|
353
|
+
when String
|
354
|
+
String === self.sudo ? self.sudo : shell.sudo
|
355
|
+
else
|
356
|
+
self.sudo
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
|
361
|
+
def remote_dirs
|
362
|
+
dirs = @log_files.values.map{|f| File.dirname(f)}
|
363
|
+
dirs.concat [@config_path, File.dirname(@pid)]
|
364
|
+
dirs.delete_if{|d| d == "."}
|
365
|
+
dirs
|
366
|
+
end
|
367
|
+
|
368
|
+
|
369
|
+
def register_after_user_script
|
370
|
+
@app.after_user_script do |app|
|
371
|
+
each_server_app do |sa|
|
372
|
+
sa.scripts[:start] << start_cmd
|
373
|
+
sa.scripts[:stop] << stop_cmd
|
374
|
+
sa.scripts[:restart] << restart_cmd
|
375
|
+
sa.scripts[:status] << status_cmd
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|
379
|
+
end
|
380
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Sunshine
|
2
|
+
|
3
|
+
##
|
4
|
+
# Simple daemon wrapper for ar_sendmail setup and control.
|
5
|
+
# By default, uses server apps with the :mail role.
|
6
|
+
|
7
|
+
class ARSendmail < Daemon
|
8
|
+
|
9
|
+
def initialize app, options={}
|
10
|
+
options[:role] ||= :mail
|
11
|
+
|
12
|
+
super app, options
|
13
|
+
|
14
|
+
@dep_name = options[:dep_name] || 'ar_mailer'
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def start_cmd
|
19
|
+
"cd #{@app.current_path} && #{@bin} -p #{@pid} -d"
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
def stop_cmd
|
24
|
+
"test -f #{@pid} && kill `cat #{@pid}` || "+
|
25
|
+
"echo 'No #{@name} process to stop for #{@app.name}'; rm -f #{@pid};"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Sunshine
|
2
|
+
|
3
|
+
##
|
4
|
+
# Simple daemon wrapper for delayed_job daemon setup and control.
|
5
|
+
# By default, uses server apps with the :dj role. Supports
|
6
|
+
# the :processes option.
|
7
|
+
|
8
|
+
class DelayedJob < Daemon
|
9
|
+
|
10
|
+
def initialize app, options={}
|
11
|
+
options[:role] ||= :dj
|
12
|
+
|
13
|
+
super app, options
|
14
|
+
|
15
|
+
@pid = "#{@app.current_path}/tmp/pids/delayed_job.pid"
|
16
|
+
|
17
|
+
@dep_name = options[:dep_name] || "daemons"
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
def start_cmd
|
22
|
+
"cd #{@app.current_path} && script/delayed_job -n #{@processes} start"
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def stop_cmd
|
27
|
+
"cd #{@app.current_path} && script/delayed_job stop"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|