Browse Source

Updated modern HTML5 reporting and added mail notifications

pmacko 1 month ago
parent
commit
b179b05f49
1 changed files with 211 additions and 31 deletions
  1. 211 31
      hdd.sh

+ 211 - 31
hdd.sh

@@ -1,42 +1,222 @@
 #!/bin/bash
 #########################################################################
-#                        Script for check HDD state                     #
+#                       Script for check HDD state                     #
 #                      Created by Pavol Macko - DoIT                    #
-#                                ver 0.2                                #
+#                               ver 0.4                                 #
 #########################################################################
 
 #------------------------------ VARIABLES ------------------------------#
+LOG="/tmp/hdd.log"
+HTML_DIR="/var/www/hdd"
+HTML_OUT="$HTML_DIR/hdd.html"
 SRV=$(hostname -s)
-LOG=/tmp/hdd.log
-test -f $LOG && rm -rf $LOG
-
-#------------------------------ HDD-INFO -------------------------------#
-checkhdd(){
-echo -e "- \e[1;32mExtracting\e[0m HDD info from [\e[1;33m$SRV\e[0m]"
-echo "------------------ ------------------- ------- ----------- ------ ------" > $LOG
-echo "MODEL SERIAL SIZE TYPE CHECK STATUS" >> $LOG
-echo "------------------ ------------------- ------- ----------- ------ ------" >> $LOG
-DRI=$(lsblk --nodeps -n -o name -S)
-for d in $DRI;
+EMAIL_TO="info@doit.sk"
+EMAIL_SUBJECT="[CRITICAL] Disk Issue Detected on $SRV"
+EMAIL_BODY=""
+HAS_ERRORS=0
+TEMP=55
+
+#------------------------------- REPORT --------------------------------#
+mkdir -p "$HTML_DIR"
+echo -e "- \e[1;32mExtracting\e[0m Local Storage info from [\e[1;33m$SRV\e[0m]"
+echo "DEV|MODEL|SERIAL|SIZE(GB)|TYPE|TEMP(C)|HOURS|HEALTH|REALLOC" > $LOG
+
+cat << EOF > "$HTML_OUT"
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>$SRV Storage</title>
+    <style>
+        :root {
+            --bg: #0f172a;
+            --surface: #1e293b;
+            --text: #f8fafc;
+            --text-muted: #94a3b8;
+            --border: #334155;
+            --ok-bg: rgba(34, 197, 94, 0.15);
+            --ok-text: #4ade80;
+            --warn-bg: rgba(239, 68, 68, 0.15);
+            --warn-text: #f87171;
+        }
+        body {
+            background-color: var(--bg);
+            color: var(--text);
+            font-family: system-ui, sans-serif;
+            padding: 2rem;
+            margin: 0;
+        }
+        .container {
+            max-width: 1200px;
+            margin: 0 auto;
+        }
+        .header {
+            display: flex;
+            justify-content: space-between;
+            align-items: flex-end;
+            border-bottom: 1px solid var(--border);
+            padding-bottom: 1rem;
+            margin-bottom: 2rem;
+        }
+        .header h1 {
+            margin: 0;
+            font-size: 1.5rem;
+            font-weight: 500;
+        }
+        table {
+            width: 100%;
+            border-collapse: collapse;
+            background-color: var(--surface);
+            border-radius: 8px;
+            overflow: hidden;
+        }
+        th, td {
+            padding: 1rem 1.25rem;
+            text-align: left;
+            border-bottom: 1px solid var(--border);
+        }
+        th {
+            background-color: rgba(0, 0, 0, 0.2);
+            color: var(--text-muted);
+            font-weight: 600;
+            font-size: 0.75rem;
+            text-transform: uppercase;
+        }
+        tr:last-child td {
+            border-bottom: none;
+        }
+        tr:hover {
+            background-color: rgba(255, 255, 255, 0.02);
+        }
+        .serial {
+            color: var(--text-muted);
+            font-family: monospace;
+            font-size: 0.85rem;
+        }
+        .badge {
+            padding: 0.25rem 0.75rem;
+            border-radius: 999px;
+            font-size: 0.75rem;
+            font-weight: 600;
+            display: inline-block;
+        }
+        .badge.ok {
+            background-color: var(--ok-bg);
+            color: var(--ok-text);
+        }
+        .badge.warn {
+            background-color: var(--warn-bg);
+            color: var(--warn-text);
+        }
+        .timestamp {
+            font-size: 0.85rem;
+            color: var(--text-muted);
+            margin-top: 1.5rem;
+            text-align: center;
+        }
+    </style>
+</head>
+<body>
+    <div class="container">
+        <div class="header">
+            <h1>Drive overview on <span style="color: var(--text-muted);">[$SRV]</span></h1>
+        </div>
+        <table>
+            <thead>
+                <tr>
+                    <th>Device</th>
+                    <th>Model</th>
+                    <th>Serial</th>
+                    <th>Size (GB)</th>
+                    <th>Type</th>
+                    <th>Temp (°C)</th>
+                    <th>Hours</th>
+                    <th>Health</th>
+                    <th>Realloc</th>
+                </tr>
+            </thead>
+            <tbody>
+EOF
+
+#------------------------------- EXTRACT -------------------------------#
+lsblk -d -n -b -o NAME,TYPE,TRAN,SIZE | awk '$2=="disk" && $1 !~ /^(zd|loop|md|dm-|ram)/' | while read -r d type tran bytes;
 do
-SMART=$(smartctl -a /dev/$d | grep "Device Model")
-if [ ! -z "$SMART" ];
-then
-HMOD=$(smartctl -a /dev/$d | grep "Device Model" | awk '{print $3"-"$4"-"$5}' | sed 's/--$//' | sed 's/-$//')
-HSER=$(smartctl -a /dev/$d | grep "Serial Number" | awk '{print $NF}')
-HCAP=$(smartctl -a /dev/$d | grep "User Capacity" | awk '{print $(NF-1)$NF}')
-HROT=$(smartctl -a /dev/$d | grep "Rotation Rate" | awk '{print $3"-"$4}')
-HHEA=$(smartctl -H /dev/$d | grep overall-health | awk '{print $NF}')
-HERR=$(smartctl -a /dev/$d | grep -i "Error [1-999]" | head -1)
-if [ ! -z "$HERR" ]; then ERR="ERROR"; else ERR="OK"; fi
-echo "$HMOD $HSER $HCAP $HROT $HHEA $ERR" >> $LOG
-fi
+    [[ "$tran" == "usb" ]] && continue
+    HCAP=$(awk -v b="$bytes" 'BEGIN { printf "%.2f", b / (1024^3) }')
+    SMART=$(smartctl -a /dev/$d 2>/dev/null)
+    [[ -z "$SMART" ]] && continue
+    HMOD=$(echo "$SMART" | grep -E "^(Device Model|Model Number):" | awk -F: '{print $2}' | xargs)
+    HSER=$(echo "$SMART" | grep -i "^Serial Number:" | awk -F: '{print $2}' | xargs)
+    HROT=$(echo "$SMART" | grep -i "^Rotation Rate:" | awk -F: '{print $2}' | xargs)
+    if [[ "$tran" == "nvme" ]] || [[ "$HROT" == *"Solid State"* ]] || [[ -z "$HROT" ]]; then
+        HTYPE="SSD/NVMe"
+    else
+        HTYPE="HDD"
+    fi
+    HHEA=$(echo "$SMART" | grep -iE "overall-health|SMART overall-health" | awk '{print $NF}')
+    HTEMP=$(echo "$SMART" | awk '/^194 Temperature_Celsius/ {print $10}; /^Temperature:/ {print $2}' | head -n 1)
+    HHOURS=$(echo "$SMART" | awk '/^  9 Power_On_Hours/ {print $10}; /^Power On Hours:/ {print $4}' | tr -d ',' | head -n 1)
+    HREALLOC=$(echo "$SMART" | awk '/^  5 Reallocated_Sector_Ct/ {print $10}' | head -n 1)
+    HMOD=${HMOD:--}
+    HSER=${HSER:--}
+    HTEMP=${HTEMP:--}
+    HHOURS=${HHOURS:--}
+    HHEA=${HHEA:--}
+    HREALLOC=${HREALLOC:--}
+    echo "$d|${HMOD}|${HSER}|$HCAP|$HTYPE|${HTEMP}|${HHOURS}|${HHEA}|${HREALLOC}" >> $LOG
+    
+    CLASS_HEA="ok"
+    if [[ "$HHEA" != "PASSED" && "$HHEA" != "OK" ]]; then
+        CLASS_HEA="warn"
+        HAS_ERRORS=1
+        EMAIL_BODY="${EMAIL_BODY}\n- /dev/$d ($HMOD, SN: $HSER): Health status is '$HHEA'!"
+    fi
+    CLASS_REA="ok"
+    if [[ "$HREALLOC" =~ ^[0-9]+$ ]] && [[ "$HREALLOC" -gt 0 ]]; then
+        CLASS_REA="warn"
+        HAS_ERRORS=1
+        EMAIL_BODY="${EMAIL_BODY}\n- /dev/$d ($HMOD, SN: $HSER): Reallocated Sectors count is $HREALLOC!"
+    fi
+    if [[ "$HTEMP" =~ ^[0-9]+$ ]] && [[ "$HTEMP" -ge "$TEMP" ]]; then
+        HAS_ERRORS=1
+        EMAIL_BODY="${EMAIL_BODY}\n- /dev/$d ($HMOD, SN: $HSER): High Temperature ($HTEMP °C)!"
+    fi
+
+    cat << EOF >> "$HTML_OUT"
+                <tr>
+                    <td style="font-weight: 500;">/dev/$d</td>
+                    <td>${HMOD}</td>
+                    <td class="serial">${HSER}</td>
+                    <td>$HCAP</td>
+                    <td>$HTYPE</td>
+                    <td>${HTEMP}</td>
+                    <td>${HHOURS}</td>
+                    <td><span class="badge $CLASS_HEA">${HHEA}</span></td>
+                    <td><span class="badge $CLASS_REA">${HREALLOC}</span></td>
+                </tr>
+EOF
 done
-}
 
