Completed
Push — develop ( 26e6a7...16a9ce )
by Nicolas
03:36 queued 10s
created

glances/main.py (1 issue)

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 (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,
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))
0 ignored issues
show
This line is too long as per the coding-style (83/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
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
305
        if args.webserver:
306
            args.process_short_name = True
307
308
        # Server or client login/password
309
        if args.username_prompt:
310
            # Every username needs a password
311
            args.password_prompt = True
312
            # Prompt username
313
            if args.server:
314
                args.username = self.__get_username(
315
                    description='Define the Glances server username: ')
316
            elif args.webserver:
317
                args.username = self.__get_username(
318
                    description='Define the Glances webserver username: ')
319
            elif args.client:
320
                args.username = self.__get_username(
321
                    description='Enter the Glances server username: ')
322
        else:
323
            if args.username_used:
324
                # A username has been set using the -u option ?
325
                args.username = args.username_used
326
            else:
327
                # Default user name is 'glances'
328
                args.username = self.username
329
330
        if args.password_prompt or args.username_used:
331
            # Interactive or file password
332
            if args.server:
333
                args.password = self.__get_password(
334
                    description='Define the Glances server password ({} username): '.format(
335
                        args.username),
336
                    confirm=True,
337
                    username=args.username)
338
            elif args.webserver:
339
                args.password = self.__get_password(
340
                    description='Define the Glances webserver password ({} username): '.format(
341
                        args.username),
342
                    confirm=True,
343
                    username=args.username)
344
            elif args.client:
345
                args.password = self.__get_password(
346
                    description='Enter the Glances server password ({} username): '.format(
347
                        args.username),
348
                    clear=True,
349
                    username=args.username)
350
        else:
351
            # Default is no password
352
            args.password = self.password
353
354
        # By default help is hidden
355
        args.help_tag = False
356
357
        # Display Rx and Tx, not the sum for the network
358
        args.network_sum = False
359
        args.network_cumul = False
360
361
        # Manage light mode
362
        if args.enable_light:
363
            logger.info("Light mode is on")
364
            args.disable_left_sidebar = True
365
            disable(args, 'process')
366
            disable(args, 'alert')
367
            disable(args, 'amps')
368
            disable(args, 'docker')
369
370
        # Manage full quicklook option
371
        if args.full_quicklook:
372
            logger.info("Full quicklook mode")
373
            enable(args, 'quicklook')
374
            disable(args, 'cpu')
375
            disable(args, 'mem')
376
            disable(args, 'memswap')
377
            enable(args, 'load')
378
379
        # Manage disable_top option
380
        if args.disable_top:
381
            logger.info("Disable top menu")
382
            disable(args, 'quicklook')
383
            disable(args, 'cpu')
384
            disable(args, 'mem')
385
            disable(args, 'memswap')
386
            disable(args, 'load')
387
388
        # Init the generate_graph tag
389
        # Should be set to True to generate graphs
390
        args.generate_graph = False
391
392
        # Control parameter and exit if it is not OK
393
        self.args = args
394
395
        # Export is only available in standalone or client mode (issue #614)
396
        export_tag = self.args.export is not None and any(self.args.export)
397
        if WINDOWS and export_tag:
398
            # On Windows, export is possible but only in quiet mode
399
            # See issue #1038
400
            logger.info("On Windows OS, export disable the Web interface")
401
            self.args.quiet = True
402
            self.args.webserver = False
403
        elif not (self.is_standalone() or self.is_client()) and export_tag:
404
            logger.critical("Export is only available in standalone or client mode")
405
            sys.exit(2)
406
407
        # Filter is only available in standalone mode
408
        if args.process_filter is not None and not self.is_standalone():
409
            logger.critical(
410
                "Process filter is only available in standalone mode")
411
            sys.exit(2)
412
413
        # Disable HDDTemp if sensors are disabled
414
        if getattr(args, 'disable_sensors', False):
415
            disable(args, 'hddtemp')
416
            logger.debug("Sensors and HDDTemp are disabled")
417
418
        return args
419
420
    def is_standalone(self):
421
        """Return True if Glances is running in standalone mode."""
422
        return (not self.args.client and
423
                not self.args.browser and
424
                not self.args.server and
425
                not self.args.webserver)
426
427
    def is_client(self):
428
        """Return True if Glances is running in client mode."""
429
        return (self.args.client or self.args.browser) and not self.args.server
430
431
    def is_client_browser(self):
432
        """Return True if Glances is running in client browser mode."""
433
        return self.args.browser and not self.args.server
434
435
    def is_server(self):
436
        """Return True if Glances is running in server mode."""
437
        return not self.args.client and self.args.server
438
439
    def is_webserver(self):
440
        """Return True if Glances is running in Web server mode."""
441
        return not self.args.client and self.args.webserver
442
443
    def get_config(self):
444
        """Return configuration file object."""
445
        return self.config
446
447
    def get_args(self):
448
        """Return the arguments."""
449
        return self.args
450
451
    def get_mode(self):
452
        """Return the mode."""
453
        return self.mode
454
455
    def __get_username(self, description=''):
456
        """Read an username from the command line."""
457
        return input(description)
458
459
    def __get_password(self, description='',
460
                       confirm=False, clear=False, username='glances'):
461
        """Read a password from the command line.
462
463
        - if confirm = True, with confirmation
464
        - if clear = True, plain (clear password)
465
        """
466
        from glances.password import GlancesPassword
467
        password = GlancesPassword(username=username)
468
        return password.get_password(description, confirm, clear)
469