ey-deploy 0.4.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/ey-deploy.rb +2 -0
- data/lib/ey-deploy/cli.rb +6 -0
- data/lib/ey-deploy/default_maintenance_page.html +29 -0
- data/lib/ey-deploy/deploy.rb +107 -44
- data/lib/ey-deploy/server.rb +1 -1
- data/lib/ey-deploy/task.rb +12 -6
- data/lib/ey-deploy/version.rb +1 -1
- data/spec/custom_deploy_spec.rb +13 -13
- metadata +16 -15
data/lib/ey-deploy.rb
CHANGED
data/lib/ey-deploy/cli.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
<!DOCTYPE html >
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Undergoing Maintenance</title>
|
5
|
+
|
6
|
+
<style type="text/css">
|
7
|
+
body{font-size: 75%;font-family: Helvetica,Arial,sans-serif;color:#333;background:#FDFDFD;}
|
8
|
+
.container{font-size:1.1em;width:700px;text-align:center;margin:80px auto;}
|
9
|
+
.message{background:#FFF;border:1px solid #EEE;padding:30px;}
|
10
|
+
h1{margin:0 0 0.5em;font-weight:normal;}
|
11
|
+
p{margin:0;line-height:1.75em;}
|
12
|
+
.foot{color:#999;margin-top:30px}
|
13
|
+
.foot a{color:#666;text-decoration:none}
|
14
|
+
</style>
|
15
|
+
</head>
|
16
|
+
|
17
|
+
<body>
|
18
|
+
<div class="container">
|
19
|
+
<div class="message">
|
20
|
+
<h1>This site is currently undergoing some maintenance.</h1>
|
21
|
+
<p>Customize this maintenance page by updating the file located at: /public/maintenance.html</p>
|
22
|
+
</div>
|
23
|
+
<div class="foot">
|
24
|
+
Hosted by <a href="http://www.engineyard.com">Engine Yard</a>
|
25
|
+
</div>
|
26
|
+
</div>
|
27
|
+
</body>
|
28
|
+
|
29
|
+
</html>
|
data/lib/ey-deploy/deploy.rb
CHANGED
@@ -11,39 +11,66 @@ module EY
|
|
11
11
|
push_code
|
12
12
|
|
13
13
|
puts "~> Starting full deploy"
|
14
|
-
|
15
14
|
copy_repository_cache
|
16
|
-
create_revision_file
|
17
|
-
bundle
|
18
|
-
symlink_configs
|
19
15
|
|
20
|
-
|
16
|
+
with_failed_release_cleanup do
|
17
|
+
create_revision_file
|
18
|
+
bundle
|
19
|
+
symlink_configs
|
20
|
+
conditionally_enable_maintenance_page
|
21
21
|
run_with_callbacks(:migrate)
|
22
|
-
|
23
|
-
|
22
|
+
callback(:before_symlink)
|
23
|
+
symlink
|
24
24
|
end
|
25
25
|
|
26
|
-
|
26
|
+
callback(:after_symlink)
|
27
|
+
run_with_callbacks(:restart)
|
28
|
+
disable_maintenance_page
|
29
|
+
|
30
|
+
cleanup_old_releases
|
27
31
|
|
28
32
|
puts "~> finalizing deploy"
|
33
|
+
rescue Exception
|
34
|
+
puts_deploy_failure
|
35
|
+
raise
|
29
36
|
end
|
30
37
|
|
31
38
|
def enable_maintenance_page
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
39
|
+
maintenance_page_candidates = [
|
40
|
+
"public/maintenance.html.custom",
|
41
|
+
"public/maintenance.html.tmp",
|
42
|
+
"public/maintenance.html",
|
43
|
+
"public/system/maintenance.html.default",
|
44
|
+
].map do |file|
|
45
|
+
File.join(c.latest_release, file)
|
46
|
+
end
|
37
47
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
48
|
+
# this one is guaranteed to exist
|
49
|
+
maintenance_page_candidates << File.expand_path(
|
50
|
+
"default_maintenance_page.html",
|
51
|
+
File.dirname(__FILE__)
|
52
|
+
)
|
53
|
+
|
54
|
+
# put in the maintenance page
|
55
|
+
maintenance_file = maintenance_page_candidates.detect do |file|
|
56
|
+
File.exists?(file)
|
57
|
+
end
|
58
|
+
|
59
|
+
@maintenance_up = true
|
60
|
+
roles :app_master, :app, :solo do
|
61
|
+
visible_maint_page = File.join(c.shared_path, "system", "maintenance.html")
|
62
|
+
run "cp '#{maintenance_file}' '#{visible_maint_page}'"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def conditionally_enable_maintenance_page
|
67
|
+
if c.migrate? || c.stack == "nginx_mongrel"
|
68
|
+
enable_maintenance_page
|
43
69
|
end
|
44
70
|
end
|
45
71
|
|
46
72
|
def disable_maintenance_page
|
73
|
+
@maintenance_up = false
|
47
74
|
roles :app_master, :app, :solo do
|
48
75
|
run "rm -f #{File.join(c.shared_path, "system", "maintenance.html")}"
|
49
76
|
end
|
@@ -65,6 +92,7 @@ module EY
|
|
65
92
|
|
66
93
|
# task
|
67
94
|
def restart
|
95
|
+
@restart_failed = true
|
68
96
|
puts "~> Restarting app servers"
|
69
97
|
puts "~> restarting app: #{c.latest_release}"
|
70
98
|
roles :app_master, :app, :solo do
|
@@ -77,6 +105,7 @@ module EY
|
|
77
105
|
sudo("touch #{c.latest_release}/tmp/restart.txt")
|
78
106
|
end
|
79
107
|
end
|
108
|
+
@restart_failed = false
|
80
109
|
end
|
81
110
|
|
82
111
|
# task
|
@@ -84,37 +113,44 @@ module EY
|
|
84
113
|
roles :app_master, :app, :solo do
|
85
114
|
if File.exist?("#{c.latest_release}/Gemfile")
|
86
115
|
puts "~> Gemfile detected, bundling gems"
|
87
|
-
run
|
116
|
+
run "cd #{c.latest_release} && bundle install"
|
88
117
|
end
|
89
118
|
end
|
90
119
|
end
|
91
120
|
|
92
121
|
# task
|
93
|
-
def
|
122
|
+
def cleanup_old_releases
|
123
|
+
@cleanup_failed = true
|
94
124
|
puts "~> cleaning up old releases"
|
95
125
|
sudo "ls #{c.release_dir} | head -n -3 | xargs -I{} rm -rf #{c.release_dir}/{}"
|
126
|
+
@cleanup_failed = false
|
96
127
|
end
|
97
128
|
|
98
129
|
# task
|
99
130
|
def rollback
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
131
|
+
if c.all_releases.size > 1
|
132
|
+
puts "~> rolling back to previous release"
|
133
|
+
c.release_path = c.previous_release
|
134
|
+
run_with_callbacks(:symlink, c.previous_release)
|
135
|
+
cleanup_latest_release
|
136
|
+
bundle
|
137
|
+
puts "~> restarting with previous release"
|
138
|
+
with_maintenance_page { run_with_callbacks(:restart) }
|
139
|
+
else
|
140
|
+
puts "~> Already at oldest release, nothing to roll back to"
|
141
|
+
exit(1)
|
142
|
+
end
|
107
143
|
end
|
108
144
|
|
109
145
|
# task
|
110
146
|
def migrate
|
147
|
+
return unless c.migrate?
|
148
|
+
@migrations_reached = true
|
111
149
|
roles :app_master, :solo do
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
run(cmd)
|
117
|
-
end
|
150
|
+
puts "~> migrating"
|
151
|
+
cmd = "cd #{c.latest_release} && #{c.framework_envs} #{c.migration_command}"
|
152
|
+
puts "~> Migrating: #{cmd}"
|
153
|
+
run(cmd)
|
118
154
|
end
|
119
155
|
end
|
120
156
|
|
@@ -150,31 +186,58 @@ module EY
|
|
150
186
|
# task
|
151
187
|
def symlink(release_to_link=c.latest_release)
|
152
188
|
puts "~> symlinking code"
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
end
|
189
|
+
sudo "rm -f #{c.current_path} && ln -nfs #{release_to_link} #{c.current_path} && chown -R #{c.user}:#{c.group} #{c.current_path}"
|
190
|
+
@symlink_changed = true
|
191
|
+
rescue Exception
|
192
|
+
sudo "rm -f #{c.current_path} && ln -nfs #{c.previous_release(release_to_link)} #{c.current_path} && chown -R #{c.user}:#{c.group} #{c.current_path}"
|
193
|
+
@symlink_changed = false
|
194
|
+
raise
|
160
195
|
end
|
161
196
|
|
162
197
|
def callback(what)
|
198
|
+
@callbacks_reached ||= true
|
163
199
|
if File.exist?("#{c.latest_release}/deploy/#{what}.rb")
|
164
200
|
eysd_path = $0 # invoke others just like we were invoked
|
165
|
-
|
166
|
-
server.run("#{eysd_path} hook '#{what}' --app '#{config.app}' --release-path #{config.release_path}")
|
167
|
-
end
|
201
|
+
run "#{eysd_path} hook '#{what}' --app '#{config.app}' --release-path #{config.release_path}"
|
168
202
|
end
|
169
203
|
end
|
170
204
|
|
171
205
|
protected
|
172
206
|
|
207
|
+
def puts_deploy_failure
|
208
|
+
if @cleanup_failed
|
209
|
+
puts "~> [Relax] Your site is running new code, but cleaning up old deploys failed"
|
210
|
+
elsif @maintenance_up
|
211
|
+
puts "~> [Attention] Maintenance page still up, consider the following before removing:"
|
212
|
+
puts " * any deploy hooks ran, be careful if they were destructive" if @callbacks_reached
|
213
|
+
puts " * any migrations ran, be careful if they were destructive" if @migrations_reached
|
214
|
+
if @symlink_changed
|
215
|
+
puts " * your new code is symlinked as current"
|
216
|
+
else
|
217
|
+
puts " * your old code is still symlinked as current"
|
218
|
+
end
|
219
|
+
puts " * application servers failed to restart" if @restart_failed
|
220
|
+
else
|
221
|
+
puts "~> [Relax] Your site is still running old code and nothing destructive could have occurred"
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
173
225
|
def with_maintenance_page
|
174
|
-
|
226
|
+
conditionally_enable_maintenance_page
|
175
227
|
yield if block_given?
|
176
228
|
disable_maintenance_page
|
177
229
|
end
|
230
|
+
|
231
|
+
def with_failed_release_cleanup
|
232
|
+
yield
|
233
|
+
rescue Exception
|
234
|
+
cleanup_latest_release
|
235
|
+
raise
|
236
|
+
end
|
237
|
+
|
238
|
+
def cleanup_latest_release
|
239
|
+
sudo "rm -rf #{c.latest_release}"
|
240
|
+
end
|
178
241
|
end
|
179
242
|
|
180
243
|
class Deploy < DeployBase
|
data/lib/ey-deploy/server.rb
CHANGED
data/lib/ey-deploy/task.rb
CHANGED
@@ -37,15 +37,11 @@ module EY
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def run(cmd)
|
40
|
-
|
41
|
-
server.run prepare_run(cmd)
|
42
|
-
end
|
40
|
+
run_on_roles { prepare_run cmd }
|
43
41
|
end
|
44
42
|
|
45
43
|
def sudo(cmd)
|
46
|
-
|
47
|
-
server.run prepare_sudo(cmd)
|
48
|
-
end
|
44
|
+
run_on_roles { prepare_sudo cmd }
|
49
45
|
end
|
50
46
|
|
51
47
|
def prepare_run(command)
|
@@ -55,5 +51,15 @@ module EY
|
|
55
51
|
def prepare_sudo(command)
|
56
52
|
Escape.shell_command ["sudo", "sh", "-l", "-c", command]
|
57
53
|
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def run_on_roles
|
58
|
+
cmd = yield
|
59
|
+
EY::Server.from_roles(@roles).inject(false) do |acc, server|
|
60
|
+
failure = !server.run(cmd)
|
61
|
+
acc || failure
|
62
|
+
end && raise(EY::RemoteFailure)
|
63
|
+
end
|
58
64
|
end
|
59
65
|
end
|
data/lib/ey-deploy/version.rb
CHANGED
data/spec/custom_deploy_spec.rb
CHANGED
@@ -18,17 +18,17 @@ describe "the EY::Deploy API" do
|
|
18
18
|
@call_order = []
|
19
19
|
end
|
20
20
|
|
21
|
-
def push_code()
|
22
|
-
def copy_repository_cache()
|
23
|
-
def create_revision_file()
|
24
|
-
def bundle()
|
25
|
-
def symlink_configs()
|
26
|
-
def migrate()
|
27
|
-
def symlink()
|
28
|
-
def restart()
|
29
|
-
def
|
30
|
-
def
|
31
|
-
def disable_maintenance_page()
|
21
|
+
def push_code() @call_order << 'push_code' end
|
22
|
+
def copy_repository_cache() @call_order << 'copy_repository_cache' end
|
23
|
+
def create_revision_file() @call_order << 'create_revision_file' end
|
24
|
+
def bundle() @call_order << 'bundle' end
|
25
|
+
def symlink_configs() @call_order << 'symlink_configs' end
|
26
|
+
def migrate() @call_order << 'migrate' end
|
27
|
+
def symlink() @call_order << 'symlink' end
|
28
|
+
def restart() @call_order << 'restart' end
|
29
|
+
def cleanup_old_releases() @call_order << 'cleanup_old_releases' end
|
30
|
+
def conditionally_enable_maintenance_page() @call_order << 'conditionally_enable_maintenance_page' end
|
31
|
+
def disable_maintenance_page() @call_order << 'disable_maintenance_page' end
|
32
32
|
end
|
33
33
|
|
34
34
|
td = TestDeploy.new(EY::Deploy::Configuration.new)
|
@@ -39,12 +39,12 @@ describe "the EY::Deploy API" do
|
|
39
39
|
create_revision_file
|
40
40
|
bundle
|
41
41
|
symlink_configs
|
42
|
-
|
42
|
+
conditionally_enable_maintenance_page
|
43
43
|
migrate
|
44
44
|
symlink
|
45
45
|
restart
|
46
46
|
disable_maintenance_page
|
47
|
-
|
47
|
+
cleanup_old_releases)
|
48
48
|
end
|
49
49
|
|
50
50
|
describe "task overrides" do
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 4
|
8
|
-
-
|
9
|
-
version: 0.4.
|
8
|
+
- 1
|
9
|
+
version: 0.4.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- EY Cloud Team
|
@@ -14,25 +14,23 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-06-
|
17
|
+
date: 2010-06-16 00:00:00 -07:00
|
18
18
|
default_executable: eysd
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
|
-
|
22
|
-
name: rake
|
23
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
21
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
24
22
|
requirements:
|
25
23
|
- - ">="
|
26
24
|
- !ruby/object:Gem::Version
|
27
25
|
segments:
|
28
26
|
- 0
|
29
27
|
version: "0"
|
28
|
+
name: rake
|
29
|
+
prerelease: false
|
30
|
+
requirement: *id001
|
30
31
|
type: :runtime
|
31
|
-
version_requirements: *id001
|
32
32
|
- !ruby/object:Gem::Dependency
|
33
|
-
|
34
|
-
name: escape
|
35
|
-
requirement: &id002 !ruby/object:Gem::Requirement
|
33
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
36
34
|
requirements:
|
37
35
|
- - ">="
|
38
36
|
- !ruby/object:Gem::Version
|
@@ -41,20 +39,22 @@ dependencies:
|
|
41
39
|
- 0
|
42
40
|
- 4
|
43
41
|
version: 0.0.4
|
42
|
+
name: escape
|
43
|
+
prerelease: false
|
44
|
+
requirement: *id002
|
44
45
|
type: :runtime
|
45
|
-
version_requirements: *id002
|
46
46
|
- !ruby/object:Gem::Dependency
|
47
|
-
|
48
|
-
name: json
|
49
|
-
requirement: &id003 !ruby/object:Gem::Requirement
|
47
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
50
48
|
requirements:
|
51
49
|
- - ">="
|
52
50
|
- !ruby/object:Gem::Version
|
53
51
|
segments:
|
54
52
|
- 0
|
55
53
|
version: "0"
|
54
|
+
name: json
|
55
|
+
prerelease: false
|
56
|
+
requirement: *id003
|
56
57
|
type: :runtime
|
57
|
-
version_requirements: *id003
|
58
58
|
description:
|
59
59
|
email: cloud@engineyard.com
|
60
60
|
executables:
|
@@ -67,6 +67,7 @@ files:
|
|
67
67
|
- bin/eysd
|
68
68
|
- lib/ey-deploy/cli.rb
|
69
69
|
- lib/ey-deploy/configuration.rb
|
70
|
+
- lib/ey-deploy/default_maintenance_page.html
|
70
71
|
- lib/ey-deploy/deploy.rb
|
71
72
|
- lib/ey-deploy/deploy_hook.rb
|
72
73
|
- lib/ey-deploy/server.rb
|