commit 27b7891bd7580e603b7d5f6624cad6617f17a79d Author: BDR Date: Sat Mar 27 23:27:40 2021 +0100 Initial commit diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3de1845 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Baptiste DE RENZO + +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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..5685834 --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ +# 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 +* 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 the checks file `checks.list` +* To add incidents or maintenance, edit `incidents.list` +* Generate status page `./tinystatus > index.html` +* Serve the page with your favorite web server + diff --git a/checks.list b/checks.list new file mode 100644 index 0000000..07a1543 --- /dev/null +++ b/checks.list @@ -0,0 +1,4 @@ +http | 200 | Google website | https://google.com +http | 404 | Google 404 | https://google.com/dummy +ping | 0 | Google ping | 8.8.8.8 +port | 0 | Google dns | 8.8.8.8:53 diff --git a/incidents.list b/incidents.list new file mode 100644 index 0000000..035ffc1 --- /dev/null +++ b/incidents.list @@ -0,0 +1,2 @@ +2021/02/01 08:00 - Site unavailable. Resolved after 5 minutes of downtime. +2021/01/01 09:00 - User may have problem with API. Incident resolved after 1 hour. diff --git a/tinystatus b/tinystatus new file mode 100755 index 0000000..08fa414 --- /dev/null +++ b/tinystatus @@ -0,0 +1,114 @@ +#!/usr/bin/env sh + +title=tinystatus +timeout=10 +tmp=${tmpdir:-/tmp/tinystatus} +useragent="User-Agent: Mozilla/5.0 (X11; Linux x86_64; Debian) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36" + +command_exists(){ + if ! command -v "${1}" >/dev/null 2>&1; then + echo >&2 "Error: ${1} missing. Please install it" + exit 1 + fi +} + +get_element(){ + echo "${2}" | awk -v col="${1}" -F'|' '{gsub(/^[ \t]+|[ \t]+$/, "", $col); print $col}' +} + +check(){ + ctype="${1}" + host="${2}" + name="${3}" + expectedcode="${4}" + + if [ ${ctype} = 'http' ]; then + statuscode="$(curl -sSkLo /dev/null -H "${useragent}" -m "${timeout}" -w "%{http_code}" "${host}" 2> "${tmp}/ko/${name}.error")" + elif [ ${ctype} = 'port' ]; then + error="$(nc -w "${timeout}" -zv $(echo "${host}" | sed 's,:, ,') 2>&1)" + statuscode=$? + [ ${statuscode} -ne 0 ] && echo "${error}" > "${tmp}/ko/${name}.error" + elif [ ${ctype} = 'ping' ]; then + ping -W "${timeout}" -c 1 "${host}" >/dev/null 2>&1 + statuscode=$? + [ ${statuscode} -ne 0 ] && echo 'Host unreachable' > "${tmp}/ko/${name}.error" + fi + + # verity status and write files + if [ ${statuscode} -eq ${expectedcode} ]; then + echo "Status code: ${statuscode}" > "${tmp}/ok/${name}.status" + else + echo "Status code: ${statuscode}" > "${tmp}/ko/${name}.status" + fi + if [ -s "${tmp}/ko/${name}.error" ]; then + sed "${tmp}/ko/${name}.error" \ + -e 's,curl: ([0-9]*) ,,' \ + -e 's,.*) failed: ,,' > "${tmp}/ko/${name}.status" + fi +} + +command_exists 'curl' +command_exists 'nc' +rm -r "${tmp}" +mkdir -p "${tmp}/ok" "${tmp}/ko" || exit 1 + +while IFS='\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 < "${1:-checks.list}" +wait + +cat << EOF +${title} + +
+

Global status

+EOF +outagenb=$(find ${tmp}/ko -mindepth 1 | grep -c 'status$') +if [ ${outagenb} -ne 0 ]; then + echo "" +else + echo "" +fi +cat << EOF +

Services

+ +

Last check: $(date +"%Y/%m/%d %H:%M:%S")

+

Incidents

+EOF +sed 's|^\(.*\)$|

\1

|' "${2:-incidents.list}" 2>/dev/null || echo "

No incident reported yet ;)

" +cat < + +EOF +