8
8
9
9
"""Containers plugin."""
10
10
11
- import os
12
11
from copy import deepcopy
12
+ from typing import Any , Dict , List , Optional , Tuple
13
13
14
+ from glances .globals import iteritems , itervalues
14
15
from glances .logger import logger
15
- from glances .plugins .containers .engines .docker import DockerContainersExtension , import_docker_error_tag
16
- from glances .plugins .containers .engines .podman import PodmanContainersExtension , import_podman_error_tag
16
+ from glances .plugins .containers .engines import ContainersExtension
17
+ from glances .plugins .containers .engines .docker import DockerExtension , import_docker_error_tag
18
+ from glances .plugins .containers .engines .podman import PodmanExtension , import_podman_error_tag
17
19
from glances .plugins .plugin .model import GlancesPluginModel
18
20
from glances .processes import glances_processes
19
21
from glances .processes import sort_stats as sort_stats_processes
@@ -139,14 +141,15 @@ def __init__(self, args=None, config=None):
139
141
# We want to display the stat in the curse interface
140
142
self .display_curse = True
141
143
144
+ self .watchers : Dict [str , ContainersExtension ] = {}
145
+
142
146
# Init the Docker API
143
- self .docker_extension = DockerContainersExtension () if not import_docker_error_tag else None
147
+ if not import_docker_error_tag :
148
+ self .watchers ['docker' ] = DockerExtension ()
144
149
145
150
# Init the Podman API
146
- if import_podman_error_tag :
147
- self .podman_extension = None
148
- else :
149
- self .podman_extension = PodmanContainersExtension (podman_sock = self ._podman_sock ())
151
+ if not import_podman_error_tag :
152
+ self .watchers ['podman' ] = PodmanExtension (podman_sock = self ._podman_sock ())
150
153
151
154
# Sort key
152
155
self .sort_key = None
@@ -155,7 +158,7 @@ def __init__(self, args=None, config=None):
155
158
self .update ()
156
159
self .refresh_timer .set (0 )
157
160
158
- def _podman_sock (self ):
161
+ def _podman_sock (self ) -> str :
159
162
"""Return the podman sock.
160
163
Could be desfined in the [docker] section thanks to the podman_sock option.
161
164
Default value: unix:///run/user/1000/podman/podman.sock
@@ -165,20 +168,19 @@ def _podman_sock(self):
165
168
return "unix:///run/user/1000/podman/podman.sock"
166
169
return conf_podman_sock [0 ]
167
170
168
- def exit (self ):
171
+ def exit (self ) -> None :
169
172
"""Overwrite the exit method to close threads."""
170
- if self .docker_extension :
171
- self .docker_extension .stop ()
172
- if self .podman_extension :
173
- self .podman_extension .stop ()
173
+ for watcher in itervalues (self .watchers ):
174
+ watcher .stop ()
175
+
174
176
# Call the father class
175
177
super ().exit ()
176
178
177
- def get_key (self ):
179
+ def get_key (self ) -> str :
178
180
"""Return the key of the list."""
179
181
return 'name'
180
182
181
- def get_export (self ):
183
+ def get_export (self ) -> List [ Dict ] :
182
184
"""Overwrite the default export method.
183
185
184
186
- Only exports containers
@@ -197,7 +199,7 @@ def get_export(self):
197
199
198
200
return ret
199
201
200
- def _all_tag (self ):
202
+ def _all_tag (self ) -> bool :
201
203
"""Return the all tag of the Glances/Docker configuration file.
202
204
203
205
# By default, Glances only display running containers
@@ -211,52 +213,35 @@ def _all_tag(self):
211
213
212
214
@GlancesPluginModel ._check_decorator
213
215
@GlancesPluginModel ._log_result_decorator
214
- def update (self ):
216
+ def update (self ) -> List [ Dict ] :
215
217
"""Update Docker and podman stats using the input method."""
216
218
# Connection should be ok
217
- if self .docker_extension is None and self .podman_extension is None :
219
+ if not self .watchers :
220
+ return self .get_init_value ()
221
+
222
+ if self .input_method != 'local' :
218
223
return self .get_init_value ()
219
224
220
- if self .input_method == 'local' :
221
- # Update stats
222
- stats_docker = self .update_docker () if self .docker_extension else {}
223
- stats_podman = self .update_podman () if self .podman_extension else {}
224
- stats = stats_docker .get ('containers' , []) + stats_podman .get ('containers' , [])
225
- elif self .input_method == 'snmp' :
226
- # Update stats using SNMP
227
- # Not available
228
- pass
225
+ # Update stats
226
+ stats = []
227
+ for engine , watcher in iteritems (self .watchers ):
228
+ version , containers = watcher .update (all_tag = self ._all_tag ())
229
+ for container in containers :
230
+ container ["engine" ] = 'docker'
231
+ stats .extend (containers )
229
232
230
233
# Sort and update the stats
231
234
# @TODO: Have a look because sort did not work for the moment (need memory stats ?)
232
235
self .sort_key , self .stats = sort_docker_stats (stats )
233
-
234
236
return self .stats
235
237
236
- def update_docker (self ):
237
- """Update Docker stats using the input method."""
238
- version , containers = self .docker_extension .update (all_tag = self ._all_tag ())
239
- for container in containers :
240
- container ["engine" ] = 'docker'
241
- return {"version" : version , "containers" : containers }
242
-
243
- def update_podman (self ):
244
- """Update Podman stats."""
245
- version , containers = self .podman_extension .update (all_tag = self ._all_tag ())
246
- for container in containers :
247
- container ["engine" ] = 'podman'
248
- return {"version" : version , "containers" : containers }
249
-
250
- def get_user_ticks (self ):
251
- """Return the user ticks by reading the environment variable."""
252
- return os .sysconf (os .sysconf_names ['SC_CLK_TCK' ])
253
-
254
- def memory_usage_no_cache (self , mem ):
238
+ @staticmethod
239
+ def memory_usage_no_cache (mem : Dict [str , float ]) -> float :
255
240
"""Return the 'real' memory usage by removing inactive_file to usage"""
256
241
# Ref: https://github.com/docker/docker-py/issues/3210
257
242
return mem ['usage' ] - (mem ['inactive_file' ] if 'inactive_file' in mem else 0 )
258
243
259
- def update_views (self ):
244
+ def update_views (self ) -> bool :
260
245
"""Update stats views."""
261
246
# Call the father's method
262
247
super ().update_views ()
@@ -305,7 +290,7 @@ def update_views(self):
305
290
306
291
return True
307
292
308
- def msg_curse (self , args = None , max_width = None ):
293
+ def msg_curse (self , args = None , max_width : Optional [ int ] = None ) -> List [ str ] :
309
294
"""Return the dict to display in the curse interface."""
310
295
# Init the return message
311
296
ret = []
@@ -369,7 +354,9 @@ def msg_curse(self, args=None, max_width=None):
369
354
if self .views ['show_pod_name' ]:
370
355
ret .append (self .curse_add_line (' {:{width}}' .format (container .get ("pod_id" , "-" ), width = 12 )))
371
356
# Name
372
- ret .append (self .curse_add_line (self ._msg_name (container = container , max_width = name_max_width )))
357
+ ret .append (
358
+ self .curse_add_line (' {:{width}}' .format (container ['name' ][:name_max_width ], width = name_max_width ))
359
+ )
373
360
# Status
374
361
status = self .container_alert (container ['status' ])
375
362
msg = '{:>10}' .format (container ['status' ][0 :10 ])
@@ -441,12 +428,8 @@ def msg_curse(self, args=None, max_width=None):
441
428
442
429
return ret
443
430
444
- def _msg_name (self , container , max_width ):
445
- """Build the container name."""
446
- name = container ['name' ][:max_width ]
447
- return ' {:{width}}' .format (name , width = max_width )
448
-
449
- def container_alert (self , status ):
431
+ @staticmethod
432
+ def container_alert (status : str ) -> str :
450
433
"""Analyse the container status."""
451
434
if status == 'running' :
452
435
return 'OK'
@@ -457,7 +440,7 @@ def container_alert(self, status):
457
440
return 'CAREFUL'
458
441
459
442
460
- def sort_docker_stats (stats ) :
443
+ def sort_docker_stats (stats : List [ Dict [ str , Any ]]) -> Tuple [ str , List [ Dict [ str , Any ]]] :
461
444
# Sort Docker stats using the same function than processes
462
445
sort_by = glances_processes .sort_key
463
446
sort_by_secondary = 'memory_usage'
0 commit comments