Skip to content

Instantly share code, notes, and snippets.

@omnifroodle
Created May 6, 2010 03:53
Show Gist options
  • Save omnifroodle/391764 to your computer and use it in GitHub Desktop.
Save omnifroodle/391764 to your computer and use it in GitHub Desktop.
a generic capistrano deploy file suitable for most rails apps
require 'active_support'
DEPLOY_CONFIG = YAML::load(File.open("config/deploy.yml"))
default_run_options[:pty] = true
#
# General Deployment settings
#
set :application, DEPLOY_CONFIG['application']
set :repository, DEPLOY_CONFIG['repository'] || 'master'
set :scm, :git
#
# Setting up deployment targets
#
# lets build some deployment target tasks!
# this creates the 'production' part of
# > cap production deploy
# based on the environments defined in deploy.yml
DEPLOY_CONFIG['environment'].each do |environment|
name = environment.keys.first #should only ever be one, but we'll be safe
env = environment[name]
desc "set the deploy target to #{name}"
task name.to_sym do
#setup this environment
set :environment, name
set :domain, ("#{name}.#{application}.com" || env['domain'])
set :rails_env, (env['rails_env'] || name.to_sym)
set :web_data, (env['data_dir'] || '/data/')
#user can be set at the app or environment level
set :user, env['user'] || DEPLOY_CONFIG['user']
puts fetch(:user)
if user == nil
set(:user) { Capistrano::CLI.ui.ask("User Name: ") }
end
set(:password) { Capistrano::CLI.ui.ask("Password: ") { |q| q.echo = "*" }}
#
# settings unlikely to change
#
set :deploy_to, "#{fetch :web_data}#{fetch :application}_#{fetch :environment}"
set :use_sudo, true
#create the servers for this environment
env['server'].each do |server|
servName = server.keys.first
serv = server[servName]
serv['role'].each do |job|
if job == 'db_primary'
role :db, servName, :primary => true
else
role job.to_sym, servName
end
end
end
end
end
#
# some custom actions you may want to use
#
set :package_assets, DEPLOY_CONFIG['package_assets'] || false # set to true if using the asset packager plugin
set :crontasks, DEPLOY_CONFIG['crontasks'] || false # requires a config/crontab/cron-settings
# file in your project (format is the same as a normal crontab file)
#
# settings unlikely to change
#
set :nginx_conf, "#{web_data}conf/"
set :nginx_remote_template, "#{nginx_conf}nginx.erb"
set :database_yml_template, "#{nginx_conf}database.yml.erb"
set :use_sudo, false
set(:application_db_pass) {ActiveSupport::SecureRandom.base64(12)}
ssh_options[:port] = 46559
set :deploy_via, :remote_cache
set :git_enable_submodules, 1
#
# insert custom tasks
#
after "deploy:update_code","deploy:symlink_configs"
after("deploy:update_code","deploy:package_assets") if package_assets
after("deploy:restart", "deploy:write_crontab") if crontasks
after("deploy:setup", "db:setup") unless fetch(:skip_db_setup, false)
after "deploy:setup", "nginx:configure"
before "deploy:restart", "nginx:configure"
before "deploy:start", "nginx:configure"
after "deploy", "deploy:cleanup"
#
# Dynamic nginx config files
#
# credit: http://www.subreview.com/articles/6
namespace(:nginx) do
task :configure do
nginx_template=<<-EOF
# File generated on <%=Time.now().strftime("%d %b %y")%>
<% if redirect %>
server {
listen 80;
client_max_body_size 3M;
server_name <%=redirect %> ;
rewrite ^/(.*) http://<%=domain %> permanent;
}
<% end %>
server {
listen 80;
server_name <%=domain %>;
client_max_body_size 3M;
rails_env <%= rails_env %>;
access_log <%=deploy_to%>/shared/log/access.log;
error_log <%=deploy_to%>/shared/log/error.log;
root <%=deploy_to%>/current/public/;
index index.html;
passenger_enabled on;
}
EOF
# run the template
template_file(nginx_template,nginx_remote_config)
#add a symlink into sites enabled
run "ln -s -f #{nginx_conf}sites-available/#{application}_#{rails_env} #{nginx_conf}sites-enabled/#{application}_#{rails_env}"
run "sudo /etc/init.d/nginx reload"
end
end
namespace(:deploy) do
task :symlink_configs, :roles => :app, :except => {:no_symlink => true} do
run <<-CMD
cd #{release_path} &&
ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml &&
ln -nfs #{shared_path}/system #{release_path}/public/system &&
ln -s #{shared_path}/news_releases #{release_path}/public/news_releases
CMD
end
task :restart do
run "touch #{current_path}/tmp/restart.txt"
end
task :write_crontab, :roles => :app do
puts "Installing server-specific crontab."
run("cd #{deploy_to}/current/config/crontab; crontab cron-settings")
end
desc "install gems listed in environment.rb"
task :install_gems do
run "cd #{current_path} && rake gems:install RAILS_ENV=production"
end
end
namespace(:monitor) do
desc "Tail the Rails production log for this environment"
task :tail_production_logs, :roles => :app do
run "tail -f #{shared_path}/log/production.log" do |channel, stream, data|
puts # for an extra line break before the host name
puts "#{channel[:server]} -> #{data}"
break if stream == :err
end
end
end
load :file => "config/my_deploy_tasks.rb" if Dir.entries('.').detect{|f| f.match 'my_deploy_tasks.rb'}
namespace :db do
desc "Creates a new database and user, and grants the user rights to the database. Creates the database.yml configuration file in shared path."
task :setup, :except => { :no_release => true } do
database_template=<<-EOF
# File generated on <%=Time.now().strftime("%d %b %y")%>
<%= rails_env %>:
adapter: mysql
encoding: utf8
database: <%= application %>_<%= rails_env[0,4] %>
pool: 5
username: <%= application %>_<%= rails_env[0,4] %>
password: <%= application_db_pass %>
socket: /var/run/mysqld/mysqld.sock
EOF
run "mkdir -p #{shared_path}/db"
run "mkdir -p #{shared_path}/config"
template_file(database_template,"#{shared_path}/config/database.yml")
#create the database and user base on the application and password
run "/data/scripts/user_and_db.rb #{application}_#{rails_env[0,4]} #{application_db_pass}"
end
desc "Updates the symlink for database.yml file to the just deployed release."
task :symlink, :except => { :no_release => true } do
run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml"
end
end
#
# Get the template as a string,
# parse it, and place the new file on the server
#
def template_file(template,remote_file_to_put)
require 'erb' #render not available in Capistrano 2
buffer= ERB.new(template).result(binding) # parse it
put buffer,remote_file_to_put # put the result
end
application: "example"
user: 'webmin'
package_assets: no
crontasks: no
environment:
- staging:
data_dir: '/data/'
#setting user here overrides
#user: 'omnifroodle'
domain: "www.example_staging.inmunited.com"
redirect: "example_staging.inmunited.com *.example_staging.inmunited.com"
server: #
- 127.0.0.1:
role:
- app
- web
- db_primary
- production:
data_dir: '/data/www/'
#setting user here overrides
#user: 'omnifroodle'
domain: "www.example.com"
redirect: "example.com *.example.com"
server:
- 127.0.0.2:
role:
- app
- web
- db_primary
- 127.0.0.3: #example of a second production server
role:
- db
@omnifroodle
Copy link
Author

I've roughed in the rest of our standard config.rb designed to support the new yml format, though it is untested

@omnifroodle
Copy link
Author

oh... and if it works we need to push it up to the standard repo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment