railscluster 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +52 -0
- data/Rakefile +14 -0
- data/lib/railscluster.rb +5 -0
- data/lib/railscluster/capistrano.rb +133 -0
- data/lib/railscluster/capistrano/backup.rb +163 -0
- data/lib/railscluster/capistrano/bundler.rb +15 -0
- data/lib/railscluster/capistrano/capistrano_extensions.rb +38 -0
- data/lib/railscluster/capistrano/changed.rb +11 -0
- data/lib/railscluster/capistrano/console.rb +40 -0
- data/lib/railscluster/capistrano/git.rb +23 -0
- data/lib/railscluster/capistrano/sidekiq.rb +21 -0
- data/lib/railscluster/capistrano/sphinx.rb +39 -0
- data/lib/railscluster/capistrano/whenever.rb +6 -0
- data/lib/railscluster/version.rb +3 -0
- data/railscluster.gemspec +25 -0
- metadata +131 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7605c3aa24bdffec8aac7565989583a7295e49ee
|
4
|
+
data.tar.gz: 2878d1423ebd23273062b9fba9b6456df4b3c3fe
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5201d9bf771ba519db7fe9ee33c6fac73c809b131c692a21127e4f2b4f1eedae6eaca4b1d5730ccf5de164770ed55318b09ca306ab797f0d10f5183d331e3859
|
7
|
+
data.tar.gz: 146c0721a034a354e65f656305572bd341bf2d1b6ce74bdd270263da3f79f61d364da700040c644d36aadb46238034da2d32b505b83d0cc917774a7bde2f5576
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Arthur Holstvoogd
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# Railscluster Deployment
|
2
|
+
|
3
|
+
This Gem enables quick deployment to railscluster.nl hosting. We make some assumptions about your setup, these can be overwritten in your deploy.rb. See section settings below for details.
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
1. Add the gem to you Gemfile:
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
gem 'railscluster', git: 'https://github.com/nedforce/railscluster'
|
10
|
+
```
|
11
|
+
|
12
|
+
2. Setup Capistrano with `bundle exec capify .`
|
13
|
+
3. Replace the content of your deploy.rb with the following:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
# Keep after settings
|
17
|
+
require 'railscluster/capistrano'
|
18
|
+
```
|
19
|
+
4. Customize any settings. See sections below.
|
20
|
+
|
21
|
+
5. Setup the environment: `cap deploy:setup`
|
22
|
+
|
23
|
+
6. Deploy: cap deploy
|
24
|
+
|
25
|
+
That should be all!
|
26
|
+
|
27
|
+
## Settings
|
28
|
+
To deploy to RailsCluster only three settings need to be provided, these can be set in your deploy.rb as follows or be provided via prompt during deployment. Settings these settings need to be kept *before* the require.
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
set :account, 'account_name'
|
32
|
+
set :repository, 'https://github.com/your/application.git'
|
33
|
+
set :branch, 'master'
|
34
|
+
```
|
35
|
+
|
36
|
+
Further settings have defaults that should be fine in most cases, however you can override/set them as needed. The most important settings you can use:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
:hard_restart # Restart by stop-start, defaults to true. Set to false to use a one-by-one restart.
|
40
|
+
|
41
|
+
:app_shared_children # Add folder and files to be symlinked into shared beyond the following defauts: tmp/pids, config/database.yml, public/uploads and private/uploads
|
42
|
+
|
43
|
+
:dbtype # Postgresql or Mysql, defaults to postgresql.
|
44
|
+
|
45
|
+
:scm # Version control used, defaults to git.
|
46
|
+
|
47
|
+
:local_precompile # Precompile locally, defaults to false.
|
48
|
+
|
49
|
+
:airbrake_enabled # Load airbreak capistrano integration, defaults to false.
|
50
|
+
|
51
|
+
```
|
52
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
module Bundler
|
4
|
+
class GemHelper
|
5
|
+
protected
|
6
|
+
def rubygem_push(path)
|
7
|
+
Bundler.with_clean_env do
|
8
|
+
out, status = sh("gem inabox #{path}")
|
9
|
+
raise "You should configure your Geminabox url: gem inabox -c" if out[/Enter the root url/]
|
10
|
+
Bundler.ui.confirm "Pushed #{name} #{version} to Geminabox"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/railscluster.rb
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'railscluster/capistrano/changed'
|
2
|
+
|
3
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
4
|
+
require 'railscluster/capistrano/capistrano_extensions'
|
5
|
+
require 'railscluster/capistrano/bundler' if File.exists?('Gemfile')
|
6
|
+
require 'railscluster/capistrano/sphinx' if File.exists?('config/sphinx.yml') || File.exists?('config/thinking_sphinx.yml')
|
7
|
+
require 'railscluster/capistrano/sidekiq' if File.exists?('config/sidekiq.yml') || !`cat Gemfile | grep "gem 'sidekiq'"`.empty?
|
8
|
+
require 'railscluster/capistrano/whenever' if File.exists?('config/schedule.rb')
|
9
|
+
require 'railscluster/capistrano/console'
|
10
|
+
require 'railscluster/capistrano/backup'
|
11
|
+
require 'railscluster/capistrano/git' if fetch(:scm, :git).to_s == 'git'
|
12
|
+
require 'airbrake/capistrano' if fetch(:airbrake_enabled, false)
|
13
|
+
load 'deploy/assets' if File.exists?('app/assets') && !fetch(:local_precompile, false)
|
14
|
+
|
15
|
+
# Set login & account details
|
16
|
+
server "ssh.railscluster.nl:2222", :app, :web, :db, :primary => true
|
17
|
+
set :ssh_options, { :forward_agent => true }
|
18
|
+
default_run_options[:pty] = false
|
19
|
+
|
20
|
+
set :use_sudo, false
|
21
|
+
set :deploy_to, defer { "/home/#{fetch(:account)}/web_root" }
|
22
|
+
set :account, fetch(:account, defer { Capistrano::CLI.ui.ask("Deploy to account: ") })
|
23
|
+
set :rails_env, defer { get_rails_env }
|
24
|
+
set :user, defer { fetch(:account) }
|
25
|
+
set :application, defer { fetch(:account) }
|
26
|
+
|
27
|
+
# Setup command env
|
28
|
+
set :cluster_service, "cluster_service"
|
29
|
+
set :backend, defer { get_backend }
|
30
|
+
set :pwd, Dir.pwd
|
31
|
+
set :copy_local_tar, '/usr/bin/gnutar' if File.exists?('/usr/bin/gnutar')
|
32
|
+
|
33
|
+
# Setup Git
|
34
|
+
set :scm, fetch(:scm, :git)
|
35
|
+
set :scm_auth_cache, false
|
36
|
+
set :git_shallow_clone, 1
|
37
|
+
set :repository, fetch(:repository, defer { Capistrano::CLI.ui.ask("Repository: ") })
|
38
|
+
|
39
|
+
# Deploy settings
|
40
|
+
set :deploy_via, :copy
|
41
|
+
set :copy_strategy, :export
|
42
|
+
set :copy_exclude, ['.git', 'test', 'spec', 'features', 'log', 'doc', 'design', 'backup']
|
43
|
+
set :keep_releases, 3
|
44
|
+
|
45
|
+
# Local precompile (Optional)
|
46
|
+
set :build_script, defer { "ln -nsf #{File.join(pwd, 'config', 'database.yml')} config/database.yml && RAILS_ENV=#{rails_env} #{rake} assets:precompile && rm config/database.yml" } if File.exists?('app/assets') && fetch(:local_precompile, false)
|
47
|
+
|
48
|
+
# Setup shared dirs
|
49
|
+
set :upload_dirs, %w(public/uploads private/uploads)
|
50
|
+
set :shared_children, defer { fetch(:upload_dirs) + %w(tmp/pids config/database.yml) + fetch(:app_shared_children, []) }
|
51
|
+
|
52
|
+
after 'deploy:update_code' do
|
53
|
+
deploy.migrate if changed? ['db/schema.rb', 'db/migrate']
|
54
|
+
end
|
55
|
+
|
56
|
+
after "deploy:restart", "deploy:cleanup"
|
57
|
+
after "deploy:setup", "configure:database"
|
58
|
+
|
59
|
+
namespace :deploy do
|
60
|
+
task :start, :roles => :app do
|
61
|
+
run "#{cluster_service} #{backend} start"
|
62
|
+
end
|
63
|
+
|
64
|
+
task :stop, :roles => :app do
|
65
|
+
run "#{cluster_service} #{backend} stop"
|
66
|
+
end
|
67
|
+
|
68
|
+
task :restart, :roles => :app do
|
69
|
+
if fetch(:hard_restart, true)
|
70
|
+
run "#{cluster_service} #{backend} restart"
|
71
|
+
else
|
72
|
+
onebyone
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
task :onebyone, :roles => :app do
|
77
|
+
run "touch #{current_path}/tmp/restart.txt"
|
78
|
+
end
|
79
|
+
|
80
|
+
task :setup, :except => { :no_release => true } do
|
81
|
+
dirs = [deploy_to, releases_path, shared_path, '~/etc', '~/tmp']
|
82
|
+
dirs += shared_children.map do |d|
|
83
|
+
d = d.split("/")[0..-2].join("/") if d =~ /\.yml|\.rb|\.conf/
|
84
|
+
File.join(shared_path, d)
|
85
|
+
end
|
86
|
+
run "#{try_sudo} mkdir -p #{dirs.join(' ')}"
|
87
|
+
run "#{try_sudo} chmod g+w #{dirs.join(' ')}" if fetch(:group_writable, true)
|
88
|
+
end
|
89
|
+
|
90
|
+
task :finalize_update, :except => { :no_release => true } do
|
91
|
+
escaped_release = latest_release.to_s.shellescape
|
92
|
+
commands = []
|
93
|
+
commands << "chmod -R -- g+w #{escaped_release}" if fetch(:group_writable, true)
|
94
|
+
|
95
|
+
# mkdir -p is making sure that the directories are there for some SCM's that don't
|
96
|
+
# save empty folders
|
97
|
+
shared_children.map do |child|
|
98
|
+
c = child.shellescape
|
99
|
+
commands << "rm -rf -- #{escaped_release}/#{c}"
|
100
|
+
if child =~ /\//
|
101
|
+
commands << "mkdir -p -- #{escaped_release}/#{child.slice(0..(child.rindex('/'))).shellescape}"
|
102
|
+
end
|
103
|
+
commands << "if [ -e #{shared_path}/#{child} ]; then ln -s -- #{shared_path}/#{child} #{escaped_release}/#{c}; fi"
|
104
|
+
end
|
105
|
+
|
106
|
+
run commands.join(' && ') if commands.any?
|
107
|
+
|
108
|
+
if fetch(:normalize_asset_timestamps, false)
|
109
|
+
stamp = Time.now.utc.strftime("%Y%m%d%H%M.%S")
|
110
|
+
asset_paths = fetch(:public_children, %w(images stylesheets javascripts)).map { |p| "#{escaped_release}/public/#{p}" }
|
111
|
+
run("find #{asset_paths.join(" ")} -exec touch -t #{stamp} -- {} ';'; true",
|
112
|
+
:env => { "TZ" => "UTC" }) if asset_paths.any?
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
namespace :configure do
|
118
|
+
task :database do
|
119
|
+
set(:dbpassword) { Capistrano::CLI.ui.ask("Database password: ") }
|
120
|
+
if !dbpassword.empty?
|
121
|
+
database_yml = <<-EOF
|
122
|
+
#{rails_env}:
|
123
|
+
adapter: #{fetch(:dbtype, 'postgresql')}
|
124
|
+
host: #{fetch(:dbtype, 'postgresql')}
|
125
|
+
username: #{fetch(:dbuser, account)}
|
126
|
+
password: #{dbpassword}
|
127
|
+
database: #{fetch(:dbname, account)}
|
128
|
+
EOF
|
129
|
+
put database_yml, "#{deploy_to}/#{shared_dir}/config/database.yml"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
module Railscluster
|
2
|
+
class Database
|
3
|
+
def self.build config
|
4
|
+
case config['adapter']
|
5
|
+
when 'postgresql'
|
6
|
+
PostgresqlDatabase
|
7
|
+
when 'mysql2'
|
8
|
+
MysqlDatabase
|
9
|
+
else
|
10
|
+
raise "unsupported adapter: #{config['adapter']}"
|
11
|
+
end.new(config)
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :config
|
15
|
+
def initialize config
|
16
|
+
@config = config
|
17
|
+
end
|
18
|
+
|
19
|
+
# Backup through gateway (connects to localhost on specified forwarded local port)
|
20
|
+
def backup_command(local_port, application); raise('not implemented'); end
|
21
|
+
def find_local_backup; raise('not implemented'); end
|
22
|
+
def restore_command(filename); raise('not implemented'); end
|
23
|
+
end
|
24
|
+
|
25
|
+
class PostgresqlDatabase < Database
|
26
|
+
def server_port
|
27
|
+
config['port'] || 5432
|
28
|
+
end
|
29
|
+
|
30
|
+
def backup_command local_port, application
|
31
|
+
filename = "#{application}.pgdump.#{Time.now.to_i}.pgz"
|
32
|
+
|
33
|
+
"PGPASSWORD='#{config['password']}' pg_dump -Fc --no-owner --no-privileges -hlocalhost --port=#{local_port} -U#{config['username']} #{config['database']} -f backups/#{filename}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def find_local_backup
|
37
|
+
`ls -tr backups/*pgdump* | tail -n 1`.chomp
|
38
|
+
end
|
39
|
+
|
40
|
+
def restore_command file
|
41
|
+
user = "-U #{config['username']}" if config['username']
|
42
|
+
password = "PGPASSWORD='#{config['password']}' " if config['password']
|
43
|
+
|
44
|
+
"#{password}pg_restore #{user} -d #{config['database']} -c -O -hlocalhost #{file}; true"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class MysqlDatabase < Database
|
49
|
+
def server_port
|
50
|
+
config['port'] || 3306
|
51
|
+
end
|
52
|
+
|
53
|
+
def backup_command local_port, application
|
54
|
+
filename = "#{application}.mysqldump.#{Time.now.to_i}.sql"
|
55
|
+
|
56
|
+
"mysqldump --user=#{config['username']} --password=#{config['password']} --host=localhost --port=#{local_port} --protocol=TCP #{config['database']} > backups/#{filename}"
|
57
|
+
end
|
58
|
+
|
59
|
+
def find_local_backup
|
60
|
+
`ls -tr backups/*mysqldump* | tail -n 1`.chomp
|
61
|
+
end
|
62
|
+
|
63
|
+
def restore_command file
|
64
|
+
"mysql --user=#{config['username']} --password=#{config['password']} #{config['database']} < #{file}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
71
|
+
namespace :backup do
|
72
|
+
task :default do
|
73
|
+
export
|
74
|
+
end
|
75
|
+
task :export do
|
76
|
+
db.export
|
77
|
+
uploads.export
|
78
|
+
end
|
79
|
+
task :restore_locally do
|
80
|
+
db.restore_locally
|
81
|
+
uploads.restore_locally
|
82
|
+
end
|
83
|
+
task :copy do
|
84
|
+
db.copy
|
85
|
+
uploads.copy
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
namespace :uploads do
|
90
|
+
desc "Backup the remote uploads (public/private) to a local tar file."
|
91
|
+
task :export, :roles => :app, :only => { :primary => true } do
|
92
|
+
filename = "#{application}.uploads.#{Time.now.to_i}.tar.gz"
|
93
|
+
file = "backups/#{filename}"
|
94
|
+
|
95
|
+
run "cd #{shared_path} && tar -czf uploads.tar.gz private/uploads public/uploads"
|
96
|
+
get "#{shared_path}/uploads.tar.gz", file
|
97
|
+
run "rm #{shared_path}/uploads.tar.gz"
|
98
|
+
end
|
99
|
+
|
100
|
+
desc "Import the latest uploads backup."
|
101
|
+
task :restore_locally, :roles => :app, :only => { :primary => true } do
|
102
|
+
filename = `ls -tr backups/*uploads* | tail -n 1`.chomp
|
103
|
+
run_locally "tar -xf #{filename}"
|
104
|
+
end
|
105
|
+
|
106
|
+
desc "Backup the remote uploads (public/private) to and expand it locally"
|
107
|
+
task :copy, :roles => :app, :only => { :primary => true } do
|
108
|
+
export
|
109
|
+
restore_locally
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
namespace :db do
|
114
|
+
require 'yaml'
|
115
|
+
|
116
|
+
desc "Backup the remote production database to a local file, uses a binary format."
|
117
|
+
task :export, :roles => :db, :only => { :primary => true } do
|
118
|
+
|
119
|
+
# First lets get the remote database config file so that we can read in the database settings
|
120
|
+
logger.info "Loading the database configuration for the #{rails_env} environment..."
|
121
|
+
|
122
|
+
tmp_db_yml = "tmp/database.yml"
|
123
|
+
get("#{shared_path}/config/database.yml", tmp_db_yml) #rescue logger.important "Could not load database configuration. Have you specified rails_env?" and exit
|
124
|
+
|
125
|
+
# load the production settings within the database file
|
126
|
+
database = Railscluster::Database.build(YAML::load_file("tmp/database.yml")[rails_env])
|
127
|
+
run_locally("rm #{tmp_db_yml}")
|
128
|
+
|
129
|
+
server = find_servers_for_task(current_task).first
|
130
|
+
gateway = Net::SSH::Gateway.new(server.host, nil)
|
131
|
+
local_port = gateway.open(database.config['host'], database.server_port)
|
132
|
+
|
133
|
+
on_rollback {
|
134
|
+
run_locally("rm #{tmp_db_yml}")
|
135
|
+
gateway.shutdown!
|
136
|
+
}
|
137
|
+
|
138
|
+
run_locally "mkdir -p -v 'backups'"
|
139
|
+
run_locally database.backup_command(local_port, application)
|
140
|
+
|
141
|
+
gateway.shutdown!
|
142
|
+
end
|
143
|
+
|
144
|
+
desc "Import the latest backup to the local development database"
|
145
|
+
task :restore_locally do
|
146
|
+
database = Railscluster::Database.build(YAML::load_file("config/database.yml")["development"])
|
147
|
+
file = database.find_local_backup
|
148
|
+
if file.empty?
|
149
|
+
logger.important "No backups found"
|
150
|
+
else
|
151
|
+
logger.debug "Loading #{file} into local development database"
|
152
|
+
run_locally database.restore_command(file)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
desc "Backup the remote production database and restore it to the local development database"
|
157
|
+
task :copy do
|
158
|
+
export
|
159
|
+
restore_locally
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'bundler/capistrano'
|
2
|
+
|
3
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
4
|
+
|
5
|
+
set :bundle_cmd, 'bundle'
|
6
|
+
set :rake, lambda { "#{bundle_cmd} exec rake" }
|
7
|
+
|
8
|
+
namespace :bundle do
|
9
|
+
# Only execute clean if you know that a rollback will not be necessary.
|
10
|
+
desc "Clean the current Bundler environment"
|
11
|
+
task :clean do
|
12
|
+
run "cd #{latest_release}; RAILS_ENV=#{rails_env} #{bundle_cmd} clean"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
Capistrano::Configuration::Actions::Invocation.class_eval do
|
2
|
+
def get_rails_env
|
3
|
+
capture 'echo $RAILS_ENV'
|
4
|
+
end
|
5
|
+
|
6
|
+
def get_backend
|
7
|
+
capture 'echo $RAILS_BACKEND'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'capistrano/recipes/deploy/scm/git'
|
12
|
+
module Capistrano
|
13
|
+
module Deploy
|
14
|
+
module SCM
|
15
|
+
class Git
|
16
|
+
def export(revision, destination)
|
17
|
+
if variable(:git_enable_submodules) || !variable(:repository).include?('git.nedforce.nl')
|
18
|
+
checkout(revision, destination) << " && rm -Rf #{destination}/.git"
|
19
|
+
else
|
20
|
+
git = command
|
21
|
+
remote = origin
|
22
|
+
|
23
|
+
args = []
|
24
|
+
|
25
|
+
args << "--verbose" if verbose.nil?
|
26
|
+
args << "--prefix=#{destination[1..-1]}/"
|
27
|
+
args << "--remote #{variable(:repository)}"
|
28
|
+
|
29
|
+
execute = []
|
30
|
+
execute << "#{git} archive #{args.join(' ')} #{revision} | (tar -x -C / -f -)"
|
31
|
+
|
32
|
+
execute.compact.join(" && ").gsub(/\s+/, ' ')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
2
|
+
def changed? files
|
3
|
+
if previous_revision.nil? || previous_revision.empty?
|
4
|
+
# No revision deployed yet, so everything is new!
|
5
|
+
true
|
6
|
+
else
|
7
|
+
pattern = files.is_a?(String) ? files : files.join(' ')
|
8
|
+
`#{source.log(previous_revision, latest_revision)} #{pattern} | wc -l`.to_i > 0
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
2
|
+
|
3
|
+
def run_interactively(cmd, server=nil)
|
4
|
+
server ||= find_servers_for_task(current_task).first
|
5
|
+
cmd = "cd #{current_path} && #{bundle_cmd} exec #{cmd}"
|
6
|
+
user = fetch(:account)
|
7
|
+
cmd = "sudo su - #{account} -c \"#{cmd}\" "
|
8
|
+
exec "ssh #{server.host} -t '#{cmd}'"
|
9
|
+
end
|
10
|
+
|
11
|
+
namespace :console do
|
12
|
+
task :default do
|
13
|
+
shell
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "Rails console"
|
17
|
+
task :rails, :roles => :app do
|
18
|
+
set(:sandbox_mode) { Capistrano::CLI.ui.ask("Start production console in sandbox mode? y/n: ") } if rails_env == 'production'
|
19
|
+
if rails_env == 'production' && sandbox_mode != 'n'
|
20
|
+
run_interactively "rails console #{rails_env} --sandbox"
|
21
|
+
else
|
22
|
+
run_interactively "rails console #{rails_env}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Is only going to work from Rails 4 onwards.
|
27
|
+
desc "Database console (Rails 4 Only)"
|
28
|
+
task :db, :roles => :app do
|
29
|
+
run_interactively "rails dbconsole #{rails_env} --include-password"
|
30
|
+
end
|
31
|
+
|
32
|
+
desc "Command line shell"
|
33
|
+
task :shell, :roles => :app do
|
34
|
+
server ||= find_servers_for_task(current_task).first
|
35
|
+
user = fetch(:account)
|
36
|
+
cmd = "sudo su - #{account}"
|
37
|
+
exec "ssh #{server.host} -t '#{cmd}'"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
2
|
+
set :branch do
|
3
|
+
tags = `git ls-remote --tags | awk -F/ '$NF !~ /[\}]$/ {print $NF}'`.split("\n")
|
4
|
+
heads = `git ls-remote --heads | awk -F/ '{print $NF}'`.split("\n")
|
5
|
+
Capistrano::CLI.ui.choose do |menu|
|
6
|
+
menu.header = "Remote Branches & Tags"
|
7
|
+
menu.choices *heads
|
8
|
+
menu.choices *tags
|
9
|
+
menu.default = tags.last || heads.select {|h| h == 'master'}.first || heads.last
|
10
|
+
menu.prompt = "Select a branch/tag [default: #{menu.default}]:"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
task :deployed_version do
|
15
|
+
tag = `git describe --all #{latest_revision} 2> /dev/null`
|
16
|
+
if tag.empty?
|
17
|
+
rev = `git log -1 --oneline #{latest_revision}`
|
18
|
+
puts "\n\nCurrently deployed revision:\n#{rev}" if rev
|
19
|
+
else
|
20
|
+
puts "\n\nCurrently deployed tag/head:\n#{tag}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
2
|
+
|
3
|
+
after 'deploy:restart', 'sidekiq:restart'
|
4
|
+
|
5
|
+
namespace :sidekiq do
|
6
|
+
desc "Start the sidekiq daemon"
|
7
|
+
task :start, :roles => :app do
|
8
|
+
run "cluster_service sidekiq start"
|
9
|
+
end
|
10
|
+
|
11
|
+
desc "Restart the sidekiq daemon"
|
12
|
+
task :restart, :roles => :app do
|
13
|
+
run "cluster_service sidekiq restart"
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "Stop the sidekiq daemon"
|
17
|
+
task :stop, :roles => :app do
|
18
|
+
run "cluster_service sidekiq stop"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
2
|
+
|
3
|
+
before 'deploy:restart' do
|
4
|
+
sphinx.configure
|
5
|
+
sphinx.restart
|
6
|
+
end
|
7
|
+
|
8
|
+
after "deploy:setup" do
|
9
|
+
run "mkdir -p #{shared_path}/index"
|
10
|
+
end
|
11
|
+
|
12
|
+
namespace :sphinx do
|
13
|
+
desc "Start the sphinx daemon"
|
14
|
+
task :start, :roles => :app do
|
15
|
+
run "cluster_service sphinx start"
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Restart the sphinx daemon"
|
19
|
+
task :restart, :roles => :app do
|
20
|
+
run "cluster_service sphinx restart"
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "Stop the sphinx daemon"
|
24
|
+
task :stop, :roles => :app do
|
25
|
+
run "cluster_service sphinx stop"
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "Reindex sphinx"
|
29
|
+
task :reindex, :roles => :app do
|
30
|
+
run "cluster_service sphinx reindex"
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "Rebuild sphinx config"
|
34
|
+
task :configure, :roles => :app do
|
35
|
+
configure_cmd = File.exists?('config/thinking_sphinx.yml') ? 'ts:configure' : 'ts:config'
|
36
|
+
run "cd #{latest_release} && #{rake} RAILS_ENV=#{rails_env} #{configure_cmd} && mv #{latest_release}/config/#{rails_env}.sphinx.conf #{shared_path}/config"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'railscluster/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "railscluster"
|
8
|
+
gem.version = Railscluster::VERSION
|
9
|
+
gem.authors = ["Arthur Holstvoogd"]
|
10
|
+
gem.email = ["a.holstvoogd@nedforce.nl"]
|
11
|
+
gem.description = %q{Gem to ease deploying to RailsCluster}
|
12
|
+
gem.summary = %q{Gem to ease deploying to RailsCluster}
|
13
|
+
gem.homepage = "http://www.railscluster.nl"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
gem.add_dependency 'capistrano', '~> 2.15'
|
20
|
+
gem.add_dependency 'bundler'
|
21
|
+
gem.add_dependency 'thin'
|
22
|
+
gem.add_dependency 'airbrake'
|
23
|
+
gem.add_dependency 'net-ssh', '~> 2.7.0'
|
24
|
+
# gem.add_dependency 'rake', '10.1.0'
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: railscluster
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Arthur Holstvoogd
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-04-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: capistrano
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.15'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.15'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: thin
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: airbrake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: net-ssh
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 2.7.0
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.7.0
|
83
|
+
description: Gem to ease deploying to RailsCluster
|
84
|
+
email:
|
85
|
+
- a.holstvoogd@nedforce.nl
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- ".gitignore"
|
91
|
+
- Gemfile
|
92
|
+
- LICENSE.txt
|
93
|
+
- README.md
|
94
|
+
- Rakefile
|
95
|
+
- lib/railscluster.rb
|
96
|
+
- lib/railscluster/capistrano.rb
|
97
|
+
- lib/railscluster/capistrano/backup.rb
|
98
|
+
- lib/railscluster/capistrano/bundler.rb
|
99
|
+
- lib/railscluster/capistrano/capistrano_extensions.rb
|
100
|
+
- lib/railscluster/capistrano/changed.rb
|
101
|
+
- lib/railscluster/capistrano/console.rb
|
102
|
+
- lib/railscluster/capistrano/git.rb
|
103
|
+
- lib/railscluster/capistrano/sidekiq.rb
|
104
|
+
- lib/railscluster/capistrano/sphinx.rb
|
105
|
+
- lib/railscluster/capistrano/whenever.rb
|
106
|
+
- lib/railscluster/version.rb
|
107
|
+
- railscluster.gemspec
|
108
|
+
homepage: http://www.railscluster.nl
|
109
|
+
licenses: []
|
110
|
+
metadata: {}
|
111
|
+
post_install_message:
|
112
|
+
rdoc_options: []
|
113
|
+
require_paths:
|
114
|
+
- lib
|
115
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
requirements: []
|
126
|
+
rubyforge_project:
|
127
|
+
rubygems_version: 2.2.0
|
128
|
+
signing_key:
|
129
|
+
specification_version: 4
|
130
|
+
summary: Gem to ease deploying to RailsCluster
|
131
|
+
test_files: []
|