Skip to content

Commit 504cf06

Browse files
authored
Merge pull request nicolargo#2919 from ariel-anieli/refactor-plugin-model-msg-curse
Refactorized `glances.plugins.containers.PluginModel.msg_curse()`
2 parents c9525b8 + fa6d46c commit 504cf06

File tree

1 file changed

+171
-94
lines changed

1 file changed

+171
-94
lines changed

glances/plugins/containers/__init__.py

Lines changed: 171 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"""Containers plugin."""
1010

1111
from copy import deepcopy
12+
from functools import partial, reduce
1213
from typing import Any, Dict, List, Optional, Tuple
1314

1415
from glances.globals import iteritems, itervalues
@@ -290,17 +291,7 @@ def update_views(self) -> bool:
290291

291292
return True
292293

293-
def msg_curse(self, args=None, max_width: Optional[int] = None) -> List[str]:
294-
"""Return the dict to display in the curse interface."""
295-
# Init the return message
296-
ret = []
297-
298-
# Only process if stats exist (and non null) and display plugin enable...
299-
if not self.stats or len(self.stats) == 0 or self.is_disabled():
300-
return ret
301-
302-
# Build the string message
303-
# Title
294+
def build_title(self, ret):
304295
msg = '{}'.format('CONTAINERS')
305296
ret.append(self.curse_add_line(msg, "TITLE"))
306297
msg = f' {len(self.stats)}'
@@ -311,97 +302,130 @@ def msg_curse(self, args=None, max_width: Optional[int] = None) -> List[str]:
311302
msg = f' (served by {self.stats[0].get("engine", "")})'
312303
ret.append(self.curse_add_line(msg))
313304
ret.append(self.curse_new_line())
314-
# Header
315-
ret.append(self.curse_new_line())
316-
# Get the maximum containers name
317-
# Max size is configurable. See feature request #1723.
318-
name_max_width = min(
319-
self.config.get_int_value('containers', 'max_name_size', default=20) if self.config is not None else 20,
320-
len(max(self.stats, key=lambda x: len(x['name']))['name']),
321-
)
305+
return ret
322306

