NVMe/SMART sections working
* Added timout status for clarity * Added short-test result to report
This commit is contained in:
parent
cee8252455
commit
99984603ed
1 changed files with 99 additions and 24 deletions
|
|
@ -169,6 +169,8 @@ class DiskObj():
|
||||||
self.disk_ok = True
|
self.disk_ok = True
|
||||||
if 'NVMe / SMART' in self.tests:
|
if 'NVMe / SMART' in self.tests:
|
||||||
self.tests['NVMe / SMART'].update_status('OVERRIDE')
|
self.tests['NVMe / SMART'].update_status('OVERRIDE')
|
||||||
|
if self.nvme_attributes or not self.smart_attributes:
|
||||||
|
# i.e. only leave enabled for SMART short-tests
|
||||||
self.tests['NVMe / SMART'].disabled = True
|
self.tests['NVMe / SMART'].disabled = True
|
||||||
|
|
||||||
def generate_report(self, brief=False, short_test=False):
|
def generate_report(self, brief=False, short_test=False):
|
||||||
|
|
@ -323,6 +325,7 @@ class DiskObj():
|
||||||
'name': _name, 'raw': _raw, 'raw_str': _raw_str}
|
'name': _name, 'raw': _raw, 'raw_str': _raw_str}
|
||||||
|
|
||||||
# Self-test data
|
# Self-test data
|
||||||
|
self.smart_self_test = {}
|
||||||
for k in ['polling_minutes', 'status']:
|
for k in ['polling_minutes', 'status']:
|
||||||
self.smart_self_test[k] = self.smartctl.get(
|
self.smart_self_test[k] = self.smartctl.get(
|
||||||
'ata_smart_data', {}).get(
|
'ata_smart_data', {}).get(
|
||||||
|
|
@ -333,6 +336,22 @@ class DiskObj():
|
||||||
"""Run safety checks and disable tests if necessary."""
|
"""Run safety checks and disable tests if necessary."""
|
||||||
if self.nvme_attributes or self.smart_attributes:
|
if self.nvme_attributes or self.smart_attributes:
|
||||||
self.check_attributes(silent)
|
self.check_attributes(silent)
|
||||||
|
|
||||||
|
# Check if a self-test is currently running
|
||||||
|
if 'remaining_percent' in self.smart_self_test['status']:
|
||||||
|
_msg='SMART self-test in progress, all tests disabled'
|
||||||
|
if not silent:
|
||||||
|
print_warning('WARNING: {}'.format(_msg))
|
||||||
|
print_standard(' ')
|
||||||
|
if ask('Abort HW Diagnostics?'):
|
||||||
|
exit_script()
|
||||||
|
if 'NVMe / SMART' in self.tests:
|
||||||
|
self.tests['NVMe / SMART'].report = self.generate_report()
|
||||||
|
self.tests['NVMe / SMART'].report.append(
|
||||||
|
'{YELLOW}WARNING: {msg}{CLEAR}'.format(msg=_msg, **COLORS))
|
||||||
|
for t in self.tests.values():
|
||||||
|
t.update_status('Denied')
|
||||||
|
t.disabled = True
|
||||||
else:
|
else:
|
||||||
# No NVMe/SMART details
|
# No NVMe/SMART details
|
||||||
if 'NVMe / SMART' in self.tests:
|
if 'NVMe / SMART' in self.tests:
|
||||||
|
|
@ -350,6 +369,8 @@ class DiskObj():
|
||||||
if not self.disk_ok:
|
if not self.disk_ok:
|
||||||
if 'NVMe / SMART' in self.tests:
|
if 'NVMe / SMART' in self.tests:
|
||||||
# NOTE: This will not overwrite the existing status if set
|
# NOTE: This will not overwrite the existing status if set
|
||||||
|
if not self.tests['NVMe / SMART'].report:
|
||||||
|
self.tests['NVMe / SMART'].report = self.generate_report()
|
||||||
self.tests['NVMe / SMART'].update_status('NS')
|
self.tests['NVMe / SMART'].update_status('NS')
|
||||||
self.tests['NVMe / SMART'].disabled = True
|
self.tests['NVMe / SMART'].disabled = True
|
||||||
for t in ['badblocks', 'I/O Benchmark']:
|
for t in ['badblocks', 'I/O Benchmark']:
|
||||||
|
|
@ -446,7 +467,7 @@ class TestObj():
|
||||||
|
|
||||||
def update_status(self, new_status=None):
|
def update_status(self, new_status=None):
|
||||||
"""Update status strings."""
|
"""Update status strings."""
|
||||||
if self.disabled:
|
if self.disabled or 'OVERRIDE' in self.status:
|
||||||
return
|
return
|
||||||
if new_status:
|
if new_status:
|
||||||
self.status = build_status_string(
|
self.status = build_status_string(
|
||||||
|
|
@ -1023,11 +1044,19 @@ def run_network_test():
|
||||||
|
|
||||||
def run_nvme_smart_tests(state, test):
|
def run_nvme_smart_tests(state, test):
|
||||||
"""Run NVMe or SMART test for test.dev."""
|
"""Run NVMe or SMART test for test.dev."""
|
||||||
|
# Bail early
|
||||||
|
if test.disabled:
|
||||||
|
return
|
||||||
_include_short_test = False
|
_include_short_test = False
|
||||||
|
test.started = True
|
||||||
|
test.update_status()
|
||||||
tmux_update_pane(
|
tmux_update_pane(
|
||||||
state.panes['Top'],
|
state.panes['Top'],
|
||||||
text='{t}\nDisk Health: {size:>6} ({tran}) {model} {serial}'.format(
|
text='{t}\nDisk Health: {size:>6} ({tran}) {model} {serial}'.format(
|
||||||
t=TOP_PANE_TEXT, **test.dev.lsblk))
|
t=TOP_PANE_TEXT, **test.dev.lsblk))
|
||||||
|
update_progress_pane(state)
|
||||||
|
|
||||||
|
# NVMe
|
||||||
if test.dev.nvme_attributes:
|
if test.dev.nvme_attributes:
|
||||||
# NOTE: Pass/Fail is just the attribute check
|
# NOTE: Pass/Fail is just the attribute check
|
||||||
if test.dev.disk_ok:
|
if test.dev.disk_ok:
|
||||||
|
|
@ -1037,37 +1066,80 @@ def run_nvme_smart_tests(state, test):
|
||||||
# NOTE: Other test(s) should've been disabled by DiskObj.safety_check()
|
# NOTE: Other test(s) should've been disabled by DiskObj.safety_check()
|
||||||
test.failed = True
|
test.failed = True
|
||||||
test.update_status('NS')
|
test.update_status('NS')
|
||||||
|
|
||||||
|
# SMART
|
||||||
elif test.dev.smart_attributes:
|
elif test.dev.smart_attributes:
|
||||||
# NOTE: Pass/Fail based on both attributes and SMART short self-test
|
# NOTE: Pass/Fail based on both attributes and SMART short self-test
|
||||||
if test.dev.disk_ok:
|
if not (test.dev.disk_ok or 'OVERRIDE' in test.status):
|
||||||
# Run short test
|
test.failed = True
|
||||||
# TODO
|
test.update_status('NS')
|
||||||
|
else:
|
||||||
|
# Prep
|
||||||
|
test.timeout = test.dev.smart_self_test['polling_minutes'].get(
|
||||||
|
'short', 5)
|
||||||
|
# TODO: fix timeout, set to polling + 5
|
||||||
|
test.timeout = int(test.timeout) + 1
|
||||||
_include_short_test = True
|
_include_short_test = True
|
||||||
_timeout = test.dev.smart_self_test['polling_minutes'].get('short', 5)
|
_self_test_started = False
|
||||||
_timeout = int(_timeout) + 5
|
|
||||||
|
|
||||||
# Check result
|
# Create monitor pane
|
||||||
# TODO
|
test.smart_out = '{}/smart.out'.format(global_vars['TmpDir'])
|
||||||
# if 'remaining_percent' in 'status' then we've started.
|
with open(test.smart_out, 'w') as f:
|
||||||
short_test_passed = True
|
f.write('SMART self-test status:\n Pending')
|
||||||
if short_test_passed:
|
state.panes['smart'] = tmux_split_window(
|
||||||
|
lines=3, vertical=True, watch=test.smart_out)
|
||||||
|
|
||||||
|
# Show attributes
|
||||||
|
clear_screen()
|
||||||
|
for line in test.dev.generate_report():
|
||||||
|
# Not saving to log; that will happen after all tests have been run
|
||||||
|
print(line)
|
||||||
|
print(' ')
|
||||||
|
|
||||||
|
# Start short test
|
||||||
|
print_standard('Running self-test...')
|
||||||
|
cmd = ['sudo', 'smartctl', '--test=short', test.dev.path]
|
||||||
|
run_program(cmd, check=False)
|
||||||
|
|
||||||
|
# Monitor progress (in 5 second increments)
|
||||||
|
for iteration in range(int(test.timeout*60/5)):
|
||||||
|
sleep(5)
|
||||||
|
|
||||||
|
# Update SMART data
|
||||||
|
test.dev.get_smart_details()
|
||||||
|
|
||||||
|
if _self_test_started:
|
||||||
|
# Update progress file
|
||||||
|
with open(test.smart_out, 'w') as f:
|
||||||
|
f.write('SMART self-test status:\n {}'.format(
|
||||||
|
test.dev.smart_self_test['status'].get('string', 'UNKNOWN')))
|
||||||
|
|
||||||
|
# Check if test has finished
|
||||||
|
if 'remaining_percent' not in test.dev.smart_self_test['status']:
|
||||||
|
break
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Check if test has started
|
||||||
|
if 'remaining_percent' in test.dev.smart_self_test['status']:
|
||||||
|
_self_test_started = True
|
||||||
|
|
||||||
|
# Check if timed out
|
||||||
|
if test.dev.smart_self_test['status'].get('passed', False):
|
||||||
|
if 'OVERRIDE' not in test.status:
|
||||||
test.passed = True
|
test.passed = True
|
||||||
test.update_status('CS')
|
test.update_status('CS')
|
||||||
else:
|
else:
|
||||||
|
test.failed = True
|
||||||
|
test.update_status('NS')
|
||||||
|
if not (test.failed or test.passed):
|
||||||
|
test.update_status('TimedOut')
|
||||||
|
|
||||||
|
# Disable other drive tests if necessary
|
||||||
|
if not test.passed:
|
||||||
for t in ['badblocks', 'I/O Benchmark']:
|
for t in ['badblocks', 'I/O Benchmark']:
|
||||||
if t in test.dev.tests:
|
if t in test.dev.tests:
|
||||||
test.dev.tests[t].update_status('Denied')
|
test.dev.tests[t].update_status('Denied')
|
||||||
test.dev.tests[t].disabled = True
|
test.dev.tests[t].disabled = True
|
||||||
# TODO
|
|
||||||
if no_logs:
|
|
||||||
test.update_status('Unknown')
|
|
||||||
else:
|
|
||||||
test.failed = True
|
|
||||||
test.update_status('NS')
|
|
||||||
|
|
||||||
else:
|
|
||||||
test.failed = True
|
|
||||||
test.update_status('NS')
|
|
||||||
|
|
||||||
# Save report
|
# Save report
|
||||||
test.report = test.dev.generate_report(
|
test.report = test.dev.generate_report(
|
||||||
|
|
@ -1076,6 +1148,9 @@ def run_nvme_smart_tests(state, test):
|
||||||
# Done
|
# Done
|
||||||
update_progress_pane(state)
|
update_progress_pane(state)
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
tmux_kill_pane(state.panes['smart'])
|
||||||
|
|
||||||
def secret_screensaver(screensaver=None):
|
def secret_screensaver(screensaver=None):
|
||||||
"""Show screensaver."""
|
"""Show screensaver."""
|
||||||
if screensaver == 'matrix':
|
if screensaver == 'matrix':
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue