1
0
Fork 0
scripts-admin-quickndirty-p.../nagios/check_forgejo_version.sh

185 lines
4.6 KiB
Bash
Executable file

#!/bin/bash
# Little monitoring script to check that the version of a
# Forgejo instance is up to date.
#
# Licence: WTFPL
# Copyright: chl-dev@bugness.org 2023
PROGPATH=$( echo $0 | sed -e 's,[\\/][^\\/][^\\/]*$,,' )
REVISION="0.1"
# Default values
DNS_RECORD_RELEASES="release.forgejo.org"
RELEASE_MEDIUM="dns"
URL_RSS_RELEASES="https://codeberg.org/forgejo/forgejo/releases.rss"
URL_LOCAL_HOSTNAME="localhost:3000"
URL_LOCAL_VERSION_TEMPLATE="%s://%s/api/v1/version"
URL_LOCAL_PROTOCOL="http"
# Include check_range()
# Not needed at the moment
#. $PROGPATH/utils.sh
STATE_OK=0
STATE_WARNING=1
STATE_CRITICAL=2
STATE_UNKNOWN=3
STATE_DEPENDENT=4
# Stop at first uncaught error
set -e
# Wrapper to use whatever is available to make HTTP queries
fetch_with_curl_wget_or_whatever () {
if which "wget" >/dev/null 2>&1; then
wget -q -O - "$1"
elif which "curl" >/dev/null 2>&1 ; then
curl -s "$1"
else
echo "UNKNOWN: no wget/curl/whatever available to make HTTP queries."
exit $STATE_UNKNOWN
fi
}
# Wrapper to use whatever is available to make DNS queries
fetch_with_dig_or_whatever () {
if which "dig" >/dev/null 2>&1; then
dig +short "$1" "$2"
elif which "nslookup" >/dev/null 2>&1; then
nslookup -query="$2" "$1" | sed -n "/$1/p"
else
echo "UNKNOWN: no dig/nslookup/whatever available to make DNS queries."
exit $STATE_UNKNOWN
fi
}
# Sort the multiple <title> contents and print the last one.
# ex: 1.21.1-5
# Note: Gitea has some spurious v1.22-dev/-rc releases, we ignore them.
get_latest_version_number_from_rss () {
fetch_with_curl_wget_or_whatever "$1" | while rdom; do
# In RSS streams, we only want the <title> in <item>
# In Atom streams, it's <entry> -> <title>
case "$E" in
"item"|"entry") INSIDE_ITEM=1;;
"/item"|"/entry") INSIDE_ITEM="";;
esac
if [ -n "$INSIDE_ITEM" ] && [ "$E" == "title" ]; then
printf "%s\n" "$C"
fi
done | sed -e 's/^v//' -e '/-dev/d' -e '/-rc/d' | sort --version-sort | tail -n 1
}
# Sort the multiple "forgejo_versions=x,y,z" and print the last one.
# ex: 1.21.1-5
get_latest_version_number_from_dns () {
fetch_with_dig_or_whatever "$1" "TXT" | \
sed -e 's/.*=\(.*\)".*/\1/' -e 's/,/\n/g' | \
sort --version-sort | \
tail -n 1
}
print_url_local_version () {
printf "$URL_LOCAL_VERSION_TEMPLATE" "$URL_LOCAL_PROTOCOL" "$URL_LOCAL_HOSTNAME"
}
# Quick 'n dirty function to parse XML without having to install
# a real parser (not necessary at the moment here, but may be
# needed in the future)
# The tag will be stored in $E and the content in $C
# note: this function is not POSIX-compliant (needs bash)
rdom () {
local IFS=\>
read -d \< E C
}
# Help function
usage() {
cat <<EOF
Usage :
$0 [-H hostname] [-u local_URL] [-sS] [-D] [-d release_dns_record] [-R] [-r release_rss_URL]
-D Use the DNS to determine the last release available (default)
-R Use the RSS to determine the last release available
-s Use HTTP to query the hostname (default)
-S Use HTTPS to query the hostname
Example :
./check_forgejo_version.sh -H forge.example.net
(seems to somewhat work for Gitea too :)
./check_forgejo_version.sh -R -r https://github.com/go-gitea/gitea/releases.atom
Default values:
local_URL: $( print_url_local_version )
release_dns_record: $DNS_RECORD_RELEASES
release_rss_URL: $URL_RSS_RELEASES
EOF
}
# Loop on parameters
while getopts hDH:r:RsSu: f; do
case "$f" in
'h')
usage
exit
;;
'D')
RELEASE_MEDIUM="dns"
;;
'H')
URL_LOCAL_HOSTNAME="$OPTARG"
;;
'r')
URL_RSS_RELEASES="$OPTARG"
;;
'R')
RELEASE_MEDIUM="rss"
;;
's')
URL_LOCAL_PROTOCOL="http"
;;
'S')
URL_LOCAL_PROTOCOL="https"
;;
'u')
URL_LOCAL_VERSION="$OPTARG"
;;
?)
usage
exit 1
;;
esac
done
# If the local URL hasn't been overridden, let's compute it.
if [ -z "$URL_LOCAL_VERSION" ]; then
URL_LOCAL_VERSION="$( print_url_local_version )"
fi
# Query the upstream and local versions...
case "$RELEASE_MEDIUM" in
'rss') UPSTREAM_VERSION="$( get_latest_version_number_from_rss "$URL_RSS_RELEASES" )" ;;
'dns') UPSTREAM_VERSION="$( get_latest_version_number_from_dns "$DNS_RECORD_RELEASES" )" ;;
esac
# note : the API seems to switch 1.21.1-0 to 1.21.1+0. We dumbly switch back ?
LOCAL_VERSION="$( fetch_with_curl_wget_or_whatever "$URL_LOCAL_VERSION" | sed -n 's/{"version":"\([^"]\+\)"}/\1/p' | sed 's/+/-/' )"
# ...and check if they match.
if [ "$UPSTREAM_VERSION" = "$LOCAL_VERSION" ]; then
echo "OK ($LOCAL_VERSION / $UPSTREAM_VERSION)"
exit $STATE_OK
else
# we are not yet able to distinguish security releases from simple upgrades
# so, to avoid alert fatigue, we chose to stay at "warning".
echo "WARNING ($LOCAL_VERSION / $UPSTREAM_VERSION)"
exit $STATE_WARNING
fi