Starting ferret at reboot using Capistrano

Posted by jeff

I like using Ferret and acts_as_ferret to add full-text search to my models in Rails in a database-independent way. I’ve had a very difficult time getting this to work smoothly with my deployment process because the ferret server needs to be run in a separate process.

Every time the server reboots, you need to start the ferret server, and everytime you deploy your app you need to restart the ferret server. You can go to the acts_as_ferret site to get more information about deployment strategies, but here’s what’s been working for me for a while now.

First, you need to create a startup script that can be run on boot. I’ve taken mine from the railsmachine tutorial, but you can also use the one from the acts_as_ferret tutorial. Mine looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# located in config/templates/ferret_ctl.erb
#!/bin/bash
#
# This script starts and stops the ferret DRb server
# chkconfig: 2345 89 36
# description: Ferret search engine for ruby apps.
#
# save the current directory
CURDIR=`pwd`
PATH=/usr/local/bin:$PATH

RORPATH="<%= current_path %>"

case "$1" in
  start)
     cd $RORPATH
     echo "Starting ferret DRb server."
     RAILS_ENV=<%= rails_env %> script/ferret_start
     ;;
  stop)
     cd $RORPATH
     echo "Stopping ferret DRb server."
     RAILS_ENV=<%= rails_env %> script/ferret_stop
    ;;
  *)
     echo $"Usage: $0 {start, stop}"
     exit 1
     ;;
esac

cd $CURDIR

Next, add the following capistrano tasks to your deploy.rb file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# =============================================================================
# FERRET
# =============================================================================
set :ferret_script_name, "ferret_#{application}_ctl"
set :ferret_ctl, "/etc/init.d/#{ferret_script_name}"

namespace :ferret do
  desc "Uploads the ferret startup script"
  task :install, :roles => :app, :only => {:primary => true} do 
    require 'erb'
    upload_path = "#{shared_path}/ferret" 
    template = File.read("config/templates/ferret_ctl.erb")
    file = ERB.new(template).result(binding) 
    put file, upload_path, :mode => 0755
    sudo "cp #{upload_path} #{ferret_ctl}"
    sudo "chmod +x #{ferret_ctl}"
    sudo "/sbin/chkconfig #{ferret_script_name} on"
  end 

  desc "Starts the ferret server"
  task :start, :roles => :app, :only => {:primary => true} do
    sudo "#{ferret_ctl} start"
  end

  desc "Stops the ferret server"
  task :stop, :roles => :app, :only => {:primary => true} do
    sudo "#{ferret_ctl} stop"
  end

  desc "Restarts the ferret server"
  task :restart, :roles => :app, :only => {:primary => true} do
    ferret.stop
    ferret.start
  end
  
  desc "Deletes the ferret startup script"
  task :uninstall, :roles => :app, :only => {:primary => true} do 
    sudo "/sbin/chkconfig #{ferret_script_name} off"
    sudo "rm -rf #{ferret_ctl}"
  end 
  
end
after "deploy:symlink", "ferret:restart"

Now you are ready to deploy – just execute the following commands to get set up with your script:

cap ferret:install
cap deploy

The installation will:

  • Upload your startup script to /etc/init.d and set the correct permissions
  • When you deploy it will restart the drb servers before restarting mongrel

Thanks to the folks at Railsmachine for providing detailed instructions about chkconfig, and the acts_as_ferret folks for providing the drb server.

Setting up and deploying a rails app to a remote git server

Posted by jeff

(Updated on 3/31/08 with new “edge” branch checkout)

In a previous post I wrote about how to get git installed on CentOS. Now that git is installed it’s time to actually set up a remote repository with git. In this tutorial I’ll explain how to:

  • create a git user on the remote server and configure the new git user correctly
  • configure the deploy user correctly
  • create a rails app locally and push it to the remote git server
  • set up capistrano for deploying the app using git

Assumptions

  • you deploy under the user “deploy”
  • your domain name is example.com
  • you have installed git at /usr/local/bin/git
  • you have root access (otherwise it might have to skip the part about setting up the git user’s shell)

Prepare the remote server

First, log into your server as deploy, create the git user and setup your ssh keys.

sudo adduser git
sudo passwd git
ssh-keygen -t rsa -f ~/.ssh/id_rsa -C "deploy@example.com" 
ssh git@example.com 'mkdir ~/.ssh;chmod 700 ~/.ssh' 
scp ~/.ssh/id_rsa.pub git@example.com:~/.ssh/authorized_keys
ssh git@example.com 'chmod 600 ~/.ssh/authorized_keys' 

As a convenience, you may want to add your ssh key to the git user’s authorized_keys. To do so, execute the following on your local machine:

cat ~/.ssh/id_rsa.pub | ssh git@example.com 'sh -c "cat - >>~/.ssh/authorized_keys"'

(you may have to change this to id_dsa.pub – or whatever your public key name is).

Back on the server, if you haven’t already, you’ll also want to set up your git config files for the deploy user:

git config --global user.name "Deploy" 
git config --global user.email "deploy@example.com" 

That name and username can be anything you want it to be.

Next, you’ll have to add a shell to /etc/shells. To do so you’ll need to be root:

su -
echo '/usr/local/bin/git-shell'>> /etc/shells
exit

To make sure this worked, you can type

cat /etc/shells

Now log in as the git user and set a few things up:

su - git
git config --global user.name "Git" 
git config --global user.email "git@example.com" 
chsh
[when prompted - enter /usr/local/bin/git-shell]
exit

Create the app

So now you have a git user with a slightly more secure git shell and your ssh keys are set up from both your local machine and your deploy user’s account. It’s time to create the rails app on your local machine. For this to work, you’ll need to make sure that you have the capistrano and railsmachine gems installed. Next create a rails app, capify and railsmachinify it and type a few git commands.

