Parse sg_ses --page=0x02 output to surface enclosure-level health data including power supply status, fan RPMs, temperature sensors, and voltage rails. Failed/critical components are reflected in the overview totals and shown as status pills in the enclosure card header with an expandable detail panel.
150 lines
3.5 KiB
Python
150 lines
3.5 KiB
Python
from pydantic import BaseModel
|
|
|
|
|
|
class Enclosure(BaseModel):
|
|
id: str
|
|
sg_device: str | None = None
|
|
vendor: str
|
|
model: str
|
|
revision: str
|
|
total_slots: int
|
|
populated_slots: int
|
|
|
|
|
|
class SlotInfo(BaseModel):
|
|
slot: int
|
|
populated: bool
|
|
device: str | None = None
|
|
|
|
|
|
class DriveDetail(BaseModel):
|
|
device: str
|
|
model: str | None = None
|
|
serial: str | None = None
|
|
wwn: str | None = None
|
|
firmware: str | None = None
|
|
capacity_bytes: int | None = None
|
|
smart_healthy: bool | None = None
|
|
smart_supported: bool = True
|
|
temperature_c: int | None = None
|
|
power_on_hours: int | None = None
|
|
reallocated_sectors: int | None = None
|
|
pending_sectors: int | None = None
|
|
uncorrectable_errors: int | None = None
|
|
wear_leveling_percent: int | None = None
|
|
zfs_pool: str | None = None
|
|
zfs_vdev: str | None = None
|
|
zfs_state: str | None = None
|
|
smart_attributes: list[dict] = []
|
|
|
|
|
|
class DriveHealthSummary(BaseModel):
|
|
device: str
|
|
model: str | None = None
|
|
serial: str | None = None
|
|
wwn: str | None = None
|
|
firmware: str | None = None
|
|
capacity_bytes: int | None = None
|
|
smart_healthy: bool | None = None
|
|
smart_supported: bool = True
|
|
temperature_c: int | None = None
|
|
power_on_hours: int | None = None
|
|
reallocated_sectors: int | None = None
|
|
pending_sectors: int | None = None
|
|
uncorrectable_errors: int | None = None
|
|
zfs_pool: str | None = None
|
|
zfs_vdev: str | None = None
|
|
zfs_state: str | None = None
|
|
health_status: str = "healthy"
|
|
|
|
|
|
class SlotWithDrive(BaseModel):
|
|
slot: int
|
|
populated: bool
|
|
device: str | None = None
|
|
drive: DriveHealthSummary | None = None
|
|
|
|
|
|
class PsuStatus(BaseModel):
|
|
index: int
|
|
status: str
|
|
fail: bool = False
|
|
ac_fail: bool = False
|
|
dc_fail: bool = False
|
|
|
|
|
|
class FanStatus(BaseModel):
|
|
index: int
|
|
status: str
|
|
rpm: int | None = None
|
|
fail: bool = False
|
|
|
|
|
|
class TempSensor(BaseModel):
|
|
index: int
|
|
status: str
|
|
temperature_c: float | None = None
|
|
|
|
|
|
class VoltageSensor(BaseModel):
|
|
index: int
|
|
status: str
|
|
voltage: float | None = None
|
|
|
|
|
|
class EnclosureHealth(BaseModel):
|
|
overall_status: str = "OK"
|
|
psus: list[PsuStatus] = []
|
|
fans: list[FanStatus] = []
|
|
temps: list[TempSensor] = []
|
|
voltages: list[VoltageSensor] = []
|
|
|
|
|
|
class EnclosureWithDrives(BaseModel):
|
|
id: str
|
|
sg_device: str | None = None
|
|
vendor: str
|
|
model: str
|
|
revision: str
|
|
total_slots: int
|
|
populated_slots: int
|
|
slots: list[SlotWithDrive]
|
|
health: EnclosureHealth | None = None
|
|
|
|
|
|
class HostDrive(BaseModel):
|
|
device: str
|
|
drive_type: str = "disk"
|
|
model: str | None = None
|
|
serial: str | None = None
|
|
wwn: str | None = None
|
|
firmware: str | None = None
|
|
capacity_bytes: int | None = None
|
|
smart_healthy: bool | None = None
|
|
smart_supported: bool = True
|
|
temperature_c: int | None = None
|
|
power_on_hours: int | None = None
|
|
reallocated_sectors: int | None = None
|
|
pending_sectors: int | None = None
|
|
uncorrectable_errors: int | None = None
|
|
zfs_pool: str | None = None
|
|
zfs_vdev: str | None = None
|
|
zfs_state: str | None = None
|
|
health_status: str = "healthy"
|
|
megaraid_id: str | None = None
|
|
physical_drives: list["HostDrive"] = []
|
|
|
|
|
|
class Overview(BaseModel):
|
|
healthy: bool
|
|
drive_count: int
|
|
warning_count: int
|
|
error_count: int
|
|
enclosures: list[EnclosureWithDrives]
|
|
host_drives: list[HostDrive] = []
|
|
|
|
|
|
class HealthCheck(BaseModel):
|
|
status: str
|
|
tools: dict[str, bool]
|