summaryrefslogtreecommitdiffstats
path: root/glances
diff options
context:
space:
mode:
authornicolargo <nicolas@nicolargo.com>2019-11-24 17:40:02 +0100
committernicolargo <nicolas@nicolargo.com>2019-11-24 17:40:02 +0100
commit3b11856926d9d512ba749033e67c326fb619fa3a (patch)
tree4c26540e15981be0ae5286d3548c67eb31050510 /glances
parent7bd6351bf27c316eaa9c25f76bf48d1b8a121d36 (diff)
Feature request: HDD S.M.A.R.T. reports #1288 (only terminal UI)
Diffstat (limited to 'glances')
-rw-r--r--glances/compat.py25
-rw-r--r--glances/outputs/glances_curses.py20
-rw-r--r--glances/plugins/glances_raid.py2
-rw-r--r--glances/plugins/glances_smart.py67
4 files changed, 74 insertions, 40 deletions
diff --git a/glances/compat.py b/glances/compat.py
index cac531f1..e16e8286 100644
--- a/glances/compat.py
+++ b/glances/compat.py
@@ -28,6 +28,7 @@ import sys
import unicodedata
import types
import subprocess
+import os
from glances.logger import logger
@@ -239,3 +240,27 @@ def time_serie_subsample(data, sampling):
def to_fahrenheit(celsius):
"""Convert Celsius to Fahrenheit."""
return celsius * 1.8 + 32
+
+
+def is_admin():
+ """
+ https://stackoverflow.com/a/19719292
+ @return: True if the current user is an 'Admin' whatever that
+ means (root on Unix), otherwise False.
+ Warning: The inner function fails unless you have Windows XP SP2 or
+ higher. The failure causes a traceback to be printed and this
+ function to return False.
+ """
+
+ if os.name == 'nt':
+ import ctypes
+ import traceback
+ # WARNING: requires Windows XP SP2 or higher!
+ try:
+ return ctypes.windll.shell32.IsUserAnAdmin()
+ except Exception as e:
+ traceback.print_exc()
+ return False
+ else:
+ # Check for root on Posix
+ return os.getuid() == 0
diff --git a/glances/outputs/glances_curses.py b/glances/outputs/glances_curses.py
index ec1afdf4..a1e00d2d 100644
--- a/glances/outputs/glances_curses.py
+++ b/glances/outputs/glances_curses.py
@@ -55,38 +55,38 @@ class _GlancesCurses(object):
'3': {'switch': 'disable_quicklook'},
'6': {'switch': 'meangpu'},
'/': {'switch': 'process_short_name'},
+ 'a': {'sort_key': 'auto'},
'A': {'switch': 'disable_amps'},
'b': {'switch': 'byte'},
'B': {'switch': 'diskio_iops'},
+ 'c': {'sort_key': 'cpu_percent'},
'C': {'switch': 'disable_cloud'},
- 'D': {'switch': 'disable_docker'},
'd': {'switch': 'disable_diskio'},
+ 'D': {'switch': 'disable_docker'},
'F': {'switch': 'fs_free_space'},
'g': {'switch': 'generate_graph'},
'G': {'switch': 'disable_gpu'},
'h': {'switch': 'help_tag'},
+ 'i': {'sort_key': 'io_counters'},
'I': {'switch': 'disable_ip'},
'k': {'switch': 'disable_connections'},
'l': {'switch': 'disable_alert'},
+ 'm': {'sort_key': 'memory_percent'},
'M': {'switch': 'reset_minmax_tag'},
'n': {'switch': 'disable_network'},
'N': {'switch': 'disable_now'},
+ 'p': {'sort_key': 'name'},
'P': {'switch': 'disable_ports'},
'Q': {'switch': 'enable_irq'},
+ 'r': {'switch': 'disable_smart'},
'R': {'switch': 'disable_raid'},
's': {'switch': 'disable_sensors'},
'S': {'switch': 'sparkline'},
+ 't': {'sort_key': 'cpu_times'},
'T': {'switch': 'network_sum'},
+ 'u': {'sort_key': 'username'},
'U': {'switch': 'network_cumul'},
'W': {'switch': 'disable_wifi'},
- # Processes sort hotkeys
- 'a': {'sort_key': 'auto'},
- 'c': {'sort_key': 'cpu_percent'},
- 'i': {'sort_key': 'io_counters'},
- 'm': {'sort_key': 'memory_percent'},
- 'p': {'sort_key': 'name'},
- 't': {'sort_key': 'cpu_times'},
- 'u': {'sort_key': 'username'},
}
_sort_loop = ['cpu_percent', 'memory_percent', 'username',
@@ -98,7 +98,7 @@ class _GlancesCurses(object):
# Define left sidebar
_left_sidebar = ['network', 'connections', 'wifi', 'ports', 'diskio', 'fs',
- 'irq', 'folders', 'raid', 'sensors', 'now']
+ 'irq', 'folders', 'raid', 'smart', 'sensors', 'now']
_left_sidebar_min_width = 23
_left_sidebar_max_width = 34
diff --git a/glances/plugins/glances_raid.py b/glances/plugins/glances_raid.py
index 7e5275b2..795812e7 100644
--- a/glances/plugins/glances_raid.py
+++ b/glances/plugins/glances_raid.py
@@ -83,7 +83,7 @@ class Plugin(GlancesPlugin):
ret = []
# Only process if stats exist...
- if not self.stats:
+ if not self.stats or self.is_disable():
return ret
# Max size for the interface name
diff --git a/glances/plugins/glances_smart.py b/glances/plugins/glances_smart.py
index f0291cad..445942cb 100644
--- a/glances/plugins/glances_smart.py
+++ b/glances/plugins/glances_smart.py
@@ -47,7 +47,7 @@ If smartmontools is not installed, we should catch the error upstream in plugin
from glances.plugins.glances_plugin import GlancesPlugin
from glances.logger import logger
from glances.main import disable
-import os
+from glances.compat import is_admin
# Import plugin specific dependency
try:
@@ -58,35 +58,10 @@ except ImportError as e:
else:
import_error_tag = False
-DEVKEY = "DeviceName"
-
-
-def is_admin():
- """
- https://stackoverflow.com/a/19719292
- @return: True if the current user is an 'Admin' whatever that
- means (root on Unix), otherwise False.
- Warning: The inner function fails unless you have Windows XP SP2 or
- higher. The failure causes a traceback to be printed and this
- function to return False.
- """
-
- if os.name == 'nt':
- import ctypes
- import traceback
- # WARNING: requires Windows XP SP2 or higher!
- try:
- return ctypes.windll.shell32.IsUserAnAdmin()
- except:
- traceback.print_exc()
- return False
- else:
- # Check for root on Posix
- return os.getuid() == 0
-
def convert_attribute_to_dict(attr):
return {
+ 'name': attr.name,
'num': attr.num,
'flags': attr.flags,
'raw': attr.raw,
@@ -114,6 +89,7 @@ def get_smart_data():
"raw": "..",
etc,
}
+ ...
}
]
"""
@@ -123,7 +99,7 @@ def get_smart_data():
for dev in devlist.devices:
stats.append({
- DEVKEY: str(dev)
+ 'DeviceName': '{} {}'.format(dev.name, dev.model),
})
for attribute in dev.attributes:
if attribute is None:
@@ -187,4 +163,37 @@ class Plugin(GlancesPlugin):
def get_key(self):
"""Return the key of the list."""
- return DEVKEY
+ 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 not self.stats or self.is_disable():
+ 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