Created
March 17, 2012 06:18
-
-
Save finack/2055725 to your computer and use it in GitHub Desktop.
Example Chef Deploy Revision for Rails 3+
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
app = node[:rails][:app] | |
rails_base app[:name] do | |
ruby_ver app[:ruby_ver] | |
gemset app[:gemset] | |
end | |
%w{config log pids cached-copy bundle system}.each do |dir| | |
directory "#{app[:app_root]}/shared/#{dir}" do | |
owner app[:deploy_user] | |
group app[:deploy_user] | |
mode '0755' | |
recursive true | |
action :create | |
end | |
end | |
keys = Chef::EncryptedDataBagItem.load('rails', app[:name]) | |
create_database_config app[:name] do | |
app_root node[:rails][:app][:app_root] | |
deploy_user node[:rails][:app][:deploy_user] | |
databases node[:rails][:app][:db][:databases] | |
aliases node[:rails][:app][:db][:aliases] | |
passwords keys["database_passwords"] | |
end | |
deploy_revision "#{app[:app_root]}" do | |
repo app[:repo] | |
revision cluster_settings["revision"] | |
user app[:deploy_user] | |
group app[:deploy_user] | |
enable_submodules true | |
environment({ | |
"RAILS_ENV" => app[:environment], | |
}) | |
shallow_clone false | |
if node["rails"][app[:name]].attribute?('one_time_action') | |
# rollback, deploy, force_deploy | |
action node["rails"][app[:name]]["one_time_action"] | |
node["rails"][app[:name]].delete('one_time_action') | |
else | |
action :deploy | |
end | |
migrate true | |
migration_command "/usr/local/rvm/bin/appname_bundle exec rake db:migrate --trace" | |
before_migrate do | |
template "#{release_path}/config/environments/#{app[:environment]}.rb" do | |
source "#{release_path}/config/environments/chef_development.rb.erb" | |
local true | |
owner app[:deploy_user] | |
group app[:deploy_user] | |
mode '0400' | |
variables(:environment_settings => app[:environment_settings].to_hash) | |
end | |
rvm_shell "Bundle install and assets precompile" do | |
ruby_string "#{app[:ruby_ver]}@#{app[:gemset]}" | |
cwd release_path | |
user app[:deploy_user] | |
group app[:deploy_user] | |
# common_groups = %w{development test cucumber} | |
# bundle install --deployment --path #{app[:app_root]}/shared/bundle --without #{common_groups.join(' ')} | |
code %{ | |
bundle install --path #{app[:app_root]}/shared/bundle | |
} | |
end | |
end | |
before_restart do | |
rvm_shell "assets precompile" do | |
ruby_string "#{app[:ruby_ver]}@#{app[:gemset]}" | |
cwd release_path | |
user app[:deploy_user] | |
group app[:deploy_user] | |
# TODO I could not set the environment via the builtin command. Does not look like it is getting passed to popen4 | |
# So instead of `environment "RAILS_ENV" => app[:environment]` I have it in the code block | |
code %{ | |
export RAILS_ENV=#{app[:environment]} | |
bundle exec rake assets:precompile | |
} | |
end | |
end | |
symlink_before_migrate({ | |
"config/database.yml" => "config/database.yml", | |
"config/environments/#{app[:environment]}.rb" => "config/environments/#{app[:environment]}.rb" | |
}) | |
after_restart do | |
notify_airbrake release_path do | |
environment app[:environment] | |
repository app[:repo] | |
end | |
notify_newrelic release_path do | |
environment app[:environment] | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#Used to configure variables for the app per environment (instead of attributes). | |
#I have since refactored how this works so treat this as example code, aka I | |
#have not tested this and it is not complete. | |
#FWIW using libraries in the cookbook to set these variables | |
#for smaller apps I would keep this in the attributes | |
app_name = 'yourname' | |
default = { | |
name: app_name | |
gemset: app_name | |
ruby_ver: 'ruby-1.8.7-p352', | |
deploy_user: 'deployer', | |
environment: node[:environment], | |
#... | |
} | |
staging = { | |
app_root: '/export/staging/yourname', | |
#... | |
} | |
case node[:environment] | |
when "staging" | |
rails_attributes = Chef::Mixin::DeepMerge.merge(default, staging) | |
end | |
# Don't know why I saved this in a seperate hash before the deep merge... | |
original_node_attributes = node.default.to_hash | |
node.default[:rails] = Chef::Mixin::DeepMerge.merge(rails_attributes, original_node_attributes["rails"]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
define :create_database_config, :passwords=>{} do | |
databases = Hash.new | |
params[:databases].each do |db_name| | |
if node[:rails][params[:name]][:db].has_key?(db_name) | |
values = node[:rails][params[:name]][:db][db_name].to_hash | |
if params[:passwords].has_key?(db_name.to_s) | |
values["password"] = params[:passwords].fetch(db_name.to_s) | |
end | |
name = values.has_key?(name) ? values[:name] : db_name | |
databases.merge!({ name.to_s => values }) | |
end | |
end | |
if params.has_key? :aliases | |
params[:aliases].each do |target,source| | |
databases[target.to_s] = databases[source.to_s] | |
end | |
end | |
file "#{params[:app_root]}/shared/config/database.yml" do | |
owner params[:deploy_user] | |
group params[:deploy_user] | |
mode '400' | |
content databases.to_yaml | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
define :notify_airbrake, :name=>nil, :environment=>nil, :repository=>nil do | |
script "notifying airbrake of deploy" do | |
interpreter "ruby" | |
user "deployer" | |
cwd params[:name] | |
code <<-EOS | |
require 'rubygems' | |
unless File.exist?("#{params[:name]}/config/initializers/airbrake.rb") | |
puts "!!! airbrake.rb not found. Not notifying Airbrake of the deploy !!!" | |
exit 0 | |
end | |
# Setup the airbrake api_key | |
require 'airbrake' | |
require 'airbrake_tasks' | |
require "#{params[:name]}/config/initializers/airbrake.rb" | |
revision = `cd #{params[:name]} && git rev-parse HEAD`.chomp | |
print "Airbrake : " | |
AirbrakeTasks.deploy(:rails_env => '#{params[:environment]}', | |
:scm_revision => revision, | |
:scm_repository => '#{params[:repository]}', | |
:local_username => 'chef') | |
EOS | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
define :notify_newrelic, :deploy_path=>nil, :environment=>nil do | |
script "notifying new relic of deploy" do | |
interpreter "ruby" | |
user "deployer" | |
cwd params[:name] | |
code <<-EOS | |
require 'rubygems' | |
unless File.exist?("#{params[:name]}/config/newrelic.yml") | |
puts "!!! newrelic.yml not found. Not notifying New Relic of the deploy !!!" | |
exit 0 | |
end | |
## When new relic is loaded it automagically loads up its configuration file | |
## And sets the config[:environment]. We are injecting the path to the configuration | |
## file and the environment via ENV variables. | |
ENV['APP_ROOT'] = "#{params[:name]}" | |
ENV['RAILS_ENV'] = "#{params[:environment]}" | |
require 'newrelic_rpm' | |
require 'new_relic/command' | |
config = NewRelic::Control.instance | |
revision = `git rev-parse HEAD`.chomp | |
deployment = NewRelic::Command::Deployments.new({:revision => revision, :user => 'chef'}) | |
print "New Relic : " | |
deployment.run | |
EOS | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
define :rails_base, :ruby_ver=>nil, :gemset=>nil do | |
include_recipe "nodejs" | |
package "mysql-client" | |
package "libmysqlclient-dev" | |
gem_package "newrelic_rpm" | |
gem_package "airbrake" | |
directory '/export' do | |
owner 'root' | |
group 'root' | |
recursive true | |
action :create | |
only_if "test -e /export" | |
end | |
create_deploy_user | |
rvm_gemset params[:gemset] do | |
ruby_string params[:ruby_ver] | |
action :create | |
end | |
rvm_gem 'bundler' do | |
ruby_string "#{params[:ruby_ver]}@#{params[:gemset]}" | |
end | |
# Creates /usr/local/rvm/bin/appname_bundle | |
rvm_wrapper params[:name] do | |
ruby_string "#{params[:ruby_ver]}@#{params[:gemset]}" | |
binary 'bundle' | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
# Handwritten from memory, probably broken | |
"id": "yourname", | |
"database_passwords": { | |
"staging": "foo" | |
} | |
} | |
@finack, Thanks for the update and its really helpful.
But a few pieces left out to make it work for me.
First, the following definition to create the database.
create_database_config app[:name] do
app_root node[:rails][:app][:app_root]
deploy_user node[:rails][:app][:deploy_user]
databases node[:rails][:app][:db][:databases]
aliases node[:rails][:app][:db][:aliases]
passwords keys["database_passwords"]
end
What would be the structure of the attributes/default.rb
file?
Does the following work or I think I need to change the attributes?
default['rails']['app']['app_root'] = "/home/deployer"
default['rails']['railsbp']['db']['railsbp_prod']['encoding'] = "utf8"
default['rails']['railsbp']['db']['railsbp_prod']['reconnect'] = "true"
default['rails']['railsbp']['db']['railsbp_prod']['adapter'] = "mysql2"
And lastly, what that source "#{release_path}/config/environments/chef_development.rb.erb"
template looks like?
Yeah, I know I'm aksing a lot. But your help is directing me to the final deploy.
Can you address those queries?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey there!
Updated the code a bit. Hopefully that helped. I have been using one of the unicorn cookbooks (i think from opscode) and apache to serve all of this. I have been separating out the app deployment from the server as we also deploy delay jobs and other systems that need RoR but not unicorn. For example our run_lists kinda look like
Hopefully this answered some of your questions. I will try to get to others but will be delayed :) Have fun!!