diff --git a/NEWS b/NEWS index 64f365fab7c2d7afeb2ca24eeba27609efb0ede7..866bf8a5859750c2822747286016b2018bec69f9 100644 --- a/NEWS +++ b/NEWS @@ -38,6 +38,13 @@ Bugs corrected: * On Windows, Glances try to display unexisting Load stats (issue #871) * Top 3 processes are back in the alert summary +Version 2.6.2 +============= + +Bugs corrected: + + * Crash with Docker 1.11 (issue #848) + Version 2.6.1 ============= diff --git a/conf/glances.conf b/conf/glances.conf index b100ee14a521de382783f31cc4ea3f7331499faf..407c887a7c724794e73425f6fda0cb0eca243541 100644 --- a/conf/glances.conf +++ b/conf/glances.conf @@ -181,29 +181,31 @@ mem_critical=90 [ports] # Ports scanner plugin configuration -# Interval in second between scan +# Interval in second between two scans refresh=30 -# Set the default timeout for a scan (can be overwrite in the scan list) +# Set the default timeout (in second) for a scan (can be overwrite in the scan list) timeout=3 -# If True, add the default gateway on top of the scan list +# If port_default_gateway is True, add the default gateway on top of the scan list port_default_gateway=True -# Define the scan list -# host (name or IP) is mandatory -# port (TCP port number) is optional (if not set, use ICMP) -# description is optional (if not set, define to host:port) -port_1_host=192.168.0.1 -port_1_port=80 -port_1_description=Home Box -port_2_host=www.free.fr -port_2_description=My ISP -port_3_host=www.google.com -port_3_description=Internet ICMP -port_4_host=www.google.com -port_4_description=Internet Web -port_4_port=80 -port_5_host=blog.nicolargo.com -port_5_description=My blog -port_5_port=80 +# Define the scan list (1 < x < 255) +# port_x_host (name or IP) is mandatory +# port_x_port (TCP port number) is optional (if not set, use ICMP) +# port_x_description is optional (if not set, define to host:port) +# port_x_timeout is optional and overwrite the default timeout value +# port_x_rtt_warning is optional and defines the warning threshold in ms +#port_1_host=192.168.0.1 +#port_1_port=80 +#port_1_description=Home Box +#port_1_timeout=1 +#port_2_host=www.free.fr +#port_2_description=My ISP +#port_3_host=www.google.com +#port_3_description=Internet ICMP +#port_3_rtt_warning=1000 +#port_4_host=www.google.com +#port_4_description=Internet Web +#port_4_port=80 +#port_4_rtt_warning=1000 ############################################################################## # Client/server diff --git a/docs/aoa/ports.rst b/docs/aoa/ports.rst index c615d84d9fb7539d53468639d57477d6ad9ad0f4..7e25a38ba0ba7ad25cee0ad4a91b3136d9557311 100644 --- a/docs/aoa/ports.rst +++ b/docs/aoa/ports.rst @@ -17,20 +17,28 @@ The list should be define in the ``[ports]`` section of the Glances configuratio [ports] # Ports scanner plugin configuration - # Interval in second between scan + # Interval in second between two scans refresh=30 - # Set the default timeout for a scan (can be overwrite in the scan list) + # Set the default timeout (in second) for a scan (can be overwrite in the scan list) timeout=3 - # If True, add the default gateway on top of the scan list + # If port_default_gateway is True, add the default gateway on top of the scan list port_default_gateway=True - # Define the scan list - # host (name or IP) is mandatory - # port (TCP port number) is optional (if not set, use ICMP) - # description is optional (if not set, define to host:port) + # Define the scan list (1 < x < 255) + # port_x_host (name or IP) is mandatory + # port_x_port (TCP port number) is optional (if not set, use ICMP) + # port_x_description is optional (if not set, define to host:port) + # port_x_timeout is optional and overwrite the default timeout value + # port_x_rtt_warning is optional and defines the warning threshold in ms port_1_host=192.168.0.1 port_1_port=80 port_1_description=Home Box + port_1_timeout=1 port_2_host=www.free.fr port_2_description=My ISP port_3_host=www.google.com - port_3_description=Internet + port_3_description=Internet ICMP + port_3_rtt_warning=1000 + port_4_host=www.google.com + port_4_description=Internet Web + port_4_port=80 + port_4_rtt_warning=1000 diff --git a/glances/plugins/glances_docker.py b/glances/plugins/glances_docker.py index fc8964fdc1fd490e76ecd389042ed0ba25c12ef4..5b75832b7b90ff64850584bafde8a495bf76af76 100644 --- a/glances/plugins/glances_docker.py +++ b/glances/plugins/glances_docker.py @@ -68,9 +68,10 @@ class Plugin(GlancesPlugin): def exit(self): """Overwrite the exit method to close threads""" - logger.debug("Stop the Docker plugin") for t in itervalues(self.thread_list): t.stop() + # Call the father class + super(Plugin, self).exit() def get_key(self): """Return the key of the list.""" diff --git a/glances/plugins/glances_ports.py b/glances/plugins/glances_ports.py index 7b2e9e418e8926ded21a7c5ad578e5d523c09a62..515771ba927c8d24354675364cb9738fafca80b0 100644 --- a/glances/plugins/glances_ports.py +++ b/glances/plugins/glances_ports.py @@ -24,6 +24,7 @@ import subprocess import threading import socket import types +import time from glances.globals import WINDOWS from glances.ports_list import GlancesPortsList @@ -51,6 +52,16 @@ class Plugin(GlancesPlugin): # Init global Timer self.timer_ports = Timer(0) + # Global Thread running all the scans + self._thread = None + + def exit(self): + """Overwrite the exit method to close threads""" + if self._thread is not None: + self._thread.stop() + # Call the father class + super(Plugin, self).exit() + @GlancesPlugin._log_result_decorator def update(self): """Update the ports list.""" @@ -59,14 +70,20 @@ class Plugin(GlancesPlugin): return {} if self.input_method == 'local': - # Only refresh every refresh seconds (define in the configuration file) - if self.timer_ports.finished(): + # Only refresh: + # * if there is not other scanning thread + # * every refresh seconds (define in the configuration file) + if self._thread is None: + thread_is_running = False + else: + thread_is_running = self._thread.isAlive() + if self.timer_ports.finished() and not thread_is_running: # Run ports scanner - thread = threading.Thread(target=self._port_scan_all, args=(self.stats,)) - thread.start() + self._thread = ThreadScanner(self.stats) + self._thread.start() # Restart timer if len(self.stats) > 0: - self.timer_ports = Timer(int(self.stats[0]['refresh'])) + self.timer_ports = Timer(self.stats[0]['refresh']) else: self.timer_ports = Timer(0) else: @@ -80,9 +97,12 @@ class Plugin(GlancesPlugin): if port['status'] is None: return 'CAREFUL' - - if port['status'] == 0: + elif port['status'] == 0: return 'CRITICAL' + elif isinstance(port['status'], (float, int)) and \ + port['rtt_warning'] is not None and \ + port['status'] > port['rtt_warning']: + return 'WARNING' return 'OK' @@ -125,6 +145,59 @@ class Plugin(GlancesPlugin): """Scan all host/port of the given stats""" for p in stats: self._port_scan(p) + # Had to wait between two scans + # If not, result are not ok + time.sleep(1) + + +class ThreadScanner(threading.Thread): + """ + Specific thread for the port scanner. + + stats is a list of dict + """ + + def __init__(self, stats): + """Init the class""" + logger.debug("ports plugin - Create thread for scan list {}".format(stats)) + super(ThreadScanner, self).__init__() + # Event needed to stop properly the thread + self._stopper = threading.Event() + # The class return the stats as a list of dict + self._stats = stats + # Is part of Ports plugin + self.plugin_name = "ports" + + def run(self): + """Function called to grab stats. + Infinite loop, should be stopped by calling the stop() method""" + + for p in self._stats: + self._port_scan(p) + if self.stopped(): + break + # Had to wait between two scans + # If not, result are not ok + time.sleep(1) + + @property + def stats(self): + """Stats getter""" + return self._stats + + @stats.setter + def stats(self, value): + """Stats setter""" + self._stats = value + + def stop(self, timeout=None): + """Stop the thread""" + logger.debug("ports plugin - Close thread for scan list {}".format(self._stats)) + self._stopper.set() + + def stopped(self): + """Return True is the thread is stopped""" + return self._stopper.isSet() def _port_scan(self, port): """Scan the port structure (dict) and update the status key""" @@ -162,7 +235,6 @@ class Plugin(GlancesPlugin): except Exception as e: logger.debug("{0}: Error while pinging host ({2})".format(self.plugin_name, port['host'], e)) - logger.info("Ping {} ({}) in {} second".format(port['host'], self._resolv_name(port['host']), port['status'])) return ret def _port_scan_tcp(self, port): @@ -171,7 +243,7 @@ class Plugin(GlancesPlugin): # Create and configure the scanning socket try: - socket.setdefaulttimeout(int(port['timeout'])) + socket.setdefaulttimeout(port['timeout']) _socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) except Exception as e: logger.debug("{0}: Error while creating scanning socket".format(self.plugin_name)) diff --git a/glances/ports_list.py b/glances/ports_list.py index af7493f041937364f331ad2b588bc7f80ad6c2f4..9c10c386727d28eba0c5a9b0c2f03ef48c503678 100644 --- a/glances/ports_list.py +++ b/glances/ports_list.py @@ -61,8 +61,8 @@ class GlancesPortsList(object): else: logger.debug("Start reading the [%s] section in the configuration file" % self._section) - refresh = config.get_value(self._section, 'refresh', default=self._default_refresh) - timeout = config.get_value(self._section, 'timeout', default=self._default_timeout) + refresh = int(config.get_value(self._section, 'refresh', default=self._default_refresh)) + timeout = int(config.get_value(self._section, 'timeout', default=self._default_timeout)) # Add default gateway on top of the ports_list lits default_gateway = config.get_value(self._section, 'port_default_gateway', default='False') @@ -75,6 +75,7 @@ class GlancesPortsList(object): new_port['refresh'] = refresh new_port['timeout'] = timeout new_port['status'] = None + new_port['rtt_warning'] = None logger.debug("Add default gateway %s to the static list" % (new_port['host'])) ports_list.append(new_port) @@ -105,9 +106,17 @@ class GlancesPortsList(object): new_port['refresh'] = refresh # Timeout in second - new_port['timeout'] = config.get_value(self._section, - '%stimeout' % postfix, - default=timeout) + new_port['timeout'] = int(config.get_value(self._section, + '%stimeout' % postfix, + default=timeout)) + + # RTT warning + new_port['rtt_warning'] = config.get_value(self._section, + '%srtt_warning' % postfix, + default=None) + if new_port['rtt_warning'] is not None: + # Convert to second + new_port['rtt_warning'] = int(new_port['rtt_warning']) / 1000.0 # Add the server to the list logger.debug("Add port %s:%s to the static list" % (new_port['host'], new_port['port']))