glances_main.py 12.9 KB
Newer Older
N
Nicolas Hennion 已提交
1 2
# -*- coding: utf-8 -*-
#
3
# This file is part of Glances.
N
Nicolas Hennion 已提交
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
#
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
#
# 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 system libs
N
Nicolas Hennion 已提交
23
import argparse
24
import os
25
import sys
26
import tempfile
N
Nicolas Hennion 已提交
27

N
Nicolas Hennion 已提交
28
# Import Glances libs
N
Nicolas Hennion 已提交
29
from glances.core.glances_config import Config
30
from glances.core.glances_globals import appname, is_windows, logger, psutil_version, version
N
Nicolas Hennion 已提交
31

N
Nicolas Hennion 已提交
32

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

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

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

N
Nicolas Hennion 已提交
40
    # Set the default cache lifetime to 1 second (only for server)
N
Nicolas Hennion 已提交
41
    # !!! Todo: configuration from the command line
A
Alessio Sergi 已提交
42
    cached_time = 1
N
Nicolas Hennion 已提交
43 44 45 46
    # 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 已提交
47 48
    # Web Server TCP port number (default is 61208)
    web_server_port = 61208
N
Nicolas Hennion 已提交
49 50 51 52
    # Default username/password for client/server mode
    username = "glances"
    password = ""

N
Nicolas Hennion 已提交
53
    def __init__(self):
A
Alessio Sergi 已提交
54 55 56 57 58
        """Manage the command line arguments."""
        self.args = self.parse_args()

    def init_args(self):
        """Init all the command line arguments."""
A
Alessio Sergi 已提交
59
        _version = "Glances v" + version + " with psutil v" + psutil_version
60 61 62 63
        parser = argparse.ArgumentParser(
            prog=appname, conflict_handler='resolve')
        parser.add_argument(
            '-V', '--version', action='version', version=_version)
N
Nicolas Hennion 已提交
64 65
        parser.add_argument('-d', '--debug', action='store_true', default=False,
                            dest='debug', help=_('Enable debug mode'))
A
Alessio Sergi 已提交
66 67
        parser.add_argument('-C', '--config', dest='conf_file',
                            help=_('path to the configuration file'))
N
Nicolargo 已提交
68
        # Enable or disable option on startup
69 70
        parser.add_argument('--disable-network', action='store_true', default=False,
                            dest='disable_network', help=_('disable network module'))
A
Alessio Sergi 已提交
71 72 73 74 75 76
        parser.add_argument('--disable-diskio', action='store_true', default=False,
                            dest='disable_diskio', help=_('disable disk I/O module'))
        parser.add_argument('--disable-fs', action='store_true', default=False,
                            dest='disable_fs', help=_('disable filesystem module'))
        parser.add_argument('--disable-sensors', action='store_true', default=False,
                            dest='disable_sensors', help=_('disable sensors module'))
77 78
        parser.add_argument('--disable-left-sidebar', action='store_true', default=False,
                            dest='disable_left_sidebar', help=_('disable network, disk io, FS and sensors modules'))
79
        parser.add_argument('--disable-process', action='store_true', default=False,
A
Alessio Sergi 已提交
80 81 82
                            dest='disable_process', help=_('disable process module'))
        parser.add_argument('--disable-log', action='store_true', default=False,
                            dest='disable_log', help=_('disable log module'))
83 84
        parser.add_argument('--disable-bold', action='store_false', default=True,
                            dest='disable_bold', help=_('disable bold mode in the terminal'))
N
Nicolargo 已提交
85
        parser.add_argument('--enable-process-extended', action='store_true', default=False,
86
                            dest='enable_process_extended', help=_('enable extended stats on top process'))
87 88 89 90
        parser.add_argument('--enable-history', action='store_true', default=False,
                            dest='enable_history', help=_('enable the history mode'))
        parser.add_argument('--path-history', default=tempfile.gettempdir(),
                            dest='path_history', help=_('Set the export path for graph history'))
N
Nicolargo 已提交
91 92
        # CSV output feature
        parser.add_argument('--output-csv', default=None,
A
Alessio Sergi 已提交
93
                            dest='output_csv', help=_('export stats to a CSV file'))
