#!/bin/bash # Pool capacity and the last scrub for the node exporter textfile collector. # A scrub in progress or cancelled keeps the previous end time: the pool has no newer completed scrub. set -euo pipefail dir={{ zfs_host_textfile_dir }} out=$dir/zfs_pool.prom tmp=$(mktemp "$dir/.zfs_pool.XXXXXX") trap 'rm -f "$tmp"' EXIT # Value of a metric line of the previous run, 0 if there is none. previous() { awk -v m="$1" -v p="$2" 'index($0, m "{pool=\"" p "\"}") == 1 {v = $2} END {print v + 0}' "$out" 2>/dev/null || echo 0 } status=$(zpool status -p) { echo '# TYPE zfs_pool_size_bytes gauge' echo '# TYPE zfs_pool_allocated_bytes gauge' echo '# TYPE zfs_pool_fragmentation_ratio gauge' zpool list -Hp -o name,size,allocated,fragmentation | while IFS=$'\t' read -r pool size alloc frag; do echo "zfs_pool_size_bytes{pool=\"$pool\"} $size" echo "zfs_pool_allocated_bytes{pool=\"$pool\"} $alloc" if [[ $frag =~ ^[0-9]+$ ]]; then echo "zfs_pool_fragmentation_ratio{pool=\"$pool\"} $(awk -v f="$frag" 'BEGIN {print f / 100}')" fi done echo '# TYPE zfs_pool_scrub_end_timestamp_seconds gauge' echo '# TYPE zfs_pool_scrub_errors gauge' zpool list -Hp -o name | while read -r pool; do scan=$(awk -v p="$pool" '$1 == "pool:" {cur = $2} cur == p && $1 == "scan:" {sub(/^[ \t]*scan:[ \t]*/, ""); print; exit}' <<< "$status") end=0 errors=0 if [[ $scan =~ ^scrub\ repaired\ .*\ with\ ([0-9]+)\ errors\ on\ (.+)$ ]]; then errors=${BASH_REMATCH[1]} end=$(date -d "${BASH_REMATCH[2]}" +%s) elif [[ $scan =~ ^scrub\ (in\ progress|canceled) ]]; then end=$(previous zfs_pool_scrub_end_timestamp_seconds "$pool") errors=$(previous zfs_pool_scrub_errors "$pool") fi echo "zfs_pool_scrub_end_timestamp_seconds{pool=\"$pool\"} $end" echo "zfs_pool_scrub_errors{pool=\"$pool\"} $errors" done } > "$tmp" chmod 0644 "$tmp" mv "$tmp" "$out" trap - EXIT