From a5b6eb9dab397d632e9945437496f3b421585ba5 Mon Sep 17 00:00:00 2001 From: nicolargo Date: Sun, 15 Feb 2015 22:17:55 +0100 Subject: [PATCH] Add a new IP information plugin (issue #509) --- glances/core/glances_main.py | 2 + glances/outputs/glances_curses.py | 32 ++++++-- glances/plugins/glances_ip.py | 120 ++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+), 8 deletions(-) create mode 100644 glances/plugins/glances_ip.py diff --git a/glances/core/glances_main.py b/glances/core/glances_main.py index b70ee25b..eb68f663 100644 --- a/glances/core/glances_main.py +++ b/glances/core/glances_main.py @@ -102,6 +102,8 @@ Start the client browser (browser mode):\n\ # Enable or disable option on startup parser.add_argument('--disable-network', action='store_true', default=False, dest='disable_network', help=_('disable network module')) + parser.add_argument('--disable-ip', action='store_true', default=False, + dest='disable_ip', help=_('disable IP module')) parser.add_argument('--disable-diskio', action='store_true', default=False, dest='disable_diskio', help=_('disable disk I/O module')) parser.add_argument('--disable-fs', action='store_true', default=False, diff --git a/glances/outputs/glances_curses.py b/glances/outputs/glances_curses.py index 7d7ca514..b5969f0b 100644 --- a/glances/outputs/glances_curses.py +++ b/glances/outputs/glances_curses.py @@ -296,6 +296,9 @@ class _GlancesCurses(object): # 'i' > Sort processes by IO rate (not available on OS X) self.args.process_sorted_by = 'io_counters' glances_processes.setmanualsortkey(self.args.process_sorted_by) + elif self.pressedkey == ord('I'): + # 'I' > Show/hide IP module + self.args.disable_ip = not self.args.disable_ip elif self.pressedkey == ord('l'): # 'l' > Show/hide log messages self.args.disable_log = not self.args.disable_log @@ -430,6 +433,10 @@ class _GlancesCurses(object): stats_memswap = stats.get_plugin('memswap').get_stats_display() stats_network = stats.get_plugin('network').get_stats_display( args=self.args, max_width=plugin_max_width) + try: + stats_ip = stats.get_plugin('ip').get_stats_display(args=self.args) + except AttributeError: + stats_ip = None stats_diskio = stats.get_plugin( 'diskio').get_stats_display(args=self.args) stats_fs = stats.get_plugin('fs').get_stats_display( @@ -479,10 +486,17 @@ class _GlancesCurses(object): # ================================== # Display first line (system+uptime) # ================================== + # Space between column + self.space_between_column = 0 self.new_line() - l = self.get_stats_display_width( - stats_system) + self.get_stats_display_width(stats_uptime) + self.space_between_column - self.display_plugin(stats_system, display_optional=(screen_x >= l)) + l_uptime = self.get_stats_display_width( + stats_system) + self.space_between_column + self.get_stats_display_width(stats_ip) + 3 + self.get_stats_display_width(stats_uptime) + self.display_plugin( + stats_system, display_optional=(screen_x >= l_uptime)) + self.new_column() + self.display_plugin(stats_ip) + # Space between column + self.space_between_column = 3 self.new_column() self.display_plugin(stats_uptime) @@ -499,11 +513,13 @@ class _GlancesCurses(object): cpu_width = self.get_stats_display_width(stats_percpu) quicklook_adapt = 114 else: - cpu_width = self.get_stats_display_width(stats_cpu, without_option=(screen_x < 80)) + cpu_width = self.get_stats_display_width( + stats_cpu, without_option=(screen_x < 80)) quicklook_adapt = 108 l = cpu_width # MEM & SWAP & LOAD - l += self.get_stats_display_width(stats_mem, without_option=(screen_x < 100)) + l += self.get_stats_display_width(stats_mem, + without_option=(screen_x < 100)) l += self.get_stats_display_width(stats_memswap) l += self.get_stats_display_width(stats_load) # Quicklook plugin size is dynamic @@ -545,9 +561,9 @@ class _GlancesCurses(object): # Backup line position self.saved_line = self.next_line - # ============================================================= + # ================================================================== # 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_raid @@ -718,7 +734,7 @@ class _GlancesCurses(object): # Exit if: # - the plugin_stats message is empty # - the display tag = False - if not plugin_stats['msgdict'] or not plugin_stats['display']: + if plugin_stats is None or not plugin_stats['msgdict'] or not plugin_stats['display']: # Exit return 0 diff --git a/glances/plugins/glances_ip.py b/glances/plugins/glances_ip.py new file mode 100644 index 00000000..200723f9 --- /dev/null +++ b/glances/plugins/glances_ip.py @@ -0,0 +1,120 @@ +# -*- coding: utf-8 -*- +# +# This file is part of Glances. +# +# Copyright (C) 2015 Nicolargo +# +# 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 . + +"""IP plugin.""" + +# Import system libs +try: + import netifaces + netifaces_tag = True +except ImportError: + netifaces_tag = False + +# Import Glances libs +from glances.core.glances_logging import logger +from glances.plugins.glances_plugin import GlancesPlugin + + +class Plugin(GlancesPlugin): + + """Glances' IP Plugin. + + stats is a dict + """ + + 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 IP stats using the input method. + + Stats is dict + """ + # Reset stats + self.reset() + + if self.get_input() == 'local' and netifaces_tag: + # Update stats using the netifaces lib + try: + default_gw = netifaces.gateways()['default'][netifaces.AF_INET] + except KeyError: + logger.debug("Can not grab the default gateway") + else: + try: + self.stats['address'] = netifaces.ifaddresses(default_gw[1])[netifaces.AF_INET][0]['addr'] + self.stats['mask'] = netifaces.ifaddresses(default_gw[1])[netifaces.AF_INET][0]['netmask'] + self.stats['mask_cidr'] = self.ip_to_cidr(self.stats['mask']) + self.stats['gateway'] = netifaces.gateways()['default'][netifaces.AF_INET][0] + except KeyError as e: + logger.debug("Can not grab IP information (%s)".format(e)) + + elif self.get_input() == 'snmp': + # Not implemented yet + pass + + # Update the view + self.update_views() + + return self.stats + + def update_views(self): + """Update stats views""" + # Call the father's method + GlancesPlugin.update_views(self) + + # Add specifics informations + # Optional + for key in self.stats.keys(): + self.views[key]['optional'] = True + + 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_ip: + return ret + + # Build the string message + msg = _(' - IP') + ret.append(self.curse_add_line(msg, 'TITLE')) + msg = ' {0:}/{1}'.format(self.stats['address'], self.stats['mask_cidr']) + ret.append(self.curse_add_line(msg)) + + return ret + + @staticmethod + def ip_to_cidr(ip): + # Convert IP address to CIDR + # Exemple: '255.255.255.0' will return 24 + return sum(map(lambda x: int(x) << 8, ip.split('.'))) / 8128