#!/bin/bash

if [ ! -f /etc/sysconfig/healthd ]; then
	echo "Missing /etc/sysconfig/healthd"
	exit 1
fi
 . /etc/sysconfig/healthd

BINDIR=/usr/lib/healthd

UPDATE_SCRIPT=$BINDIR/healthd-monitor
GRAPH_SCRIPT=$BINDIR/healthd-graph
USAGEFILE="$RRD_DIR/usage.rrd"
HEALTHFILE="$RRD_DIR/health.rrd"

# Sanity checks
if [ ! -d $RRD_DIR ]; then
	echo "$RRD_DIR is missing."
	exit 1
fi
if [ -e $USAGEFILE ] ; then
    echo "Error: $USAGEFILE already exits!" >&2
    exit 1
fi
if [ -e $HEALTHFILE ] ; then
    echo "Error: $HEALTHFILE already exits!" >&2
fi

# "parse" separated values
function getOne() {
  echo $2 | {
    i=$1
    while [ $i -gt 0 ] ; do i=$((i-1)) ; read -d \; ; done
    echo $REPLY
  }
}

if [ -z $REFRESH_PERIOD ]; then
    REFRESH_PERIOD=60
fi

# create and update command beginnings
CREATEUSAGE="rrdtool create $USAGEFILE --step $REFRESH_PERIOD"
CREATEHEALTH="rrdtool create $HEALTHFILE --step $REFRESH_PERIOD"
HEARTBEAT=$((2*$REFRESH_PERIOD))
UPDATEUSAGEC="rrdtool update $USAGEFILE \"N"
UPDATEHEALTHC="rrdtool update $HEALTHFILE \"N"
UCOLIDXH=1
UCOLIDXN=1
TCOLIDX=1


