chg: plugin(docker) - add some typing

This commit is contained in:
Bharath Vignesh J K 2024-06-30 03:52:09 +05:30
parent 0e1d462c69
commit 99e65079a0
4 changed files with 52 additions and 60 deletions

View File

@ -8,12 +8,14 @@
"""Containers plugin.""" """Containers plugin."""
import os
from copy import deepcopy from copy import deepcopy
from typing import Any, Dict, List, Optional, Tuple
from glances.globals import iteritems, itervalues
from glances.logger import logger from glances.logger import logger
from glances.plugins.containers.engines.docker import DockerContainersExtension, import_docker_error_tag from glances.plugins.containers.engines import ContainersExtension
from glances.plugins.containers.engines.podman import PodmanContainersExtension, import_podman_error_tag from glances.plugins.containers.engines.docker import DockerExtension, import_docker_error_tag
from glances.plugins.containers.engines.podman import PodmanExtension, import_podman_error_tag
from glances.plugins.plugin.model import GlancesPluginModel from glances.plugins.plugin.model import GlancesPluginModel
from glances.processes import glances_processes from glances.processes import glances_processes
from glances.processes import sort_stats as sort_stats_processes from glances.processes import sort_stats as sort_stats_processes
@ -139,14 +141,15 @@ class PluginModel(GlancesPluginModel):
# We want to display the stat in the curse interface # We want to display the stat in the curse interface
self.display_curse = True self.display_curse = True
self.watchers: Dict[str, ContainersExtension] = {}
# Init the Docker API # Init the Docker API
self.docker_extension = DockerContainersExtension() if not import_docker_error_tag else None if not import_docker_error_tag:
self.watchers['docker'] = DockerExtension()
# Init the Podman API # Init the Podman API
if import_podman_error_tag: if not import_podman_error_tag:
self.podman_extension = None self.watchers['podman'] = PodmanExtension(podman_sock=self._podman_sock())
else:
self.podman_extension = PodmanContainersExtension(podman_sock=self._podman_sock())
# Sort key # Sort key
self.sort_key = None self.sort_key = None
@ -155,7 +158,7 @@ class PluginModel(GlancesPluginModel):
self.update() self.update()
self.refresh_timer.set(0) self.refresh_timer.set(0)
def _podman_sock(self): def _podman_sock(self) -> str:
"""Return the podman sock. """Return the podman sock.
Could be desfined in the [docker] section thanks to the podman_sock option. Could be desfined in the [docker] section thanks to the podman_sock option.
Default value: unix:///run/user/1000/podman/podman.sock Default value: unix:///run/user/1000/podman/podman.sock
@ -165,20 +168,19 @@ class PluginModel(GlancesPluginModel):
return "unix:///run/user/1000/podman/podman.sock" return "unix:///run/user/1000/podman/podman.sock"
return conf_podman_sock[0] return conf_podman_sock[0]
def exit(self): def exit(self) -> None:
"""Overwrite the exit method to close threads.""" """Overwrite the exit method to close threads."""
if self.docker_extension: for watcher in itervalues(self.watchers):
self.docker_extension.stop() watcher.stop()
if self.podman_extension:
self.podman_extension.stop()
# Call the father class # Call the father class
super().exit() super().exit()
def get_key(self): def get_key(self) -> str:
"""Return the key of the list.""" """Return the key of the list."""
return 'name' return 'name'
def get_export(self): def get_export(self) -> List[Dict]:
"""Overwrite the default export method. """Overwrite the default export method.
- Only exports containers - Only exports containers
@ -197,7 +199,7 @@ class PluginModel(GlancesPluginModel):
return ret return ret
def _all_tag(self): def _all_tag(self) -> bool:
"""Return the all tag of the Glances/Docker configuration file. """Return the all tag of the Glances/Docker configuration file.
# By default, Glances only display running containers # By default, Glances only display running containers
@ -211,52 +213,35 @@ class PluginModel(GlancesPluginModel):
@GlancesPluginModel._check_decorator @GlancesPluginModel._check_decorator
@GlancesPluginModel._log_result_decorator @GlancesPluginModel._log_result_decorator
def update(self): def update(self) -> List[Dict]:
"""Update Docker and podman stats using the input method.""" """Update Docker and podman stats using the input method."""
# Connection should be ok # Connection should be ok
if self.docker_extension is None and self.podman_extension is None: if not self.watchers:
return self.get_init_value() return self.get_init_value()
if self.input_method == 'local': if self.input_method != 'local':
# Update stats return self.get_init_value()
stats_docker = self.update_docker() if self.docker_extension else {}
stats_podman = self.update_podman() if self.podman_extension else {} # Update stats
stats = stats_docker.get('containers', []) + stats_podman.get('containers', []) stats = []
elif self.input_method == 'snmp': for engine, watcher in iteritems(self.watchers):
# Update stats using SNMP version, containers = watcher.update(all_tag=self._all_tag())
# Not available for container in containers:
pass container["engine"] = 'docker'
stats.extend(containers)
# Sort and update the stats # Sort and update the stats
# @TODO: Have a look because sort did not work for the moment (need memory stats ?) # @TODO: Have a look because sort did not work for the moment (need memory stats ?)
self.sort_key, self.stats = sort_docker_stats(stats) self.sort_key, self.stats = sort_docker_stats(stats)
return self.stats return self.stats
def update_docker(self): @staticmethod
"""Update Docker stats using the input method.""" def memory_usage_no_cache(mem: Dict[str, float]) -> float:
version, containers = self.docker_extension.update(all_tag=self._all_tag())
for container in containers:
container["engine"] = 'docker'
return {"version": version, "containers": containers}
def update_podman(self):
"""Update Podman stats."""
version, containers = self.podman_extension.update(all_tag=self._all_tag())
for container in containers:
container["engine"] = 'podman'
return {"version": version, "containers": containers}
def get_user_ticks(self):
"""Return the user ticks by reading the environment variable."""
return os.sysconf(os.sysconf_names['SC_CLK_TCK'])
def memory_usage_no_cache(self, mem):
"""Return the 'real' memory usage by removing inactive_file to usage""" """Return the 'real' memory usage by removing inactive_file to usage"""
# Ref: https://github.com/docker/docker-py/issues/3210 # Ref: https://github.com/docker/docker-py/issues/3210
return mem['usage'] - (mem['inactive_file'] if 'inactive_file' in mem else 0) return mem['usage'] - (mem['inactive_file'] if 'inactive_file' in mem else 0)
def update_views(self): def update_views(self) -> bool:
"""Update stats views.""" """Update stats views."""
# Call the father's method # Call the father's method
super().update_views() super().update_views()
@ -305,7 +290,7 @@ class PluginModel(GlancesPluginModel):
return True return True
def msg_curse(self, args=None, max_width=None): def msg_curse(self, args=None, max_width: Optional[int] = None) -> List[str]:
"""Return the dict to display in the curse interface.""" """Return the dict to display in the curse interface."""
# Init the return message # Init the return message
ret = [] ret = []
@ -369,7 +354,9 @@ class PluginModel(GlancesPluginModel):
if self.views['show_pod_name']: if self.views['show_pod_name']:
ret.append(self.curse_add_line(' {:{width}}'.format(container.get("pod_id", "-"), width=12))) ret.append(self.curse_add_line(' {:{width}}'.format(container.get("pod_id", "-"), width=12)))
# Name # Name
ret.append(self.curse_add_line(self._msg_name(container=container, max_width=name_max_width))) ret.append(
self.curse_add_line(' {:{width}}'.format(container['name'][:name_max_width], width=name_max_width))
)
# Status # Status
status = self.container_alert(container['status']) status = self.container_alert(container['status'])
msg = '{:>10}'.format(container['status'][0:10]) msg = '{:>10}'.format(container['status'][0:10])
@ -441,12 +428,8 @@ class PluginModel(GlancesPluginModel):
return ret return ret
def _msg_name(self, container, max_width): @staticmethod
"""Build the container name.""" def container_alert(status: str) -> str:
name = container['name'][:max_width]
return ' {:{width}}'.format(name, width=max_width)
def container_alert(self, status):
"""Analyse the container status.""" """Analyse the container status."""
if status == 'running': if status == 'running':
return 'OK' return 'OK'
@ -457,7 +440,7 @@ class PluginModel(GlancesPluginModel):
return 'CAREFUL' return 'CAREFUL'
def sort_docker_stats(stats): def sort_docker_stats(stats: List[Dict[str, Any]]) -> Tuple[str, List[Dict[str, Any]]]:
# Sort Docker stats using the same function than processes # Sort Docker stats using the same function than processes
sort_by = glances_processes.sort_key sort_by = glances_processes.sort_key
sort_by_secondary = 'memory_usage' sort_by_secondary = 'memory_usage'

View File

@ -0,0 +1,9 @@
from typing import Any, Dict, Protocol, Tuple
class ContainersExtension(Protocol):
def stop(self) -> None:
raise NotImplementedError
def update(self, all_tag) -> Tuple[Dict, list[Dict[str, Any]]]:
raise NotImplementedError

View File

@ -207,7 +207,7 @@ class DockerStatsFetcher:
return stats return stats
class DockerContainersExtension: class DockerExtension:
"""Glances' Containers Plugin's Docker Extension unit""" """Glances' Containers Plugin's Docker Extension unit"""
CONTAINER_ACTIVE_STATUS = ['running', 'paused'] CONTAINER_ACTIVE_STATUS = ['running', 'paused']

View File

@ -243,7 +243,7 @@ class PodmanPodStatsFetcher:
return {"ior": ior, "iow": iow, "time_since_update": 1} return {"ior": ior, "iow": iow, "time_since_update": 1}
class PodmanContainersExtension: class PodmanExtension:
"""Glances' Containers Plugin's Docker Extension unit""" """Glances' Containers Plugin's Docker Extension unit"""
CONTAINER_ACTIVE_STATUS = ['running', 'paused'] CONTAINER_ACTIVE_STATUS = ['running', 'paused']