jump to navigation

Scrape mongrel status from Apache’s mod_proxy_balancer January 4, 2008

Posted by John Dewey in Apache, Capistrano, Code, Command Line, Configuration, Example, Rails, Rake, WebServers.
1 comment so far

Access to Apache’s load balancer manager (mod_proxy_balancer) is typically protected.  Rather than maintaining an ever changing list of ACLs or configuring HTTP authentication, I wrote a simple scraper Rake task.

This task is bundled with all of our rails applications as a svn external, and included in our common Capistrano tasks.This task is a quick and dirty solution to checking the status of your Mongrels.

Feel free to modify, and provide a pastie.http://pastie.caboo.se/135223

P.S. The SAs can plug this into their monitoring software as well.

Patching Capistrano to use CVS over SSH September 11, 2007

Posted by reidmix in Capistrano, Code, Command Line, CVS, Monkey Patch, Ruby, SSH.
4 comments

At work we still use CVS as our versioning repository and most of our systems rely on CVS to build and deploy into production. Currently there is no effort to transition to SVN, so we need to develop a patch to Capistrano to allow our projects to deploy to our development lab. We needed to extend Capistrano handle SSH logins to CVS and handle CVS repository directories.

Overall, both changes needed to be applied to the checkout method in Capistrano’s Cvs class.

We use SSH as the underlying communication mechanism for CVS but there is a difference in the password prompt: SSH’s is capitalized. We just need to make the prompt check case insensitive with the i switch:

if out =~ %r{password:}i

When setting up Capistrano (v1.4) for use in our development lab, the :application configuration is not sufficient to identify our rails project the CVS tree. We are not cool enough to setup or use modules to map into our repository directories, so our projects are usually in some form of webdev/project/appname. To handle this, i create an additional configuration parameter called :project in the deploy.rb:

set :project, "cvs/dir/to/myproj"

And we no longer use the application name for the CVS path, we use the project variable:

project = configuration[:project] || actor.application
command = <<-CMD
  cd #{configuration.releases_path};
  CVS_RSH="#{cvs_rsh}" #{cvs} -d #{configuration.repository} -Q #{op} -D "#{configuration.revision}" #{branch_option} -d #{File.basename(actor.release_path)} #{project};
CMD

The hardest part is patching Capistrano. Capistrano’s code gets loaded well after any library or environment gets loaded. The trick is to use the method_added hook to wait for the checkout method to get loaded and then alias the method to the patched one, we need to keep a variable around to check if we’ve patched the method so we don’t end up in an infinite loop:

@@checkout_patched = false
def Cvs.method_added(id)
  if id.id2name == "checkout"
    unless @@checkout_patched
      @@checkout_patched = true
      alias_method :checkout, :checkout_patch
    end
  end
end

I’ve not checked to see how these changes work or differ in Capistrano 2. But with all these elements together using Capistrano v1.4, I can drop this file in my lib directory or create a plugin with it. Together, here is the full patch which I have in a file called capistrano_cvs_ext.rb:

module Capistrano
  module SCM
    class Cvs < Base
      @@checkout_patched = false
      def Cvs.method_added(id)
        if id.id2name == "checkout"
          unless @@checkout_patched
            @@checkout_patched = true
            alias_method :checkout, :checkout_patch
          end
        end
      end

      def checkout_patch(actor)
        cvs = configuration[:cvs] || "cvs"
        cvs_rsh = configuration[:cvs_rsh] || ENV['CVS_RSH'] || "ssh"

        if "HEAD" == configuration.branch then
            branch_option = ""
        else
            branch_option = "-r #{configuration.branch}"
        end

        # cvs has a root and repository, repository is not the same as application name as it can be a path
        op = configuration[:checkout] || "co"
        project = configuration[:project] || actor.application

        command = <<-CMD
          cd #{configuration.releases_path};
          CVS_RSH="#{cvs_rsh}" #{cvs} -d #{configuration.repository} -Q #{op} -D "#{configuration.revision}" #{branch_option} -d #{File.basename(actor.release_path)} #{project};
        CMD

        run_checkout(actor, command) do |ch, stream, out|
          prefix = "#{stream} :: #{ch[:host]}"
          actor.logger.info out, prefix
          if out =~ %r{password:}i  # SSH asks for "Password" with a capital P
            actor.logger.info "CVS is asking for a password", prefix
            ch.send_data "#{actor.password}n"
          elsif out =~ %r{^Enter passphrase}
            message = "CVS needs your key's passphrase and cannot proceed"
            actor.logger.info message, prefix
            raise message
          end
        end
      end
    end
  end
end