def check_snmp(self): """Chek if SNMP is available on the server.""" # Import the SNMP client class from glances.core.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: {0}".format(self.system_name)) except KeyError: self.system_name = None logger.warning("Cannot detect SNMP system name") return ret
def __init__(self, config=None, args=None): # Init stats self.stats = GlancesStats(config=config, args=args) # Default number of processes to displayed is set to 50 glances_processes.set_max_processes(50) # If process extended stats is disabled by user if not args.enable_process_extended: logger.info("Extended stats for top process are disabled (default behavior)") glances_processes.disable_extended() else: logger.debug("Extended stats for top process are enabled") glances_processes.enable_extended() # Manage optionnal process filter if args.process_filter is not None: glances_processes.set_process_filter(args.process_filter) if (not is_windows) and args.no_kernel_threads: # Ignore kernel threads in process list glances_processes.disable_kernel_threads() if args.process_tree: # Enable process tree view glances_processes.enable_tree() # Initial system informations update self.stats.update() # Init screen self.screen = GlancesCursesStandalone(args=args)
def __init__(self, requestHandler=GlancesXMLRPCHandler, cached_time=1, config=None, args=None): # Args self.args = args # Init the XML RPC server try: self.server = GlancesXMLRPCServer(args.bind_address, args.port, requestHandler) except Exception as e: logger.critical("Cannot start Glances server: {0}".format(e)) sys.exit(2) # The users dict # username / password couple # By default, no auth is needed self.server.user_dict = {} self.server.isAuth = False # Register functions self.server.register_introspection_functions() self.server.register_instance(GlancesInstance(cached_time, config)) if not self.args.disable_autodiscover: # Note: The Zeroconf service name will be based on the hostname self.autodiscover_client = GlancesAutoDiscoverClient(socket.gethostname(), args) else: logger.info("Glances autodiscover announce is disabled")
def init(self): """Init the connection to the InfluxDB server.""" if not self.export_enable: return None try: db = InfluxDBClient(host=self.host, port=self.port, username=self.user, password=self.password, database=self.db) get_all_db = [i['name'] for i in db.get_list_database()] except InfluxDBClientError: # https://github.com/influxdb/influxdb-python/issues/138 logger.info("Trying fallback to InfluxDB v0.8") db = InfluxDBClient08(host=self.host, port=self.port, username=self.user, password=self.password, database=self.db) get_all_db = [i['name'] for i in db.get_list_database()] except InfluxDBClientError08 as e: logger.critical("Cannot connect to InfluxDB database '%s' (%s)" % (self.db, e)) sys.exit(2) if self.db in get_all_db: logger.info( "Stats will be exported to InfluxDB server: {0}".format(db._baseurl)) else: logger.critical("InfluxDB database '%s' did not exist. Please create it" % self.db) sys.exit(2) return db
def __init__(self, hostname, args=None): if zeroconf_tag: zeroconf_bind_address = args.bind_address try: self.zeroconf = Zeroconf() except socket.error as e: logger.error("Cannot start zeroconf: {0}".format(e)) if netifaces_tag: # -B @ overwrite the dynamic IPv4 choice if zeroconf_bind_address == '0.0.0.0': zeroconf_bind_address = self.find_active_ip_address() else: logger.error("Couldn't find the active IP address: netifaces library not found.") logger.info("Announce the Glances server on the LAN (using {0} IP address)".format(zeroconf_bind_address)) print("Announce the Glances server on the LAN (using {0} IP address)".format(zeroconf_bind_address)) self.info = ServiceInfo( zeroconf_type, '{0}:{1}.{2}'.format(hostname, args.port, zeroconf_type), address=socket.inet_aton(zeroconf_bind_address), port=args.port, weight=0, priority=0, properties={}, server=hostname) self.zeroconf.register_service(self.info) else: logger.error("Cannot announce Glances server on the network: zeroconf library not found.")
def __init__(self, requestHandler=GlancesXMLRPCHandler, cached_time=1, config=None, args=None): # Args self.args = args # Init the XML RPC server try: self.server = GlancesXMLRPCServer(args.bind_address, args.port, requestHandler) except Exception as e: logger.critical("Cannot start Glances server: {0}".format(e)) sys.exit(2) # The users dict # username / password couple # By default, no auth is needed self.server.user_dict = {} self.server.isAuth = False # Register functions self.server.register_introspection_functions() self.server.register_instance(GlancesInstance(cached_time, config)) if not self.args.disable_autodiscover: # Note: The Zeroconf service name will be based on the hostname self.autodiscover_client = GlancesAutoDiscoverClient( socket.gethostname(), args) else: logger.info("Glances autodiscover announce is disabled")
def check_snmp(self): """Chek if SNMP is available on the server.""" # Import the SNMP client class from glances.core.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: {0}".format(self.system_name)) except KeyError: self.system_name = None logger.warning("Cannot detect SNMP system name") return ret
def __init__(self, config=None, args=None): # Init stats self.stats = GlancesStats(config=config, args=args) # Default number of processes to displayed is set to 50 glances_processes.set_max_processes(50) # If process extended stats is disabled by user if not args.enable_process_extended: logger.info( "Extended stats for top process are disabled (default behavior)" ) glances_processes.disable_extended() else: logger.debug("Extended stats for top process are enabled") glances_processes.enable_extended() # Manage optionnal process filter if args.process_filter is not None: glances_processes.set_process_filter(args.process_filter) if (not is_windows) and args.no_kernel_threads: # Ignore kernel threads in process list glances_processes.disable_kernel_threads() if args.process_tree: # Enable process tree view glances_processes.enable_tree() # Initial system informations update self.stats.update() # Init screen self.screen = GlancesCursesStandalone(args=args)
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_raw_option( 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'] = '******' 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 parse_tags(self): """ Parses some tags into a dict""" if self.tags: try: self.tags = dict([x.split(':') for x in self.tags.split(',')]) except ValueError: # one of the keyvalue pairs was missing logger.info('invalid tags passed: %s', self.tags) self.tags = {} else: self.tags = {}
def parse_tags(self): """ Parses some tags into a dict""" if self.tags: try: self.tags = dict([x.split(':') for x in self.tags.split(',')]) except ValueError: # one of the keyvalue pairs was missing logger.info('invalid tags passed: %s', self.tags) self.tags = {} else: self.tags = {}
def get_password(self, description='', confirm=False, clear=False): """Get the password from a Glances client or server. For Glances server, get the password (confirm=True, clear=False): 1) from the password file (if it exists) 2) from the CLI Optionally: save the password to a file (hashed with salt + SHA-256) For Glances client, get the password (confirm=False, clear=True): 1) from the CLI 2) the password is hashed with SHA-256 (only SHA string transit through the network) """ if os.path.exists(self.password_filepath) and not clear: # If the password file exist then use it logger.info("Read password from file {0}".format( self.password_filepath)) password = self.load_password() else: # Else enter the password from the command line if description != '': print(description) # password_plain is the plain SHA-256 password # password_hashed is the salt + SHA-256 password password_sha = hashlib.sha256( getpass.getpass(_("Password: "******"Password (confirm): ")).encode( 'utf-8')).hexdigest() if not self.check_password(password_hashed, password_confirm): logger.critical("Sorry, passwords do not match. Exit.") sys.exit(1) # Return the plain or hashed password if clear: password = password_sha else: password = password_hashed # Save the hashed password to the password file if not clear: save_input = input( _("Do you want to save the password? [Yes/No]: ")) if len(save_input) > 0 and save_input[0].upper() == _('Y'): self.save_password(password_hashed) return password
def start(self, stats): """Start the bottle.""" # Init stats self.stats = stats # Init plugin list self.plugins_list = self.stats.getAllPlugins() # Bind the Bottle TCP address/port bindmsg = 'Glances web server started on http://{0}:{1}/'.format(self.args.bind_address, self.args.port) logger.info(bindmsg) print(bindmsg) self._app.run(host=self.args.bind_address, port=self.args.port, quiet=not self.args.debug)
def process_filter(self, value): """Set the process filter.""" logger.info("Set process filter to {0}".format(value)) self._process_filter = value if value is not None: try: self._process_filter_re = re.compile(value) logger.debug("Process filter regex compilation OK: {0}".format(self.process_filter)) except Exception: logger.error("Cannot compile process filter regex: {0}".format(value)) self._process_filter_re = None else: self._process_filter_re = None
def process_filter(self, value): """Set the process filter.""" logger.info("Set process filter to {0}".format(value)) self._process_filter = value if value is not None: try: self._process_filter_re = re.compile(value) logger.debug("Process filter regex compilation OK: {0}".format( self.process_filter)) except Exception: logger.error( "Cannot compile process filter regex: {0}".format(value)) self._process_filter_re = None else: self._process_filter_re = None
def __init__(self, args=None): # CSV file name self.csv_filename = args.output_csv # Set the CSV output file try: if is_py3: self.csv_file = open(self.csv_filename, 'w', newline='') else: self.csv_file = open(self.csv_filename, 'wb') self.writer = csv.writer(self.csv_file) except IOError as e: logger.critical("Cannot create the CSV file: {0}".format(e)) sys.exit(2) logger.info("Stats dumped to CSV file: {0}".format(self.csv_filename))
def load(self): """Load a config file from the list of paths, if it exists.""" for config_file in self.get_config_paths(): if os.path.isfile(config_file) and os.path.getsize(config_file) > 0: try: if is_py3: self.parser.read(config_file, encoding='utf-8') else: self.parser.read(config_file) logger.info("Read configuration file '{0}'".format(config_file)) except UnicodeDecodeError as e: logger.error("Cannot decode configuration file '{0}': {1}".format(config_file, e)) sys.exit(1) # Save the loaded configuration file path (issue #374) self._loaded_config_file = config_file break
def __init__(self, args=None): if zeroconf_tag: logger.info("Init autodiscover mode (Zeroconf protocol)") try: self.zeroconf = Zeroconf() except socket.error as e: logger.error("Cannot start Zeroconf (%s)" % e) self.zeroconf_enable_tag = False else: self.listener = GlancesAutoDiscoverListener() self.browser = ServiceBrowser( self.zeroconf, zeroconf_type, self.listener) self.zeroconf_enable_tag = True else: logger.error("Cannot start autodiscover mode (Zeroconf lib is not installed)") self.zeroconf_enable_tag = False
def __init__(self, args=None): if zeroconf_tag: logger.info("Init autodiscover mode (Zeroconf protocol)") try: self.zeroconf = Zeroconf() except socket.error as e: logger.error("Cannot start Zeroconf (%s)" % e) self.zeroconf_enable_tag = False else: self.listener = GlancesAutoDiscoverListener() self.browser = ServiceBrowser( self.zeroconf, zeroconf_type, self.listener) self.zeroconf_enable_tag = True else: logger.error("Cannot start autodiscover mode (Zeroconf lib is not installed)") self.zeroconf_enable_tag = False
def start(self, stats): """Start the bottle.""" # Init stats self.stats = stats # Init plugin list self.plugins_list = self.stats.getAllPlugins() # Bind the Bottle TCP address/port bindmsg = _("Glances web server started on http://{0}:{1}/").format( self.args.bind_address, self.args.port) logger.info(bindmsg) print(bindmsg) self._app.run(host=self.args.bind_address, port=self.args.port, quiet=not self.args.debug)
def get_password(self, description='', confirm=False, clear=False): """Get the password from a Glances client or server. For Glances server, get the password (confirm=True, clear=False): 1) from the password file (if it exists) 2) from the CLI Optionally: save the password to a file (hashed with salt + SHA-256) For Glances client, get the password (confirm=False, clear=True): 1) from the CLI 2) the password is hashed with SHA-256 (only SHA string transit through the network) """ if os.path.exists(self.password_filepath) and not clear: # If the password file exist then use it logger.info("Read password from file {0}".format(self.password_filepath)) password = self.load_password() else: # Else enter the password from the command line if description != '': print(description) # password_sha256 is the plain SHA-256 password # password_hashed is the salt + SHA-256 password password_sha256 = self.sha256_hash(getpass.getpass('Password: '******'Password (confirm): ')) if not self.check_password(password_hashed, password_confirm): logger.critical("Sorry, passwords do not match. Exit.") sys.exit(1) # Return the plain SHA-256 or the salted password if clear: password = password_sha256 else: password = password_hashed # Save the hashed password to the password file if not clear: save_input = input('Do you want to save the password? [Yes/No]: ') if len(save_input) > 0 and save_input[0].upper() == 'Y': self.save_password(password_hashed) return password
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_raw_option(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'] = '******' 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, config=None, args=None): # Quiet mode self._quiet = args.quiet self.refresh_time = args.time # Init stats self.stats = GlancesStats(config=config, args=args) # If process extended stats is disabled by user if not args.enable_process_extended: logger.debug("Extended stats for top process are disabled") glances_processes.disable_extended() else: logger.debug("Extended stats for top process are enabled") glances_processes.enable_extended() # Manage optionnal process filter if args.process_filter is not None: glances_processes.process_filter = args.process_filter if (not is_windows) and args.no_kernel_threads: # Ignore kernel threads in process list glances_processes.disable_kernel_threads() try: if args.process_tree: # Enable process tree view glances_processes.enable_tree() except AttributeError: pass # Initial system informations update self.stats.update() if self.quiet: logger.info("Quiet mode is ON: Nothing will be displayed") # In quiet mode, nothing is displayed glances_processes.max_processes = 0 else: # Default number of processes to displayed is set to 50 glances_processes.max_processes = 50 # Init screen self.screen = GlancesCursesStandalone(args=args)
def __init__(self, config=None, args=None): # Quiet mode self._quiet = args.quiet self.refresh_time = args.time # Init stats self.stats = GlancesStats(config=config, args=args) # If process extended stats is disabled by user if not args.enable_process_extended: logger.debug("Extended stats for top process are disabled") glances_processes.disable_extended() else: logger.debug("Extended stats for top process are enabled") glances_processes.enable_extended() # Manage optionnal process filter if args.process_filter is not None: glances_processes.process_filter = args.process_filter if (not is_windows) and args.no_kernel_threads: # Ignore kernel threads in process list glances_processes.disable_kernel_threads() try: if args.process_tree: # Enable process tree view glances_processes.enable_tree() except AttributeError: pass # Initial system informations update self.stats.update() if self.quiet: logger.info("Quiet mode is ON: Nothing will be displayed") # In quiet mode, nothing is displayed glances_processes.max_processes = 0 else: # Default number of processes to displayed is set to 50 glances_processes.max_processes = 50 # Init screen self.screen = GlancesCursesStandalone(args=args)
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 init(self): """Init the connection to the InfluxDB server""" if not self.export_enable: return None db = InfluxDBClient(self.influxdb_host, self.influxdb_port, self.influxdb_user, self.influxdb_password, self.influxdb_db) try: get_all_db = db.get_database_list()[0].values() except client.InfluxDBClientError as e: logger.critical("Can not connect to InfluxDB database '%s' (%s)" % (self.influxdb_db, e)) sys.exit(2) if self.influxdb_db in get_all_db: logger.info( "Stats will be exported to InfluxDB server: {0}".format(db._baseurl)) else: logger.critical("InfluxDB database '%s' did not exist. Please create it" % self.influxdb_db) sys.exit(2) return db
def __init__(self, config=None, args=None): """Init the CSV export IF.""" GlancesExport.__init__(self, config=config, args=args) # CSV file name self.csv_filename = args.export_csv # Set the CSV output file try: if is_py3: self.csv_file = open(self.csv_filename, 'w', newline='') else: self.csv_file = open(self.csv_filename, 'wb') self.writer = csv.writer(self.csv_file) except IOError as e: logger.critical("Cannot create the CSV file: {0}".format(e)) sys.exit(2) logger.info("Stats exported to CSV file: {0}".format(self.csv_filename)) self.export_enable = True self.first_line = True
def __catch_key(self, servers_list): # Catch the browser pressed key self.pressedkey = self.get_key(self.term_window) # Actions... if self.pressedkey == ord('\x1b') or self.pressedkey == ord('q'): # 'ESC'|'q' > Quit self.end() logger.info("Stop Glances client browser") sys.exit(0) elif self.pressedkey == 10: # 'ENTER' > Run Glances on the selected server logger.debug("Server number {0} selected".format(self.cursor + 1)) self.active_server = self.cursor elif self.pressedkey == 259: # 'UP' > Up in the server list self.cursor_up(servers_list) elif self.pressedkey == 258: # 'DOWN' > Down in the server list self.cursor_down(servers_list) # Return the key code return self.pressedkey
def __catch_key(self, servers_list): # Catch the browser pressed key self.pressedkey = self.get_key(self.term_window) # Actions... if self.pressedkey == ord("\x1b") or self.pressedkey == ord("q"): # 'ESC'|'q' > Quit self.end() logger.info("Stop Glances client browser") sys.exit(0) elif self.pressedkey == 10: # 'ENTER' > Run Glances on the selected server logger.debug("Server number {0} selected".format(self.cursor + 1)) self.active_server = self.cursor elif self.pressedkey == 259: # 'UP' > Up in the server list self.cursor_up(servers_list) elif self.pressedkey == 258: # 'DOWN' > Down in the server list self.cursor_down(servers_list) # Return the key code return self.pressedkey
def run(self, stat_name, criticity, commands, mustache_dict=None): """Run the commands (in background). - stats_name: plugin_name (+ header) - criticity: criticity of the trigger - commands: a list of command line with optional {{mustache}} - mustache_dict: Plugin stats (can be use within {{mustache}}) Return True if the commands have been ran. """ if self.get(stat_name) == criticity: # Action already executed => Exit return False logger.debug("Run action {0} for {1} ({2}) with stats {3}".format( commands, stat_name, criticity, mustache_dict)) # Run all actions in background for cmd in commands: # Replace {{arg}} by the dict one (Thk to {Mustache}) if pystache_tag: cmd_full = pystache.render(cmd, mustache_dict) else: cmd_full = cmd # Execute the action logger.info("Action triggered for {0} ({1}): {2}".format( stat_name, criticity, cmd_full)) logger.debug( "Stats value for the trigger: {0}".format(mustache_dict)) try: Popen(cmd_full, shell=True) except OSError as e: logger.error("Can't execute the action ({0})".format(e)) self.set(stat_name, criticity) return True
def run(self, stat_name, criticity, commands, mustache_dict=None): """Run the commands (in background). - stats_name: plugin_name (+ header) - criticity: criticity of the trigger - commands: a list of command line with optional {{mustache}} - mustache_dict: Plugin stats (can be use within {{mustache}}) Return True if the commands have been ran. """ if self.get(stat_name) == criticity: # Action already executed => Exit return False logger.debug("Run action {0} for {1} ({2}) with stats {3}".format(commands, stat_name, criticity, mustache_dict)) # Run all actions in background for cmd in commands: # Replace {{arg}} by the dict one (Thk to {Mustache}) if pystache_tag: cmd_full = pystache.render(cmd, mustache_dict) else: cmd_full = cmd # Execute the action logger.info("Action triggered for {0} ({1}): {2}".format(stat_name, criticity, cmd_full)) logger.debug("Stats value for the trigger: {0}".format(mustache_dict)) try: Popen(cmd_full, shell=True) except OSError as e: logger.error("Can't execute the action ({0})".format(e)) self.set(stat_name, criticity) return True
def __init__(self, config=None, args=None): """Init the CSV export IF.""" GlancesExport.__init__(self, config=config, args=args) # CSV file name self.csv_filename = args.export_csv # Set the CSV output file try: if is_py3: self.csv_file = open(self.csv_filename, 'w', newline='') else: self.csv_file = open(self.csv_filename, 'wb') self.writer = csv.writer(self.csv_file) except IOError as e: logger.critical("Cannot create the CSV file: {0}".format(e)) sys.exit(2) logger.info("Stats exported to CSV file: {0}".format( self.csv_filename)) self.export_enable = True self.first_line = 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 end(): """Stop Glances.""" if core.is_standalone(): # Stop the standalone (CLI) standalone.end() logger.info("Stop Glances (with CTRL-C)") elif core.is_client(): # Stop the client client.end() logger.info("Stop Glances client (with CTRL-C)") elif core.is_server(): # Stop the server server.end() logger.info("Stop Glances server (with CTRL-C)") elif core.is_webserver(): # Stop the Web server webserver.end() logger.info("Stop Glances web server(with CTRL-C)") # The end... sys.exit(0)
def end(): """Stop Glances.""" if core.is_standalone(): # Stop the standalone (CLI) standalone.end() logger.info("Stop Glances (with CTRL-C)") elif core.is_client(): # Stop the client client.end() logger.info("Stop Glances client (with CTRL-C)") elif core.is_server(): # Stop the server server.end() logger.info("Stop Glances server (with CTRL-C)") elif core.is_webserver(): # Stop the Web server webserver.end() logger.info("Stop Glances web server(with CTRL-C)") # The end... sys.exit(0)
def login(self): """Logon to the server.""" ret = True if not self.args.snmp_force: # First of all, trying to connect to a Glances server client_version = None try: client_version = self.client.init() except socket.error as err: # Fallback to SNMP self.client_mode = 'snmp' logger.error("Connection to Glances server failed: {0}".format(err)) fallbackmsg = 'No Glances server found. Trying fallback to SNMP...' if not self.return_to_browser: print(fallbackmsg) else: logger.info(fallbackmsg) except ProtocolError as err: # Others errors if str(err).find(" 401 ") > 0: msg = "Connection to server failed (bad password)" else: msg = "Connection to server failed ({0})".format(err) self.log_and_exit(msg) return False if self.client_mode == 'glances': # Check that both client and server are in the same major version if version.split('.')[0] == client_version.split('.')[0]: # Init stats self.stats = GlancesStatsClient(config=self.config, args=self.args) self.stats.set_plugins(json.loads(self.client.getAllPlugins())) logger.debug("Client version: {0} / Server version: {1}".format(version, client_version)) else: self.log_and_exit("Client and server not compatible: \ Client version: {0} / Server version: {1}".format(version, client_version)) return False else: self.client_mode = 'snmp' # SNMP mode if self.client_mode == 'snmp': logger.info("Trying to grab stats by SNMP...") from glances.core.glances_stats import GlancesStatsClientSNMP # Init stats self.stats = GlancesStatsClientSNMP(config=self.config, args=self.args) if not self.stats.check_snmp(): self.log_and_exit("Connection to SNMP server failed") return False if ret: # Load limits from the configuration file # Each client can choose its owns limits self.stats.load_limits(self.config) # Init screen self.screen = GlancesCursesClient(args=self.args) # Return result return ret
def __init__(self, args=None): # Init args self.args = args # Init windows positions self.term_w = 80 self.term_h = 24 # Space between stats self.space_between_column = 3 self.space_between_line = 2 # Init the curses screen self.screen = curses.initscr() if not self.screen: logger.critical("Cannot init the curses library.\n") sys.exit(1) # Set curses options if hasattr(curses, 'start_color'): curses.start_color() if hasattr(curses, 'use_default_colors'): curses.use_default_colors() if hasattr(curses, 'noecho'): curses.noecho() if hasattr(curses, 'cbreak'): curses.cbreak() self.set_cursor(0) # Init colors self.hascolors = False if curses.has_colors() and curses.COLOR_PAIRS > 8: self.hascolors = True # FG color, BG color if args.theme_white: curses.init_pair(1, curses.COLOR_BLACK, -1) else: curses.init_pair(1, curses.COLOR_WHITE, -1) 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) try: curses.init_pair(9, curses.COLOR_MAGENTA, -1) except Exception: if args.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 args.theme_white: curses.init_pair(10, curses.COLOR_BLACK, -1) else: curses.init_pair(10, curses.COLOR_WHITE, -1) else: self.hascolors = False if args.disable_bold: A_BOLD = curses.A_BOLD else: A_BOLD = 0 self.title_color = A_BOLD self.title_underline_color = A_BOLD | curses.A_UNDERLINE self.help_color = A_BOLD if self.hascolors: # Colors text styles self.no_color = curses.color_pair(1) self.default_color = curses.color_pair(3) | A_BOLD self.nice_color = curses.color_pair(9) | A_BOLD 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) | A_BOLD self.ifCAREFUL_color2 = curses.color_pair(8) | A_BOLD 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 else: # B&W text styles self.no_color = curses.A_NORMAL self.default_color = curses.A_NORMAL self.nice_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, 'FILTER': self.filter_color, 'TITLE': self.title_color, 'PROCESS': self.default_color2, 'STATUS': self.default_color2, 'NICE': self.nice_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 } # Init main window self.term_window = self.screen.subwin(0, 0) # Init refresh time self.__refresh_time = args.time # Init process sort method self.args.process_sorted_by = 'auto' # Init edit filter tag self.edit_filter = False # Catch key pressed with non blocking mode self.term_window.keypad(1) self.term_window.nodelay(1) self.pressedkey = -1 # History tag self.reset_history_tag = False self.history_tag = False if args.enable_history: logger.info('Stats history enabled with output path %s' % args.path_history) from glances.exports.glances_history import GlancesHistory self.glances_history = GlancesHistory(args.path_history) if not self.glances_history.graph_enabled(): args.enable_history = False logger.error( 'Stats history disabled because MatPlotLib is not installed')
def __catch_key(self, return_to_browser=False): # Catch the pressed key self.pressedkey = self.get_key(self.term_window) # Actions... if self.pressedkey == ord('\x1b') or self.pressedkey == ord('q'): # 'ESC'|'q' > Quit if return_to_browser: logger.info("Stop Glances client and return to the browser") else: self.end() logger.info("Stop Glances") sys.exit(0) elif self.pressedkey == 10: # 'ENTER' > Edit the process filter self.edit_filter = not self.edit_filter elif self.pressedkey == ord('1'): # '1' > Switch between CPU and PerCPU information self.args.percpu = not self.args.percpu elif self.pressedkey == ord('2'): # '2' > Enable/disable left sidebar self.args.disable_left_sidebar = not self.args.disable_left_sidebar elif self.pressedkey == ord('/'): # '/' > Switch between short/long name for processes self.args.process_short_name = not self.args.process_short_name elif self.pressedkey == ord('a'): # 'a' > Sort processes automatically self.args.process_sorted_by = 'auto' glances_processes.resetsort() elif self.pressedkey == ord('b'): # 'b' > Switch between bit/s and Byte/s for network IO # self.net_byteps_tag = not self.net_byteps_tag self.args.byte = not self.args.byte elif self.pressedkey == ord('c'): # 'c' > Sort processes by CPU usage self.args.process_sorted_by = 'cpu_percent' glances_processes.setmanualsortkey(self.args.process_sorted_by) elif self.pressedkey == ord('d'): # 'd' > Show/hide disk I/O stats self.args.disable_diskio = not self.args.disable_diskio elif self.pressedkey == ord('D'): # 'D' > Show/hide Docker stats self.args.disable_docker = not self.args.disable_docker elif self.pressedkey == ord('e'): # 'e' > Enable/Disable extended stats for top process self.args.enable_process_extended = not self.args.enable_process_extended if not self.args.enable_process_extended: glances_processes.disable_extended() else: glances_processes.enable_extended() elif self.pressedkey == ord('F'): # 'F' > Switch between FS available and free space self.args.fs_free_space = not self.args.fs_free_space elif self.pressedkey == ord('f'): # 'f' > Show/hide fs stats self.args.disable_fs = not self.args.disable_fs elif self.pressedkey == ord('g'): # 'g' > History self.history_tag = not self.history_tag elif self.pressedkey == ord('h'): # 'h' > Show/hide help self.args.help_tag = not self.args.help_tag elif self.pressedkey == ord('i'): # '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('l'): # 'l' > Show/hide log messages self.args.disable_log = not self.args.disable_log elif self.pressedkey == ord('m'): # 'm' > Sort processes by MEM usage self.args.process_sorted_by = 'memory_percent' glances_processes.setmanualsortkey(self.args.process_sorted_by) elif self.pressedkey == ord('n'): # 'n' > Show/hide network stats self.args.disable_network = not self.args.disable_network elif self.pressedkey == ord('p'): # 'p' > Sort processes by name self.args.process_sorted_by = 'name' glances_processes.setmanualsortkey(self.args.process_sorted_by) 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 elif self.pressedkey == ord('t'): # 't' > Sort processes by TIME usage self.args.process_sorted_by = 'cpu_times' glances_processes.setmanualsortkey(self.args.process_sorted_by) elif self.pressedkey == ord('T'): # 'T' > View network traffic as sum Rx+Tx self.args.network_sum = not self.args.network_sum elif self.pressedkey == ord('u'): # 'u' > View cumulative network IO (instead of bitrate) self.args.network_cumul = not self.args.network_cumul elif self.pressedkey == ord('w'): # 'w' > Delete finished warning logs glances_logs.clean() elif self.pressedkey == ord('x'): # 'x' > Delete finished warning and critical logs glances_logs.clean(critical=True) elif self.pressedkey == ord('z'): # 'z' > Enable/Disable processes stats (count + list + monitor) # Enable/Disable display self.args.disable_process = not self.args.disable_process # Enable/Disable update if self.args.disable_process: glances_processes.disable() else: glances_processes.enable() # Return the key code return self.pressedkey
# Import Glances lib from glances.core.glances_logging import logger # Import specific lib 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 def graph_enabled(self): """Return True if Glances can generaate history graphs""" return matplotlib_check
def parse_args(self): """Parse command line arguments.""" args = self.init_args().parse_args() # Load the configuration file, if it exists self.config = Config(args.conf_file) # Debug mode if args.debug: from logging import DEBUG logger.setLevel(DEBUG) # Client/server Port if args.port is None: if args.webserver: args.port = self.web_server_port else: args.port = self.server_port # Autodiscover if args.disable_autodiscover: logger.info("Auto discover mode is disabled") # In web server mode, defaul refresh time: 5 sec if args.webserver: args.time = 5 args.process_short_name = True # Server or client login/password args.username = self.username if args.password_prompt: # Interactive or file password if args.server: args.password = self.__get_password( description='Define the password for the Glances server', confirm=True) elif args.webserver: args.password = self.__get_password( description='Define the password for the Glances web server\nUser name: glances', confirm=True) elif args.client: args.password = self.__get_password( description='Enter the Glances server password', clear=True) else: # Default is no password args.password = self.password # By default help is hidden args.help_tag = False # Display Rx and Tx, not the sum for the network args.network_sum = False args.network_cumul = False # Manage full quicklook option if args.full_quicklook: args.disable_quicklook = False args.disable_cpu = True args.disable_mem = True args.disable_swap = True args.disable_load = False else: args.disable_quicklook = False args.disable_cpu = False args.disable_mem = False args.disable_swap = False args.disable_load = False # Control parameter and exit if it is not OK self.args = args # Export is only available in standalone or client mode (issue #614) export_tag = args.export_csv or args.export_statsd or args.export_influxdb or args.export_opentsdb or args.export_rabbitmq if not (self.is_standalone() or self.is_client()) and export_tag: logger.critical("Export is only available in standalone or client mode") sys.exit(2) # Filter is only available in standalone mode if args.process_filter is not None and not self.is_standalone(): logger.critical("Process filter is only available in standalone mode") sys.exit(2) # Check graph output path if args.enable_history and args.path_history is not None: if not os.access(args.path_history, os.W_OK): logger.critical("History output path {0} do not exist or is not writable".format(args.path_history)) sys.exit(2) logger.debug("History output path is set to {0}".format(args.path_history)) # Disable HDDTemp if sensors are disabled if args.disable_sensors: args.disable_hddtemp = True logger.debug("Sensors and HDDTemp are disabled") return args
def parse_args(self): """Parse command line arguments.""" args = self.init_args().parse_args() # Load the configuration file, if it exists self.config = Config(args.conf_file) # Debug mode if args.debug: from logging import DEBUG logger.setLevel(DEBUG) # Client/server Port if args.port is None: if args.webserver: args.port = self.web_server_port else: args.port = self.server_port # Autodiscover if args.disable_autodiscover: logger.info("Auto discover mode is disabled") # In web server mode, defaul refresh time: 5 sec if args.webserver: args.time = 5 args.process_short_name = True # Server or client login/password args.username = self.username if args.password_arg is not None: from hashlib import sha256 # Password is given as an argument # Hash with SHA256 # Only the SHA will be transmit on the network args.password = sha256(args.password_arg).hexdigest() elif args.password_prompt: # Interactive or file password if args.server: args.password = self.__get_password( description=_( "Define the password for the Glances server"), confirm=True) elif args.client: args.password = self.__get_password( description=_("Enter the Glances server password"), clear=True) else: # Default is no password args.password = self.password # By default help is hidden args.help_tag = False # Display Rx and Tx, not the sum for the network args.network_sum = False args.network_cumul = False # Control parameter and exit if it is not OK self.args = args # Filter is only available in standalone mode if args.process_filter is not None and not self.is_standalone(): logger.critical("Process filter is only available in standalone mode") sys.exit(2) # Check graph output path if args.enable_history and args.path_history is not None: if not os.access(args.path_history, os.W_OK): logger.critical("History output path {0} do not exist or is not writable".format(args.path_history)) sys.exit(2) logger.debug("History output path is set to {0}".format(args.path_history)) return args
def remove_service(self, zeroconf, srv_type, srv_name): """Remove the server from the list.""" self.servers.remove_server(srv_name) logger.info( "Glances server %s removed from the autodetect list" % srv_name)
except ImportError: print('PSutil library not found. Glances cannot start.') sys.exit(1) # Import Glances libs # Note: others Glances libs will be imported optionally from glances.core.glances_globals import gettext_domain, locale_dir from glances.core.glances_logging import logger from glances.core.glances_main import GlancesMain # Get PSutil version psutil_min_version = (2, 0, 0) psutil_version = tuple([int(num) for num in __psutil_version.split('.')]) # First log with Glances and PSUtil version logger.info('Start Glances {0}'.format(__version__)) logger.info('{0} {1} and PSutil {2} detected'.format( platform.python_implementation(), platform.python_version(), __psutil_version)) # Check PSutil version if psutil_version < psutil_min_version: logger.critical('PSutil 2.0 or higher is needed. Glances cannot start.') sys.exit(1) def __signal_handler(signal, frame): """Callback for CTRL-C.""" end()
def remove_service(self, zeroconf, srv_type, srv_name): # Remove the server from the list self.servers.remove_server(srv_name) logger.info( "Glances server %s removed from the autodetect list" % srv_name)
def main(): """Main entry point for Glances. Select the mode (standalone, client or server) Run it... """ # Log Glances and PSutil version logger.info('Start Glances {0}'.format(__version__)) logger.info('{0} {1} and PSutil {2} detected'.format( platform.python_implementation(), platform.python_version(), __psutil_version)) # Share global var global core, standalone, client, server, webserver # Create the Glances main instance core = GlancesMain() prctl.prctl(prctl.PDEATHSIG, signal.SIGTERM) # Catch the CTRL-C signal signal.signal(signal.SIGINT, __signal_handler) # Glances can be ran in standalone, client or server mode if core.is_standalone(): logger.info("Start standalone mode") # Import the Glances standalone module from glances.core.glances_standalone import GlancesStandalone # Init the standalone mode standalone = GlancesStandalone(config=core.get_config(), args=core.get_args()) # Start the standalone (CLI) loop standalone.serve_forever() elif core.is_client(): if core.is_client_browser(): logger.info("Start client mode (browser)") # Import the Glances client browser module from glances.core.glances_client_browser import GlancesClientBrowser # Init the client client = GlancesClientBrowser(config=core.get_config(), args=core.get_args()) else: logger.info("Start client mode") # Import the Glances client module from glances.core.glances_client import GlancesClient # Init the client client = GlancesClient(config=core.get_config(), args=core.get_args()) # Test if client and server are in the same major version if not client.login(): logger.critical("The server version is not compatible with the client") sys.exit(2) # Start the client loop client.serve_forever() # Shutdown the client client.end() elif core.is_server(): logger.info("Start server mode") # Import the Glances server module from glances.core.glances_server import GlancesServer args = core.get_args() server = GlancesServer(cached_time=core.cached_time, config=core.get_config(), args=args) print('Glances server is running on {0}:{1}'.format(args.bind_address, args.port)) # Set the server login/password (if -P/--password tag) if args.password != "": server.add_user(args.username, args.password) # Start the server loop server.serve_forever() # Shutdown the server? server.server_close() elif core.is_webserver(): logger.info("Start web server mode") # Import the Glances web server module from glances.core.glances_webserver import GlancesWebServer # Init the web server mode webserver = GlancesWebServer(config=core.get_config(), args=core.get_args()) # Start the web server loop webserver.serve_forever()
def parse_args(self): """Parse command line arguments.""" args = self.init_args().parse_args() # Load the configuration file, if it exists self.config = Config(args.conf_file) # Debug mode if args.debug: from logging import DEBUG logger.setLevel(DEBUG) # Client/server Port if args.port is None: if args.webserver: args.port = self.web_server_port else: args.port = self.server_port # Autodiscover if args.disable_autodiscover: logger.info("Auto discover mode is disabled") # In web server mode, defaul refresh time: 5 sec if args.webserver: args.time = 5 args.process_short_name = True # Server or client login/password args.username = self.username if args.password_prompt: # Interactive or file password if args.server: args.password = self.__get_password( description='Define the password for the Glances server', confirm=True) elif args.webserver: args.password = self.__get_password( description= 'Define the password for the Glances web server\nUser name: glances', confirm=True) elif args.client: args.password = self.__get_password( description='Enter the Glances server password', clear=True) else: # Default is no password args.password = self.password # By default help is hidden args.help_tag = False # Display Rx and Tx, not the sum for the network args.network_sum = False args.network_cumul = False # Manage full quicklook option if args.full_quicklook: args.disable_quicklook = False args.disable_cpu = True args.disable_mem = True args.disable_swap = True args.disable_load = False else: args.disable_quicklook = False args.disable_cpu = False args.disable_mem = False args.disable_swap = False args.disable_load = False # Control parameter and exit if it is not OK self.args = args # Export is only available in standalone or client mode (issue #614) export_tag = args.export_csv or args.export_statsd or args.export_influxdb or args.export_opentsdb or args.export_rabbitmq if not (self.is_standalone() or self.is_client()) and export_tag: logger.critical( "Export is only available in standalone or client mode") sys.exit(2) # Filter is only available in standalone mode if args.process_filter is not None and not self.is_standalone(): logger.critical( "Process filter is only available in standalone mode") sys.exit(2) # Check graph output path if args.enable_history and args.path_history is not None: if not os.access(args.path_history, os.W_OK): logger.critical( "History output path {0} do not exist or is not writable". format(args.path_history)) sys.exit(2) logger.debug("History output path is set to {0}".format( args.path_history)) # Disable HDDTemp if sensors are disabled if args.disable_sensors: args.disable_hddtemp = True logger.debug("Sensors and HDDTemp are disabled") return args
def __serve_forever(self): """Main client loop.""" while True: # No need to update the server list # It's done by the GlancesAutoDiscoverListener class (glances_autodiscover.py) # Or define staticaly in the configuration file (module glances_staticlist.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 str(e).find(" 401 ") > 0: # 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}".format(uri, e)) 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: from hashlib import sha256 # Display a popup to enter password clear_password = self.screen.display_popup( 'Password needed for {0}: '.format(v['name']), is_input=True) # Hash with SHA256 encoded_password = sha256(clear_password.encode('utf-8')).hexdigest() # Store the password for the selected server self.set_in_selected('password', encoded_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
def serve_forever(self): """Main client loop.""" while True: # No need to update the server list # It's done by the GlancesAutoDiscoverListener class (glances_autodiscover.py) # Or define staticaly in the configuration file (module glances_staticlist.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 # Select the connection mode (with or without password) if v['password'] != "": uri = 'http://{0}:{1}@{2}:{3}'.format( v['username'], v['password'], v['ip'], v['port']) else: uri = 'http://{0}:{1}'.format(v['ip'], v['port']) # 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 str(e).find(" 401 ") > 0: # 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}".format( uri, e)) 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.get_active() 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: %s" % self.get_servers_list()[self.screen.get_active()]) # Connection can take time # Display a popup self.screen.display_popup(_("Connect to %s:%s" % (v['name'], v['port'])), duration=1) # A password is needed to access to the server's stats if self.get_servers_list()[ self.screen.get_active()]['password'] is None: from hashlib import sha256 # Display a popup to enter password clear_password = self.screen.display_popup(_( "Password needed for %s: " % v['name']), is_input=True) # Hash with SHA256 encoded_password = sha256(clear_password).hexdigest() # Store the password for the selected server self.set_in_selected('password', encoded_password) # Display the Glance client on the selected server logger.info( "Connect Glances client to the %s server" % self.get_servers_list()[self.screen.get_active()]['key']) # Init the client args_server = self.args # Overwrite connection setting args_server.client = self.get_servers_list()[ self.screen.get_active()]['ip'] args_server.port = self.get_servers_list()[ self.screen.get_active()]['port'] args_server.username = self.get_servers_list()[ self.screen.get_active()]['username'] args_server.password = self.get_servers_list()[ self.screen.get_active()]['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 %s (see log file for additional information)" % 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 %s server" % self.get_servers_list()[ self.screen.get_active()]['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.set_active(None)
def main(): """Main entry point for Glances. Select the mode (standalone, client or server) Run it... """ # Setup translations locale.setlocale(locale.LC_ALL, '') gettext.install(gettext_domain, locale_dir) # Share global var global core, standalone, client, server, webserver # Create the Glances main instance core = GlancesMain() # Catch the CTRL-C signal signal.signal(signal.SIGINT, __signal_handler) # Glances can be ran in standalone, client or server mode if core.is_standalone(): logger.info("Start standalone mode") # Import the Glances standalone module from glances.core.glances_standalone import GlancesStandalone # Init the standalone mode standalone = GlancesStandalone(config=core.get_config(), args=core.get_args()) # Start the standalone (CLI) loop standalone.serve_forever() elif core.is_client(): if core.is_client_browser(): logger.info("Start client mode (browser)") # Import the Glances client browser module from glances.core.glances_client_browser import GlancesClientBrowser # Init the client client = GlancesClientBrowser(config=core.get_config(), args=core.get_args()) else: logger.info("Start client mode") # Import the Glances client module from glances.core.glances_client import GlancesClient # Init the client client = GlancesClient(config=core.get_config(), args=core.get_args()) # Test if client and server are in the same major version if not client.login(): logger.critical( "The server version is not compatible with the client") sys.exit(2) # Start the client loop client.serve_forever() # Shutdown the client client.end() elif core.is_server(): logger.info("Start server mode") # Import the Glances server module from glances.core.glances_server import GlancesServer args = core.get_args() server = GlancesServer(cached_time=core.cached_time, config=core.get_config(), args=args) print( _("Glances server is running on {0}:{1}").format( args.bind_address, args.port)) # Set the server login/password (if -P/--password tag) if args.password != "": server.add_user(args.username, args.password) # Start the server loop server.serve_forever() # Shutdown the server? server.server_close() elif core.is_webserver(): logger.info("Start web server mode") # Import the Glances web server module from glances.core.glances_webserver import GlancesWebServer # Init the web server mode webserver = GlancesWebServer(config=core.get_config(), args=core.get_args()) # Start the web server loop webserver.serve_forever()
def read(self): """Read the config file, if it exists. Using defaults otherwise.""" for config_file in self.config_file_paths(): if os.path.exists(config_file): try: if is_py3: self.parser.read(config_file, encoding='utf-8') else: self.parser.read(config_file) logger.info("Read configuration file '{0}'".format(config_file)) except UnicodeDecodeError as err: logger.error("Cannot decode configuration file '{0}': {1}".format(config_file, err)) sys.exit(1) # Save the loaded configuration file path (issue #374) self._loaded_config_file = config_file break # Quicklook if not self.parser.has_section('quicklook'): self.parser.add_section('quicklook') self.parser.set('quicklook', 'cpu_careful', '50') self.parser.set('quicklook', 'cpu_warning', '70') self.parser.set('quicklook', 'cpu_critical', '90') self.parser.set('quicklook', 'mem_careful', '50') self.parser.set('quicklook', 'mem_warning', '70') self.parser.set('quicklook', 'mem_critical', '90') self.parser.set('quicklook', 'swap_careful', '50') self.parser.set('quicklook', 'swap_warning', '70') self.parser.set('quicklook', 'swap_critical', '90') # CPU if not self.parser.has_section('cpu'): self.parser.add_section('cpu') self.parser.set('cpu', 'user_careful', '50') self.parser.set('cpu', 'user_warning', '70') self.parser.set('cpu', 'user_critical', '90') self.parser.set('cpu', 'iowait_careful', '50') self.parser.set('cpu', 'iowait_warning', '70') self.parser.set('cpu', 'iowait_critical', '90') self.parser.set('cpu', 'system_careful', '50') self.parser.set('cpu', 'system_warning', '70') self.parser.set('cpu', 'system_critical', '90') self.parser.set('cpu', 'steal_careful', '50') self.parser.set('cpu', 'steal_warning', '70') self.parser.set('cpu', 'steal_critical', '90') # Per-CPU if not self.parser.has_section('percpu'): self.parser.add_section('percpu') self.parser.set('percpu', 'user_careful', '50') self.parser.set('percpu', 'user_warning', '70') self.parser.set('percpu', 'user_critical', '90') self.parser.set('percpu', 'iowait_careful', '50') self.parser.set('percpu', 'iowait_warning', '70') self.parser.set('percpu', 'iowait_critical', '90') self.parser.set('percpu', 'system_careful', '50') self.parser.set('percpu', 'system_warning', '70') self.parser.set('percpu', 'system_critical', '90') # Load if not self.parser.has_section('load'): self.parser.add_section('load') self.parser.set('load', 'careful', '0.7') self.parser.set('load', 'warning', '1.0') self.parser.set('load', 'critical', '5.0') # Mem if not self.parser.has_section('mem'): self.parser.add_section('mem') self.parser.set('mem', 'careful', '50') self.parser.set('mem', 'warning', '70') self.parser.set('mem', 'critical', '90') # Swap if not self.parser.has_section('memswap'): self.parser.add_section('memswap') self.parser.set('memswap', 'careful', '50') self.parser.set('memswap', 'warning', '70') self.parser.set('memswap', 'critical', '90') # FS if not self.parser.has_section('fs'): self.parser.add_section('fs') self.parser.set('fs', 'careful', '50') self.parser.set('fs', 'warning', '70') self.parser.set('fs', 'critical', '90') # Sensors if not self.parser.has_section('sensors'): self.parser.add_section('sensors') self.parser.set('sensors', 'temperature_core_careful', '60') self.parser.set('sensors', 'temperature_core_warning', '70') self.parser.set('sensors', 'temperature_core_critical', '80') self.parser.set('sensors', 'temperature_hdd_careful', '45') self.parser.set('sensors', 'temperature_hdd_warning', '52') self.parser.set('sensors', 'temperature_hdd_critical', '60') self.parser.set('sensors', 'battery_careful', '80') self.parser.set('sensors', 'battery_warning', '90') self.parser.set('sensors', 'battery_critical', '95') # Process list if not self.parser.has_section('processlist'): self.parser.add_section('processlist') self.parser.set('processlist', 'cpu_careful', '50') self.parser.set('processlist', 'cpu_warning', '70') self.parser.set('processlist', 'cpu_critical', '90') self.parser.set('processlist', 'mem_careful', '50') self.parser.set('processlist', 'mem_warning', '70') self.parser.set('processlist', 'mem_critical', '90')
def login(self): """Logon to the server.""" ret = True if not self.args.snmp_force: # First of all, trying to connect to a Glances server self.set_mode('glances') client_version = None try: client_version = self.client.init() except socket.error as err: # Fallback to SNMP logger.error("Connection to Glances server failed (%s)" % err) self.set_mode('snmp') fallbackmsg = _("Trying fallback to SNMP...") if not self.return_to_browser: print(fallbackmsg) else: logger.info(fallbackmsg) except ProtocolError as err: # Others errors if str(err).find(" 401 ") > 0: msg = "Connection to server failed (bad password)" else: msg = "Connection to server failed ({0})".format(err) self.log_and_exit(msg) return False if self.get_mode() == 'glances' and version.split( '.')[0] == client_version.split('.')[0]: # Init stats self.stats = GlancesStatsClient() self.stats.set_plugins(json.loads(self.client.getAllPlugins())) logger.debug("Client version: %s / Server version: %s" % (version, client_version)) elif self.get_mode() == 'glances': self.log_and_exit( "Client and server not compatible: Client version: %s / Server version: %s" % (version, client_version)) return False else: self.set_mode('snmp') if self.get_mode() == 'snmp': logger.info("Trying to grab stats by SNMP...") # Fallback to SNMP if needed from glances.core.glances_stats import GlancesStatsClientSNMP # Init stats self.stats = GlancesStatsClientSNMP(args=self.args) if not self.stats.check_snmp(): self.log_and_exit("Connection to SNMP server failed") return False if ret: # Load limits from the configuration file # Each client can choose its owns limits self.stats.load_limits(self.config) # Init screen self.screen = GlancesCursesClient(args=self.args) # Return result return ret
def main(): """Main entry point for Glances. Select the mode (standalone, client or server) Run it... """ # Setup translations locale.setlocale(locale.LC_ALL, '') gettext.install(gettext_domain, locale_dir) # Share global var global core, standalone, client, server, webserver # Create the Glances main instance core = GlancesMain() # Catch the CTRL-C signal signal.signal(signal.SIGINT, __signal_handler) # Glances can be ran in standalone, client or server mode if core.is_standalone(): logger.info("Start standalone mode") # Import the Glances standalone module from glances.core.glances_standalone import GlancesStandalone # Init the standalone mode standalone = GlancesStandalone(config=core.get_config(), args=core.get_args()) # Start the standalone (CLI) loop standalone.serve_forever() elif core.is_client(): if core.is_client_browser(): logger.info("Start client mode (browser)") # Import the Glances client browser module from glances.core.glances_client_browser import GlancesClientBrowser # Init the client client = GlancesClientBrowser(config=core.get_config(), args=core.get_args()) else: logger.info("Start client mode") # Import the Glances client module from glances.core.glances_client import GlancesClient # Init the client client = GlancesClient(config=core.get_config(), args=core.get_args()) # Test if client and server are in the same major version if not client.login(): logger.critical("The server version is not compatible with the client") sys.exit(2) # Start the client loop client.serve_forever() # Shutdown the client client.end() elif core.is_server(): logger.info("Start server mode") # Import the Glances server module from glances.core.glances_server import GlancesServer args = core.get_args() server = GlancesServer(cached_time=core.cached_time, config=core.get_config(), args=args) print(_("Glances server is running on {0}:{1}").format(args.bind_address, args.port)) # Set the server login/password (if -P/--password tag) if args.password != "": server.add_user(args.username, args.password) # Start the server loop server.serve_forever() # Shutdown the server? server.server_close() elif core.is_webserver(): logger.info("Start web server mode") # Import the Glances web server module from glances.core.glances_webserver import GlancesWebServer # Init the web server mode webserver = GlancesWebServer(config=core.get_config(), args=core.get_args()) # Start the web server loop webserver.serve_forever()
def __catch_key(self, return_to_browser=False): # Catch the pressed key self.pressedkey = self.get_key(self.term_window) # Actions... if self.pressedkey == ord("\x1b") or self.pressedkey == ord("q"): # 'ESC'|'q' > Quit if return_to_browser: logger.info("Stop Glances client and return to the browser") else: self.end() logger.info("Stop Glances") sys.exit(0) elif self.pressedkey == 10: # 'ENTER' > Edit the process filter self.edit_filter = not self.edit_filter elif self.pressedkey == ord("1"): # '1' > Switch between CPU and PerCPU information self.args.percpu = not self.args.percpu elif self.pressedkey == ord("2"): # '2' > Enable/disable left sidebar self.args.disable_left_sidebar = not self.args.disable_left_sidebar elif self.pressedkey == ord("3"): # '3' > Enable/disable quicklook self.args.disable_quicklook = not self.args.disable_quicklook elif self.pressedkey == ord("/"): # '/' > Switch between short/long name for processes self.args.process_short_name = not self.args.process_short_name elif self.pressedkey == ord("a"): # 'a' > Sort processes automatically and reset to 'cpu_percent' glances_processes.auto_sort = True glances_processes.sort_key = "cpu_percent" elif self.pressedkey == ord("b"): # 'b' > Switch between bit/s and Byte/s for network IO # self.net_byteps_tag = not self.net_byteps_tag self.args.byte = not self.args.byte elif self.pressedkey == ord("c"): # 'c' > Sort processes by CPU usage glances_processes.auto_sort = False glances_processes.sort_key = "cpu_percent" elif self.pressedkey == ord("d"): # 'd' > Show/hide disk I/O stats self.args.disable_diskio = not self.args.disable_diskio elif self.pressedkey == ord("D"): # 'D' > Show/hide Docker stats self.args.disable_docker = not self.args.disable_docker elif self.pressedkey == ord("e"): # 'e' > Enable/Disable extended stats for top process self.args.enable_process_extended = not self.args.enable_process_extended if not self.args.enable_process_extended: glances_processes.disable_extended() else: glances_processes.enable_extended() elif self.pressedkey == ord("F"): # 'F' > Switch between FS available and free space self.args.fs_free_space = not self.args.fs_free_space elif self.pressedkey == ord("f"): # 'f' > Show/hide fs stats self.args.disable_fs = not self.args.disable_fs elif self.pressedkey == ord("g"): # 'g' > History self.history_tag = not self.history_tag elif self.pressedkey == ord("h"): # 'h' > Show/hide help self.args.help_tag = not self.args.help_tag elif self.pressedkey == ord("i"): # 'i' > Sort processes by IO rate (not available on OS X) glances_processes.auto_sort = False glances_processes.sort_key = "io_counters" 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 elif self.pressedkey == ord("m"): # 'm' > Sort processes by MEM usage glances_processes.auto_sort = False glances_processes.sort_key = "memory_percent" elif self.pressedkey == ord("n"): # 'n' > Show/hide network stats self.args.disable_network = not self.args.disable_network elif self.pressedkey == ord("p"): # 'p' > Sort processes by name glances_processes.auto_sort = False glances_processes.sort_key = "name" 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 elif self.pressedkey == ord("t"): # 't' > Sort processes by TIME usage glances_processes.auto_sort = False glances_processes.sort_key = "cpu_times" elif self.pressedkey == ord("T"): # 'T' > View network traffic as sum Rx+Tx self.args.network_sum = not self.args.network_sum elif self.pressedkey == ord("u"): # 'u' > Sort processes by USER glances_processes.auto_sort = False glances_processes.sort_key = "username" elif self.pressedkey == ord("U"): # 'U' > View cumulative network I/O (instead of bitrate) self.args.network_cumul = not self.args.network_cumul elif self.pressedkey == ord("w"): # 'w' > Delete finished warning logs glances_logs.clean() elif self.pressedkey == ord("x"): # 'x' > Delete finished warning and critical logs glances_logs.clean(critical=True) elif self.pressedkey == ord("z"): # 'z' > Enable/Disable processes stats (count + list + monitor) # Enable/Disable display self.args.disable_process = not self.args.disable_process # Enable/Disable update if self.args.disable_process: glances_processes.disable() else: glances_processes.enable() # Return the key code return self.pressedkey