307+
def maybe_add_engine_name_or_pod_line(self, ret):
323308
if self.views['show_engine_name']:
324-
msg = ' {:{width}}'.format('Engine', width=6)
325-
ret.append(self.curse_add_line(msg))
309+
ret = self.add_msg_to_line(ret, ' {:{width}}'.format('Engine', width=6))
326310
if self.views['show_pod_name']:
327-
msg = ' {:{width}}'.format('Pod', width=12)
328-
ret.append(self.curse_add_line(msg))
311+
ret = self.add_msg_to_line(ret, ' {:{width}}'.format('Pod', width=12))
312+
313+
return ret
314+
315+
def maybe_add_engine_name_or_pod_name(self, ret, container):
316+
ret.append(self.curse_new_line())
317+
if self.views['show_engine_name']:
318+
ret.append(self.curse_add_line(' {:{width}}'.format(container["engine"], width=6)))
319+
if self.views['show_pod_name']:
320+
ret.append(self.curse_add_line(' {:{width}}'.format(container.get("pod_id", "-"), width=12)))
321+
322+
return ret
323+
324+
def build_container_name(self, name_max_width):
325+
def build_for_this_max_length(ret, container):
326+
ret.append(
327+
self.curse_add_line(' {:{width}}'.format(container['name'][:name_max_width], width=name_max_width))
328+
)
329+
330+
return ret
331+
332+
return build_for_this_max_length
333+
334+
def build_header(self, ret, name_max_width):
335+
ret.append(self.curse_new_line())
336+
337+
ret = self.maybe_add_engine_name_or_pod_line(ret)
338+
329339
msg = ' {:{width}}'.format('Name', width=name_max_width)
330340
ret.append(self.curse_add_line(msg, 'SORT' if self.sort_key == 'name' else 'DEFAULT'))
331-
msg = '{:>10}'.format('Status')
332-
ret.append(self.curse_add_line(msg))
333-
msg = '{:>10}'.format('Uptime')
334-
ret.append(self.curse_add_line(msg))
341+
342+
msgs = ['{:>10}'.format('Status'), '{:>10}'.format('Uptime')]
343+
ret = reduce(self.add_msg_to_line, msgs, ret)
344+
335345
msg = '{:>6}'.format('CPU%')
336346
ret.append(self.curse_add_line(msg, 'SORT' if self.sort_key == 'cpu_percent' else 'DEFAULT'))
337347
msg = '{:>7}'.format('MEM')
338348
ret.append(self.curse_add_line(msg, 'SORT' if self.sort_key == 'memory_usage' else 'DEFAULT'))
339-
msg = '/{:<7}'.format('MAX')
340-
ret.append(self.curse_add_line(msg))
341-
msg = '{:>7}'.format('IOR/s')
342-
ret.append(self.curse_add_line(msg))
343-
msg = ' {:<7}'.format('IOW/s')
349+
350+
msgs = [
351+
'/{:<7}'.format('MAX'),
352+
'{:>7}'.format('IOR/s'),
353+
' {:<7}'.format('IOW/s'),
354+
'{:>7}'.format('Rx/s'),
355+
' {:<7}'.format('Tx/s'),
356+
' {:8}'.format('Command'),
357+
]
358+
359+
return reduce(self.add_msg_to_line, msgs, ret)
360+
361+
def add_msg_to_line(self, ret, msg):
344362
ret.append(self.curse_add_line(msg))
345-
msg = '{:>7}'.format('Rx/s')
363+
364+
return ret
365+
366+
def get_max_of_container_names(self):
367+
return min(
368+
self.config.get_int_value('containers', 'max_name_size', default=20) if self.config is not None else 20,
369+
len(max(self.stats, key=lambda x: len(x['name']))['name']),
370+
)
371+
372+
def build_status_name(self, ret, container):
373+
status = self.container_alert(container['status'])
374+
msg = '{:>10}'.format(container['status'][0:10])
375+
ret.append(self.curse_add_line(msg, status))
376+
377+
return ret
378+
379+
def build_uptime_line(self, ret, container):
380+
if container['uptime']:
381+
msg = '{:>10}'.format(container['uptime'])
382+
else:
383+
msg = '{:>10}'.format('_')
384+
385+
return self.add_msg_to_line(ret, msg)
386+
387+
def build_cpu_line(self, ret, container):
388+
try:
389+
msg = '{:>6.1f}'.format(container['cpu']['total'])
390+
except (KeyError, TypeError):
391+
msg = '{:>6}'.format('_')
392+
ret.append(self.curse_add_line(msg, self.get_views(item=container['name'], key='cpu', option='decoration')))
393+
394+
return ret
395+
396+
def build_memory_line(self, ret, container):
397+
try:
398+
msg = '{:>7}'.format(self.auto_unit(self.memory_usage_no_cache(container['memory'])))
399+
except KeyError:
400+
msg = '{:>7}'.format('_')
401+
ret.append(self.curse_add_line(msg, self.get_views(item=container['name'], key='mem', option='decoration')))
402+
try:
403+
msg = '/{:<7}'.format(self.auto_unit(container['memory']['limit']))
404+
except (KeyError, TypeError):
405+
msg = '/{:<7}'.format('_')
346406
ret.append(self.curse_add_line(msg))
347-
msg = ' {:<7}'.format('Tx/s')
407+
408+
return ret
409+
410+
def build_io_line(self, ret, container):
411+
unit = 'B'
412+
try:
413+
value = self.auto_unit(int(container['io_rx'])) + unit
414+
msg = f'{value:>7}'
415+
except (KeyError, TypeError):
416+
msg = '{:>7}'.format('_')
348417
ret.append(self.curse_add_line(msg))
349-
msg = ' {:8}'.format('Command')
418+
try:
419+
value = self.auto_unit(int(container['io_wx'])) + unit
420+
msg = f' {value:<7}'
421+
except (KeyError, TypeError):
422+
msg = ' {:<7}'.format('_')
350423
ret.append(self.curse_add_line(msg))
351424

