Support model-specifc attribute thresholds

* Addresses issue #142
This commit is contained in:
2Shirt 2019-11-08 16:00:27 -07:00
parent 3a2924bd51
commit 205c5ed0fc
Signed by: 2Shirt
GPG key ID: 152FAC923B0E132C
3 changed files with 70 additions and 30 deletions

View file

@ -2,8 +2,19 @@
# pylint: disable=bad-whitespace,line-too-long
# vim: sts=2 sw=2 ts=2
import re
KNOWN_ATTRIBUTES = {
# STATIC VARIABLES
ATTRIBUTE_COLORS = (
# NOTE: Ordered by ascending importance
('Warning', 'YELLOW'),
('Error', 'RED'),
('Maximum', 'PURPLE'),
)
KEY_NVME = 'nvme_smart_health_information_log'
KEY_SMART = 'ata_smart_attributes'
KNOWN_DISK_ATTRIBUTES = {
# NVMe
'critical_warning': {'Blocking': True, 'Warning': None, 'Error': 1, 'Maximum': None, },
'media_errors': {'Blocking': False, 'Warning': None, 'Error': 1, 'Maximum': None, },
@ -22,6 +33,25 @@ KNOWN_ATTRIBUTES = {
199: {'Hex': 'C7', 'Blocking': False, 'Warning': None, 'Error': 1, 'Maximum': None, },
201: {'Hex': 'C9', 'Blocking': False, 'Warning': None, 'Error': 1, 'Maximum': 10000, },
}
KNOWN_DISK_MODELS = {
# model_regex: model_attributes
r'CT(250|500|1000|2000)MX500SSD(1|4)': {
197: {'Warning': 1, 'Error': 2, 'Note': '(MX500 thresholds)',},
},
}
KNOWN_RAM_VENDOR_IDS = {
# https://github.com/hewigovens/hewigovens.github.com/wiki/Memory-vendor-code
'0x014F': 'Transcend',
'0x2C00': 'Micron',
'0x802C': 'Micron',
'0x80AD': 'Hynix',
'0x80CE': 'Samsung',
'0xAD00': 'Hynix',
'0xCE00': 'Samsung',
}
REGEX_POWER_ON_TIME = re.compile(
r'^(\d+)([Hh].*|\s+\(\d+\s+\d+\s+\d+\).*)'
)
if __name__ == '__main__':

View file

@ -9,34 +9,21 @@ import re
from collections import OrderedDict
from wk.cfg.hw import KNOWN_ATTRIBUTES
from wk.cfg.hw import (
ATTRIBUTE_COLORS,
KEY_NVME,
KEY_SMART,
KNOWN_DISK_ATTRIBUTES,
KNOWN_DISK_MODELS,
KNOWN_RAM_VENDOR_IDS,
REGEX_POWER_ON_TIME,
)
from wk.exe import get_json_from_command, run_program
from wk.std import bytes_to_string, color_string, sleep, string_to_bytes
# STATIC VARIABLES
ATTRIBUTE_COLORS = (
# NOTE: Ordered by ascending importance
('Warning', 'YELLOW'),
('Error', 'RED'),
('Maximum', 'PURPLE'),
)
KEY_NVME = 'nvme_smart_health_information_log'
KEY_SMART = 'ata_smart_attributes'
KNOWN_RAM_VENDOR_IDS = {
# https://github.com/hewigovens/hewigovens.github.com/wiki/Memory-vendor-code
'0x014F': 'Transcend',
'0x2C00': 'Micron',
'0x802C': 'Micron',
'0x80AD': 'Hynix',
'0x80CE': 'Samsung',
'0xAD00': 'Hynix',
'0xCE00': 'Samsung',
}
LOG = logging.getLogger(__name__)
REGEX_POWER_ON_TIME = re.compile(
r'^(\d+)([Hh].*|\s+\(\d+\s+\d+\s+\d+\).*)'
)
# Exception Classes
@ -172,15 +159,16 @@ class Disk(BaseObj):
def check_attributes(self, only_blocking=False):
"""Check if any known attributes are failing, returns bool."""
attributes_ok = True
known_attributes = get_known_disk_attributes(self.details['model'])
for attr, value in self.attributes.items():
# Skip unknown attributes
if attr not in KNOWN_ATTRIBUTES:
if attr not in known_attributes:
continue
# Get thresholds
blocking_attribute = KNOWN_ATTRIBUTES[attr].get('Blocking', False)
err_thresh = KNOWN_ATTRIBUTES[attr].get('Error', None)
max_thresh = KNOWN_ATTRIBUTES[attr].get('Maximum', None)
blocking_attribute = known_attributes[attr].get('Blocking', False)
err_thresh = known_attributes[attr].get('Error', None)
max_thresh = known_attributes[attr].get('Maximum', None)
if not max_thresh:
max_thresh = float('inf')
@ -212,15 +200,19 @@ class Disk(BaseObj):
def generate_attribute_report(self):
"""Generate attribute report, returns list."""
known_attributes = get_known_disk_attributes(self.details['model'])
report = []
for attr, value in sorted(self.attributes.items()):
note = ''
value_color = 'GREEN'
# Skip attributes not in our list
if attr not in KNOWN_ATTRIBUTES:
if attr not in known_attributes:
continue
# Check for attribute note
note = known_attributes[attr].get('Note', '')
# ID / Name
label = f'{attr:>3}'
if isinstance(attr, int):
@ -230,11 +222,11 @@ class Disk(BaseObj):
# Value color
for threshold, color in ATTRIBUTE_COLORS:
threshold_val = KNOWN_ATTRIBUTES[attr].get(threshold, None)
threshold_val = known_attributes[attr].get(threshold, None)
if threshold_val and value['raw'] >= threshold_val:
value_color = color
if threshold == 'Error':
note = '(Failed)'
note = '(failed)'
elif threshold == 'Maximum':
note = '(invalid?)'
@ -604,6 +596,23 @@ def get_disk_serial_macos(path):
return serial
def get_known_disk_attributes(model):
"""Get known NVMe/SMART attributes (model specific), returns str."""
known_attributes = KNOWN_DISK_ATTRIBUTES.copy()
# Apply model-specific data
for regex, data in KNOWN_DISK_MODELS.items():
if re.search(regex, model):
for attr, thresholds in data.items():
if attr in known_attributes:
known_attributes[attr].update(thresholds)
else:
known_attributes[attr] = thresholds
# Done
return known_attributes
def get_ram_list_linux():
"""Get RAM list using dmidecode."""
cmd = ['sudo', 'dmidecode', '--type', 'memory']

View file

@ -1,4 +1,5 @@
"""WizardKit: Standard Functions"""
# pylint: disable=too-many-lines
# vim: sts=2 sw=2 ts=2
import itertools