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 can not 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(_('Can not detect SNMP system name')) return ret
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 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")) self.set_mode('snmp') fallbackmsg = _("Trying fallback to SNMP...") print(fallbackmsg) except ProtocolError as err: # Others errors if str(err).find(" 401 ") > 0: logger.error( _("Connection to server failed (Bad password)")) else: logger.error( _("Connection to server failed ({0})").format(err)) sys.exit(2) if self.get_mode( ) == 'glances' and version[:3] == client_version[:3]: # Init stats self.stats = GlancesStatsClient() self.stats.set_plugins(json.loads(self.client.getAllPlugins())) else: logger.error("Client version: %s / Server version: %s" % (version, client_version)) 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(): logger.error(_("Connection to SNMP server failed")) sys.exit(2) 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 = GlancesCurses(args=self.args) # Return result 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 args.disable_process_extended: logger.info(_("Extended stats for top process is disabled")) glances_processes.disable_extended() else: logger.debug(_("Extended stats for top process is enabled (default behavor)")) glances_processes.enable_extended() # Manage optionnal process filter if args.process_filter is not None: glances_processes.set_process_filter(args.process_filter) # Initial system informations update self.stats.update() # Init CSV output if args.output_csv is not None: from glances.outputs.glances_csv import GlancesCSV self.csvoutput = GlancesCSV(args=args) self.csv_tag = True else: self.csv_tag = False # Init screen self.screen = GlancesCurses(args=args)
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 can not 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(_('Can not 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 20 glances_processes.set_max_processes(20) # If process extended stats is disabled by user if args.disable_process_extended: logger.info(_("Extended stats for top process is disabled")) glances_processes.disable_extended() else: logger.debug( _("Extended stats for top process is enabled (default behavor)" )) glances_processes.enable_extended() # Manage optionnal process filter if args.process_filter is not None: glances_processes.set_process_filter(args.process_filter) # Initial system informations update self.stats.update() # Init CSV output if args.output_csv is not None: from glances.outputs.glances_csv import GlancesCSV self.csvoutput = GlancesCSV(args=args) self.csv_tag = True else: self.csv_tag = False # Init screen self.screen = GlancesCurses(args=args)
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")) self.set_mode('snmp') fallbackmsg = _("Trying fallback to SNMP...") print(fallbackmsg) except ProtocolError as err: # Others errors if str(err).find(" 401 ") > 0: logger.error(_("Connection to server failed (Bad password)")) else: logger.error(_("Connection to server failed ({0})").format(err)) sys.exit(2) if self.get_mode() == 'glances' and version[:3] == client_version[:3]: # Init stats self.stats = GlancesStatsClient() self.stats.set_plugins(json.loads(self.client.getAllPlugins())) else: logger.error("Client version: %s / Server version: %s" % (version, client_version)) 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(): logger.error(_("Connection to SNMP server failed")) sys.exit(2) 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 = GlancesCurses(args=self.args) # Return result return ret
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, but passwords did not match...")) 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 set_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.get_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 return self.process_filter
def set_process_filter(self, value): """Set the process filter""" logger.info(_("Set process filter to %s") % value) self.process_filter = value if value is not None: try: self.process_filter_re = re.compile(value) logger.debug(_("Process filter regular expression compilation OK: %s") % self.get_process_filter()) except: logger.error(_("Can not compile process filter regular expression: %s") % value) self.process_filter_re = None else: self.process_filter_re = None return self.process_filter
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 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 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 %s") % 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): # 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 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 __init__(self, config=None, args=None): # Init stats self.stats = GlancesStats(config=config, args=args) # If configured, set the maximum processes number to display try: max_processes = int( self.stats.get_plugin('processlist').get_conf_value( 'max_processes')) logger.debug( _("Limit maximum displayed processes to %s") % max_processes) except: max_processes = None logger.warning( _("Maximum displayed processes is not configured (high CPU consumption)" )) glances_processes.set_max_processes(max_processes) # If process extended stats is disabled by user if args.disable_process_extended: logger.info(_("Extended stats for top process is disabled")) glances_processes.disable_extended() else: logger.debug( _("Extended stats for top process is enabled (default behavor)" )) glances_processes.enable_extended() # Manage optionnal process filter if args.process_filter is not None: glances_processes.set_process_filter(args.process_filter) # Initial system informations update self.stats.update() # Init CSV output if args.output_csv is not None: from glances.outputs.glances_csv import GlancesCSV self.csvoutput = GlancesCSV(args=args) self.csv_tag = True else: self.csv_tag = False # Init screen self.screen = GlancesCurses(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 __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( _("Error: Cannot create the CSV file: {0}").format(e)) sys.exit(2) logger.info( _("Stats dumped to CSV file: {0}").format(self.csv_filename))
def set_process_filter(self, value): """Set the process filter""" logger.info(_("Set process filter to %s") % value) self.process_filter = value if value is not None: try: self.process_filter_re = re.compile(value) logger.debug( _("Process filter regular expression compilation OK: %s") % self.get_process_filter()) except: logger.error( _("Can not compile process filter regular expression: %s") % value) self.process_filter_re = None else: self.process_filter_re = None return self.process_filter
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 CSV output if args.output_csv is not None: from glances.outputs.glances_csv import GlancesCSV self.csvoutput = GlancesCSV(args=args) self.csv_tag = True else: self.csv_tag = False # Init screen self.screen = GlancesCursesStandalone(args=args)
def __init__(self, config=None, args=None): # Init stats self.stats = GlancesStats(config=config, args=args) # If configured, set the maximum processes number to display try: max_processes = int(self.stats.get_plugin('processlist').get_conf_value('max_processes')) logger.debug(_("Limit maximum displayed processes to %s") % max_processes) except: max_processes = None logger.warning(_("Maximum displayed processes is not configured (high CPU consumption)")) glances_processes.set_max_processes(max_processes) # If process extended stats is disabled by user if args.disable_process_extended: logger.info(_("Extended stats for top process is disabled")) glances_processes.disable_extended() else: logger.debug(_("Extended stats for top process is enabled (default behavor)")) glances_processes.enable_extended() # Manage optionnal process filter if args.process_filter is not None: glances_processes.set_process_filter(args.process_filter) # Initial system informations update self.stats.update() # Init CSV output if args.output_csv is not None: from glances.outputs.glances_csv import GlancesCSV self.csvoutput = GlancesCSV(args=args) self.csv_tag = True else: self.csv_tag = False # Init screen self.screen = GlancesCurses(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 __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 %s selected" % (self.cursor_get() + 1)) self.set_active(self.cursor_get()) elif self.pressedkey == 259: # 'UP' > Up in the server list logger 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 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 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(): 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.close() 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()
from psutil import __version__ as __psutil_version 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, 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()
import tempfile # Import Glances lib from glances.core.glances_globals import logger # Import specific lib try: from matplotlib import __version__ as matplotlib_version import matplotlib.pyplot as plt import matplotlib.dates as dates except: matplotlib_check = False logger.warning('Can not 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=tempfile.gettempdir()): # !!! MINUS: matplotlib footprint (mem/cpu) => Fork process ? # !!! MINUS: Mem used to store history # !!! TODO: sampling before graph => Usefull ? # !!! TODO: do not display first two point (glances is running) # !!! TODO: replace /tmp by a cross platform way to get /tmp folder self.output_folder = output_folder def get_output_folder(self):
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 # 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
from psutil import __version__ as __psutil_version 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, 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 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(): 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.close() 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 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 __catch_key(self): # Catch the pressed key # ~ self.pressedkey = self.term_window.getch() 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") 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('/'): # '/' > 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('e'): # 'e' > Enable/Disable extended stats for top process self.args.disable_process_extended = not self.args.disable_process_extended if self.args.disable_process_extended: glances_processes.disable_extended() else: glances_processes.enable_extended() 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('s'): # 's' > Show/hide sensors stats (Linux-only) self.args.disable_sensors = not self.args.disable_sensors 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
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(_("Error: 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: 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: 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') from glances.outputs.glances_history import GlancesHistory self.glances_history = GlancesHistory() if not self.glances_history.graph_enabled(): args.enable_history = False logger.error( 'Stats history disabled because graph lib is not available' )
# Import Glances lib from glances.core.glances_globals import logger # Import specific lib try: from matplotlib import __version__ as matplotlib_version import matplotlib.pyplot as plt import matplotlib.dates as dates except: matplotlib_check = False logger.warning( 'Can not 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=tempfile.gettempdir()): # !!! MINUS: matplotlib footprint (mem/cpu) => Fork process ? # !!! MINUS: Mem used to store history # !!! TODO: sampling before graph => Usefull ? # !!! TODO: do not display first two point (glances is running) # !!! TODO: replace /tmp by a cross platform way to get /tmp 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 __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('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('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
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.outputs.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')