sudo gem install capistrano railsmachine --no-ri --no-rdoc
rails git_import_test
cd git_import_test
capify .
railsmachine --apply-to . --name git_import_test --domain example.com

Now go into config/deploy.rb and add the following task to the bottom of the file (you can also add this to your ~/.caprc file to use it across all of your rails apps):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
require 'fileutils'
Capistrano::Configuration.instance(:must_exist).load do

  namespace :git do
    desc "Setup directory structure and initialize git repository on remote server"
    task :setup, :roles => :scm do
      dir =  "#{deploy_to}/git"
      run    "mkdir -p #{dir}"
      sudo   "chown -R deploy:deploy #{dir}"
      run   "cd #{dir} && git --bare init"
      run   "chmod 770 #{dir}"
      sudo   "chown -R git:git #{dir}"
    end

    desc "Import code into remote git repository."
    task :import  do
      puts "Initializing local git repository"
      system  "git init"

      puts "Adding remote server pointing to #{repository}"
      system  "git remote add origin #{repository}"

      puts "Adding .gitignore file"
      system "echo 'log/*'>> .gitignore"
      system "echo 'tmp/*'>> .gitignore"
      system "echo '.DS_Store'>> .gitignore"
      system "echo 'public/cache/**/*'>> .gitignore"
      system "git add .gitignore"

      puts "Committing application locally"
      system "git add *"
      system 'git commit -a -v -m "initial import of site"'

      puts "Pushing application to the remote server.  The name of the branch is:"
      system  "git remote"
      system  "git push origin master"
      puts "Creating edge branch on remote"
      system "git push origin master:refs/heads/edge"
      puts "create a local tracking edge branch"
      system "git branch --track edge origin/edge"
      puts "checking out edge repository"
      system "git checkout edge"
      puts "git setup complete"
      puts "You can clone this repository with git clone #{repository}"
    end
  end
end

This will

  • Create the local repository
  • Add an ignore file
  • Add all files
  • Push to the master
  • Create a new edge branch on the local and remote
  • Switch the local branch to edge

Next, update your deploy.rb file to point to your new git repository and you’ll be ready to deploy. Make sure your deploy.rb file has entries that look like:

1
2
set :repository,    "ssh://git@example.com#{deploy_to}/git"
set :scm,           :git

Deploy

To deploy you can use the tasks that come with the railsmachine gem, along with your new git capistrano task:

cap deploy:setup
cap git:setup
cap apache:configure
cap mongrel:cluster:configure
cap git:import

If you are using mysql, you will have to also run

cap mysql:setup

Now you can deploy, run migrations, start your mongrels and restart your web server with

cap deploy:cold

References:

This post heavily references:

Related posts:

Installing Git on Railsmachine (CentOS 4.4)

Posted by jeff

[updated 03/09/2008]

[updated 03/21/2008 for Git 1.5.4.4]

[you can also follow the RailsMachine wiki instructions ]

Keeping up with the Joneses

A few days ago I read that mephisto 0.8 was released and that all of the cool kids were grabbing it from the git repository. I promptly got hip to git from John Nunemaker’s post on git and github and grabbed the peepcode screencast to get started.

A few minutes later I was ready to deploy to my Rails Machine slice running CentOS 4.4.

Not so yummy

I dig package managers, and since git is really a collection of a few dozen executables it’s the perfect candidate. So I naively typed

1
yum install git

thinking that it might “just work”, but instead it completely blew up on me with errors such as:

1
2
Error: Missing Dependency: libaprutil-0.so.0 is needed by package subversion
Error: Missing Dependency: libapr-0.so.0 is needed by package subversion

After a few support emails with Rails Machine, it seemed like there might be some discrepancies with the rpms from the RailsMachine repo and the rpmforge repo. Not being familiar with yum, I had no idea what to do (and still don’t), so I abandoned yum altogether.

Consider the source

Thanks to Rob over at Rails Machine and cactus over at the slicehost forum I got git installed from source on the slice. Here’s what worked for me:

Follow the instructions from Dan Insley and setup the following repositories:

to follow the steps below and git will be installed in a snap:

$ sudo touch /etc/yum.repos.d/atrpms.repo /etc/yum.repos.d/dag.repo
[atrpms]
name=ATrpms for Enterprise Linux $releasever - $basearch
baseurl=http://dl.atrpms.net/el$releasever-$basearch/atrpms/stable
enabled=0
gpgcheck=1
gpgkey=http://ATrpms.net/RPM-GPG-KEY.atrpms
[dag]
name=Dag
enabled=0
baseurl=http://dag.freshrpms.net/redhat/el4/en/$basearch/dag
http://ftp.heanet.ie/pub/freshrpms/pub/dag/redhat/el4/en/i386/dag/
gpgcheck=1
gpgkey=http://dag.wieers.com/packages/RPM-GPG-KEY.dag.txt
1
2
3
4
5
6
7
8
9
10
sudo yum --enablerepo=dag --enablerepo=atrpms install asciidoc xmlto curl curl-devel
mkdir -p ~/sources
cd ~/sources
wget http://kernel.org/pub/software/scm/git/git-1.5.4.4.tar.gz
tar xvzf git-1.5.4.4.tar.gz
cd git-1.5.4.4
make configure
./configure --prefix=/usr/local
NO_TCLTK=yes make all doc
NO_TCLTK=yes sudo make install install-doc

You can also save yourself some time if you don’t need the docs by changing those last 2 lines to:

NO_TCLTK=yes make all
NO_TCLTK=yes sudo make install

Depending on your setup, the “NO_TCLTK=yes” flag might not be necessary. You can always try it without first if you are unsure, but I’ve needed it on all of my RailsMachine slices.

References