/usr/lib/python3/dist-packages/glances/outputs/glances_curses_browser.py is in glances 2.7.1.1-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 | # -*- coding: utf-8 -*-
#
# This file is part of Glances.
#
# Copyright (C) 2016 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/>.
"""Curses browser interface class ."""
import sys
from glances.outputs.glances_curses import _GlancesCurses
from glances.logger import logger
from glances.timer import Timer
class GlancesCursesBrowser(_GlancesCurses):
"""Class for the Glances curse client browser."""
def __init__(self, args=None):
# Init the father class
super(GlancesCursesBrowser, self).__init__(args=args)
_colors_list = {
'UNKNOWN': self.no_color,
'SNMP': self.default_color2,
'ONLINE': self.default_color2,
'OFFLINE': self.ifCRITICAL_color2,
'PROTECTED': self.ifWARNING_color2,
}
self.colors_list.update(_colors_list)
# First time scan tag
# Used to display a specific message when the browser is started
self.first_scan = True
# Init refresh time
self.__refresh_time = args.time
# Init the cursor position for the client browser
self.cursor_position = 0
# Active Glances server number
self._active_server = None
@property
def active_server(self):
"""Return the active server or None if it's the browser list."""
return self._active_server
@active_server.setter
def active_server(self, index):
"""Set the active server or None if no server selected."""
self._active_server = index
@property
def cursor(self):
"""Get the cursor position."""
return self.cursor_position
@cursor.setter
def cursor(self, position):
"""Set the cursor position."""
self.cursor_position = position
def cursor_up(self, servers_list):
"""Set the cursor to position N-1 in the list."""
if self.cursor_position > 0:
self.cursor_position -= 1
else:
self.cursor_position = len(servers_list) - 1
def cursor_down(self, servers_list):
"""Set the cursor to position N-1 in the list."""
if self.cursor_position < len(servers_list) - 1:
self.cursor_position += 1
else:
self.cursor_position = 0
def __catch_key(self, servers_list):
# Catch the browser pressed key
self.pressedkey = self.get_key(self.term_window)
if self.pressedkey != -1:
logger.debug("Key pressed. Code=%s" % self.pressedkey)
# 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 {} selected".format(self.cursor + 1))
self.active_server = self.cursor
elif self.pressedkey == 65:
# 'UP' > Up in the server list
self.cursor_up(servers_list)
elif self.pressedkey == 66:
# 'DOWN' > Down in the server list
self.cursor_down(servers_list)
# Return the key code
return self.pressedkey
def update(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
logger.debug('Servers list: {}'.format(servers_list))
self.flush(servers_list)
# Wait
exitkey = False
countdown = Timer(self.__refresh_time)
while not countdown.finished() and not exitkey:
# Getkey
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...
self.wait()
return self.active_server
def flush(self, servers_list):
"""Update the servers' list screen.
servers_list: List of dict with servers stats
"""
self.erase()
self.display(servers_list)
def display(self, servers_list):
"""Display the servers list.
Return:
True if the stats have been displayed
False if the stats have not been displayed (no server available)
"""
# 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]
# Init position
x = 0
y = 0
# Display top header
if len(servers_list) == 0:
if self.first_scan and not self.args.disable_autodiscover:
msg = 'Glances is scanning your network. Please wait...'
self.first_scan = False
else:
msg = 'No Glances server available'
elif len(servers_list) == 1:
msg = 'One Glances server available'
else:
msg = '{} Glances servers available'.format(len(servers_list))
if self.args.disable_autodiscover:
msg += ' ' + '(auto discover is disabled)'
self.term_window.addnstr(y, x,
msg,
screen_x - x,
self.colors_list['TITLE'])
if len(servers_list) == 0:
return False
# Display the Glances server list
# ================================
# Table of table
# Item description: [stats_id, column name, column size]
column_def = [
['name', 'Name', 16],
['alias', None, None],
['load_min5', 'LOAD', 6],
['cpu_percent', 'CPU%', 5],
['mem_percent', 'MEM%', 5],
['status', 'STATUS', 9],
['ip', 'IP', 15],
# ['port', 'PORT', 5],
['hr_name', 'OS', 16],
]
y = 2
# Display table header
xc = x + 2
for cpt, c in enumerate(column_def):
if xc < screen_x and y < screen_y and c[1] is not None:
self.term_window.addnstr(y, xc,
c[1],
screen_x - x,
self.colors_list['BOLD'])
xc += c[2] + self.space_between_column
y += 1
# If a servers has been deleted from the list...
# ... and if the cursor is in the latest position
if self.cursor > len(servers_list) - 1:
# Set the cursor position to the latest item
self.cursor = len(servers_list) - 1
# Display table
line = 0
for v in servers_list:
# Get server stats
server_stat = {}
for c in column_def:
try:
server_stat[c[0]] = v[c[0]]
except KeyError as e:
logger.debug(
"Cannot grab stats {} from server (KeyError: {})".format(c[0], e))
server_stat[c[0]] = '?'
# Display alias instead of name
try:
if c[0] == 'alias' and v[c[0]] is not None:
server_stat['name'] = v[c[0]]
except KeyError:
pass
# Display line for server stats
cpt = 0
xc = x
# Is the line selected ?
if line == self.cursor:
# Display cursor
self.term_window.addnstr(
y, xc, ">", screen_x - xc, self.colors_list['BOLD'])
# Display the line
xc += 2
for c in column_def:
if xc < screen_x and y < screen_y and c[1] is not None:
# Display server stats
self.term_window.addnstr(
y, xc, format(server_stat[c[0]]), c[2], self.colors_list[v['status']])
xc += c[2] + self.space_between_column
cpt += 1
# Next line, next server...
y += 1
line += 1
return True
|