ey-deploy 0.4.0 → 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/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
|