main.py 18.2 KB
Newer Older
N
Nicolas Hennion 已提交
1 2
# -*- coding: utf-8 -*-
#
3
# This file is part of Glances.
N
Nicolas Hennion 已提交
4
#
5
# Copyright (C) 2015 Nicolargo <nicolas@nicolargo.com>
N
Nicolas Hennion 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18
#
# Glances is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Glances is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
A
PEP 257  
Alessio Sergi 已提交
19 20

"""Glances main class."""
N
Nicolas Hennion 已提交
21

N
Nicolas Hennion 已提交
22
import argparse
23
import os
24
import sys
25
import tempfile
N
Nicolas Hennion 已提交
26

27
from glances.config import Config
A
Alessio Sergi 已提交
28
from glances.globals import appname, LINUX, WINDOWS, psutil_version, version
29
from glances.logger import logger
N
Nicolas Hennion 已提交
30

N
Nicolas Hennion 已提交
31

32
class GlancesMain(object):
A
PEP 257  
Alessio Sergi 已提交
33 34

    """Main class to manage Glances instance."""
N
Nicolas Hennion 已提交
35

N
Nicolas Hennion 已提交
36 37
    # Default stats' refresh time is 3 seconds
    refresh_time = 3
38

N
Nicolas Hennion 已提交
39
    # Set the default cache lifetime to 1 second (only for server)
N
Nicolas Hennion 已提交
40
    # !!! Todo: configuration from the command line
A
Alessio Sergi 已提交
41
    cached_time = 1
N
Nicolas Hennion 已提交
42 43 44 45
    # By default, Glances is ran in standalone mode (no client/server)
    client_tag = False
    # Server TCP port number (default is 61209)
    server_port = 61209
N
Nicolas Hennion 已提交
46 47
    # Web Server TCP port number (default is 61208)
    web_server_port = 61208
N
Nicolas Hennion 已提交
48 49 50 51
    # Default username/password for client/server mode
    username = "glances"
    password = ""

N
Nicolargo 已提交
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
    # Exemple of use
    example_of_use = "\
Examples of use:\n\
\n\
Monitor local machine (standalone mode):\n\
  $ glances\n\
\n\
Monitor local machine with the Web interface (Web UI):\n\
  $ glances -w\n\
  Glances web server started on http://0.0.0.0:61208/\n\
\n\
Monitor local machine and export stats to a CSV file (standalone mode):\n\
  $ glances --export-csv\n\
\n\
Monitor local machine and export stats to a InfluxDB server with 5s refresh time (standalone mode):\n\
N
Nicolargo 已提交
67
  $ glances -t 5 --export-influxdb\n\
N
Nicolargo 已提交
68 69 70 71 72 73 74 75 76 77 78 79 80 81
\n\
Start a Glances server (server mode):\n\
  $ glances -s\n\
\n\
Connect Glances to a Glances server (client mode):\n\
  $ glances -c <ip_server>\n\
\n\
Connect Glances to a Glances server and export stats to a StatsD server (client mode):\n\
  $ glances -c <ip_server> --export-statsd\n\
\n\
Start the client browser (browser mode):\n\
  $ glances --browser\n\
    "

N
Nicolas Hennion 已提交
82
    def __init__(self):
A
Alessio Sergi 已提交
83 84 85 86 87
        """Manage the command line arguments."""
        self.args = self.parse_args()

    def init_args(self):
        """Init all the command line arguments."""
A
Alessio Sergi 已提交
88
        _version = "Glances v" + version + " with psutil v" + psutil_version
89
        parser = argparse.ArgumentParser(
N
Nicolargo 已提交
90 91 92 93
            prog=appname,
            conflict_handler='resolve',
            formatter_class=argparse.RawDescriptionHelpFormatter,
            epilog=self.example_of_use)
94 95
        parser.add_argument(
            '-V', '--version', action='version', version=_version)
N
Nicolas Hennion 已提交
96
        parser.add_argument('-d', '--debug', action='store_true', default=False,
A
Alessio Sergi 已提交
97
                            dest='debug', help='enable debug mode')
A
Alessio Sergi 已提交
98
        parser.add_argument('-C', '--config', dest='conf_file',
A
Alessio Sergi 已提交
99
                            help='path to the configuration file')
N
Nicolargo 已提交
100
        # Enable or disable option on startup