-#---------------------------- QUICK-CHECK ------------------------------#
-#smartctl -t short /dev/sdb
+if [[ "$HAS_ERRORS" -eq 1 ]]; then
+    FULL_MAIL_BODY="HDD/SSD alert triggered on server: $SRV\nDate: $(date +'%Y-%m-%d %H:%M:%S')\n\nDetected issues:$EMAIL_BODY\n\nCheck full dashboard at HTML report."
+    echo -e "$FULL_MAIL_BODY" | mail -s "$EMAIL_SUBJECT" "$EMAIL_TO"
+fi
+
+CLI_OUT=$(column -t -s '|' $LOG)
+HEADER=$(echo "$CLI_OUT" | head -n 1)
+DASHES=$(echo "$HEADER" | sed 's/[^ ]/-/g')
+echo -e "\e[1;36m$DASHES\e[0m"
+echo -e "\e[1;36m$HEADER\e[0m"
+echo -e "\e[1;36m$DASHES\e[0m"
+echo "$CLI_OUT" | tail -n +2
+rm -f $LOG
 
-#------------------------------- CORE ----------------------------------#
-checkhdd
-cat $LOG | column -t
+cat << EOF >> "$HTML_OUT"
+            </tbody>
+        </table>
+        <div class="timestamp">Last updated: $(date +'%Y-%m-%d %H:%M:%S')</div>
+    </div>
+</body>
+</html>
+EOF