summaryrefslogtreecommitdiffstats
path: root/glances/plugins/smart/model.py
diff options
context:
space:
mode:
Diffstat (limited to 'glances/plugins/smart/model.py')
-rw-r--r--glances/plugins/smart/model.py191
1 files changed, 0 insertions, 191 deletions
diff --git a/glances/plugins/smart/model.py b/glances/plugins/smart/model.py
deleted file mode 100644
index 3cb5376b..00000000
--- a/glances/plugins/smart/model.py
+++ /dev/null
@@ -1,191 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# This file is part of Glances.
-#
-# Copyright (C) 2018 Tim Nibert <docz2a@gmail.com>
-#
-# SPDX-License-Identifier: LGPL-3.0-only
-#
-
-"""
-Hard disk SMART attributes plugin.
-Depends on pySMART and smartmontools
-Must execute as root
-"usermod -a -G disk USERNAME" is not sufficient unfortunately
-SmartCTL (/usr/sbin/smartctl) must be in system path for python2.
-
-Regular PySMART is a python2 library.
-We are using the pySMART.smartx updated library to support both python 2 and 3.
-
-If we only have disk group access (no root):
-$ smartctl -i /dev/sda
-smartctl 6.6 2016-05-31 r4324 [x86_64-linux-4.15.0-30-generic] (local build)
-Copyright (C) 2002-16, Bruce Allen, Christian Franke, www.smartmontools.org
-
-
-Probable ATA device behind a SAT layer
-Try an additional '-d ata' or '-d sat' argument.
-
-This is not very hopeful: https://medium.com/opsops/why-smartctl-could-not-be-run-without-root-7ea0583b1323
-
-So, here is what we are going to do:
-Check for admin access. If no admin access, disable SMART plugin.
-
-If smartmontools is not installed, we should catch the error upstream in plugin initialization.
-"""
-
-from glances.plugins.plugin.model import GlancesPluginModel
-from glances.logger import logger
-from glances.main import disable
-from glances.globals import is_admin
-
-# Import plugin specific dependency
-try:
- from pySMART import DeviceList
-except ImportError as e:
- import_error_tag = True
- logger.warning("Missing Python Lib ({}), HDD Smart plugin is disabled".format(e))
-else:
- import_error_tag = False
-
-
-def convert_attribute_to_dict(attr):
- return {
- 'name': attr.name,
- 'num': attr.num,
- 'flags': attr.flags,
- 'raw': attr.raw,
- 'value': attr.value,
- 'worst': attr.worst,
- 'threshold': attr.thresh,
- 'type': attr.type,
- 'updated': attr.updated,
- 'when_failed': attr.when_failed,
- }
-
-
-def get_smart_data():
- """
- Get SMART attribute data
- :return: list of multi leveled dictionaries
- each dict has a key "DeviceName" with the identification of the device in smartctl
- also has keys of the SMART attribute id, with value of another dict of the attributes
- [
- {
- "DeviceName": "/dev/sda blahblah",
- "1":
- {
- "flags": "..",
- "raw": "..",
- etc,
- }
- ...
- }
- ]
- """
- stats = []
- # get all devices
- try:
- devlist = DeviceList()
- except TypeError as e:
- # Catch error (see #1806)
- logger.debug('Smart plugin error - Can not grab device list ({})'.format(e))
- global import_error_tag
- import_error_tag = True
- return stats
-
- for dev in devlist.devices:
- stats.append(
- {
- 'DeviceName': '{} {}'.format(dev.name, dev.model),
- }
- )
- for attribute in dev.attributes:
- if attribute is None:
- pass
- else:
- attrib_dict = convert_attribute_to_dict(attribute)
-
- # we will use the attribute number as the key
- num = attrib_dict.pop('num', None)
- try:
- assert num is not None
- except Exception as e:
- # we should never get here, but if we do, continue to next iteration and skip this attribute
- logger.debug('Smart plugin error - Skip the attribute {} ({})'.format(attribute, e))
- continue
-
- stats[-1][num] = attrib_dict
- return stats
-
-
-class PluginModel(GlancesPluginModel):
- """Glances' HDD SMART plugin."""
-
- def __init__(self, args=None, config=None, stats_init_value=[]):
- """Init the plugin."""
- # check if user is admin
- if not is_admin():
- disable(args, "smart")
- logger.debug("Current user is not admin, HDD SMART plugin disabled.")
-
- super(PluginModel, self).__init__(args=args, config=config)
-
- # We want to display the stat in the curse interface
- self.display_curse = True
-
- @GlancesPluginModel._check_decorator
- @GlancesPluginModel._log_result_decorator
- def update(self):
- """Update SMART stats using the input method."""
- # Init new stats
- stats = self.get_init_value()
-
- if import_error_tag:
- return self.stats
-
- if self.input_method == 'local':
- stats = get_smart_data()
- elif self.input_method == 'snmp':
- pass
-
- # Update the stats
- self.stats = stats
-
- return self.stats
-
- def get_key(self):
- """Return the key of the list."""
- return 'DeviceName'
-
- def msg_curse(self, args=None, max_width=None):
- """Return the dict to display in the curse interface."""
- # Init the return message
- ret = []
-
- # Only process if stats exist...
- if import_error_tag or not self.stats or self.is_disabled():
- return ret
-
- # Max size for the interface name
- name_max_width = max_width - 6
-
- # Header
- msg = '{:{width}}'.format('SMART disks', width=name_max_width)
- ret.append(self.curse_add_line(msg, "TITLE"))
- # Data
- for device_stat in self.stats:
- # New line
- ret.append(self.curse_new_line())
- msg = '{:{width}}'.format(device_stat['DeviceName'][:max_width], width=max_width)
- ret.append(self.curse_add_line(msg))
- for smart_stat in sorted([i for i in device_stat.keys() if i != 'DeviceName'], key=int):
- ret.append(self.curse_new_line())
- msg = ' {:{width}}'.format(
- device_stat[smart_stat]['name'][: name_max_width - 1].replace('_', ' '), width=name_max_width - 1
- )
- ret.append(self.curse_add_line(msg))
- msg = '{:>8}'.format(device_stat[smart_stat]['raw'])
- ret.append(self.curse_add_line(msg))
-
- return ret