N
Nicolargo 已提交
101 102 103 104
        parser.add_argument('-3', '--disable-quicklook', action='store_true', default=False,
                            dest='disable_quicklook', help='disable quick look module')
        parser.add_argument('-4', '--full-quicklook', action='store_true', default=False,
                            dest='full_quicklook', help='disable all but quick look and load')
105 106 107 108 109 110 111 112
        parser.add_argument('--disable-cpu', action='store_true', default=False,
                            dest='disable_cpu', help='disable CPU module')
        parser.add_argument('--disable-mem', action='store_true', default=False,
                            dest='disable_mem', help='disable memory module')
        parser.add_argument('--disable-swap', action='store_true', default=False,
                            dest='disable_swap', help='disable swap module')
        parser.add_argument('--disable-load', action='store_true', default=False,
                            dest='disable_load', help='disable load module')
113
        parser.add_argument('--disable-network', action='store_true', default=False,
A
Alessio Sergi 已提交
114
                            dest='disable_network', help='disable network module')
115
        parser.add_argument('--disable-ip', action='store_true', default=False,
A
Alessio Sergi 已提交
116
                            dest='disable_ip', help='disable IP module')
A
Alessio Sergi 已提交
117
        parser.add_argument('--disable-diskio', action='store_true', default=False,
A
Alessio Sergi 已提交
118
                            dest='disable_diskio', help='disable disk I/O module')
A
Alessio Sergi 已提交
119
        parser.add_argument('--disable-fs', action='store_true', default=False,
A
Alessio Sergi 已提交
120
                            dest='disable_fs', help='disable filesystem module')
N
nicolargo 已提交
121 122
        parser.add_argument('--disable-folder', action='store_true', default=False,
                            dest='disable_folder', help='disable folder module')
A
Alessio Sergi 已提交
123
        parser.add_argument('--disable-sensors', action='store_true', default=False,
A
Alessio Sergi 已提交
124
                            dest='disable_sensors', help='disable sensors module')
125
        parser.add_argument('--disable-hddtemp', action='store_true', default=False,
A
Alessio Sergi 已提交
126
                            dest='disable_hddtemp', help='disable HD temperature module')
N
Nicolargo 已提交
127
        parser.add_argument('--disable-raid', action='store_true', default=False,
A
Alessio Sergi 已提交
128
                            dest='disable_raid', help='disable RAID module')
N
Nicolargo 已提交
129
        parser.add_argument('--disable-docker', action='store_true', default=False,
A
Alessio Sergi 已提交
130
                            dest='disable_docker', help='disable Docker module')
131 132 133
        parser.add_argument('-5', '--disable-top', action='store_true',
                            default=False, dest='disable_top',
                            help='disable top menu (QL, CPU, MEM, SWAP and LOAD)')
134
        parser.add_argument('-2', '--disable-left-sidebar', action='store_true',
A
Alessio Sergi 已提交
135
                            default=False, dest='disable_left_sidebar',
136
                            help='disable network, disk I/O, FS and sensors modules')
137
        parser.add_argument('--disable-process', action='store_true', default=False,
A
Alessio Sergi 已提交
138
                            dest='disable_process', help='disable process module')
A
Alessio Sergi 已提交
139
        parser.add_argument('--disable-log', action='store_true', default=False,
A
Alessio Sergi 已提交
140
                            dest='disable_log', help='disable log module')
141
        parser.add_argument('--disable-bold', action='store_true', default=False,
A
Alessio Sergi 已提交
142
                            dest='disable_bold', help='disable bold mode in the terminal')
143
        parser.add_argument('--disable-bg', action='store_true', default=False,
144
                            dest='disable_bg', help='disable background colors in the terminal')
N
Nicolargo 已提交
145
        parser.add_argument('--enable-process-extended', action='store_true', default=False,
A
Alessio Sergi 已提交
146
                            dest='enable_process_extended', help='enable extended stats on top process')
147
        parser.add_argument('--enable-history', action='store_true', default=False,
A
Alessio Sergi 已提交
148
                            dest='enable_history', help='enable the history mode (matplotlib needed)')
149
        parser.add_argument('--path-history', default=tempfile.gettempdir(),
A
Alessio Sergi 已提交
150
                            dest='path_history', help='set the export path for graph history')
