Track initial and current SMART attributes

Addresses issue #194
This commit is contained in:
2Shirt 2022-10-08 19:26:20 -07:00
parent 4465caa9fd
commit 7714b3436f
Signed by: 2Shirt
GPG key ID: 152FAC923B0E132C
2 changed files with 45 additions and 20 deletions

View file

@ -1,6 +1,7 @@
"""WizardKit: Disk object and functions""" """WizardKit: Disk object and functions"""
# vim: sts=2 sw=2 ts=2 # vim: sts=2 sw=2 ts=2
import copy
import logging import logging
import pathlib import pathlib
import platform import platform
@ -36,26 +37,27 @@ WK_LABEL_REGEX = re.compile(
class Disk: class Disk:
# pylint: disable=too-many-instance-attributes # pylint: disable=too-many-instance-attributes
"""Object for tracking disk specific data.""" """Object for tracking disk specific data."""
attributes: dict[Any, dict] = field(init=False, default_factory=dict) attributes: dict[Any, dict] = field(init=False, default_factory=dict)
bus: str = field(init=False) bus: str = field(init=False)
children: list[dict] = field(init=False, default_factory=list) children: list[dict] = field(init=False, default_factory=list)
description: str = field(init=False) description: str = field(init=False)
filesystem: str = field(init=False) filesystem: str = field(init=False)
known_attributes: dict[Any, dict] = field(init=False, default_factory=dict) initial_attributes: dict[Any, dict] = field(init=False)
log_sec: int = field(init=False) known_attributes: dict[Any, dict] = field(init=False, default_factory=dict)
model: str = field(init=False) log_sec: int = field(init=False)
name: str = field(init=False) model: str = field(init=False)
notes: list[str] = field(init=False, default_factory=list) name: str = field(init=False)
notes: list[str] = field(init=False, default_factory=list)
path: Union[pathlib.Path, str] path: Union[pathlib.Path, str]
parent: str = field(init=False) parent: str = field(init=False)
phy_sec: int = field(init=False) phy_sec: int = field(init=False)
raw_details: dict[str, Any] = field(init=False) raw_details: dict[str, Any] = field(init=False)
raw_smartctl: dict[str, Any] = field(init=False) raw_smartctl: dict[str, Any] = field(init=False)
serial: str = field(init=False) serial: str = field(init=False)
size: int = field(init=False) size: int = field(init=False)
ssd: bool = field(init=False) ssd: bool = field(init=False)
tests: list[Test] = field(init=False, default_factory=list) tests: list[Test] = field(init=False, default_factory=list)
use_sat: bool = field(init=False, default=False) use_sat: bool = field(init=False, default=False)
def __post_init__(self) -> None: def __post_init__(self) -> None:
self.path = pathlib.Path(self.path).resolve() self.path = pathlib.Path(self.path).resolve()
@ -71,6 +73,7 @@ class Disk:
self.use_sat = True self.use_sat = True
enable_smart(self) enable_smart(self)
update_smart_details(self) update_smart_details(self)
self.initial_attributes = copy.deepcopy(self.attributes)
if not self.is_4k_aligned(): if not self.is_4k_aligned():
self.add_note('One or more partitions are not 4K aligned', 'YELLOW') self.add_note('One or more partitions are not 4K aligned', 'YELLOW')

View file

@ -158,7 +158,7 @@ def generate_attribute_report(dev) -> list[str]:
# Build colored string and append to report # Build colored string and append to report
line = color_string( line = color_string(
[label, value['raw_str'], note], [label, get_attribute_value_string(dev, attr), note],
[None, value_color, 'YELLOW'], [None, value_color, 'YELLOW'],
) )
report.append(line) report.append(line)
@ -167,6 +167,28 @@ def generate_attribute_report(dev) -> list[str]:
return report 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: def get_known_disk_attributes(model) -> None:
"""Get known disk attributes based on the device model.""" """Get known disk attributes based on the device model."""
known_attributes = copy.deepcopy(KNOWN_DISK_ATTRIBUTES) known_attributes = copy.deepcopy(KNOWN_DISK_ATTRIBUTES)