a) A GNU system
b) bash
-c) vmstat
1) INSTALLATION INSTRUCTIONS
BUGFIXES:
- Fix sqlite3 logging -- needs to be globally writable
May require folder structure refactoring
+ - Confirm configure correctly adds/removes services
+ - Fix deploy for refactored locations
PLUGINS:
- - Starting vmstat on monitor (but not www) echos SSH banner
+ - sqlite3/file processors to reject and log malformed records\
+ - logging of processor start/stop
+ - I/O - iostat
+ - RAM - free/vmstat
+ - Network - netstat, netstat -D
+ - Uptime - uptime
+ - IP address - ipconfig
+ - updates - (package manager)
+ - Users active - ps -ef
+ - Processes active - ps -ef
REFACTORING:
- - Folder structure
+ - Folder structure -- add to PATH?
+ (WIP -- updated in main script, processors)
bin/bdsm
- etc/bdsm.d/monitors
- etc/bdsm.d/processors
- etc/bdsm.d/bdsm.db
- etc/bdsm.d/bdsm.conf
- etc/bdsm.d/out.fifo
- etc/bdsm.d/in.fifo
- etc/bdsm.d/pids
- etc/bdsm.d/errors.log
- etc/bdsm.d/bdsm.log
+ etc/bdsm/monitors/
+ etc/bdsm/processors/
+ etc/bdsm/bdsm.db
+ etc/bdsm/bdsm.conf
+ pids/
+ bdsm.log
+ bdsm.err
+ out.fifo
+ in.fifo
+
- Move all pids to pid folder
- Add a generic function for killing a process and deleting the pid file
Then add checking for 'orphaned' pids
- - Replace some of the /dev/null redirects with error logging
\ No newline at end of file
+ - Replace some of the /dev/null redirects with error logging
+ - Have log levels and autologging from info/warn/error functions
\ No newline at end of file
--- /dev/null
+#!/bin/bash
+################################################################################
+#
+# bdsm
+# Bash Daemon for System Monitoring
+# This script provides true agentless monitoring for Linux and Unix systems
+# using a number of replaceable modules
+#
+# Return Codes:
+# 1: User terminated
+#
+# 255: Unknown Signal Received
+#
+###############################################################################
+
+# CONFIGURATION
+###############################################################################
+#config_path="`basename $0`/../etc/bdsm"
+config_path="/home/bdsm/etc/bdsm/"
+pid_path="/home/bdsm/pids/"
+
+# TRAP UNKNOWN ERRORS
+###############################################################################
+
+trap failure SIGFPE SIGHUP SIGABRT SIGALRM SIGQUIT
+trap term SIGTERM SIGINT
+
+term()
+{
+ echo
+ echo
+ error "BDSM TERMINATED (Received signal $?)"
+ exit 1
+}
+
+failure()
+{
+ echo
+ echo
+ error "Something has gone SERIOUSLY wrong! (Received signal $?)"
+ exit 255
+}
+
+
+# VARIABLES
+###############################################################################
+
+if [ -f "$config_path/processors/$2.processor" ]; then
+ processor="${2}"
+else
+ processor=""
+fi
+
+# 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"
+}
+
+# Select an item from a list
+# Arguments: <Selection prompt> <Option 1> <Option 2> [<Additional Options>]
+# Echo: The option selected
+# Returns: NONE
+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]}
+}
+
+# Prompt for confirmation
+# Arguments: <Prompt>
+# Returns: 0 for Yes, 1 for No
+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 the monitors
+# Arguments: NONE
+# Returns: NONE
+start()
+{
+ # Start the processor
+ processors=($(ls $config_path/processors/*.processor | sed 's|.*/\(.*\).processor|\1|g'))
+ if [ ${#processors[@]} -eq 0 ]; then
+ error "No processors available!"
+ error "Please install a .processor script to $config_path/processors"
+ elif [ ${#processors} -eq 1 ]; then
+ processor=${processors[0]}
+ else
+ processor=`selector "Select a processor" ${processors[@]}`
+ fi
+ $config_path/processors/$processor.processor start "$config_path"
+ touch /home/bdsm/pids/$processor.processor
+
+ 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 $config_path/.bdsm.conf.tmp | grep "$type:$host" | sed 's/.*{\(.*\)}.*/\1/'`
+
+ ssh -q $host "cat /home/bdsm/out.fifo" > /home/bdsm/in.fifo &
+ echo $! > /home/bdsm/pids/$host.in
+
+
+ j=0
+ while read -u10 line; do
+ command=`echo $line | cut -d' ' -f1`
+ if [ "$command" == "" ]; then
+ continue
+ fi
+ args="`echo $line | cut -d' ' -f2-`"
+ if [ -f $config_path/monitors/$command.$type ]; then
+ $config_path/monitors/$command.$type start $host $args
+ elif [ -f $config_path/monitors/$command.$type ]; then
+ $config_path/monitors/$command.generic start $host $args
+ else
+ error "Could not find plugin for $command on $type:$host!"
+ fi
+ done 10< <(echo $functions | tr ';' '\n' | sed 's/[(),]/ /g')
+
+ 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 $config_path/.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`
+ if [ "$command" == "" ]; then
+ continue
+ fi
+ args="`echo $line | cut -d' ' -f2-`"
+ if [ -f $config_path/monitors/$command.$type ]; then
+ $config_path/monitors/$command.$type stop $host $args
+ elif [ -f $config_path/monitors/$command.$type ]; then
+ $config_path/monitors/$command.generic stop $host $args
+ else
+ error "Could not find plugin for $command on $type:$host!"
+ fi
+ done
+
+ # These should terminate once all writing processes are killed
+ # Might need some error handling here -- this command SHOULD always fail
+ # If the processes exist, something is wrong!
+ kill `cat /home/bdsm/pids/$host.in` 2>/dev/null
+ rm /home/bdsm/pids/$host.in
+
+ processor="`basename /home/bdsm/pids/*.processor`"
+ $config_path/processors/$processor stop
+
+ 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 "Checking status of $type monitors on $host..."
+ functions=`cat $config_path/.bdsm.conf.tmp | grep "$type:$host" | sed 's/.*{\(.*\)}.*/\1/'`
+
+ j=0
+ while read -u10 line; do
+ command=`echo $line | cut -d' ' -f1`
+ if [ "$command" == "" ]; then
+ continue
+ fi
+ prefix="$type:$host|$command|"
+ if [ -f $config_path/monitors/$command.$type ]; then
+ $config_path/monitors/$command.$type status $host | sed "s/^/$prefix/g"
+ elif [ -f $config_path/monitors/$command.$type ]; then
+ $config_path/monitors/$command.generic status $host | sed "s/^/$prefix/g"
+ else
+ error "Could not find plugin for $command on $type:$host!"
+ fi
+ done 10< <(echo $functions | tr ';' '\n' | sed 's/[(),]/ /g')
+
+ pid=`cat /home/bdsm/pids/$host.in 2>/dev/null`
+ if [ ! -f $config_path/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
+
+ processor="`basename /home/bdsm/pids/*.processor`"
+ processor="`$config_path/processors/$processor status`"
+ echo "PROCESSOR|$processor"
+}
+
+configure()
+{
+ configured=0
+ if [ -f $config_path/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 $config_path/bdsm.conf
+ touch $config_path/bdsm.conf
+ else
+ error "Invalid selection."
+ return 1
+ fi
+ else
+ touch $config_path/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 $config_path/monitors/ | 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 "$type:$host{}" >> $config_path/.bdsm.conf.tmp
+ else
+ host=""
+ fi
+ done
+
+ header "Configuring $host"
+ availServices=()
+ while read service; do
+ if [ -f $config_path/monitors/$service.$type ]; then
+ serviceFile="$service.$type"
+ elif [ -f $config_path/monitors/$service.generic ]; then
+ serviceFile="$service.generic"
+ else
+ error "$service plugin not found!"
+ fi
+
+ compatible=($($config_path/monitors/$serviceFile compatible $host))
+ if [ "$compatible" -eq "1" ]; then
+ availServices+=($service)
+ fi
+ done < <(find $config_path/monitors/ -executable -type f | \
+ sed "s|$config_path/monitors/||g" | \
+ cut -d'.' -f1 | \
+ sort -u)
+
+ services=$(cat $config_path/.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
+ cat $config_path/.bdsm.conf.tmp | \
+ sed 's/\(.*:$host{.*\)$service;\(.*\)/\1\2/g' \
+ > $config_path/.bdsm.conf.tmp2
+ mv $config_path/.bdsm.conf.tmp2 $config_path/.bdsm.conf.tmp
+ else
+ header "Reconfiguring $service"
+ svc=`echo $service | sed 's/(.*)$//g'`
+ if [ -f $config_path/monitors/$svc.$type ]; then
+ serviceFile="$svc.$type"
+ elif [ -f $config_path/monitors/$svc.generic ]; then
+ serviceFile="$svc.generic"
+ else
+ error "$service plugin not found!"
+ fi
+
+ max=`$config_path/monitors/$serviceFile help | grep "^::" | wc -l`
+ newservice=`echo $service | cut -d'(' -f1`"("
+ i=1
+ while [ $i -le $max ]; do
+ param="`$config_path/monitors/$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 $config_path/.bdsm.conf.tmp | grep ":$host{"`"
+ curHost=`echo $curHost | sed "s/$service;//g" | sed "s|}\$|$newservice;}|g"`
+ cat $config_path/.bdsm.conf.tmp | \
+ grep -v ":$host{" \
+ > $config_path/.bdsm.conf.tmp2
+ echo $curHost >> $config_path/.bdsm.conf.tmp2
+ mv $config_path/.bdsm.conf.tmp2 $config_path/.bdsm.conf.tmp
+ # Reload the hosts list
+ hosts=$(cat $config_path/.bdsm.conf.tmp | cut -d'{' -f1)
+ done
+
+ # Convert config back to a more readable format
+ cat $config_path/.bdsm.conf.tmp | sed 's/{/\
+ {\
+ /g' | sed 's/;/;\
+ /g' | sed 's/}/}\
+ /g' > $config_path/bdsm.conf
+ rm $config_path/.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 -o PreferredAuthentications=publickey bdsm@$host "echo > /dev/null"
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ info "Passwordless SSH not configured. Login as root to configure:"
+ cat /home/bdsm/.ssh/id_rsa.pub | ssh -q root@$host "cat >> /tmp/bdsmid; useradd --home-dir /home/bdsm bdsm; mkdir -p /home/bdsm/.ssh/; cat /tmp/bdsmid >> /home/bdsm/.ssh/authorized_keys"
+ fi
+
+ ssh -q bdsm@$host "mkfifo /home/bdsm/out.fifo; mkdir /home/bdsm/pids/"
+ i=`expr $i + 1`
+ done
+
+ mkfifo /home/bdsm/in.fifo
+ mkdir /home/bdsm/pids
+}
+
+# SCRIPT START
+###############################################################################
+
+# Reformat config file to be more machine-readable
+# Removes whitespace and adds semicolons after property values
+cat /$config_pathbdsm.conf | tr '\n' ' ' | sed "s/[[:space:]]//g" | sed 's/}/}\
+/g' | sed 's/^;*//g' | sed 's/\([{}]\);/\1/g' \
+> $config_path/.bdsm.conf.tmp
+
+# Get a list of configured hosts
+hosts=($(cat $config_path/.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
--- /dev/null
+generic:bdsm
+{
+ vmstat(5);
+}
--- /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
+DRIVE=$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 -q $HOSTNAME "cat /home/bdsm/pids/df.pid 2>/dev/null | \
+ xargs ps -p 2>/dev/null | \
+ 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 "$DRIVE" | tail -1 | sed 's/[^0-9]//g'\`
+ ts=\`date '+%s'\`
+ stdbuf -oL echo "\$ts|$HOSTNAME|DISK-$LABEL-USED|\$df"
+ sleep $DELAY
+ done >> $OUTPATH &
+ echo \$! >/home/bdsm/pids/df.pid
+EOF
+ else
+ echo "Already Running"
+ fi
+}
+
+stop()
+{
+ ssh $HOSTNAME 'kill `cat /home/bdsm/pids/df.pid`'
+ ssh $HOSTNAME 'rm /home/bdsm/pids/df.pid'
+}
+
+status()
+{
+ running=`ssh $HOSTNAME "cat /home/bdsm/pids/df.pid 2>/dev/null | \
+ xargs ps -p 2>/dev/null | \
+ grep -v PID | \
+ wc -l"`
+
+ if [ -z "$running" ]; then
+ running=0
+ fi
+ if [ $running -eq 0 ]; then
+ echo "OFF"
+ else
+ echo "ON"
+ fi
+}
+
+compatible()
+{
+ compatible="`ssh -q -n $HOSTNAME 'df --output=pcent /' 2>&1 1>/dev/null`"
+ if [ "$compatible" != "" ]; then
+ echo 0
+ else
+ echo 1
+ fi
+}
+
+# SCRIPT START
+###############################################################################
+
+if [ -z $1 ]; then
+ help
+elif [ $1 == "start" ]; then
+ start
+elif [ $1 == "stop" ]; then
+ stop
+elif [ $1 == "status" ]; then
+ status
+elif [ $1 == "compatible" ]; then
+ compatible
+elif [ $1 == "help" ]; then
+ help
+fi
--- /dev/null
+#!/bin/bash
+################################################################################
+#
+# sensors.generic
+# Bash Daemon for System Monitoring
+# Generic sensors plugin for monitoring temperature through lm_sensors
+#
+#
+#
+#
+###############################################################################
+
+# 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 temperature monitoring through lm_sensors"
+ 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 -q $HOSTNAME "cat /home/bdsm/pids/sensors.pid 2>/dev/null | \
+ xargs ps -p 2>/dev/null | \
+ grep -v PID | \
+ wc -l"` 2>/dev/null
+
+ if [ $running -eq 0 ] || [ $running -gt 5 ]; then
+ # Check if sensors is installed
+ installed=`ssh -q $HOSTNAME "sensors > /dev/null 2>&1; echo $?"`
+ if [ ! $installed ]; then
+ echo "" > $OUTPATH
+ return 1
+ fi
+
+ ssh -q $HOSTNAME <<EOF
+ while [ 1 ]; do
+ ts=\`date '+%s'\`
+ stdbuf -o0 sensors | \
+ sed 's/ */ /g' | \
+ sed 's/[(].*[)]//g' \
+ | awk -v ts=\$ts -v host=\$HOSTNAME 'BEGIN {
+ line=1
+ } {
+ if($0 == "") {
+ line=0
+ } else if(line == 1) {
+ device=$0
+ } else if(line == 2) {
+ adapter=$2 $3 $4
+ } else if(line > 2) {
+ FS=":"
+ printf ts "|" host "|" device " " adapter " " $0 "\n"
+ FS=" "
+ } line=line+1
+ }' | tr ':' '|'
+ sleep $DELAY
+ done >> $OUTPATH &
+ echo \$! > /home/bdsm/pids/sensors.pid
+EOF
+ else
+ echo "Already Running"
+ fi
+}
+
+stop()
+{
+ ssh $HOSTNAME 'kill `cat /home/bdsm/pids/sensors.pid`'
+ ssh $HOSTNAME 'rm /home/bdsm/pids/sensors.pid'
+}
+
+status()
+{
+ running=`ssh $HOSTNAME "cat /home/bdsm/pids/sensors.pid 2>/dev/null | \
+ xargs ps -p 2>/dev/null | \
+ grep -v PID | \
+ wc -l"`
+
+ if [ -z "$running" ]; then
+ running=0
+ fi
+ if [ $running -eq 0 ]; then
+ echo "OFF"
+ else
+ echo "ON"
+ fi
+}
+
+compatible()
+{
+ compatible="`ssh -q -n $HOSTNAME 'sensors' 2>&1 1>/dev/null`"
+ if [ "$compatible" != "" ]; then
+ echo 0
+ else
+ echo 1
+ fi
+}
+
+# SCRIPT START
+###############################################################################
+
+if [ -z $1 ]; then
+ help
+elif [ $1 == "start" ]; then
+ start
+elif [ $1 == "stop" ]; then
+ stop
+elif [ $1 == "status" ]; then
+ status
+elif [ $1 == "compatible" ]; then
+ compatible
+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
+}
+
+compatible()
+{
+ # Check if this plugin is compatible with the given host
+}
+
+# SCRIPT START
+###############################################################################
+
+if [ -z $1 ]; then
+ help
+elif [ $1 == "start" ]; then
+ start
+elif [ $1 == "stop" ]; then
+ stop
+elif [ $1 == "status" ]; then
+ status
+elif [ $1 == "compatible" ]; then
+ compatible
+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 -q $HOSTNAME "cat /home/bdsm/pids/vmstat.pid 2>/dev/null | \
+ xargs ps -p 2>/dev/null | \
+ 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 [ "`ssh -qn $HOSTNAME \"echo | awk -W interactive '{print 1}' 2>&1 1>/dev/null\"`" != "" ]; then
+ awkopt=""
+ else
+ awkopt="-W interactive"
+ fi
+
+ ssh -q $HOSTNAME 2>/dev/null <<EOF
+ nohup stdbuf -oL 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 2>/home/bdsm/err.log &
+EOF
+ ssh -q $HOSTNAME 2>/dev/null "ps aux | \
+ grep bdsm | \
+ grep vmstat | \
+ grep -v grep | \
+ awk '{print \$2}' \
+ > /home/bdsm/pids/vmstat.pid &"
+ else
+ echo "Already Running"
+ fi
+}
+
+stop()
+{
+ ssh $HOSTNAME 'kill `cat /home/bdsm/pids/vmstat.pid`'
+ ssh $HOSTNAME 'rm /home/bdsm/pids/vmstat.pid'
+}
+
+status()
+{
+ running=`ssh $HOSTNAME "cat /home/bdsm/pids/vmstat.pid 2>/dev/null | \
+ xargs ps -p 2>/dev/null | \
+ grep -v PID | \
+ wc -l"`
+
+ if [ $running -eq 0 ]; then
+ echo "OFF"
+ else
+ echo "ON"
+ fi
+}
+
+compatible()
+{
+ compatible="`ssh -q -n $HOSTNAME 'stdbuf -oL vmstat' 2>&1 1>/dev/null`"
+ if [ "$compatible" != "" ]; then
+ echo 0
+ else
+ echo 1
+ fi
+}
+
+# SCRIPT START
+###############################################################################
+
+if [ -z $1 ]; then
+ help
+elif [ $1 == "start" ]; then
+ start
+elif [ $1 == "stop" ]; then
+ stop
+elif [ $1 == "status" ]; then
+ status
+elif [ $1 == "compatible" ]; then
+ compatible
+elif [ $1 == "help" ]; then
+ help
+fi
--- /dev/null
+#!/bin/bash
+################################################################################
+#
+# file.processor
+# Bash Daemon for System Monitoring
+# Logging to a text file
+#
+###############################################################################
+
+# 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
+CONFIG_PATH=$2
+
+# MAIN FUNCTIONS
+###############################################################################
+help()
+{
+ echo "Logging to a flat file"
+ echo "USAGE: $0 [FUNCTION]"
+ echo "FUNCTION -- start/stop/status/help"
+ exit 0
+}
+
+start()
+{
+ cat /home/bdsm/in.fifo >> /home/bdsm/bdsm.out &
+ echo $! > /home/bdsm/pids/file.processor.pid
+}
+
+stop()
+{
+ kill `cat /home/bdsm/pids/file.processor.pid`
+ rm /home/bdsm/pids/file.processor.pid
+}
+
+status()
+{
+ running=`cat /home/bdsm/pids/file.processor.pid 2>/dev/null | \
+ xargs ps -p 2>/dev/null | \
+ grep -v PID | \
+ wc -l`
+
+ if [ -z "$running" ]; then
+ running=0
+ fi
+ if [ $running -eq 0 ]; then
+ echo "OFF"
+ else
+ echo "ON"
+ fi
+}
+
+# SCRIPT START
+###############################################################################
+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
+################################################################################
+#
+# sqlite3.processor
+# Bash Daemon for System Monitoring
+# Logging to an sqlite3 database file
+#
+###############################################################################
+
+# 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
+CONFIG_PATH=$2
+
+# MAIN FUNCTIONS
+###############################################################################
+help()
+{
+ echo "Logging to an sqlite3 database file"
+ echo "USAGE: $0 [FUNCTION]"
+ echo "FUNCTION -- start/stop/status/help"
+ exit 0
+}
+
+start()
+{
+ sqlite3 $CONFIG_PATH/bdsm.db "SELECT 1 FROM MEASUREMENTS" 2>/dev/null 1>&2
+ if [ $? -eq 1 ]; then
+ sqlite3 $CONFIG_PATH/bdsm.db \
+ "CREATE TABLE MEASUREMENTS(\
+ id integer primary key,
+ timestamp integer,
+ host varchar(128),
+ attribute varchar(128),
+ value varchar(128))"
+ fi
+
+ cat /home/bdsm/in.fifo | awk -F'|' '{ \
+ printf("INSERT INTO MEASUREMENTS(timestamp,host,attribute,value) \
+ VALUES (%s,\"%s\", \"%s\", \"%s\");\n",$1,$2, $3, $4) }' | \
+ sqlite3 $CONFIG_PATH/bdsm.db &
+ echo $! > /home/bdsm/pids/sqlite3.processor.pid
+}
+
+stop()
+{
+ kill `cat /home/bdsm/pids/sqlite3.processor.pid`
+ rm /home/bdsm/pids/sqlite3.processor.pid
+}
+
+status()
+{
+ running=`cat /home/bdsm/.processor.pid 2>/dev/null | \
+ xargs ps -T | \
+ grep -v PID | \
+ wc -l`
+
+ if [ -z "$running" ]; then
+ running=0
+ fi
+ if [ $running -eq 0 ]; then
+ echo "OFF"
+ else
+ echo "ON"
+ fi
+}
+
+# SCRIPT START
+###############################################################################
+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