Test Failed
Push — master ( 69b639...e7fa0a )
by Nicolas
04:05 queued 01:05
created

glances.main.GlancesMain.is_standalone()   A

Complexity

Conditions 1

Size

Total Lines 6
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

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