#!/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