Added Disk().generate_report()
* Uses new merged ATTRIBUTES config
This commit is contained in:
parent
fbb480dae6
commit
c7090e77c2
3 changed files with 116 additions and 4 deletions
|
|
@ -1,5 +1,6 @@
|
|||
"""WizardKit: cfg module init"""
|
||||
|
||||
from wk.cfg import hw
|
||||
from wk.cfg import log
|
||||
from wk.cfg import main
|
||||
from wk.cfg import net
|
||||
|
|
|
|||
34
scripts/wk/cfg/hw.py
Normal file
34
scripts/wk/cfg/hw.py
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
"""WizardKit: Config - Hardware"""
|
||||
# pylint: disable=bad-whitespace,line-too-long
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
||||
|
||||
ATTRIBUTES = {
|
||||
# NVMe
|
||||
'critical_warning': {'Critical': True, 'Ignore': False, 'Warning': None, 'Error': 1, 'Maximum': None, },
|
||||
'media_errors': {'Critical': False, 'Ignore': False, 'Warning': None, 'Error': 1, 'Maximum': None, },
|
||||
'power_on_hours': {'Critical': False, 'Ignore': True, 'Warning': 17532, 'Error': 26298, 'Maximum': None, },
|
||||
'unsafe_shutdowns': {'Critical': False, 'Ignore': True, 'Warning': 1, 'Error': None, 'Maximum': None, },
|
||||
# SMART
|
||||
5: {'Hex': '05', 'Critical': True, 'Ignore': False, 'Warning': None, 'Error': 1, 'Maximum': None, },
|
||||
9: {'Hex': '09', 'Critical': False, 'Ignore': True, 'Warning': 17532, 'Error': 26298, 'Maximum': None, },
|
||||
10: {'Hex': '10', 'Critical': False, 'Ignore': False, 'Warning': 1, 'Error': 10, 'Maximum': 10000, },
|
||||
184: {'Hex': 'B8', 'Critical': False, 'Ignore': False, 'Warning': 1, 'Error': 10, 'Maximum': 10000, },
|
||||
187: {'Hex': 'BB', 'Critical': False, 'Ignore': False, 'Warning': 1, 'Error': 10, 'Maximum': 10000, },
|
||||
188: {'Hex': 'BC', 'Critical': False, 'Ignore': False, 'Warning': 1, 'Error': 10, 'Maximum': 10000, },
|
||||
196: {'Hex': 'C4', 'Critical': False, 'Ignore': False, 'Warning': 1, 'Error': 10, 'Maximum': 10000, },
|
||||
197: {'Hex': 'C5', 'Critical': True, 'Ignore': False, 'Warning': None, 'Error': 1, 'Maximum': None, },
|
||||
198: {'Hex': 'C6', 'Critical': True, 'Ignore': False, 'Warning': None, 'Error': 1, 'Maximum': None, },
|
||||
199: {'Hex': 'C7', 'Critical': False, 'Ignore': True, 'Warning': None, 'Error': 1, 'Maximum': None, },
|
||||
201: {'Hex': 'C9', 'Critical': False, 'Ignore': False, 'Warning': None, 'Error': 1, 'Maximum': 10000, },
|
||||
}
|
||||
ATTRIBUTE_COLORS = (
|
||||
# NOTE: Ordered by ascending importance
|
||||
('Warning', 'YELLOW'),
|
||||
('Error', 'RED'),
|
||||
('Maximum', 'PURPLE'),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("This file is not meant to be called directly.")
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
"""WizardKit: Hardware objects (mostly)."""
|
||||
"""WizardKit: Hardware objects (mostly)"""
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
||||
import logging
|
||||
|
|
@ -9,6 +9,7 @@ import re
|
|||
|
||||
from collections import OrderedDict
|
||||
|
||||
from wk.cfg.hw import ATTRIBUTES, ATTRIBUTE_COLORS
|
||||
from wk.exe import get_json_from_command, run_program
|
||||
from wk.std import bytes_to_string, color_string, string_to_bytes
|
||||
|
||||
|
|
@ -93,8 +94,8 @@ class CpuRam():
|
|||
f'{count}x {desc}' for desc, count in sorted(details.items())
|
||||
]
|
||||
|
||||
def generate_cpu_report(self):
|
||||
"""Generate CPU report with data from all tests."""
|
||||
def generate_report(self):
|
||||
"""Generate CPU & RAM report, returns list."""
|
||||
report = []
|
||||
report.append(color_string('Device', 'BLUE'))
|
||||
report.append(f' {self.description}')
|
||||
|
|
@ -116,7 +117,7 @@ class Disk():
|
|||
self.attributes = {}
|
||||
self.description = 'Unknown'
|
||||
self.details = {}
|
||||
self.nvme_smart_notes = {}
|
||||
self.notes = {}
|
||||
self.path = pathlib.Path(path).resolve()
|
||||
self.smartctl = {}
|
||||
self.tests = OrderedDict()
|
||||
|
|
@ -137,6 +138,77 @@ class Disk():
|
|||
]
|
||||
run_program(cmd, check=False)
|
||||
|
||||
def generate_attribute_report(self):
|
||||
"""Generate attribute report, returns list."""
|
||||
report = []
|
||||
for attr, value in sorted(self.attributes.items()):
|
||||
note = ''
|
||||
value_color = 'GREEN'
|
||||
|
||||
# Skip attributes not in our list
|
||||
if attr not in ATTRIBUTES:
|
||||
continue
|
||||
|
||||
# ID / Name
|
||||
label = f'{attr:>3}'
|
||||
if isinstance(attr, int):
|
||||
# Assuming SMART, include hex ID and name
|
||||
label += f' / {str(hex(attr))[2:].upper():0>2}: {value["name"]}'
|
||||
label = f' {label.replace("_", " "):38}'
|
||||
|
||||
# Value color
|
||||
for threshold, color in ATTRIBUTE_COLORS:
|
||||
if value['raw'] >= ATTRIBUTES.get(threshold, float('inf')):
|
||||
value_color = color
|
||||
if threshold == 'Maximum':
|
||||
note = '(invalid?)'
|
||||
|
||||
# 199/C7 warning
|
||||
if str(attr) == '199' and value['raw'] > 0:
|
||||
note = '(bad cable?)'
|
||||
|
||||
# Build colored string and append to report
|
||||
line = color_string(
|
||||
[label, value['raw_str'], note],
|
||||
[None, value_color, 'YELLOW'],
|
||||
)
|
||||
report.append(line)
|
||||
|
||||
# Done
|
||||
return report
|
||||
|
||||
|
||||
def generate_report(self):
|
||||
"""Generate Disk report, returns list."""
|
||||
report = []
|
||||
report.append(color_string(f'Device {self.path.name}', 'BLUE'))
|
||||
report.append(f' {self.description}')
|
||||
|
||||
# Attributes
|
||||
if self.attributes:
|
||||
report.append(color_string('Attributes', 'BLUE'))
|
||||
report.extend(self.generate_attribute_report())
|
||||
else:
|
||||
report.append(
|
||||
color_string(' No NVMe or SMART data available', 'YELLOW'))
|
||||
|
||||
# Notes
|
||||
if self.notes:
|
||||
report.append(color_string('Notes', 'BLUE'))
|
||||
for note in sorted(self.notes.keys()):
|
||||
report.append(f' {note}')
|
||||
|
||||
# 4K alignment check
|
||||
if not self.is_4k_aligned():
|
||||
report.append(color_string('Warning', 'YELLOW'))
|
||||
report.append(' One or more partitions are not 4K aligned')
|
||||
|
||||
# Tests
|
||||
for test in self.tests.values():
|
||||
report.extend(test.report)
|
||||
|
||||
return report
|
||||
|
||||
def get_details(self):
|
||||
"""Get disk details using OS specific methods.
|
||||
|
||||
|
|
@ -187,6 +259,11 @@ class Disk():
|
|||
# Done
|
||||
return labels
|
||||
|
||||
def is_4k_aligned(self):
|
||||
"""Check that all disk partitions are aligned, returns bool."""
|
||||
#TODO: Make real
|
||||
return True
|
||||
|
||||
def update_smart_details(self):
|
||||
"""Update SMART details via smartctl."""
|
||||
self.attributes = {}
|
||||
|
|
|
|||
Loading…
Reference in a new issue