Browser first public version !

This commit is contained in:
Nicolargo 2014-11-16 19:15:46 +01:00
parent 891827ace4
commit af62415923
5 changed files with 124 additions and 59 deletions

View File

@ -151,7 +151,7 @@ def main():
client.serve_forever()
# Shutdown the client
client.close()
client.end()
elif core.is_server():
logger.info("Start server mode")

View File

@ -21,7 +21,6 @@
# Import system libs
import socket
import time
try:
import netifaces
netifaces_tag = True
@ -55,9 +54,14 @@ class AutoDiscovered(object):
def add_server(self, name, ip, port):
"""Add a new server to the list"""
new_server = {'key': name, 'name': name.split(':')[0], 'ip': ip, 'port': port}
new_server = {'key': name, # Zeroconf name with both hostname and port
'name': name.split(':')[0], # Short name
'ip': ip, # IP address seen by the client
'port': port, # TCP port
}
self._server_list.append(new_server)
logger.debug("Servers list: %s" % self._server_list)
logger.debug("Updated servers list (%s servers): %s" %
(len(self._server_list), self._server_list))
def remove_server(self, name):
"""Remove a server from the dict"""
@ -66,9 +70,11 @@ class AutoDiscovered(object):
try:
self._server_list.remove(i)
logger.debug("Remove server %s from the list" % name)
logger.debug("Updated servers list: %s" % self._server_list)
logger.debug("Updated servers list (%s servers): %s" % (
len(self._server_list), self._server_list))
except ValueError:
logger.error("Can not remove server %s from the list" % name)
logger.error(
"Can not remove server %s from the list" % name)
class GlancesAutoDiscoverListener(object):
@ -90,7 +96,8 @@ class GlancesAutoDiscoverListener(object):
"""
if srv_type != zeroconf_type:
return False
logger.debug("Check new Zeroconf server: %s / %s" % (srv_type, srv_name))
logger.debug("Check new Zeroconf server: %s / %s" %
(srv_type, srv_name))
info = zeroconf.getServiceInfo(srv_type, srv_name)
if info:
new_server_ip = socket.inet_ntoa(info.getAddress())
@ -145,21 +152,23 @@ class GlancesAutoDiscoverClient(object):
def __init__(self, hostname, args=None):
if netifaces_tag:
# !!! TO BE REFACTOR
try:
zeroconf_bind_address = netifaces.ifaddresses(netifaces.interfaces()[1])[netifaces.AF_INET][0]['addr']
zeroconf_bind_address = netifaces.ifaddresses(
netifaces.interfaces()[1])[netifaces.AF_INET][0]['addr']
except:
zeroconf_bind_address = args.bind_address
print("Announce the Glances server on the local area network (using %s IP address)" % zeroconf_bind_address)
# /!!!
print("Announce the Glances server on the local area network (using %s IP address)" %
zeroconf_bind_address)
if zeroconf_tag:
logger.info(
"Announce the Glances server on the local area network (using %s IP address)" % zeroconf_bind_address)
self.zeroconf = Zeroconf()
self.info = ServiceInfo(zeroconf_type,
hostname+':'+str(args.port)+'.'+zeroconf_type,
address=socket.inet_aton(zeroconf_bind_address),
hostname + ':' +
str(args.port) + '.' + zeroconf_type,
address=socket.inet_aton(
zeroconf_bind_address),
port=args.port,
weight=0,
priority=0,

View File

@ -78,20 +78,9 @@ class GlancesClient(object):
try:
self.client = ServerProxy(uri, transport=transport)
except Exception as e:
logger.error("Couldn't create socket {0}: {1}".format(uri, e))
logger.error("Client couldn't create socket {0}: {1}".format(uri, e))
sys.exit(2)
# Start the autodiscover mode (Zeroconf listener)
if self.args.autodiscover:
self.autodiscover_server = GlancesAutoDiscoverServer()
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 set_mode(self, mode='glances'):
"""Set the client mode.
@ -175,7 +164,7 @@ class GlancesClient(object):
return self.update_snmp()
else:
self.end()
logger.critical("Unknown server mode: {0}").format(self.get_mode())
logger.critical(_("Unknown server mode: {0}").format(self.get_mode()))
sys.exit(2)
def update_glances(self):
@ -217,14 +206,19 @@ class GlancesClient(object):
# Grab success
return "SNMP"
def serve_forever(self):
def serve_forever(self, return_to_browser=False):
"""Main client loop."""
while True:
exitkey = False
while True and not exitkey:
# Update the stats
cs_status = self.update()
# Update the screen
self.screen.update(self.stats, cs_status=cs_status)
exitkey = self.screen.update(self.stats,
cs_status=cs_status,
return_to_browser=return_to_browser)
def end(self):
"""End of the client session."""

View File

