Commit b9e9d5d1 authored by Vitaly Lipatov's avatar Vitaly Lipatov

hdd: add shelf-layout.sh to draw disk shelf grid from SES enclosure data

Maps slot -> block device via /sys/class/enclosure/, joins lsblk size/model and zpool membership, renders a text table plus a colored cols x rows grid of the physical shelf (slot 0 top-left, left to right). Geometry is configurable via COLS/ROWS env vars; default 6x4 fits a 24-bay shelf. Co-Authored-By: 's avatarClaude Opus 4.7 (1M context) <noreply@anthropic.com>
parent e998b05f
#!/bin/bash
# Draw disk shelf layout from /sys/class/enclosure/ data.
# Maps slot numbers to block devices, sizes, models, and ZFS pool membership.
#
# Usage: shelf-layout.sh [enclosure_addr]
# Example: shelf-layout.sh 6:0:22:0
# Env: COLS=6 ROWS=4 shelf geometry, slot 0 top-left, left->right then row down
set -u
enc=${1:-$(ls /sys/class/enclosure/ 2>/dev/null | head -1)}
[ -n "$enc" ] || { echo "shelf-layout: no enclosure under /sys/class/enclosure/" >&2; exit 1; }
encdir=/sys/class/enclosure/$enc
[ -d "$encdir" ] || { echo "shelf-layout: $encdir does not exist" >&2; exit 1; }
cols=${COLS:-6}
rows=${ROWS:-4}
declare -A slot_dev slot_status
for d in "$encdir"/[0-9]*; do
[ -d "$d" ] || continue
s=${d##*/}
slot_dev[$s]=$(ls "$d/device/block/" 2>/dev/null | head -1)
slot_status[$s]=$(cat "$d/status" 2>/dev/null)
done
declare -A dev_size dev_model
while read -r name size model; do
dev_size[$name]=$size
dev_model[$name]=$model
done < <(lsblk -d -n -o NAME,SIZE,MODEL)
declare -A dev_pool
if command -v zpool >/dev/null 2>&1; then
pool=
while IFS= read -r line; do
if [[ $line =~ ^[[:space:]]*pool:[[:space:]]+(.+) ]]; then
pool=${BASH_REMATCH[1]}
continue
fi
id=$(awk '{print $1}' <<<"$line")
case "$id" in
wwn-*|ata-*|scsi-*|nvme-*)
tgt=/dev/disk/by-id/$id
[ -e "$tgt" ] || continue
dev=$(basename "$(readlink -f "$tgt")")
[[ $dev =~ ^(sd[a-z]+)[0-9]+$ ]] && dev=${BASH_REMATCH[1]}
dev_pool[$dev]=$pool
;;
esac
done < <(zpool status)
fi
mapfile -t slots < <(printf '%s\n' "${!slot_dev[@]}" | sort -n)
echo "Enclosure: $enc"
printf '%-5s %-5s %-7s %-22s %s\n' Slot Dev Size Model Pool
printf '%-5s %-5s %-7s %-22s %s\n' ---- --- ---- ----- ----
for s in "${slots[@]}"; do
dev=${slot_dev[$s]:-}
if [ -z "$dev" ]; then
printf '%-5s %-5s %-7s %-22s %s\n' "$s" "-" "-" "(${slot_status[$s]:-empty})" "-"
else
printf '%-5s %-5s %-7s %-22.22s %s\n' \
"$s" "$dev" "${dev_size[$dev]:--}" "${dev_model[$dev]:--}" "${dev_pool[$dev]:--}"
fi
done
echo
echo "Shelf ${cols}x${rows} (slot 0 top-left, left->right top->bottom):"
echo
declare -A pool_color
palette=(31 32 33 34 35 36 91 92 93 94 95 96)
ci=0
for p in $(printf '%s\n' "${dev_pool[@]}" | sort -u); do
[ -z "$p" ] && continue
pool_color[$p]=${palette[$ci]}
ci=$(( (ci+1) % ${#palette[@]} ))
done
use_color=1
[ -t 1 ] || use_color=0
cw=22
hborder() {
local c
printf '+'
for ((c=0;c<cols;c++)); do
printf -- '%*s' $cw '' | tr ' ' '-'
printf '+'
done
printf '\n'
}
cell() {
local s=$1 line=$2
local dev=${slot_dev[$s]:-}
local pool= col=37
if [ -n "$dev" ]; then
pool=${dev_pool[$dev]:-}
[ -n "$pool" ] && col=${pool_color[$pool]:-37}
fi
local txt=
case $line in
1) if [ -n "$dev" ]; then
txt=$(printf 'slot %-2s %-7s' "$s" "$dev")
else
local st=${slot_status[$s]:-empty}
[ "$st" = "not installed" ] && st=empty
txt=$(printf 'slot %-2s %s' "$s" "$st")
fi ;;
2) [ -n "$dev" ] && txt=$(printf '%-7s %-12.12s' "${dev_size[$dev]:--}" "${dev_model[$dev]:-}") ;;
3) [ -n "$dev" ] && txt=${pool:-(no pool)} ;;
esac
if [ "$use_color" = 1 ]; then
printf ' \e[%sm%-*s\e[0m|' "$col" $((cw-1)) "$txt"
else
printf ' %-*s|' $((cw-1)) "$txt"
fi
}
slot_count=${#slots[@]}
for ((r=0;r<rows;r++)); do
hborder
for ln in 1 2 3; do
printf '|'
for ((c=0;c<cols;c++)); do
idx=$((r*cols+c))
[ $idx -ge $slot_count ] && { printf ' %*s|' $((cw-1)) ''; continue; }
cell "${slots[$idx]}" "$ln"
done
printf '\n'
done
done
hborder
echo
echo "Pools:"
for p in "${!pool_color[@]}"; do
if [ "$use_color" = 1 ]; then
printf ' \e[%sm%s\e[0m\n' "${pool_color[$p]}" "$p"
else
printf ' %s\n' "$p"
fi
done
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment