Browse files

Add integration with SwitchTower (rake tasks, default deploy.rb recipe)

git-svn-id: 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
1 parent 3fc8639 commit 3d4a32377651a13575ce6da84875af764fdbe339 @jamis jamis committed Aug 3, 2005
@@ -1,5 +1,7 @@
+* Add integration with SwitchTower (rake tasks, default deploy.rb recipe)
* Allow ERb in the database.yml file (just like with fixtures), so you can pull out the database configuration in environment variables #1822 [Duane Johnson]
* Added convenience controls for FCGI processes (especially when managed remotely): spinner, spawner, and reaper. They reside in script/process. More details can be had by calling them with -h/--help.
@@ -0,0 +1,4 @@
+if not system "switchtower #{ARGV.join(" ")}"
+ abort "Could not execute switchtower. Is it installed?"
@@ -0,0 +1,4 @@
+require 'rubygems'
+require_gem 'switchtower'
+load 'switchtower'
@@ -0,0 +1,115 @@
+# This defines a deployment "recipe" that you can feed to switchtower
+# ( It allows you to automate
+# (among other things) the deployment of your application.
+# =============================================================================
+# =============================================================================
+# You must always specify the application and repository for every recipe. The
+# repository must be the URL of the repository you want this recipe to
+# correspond to. The deploy_to path must be the path on each machine that will
+# form the root of the application path.
+set :application, "<%= File.basename(destination_root) %>"
+set :repository, "{application}/trunk"
+# =============================================================================
+# =============================================================================
+# You can define any number of roles, each of which contains any number of
+# machines. Roles might include such things as :web, or :app, or :db, defining
+# what the purpose of each machine is. You can also specify options that can
+# be used to single out a specific subset of boxes in a particular role, like
+# :primary => true.
+role :web, "", ""
+role :app, "", "", ""
+role :db, "", :primary => true
+role :db, "", ""
+# =============================================================================
+# =============================================================================
+# set :deploy_to, "/path/to/app" # defaults to "/u/apps/#{application}"
+# set :user, "flippy" # defaults to the currently logged in user
+# set :scm, :darcs # defaults to :subversion
+# set :svn, "/path/to/svn" # defaults to searching the PATH
+# set :darcs, "/path/to/darcs" # defaults to searching the PATH
+# set :gateway, "" # default to no gateway
+# =============================================================================
+# =============================================================================
+# Define tasks that run on all (or only some) of the machines. You can specify
+# a role (or set of roles) that each task should be executed on. You can also
+# narrow the set of servers to a subset of a role by specifying options, which
+# must match the options given for the servers to select (like :primary => true)
+desc <<DESC
+An imaginary backup task. (Execute the 'show_tasks' task to display all
+available tasks.)
+task :backup, :roles => :db, :only => { :primary => true } do
+ # the on_rollback handler is only executed if this task is executed within
+ # a transaction (see below), AND it or a subsequent task fails.
+ on_rollback { delete "/tmp/dump.sql" }
+ run "mysqldump -u theuser -p thedatabase > /tmp/dump.sql" do |ch, stream, out|
+ ch.send_data "thepassword\n" if out =~ /^Enter password:/
+ end
+# Tasks may take advantage of several different helper methods to interact
+# with the remote server(s). These are:
+# * run(command, options={}, &block): execute the given command on all servers
+# associated with the current task, in parallel. The block, if given, should
+# accept three parameters: the communication channel, a symbol identifying the
+# type of stream (:err or :out), and the data. The block is invoked for all
+# output from the command, allowing you to inspect output and act
+# accordingly.
+# * sudo(command, options={}, &block): same as run, but it executes the command
+# via sudo.
+# * delete(path, options={}): deletes the given file or directory from all
+# associated servers. If :recursive => true is given in the options, the
+# delete uses "rm -rf" instead of "rm -f".
+# * put(buffer, path, options={}): creates or overwrites a file at "path" on
+# all associated servers, populating it with the contents of "buffer". You
+# can specify :mode as an integer value, which will be used to set the mode
+# on the file.
+# * render(template, options={}) or render(options={}): renders the given
+# template and returns a string. Alternatively, if the :template key is given,
+# it will be treated as the contents of the template to render. Any other keys
+# are treated as local variables, which are made available to the (ERb)
+# template.
+desc "Demonstrates the various helper methods available to recipes."
+task :helper_demo do
+ # "setup" is a standard task which sets up the directory structure on the
+ # remote servers. It is a good idea to run the "setup" task at least once
+ # at the beginning of your app's lifetime (it is non-destructive).
+ setup
+ buffer = render("maintenance.rhtml", :deadline => ENV['UNTIL'])
+ put buffer, "#{shared_path}/system/maintenance.html", :mode => 0644
+ sudo "killall -USR1 dispatch.fcgi"
+ run "#{release_path}/script/spin"
+ delete "#{shared_path}/system/maintenance.html"
+# You can use "transaction" to indicate that if any of the tasks within it fail,
+# all should be rolled back (for each task that specifies an on_rollback
+# handler).
+desc "A task demonstrating the use of transactions."
+task :long_deploy do
+ transaction do
+ update_code
+ disable_web
+ symlink
+ migrate
+ end
+ restart
+ enable_web
@@ -219,3 +219,28 @@ task :load_fixtures => :environment do
Fixtures.create_fixtures('test/fixtures', File.basename(fixture_file, '.*'))
+desc "Push the latest revision into production using the release manager"
+task :deploy do
+ system "script/switchtower -vvvv -r config/deploy -a deploy"
+desc "Rollback to the release before the current release in production"
+task :rollback do
+ system "script/switchtower -vvvv -r config/deploy -a rollback"
+desc "Enumerate all available deployment tasks"
+task :show_deploy_tasks do
+ system "script/switchtower -r config/deploy -a show_tasks"
+desc "Execute a specific action using the release manager"
+task :remote_exec do
+ unless ENV['ACTION']
+ raise "Please specify an action (or comma separated list of actions) via the ACTION environment variable"
+ end
+ actions = ENV['ACTION'].split(",").map { |a| "-a #{a}" }.join(" ")
+ system "script/switchtower -vvvv -r config/deploy #{actions}"
@@ -34,6 +34,7 @@ def manifest
# database.yml and .htaccess
m.template "configs/database.yml", "config/database.yml"
m.template "configs/routes.rb", "config/routes.rb"
+ m.template "configs/deploy.rb", "config/deploy.rb"
m.template "configs/apache.conf", "public/.htaccess"
# Environments
@@ -48,8 +49,10 @@ def manifest
if options[:gem]
m.file "bin/breakpointer_for_gem", "script/breakpointer", script_options
+ m.file "bin/switchtower_for_gem", "script/switchtower", script_options
m.file "bin/breakpointer", "script/breakpointer", script_options
+ m.file "bin/switchtower", "script/switchtower", script_options
# Dispatches

0 comments on commit 3d4a323

Please sign in to comment.