Browse files

Implemented an init.d script to manage the Jungle.

The script allows running Puma apps as daemons using start-stop-daemon and adds an easy way to log its activity.
  • Loading branch information...
1 parent ca21111 commit f2cb62c74977317e606a292805205464cdaa5729 Darío Javier Cravero committed Aug 11, 2012
Showing with 391 additions and 0 deletions.
  1. +4 −0 README.md
  2. +52 −0 tools/jungle/README.md
  3. +332 −0 tools/jungle/puma
  4. +3 −0 tools/jungle/run-puma
View
4 README.md
@@ -122,6 +122,10 @@ If you start puma with `-S some/path` then you can pass that same path to the `p
will cause the server to perform a restart. `pumactl` is a simple CLI frontend to the control/status app described above.
+## Managing multiple Pumas / init.d script
+
+If you want an easy way to manage multiple scripts at once check "tools/jungle" for an init.d script.
+
## License
Puma is copyright 2011 Evan Phoenix and contributors. It is licensed under the BSD license. See the include LICENSE file for details.
View
52 tools/jungle/README.md
@@ -0,0 +1,52 @@
+# Puma daemon service
+
+Init script to manage multiple Puma servers on the same box using start-stop-daemon.
+
+## Installation
+
+ # Copy the init script to services directory
+ sudo cp puma /etc/init.d
+ sudo chmod +x /etc/init.d/puma
+
+ # Make it start at boot time.
+ sudo update-rc.d -f puma defaults
+
+ # Copy the Puma runner to an accessible location
+ sudo cp run-puma /usr/local/bin
+ sudo chmod +x /usr/local/bin/run-puma
+
+ # Create an empty configuration file
+ sudo touch /etc/puma.conf
+
+## Managing the jungle
+
+Puma apps are held in /etc/puma.conf by default. It's mainly a CSV file and every line represents one app. Here's the syntax:
+
+ app-path,user,config-file-path,log-file-path
+
+You can add an instance by editing the file or running the following command:
+
+ sudo /etc/init.d/puma add /path/to/app user /path/to/app/config/puma.rb /path/to/app/config/log/puma.log
+
+The config and log paths are optional parameters and default to:
+
+* config: /path/to/app/*config/puma.rb*
+* log: /path/to/app/*config/puma.log*
+
+To remove an app, simply delete the line from the config file or run:
+
+ sudo /etc/init.d/puma remove /path/to/app
+
+The command will make sure the Puma instance stops before removing it from the jungle.
+
+## Assumptions
+
+* The script expects a temporary folder named /path/to/app/*tmp/puma* to exist. Create it if it's not there by default.
+The pid and state files should live there and must be called: *tmp/puma/pid* and *tmp/puma/state*.
+You can change those if you want but you'll have to adapt the script for it to work.
+
+* Here's what a minimal app's config file should have:
+
+ pidfile "/path/to/app/tmp/puma/pid"
+ state_path "/path/to/app/tmp/puma/state"
+ activate_control_app
View
332 tools/jungle/puma
@@ -0,0 +1,332 @@
+#! /bin/sh
+### BEGIN INIT INFO
+# Provides: puma
+# Required-Start: $remote_fs $syslog
+# Required-Stop: $remote_fs $syslog
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: Example initscript
+# Description: This file should be used to construct scripts to be
+# placed in /etc/init.d.
+### END INIT INFO
+
+# Author: Darío Javier Cravero <dario@exordo.com>
+#
+# Do NOT "set -e"
+
+# PATH should only include /usr/* if it runs after the mountnfs.sh script
+PATH=/usr/local/bin:/usr/local/sbin/:/sbin:/usr/sbin:/bin:/usr/bin
+DESC="Puma rack web server"
+NAME=puma
+DAEMON=$NAME
+SCRIPTNAME=/etc/init.d/$NAME
+CONFIG=/etc/puma.conf
+JUNGLE=`cat $CONFIG`
+RUNPUMA=/usr/local/bin/run-puma
+
+# 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 jungle
+#
+do_start() {
+ log_daemon_msg "=> Running the jungle..."
+ for i in $JUNGLE; do
+ dir=`echo $i | cut -d , -f 1`
+ user=`echo $i | cut -d , -f 2`
+ config_file=`echo $i | cut -d , -f 3`
+ if [ "$config_file" = "" ]; then
+ config_file="$dir/config/puma.rb"
+ fi
+ log_file=`echo $i | cut -d , -f 4`
+ if [ "$log_file" = "" ]; then
+ log_file="$dir/log/puma.log"
+ fi
+ do_start_one $dir $user $config_file $log_file
+ done
+}
+
+do_start_one() {
+ PIDFILE=$1/tmp/puma/pid
+ if [ -e $PIDFILE ]; then
+ PID=`cat $PIDFILE`
+ # If the puma isn't running, run it, otherwise restart it.
+ if [ "`ps -A -o pid= | grep -c $PID`" -eq 0 ]; then
+ do_start_one_do $1 $2 $3 $4
+ else
+ do_restart_one $1
+ fi
+ else
+ do_start_one_do $1 $2 $3 $4
+ fi
+}
+
+do_start_one_do() {
+ log_daemon_msg "--> Woke up puma $1"
+ log_daemon_msg "user $2"
+ log_daemon_msg "log to $4"
+ start-stop-daemon --verbose --start --chdir $1 --chuid $2 --background --exec $RUNPUMA -- $1 $3 $4
+}
+
+#
+# Function that stops the jungle
+#
+do_stop() {
+ log_daemon_msg "=> Putting all the beasts to bed..."
+ for i in $JUNGLE; do
+ dir=`echo $i | cut -d , -f 1`
+ do_stop_one $dir
+ done
+}
+#
+# Function that stops the daemon/service
+#
+do_stop_one() {
+ log_daemon_msg "--> Stopping $1"
+ PIDFILE=$1/tmp/puma/pid
+ STATEFILE=$1/tmp/puma/state
+ if [ -e $PIDFILE ]; then
+ PID=`cat $PIDFILE`
+ if [ "`ps -A -o pid= | grep -c $PID`" -eq 0 ]; then
+ log_daemon_msg "---> Puma $1 isn't running."
+ else
+ log_daemon_msg "---> About to kill PID `cat $PIDFILE`"
+ pumactl --state $STATEFILE stop
+ # Many daemons don't delete their pidfiles when they exit.
+ rm -f $PIDFILE $STATEFILE
+ fi
+ else
+ log_daemon_msg "---> No puma here..."
+ fi
+ return 0
+}
+
+#
+# Function that restarts the jungle
+#
+do_restart() {
+ for i in $JUNGLE; do
+ dir=`echo $i | cut -d , -f 1`
+ do_restart_one $dir
+ done
+}
+
+#
+# Function that sends a SIGUSR2 to the daemon/service
+#
+do_restart_one() {
+ PIDFILE=$1/tmp/puma/pid
+ i=`grep $1 $CONFIG`
+ dir=`echo $i | cut -d , -f 1`
+
+ if [ -e $PIDFILE ]; then
+ log_daemon_msg "--> About to restart puma $1"
+ pumactl --state $dir/tmp/puma/state restart
+ # kill -s USR2 `cat $PIDFILE`
+ # TODO Check if process exist
+ else
+ log_daemon_msg "--> Your puma was never playing... Let's get it out there first"
+ user=`echo $i | cut -d , -f 2`
+ config_file=`echo $i | cut -d , -f 3`
+ if [ "$config_file" = "" ]; then
+ config_file="$dir/config/puma.rb"
+ fi
+ log_file=`echo $i | cut -d , -f 4`
+ if [ "$log_file" = "" ]; then
+ log_file="$dir/log/puma.log"
+ fi
+ do_start_one $dir $user $config_file $log_file
+ fi
+ return 0
+}
+
+#
+# Function that statuss the jungle
+#
+do_status() {
+ for i in $JUNGLE; do
+ dir=`echo $i | cut -d , -f 1`
+ do_status_one $dir
+ done
+}
+
+#
+# Function that sends a SIGUSR2 to the daemon/service
+#
+do_status_one() {
+ PIDFILE=$1/tmp/puma/pid
+ i=`grep $1 $CONFIG`
+ dir=`echo $i | cut -d , -f 1`
+
+ if [ -e $PIDFILE ]; then
+ log_daemon_msg "--> About to status puma $1"
+ pumactl --state $dir/tmp/puma/state stats
+ # kill -s USR2 `cat $PIDFILE`
+ # TODO Check if process exist
+ else
+ log_daemon_msg "--> $1 isn't there :(..."
+ fi
+ return 0
+}
+
+do_add() {
+ str=""
+ # App's directory
+ if [ -d "$1" ]; then
+ if [ "`grep -c "^$1" $CONFIG`" -eq 0 ]; then
+ str=$1
+ else
+ echo "The app is already being managed. Remove it if you want to update its config."
+ exit 1
+ fi
+ else
+ echo "The directory $1 doesn't exist."
+ exit 1
+ fi
+ # User to run it as
+ if [ "`grep -c "^$2:" /etc/passwd`" -eq 0 ]; then
+ echo "The user $2 doesn't exist."
+ exit 1
+ else
+ str="$str,$2"
+ fi
+ # Config file
+ if [ "$3" != "" ]; then
+ if [ -e $3 ]; then
+ str="$str,$3"
+ else
+ echo "The config file $3 doesn't exist."
+ exit 1
+ fi
+ fi
+ # Log file
+ if [ "$4" != "" ]; then
+ str="$str,$4"
+ fi
+
+ # Add it to the jungle
+ echo $str >> $CONFIG
+ log_daemon_msg "Added a Puma to the jungle: $str. You still have to start it though."
+}
+
+do_remove() {
+ if [ "`grep -c "^$1" $CONFIG`" -eq 0 ]; then
+ echo "There's no app $1 to remove."
+ else
+ # Stop it first.
+ do_stop_one $1
+ # Remove it from the config.
+ sed -i "\\:^$1:d" $CONFIG
+ log_daemon_msg "Removed a Puma from the jungle: $1."
+ fi
+}
+
+case "$1" in
+ start)
+ [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
+ if [ "$#" -eq 1 ]; then
+ do_start
+ else
+ i=`grep $2 $CONFIG`
+ dir=`echo $i | cut -d , -f 1`
+ user=`echo $i | cut -d , -f 2`
+ config_file=`echo $i | cut -d , -f 3`
+ if [ "$config_file" = "" ]; then
+ config_file="$dir/config/puma.rb"
+ fi
+ log_file=`echo $i | cut -d , -f 4`
+ if [ "$log_file" = "" ]; then
+ log_file="$dir/log/puma.log"
+ fi
+ do_start_one $dir $user $config_file $log_file
+ fi
+ 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"
+ if [ "$#" -eq 1 ]; then
+ do_stop
+ else
+ i=`grep $2 $CONFIG`
+ dir=`echo $i | cut -d , -f 1`
+ do_stop_one $dir
+ fi
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ status)
+ # TODO Implement.
+ log_daemon_msg "Status $DESC" "$NAME"
+ if [ "$#" -eq 1 ]; then
+ do_status
+ else
+ i=`grep $2 $CONFIG`
+ dir=`echo $i | cut -d , -f 1`
+ do_status_one $dir
+ fi
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ restart)
+ log_daemon_msg "Restarting $DESC" "$NAME"
+ if [ "$#" -eq 1 ]; then
+ do_restart
+ else
+ i=`grep $2 $CONFIG`
+ dir=`echo $i | cut -d , -f 1`
+ do_restart_one $dir
+ fi
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ add)
+ if [ "$#" -lt 3 ]; then
+ echo "Please, specifiy the app's directory and the user that will run it at least."
+ echo " Usage: $SCRIPTNAME add /path/to/app user /path/to/app/config/puma.rb /path/to/app/config/log/puma.log"
+ echo " config and log are optionals."
+ exit 1
+ else
+ do_add $2 $3 $4 $5
+ fi
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ remove)
+ if [ "$#" -lt 2 ]; then
+ echo "Please, specifiy the app's directory to remove."
+ exit 1
+ else
+ do_remove $2
+ fi
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ *)
+ echo "Usage:" >&2
+ echo " Run the jungle: $SCRIPTNAME {start|stop|status|restart}" >&2
+ echo " Add a Puma: $SCRIPTNAME add /path/to/app user /path/to/app/config/puma.rb /path/to/app/config/log/puma.log"
+ echo " config and log are optionals."
+ echo " Remove a Puma: $SCRIPTNAME remove /path/to/app"
+ echo " On a Puma: $SCRIPTNAME {start|stop|status|restart} PUMA-NAME" >&2
+ exit 3
+ ;;
+esac
+:
View
3 tools/jungle/run-puma
@@ -0,0 +1,3 @@
+#!/bin/bash
+app=$1; config=$2; log=$3;
+cd $app && exec bundle exec puma -C $config 2>&1 >> $log

0 comments on commit f2cb62c

Please sign in to comment.