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.
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.)
(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