151 152
        # Export modules feature
        parser.add_argument('--export-csv', default=None,
A
Alessio Sergi 已提交
153
                            dest='export_csv', help='export stats to a CSV file')
N
Nicolargo 已提交
154
        parser.add_argument('--export-influxdb', action='store_true', default=False,
A
Alessio Sergi 已提交
155
                            dest='export_influxdb', help='export stats to an InfluxDB server (influxdb needed)')
156 157
        parser.add_argument('--export-opentsdb', action='store_true', default=False,
                            dest='export_opentsdb', help='export stats to an OpenTSDB server (potsdb needed)')
N
Nicolargo 已提交
158
        parser.add_argument('--export-statsd', action='store_true', default=False,
A
Alessio Sergi 已提交
159 160 161
                            dest='export_statsd', help='export stats to a StatsD server (statsd needed)')
        parser.add_argument('--export-rabbitmq', action='store_true', default=False,
                            dest='export_rabbitmq', help='export stats to rabbitmq broker (pika needed)')
N
Nicolargo 已提交
162 163
        # Client/Server option
        parser.add_argument('-c', '--client', dest='client',
A
Alessio Sergi 已提交
164
                            help='connect to a Glances server by IPv4/IPv6 address or hostname')
N
Nicolargo 已提交
165
        parser.add_argument('-s', '--server', action='store_true', default=False,
A
Alessio Sergi 已提交
166
                            dest='server', help='run Glances in server mode')
167
        parser.add_argument('--browser', action='store_true', default=False,
A
Alessio Sergi 已提交
168
                            dest='browser', help='start the client browser (list of servers)')
169
        parser.add_argument('--disable-autodiscover', action='store_true', default=False,
A
Alessio Sergi 已提交
170
                            dest='disable_autodiscover', help='disable autodiscover feature')
171
        parser.add_argument('-p', '--port', default=None, type=int, dest='port',
A
Alessio Sergi 已提交
172
                            help='define the client/server TCP port [default: {0}]'.format(self.server_port))
N
Nicolargo 已提交
173
        parser.add_argument('-B', '--bind', default='0.0.0.0', dest='bind_address',
A
Alessio Sergi 已提交
174
                            help='bind server to the given IPv4/IPv6 address or hostname')
A
Alessio Sergi 已提交
175
        parser.add_argument('--password', action='store_true', default=False, dest='password_prompt',
A
Alessio Sergi 已提交
176
                            help='define a client/server password')
177
        parser.add_argument('--snmp-community', default='public', dest='snmp_community',
A
Alessio Sergi 已提交
178
                            help='SNMP community')
A
Alessio Sergi 已提交
179
        parser.add_argument('--snmp-port', default=161, type=int,
A
Alessio Sergi 已提交
180
                            dest='snmp_port', help='SNMP port')
N
Nicolargo 已提交
181
        parser.add_argument('--snmp-version', default='2c', dest='snmp_version',
A
Alessio Sergi 已提交
182
                            help='SNMP version (1, 2c or 3)')
N
Nicolargo 已提交
183
        parser.add_argument('--snmp-user', default='private', dest='snmp_user',
A
Alessio Sergi 已提交
184
                            help='SNMP username (only for SNMPv3)')
N
Nicolargo 已提交
185
        parser.add_argument('--snmp-auth', default='password', dest='snmp_auth',
A
Alessio Sergi 已提交
186
                            help='SNMP authentication key (only for SNMPv3)')
187
        parser.add_argument('--snmp-force', action='store_true', default=False,
A
Alessio Sergi 已提交
188
                            dest='snmp_force', help='force SNMP mode')
189
        parser.add_argument('-t', '--time', default=self.refresh_time, type=float,
A
Alessio Sergi 已提交
190
                            dest='time', help='set refresh time in seconds [default: {0} sec]'.format(self.refresh_time))
A
Alessio Sergi 已提交
191
        parser.add_argument('-w', '--webserver', action='store_true', default=False,
A
Alessio Sergi 已提交
192
                            dest='webserver', help='run Glances in web server mode (bottle needed)')
193
        # Display options
N
nicolargo 已提交
194
        parser.add_argument('-q', '--quiet', default=False, action='store_true',
A
Alessio Sergi 已提交
195
                            dest='quiet', help='do not display the curses interface')