function usage_add_disk() {
    local disk=$1
    shift
    local label="$*"
    if [ "$label" == "" ]; then
        label=$net
    fi

    CREATEUSAGE+="
  DS:hdd${UCOLIDXH}r:COUNTER:$HEARTBEAT:U:U
  DS:hdd${UCOLIDXH}w:COUNTER:$HEARTBEAT:U:U"
    UPDATEUSAGE+="
    VAL_H${UCOLIDXH}r=\`${BINDIR}/hddstat ${disk} 3\`
    if [ \$? -ne 0 ]; then VAL_H${UCOLIDXH}r=''; fi
    VAL_H${UCOLIDXH}w=\`${BINDIR}/hddstat ${disk} 7\`
    if [ \$? -ne 0 ]; then VAL_H${UCOLIDXH}w=''; fi"
    GRAPHHDD+=" \\
  DEF:hdd${UCOLIDXH}r_s=usage.rrd:hdd${UCOLIDXH}r:AVERAGE \\
  DEF:hdd${UCOLIDXH}w_s=usage.rrd:hdd${UCOLIDXH}w:AVERAGE \\
  CDEF:hdd${UCOLIDXH}r=hdd${UCOLIDXH}r_s,512,* \\
  CDEF:hdd${UCOLIDXH}w=hdd${UCOLIDXH}w_s,512,* \\
  LINE2:hdd${UCOLIDXH}r$(getOne $UCOLIDXH $COLORS):\"${label} read\" \\
  LINE2:hdd${UCOLIDXH}w$(getOne $((UCOLIDXH+1)) $COLORS):\"${label} write\" " 
    UPDATEUSAGEC+=":\${VAL_H${UCOLIDXH}r:-U}:\${VAL_H${UCOLIDXH}w:-U}"
    UCOLIDXH=$((UCOLIDXH+2)) ;
}

function usage_add_net() {
    local net=$1
    shift
    local label="$*"
    if [ "$label" == "" ]; then
        label=$net
    fi

    CREATEUSAGE+="
  DS:net${UCOLIDXN}r:COUNTER:$HEARTBEAT:U:U
  DS:net${UCOLIDXN}w:COUNTER:$HEARTBEAT:U:U"
    UPDATEUSAGE+="
    VAL_N${UCOLIDXN}r=\`${BINDIR}/netstats ${net} RX\`
    if [ \$? -ne 0 ]; then VAL_N${UCOLIDXH}r=''; fi
    VAL_N${UCOLIDXN}w=\`${BINDIR}/netstats ${net} TX\`
    if [ \$? -ne 0 ]; then VAL_N${UCOLIDXH}w=''; fi"
    GRAPHNET+=" \\
  DEF:n${UCOLIDXN}r=usage.rrd:net${UCOLIDXN}r:AVERAGE \\
  DEF:n${UCOLIDXN}w=usage.rrd:net${UCOLIDXN}w:AVERAGE \\
  LINE2:n${UCOLIDXN}r`getOne $UCOLIDXN $COLORS`:\"${label} recv\" \\
  LINE2:n${UCOLIDXN}w`getOne $((UCOLIDXN+1)) $COLORS`:\"${label} send\" " ;
    UPDATEUSAGEC+=":\${VAL_N${UCOLIDXN}r:-U}:\${VAL_N${UCOLIDXN}w:-U}"
    UCOLIDXN=$((UCOLIDXN+2))
}

# usage
for i in $USAGE_STATS; do
    DEVTYPE=$(getOne 1 "${i}")
    case "$DEVTYPE" in
        "hd")
            device=$(getOne 2 "${i}")
            label=$(getOne 3 "${i}" | sed -e 's/+/ /g')
            usage_add_disk "$device" "$label"
            ;;
        "net")
            device=$(getOne 2 "${i}")
            label=$(getOne 3 "${i}" | sed -e 's/+/ /g')
            usage_add_net "$device" "$label"
            ;;
        *)
            echo "Unrecognized device format '$i'" >&2
            exit 1
            ;;
    esac
done

function health_add_hdd() {
    local disk=$1
    shift
    local label="$*"
    if [ "$label" == "" ]; then
        label=$disk
    fi

    UPDATEHEALTH+="
    TEMP_${TCOLIDX}=\`${BINDIR}/hddtemp /dev/${disk}\`
    if [ \$? -ne 0 ]; then TEMP_${TCOLIDX}=''; fi"
}

function health_add_sensor() {
    local chip=$1
    local sensor=$2
    shift 2
    local label="$*"
    if [ "$label" == "" ]; then
        label="$chip $sensor"
    fi

    UPDATEHEALTH+="
    TEMP_${TCOLIDX}=\`${BINDIR}/senstemp ${chip} ${sensor}\`
    if [ \$? -ne 0 ]; then TEMP_${TCOLIDX}=''; fi"
}
# health
echo "HEALTH"
for i in $HEALTH_STATS; do
    DEVTYPE=$(getOne 1 "${i}")
    case "$DEVTYPE" in
        "hd")
            device=$(getOne 2 "${i}")
            label=$(getOne 3 "${i}" | sed -e 's/+/ /g')
            health_add_hdd "$device" "$label"
            ;;
        "sensor")
            chip=$(getOne 2 "${i}" | sed -e 's/+/ /g')
            sensor=$(getOne 3 "${i}" | sed -e 's/+/ /g')
            label=$(getOne 4 "${i}" | sed -e 's/+/ /g')
            health_add_sensor "$chip" "$sensor" "$label"
            ;;
        *)
            echo "Unrecognized device format '$i'" >&2
            exit 1
            ;;
    esac

    CREATEHEALTH+=" DS:T${TCOLIDX}:GAUGE:$HEARTBEAT:0:160"


    GRAPHTEMP+=" \\
    DEF:T${TCOLIDX}=health.rrd:T${TCOLIDX}:AVERAGE \\
    LINE2:T${TCOLIDX}`getOne $TCOLIDX $COLORS`:\"${label}\" "
    UPDATEHEALTHC="$UPDATEHEALTHC:\${TEMP_${TCOLIDX}:-U}"

    TCOLIDX=$((TCOLIDX+1))

done
# assemble commands
CREATEUSAGE+=" DS:cpu:GAUGE:$HEARTBEAT:0:U DS:load:GAUGE:$HEARTBEAT:0:U
RRA:AVERAGE:0.5:1:2880
RRA:MAX:0.5:1:2880
RRA:AVERAGE:0.5:30:672
RRA:MAX:0.5:30:672
RRA:AVERAGE:0.5:120:4380
RRA:MAX:0.5:120:4380"
CREATEHEALTH+=" RRA:AVERAGE:0.5:1:2880
RRA:MAX:0.5:1:2880
RRA:AVERAGE:0.5:30:672
RRA:MAX:0.5:30:672
RRA:AVERAGE:0.5:120:4380
RRA:MAX:0.5:120:4380"
UPDATEUSAGEC+=":\`${BINDIR}/cpustat 2 10\`:\`${BINDIR}/cpustat\`\""
UPDATEHEALTHC+="\""

$CREATEUSAGE && echo "RRD file $USAGEFILE successfully created"
$CREATEHEALTH && echo "RRD file $HEALTHFILE successfully created"

# create update shell file
cat <<EOF > $UPDATE_SCRIPT
#!/bin/sh

# Try loading the built-in sleep implementation to avoid spawning a
# new process every 15 seconds
enable -f sleep sleep >/dev/null 2>&1

while true; do
  start_time=\$(date +%s)
  { $UPDATEUSAGE
    $UPDATEUSAGEC
  } &
  { $UPDATEHEALTH
    $UPDATEHEALTHC
  } &
  wait
  end_time=\$(date +%s)
  execution_time=\$((end_time - start_time))
  sleep_time=\$(($REFRESH_PERIOD - execution_time))

  if [ "\$sleep_time" -gt 0 ]; then
    sleep "\$sleep_time"
  fi
done
EOF
chmod 755 $UPDATE_SCRIPT
echo "Created $UPDATE_SCRIPT"

# create graph creation shell file
cat <<EOF  > $GRAPH_SCRIPT
#!/bin/bash
function tempg {
  rrdtool graph $WEB_DIR/\$1.png \$5 \\
    --width \$3 \\
    --height \$4 \\
    --start now-\$2 \\
    --vertical-label "C" \\
    --title "System Temps: \$2" \\
    --alt-autoscale \\
	$GRAPHTEMP
}

function hddg {
  rrdtool graph $WEB_DIR/\$1.png \$5 \\
    --width \$3 \\
    --height \$4 \\
    --start now-\$2 \\
    --title "HDD Throughput: \$2" \\
    --vertical-label "bytes/s" \\
    --logarithmic \\
    --units=si \\
    --lower-limit 1000 \\
    --rigid \\
	$GRAPHHDD
}

function netg {
  rrdtool graph $WEB_DIR/\$1.png \$5 \\
    --width \$3 \\
    --height \$4 \\
    --start now-\$2 \\
    --title "Network Throughput" \\
    --vertical-label "bytes/s" \\
    --logarithmic \\
    --units=si \\
    --lower-limit 1000 \\
    --rigid \\
	$GRAPHNET
}

function cpug {
  rrdtool graph $WEB_DIR/\$1.png \$5 \\
    --width \$3 \\
    --height \$4 \\
    --start now-\$2 \\
    --title "CPU usage: \$2" \\
    --vertical-label "load" \\
    --lower-limit 0 --upper-limit 100 --rigid \\
    --right-axis 0.1:0 \\
    --right-axis-label "Load Average" \\
    --right-axis-format "%1.1lf"  \\
    DEF:cpu_s=usage.rrd:cpu:AVERAGE \\
    DEF:load_s=usage.rrd:load:AVERAGE \\
    CDEF:cpu=100.0,cpu_s,- \\
    CDEF:load=load_s,10,* \\
    AREA:cpu#808080C0:"CPU %" \\
    LINE2:load#0000FF:"CPU load"
}

function dograph {
    echo \$1
    \$1g \$1-hour-big 1h 1200 500
    \$1g \$1-hour 1h 1000 200 --slope-mode
    \$1g \$1-day-big 1d 1200 500
    \$1g \$1-day 1d 450 120 --slope-mode
    \$1g \$1-week-big 7d 1200 500
    \$1g \$1-week 7d 450 120 --slope-mode
    \$1g \$1-long-big 50d 1200 500
    \$1g \$1-long 50d 1000 120 -Eg
}

cd ${RRD_DIR}

dograph temp > /dev/null
dograph hdd > /dev/null
dograph cpu > /dev/null
dograph net > /dev/null

EOF

if [ "$MDSTATS" != "" ]; then
	cat <<EOF >> $GRAPH_SCRIPT
(
  echo '<pre><code>'
  echo -e "\n\n/proc/mdstat:"
  cat /proc/mdstat
EOF

	for md in $MDSTATS; do
		echo "  mdadm --detail /dev/$md" >> $GRAPH_SCRIPT
	done

	cat <<EOF >> $GRAPH_SCRIPT
  echo '</code></pre>'
) > $WEB_DIR/mdadm.html
EOF
fi

if [ "$UPSSTATS" != "" ]; then
	cat <<EOF >> $GRAPH_SCRIPT
(
  echo '<pre><code>'
EOF

	for ups in $UPSSTATS; do
			cat <<EOF >> $GRAPH_SCRIPT
  echo "<b>$ups</b>"
  upsc $ups
EOF
	done
	cat <<EOF >> $GRAPH_SCRIPT
  echo '</code></pre>'
) > $WEB_DIR/ups.html
EOF
fi

if [ "$DOCKERSTATS" != "" ]; then
	D_ARG=""
	if [ "$DOCKERSTATS" != "*" ]; then
		D_ARG=$DOCKERSTATS
	fi
	cat <<EOF >> $GRAPH_SCRIPT
(
  echo '<pre><code>'
  docker stats --no-stream --no-trunc $D_ARG
  echo '</code></pre>'
) > $WEB_DIR/docker.html
EOF
fi

cat <<EOF >> $GRAPH_SCRIPT
(
  echo '<pre><code>'
  echo '<b>Hostname</b>'
  hostname

  echo -e "\n<b>Uname</b>"
  uname -a

  echo -e '\n<b>Date</b>'
  date -R

  echo -e '\n<b>Uptime</b>'
  uptime

  echo -e "\n<b>Free Memory</b>"
  free

  echo -e "\n\n<b>OS-release</b>"
  cat /etc/os-release
  echo '</code></pre>'
) > $WEB_DIR/sys-info.html

(
  echo '<pre><code>'
  ps aux --forest | sed -e 's/</\&#60;/g' -e 's/>/\&#62;/g'
  echo '</code></pre>'
) > $WEB_DIR/ps.html

(
  echo '<h2 id="systemctl-running">systemctl --state=running</h2>'
  echo '<pre><code>'
  systemctl --state=running
  echo -e "\n\n"
  echo '</code></pre>'

  echo '<h2 id="systemctl-failed">systemctl --state=failed</h2>'
  echo '<pre><code>'
  systemctl --state=failed
  echo -e "\n\n"
  echo '</code></pre>'
) > $WEB_DIR/systemctl.html
EOF

chmod 755 $GRAPH_SCRIPT
echo "Created $GRAPH_SCRIPT"
