feat: add smart_serial() function to extract manufacturer serial numbers from SMART data with fallback chain and parallel execution
Add smart_serial() function with smartctl -i command execution, fallback to -d sat mode, and Serial Number: field regex extraction with WWN/0x prefix filtering to prefer physical serial over logical identifiers. Add serial_futures dict with service_check_executor.submit() calls for parallel serial reads alongside smart_futures/temperature_futures. Update raid_status() disk
This commit is contained in:
1 parent
02449a80de
commit
d4c24f02d4
1 file changed
+15
-1
@@ -365,6 +365,18 @@ def smart_status(device):
|
|||||||
health = re.search(r"(?:SMART overall-health self-assessment test result|SMART Health Status):\s*(.+)", smart_output, re.IGNORECASE)
|
health = re.search(r"(?:SMART overall-health self-assessment test result|SMART Health Status):\s*(.+)", smart_output, re.IGNORECASE)
|
||||||
return health.group(1).strip() if health else ("Fehler: " + smart_error.strip()[:80] if smart_error.strip() else "Nicht unterstützt")
|
return health.group(1).strip() if health else ("Fehler: " + smart_error.strip()[:80] if smart_error.strip() else "Nicht unterstützt")
|
||||||
|
|
||||||
|
def smart_serial(device):
|
||||||
|
"""Read the manufacturer serial, not a WWN or SCSI by-id alias."""
|
||||||
|
if not shutil.which("smartctl"):
|
||||||
|
return ""
|
||||||
|
smart_device = device.replace("/dev/", f"{HOST_DEVICE_PATH.rstrip('/')}/", 1)
|
||||||
|
for command in (["smartctl", "-i", "-d", "sat", smart_device], ["smartctl", "-i", smart_device]):
|
||||||
|
output, _ = _read_command(command, timeout=6, warn_on_nonzero=False)
|
||||||
|
match = re.search(r"^\s*Serial Number:\s*(\S+)\s*$", output, re.IGNORECASE | re.MULTILINE)
|
||||||
|
if match and not match.group(1).lower().startswith(("wwn-", "0x")):
|
||||||
|
return match.group(1).strip()
|
||||||
|
return ""
|
||||||
|
|
||||||
def smart_temperature(device):
|
def smart_temperature(device):
|
||||||
"""Read the drive temperature in a controller-friendly way."""
|
"""Read the drive temperature in a controller-friendly way."""
|
||||||
if not SMART_ENABLED or not shutil.which("smartctl"):
|
if not SMART_ENABLED or not shutil.which("smartctl"):
|
||||||
@@ -457,9 +469,11 @@ def raid_status():
|
|||||||
except (ValueError, AttributeError):
|
except (ValueError, AttributeError):
|
||||||
block_devices = {}
|
block_devices = {}
|
||||||
smart_futures = {}
|
smart_futures = {}
|
||||||
|
serial_futures = {}
|
||||||
temperature_futures = {}
|
temperature_futures = {}
|
||||||
if shutil.which("smartctl"):
|
if shutil.which("smartctl"):
|
||||||
smart_futures = {disk["device"]: service_check_executor.submit(smart_status, disk["device"]) for disk in devices}
|
smart_futures = {disk["device"]: service_check_executor.submit(smart_status, disk["device"]) for disk in devices}
|
||||||
|
serial_futures = {disk["device"]: service_check_executor.submit(smart_serial, disk["device"]) for disk in devices}
|
||||||
temperature_futures = {disk["device"]: service_check_executor.submit(smart_temperature, disk["device"]) for disk in devices}
|
temperature_futures = {disk["device"]: service_check_executor.submit(smart_temperature, disk["device"]) for disk in devices}
|
||||||
for disk in devices:
|
for disk in devices:
|
||||||
info = block_devices.get(disk["device"], {})
|
info = block_devices.get(disk["device"], {})
|
||||||
@@ -473,7 +487,7 @@ def raid_status():
|
|||||||
info = host_items[0] if host_items else {}
|
info = host_items[0] if host_items else {}
|
||||||
except (ValueError, AttributeError):
|
except (ValueError, AttributeError):
|
||||||
info = {}
|
info = {}
|
||||||
serial = info.get("serial") or _device_serial(disk["device"])
|
serial = (serial_futures[disk["device"]].result() if disk["device"] in serial_futures else "") or info.get("serial") or _device_serial(disk["device"])
|
||||||
disk.update({"size": format_bytes(info.get("size") or 0) if info.get("size") else "—", "model": info.get("model") or "—", "serial": serial or "—"})
|
disk.update({"size": format_bytes(info.get("size") or 0) if info.get("size") else "—", "model": info.get("model") or "—", "serial": serial or "—"})
|
||||||
serial_log_key = "serial:" + disk["device"]
|
serial_log_key = "serial:" + disk["device"]
|
||||||
if not serial and serial_log_key not in hardware_log_once:
|
if not serial and serial_log_key not in hardware_log_once:
|
||||||
|
|||||||
Reference in new issue
Block a user