@ -32,7 +32,7 @@ except ImportError:
from glances.core.glances_globals import logger
from glances.outputs.glances_curses import GlancesCursesBrowser
from glances.core.glances_autodiscover import GlancesAutoDiscoverServer
from glances.core.glances_client import GlancesClientTransport
from glances.core.glances_client import GlancesClientTransport, GlancesClient
class GlancesClientBrowser(object):
@ -52,7 +52,7 @@ class GlancesClientBrowser(object):
self.screen = GlancesCursesBrowser(args=self.args)
def get_servers_list(self):
"""Return the current server list (dict of dict)"""
"""Return the current server list (list of dict)"""
if self.args.autodiscover:
return self.autodiscover_server.get_servers_list()
else:
@ -78,26 +78,60 @@ class GlancesClientBrowser(object):
try:
s = ServerProxy(uri, t)
except Exception as e:
logger.warning("Couldn't create socket {0}: {1}".format(uri, e))
logger.warning(
"Client browser couldn't create socket {0}: {1}".format(uri, e))
else:
try:
# LOAD
v['load_min5'] = json.loads(s.getLoad())['min5']
# CPU%
v['cpu_percent'] = 100 - json.loads(s.getCpu())['idle']
v['cpu_percent'] = 100 - \
json.loads(s.getCpu())['idle']
# MEM%
v['mem_percent'] = json.loads(s.getMem())['percent']
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.warning("Can not grab stats form {0}: {1}".format(uri, e))
logger.warning(
"Can not grab 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)")
logger.debug(
"Server list dictionnary change inside the loop (wait next update)")
# Update the screen
self.screen.update(self.get_servers_list())
# 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 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']
client = GlancesClient(config=self.config,
args=args_server)
# Test if client and server are in the same major version
if not client.login():
logger.error(
"The server version is not compatible with the client")
# Start the client loop
client.serve_forever(return_to_browser=True)
logger.debug("Disconnect Glances client from the %s server" %
self.get_servers_list()[self.screen.get_active()]['key'])
self.screen.set_active(None)
def end(self):
"""End of the client session."""
pass
"""End of the client browser session."""
self.screen.end()

View File

@ -19,8 +19,6 @@
"""Curses interface class."""
# !!! TODO: split GlancesCurses for client and client_browser
# Import system lib
import sys
@ -218,7 +216,7 @@ class _GlancesCurses(object):
keycode[1] = window.getch()
if keycode != [-1, -1]:
logger.debug("Keypressed ! Code: %s" % keycode)
logger.debug("Keypressed (code: %s)" % keycode)
if keycode[0] == 27 and keycode[1] != -1:
# Do not escape on specials keys
@ -226,16 +224,19 @@ class _GlancesCurses(object):
else:
return keycode[0]
def __catch_key(self):
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
self.end()
logger.info("Stop Glances")
sys.exit(0)
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
@ -736,30 +737,44 @@ class _GlancesCurses(object):
self.erase()
self.display(stats, cs_status=cs_status)
def update(self, stats, cs_status="None"):
def update(self, stats, cs_status="None", return_to_browser=False):
"""Update the screen.
Wait for __refresh_time sec / catch key every 100 ms.
INPUT
stats: Stats database to display
cs_status:
"None": standalone or server mode
"Connected": Client is connected to the server
"Disconnected": Client is disconnected from the server
return_to_browser:
True: Do not exist, return to the browser list
False: Exit and return to the shell
OUPUT
True: Exit key has been pressed
False: Others cases...
"""
# Flush display
self.flush(stats, cs_status=cs_status)
# Wait
exitkey = False
countdown = Timer(self.__refresh_time)
while not countdown.finished():
while not countdown.finished() and not exitkey:
# Getkey
if self.__catch_key() > -1:
pressedkey = self.__catch_key(return_to_browser=return_to_browser)
# Is it an exit key ?
exitkey = (pressedkey == ord('\x1b') or pressedkey == ord('q'))
if not exitkey and pressedkey > -1:
# Redraw display
self.flush(stats, cs_status=cs_status)
# Wait 100ms...
curses.napms(100)
return exitkey
def get_stats_display_width(self, curse_msg, without_option=False):
"""Return the width of the formatted curses message.
@ -813,12 +828,24 @@ class GlancesCursesBrowser(_GlancesCurses):
# Init the cursor position for the client browser
self.cursor_init()
# Active Glances server number
self.set_active()
def set_active(self, index=None):
"""Set the active server or None if no server selected"""
self.active_server = index
return self.active_server
def get_active(self):
"""Return the active server (the one display in front) or None if it is the browser list"""
return self.active_server
def cursor_init(self):
"""Init the cursor position to the top of the list"""
return self.cursor_set(0)
def cursor_set(self, pos):
"""Set the cursor position andd return it"""
"""Set the cursor position and return it"""
self.cursor_position = pos
return self.cursor_position
@ -851,7 +878,7 @@ class GlancesCursesBrowser(_GlancesCurses):
elif self.pressedkey == 10:
# 'ENTER' > Run Glances on the selected server
logger.debug("Server number %s selected" % (self.cursor_get() + 1))
self.run_client(servers_list[self.cursor_get()])
self.set_active(self.cursor_get())
elif self.pressedkey == 259:
# 'UP' > Up in the server list
logger
@ -863,11 +890,6 @@ class GlancesCursesBrowser(_GlancesCurses):
# Return the key code
return self.pressedkey
def run_client(self, server):
"""Run the Glances client to the given server"""
logger.debug("Run Glances client on %s" % server)
def update(self, servers_list):
"""Update the servers' list screen.
@ -879,15 +901,21 @@ class GlancesCursesBrowser(_GlancesCurses):
self.flush(servers_list)
# Wait
exitkey = False
countdown = Timer(self.__refresh_time)
while not countdown.finished():
while not countdown.finished() and not exitkey:
# Getkey
if self.__catch_key(servers_list) > -1:
pressedkey = self.__catch_key(servers_list)
# Is it an exit or select server key ?
exitkey = (pressedkey == ord('\x1b') or pressedkey == ord('q') or pressedkey == 10)
if not exitkey and pressedkey > -1:
# Redraw display
self.flush(servers_list)
# Wait 100ms...
curses.napms(100)
return self.get_active()
def flush(self, servers_list):
"""Update the servers' list screen.
servers_list: List of dict with servers stats