ms_deploy 0.2.3 → 0.2.4
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/examples/deploy.rb +0 -4
- data/lib/ms_deploy/recipes/assets.rb +20 -12
- data/lib/ms_deploy/recipes/database.rb +44 -0
- data/lib/ms_deploy/recipes/defaults.rb +5 -1
- data/lib/ms_deploy/recipes/nginx.rb +57 -59
- data/lib/ms_deploy/recipes/unicorn.rb +26 -18
- data/lib/ms_deploy/templates/unicorn/unicorn.rb.erb +34 -0
- data/lib/ms_deploy/templates/vhost.erb +1 -1
- data/lib/ms_deploy/version.rb +1 -1
- data/lib/mysql.rb +109 -0
- data/lib/util.rb +10 -0
- metadata +6 -2
data/lib/examples/deploy.rb
CHANGED
@@ -1,18 +1,26 @@
|
|
1
1
|
Capistrano::Configuration.instance.load do
|
2
2
|
|
3
|
-
load 'deploy/assets' # http://guides.rubyonrails.org/asset_pipeline.html#in-production
|
3
|
+
load 'deploy/assets' unless ENV['NOASSETS'] # http://guides.rubyonrails.org/asset_pipeline.html#in-production
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
5
|
+
set :assets_dir, 'system' unless exists?(:assets_dir)
|
6
|
+
set :local_assets_dir, 'public' unless exists?(:local_assets_dir)
|
7
|
+
|
8
|
+
namespace :assets do
|
9
|
+
namespace :local do
|
10
|
+
desc 'Synchronize your local assets using remote assets'
|
11
|
+
task :sync do
|
12
|
+
if Util.prompt "Are you sure you want to erase your local assets with server assets"
|
13
|
+
servers = find_servers :roles => :app
|
14
|
+
[assets_dir].flatten.each do |dir|
|
15
|
+
system("rsync -a --del --progress --rsh='ssh -p #{fetch(:ssh_port, 22)}' #{user}@#{servers.first}:#{shared_path}/#{dir}/ #{local_assets_dir}")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'Synchronize your local assets using remote assets'
|
22
|
+
task :pull do
|
23
|
+
assets.local.sync
|
16
24
|
end
|
17
25
|
end
|
18
26
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
Capistrano::Configuration.instance.load do |instance|
|
2
|
+
|
3
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../../util")
|
4
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../../mysql")
|
5
|
+
|
6
|
+
instance.set :local_rails_env, ENV['RAILS_ENV'] || 'development' unless exists?(:local_rails_env)
|
7
|
+
instance.set :db_local_clean, false unless exists?(:db_local_clean)
|
8
|
+
|
9
|
+
namespace :db do
|
10
|
+
namespace :remote do
|
11
|
+
desc 'Synchronize the local database to the remote database'
|
12
|
+
task :sync, :roles => :db do
|
13
|
+
if if Util.prompt 'Are you sure you want to REPLACE THE REMOTE DATABASE with local database'
|
14
|
+
Database.local_to_remote(instance)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
namespace :local do
|
20
|
+
desc 'Synchronize your local database using remote database data'
|
21
|
+
task :sync, :roles => :db do
|
22
|
+
puts "Local database: #{Database::Local.new(instance).database}"
|
23
|
+
if rails_env == 'production'
|
24
|
+
puts 'Never sync remote production database!'
|
25
|
+
else
|
26
|
+
if Util.prompt 'Are you sure you want to erase your local database with server database'
|
27
|
+
Database.remote_to_local(instance)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
desc 'Synchronize your local database using remote database data'
|
34
|
+
task :pull do
|
35
|
+
db.local.sync
|
36
|
+
end
|
37
|
+
|
38
|
+
desc 'Synchronize the local database to the remote database'
|
39
|
+
task :push do
|
40
|
+
db.remote.sync
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
Capistrano::Configuration.instance.load do
|
2
2
|
|
3
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../../util")
|
4
|
+
|
3
5
|
set :keep_releases, 10
|
4
6
|
set :use_sudo, false
|
5
7
|
|
@@ -20,8 +22,10 @@ Capistrano::Configuration.instance.load do
|
|
20
22
|
|
21
23
|
default_run_options[:pty] = true
|
22
24
|
|
25
|
+
# if you want to remove the dump file after loading
|
26
|
+
set :db_local_clean, true
|
27
|
+
|
23
28
|
task :test_and_prepare_cap_env do
|
24
|
-
abort "You must run this using 'bundle exec ...'" unless ENV['BUNDLE_BIN_PATH'] || ENV['BUNDLE_GEMFILE']
|
25
29
|
abort "You must set :user before using defaults" unless fetch(:user, nil)
|
26
30
|
abort "You must set :repository before using defaults" unless fetch(:repository, nil)
|
27
31
|
abort "You must set :branch before using defaults" unless fetch(:branch, nil)
|
@@ -2,81 +2,79 @@ require "ms_deploy/render"
|
|
2
2
|
|
3
3
|
Capistrano::Configuration.instance.load do
|
4
4
|
|
5
|
-
namespace :
|
6
|
-
|
7
|
-
desc <<-DESC
|
5
|
+
namespace :nginx do
|
6
|
+
desc <<-DESC
|
8
7
|
Starts the nginx web-server.
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
8
|
+
DESC
|
9
|
+
task :start do
|
10
|
+
#run "sudo god start nginx"
|
11
|
+
run "sudo /etc/init.d/nginx start"
|
12
|
+
end
|
14
13
|
|
15
|
-
|
14
|
+
desc <<-DESC
|
16
15
|
#Stops the nginx web-server.
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
16
|
+
DESC
|
17
|
+
task :stop do
|
18
|
+
#run "sudo god stop nginx"
|
19
|
+
run "sudo /etc/init.d/nginx stop"
|
20
|
+
end
|
22
21
|
|
23
|
-
|
22
|
+
desc <<-DESC
|
24
23
|
Restarts the nginx web-server.
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
24
|
+
DESC
|
25
|
+
task :restart do
|
26
|
+
#run "sudo god restart nginx"
|
27
|
+
run "sudo /etc/init.d/nginx restart"
|
28
|
+
end
|
30
29
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
30
|
+
task :setup do
|
31
|
+
protocol = fetch(:protocol, nil).to_s
|
32
|
+
template_path = File.expand_path('../../templates/vhost.erb', __FILE__)
|
33
|
+
vars = {
|
34
|
+
'application' => application,
|
35
|
+
'project_root' => deploy_to + '/current',
|
36
|
+
'domain' => vhost_domain, 'stage' => stage,
|
37
|
+
'auth_basic_title' => fetch(:auth_basic_title, nil),
|
38
|
+
'auth_basic_password_file' => fetch(:auth_basic_password_file, nil),
|
39
|
+
'protocol' => 'http',
|
40
|
+
'nginx_cert_dir' => fetch(:nginx_cert_dir, '/etc/nginx/cert'),
|
41
|
+
'with_upstream_server' => true,
|
42
|
+
'with_file_expire_max' => fetch(:with_file_expire_max, true),
|
43
|
+
'optional_http_content' => fetch(:optional_nginx_server_http_content, ''),
|
44
|
+
'optional_https_content' => fetch(:optional_nginx_server_https_content, ''),
|
45
|
+
'cert_type' => fetch(:cert_type, 'pem'),
|
46
|
+
'key_type' => fetch(:cert_type, 'key')
|
47
|
+
}
|
49
48
|
|
50
|
-
|
51
|
-
|
49
|
+
if protocol.nil? or protocol == 'http' or protocol == 'both'
|
50
|
+
config_path = "#{shared_path}/config/#{application}_vhost.conf"
|
52
51
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
52
|
+
put(render_erb_template(template_path, vars), config_path)
|
53
|
+
sudo "rm -f /etc/nginx/sites-enabled/#{application}_#{stage}.conf"
|
54
|
+
sudo "ln -s #{config_path} /etc/nginx/sites-enabled/#{application}_#{stage}.conf"
|
55
|
+
end
|
56
|
+
if protocol == 'https' or protocol == 'both'
|
57
|
+
vars.merge!({'protocol' => 'https'})
|
59
58
|
|
60
|
-
|
59
|
+
config_path = "#{shared_path}/config/#{application}_ssl_vhost.conf"
|
61
60
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
end
|
61
|
+
put(render_erb_template(template_path, vars), config_path)
|
62
|
+
sudo "rm -f /etc/nginx/sites-enabled/#{application}_#{stage}_ssl.conf"
|
63
|
+
sudo "ln -s #{config_path} /etc/nginx/sites-enabled/#{application}_#{stage}_ssl.conf"
|
66
64
|
end
|
65
|
+
end
|
67
66
|
|
68
|
-
|
69
|
-
|
67
|
+
task :uninstall do
|
68
|
+
protocol = fetch(:protocol, nil)
|
70
69
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
end
|
70
|
+
if protocol.blank? or protocol == 'http' or protocol == 'both'
|
71
|
+
sudo "rm -f /etc/nginx/sites-enabled/#{application}_#{stage}.conf"
|
72
|
+
elsif protocol == 'https' or protocol == 'both'
|
73
|
+
sudo "rm -f /etc/nginx/sites-enabled/#{application}_#{stage}_ssl.conf"
|
76
74
|
end
|
77
75
|
end
|
78
76
|
end
|
79
77
|
|
80
|
-
after :"deploy:setup", :"
|
78
|
+
after :"deploy:setup", :"nginx:setup";
|
81
79
|
|
82
80
|
end
|
@@ -1,25 +1,33 @@
|
|
1
1
|
Capistrano::Configuration.instance.load do
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
_cset :unicorn_bin, "bundle exec unicorn"
|
4
|
+
_cset :unicorn_pid, "#{deploy_to}/current/tmp/pids/unicorn.pid"
|
5
|
+
_cset :unicorn_std_log, "log/unicorn.stderr.log"
|
6
|
+
_cset :unicorn_err_log, "log/unicorn.stderr.log"
|
7
|
+
_cset :unicorn_worker_processes, 2
|
8
|
+
_cset :unicorn_listen_backlog, 2048
|
6
9
|
|
7
|
-
|
8
|
-
desc "Zero-downtime restart of Unicorn"
|
9
|
-
task :restart, :except => { :no_release => true } do
|
10
|
-
stop
|
11
|
-
start
|
12
|
-
end
|
13
|
-
|
14
|
-
desc "Start unicorn"
|
15
|
-
task :start, :except => { :no_release => true } do
|
16
|
-
set :unicorn_config, "config/unicorn.#{fetch(:stage, 'production')}.rb"
|
17
|
-
run "cd #{current_path} && #{try_sudo} #{unicorn_bin} -c #{current_path}/#{unicorn_config} -E #{rails_env} -D"
|
18
|
-
end
|
10
|
+
require "capistrano-unicorn"
|
19
11
|
|
20
|
-
|
21
|
-
|
22
|
-
|
12
|
+
namespace :unicorn do
|
13
|
+
desc "Setup unicorn"
|
14
|
+
task :setup, :except => { :no_release => true } do
|
15
|
+
run "mkdir -p \"#{shared_path}/config/unicorn\""
|
16
|
+
config_path = "#{shared_path}/config/unicorn/#{stage}.rb"
|
17
|
+
template_path = File.expand_path('../../templates/unicorn/unicorn.rb.erb', __FILE__)
|
18
|
+
vars = {
|
19
|
+
'application'=> application,
|
20
|
+
'current_path' => current_path,
|
21
|
+
'unicorn_pid' => unicorn_pid,
|
22
|
+
'unicorn_std_log' => unicorn_std_log,
|
23
|
+
'unicorn_err_log' => unicorn_err_log,
|
24
|
+
'stage' => stage,
|
25
|
+
'unicorn_listen_backlog' => unicorn_listen_backlog,
|
26
|
+
'unicorn_worker_processes' => unicorn_worker_processes
|
27
|
+
}
|
28
|
+
put(render_erb_template(template_path, vars), config_path)
|
23
29
|
end
|
24
30
|
end
|
31
|
+
|
32
|
+
after :"deploy:setup", :"unicorn:setup";
|
25
33
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
working_directory "<%= current_path %>"
|
2
|
+
pid "<%= unicorn_pid %>"
|
3
|
+
stderr_path "<%= unicorn_std_log %>"
|
4
|
+
stdout_path "<%= unicorn_err_log %>"
|
5
|
+
|
6
|
+
listen "/tmp/socket.<%= application %>_<%= stage %>.sock", :backlog => <%= unicorn_listen_backlog %>
|
7
|
+
worker_processes <%= unicorn_worker_processes %>
|
8
|
+
timeout 30
|
9
|
+
|
10
|
+
preload_app true
|
11
|
+
|
12
|
+
before_fork do |server, worker|
|
13
|
+
# Disconnect since the database connection will not carry over
|
14
|
+
if defined? ActiveRecord::Base
|
15
|
+
ActiveRecord::Base.connection.disconnect!
|
16
|
+
end
|
17
|
+
|
18
|
+
# Quit the old unicorn process
|
19
|
+
old_pid = "#{server.config[:pid]}.oldbin"
|
20
|
+
if File.exists?(old_pid) && server.pid != old_pid
|
21
|
+
begin
|
22
|
+
Process.kill("QUIT", File.read(old_pid).to_i)
|
23
|
+
rescue Errno::ENOENT, Errno::ESRCH
|
24
|
+
# someone else did our job for us
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
after_fork do |server, worker|
|
30
|
+
# Start up the database connection again in the worker
|
31
|
+
if defined?(ActiveRecord::Base)
|
32
|
+
ActiveRecord::Base.establish_connection
|
33
|
+
end
|
34
|
+
end
|
@@ -7,7 +7,7 @@ upstream <%= application %>_<%= stage %>_<%= protocol %>_server {
|
|
7
7
|
# single worker for timing out).
|
8
8
|
|
9
9
|
# This is the socket we configured in unicorn.rb
|
10
|
-
server unix:/tmp/
|
10
|
+
server unix:/tmp/socket.<%= application %>_<%= stage %>.sock fail_timeout=0;
|
11
11
|
|
12
12
|
# for TCP setups, point these to your backend servers
|
13
13
|
# server 127.0.0.1:8080 fail_timeout=0;
|
data/lib/ms_deploy/version.rb
CHANGED
data/lib/mysql.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
module Database
|
2
|
+
class Base
|
3
|
+
attr_accessor :config, :output_file
|
4
|
+
def initialize(cap_instance)
|
5
|
+
@cap = cap_instance
|
6
|
+
end
|
7
|
+
|
8
|
+
def mysql?
|
9
|
+
@config['adapter'] == 'mysql' || @config['adapter'] == 'mysql2'
|
10
|
+
end
|
11
|
+
|
12
|
+
def credentials
|
13
|
+
" -u #{@config['username']} " + (@config['password'] ? " -p\"#{@config['password']}\" " : '') + (@config['host'] ? " -h #{@config['host']}" : '')
|
14
|
+
end
|
15
|
+
|
16
|
+
def database
|
17
|
+
@config['database']
|
18
|
+
end
|
19
|
+
|
20
|
+
def output_file
|
21
|
+
@output_file ||= "db/dump_#{database}.sql.bz2"
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def dump_cmd
|
26
|
+
"mysqldump #{credentials} #{database}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def import_cmd(file)
|
30
|
+
"mysql #{credentials} -D #{database} < #{file}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Remote < Base
|
35
|
+
def initialize(cap_instance)
|
36
|
+
super(cap_instance)
|
37
|
+
@cap.run("cat #{@cap.current_path}/config/database.yml") { |c, s, d| @config = YAML.load(d)[(@cap.rails_env || 'production').to_s] }
|
38
|
+
end
|
39
|
+
|
40
|
+
def dump
|
41
|
+
@cap.run "cd #{@cap.current_path}; #{dump_cmd} | bzip2 - - > #{output_file}"
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
def download(local_file = "#{output_file}")
|
46
|
+
remote_file = "#{@cap.current_path}/#{output_file}"
|
47
|
+
@cap.get remote_file, local_file
|
48
|
+
end
|
49
|
+
|
50
|
+
# cleanup = true removes the mysqldump file after loading, false leaves it in db/
|
51
|
+
def load(file, cleanup)
|
52
|
+
unzip_file = File.join(File.dirname(file), File.basename(file, '.bz2'))
|
53
|
+
@cap.run "cd #{@cap.current_path}; bunzip2 -f #{file} && RAILS_ENV=#{@cap.rails_env} rake db:drop db:create && #{import_cmd(unzip_file)}"
|
54
|
+
File.unlink(unzip_file) if cleanup
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class Local < Base
|
59
|
+
def initialize(cap_instance)
|
60
|
+
super(cap_instance)
|
61
|
+
@config = YAML.load_file(File.join('config', 'database.yml'))[@cap.local_rails_env]
|
62
|
+
end
|
63
|
+
|
64
|
+
# cleanup = true removes the mysqldump file after loading, false leaves it in db/
|
65
|
+
def load(file, cleanup)
|
66
|
+
unzip_file = File.join(File.dirname(file), File.basename(file, '.bz2'))
|
67
|
+
system("bunzip2 -f #{file} && rake db:drop db:create && #{import_cmd(unzip_file)} && rake db:migrate")
|
68
|
+
File.unlink(unzip_file) if cleanup
|
69
|
+
end
|
70
|
+
|
71
|
+
def dump
|
72
|
+
system "#{dump_cmd} | bzip2 - - > #{output_file}"
|
73
|
+
self
|
74
|
+
end
|
75
|
+
|
76
|
+
def upload
|
77
|
+
remote_file = "#{@cap.current_path}/#{output_file}"
|
78
|
+
@cap.upload output_file, remote_file
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class << self
|
83
|
+
def check(local_db, remote_db)
|
84
|
+
unless local_db.mysql? && remote_db.mysql?
|
85
|
+
raise 'Only mysql on remote and local server is supported'
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def remote_to_local(instance)
|
90
|
+
local_db = Database::Local.new(instance)
|
91
|
+
remote_db = Database::Remote.new(instance)
|
92
|
+
|
93
|
+
check(local_db, remote_db)
|
94
|
+
|
95
|
+
remote_db.dump.download
|
96
|
+
local_db.load(remote_db.output_file, instance.fetch(:db_local_clean))
|
97
|
+
end
|
98
|
+
|
99
|
+
def local_to_remote(instance)
|
100
|
+
local_db = Database::Local.new(instance)
|
101
|
+
remote_db = Database::Remote.new(instance)
|
102
|
+
|
103
|
+
check(local_db, remote_db)
|
104
|
+
|
105
|
+
local_db.dump.upload
|
106
|
+
remote_db.load(local_db.output_file, instance.fetch(:db_local_clean))
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
data/lib/util.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
module Util
|
2
|
+
def self.prompt(msg, prompt = "(y)es, (n)o ")
|
3
|
+
answer = Capistrano::CLI.ui.ask("#{msg} #{prompt} ? ") do |q|
|
4
|
+
q.overwrite = false
|
5
|
+
q.validate = /^y$|^yes$|^n$|^no$/i
|
6
|
+
q.responses[:not_valid] = prompt
|
7
|
+
end
|
8
|
+
(answer =~ /^y$|^yes$/i) == 0
|
9
|
+
end
|
10
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ms_deploy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-08-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: gemcutter
|
@@ -171,6 +171,7 @@ files:
|
|
171
171
|
- lib/ms_deploy/recipes/airbrake.rb
|
172
172
|
- lib/ms_deploy/recipes/assets.rb
|
173
173
|
- lib/ms_deploy/recipes/bundler.rb
|
174
|
+
- lib/ms_deploy/recipes/database.rb
|
174
175
|
- lib/ms_deploy/recipes/defaults.rb
|
175
176
|
- lib/ms_deploy/recipes/info.rb
|
176
177
|
- lib/ms_deploy/recipes/monitoring.rb
|
@@ -187,8 +188,11 @@ files:
|
|
187
188
|
- lib/ms_deploy/recipes/unicorn.rb
|
188
189
|
- lib/ms_deploy/recipes/whenever.rb
|
189
190
|
- lib/ms_deploy/render.rb
|
191
|
+
- lib/ms_deploy/templates/unicorn/unicorn.rb.erb
|
190
192
|
- lib/ms_deploy/templates/vhost.erb
|
191
193
|
- lib/ms_deploy/version.rb
|
194
|
+
- lib/mysql.rb
|
195
|
+
- lib/util.rb
|
192
196
|
- ms_deploy.gemspec
|
193
197
|
homepage: https://github.com/mschiller/ms_deploy
|
194
198
|
licenses: []
|