#!/bin/ksh # export PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin CHECKFILE="checks.csv" HEADER="Global Status" HTMLDIR="/var/www/htdocs/default" HTMLFILE="index.html" INCIDENTSFILE="incidents.txt" PASTINCIDENTSFILE="pastincidents.txt" PUSHOVER="/home/mischa/bin/pushover.pl" PUSHOVER_CONF="/home/mischa/_pushover.conf" PUSHOVER_STATUS="status" RECIPIENT="alerts@high5.nl" REFRESH=60 SENDER="tinystatus@high5.nl" TIMEOUT=10 TITLE="Tiny Status" USERAGENT="User-Agent: Mozilla/5.0 (OpenBSD; Intel OpenBSD 7.4; rv:109.0) Gecko/20100101 Firefox/113.0" WORKDIR=/home/mischa/tinystatus usage() { echo "usage: ${0##*/} [-c checksfile] [-i incidentsfile] [-p pastincidentsfile] [-o htmlfile]" 1>&2 exit } get_element() { echo "${2}" | awk -v col="${1}" -F',' '{gsub(/^[ \t]+|[ \t]+$/, "", $col); print $col}' } notify() { name="${1}" status="${2}" priority="${3}" if [ ${priority} == "KO" ]; then echo "${status}." | mail -r "${TITLE} <${SENDER}>" -s "${name} DOWN" ${RECIPIENT} ${PUSHOVER} -c ${PUSHOVER_CONF} -t "${TITLE}" -m "${name} DOWN ${status}." -p 1 >/dev/null 2>&1 touch "${PUSHOVER_STATUS}/${name}" fi if [ ${priority} == "OK" ]; then _seconds=$(expr $(date +%s) - $(stat -r ${PUSHOVER_STATUS}/${name} | awk '{print $11}')) _downtime=$(date -r${_seconds} -u +%H:%M:%S) echo "${status} - down for ${_downtime}" | mail -r "${TITLE} <${SENDER}>" -s "${name} OK" ${RECIPIENT} ${PUSHOVER} -c ${PUSHOVER_CONF} -t "${TITLE}" -m "${name} OK ${status} - down for ${_downtime}" >/dev/null 2>&1 rm -rf "${PUSHOVER_STATUS}/${name}" fi } check(){ ctype="${1}" host="${2}" name="${3}" expectedcode="${4}" IPv="${ctype#(http|ping|port)}" case "${ctype}" in http*) statuscode="$(curl -${IPv}sSkLo /dev/null -H "${USERAGENT}" -m "${TIMEOUT}" -w "%{http_code}" "${host}" 2> "${tmp}/ko/${name}.error")" if [ "${statuscode}" -ne "${expectedcode}" ]; then if [ -s "${tmp}/ko/${name}.error" ]; then sed -e 's,curl: ([0-9]*) ,,' "${tmp}/ko/${name}.error" > "${tmp}/ko/${name}.status" else echo "Status code: ${statuscode}" > "${tmp}/ko/${name}.status" fi else echo "Status code: ${statuscode}" > "${tmp}/ok/${name}.status" fi ;; ping*) ping -${IPv}w "${TIMEOUT}" -c 1 "${host}" >/dev/null 2>&1 statuscode=$? if [ "${statuscode}" -ne "${expectedcode}" ]; then echo "Host unreachable" > "${tmp}/ko/${name}.status" else echo "Host reachable" > "${tmp}/ok/${name}.status" fi ;; port*) error="$(nc -${IPv}w "${TIMEOUT}" -zv ${host} 2>&1)" statuscode=$? if [ "${statuscode}" -ne "${expectedcode}" ]; then echo "Connection refused" > "${tmp}/ko/${name}.status" else echo "Connection succeeded" > "${tmp}/ok/${name}.status" fi ;; maint*) echo "Maintenance" > "${tmp}/maint/${name}.status" ;; esac } while getopts c:i:o:h arg; do case ${arg} in c) CHECKFILE=${OPTARG};; i) INCIDENTSFILE=${OPTARG};; p) PASTINCIDENTSFILE=${OPTARG};; o) HTMLFILE=${OPTARG};; h) usage;; *) usage;; esac done cd ${WORKDIR} if [ ! -e "${CHECKFILE}" ]; then echo "Checkfile ${WORKDIR}/${CHECKFILE} doesn't exist." exit fi tmp="$(mktemp -d)" mkdir -p "${tmp}/ok" "${tmp}/ko" "${tmp}/maint" || exit 1 _htmlfile="${tmp}/${HTMLFILE}" while IFS="$(printf '\n')" read -r line; do ctype="$(get_element 1 "${line}")" code="$(get_element 2 "${line}")" name="$(get_element 3 "${line}")" host="$(get_element 4 "${line}")" check "${ctype}" "${host}" "${name}" "${code}" & done < "${CHECKFILE}" wait cat << EOF >> ${_htmlfile} ${TITLE}

${HEADER}

EOF _outage_count="$(find "${tmp}/ko" -mindepth 1 | grep -c 'status$')" _maint_count="$(find "${tmp}/maint" -mindepth 1 | grep -c 'status$')" if [ "${_outage_count}" -ne 0 ]; then echo "" >> ${_htmlfile} fi if [ "${_maint_count}" -ne 0 ]; then echo "" >> ${_htmlfile} fi if [[ "${_outage_count}" -eq 0 && "${_maint_count}" -eq 0 ]]; then echo "" >> ${_htmlfile} fi if [ -f "${INCIDENTSFILE}" ]; then echo '

Incidents

' >> ${_htmlfile} if [ -s "${INCIDENTSFILE}" ]; then sed 's|^\(.*\)$|

\1

|' "${INCIDENTSFILE}" >> ${_htmlfile} else echo '

No incident reported yet ;)

' >> ${_htmlfile} fi fi cat << EOF >> ${_htmlfile}

Services

Last check: $(date +%FT%T%z) Tinystatus loosely based on Tinystatus

EOF if [ -s "${PASTINCIDENTSFILE}" ]; then echo '

Past Incidents

' >> ${_htmlfile} sed 's|^\(.*\)$|

\1

|' "${PASTINCIDENTSFILE}" >> ${_htmlfile} fi cat << EOF >> ${_htmlfile}
EOF cp ${_htmlfile} ${HTMLDIR}/${HTMLFILE} rm -r "${tmp}" 2>/dev/null