# -*- 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: * 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') """ import os import shutil import core.module import core.widget import core.decorators import util.cli class Module(core.module.Module): @core.decorators.every(minutes=5) def __init__(self, config, theme): super().__init__(config, theme, []) 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": widget = core.widget.Widget(module=self) widget.set("device", "combined") widget.set("assessment", self.combined()) self.output(widget) widgets.append(widget) else: for device in self.devices: if self.display == "singles" and device not in self.drives: continue widget = core.widget.Widget(module=self) widget.set("device", device) widget.set("assessment", self.smart(device)) self.output(widget) widgets.append(widget) return widgets def update(self): for widget in self.widgets(): 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") widget.full_text("{}: {}".format(device, assessment)) 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": devices = { "".join(filter(lambda i: i.isdigit() == False, file)) for file in files if "sd" in file } 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): smartctl = shutil.which("smartctl") assessment = None output = util.cli.execute( "sudo {} --health {}".format(smartctl, os.path.join("/dev/", disk_name)) ) output = output.split("\n") line = output[4] if "SMART" in line: if any([i in line for i in ["PASSED", "OK"]]): assessment = "OK" else: assessment = "Fail" if assessment == "OK": output = util.cli.execute( "sudo {} -A {}".format(smartctl, os.path.join("/dev/", disk_name)) ) output = output.split("\n") for line in output: if "Pre-fail" in line: assessment = "Pre-fail" return assessment # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4