|
|
@@ -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
|