oxen_deployer 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/oxen_deployer.rb +1 -1
- data/lib/oxen_deployer/apache.rb +37 -0
- data/lib/oxen_deployer/core.rb +227 -0
- data/lib/oxen_deployer/maintenance.rb +25 -0
- data/lib/oxen_deployer/passenger.rb +8 -0
- data/lib/oxen_deployer/rails.rb +35 -0
- data/lib/oxen_deployer/subversion.rb +27 -0
- metadata +7 -1
data/lib/oxen_deployer.rb
CHANGED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'oxen_deployer'
|
2
|
+
|
3
|
+
namespace :oxen do
|
4
|
+
##
|
5
|
+
# Apache web server
|
6
|
+
|
7
|
+
set :web_command, "apachectl"
|
8
|
+
|
9
|
+
desc "(Re)Start the web servers"
|
10
|
+
|
11
|
+
remote_task :start_web, :roles => :web do
|
12
|
+
run "#{web_command} restart"
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "Stop the web servers"
|
16
|
+
|
17
|
+
remote_task :stop_web, :roles => :web do
|
18
|
+
run "#{web_command} stop"
|
19
|
+
end
|
20
|
+
|
21
|
+
##
|
22
|
+
# Everything HTTP.
|
23
|
+
|
24
|
+
desc "(Re)Start the web and app servers"
|
25
|
+
|
26
|
+
remote_task :start do
|
27
|
+
Rake::Task['oxen:start_app'].invoke
|
28
|
+
Rake::Task['oxen:start_web'].invoke
|
29
|
+
end
|
30
|
+
|
31
|
+
desc "Stop the web and app servers"
|
32
|
+
|
33
|
+
remote_task :stop do
|
34
|
+
Rake::Task['oxen:stop_app'].invoke
|
35
|
+
Rake::Task['oxen:stop_web'].invoke
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,227 @@
|
|
1
|
+
require 'oxen_deployer'
|
2
|
+
|
3
|
+
##
|
4
|
+
# used by update, out here so we can ensure all threads have the same value
|
5
|
+
def now
|
6
|
+
@now ||= Time.now.utc.strftime("%Y%m%d%H%M.%S")
|
7
|
+
end
|
8
|
+
|
9
|
+
namespace :oxen do
|
10
|
+
desc "Show the oxen_deployer setup. This is all the default variables for oxen_deployer
|
11
|
+
tasks.".cleanup
|
12
|
+
|
13
|
+
task :debug do
|
14
|
+
require 'yaml'
|
15
|
+
|
16
|
+
# force them into values
|
17
|
+
Rake::RemoteTask.env.keys.each do |key|
|
18
|
+
next if key =~ /_release|releases|sudo_password/
|
19
|
+
Rake::RemoteTask.fetch key
|
20
|
+
end
|
21
|
+
|
22
|
+
puts "# Environment:"
|
23
|
+
puts
|
24
|
+
puts Rake::RemoteTask.env.to_yaml
|
25
|
+
puts "# Roles:"
|
26
|
+
puts Rake::RemoteTask.roles.to_yaml
|
27
|
+
end
|
28
|
+
|
29
|
+
append :ancillary_dir
|
30
|
+
|
31
|
+
desc "Setup your servers. Before you can use any of the deployment
|
32
|
+
tasks with your project, you will need to make sure all of your
|
33
|
+
servers have been prepared with 'rake oxen:setup'. It is safe to
|
34
|
+
run this task on servers that have already been set up; it will
|
35
|
+
not destroy any deployed revisions or data.".cleanup
|
36
|
+
|
37
|
+
task :setup do
|
38
|
+
Rake::Task['oxen:setup_app'].invoke
|
39
|
+
end
|
40
|
+
|
41
|
+
desc "Prepares application servers for deployment.".cleanup
|
42
|
+
|
43
|
+
remote_task :setup_app, :roles => :app do
|
44
|
+
dirs = [deploy_to, releases_path, shared_path]
|
45
|
+
dirs << scm_path unless skip_scm
|
46
|
+
dirs += shared_paths.keys.map { |d| File.join(shared_path, d) }
|
47
|
+
dirs += ancillary_dir
|
48
|
+
dirs = dirs.join(' ')
|
49
|
+
|
50
|
+
commands = []
|
51
|
+
|
52
|
+
commands << "umask #{umask}" if umask
|
53
|
+
commands << "mkdir -p #{dirs}"
|
54
|
+
|
55
|
+
commands << "chown #{perm_owner} #{dirs}" if perm_owner
|
56
|
+
commands << "chgrp #{perm_group} #{dirs}" if perm_group
|
57
|
+
|
58
|
+
run commands.join(' && ')
|
59
|
+
end
|
60
|
+
|
61
|
+
desc "Updates your application server to the latest revision. Syncs
|
62
|
+
a copy of the repository, exports it as the latest release, fixes
|
63
|
+
up your symlinks, symlinks the latest revision to current and logs
|
64
|
+
the update.".cleanup
|
65
|
+
|
66
|
+
remote_task :update, :roles => :app do
|
67
|
+
Rake::Task['oxen:update_app'].invoke
|
68
|
+
Rake::Task['oxen:update_symlinks'].invoke
|
69
|
+
Rake::Task['oxen:log_revision'].invoke
|
70
|
+
end
|
71
|
+
|
72
|
+
desc "Updates your application server to the latest revision. Syncs
|
73
|
+
a copy of the repository, exports it as the latest release".cleanup
|
74
|
+
|
75
|
+
remote_task :update_app, :roles => :app do
|
76
|
+
begin
|
77
|
+
commands = []
|
78
|
+
commands << "umask #{umask}" if umask
|
79
|
+
unless skip_scm
|
80
|
+
commands << "cd #{scm_path}"
|
81
|
+
commands << "#{source.checkout revision, scm_path}"
|
82
|
+
end
|
83
|
+
commands << "#{source.export revision, release_path}"
|
84
|
+
|
85
|
+
unless shared_paths.empty?
|
86
|
+
commands << "rm -rf #{shared_paths.values.map { |p| File.join(latest_release, p) }.join(' ')}"
|
87
|
+
end
|
88
|
+
unless mkdirs.empty?
|
89
|
+
dirs = mkdirs.map { |d| File.join(latest_release, d) }.join(' ')
|
90
|
+
commands << "mkdir -p #{dirs}"
|
91
|
+
commands << "chown -R #{perm_owner} #{dirs}" if perm_owner
|
92
|
+
commands << "chgrp -R #{perm_group} #{dirs}" if perm_group
|
93
|
+
end
|
94
|
+
|
95
|
+
commands << "chown -R #{perm_owner} #{latest_release}" if perm_owner
|
96
|
+
commands << "chgrp -R #{perm_group} #{latest_release}" if perm_group
|
97
|
+
|
98
|
+
run commands.join(" && ")
|
99
|
+
rescue => e
|
100
|
+
run "rm -rf #{release_path}"
|
101
|
+
raise e
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
desc "Updates up your symlinks, sets the latest revision to current and updates symlink for shared path".cleanup
|
106
|
+
|
107
|
+
remote_task :update_symlinks, :roles => :app do
|
108
|
+
begin
|
109
|
+
ops = []
|
110
|
+
unless shared_paths.empty?
|
111
|
+
shared_paths.each do |sp, rp|
|
112
|
+
ops << "ln -s #{shared_path}/#{sp} #{latest_release}/#{rp}"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
ops << "rm -f #{current_path}"
|
116
|
+
ops << "ln -s #{latest_release} #{current_path}"
|
117
|
+
run ops.join(' && ') unless ops.empty?
|
118
|
+
rescue => e
|
119
|
+
run "rm -f #{current_path} && ln -s #{previous_release} #{current_path}"
|
120
|
+
run "rm -rf #{release_path}"
|
121
|
+
raise e
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
desc "Log the update".cleanup
|
126
|
+
|
127
|
+
remote_task :log_revision, :roles => :app do
|
128
|
+
begin
|
129
|
+
commands = []
|
130
|
+
|
131
|
+
commands << "umask #{umask}" if umask
|
132
|
+
|
133
|
+
commands += [
|
134
|
+
"echo #{now} $USER #{revision} #{File.basename(release_path)} >> #{deploy_to}/revisions.log"
|
135
|
+
]
|
136
|
+
|
137
|
+
commands << "chown #{perm_owner} #{deploy_to}/revisions.log" if perm_owner
|
138
|
+
commands << "chgrp #{perm_group} #{deploy_to}/revisions.log" if perm_group
|
139
|
+
|
140
|
+
run commands.join(' && ')
|
141
|
+
rescue => e
|
142
|
+
run "rm -f #{current_path} && ln -s #{previous_release} #{current_path}"
|
143
|
+
run "rm -rf #{release_path}"
|
144
|
+
raise e
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
desc "Invoke a single command on every remote server. This is useful for
|
150
|
+
performing one-off commands that may not require a full task to be written
|
151
|
+
for them. Simply specify the command to execute via the COMMAND
|
152
|
+
environment variable. To execute the command only on certain roles,
|
153
|
+
specify the ROLES environment variable as a comma-delimited list of role
|
154
|
+
names.
|
155
|
+
|
156
|
+
$ rake oxen:invoke COMMAND='uptime'".cleanup
|
157
|
+
|
158
|
+
remote_task :invoke do
|
159
|
+
command = ENV["COMMAND"]
|
160
|
+
abort "Please specify a command to execute on the remote servers (via the COMMAND environment variable)" unless command
|
161
|
+
run(command)
|
162
|
+
end
|
163
|
+
|
164
|
+
desc "Copy arbitrary files to the currently deployed version using
|
165
|
+
FILES=a,b,c. This is useful for updating files piecemeal when you
|
166
|
+
need to quickly deploy only a single file.
|
167
|
+
|
168
|
+
To use this task, specify the files and directories you want to copy as a
|
169
|
+
comma-delimited list in the FILES environment variable. All directories
|
170
|
+
will be processed recursively, with all files being pushed to the
|
171
|
+
deployment servers. Any file or directory starting with a '.' character
|
172
|
+
will be ignored.
|
173
|
+
|
174
|
+
$ rake oxen:upload FILES=templates,controller.rb".cleanup
|
175
|
+
|
176
|
+
remote_task :upload do
|
177
|
+
file_list = (ENV["FILES"] || "").split(",")
|
178
|
+
|
179
|
+
files = file_list.map do |f|
|
180
|
+
f = f.strip
|
181
|
+
File.directory?(f) ? Dir["#{f}/**/*"] : f
|
182
|
+
end.flatten
|
183
|
+
|
184
|
+
files = files.reject { |f| File.directory?(f) || File.basename(f)[0] == ?. }
|
185
|
+
|
186
|
+
abort "Please specify at least one file to update (via the FILES environment variable)" if files.empty?
|
187
|
+
|
188
|
+
files.each do |file|
|
189
|
+
rsync file, File.join(current_path, file)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
desc "Rolls back to a previous version and restarts. This is handy if you
|
194
|
+
ever discover that you've deployed a lemon; 'rake oxen:rollback' and
|
195
|
+
you're right back where you were, on the previously deployed
|
196
|
+
version.".cleanup
|
197
|
+
|
198
|
+
remote_task :rollback, :roles => :app do
|
199
|
+
if releases.length < 2 then
|
200
|
+
abort "could not rollback the code because there is no prior release"
|
201
|
+
else
|
202
|
+
run "rm -f #{current_path}; ln -s #{previous_release} #{current_path} && rm -rf #{current_release}"
|
203
|
+
end
|
204
|
+
|
205
|
+
Rake::Task['oxen:start'].invoke
|
206
|
+
end
|
207
|
+
|
208
|
+
desc "Clean up old releases. By default, the last 5 releases are kept on
|
209
|
+
each server (though you can change this with the keep_releases variable).
|
210
|
+
All other deployed revisions are removed from the servers.".cleanup
|
211
|
+
|
212
|
+
remote_task :cleanup, :roles => :app do
|
213
|
+
max = keep_releases
|
214
|
+
if releases.length <= max then
|
215
|
+
puts "no old releases to clean up #{releases.length} <= #{max}"
|
216
|
+
else
|
217
|
+
puts "keeping #{max} of #{releases.length} deployed releases"
|
218
|
+
|
219
|
+
directories = (releases - releases.last(max)).map { |release|
|
220
|
+
File.join(releases_path, release)
|
221
|
+
}.join(" ")
|
222
|
+
|
223
|
+
run "rm -rf #{directories}"
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
end # namespace vlad
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'oxen_deployer'
|
2
|
+
|
3
|
+
##
|
4
|
+
# See the following documents for recipes:
|
5
|
+
#
|
6
|
+
# * http://clarkware.com/blog/2007/1/5/custom-maintenance-pages
|
7
|
+
# * http://blog.nodeta.fi/2009/03/11/stopping-your-rails-application-with-phusion-passenger/
|
8
|
+
#
|
9
|
+
|
10
|
+
namespace :oxen do
|
11
|
+
namespace :maintenance do
|
12
|
+
|
13
|
+
desc "Turn on the maintenance web page"
|
14
|
+
|
15
|
+
remote_task :on, :roles => [:web] do
|
16
|
+
run "cp -f #{shared_path}/config/maintenance.html #{shared_path}/system/"
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "Turn off the maintenance web page"
|
20
|
+
|
21
|
+
remote_task :off, :roles => [:web] do
|
22
|
+
run "rm -f #{shared_path}/system/maintenance.html"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
namespace :oxen do
|
2
|
+
set :rails_env, "production"
|
3
|
+
set :rails_env_var, "RAILS_ENV"
|
4
|
+
set :migrate_args, ""
|
5
|
+
set :migrate_target, :latest
|
6
|
+
set :mkdirs, %w(tmp db)
|
7
|
+
set :shared_paths, {
|
8
|
+
'log' => 'log',
|
9
|
+
'system' => 'public/system',
|
10
|
+
'pids' => 'tmp/pids',
|
11
|
+
}
|
12
|
+
|
13
|
+
desc "Run the migrate rake task for the the app. By default this is run in
|
14
|
+
the latest app directory. You can run migrations for the current app
|
15
|
+
directory by setting :migrate_target to :current. Additional environment
|
16
|
+
variables can be passed to rake via the migrate_args variable.".cleanup
|
17
|
+
|
18
|
+
# No application files are on the DB machine, also migrations should only be
|
19
|
+
# run once.
|
20
|
+
remote_task :migrate, :roles => :app do
|
21
|
+
next unless target_host == Rake::RemoteTask.hosts_for(:app).first
|
22
|
+
|
23
|
+
directory = case migrate_target.to_sym
|
24
|
+
when :current then current_path
|
25
|
+
when :latest then latest_release
|
26
|
+
else
|
27
|
+
raise(ArgumentError,
|
28
|
+
"unknown migration target #{migrate_target.inspect}")
|
29
|
+
end
|
30
|
+
|
31
|
+
run ["cd #{directory}",
|
32
|
+
"#{rake_cmd} #{rails_env_var}=#{rails_env} db:migrate #{migrate_args}"
|
33
|
+
].join(" && ")
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class OxenDeployer::Subversion
|
2
|
+
|
3
|
+
set :source, OxenDeployer::Subversion.new
|
4
|
+
set :svn_cmd, "svn"
|
5
|
+
set :revision, "HEAD"
|
6
|
+
|
7
|
+
##
|
8
|
+
# Returns the command that will check out +revision+ from the repository
|
9
|
+
# into directory +destination+
|
10
|
+
|
11
|
+
def checkout(revision, destination)
|
12
|
+
"#{svn_cmd} co -r #{revision} #{repository} #{destination}"
|
13
|
+
end
|
14
|
+
|
15
|
+
##
|
16
|
+
# Returns the command that will export +revision+ from the repository into
|
17
|
+
# the directory +destination+.
|
18
|
+
|
19
|
+
def export(revision_or_source, destination)
|
20
|
+
"#{svn_cmd} #{deploy_via} " +
|
21
|
+
if revision_or_source =~ /^(\d+|head)$/i then
|
22
|
+
"-r #{revision_or_source} #{repository} #{destination}"
|
23
|
+
else
|
24
|
+
"#{revision_or_source} #{destination}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oxen_deployer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -21,6 +21,12 @@ extensions: []
|
|
21
21
|
extra_rdoc_files: []
|
22
22
|
files:
|
23
23
|
- lib/oxen_deployer.rb
|
24
|
+
- lib/oxen_deployer/apache.rb
|
25
|
+
- lib/oxen_deployer/core.rb
|
26
|
+
- lib/oxen_deployer/maintenance.rb
|
27
|
+
- lib/oxen_deployer/passenger.rb
|
28
|
+
- lib/oxen_deployer/rails.rb
|
29
|
+
- lib/oxen_deployer/subversion.rb
|
24
30
|
homepage: https://github.com/wdiechmann/oxen_deployer
|
25
31
|
licenses: []
|
26
32
|
post_install_message:
|