N
Nicolargo 已提交
94 95 96 97 98
        # Client/Server option
        parser.add_argument('-c', '--client', dest='client',
                            help=_('connect to a Glances server by IPv4/IPv6 address or hostname'))
        parser.add_argument('-s', '--server', action='store_true', default=False,
                            dest='server', help=_('run Glances in server mode'))
99 100
        parser.add_argument('--browser', action='store_true', default=False,
                            dest='browser', help=_('start the client browser (list of servers)'))
101
        parser.add_argument('--disable-autodiscover', action='store_true', default=False,
102
                            dest='disable_autodiscover', help=_('disable autodiscover feature'))
103
        parser.add_argument('-p', '--port', default=None, type=int, dest='port',
A
Alessio Sergi 已提交
104
                            help=_('define the client/server TCP port [default: {0}]').format(self.server_port))
N
Nicolargo 已提交
105 106
        parser.add_argument('-B', '--bind', default='0.0.0.0', dest='bind_address',
                            help=_('bind server to the given IPv4/IPv6 address or hostname'))
N
Nicolargo 已提交
107
        parser.add_argument('--password-badidea', dest='password_arg',
A
Alessio Sergi 已提交
108
                            help=_('define password from the command line'))
A
Alessio Sergi 已提交
109
        parser.add_argument('--password', action='store_true', default=False, dest='password_prompt',
N
Nicolargo 已提交
110
                            help=_('define a client/server password from the prompt or file'))
111 112
        parser.add_argument('--snmp-community', default='public', dest='snmp_community',
                            help=_('SNMP community'))
A
Alessio Sergi 已提交
113
        parser.add_argument('--snmp-port', default=161, type=int,
114
                            dest='snmp_port', help=_('SNMP port'))
N
Nicolargo 已提交
115 116 117 118 119 120
        parser.add_argument('--snmp-version', default='2c', dest='snmp_version',
                            help=_('SNMP version (1, 2c or 3)'))
        parser.add_argument('--snmp-user', default='private', dest='snmp_user',
                            help=_('SNMP username (only for SNMPv3)'))
        parser.add_argument('--snmp-auth', default='password', dest='snmp_auth',
                            help=_('SNMP authentication key (only for SNMPv3)'))
121 122
        parser.add_argument('--snmp-force', action='store_true', default=False,
                            dest='snmp_force', help=_('force SNMP mode'))
123
        parser.add_argument('-t', '--time', default=self.refresh_time, type=float,
A
Alessio Sergi 已提交
124
                            dest='time', help=_('set refresh time in seconds [default: {0} sec]').format(self.refresh_time))
A
Alessio Sergi 已提交
125 126
        parser.add_argument('-w', '--webserver', action='store_true', default=False,
                            dest='webserver', help=_('run Glances in web server mode'))
127
        # Display options
N
Nicolargo 已提交
128
        parser.add_argument('-f', '--process-filter', default=None, type=str,
N
Nicolargo 已提交
129
                            dest='process_filter', help=_('set the process filter pattern (regular expression)'))
130 131
        parser.add_argument('--process-short-name', action='store_true', default=False,
                            dest='process_short_name', help=_('force short name for processes name'))
132 133 134
        if not is_windows:
            parser.add_argument('--hide-kernel-threads', action='store_true', default=False,
                                dest='no_kernel_threads', help=_('hide kernel threads in process list'))
135 136
        parser.add_argument('--tree', action='store_true', default=False,
                            dest='process_tree', help=_('display processes as a tree'))
N
Nicolargo 已提交
137 138
        parser.add_argument('-b', '--byte', action='store_true', default=False,
                            dest='byte', help=_('display network rate in byte per second'))
A
Alessio Sergi 已提交
139 140
        parser.add_argument('-1', '--percpu', action='store_true', default=False,
                            dest='percpu', help=_('start Glances in per CPU mode'))
141 142
        parser.add_argument('--fs-free-space', action='store_false', default=False,
                            dest='fs_free_space', help=_('display FS free space instead of used'))
N
Nicolargo 已提交
143 144
        parser.add_argument('--theme-white', action='store_true', default=False,
                            dest='theme_white', help=_('optimize display for white background'))
A
Alessio Sergi 已提交
145 146 147 148 149 150 151

        return parser

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

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

N
Nicolas Hennion 已提交
155 156 157 158 159
        # Debug mode
        if args.debug:
            from logging import DEBUG
            logger.setLevel(DEBUG)

