Curses interface OK

This commit is contained in:
Nicolargo 2014-12-21 22:48:30 +01:00
parent 96d2e841de
commit c22d4407b5
5 changed files with 158 additions and 2 deletions

1
NEWS
View File

@ -5,6 +5,7 @@ Glances Version 2.x
Version 2.X
===========
* Add the RAID plugins (issue #447)
* Fix incorrect kernel thread detection with --hide-kernel-threads (issue #457)
* Handle IOError exception if no /etc/os-release to use Glances on Synology DSM (issue #458)
* Check issue error in client/server mode (issue #459)

View File

@ -75,6 +75,8 @@ class GlancesMain(object):
dest='disable_fs', help=_('disable filesystem module'))
parser.add_argument('--disable-sensors', action='store_true', default=False,
dest='disable_sensors', help=_('disable sensors module'))
parser.add_argument('--disable-raid', action='store_true', default=False,
dest='disable_raid', help=_('disable RAID module'))
parser.add_argument('--disable-left-sidebar', action='store_true', default=False,
dest='disable_left_sidebar', help=_('disable network, disk io, FS and sensors modules'))
parser.add_argument('--disable-process', action='store_true', default=False,

View File

@ -306,6 +306,9 @@ class _GlancesCurses(object):
elif self.pressedkey == ord('r'):
# 'r' > Reset history
self.reset_history_tag = not self.reset_history_tag
elif self.pressedkey == ord('R'):
# 'R' > Hide RAID plugins
self.args.disable_raid = not self.args.disable_raid
elif self.pressedkey == ord('s'):
# 's' > Show/hide sensors stats (Linux-only)
self.args.disable_sensors = not self.args.disable_sensors
@ -424,6 +427,8 @@ class _GlancesCurses(object):
'diskio').get_stats_display(args=self.args)
stats_fs = stats.get_plugin('fs').get_stats_display(
args=self.args, max_width=plugin_max_width)
stats_raid = stats.get_plugin('raid').get_stats_display(
args=self.args, max_width=plugin_max_width)
stats_sensors = stats.get_plugin(
'sensors').get_stats_display(args=self.args)
stats_now = stats.get_plugin('now').get_stats_display()
@ -507,7 +512,8 @@ class _GlancesCurses(object):
# Display left sidebar (NETWORK+DISKIO+FS+SENSORS+Current time)
self.init_column()
if (not (self.args.disable_network and self.args.disable_diskio
and self.args.disable_fs and self.args.disable_sensors)) \
and self.args.disable_fs and self.args.disable_raid
and self.args.disable_sensors)) \
and not self.args.disable_left_sidebar:
self.new_line()
self.display_plugin(stats_network)
@ -516,6 +522,8 @@ class _GlancesCurses(object):
self.new_line()
self.display_plugin(stats_fs)
self.new_line()
self.display_plugin(stats_raid)
self.new_line()
self.display_plugin(stats_sensors)
self.new_line()
self.display_plugin(stats_now)

View File

@ -0,0 +1,144 @@
# -*- coding: utf-8 -*-
#
# This file is part of Glances.
#
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
#
# Glances is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Glances is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""RAID plugin."""
# Import Glances libs
from glances.core.glances_logging import logger
from glances.plugins.glances_plugin import GlancesPlugin
# pymdstat only available on GNU/Linux OS
try:
from pymdstat import MdStat
except ImportError:
logger.debug("pymdstat library not found. Glances cannot grab RAID info.")
pass
class Plugin(GlancesPlugin):
"""Glances' RAID plugin.
stats is a dict (see pymdstat documentation)
"""
def __init__(self, args=None):
"""Init the plugin."""
GlancesPlugin.__init__(self, args=args)
# We want to display the stat in the curse interface
self.display_curse = True
# Init the stats
self.reset()
def reset(self):
"""Reset/init the stats."""
self.stats = {}
@GlancesPlugin._log_result_decorator
def update(self):
"""Update RAID stats using the input method."""
# Reset stats
self.reset()
if self.get_input() == 'local':
# Update stats using the PyMDstat lib (https://github.com/nicolargo/pymdstat)
try:
# !!! Path ONLY for dev
mds = MdStat('/home/nicolargo/dev/pymdstat/tests/mdstat.09')
self.stats = mds.get_stats()['arrays']
except Exception as e:
logger.debug("Can not grab RAID stats (%s)" % e)
return self.stats
elif self.get_input() == 'snmp':
# Update stats using SNMP
# No standard way for the moment...
pass
return self.stats
def msg_curse(self, args=None):
"""Return the dict to display in the curse interface."""
# Init the return message
ret = []
# Only process if stats exist and display plugin enable...
if not self.stats or args.disable_raid:
return ret
# Build the string message
# Header
msg = '{0:10}'.format(_('RAID disks'))
ret.append(self.curse_add_line(msg, "TITLE"))
msg = '{0:>6}'.format(_("Used"))
ret.append(self.curse_add_line(msg))
msg = '{0:>7}'.format(_("Avail"))
ret.append(self.curse_add_line(msg))
# Data
arrays = self.stats.keys()
arrays.sort()
for array in arrays:
# New line
ret.append(self.curse_new_line())
# Display the current status
status = self.raid_alert(self.stats[array]['status'], self.stats[array]['used'], self.stats[array]['available'])
# Data: RAID type name | disk used | disk available
msg = '{0:<5}{1:>6}'.format(self.stats[array]['type'].upper(), array)
ret.append(self.curse_add_line(msg))
if self.stats[array]['status'] == 'active':
msg = '{0:>5}'.format(self.stats[array]['used'])
ret.append(self.curse_add_line(msg, status))
msg = '{0:>7}'.format(self.stats[array]['available'])
ret.append(self.curse_add_line(msg, status))
elif self.stats[array]['status'] == 'inactive':
ret.append(self.curse_new_line())
msg = '|_ Status {}'.format(self.stats[array]['status'])
ret.append(self.curse_add_line(msg, status))
components = self.stats[array]['components'].keys()
components.sort()
for component in components:
ret.append(self.curse_new_line())
msg = ' |_ disk {0}: '.format(self.stats[array]['components'][component])
ret.append(self.curse_add_line(msg))
msg = '{0}'.format(component)
ret.append(self.curse_add_line(msg))
if self.stats[array]['used'] < self.stats[array]['available']:
# Display current array configuration
ret.append(self.curse_new_line())
msg = '|_ Degraded mode'
ret.append(self.curse_add_line(msg, status))
if len(self.stats[array]['config']) < 17:
ret.append(self.curse_new_line())
msg = ' |_ {0}'.format(self.stats[array]['config'].replace('_', 'A'))
ret.append(self.curse_add_line(msg))
return ret
def raid_alert(self, status, used, available):
"""
[available/used] means that ideally the array would have _available_ devices however, _used_ devices are in use.
Obviously when used >= available then things are good.
"""
if status == 'inactive':
return 'CRITICAL'
if used < available:
return 'WARNING'
return 'OK'

View File

@ -65,7 +65,8 @@ setup(
'BATINFO': ['batinfo'],
'SNMP': ['pysnmp'],
'CHART': ['matplotlib'],
'BROWSER': ['zeroconf>=0.16', 'netifaces']
'BROWSER': ['zeroconf>=0.16', 'netifaces'],
'RAID': ['pymdstat']
},
packages=['glances'],
include_package_data=True,