Test Failed
Push — develop ( d7cf39...faa4bd )
by Nicolas
04:34 queued 10s
created

glances/main.py (3 issues)

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
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in input.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
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 (any modes):
102
    $ glances --disable-plugin network,ports
103
"""
104
105
    def __init__(self):
106
        """Manage the command line arguments."""
107
        # Read the command line arguments
108
        self.args = self.parse_args()
109
110
    def init_args(self):
111
        """Init all the command line arguments."""
112
        version = "Glances v" + __version__ + " with psutil v" + psutil_version
113
        parser = argparse.ArgumentParser(
114
            prog='glances',
115
            conflict_handler='resolve',
116
            formatter_class=argparse.RawDescriptionHelpFormatter,
117
            epilog=self.example_of_use)
118
        parser.add_argument(
119
            '-V', '--version', action='version', version=version)
120
        parser.add_argument('-d', '--debug', action='store_true', default=False,
121
                            dest='debug', help='enable debug mode')
122
        parser.add_argument('-C', '--config', dest='conf_file',
123
                            help='path to the configuration file')
124
        # Disable plugin
125
        parser.add_argument('--modules-list', '--module-list',
126
                            action='store_true', default=False,
127
                            dest='modules_list',
128
                            help='display modules (plugins & exports) list and exit')
129
        parser.add_argument('--disable-plugin', dest='disable_plugin',
130
                            help='disable plugin (comma separed list)')
131
        parser.add_argument('--disable-process', action='store_true', default=False,
132
                            dest='disable_process', help='disable process module')
133
        # Enable or disable option
134
        parser.add_argument('--disable-webui', action='store_true', default=False,
135
                            dest='disable_webui', help='disable the Web Interface')
136
        parser.add_argument('--light', '--enable-light', action='store_true',
137
                            default=False, dest='enable_light',
138
                            help='light mode for Curses UI (disable all but top menu)')
139
        parser.add_argument('-0', '--disable-irix', action='store_true', default=False,
140
                            dest='disable_irix', help='task\'s cpu usage will be divided by the total number of CPUs')
141
        parser.add_argument('-1', '--percpu', action='store_true', default=False,
142
                            dest='percpu', help='start Glances in per CPU mode')
143
        parser.add_argument('-2', '--disable-left-sidebar', action='store_true',
144
                            default=False, dest='disable_left_sidebar',
145
                            help='disable network, disk I/O, FS and sensors modules')
146
        parser.add_argument('-3', '--disable-quicklook', action='store_true', default=False,
147
                            dest='disable_quicklook', help='disable quick look module')
148
        parser.add_argument('-4', '--full-quicklook', action='store_true', default=False,
149
                            dest='full_quicklook', help='disable all but quick look and load')
150
        parser.add_argument('-5', '--disable-top', action='store_true',
151
                            default=False, dest='disable_top',
152
                            help='disable top menu (QL, CPU, MEM, SWAP and LOAD)')
153
        parser.add_argument('-6', '--meangpu', action='store_true', default=False,
154
                            dest='meangpu', help='start Glances in mean GPU mode')
155
        parser.add_argument('--disable-history', action='store_true', default=False,
156
                            dest='disable_history', help='disable stats history')
157
        parser.add_argument('--disable-bold', action='store_true', default=False,
158
                            dest='disable_bold', help='disable bold mode in the terminal')
159
        parser.add_argument('--disable-bg', action='store_true', default=False,
160
                            dest='disable_bg', help='disable background colors in the terminal')
161
        parser.add_argument('--enable-irq', action='store_true', default=False,
0 ignored issues
show
Unused Code Bug introduced by
The expression (parser.add_argument('--...'enable IRQ module'), ) does not seem to have sideeffects and its result is not used.

If a expression has no sideeffects (any lasting effect after it has been called) and its return value is not used, this usually means that this code can be removed or that an assignment is missing.

Loading history...
162
                            dest='enable_irq', help='enable IRQ module'),
163
        parser.add_argument('--enable-process-extended', action='store_true', default=False,
164
                            dest='enable_process_extended', help='enable extended stats on top process')
165
        # Export modules feature
166
        parser.add_argument('--export', dest='export',
167
                            help='enable export module (comma separed list)')
168
        parser.add_argument('--export-csv-file',
169
                            default='./glances.csv',
170
                            dest='export_csv_file',
171
                            help='file path for CSV exporter')
172
        parser.add_argument('--export-csv-overwrite', action='store_true', default=False,
173
                            dest='export_csv_overwrite', help='overwrite existing CSV file')
174
        parser.add_argument('--export-json-file',
175
                            default='./glances.json',
176
                            dest='export_json_file',
177
                            help='file path for JSON exporter')
178
        parser.add_argument('--export-graph-path',
179
                            default=tempfile.gettempdir(),
180
                            dest='export_graph_path',
181
                            help='Folder for Graph exporter')
182
        # Client/Server option
183
        parser.add_argument('-c', '--client', dest='client',
184
                            help='connect to a Glances server by IPv4/IPv6 address or hostname')
185
        parser.add_argument('-s', '--server', action='store_true', default=False,
186
                            dest='server', help='run Glances in server mode')
187
        parser.add_argument('--browser', action='store_true', default=False,
188
                            dest='browser', help='start the client browser (list of servers)')
189
        parser.add_argument('--disable-autodiscover', action='store_true', default=False,
190
                            dest='disable_autodiscover', help='disable autodiscover feature')
191
        parser.add_argument('-p', '--port', default=None, type=int, dest='port',
192
                            help='define the client/server TCP port [default: {}]'.format(self.server_port))
193
        parser.add_argument('-B', '--bind', default='0.0.0.0', dest='bind_address',
194
                            help='bind server to the given IPv4/IPv6 address or hostname')
195
        parser.add_argument('--username', action='store_true', default=False, dest='username_prompt',
196
                            help='define a client/server username')
197
        parser.add_argument('--password', action='store_true', default=False, dest='password_prompt',
198
                            help='define a client/server password')
199
        parser.add_argument('-u', dest='username_used',
200
                            help='use the given client/server username')
201
        parser.add_argument('--snmp-community', default='public', dest='snmp_community',
202
                            help='SNMP community')
203
        parser.add_argument('--snmp-port', default=161, type=int,
204
                            dest='snmp_port', help='SNMP port')
205
        parser.add_argument('--snmp-version', default='2c', dest='snmp_version',
206
                            help='SNMP version (1, 2c or 3)')
207
        parser.add_argument('--snmp-user', default='private', dest='snmp_user',
208
                            help='SNMP username (only for SNMPv3)')
209
        parser.add_argument('--snmp-auth', default='password', dest='snmp_auth',
210
                            help='SNMP authentication key (only for SNMPv3)')
211
        parser.add_argument('--snmp-force', action='store_true', default=False,
212
                            dest='snmp_force', help='force SNMP mode')
213
        parser.add_argument('-t', '--time', default=self.refresh_time, type=float,
214
                            dest='time', help='set refresh time in seconds [default: {} sec]'.format(self.refresh_time))
215
        parser.add_argument('-w', '--webserver', action='store_true', default=False,
216
                            dest='webserver', help='run Glances in web server mode (bottle needed)')
217
        parser.add_argument('--cached-time', default=self.cached_time, type=int,
218
                            dest='cached_time', help='set the server cache time [default: {} sec]'.format(self.cached_time))
219
        parser.add_argument('--open-web-browser', action='store_true', default=False,
220
                            dest='open_web_browser', help='try to open the Web UI in the default Web browser')
221
        # Display options
222
        parser.add_argument('-q', '--quiet', default=False, action='store_true',
223
                            dest='quiet', help='do not display the curses interface')
224
        parser.add_argument('-f', '--process-filter', default=None, type=str,
225
                            dest='process_filter', help='set the process filter pattern (regular expression)')
226
        parser.add_argument('--process-short-name', action='store_true', default=False,
227
                            dest='process_short_name', help='force short name for processes name')
228
        parser.add_argument('--stdout', default=None,
229
                            dest='stdout', help='display stats to stdout, one stat per line (comma separated list of plugins/plugins.attribute)')
230
        parser.add_argument('--stdout-csv', default=None,
231
                            dest='stdout_csv', help='display stats to stdout, csv format (comma separated list of plugins/plugins.attribute)')
232
        if not WINDOWS:
233
            parser.add_argument('--hide-kernel-threads', action='store_true', default=False,
234
                                dest='no_kernel_threads', help='hide kernel threads in process list (not available on Windows)')
235
        parser.add_argument('-b', '--byte', action='store_true', default=False,
236
                            dest='byte', help='display network rate in byte per second')
237
        parser.add_argument('--diskio-show-ramfs', action='store_true', default=False,
238
                            dest='diskio_show_ramfs', help='show RAM Fs in the DiskIO plugin')
239
        parser.add_argument('--diskio-iops', action='store_true', default=False,
240
                            dest='diskio_iops', help='show IO per second in the DiskIO plugin')
241
        parser.add_argument('--fahrenheit', action='store_true', default=False,
242
                            dest='fahrenheit', help='display temperature in Fahrenheit (default is Celsius)')
243
        parser.add_argument('--fs-free-space', action='store_true', default=False,
244
                            dest='fs_free_space', help='display FS free space instead of used')
245
        parser.add_argument('--sparkline', action='store_true', default=False,
246
                            dest='sparkline', help='display sparklines instead of bar in the curses interface')
247
        parser.add_argument('--theme-white', action='store_true', default=False,
248
                            dest='theme_white', help='optimize display colors for white background')
249
        # Globals options
250
        parser.add_argument('--disable-check-update', action='store_true', default=False,
251
                            dest='disable_check_update', help='disable online Glances version ckeck')
252
        return parser
253
254
    def parse_args(self):
255
        """Parse command line arguments."""
256
        args = self.init_args().parse_args()
257
258
        # Load the configuration file, if it exists
259
        self.config = Config(args.conf_file)
260
261
        # Debug mode
262
        if args.debug:
263
            from logging import DEBUG
264
            logger.setLevel(DEBUG)
265
        else:
266
            from warnings import simplefilter
267
            simplefilter("ignore")
268
269
        # Plugins disable/enable
270
        if args.disable_plugin is not None:
271
            for p in args.disable_plugin.split(','):
272
                disable(args, p)
273
        else:
274
            # Allow users to disable plugins from the glances.conf (issue #1378)
275
            for s in self.config.sections():
276
                if self.config.has_section(s) \
277
                   and (self.config.get_bool_value(s, 'disable', False)):
278
                    disable(args, s)
279
                    logger.debug('{} disabled by the configuration file'.format(s))
280
281
        # Exporters activation
282
        if args.export is not None:
283
            for p in args.export.split(','):
284
                setattr(args, 'export_' + p, True)
285
286
        # Client/server Port
287
        if args.port is None:
288
            if args.webserver:
289
                args.port = self.web_server_port
290
            else:
291
                args.port = self.server_port
292
        # Port in the -c URI #996
293
        if args.client is not None:
294
            args.client, args.port = (x if x else y for (x, y) in zip(args.client.partition(':')[::2], (args.client, args.port)))
295
296
        # Autodiscover
297
        if args.disable_autodiscover:
298
            logger.info("Auto discover mode is disabled")
299
300
        # By default Windows is started in Web mode
301
        if WINDOWS:
302
            args.webserver = True
303
304
        # In web server mode, default refresh time: 5 sec
305
        if args.webserver:
306
            args.time = 5
307
            args.process_short_name = True
308
309
        # Server or client login/password
310
        if args.username_prompt:
311
            # Every username needs a password
312
            args.password_prompt = True
313
            # Prompt username
314
            if args.server:
315
                args.username = self.__get_username(
316
                    description='Define the Glances server username: ')
317
            elif args.webserver:
318
                args.username = self.__get_username(
319
                    description='Define the Glances webserver username: ')
320
            elif args.client:
321
                args.username = self.__get_username(
322
                    description='Enter the Glances server username: ')
323
        else:
324
            if args.username_used:
325
                # A username has been set using the -u option ?
326
                args.username = args.username_used
327
            else:
328
                # Default user name is 'glances'
329
                args.username = self.username
330
331
        if args.password_prompt or args.username_used:
332
            # Interactive or file password
333
            if args.server:
334
                args.password = self.__get_password(
335
                    description='Define the Glances server password ({} username): '.format(
336
                        args.username),
337
                    confirm=True,
338
                    username=args.username)
339
            elif args.webserver:
340
                args.password = self.__get_password(
341
                    description='Define the Glances webserver password ({} username): '.format(
342
                        args.username),
343
                    confirm=True,
344
                    username=args.username)
345
            elif args.client:
346
                args.password = self.__get_password(
347
                    description='Enter the Glances server password ({} username): '.format(
348
                        args.username),
349
                    clear=True,
350
                    username=args.username)
351
        else:
352
            # Default is no password
353
            args.password = self.password
354
355
        # By default help is hidden
356
        args.help_tag = False
357
358
        # Display Rx and Tx, not the sum for the network
359
        args.network_sum = False
360
        args.network_cumul = False
361
362
        # Manage light mode
363
        if args.enable_light:
364
            logger.info("Light mode is on")
365
            args.disable_left_sidebar = True
366
            disable(args, 'process')
367
            disable(args, 'alert')
368
            disable(args, 'amps')
369
            disable(args, 'docker')
370
371
        # Manage full quicklook option
372
        if args.full_quicklook:
373
            logger.info("Full quicklook mode")
374
            enable(args, 'quicklook')
375
            disable(args, 'cpu')
376
            disable(args, 'mem')
377
            disable(args, 'memswap')
378
            enable(args, 'load')
379
380
        # Manage disable_top option
381
        if args.disable_top:
382
            logger.info("Disable top menu")
383
            disable(args, 'quicklook')
384
            disable(args, 'cpu')
385
            disable(args, 'mem')
386
            disable(args, 'memswap')
387
            disable(args, 'load')
388
389
        # Init the generate_graph tag
390
        # Should be set to True to generate graphs
391
        args.generate_graph = False
392
393
        # Control parameter and exit if it is not OK
394
        self.args = args
395
396
        # Export is only available in standalone or client mode (issue #614)
397
        export_tag = self.args.export is not None and any(self.args.export)
398
        if WINDOWS and export_tag:
399
            # On Windows, export is possible but only in quiet mode
400
            # See issue #1038
401
            logger.info("On Windows OS, export disable the Web interface")
402
            self.args.quiet = True
403
            self.args.webserver = False
404
        elif not (self.is_standalone() or self.is_client()) and export_tag:
405
            logger.critical("Export is only available in standalone or client mode")
406
            sys.exit(2)
407
408
        # Filter is only available in standalone mode
409
        if args.process_filter is not None and not self.is_standalone():
410
            logger.critical(
411
                "Process filter is only available in standalone mode")
412
            sys.exit(2)
413
414
        # Disable HDDTemp if sensors are disabled
415
        if getattr(args, 'disable_sensors', False):
416
            disable(args, 'hddtemp')
417
            logger.debug("Sensors and HDDTemp are disabled")
418
419
        return args
420
421
    def is_standalone(self):
422
        """Return True if Glances is running in standalone mode."""
423
        return (not self.args.client and
424
                not self.args.browser and
425
                not self.args.server and
426
                not self.args.webserver)
427
428
    def is_client(self):
429
        """Return True if Glances is running in client mode."""
430
        return (self.args.client or self.args.browser) and not self.args.server
431
432
    def is_client_browser(self):
433
        """Return True if Glances is running in client browser mode."""
434
        return self.args.browser and not self.args.server
435
436
    def is_server(self):
437
        """Return True if Glances is running in server mode."""
438
        return not self.args.client and self.args.server
439
440
    def is_webserver(self):
441
        """Return True if Glances is running in Web server mode."""
442
        return not self.args.client and self.args.webserver
443
444
    def get_config(self):
445
        """Return configuration file object."""
446
        return self.config
447
448
    def get_args(self):
449
        """Return the arguments."""
450
        return self.args
451
452
    def get_mode(self):
453
        """Return the mode."""
454
        return self.mode
0 ignored issues
show
The Instance of GlancesMain does not seem to have a member named mode.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
455
456
    def __get_username(self, description=''):
457
        """Read an username from the command line."""
458
        return input(description)
459
460
    def __get_password(self, description='',
461
                       confirm=False, clear=False, username='glances'):
462
        """Read a password from the command line.
463
464
        - if confirm = True, with confirmation
465
        - if clear = True, plain (clear password)
466
        """
467
        from glances.password import GlancesPassword
468
        password = GlancesPassword(username=username)
469
        return password.get_password(description, confirm, clear)
470