Reworked checking Disk() attributes
* Added separate Disk().check_attributes() function * Can be used to check all KNOWN_ATTRIBUTES or just blocking ones * Renamed ATTRIBUTES to KNOWN_ATTRIBUTES for clarity * Renamed 'Critical' column to 'Blocking' * Added '(Failed)' note to attribute report * Addresses issue #131
This commit is contained in:
parent
07fdbcdd7c
commit
93102b5144
2 changed files with 61 additions and 51 deletions
|
|
@ -3,31 +3,25 @@
|
|||
# vim: sts=2 sw=2 ts=2
|
||||
|
||||
|
||||
ATTRIBUTES = {
|
||||
KNOWN_ATTRIBUTES = {
|
||||
# NVMe
|
||||
'critical_warning': {'Critical': True, 'Warning': None, 'Error': 1, 'Maximum': None, },
|
||||
'media_errors': {'Critical': False, 'Warning': None, 'Error': 1, 'Maximum': None, },
|
||||
'power_on_hours': {'Critical': False, 'Warning': 17532, 'Error': 26298, 'Maximum': None, },
|
||||
'unsafe_shutdowns': {'Critical': False, 'Warning': 1, 'Error': None, 'Maximum': None, },
|
||||
'critical_warning': {'Blocking': True, 'Warning': None, 'Error': 1, 'Maximum': None, },
|
||||
'media_errors': {'Blocking': False, 'Warning': None, 'Error': 1, 'Maximum': None, },
|
||||
'power_on_hours': {'Blocking': False, 'Warning': 17532, 'Error': 26298, 'Maximum': None, },
|
||||
'unsafe_shutdowns': {'Blocking': False, 'Warning': 1, 'Error': None, 'Maximum': None, },
|
||||
# SMART
|
||||
5: {'Hex': '05', 'Critical': True, 'Warning': None, 'Error': 1, 'Maximum': None, },
|
||||
9: {'Hex': '09', 'Critical': False, 'Warning': 17532, 'Error': 26298, 'Maximum': None, },
|
||||
10: {'Hex': '10', 'Critical': False, 'Warning': 1, 'Error': 10, 'Maximum': 10000, },
|
||||
184: {'Hex': 'B8', 'Critical': False, 'Warning': 1, 'Error': 10, 'Maximum': 10000, },
|
||||
187: {'Hex': 'BB', 'Critical': False, 'Warning': 1, 'Error': 10, 'Maximum': 10000, },
|
||||
188: {'Hex': 'BC', 'Critical': False, 'Warning': 1, 'Error': 10, 'Maximum': 10000, },
|
||||
196: {'Hex': 'C4', 'Critical': False, 'Warning': 1, 'Error': 10, 'Maximum': 10000, },
|
||||
197: {'Hex': 'C5', 'Critical': True, 'Warning': None, 'Error': 1, 'Maximum': None, },
|
||||
198: {'Hex': 'C6', 'Critical': True, 'Warning': None, 'Error': 1, 'Maximum': None, },
|
||||
199: {'Hex': 'C7', 'Critical': False, 'Warning': None, 'Error': 1, 'Maximum': None, },
|
||||
201: {'Hex': 'C9', 'Critical': False, 'Warning': None, 'Error': 1, 'Maximum': 10000, },
|
||||
5: {'Hex': '05', 'Blocking': True, 'Warning': None, 'Error': 1, 'Maximum': None, },
|
||||
9: {'Hex': '09', 'Blocking': False, 'Warning': 17532, 'Error': 26298, 'Maximum': None, },
|
||||
10: {'Hex': '10', 'Blocking': False, 'Warning': 1, 'Error': 10, 'Maximum': 10000, },
|
||||
184: {'Hex': 'B8', 'Blocking': False, 'Warning': 1, 'Error': 10, 'Maximum': 10000, },
|
||||
187: {'Hex': 'BB', 'Blocking': False, 'Warning': 1, 'Error': 10, 'Maximum': 10000, },
|
||||
188: {'Hex': 'BC', 'Blocking': False, 'Warning': 1, 'Error': 10, 'Maximum': 10000, },
|
||||
196: {'Hex': 'C4', 'Blocking': False, 'Warning': 1, 'Error': 10, 'Maximum': 10000, },
|
||||
197: {'Hex': 'C5', 'Blocking': True, 'Warning': None, 'Error': 1, 'Maximum': None, },
|
||||
198: {'Hex': 'C6', 'Blocking': True, 'Warning': None, 'Error': 1, 'Maximum': None, },
|
||||
199: {'Hex': 'C7', 'Blocking': False, 'Warning': None, 'Error': 1, 'Maximum': None, },
|
||||
201: {'Hex': 'C9', 'Blocking': False, 'Warning': None, 'Error': 1, 'Maximum': 10000, },
|
||||
}
|
||||
ATTRIBUTE_COLORS = (
|
||||
# NOTE: Ordered by ascending importance
|
||||
('Warning', 'YELLOW'),
|
||||
('Error', 'RED'),
|
||||
('Maximum', 'PURPLE'),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
|||
|
|
@ -9,12 +9,18 @@ import re
|
|||
|
||||
from collections import OrderedDict
|
||||
|
||||
from wk.cfg.hw import ATTRIBUTES, ATTRIBUTE_COLORS
|
||||
from wk.cfg.hw import KNOWN_ATTRIBUTES
|
||||
from wk.exe import get_json_from_command, run_program
|
||||
from wk.std import bytes_to_string, color_string, 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 = {
|
||||
|
|
@ -144,6 +150,36 @@ class Disk():
|
|||
self.notes.append(note)
|
||||
self.notes.sort()
|
||||
|
||||
def check_attributes(self, only_blocking=False):
|
||||
"""Check if any known attributes are failing, returns bool."""
|
||||
attributes_ok = True
|
||||
for attr, value in self.attributes.items():
|
||||
# Skip unknown 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)
|
||||
if not max_thresh:
|
||||
max_thresh = float('inf')
|
||||
|
||||
# Skip non-blocking attributes if necessary
|
||||
if only_blocking and not blocking_attribute:
|
||||
continue
|
||||
|
||||
# Skip informational attributes
|
||||
if not err_thresh:
|
||||
continue
|
||||
|
||||
# Check attribute
|
||||
if err_thresh <= value['raw'] < max_thresh:
|
||||
attributes_ok = False
|
||||
|
||||
# Done
|
||||
return attributes_ok
|
||||
|
||||
def enable_smart(self):
|
||||
"""Try enabling SMART for this disk."""
|
||||
cmd = [
|
||||
|
|
@ -163,7 +199,7 @@ class Disk():
|
|||
value_color = 'GREEN'
|
||||
|
||||
# Skip attributes not in our list
|
||||
if attr not in ATTRIBUTES:
|
||||
if attr not in KNOWN_ATTRIBUTES:
|
||||
continue
|
||||
|
||||
# ID / Name
|
||||
|
|
@ -175,10 +211,12 @@ class Disk():
|
|||
|
||||
# Value color
|
||||
for threshold, color in ATTRIBUTE_COLORS:
|
||||
threshold_val = ATTRIBUTES.get(attr, {}).get(threshold, float('inf'))
|
||||
threshold_val = KNOWN_ATTRIBUTES[attr].get(threshold, None)
|
||||
if threshold_val and value['raw'] >= threshold_val:
|
||||
value_color = color
|
||||
if threshold == 'Maximum':
|
||||
if threshold == 'Error':
|
||||
note = '(Failed)'
|
||||
elif threshold == 'Maximum':
|
||||
note = '(invalid?)'
|
||||
|
||||
# 199/C7 warning
|
||||
|
|
@ -286,31 +324,9 @@ class Disk():
|
|||
self.update_smart_details()
|
||||
|
||||
# Attributes
|
||||
for attr, value in self.attributes.items():
|
||||
# Skip unknown attributes
|
||||
if attr not in ATTRIBUTES:
|
||||
continue
|
||||
|
||||
# Get thresholds
|
||||
critical = ATTRIBUTES[attr].get('Critical', False)
|
||||
err_thresh = ATTRIBUTES[attr].get('Error', None)
|
||||
max_thresh = ATTRIBUTES[attr].get('Maximum', None)
|
||||
if not max_thresh:
|
||||
max_thresh = float('inf')
|
||||
|
||||
# Skip non-critical attributes
|
||||
if not critical:
|
||||
continue
|
||||
|
||||
# Skip informational attributes
|
||||
if not err_thresh:
|
||||
continue
|
||||
|
||||
# Check attribute
|
||||
if err_thresh <= value['raw'] < max_thresh:
|
||||
if not self.check_attributes(only_blocking=True):
|
||||
blocking_event_encountered = True
|
||||
msg = f'Failed attribute: {attr}'
|
||||
LOG.error('%s %s', self.path, msg)
|
||||
LOG.error('%s: Blocked for failing attributes', self.path)
|
||||
|
||||
# NVMe status
|
||||
# TODO: See https://github.com/2Shirt/WizardKit/issues/130
|
||||
|
|
|
|||
Loading…
Reference in a new issue