2020-04-26 10:01:51 +02:00
|
|
|
# -*- coding: UTF-8 -*-
|
|
|
|
|
|
|
|
# smart function inspired by py-SMART https://github.com/freenas/py-SMART
|
|
|
|
# under Copyright (C) 2015 Marc Herndon and GPL2
|
|
|
|
|
|
|
|
"""Displays HDD smart status of different drives or all drives
|
|
|
|
|
|
|
|
Parameters:
|
2020-04-26 10:02:05 +02:00
|
|
|
* smartstatus.display: how to display (defaults to 'combined', other choices: 'seperate' or 'singles')
|
|
|
|
* smartstauts.drives: in the case of singles which drives to display, separated comma list value, multiple accepted (defaults to 'sda', example:'sda,sdc')
|
2020-04-26 10:01:51 +02:00
|
|
|
"""
|
|
|
|
|
|
|
|
import os
|
|
|
|
|
2020-04-26 10:07:17 +02:00
|
|
|
import shutil
|
2020-04-26 10:01:51 +02:00
|
|
|
|
2020-04-26 10:07:17 +02:00
|
|
|
import core.module
|
|
|
|
import core.widget
|
|
|
|
import core.decorators
|
2020-04-26 10:01:51 +02:00
|
|
|
|
2020-04-26 10:07:17 +02:00
|
|
|
import util.cli
|
|
|
|
|
|
|
|
class Module(core.module.Module):
|
|
|
|
@core.decorators.every(minutes=5)
|
2020-04-26 16:39:24 +02:00
|
|
|
def __init__(self, config, theme):
|
|
|
|
super().__init__(config, theme, [])
|
2020-04-26 10:01:51 +02:00
|
|
|
|
|
|
|
self.devices = self.list_devices()
|
|
|
|
self.display = self.parameter('display', 'combined')
|
|
|
|
self.drives = self.parameter('drives', 'sda')
|
|
|
|
self.widgets(self.create_widgets())
|
|
|
|
|
|
|
|
def create_widgets(self):
|
|
|
|
widgets = []
|
|
|
|
if self.display == 'combined':
|
2020-05-01 13:23:12 +02:00
|
|
|
widget = core.widget.Widget(module=self)
|
2020-04-26 10:01:51 +02:00
|
|
|
widget.set('device', 'combined')
|
|
|
|
widget.set('assessment', self.combined())
|
|
|
|
self.output(widget)
|
|
|
|
widgets.append(widget)
|
|
|
|
else:
|
|
|
|
for device in self.devices:
|
2020-04-26 10:02:05 +02:00
|
|
|
if self.display == 'singles' and device not in self.drives:
|
2020-04-26 10:01:51 +02:00
|
|
|
continue
|
2020-05-01 13:23:12 +02:00
|
|
|
widget = core.widget.Widget(module=self)
|
2020-04-26 10:01:51 +02:00
|
|
|
widget.set('device', device)
|
|
|
|
widget.set('assessment', self.smart(device))
|
|
|
|
self.output(widget)
|
|
|
|
widgets.append(widget)
|
|
|
|
return widgets
|
|
|
|
|
2020-04-26 10:07:17 +02:00
|
|
|
def update(self):
|
|
|
|
for widget in self.widgets():
|
2020-04-26 10:01:51 +02:00
|
|
|
device = widget.get('device')
|
|
|
|
if device == 'combined':
|
|
|
|
widget.set('assessment', self.combined())
|
|
|
|
self.output(widget)
|
|
|
|
else:
|
|
|
|
widget.set('assessment', self.smart(device))
|
|
|
|
self.output(widget)
|
|
|
|
|
|
|
|
def output(self, widget):
|
|
|
|
device = widget.get('device')
|
|
|
|
assessment = widget.get('assessment')
|
2020-04-26 10:02:05 +02:00
|
|
|
widget.full_text('{}: {}'.format(device, assessment))
|
2020-04-26 10:01:51 +02:00
|
|
|
|
|
|
|
def state(self, widget):
|
|
|
|
states = []
|
|
|
|
assessment = widget.get('assessment')
|
|
|
|
if assessment == 'Pre-fail':
|
|
|
|
states.append('warning')
|
|
|
|
if assessment == 'Fail':
|
|
|
|
states.append('critical')
|
|
|
|
return states
|
|
|
|
|
|
|
|
def combined(self):
|
|
|
|
for device in self.devices:
|
|
|
|
result = self.smart(device)
|
|
|
|
if result == 'Fail':
|
|
|
|
return 'Fail'
|
|
|
|
if result == 'Pre-fail':
|
|
|
|
return 'Pre-fail'
|
|
|
|
return 'OK'
|
|
|
|
|
|
|
|
def list_devices(self):
|
|
|
|
for (root, folders, files) in os.walk('/dev'):
|
|
|
|
if root == '/dev':
|
2020-04-26 10:02:05 +02:00
|
|
|
devices = {''.join(filter(lambda i: i.isdigit() == False, file)) for file in files if 'sd' in file}
|
2020-04-26 10:01:51 +02:00
|
|
|
nvme = {file for file in files if('nvme0n' in file and 'p' not in file)}
|
|
|
|
devices.update(nvme)
|
|
|
|
return devices
|
|
|
|
|
|
|
|
def smart(self, disk_name):
|
2020-04-26 10:07:17 +02:00
|
|
|
smartctl = shutil.which('smartctl')
|
2020-04-26 10:01:51 +02:00
|
|
|
assessment = None
|
2020-04-26 10:07:17 +02:00
|
|
|
|
|
|
|
output = util.cli.execute('sudo {} --health {}'.format(
|
|
|
|
smartctl, os.path.join('/dev/', disk_name)
|
|
|
|
))
|
|
|
|
output = output.split('\n')
|
|
|
|
line = output[4]
|
2020-04-26 10:01:51 +02:00
|
|
|
if 'SMART' in line:
|
|
|
|
if any([i in line for i in ['PASSED', 'OK']]):
|
|
|
|
assessment = 'OK'
|
|
|
|
else:
|
|
|
|
assessment = 'Fail'
|
|
|
|
|
|
|
|
if assessment == 'OK':
|
2020-04-26 10:07:17 +02:00
|
|
|
output = util.cli.execute('sudo {} -A {}'.format(
|
|
|
|
smartctl, os.path.join('/dev/', disk_name)
|
|
|
|
))
|
|
|
|
output = output.split('\n')
|
|
|
|
for line in output:
|
2020-04-26 10:02:05 +02:00
|
|
|
if 'Pre-fail' in line:
|
|
|
|
assessment = 'Pre-fail'
|
2020-04-26 10:01:51 +02:00
|
|
|
return assessment
|
2020-04-26 10:07:17 +02:00
|
|
|
|
|
|
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|