Friday, February 12, 2010

An init.d script for CouchDB Lucene

‹prev | My Chain | next›

I am not in a particular hurry to deploy my bleeding edge EEE Cooks (running CouchDB 0.10, couchdb-lucene 0.5 pre-release, and Sinatra 1.0 pre-release). I have not added any new functionality, though I have smoothed some rough edges. Still, it's best to deploy often.

If I am to have couchdb-lucene running as a daemon on an actual install, I will need a way to start / stop it. It is packaged with a run script:
#!/bin/sh

DIR=`dirname "$0"`
cd $DIR/..

JAVA_OPTS="-server -Xmx1g"
CLASS=com.github.rnewson.couchdb.lucene.Main

CLASSPATH="conf"
for JAR in `ls lib/*.jar`
do
CLASSPATH="$CLASSPATH:$JAR"
done

exec java $JAVA_OPTS -cp $CLASSPATH $CLASS
That works fine when testing, but all it is doing is exec'ing a java server process—no PID is generated for God to monitor and no easy way to start up when the server starts.

It looks as though upstart might be an interesting option for this. Since my production server is Debian, not Ubuntu, that may be too much work for now. So I will stick with good old init.d scripts and the start-stop-daemon command.

The PIDFILE stop-start-daemon equivalent of the exec in couchdb-lucene's bin/run would look something like:
start-stop-daemon --start \
--background --oknodo \
--make-pidfile --pidfile /tmp/couchdb-lucene.pid \
--exec /usr/bin/java -- $JAVA_OPTS -cp $CLASSPATH $CLASS
Most of the options are fairly obvious and are described well enough in the man page. The --make-pidfile and --pidfile options take care of creating a standard PID file that the start-stop-daemon and process monitors can use. The only interesting option in there is --oknodo, which some folks think ought to be the default. It instructs start-stop-daemon to treat no-operations (like calling start after the process is already started) as a success—it is OK if there is nothing to do. Getting a failure in that case seems silly.

I can use that command line to build a full fledge init.d script that looks like this:
#!/bin/sh

#Original /etc/init.d/skeleton modified for http://mydebian.blogdns.org

COUCHDB_LUCENE_DIR="/home/cstrom/local/couchdb-lucene"

### BEGIN INIT INFO
# Provides: couchdb
# Required-Start: $local_fs $remote_fs
# Required-Stop: $local_fs $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Apache CouchDB init script
# Description: Apache CouchDB init script for the database server.
### END INIT INFO


# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="lucene server for CouchDB"
NAME="couchdb-lucene"
DAEMON=/usr/bin/java

JAVA_OPTS="-server -Xmx1g"
CLASS=com.github.rnewson.couchdb.lucene.Main
CLASSPATH="$COUCHDB_LUCENE_DIR/conf"
for JAR in `ls $COUCHDB_LUCENE_DIR/lib/*.jar`
do
CLASSPATH="$CLASSPATH:$JAR"
done

PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/couchdb-lucene
#the user that will run the script
USER=couchdb

# NO NEED TO MODIFY THE LINES BELOW

# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions

#
# Function that starts the daemon/service
#
do_start()
{
start-stop-daemon --start --oknodo --make-pidfile --pidfile $PIDFILE --background --chuid $USER --exec $DAEMON -- $JAVA_OPTS -cp $CLASSPATH $CLASS
}

#
# Function that stops the daemon/service
#
do_stop()
{
start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE
RETVAL="$?"
rm -f $PIDFILE
return "$RETVAL"
}

case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
restart)
#
# If the "reload" option is implemented then remove the
# 'force-reload' alias
#
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|restart}" >&2
exit 3
;;
esac

:
The skeleton for that script was taken from the mydebian site and modified slightly for an Ubuntu environment.

Logging is done via log4j, which is configured in the COUCHDB_LUCENE_DIR/conf/log4j.xml file. Specifically, I specify the path to the file:
  <!-- Output to file, adjust path to taste. -->
<appender name="FILE" class="org.apache.log4j.RollingFileAppender">
<param name="file" value="/var/log/couchdb/couchdb-lucene.log"/>
</appender>
...
<root>
<priority value="WARN"/>
<appender-ref ref="FILE"/>
</root>
...
With that, I can /etc/init.d/couchdb-lucene start and check /var/log/couchdb/couchdb-lucene.log to find:
2010-02-12 23:47:01,133 INFO [Main] Index output goes to: /home/cstrom/local/couchdb-lucene-0.5-SNAPSHOT/indexes
2010-02-12 23:47:01,237 INFO [Main] Accepting connections with SelectChannelConnector@localhost:5985
Update: Because I used the INIT INFO section, I can add the couchdb-lucene init.d scripts to the appropriate start-up levels via update-rc.d:
cstrom@whitefall:~/repos/eee-code$ sudo update-rc.d couchdb-lucene defaults
Adding system startup for /etc/init.d/couchdb-lucene ...
/etc/rc0.d/K20couchdb-lucene -> ../init.d/couchdb-lucene
/etc/rc1.d/K20couchdb-lucene -> ../init.d/couchdb-lucene
/etc/rc6.d/K20couchdb-lucene -> ../init.d/couchdb-lucene
/etc/rc2.d/S20couchdb-lucene -> ../init.d/couchdb-lucene
/etc/rc3.d/S20couchdb-lucene -> ../init.d/couchdb-lucene
/etc/rc4.d/S20couchdb-lucene -> ../init.d/couchdb-lucene
/etc/rc5.d/S20couchdb-lucene -> ../init.d/couchdb-lucene

Day #12

No comments:

Post a Comment