Refactor SMART self-test checks

- Preserve TimedOut status
- Adds last self-test result to notes (if present and result is unknown)
This commit is contained in:
2Shirt 2023-05-21 14:52:28 -07:00
parent 96136e8e46
commit 59d89575ed
Signed by: 2Shirt
GPG key ID: 152FAC923B0E132C
2 changed files with 38 additions and 3 deletions

View file

@ -118,7 +118,13 @@ class State():
for dev in self.disks:
disk_smart_status_check(dev, mid_run=True)
for test in dev.tests:
if test.failed and 'Attributes' not in test.name:
if test.failed:
# Skip acceptable failure states
if 'Attributes' in test.name:
continue
if 'Self-Test' in test.name and 'TimedOut' in test.status:
continue
# Disable remaining tests
dev.disable_disk_tests()
break

View file

@ -231,6 +231,28 @@ def get_smart_self_test_details(dev) -> dict[Any, Any]:
return details
def get_smart_self_test_last_result(dev) -> str:
"""Get last SMART self-test result, returns str."""
result = 'Unknown'
# Parse SMART data
data = dev.raw_smartctl.get('ata_smart_self_test_log', {}).get('standard', {}).get('table', [])
if not data:
# No results found
return result
# Build result string
result = (
f'Power-on hours: {data.get("lifetime_hours", "?")}'
f', Type: {data.get("type", {}).get("string", "?")}'
f', Passed: {data.get("status", {}).get("passed", "?")}'
f', Result: {data.get("status", {}).get("string", "?")}'
)
# Done
return result
def monitor_smart_self_test(test_obj, header_str, log_path) -> bool:
"""Monitor SMART self-test status and update test_obj, returns bool."""
started = False
@ -262,6 +284,10 @@ def monitor_smart_self_test(test_obj, header_str, log_path) -> bool:
if _i * 5 >= SMART_SELF_TEST_START_TIMEOUT_IN_SECONDS:
# Test didn't start within limit, stop waiting
abort_self_test(test_obj.dev)
result = get_smart_self_test_last_result(test_obj.dev)
if result == 'Unknown':
result = 'SMART self-test failed to start'
test_obj.dev.add_note(result)
test_obj.failed = True
test_obj.set_status('TimedOut')
break
@ -290,7 +316,7 @@ def run_self_test(test_obj, log_path) -> None:
run_smart_self_test(test_obj, log_path)
def run_smart_self_test(test_obj, log_path) -> bool:
def run_smart_self_test(test_obj, log_path) -> None:
"""Run SMART self-test and check if it passed, returns bool.
NOTE: An exception will be raised if the disk lacks SMART support.
@ -352,7 +378,10 @@ def run_smart_self_test(test_obj, log_path) -> bool:
test_obj.failed = test_obj.failed or not test_obj.passed
# Set status
if test_obj.failed and test_obj.status != 'TimedOut':
if test_obj.status == 'TimedOut':
# Preserve TimedOut status
pass
elif test_obj.failed:
test_obj.set_status('Failed')
elif test_obj.passed:
test_obj.set_status('Passed')