The Artima Developer Community
Sponsored Link

Ruby Buzz Forum
Fun with SwitchTower

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Jamis Buck

Posts: 184
Nickname: minam
Registered: Oct, 2004

Jamis Buck is a C/Java software developer for BYU, and hacks in Ruby for fun.
Fun with SwitchTower Posted: Aug 7, 2005 9:32 AM
Reply to this message Reply

This post originated from an RSS feed registered with Ruby Buzz by Jamis Buck.
Original Post: Fun with SwitchTower
Feed Title: the buckblogs here
Feed URL: http://weblog.jamisbuck.org/blog.cgi/programming/index.rss
Feed Description: Jamis Buck's corner of the blogging universe. Mostly about ruby, but includes ramblings on a variety of topics.
Latest Ruby Buzz Posts
Latest Ruby Buzz Posts by Jamis Buck
Latest Posts From the buckblogs here

Advertisement

With SwitchTower out of the gate and feedback coming in, I thought I’d take a moment to post a few custom tasks I created while working on Backpack and Tada Lists.

Firstly, the default SwitchTower tasks assume you are using Apache to host your apps. (Mostly this is an assumption of the enable_web and disable_web tasks, because they require some conditional rewrite rules in order to do their thing.) However, Tada Lists is being run via lighttpd, which doesn’t have (to my knowledge) any way to say “use this rewrite rule only if this file exists”.

So, what we’re doing instead is managing two lighttpd configurations—one for “live” mode, and one for “maintenance” mode. When in maintenance mode, all requests are rewritten so that a “system/maintenance.html” file is displayed.

Then, I create two new tasks, after_disable_web and before_enable_web. I use these tasks to kill the running lighttpd instance on the web servers, and then start up a new lighttpd instance using the correct configuration:

(Note that these are “hook” tasks that are called automatically by SwitchTower when the disable_web and enable_web tasks are called—you don’t need to call these explicitly, they just extend the existing tasks.)

  desc "Restart lighttpd with the $HOST-maint.conf file" 
  task :after_disable_web, :roles => :web do
    pids = "ps wwwax | grep lighttpd | grep -v grep " +
            "| grep -v assets | cut -b 1-5" 
    sudo "kill `#{pids}`" 
    sudo "lighttpd -f #{current_path}/config/lighttpd/" +
            "${HOSTNAME%.37signals.com}-maint.conf" 
  end

  desc "Restart lighttpd with the $HOST.conf file" 
  task :before_enable_web, :roles => :web do
    pids = "ps wwwax | grep lighttpd | grep maint " +
           "| grep -v grep | cut -b 1-5" 
    sudo "kill `#{pids}`" 
    sudo "lighttpd -f #{current_path}/config/lighttpd/" +
           "${HOSTNAME%.37signals.com}.conf" 
  end

(Note that the above tasks will need a little more work if you host multiple apps on the same web server—you’ll probably want to find a way to only kill the lighttpd instances pertaining to the app in question.)

The other tasks I created were for examing the status of the master and slave database servers. To do this, I needed the root MySQL password so that I could run the SHOW MASTER STATUS query, but I didn’t want to put the password in the recipe… not exactly a secure solution. So, instead, I set the password variable to a Proc instance. When SwitchTower sees a variable that is a Proc, it will execute the Proc and cache the result. So, the variable is defined like this:

  set :root_db_password, Proc.new {
    sync = STDOUT.sync
    begin
      echo false
      STDOUT.sync = true
      print "Enter DB password for 'root': " 
      gets.chomp
    ensure
      STDOUT.sync = sync
      echo true
      puts
    end
  }

This means that the first time the root_db_password is queried, the Proc will be invoked, the user will be prompted for the root DB password, and the result cached so that subsequent uses of the variable reuse the result.

The tasks themselves look something like this:

  desc "Show the master DB status" 
  task :show_master_status, :roles => :db, :only => { :primary => true } do
    require 'yaml'
    db = YAML.load(File.read(File.dirname(__FILE__) + "/database.yml"))
    prod = db['production']

    cmd = 'echo "SHOW MASTER STATUS\G" ' +
          "| mysql -u root -p #{prod['database']}" 

    run cmd do |ch, stream, data|
      logger.info data, "[#{stream} :: #{ch[:host]}]" 
      ch.send_data "#{root_db_password}\n" if data =~ /^Enter password:/
    end
  end

  desc "Show the slave DB status" 
  task :show_slave_status, :roles => :db, :only => { :slave => true } do
    require 'yaml'
    db = YAML.load(File.read(File.dirname(__FILE__) + "/database.yml"))
    prod = db['production']

    cmd = 'echo "SHOW SLAVE STATUS\G" ' +
          "| mysql -u root -p #{prod['database']}" 

    run cmd do |ch, stream, data|
      logger.info data, "[#{stream} :: #{ch[:host]}]" 
      ch.send_data "#{root_db_password}\n" if data =~ /^Enter password:/
    end
  end

To use them, then, I just do:

  rake remote_exec ACTION=show_master_status,show_slave_status

And voila!

Read: Fun with SwitchTower

Topic: Congratulations to DHH! Previous Topic   Next Topic Topic: GeoURL Yahoo! Mapping

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use