N
Nicolargo 已提交
196
        parser.add_argument('-f', '--process-filter', default=None, type=str,
A
Alessio Sergi 已提交
197
                            dest='process_filter', help='set the process filter pattern (regular expression)')
198
        parser.add_argument('--process-short-name', action='store_true', default=False,
A
Alessio Sergi 已提交
199
                            dest='process_short_name', help='force short name for processes name')
200
        parser.add_argument('-0', '--disable-irix', action='store_true', default=False,
201
                            dest='disable_irix', help='Task\'s cpu usage will be divided by the total number of CPUs')
A
Alessio Sergi 已提交
202
        if not WINDOWS:
203
            parser.add_argument('--hide-kernel-threads', action='store_true', default=False,
A
Alessio Sergi 已提交
204
                                dest='no_kernel_threads', help='hide kernel threads in process list')
A
Alessio Sergi 已提交
205
        if LINUX:
206 207
            parser.add_argument('--tree', action='store_true', default=False,
                                dest='process_tree', help='display processes as a tree')
N
Nicolargo 已提交
208
        parser.add_argument('-b', '--byte', action='store_true', default=False,
A
Alessio Sergi 已提交
209
                            dest='byte', help='display network rate in byte per second')
210 211
        parser.add_argument('--diskio-show-ramfs', action='store_true', default=False,
                            dest='diskio_show_ramfs', help='show RAM Fs in the DiskIO plugin')
212 213
        parser.add_argument('--diskio-iops', action='store_true', default=False,
                            dest='diskio_iops', help='show IO per second in the DiskIO plugin')
N
nicolargo 已提交
214 215
        parser.add_argument('--fahrenheit', action='store_true', default=False,
                            dest='fahrenheit', help='display temperature in Fahrenheit (default is Celsius)')
A
Alessio Sergi 已提交
216
        parser.add_argument('-1', '--percpu', action='store_true', default=False,
A
Alessio Sergi 已提交
217
                            dest='percpu', help='start Glances in per CPU mode')
218
        parser.add_argument('--fs-free-space', action='store_false', default=False,
A
Alessio Sergi 已提交
219
                            dest='fs_free_space', help='display FS free space instead of used')
N
Nicolargo 已提交
220
        parser.add_argument('--theme-white', action='store_true', default=False,
A
Alessio Sergi 已提交
221
                            dest='theme_white', help='optimize display colors for white background')
A
Alessio Sergi 已提交
222 223 224 225 226 227 228

        return parser

    def parse_args(self):
        """Parse command line arguments."""
        args = self.init_args().parse_args()

229
        # Load the configuration file, if it exists
A
Alessio Sergi 已提交
230 231
        self.config = Config(args.conf_file)

N
Nicolas Hennion 已提交
232 233 234 235 236
        # Debug mode
        if args.debug:
            from logging import DEBUG
            logger.setLevel(DEBUG)

237
        # Client/server Port
238 239 240 241
        if args.port is None:
            if args.webserver:
                args.port = self.web_server_port
            else:
242
                args.port = self.server_port
243

244 245 246 247
        # Autodiscover
        if args.disable_autodiscover:
            logger.info("Auto discover mode is disabled")

248
        # In web server mode, defaul refresh time: 5 sec
A
Alessio Sergi 已提交
249
        if args.webserver:
N
Nicolargo 已提交
250
            args.time = 5
251
            args.process_short_name = True
N
Nicolas Hennion 已提交
252 253 254

        # Server or client login/password
        args.username = self.username
255
        if args.password_prompt:
N
Nicolargo 已提交
256
            # Interactive or file password
A
Alessio Sergi 已提交
257
            if args.server:
N
Nicolas Hennion 已提交
258
                args.password = self.__get_password(
A
Alessio Sergi 已提交
259
                    description='Define the password for the Glances server',
A
Alessio Sergi 已提交
260
                    confirm=True)
261 262
            elif args.webserver:
                args.password = self.__get_password(
263
                    description='Define the password for the Glances web server\nUser name: glances',
264
                    confirm=True)
A
Alessio Sergi 已提交
265
            elif args.client:
N
Nicolas Hennion 已提交
266
                args.password = self.__get_password(
A
Alessio Sergi 已提交
267
                    description='Enter the Glances server password',
N
Nicolargo 已提交
268
                    clear=True)
N
Nicolas Hennion 已提交
269 270 271 272
        else:
            # Default is no password
            args.password = self.password

