From 7714b3436f9b6a5def2cfccc348b64debabf9059 Mon Sep 17 00:00:00 2001 From: 2Shirt <2xShirt@gmail.com> Date: Sat, 8 Oct 2022 19:26:20 -0700 Subject: [PATCH] Track initial and current SMART attributes Addresses issue #194 --- scripts/wk/hw/disk.py | 41 ++++++++++++++++++++++------------------- scripts/wk/hw/smart.py | 24 +++++++++++++++++++++++- 2 files changed, 45 insertions(+), 20 deletions(-) diff --git a/scripts/wk/hw/disk.py b/scripts/wk/hw/disk.py index c84fa69d..659a6bc1 100644 --- a/scripts/wk/hw/disk.py +++ b/scripts/wk/hw/disk.py @@ -1,6 +1,7 @@ """WizardKit: Disk object and functions""" # vim: sts=2 sw=2 ts=2 +import copy import logging import pathlib import platform @@ -36,26 +37,27 @@ WK_LABEL_REGEX = re.compile( class Disk: # pylint: disable=too-many-instance-attributes """Object for tracking disk specific data.""" - attributes: dict[Any, dict] = field(init=False, default_factory=dict) - bus: str = field(init=False) - children: list[dict] = field(init=False, default_factory=list) - description: str = field(init=False) - filesystem: str = field(init=False) - known_attributes: dict[Any, dict] = field(init=False, default_factory=dict) - log_sec: int = field(init=False) - model: str = field(init=False) - name: str = field(init=False) - notes: list[str] = field(init=False, default_factory=list) + attributes: dict[Any, dict] = field(init=False, default_factory=dict) + bus: str = field(init=False) + children: list[dict] = field(init=False, default_factory=list) + description: str = field(init=False) + filesystem: str = field(init=False) + initial_attributes: dict[Any, dict] = field(init=False) + known_attributes: dict[Any, dict] = field(init=False, default_factory=dict) + log_sec: int = field(init=False) + model: str = field(init=False) + name: str = field(init=False) + notes: list[str] = field(init=False, default_factory=list) path: Union[pathlib.Path, str] - parent: str = field(init=False) - phy_sec: int = field(init=False) - raw_details: dict[str, Any] = field(init=False) - raw_smartctl: dict[str, Any] = field(init=False) - serial: str = field(init=False) - size: int = field(init=False) - ssd: bool = field(init=False) - tests: list[Test] = field(init=False, default_factory=list) - use_sat: bool = field(init=False, default=False) + parent: str = field(init=False) + phy_sec: int = field(init=False) + raw_details: dict[str, Any] = field(init=False) + raw_smartctl: dict[str, Any] = field(init=False) + serial: str = field(init=False) + size: int = field(init=False) + ssd: bool = field(init=False) + tests: list[Test] = field(init=False, default_factory=list) + use_sat: bool = field(init=False, default=False) def __post_init__(self) -> None: self.path = pathlib.Path(self.path).resolve() @@ -71,6 +73,7 @@ class Disk: self.use_sat = True enable_smart(self) update_smart_details(self) + self.initial_attributes = copy.deepcopy(self.attributes) if not self.is_4k_aligned(): self.add_note('One or more partitions are not 4K aligned', 'YELLOW') diff --git a/scripts/wk/hw/smart.py b/scripts/wk/hw/smart.py index 248959f0..85afebe3 100644 --- a/scripts/wk/hw/smart.py +++ b/scripts/wk/hw/smart.py @@ -158,7 +158,7 @@ def generate_attribute_report(dev) -> list[str]: # Build colored string and append to report line = color_string( - [label, value['raw_str'], note], + [label, get_attribute_value_string(dev, attr), note], [None, value_color, 'YELLOW'], ) report.append(line) @@ -167,6 +167,28 @@ def generate_attribute_report(dev) -> list[str]: return report +def get_attribute_value_string(dev, attr) -> str: + """Get attribute value string and report if it has changed.""" + current_value = dev.attributes.get(attr, {}) + initial_value = dev.initial_attributes.get(attr, {}) + value_str = current_value.get('raw_str', '') + + # Compare current value against initial value + if ( + current_value.get('raw', None) is None + or initial_value.get('raw', None) is None + ): + return value_str + if current_value['raw'] != initial_value['raw']: + value_str = ( + f'{initial_value.get("raw_str", "?")} --> ' + f'{current_value.get("raw_str", "?")}' + ) + + # Done + return value_str + + def get_known_disk_attributes(model) -> None: """Get known disk attributes based on the device model.""" known_attributes = copy.deepcopy(KNOWN_DISK_ATTRIBUTES)