colorize cli
This commit is contained in:
@@ -83,8 +83,50 @@ state_html() {
|
||||
esac
|
||||
}
|
||||
|
||||
# Terminal colors (same palette as the HTML), only when stdout is a TTY
|
||||
# so piped/redirected output stays clean.
|
||||
COLOR=false
|
||||
C_BOLD=""
|
||||
C_RED=""
|
||||
C_RESET=""
|
||||
if [ -t 1 ]; then
|
||||
COLOR=true
|
||||
C_BOLD=$'\e[1m'
|
||||
C_RED=$'\e[1;38;2;207;34;46m'
|
||||
C_RESET=$'\e[0m'
|
||||
fi
|
||||
|
||||
state_txt() {
|
||||
if [ "$COLOR" = true ]; then
|
||||
local c
|
||||
case "$1" in
|
||||
PASSED|ONLINE) c=$'\e[1;38;2;26;127;55m' ;;
|
||||
UNKNOWN) c=$'\e[1;38;2;154;103;0m' ;;
|
||||
*) c=$'\e[1;38;2;207;34;46m' ;;
|
||||
esac
|
||||
printf '%s%s%s' "$c" "$1" "$C_RESET"
|
||||
else
|
||||
printf '%s' "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
# $1 = percentage (drives the gradient), $2 = text to print. Callers pad
|
||||
# $2 to its column width BEFORE calling — ANSI codes are invisible but
|
||||
# still count as characters, so padding after coloring breaks alignment.
|
||||
usage_txt() {
|
||||
if [ "$COLOR" = true ]; then
|
||||
local hex
|
||||
hex=$(usage_color "$1")
|
||||
printf '\e[38;2;%d;%d;%dm%s%s' \
|
||||
"$((16#${hex:1:2}))" "$((16#${hex:3:2}))" "$((16#${hex:5:2}))" \
|
||||
"$2" "$C_RESET"
|
||||
else
|
||||
printf '%s' "$2"
|
||||
fi
|
||||
}
|
||||
|
||||
# ─── SMART Disk Health (SATA/SAS) ───────────────────────────────
|
||||
STATUS+="SMART (SATA):\n"
|
||||
STATUS+="${C_BOLD}SMART (SATA):${C_RESET}\n"
|
||||
for disk in /dev/sd?; do
|
||||
[ -b "$disk" ] || continue
|
||||
|
||||
@@ -103,7 +145,7 @@ for disk in /dev/sd?; do
|
||||
model=$(smartctl -i "$disk" 2>/dev/null | awk -F': +' '/Device Model|Model Number/{print $2; exit}') || true
|
||||
model="${model:-unknown}"
|
||||
|
||||
STATUS+=" $disk ($model): $health, ${temp}C, ${hours}h\n"
|
||||
STATUS+=$(printf ' %-13s %-24s %5s %7s ' "$disk" "$model" "${temp}C" "${hours}h")$(state_txt "$health")"\n"
|
||||
HTML_SATA+="<tr><td $TD>$disk</td><td $TD>$model</td><td $TD>$(state_html "$health")</td><td $TDR>${temp}C</td><td $TDR>${hours}h</td></tr>"$'\n'
|
||||
|
||||
if [ "$health" != "PASSED" ] && [ "$health" != "UNKNOWN" ]; then
|
||||
@@ -130,7 +172,7 @@ for disk in /dev/sd?; do
|
||||
done
|
||||
|
||||
# ─── SMART Disk Health (NVMe) ───────────────────────────────────
|
||||
STATUS+="\nSMART (NVMe):\n"
|
||||
STATUS+="\n${C_BOLD}SMART (NVMe):${C_RESET}\n"
|
||||
for disk in /dev/nvme[0-9]*; do
|
||||
# Match only controller devices (nvme0, nvme1), not namespaces (nvme0n1)
|
||||
[[ "$disk" =~ ^/dev/nvme[0-9]+$ ]] || continue
|
||||
@@ -153,7 +195,7 @@ for disk in /dev/nvme[0-9]*; do
|
||||
# NVMe percentage used — 100% means full rated write endurance consumed
|
||||
pct_used=$(smartctl -A "$ns" 2>/dev/null | awk -F': +' '/Percentage Used/{print $2; exit}' | tr -d '%') || true
|
||||
|
||||
STATUS+=" $ns ($model): $health, ${temp}C, ${hours}h\n"
|
||||
STATUS+=$(printf ' %-13s %-24s %5s %7s ' "$ns" "$model" "${temp}C" "${hours}h")$(state_txt "$health")"\n"
|
||||
HTML_NVME+="<tr><td $TD>$ns</td><td $TD>$model</td><td $TD>$(state_html "$health")</td><td $TDR>${temp}C</td><td $TDR>${hours}h</td></tr>"$'\n'
|
||||
|
||||
if [ "$health" != "PASSED" ] && [ "$health" != "UNKNOWN" ]; then
|
||||
@@ -166,16 +208,16 @@ for disk in /dev/nvme[0-9]*; do
|
||||
done
|
||||
|
||||
# ─── ZFS Pool Health ─────────────────────────────────────────────
|
||||
STATUS+="\nZFS Pools:\n"
|
||||
STATUS+="\n${C_BOLD}ZFS Pools:${C_RESET}\n"
|
||||
while IFS= read -r pool; do
|
||||
[ -n "$pool" ] || continue
|
||||
state=$(zpool list -H -o health "$pool" 2>/dev/null) || true
|
||||
state="${state:-UNKNOWN}"
|
||||
pool_info=$(zpool list -H -o name,size,alloc,free,cap "$pool" 2>/dev/null) || true
|
||||
STATUS+=" $pool_info $state\n"
|
||||
|
||||
# zpool -H output is tab-separated
|
||||
IFS=$'\t' read -r p_name p_size p_alloc p_free p_cap <<< "$pool_info" || true
|
||||
STATUS+=$(printf ' %-12s %7s %7s %7s ' "${p_name:-$pool}" "$p_size" "$p_alloc" "$p_free")$(usage_txt "${p_cap%\%}" "$(printf '%5s' "$p_cap")")" "$(state_txt "$state")"\n"
|
||||
cap_cell="<span style=\"color:$(usage_color "${p_cap%\%}")\">$p_cap</span>"
|
||||
HTML_ZFS+="<tr><td $TD>${p_name:-$pool}</td><td $TDR>$p_size</td><td $TDR>$p_alloc</td><td $TDR>$p_free</td><td $TDR>$cap_cell</td><td $TD>$(state_html "$state")</td></tr>"$'\n'
|
||||
|
||||
@@ -215,7 +257,7 @@ done < <(zpool list -H -o name 2>/dev/null || true)
|
||||
# Quotas are hard limits — writes fail at 100% — so warn before the kids
|
||||
# hit the wall. Lists every dataset with a quota set (with -p, an unset
|
||||
# quota reads as 0).
|
||||
STATUS+="\nQuotas:\n"
|
||||
STATUS+="\n${C_BOLD}Quotas:${C_RESET}\n"
|
||||
HTML_QUOTA=""
|
||||
while IFS=$'\t' read -r ds used quota; do
|
||||
[ -n "$ds" ] || continue
|
||||
@@ -223,7 +265,7 @@ while IFS=$'\t' read -r ds used quota; do
|
||||
pct=$(( used * 100 / quota ))
|
||||
used_h=$(numfmt --to=iec "$used" 2>/dev/null || echo "$used")
|
||||
quota_h=$(numfmt --to=iec "$quota" 2>/dev/null || echo "$quota")
|
||||
STATUS+=" $ds: ${pct}% (${used_h}/${quota_h})\n"
|
||||
STATUS+=$(printf ' %-18s ' "$ds")$(usage_txt "$pct" "$(printf '%4s' "${pct}%")")" (${used_h}/${quota_h})\n"
|
||||
weight=""
|
||||
if [ "$pct" -gt "$QUOTA_THRESHOLD" ]; then
|
||||
PROBLEMS+="[QUOTA] $ds is at ${pct}% of its ${quota_h} quota\n"
|
||||
@@ -233,7 +275,7 @@ while IFS=$'\t' read -r ds used quota; do
|
||||
done < <(zfs list -Hp -o name,used,quota -t filesystem 2>/dev/null || true)
|
||||
|
||||
# ─── Disk Space ──────────────────────────────────────────────────
|
||||
STATUS+="\nDisk Space:\n"
|
||||
STATUS+="\n${C_BOLD}Disk Space:${C_RESET}\n"
|
||||
while IFS= read -r line; do
|
||||
[ -n "$line" ] || continue
|
||||
usage=$(echo "$line" | awk '{print $5}' | tr -d '%')
|
||||
@@ -241,7 +283,7 @@ while IFS= read -r line; do
|
||||
size=$(echo "$line" | awk '{print $2}')
|
||||
used=$(echo "$line" | awk '{print $3}')
|
||||
avail=$(echo "$line" | awk '{print $4}')
|
||||
STATUS+=" $mount: ${usage}% (${used}/${size}, ${avail} free)\n"
|
||||
STATUS+=$(printf ' %-12s ' "$mount")$(usage_txt "$usage" "$(printf '%4s' "${usage}%")")" (${used}/${size}, ${avail} free)\n"
|
||||
weight=""
|
||||
if [ "$usage" -gt "$SPACE_THRESHOLD" ] 2>/dev/null; then
|
||||
PROBLEMS+="[SPACE] $mount is ${usage}% full\n"
|
||||
@@ -259,7 +301,7 @@ if [ "$ERROR_ONLY" = true ]; then
|
||||
exit 0
|
||||
fi
|
||||
SUBJECT="[ALERT] $HOSTNAME health check failed"
|
||||
BODY="Health check found issues on $HOSTNAME at $(date):\n\n$PROBLEMS\n---\n"
|
||||
BODY="Health check found issues on $HOSTNAME at $(date):\n\n${C_RED}$PROBLEMS${C_RESET}\n---\n"
|
||||
else
|
||||
if [ -n "$PROBLEMS" ]; then
|
||||
SUBJECT="[REPORT] $HOSTNAME health — ISSUES FOUND"
|
||||
@@ -268,7 +310,7 @@ else
|
||||
fi
|
||||
BODY="Health report for $HOSTNAME at $(date):\n\n"
|
||||
if [ -n "$PROBLEMS" ]; then
|
||||
BODY+="*** ISSUES ***\n\n$PROBLEMS\n"
|
||||
BODY+="${C_RED}*** ISSUES ***\n\n$PROBLEMS${C_RESET}\n"
|
||||
fi
|
||||
BODY+="--- Status ---\n\n$STATUS\n---\n"
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user