--- /dev/null
+#!/bin/bash
+################################################################################
+#
+# df.generic
+# Bash Daemon for System Monitoring
+# Generic df plugin for monitoring disk utilization
+#
+#
+#
+#
+###############################################################################
+
+# TRAP UNKNOWN ERRORS
+###############################################################################
+trap failure SIGTERM SIGINT SIGFPE
+
+failure()
+{
+ error "Something has gone SERIOUSLY wrong! (Received signal $?)"
+ return 255
+}
+
+error()
+{
+ printf "\e[41m" 1>&2
+ printf "ERROR: $1" 1>&2
+ printf "\e[0m\n" 1>&2
+}
+
+# VARIABLES
+###############################################################################
+SCRIPT=$0
+HOSTNAME=$2
+DELAY=$3
+LABEL=$4
+PATH=$5
+OUTPATH=/home/bdsm/out.fifo
+
+# MAIN FUNCTIONS
+###############################################################################
+help()
+{
+ echo "Generic df disk utilization monitoring"
+ echo "USAGE: $0 [FUNCTION] [HOSTNAME] [DELAY]"
+ echo "FUNCTION -- start/stop/status/help"
+ echo "HOSTNAME -- the hostname to monitor"
+ echo "::DELAY -- seconds between measurements"
+ echo "::LABEL -- label for this drive"
+ echo "::DRIVE -- filesystem path to monitor"
+ exit 0
+}
+
+start()
+{
+ running=`ssh $HOSTNAME "cat /home/bdsm/.df.pid | \
+ xargs ps -T | \
+ grep -v PID | \
+ wc -l"` 2>/dev/null
+
+ if [ $running -eq 0 ] || [ $running -gt 5 ]; then
+ # Check if df is installed
+ installed=`ssh -q $HOSTNAME "df > /dev/null 2>&1; echo $?"`
+ if [ ! $installed ]; then
+ echo "" > $OUTPATH
+ return 1
+ fi
+
+ ssh -q $HOSTNAME <<EOF
+ while [ 1 ]; do
+ df=`df --output=pcent / | tail -1 | sed 's/[^0-9]//g'`
+ ts=`date '+%s'`
+ echo "$ts|$HOSTNAME|DISK-$LABEL-USED|$df" >> $OUTPATH
+ sleep $DELAY
+ done &
+EOF
+ ssh -q $HOSTNAME "ps aux | \
+ grep bdsm | \
+ grep df | \
+ grep -v grep | \
+ awk '{print \$2}' \
+ > /home/bdsm/.df.pid &"
+ else
+ echo "Already Running"
+ fi
+}
+
+stop()
+{
+ ssh $HOSTNAME "kill `cat /home/bdsm/.df.pid`"
+ ssh $HOSTNAME "rm /home/bdsm/.df.pid"
+}
+
+status()
+{
+ running=`ssh $HOSTNAME "cat /home/bdsm/.df.pid | \
+ xargs ps -T | \
+ grep -v PID | \
+ wc -l"`
+
+ if [ $running -eq 0 ]; then
+ echo "OFF"
+ else
+ echo "ON"
+ fi
+}
+
+# UTILITY FUNCTIONS
+###############################################################################
+
+formatConfig()
+{
+ # Reformat config file to be more machine-readable
+ # Removes whitespace and adds semicolons after property values
+ cat /home/bdsm/bdsm.conf | tr '\n' ' ' | sed 's/}/}\
+ /g' | sed 's/^;*//g' | sed "s/[[:space:]]//g"| \
+ sed 's/;\([{}]\)/\1/g' | sed 's/\([{}]\);/\1/g' \
+ > /home/bdsm/.bdsm.conf.tmp
+}
+
+# SCRIPT START
+###############################################################################
+
+# Get a list of configured hosts
+hosts=$(cat /home/bdsm/.bdsm.conf.tmp | cut -d'{' -f1)
+
+if [ -z $1 ]; then
+ help
+elif [ $1 == "start" ]; then
+ formatConfig
+ start
+elif [ $1 == "stop" ]; then
+ formatConfig
+ stop
+elif [ $1 == "status" ]; then
+ formatConfig
+ status
+elif [ $1 == "help" ]; then
+ help
+fi
--- /dev/null
+#!/bin/bash
+################################################################################
+#
+# template.generic
+# Bash Daemon for System Monitoring
+# Generic plugin template
+#
+###############################################################################
+
+# TRAP UNKNOWN ERRORS
+###############################################################################
+trap failure SIGTERM SIGINT SIGFPE
+
+failure()
+{
+ error "Something has gone SERIOUSLY wrong! (Received signal $?)"
+ return 255
+}
+
+error()
+{
+ printf "\e[41m" 1>&2
+ printf "ERROR: $1" 1>&2
+ printf "\e[0m\n" 1>&2
+}
+
+# VARIABLES
+###############################################################################
+SCRIPT=$0
+HOSTNAME=$2
+
+# FIFO pipe to be used for output
+OUTPATH=/home/bdsm/out.fifo
+
+# Optional Parameters
+PARAM1=$3
+PARAM2=$4
+
+# MAIN FUNCTIONS
+###############################################################################
+help()
+{
+ # Print usage information
+ # Formatting is important here, as this is processed by bdsm.sh!
+ # First two parameters should be function and hostname
+ # Other parameters are optional and will be stored in bdsm.conf
+ # Any parameters to be stored in BSDM.conf should output as:
+ # ::[PARAM NAME] -- [PARAM DESCRIPTION]
+ # Parameters NOT stored in bsfc.conf must NOT start with ::!
+ echo "PLUGIN DESCRIPTION GOES HERE"
+ echo "USAGE: $0 [FUNCTION] [HOSTNAME] [PARAMETER 1] [PARAMETER 2]"
+ echo "FUNCTION -- start, stop, status or help"
+ echo "HOSTNAME -- host to run the monitor on"
+ echo "::PARAM1 -- description of the first parameter"
+ echo "::PARAM2 -- description of the second parameter"
+ exit 0
+}
+
+start()
+{
+ # Start the monitor and write output to $OUTPATH
+ # Output should be pipe-delimited
+ # One line per attribute
+ # Format:
+ # $TIMESTAMP|$HOST|$ATTRIBUTE|$VALUE
+ #
+ # TIMESTAMP format is date +%s
+ # HOSTNAME is a global variable
+ # ATTRIBUTE is a string describing what is being measure
+ # ex. "CPU-SY" for system CPU utilization
+ # VALUE is the value measured (ie, percentage)
+ # : Don't include units -- ie, 59 not 59%
+ # : UP/DOWN/??? for service up/down checks
+ # : If those don't make sense, use whatever does, but keep it concise!
+}
+
+stop()
+{
+ # Stop the monitor
+}
+
+status()
+{
+ # Check if the monitor is running and echo ON or OFF
+}
+
+# SCRIPT START
+###############################################################################
+
+# Reformat config file to be more machine-readable
+# Removes whitespace and adds semicolons after property values
+cat /home/bdsm/bdsm.conf | sed "s/[[:space:]]//g" | tr '\n' ' ' | sed 's/}/}\
+ /g' | sed 's/^;*//g' | sed 's/;\([{}]\)/\1/g' | sed 's/\([{}]\);/\1/g' \
+ > /home/bdsm/.bdsm.conf.tmp
+
+# Get a list of configured hosts
+hosts=$(cat /home/bdsm/.bdsm.conf.tmp | cut -d'{' -f1)
+
+if [ -z $1 ]; then
+ help
+elif [ $1 == "start" ]; then
+ start
+elif [ $1 == "stop" ]; then
+ stop
+elif [ $1 == "status" ]; then
+ status
+elif [ $1 == "help" ]; then
+ help
+fi
--- /dev/null
+#!/bin/bash
+################################################################################
+#
+# vmstat.generic
+# Bash Daemon for System Monitoring
+# Generic vmstat plugin
+#
+#
+#
+#
+###############################################################################
+
+# TRAP UNKNOWN ERRORS
+###############################################################################
+trap failure SIGTERM SIGINT SIGFPE
+
+failure()
+{
+ error "Something has gone SERIOUSLY wrong! (Received signal $?)"
+ return 255
+}
+
+error()
+{
+ printf "\e[41m" 1>&2
+ printf "ERROR: $1" 1>&2
+ printf "\e[0m\n" 1>&2
+}
+
+# VARIABLES
+###############################################################################
+SCRIPT=$0
+HOSTNAME=$2
+DELAY=$3
+OUTPATH=/home/bdsm/out.fifo
+
+# MAIN FUNCTIONS
+###############################################################################
+help()
+{
+ echo "Generic vmstat monitoring"
+ echo "USAGE: $0 [FUNCTION] [HOSTNAME] [DELAY]"
+ echo "FUNCTION -- start/stop/status/help"
+ echo "HOSTNAME -- the hostname to monitor"
+ echo "::DELAY -- seconds between measurements"
+ exit 0
+}
+
+start()
+{
+ running=`ssh $HOSTNAME "cat /home/bdsm/.vmstat.pid | \
+ xargs ps -T | \
+ grep -v PID | \
+ wc -l"` 2>/dev/null
+
+ if [ $running -eq 0 ] || [ $running -gt 5 ]; then
+ # Check if vmstat is installed
+ installed=`ssh -q $HOSTNAME "vmstat > /dev/null 2>&1; echo $?"`
+ if [ ! $installed ]; then
+ echo "" > $OUTPATH
+ return 1
+ fi
+
+ # Check what options vmstat supports
+ if [ `ssh -q $HOSTNAME "vmstat -n >/dev/null 2>&1; echo $?"` ]; then
+ vmopt="-n"
+ else
+ vmopt=""
+ fi
+
+ # Check what options awk supports
+ if [ ! -z `ssh $HOSTNAME "echo | awk -W interactive '{print 1}' 2>&1 >/dev/null"` ]; then
+ awkopt=""
+ else
+ awkopt="-W interactive"
+ fi
+
+ ssh -q $HOSTNAME <<EOF
+ vmstat $vmopt $DELAY | awk $awkopt -v host=$HOSTNAME 'BEGIN {
+ OFS="|"
+ }
+ /us/ {
+ uscol=99
+ for(i=1; i<NF; i++)
+ {
+ if(\$i == "us")
+ uscol=i
+ if(\$i == "sy" && i > uscol)
+ sycol=i
+ if(\$i == "wa" && i > uscol)
+ wacol=i
+ if(\$i == "id" && i > uscol)
+ idcol=i
+ }
+ }
+ !/[a-z-]/ {
+ "date '+%s'" | getline ts
+ if(uscol != 99 && uscol != 0)
+ print ts,host,"CPU-US",\$uscol
+ if(sycol != 0)
+ print ts,host,"CPU-SY",\$sycol
+ if(wacol != 0)
+ print ts,host,"CPU-WA",\$wacol
+ if(idcol != 0)
+ print ts,host,"CPU-ID",\$idcol
+ close("date '+%s'")
+ }' >> $OUTPATH &
+EOF
+ ssh -q $HOSTNAME "ps aux | \
+ grep bdsm | \
+ grep vmstat | \
+ grep -v grep | \
+ awk '{print \$2}' \
+ > /home/bdsm/.vmstat.pid &"
+ else
+ echo "Already Running"
+ fi
+}
+
+stop()
+{
+ ssh $HOSTNAME "kill `cat /home/bdsm/.vmstat.pid`"
+ ssh $HOSTNAME "rm /home/bdsm/.vmstat.pid"
+}
+
+status()
+{
+ running=`ssh $HOSTNAME "cat /home/bdsm/.vmstat.pid | \
+ xargs ps -T | \
+ grep -v PID | \
+ wc -l"`
+
+ if [ $running -eq 0 ]; then
+ echo "OFF"
+ else
+ echo "ON"
+ fi
+}
+
+# UTILITY FUNCTIONS
+###############################################################################
+
+formatConfig()
+{
+ # Reformat config file to be more machine-readable
+ # Removes whitespace and adds semicolons after property values
+ cat /home/bdsm/bdsm.conf | tr '\n' ' ' | sed 's/}/}\
+ /g' | sed 's/^;*//g' | sed "s/[[:space:]]//g"| \
+ sed 's/;\([{}]\)/\1/g' | sed 's/\([{}]\);/\1/g' \
+ > /home/bdsm/.bdsm.conf.tmp
+}
+
+# SCRIPT START
+###############################################################################
+
+# Get a list of configured hosts
+hosts=$(cat /home/bdsm/.bdsm.conf.tmp | cut -d'{' -f1)
+
+if [ -z $1 ]; then
+ help
+elif [ $1 == "start" ]; then
+ formatConfig
+ start
+elif [ $1 == "stop" ]; then
+ formatConfig
+ stop
+elif [ $1 == "status" ]; then
+ formatConfig
+ status
+elif [ $1 == "help" ]; then
+ help
+fi
--- /dev/null
+#!/bin/bash
+################################################################################
+#
+# bdsm.sh
+# Bash Daemon for System Monitoring
+#
+# TODO:
+# 1) Fully shakeout configure
+# 2) Finish Deploy
+# ) Plugins:
+# 3) iostat
+# 4) ram
+# 5) disk utilization
+#
+###############################################################################
+
+# TRAP UNKNOWN ERRORS
+###############################################################################
+
+trap failure SIGFPE SIGHUP SIGABRT SIGALRM SIGQUIT
+trap term SIGTERM SIGINT
+
+term()
+{
+ echo
+ echo
+ error "BDSM TERMINATED."
+ exit 1
+}
+
+failure()
+{
+ echo
+ echo
+ error "Something has gone SERIOUSLY wrong! (Received signal $?)"
+ exit 255
+}
+
+# UTILITY FUNCTIONS
+###############################################################################
+error()
+{
+ printf "\e[41m" 1>&2
+ printf "ERROR: $1" 1>&2
+ printf "\e[0m\n" 1>&2
+}
+
+warn()
+{
+ printf "\e[30;43m" 1>&2
+ printf "WARNING: $1" 1>&2
+ printf "\e[0m\n" 1>&2
+
+}
+
+header()
+{
+ echo
+ printf "\e[44m" 1>&2
+ printf " $1" 1>&2
+ printf "\e[0m\n" 1>&2
+}
+
+option()
+{
+ printf "\e[36m" 1>&2
+ printf " $1" 1>&2
+ printf "\e[0m\n" 1>&2
+}
+
+prompt()
+{
+ read -t .25 -n 1000 discard </dev/tty
+ printf "\e[30;46m" 1>&2
+ printf "\r$1" 1>&2
+ printf "\e[0;0m " 1>&2
+}
+
+info()
+{
+ printf "\e[33m"
+ printf "INFO: $1"
+ printf "\e[0m\n"
+}
+
+selector()
+{
+ prmpt=${1}
+ shift
+
+ argarr=( "$@" )
+ i=0
+ while [ ! -z "$1" ]; do
+ option "$i. $1"
+ i=`expr $i + 1`
+ shift
+ done
+
+ selection=-1
+ while [ "$selection" -lt 0 ] || \
+ [ "$selection" -gt $i ] || \
+ [ "`echo $selection | sed 's/[^0-9]//g'`" != "$selection" ]; do
+ prompt "$prmpt: "
+ read selection
+ done
+
+ echo ${argarr[$selection]}
+}
+
+confirm()
+{
+ prmpt=${1}
+
+ prompt "CONFIRM: $prmpt Y/[N]"
+ read selection
+ if [ "$selection" == "Y" ] || [ "$selection" == "y" ]; then
+ echo 0
+ else
+ echo 1
+ fi
+}
+
+# ACTION FUNCTIONS
+###############################################################################
+
+help()
+{
+ echo
+ echo "Bash Daemon for System Monitoring (bdsm.sh)"
+ echo "USAGE: $0 [start|stop|status|deploy|configure|help]"
+ echo
+ echo "If this is your first time executing $0, start with:"
+ echo " $0 configure"
+ echo
+ echo "Once configuration is complete, you must deploy with:"
+ echo " $0 deploy"
+ echo
+ echo "During deployment you may be asked for the root password"
+ echo " for these systems. This is required for configuring user"
+ echo " setup. To avoid this, create a user 'bdsm' on the remote"
+ echo " server and configure passwordless SSH access to this user."
+ echo " This user will need very limited permissions."
+ echo
+ echo " After deployment is completed, you can start, check, or stop:"
+ echo " $0 start"
+ echo " $0 status"
+ echo " $0 stop"
+ echo
+ echo "Returns:"
+ echo " 0: Success!"
+ echo " 1: PEBKAC"
+ echo " 2: Could not connect to remote host"
+ echo " 255: You're on your own. Good luck!"
+}
+
+start()
+{
+ i=0
+ while [ $i -lt ${#hosts[@]} ]; do
+ type=`echo ${hosts[$i]} | cut -d':' -f1`
+ host=`echo ${hosts[$i]} | cut -d':' -f2-`
+ info "Starting $type monitors on $host..."
+ functions=`cat /home/bdsm/.bdsm.conf.tmp | grep "$type:$host" | sed 's/.*{\(.*\)}.*/\1/'`
+
+ j=0
+ echo $functions | tr ';' '\n' | sed 's/[(),]/ /g' | while read line; do
+ command=`echo $line | cut -d' ' -f1`
+ args="`echo $line | cut -d' ' -f2-`"
+ if [ -f /home/bdsm/bdsm.d/$command.$type ]; then
+ /home/bdsm/bdsm.d/$command.$type start $host $args
+ elif [ -f /home/bdsm/bdsm.d/$command.$type ]; then
+ /home/bdsm/bdsm.d/$command.generic start $host $args
+ else
+ error "Could not find plugin for $command on $type:$host!"
+ fi
+ done
+
+ ssh $host "cat /home/bdsm/out.fifo" > /home/bdsm/in.fifo &
+ echo $! > /home/bdsm/pids/$host.in
+
+ i=`expr $i + 1`
+ done
+}
+
+stop()
+{
+ i=0
+ while [ $i -lt ${#hosts[@]} ]; do
+ type=`echo ${hosts[$i]} | cut -d':' -f1`
+ host=`echo ${hosts[$i]} | cut -d':' -f2-`
+ info "Stopping $type monitors on $host..."
+ functions=`cat /home/bdsm/.bdsm.conf.tmp | grep "$type:$host" | sed 's/.*{\(.*\)}.*/\1/'`
+
+ j=0
+ echo $functions | tr ';' '\n' | sed 's/[(),]/ /g' | while read line; do
+ command=`echo $line | cut -d' ' -f1`
+ args="`echo $line | cut -d' ' -f2-`"
+ if [ -f /home/bdsm/bdsm.d/$command.$type ]; then
+ /home/bdsm/bdsm.d/$command.$type stop $host $args
+ elif [ -f /home/bdsm/bdsm.d/$command.$type ]; then
+ /home/bdsm/bdsm.d/$command.generic stop $host $args
+ else
+ error "Could not find plugin for $command on $type:$host!"
+ fi
+ done
+
+ kill `cat /home/bdsm/pids/$host.in` 2>/dev/null
+ rm /home/bdsm/pids/$host.in
+
+ i=`expr $i + 1`
+ done
+}
+
+status()
+{
+ i=0
+ while [ $i -lt ${#hosts[@]} ]; do
+ type=`echo ${hosts[$i]} | cut -d':' -f1`
+ host=`echo ${hosts[$i]} | cut -d':' -f2-`
+ info "Stopping $type monitors on $host..."
+ functions=`cat /home/bdsm/.bdsm.conf.tmp | grep "$type:$host" | sed 's/.*{\(.*\)}.*/\1/'`
+
+ j=0
+ echo $functions | tr ';' '\n' | sed 's/[(),]/ /g' | while read line; do
+ command=`echo $line | cut -d' ' -f1`
+ prefix="$type:$host|$command|"
+ if [ -f /home/bdsm/bdsm.d/$command.$type ]; then
+ /home/bdsm/bdsm.d/$command.$type status $host | sed "s/^/$prefix/g"
+ elif [ -f /home/bdsm/bdsm.d/$command.$type ]; then
+ /home/bdsm/bdsm.d/$command.generic status $host | sed "s/^/$prefix/g"
+ else
+ error "Could not find plugin for $command on $type:$host!"
+ fi
+ done
+
+ pid=`cat /home/bdsm/pids/$host.in`
+ if [ ! -f /home/bdsm/pids/$host.in ]; then
+ echo "$type:$host:MONITOR|???"
+ elif [ `ps -p $pid | wc -l` -ge 2 ]; then
+ echo "$type:$host:MONITOR|UP"
+ else
+ echo "$type:$host:MONITOR|DOWN"
+ fi
+
+ i=`expr $i + 1`
+ done
+}
+
+configure()
+{
+ configured=0
+ if [ -f /home/bdsm/bdsm.conf ]; then
+ prompt "Configuration already exists! [K]eep, [U]pdate, or [D]elete?"
+ read selection
+ if [ $selection == "K" ]; then
+ info "Proceeding with existing configuration..."
+ configured=1
+ elif [ $selection == "U" ]; then
+ info "Updating existing configuration..."
+ elif [ $selection == "D" ]; then
+ info "Purging existing configuration..."
+ rm /home/bdsm/bdsm.conf
+ touch /home/bdsm/bdsm.conf
+ else
+ error "Invalid selection."
+ return 1
+ fi
+ else
+ touch /home/bdsm/bdsm.conf
+ fi
+
+ while [ $configured -ne 1 ]; do
+ # Prompt which host to configure
+ header "Select a host to configure:"
+
+ host=`selector "Select a host" $hosts "New..." "Done"`
+ if [ "$host" == "New..." ]; then
+ host=""
+ elif [ "$host" == "Done" ]; then
+ configured=1
+ break
+ else
+ type=`echo $host | cut -d':' -f1`
+ host=`echo $host | cut -d':' -f2-`
+ fi
+ while [ -z $host ]; do
+ header "Configure a new host"
+
+ types=$(ls /home/bdsm/bdsm.d/ | cut -d'.' -f2 | sort -u)
+ type=`selector "Host type" $types`
+
+ prompt "Hostname: "
+ read host
+
+ if [ `confirm "Confirm creation of $type:$host?"` -eq 0 ]; then
+ echo "$host{}" >> /home/bdsm/.bdsm.conf.tmp
+ else
+ host=""
+ fi
+ done
+
+ header "Configuring $host"
+ availServices=$(ls /home/bdsm/bdsm.d | cut -d'.' -f1 | sort -u)
+ services=$(cat /home/bdsm/.bdsm.conf.tmp | grep ":$host{" | \
+ sed 's/.*{\(.*\)}/\1/g' | tr ';' ' ')
+ service=`selector "Select a service to configure" $services "Add a service..." "Done"`
+
+ if [ "$service" == "Add a service..." ]; then
+ header "Add a new service"
+ service=`selector "Service type: " $availServices`
+ elif [ "$service" == "Done" ]; then
+ continue
+ fi
+
+ header "Configuring $service"
+ if [ `confirm "Disable $service?"` -eq 0 ]; then
+ # TODO
+ # This may need fixed
+ # TODO
+ cat /home/bdsm/.bdsm.conf.tmp | \
+ sed 's/\(.*:$host{.*\)$service;\(.*\)/\1\2/g' \
+ > /home/bdsm/.bdsm.conf.tmp2
+ mv /home/bdsm/.bdsm.conf.tmp2 /home/bdsm/.bdsm.conf.tmp
+ else
+ header "Reconfiguring $service"
+ svc=`echo $service | sed 's/(.*)$//g'`
+ if [ -f /home/bdsm/bdsm.d/$svc.$type ]; then
+ serviceFile="$svc.$type"
+ elif [ -f /home/bdsm/bdsm.d/$svc.generic ]; then
+ serviceFile="$svc.generic"
+ else
+ error "$service plugin not found!"
+ fi
+
+ max=`echo $params | wc -l`
+ newservice=`echo $service | cut -d'(' -f1`"("
+ i=1
+ while [ $i -le $max ]; do
+ param="`/home/bdsm/bdsm.d/$serviceFile help | grep "^::" | sed -n ${i}p`"
+ paramName="`echo ${param} | sed 's/^::\(.*\) *--.*/\1/g'`"
+ paramDesc="`echo ${param} | sed 's/^.*--\(.*\)/\1/g'`"
+ prompt "$paramName: "
+ read param
+ newservice=${newservice}${param}","
+ i=`expr $i + 1`
+ done
+ newservice=`echo $newservice | sed 's/,$/)/g'`
+ fi
+
+ # TODO
+ # Validate removal/replacement of old service
+ # TODO
+ curHost="`cat /home/bdsm/.bdsm.conf.tmp | grep ":$host{"`"
+ curHost=`echo $curHost | sed "s/$service;//g" | sed "s/}\$/$newservice;}/g"`
+ cat /home/bdsm/.bdsm.conf.tmp | \
+ grep -v ":$host{" \
+ > /home/bdsm/.bdsm.conf.tmp2
+ echo $curHost >> /home/bdsm/.bdsm.conf.tmp2
+ mv /home/bdsm/.bdsm.conf.tmp2 /home/bdsm/.bdsm.conf.tmp
+ # Reload the hosts list
+ hosts=$(cat /home/bdsm/.bdsm.conf.tmp | cut -d'{' -f1)
+ done
+
+ # Convert config back to a more readable format
+ cat /home/bdsm/.bdsm.conf.tmp | sed 's/{/\
+ {\
+ /g' | sed 's/;/;\
+ /g' | sed 's/}/}\
+ /g' > /home/bdsm/bdsm.conf
+ rm /home/bdsm/.bdsm.conf.tmp
+
+ info "Configuration complete!"
+ info "Don't forget to DEPLOY these changes!"
+ exit 0
+}
+
+deploy()
+{
+ i=0
+ while [ $i -lt ${#hosts[@]} ]; do
+ type=`echo ${hosts[$i]} | cut -d':' -f1`
+ host=`echo ${hosts[$i]} | cut -d':' -f2-`
+ info "Deploying on $host..."
+
+ ssh -q bdsm@$host
+ ret=$?
+ if [ ! $ret ]; then
+ info "Passwordless SSH not configured. Creating bdsm user as root..."
+ ssh root@$host "useradd --home-dir /home/bdsm bdsm"
+
+ info "Logging in as bdsm user to transfer SSH key..."
+ cat /home/bdsm/.ssh/id_rsa.pub | ssh bdsm@$host 'cat >> ~/.ssh/authorized_keys'
+ fi
+
+ ssh bdsm@$host "mkfifo /home/bdsm/out.fifo"
+ done
+}
+
+# SCRIPT START
+###############################################################################
+
+# Reformat config file to be more machine-readable
+# Removes whitespace and adds semicolons after property values
+cat /home/bdsm/bdsm.conf | tr '\n' ' ' | sed "s/[[:space:]]//g" | sed 's/}/}\
+/g' | sed 's/^;*//g' | sed 's/\([{}]\);/\1/g' \
+> /home/bdsm/.bdsm.conf.tmp
+
+# Get a list of configured hosts
+hosts=$(cat /home/bdsm/.bdsm.conf.tmp | cut -d'{' -f1)
+
+if [ -z $1 ]; then
+ help
+elif [ $1 == "start" ]; then
+ start
+elif [ $1 == "stop" ]; then
+ stop
+elif [ $1 == "status" ]; then
+ status
+elif [ $1 == "configure" ]; then
+ configure
+elif [ $1 == "deploy" ]; then
+ deploy
+else
+ help
+fi
\ No newline at end of file