Refactoring the directory structure
authorBrian Flowers <git-admn@bsflowers.net>
Fri, 4 Nov 2016 00:58:18 +0000 (20:58 -0400)
committerBrian Flowers <git-admn@bsflowers.net>
Fri, 4 Nov 2016 00:58:18 +0000 (20:58 -0400)
README
TODO
bin/bdsm.sh [new file with mode: 0755]
etc/bdsm/bdsm.conf [new file with mode: 0644]
etc/bdsm/bdsm.db [new file with mode: 0644]
etc/bdsm/monitors/df.generic [new file with mode: 0755]
etc/bdsm/monitors/sensors.generic [new file with mode: 0755]
etc/bdsm/monitors/template.generic [new file with mode: 0644]
etc/bdsm/monitors/vmstat.generic [new file with mode: 0755]
etc/bdsm/processors/file.processor [new file with mode: 0644]
etc/bdsm/processors/sqlite3.processor [new file with mode: 0644]

diff --git a/README b/README
index b5b07b6..3d92685 100644 (file)
--- a/README
+++ b/README
@@ -8,7 +8,6 @@ bdsm is the Bash Daemon for System Monitoring, a truly agentless system monitori
 
 a) A GNU system
 b) bash
-c) vmstat
 
 1) INSTALLATION INSTRUCTIONS
 
diff --git a/TODO b/TODO
index dd59d54..6b903a2 100644 (file)
--- a/TODO
+++ b/TODO
@@ -3,24 +3,38 @@ TODO
 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
diff --git a/bin/bdsm.sh b/bin/bdsm.sh
new file mode 100755 (executable)
index 0000000..fb26406
--- /dev/null
@@ -0,0 +1,499 @@
+#!/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
diff --git a/etc/bdsm/bdsm.conf b/etc/bdsm/bdsm.conf
new file mode 100644 (file)
index 0000000..f7ecb56
--- /dev/null
@@ -0,0 +1,4 @@
+generic:bdsm
+{
+  vmstat(5);
+}
diff --git a/etc/bdsm/bdsm.db b/etc/bdsm/bdsm.db
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/etc/bdsm/monitors/df.generic b/etc/bdsm/monitors/df.generic
new file mode 100755 (executable)
index 0000000..085d17d
--- /dev/null
@@ -0,0 +1,130 @@
+#!/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
diff --git a/etc/bdsm/monitors/sensors.generic b/etc/bdsm/monitors/sensors.generic
new file mode 100755 (executable)
index 0000000..f9e31c5
--- /dev/null
@@ -0,0 +1,142 @@
+#!/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
diff --git a/etc/bdsm/monitors/template.generic b/etc/bdsm/monitors/template.generic
new file mode 100644 (file)
index 0000000..f759409
--- /dev/null
@@ -0,0 +1,107 @@
+#!/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
diff --git a/etc/bdsm/monitors/vmstat.generic b/etc/bdsm/monitors/vmstat.generic
new file mode 100755 (executable)
index 0000000..00f354f
--- /dev/null
@@ -0,0 +1,165 @@
+#!/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
diff --git a/etc/bdsm/processors/file.processor b/etc/bdsm/processors/file.processor
new file mode 100644 (file)
index 0000000..4b3f308
--- /dev/null
@@ -0,0 +1,83 @@
+#!/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
diff --git a/etc/bdsm/processors/sqlite3.processor b/etc/bdsm/processors/sqlite3.processor
new file mode 100644 (file)
index 0000000..2b55f8d
--- /dev/null
@@ -0,0 +1,97 @@
+#!/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