A
Alessio Sergi 已提交
273 274 275 276 277 278 279
        # By default help is hidden
        args.help_tag = False

        # Display Rx and Tx, not the sum for the network
        args.network_sum = False
        args.network_cumul = False

280 281
        # Manage full quicklook option
        if args.full_quicklook:
282
            logger.info("Disable QuickLook menu")
283 284 285 286 287
            args.disable_quicklook = False
            args.disable_cpu = True
            args.disable_mem = True
            args.disable_swap = True
            args.disable_load = False
288 289 290 291 292 293 294 295 296

        # Manage disable_top option
        if args.disable_top:
            logger.info("Disable top menu")
            args.disable_quicklook = True
            args.disable_cpu = True
            args.disable_mem = True
            args.disable_swap = True
            args.disable_load = True
297

298 299 300
        # Control parameter and exit if it is not OK
        self.args = args

301
        # Export is only available in standalone or client mode (issue #614)
302
        export_tag = args.export_csv or args.export_statsd or args.export_influxdb or args.export_opentsdb or args.export_rabbitmq
303 304 305 306
        if not (self.is_standalone() or self.is_client()) and export_tag:
            logger.critical("Export is only available in standalone or client mode")
            sys.exit(2)

307 308
        # Filter is only available in standalone mode
        if args.process_filter is not None and not self.is_standalone():
A
Alessio Sergi 已提交
309
            logger.critical("Process filter is only available in standalone mode")
310 311
            sys.exit(2)

312 313 314
        # Check graph output path
        if args.enable_history and args.path_history is not None:
            if not os.access(args.path_history, os.W_OK):
A
Alessio Sergi 已提交
315
                logger.critical("History output path {0} do not exist or is not writable".format(args.path_history))
316
                sys.exit(2)
A
Alessio Sergi 已提交
317
            logger.debug("History output path is set to {0}".format(args.path_history))
318

319 320 321 322 323
        # Disable HDDTemp if sensors are disabled
        if args.disable_sensors:
            args.disable_hddtemp = True
            logger.debug("Sensors and HDDTemp are disabled")

N
Nicolas Hennion 已提交
324
        return args
N
Nicolas Hennion 已提交
325

N
Nicolargo 已提交
326
    def __get_password(self, description='', confirm=False, clear=False):
A
PEP 257  
Alessio Sergi 已提交
327 328 329 330
        """Read a password from the command line.

        - if confirm = True, with confirmation
        - if clear = True, plain (clear password)
N
Nicolargo 已提交
331
        """
332
        from glances.password import GlancesPassword
A
Alessio Sergi 已提交
333
        password = GlancesPassword()
N
Nicolargo 已提交
334
        return password.get_password(description, confirm, clear)
N
Nicolas Hennion 已提交
335

N
Nicolas Hennion 已提交
336
    def is_standalone(self):
A
PEP 257  
Alessio Sergi 已提交
337
        """Return True if Glances is running in standalone mode."""
338
        return not self.args.client and not self.args.browser and not self.args.server and not self.args.webserver
N
Nicolas Hennion 已提交
339 340

    def is_client(self):
A
PEP 257  
Alessio Sergi 已提交
341
        """Return True if Glances is running in client mode."""
342
        return (self.args.client or self.args.browser) and not self.args.server
343

344 345 346
    def is_client_browser(self):
        """Return True if Glances is running in client browser mode."""
        return self.args.browser and not self.args.server
N
Nicolas Hennion 已提交
347 348

    def is_server(self):
A
PEP 257  
Alessio Sergi 已提交
349
        """Return True if Glances is running in server mode."""
350
        return not self.args.client and self.args.server
N
Nicolas Hennion 已提交
351

352
    def is_webserver(self):
A
PEP 257  
Alessio Sergi 已提交
353
        """Return True if Glances is running in Web server mode."""
354
        return not self.args.client and self.args.webserver
N
Nicolas Hennion 已提交
355

356
    def get_config(self):
A
PEP 257  
Alessio Sergi 已提交
357
        """Return configuration file object."""
358
        return self.config
N
Nicolas Hennion 已提交
359 360

    def get_args(self):
A
PEP 257  
Alessio Sergi 已提交
361
        """Return the arguments."""
A
Alessio Sergi 已提交
362
        return self.args