From ce12f49a08e6bc2a4af6763d7aaf4d5aba161afd Mon Sep 17 00:00:00 2001 From: Eric Wheeler Date: Fri, 24 Mar 2023 19:02:49 -0700 Subject: [PATCH 1/2] Recurse block device stacking hierarchies Turn LEDs on or off depending on their existence at the bottom of block device stacks. This works with pretty much any hierarchy (RAID, LVM, DM, etc) because the kernel tracks block device stacking dependencies in /sys/block//slaves/* (which can be seen as a tree using the tool `lsblk`). For example: ] grep md9 /proc/mdstat md9 : active raid5 sdg[0] sde[6] sdj[4] sdk[3] sdf[2] sdl[1] ] encled md9 0:0:18:0/Slot11 sde fault_off locate_off 0:0:18:0/Slot08 sdf fault_off locate_off 0:0:18:0/Slot06 sdg fault_off locate_off 0:0:18:0/Slot10 sdj fault_off locate_off 0:0:18:0/Slot09 sdk fault_off locate_off 0:0:18:0/Slot07 sdl fault_off locate_off ] encled md9 locate ] encled md9 0:0:18:0/Slot11 sde fault_off LOCATE_ON 0:0:18:0/Slot08 sdf fault_off LOCATE_ON 0:0:18:0/Slot06 sdg fault_off LOCATE_ON 0:0:18:0/Slot10 sdj fault_off LOCATE_ON 0:0:18:0/Slot09 sdk fault_off LOCATE_ON 0:0:18:0/Slot07 sdl fault_off LOCATE_ON In the more complex stack shown below, /dev/bcache0 is backed by /dev/md125 and /dev/md126. Now encled can find the referenced devices at any point in the stack: ] encled md125 0:0:18:0/Slot03 sdh fault_off locate_off 0:0:18:0/Slot02 sdc fault_off locate_off ] encled md126 0:0:18:0/Slot01 sdb fault_off locate_off 0:0:18:0/Slot00 sdi fault_off locate_off ] encled bcache0 0:0:18:0/Slot03 sdh fault_off locate_off 0:0:18:0/Slot01 sdb fault_off locate_off 0:0:18:0/Slot02 sdc fault_off locate_off 0:0:18:0/Slot00 sdi fault_off locate_off Signed-off-by: Eric Wheeler --- encled | 77 ++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 59 insertions(+), 18 deletions(-) diff --git a/encled b/encled index 8046f69..3d726be 100755 --- a/encled +++ b/encled @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import os import sys +import re HELP = """ @@ -30,6 +31,12 @@ HELP = """ encled sda locate - enable 'locate' for slot with sda block device encled /dev/sdbz fault - enable fault indicator slot with sdbz block device + Recurse block device stacking hierarchies: + encled bcache0 locate - locate all disks used by /dev/bcache0 + encled md0 - list all disks that are RAID members of /dev/md0 + encled /dev/vg0/lv - list all disks that back the logical volume 'vg0/lv' + encled /dev/mapper/myluks - list all disks that back an encrypted volume + """ CLASS = '/sys/class/enclosure/' @@ -153,6 +160,38 @@ def list_all(): devlist.append((e, s, path, status)) return devlist +# Recursively find SCSI devices in block device stacking hierarchies +# by referencing /sys/block//slaves/* +def find_parent_devs(dev_names): + global depth + + new_names = [] + for dev_path in dev_names: + # Read symlinks, like from /dev/mapper/foo: + if os.path.islink(dev_path): + dev_path = os.readlink(dev_path) + + # Use basename, we only need the name not the path: + dev_name = os.path.basename(dev_path) + + # Strip partition numbers: + dev_name = re.sub('^(sd[a-z]+)\d*$', lambda x: x.group(1), dev_name) + + slave_path = '/sys/block/' + dev_name + '/slaves/' + if re.match('^sd[a-z]+$', dev_name): + new_names.append(dev_name) + elif os.path.exists(slave_path): + new_names += find_parent_devs(os.listdir(slave_path)) + + dev_names += new_names + + # Only return SCSI devices: + sd = [] + for dev in dev_names: + if re.match('^sd[a-z]+$', dev): + sd.append(dev) + + return set(sd) def main(argv): if len(argv) > 1 and argv[1] in ('--help', '-h', '-help', '/?', '?', 'help', '-v', '--version', '-V'): @@ -164,6 +203,7 @@ def main(argv): return(-1) devlist = list_all() + devs = [] if len(argv) < 2: if not devlist: print ("No enclosure devices found") @@ -190,29 +230,30 @@ def main(argv): if result: return(result) return(0) - if 'sd' in argv[1] or '/dev' in argv[1]: - name = argv[1].lower().split('/')[-1] - for d in devlist: - if(d[3][0] == name): - dev = d - break - else: - print(f"encled: Unable to find device {name} in enclosure slots. (note: on-board SATA ports are not supported)") - return(-1) - - elif '/' in argv[1]: + if re.match('^\d+:\d+:\d+:\d+/Slot\d+$', argv[1]): (enc, slot) = argv[1].split('/') path = find_name(enc, slot) dev = (enc, slot, path, get_status(path)) + devs.append(dev) + if not len(devs): + print ("encled: Incorrect enclosure/slot or device syntax") + print (HELP) + return(-1) else: - print ("encled: Incorrect enclosure/slot or device syntax") - print (HELP) - return(-1) + names = find_parent_devs([ argv[1] ]) + for d in devlist: + if(d[3][0] in names): + devs.append(d) + if not len(devs): + print(f"encled: Unable to find device {argv[1]} in enclosure slots. (note: on-board SATA ports are not supported)") + return(-1) - if len(argv) < 3: - print_status(dev[0], dev[1], dev[3]) - else: - set_status(dev[2], argv[2]) + + for dev in devs: + if len(argv) < 3: + print_status(dev[0], dev[1], dev[3]) + else: + set_status(dev[2], argv[2]) if __name__ == '__main__': From 3ceda225b6d7466125e91a4512b11d17e8033405 Mon Sep 17 00:00:00 2001 From: Eric Wheeler Date: Fri, 24 Mar 2023 19:11:15 -0700 Subject: [PATCH 2/2] Sort output listings by Enclosure and Slot Before: ENCLOSURE/SLOT DEV FAULT_LED LOCATION_LED ---------------------------------------------------- 0:0:18:0/Slot05 ---- fault_off locate_off 0:0:18:0/Slot23 ---- fault_off locate_off 0:0:18:0/Slot13 ---- fault_off locate_off 0:0:18:0/Slot03 sdh fault_off locate_off 0:0:18:0/Slot21 ---- fault_off locate_off 0:0:18:0/Slot11 sde fault_off locate_off 0:0:18:0/Slot01 sdb fault_off locate_off 0:0:18:0/Slot18 ---- fault_off locate_off 0:0:18:0/Slot08 sdf fault_off locate_off 0:0:18:0/Slot16 ---- fault_off locate_off 0:0:18:0/Slot06 sdg fault_off locate_off 0:0:18:0/Slot14 ---- fault_off locate_off 0:0:18:0/Slot04 ---- fault_off locate_off 0:0:18:0/Slot22 ---- fault_off locate_off 0:0:18:0/Slot12 ---- fault_off locate_off 0:0:18:0/Slot02 sdc fault_off locate_off 0:0:18:0/Slot20 ---- fault_off locate_off 0:0:18:0/Slot10 sdj fault_off locate_off 0:0:18:0/Slot00 sdi fault_off locate_off 0:0:18:0/Slot19 ---- fault_off locate_off 0:0:18:0/Slot09 sdk fault_off locate_off 0:0:18:0/Slot17 ---- fault_off locate_off 0:0:18:0/Slot07 sdl fault_off locate_off 0:0:18:0/Slot15 ---- fault_off locate_off After: ENCLOSURE/SLOT DEV FAULT_LED LOCATION_LED ---------------------------------------------------- 0:0:18:0/Slot00 sdi fault_off locate_off 0:0:18:0/Slot01 sdb fault_off locate_off 0:0:18:0/Slot02 sdc fault_off locate_off 0:0:18:0/Slot03 sdh fault_off locate_off 0:0:18:0/Slot04 ---- fault_off locate_off 0:0:18:0/Slot05 ---- fault_off locate_off 0:0:18:0/Slot06 sdg fault_off locate_off 0:0:18:0/Slot07 sdl fault_off locate_off 0:0:18:0/Slot08 sdf fault_off locate_off 0:0:18:0/Slot09 sdk fault_off locate_off 0:0:18:0/Slot10 sdj fault_off locate_off 0:0:18:0/Slot11 sde fault_off locate_off 0:0:18:0/Slot12 ---- fault_off locate_off 0:0:18:0/Slot13 ---- fault_off locate_off 0:0:18:0/Slot14 ---- fault_off locate_off 0:0:18:0/Slot15 ---- fault_off locate_off 0:0:18:0/Slot16 ---- fault_off locate_off 0:0:18:0/Slot17 ---- fault_off locate_off 0:0:18:0/Slot18 ---- fault_off locate_off 0:0:18:0/Slot19 ---- fault_off locate_off 0:0:18:0/Slot20 ---- fault_off locate_off 0:0:18:0/Slot21 ---- fault_off locate_off 0:0:18:0/Slot22 ---- fault_off locate_off 0:0:18:0/Slot23 ---- fault_off locate_off Signed-off-by: Eric Wheeler --- encled | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/encled b/encled index 3d726be..57d4dfe 100755 --- a/encled +++ b/encled @@ -210,7 +210,7 @@ def main(argv): return(-1) print ("ENCLOSURE/SLOT\tDEV\tFAULT_LED\tLOCATION_LED") print ("-"*52) - for d in devlist: + for d in sorted(devlist, key=lambda x: x[2]): print_status(d[0], d[1], d[3]) return(0) @@ -249,7 +249,7 @@ def main(argv): return(-1) - for dev in devs: + for dev in sorted(devs, key=lambda x: x[2]): if len(argv) < 3: print_status(dev[0], dev[1], dev[3]) else: