sunshine 1.2.0 → 1.2.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/History.txt +26 -0
- data/Manifest.txt +1 -0
- data/bin/sunshine +8 -1
- data/lib/commands/list.rb +11 -6
- data/lib/commands/restart.rb +6 -5
- data/lib/commands/rm.rb +6 -5
- data/lib/commands/script.rb +5 -4
- data/lib/commands/start.rb +7 -6
- data/lib/commands/stop.rb +6 -5
- data/lib/sunshine.rb +68 -50
- data/lib/sunshine/app.rb +269 -55
- data/lib/sunshine/daemon.rb +72 -18
- data/lib/sunshine/dependency_lib.rb +0 -2
- data/lib/sunshine/exceptions.rb +35 -17
- data/lib/sunshine/package_managers/apt.rb +1 -1
- data/lib/sunshine/package_managers/dependency.rb +0 -5
- data/lib/sunshine/package_managers/yum.rb +1 -1
- data/lib/sunshine/remote_shell.rb +21 -5
- data/lib/sunshine/repo.rb +5 -6
- data/lib/sunshine/repos/rsync_repo.rb +1 -1
- data/lib/sunshine/server_app.rb +146 -14
- data/lib/sunshine/shell.rb +49 -24
- data/lib/sunshine/trap_stack.rb +54 -0
- data/templates/nginx/nginx.conf.erb +24 -0
- data/test/helper_methods.rb +1 -1
- data/test/unit/test_app.rb +48 -6
- data/test/unit/test_daemon.rb +3 -3
- data/test/unit/test_nginx.rb +7 -4
- data/test/unit/test_server.rb +6 -6
- data/test/unit/test_server_app.rb +107 -9
- metadata +8 -7
data/History.txt
CHANGED
@@ -1,3 +1,29 @@
|
|
1
|
+
=== 1.2.1 / 2010-10-05
|
2
|
+
|
3
|
+
* Improvements:
|
4
|
+
|
5
|
+
* Added customizable behaviors for sigint and failures during deploys.
|
6
|
+
|
7
|
+
* Added Sunshine irb shell to work directly with deploying apps.
|
8
|
+
|
9
|
+
* Added ability to launch a pseudo terminal from a RemoteShell.
|
10
|
+
|
11
|
+
* Added exit code to CmdError.
|
12
|
+
|
13
|
+
* Added exclude paths for checkout by copy.
|
14
|
+
|
15
|
+
* Bugfixes:
|
16
|
+
|
17
|
+
* Fixed custom scripts.
|
18
|
+
|
19
|
+
* Fixed deploy env defaults.
|
20
|
+
|
21
|
+
* Removed Shell#update_timeout as it was unnecessary.
|
22
|
+
|
23
|
+
* RemoteShell rsync recurses by default.
|
24
|
+
|
25
|
+
* Fixed start and stop script permissions when calling sunshine commands.
|
26
|
+
|
1
27
|
=== 1.2.0 / 2010-09-08
|
2
28
|
|
3
29
|
* Improvements:
|
data/Manifest.txt
CHANGED
@@ -46,6 +46,7 @@ lib/sunshine/repos/rsync_repo.rb
|
|
46
46
|
lib/sunshine/repos/svn_repo.rb
|
47
47
|
lib/sunshine/server_app.rb
|
48
48
|
lib/sunshine/shell.rb
|
49
|
+
lib/sunshine/trap_stack.rb
|
49
50
|
templates/apache/apache.conf.erb
|
50
51
|
templates/mongrel_rails/mongrel_rails.conf.erb
|
51
52
|
templates/nginx/nginx.conf.erb
|
data/bin/sunshine
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
#!/usr/bin/env ruby -w
|
2
2
|
|
3
|
-
|
3
|
+
begin
|
4
|
+
require 'sunshine'
|
5
|
+
rescue LoadError => e
|
6
|
+
raise e unless e.message =~ %r{no such file to load -- sunshine}
|
7
|
+
|
8
|
+
$: << File.join(File.dirname(__FILE__), "../lib")
|
9
|
+
require 'sunshine'
|
10
|
+
end
|
4
11
|
|
5
12
|
Sunshine.run
|
data/lib/commands/list.rb
CHANGED
@@ -16,6 +16,7 @@ module Sunshine
|
|
16
16
|
# -f, --format FORMAT Set the output format (txt, yml, json)
|
17
17
|
# -u, --user USER User to use for remote login. Use with -r
|
18
18
|
# -r, --remote svr1,svr2 Run on one or more remote servers.
|
19
|
+
# -S, --sudo Run remote commands using sudo or sudo -u USER
|
19
20
|
# -v, --verbose Run in verbose mode.
|
20
21
|
|
21
22
|
class ListCommand < DefaultCommand
|
@@ -176,7 +177,11 @@ module Sunshine
|
|
176
177
|
|
177
178
|
def status(*app_names)
|
178
179
|
each_app(*app_names) do |server_app|
|
179
|
-
|
180
|
+
begin
|
181
|
+
server_app.status
|
182
|
+
rescue => e
|
183
|
+
e.message
|
184
|
+
end
|
180
185
|
end
|
181
186
|
end
|
182
187
|
|
@@ -185,17 +190,17 @@ module Sunshine
|
|
185
190
|
# Runs a command and returns the status for each app_name:
|
186
191
|
# status_after_command 'restart', ['app1', 'app2']
|
187
192
|
|
188
|
-
def status_after_command cmd, app_names
|
193
|
+
def status_after_command cmd, app_names, options=nil
|
189
194
|
each_app(*app_names) do |server_app|
|
190
195
|
|
191
196
|
yield(server_app) if block_given?
|
192
197
|
|
193
198
|
begin
|
194
|
-
server_app.run_script cmd
|
195
|
-
server_app.
|
199
|
+
server_app.run_script! cmd, options
|
200
|
+
server_app.status.to_s
|
196
201
|
|
197
202
|
rescue CmdError => e
|
198
|
-
raise "Failed running #{cmd}: #{server_app.status}"
|
203
|
+
raise "Failed running #{cmd}: #{server_app.status rescue :not_found}"
|
199
204
|
end
|
200
205
|
end
|
201
206
|
end
|
@@ -268,7 +273,7 @@ module Sunshine
|
|
268
273
|
# Load the app list yaml file from the server.
|
269
274
|
|
270
275
|
def self.load_list server
|
271
|
-
yml_list = server.call "cat #{Sunshine::APP_LIST_PATH} || echo
|
276
|
+
yml_list = server.call "cat #{Sunshine::APP_LIST_PATH} || echo"
|
272
277
|
|
273
278
|
list = YAML.load yml_list
|
274
279
|
list = {} unless Hash === list
|
data/lib/commands/restart.rb
CHANGED
@@ -9,10 +9,11 @@ module Sunshine
|
|
9
9
|
# app_name Name of the application to restart.
|
10
10
|
#
|
11
11
|
# Options:
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
12
|
+
# -f, --format FORMAT Set the output format (txt, yml, json)
|
13
|
+
# -u, --user USER User to use for remote login. Use with -r.
|
14
|
+
# -r, --remote svr1,svr2 Run on one or more remote servers.
|
15
|
+
# -S, --sudo Run remote commands using sudo or sudo -u USER
|
16
|
+
# -v, --verbose Run in verbose mode.
|
16
17
|
|
17
18
|
class RestartCommand < ListCommand
|
18
19
|
|
@@ -38,7 +39,7 @@ module Sunshine
|
|
38
39
|
# Restart specified apps.
|
39
40
|
|
40
41
|
def restart app_names
|
41
|
-
status_after_command :restart, app_names
|
42
|
+
status_after_command :restart, app_names, :sudo => false
|
42
43
|
end
|
43
44
|
|
44
45
|
|
data/lib/commands/rm.rb
CHANGED
@@ -9,11 +9,12 @@ module Sunshine
|
|
9
9
|
# app_name Name of the application to remove.
|
10
10
|
#
|
11
11
|
# Options:
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
12
|
+
# -d, --delete Delete the app directory.
|
13
|
+
# -f, --format FORMAT Set the output format (txt, yml, json)
|
14
|
+
# -u, --user USER User to use for remote login. Use with -r.
|
15
|
+
# -r, --remote svr1,svr2 Run on one or more remote servers.
|
16
|
+
# -S, --sudo Run remote commands using sudo or sudo -u USER
|
17
|
+
# -v, --verbose Run in verbose mode.
|
17
18
|
|
18
19
|
class RmCommand < ListCommand
|
19
20
|
|
data/lib/commands/script.rb
CHANGED
@@ -10,10 +10,11 @@ module Sunshine
|
|
10
10
|
# app_name Name of the application to run script for.
|
11
11
|
#
|
12
12
|
# Options:
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
13
|
+
# -f, --format FORMAT Set the output format (txt, yml, json)
|
14
|
+
# -u, --user USER User to use for remote login. Use with -r.
|
15
|
+
# -r, --remote svr1,svr2 Run on one or more remote servers.
|
16
|
+
# -S, --sudo Run remote commands using sudo or sudo -u USER
|
17
|
+
# -v, --verbose Run in verbose mode.
|
17
18
|
|
18
19
|
class ScriptCommand < ListCommand
|
19
20
|
|
data/lib/commands/start.rb
CHANGED
@@ -9,11 +9,12 @@ module Sunshine
|
|
9
9
|
# app_name Name of the application to start.
|
10
10
|
#
|
11
11
|
# Options:
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
12
|
+
# -F, --force Stop apps that are running, then start them.
|
13
|
+
# -f, --format FORMAT Set the output format (txt, yml, json)
|
14
|
+
# -u, --user USER User to use for remote login. Use with -r.
|
15
|
+
# -r, --remote svr1,svr2 Run on one or more remote servers.
|
16
|
+
# -S, --sudo Run remote commands using sudo or sudo -u USER
|
17
|
+
# -v, --verbose Run in verbose mode.
|
17
18
|
|
18
19
|
class StartCommand < ListCommand
|
19
20
|
|
@@ -41,7 +42,7 @@ module Sunshine
|
|
41
42
|
# Start specified apps.
|
42
43
|
|
43
44
|
def start app_names, force=false
|
44
|
-
status_after_command :start, app_names do |server_app|
|
45
|
+
status_after_command :start, app_names, :sudo => false do |server_app|
|
45
46
|
|
46
47
|
server_app.stop if server_app.running? && force
|
47
48
|
end
|
data/lib/commands/stop.rb
CHANGED
@@ -9,10 +9,11 @@ module Sunshine
|
|
9
9
|
# app_name Name of the application to stop.
|
10
10
|
#
|
11
11
|
# Options:
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
12
|
+
# -f, --format FORMAT Set the output format (txt, yml, json)
|
13
|
+
# -u, --user USER User to use for remote login. Use with -r.
|
14
|
+
# -r, --remote svr1,svr2 Run on one or more remote servers.
|
15
|
+
# -S, --sudo Run remote commands using sudo or sudo -u USER
|
16
|
+
# -v, --verbose Run in verbose mode.
|
16
17
|
|
17
18
|
class StopCommand < ListCommand
|
18
19
|
|
@@ -38,7 +39,7 @@ module Sunshine
|
|
38
39
|
# Stop specified apps.
|
39
40
|
|
40
41
|
def stop app_names
|
41
|
-
status_after_command :stop, app_names
|
42
|
+
status_after_command :stop, app_names, :sudo => false
|
42
43
|
end
|
43
44
|
|
44
45
|
##
|
data/lib/sunshine.rb
CHANGED
@@ -11,6 +11,12 @@ require 'optparse'
|
|
11
11
|
require 'time'
|
12
12
|
require 'fileutils'
|
13
13
|
require 'tmpdir'
|
14
|
+
require 'irb'
|
15
|
+
|
16
|
+
|
17
|
+
# Turn off EOF tracking to be able to prompt on deploy exceptions.
|
18
|
+
HighLine.track_eof = false
|
19
|
+
|
14
20
|
|
15
21
|
##
|
16
22
|
# Main module, used for configuration and running commands.
|
@@ -19,7 +25,7 @@ module Sunshine
|
|
19
25
|
|
20
26
|
##
|
21
27
|
# Sunshine version.
|
22
|
-
VERSION = '1.2.
|
28
|
+
VERSION = '1.2.1'
|
23
29
|
|
24
30
|
##
|
25
31
|
# Path to the list of installed sunshine apps.
|
@@ -36,18 +42,16 @@ module Sunshine
|
|
36
42
|
##
|
37
43
|
# Default configuration.
|
38
44
|
DEFAULT_CONFIG = {
|
39
|
-
'
|
45
|
+
'interactive' => true,
|
40
46
|
'auto_dependencies' => true,
|
41
|
-
'deploy_env' =>
|
42
|
-
|
43
|
-
|
44
|
-
ENV['RACK_ENV'] ||
|
45
|
-
ENV['RAILS_ENV'] ||
|
46
|
-
:development ),
|
47
|
+
'deploy_env' => :development,
|
48
|
+
'exception_behavior' => :revert,
|
49
|
+
'exclude_paths' => [],
|
47
50
|
'level' => 'info',
|
48
51
|
'max_deploy_versions' => 5,
|
49
52
|
'remote_checkouts' => false,
|
50
53
|
'timeout' => 300,
|
54
|
+
'sigint_behavior' => :revert,
|
51
55
|
'web_directory' => '/srv/http'
|
52
56
|
}
|
53
57
|
|
@@ -113,11 +117,34 @@ module Sunshine
|
|
113
117
|
|
114
118
|
|
115
119
|
##
|
116
|
-
#
|
117
|
-
#
|
120
|
+
# Defines what to do when deploy raises an exception.
|
121
|
+
# Supported values are:
|
122
|
+
# ::revert: Revert to the previous deploy.
|
123
|
+
# ::console: Start an interactive ruby shell within the app's context.
|
124
|
+
# ::exit: Stop deploy and exit, leaving deploy in unfinished state.
|
125
|
+
# ::prompt: Ask what to do.
|
126
|
+
# Defaults to :revert. Overridden in the config.
|
127
|
+
|
128
|
+
def self.exception_behavior
|
129
|
+
@config['exception_behavior']
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
##
|
134
|
+
# Array of paths or globs that should be excluded from the checkout.
|
135
|
+
# Does not work with remote_checkouts enabled.
|
136
|
+
|
137
|
+
def self.exclude_paths
|
138
|
+
@config['exclude_paths']
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
##
|
143
|
+
# Should sunshine ever ask for user input? True by default.
|
144
|
+
# Overridden in the config or with the -a option.
|
118
145
|
|
119
146
|
def self.interactive?
|
120
|
-
|
147
|
+
@config['interactive']
|
121
148
|
end
|
122
149
|
|
123
150
|
|
@@ -155,6 +182,20 @@ module Sunshine
|
|
155
182
|
end
|
156
183
|
|
157
184
|
|
185
|
+
##
|
186
|
+
# Defines what to do when sigint is sent during deploys.
|
187
|
+
# Supported values are:
|
188
|
+
# ::revert: Revert to the previous deploy.
|
189
|
+
# ::console: Start an interactive ruby shell within the app's context.
|
190
|
+
# ::exit: Stop deploy and exit, leaving deploy in unfinished state.
|
191
|
+
# ::prompt: Ask what to do.
|
192
|
+
# Defaults to :revert. Overridden in the config.
|
193
|
+
|
194
|
+
def self.sigint_behavior
|
195
|
+
@config['sigint_behavior']
|
196
|
+
end
|
197
|
+
|
198
|
+
|
158
199
|
##
|
159
200
|
# How long to wait on a command to finish when no output is received.
|
160
201
|
# Defaults to 300 (seconds). Overridden in the config.
|
@@ -186,42 +227,6 @@ module Sunshine
|
|
186
227
|
end
|
187
228
|
|
188
229
|
|
189
|
-
##
|
190
|
-
# Adds an INT signal trap with its description on the stack.
|
191
|
-
# Returns a trap_item Array.
|
192
|
-
|
193
|
-
def self.add_trap desc, &block
|
194
|
-
trap_item = [desc, block]
|
195
|
-
(@trap_stack ||= []).unshift trap_item
|
196
|
-
trap_item
|
197
|
-
end
|
198
|
-
|
199
|
-
add_trap "Disconnecting all remote shells." do
|
200
|
-
RemoteShell.disconnect_all
|
201
|
-
end
|
202
|
-
|
203
|
-
|
204
|
-
##
|
205
|
-
# Call a trap item and display it's message.
|
206
|
-
|
207
|
-
def self.call_trap trap_item
|
208
|
-
return unless trap_item
|
209
|
-
|
210
|
-
msg, block = trap_item
|
211
|
-
|
212
|
-
logger.info :INT, msg do
|
213
|
-
block.call
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
|
218
|
-
##
|
219
|
-
# Remove a trap_item from the stack.
|
220
|
-
|
221
|
-
def self.delete_trap trap_item
|
222
|
-
@trap_stack.delete trap_item
|
223
|
-
end
|
224
|
-
|
225
230
|
|
226
231
|
##
|
227
232
|
# Global value of sudo to use. Returns true, nil, or a username.
|
@@ -264,6 +269,15 @@ module Sunshine
|
|
264
269
|
end
|
265
270
|
|
266
271
|
load_config_file USER_CONFIG_FILE
|
272
|
+
|
273
|
+
@config['deploy_env'] =
|
274
|
+
ENV['DEPLOY_ENV'] ||
|
275
|
+
ENV['env'] ||
|
276
|
+
ENV['RACK_ENV'] ||
|
277
|
+
ENV['RAILS_ENV'] ||
|
278
|
+
@config['deploy_env']
|
279
|
+
|
280
|
+
@config
|
267
281
|
end
|
268
282
|
|
269
283
|
|
@@ -282,15 +296,18 @@ module Sunshine
|
|
282
296
|
def self.setup new_config={}, reset=false
|
283
297
|
@config = DEFAULT_CONFIG.dup if reset
|
284
298
|
|
285
|
-
|
299
|
+
TrapStack.trap_signal :INT do |msg|
|
286
300
|
$stderr << "\n\n"
|
287
301
|
logger.indent = 0
|
288
302
|
logger.fatal :INT, "Caught INT signal!"
|
303
|
+
logger.info :INT, msg
|
304
|
+
end
|
289
305
|
|
290
|
-
|
291
|
-
|
306
|
+
TrapStack.add_trap "Disconnecting all remote shells." do
|
307
|
+
RemoteShell.disconnect_all
|
292
308
|
end
|
293
309
|
|
310
|
+
|
294
311
|
require_libs(*new_config['require'])
|
295
312
|
|
296
313
|
config.merge! new_config
|
@@ -369,6 +386,7 @@ module Sunshine
|
|
369
386
|
|
370
387
|
|
371
388
|
require 'sunshine/exceptions'
|
389
|
+
require 'sunshine/trap_stack'
|
372
390
|
|
373
391
|
require 'sunshine/shell'
|
374
392
|
require 'sunshine/remote_shell'
|
data/lib/sunshine/app.rb
CHANGED
@@ -176,6 +176,8 @@ module Sunshine
|
|
176
176
|
|
177
177
|
@deploy_name = options[:deploy_name] || Time.now.to_i.to_s
|
178
178
|
|
179
|
+
@deploy_env = options[:deploy_env] if options[:deploy_env]
|
180
|
+
|
179
181
|
set_deploy_paths options[:root_path]
|
180
182
|
|
181
183
|
@server_apps = server_apps_from_config options[:remote_shells]
|
@@ -192,7 +194,7 @@ module Sunshine
|
|
192
194
|
|
193
195
|
@post_user_lambdas = []
|
194
196
|
|
195
|
-
@
|
197
|
+
@on_sigint = @on_exception = nil
|
196
198
|
end
|
197
199
|
|
198
200
|
|
@@ -220,7 +222,8 @@ module Sunshine
|
|
220
222
|
|
221
223
|
|
222
224
|
##
|
223
|
-
# Check if server apps are connected
|
225
|
+
# Check if all server apps are connected and returns a boolean.
|
226
|
+
# Supports any App#find options.
|
224
227
|
|
225
228
|
def connected? options=nil
|
226
229
|
each options do |server_app|
|
@@ -231,6 +234,19 @@ module Sunshine
|
|
231
234
|
end
|
232
235
|
|
233
236
|
|
237
|
+
##
|
238
|
+
# Check if any server apps are connected and returns a boolean.
|
239
|
+
# Supports any App#find options.
|
240
|
+
|
241
|
+
def any_connected? options=nil
|
242
|
+
each options do |server_app|
|
243
|
+
return true if server_app.shell.connected?
|
244
|
+
end
|
245
|
+
|
246
|
+
false
|
247
|
+
end
|
248
|
+
|
249
|
+
|
234
250
|
##
|
235
251
|
# Disconnect server apps. Supports any App#find options.
|
236
252
|
|
@@ -247,6 +263,13 @@ module Sunshine
|
|
247
263
|
# Deploy the application to deploy servers and
|
248
264
|
# call user's post-deploy code. Supports any App#find options.
|
249
265
|
#
|
266
|
+
# If the deploy fails or an exception is raised, it will attempt to
|
267
|
+
# run the Sunshine.failed_deploy_behavior, which is set to :revert by
|
268
|
+
# default. However, this is not true of ssh connection failures.
|
269
|
+
#
|
270
|
+
# If the deploy is interrupted by a SIGINT, it will attempt to run
|
271
|
+
# the Sunshine.sigint_behavior, which is set to :revert by default.
|
272
|
+
#
|
250
273
|
# Note: The deploy method will stop the former deploy just before
|
251
274
|
# symlink and the passed block is run.
|
252
275
|
#
|
@@ -254,28 +277,28 @@ module Sunshine
|
|
254
277
|
# run App#start.
|
255
278
|
|
256
279
|
def deploy options=nil
|
257
|
-
success = false
|
258
|
-
prev_connection = connected?
|
259
280
|
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
281
|
+
state = {
|
282
|
+
:success => false,
|
283
|
+
:stopped => false,
|
284
|
+
:symlinked => false
|
285
|
+
}
|
265
286
|
|
266
|
-
Sunshine.logger.info :app, "Beginning
|
287
|
+
Sunshine.logger.info :app, "Beginning #{@name} deploy"
|
267
288
|
|
268
|
-
with_session options do
|
289
|
+
with_session options do |app|
|
290
|
+
|
291
|
+
interruptable state do
|
292
|
+
raise DeployError, "No servers defined for #{@name}" if
|
293
|
+
@server_apps.empty?
|
269
294
|
|
270
|
-
with_filter options do |app|
|
271
295
|
make_app_directories
|
272
296
|
checkout_codebase
|
273
297
|
|
274
|
-
stop
|
275
|
-
|
276
|
-
symlink_current_dir
|
298
|
+
state[:stopped] = true if stop
|
299
|
+
state[:symlinked] = true if symlink_current_dir
|
277
300
|
|
278
|
-
yield
|
301
|
+
yield self if block_given?
|
279
302
|
|
280
303
|
run_post_user_lambdas
|
281
304
|
|
@@ -287,29 +310,136 @@ module Sunshine
|
|
287
310
|
|
288
311
|
register_as_deployed
|
289
312
|
|
290
|
-
success = start :force => true
|
291
|
-
|
292
|
-
remove_old_deploys
|
293
|
-
success &&= deployed?
|
313
|
+
state[:success] = true if start! :force => true
|
294
314
|
end
|
315
|
+
|
316
|
+
remove_old_deploys if state[:success] rescue
|
317
|
+
Sunshine.logger.error :app, "Could not remove old deploys"
|
318
|
+
|
319
|
+
state[:success] &&= deployed?
|
295
320
|
end
|
296
321
|
|
297
|
-
Sunshine.logger.info :app, "
|
322
|
+
Sunshine.logger.info :app, "Finished #{@name} deploy" if state[:success]
|
323
|
+
state[:success]
|
324
|
+
end
|
298
325
|
|
299
|
-
rescue => e
|
300
|
-
message = "#{e.class}: #{e.message}"
|
301
326
|
|
302
|
-
|
327
|
+
##
|
328
|
+
# Handles SIGINTs and exceptions according to rules set by
|
329
|
+
# Sunshine.sigint_behavior and Sunshine.exception_behavior
|
330
|
+
# or with the override hooks App#on_sigint and App#on_exception.
|
331
|
+
|
332
|
+
def interruptable options={}
|
333
|
+
interrupt_trap =
|
334
|
+
TrapStack.add_trap "Interrupted #{@name}" do
|
335
|
+
handle_sigint options
|
336
|
+
end
|
337
|
+
|
338
|
+
yield if block_given?
|
339
|
+
|
340
|
+
rescue => e
|
341
|
+
Sunshine.logger.error :app, "#{e.class}: #{e.message}" do
|
303
342
|
Sunshine.logger.error '>>', e.backtrace.join("\n")
|
304
|
-
revert! options
|
305
|
-
start options
|
306
343
|
end
|
307
344
|
|
345
|
+
handle_exception e, options
|
346
|
+
|
308
347
|
ensure
|
309
|
-
|
310
|
-
|
348
|
+
TrapStack.delete_trap interrupt_trap
|
349
|
+
end
|
350
|
+
|
351
|
+
|
352
|
+
##
|
353
|
+
# Calls the Apps on_sigint hook or the default Sunshine.sigint_behavior.
|
311
354
|
|
312
|
-
|
355
|
+
def handle_sigint state={}
|
356
|
+
return @on_sigint.call(state) if @on_sigint
|
357
|
+
handle_interruption Sunshine.sigint_behavior, state
|
358
|
+
end
|
359
|
+
|
360
|
+
|
361
|
+
##
|
362
|
+
# Calls the Apps on_exception hook or the default
|
363
|
+
# Sunshine.exception_behavior.
|
364
|
+
|
365
|
+
def handle_exception exception, state={}
|
366
|
+
return @on_exception.call(exception, state) if @on_exception
|
367
|
+
handle_interruption Sunshine.exception_behavior, state
|
368
|
+
end
|
369
|
+
|
370
|
+
|
371
|
+
##
|
372
|
+
# Set this to define the behavior of SIGINT during a deploy.
|
373
|
+
# Defines what to do when an INT signal is received when running
|
374
|
+
# a proc through App#interruptable. Used primarily to catch SIGINTs
|
375
|
+
# during deploys. Passes the block a hash with the state of the deploy:
|
376
|
+
#
|
377
|
+
# app.on_sigint do |deploy_state_hash|
|
378
|
+
# deploy_state_hash
|
379
|
+
# #=> {:stopped => true, :symlinked => true, :success => false}
|
380
|
+
# end
|
381
|
+
|
382
|
+
def on_sigint &block
|
383
|
+
@on_sigint = block
|
384
|
+
end
|
385
|
+
|
386
|
+
|
387
|
+
##
|
388
|
+
# Set this to define the behavior of exceptions during a deploy.
|
389
|
+
# Defines what to do when an exception is received when running
|
390
|
+
# a proc through App#interruptable. Used primarily to catch exceptions
|
391
|
+
# during deploys. Passes the block the exception and a hash with the
|
392
|
+
# state of the deploy:
|
393
|
+
#
|
394
|
+
# app.on_exception do |exception, deploy_state_hash|
|
395
|
+
# # do something...
|
396
|
+
# end
|
397
|
+
|
398
|
+
def on_exception &block
|
399
|
+
@on_exception = block
|
400
|
+
end
|
401
|
+
|
402
|
+
|
403
|
+
##
|
404
|
+
# Handles the behavior of a failed or interrupted deploy.
|
405
|
+
# Takes a behavior symbol defining how to handle the interruption
|
406
|
+
# and a hash representing the state of the deploy when it was
|
407
|
+
# interrupted.
|
408
|
+
#
|
409
|
+
# Supported bahavior symbols are:
|
410
|
+
# ::revert: Revert to previous deploy (default)
|
411
|
+
# ::console: Start an interactive console with the app's binding
|
412
|
+
# ::exit: Stop deploy and exit
|
413
|
+
# ::prompt: Ask what to do
|
414
|
+
#
|
415
|
+
# The state hash supports the following keys:
|
416
|
+
# ::stopped: Was the previous deploy stopped.
|
417
|
+
# ::symlinked: Was the new deployed symlinked as the current deploy.
|
418
|
+
|
419
|
+
def handle_interruption behavior, state={}
|
420
|
+
case behavior
|
421
|
+
|
422
|
+
when :exit
|
423
|
+
Sunshine.exit 1, "Error: Deploy of #{@name} failed"
|
424
|
+
|
425
|
+
when :revert
|
426
|
+
revert! if state[:symlinked]
|
427
|
+
start if state[:stopped]
|
428
|
+
|
429
|
+
when Sunshine.interactive? && :console
|
430
|
+
self.console!
|
431
|
+
|
432
|
+
when Sunshine.interactive? && :prompt
|
433
|
+
Sunshine.shell.choose do |menu|
|
434
|
+
menu.prompt = "Deploy interrupted:"
|
435
|
+
menu.choice(:revert) { handle_interruption :revert, state }
|
436
|
+
menu.choice(:console){ handle_interruption :console, state }
|
437
|
+
menu.choice(:exit) { handle_interruption :exit, state }
|
438
|
+
end
|
439
|
+
|
440
|
+
else
|
441
|
+
raise DeployError, "Deploy of #{@name} was interrupted."
|
442
|
+
end
|
313
443
|
end
|
314
444
|
|
315
445
|
|
@@ -343,7 +473,7 @@ module Sunshine
|
|
343
473
|
# application and job name, including previous deploys.
|
344
474
|
|
345
475
|
def add_to_crontab name, cronjob, options=nil
|
346
|
-
|
476
|
+
each options do |server_app|
|
347
477
|
server_app.crontab[name] << cronjob
|
348
478
|
end
|
349
479
|
end
|
@@ -357,7 +487,7 @@ module Sunshine
|
|
357
487
|
# application and job name, including previous deploys.
|
358
488
|
|
359
489
|
def cronjob name, cronjob, options=nil
|
360
|
-
|
490
|
+
each options do |server_app|
|
361
491
|
server_app.crontab[name] = cronjob
|
362
492
|
end
|
363
493
|
end
|
@@ -369,7 +499,7 @@ module Sunshine
|
|
369
499
|
# add_to_script :start, "start_mail", :role => :mail
|
370
500
|
|
371
501
|
def add_to_script name, script, options=nil
|
372
|
-
|
502
|
+
each options do |server_app|
|
373
503
|
server_app.scripts[name] << script
|
374
504
|
end
|
375
505
|
end
|
@@ -432,13 +562,44 @@ module Sunshine
|
|
432
562
|
end
|
433
563
|
|
434
564
|
|
565
|
+
##
|
566
|
+
# Starts an IRB console with the instance's binding.
|
567
|
+
|
568
|
+
def console!
|
569
|
+
IRB.setup nil unless defined?(IRB::UnrecognizedSwitch)
|
570
|
+
|
571
|
+
workspace = IRB::WorkSpace.new binding
|
572
|
+
irb = IRB::Irb.new workspace
|
573
|
+
|
574
|
+
irb.context.irb_name = "sunshine(#{@name})"
|
575
|
+
irb.context.prompt_c = "%N:%03n:%i* "
|
576
|
+
irb.context.prompt_i = "%N:%03n:%i> "
|
577
|
+
irb.context.prompt_n = "%N:%03n:%i> "
|
578
|
+
|
579
|
+
IRB.class_eval do
|
580
|
+
@CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
|
581
|
+
@CONF[:MAIN_CONTEXT] = irb.context
|
582
|
+
end
|
583
|
+
|
584
|
+
#TODO: remove sigint trap when irb session is closed
|
585
|
+
#trap("INT") do
|
586
|
+
# irb.signal_handle
|
587
|
+
#end
|
588
|
+
|
589
|
+
catch(:IRB_EXIT) do
|
590
|
+
irb.eval_input
|
591
|
+
end
|
592
|
+
end
|
593
|
+
|
594
|
+
|
435
595
|
##
|
436
596
|
# Checks out the app's codebase to one or all deploy servers.
|
437
597
|
# Supports all App#find options, plus:
|
438
598
|
# :copy:: Bool - Checkout locally and rsync; defaults to false.
|
439
599
|
|
440
600
|
def checkout_codebase options=nil
|
441
|
-
copy_option = options
|
601
|
+
copy_option = options[:copy] if options
|
602
|
+
exclude = options.delete(:exclude) if options
|
442
603
|
|
443
604
|
if @remote_checkout && !copy_option
|
444
605
|
with_server_apps options,
|
@@ -451,13 +612,13 @@ module Sunshine
|
|
451
612
|
tmp_path = File.join Sunshine::TMP_DIR, "#{@name}_checkout"
|
452
613
|
scm_info = @repo.checkout_to tmp_path
|
453
614
|
|
615
|
+
scm_info[:exclude] =
|
616
|
+
[Sunshine.exclude_paths, exclude].flatten.compact
|
617
|
+
|
454
618
|
with_server_apps options,
|
455
619
|
:send => [:upload_codebase, tmp_path, scm_info]
|
456
620
|
end
|
457
621
|
end
|
458
|
-
|
459
|
-
rescue => e
|
460
|
-
raise CriticalDeployError, e
|
461
622
|
end
|
462
623
|
|
463
624
|
|
@@ -612,9 +773,6 @@ module Sunshine
|
|
612
773
|
with_server_apps options,
|
613
774
|
:msg => "Creating #{@name} directories",
|
614
775
|
:send => :make_app_directories
|
615
|
-
|
616
|
-
rescue => e
|
617
|
-
raise FatalDeployError, e
|
618
776
|
end
|
619
777
|
|
620
778
|
|
@@ -692,6 +850,18 @@ module Sunshine
|
|
692
850
|
end
|
693
851
|
|
694
852
|
|
853
|
+
##
|
854
|
+
# Run the restart script of a deployed app on the specified
|
855
|
+
# deploy servers. Raises an exception on failure.
|
856
|
+
# Post-deploy only.
|
857
|
+
|
858
|
+
def restart! options=nil
|
859
|
+
with_server_apps options,
|
860
|
+
:msg => "Running restart script",
|
861
|
+
:send => :restart!
|
862
|
+
end
|
863
|
+
|
864
|
+
|
695
865
|
##
|
696
866
|
# Runs bundler on deploy servers.
|
697
867
|
|
@@ -699,9 +869,6 @@ module Sunshine
|
|
699
869
|
with_server_apps options,
|
700
870
|
:msg => "Running Bundler",
|
701
871
|
:send => [:run_bundler, options]
|
702
|
-
|
703
|
-
rescue => e
|
704
|
-
raise CriticalDeployError, e
|
705
872
|
end
|
706
873
|
|
707
874
|
|
@@ -712,9 +879,6 @@ module Sunshine
|
|
712
879
|
with_server_apps options,
|
713
880
|
:msg => "Running GemInstaller",
|
714
881
|
:send => [:run_geminstaller, options]
|
715
|
-
|
716
|
-
rescue => e
|
717
|
-
raise CriticalDeployError, e
|
718
882
|
end
|
719
883
|
|
720
884
|
|
@@ -741,6 +905,18 @@ module Sunshine
|
|
741
905
|
end
|
742
906
|
|
743
907
|
|
908
|
+
##
|
909
|
+
# Run the given script of a deployed app on the specified
|
910
|
+
# deploy servers. Raises an exception on failure.
|
911
|
+
# Post-deploy only.
|
912
|
+
|
913
|
+
def run_script! name, options=nil
|
914
|
+
with_server_apps options,
|
915
|
+
:msg => "Running #{name} script",
|
916
|
+
:send => [:run_script!, name, options]
|
917
|
+
end
|
918
|
+
|
919
|
+
|
744
920
|
##
|
745
921
|
# Run a sass task on any or all deploy servers.
|
746
922
|
|
@@ -763,6 +939,8 @@ module Sunshine
|
|
763
939
|
@shell_env.merge!(env_hash)
|
764
940
|
|
765
941
|
with_server_apps :all,
|
942
|
+
:no_threads => true,
|
943
|
+
:no_session => true,
|
766
944
|
:msg => "Shell env: #{@shell_env.inspect}" do |server_app|
|
767
945
|
server_app.shell_env.merge!(@shell_env)
|
768
946
|
end
|
@@ -783,6 +961,18 @@ module Sunshine
|
|
783
961
|
end
|
784
962
|
|
785
963
|
|
964
|
+
##
|
965
|
+
# Run the start script of a deployed app on the specified
|
966
|
+
# deploy servers. Raises an exception on failure.
|
967
|
+
# Post-deploy only.
|
968
|
+
|
969
|
+
def start! options=nil
|
970
|
+
with_server_apps options,
|
971
|
+
:msg => "Running start script",
|
972
|
+
:send => [:start!, options]
|
973
|
+
end
|
974
|
+
|
975
|
+
|
786
976
|
##
|
787
977
|
# Get a hash of which deploy server apps are :running or :down.
|
788
978
|
# Post-deploy only.
|
@@ -810,12 +1000,26 @@ module Sunshine
|
|
810
1000
|
end
|
811
1001
|
|
812
1002
|
|
1003
|
+
##
|
1004
|
+
# Run the stop script of a deployed app on the specified
|
1005
|
+
# deploy servers. Raises an exception on failure.
|
1006
|
+
# Post-deploy only.
|
1007
|
+
|
1008
|
+
def stop! options=nil
|
1009
|
+
with_server_apps options,
|
1010
|
+
:msg => "Running stop script",
|
1011
|
+
:send => :stop!
|
1012
|
+
end
|
1013
|
+
|
1014
|
+
|
813
1015
|
##
|
814
1016
|
# Use sudo on deploy servers. Set to true/false, or
|
815
1017
|
# a username to use 'sudo -u'.
|
816
1018
|
|
817
1019
|
def sudo=(value)
|
818
1020
|
with_server_apps :all,
|
1021
|
+
:no_threads => true,
|
1022
|
+
:no_session => true,
|
819
1023
|
:msg => "Using sudo = #{value.inspect}" do |server_app|
|
820
1024
|
server_app.shell.sudo = value
|
821
1025
|
end
|
@@ -831,9 +1035,6 @@ module Sunshine
|
|
831
1035
|
with_server_apps options,
|
832
1036
|
:msg => "Symlinking #{@checkout_path} -> #{@current_path}",
|
833
1037
|
:send => :symlink_current_dir
|
834
|
-
|
835
|
-
rescue => e
|
836
|
-
raise CriticalDeployError, e
|
837
1038
|
end
|
838
1039
|
|
839
1040
|
|
@@ -916,6 +1117,7 @@ module Sunshine
|
|
916
1117
|
# a session to avoid multiple ssh login prompts. Supports all App#find
|
917
1118
|
# options, plus:
|
918
1119
|
# :no_threads:: bool - disable threaded execution
|
1120
|
+
# :no_session:: bool - disable auto session creation
|
919
1121
|
# :msg:: "some message" - log message
|
920
1122
|
#
|
921
1123
|
# app.with_server_apps :all, :msg => "doing something" do |server_app|
|
@@ -925,12 +1127,16 @@ module Sunshine
|
|
925
1127
|
# app.with_server_apps :role => :db, :user => "bob" do |server_app|
|
926
1128
|
# # do something here
|
927
1129
|
# end
|
1130
|
+
#
|
1131
|
+
# Note: App#with_server_apps calls App#with_session. If you do not need
|
1132
|
+
# or want a server connection you can pass :no_session.
|
928
1133
|
|
929
1134
|
def with_server_apps search_options, options={}
|
930
1135
|
options = search_options.merge options if Hash === search_options
|
931
1136
|
|
932
1137
|
message = options[:msg]
|
933
1138
|
method = options[:no_threads] ? :each : :threaded_each
|
1139
|
+
auto_session = !options[:no_session]
|
934
1140
|
|
935
1141
|
block = lambda do
|
936
1142
|
send(method, search_options) do |server_app|
|
@@ -945,7 +1151,7 @@ module Sunshine
|
|
945
1151
|
end
|
946
1152
|
|
947
1153
|
|
948
|
-
|
1154
|
+
msg_block = lambda do
|
949
1155
|
if message
|
950
1156
|
Sunshine.logger.info(:app, message, &block)
|
951
1157
|
|
@@ -953,6 +1159,8 @@ module Sunshine
|
|
953
1159
|
block.call
|
954
1160
|
end
|
955
1161
|
end
|
1162
|
+
|
1163
|
+
auto_session ? with_session(&msg_block) : msg_block.call
|
956
1164
|
end
|
957
1165
|
|
958
1166
|
|
@@ -960,16 +1168,22 @@ module Sunshine
|
|
960
1168
|
# Runs block ensuring a connection to remote_shells.
|
961
1169
|
# Connecting and disconnecting will be ignored if a session
|
962
1170
|
# already exists. Supports all App#find options.
|
1171
|
+
#
|
1172
|
+
# Ensures that servers are disconnected after the block is run
|
1173
|
+
# if servers were not previously connected.
|
963
1174
|
|
964
1175
|
def with_session options=nil
|
1176
|
+
with_filter options do
|
1177
|
+
prev_connection = connected?
|
965
1178
|
|
966
|
-
|
967
|
-
|
1179
|
+
begin
|
1180
|
+
connect unless prev_connection
|
1181
|
+
yield self
|
968
1182
|
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
1183
|
+
ensure
|
1184
|
+
disconnect unless prev_connection
|
1185
|
+
end
|
1186
|
+
end
|
973
1187
|
end
|
974
1188
|
|
975
1189
|
|