Checkmk/local checks/gpfs_fileset_inodes
2026-01-14 07:28:32 +01:00

290 lines
10 KiB
Bash
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
#
# CheckMK Local Check für GPFS Fileset Inodes
# Datei: /usr/lib/check_mk_agent/local/gpfs_fileset_inodes
# Ausführbar machen: chmod +x /usr/lib/check_mk_agent/local/gpfs_fileset_inodes
#
# Überwacht Inode-Verbrauch aller Filesets in allen GPFS Filesystemen
#
# GPFS Management API Konfiguration
USER="checkmk"
PASSWORD="RUIMv7A9CnUaWtnxVMzn"
HOST="spsctstrz.ad.ghnit.net"
PORT="443"
BASE_URL="https://${HOST}:${PORT}/scalemgmt/v2/filesystems"
# Schwellwerte in Prozent
WARN_THRESHOLD=80
CRIT_THRESHOLD=90
# Hostname für Service-Namen
HOSTNAME=$(hostname)
# Funktion für API-Aufrufe
gpfs_api_call() {
    local url="$1"
    curl -s -u "${USER}:${PASSWORD}" \
         -H "Accept: application/json" \
         -H "Content-Type: application/json" \
         -X GET "${url}" 2>/dev/null
}
# Prozentsatz berechnen - ohne bc für bessere Kontrolle
calculate_percentage() {
    local used=$1
    local max=$2
    if [ "$max" -gt 0 ]; then
        # Bash-Integer-Arithmetik: (used * 10000 / max) / 100 für 2 Dezimalstellen
        local result=$((used * 10000 / max))
        local integer_part=$((result / 100))
        local decimal_part=$((result % 100))
        printf "%d.%02d" "$integer_part" "$decimal_part"
    else
        echo "0.00"
    fi
}
# CheckMK Status-Code bestimmen - ohne bc
get_status_code() {
    local percentage_str=$1
    # Prozentsatz in Integer umwandeln für Vergleich (z.B. "1.52" -> 152)
    local percentage_int=$(echo "$percentage_str" | sed 's/\.//' | sed 's/^0*//')
    [ -z "$percentage_int" ] && percentage_int=0
    local warn_int=$((WARN_THRESHOLD * 100))
    local crit_int=$((CRIT_THRESHOLD * 100))
    if [ "$percentage_int" -ge "$crit_int" ]; then
        echo "2"
    elif [ "$percentage_int" -ge "$warn_int" ]; then
        echo "1"
    else
        echo "0"
    fi
}
# Status-Text bestimmen
get_status_text() {
    local code=$1
    case $code in
        0) echo "OK" ;;
        1) echo "WARNING" ;;
        2) echo "CRITICAL" ;;
        *) echo "UNKNOWN" ;;
    esac
}
# Einzelnes Fileset prüfen
check_fileset() {
    local filesystem=$1
    local fileset=$2
    # Service-Name erstellen
    local service_name="GPFS FILESET INODES ${filesystem}_${fileset} ${HOSTNAME}"
    # Fileset-Details von API abrufen
    local detail_response=$(gpfs_api_call "${BASE_URL}/${filesystem}/filesets/${fileset}")
    if [ $? -ne 0 ] || [ -z "$detail_response" ]; then
        echo "2 \"$service_name\" - CRITICAL: API call failed for fileset $fileset in $filesystem"
        return
    fi
    # JSON parsen - verschiedene mögliche Pfade versuchen
    local used_inodes=$(echo "$detail_response" | jq -r '
        .filesets[0]?.usage?.usedInodes //
        .usage?.usedInodes //
        .filesets[0]?.usage?.inodeSpaceUsedInodes //
        .usage?.inodeSpaceUsedInodes //
        0' 2>/dev/null)
    local allocated_inodes=$(echo "$detail_response" | jq -r '
        .filesets[0]?.usage?.allocatedInodes //
        .usage?.allocatedInodes //
        0' 2>/dev/null)
    local max_inodes=$(echo "$detail_response" | jq -r '
        .filesets[0]?.config?.maxNumInodes //
        .config?.maxNumInodes //
        0' 2>/dev/null)
    local free_inodes=$(echo "$detail_response" | jq -r '
        .filesets[0]?.usage?.inodeSpaceFreeInodes //
        .usage?.inodeSpaceFreeInodes //
        0' 2>/dev/null)
    # Fallback: wenn max_inodes 0 oder null ist, allocated_inodes verwenden
    if [ "$max_inodes" = "0" ] || [ "$max_inodes" = "null" ]; then
        max_inodes="$allocated_inodes"
    fi
    # Validierung der Werte
    if ! [[ "$used_inodes" =~ ^[0-9]+$ ]] || ! [[ "$max_inodes" =~ ^[0-9]+$ ]]; then
        echo "3 \"$service_name\" - UNKNOWN: Invalid inode data (used: $used_inodes, max: $max_inodes)"
        return
    fi
    if [ "$max_inodes" -eq 0 ]; then
        echo "0 \"$service_name\" used_inodes=$used_inodes;;;0 OK: No inode limit set for fileset"
        return
    fi
    # Prozentsatz und Status berechnen
    local percentage=$(calculate_percentage "$used_inodes" "$max_inodes")
    local status_code=$(get_status_code "$percentage")
    local status_text=$(get_status_text "$status_code")
    # Freie Inodes berechnen
    local calculated_free=$((max_inodes - used_inodes))
    if [ "$free_inodes" = "0" ] || [ "$free_inodes" = "null" ]; then
        free_inodes=$calculated_free
    fi
    # Schwellwerte für Performance-Daten berechnen
    local warn_absolute=$(echo "scale=0; $max_inodes * $WARN_THRESHOLD / 100" | bc -l)
    local crit_absolute=$(echo "scale=0; $max_inodes * $CRIT_THRESHOLD / 100" | bc -l)
    # Zusätzliche Metriken aus JSON extrahieren
    local used_bytes=$(echo "$detail_response" | jq -r '
        .filesets[0]?.usage?.usedBytes //
        .usage?.usedBytes //
        0' 2>/dev/null)
    local allocated_bytes=$(echo "$detail_response" | jq -r '
        .filesets[0]?.usage?.allocatedBytes //
        .usage?.allocatedBytes //
        0' 2>/dev/null)
    local max_bytes=$(echo "$detail_response" | jq -r '
        .filesets[0]?.config?.maxBytes //
        .config?.maxBytes //
        0' 2>/dev/null)
    local free_bytes=0
    if [ "$allocated_bytes" -gt 0 ] && [ "$used_bytes" -gt 0 ]; then
        free_bytes=$((allocated_bytes - used_bytes))
    fi
    # Performance-Daten erstellen - CheckMK-konformes Format
    # Format: metric=value;warn;crit;min;max (getrennt durch Leerzeichen oder |)
    local perfdata="used_inodes=${used_inodes};${warn_absolute};${crit_absolute};0;${max_inodes}"
    perfdata="${perfdata}|free_inodes=${free_inodes};;;0;${max_inodes}"
    perfdata="${perfdata}|allocated_inodes=${allocated_inodes};;;0"
    perfdata="${perfdata}|max_inodes=${max_inodes};;;0"
    perfdata="${perfdata}|usage_percent=${percentage};${WARN_THRESHOLD};${CRIT_THRESHOLD};0;100"
    # Bytes-Metriken hinzufügen (falls verfügbar)
    if [ "$used_bytes" != "0" ] && [ "$used_bytes" != "null" ]; then
        perfdata="${perfdata}|used_bytes=${used_bytes};;;0"
    fi
    if [ "$allocated_bytes" != "0" ] && [ "$allocated_bytes" != "null" ]; then
        perfdata="${perfdata}|allocated_bytes=${allocated_bytes};;;0"
        if [ "$free_bytes" -gt 0 ]; then
            perfdata="${perfdata}|free_bytes=${free_bytes};;;0"
        fi
    fi
    if [ "$max_bytes" != "0" ] && [ "$max_bytes" != "null" ]; then
        perfdata="${perfdata}|max_bytes=${max_bytes};;;0"
        # Bytes-Prozentsatz berechnen
        if [ "$max_bytes" -gt 0 ] && [ "$used_bytes" -gt 0 ]; then
            local bytes_percentage=$(calculate_percentage "$used_bytes" "$max_bytes")
            perfdata="${perfdata}|bytes_usage_percent=${bytes_percentage};;;0;100"
        fi
    fi
    # Details-Text erstellen - mehr Informationen
    local details="Inodes: ${used_inodes}/${max_inodes} (${percentage}%)"
    if [ "$allocated_inodes" != "$max_inodes" ] && [ "$allocated_inodes" -gt 0 ]; then
        details="${details}, allocated: ${allocated_inodes}"
    fi
    # Bytes-Information hinzufügen falls verfügbar
    if [ "$used_bytes" != "0" ] && [ "$used_bytes" != "null" ]; then
        local used_mb=$((used_bytes / 1024 / 1024))
        details="${details}, Size: ${used_mb}MB"
        if [ "$allocated_bytes" != "0" ] && [ "$allocated_bytes" != "null" ]; then
            local allocated_mb=$((allocated_bytes / 1024 / 1024))
            details="${details}/${allocated_mb}MB"
        fi
        if [ "$max_bytes" != "0" ] && [ "$max_bytes" != "null" ] && [ "$max_bytes" -gt 0 ]; then
            local max_mb=$((max_bytes / 1024 / 1024))
            local bytes_percentage=$(calculate_percentage "$used_bytes" "$max_bytes")
            details="${details} (limit: ${max_mb}MB, ${bytes_percentage}%)"
        fi
    fi
    # CheckMK Service ausgeben
    # Format: STATUS_CODE "SERVICENAME" PERFDATA MESSAGE
    echo "$status_code \"$service_name\" $perfdata $status_text: $details"
}
# Alle Filesysteme abrufen
get_filesystems() {
    local response=$(gpfs_api_call "$BASE_URL")
    if [ $? -ne 0 ] || [ -z "$response" ]; then
        echo "2 \"GPFS FILESET INODES GLOBAL $HOSTNAME\" - CRITICAL: Cannot connect to GPFS Management API"
        return 1
    fi
    echo "$response" | jq -r '.filesystems[]?.name // empty' 2>/dev/null
}
# Filesets eines Filesystems abrufen
get_filesets() {
    local filesystem=$1
    local response=$(gpfs_api_call "${BASE_URL}/${filesystem}/filesets")
    if [ $? -ne 0 ] || [ -z "$response" ]; then
        echo "2 \"GPFS FILESET INODES ${filesystem}_ERROR $HOSTNAME\" - CRITICAL: Cannot get filesets for filesystem $filesystem"
        return 1
    fi
    echo "$response" | jq -r '.filesets[]?.filesetName // empty' 2>/dev/null
}
# ============================================================================
# HAUPTTEIL: Alle Filesysteme und Filesets durchgehen
# ============================================================================
# Prüfen ob jq verfügbar ist
if ! command -v jq >/dev/null 2>&1; then
    echo "2 \"GPFS FILESET INODES GLOBAL $HOSTNAME\" - CRITICAL: jq command not found - required for JSON parsing"
    exit 0
fi
# Prüfen ob bc verfügbar ist
if ! command -v bc >/dev/null 2>&1; then
    echo "2 \"GPFS FILESET INODES GLOBAL $HOSTNAME\" - CRITICAL: bc command not found - required for calculations"
    exit 0
fi
# Alle Filesysteme abrufen
filesystems=$(get_filesystems)
if [ $? -ne 0 ] || [ -z "$filesystems" ]; then
    exit 0
fi
# Für jedes Filesystem alle Filesets prüfen
for filesystem in $filesystems; do
    filesets=$(get_filesets "$filesystem")
    if [ $? -ne 0 ]; then
        continue
    fi
    if [ -z "$filesets" ]; then
        echo "1 \"GPFS FILESET INODES ${filesystem}_EMPTY $HOSTNAME\" - WARNING: No filesets found in filesystem $filesystem"
        continue
    fi
    # Für jedes Fileset einen separaten Service erstellen
    for fileset in $filesets; do
        if [ -n "$fileset" ]; then
            check_fileset "$filesystem" "$fileset"
        fi
    done
done