-
Notifications
You must be signed in to change notification settings - Fork 4
/
zpool_report.sh
executable file
·128 lines (116 loc) · 5.08 KB
/
zpool_report.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#!/usr/bin/env bash
#
# Send a zpool status summary and detailed report of all pools via Email.
readonly SCRIPT_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
# shellcheck source=user.example.conf
source "${SCRIPT_PATH}/user.conf"
# shellcheck source=global.conf
source "${SCRIPT_PATH}/global.conf"
# shellcheck source=format_email.sh
source "${SCRIPT_PATH}/format_email.sh"
readonly EMAIL_SUBJECT="TrueNAS $(hostname): zpool status report"
readonly EMAIL_BODY="/tmp/zpool_report.html"
# Only specify monospace font to let Email client decide of the rest.
echo "<pre style=\"font-family:monospace\">" > "${EMAIL_BODY}"
# Print a summary table of the status of all pools.
(
echo "<b>ZPool status report summary for all pools:</b>"
echo "+--------------+--------+------+------+------+----+--------+------+-----+"
echo "|Pool Name |Status |Read |Write |Cksum |Used|Scrub |Scrub |Last |"
echo "| | |Errors|Errors|Errors| |Repaired|Errors|Scrub|"
echo "| | | | | | |Bytes | |Age |"
echo "+--------------+--------+------+------+------+----+--------+------+-----+"
) >> "${EMAIL_BODY}"
for pool_name in ${ZFS_POOLS}; do
pool_health="$(zpool list -H -o health "${pool_name}")"
pool_status="$(zpool status "${pool_name}")"
pool_used_capacity="$(zpool list -H -p -o capacity "${pool_name}")"
pool_errors="$(echo "${pool_status}" | grep -E "(ONLINE|DEGRADED|FAULTED|UNAVAIL|REMOVED)[ \t]+[0-9]+")"
# Count the number of read errors in the pool by counting the numbers in the READ column of the zpool status output.
read_errors=0
for error in $(echo "${pool_errors}" | awk '{print $3}'); do
# Check if only numbers are displayed in the read errors column, zpool status will abbrieviate 1000 with 1K so if
# there's a K in the column that means there's more than 1000 errors and we don't need to check any further because
# if a pool gets to this point then knowing if there's 10K or 1K errors doesn't mean much and also because I'm lazy
# and I don't want to write the code for it.
if echo "${error}" | grep -Eq "[^0-9]+"; then
read_errors=1000
break
fi
read_errors=$((read_errors + error))
done
if [[ "${read_errors}" -ge 1000 ]]; then
read_errors=">1K"
fi
# Do the same for the write and checksum errors.
write_errors=0
for error in $(echo "${pool_errors}" | awk '{print $4}'); do
if echo "${error}" | grep -Eq "[^0-9]+"; then
write_errors=1000
break
fi
write_errors=$((write_errors + error))
done
if [[ "${write_errors}" -ge 1000 ]]; then
write_errors=">1K"
fi
checksum_errors=0
for error in $(echo "${pool_errors}" | awk '{print $5}'); do
if echo "${error}" | grep -Eq "[^0-9]+"; then
checksum_errors=1000
break
fi
checksum_errors=$((checksum_errors + error))
done
if [[ "${checksum_errors}" -ge 1000 ]]; then
checksum_errors=">1K"
fi
scrub_repaired_bytes="N/A"
scrub_errors="N/A"
scrub_age="N/A"
if [[ "$(echo "${pool_status}" | grep "scan" | awk '{print $2}')" == "scrub" ]]; then
scrub_repaired_bytes="$(echo "${pool_status}" | grep "scan" | awk '{print $4}')"
scrub_errors="$(echo "${pool_status}" | grep "scan" | awk '{print $8}')"
scrub_date="$(echo "${pool_status}" | grep "scan" | awk '{print $15"-"$12"-"$13"_"$14}')"
scrub_timestamp="$(date -j -f "%Y-%b-%e_%H:%M:%S" "${scrub_date}" "+%s")"
current_timestamp="$(date "+%s")"
scrub_age=$((((current_timestamp - scrub_timestamp) + 43200) / 86400))
fi
# Choose the symbol to display beside the pool name.
if [[ "${pool_health}" == "FAULTED" ]] ||
[[ "${pool_used_capacity}" -ge "${ZFS_POOL_CAPACITY_CRITICAL}" ]] ||
{ [[ "${scrub_errors}" != "N/A" ]] && [[ "${scrub_errors}" != "0" ]]; }; then
ui_symbol="${UI_CRITICAL_SYMBOL}"
elif [[ "${pool_health}" != "ONLINE" ]] ||
[[ "${read_errors}" != "0" ]] ||
[[ "${write_errors}" != "0" ]] ||
[[ "${checksum_errors}" != "0" ]] ||
[[ "${pool_used_capacity}" -ge "${ZFS_POOL_CAPACITY_WARNING}" ]] ||
[[ "${scrub_repaired_bytes}" != "0B" ]] ||
[[ "$(echo "${scrub_age}" | awk '{print int($1)}')" -ge "${SCRUB_AGE_WARNING}" ]]; then
ui_symbol="${UI_WARNING_SYMBOL}"
else
ui_symbol=" "
fi
# Print the row with all the attributes corresponding to the pool.
printf "|%-12s %1s|%-8s|%6s|%6s|%6s|%3s%%|%8s|%6s|%5s|\n" "${pool_name}" "${ui_symbol}" "${pool_health}" \
"${read_errors}" "${write_errors}" "${checksum_errors}" "${pool_used_capacity}" "${scrub_repaired_bytes}" "${scrub_errors}" \
"${scrub_age}" >> "${EMAIL_BODY}"
done
echo "+--------------+--------+------+------+------+----+--------+------+-----+" >> "${EMAIL_BODY}"
# Print a detailed status report for each pool.
for pool_name in ${ZFS_POOLS}; do
(
echo ""
echo ""
echo "<b>ZPool status report for ${pool_name}:</b>"
zpool status -v "${pool_name}"
) >> "${EMAIL_BODY}"
done
(
echo ""
echo "-- End of ZPool status report --"
echo "</pre>"
) >> "${EMAIL_BODY}"
format_email "${EMAIL_SUBJECT}" "${EMAIL_ADDRESS}" "${EMAIL_BODY}" | sendmail -i -t
rm "${EMAIL_BODY}"