Search

Enter a search word or two and press return to see the search results.

Who am I?

Hi, I’m Graeme and these are my notes, from my messy desk. I started this blog because Google proved to be more useful at finding content than anything else I’ve used.

So I started adding my own content in the hopes that Google would index it and allow me to find things again in the future.

It works.

You can find out more about me here, and you should follow me on Twitter here.

Keeping up

You can automatically receive new content here by subscribing to the “Blog RSS” (link below). This is the easiest way to keep up with what I write here.  See this BBC article for a good introduction on RSS and keeping up with the goings on of the Internet more easily.

« Tracking which deployment you're looking at | Main | Solaris: Upgrading to Sun Studio 12 »
Sunday
24Jun2007

Integrating capistrano with SMF

I've got a new application I'm in the process of deploying in order to demo for a client (no, it's not ready for everybody else to have a nosy at just yet!) and figured I'd take the opportunity to learn two things:

* What's new and shiny about [Capistrano 2](http://www.capify.org/). Most of that was putting what I learned at [Harnessing Capistrano](/2007/05/18/harnessing-capistrano/) into practice.
* How to make the Solaris [Service Management Facility](http://www.opensolaris.org/os/community/smf/) (SMF) manage all my mongrel processes for me.

And I think I've pulled the right bits together to make it work rather well. If I do say so myself. :-)

First up I got the basic project running and deploying. I decided to work with, rather than against, capistrano as much as possible. So that meant using `script/spin` and `script/process/*` instead of messing around with trying to port `mongrel_cluster` recipes to cap2. So I created a `script/spin` with the following:

#!/usr/bin/env bash

/u/apps/example/current/script/process/spawner mongrel -p 9000 -i 3 -a 127.0.0.1

which makes the spawner start three mongrel processes, listening at 9000, 9001, & 9002, on localhost. Dead simple. Add that to your subversion repository and commit. Now let's create a default capistrano configuration for the project:

mathie@lagavulin:example$ capify .
[add] writing `./Capfile'
[add] writing `./config/deploy.rb'
[done] capified!

Before I go any further, let's have a wee aside about my current capistrano setup. I still have applications that require Capistrano 1.4.x (they're using third party plugins which haven't yet been ported), so I need to have access to both versions in my environment. I've done this by having both versions of the gem installed. Then in my bash environment, I have the following:

alias cap1="`which cap` _1.4.1_"
alias cap2="`which cap`"
alias cap="echo 'Please explicitly choose cap1 or cap2.'"

So running `cap1` will pick capistrano version 1.4.1, and `cap2` will run the latest installed version. Another useful snippet picked up from the Harnessing Capistrano tutorial -- thanks Jamis!

Anyway, on with the show. Let's create a very basic deployment which deploys the application to 'example.rubaidh.com' running as the user 'deploy':

# Basic configuration
set :application, "example"
set :repository, "http://svn.rubaidh.com/#{application}/trunk"
set :host, "example.rubaidh.com"
set :user, "deploy"
set :scm_username, ENV['USER']
set :deploy_via, :remote_cache
set :use_sudo, false

role :app, host
role :web, host
role :db, host, :primary => true

# Specify some dependencies
depend :remote, :command, :gem
depend :remote, :gem, :mongrel, '>=1.0.1'
depend :remote, :gem, :hpricot, '>=0.6'
depend :remote, :gem, :rmagick, '>=1.15.7'
depend :remote, :gem, :rake, '>=0.7'
depend :remote, :gem, "bcrypt-ruby", '>=2.0.2'
depend :remote, :gem, :BlueCloth, '>=1.0.0'

# Clean up after ourselves, so we don't leave too many old releases lying
# around.
after :deploy, "deploy:cleanup"

A pretty simple configuration, but it shows off a couple of new features in Capistrano 2, the dependency checking (`depend`) and the new hooks system (`after`). The latter, in particular, is a neat wee trick, I reckon. After it's finished a deployment, it'll automatically clean up old releases, only leaving around the last 5. Kudos to [Craig](http://beer-monkey.com/) for introducing that to me after we ran out of disk space on one production machine with 200+ old deployments lying around!

Doing a deployment is pretty simple:

mathie@lagavulin:nang$ cap2 deploy:setup
* executing `deploy:setup'
[ snip ]
command finished
mathie@lagavulin:nang$ cap2 deploy:cold
* executing `deploy:cold'
[ snip ]
command finished

Which will do the usual setup tasks, deploy the system, run any pending migrations and start up the servers. That's us done for part one. Now to get SMF to manage the mongrels for us. First of all, we need to create a service manifest. Create the following file on the server:
























































This probably deserves some explanation. We're creating a service manifest for the service with the FMRI of `svc:/application/rails/example`. We're saying that it shouldn't be enabled by default when it's imported, and that there can only be one instance of it running at a time. Next we say what the dependencies are, and what services are dependent upon it (Apache, mostly). We configure its environment (working directory, user, path and `RAILS_ENV`). The methods for starting, stopping and restarting the service are all cargo-culted directly from the capistrano 2 default deployment recipe. Finally, there's a wee bit of magic: We are telling the SMF framework that anybody who has been granted the `rails.applications` authorisation is allowed to stop and start the service, so you no longer need to be root to restart it!

Once you've created that file on the server, import it and check that it's been done correctly:

mathie@example:~$ pfexec svccfg import smf.xml
mathie@example:~$ svcs example
STATE STIME FMRI
disabled 20:54:15 svc:/application/rails/example:default

Excellent! Now we have to do a little extra fiddling to get the authorisation to work. Add the following to the end of `/etc/security/auth_attr`:

rails.applications:::Manage Rails applications::

And the following to the end of `/etc/user_attr`:

deploy::::type=normal;auths=rails.applications

This declares the authorisation and assigns it to the deploy user. We can check that it's been done correctly by running:

mathie@cardhu:~$ auths deploy
rails.applications,[ snip ]

Finally, we need to modify the capistrano deployment slightly. But before we do that, make sure and stop the app servers with the old configuration so nothing gets confused:

mathie@lagavulin:example$ cap2 deploy:stop

Remove the `set :use_sudo, false` line from `config/deploy.rb` because we are going to want to use the sudo mechanism, though not for launching sudo. Then append the following:

set :fmri, "application/rails/#{application}"
set :sudo, 'pfexec'

namespace :deploy do
task :start, :roles => :app do
invoke_command "/usr/sbin/svcadm enable #{fmri}", :via => fetch(:run_method, :sudo)
end

task :stop, :roles => :app do
invoke_command "/usr/sbin/svcadm disable #{fmri}", :via => fetch(:run_method, :sudo)
end

task :restart, :roles => :app do
invoke_command "/usr/sbin/svcadm restart #{fmri}", :via => fetch(:run_method, :sudo)
end
end

This overrides the default start, stop and restart tasks for the deployment scenario to use `pfexec` (to gain the appropriate authorisation) and `svcadm` to control the service. Run:

mathie@lagavulin:example$ cap2 deploy:start

to make sure it works. You can verify it works by looking at `svcs` on the server:

mathie@cardhu:~$ svcs -p example
STATE STIME FMRI
online 20:56:08 svc:/application/rails/example:default
20:56:07 5953 mongrel_rails
20:56:07 5956 mongrel_rails
20:56:08 5959 mongrel_rails

We have a running app. :-) Satisfy yourself that it's all working OK by doing a full deploy (`cap2 deploy`) then checking that the pids listed in the `svcs -p` output have changed and that your app has updated. Finally, reboot the machine to check that it all comes back up again afterwards? It does? How excellent is that? :)

PrintView Printer Friendly Version

EmailEmail Article to Friend

Reader Comments (4)

Excellent writeup. It's great to see people starting to use cap2! Thanks for sharing.

July 7, 2007 | Unregistered CommenterJamis

[...] Integrating capistrano with SMF | Notes from a messy desk (tags: capistrano solaris) [...]

February 24, 2008 | Unregistered CommenterRAILroading » Blog Archi

For using 'pfexec' instead of 'sudo' using capistrano >= 2.1, you need to patch capistrano, as it adds "-p ..." option to the sudo call by default (which is not understood by pfexec).

To get the patch got to: http://capistrano.lighthouseapp.com/projects/8716/tickets/49-patch-do-not-use-p-option-with-sudo-if-sudo_prompt-is-empty

September 15, 2008 | Unregistered CommenterMatthias Marschall

Hi,
Unfortunately the SMF XML seems to have been eaten up by your parser.
Could I ask you to fix the article/e-mail the SMF to me?

Thank you

December 21, 2008 | Unregistered CommenterFrank Malina

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>