#!/bin/bash
#
# Author  Pierre Fumet <pfumet@easter-eggs.com>
# Date    Fri, 06 Jan 2023 12:19:10 +0100
# Desc    Check github release for a project

# vars
ACK_DAYS_MAX=30
VERSION_DIR="/var/lib/nagios/${0##*/}"

usage () {
	echo "
Check if an application is up-to-date with Github repo last release:
Currently supports : etherpad, glpi, nextcloud, privatebin, rocketchat (package install only, not Docker), roundcube, wordpress.

Usage: $0 -a APP [-h] [-p APP_DIR] [-t ACK_DAYS_MAX]
  - APP is required
  - APP_DIR can be passed as \"-p PATH\", if not def. \"/var/www/APP/public_html\"
  - ACK_DAYS_MAX can be passed as \"-t $ACK_DAYS_MAX\", if not def. $ACK_DAYS_MAX
  - CURRENT_VERSION is stored in \$VERSION_DIR/APP
  - to ACK alert, create as nagios user an empty file \$VERSION_DIR/\$APP.ack : Icinga will print this status
  - ACK file older than \$ACK_DAYS_MAX will be ignored and run icinga alert again"
	exit 3
}

check_version_file () {
	[[ -s $version_file ]] || { echo "$version_file not found or empty, need to fix path"; exit 3; }
}

# pre
[[ $USER == nagios ]] || { echo User is $USER, must run as nagios; exit 3; }
test -d $VERSION_DIR || mkdir $VERSION_DIR

## main
while getopts ":a:hp:t:" opt
do
	case $opt in
		a) APP=$OPTARG ;;
		h) usage ;;
		p) APP_DIR=$OPTARG ;;
		t) ACK_DAYS_MAX=$OPTARG ;;
		:) echo Missing argument for option -$OPTARG; usage ;;
                ?) echo $OPTARG : bad option; usage ;;
	esac
done

[[ -n "$APP" ]] || { echo App missing; usage; }
APP_DIR=${APP_DIR:-/var/www/$APP/public_html}
test -d $APP_DIR || { echo "$APP_DIR is missing or access is forbidden :
- set correct path
- set permissions (maybe need to add nagios to www-data group)
- check if app is really installed in this machine"; exit 3; }

# store current version
case $APP in 
	etherpad)
		G_REPO=ether/etherpad-lite
		version_file="$APP_DIR/CHANGELOG.md"
		check_version_file
		head -1 $version_file | sed 's/^# //' > $VERSION_DIR/$APP ;;
	glpi)
		G_REPO=glpi-project/glpi
		version_file="$APP_DIR/inc/define.php"
		check_version_file
		awk '/^define.*GLPI_VERSION/ {print $2}' $version_file | sed "s/'//g;s/);//" > $VERSION_DIR/$APP ;;
	nextcloud)
		G_REPO=nextcloud/server
		version_file="$APP_DIR/version.php"
		check_version_file
		awk '/OC_VersionString/ {print $3}' $version_file | sed "s/'//;s/'\;$//;s/v//" > $VERSION_DIR/$APP ;;
	privatebin)
		G_REPO=PrivateBin/PrivateBin
		version_file="$APP_DIR/README.md"
		check_version_file
		awk '/Current version/ {print $3}' $version_file | sed 's/*$//' > $VERSION_DIR/$APP ;;
	rocketchat)
		G_REPO=RocketChat/Rocket.Chat
		dpkg -l $APP 2>/dev/null && dpkg -l $APP | awk '/^ii/ {print $3}' > $VERSION_DIR/$APP || { echo "$APP not installed or install mode non supported (eg. docker)"; exit 3; } ;;
	roundcube)
		G_REPO=roundcube/roundcubemail
		version_file="$APP_DIR/program/include/iniset.php"
		check_version_file
		awk '/RCMAIL_VERSION/ {print $2}' $version_file | sed "s/'//;s/')\;$//" > $VERSION_DIR/$APP ;;
	wordpress)
		G_REPO=WordPress/WordPress
		version_file="$APP_DIR/wp-includes/version.php"
		check_version_file
		awk '/wp_version =/ {print $3}' $version_file | sed "s/'//;s/'\;$//" > $VERSION_DIR/$APP ;;
	*)
		echo $OPTARG is not supported; usage; exit 3 ;;
esac

# get lastest: release if available, otherwise tag (eg. Wordpress does not use releases)
test -f $VERSION_DIR/$APP || { echo "$VERSION_DIR/$APP should exist but not found: something went wrong"; exit 3; }
CURRENT_VERSION=$(cat $VERSION_DIR/$APP)
LAST_VERSION="$(curl -s https://api.github.com/repos/$G_REPO/releases/latest | jq -r .tag_name | sed 's/^v//')"
[[ $LAST_VERSION != null ]] || LAST_VERSION="$(curl -s https://api.github.com/repos/$G_REPO/tags | jq -r '.[0].name')"

# compare versions and exit with Nagios code ; if ack older than ACK_DAYS_MAX, return critical, otherwise return OK
if [[ $LAST_VERSION != $CURRENT_VERSION ]]
then
	if [[ -f $VERSION_DIR/$APP.ack ]]
	then
		date=$(date +%s)
		ack_date=$(stat -c %Y $VERSION_DIR/$APP.ack)
		#echo diff date-ack $(( date - ack_date )); echo max-ack $(( ACK_DAYS_MAX * 86400 )); echo $ACK_DAYS_MAX ; exit
		[[ $(( date - ack_date )) -gt $(( ACK_DAYS_MAX * 86400 )) ]] && \
			{ echo "CRITICAL : $APP is in version $CURRENT_VERSION, upstream is $LAST_VERSION ; found $VERSION_DIR/$APP.ack $(( (date - ack_date) / 86400 )) days old, more than max ack days $ACK_DAYS_MAX - maybe $APP really needs upgrade"; exit 2; } || \
			{ echo "OK : $APP is in version $CURRENT_VERSION, upstream is $LAST_VERSION ; found $VERSION_DIR/$APP.ack $(( (date - ack_date) / 86400 )) days old, less than max ack days $ACK_DAYS_MAX - remove this file to reactivate the alert"; exit 0; }
	else
		{ echo "Warning : $APP is in version $CURRENT_VERSION, upstream is $LAST_VERSION ; to ack the alert but see this mismatch, touch empty file $VERSION_DIR/$APP.ack as nagios user ; ack will be valid during $(( ACK_DAYS_MAX * 86400 )) days"; exit 1; }
	fi
else
	echo "OK : $APP is in version $CURRENT_VERSION, upstream is $LAST_VERSION"
	exit 0
fi
