driveAtlas: redraw the Sliger CX4712 as a real front elevation
Lint / Shell (shellcheck) (push) Successful in 10s
Lint / Shell (shellcheck) (push) Successful in 10s
The old 10-bay render was a 138-column strip of ten wide horizontal boxes,
which is not what this chassis looks like. Sliger's own photos and CAD show
the ten 3.5" bays are a SINGLE ROW of ten with the drives mounted ON EDGE,
so from the front each bay is a tall narrow slot - ten thin vertical bars in
a row is the signature of the case. Drawn as stacked horizontal trays it was
simply wrong.
Redraw it as a true front elevation at the real proportions (4U, 431.8 x
176.8 mm, ~2.75:1 with rack ears):
- two 5.25" filler blanks side by side directly above the bay row, spanning
the same width (these are unused on all three nodes)
- one row of ten vertical bay slots, solid when occupied, dim ghost when not
- the narrow front I/O strip at the right: power ring, 2x USB-A, USB-C, and
the drive-lock key cylinder
- rack ears with vertical handles bracketing both edges
There are no front fans, no reset button, no badge and no per-bay LEDs on
this chassis, so none are drawn.
All text is pushed out of the picture into BAY/DEV caption rows column-aligned
under the slots, keeping the chassis a clean silhouette. M.2 and internal
drives are not on the front face, so they are listed as a legend beneath.
Also surface the two facts that actually matter for using this map: the case
has NO backplane (each bay is an individually hand-cabled SFF-8482 to SATA
adapter) and NO per-bay LEDs, so bay numbering is a LOCAL left-to-right
convention rather than a vendor one, and a drive can only be identified
physically by its serial - there is no bay LED to blink.
Fixed 88-column canvas, identical display width on every line in monochrome
and colour, colour runs coalesced per run of like bays to keep escape churn
low, SAFE width-1 glyphs only.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+128
-53
@@ -446,74 +446,149 @@ run_diagnose() {
|
||||
#------------------------------------------------------------------------------
|
||||
# generate_10bay_layout
|
||||
#
|
||||
# Generates ASCII art representation of a 10-bay hot-swap chassis (Sliger CX4712).
|
||||
# Shows storage controllers, M.2 NVMe slot, and 10 front hot-swap bays.
|
||||
# FRONT ELEVATION of a Sliger CX4712 4U rackmount chassis (faceplate removed).
|
||||
# - 2x 5.25" filler blanks side by side, spanning the bay region
|
||||
# - 10x 3.5" hot-swap bays in ONE row; drives sit on edge, so each bay reads
|
||||
# as a tall narrow slot -- the signature of this chassis
|
||||
# - narrow front I/O strip (power ring, 2x USB-A, USB-C, key lock)
|
||||
# - rack ears with vertical handles on both sides
|
||||
# Occupied bays are solid, empty bays are dim ghosts. M.2 / internal drives are
|
||||
# not on the front face, so they are listed as a legend under the drawing.
|
||||
#
|
||||
# Chassis has NO backplane and NO per-bay LEDs: each bay is an individually
|
||||
# hand-cabled SFF-8482 to SATA adapter, so bay numbering is a LOCAL
|
||||
# left-to-right convention, not a vendor one, and a drive can only be
|
||||
# identified physically by its SERIAL (there is no bay LED to blink).
|
||||
#
|
||||
# Args:
|
||||
# $1 - Hostname to display in the layout header
|
||||
# $1 - Hostname to display in the header
|
||||
#
|
||||
# Side effects: Calls build_drive_map() to populate DRIVE_MAP
|
||||
#
|
||||
# The art printfs embed our own ANSI colour vars (DA_*) and literal box-drawing
|
||||
# in the format string by design; device names are passed as %s args.
|
||||
#------------------------------------------------------------------------------
|
||||
# shellcheck disable=SC2059
|
||||
generate_10bay_layout() {
|
||||
local hostname="$1"
|
||||
build_drive_map
|
||||
local host="${1:-unknown}"
|
||||
local i j k n st run cell c s lp
|
||||
|
||||
# Box interior width = 136 (determined by 10 bay boxes: 4 + 10*13 + 2)
|
||||
# Total box width = 138 (136 interior + 2 for │ borders)
|
||||
|
||||
# Main chassis section
|
||||
printf "┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐\n"
|
||||
printf "│ %-132s │\n" "$hostname - Sliger CX4712 (10x 3.5\" Hot-swap)"
|
||||
printf "│%-136s│\n" ""
|
||||
|
||||
# Show storage controllers
|
||||
printf "│ %-134s│\n" "Storage Controllers:"
|
||||
while IFS= read -r ctrl; do
|
||||
[[ -n "$ctrl" ]] && printf "│ %-134.134s│\n" "$ctrl"
|
||||
done < <(get_storage_controllers)
|
||||
printf "│%-136s│\n" ""
|
||||
|
||||
# M.2 NVMe slot if present
|
||||
if [[ -n "${DRIVE_MAP[m2-1]}" ]]; then
|
||||
printf "│ %-134s│\n" " M.2 NVMe: ${DRIVE_MAP[m2-1]}"
|
||||
printf "│%-136s│\n" ""
|
||||
if declare -F build_drive_map >/dev/null 2>&1; then
|
||||
build_drive_map 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Internal (non-bay) drives if present
|
||||
local int_keys
|
||||
int_keys="$(printf '%s\n' "${!DRIVE_MAP[@]}" | grep -E '^int-' | sort)"
|
||||
if [[ -n "$int_keys" ]]; then
|
||||
while IFS= read -r int_key; do
|
||||
printf "│ %-134s│\n" " Internal (non-bay): ${DRIVE_MAP[$int_key]}"
|
||||
done <<< "$int_keys"
|
||||
printf "│%-136s│\n" ""
|
||||
if ! declare -p DRIVE_MAP >/dev/null 2>&1; then
|
||||
declare -g -A DRIVE_MAP=()
|
||||
fi
|
||||
|
||||
printf "│ %-134s│\n" " Front Hot-swap Bays:"
|
||||
printf "│%-136s│\n" ""
|
||||
|
||||
# Bay top borders
|
||||
printf "│ "
|
||||
for bay in {1..10}; do
|
||||
printf "┌──────────┐ "
|
||||
if declare -F da_color_init >/dev/null 2>&1; then da_color_init; fi
|
||||
# make every palette global exist -- safe under `set -u`, no-op when set
|
||||
for s in DA_ST DA_HL DA_DIM DA_OK DA_YEL DA_HOT DA_BLU DA_CYN DA_RST DA_SR; do
|
||||
printf -v "$s" '%s' "${!s-}"
|
||||
done
|
||||
printf " │\n"
|
||||
|
||||
# Bay contents
|
||||
printf "│ "
|
||||
for bay in {1..10}; do
|
||||
printf "│%-2d:%-7s│ " "$bay" "${DRIVE_MAP[$bay]:-EMPTY}"
|
||||
# ---- geometry -----------------------------------------------------------
|
||||
# display width 88 = |1| 1 ear 3 | 2 | bays 61 | 5 | I/O 8 | 2 | ear 3 | 1 |1|
|
||||
# bay strip 61 = wall + 10 slots of 5 cols separated by 1 col + wall
|
||||
local -a state=() namec=() numc=()
|
||||
for ((i = 1; i <= 10; i++)); do
|
||||
s="${DRIVE_MAP[$i]:-}"
|
||||
if [ -n "$s" ]; then state[i]=on; else state[i]=off; s='--'; fi
|
||||
printf -v c '%-5.5s' "$s" # hard truncate: borders can never move
|
||||
s="${c%% *}"
|
||||
lp=$(( (5 - ${#s}) / 2 ))
|
||||
printf -v c '%*s%s%*s' "$lp" '' "$s" "$((5 - lp - ${#s}))" ''
|
||||
namec[i]="$c"
|
||||
s="$i"
|
||||
lp=$(( (5 - ${#s}) / 2 ))
|
||||
printf -v c '%*s%s%*s' "$lp" '' "$s" "$((5 - lp - ${#s}))" ''
|
||||
numc[i]="$c"
|
||||
done
|
||||
printf " │\n"
|
||||
|
||||
# Bay bottom borders
|
||||
printf "│ "
|
||||
for bay in {1..10}; do
|
||||
printf "└──────────┘ "
|
||||
# ---- coalesced colour runs: one escape pair per RUN of like bays --------
|
||||
local fillrow='' namerow='' numrow=''
|
||||
i=1
|
||||
while [ "$i" -le 10 ]; do
|
||||
st="${state[i]}"
|
||||
j="$i"
|
||||
while [ "$j" -le 10 ] && [ "${state[j]}" = "$st" ]; do j=$((j + 1)); done
|
||||
n=$((j - i))
|
||||
if [ "$st" = on ]; then cell='█████'; c="$DA_OK"; else cell='░░░░░'; c="$DA_DIM"; fi
|
||||
run=''
|
||||
for ((k = 0; k < n; k++)); do [ "$k" -gt 0 ] && run+=' '; run+="$cell"; done
|
||||
fillrow+="${c}${run}${DA_SR}"
|
||||
run=''
|
||||
for ((k = i; k < j; k++)); do [ "$k" -gt "$i" ] && run+=' '; run+="${namec[k]}"; done
|
||||
namerow+="${c}${run}${DA_SR}"
|
||||
if [ "$j" -le 10 ]; then fillrow+=' '; namerow+=' '; fi
|
||||
i="$j"
|
||||
done
|
||||
for ((i = 1; i <= 10; i++)); do
|
||||
[ "$i" -gt 1 ] && numrow+=' '
|
||||
numrow+="${numc[i]}"
|
||||
done
|
||||
printf " │\n"
|
||||
|
||||
printf "└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘\n"
|
||||
# ---- header -------------------------------------------------------------
|
||||
local hostp tail
|
||||
printf -v hostp '%-24.24s' "$host"
|
||||
printf -v tail '%-52.52s' 'Sliger CX4712 - 4U - 431.8 x 176.8 mm'
|
||||
printf '\n'
|
||||
printf "${DA_CYN}driveAtlas${DA_SR} ${DA_HL}%s${DA_SR} ${DA_ST}%s${DA_RST}\n" "$hostp" "$tail"
|
||||
printf -v tail '%-88.88s' 'FRONT ELEVATION - mesh faceplate removed - drives mounted on edge'
|
||||
printf "${DA_DIM}%s${DA_RST}\n" "$tail"
|
||||
printf '\n'
|
||||
|
||||
# ---- chassis ------------------------------------------------------------
|
||||
local T525='┌─────────────────────────────┬─────────────────────────────┐'
|
||||
local M525='│ 5.25" FILLER │ 5.25" FILLER │'
|
||||
local B525='└─────────────────────────────┴─────────────────────────────┘'
|
||||
local TBAY='┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐'
|
||||
local BBAY='└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘'
|
||||
local GAP61=' '
|
||||
local GAP74=' '
|
||||
|
||||
printf "${DA_ST}┌──────────────────────────────────────────────────────────────────────────────────────┐${DA_RST}\n"
|
||||
printf "${DA_ST}│ ${DA_HL}╭─╮${DA_SR} %s ${DA_HL}╭─╮${DA_SR} │${DA_RST}\n" "$GAP74"
|
||||
printf "${DA_ST}│ ${DA_HL}│ │${DA_SR} ${DA_DIM}%s${DA_SR} ┌──────┐ ${DA_HL}│ │${DA_SR} │${DA_RST}\n" "$T525"
|
||||
printf "${DA_ST}│ ${DA_HL}│ │${DA_SR} ${DA_DIM}%s${DA_SR} │ ${DA_HL}(o)${DA_SR} │ ${DA_HL}│ │${DA_SR} │${DA_RST}\n" "$M525"
|
||||
printf "${DA_ST}│ ${DA_HL}│ │${DA_SR} ${DA_DIM}%s${DA_SR} │ │ ${DA_HL}│ │${DA_SR} │${DA_RST}\n" "$B525"
|
||||
printf "${DA_ST}│ ${DA_HL}│ │${DA_SR} %s │ ${DA_BLU}[A]${DA_SR} │ ${DA_HL}│ │${DA_SR} │${DA_RST}\n" "$GAP61"
|
||||
printf "${DA_ST}│ ${DA_HL}│ │${DA_SR} ${DA_HL}%s${DA_SR} │ ${DA_BLU}[A]${DA_SR} │ ${DA_HL}│ │${DA_SR} │${DA_RST}\n" "$TBAY"
|
||||
printf "${DA_ST}│ ${DA_HL}│ │${DA_SR} ${DA_HL}│${DA_SR}%s${DA_HL}│${DA_SR} │ ${DA_BLU}[C]${DA_SR} │ ${DA_HL}│ │${DA_SR} │${DA_RST}\n" "$fillrow"
|
||||
printf "${DA_ST}│ ${DA_HL}│ │${DA_SR} ${DA_HL}│${DA_SR}%s${DA_HL}│${DA_SR} │ │ ${DA_HL}│ │${DA_SR} │${DA_RST}\n" "$fillrow"
|
||||
printf "${DA_ST}│ ${DA_HL}│ │${DA_SR} ${DA_HL}│${DA_SR}%s${DA_HL}│${DA_SR} │ ${DA_DIM}(-)${DA_SR} │ ${DA_HL}│ │${DA_SR} │${DA_RST}\n" "$fillrow"
|
||||
printf "${DA_ST}│ ${DA_HL}│ │${DA_SR} ${DA_HL}│${DA_SR}%s${DA_HL}│${DA_SR} │ │ ${DA_HL}│ │${DA_SR} │${DA_RST}\n" "$fillrow"
|
||||
printf "${DA_ST}│ ${DA_HL}│ │${DA_SR} ${DA_HL}│${DA_SR}%s${DA_HL}│${DA_SR} │ │ ${DA_HL}│ │${DA_SR} │${DA_RST}\n" "$fillrow"
|
||||
printf "${DA_ST}│ ${DA_HL}│ │${DA_SR} ${DA_HL}│${DA_SR}%s${DA_HL}│${DA_SR} │ │ ${DA_HL}│ │${DA_SR} │${DA_RST}\n" "$fillrow"
|
||||
printf "${DA_ST}│ ${DA_HL}│ │${DA_SR} ${DA_HL}%s${DA_SR} └──────┘ ${DA_HL}│ │${DA_SR} │${DA_RST}\n" "$BBAY"
|
||||
printf "${DA_ST}│ ${DA_HL}╰─╯${DA_SR} %s ${DA_HL}╰─╯${DA_SR} │${DA_RST}\n" "$GAP74"
|
||||
printf "${DA_ST}└──────────────────────────────────────────────────────────────────────────────────────┘${DA_RST}\n"
|
||||
|
||||
# ---- captions, aligned under the ten slots ------------------------------
|
||||
printf "${DA_ST} BAY %s${DA_ST} ${DA_RST}\n" "$numrow"
|
||||
printf "${DA_ST} DEV %s${DA_ST} ${DA_RST}\n" "$namerow"
|
||||
printf '\n'
|
||||
|
||||
# ---- off-panel drives + the one thing you must know ---------------------
|
||||
local off='' v
|
||||
[ -n "${DRIVE_MAP[m2-1]:-}" ] && off="M.2 ${DRIVE_MAP[m2-1]}"
|
||||
for i in 1 2 3 4 5 6 7 8; do
|
||||
v="${DRIVE_MAP[int-$i]:-}"
|
||||
[ -n "$v" ] || continue
|
||||
[ -n "$off" ] && off+=" "
|
||||
off+="internal $v"
|
||||
done
|
||||
[ -n "$off" ] || off='none'
|
||||
printf -v off '%-66.66s' "$off"
|
||||
printf "${DA_ST} not on front face ${DA_CYN}%s${DA_RST}\n" "$off"
|
||||
printf -v tail '%-88.88s' ' No backplane and no per-bay LEDs: every bay is a hand-cabled SFF-8482 to SATA lead.'
|
||||
printf "${DA_DIM}%s${DA_RST}\n" "$tail"
|
||||
printf -v tail '%-88.88s' ' Bay numbers are a LOCAL left-to-right convention - identify a drive by SERIAL.'
|
||||
printf "${DA_DIM}%s${DA_RST}\n" "$tail"
|
||||
|
||||
if declare -F get_storage_controllers >/dev/null 2>&1; then
|
||||
printf '\n'
|
||||
printf " ${DA_HL}STORAGE CONTROLLERS${DA_RST}\n"
|
||||
get_storage_controllers 2>/dev/null | sed 's/^/ /'
|
||||
fi
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user