1 | # -*- coding: utf-8 -*- |
||
2 | # |
||
3 | # This file is part of Glances. |
||
4 | # |
||
5 | # Copyright (C) 2019 Nicolargo <[email protected]> |
||
6 | # |
||
7 | # Glances is free software; you can redistribute it and/or modify |
||
8 | # it under the terms of the GNU Lesser General Public License as published by |
||
9 | # the Free Software Foundation, either version 3 of the License, or |
||
10 | # (at your option) any later version. |
||
11 | # |
||
12 | # Glances is distributed in the hope that it will be useful, |
||
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
15 | # GNU Lesser General Public License for more details. |
||
16 | # |
||
17 | # You should have received a copy of the GNU Lesser General Public License |
||
18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
||
19 | |||
20 | """Glances main class.""" |
||
21 | |||
22 | import argparse |
||
23 | import sys |
||
24 | import tempfile |
||
25 | |||
26 | from glances import __version__, psutil_version |
||
27 | from glances.compat import input |
||
28 | from glances.config import Config |
||
29 | from glances.globals import WINDOWS |
||
30 | from glances.logger import logger |
||
31 | |||
32 | |||
33 | def disable(class_name, var): |
||
34 | """Set disable_<var> to True in the class class_name.""" |
||
35 | setattr(class_name, 'disable_' + var, True) |
||
36 | |||
37 | |||
38 | def enable(class_name, var): |
||
39 | """Set disable_<var> to False in the class class_name.""" |
||
40 | setattr(class_name, 'disable_' + var, False) |
||
41 | |||
42 | |||
43 | class GlancesMain(object): |
||
44 | """Main class to manage Glances instance.""" |
||
45 | |||
46 | # Default stats' refresh time is 3 seconds |
||
47 | refresh_time = 3 |
||
48 | # Set the default cache lifetime to 1 second (only for server) |
||
49 | cached_time = 1 |
||
50 | # By default, Glances is ran in standalone mode (no client/server) |
||
51 | client_tag = False |
||
52 | # Server TCP port number (default is 61209) |
||
53 | server_port = 61209 |
||
54 | # Web Server TCP port number (default is 61208) |
||
55 | web_server_port = 61208 |
||
56 | # Default username/password for client/server mode |
||
57 | username = "glances" |
||
58 | password = "" |
||
59 | |||
60 | # Examples of use |
||
61 | example_of_use = """ |
||
62 | Examples of use: |
||
63 | Monitor local machine (standalone mode): |
||
64 | $ glances |
||
65 | |||
66 | Display all Glances modules (plugins and exporters) and exit: |
||
67 | $ glances --module-list |
||
68 | |||
69 | Monitor local machine with the Web interface and start RESTful server: |
||
70 | $ glances -w |
||
71 | Glances web server started on http://0.0.0.0:61208/ |
||
72 | |||
73 | Only start RESTful API (without the WebUI): |
||
74 | $ glances -w --disable-webui |
||
75 | Glances API available on http://0.0.0.0:61208/api/ |
||
76 | |||
77 | Monitor local machine and export stats to a CSV file (standalone mode): |
||
78 | $ glances --export csv --export-csv-file /tmp/glances.csv |
||
79 | |||
80 | Monitor local machine and export stats to a InfluxDB server with 5s refresh time (standalone mode): |
||
81 | $ glances -t 5 --export influxdb |
||
82 | |||
83 | Start a Glances XML/RCP server (server mode): |
||
84 | $ glances -s |
||
85 | |||
86 | Connect Glances to a Glances XML/RCP server (client mode): |
||
87 | $ glances -c <ip_server> |
||
88 | |||
89 | Connect Glances to a Glances server and export stats to a StatsD server (client mode): |
||
90 | $ glances -c <ip_server> --export statsd |
||
91 | |||
92 | Start the client browser (browser mode): |
||
93 | $ glances --browser |
||
94 | |||
95 | Display stats to stdout (one stat per line): |
||
96 | $ glances --stdout now,cpu.user,mem.used,load |
||
97 | |||
98 | Display CSV stats to stdout (all stats in one line): |
||
99 | $ glances --stdout-csv now,cpu.user,mem.used,load |
||
100 | |||
101 | Disable some plugins (comma separated list): |
||
102 | $ glances --disable-plugin network,ports |
||
103 | |||
104 | Enable some plugins (comma separated list): |
||
105 | $ glances --enable-plugin sensors |
||
106 | """ |
||
107 | |||
108 | def __init__(self): |
||
109 | """Manage the command line arguments.""" |
||
110 | # Read the command line arguments |
||
111 | self.args = self.parse_args() |
||
112 | |||
113 | def init_args(self): |
||
114 | """Init all the command line arguments.""" |
||
115 | version = "Glances v" + __version__ + " with psutil v" + psutil_version |
||
116 | parser = argparse.ArgumentParser( |
||
117 | prog='glances', |
||
118 | conflict_handler='resolve', |
||
119 | formatter_class=argparse.RawDescriptionHelpFormatter, |
||
120 | epilog=self.example_of_use) |
||
121 | parser.add_argument( |
||
122 | '-V', '--version', action='version', version=version) |
||
123 | parser.add_argument('-d', '--debug', action='store_true', default=False, |
||
124 | dest='debug', help='enable debug mode') |
||
125 | parser.add_argument('-C', '--config', dest='conf_file', |
||
126 | help='path to the configuration file') |
||
127 | # Disable plugin |
||
128 | parser.add_argument('--modules-list', '--module-list', |
||
129 | action='store_true', default=False, |
||
130 | dest='modules_list', |
||
131 | help='display modules (plugins & exports) list and exit') |
||
132 | parser.add_argument('--disable-plugin', '--disable-plugins', dest='disable_plugin', |
||
133 | help='disable plugin (comma separed list)') |
||
134 | parser.add_argument('--enable-plugin', '--enable-plugins', dest='enable_plugin', |
||
135 | help='enable plugin (comma separed list)') |
||
136 | parser.add_argument('--disable-process', action='store_true', default=False, |
||
137 | dest='disable_process', help='disable process module') |
||
138 | # Enable or disable option |
||
139 | parser.add_argument('--disable-webui', action='store_true', default=False, |
||
140 | dest='disable_webui', help='disable the Web Interface') |
||
141 | parser.add_argument('--light', '--enable-light', action='store_true', |
||
142 | default=False, dest='enable_light', |
||
143 | help='light mode for Curses UI (disable all but top menu)') |
||
144 | parser.add_argument('-0', '--disable-irix', action='store_true', default=False, |
||
145 | dest='disable_irix', help='task\'s cpu usage will be divided by the total number of CPUs') |
||
146 | parser.add_argument('-1', '--percpu', action='store_true', default=False, |
||
147 | dest='percpu', help='start Glances in per CPU mode') |
||
148 | parser.add_argument('-2', '--disable-left-sidebar', action='store_true', |
||
149 | default=False, dest='disable_left_sidebar', |
||
150 | help='disable network, disk I/O, FS and sensors modules') |
||
151 | parser.add_argument('-3', '--disable-quicklook', action='store_true', default=False, |
||
152 | dest='disable_quicklook', help='disable quick look module') |
||
153 | parser.add_argument('-4', '--full-quicklook', action='store_true', default=False, |
||
154 | dest='full_quicklook', help='disable all but quick look and load') |
||
155 | parser.add_argument('-5', '--disable-top', action='store_true', |
||
156 | default=False, dest='disable_top', |
||
157 | help='disable top menu (QL, CPU, MEM, SWAP and LOAD)') |
||
158 | parser.add_argument('-6', '--meangpu', action='store_true', default=False, |
||
159 | dest='meangpu', help='start Glances in mean GPU mode') |
||
160 | parser.add_argument('--disable-history', action='store_true', default=False, |
||
161 | dest='disable_history', help='disable stats history') |
||
162 | parser.add_argument('--disable-bold', action='store_true', default=False, |
||
163 | dest='disable_bold', help='disable bold mode in the terminal') |
||
164 | parser.add_argument('--disable-bg', action='store_true', default=False, |
||
165 | dest='disable_bg', help='disable background colors in the terminal') |
||
166 | parser.add_argument('--enable-irq', action='store_true', default=False, |
||
167 | dest='enable_irq', help='enable IRQ module'), |
||
168 | parser.add_argument('--enable-process-extended', action='store_true', default=False, |
||
169 | dest='enable_process_extended', help='enable extended stats on top process') |
||
170 | # Export modules feature |
||
171 | parser.add_argument('--export', dest='export', |
||
172 | help='enable export module (comma separed list)') |
||
173 | parser.add_argument('--export-csv-file', |
||
174 | default='./glances.csv', |
||
175 | dest='export_csv_file', |
||
176 | help='file path for CSV exporter') |
||
177 | parser.add_argument('--export-csv-overwrite', action='store_true', default=False, |
||
178 | dest='export_csv_overwrite', help='overwrite existing CSV file') |
||
179 | parser.add_argument('--export-json-file', |
||
180 | default='./glances.json', |
||
181 | dest='export_json_file', |
||
182 | help='file path for JSON exporter') |
||
183 | parser.add_argument('--export-graph-path', |
||
184 | default=tempfile.gettempdir(), |
||
185 | dest='export_graph_path', |
||
186 | help='Folder for Graph exporter') |
||
187 | # Client/Server option |
||
188 | parser.add_argument('-c', '--client', dest='client', |
||
189 | help='connect to a Glances server by IPv4/IPv6 address or hostname') |
||
190 | parser.add_argument('-s', '--server', action='store_true', default=False, |
||
191 | dest='server', help='run Glances in server mode') |
||
192 | parser.add_argument('--browser', action='store_true', default=False, |
||
193 | dest='browser', help='start the client browser (list of servers)') |
||
194 | parser.add_argument('--disable-autodiscover', action='store_true', default=False, |
||
195 | dest='disable_autodiscover', help='disable autodiscover feature') |
||
196 | parser.add_argument('-p', '--port', default=None, type=int, dest='port', |
||
197 | help='define the client/server TCP port [default: {}]'.format(self.server_port)) |
||
198 | parser.add_argument('-B', '--bind', default='0.0.0.0', dest='bind_address', |
||
199 | help='bind server to the given IPv4/IPv6 address or hostname') |
||
200 | parser.add_argument('--username', action='store_true', default=False, dest='username_prompt', |
||
201 | help='define a client/server username') |
||
202 | parser.add_argument('--password', action='store_true', default=False, dest='password_prompt', |
||
203 | help='define a client/server password') |
||
204 | parser.add_argument('-u', dest='username_used', |
||
205 | help='use the given client/server username') |
||
206 | parser.add_argument('--snmp-community', default='public', dest='snmp_community', |
||
207 | help='SNMP community') |
||
208 | parser.add_argument('--snmp-port', default=161, type=int, |
||
209 | dest='snmp_port', help='SNMP port') |
||
210 | parser.add_argument('--snmp-version', default='2c', dest='snmp_version', |
||
211 | help='SNMP version (1, 2c or 3)') |
||
212 | parser.add_argument('--snmp-user', default='private', dest='snmp_user', |
||
213 | help='SNMP username (only for SNMPv3)') |
||
214 | parser.add_argument('--snmp-auth', default='password', dest='snmp_auth', |
||
215 | help='SNMP authentication key (only for SNMPv3)') |
||
216 | parser.add_argument('--snmp-force', action='store_true', default=False, |
||
217 | dest='snmp_force', help='force SNMP mode') |
||
218 | parser.add_argument('-t', '--time', default=self.refresh_time, type=float, |
||
219 | dest='time', help='set refresh time in seconds [default: {} sec]'.format(self.refresh_time)) |
||
220 | parser.add_argument('-w', '--webserver', action='store_true', default=False, |
||
221 | dest='webserver', help='run Glances in web server mode (bottle needed)') |
||
222 | parser.add_argument('--cached-time', default=self.cached_time, type=int, |
||
223 | dest='cached_time', help='set the server cache time [default: {} sec]'.format(self.cached_time)) |
||
224 | parser.add_argument('--open-web-browser', action='store_true', default=False, |
||
225 | dest='open_web_browser', help='try to open the Web UI in the default Web browser') |
||
226 | # Display options |
||
227 | parser.add_argument('-q', '--quiet', default=False, action='store_true', |
||
228 | dest='quiet', help='do not display the curses interface') |
||
229 | parser.add_argument('-f', '--process-filter', default=None, type=str, |
||
230 | dest='process_filter', help='set the process filter pattern (regular expression)') |
||
231 | parser.add_argument('--process-short-name', action='store_true', default=False, |
||
232 | dest='process_short_name', help='force short name for processes name') |
||
233 | parser.add_argument('--stdout', default=None, |
||
234 | dest='stdout', help='display stats to stdout, one stat per line (comma separated list of plugins/plugins.attribute)') |
||
235 | parser.add_argument('--stdout-csv', default=None, |
||
236 | dest='stdout_csv', help='display stats to stdout, csv format (comma separated list of plugins/plugins.attribute)') |
||
237 | if not WINDOWS: |
||
238 | parser.add_argument('--hide-kernel-threads', action='store_true', default=False, |
||
239 | dest='no_kernel_threads', help='hide kernel threads in process list (not available on Windows)') |
||
240 | parser.add_argument('-b', '--byte', action='store_true', default=False, |
||
241 | dest='byte', help='display network rate in byte per second') |
||
242 | parser.add_argument('--diskio-show-ramfs', action='store_true', default=False, |
||
243 | dest='diskio_show_ramfs', help='show RAM Fs in the DiskIO plugin') |
||
244 | parser.add_argument('--diskio-iops', action='store_true', default=False, |
||
245 | dest='diskio_iops', help='show IO per second in the DiskIO plugin') |
||
246 | parser.add_argument('--fahrenheit', action='store_true', default=False, |
||
247 | dest='fahrenheit', help='display temperature in Fahrenheit (default is Celsius)') |
||
248 | parser.add_argument('--fs-free-space', action='store_true', default=False, |
||
249 | dest='fs_free_space', help='display FS free space instead of used') |
||
250 | parser.add_argument('--sparkline', action='store_true', default=False, |
||
251 | dest='sparkline', help='display sparklines instead of bar in the curses interface') |
||
252 | parser.add_argument('--theme-white', action='store_true', default=False, |
||
253 | dest='theme_white', help='optimize display colors for white background') |
||
254 | # Globals options |
||
255 | parser.add_argument('--disable-check-update', action='store_true', default=False, |
||
256 | dest='disable_check_update', help='disable online Glances version ckeck') |
||
257 | return parser |
||
258 | |||
259 | def parse_args(self): |
||
260 | """Parse command line arguments.""" |
||
261 | args = self.init_args().parse_args() |
||
262 | |||
263 | # Load the configuration file, if it exists |
||
264 | self.config = Config(args.conf_file) |
||
265 | |||
266 | # Debug mode |
||
267 | if args.debug: |
||
268 | from logging import DEBUG |
||
269 | logger.setLevel(DEBUG) |
||
270 | else: |
||
271 | from warnings import simplefilter |
||
272 | simplefilter("ignore") |
||
273 | |||
274 | # Plugins disable/enable |
||
275 | # Allow users to disable plugins from the glances.conf (issue #1378) |
||
276 | for s in self.config.sections(): |
||
277 | if self.config.has_section(s) \ |
||
278 | and (self.config.get_bool_value(s, 'disable', False)): |
||
279 | disable(args, s) |
||
280 | logger.debug('{} disabled by the configuration file'.format(s)) |
||
281 | # The configuration key can be overwrite from the command line |
||
282 | if args.disable_plugin is not None: |
||
283 | for p in args.disable_plugin.split(','): |
||
284 | disable(args, p) |
||
285 | if args.enable_plugin is not None: |
||
286 | for p in args.enable_plugin.split(','): |
||
0 ignored issues
–
show
|
|||
287 | enable(args, p) |
||
288 | |||
289 | # Exporters activation |
||
290 | if args.export is not None: |
||
291 | for p in args.export.split(','): |
||
292 | setattr(args, 'export_' + p, True) |
||
293 | |||
294 | # Client/server Port |
||
295 | if args.port is None: |
||
296 | if args.webserver: |
||
297 | args.port = self.web_server_port |
||
298 | else: |
||
299 | args.port = self.server_port |
||
300 | # Port in the -c URI #996 |
||
301 | if args.client is not None: |
||
302 | args.client, args.port = (x if x else y for (x, y) in zip(args.client.partition(':')[::2], (args.client, args.port))) |
||
303 | |||
304 | # Autodiscover |
||
305 | if args.disable_autodiscover: |
||
306 | logger.info("Auto discover mode is disabled") |
||
307 | |||
308 | # By default Windows is started in Web mode |
||
309 | if WINDOWS: |
||
310 | args.webserver = True |
||
311 | |||
312 | # In web server mode |
||
313 | if args.webserver: |
||
314 | args.process_short_name = True |
||
315 | |||
316 | # Server or client login/password |
||
317 | if args.username_prompt: |
||
318 | # Every username needs a password |
||
319 | args.password_prompt = True |
||
320 | # Prompt username |
||
321 | if args.server: |
||
322 | args.username = self.__get_username( |
||
323 | description='Define the Glances server username: ') |
||
324 | elif args.webserver: |
||
325 | args.username = self.__get_username( |
||
326 | description='Define the Glances webserver username: ') |
||
327 | elif args.client: |
||
328 | args.username = self.__get_username( |
||
329 | description='Enter the Glances server username: ') |
||
330 | else: |
||
331 | if args.username_used: |
||
332 | # A username has been set using the -u option ? |
||
333 | args.username = args.username_used |
||
334 | else: |
||
335 | # Default user name is 'glances' |
||
336 | args.username = self.username |
||
337 | |||
338 | if args.password_prompt or args.username_used: |
||
339 | # Interactive or file password |
||
340 | if args.server: |
||
341 | args.password = self.__get_password( |
||
342 | description='Define the Glances server password ({} username): '.format( |
||
343 | args.username), |
||
344 | confirm=True, |
||
345 | username=args.username) |
||
346 | elif args.webserver: |
||
347 | args.password = self.__get_password( |
||
348 | description='Define the Glances webserver password ({} username): '.format( |
||
349 | args.username), |
||
350 | confirm=True, |
||
351 | username=args.username) |
||
352 | elif args.client: |
||
353 | args.password = self.__get_password( |
||
354 | description='Enter the Glances server password ({} username): '.format( |
||
355 | args.username), |
||
356 | clear=True, |
||
357 | username=args.username) |
||
358 | else: |
||
359 | # Default is no password |
||
360 | args.password = self.password |
||
361 | |||
362 | # By default help is hidden |
||
363 | args.help_tag = False |
||
364 | |||
365 | # Display Rx and Tx, not the sum for the network |
||
366 | args.network_sum = False |
||
367 | args.network_cumul = False |
||
368 | |||
369 | # Manage light mode |
||
370 | if args.enable_light: |
||
371 | logger.info("Light mode is on") |
||
372 | args.disable_left_sidebar = True |
||
373 | disable(args, 'process') |
||
374 | disable(args, 'alert') |
||
375 | disable(args, 'amps') |
||
376 | disable(args, 'docker') |
||
377 | |||
378 | # Manage full quicklook option |
||
379 | if args.full_quicklook: |
||
380 | logger.info("Full quicklook mode") |
||
381 | enable(args, 'quicklook') |
||
382 | disable(args, 'cpu') |
||
383 | disable(args, 'mem') |
||
384 | disable(args, 'memswap') |
||
385 | enable(args, 'load') |
||
386 | |||
387 | # Manage disable_top option |
||
388 | if args.disable_top: |
||
389 | logger.info("Disable top menu") |
||
390 | disable(args, 'quicklook') |
||
391 | disable(args, 'cpu') |
||
392 | disable(args, 'mem') |
||
393 | disable(args, 'memswap') |
||
394 | disable(args, 'load') |
||
395 | |||
396 | # Init the generate_graph tag |
||
397 | # Should be set to True to generate graphs |
||
398 | args.generate_graph = False |
||
399 | |||
400 | # Control parameter and exit if it is not OK |
||
401 | self.args = args |
||
402 | |||
403 | # Export is only available in standalone or client mode (issue #614) |
||
404 | export_tag = self.args.export is not None and any(self.args.export) |
||
405 | if WINDOWS and export_tag: |
||
406 | # On Windows, export is possible but only in quiet mode |
||
407 | # See issue #1038 |
||
408 | logger.info("On Windows OS, export disable the Web interface") |
||
409 | self.args.quiet = True |
||
410 | self.args.webserver = False |
||
411 | elif not (self.is_standalone() or self.is_client()) and export_tag: |
||
412 | logger.critical("Export is only available in standalone or client mode") |
||
413 | sys.exit(2) |
||
414 | |||
415 | # Filter is only available in standalone mode |
||
416 | if args.process_filter is not None and not self.is_standalone(): |
||
417 | logger.critical( |
||
418 | "Process filter is only available in standalone mode") |
||
419 | sys.exit(2) |
||
420 | |||
421 | # Disable HDDTemp if sensors are disabled |
||
422 | if getattr(args, 'disable_sensors', False): |
||
423 | disable(args, 'hddtemp') |
||
424 | logger.debug("Sensors and HDDTemp are disabled") |
||
425 | |||
426 | return args |
||
427 | |||
428 | def is_standalone(self): |
||
429 | """Return True if Glances is running in standalone mode.""" |
||
430 | return (not self.args.client and |
||
431 | not self.args.browser and |
||
432 | not self.args.server and |
||
433 | not self.args.webserver) |
||
434 | |||
435 | def is_client(self): |
||
436 | """Return True if Glances is running in client mode.""" |
||
437 | return (self.args.client or self.args.browser) and not self.args.server |
||
438 | |||
439 | def is_client_browser(self): |
||
440 | """Return True if Glances is running in client browser mode.""" |
||
441 | return self.args.browser and not self.args.server |
||
442 | |||
443 | def is_server(self): |
||
444 | """Return True if Glances is running in server mode.""" |
||
445 | return not self.args.client and self.args.server |
||
446 | |||
447 | def is_webserver(self): |
||
448 | """Return True if Glances is running in Web server mode.""" |
||
449 | return not self.args.client and self.args.webserver |
||
450 | |||
451 | def get_config(self): |
||
452 | """Return configuration file object.""" |
||
453 | return self.config |
||
454 | |||
455 | def get_args(self): |
||
456 | """Return the arguments.""" |
||
457 | return self.args |
||
458 | |||
459 | def get_mode(self): |
||
460 | """Return the mode.""" |
||
461 | return self.mode |
||
462 | |||
463 | def __get_username(self, description=''): |
||
464 | """Read an username from the command line.""" |
||
465 | return input(description) |
||
466 | |||
467 | def __get_password(self, description='', |
||
468 | confirm=False, clear=False, username='glances'): |
||
469 | """Read a password from the command line. |
||
470 | |||
471 | - if confirm = True, with confirmation |
||
472 | - if clear = True, plain (clear password) |
||
473 | """ |
||
474 | from glances.password import GlancesPassword |
||
475 | password = GlancesPassword(username=username) |
||
476 | return password.get_password(description, confirm, clear) |
||
477 |
This check looks for invalid names for a range of different identifiers.
You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.
If your project includes a Pylint configuration file, the settings contained in that file take precedence.
To find out more about Pylint, please refer to their site.