Update HW diags and ddrescue to use new HW classes
This commit is contained in:
parent
56e145942a
commit
8582046948
2 changed files with 52 additions and 46 deletions
|
|
@ -27,7 +27,10 @@ from wk.cfg.ddrescue import (
|
||||||
DDRESCUE_SETTINGS,
|
DDRESCUE_SETTINGS,
|
||||||
DDRESCUE_SPECIFIC_PASS_SETTINGS,
|
DDRESCUE_SPECIFIC_PASS_SETTINGS,
|
||||||
)
|
)
|
||||||
from wk.hw import obj as hw_obj
|
from wk.hw import disk as hw_disk
|
||||||
|
from wk.hw import sensors as hw_sensors
|
||||||
|
from wk.hw import system as hw_system
|
||||||
|
from wk.hw.test import Test
|
||||||
|
|
||||||
|
|
||||||
# STATIC VARIABLES
|
# STATIC VARIABLES
|
||||||
|
|
@ -272,7 +275,7 @@ class BlockPair():
|
||||||
"""Run safety check and abort if necessary."""
|
"""Run safety check and abort if necessary."""
|
||||||
dest_size = -1
|
dest_size = -1
|
||||||
if self.destination.exists():
|
if self.destination.exists():
|
||||||
dest_obj = hw_obj.Disk(self.destination)
|
dest_obj = hw_disk.Disk(self.destination)
|
||||||
dest_size = dest_obj.details['size']
|
dest_size = dest_obj.details['size']
|
||||||
del dest_obj
|
del dest_obj
|
||||||
|
|
||||||
|
|
@ -488,7 +491,7 @@ class State():
|
||||||
if settings['Partition Mapping']:
|
if settings['Partition Mapping']:
|
||||||
# Resume previous run, load pairs from settings file
|
# Resume previous run, load pairs from settings file
|
||||||
for part_map in settings['Partition Mapping']:
|
for part_map in settings['Partition Mapping']:
|
||||||
bp_source = hw_obj.Disk(
|
bp_source = hw_disk.Disk(
|
||||||
f'{self.source.path}{source_sep}{part_map[0]}',
|
f'{self.source.path}{source_sep}{part_map[0]}',
|
||||||
)
|
)
|
||||||
bp_dest = pathlib.Path(
|
bp_dest = pathlib.Path(
|
||||||
|
|
@ -948,7 +951,7 @@ class State():
|
||||||
"""Run safety checks for destination and abort if necessary."""
|
"""Run safety checks for destination and abort if necessary."""
|
||||||
try:
|
try:
|
||||||
self.destination.safety_checks()
|
self.destination.safety_checks()
|
||||||
except hw_obj.CriticalHardwareError as err:
|
except hw_disk.CriticalHardwareError as err:
|
||||||
std.print_error(
|
std.print_error(
|
||||||
f'Critical error(s) detected for: {self.destination.path}',
|
f'Critical error(s) detected for: {self.destination.path}',
|
||||||
)
|
)
|
||||||
|
|
@ -1097,7 +1100,7 @@ class State():
|
||||||
string = ''
|
string = ''
|
||||||
|
|
||||||
# Build base string
|
# Build base string
|
||||||
if isinstance(obj, hw_obj.Disk):
|
if isinstance(obj, hw_disk.Disk):
|
||||||
string = f'{obj.path} {obj.description}'
|
string = f'{obj.path} {obj.description}'
|
||||||
elif obj.is_dir():
|
elif obj.is_dir():
|
||||||
string = f'{obj}/'
|
string = f'{obj}/'
|
||||||
|
|
@ -1122,7 +1125,7 @@ class State():
|
||||||
if self.source:
|
if self.source:
|
||||||
source_exists = self.source.path.exists()
|
source_exists = self.source.path.exists()
|
||||||
if self.destination:
|
if self.destination:
|
||||||
if isinstance(self.destination, hw_obj.Disk):
|
if isinstance(self.destination, hw_disk.Disk):
|
||||||
dest_exists = self.destination.path.exists()
|
dest_exists = self.destination.path.exists()
|
||||||
else:
|
else:
|
||||||
dest_exists = self.destination.exists()
|
dest_exists = self.destination.exists()
|
||||||
|
|
@ -1485,18 +1488,18 @@ def check_destination_health(destination):
|
||||||
result = ''
|
result = ''
|
||||||
|
|
||||||
# Bail early
|
# Bail early
|
||||||
if not isinstance(destination, hw_obj.Disk):
|
if not isinstance(destination, hw_disk.Disk):
|
||||||
# Return empty string
|
# Return empty string
|
||||||
return result
|
return result
|
||||||
|
|
||||||
# Run safety checks
|
# Run safety checks
|
||||||
try:
|
try:
|
||||||
destination.safety_checks()
|
destination.safety_checks()
|
||||||
except hw_obj.CriticalHardwareError:
|
except hw_disk.CriticalHardwareError:
|
||||||
result = 'Critical hardware error detected on destination'
|
result = 'Critical hardware error detected on destination'
|
||||||
except hw_obj.SMARTSelfTestInProgressError:
|
except hw_disk.SMARTSelfTestInProgressError:
|
||||||
result = 'SMART self-test in progress on destination'
|
result = 'SMART self-test in progress on destination'
|
||||||
except hw_obj.SMARTNotSupportedError:
|
except hw_disk.SMARTNotSupportedError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Done
|
# Done
|
||||||
|
|
@ -1668,20 +1671,20 @@ def get_object(path):
|
||||||
# Check path
|
# Check path
|
||||||
path = pathlib.Path(path).resolve()
|
path = pathlib.Path(path).resolve()
|
||||||
if path.is_block_device() or path.is_char_device():
|
if path.is_block_device() or path.is_char_device():
|
||||||
obj = hw_obj.Disk(path)
|
obj = hw_disk.Disk(path)
|
||||||
|
|
||||||
# Child/Parent check
|
# Child/Parent check
|
||||||
parent = obj.details['parent']
|
parent = obj.details['parent']
|
||||||
if parent:
|
if parent:
|
||||||
std.print_warning(f'"{obj.path}" is a child device')
|
std.print_warning(f'"{obj.path}" is a child device')
|
||||||
if std.ask(f'Use parent device "{parent}" instead?'):
|
if std.ask(f'Use parent device "{parent}" instead?'):
|
||||||
obj = hw_obj.Disk(parent)
|
obj = hw_disk.Disk(parent)
|
||||||
elif path.is_dir():
|
elif path.is_dir():
|
||||||
obj = path
|
obj = path
|
||||||
elif path.is_file():
|
elif path.is_file():
|
||||||
# Assuming file is a raw image, mounting
|
# Assuming file is a raw image, mounting
|
||||||
loop_path = mount_raw_image(path)
|
loop_path = mount_raw_image(path)
|
||||||
obj = hw_obj.Disk(loop_path)
|
obj = hw_disk.Disk(loop_path)
|
||||||
|
|
||||||
# Abort if obj not set
|
# Abort if obj not set
|
||||||
if not obj:
|
if not obj:
|
||||||
|
|
@ -1830,8 +1833,8 @@ def source_or_destination_changed(state):
|
||||||
elif hasattr(obj, 'exists'):
|
elif hasattr(obj, 'exists'):
|
||||||
# Assuming dest path
|
# Assuming dest path
|
||||||
changed = changed or not obj.exists()
|
changed = changed or not obj.exists()
|
||||||
elif isinstance(obj, hw_obj.Disk):
|
elif isinstance(obj, hw_disk.Disk):
|
||||||
compare_dev = hw_obj.Disk(obj.path)
|
compare_dev = hw_disk.Disk(obj.path)
|
||||||
for key in ('model', 'serial'):
|
for key in ('model', 'serial'):
|
||||||
changed = changed or obj.details[key] != compare_dev.details[key]
|
changed = changed or obj.details[key] != compare_dev.details[key]
|
||||||
|
|
||||||
|
|
@ -2217,7 +2220,7 @@ def run_recovery(state, main_menu, settings_menu, dry_run=True):
|
||||||
def select_disk(prompt, skip_disk=None):
|
def select_disk(prompt, skip_disk=None):
|
||||||
"""Select disk from list, returns Disk()."""
|
"""Select disk from list, returns Disk()."""
|
||||||
std.print_info('Scanning disks...')
|
std.print_info('Scanning disks...')
|
||||||
disks = hw_obj.get_disks()
|
disks = hw_disk.get_disks()
|
||||||
menu = std.Menu(
|
menu = std.Menu(
|
||||||
title=std.color_string(f'ddrescue TUI: {prompt} Selection', 'GREEN'),
|
title=std.color_string(f'ddrescue TUI: {prompt} Selection', 'GREEN'),
|
||||||
)
|
)
|
||||||
|
|
@ -2327,10 +2330,10 @@ def select_disk_parts(prompt, disk):
|
||||||
# Replace part list with whole disk obj
|
# Replace part list with whole disk obj
|
||||||
object_list = [disk.path]
|
object_list = [disk.path]
|
||||||
|
|
||||||
# Convert object_list to hw_obj.Disk() objects
|
# Convert object_list to hw_disk.Disk() objects
|
||||||
print(' ')
|
print(' ')
|
||||||
std.print_info('Getting disk/partition details...')
|
std.print_info('Getting disk/partition details...')
|
||||||
object_list = [hw_obj.Disk(path) for path in object_list]
|
object_list = [hw_disk.Disk(path) for path in object_list]
|
||||||
|
|
||||||
# Done
|
# Done
|
||||||
return object_list
|
return object_list
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,10 @@ from docopt import docopt
|
||||||
|
|
||||||
from wk import cfg, debug, exe, graph, log, net, std, tmux
|
from wk import cfg, debug, exe, graph, log, net, std, tmux
|
||||||
from wk import os as wk_os
|
from wk import os as wk_os
|
||||||
from wk.hw import obj as hw_obj
|
from wk.hw import disk as hw_disk
|
||||||
from wk.hw import sensors as hw_sensors
|
from wk.hw import sensors as hw_sensors
|
||||||
|
from wk.hw import system as hw_system
|
||||||
|
from wk.hw.test import Test
|
||||||
|
|
||||||
|
|
||||||
# STATIC VARIABLES
|
# STATIC VARIABLES
|
||||||
|
|
@ -100,11 +102,11 @@ class DeviceTooSmallError(RuntimeError):
|
||||||
class State():
|
class State():
|
||||||
"""Object for tracking hardware diagnostic data."""
|
"""Object for tracking hardware diagnostic data."""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.cpu = None
|
|
||||||
self.disks = []
|
self.disks = []
|
||||||
self.layout = cfg.hw.TMUX_LAYOUT.copy()
|
self.layout = cfg.hw.TMUX_LAYOUT.copy()
|
||||||
self.log_dir = None
|
self.log_dir = None
|
||||||
self.panes = {}
|
self.panes = {}
|
||||||
|
self.system = None
|
||||||
self.tests = OrderedDict({
|
self.tests = OrderedDict({
|
||||||
'CPU & Cooling': {
|
'CPU & Cooling': {
|
||||||
'Enabled': False,
|
'Enabled': False,
|
||||||
|
|
@ -165,12 +167,12 @@ class State():
|
||||||
disable_tests = False
|
disable_tests = False
|
||||||
|
|
||||||
# Skip already disabled devices
|
# Skip already disabled devices
|
||||||
if all(test.disabled for test in disk.tests.values()):
|
if all(test.disabled for test in disk.tests):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
disk.safety_checks()
|
disk.safety_checks()
|
||||||
except hw_obj.CriticalHardwareError:
|
except hw_disk.CriticalHardwareError:
|
||||||
disable_tests = True
|
disable_tests = True
|
||||||
disk.add_note('Critical hardware error detected.', 'RED')
|
disk.add_note('Critical hardware error detected.', 'RED')
|
||||||
if 'Disk Attributes' in disk.tests:
|
if 'Disk Attributes' in disk.tests:
|
||||||
|
|
@ -183,7 +185,7 @@ class State():
|
||||||
'Critical hardware error detected during diagnostics',
|
'Critical hardware error detected during diagnostics',
|
||||||
'YELLOW',
|
'YELLOW',
|
||||||
)
|
)
|
||||||
except hw_obj.SMARTSelfTestInProgressError as err:
|
except hw_disk.SMARTSelfTestInProgressError as err:
|
||||||
if prep:
|
if prep:
|
||||||
std.print_warning(f'SMART self-test(s) in progress for {disk.path}')
|
std.print_warning(f'SMART self-test(s) in progress for {disk.path}')
|
||||||
if std.ask('Continue with all tests disabled for this device?'):
|
if std.ask('Continue with all tests disabled for this device?'):
|
||||||
|
|
@ -293,8 +295,8 @@ class State():
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add HW Objects
|
# Add HW Objects
|
||||||
self.cpu = hw_obj.CpuRam()
|
self.system = hw_system.System()
|
||||||
self.disks = hw_obj.get_disks(skip_kits=True)
|
self.disks = hw_disk.get_disks(skip_kits=True)
|
||||||
|
|
||||||
# Add test objects
|
# Add test objects
|
||||||
for name, details in menu.options.items():
|
for name, details in menu.options.items():
|
||||||
|
|
@ -304,16 +306,17 @@ class State():
|
||||||
if 'CPU' in name:
|
if 'CPU' in name:
|
||||||
# Create two Test objects which will both be used by cpu_stress_tests
|
# Create two Test objects which will both be used by cpu_stress_tests
|
||||||
# NOTE: Prime95 should be added first
|
# NOTE: Prime95 should be added first
|
||||||
test_mprime_obj = hw_obj.Test(dev=self.cpu, label='Prime95')
|
self.system.tests.append(
|
||||||
test_cooling_obj = hw_obj.Test(dev=self.cpu, label='Cooling')
|
Test(dev=self.system, label='Prime95', name=name),
|
||||||
self.cpu.tests[test_mprime_obj.label] = test_mprime_obj
|
)
|
||||||
self.cpu.tests[test_cooling_obj.label] = test_cooling_obj
|
self.system.tests.append(
|
||||||
self.tests[name]['Objects'].append(test_mprime_obj)
|
Test(dev=self.system, label='Cooling', name=name),
|
||||||
self.tests[name]['Objects'].append(test_cooling_obj)
|
)
|
||||||
|
self.tests[name]['Objects'].extend(self.system.tests)
|
||||||
elif 'Disk' in name:
|
elif 'Disk' in name:
|
||||||
for disk in self.disks:
|
for disk in self.disks:
|
||||||
test_obj = hw_obj.Test(dev=disk, label=disk.path.name)
|
test_obj = Test(dev=disk, label=disk.path.name, name=name)
|
||||||
disk.tests[name] = test_obj
|
disk.test.append(test_obj)
|
||||||
self.tests[name]['Objects'].append(test_obj)
|
self.tests[name]['Objects'].append(test_obj)
|
||||||
|
|
||||||
# Run safety checks
|
# Run safety checks
|
||||||
|
|
@ -360,14 +363,6 @@ class State():
|
||||||
with open(f'{debug_dir}/state.report', 'a', encoding='utf-8') as _f:
|
with open(f'{debug_dir}/state.report', 'a', encoding='utf-8') as _f:
|
||||||
_f.write('\n'.join(debug.generate_object_report(self)))
|
_f.write('\n'.join(debug.generate_object_report(self)))
|
||||||
|
|
||||||
# CPU/RAM
|
|
||||||
with open(f'{debug_dir}/cpu.report', 'a', encoding='utf-8') as _f:
|
|
||||||
_f.write('\n'.join(debug.generate_object_report(self.cpu)))
|
|
||||||
_f.write('\n\n[Tests]')
|
|
||||||
for name, test in self.cpu.tests.items():
|
|
||||||
_f.write(f'\n{name}:\n')
|
|
||||||
_f.write('\n'.join(debug.generate_object_report(test, indent=1)))
|
|
||||||
|
|
||||||
# Disks
|
# Disks
|
||||||
for disk in self.disks:
|
for disk in self.disks:
|
||||||
with open(
|
with open(
|
||||||
|
|
@ -375,8 +370,8 @@ class State():
|
||||||
encoding='utf-8') as _f:
|
encoding='utf-8') as _f:
|
||||||
_f.write('\n'.join(debug.generate_object_report(disk)))
|
_f.write('\n'.join(debug.generate_object_report(disk)))
|
||||||
_f.write('\n\n[Tests]')
|
_f.write('\n\n[Tests]')
|
||||||
for name, test in disk.tests.items():
|
for test in disk.tests:
|
||||||
_f.write(f'\n{name}:\n')
|
_f.write(f'\n{test.name}:\n')
|
||||||
_f.write('\n'.join(debug.generate_object_report(test, indent=1)))
|
_f.write('\n'.join(debug.generate_object_report(test, indent=1)))
|
||||||
|
|
||||||
# SMC
|
# SMC
|
||||||
|
|
@ -394,6 +389,14 @@ class State():
|
||||||
with open(f'{debug_dir}/smc.data', 'a', encoding='utf-8') as _f:
|
with open(f'{debug_dir}/smc.data', 'a', encoding='utf-8') as _f:
|
||||||
_f.write('\n'.join(data))
|
_f.write('\n'.join(data))
|
||||||
|
|
||||||
|
# System
|
||||||
|
with open(f'{debug_dir}/system.report', 'a', encoding='utf-8') as _f:
|
||||||
|
_f.write('\n'.join(debug.generate_object_report(self.system)))
|
||||||
|
_f.write('\n\n[Tests]')
|
||||||
|
for test in self.system.tests:
|
||||||
|
_f.write(f'\n{test.name}:\n')
|
||||||
|
_f.write('\n'.join(debug.generate_object_report(test, indent=1)))
|
||||||
|
|
||||||
def update_clock(self):
|
def update_clock(self):
|
||||||
"""Update 'Started' pane following clock sync."""
|
"""Update 'Started' pane following clock sync."""
|
||||||
tmux.respawn_pane(
|
tmux.respawn_pane(
|
||||||
|
|
@ -725,7 +728,7 @@ def cpu_stress_tests(state, test_objects):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Prep
|
# Prep
|
||||||
state.update_top_pane(test_mprime_obj.dev.description)
|
state.update_top_pane(test_mprime_obj.dev.cpu_description)
|
||||||
test_cooling_obj.set_status('Working')
|
test_cooling_obj.set_status('Working')
|
||||||
test_mprime_obj.set_status('Working')
|
test_mprime_obj.set_status('Working')
|
||||||
|
|
||||||
|
|
@ -1008,7 +1011,7 @@ def disk_self_test(state, test_objects):
|
||||||
except TimeoutError:
|
except TimeoutError:
|
||||||
test_obj.failed = True
|
test_obj.failed = True
|
||||||
result = 'TimedOut'
|
result = 'TimedOut'
|
||||||
except hw_obj.SMARTNotSupportedError:
|
except hw_disk.SMARTNotSupportedError:
|
||||||
# Pass test since it doesn't apply
|
# Pass test since it doesn't apply
|
||||||
test_obj.passed = True
|
test_obj.passed = True
|
||||||
result = 'N/A'
|
result = 'N/A'
|
||||||
|
|
@ -1463,7 +1466,7 @@ def show_results(state):
|
||||||
if name.startswith('CPU')]
|
if name.startswith('CPU')]
|
||||||
if any(cpu_tests_enabled):
|
if any(cpu_tests_enabled):
|
||||||
std.print_success('CPU:')
|
std.print_success('CPU:')
|
||||||
std.print_report(state.cpu.generate_report())
|
std.print_report(state.system.generate_report())
|
||||||
std.print_standard(' ')
|
std.print_standard(' ')
|
||||||
|
|
||||||
# Disk Tests
|
# Disk Tests
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue