Apache Cassandra FreeBSD rc.d script

We are a FreeBSD shop, so naturally we run our Apache Cassandra cluster on it. Unfortunately, there isn’t an rc.d script for it. Using cassandra/bin/cassandra -p /var/run/cassandra.pid has been working fine without any grief. However, it would be nice to utilize the rc system built into FreeBSD. I took the Tomcat 6.0 rc script that it is in the port system (www/tomcat6) and adapted it for cassandra.

Place into /usr/local/etc/rc.d/cassandra

#!/bin/sh
#

# PROVIDE: cassandra
# REQUIRE: LOGIN
# KEYWORD: shutdown

#
# Configuration settings for cassandra in /etc/rc.conf:
#
# cassandra_enable (bool):
#   Set to "NO" by default.
#   Set it to "YES" to enable Cassandra
#
# cassandra_user (bool):
#   Set to "cassandra" by default.
#
# cassandra_home (str):
#   Default to "/usr/local/cassandra"
#   Base cassandra directory
#
# cassandra_base (str):
#   Default to "/usr/local/share/cassandra"
#   Directory containing Cassandra config files
#
# cassandra_stdout_log (str):
#   Default to "/var/logs/cassandra/stdout.log"
#
# cassandra_stderr_log (str):
#   Default to "/var/logs/cassandra/stderr.log"
#
# cassandra_props (str):
#
# cassandra_java_home (str):
# cassandra_java_vendor (str):
# cassandra_java_version (str):
# cassandra_java_os (str):
#   Requires of the Java VM. See javavm(1).
#
# cassandra_jvm_opts (str):
#   Default to ones provided in "${cassandra_base}/conf/cassandra-env.sh"
# 

. /etc/rc.subr

name="cassandra"
rcvar=`set_rcvar`
pidfile="/var/run/cassandra.pid"

load_rc_config "${name}"

: ${cassandra_enable="NO"}
: ${cassandra_user="cassandra"}
: ${cassandra_home="/usr/local/cassandra"}
: ${cassandra_base="/usr/local/share/cassandra"}
: ${cassandra_stdout_log="/var/logs/cassandra/stdout.log"}
: ${cassandra_stderr_log="/var/logs/cassandra/stderr.log"}

required_files="${cassandra_base}/conf/cassandra.yaml ${cassandra_base}/conf/log4j-server.properties"

if [ -z "${cassandra_jvm_opts}" -a -f "${cassandra_base}/conf/cassandra-env.sh" ]; then
    . "${cassandra_base}/conf/cassandra-env.sh"
fi

if [ -n "${JVM_OPTS}" ] ; then
    cassandra_jvm_opts="${JVM_OPTS}"
fi

if [ -n "${cassandra_java_home}" ] ; then
    export JAVA_HOME="${cassandra_java_home}"
fi

if [ -n "${cassandra_java_version}" ] ; then
    export JAVA_VERSION="${cassandra_java_version}"
fi

if [ -n "${cassandra_java_vendor}" ] ; then
    export JAVA_VENDOR="${cassandra_java_vendor}"
fi

if [ -n "${cassandra_java_os}" ] ; then
    export JAVA_OS="${cassandra_java_os}"
fi

cassandra_classpath="${cassandra_base}/conf:${cassandra_home}/build/classes"

for jar in ${cassandra_home}/lib/*.jar ; do
    cassandra_classpath=${cassandra_classpath}:${jar}
done

java_class="org.apache.cassandra.thrift.CassandraDaemon"
java_command="/usr/local/bin/java \
    ${cassandra_jvm_opts} \
    -Dlog4j.configuration=log4j-server.properties \
    -Dcassandra-pidfile=${pidfile} \
    -cp ${cassandra_classpath} \
    ${cassandra_props}
    ${java_class}"

log_args=">> ${cassandra_stdout_log} \
    2>> ${cassandra_stderr_log} "

command="/usr/sbin/daemon"
command_args="-p ${pidfile} -u ${cassandra_user} ${java_command} ${log_args}"

start_precmd="pid_touch"
start_cmd="cassandra_start"
stop_cmd="cassandra_stop"
status_cmd="cassandra_status"

pid_touch() {
    touch ${pidfile}
    chown ${cassandra_user} ${pidfile}
}

cassandra_start() {
    echo "Starting cassandra."
    exec ${command} ${command_args}
}

cassandra_stop() {
    rc_pid=$(cassandra_check_pidfile ${pidfile})

    if [ -z "${rc_pid}" ]; then
        [ -n "${rc_fast}" ] && return 0
        echo "${name} not running? (check ${pidfile})."
        return 1
    fi
    
    echo "Stopping ${name}."
    kill -KILL ${rc_pid} 2> /dev/null && echo "Killed."
    rm -f ${pidfile}
}

cassandra_status() {
    rc_pid=$(cassandra_check_pidfile $pidfile)

    if [ -n "${rc_pid}" ]; then
        echo "${name} is running as pid ${rc_pid}."
    else
        echo "${name} is not running."
        return 1
    fi
}

cassandra_check_pidfile() {
    _pidfile=$1
    if [ -z "${_pidfile}" ]; then
        err 3 'USAGE: cassandra_check_pidfile pidfile'
    fi
    if [ ! -f ${_pidfile} ]; then
        debug "pid file (${_pidfile}): not readable."
        return
    fi
    read _pid _junk < ${_pidfile}
    if [ -z "${_pid}" ]; then
        debug "pid file (${_pidfile}): no pid in file."
        return
    fi
    if [ -n "`/usr/local/bin/jps -l | grep -e "^${_pid} ${java_class}\$"`" ]; then
        echo -n ${_pid}
    fi
}

run_rc_command "$1"

  • Pingback: Tweets that mention Apache Cassandra FreeBSD rc.d script « Dctr Watson -- Topsy.com()

  • Rob N

    Hiya,
    Very helpful to see your code. If you are interested I was able to take some of your ideas and use more of the freely provided FreeBSD infrastructure to simplify the startup script.
    My particular need was to kick off a shell script at boot. Making use of the status and stop logic built into FreeBSD’s rc.subr library.
    The main difference is that you can eliminate the need for the _stop(), _status() and _check_pidfile() routines making your code much easier to maintain.
    Here is my skeleton rc.d script:

    #!/bin/sh

    # @(#) $Header: /home/cvs/configs/rc.d.skel,v 1.1 2012/10/13 00:43:08 ran Exp $

    # PROVIDE: poop
    # REQUIRE: postgresql_prod

    . /etc/rc.subr

    name=”poop”
    rcvar=$(set_rcvar)

    # set default values, to be overridden in /etc/rc.conf
    poop_pgdata=${poop_pgdata:-“/data/pg/prod”}
    poop_user=${poop_user:-“postgres”}
    poop_watcher=${poop_watcher:-“/tmp/sleeper.sh”}
    poop_watcher_args=”-D ${poop_pgdata}”

    pidfile=/var/run/${name}.pid
    command=/usr/sbin/daemon
    command_args=”-f -p ${pidfile} -u ${poop_user} ${poop_watcher} ${poop_watcher_args}”

    start_cmd=”${name}_start”
    start_precmd=”touch_pid”
    procname=”/usr/local/bin/ksh93″
    required_files=”${poop_watcher}”

    poop_start()
    {
    exec ${command} ${command_args}
    }

    touch_pid()
    {
    touch ${pidfile}
    chown ${poop_user} ${pidfile}
    }

    load_rc_config $name
    run_rc_command “$1″