352-
# Data
353-
for container in self.stats:
354-
ret.append(self.curse_new_line())
355-
if self.views['show_engine_name']:
356-
ret.append(self.curse_add_line(' {:{width}}'.format(container["engine"], width=6)))
357-
if self.views['show_pod_name']:
358-
ret.append(self.curse_add_line(' {:{width}}'.format(container.get("pod_id", "-"), width=12)))
359-
# Name
360-
ret.append(
361-
self.curse_add_line(' {:{width}}'.format(container['name'][:name_max_width], width=name_max_width))
362-
)
363-
# Status
364-
status = self.container_alert(container['status'])
365-
msg = '{:>10}'.format(container['status'][0:10])
366-
ret.append(self.curse_add_line(msg, status))
367-
# Uptime
368-
if container['uptime']:
369-
msg = '{:>10}'.format(container['uptime'])
370-
else:
371-
msg = '{:>10}'.format('_')
372-
ret.append(self.curse_add_line(msg))
373-
# CPU
374-
try:
375-
msg = '{:>6.1f}'.format(container['cpu']['total'])
376-
except (KeyError, TypeError):
377-
msg = '{:>6}'.format('_')
378-
ret.append(self.curse_add_line(msg, self.get_views(item=container['name'], key='cpu', option='decoration')))
379-
# MEM
380-
try:
381-
msg = '{:>7}'.format(self.auto_unit(self.memory_usage_no_cache(container['memory'])))
382-
except KeyError:
383-
msg = '{:>7}'.format('_')
384-
ret.append(self.curse_add_line(msg, self.get_views(item=container['name'], key='mem', option='decoration')))
385-
try:
386-
msg = '/{:<7}'.format(self.auto_unit(container['memory']['limit']))
387-
except (KeyError, TypeError):
388-
msg = '/{:<7}'.format('_')
389-
ret.append(self.curse_add_line(msg))
390-
# IO R/W
391-
unit = 'B'
392-
try:
393-
value = self.auto_unit(int(container['io_rx'])) + unit
394-
msg = f'{value:>7}'
395-
except (KeyError, TypeError):
396-
msg = '{:>7}'.format('_')
397-
ret.append(self.curse_add_line(msg))
398-
try:
399-
value = self.auto_unit(int(container['io_wx'])) + unit
400-
msg = f' {value:<7}'
401-
except (KeyError, TypeError):
402-
msg = ' {:<7}'.format('_')
403-
ret.append(self.curse_add_line(msg))
404-
# NET RX/TX
425+
return ret
426+
427+
def build_net_line(self, args):
428+
def build_with_this_args(ret, container):
405429
if args.byte:
406430
# Bytes per second (for dummy)
407431
to_bit = 1
@@ -422,15 +446,68 @@ def msg_curse(self, args=None, max_width: Optional[int] = None) -> List[str]:
422446
except (KeyError, TypeError):
423447
msg = ' {:<7}'.format('_')
424448
ret.append(self.curse_add_line(msg))
425-
# Command
426-
if container['command'] is not None:
427-
msg = ' {}'.format(container['command'])
428-
else:
429-
msg = ' {}'.format('_')
430-
ret.append(self.curse_add_line(msg, splittable=True))
449+
450+
return ret
451+
452+
return build_with_this_args
453+
454+
def build_cmd_line(self, ret, container):
455+
if container['command'] is not None:
456+
msg = ' {}'.format(container['command'])
457+
else:
458+
msg = ' {}'.format('_')
459+
ret.append(self.curse_add_line(msg, splittable=True))
431460

432461
return ret
433462

463+
def msg_curse(self, args=None, max_width: Optional[int] = None) -> List[str]:
464+
"""Return the dict to display in the curse interface."""
465+
# Init the return message
466+
init = []
467+
468+
# Only process if stats exist (and non null) and display plugin enable...
469+
conditions = [not self.stats, len(self.stats) == 0, self.is_disabled()]
470+
if any(conditions):
471+
return init
472+
473+
# Build the string message
474+
# Get the maximum containers name
475+
# Max size is configurable. See feature request #1723.
476+
name_max_width = self.get_max_of_container_names()
477+
478+
steps = [
479+
self.build_title,
480+
partial(self.build_header, name_max_width=name_max_width),
481+
self.build_data_line(name_max_width, args),
482+
]
483+
484+
return reduce(lambda ret, step: step(ret), steps, init)
485+
486+
def build_data_line(self, name_max_width, args):
487+
def build_for_this_params(ret):
488+
build_data_with_params = self.build_container_data(name_max_width, args)
489+
return reduce(build_data_with_params, self.stats, ret)
490+
491+
return build_for_this_params
492+
493+
def build_container_data(self, name_max_width, args):
494+
def build_with_this_params(ret, container):
495+
steps = [
496+
self.maybe_add_engine_name_or_pod_name,
497+
self.build_container_name(name_max_width),
498+
self.build_status_name,
499+
self.build_uptime_line,
500+
self.build_cpu_line,
501+
self.build_memory_line,
502+
self.build_io_line,
503+
self.build_net_line(args),
504+
self.build_cmd_line,
505+
]
506+
507+
return reduce(lambda ret, step: step(ret, container), steps, ret)
508+
509+
return build_with_this_params
510+
434511
@staticmethod
435512
def container_alert(status: str) -> str:
436513
"""Analyse the container status.

0 commit comments

Comments
 (0)