def __init__(self): """Init sensors stats.""" # Temperatures try: # psutil>=5.1.0 is required self.stemps = psutil.sensors_temperatures() except AttributeError: logger.warning( "PsUtil 5.1.0 or higher is needed to grab temperatures sensors" ) self.initok = False self.stemps = {} else: self.initok = True # Fans try: # psutil>=5.2.0 is required self.sfans = psutil.sensors_fans() except AttributeError: logger.warning( "PsUtil 5.2.0 or higher is needed to grab fans sensors") self.sfans = {} # Init the stats self.reset()
def check_snmp(self): """Chek if SNMP is available on the server.""" # Import the SNMP client class from glances.snmp import GlancesSNMPClient # Create an instance of the SNMP client clientsnmp = GlancesSNMPClient(host=self.args.client, port=self.args.snmp_port, version=self.args.snmp_version, community=self.args.snmp_community, user=self.args.snmp_user, auth=self.args.snmp_auth) # If we cannot grab the hostname, then exit... ret = clientsnmp.get_by_oid("1.3.6.1.2.1.1.5.0") != {} if ret: # Get the OS name (need to grab the good OID...) oid_os_name = clientsnmp.get_by_oid("1.3.6.1.2.1.1.1.0") try: self.system_name = self.get_system_name( oid_os_name['1.3.6.1.2.1.1.1.0']) logger.info("SNMP system name detected: {}".format( self.system_name)) except KeyError: self.system_name = None logger.warning("Cannot detect SNMP system name") return ret
def check_snmp(self): """Chek if SNMP is available on the server.""" # Import the SNMP client class from glances.snmp import GlancesSNMPClient # Create an instance of the SNMP client clientsnmp = GlancesSNMPClient(host=self.args.client, port=self.args.snmp_port, version=self.args.snmp_version, community=self.args.snmp_community, user=self.args.snmp_user, auth=self.args.snmp_auth) # If we cannot grab the hostname, then exit... ret = clientsnmp.get_by_oid("1.3.6.1.2.1.1.5.0") != {} if ret: # Get the OS name (need to grab the good OID...) oid_os_name = clientsnmp.get_by_oid("1.3.6.1.2.1.1.1.0") try: self.system_name = self.get_system_name(oid_os_name['1.3.6.1.2.1.1.1.0']) logger.info("SNMP system name detected: {}".format(self.system_name)) except KeyError: self.system_name = None logger.warning("Cannot detect SNMP system name") return ret
def __init__(self): """Init sensors stats.""" # Temperatures self.init_temp = False self.stemps = {} try: # psutil>=5.1.0 is required self.stemps = psutil.sensors_temperatures() except AttributeError: logger.warning("PsUtil 5.1.0 or higher is needed to grab temperatures sensors") except OSError as e: # FreeBSD: If oid 'hw.acpi.battery' not present, Glances wont start #1055 logger.error("Can not grab temperatures sensors ({})".format(e)) else: self.init_temp = True # Fans self.init_fan = False self.sfans = {} try: # psutil>=5.2.0 is required self.sfans = psutil.sensors_fans() except AttributeError: logger.warning("PsUtil 5.2.0 or higher is needed to grab fans sensors") except OSError as e: logger.error("Can not grab fans sensors ({})".format(e)) else: self.init_fan = True # !!! Disable Fan: High CPU consumption is PSUtil 5.2.0 # Delete the following line when corrected self.init_fan = False # Init the stats self.reset()
def __update_stats(self, server): """ Update stats for the given server (picked from the server list) """ # Get the server URI uri = self.__get_uri(server) # Try to connect to the server t = GlancesClientTransport() t.set_timeout(3) # Get common stats try: s = ServerProxy(uri, transport=t) except Exception as e: logger.warning( "Client browser couldn't create socket {}: {}".format(uri, e)) else: # Mandatory stats try: # CPU% cpu_percent = 100 - json.loads(s.getCpu())['idle'] server['cpu_percent'] = '{:.1f}'.format(cpu_percent) # MEM% server['mem_percent'] = json.loads(s.getMem())['percent'] # OS (Human Readable name) server['hr_name'] = json.loads(s.getSystem())['hr_name'] except (socket.error, Fault, KeyError) as e: logger.debug("Error while grabbing stats form {}: {}".format( uri, e)) server['status'] = 'OFFLINE' except ProtocolError as e: if e.errcode == 401: # Error 401 (Authentication failed) # Password is not the good one... server['password'] = None server['status'] = 'PROTECTED' else: server['status'] = 'OFFLINE' logger.debug("Cannot grab stats from {} ({} {})".format( uri, e.errcode, e.errmsg)) else: # Status server['status'] = 'ONLINE' # Optional stats (load is not available on Windows OS) try: # LOAD load_min5 = json.loads(s.getLoad())['min5'] server['load_min5'] = '{:.2f}'.format(load_min5) except Exception as e: logger.warning( "Error while grabbing stats form {}: {}".format( uri, e)) return server
def load(self, config): """Load the server list from the configuration file.""" server_list = [] if config is None: logger.debug( "No configuration file available. Cannot load server list.") elif not config.has_section(self._section): logger.warning( "No [%s] section in the configuration file. Cannot load server list." % self._section) else: logger.info( "Start reading the [%s] section in the configuration file" % self._section) for i in range(1, 256): new_server = {} postfix = 'server_%s_' % str(i) # Read the server name (mandatory) for s in ['name', 'port', 'alias']: new_server[s] = config.get_value(self._section, '%s%s' % (postfix, s)) if new_server['name'] is not None: # Manage optionnal information if new_server['port'] is None: new_server['port'] = '61209' new_server['username'] = '******' # By default, try empty (aka no) password new_server['password'] = '' try: new_server['ip'] = gethostbyname(new_server['name']) except gaierror as e: logger.error( "Cannot get IP address for server %s (%s)" % (new_server['name'], e)) continue new_server[ 'key'] = new_server['name'] + ':' + new_server['port'] # Default status is 'UNKNOWN' new_server['status'] = 'UNKNOWN' # Server type is 'STATIC' new_server['type'] = 'STATIC' # Add the server to the list logger.debug("Add server %s to the static list" % new_server['name']) server_list.append(new_server) # Server list loaded logger.info("%s server(s) loaded from the configuration file" % len(server_list)) logger.debug("Static server list: %s" % server_list) return server_list
def __update_stats(self, server): """ Update stats for the given server (picked from the server list) """ # Get the server URI uri = self.__get_uri(server) # Try to connect to the server t = GlancesClientTransport() t.set_timeout(3) # Get common stats try: s = ServerProxy(uri, transport=t) except Exception as e: logger.warning( "Client browser couldn't create socket {}: {}".format(uri, e)) else: # Mandatory stats try: # CPU% cpu_percent = 100 - json.loads(s.getCpu())['idle'] server['cpu_percent'] = '{:.1f}'.format(cpu_percent) # MEM% server['mem_percent'] = json.loads(s.getMem())['percent'] # OS (Human Readable name) server['hr_name'] = json.loads(s.getSystem())['hr_name'] except (socket.error, Fault, KeyError) as e: logger.debug( "Error while grabbing stats form {}: {}".format(uri, e)) server['status'] = 'OFFLINE' except ProtocolError as e: if e.errcode == 401: # Error 401 (Authentication failed) # Password is not the good one... server['password'] = None server['status'] = 'PROTECTED' else: server['status'] = 'OFFLINE' logger.debug("Cannot grab stats from {} ({} {})".format(uri, e.errcode, e.errmsg)) else: # Status server['status'] = 'ONLINE' # Optional stats (load is not available on Windows OS) try: # LOAD load_min5 = json.loads(s.getLoad())['min5'] server['load_min5'] = '{:.2f}'.format(load_min5) except Exception as e: logger.warning( "Error while grabbing stats form {}: {}".format(uri, e)) return server
def load_config(self, config): """Load AMP parameters from the configuration file.""" # Read AMP confifuration. # For ex, the AMP foo should have the following section: # # [foo] # enable=true # regex=\/usr\/bin\/nginx # refresh=60 # # and optionnaly: # # one_line=false # option1=opt1 # ... # amp_section = 'amp_' + self.amp_name if (hasattr(config, 'has_section') and config.has_section(amp_section)): logger.debug("{}: Load configuration".format(self.NAME)) for param, _ in config.items(amp_section): try: self.configs[param] = config.get_float_value( amp_section, param) except ValueError: self.configs[param] = config.get_value(amp_section, param).split(',') if len(self.configs[param]) == 1: self.configs[param] = self.configs[param][0] logger.debug("{}: Load parameter: {} = {}".format( self.NAME, param, self.configs[param])) else: logger.debug( "{}: Can not find section {} in the configuration file".format( self.NAME, self.amp_name)) return False # enable, regex and refresh are mandatories # if not configured then AMP is disabled if self.enable(): for k in ['regex', 'refresh']: if k not in self.configs: logger.warning( "{}: Can not find configuration key {} in section {}". format(self.NAME, k, self.amp_name)) self.configs['enable'] = 'false' else: logger.debug("{} is disabled".format(self.NAME)) # Init the count to 0 self.configs['count'] = 0 return self.enable()
def update(self, stats, duration=3, cs_status=None, return_to_browser=False): """Update the screen. INPUT stats: Stats database to display duration: duration of the loop cs_status: "None": standalone or server mode "Connected": Client is connected to the server "Disconnected": Client is disconnected from the server return_to_browser: True: Do not exist, return to the browser list False: Exit and return to the shell OUTPUT True: Exit key has been pressed False: Others cases... """ # Flush display self.flush(stats, cs_status=cs_status) # If the duration is < 0 (update + export time > refresh_time) # Then display the interface and log a message if duration <= 0: logger.warning('Update and export time higher than refresh_time.') duration = 0.1 # Wait duration (in s) time exitkey = False countdown = Timer(duration) # Set the default timeout (in ms) for the getch method self.term_window.timeout(int(duration * 1000)) while not countdown.finished() and not exitkey: # Getkey pressedkey = self.__catch_key(return_to_browser=return_to_browser) # Is it an exit key ? exitkey = (pressedkey == ord('\x1b') or pressedkey == ord('q')) if not exitkey and pressedkey > -1: # Redraw display self.flush(stats, cs_status=cs_status) # Overwrite the timeout with the countdown self.term_window.timeout(int(countdown.get() * 1000)) return exitkey
def fetch(self): """Fetch the data from hddtemp daemon.""" # Taking care of sudden deaths/stops of hddtemp daemon try: sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sck.connect((self.host, self.port)) data = sck.recv(4096) except socket.error as e: logger.warning("Can not connect to an HDDtemp server ({0}:{1} => {2})".format(self.host, self.port, e)) logger.debug("Disable the HDDtemp module. Use the --disable-hddtemp to hide the previous message.") self.args.disable_hddtemp = True data = "" finally: sck.close() return data
def load_config(self, config): """Load AMP parameters from the configuration file.""" # Read AMP confifuration. # For ex, the AMP foo should have the following section: # # [foo] # enable=true # regex=\/usr\/bin\/nginx # refresh=60 # # and optionnaly: # # one_line=false # option1=opt1 # ... # amp_section = 'amp_' + self.amp_name if (hasattr(config, 'has_section') and config.has_section(amp_section)): logger.debug("AMP - {}: Load configuration".format(self.NAME)) for param, _ in config.items(amp_section): try: self.configs[param] = config.get_float_value(amp_section, param) except ValueError: self.configs[param] = config.get_value(amp_section, param).split(',') if len(self.configs[param]) == 1: self.configs[param] = self.configs[param][0] logger.debug("AMP - {}: Load parameter: {} = {}".format(self.NAME, param, self.configs[param])) else: logger.debug("AMP - {}: Can not find section {} in the configuration file".format(self.NAME, self.amp_name)) return False # enable, regex and refresh are mandatories # if not configured then AMP is disabled if self.enable(): for k in ['regex', 'refresh']: if k not in self.configs: logger.warning("AMP - {}: Can not find configuration key {} in section {}".format(self.NAME, k, self.amp_name)) self.configs['enable'] = 'false' else: logger.debug("AMP - {} is disabled".format(self.NAME)) # Init the count to 0 self.configs['count'] = 0 return self.enable()
def load(self, config): """Load the server list from the configuration file.""" server_list = [] if config is None: logger.warning("No configuration file available. Cannot load server list.") elif not config.has_section(self._section): logger.warning("No [%s] section in the configuration file. Cannot load server list." % self._section) else: logger.info("Start reading the [%s] section in the configuration file" % self._section) for i in range(1, 256): new_server = {} postfix = "server_%s_" % str(i) # Read the server name (mandatory) for s in ["name", "port", "alias"]: new_server[s] = config.get_value(self._section, "%s%s" % (postfix, s)) if new_server["name"] is not None: # Manage optionnal information if new_server["port"] is None: new_server["port"] = "61209" new_server["username"] = "******" # By default, try empty (aka no) password new_server["password"] = "" try: new_server["ip"] = gethostbyname(new_server["name"]) except gaierror as e: logger.error("Cannot get IP address for server %s (%s)" % (new_server["name"], e)) continue new_server["key"] = new_server["name"] + ":" + new_server["port"] # Default status is 'UNKNOWN' new_server["status"] = "UNKNOWN" # Server type is 'STATIC' new_server["type"] = "STATIC" # Add the server to the list logger.debug("Add server %s to the static list" % new_server["name"]) server_list.append(new_server) # Server list loaded logger.info("%s server(s) loaded from the configuration file" % len(server_list)) logger.debug("Static server list: %s" % server_list) return server_list
def load(self, config): """Load the server list from the configuration file.""" server_list = [] if config is None: logger.debug("No configuration file available. Cannot load server list.") elif not config.has_section(self._section): logger.warning("No [%s] section in the configuration file. Cannot load server list." % self._section) else: logger.info("Start reading the [%s] section in the configuration file" % self._section) for i in range(1, 256): new_server = {} postfix = 'server_%s_' % str(i) # Read the server name (mandatory) for s in ['name', 'port', 'alias']: new_server[s] = config.get_value(self._section, '%s%s' % (postfix, s)) if new_server['name'] is not None: # Manage optionnal information if new_server['port'] is None: new_server['port'] = '61209' new_server['username'] = '******' # By default, try empty (aka no) password new_server['password'] = '' try: new_server['ip'] = gethostbyname(new_server['name']) except gaierror as e: logger.error("Cannot get IP address for server %s (%s)" % (new_server['name'], e)) continue new_server['key'] = new_server['name'] + ':' + new_server['port'] # Default status is 'UNKNOWN' new_server['status'] = 'UNKNOWN' # Server type is 'STATIC' new_server['type'] = 'STATIC' # Add the server to the list logger.debug("Add server %s to the static list" % new_server['name']) server_list.append(new_server) # Server list loaded logger.info("%s server(s) loaded from the configuration file" % len(server_list)) logger.debug("Static server list: %s" % server_list) return server_list
def load(self, config): """Load the password from the configuration file.""" password_dict = {} if config is None: logger.warning("No configuration file available. Cannot load password list.") elif not config.has_section(self._section): logger.warning("No [%s] section in the configuration file. Cannot load password list." % self._section) else: logger.info("Start reading the [%s] section in the configuration file" % self._section) password_dict = dict(config.items(self._section)) # Password list loaded logger.info("%s password(s) loaded from the configuration file" % len(password_dict)) logger.debug("Password dictionary: %s" % password_dict) return password_dict
def __init__(self): """Init sensors stats.""" # Temperatures self.init_temp = False self.stemps = {} try: # psutil>=5.1.0 is required self.stemps = psutil.sensors_temperatures() except AttributeError: logger.warning( "PsUtil 5.1.0 or higher is needed to grab temperatures sensors" ) except OSError as e: # FreeBSD: If oid 'hw.acpi.battery' not present, Glances wont start #1055 logger.error("Can not grab temperatures sensors ({})".format(e)) else: self.init_temp = True # Fans self.init_fan = False self.sfans = {} try: # psutil>=5.2.0 is required self.sfans = psutil.sensors_fans() except AttributeError: logger.warning( "PsUtil 5.2.0 or higher is needed to grab fans sensors") except OSError as e: logger.error("Can not grab fans sensors ({})".format(e)) else: self.init_fan = True # !!! Disable Fan: High CPU consumption is PSUtil 5.2.0 # Delete the following line when corrected self.init_fan = False # Init the stats self.reset()
def add_service(self, zeroconf, srv_type, srv_name): """Method called when a new Zeroconf client is detected. Return True if the zeroconf client is a Glances server Note: the return code will never be used """ if srv_type != zeroconf_type: return False logger.debug("Check new Zeroconf server: %s / %s" % (srv_type, srv_name)) info = zeroconf.get_service_info(srv_type, srv_name) if info: new_server_ip = socket.inet_ntoa(info.address) new_server_port = info.port # Add server to the global dict self.servers.add_server(srv_name, new_server_ip, new_server_port) logger.info("New Glances server detected (%s from %s:%s)" % (srv_name, new_server_ip, new_server_port)) else: logger.warning( "New Glances server detected, but Zeroconf info failed to be grabbed") return True
def load(self, config): """Load the password from the configuration file.""" password_dict = [] if config is None: logger.warning( "No configuration file available. Cannot load password list.") elif not config.has_section(self._section): logger.warning( "No [%s] section in the configuration file. Cannot load password list." % self._section) else: logger.info( "Start reading the [%s] section in the configuration file" % self._section) password_dict = dict(config.items(self._section)) # Password list loaded logger.info("%s password(s) loaded from the configuration file" % len(password_dict)) logger.debug("Password dictionary: %s" % password_dict) return password_dict
def load_configs(self): """Load the AMP configuration files.""" if self.config is None: return False # Display a warning (deprecated) message if the monitor section exist if "monitor" in self.config.sections(): logger.warning( "A deprecated [monitor] section exists in the Glances configuration file. You should use the new Applications Monitoring Process module instead (http://glances.readthedocs.io/en/develop/aoa/amps.html)." ) header = "glances_" # For each AMP scrip, call the load_config method for s in self.config.sections(): if s.startswith("amp_"): # An AMP section exists in the configuration file # If an AMP script exist in the glances/amps folder, use it amp_conf_name = s[4:] amp_script = os.path.join(amps_path, header + s[4:] + ".py") if not os.path.exists(amp_script): # If not, use the default script amp_script = os.path.join(amps_path, "glances_default.py") try: amp = __import__(os.path.basename(amp_script)[:-3]) except ImportError as e: logger.warning( "Cannot load {}, you need to install an external Python package ({})" .format(os.path.basename(amp_script), e)) except Exception as e: logger.warning("Cannot load {} ({})".format( os.path.basename(amp_script), e)) else: # Add the AMP to the dictionary # The key is the AMP name # for example, the file glances_xxx.py # generate self._amps_list["xxx"] = ... self.__amps_dict[amp_conf_name] = amp.Amp( name=amp_conf_name, args=self.args) # Load the AMP configuration self.__amps_dict[amp_conf_name].load_config(self.config) # Log AMPs list logger.debug("AMPs list: {}".format(self.getList())) return True
def load_configs(self): """Load the AMP configuration files.""" if self.config is None: return False # Display a warning (deprecated) message if the monitor section exist if "monitor" in self.config.sections(): logger.warning("A deprecated [monitor] section exists in the Glances configuration file. You should use the new Applications Monitoring Process module instead (http://glances.readthedocs.io/en/develop/aoa/amps.html).") header = "glances_" # For each AMP scrip, call the load_config method for s in self.config.sections(): if s.startswith("amp_"): # An AMP section exists in the configuration file # If an AMP script exist in the glances/amps folder, use it amp_conf_name = s[4:] amp_script = os.path.join(amps_path, header + s[4:] + ".py") if not os.path.exists(amp_script): # If not, use the default script amp_script = os.path.join(amps_path, "glances_default.py") try: amp = __import__(os.path.basename(amp_script)[:-3]) except ImportError as e: logger.warning("Cannot load {}, you need to install an external Python package ({})".format(os.path.basename(amp_script), e)) except Exception as e: logger.warning("Cannot load {} ({})".format(os.path.basename(amp_script), e)) else: # Add the AMP to the dictionary # The key is the AMP name # for example, the file glances_xxx.py # generate self._amps_list["xxx"] = ... self.__amps_dict[amp_conf_name] = amp.Amp(name=amp_conf_name, args=self.args) # Load the AMP configuration self.__amps_dict[amp_conf_name].load_config(self.config) # Log AMPs list logger.debug("AMPs list: {}".format(self.getList())) return True
# 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.""" from glances.compat import iterkeys from glances.logger import logger from glances.plugins.glances_plugin import GlancesPlugin # Import plugin specific dependency try: from pymdstat import MdStat except ImportError as e: import_error_tag = True logger.warning( "Missing Python Lib ({}), Raid plugin is disabled".format(e)) else: import_error_tag = False class Plugin(GlancesPlugin): """Glances RAID plugin. stats is a dict (see pymdstat documentation) """ def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args) # We want to display the stat in the curse interface self.display_curse = True
import operator from glances.compat import nativestr from glances.logger import logger from glances.plugins.glances_plugin import GlancesPlugin import psutil # Use the Wifi Python lib (https://pypi.python.org/pypi/wifi) # Linux-only try: from wifi.scan import Cell from wifi.exceptions import InterfaceError except ImportError as e: import_error_tag = True logger.warning("Missing Python Lib ({}), Wifi plugin is disabled".format(e)) else: import_error_tag = False class Plugin(GlancesPlugin): """Glances Wifi plugin. Get stats of the current Wifi hotspots. """ def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args, stats_init_value=[])
import numbers from glances.globals import WINDOWS, MACOS, BSD from glances.ports_list import GlancesPortsList from glances.web_list import GlancesWebList from glances.timer import Timer, Counter from glances.compat import bool_type from glances.logger import logger from glances.plugins.glances_plugin import GlancesPlugin try: import requests requests_tag = True except ImportError as e: requests_tag = False logger.warning("Missing Python Lib ({}), Ports plugin is limited to port scanning".format(e)) class Plugin(GlancesPlugin): """Glances ports scanner plugin.""" def __init__(self, args=None, config=None): """Init the plugin.""" super(Plugin, self).__init__(args=args, stats_init_value=[]) self.args = args self.config = config # We want to display the stat in the curse interface self.display_curse = True
"""Quicklook plugin.""" from glances.cpu_percent import cpu_percent from glances.logger import logger from glances.outputs.glances_bars import Bar from glances.plugins.glances_plugin import GlancesPlugin import psutil # Import plugin specific dependency try: from cpuinfo import cpuinfo except ImportError as e: cpuinfo_tag = False logger.warning("Missing Python Lib ({}), Quicklook plugin will not display CPU info".format(e)) else: cpuinfo_tag = True class Plugin(GlancesPlugin): """Glances quicklook plugin. 'stats' is a dictionary. """ def __init__(self, args=None): """Init the quicklook plugin.""" super(Plugin, self).__init__(args=args) # We want to display the stat in the curse interface
def __serve_forever(self): """Main client loop.""" while True: # No need to update the server list # It's done by the GlancesAutoDiscoverListener class (autodiscover.py) # Or define staticaly in the configuration file (module static_list.py) # For each server in the list, grab elementary stats (CPU, LOAD, MEM, OS...) # logger.debug(self.get_servers_list()) try: for v in self.get_servers_list(): # Do not retreive stats for statics server # Why ? Because for each offline servers, the timeout will be reached # So ? The curse interface freezes if v['type'] == 'STATIC' and v['status'] in [ 'UNKNOWN', 'SNMP', 'OFFLINE' ]: continue # Get the server URI uri = self.__get_uri(v) # Try to connect to the server t = GlancesClientTransport() t.set_timeout(3) # Get common stats try: s = ServerProxy(uri, transport=t) except Exception as e: logger.warning( "Client browser couldn't create socket {0}: {1}". format(uri, e)) else: # Mandatory stats try: # CPU% cpu_percent = 100 - json.loads(s.getCpu())['idle'] v['cpu_percent'] = '{0:.1f}'.format(cpu_percent) # MEM% v['mem_percent'] = json.loads( s.getMem())['percent'] # OS (Human Readable name) v['hr_name'] = json.loads(s.getSystem())['hr_name'] except (socket.error, Fault, KeyError) as e: logger.debug( "Error while grabbing stats form {0}: {1}". format(uri, e)) v['status'] = 'OFFLINE' except ProtocolError as e: if e.errcode == 401: # Error 401 (Authentication failed) # Password is not the good one... v['password'] = None v['status'] = 'PROTECTED' else: v['status'] = 'OFFLINE' logger.debug( "Cannot grab stats from {0} ({1} {2})".format( uri, e.errcode, e.errmsg)) else: # Status v['status'] = 'ONLINE' # Optional stats (load is not available on Windows OS) try: # LOAD load_min5 = json.loads(s.getLoad())['min5'] v['load_min5'] = '{0:.2f}'.format(load_min5) except Exception as e: logger.warning( "Error while grabbing stats form {0}: {1}". format(uri, e)) # List can change size during iteration... except RuntimeError: logger.debug( "Server list dictionnary change inside the loop (wait next update)" ) # Update the screen (list or Glances client) if self.screen.active_server is None: # Display the Glances browser self.screen.update(self.get_servers_list()) else: # Display the Glances client for the selected server logger.debug("Selected server: {0}".format( self.get_servers_list()[self.screen.active_server])) # Connection can take time # Display a popup self.screen.display_popup('Connect to {0}:{1}'.format( v['name'], v['port']), duration=1) # A password is needed to access to the server's stats if self.get_servers_list()[ self.screen.active_server]['password'] is None: # First of all, check if a password is available in the [passwords] section clear_password = self.password.get_password(v['name']) if (clear_password is None or self.get_servers_list() [self.screen.active_server]['status'] == 'PROTECTED'): # Else, the password should be enter by the user # Display a popup to enter password clear_password = self.screen.display_popup( 'Password needed for {0}: '.format(v['name']), is_input=True) # Store the password for the selected server if clear_password is not None: self.set_in_selected( 'password', self.password.sha256_hash(clear_password)) # Display the Glance client on the selected server logger.info("Connect Glances client to the {0} server".format( self.get_servers_list()[self.screen.active_server]['key'])) # Init the client args_server = self.args # Overwrite connection setting args_server.client = self.get_servers_list()[ self.screen.active_server]['ip'] args_server.port = self.get_servers_list()[ self.screen.active_server]['port'] args_server.username = self.get_servers_list()[ self.screen.active_server]['username'] args_server.password = self.get_servers_list()[ self.screen.active_server]['password'] client = GlancesClient(config=self.config, args=args_server, return_to_browser=True) # Test if client and server are in the same major version if not client.login(): self.screen.display_popup( "Sorry, cannot connect to '{0}'\n" "See 'glances.log' for more details".format(v['name'])) # Set the ONLINE status for the selected server self.set_in_selected('status', 'OFFLINE') else: # Start the client loop # Return connection type: 'glances' or 'snmp' connection_type = client.serve_forever() try: logger.debug( "Disconnect Glances client from the {0} server". format(self.get_servers_list()[ self.screen.active_server]['key'])) except IndexError: # Server did not exist anymore pass else: # Set the ONLINE status for the selected server if connection_type == 'snmp': self.set_in_selected('status', 'SNMP') else: self.set_in_selected('status', 'ONLINE') # Return to the browser (no server selected) self.screen.active_server = None
# 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/>. """Manage on alert actions.""" from subprocess import Popen from glances.logger import logger from glances.timer import Timer try: import pystache except ImportError: logger.warning( "PyStache lib not installed (action script with mustache will not work)" ) pystache_tag = False else: pystache_tag = True class GlancesActions(object): """This class manage action if an alert is reached.""" def __init__(self, args=None): """Init GlancesActions class.""" # Dict with the criticity status # - key: stat_name # - value: criticity # Goal: avoid to execute the same command twice self.status = {}
"""Manage sparklines for Glances output.""" from __future__ import unicode_literals from __future__ import division import sys from math import modf from glances.logger import logger from glances.compat import nativestr sparklines_module = True try: from sparklines import sparklines except ImportError as e: logger.warning("Sparklines module not found ({})".format(e)) sparklines_module = False try: '┌┬┐╔╦╗╒╤╕╓╥╖│║─═├┼┤╠╬╣╞╪╡╟╫╢└┴┘╚╩╝╘╧╛╙╨╜'.encode(sys.stdout.encoding) except (UnicodeEncodeError, TypeError): logger.warning("UTF-8 is mandatory for sparklines ({})".format(e)) sparklines_module = False class Sparkline(object): r"""Manage sparklines (see https://pypi.org/project/sparklines/).""" def __init__(self, size, pre_char='[', post_char=']', empty_char=' ', with_text=True): # If the sparklines python module available ?
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.glances_plugin import GlancesPlugin from glances.logger import logger from glances.main import disable from glances.compat 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,
def __serve_forever(self): """Main client loop.""" while True: # No need to update the server list # It's done by the GlancesAutoDiscoverListener class (autodiscover.py) # Or define staticaly in the configuration file (module static_list.py) # For each server in the list, grab elementary stats (CPU, LOAD, MEM, OS...) # logger.debug(self.get_servers_list()) try: for v in self.get_servers_list(): # Do not retreive stats for statics server # Why ? Because for each offline servers, the timeout will be reached # So ? The curse interface freezes if v['type'] == 'STATIC' and v['status'] in ['UNKNOWN', 'SNMP', 'OFFLINE']: continue # Get the server URI uri = self.__get_uri(v) # Try to connect to the server t = GlancesClientTransport() t.set_timeout(3) # Get common stats try: s = ServerProxy(uri, transport=t) except Exception as e: logger.warning( "Client browser couldn't create socket {0}: {1}".format(uri, e)) else: # Mandatory stats try: # CPU% cpu_percent = 100 - json.loads(s.getCpu())['idle'] v['cpu_percent'] = '{0:.1f}'.format(cpu_percent) # MEM% v['mem_percent'] = json.loads(s.getMem())['percent'] # OS (Human Readable name) v['hr_name'] = json.loads(s.getSystem())['hr_name'] except (socket.error, Fault, KeyError) as e: logger.debug( "Error while grabbing stats form {0}: {1}".format(uri, e)) v['status'] = 'OFFLINE' except ProtocolError as e: if e.errcode == 401: # Error 401 (Authentication failed) # Password is not the good one... v['password'] = None v['status'] = 'PROTECTED' else: v['status'] = 'OFFLINE' logger.debug("Cannot grab stats from {0} ({1} {2})".format(uri, e.errcode, e.errmsg)) else: # Status v['status'] = 'ONLINE' # Optional stats (load is not available on Windows OS) try: # LOAD load_min5 = json.loads(s.getLoad())['min5'] v['load_min5'] = '{0:.2f}'.format(load_min5) except Exception as e: logger.warning( "Error while grabbing stats form {0}: {1}".format(uri, e)) # List can change size during iteration... except RuntimeError: logger.debug( "Server list dictionnary change inside the loop (wait next update)") # Update the screen (list or Glances client) if not self.screen.active_server: # Display the Glances browser self.screen.update(self.get_servers_list()) else: # Display the Glances client for the selected server logger.debug("Selected server: {0}".format(self.get_servers_list()[self.screen.active_server])) # Connection can take time # Display a popup self.screen.display_popup( 'Connect to {0}:{1}'.format(v['name'], v['port']), duration=1) # A password is needed to access to the server's stats if self.get_servers_list()[self.screen.active_server]['password'] is None: # First of all, check if a password is available in the [passwords] section clear_password = self.password.get_password(v['name']) if (clear_password is None or self.get_servers_list() [self.screen.active_server]['status'] == 'PROTECTED'): # Else, the password should be enter by the user # Display a popup to enter password clear_password = self.screen.display_popup( 'Password needed for {0}: '.format(v['name']), is_input=True) # Store the password for the selected server if clear_password is not None: self.set_in_selected('password', self.password.sha256_hash(clear_password)) # Display the Glance client on the selected server logger.info("Connect Glances client to the {0} server".format( self.get_servers_list()[self.screen.active_server]['key'])) # Init the client args_server = self.args # Overwrite connection setting args_server.client = self.get_servers_list()[self.screen.active_server]['ip'] args_server.port = self.get_servers_list()[self.screen.active_server]['port'] args_server.username = self.get_servers_list()[self.screen.active_server]['username'] args_server.password = self.get_servers_list()[self.screen.active_server]['password'] client = GlancesClient(config=self.config, args=args_server, return_to_browser=True) # Test if client and server are in the same major version if not client.login(): self.screen.display_popup( "Sorry, cannot connect to '{0}'\n" "See 'glances.log' for more details".format(v['name'])) # Set the ONLINE status for the selected server self.set_in_selected('status', 'OFFLINE') else: # Start the client loop # Return connection type: 'glances' or 'snmp' connection_type = client.serve_forever() try: logger.debug("Disconnect Glances client from the {0} server".format( self.get_servers_list()[self.screen.active_server]['key'])) except IndexError: # Server did not exist anymore pass else: # Set the ONLINE status for the selected server if connection_type == 'snmp': self.set_in_selected('status', 'SNMP') else: self.set_in_selected('status', 'ONLINE') # Return to the browser (no server selected) self.screen.active_server = None
import operator from glances.compat import nativestr, PY3 from glances.logger import logger from glances.plugins.glances_plugin import GlancesPlugin import psutil # Use the Wifi Python lib (https://pypi.python.org/pypi/wifi) # Linux-only try: from wifi.scan import Cell from wifi.exceptions import InterfaceError except ImportError as e: import_error_tag = True logger.warning("Missing Python Lib ({}), Wifi plugin is disabled".format(e)) else: import_error_tag = False # Python 3 is not supported (see issue #1377) if PY3: import_error_tag = True logger.warning("Wifi lib is not compliant with Python 3, Wifi plugin is disabled") class Plugin(GlancesPlugin): """Glances Wifi plugin. Get stats of the current Wifi hotspots. """
# # 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/>. """GPU plugin (limited to NVIDIA chipsets).""" from glances.compat import nativestr from glances.logger import logger from glances.plugins.glances_plugin import GlancesPlugin try: import pynvml except Exception as e: import_error_tag = True # Display debu message if import KeyError logger.warning("Missing Python Lib ({}), Nvidia GPU plugin is disabled".format(e)) else: import_error_tag = False # Define the history items list # All items in this list will be historised if the --enable-history tag is set items_history_list = [{'name': 'proc', 'description': 'GPU processor', 'y_unit': '%'}, {'name': 'mem', 'description': 'Memory consumption', 'y_unit': '%'}] class Plugin(GlancesPlugin): """Glances GPU plugin (limited to NVIDIA chipsets).
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.glances_plugin import GlancesPlugin from glances.logger import logger from glances.main import disable import os # 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 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. """
def _init_colors(self): """Init the Curses color layout.""" # Set curses options try: if hasattr(curses, 'start_color'): curses.start_color() if hasattr(curses, 'use_default_colors'): curses.use_default_colors() except Exception as e: logger.warning('Error initializing terminal color ({})'.format(e)) # Init colors if self.args.disable_bold: A_BOLD = 0 self.args.disable_bg = True else: A_BOLD = curses.A_BOLD self.title_color = A_BOLD self.title_underline_color = A_BOLD | curses.A_UNDERLINE self.help_color = A_BOLD if curses.has_colors(): # The screen is compatible with a colored design if self.is_theme('white'): # White theme: black ==> white curses.init_pair(1, curses.COLOR_BLACK, -1) else: curses.init_pair(1, curses.COLOR_WHITE, -1) if self.args.disable_bg: curses.init_pair(2, curses.COLOR_RED, -1) curses.init_pair(3, curses.COLOR_GREEN, -1) curses.init_pair(4, curses.COLOR_BLUE, -1) curses.init_pair(5, curses.COLOR_MAGENTA, -1) else: curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_RED) curses.init_pair(3, curses.COLOR_WHITE, curses.COLOR_GREEN) curses.init_pair(4, curses.COLOR_WHITE, curses.COLOR_BLUE) curses.init_pair(5, curses.COLOR_WHITE, curses.COLOR_MAGENTA) curses.init_pair(6, curses.COLOR_RED, -1) curses.init_pair(7, curses.COLOR_GREEN, -1) curses.init_pair(8, curses.COLOR_BLUE, -1) # Colors text styles if curses.COLOR_PAIRS > 8: try: curses.init_pair(9, curses.COLOR_MAGENTA, -1) except Exception: if self.is_theme('white'): curses.init_pair(9, curses.COLOR_BLACK, -1) else: curses.init_pair(9, curses.COLOR_WHITE, -1) try: curses.init_pair(10, curses.COLOR_CYAN, -1) except Exception: if self.is_theme('white'): curses.init_pair(10, curses.COLOR_BLACK, -1) else: curses.init_pair(10, curses.COLOR_WHITE, -1) self.ifWARNING_color2 = curses.color_pair(9) | A_BOLD self.ifCRITICAL_color2 = curses.color_pair(6) | A_BOLD self.filter_color = curses.color_pair(10) | A_BOLD self.no_color = curses.color_pair(1) self.default_color = curses.color_pair(3) | A_BOLD self.nice_color = curses.color_pair(9) self.cpu_time_color = curses.color_pair(9) self.ifCAREFUL_color = curses.color_pair(4) | A_BOLD self.ifWARNING_color = curses.color_pair(5) | A_BOLD self.ifCRITICAL_color = curses.color_pair(2) | A_BOLD self.default_color2 = curses.color_pair(7) self.ifCAREFUL_color2 = curses.color_pair(8) | A_BOLD else: # The screen is NOT compatible with a colored design # switch to B&W text styles self.no_color = curses.A_NORMAL self.default_color = curses.A_NORMAL self.nice_color = A_BOLD self.cpu_time_color = A_BOLD self.ifCAREFUL_color = curses.A_UNDERLINE self.ifWARNING_color = A_BOLD self.ifCRITICAL_color = curses.A_REVERSE self.default_color2 = curses.A_NORMAL self.ifCAREFUL_color2 = curses.A_UNDERLINE self.ifWARNING_color2 = A_BOLD self.ifCRITICAL_color2 = curses.A_REVERSE self.filter_color = A_BOLD # Define the colors list (hash table) for stats self.colors_list = { 'DEFAULT': self.no_color, 'UNDERLINE': curses.A_UNDERLINE, 'BOLD': A_BOLD, 'SORT': A_BOLD, 'OK': self.default_color2, 'MAX': self.default_color2 | curses.A_BOLD, 'FILTER': self.filter_color, 'TITLE': self.title_color, 'PROCESS': self.default_color2, 'STATUS': self.default_color2, 'NICE': self.nice_color, 'CPU_TIME': self.cpu_time_color, 'CAREFUL': self.ifCAREFUL_color2, 'WARNING': self.ifWARNING_color2, 'CRITICAL': self.ifCRITICAL_color2, 'OK_LOG': self.default_color, 'CAREFUL_LOG': self.ifCAREFUL_color, 'WARNING_LOG': self.ifWARNING_color, 'CRITICAL_LOG': self.ifCRITICAL_color, 'PASSWORD': curses.A_PROTECT }
# 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/>. """Graph generation class.""" import os from glances.compat import iterkeys from glances.logger import logger try: from matplotlib import __version__ as matplotlib_version import matplotlib.pyplot as plt except ImportError: matplotlib_check = False logger.warning('Cannot load Matplotlib library. Please install it using "pip install matplotlib"') else: matplotlib_check = True logger.info("Load Matplotlib version %s" % matplotlib_version) class GlancesGraph(object): """Thanks to this class, Glances can export history to graphs.""" def __init__(self, output_folder): self.output_folder = output_folder def get_output_folder(self): """Return the output folder where the graph are generated.""" return self.output_folder
def __init__(self, cache_timeout=60): """Init the class to collect stats about processes.""" # Add internals caches because psutil do not cache all the stats # See: https://code.google.com/p/psutil/issues/detail?id=462 self.username_cache = {} self.cmdline_cache = {} # The internals caches will be cleaned each 'cache_timeout' seconds self.cache_timeout = cache_timeout self.cache_timer = Timer(self.cache_timeout) # Init the io dict # key = pid # value = [ read_bytes_old, write_bytes_old ] self.io_old = {} # Init stats self.auto_sort = None self._sort_key = None # Default processes sort key is 'auto' # Can be overwrite from the configuration file (issue#1536) => See glances_processlist.py init self.set_sort_key('auto', auto=True) self.processlist = [] self.reset_processcount() # Tag to enable/disable the processes stats (to reduce the Glances CPU consumption) # Default is to enable the processes stats self.disable_tag = False # Extended stats for top process is enable by default self.disable_extended_tag = False # Test if the system can grab io_counters try: p = psutil.Process() p.io_counters() except Exception as e: logger.warning( 'PsUtil can not grab processes io_counters ({})'.format(e)) self.disable_io_counters = True else: logger.debug('PsUtil can grab processes io_counters') self.disable_io_counters = False # Test if the system can grab gids try: p = psutil.Process() p.gids() except Exception as e: logger.warning('PsUtil can not grab processes gids ({})'.format(e)) self.disable_gids = True else: logger.debug('PsUtil can grab processes gids') self.disable_gids = False # Maximum number of processes showed in the UI (None if no limit) self._max_processes = None # Process filter is a regular expression self._filter = GlancesFilter() # Whether or not to hide kernel threads self.no_kernel_threads = False # Store maximums values in a dict # Used in the UI to highlight the maximum value self._max_values_list = ('cpu_percent', 'memory_percent') # { 'cpu_percent': 0.0, 'memory_percent': 0.0 } self._max_values = {} self.reset_max_values()
# 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/>. """Manage on alert actions.""" from subprocess import Popen from glances.logger import logger from glances.timer import Timer try: import pystache except ImportError: logger.warning("PyStache lib not installed (action script with mustache will not work)") pystache_tag = False else: pystache_tag = True class GlancesActions(object): """This class manage action if an alert is reached.""" def __init__(self, args=None): """Init GlancesActions class.""" # Dict with the criticity status # - key: stat_name # - value: criticity # Goal: avoid to execute the same command twice
# 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/>. """History class.""" import os from glances.compat import iterkeys from glances.logger import logger try: from matplotlib import __version__ as matplotlib_version import matplotlib.pyplot as plt except ImportError: matplotlib_check = False logger.warning( 'Cannot load Matplotlib library. Please install it using "pip install matplotlib"' ) else: matplotlib_check = True logger.info('Load Matplotlib version %s' % matplotlib_version) class GlancesHistory(object): """This class define the object to manage stats history.""" def __init__(self, output_folder): self.output_folder = output_folder def get_output_folder(self): """Return the output folder where the graph are generated.""" return self.output_folder
# # 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/>. """GPU plugin (limited to NVIDIA chipsets).""" from glances.compat import nativestr, to_fahrenheit from glances.logger import logger from glances.plugins.glances_plugin import GlancesPlugin # In Glances 3.1.4 or higher, we use the py3nvml lib (see issue #1523) try: import py3nvml.py3nvml as pynvml except Exception as e: import_error_tag = True # Display debu message if import KeyError logger.warning( "Missing Python Lib ({}), Nvidia GPU plugin is disabled".format(e)) else: import_error_tag = False # Define the history items list # All items in this list will be historised if the --enable-history tag is set items_history_list = [{ 'name': 'proc', 'description': 'GPU processor', 'y_unit': '%' }, { 'name': 'mem', 'description': 'Memory consumption', 'y_unit': '%' }]
from glances.globals import WINDOWS, MACOS, BSD from glances.ports_list import GlancesPortsList from glances.web_list import GlancesWebList from glances.timer import Timer, Counter from glances.compat import bool_type from glances.logger import logger from glances.plugins.glances_plugin import GlancesPlugin try: import requests requests_tag = True except ImportError as e: requests_tag = False logger.warning( "Missing Python Lib ({}), Ports plugin is limited to port scanning". format(e)) class Plugin(GlancesPlugin): """Glances ports scanner plugin.""" def __init__(self, args=None, config=None): """Init the plugin.""" super(Plugin, self).__init__(args=args, config=config, stats_init_value=[]) self.args = args self.config = config # We want to display the stat in the curse interface self.display_curse = True
from glances.logger import logger from glances.compat import iterkeys, itervalues, nativestr from glances.timer import getTimeSinceLastUpdate from glances.plugins.glances_plugin import GlancesPlugin from glances.processes import sort_stats as sort_stats_processes, weighted, glances_processes # Docker-py library (optional and Linux-only) # https://github.com/docker/docker-py try: import docker except Exception as e: import_error_tag = True # Display debu message if import KeyError logger.warning( "Error loading Docker Python Lib. Docker plugin is disabled ({})". format(e)) else: import_error_tag = False # Define the items history list (list of items to add to history) # TODO: For the moment limited to the CPU. Had to change the graph exports # method to display one graph per container. # items_history_list = [{'name': 'cpu_percent', # 'description': 'Container CPU consumption in %', # 'y_unit': '%'}, # {'name': 'memory_usage', # 'description': 'Container memory usage in bytes', # 'y_unit': 'B'}, # {'name': 'network_rx', # 'description': 'Container network RX bitrate in bits per second',
"""Quicklook plugin.""" from glances.cpu_percent import cpu_percent from glances.logger import logger from glances.outputs.glances_bars import Bar from glances.plugins.glances_plugin import GlancesPlugin import psutil # Import plugin specific dependency try: from cpuinfo import cpuinfo except ImportError as e: cpuinfo_tag = False logger.warning( "Missing Python Lib ({}), Quicklook plugin will not display CPU info". format(e)) else: cpuinfo_tag = True class Plugin(GlancesPlugin): """Glances quicklook plugin. 'stats' is a dictionary. """ def __init__(self, args=None): """Init the quicklook plugin.""" super(Plugin, self).__init__(args=args) # We want to display the stat in the curse interface
import operator from glances.compat import nativestr, PY3 from glances.logger import logger from glances.plugins.glances_plugin import GlancesPlugin import psutil # Use the Wifi Python lib (https://pypi.python.org/pypi/wifi) # Linux-only try: from wifi.scan import Cell from wifi.exceptions import InterfaceError except ImportError as e: import_error_tag = True logger.warning( "Missing Python Lib ({}), Wifi plugin is disabled".format(e)) else: import_error_tag = False # Python 3 is not supported (see issue #1377) if PY3: import_error_tag = True logger.warning( "Wifi lib is not compliant with Python 3, Wifi plugin is disabled") class Plugin(GlancesPlugin): """Glances Wifi plugin. Get stats of the current Wifi hotspots. """