160
        # Client/server Port
161 162 163 164
        if args.port is None:
            if args.webserver:
                args.port = self.web_server_port
            else:
165
                args.port = self.server_port
166

167 168 169 170
        # Autodiscover
        if args.disable_autodiscover:
            logger.info("Auto discover mode is disabled")

171
        # In web server mode, defaul refresh time: 5 sec
A
Alessio Sergi 已提交
172
        if args.webserver:
N
Nicolargo 已提交
173
            args.time = 5
N
Nicolas Hennion 已提交
174 175 176

        # Server or client login/password
        args.username = self.username
A
Alessio Sergi 已提交
177
        if args.password_arg is not None:
178
            from hashlib import sha256
N
Nicolargo 已提交
179
            # Password is given as an argument
180 181 182
            # Hash with SHA256
            # Only the SHA will be transmit on the network
            args.password = sha256(args.password_arg).hexdigest()
A
Alessio Sergi 已提交
183
        elif args.password_prompt:
N
Nicolargo 已提交
184
            # Interactive or file password
A
Alessio Sergi 已提交
185
            if args.server:
N
Nicolas Hennion 已提交
186
                args.password = self.__get_password(
187 188
                    description=_(
                        "Define the password for the Glances server"),
A
Alessio Sergi 已提交
189 190
                    confirm=True)
            elif args.client:
N
Nicolas Hennion 已提交
191
                args.password = self.__get_password(
A
Alessio Sergi 已提交
192
                    description=_("Enter the Glances server password"),
N
Nicolargo 已提交
193
                    clear=True)
N
Nicolas Hennion 已提交
194 195 196 197
        else:
            # Default is no password
            args.password = self.password

A
Alessio Sergi 已提交
198 199 200 201 202 203 204
        # 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

205 206 207 208 209
        # Control parameter and exit if it is not OK
        self.args = args

        # Filter is only available in standalone mode
        if args.process_filter is not None and not self.is_standalone():
210 211
            logger.critical(
                _("Process filter is only available in standalone mode"))
212 213
            sys.exit(2)

214 215 216
        # 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):
217 218
                logger.critical(
                    _("History output path (%s) do not exist or is not writable") % args.path_history)
219
                sys.exit(2)
220 221
            logger.debug(_("History output path is set to %s") %
                         args.path_history)
222

N
Nicolas Hennion 已提交
223
        return args
N
Nicolas Hennion 已提交
224

N
Nicolargo 已提交
225
    def __hash_password(self, plain_password):
A
PEP 257  
Alessio Sergi 已提交
226
        """Hash a plain password and return the hashed one."""
A
Alessio Sergi 已提交
227
        from glances.core.glances_password import GlancesPassword
N
Nicolas Hennion 已提交
228

A
Alessio Sergi 已提交
229
        password = GlancesPassword()
N
Nicolas Hennion 已提交
230

N
Nicolargo 已提交
231
        return password.hash_password(plain_password)
N
Nicolas Hennion 已提交
232

N
Nicolargo 已提交
233
    def __get_password(self, description='', confirm=False, clear=False):
A
PEP 257  
Alessio Sergi 已提交
234 235 236 237
        """Read a password from the command line.

        - if confirm = True, with confirmation
        - if clear = True, plain (clear password)
N
Nicolargo 已提交
238
        """
A
Alessio Sergi 已提交
239
        from glances.core.glances_password import GlancesPassword
N
Nicolargo 已提交
240

A
Alessio Sergi 已提交
241
        password = GlancesPassword()
N
Nicolargo 已提交
242 243

        return password.get_password(description, confirm, clear)
N
Nicolas Hennion 已提交
244

N
Nicolas Hennion 已提交
245
    def is_standalone(self):
A
PEP 257  
Alessio Sergi 已提交
246
        """Return True if Glances is running in standalone mode."""
247
        return not self.args.client and not self.args.browser and not self.args.server and not self.args.webserver
N
Nicolas Hennion 已提交
248 249

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

253 254 255
    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 已提交
256 257

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

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

265
    def get_config(self):
A
PEP 257  
Alessio Sergi 已提交
266
        """Return configuration file object."""
267
        return self.config
N
Nicolas Hennion 已提交
268 269

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