#!/bin/bash # /usr/lib/check_mk_agent/local/300/check_mail_archiver set -u CONFIG="/etc/check_mk/mail_archiver.conf" OK=0 WARN=1 CRIT=2 UNKNOWN=3 # # --------------------------------------------------------------------------- # Configuration # --------------------------------------------------------------------------- # if [[ ! -r "$CONFIG" ]]; then printf '%s\n' \ "${UNKNOWN} \"Mail Archiver\" - Configuration file ${CONFIG} missing or unreadable" exit 0 fi # shellcheck disable=SC1090 source "$CONFIG" MAIL_ARCHIVER_URL="${MAIL_ARCHIVER_URL:-http://127.0.0.1:5000}" MAIL_ARCHIVER_TOKEN="${MAIL_ARCHIVER_TOKEN:-}" WARN_SYNC_AGE="${WARN_SYNC_AGE:-3600}" CRIT_SYNC_AGE="${CRIT_SYNC_AGE:-7200}" CHECK_UPDATES="${CHECK_UPDATES:-yes}" MAIL_ARCHIVER_RELEASE_API="${MAIL_ARCHIVER_RELEASE_API:-https://api.github.com/repos/s1t5/mail-archiver/releases/latest}" VERSION_FILE="${VERSION_FILE:-/root/.mail-archiver}" # # --------------------------------------------------------------------------- # Requirements # --------------------------------------------------------------------------- # if ! command -v curl >/dev/null 2>&1; then printf '%s\n' \ "${UNKNOWN} \"Mail Archiver\" - curl is not installed" exit 0 fi if ! command -v jq >/dev/null 2>&1; then printf '%s\n' \ "${UNKNOWN} \"Mail Archiver\" - jq is not installed" exit 0 fi if ! command -v date >/dev/null 2>&1; then printf '%s\n' \ "${UNKNOWN} \"Mail Archiver\" - date is not available" exit 0 fi if [[ -z "$MAIL_ARCHIVER_TOKEN" ]]; then printf '%s\n' \ "${UNKNOWN} \"Mail Archiver\" - MAIL_ARCHIVER_TOKEN is not configured" exit 0 fi # # --------------------------------------------------------------------------- # Validate thresholds # --------------------------------------------------------------------------- # if ! [[ "$WARN_SYNC_AGE" =~ ^[0-9]+$ ]]; then printf '%s\n' \ "${UNKNOWN} \"Mail Archiver\" - WARN_SYNC_AGE must be an integer" exit 0 fi if ! [[ "$CRIT_SYNC_AGE" =~ ^[0-9]+$ ]]; then printf '%s\n' \ "${UNKNOWN} \"Mail Archiver\" - CRIT_SYNC_AGE must be an integer" exit 0 fi if [[ "$CRIT_SYNC_AGE" -le "$WARN_SYNC_AGE" ]]; then printf '%s\n' \ "${UNKNOWN} \"Mail Archiver\" - CRIT_SYNC_AGE must be greater than WARN_SYNC_AGE" exit 0 fi # # --------------------------------------------------------------------------- # curl configuration # --------------------------------------------------------------------------- # CURL_OPTS=( --silent --show-error --fail --connect-timeout 3 --max-time 10 ) AUTH_HEADER="Authorization: Bearer ${MAIL_ARCHIVER_TOKEN}" # # --------------------------------------------------------------------------- # Accounts API / application health # --------------------------------------------------------------------------- # ACCOUNTS_RESPONSE="$( curl \ "${CURL_OPTS[@]}" \ -H "$AUTH_HEADER" \ "${MAIL_ARCHIVER_URL%/}/api/v1/accounts" \ 2>/dev/null )" CURL_RC=$? if [[ $CURL_RC -ne 0 || -z "$ACCOUNTS_RESPONSE" ]]; then printf '%s\n' \ "${CRIT} \"Mail Archiver\" - API unavailable or authentication failed at ${MAIL_ARCHIVER_URL}" exit 0 fi if ! printf '%s' "$ACCOUNTS_RESPONSE" | jq -e 'type == "array"' >/dev/null 2>&1 then printf '%s\n' \ "${UNKNOWN} \"Mail Archiver\" - Accounts API returned unexpected data" exit 0 fi ACCOUNT_COUNT="$( printf '%s' "$ACCOUNTS_RESPONSE" | jq 'length' )" ENABLED_COUNT="$( printf '%s' "$ACCOUNTS_RESPONSE" | jq '[.[] | select(.isEnabled == true)] | length' )" DISABLED_COUNT=$((ACCOUNT_COUNT - ENABLED_COUNT)) printf '%s\n' \ "${OK} \"Mail Archiver\" accounts=${ACCOUNT_COUNT};;;0|enabled=${ENABLED_COUNT};;;0|disabled=${DISABLED_COUNT};;;0 API reachable and authenticated - ${ENABLED_COUNT}/${ACCOUNT_COUNT} accounts enabled" # # --------------------------------------------------------------------------- # Archive statistics # --------------------------------------------------------------------------- # STATS_RESPONSE="$( curl \ "${CURL_OPTS[@]}" \ -H "$AUTH_HEADER" \ "${MAIL_ARCHIVER_URL%/}/api/v1/stats" \ 2>/dev/null )" STATS_RC=$? if [[ $STATS_RC -ne 0 || -z "$STATS_RESPONSE" ]]; then printf '%s\n' \ "${UNKNOWN} \"Mail Archive Statistics\" - Unable to retrieve archive statistics" elif ! printf '%s' "$STATS_RESPONSE" | jq -e 'type == "object"' >/dev/null 2>&1 then printf '%s\n' \ "${UNKNOWN} \"Mail Archive Statistics\" - Statistics API returned unexpected data" else EMAILS="$( printf '%s' "$STATS_RESPONSE" | jq -r '.emails // 0' )" STATS_ACCOUNTS="$( printf '%s' "$STATS_RESPONSE" | jq -r '.accounts // 0' )" ATTACHMENTS="$( printf '%s' "$STATS_RESPONSE" | jq -r '.attachments // 0' )" DATABASE_MB="$( printf '%s' "$STATS_RESPONSE" | jq -r '.databaseSizeInMB // "0"' )" [[ "$EMAILS" =~ ^[0-9]+$ ]] || EMAILS=0 [[ "$STATS_ACCOUNTS" =~ ^[0-9]+$ ]] || STATS_ACCOUNTS=0 [[ "$ATTACHMENTS" =~ ^[0-9]+$ ]] || ATTACHMENTS=0 [[ "$DATABASE_MB" =~ ^[0-9]+([.][0-9]+)?$ ]] || DATABASE_MB=0 printf '%s\n' \ "${OK} \"Mail Archive Statistics\" emails=${EMAILS};;;0|accounts=${STATS_ACCOUNTS};;;0|attachments=${ATTACHMENTS};;;0|database_size=${DATABASE_MB}MB;;;0 ${EMAILS} emails, ${STATS_ACCOUNTS} accounts, ${ATTACHMENTS} attachments, database ${DATABASE_MB} MB" fi # # --------------------------------------------------------------------------- # Individual account sync state # --------------------------------------------------------------------------- # # Mail-Archiver returns lastSync values such as: # # 2026-09-13T07:33:35.199543 # # These represent UTC, but do not contain a timezone suffix. # # Therefore we explicitly parse them with TZ=UTC. Once converted to Unix # epoch seconds, comparisons are timezone-independent and automatically safe # across CET/CEST daylight-saving changes. # NOW_EPOCH="$(date +%s)" while IFS= read -r ACCOUNT; do ACCOUNT_NAME="$( printf '%s' "$ACCOUNT" | jq -r '.name // empty' )" EMAIL_ADDRESS="$( printf '%s' "$ACCOUNT" | jq -r '.emailAddress // empty' )" PROVIDER="$( printf '%s' "$ACCOUNT" | jq -r '.provider // "Unknown"' )" ENABLED="$( printf '%s' "$ACCOUNT" | jq -r '.isEnabled // false' )" LAST_SYNC="$( printf '%s' "$ACCOUNT" | jq -r '.lastSync // empty' )" # # Prefer friendly account name, then email address. # if [[ -n "$ACCOUNT_NAME" ]]; then SERVICE_NAME="$ACCOUNT_NAME" elif [[ -n "$EMAIL_ADDRESS" ]]; then SERVICE_NAME="$EMAIL_ADDRESS" else SERVICE_NAME="Unknown" fi SERVICE_NAME="${SERVICE_NAME//\"/\'}" # # Disabled accounts are treated as intentional. # if [[ "$ENABLED" != "true" ]]; then printf '%s\n' \ "${OK} \"Mail Archive ${SERVICE_NAME}\" - Disabled, provider ${PROVIDER}" continue fi # # Enabled account without a sync timestamp. # if [[ -z "$LAST_SYNC" || "$LAST_SYNC" == "null" ]]; then printf '%s\n' \ "${WARN} \"Mail Archive ${SERVICE_NAME}\" - Enabled but no successful sync timestamp is available, provider ${PROVIDER}" continue fi # # Mail-Archiver supplies UTC without an explicit Z/+00:00 suffix. # Force UTC interpretation rather than allowing GNU date to interpret # the timestamp using the host's local timezone. # LAST_SYNC_EPOCH="$( TZ=UTC date -d "$LAST_SYNC" +%s 2>/dev/null || true )" if [[ -z "$LAST_SYNC_EPOCH" || ! "$LAST_SYNC_EPOCH" =~ ^[0-9]+$ ]]; then printf '%s\n' \ "${UNKNOWN} \"Mail Archive ${SERVICE_NAME}\" - Unable to parse lastSync '${LAST_SYNC}'" continue fi SYNC_AGE=$((NOW_EPOCH - LAST_SYNC_EPOCH)) # # Protect against small clock differences between systems. # if [[ "$SYNC_AGE" -lt 0 ]]; then SYNC_AGE=0 fi DAYS=$((SYNC_AGE / 86400)) HOURS=$(((SYNC_AGE % 86400) / 3600)) MINUTES=$(((SYNC_AGE % 3600) / 60)) if [[ "$DAYS" -gt 0 ]]; then AGE_TEXT="${DAYS}d ${HOURS}h ${MINUTES}m" elif [[ "$HOURS" -gt 0 ]]; then AGE_TEXT="${HOURS}h ${MINUTES}m" else AGE_TEXT="${MINUTES}m" fi STATE=$OK if [[ "$SYNC_AGE" -ge "$CRIT_SYNC_AGE" ]]; then STATE=$CRIT elif [[ "$SYNC_AGE" -ge "$WARN_SYNC_AGE" ]]; then STATE=$WARN fi printf '%s\n' \ "${STATE} \"Mail Archive ${SERVICE_NAME}\" sync_age=${SYNC_AGE};${WARN_SYNC_AGE};${CRIT_SYNC_AGE};0 Last sync ${AGE_TEXT} ago, provider ${PROVIDER}" done < <( printf '%s' "$ACCOUNTS_RESPONSE" | jq -c '.[]' ) # # --------------------------------------------------------------------------- # Installed version # --------------------------------------------------------------------------- # # Community Scripts stores the deployed Mail-Archiver release version in: # # /root/.mail-archiver # # This is maintained by the Community Scripts installer/updater and is used # as the authoritative installed-version source here. # INSTALLED_VERSION="" if [[ -r "$VERSION_FILE" ]]; then INSTALLED_VERSION="$( head -n 1 "$VERSION_FILE" | tr -d '[:space:]' )" fi INSTALLED_VERSION="${INSTALLED_VERSION#v}" # # --------------------------------------------------------------------------- # Mail-Archiver update check # --------------------------------------------------------------------------- # if [[ "$CHECK_UPDATES" == "yes" ]]; then RELEASE_RESPONSE="$( curl \ "${CURL_OPTS[@]}" \ -H "Accept: application/vnd.github+json" \ -H "User-Agent: checkmk-mail-archiver-local-check" \ "$MAIL_ARCHIVER_RELEASE_API" \ 2>/dev/null )" RELEASE_RC=$? if [[ $RELEASE_RC -ne 0 || -z "$RELEASE_RESPONSE" ]]; then if [[ -n "$INSTALLED_VERSION" ]]; then printf '%s\n' \ "${UNKNOWN} \"Mail Archiver Update\" - Installed ${INSTALLED_VERSION}, unable to query GitHub releases" else printf '%s\n' \ "${UNKNOWN} \"Mail Archiver Update\" - Unable to determine installed version or query GitHub releases" fi elif ! printf '%s' "$RELEASE_RESPONSE" | jq -e 'type == "object"' >/dev/null 2>&1 then printf '%s\n' \ "${UNKNOWN} \"Mail Archiver Update\" - GitHub release API returned unexpected data" else LATEST_VERSION="$( printf '%s' "$RELEASE_RESPONSE" | jq -r '.tag_name // empty' )" LATEST_VERSION="${LATEST_VERSION#v}" if [[ -z "$LATEST_VERSION" ]]; then printf '%s\n' \ "${UNKNOWN} \"Mail Archiver Update\" - Unable to determine latest release" elif [[ -z "$INSTALLED_VERSION" ]]; then printf '%s\n' \ "${UNKNOWN} \"Mail Archiver Update\" - Latest ${LATEST_VERSION}, but installed version marker ${VERSION_FILE} is missing or unreadable" elif [[ ! "$INSTALLED_VERSION" =~ ^[0-9]+([.][0-9]+)*$ ]]; then printf '%s\n' \ "${UNKNOWN} \"Mail Archiver Update\" - Unable to parse installed version ${INSTALLED_VERSION}" elif [[ ! "$LATEST_VERSION" =~ ^[0-9]+([.][0-9]+)*$ ]]; then printf '%s\n' \ "${UNKNOWN} \"Mail Archiver Update\" - Unable to parse latest version ${LATEST_VERSION}" else NEWEST="$( printf '%s\n%s\n' \ "$INSTALLED_VERSION" \ "$LATEST_VERSION" | sort -V | tail -n 1 )" if [[ "$INSTALLED_VERSION" == "$LATEST_VERSION" ]]; then printf '%s\n' \ "${OK} \"Mail Archiver Update\" - Current: installed ${INSTALLED_VERSION}, latest ${LATEST_VERSION}" elif [[ "$NEWEST" == "$LATEST_VERSION" ]]; then printf '%s\n' \ "${WARN} \"Mail Archiver Update\" - Update available: installed ${INSTALLED_VERSION}, latest ${LATEST_VERSION}" else printf '%s\n' \ "${OK} \"Mail Archiver Update\" - Installed ${INSTALLED_VERSION} is newer than latest ${LATEST_VERSION}" fi fi fi fi exit 0