commit fe3bb0937f7ea69293c9b8789aca029b334e45bb from: mischa date: Tue May 30 13:04:46 2023 UTC Initial commit commit - /dev/null commit + fe3bb0937f7ea69293c9b8789aca029b334e45bb blob - /dev/null blob + f0f68a9c44f5ae2c9f3dda95b6ecde4000c858de (mode 644) --- /dev/null +++ .gitignore @@ -0,0 +1,2 @@ +high5* +obsdams* blob - /dev/null blob + 71449054ffac117435924a92616193732f780a06 (mode 644) --- /dev/null +++ LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2021 Baptiste DE RENZO +Copyright (c) 2023 Mischa Peters + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. blob - /dev/null blob + 70452aa736e953905c47e432edecb60bdb8a3c3f (mode 644) --- /dev/null +++ README.md @@ -0,0 +1,45 @@ +# Tinystatus + +tinystatus generate an html status page via shell script. + +## Features + +* Parallel checks +* HTTP, ping, port checks +* HTTP expected status code (401, ...) +* Minimal dependencies (curl, nc and coreutils) +* Easy configuration and customisation +* Tiny (~1kb) optimized result page +* Incident history (manual) + +## Demo + +An example site is available [here](https://lab.bdro.fr/tinystatus/). + +## Setup + +To install tinystatus: + +* Clone the repository and go to the created directory +* Edit `tinystatus` variables to your liking +* Edit the checks file `checks.csv` +* To add incidents or maintenance, edit `incidents.txt` +* Generate status page `./tinystatus` +* Serve the page with your favorite web server + +## Configuration file + +The syntax of `checks.csv` file is: +``` +Command, Expected Code, Status Text, Host to check +``` + +Command can be: +* `http` - Check http status +* `ping` - Check ping status +* `port` - Check open port status +* `maint` - Host is in maintance + +There are also `http4`, `http6`, `ping4`, `ping6`, `port4`, `port6` for IPv4 or IPv6 only check. +Note: `port4` and `port6` require OpenBSD `nc` binary. + blob - /dev/null blob + b178fc7dba6245fb98efe9073db2906ffcb16790 (mode 644) --- /dev/null +++ checks.csv @@ -0,0 +1,7 @@ +http, 200, Google Website, https://google.com +http4, 200, Google Website (IPv4), https://google.com +http6, 200, Google Website (IPv6), https://google.com +http, 404, Google 404, https://google.com/dummy +maint, 200, Google Drive Maintenance, https://drive.google.com +ping, 0, Google ping, 8.8.8.8 +port, 0, Google DNS, 8.8.8.8 53 blob - /dev/null blob + a4a2be5b2d4c7ff1b81ea7a89f08731372555602 (mode 644) --- /dev/null +++ incidents.txt @@ -0,0 +1 @@ +2023-05-28 21:17 - Short network outage was observed at our upstream provider between 2023-05-28 21:17:28 UTC and 2023-05-28 21:19:17 UTC blob - /dev/null blob + 7ba1e44c11f24a5f34bb813bd4970e0995693a43 (mode 755) --- /dev/null +++ tinystatus @@ -0,0 +1,192 @@ +#!/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" +PUSHOVER="/home/mischa/bin/pushover.pl" +PUSHOVER_CONF="/home/mischa/_pushover.conf" +PUSHOVER_STATUS="status" +RECIPIENT="mischa@high5.nl" +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 + +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: arg; do + case ${arg} in + c) CHECKFILE=${OPTARG};; + i) INCIDENTSFILE=${OPTARG};; + o) HTMLFILE=${OPTARG};; + *) 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}")" + method="$(get_element 5 "${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) loosely based on Tinystatus

+
+ +EOF + +cp ${_htmlfile} ${HTMLDIR}/${HTMLFILE} +rm -r "${tmp}" 2>/dev/null