mirror of https://github.com/nicolargo/glances
Correct issue #414
parent
7d5dca88c7
commit
934a7479f3
|
@ -121,30 +121,34 @@ def main():
|
||||||
standalone.serve_forever()
|
standalone.serve_forever()
|
||||||
|
|
||||||
elif core.is_client():
|
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())
|
|
||||||
|
|
||||||
if core.is_client_autodiscover():
|
if core.is_client_autodiscover():
|
||||||
# !!! Create a new script with the client_browser feature
|
logger.info("Start client mode (browser)")
|
||||||
import time
|
|
||||||
while True:
|
# Import the Glances client browser module
|
||||||
print client.get_servers_list()
|
from glances.core.glances_client_browser import GlancesClientBrowser
|
||||||
time.sleep(3)
|
|
||||||
|
# Init the client
|
||||||
|
client = GlancesClientBrowser(config=core.get_config(),
|
||||||
|
args=core.get_args())
|
||||||
|
|
||||||
else:
|
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
|
# Test if client and server are in the same major version
|
||||||
if not client.login():
|
if not client.login():
|
||||||
logger.critical(
|
logger.critical(
|
||||||
_("The server version is not compatible with the client"))
|
_("The server version is not compatible with the client"))
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
||||||
# Start the client loop
|
# Start the client loop
|
||||||
client.serve_forever()
|
client.serve_forever()
|
||||||
|
|
||||||
# Shutdown the client
|
# Shutdown the client
|
||||||
client.close()
|
client.close()
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# This file is part of Glances.
|
||||||
|
#
|
||||||
|
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||||
|
#
|
||||||
|
# Glances is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Glances is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
"""Manage the Glances client browser (list of Glances server)."""
|
||||||
|
|
||||||
|
# Import system libs
|
||||||
|
import time
|
||||||
|
import json
|
||||||
|
try:
|
||||||
|
from xmlrpc.client import Transport, ServerProxy, ProtocolError, Fault
|
||||||
|
except ImportError:
|
||||||
|
# Python 2
|
||||||
|
from xmlrpclib import Transport, ServerProxy, ProtocolError, Fault
|
||||||
|
|
||||||
|
# Import Glances libs
|
||||||
|
from glances.core.glances_globals import logger
|
||||||
|
from glances.outputs.glances_curses import GlancesCurses
|
||||||
|
from glances.core.glances_autodiscover import GlancesAutoDiscoverServer
|
||||||
|
|
||||||
|
|
||||||
|
class GlancesClientBrowser(object):
|
||||||
|
|
||||||
|
"""This class creates and manages the TCP client browser (servers' list)."""
|
||||||
|
|
||||||
|
def __init__(self, config=None, args=None):
|
||||||
|
# Store the arg/config
|
||||||
|
self.args = args
|
||||||
|
self.config = config
|
||||||
|
|
||||||
|
# Start the autodiscover mode (Zeroconf listener)
|
||||||
|
if self.args.autodiscover:
|
||||||
|
self.autodiscover_server = GlancesAutoDiscoverServer()
|
||||||
|
|
||||||
|
# Init screen
|
||||||
|
self.screen = GlancesCurses(args=self.args)
|
||||||
|
|
||||||
|
def get_servers_list(self):
|
||||||
|
"""Return the current server list (dict of dict)"""
|
||||||
|
if self.args.autodiscover:
|
||||||
|
return self.autodiscover_server.get_servers_list()
|
||||||
|
else:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
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)
|
||||||
|
# For each server in the list, grab elementary stats (CPU, LOAD, MEM)
|
||||||
|
# logger.debug(self.get_servers_list())
|
||||||
|
try:
|
||||||
|
iteritems = self.get_servers_list().iteritems()
|
||||||
|
except AttributeError:
|
||||||
|
iteritems = self.get_servers_list().items()
|
||||||
|
for k, v in iteritems:
|
||||||
|
s = ServerProxy('http://%s:%s' % (self.get_servers_list()[k]['ip'], self.get_servers_list()[k]['port']))
|
||||||
|
# !!! 3 requests => high CPU consumption on the server :(
|
||||||
|
# !!! Try a getAll ??? Optimize server ???
|
||||||
|
self.get_servers_list()[k]['load_min5'] = json.loads(s.getLoad())['min5']
|
||||||
|
self.get_servers_list()[k]['cpu_percent'] = 100 - json.loads(s.getCpu())['idle']
|
||||||
|
self.get_servers_list()[k]['mem_percent'] = json.loads(s.getMem())['percent']
|
||||||
|
|
||||||
|
# Update the screen
|
||||||
|
self.screen.update_browser(self.get_servers_list())
|
||||||
|
|
||||||
|
def end(self):
|
||||||
|
"""End of the client session."""
|
||||||
|
pass
|
|
@ -149,8 +149,12 @@ class GlancesProcesses(object):
|
||||||
procstat['mandatory_stats'] = True
|
procstat['mandatory_stats'] = True
|
||||||
|
|
||||||
# Process CPU, MEM percent and name
|
# Process CPU, MEM percent and name
|
||||||
procstat.update(
|
try:
|
||||||
proc.as_dict(attrs=['cpu_percent', 'memory_percent', 'name'], ad_value=''))
|
procstat.update(
|
||||||
|
proc.as_dict(attrs=['cpu_percent', 'memory_percent', 'name'], ad_value=''))
|
||||||
|
except psutil.NoSuchProcess:
|
||||||
|
# Correct issue #414
|
||||||
|
return None
|
||||||
if procstat['cpu_percent'] == '' or procstat['memory_percent'] == '':
|
if procstat['cpu_percent'] == '' or procstat['memory_percent'] == '':
|
||||||
# Do not display process if we can not get the basic
|
# Do not display process if we can not get the basic
|
||||||
# cpu_percent or memory_percent stats
|
# cpu_percent or memory_percent stats
|
||||||
|
|
|
@ -176,8 +176,7 @@ class GlancesInstance(object):
|
||||||
if item.startswith(header):
|
if item.startswith(header):
|
||||||
try:
|
try:
|
||||||
# Update the stat
|
# Update the stat
|
||||||
# !!! All the stat are updated before one grab (not optimized)
|
self.__update__()
|
||||||
self.stats.update()
|
|
||||||
# Return the attribute
|
# Return the attribute
|
||||||
return getattr(self.stats, item)
|
return getattr(self.stats, item)
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|
|
@ -361,6 +361,65 @@ class GlancesCurses(object):
|
||||||
"""New column in the curses interface"""
|
"""New column in the curses interface"""
|
||||||
self.column = self.next_column
|
self.column = self.next_column
|
||||||
|
|
||||||
|
def display_browser(self, servers_list):
|
||||||
|
"""Display the servers list
|
||||||
|
Return:
|
||||||
|
True if the stats have been displayed
|
||||||
|
False if the help have been displayed
|
||||||
|
"""
|
||||||
|
# Init the internal line/column for Glances Curses
|
||||||
|
self.init_line_column()
|
||||||
|
|
||||||
|
# Get the current screen size
|
||||||
|
screen_x = self.screen.getmaxyx()[1]
|
||||||
|
screen_y = self.screen.getmaxyx()[0]
|
||||||
|
|
||||||
|
# Display header
|
||||||
|
x = 0
|
||||||
|
y = 0
|
||||||
|
if len(servers_list) == 0:
|
||||||
|
msg = _("No Glances server detected on your network")
|
||||||
|
elif len(servers_list) == 1:
|
||||||
|
msg = _("One Glances server detected on your network")
|
||||||
|
else:
|
||||||
|
msg = _("%d Glances servers detected on your network" % len(servers_list))
|
||||||
|
self.term_window.addnstr(y, x,
|
||||||
|
msg,
|
||||||
|
screen_x - x,
|
||||||
|
self.__colors_list['TITLE'])
|
||||||
|
|
||||||
|
# Display the Glances server list
|
||||||
|
y = 2
|
||||||
|
try:
|
||||||
|
iteritems = servers_list.iteritems()
|
||||||
|
except AttributeError:
|
||||||
|
iteritems = servers_list.items()
|
||||||
|
for k, v in iteritems:
|
||||||
|
# Display server address:port
|
||||||
|
msg = "%s:%s" % (servers_list[k]['ip'], servers_list[k]['port'])
|
||||||
|
self.term_window.addnstr(y, x,
|
||||||
|
"%21s" % msg,
|
||||||
|
screen_x - x,
|
||||||
|
self.__colors_list['BOLD'])
|
||||||
|
# Display server LOAD
|
||||||
|
self.term_window.addnstr(y, x + 24,
|
||||||
|
"%6s" % servers_list[k]['load_min5'],
|
||||||
|
screen_x - x,
|
||||||
|
self.__colors_list['DEFAULT'])
|
||||||
|
# Display server CPU%
|
||||||
|
self.term_window.addnstr(y, x + 32,
|
||||||
|
"%6s" % servers_list[k]['cpu_percent'],
|
||||||
|
screen_x - x,
|
||||||
|
self.__colors_list['DEFAULT'])
|
||||||
|
# Display server MEM%
|
||||||
|
self.term_window.addnstr(y, x + 40,
|
||||||
|
"%6s" % servers_list[k]['mem_percent'],
|
||||||
|
screen_x - x,
|
||||||
|
self.__colors_list['DEFAULT'])
|
||||||
|
y += 1
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
def display(self, stats, cs_status="None"):
|
def display(self, stats, cs_status="None"):
|
||||||
"""Display stats on the screen.
|
"""Display stats on the screen.
|
||||||
|
|
||||||
|
@ -731,6 +790,14 @@ class GlancesCurses(object):
|
||||||
self.erase()
|
self.erase()
|
||||||
self.display(stats, cs_status=cs_status)
|
self.display(stats, cs_status=cs_status)
|
||||||
|
|
||||||
|
def flush_browser(self, servers_list):
|
||||||
|
"""Update the servers' list screen.
|
||||||
|
|
||||||
|
servers_list: Dict of dict with servers stats
|
||||||
|
"""
|
||||||
|
self.erase()
|
||||||
|
self.display_browser(servers_list)
|
||||||
|
|
||||||
def update(self, stats, cs_status="None"):
|
def update(self, stats, cs_status="None"):
|
||||||
"""Update the screen.
|
"""Update the screen.
|
||||||
|
|
||||||
|
@ -755,6 +822,26 @@ class GlancesCurses(object):
|
||||||
# Wait 100ms...
|
# Wait 100ms...
|
||||||
curses.napms(100)
|
curses.napms(100)
|
||||||
|
|
||||||
|
def update_browser(self, servers_list):
|
||||||
|
"""Update the servers' list screen.
|
||||||
|
|
||||||
|
Wait for __refresh_time sec / catch key every 100 ms.
|
||||||
|
|
||||||
|
servers_list: Dict of dict with servers stats
|
||||||
|
"""
|
||||||
|
# Flush display
|
||||||
|
self.flush_browser(servers_list)
|
||||||
|
|
||||||
|
# Wait
|
||||||
|
countdown = Timer(self.__refresh_time)
|
||||||
|
while not countdown.finished():
|
||||||
|
# Getkey
|
||||||
|
if self.__catch_key() > -1:
|
||||||
|
# Redraw display
|
||||||
|
self.flush_browser(servers_list)
|
||||||
|
# Wait 100ms...
|
||||||
|
curses.napms(100)
|
||||||
|
|
||||||
def get_stats_display_width(self, curse_msg, without_option=False):
|
def get_stats_display_width(self, curse_msg, without_option=False):
|
||||||
"""Return the width of the formatted curses message.
|
"""Return the width of the formatted curses message.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue