185 lines
4.6 KiB
Bash
Executable file
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
|