Test Failed
Push — develop ( 66c9ff...e21229 )
by Nicolas
05:06
created

glances/outputs/glances_bottle.py (96 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
"""Web interface class."""
21
22
import json
0 ignored issues
show
import missing from __future__ import absolute_import
Loading history...
23
import os
0 ignored issues
show
import missing from __future__ import absolute_import
Loading history...
24
import sys
0 ignored issues
show
import missing from __future__ import absolute_import
Loading history...
25
import tempfile
0 ignored issues
show
import missing from __future__ import absolute_import
Loading history...
26
from io import open
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in open.

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

Loading history...
import missing from __future__ import absolute_import
Loading history...
27
import webbrowser
0 ignored issues
show
import missing from __future__ import absolute_import
Loading history...
28
import zlib
0 ignored issues
show
import missing from __future__ import absolute_import
Loading history...
29
30
from glances.compat import b
0 ignored issues
show
import missing from __future__ import absolute_import
Loading history...
31
from glances.timer import Timer
0 ignored issues
show
import missing from __future__ import absolute_import
Loading history...
32
from glances.logger import logger
0 ignored issues
show
import missing from __future__ import absolute_import
Loading history...
33
34
try:
35
    from bottle import Bottle, static_file, abort, response, request, auth_basic, template, TEMPLATE_PATH
0 ignored issues
show
This line is too long as per the coding-style (105/80).

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

Loading history...
import missing from __future__ import absolute_import
Loading history...
36
except ImportError:
37
    logger.critical('Bottle module not found. Glances cannot start in web server mode.')
0 ignored issues
show
This line is too long as per the coding-style (88/80).

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

Loading history...
38
    sys.exit(2)
39
40
41
def compress(func):
42
    """Compress result with deflate algorithm if the client ask for it."""
43
    def wrapper(*args, **kwargs):
44
        """Wrapper that take one function and return the compressed result."""
45
        ret = func(*args, **kwargs)
46
        logger.debug('Receive {} {} request with header: {}'.format(
0 ignored issues
show
Use formatting in logging functions and pass the parameters as arguments
Loading history...
47
            request.method,
48
            request.url,
49
            ['{}: {}'.format(h, request.headers.get(h)) for h in request.headers.keys()]
0 ignored issues
show
This line is too long as per the coding-style (88/80).

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

Loading history...
50
        ))
51
        if 'deflate' in request.headers.get('Accept-Encoding', ''):
52
            response.headers['Content-Encoding'] = 'deflate'
53
            ret = deflate_compress(ret)
54
        else:
55
            response.headers['Content-Encoding'] = 'identity'
56
        return ret
57
58
    def deflate_compress(data, compress_level=6):
59
        """Compress given data using the DEFLATE algorithm"""
60
        # Init compression
61
        zobj = zlib.compressobj(compress_level,
62
                                zlib.DEFLATED,
63
                                zlib.MAX_WBITS,
64
                                zlib.DEF_MEM_LEVEL,
65
                                zlib.Z_DEFAULT_STRATEGY)
66
67
        # Return compressed object
68
        return zobj.compress(b(data)) + zobj.flush()
69
70
    return wrapper
71
72
73
class GlancesBottle(object):
0 ignored issues
show
Too many instance attributes (8/7)
Loading history...
74
    """This class manages the Bottle Web server."""
75
76
    API_VERSION = '3'
77
78
    def __init__(self, config=None, args=None):
79
        # Init config
80
        self.config = config
81
82
        # Init args
83
        self.args = args
84
85
        # Init stats
86
        # Will be updated within Bottle route
87
        self.stats = None
88
89
        # cached_time is the minimum time interval between stats updates
90
        # i.e. HTTP/RESTful calls will not retrieve updated info until the time
91
        # since last update is passed (will retrieve old cached info instead)
92
        self.timer = Timer(0)
93
94
        # Load configuration file
95
        self.load_config(config)
96
97
        # Set the bind URL
98
        self.bind_url = 'http://{}:{}/'.format(self.args.bind_address,
99
                                               self.args.port)
100
101
        # Init Bottle
102
        self._app = Bottle()
103
        # Enable CORS (issue #479)
104
        self._app.install(EnableCors())
105
        # Password
106
        if args.password != '':
107
            self._app.install(auth_basic(self.check_auth))
108
        # Define routes
109
        self._route()
110
111
        # Path where the statics files are stored
112
        self.STATIC_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'static/public')
0 ignored issues
show
This line is too long as per the coding-style (101/80).

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

Loading history...
Coding Style Naming introduced by
The name STATIC_PATH does not conform to the attribute naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
113
114
        # Paths for templates
115
        TEMPLATE_PATH.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)), 'static/templates'))
0 ignored issues
show
This line is too long as per the coding-style (110/80).

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

Loading history...
116
117
    def load_config(self, config):
0 ignored issues
show
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
118
        """Load the outputs section of the configuration file."""
119
        # Limit the number of processes to display in the WebUI
120
        if config is not None and config.has_section('outputs'):
121
            logger.debug('Read number of processes to display in the WebUI')
122
            n = config.get_value('outputs', 'max_processes_display', default=None)
0 ignored issues
show
This line is too long as per the coding-style (82/80).

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

Loading history...
Coding Style Naming introduced by
The name n does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
123
            logger.debug('Number of processes to display in the WebUI: {}'.format(n))
0 ignored issues
show
This line is too long as per the coding-style (85/80).

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

Loading history...
Use formatting in logging functions and pass the parameters as arguments
Loading history...
124
125
    def __update__(self):
126
        # Never update more than 1 time per cached_time
127
        if self.timer.finished():
128
            self.stats.update()
129
            self.timer = Timer(self.args.cached_time)
130
131
    def app(self):
0 ignored issues
show
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
132
        return self._app()
133
134
    def check_auth(self, username, password):
135
        """Check if a username/password combination is valid."""
136
        if username == self.args.username:
0 ignored issues
show
Unnecessary "else" after "return"
Loading history...
137
            from glances.password import GlancesPassword
0 ignored issues
show
import missing from __future__ import absolute_import
Loading history...
138
            pwd = GlancesPassword()
139
            return pwd.check_password(self.args.password, pwd.sha256_hash(password))
0 ignored issues
show
This line is too long as per the coding-style (84/80).

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

Loading history...
140
        else:
141
            return False
142
143
    def _route(self):
144
        """Define route."""
145
        # REST API
146
        self._app.route('/api/%s/config' % self.API_VERSION, method="GET",
147
                        callback=self._api_config)
148
        self._app.route('/api/%s/config/<item>' % self.API_VERSION, method="GET",
0 ignored issues
show
This line is too long as per the coding-style (81/80).

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

Loading history...
149
                        callback=self._api_config_item)
150
        self._app.route('/api/%s/args' % self.API_VERSION, method="GET",
151
                        callback=self._api_args)
152
        self._app.route('/api/%s/args/<item>' % self.API_VERSION, method="GET",
153
                        callback=self._api_args_item)
154
        self._app.route('/api/%s/help' % self.API_VERSION, method="GET",
155
                        callback=self._api_help)
156
        self._app.route('/api/%s/pluginslist' % self.API_VERSION, method="GET",
157
                        callback=self._api_plugins)
158
        self._app.route('/api/%s/all' % self.API_VERSION, method="GET",
159
                        callback=self._api_all)
160
        self._app.route('/api/%s/all/limits' % self.API_VERSION, method="GET",
161
                        callback=self._api_all_limits)
162
        self._app.route('/api/%s/all/views' % self.API_VERSION, method="GET",
163
                        callback=self._api_all_views)
164
        self._app.route('/api/%s/<plugin>' % self.API_VERSION, method="GET",
165
                        callback=self._api)
166
        self._app.route('/api/%s/<plugin>/history' % self.API_VERSION, method="GET",
0 ignored issues
show
This line is too long as per the coding-style (84/80).

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

Loading history...
167
                        callback=self._api_history)
168
        self._app.route('/api/%s/<plugin>/history/<nb:int>' % self.API_VERSION, method="GET",
0 ignored issues
show
This line is too long as per the coding-style (93/80).

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

Loading history...
169
                        callback=self._api_history)
170
        self._app.route('/api/%s/<plugin>/limits' % self.API_VERSION, method="GET",
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...
171
                        callback=self._api_limits)
172
        self._app.route('/api/%s/<plugin>/views' % self.API_VERSION, method="GET",
0 ignored issues
show
This line is too long as per the coding-style (82/80).

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

Loading history...
173
                        callback=self._api_views)
174
        self._app.route('/api/%s/<plugin>/<item>' % self.API_VERSION, method="GET",
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...
175
                        callback=self._api_item)
176
        self._app.route('/api/%s/<plugin>/<item>/history' % self.API_VERSION, method="GET",
0 ignored issues
show
This line is too long as per the coding-style (91/80).

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

Loading history...
177
                        callback=self._api_item_history)
178
        self._app.route('/api/%s/<plugin>/<item>/history/<nb:int>' % self.API_VERSION, method="GET",
0 ignored issues
show
This line is too long as per the coding-style (100/80).

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

Loading history...
179
                        callback=self._api_item_history)
180
        self._app.route('/api/%s/<plugin>/<item>/<value>' % self.API_VERSION, method="GET",
0 ignored issues
show
This line is too long as per the coding-style (91/80).

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

Loading history...
181
                        callback=self._api_value)
182
        bindmsg = 'Glances RESTful API Server started on {}api/{}/'.format(self.bind_url,
0 ignored issues
show
This line is too long as per the coding-style (89/80).

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

Loading history...
183
                                                                           self.API_VERSION)
0 ignored issues
show
This line is too long as per the coding-style (92/80).

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

Loading history...
184
        logger.info(bindmsg)
185
186
        # WEB UI
187
        if not self.args.disable_webui:
188
            self._app.route('/', method="GET", callback=self._index)
189
            self._app.route('/<refresh_time:int>', method=["GET"], callback=self._index)
0 ignored issues
show
This line is too long as per the coding-style (88/80).

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

Loading history...
190
            self._app.route('/<filepath:path>', method="GET", callback=self._resource)
0 ignored issues
show
This line is too long as per the coding-style (86/80).

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

Loading history...
191
            bindmsg = 'Glances Web User Interface started on {}'.format(self.bind_url)
0 ignored issues
show
This line is too long as per the coding-style (86/80).

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

Loading history...
192
            logger.info(bindmsg)
193
        else:
194
            logger.info('The WebUI is disable (--disable-webui)')
195
196
        print(bindmsg)
0 ignored issues
show
Unused Code Coding Style introduced by
Unnecessary parens after u'print' keyword
Loading history...
print statement used
Loading history...
197
198
    def start(self, stats):
199
        """Start the bottle."""
200
        # Init stats
201
        self.stats = stats
202
203
        # Init plugin list
204
        self.plugins_list = self.stats.getPluginsList()
0 ignored issues
show
The attribute plugins_list was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
205
206
        # Bind the Bottle TCP address/port
207
        if self.args.open_web_browser:
208
            # Implementation of the issue #946
209
            # Try to open the Glances Web UI in the default Web browser if:
210
            # 1) --open-web-browser option is used
211
            # 2) Glances standalone mode is running on Windows OS
212
            webbrowser.open(self.bind_url,
213
                            new=2,
214
                            autoraise=1)
215
216
        self._app.run(host=self.args.bind_address,
217
                      port=self.args.port,
218
                      quiet=not self.args.debug)
219
220
    def end(self):
221
        """End the bottle."""
222
        pass
223
224
    def _index(self, refresh_time=None):
225
        """Bottle callback for index.html (/) file."""
226
227
        if refresh_time is None or refresh_time < 1:
228
            refresh_time = self.args.time
229
230
        # Update the stat
231
        self.__update__()
232
233
        # Display
234
        return template("index.html", refresh_time=refresh_time)
235
236
    def _resource(self, filepath):
237
        """Bottle callback for resources files."""
238
        # Return the static file
239
        return static_file(filepath, root=self.STATIC_PATH)
240
241
    @compress
242
    def _api_help(self):
243
        """Glances API RESTful implementation.
244
245
        Return the help data or 404 error.
246
        """
247
        response.content_type = 'application/json; charset=utf-8'
248
249
        # Update the stat
250
        view_data = self.stats.get_plugin("help").get_view_data()
251
        try:
252
            plist = json.dumps(view_data, sort_keys=True)
253
        except Exception as e:
0 ignored issues
show
Catching very general exceptions such as Exception is usually not recommended.

Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.

So, unless you specifically plan to handle any error, consider adding a more specific exception.

Loading history...
Coding Style Naming introduced by
The name e does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
254
            abort(404, "Cannot get help view data (%s)" % str(e))
255
        return plist
256
257
    @compress
258
    def _api_plugins(self):
259
        """Glances API RESTFul implementation.
260
261
        @api {get} /api/%s/pluginslist Get plugins list
262
        @apiVersion 2.0
263
        @apiName pluginslist
264
        @apiGroup plugin
265
266
        @apiSuccess {String[]} Plugins list.
267
268
        @apiSuccessExample Success-Response:
269
            HTTP/1.1 200 OK
270
            [
271
               "load",
272
               "help",
273
               "ip",
274
               "memswap",
275
               "processlist",
276
               ...
277
            ]
278
279
         @apiError Cannot get plugin list.
280
281
         @apiErrorExample Error-Response:
282
            HTTP/1.1 404 Not Found
283
        """
284
        response.content_type = 'application/json; charset=utf-8'
285
286
        # Update the stat
287
        self.__update__()
288
289
        try:
290
            plist = json.dumps(self.plugins_list)
291
        except Exception as e:
0 ignored issues
show
Catching very general exceptions such as Exception is usually not recommended.

Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.

So, unless you specifically plan to handle any error, consider adding a more specific exception.

Loading history...
Coding Style Naming introduced by
The name e does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
292
            abort(404, "Cannot get plugin list (%s)" % str(e))
293
        return plist
294
295
    @compress
296
    def _api_all(self):
297
        """Glances API RESTful implementation.
298
299
        Return the JSON representation of all the plugins
300
        HTTP/200 if OK
301
        HTTP/400 if plugin is not found
302
        HTTP/404 if others error
303
        """
304
        response.content_type = 'application/json; charset=utf-8'
305
306
        if self.args.debug:
307
            fname = os.path.join(tempfile.gettempdir(), 'glances-debug.json')
308
            try:
309
                with open(fname) as f:
0 ignored issues
show
Coding Style Naming introduced by
The name f does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
310
                    return f.read()
311
            except IOError:
312
                logger.debug("Debug file (%s) not found" % fname)
0 ignored issues
show
Coding Style Best Practice introduced by
Specify string format arguments as logging function parameters
Loading history...
313
314
        # Update the stat
315
        self.__update__()
316
317
        try:
318
            # Get the JSON value of the stat ID
319
            statval = json.dumps(self.stats.getAllAsDict())
320
        except Exception as e:
0 ignored issues
show
Catching very general exceptions such as Exception is usually not recommended.

Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.

So, unless you specifically plan to handle any error, consider adding a more specific exception.

Loading history...
Coding Style Naming introduced by
The name e does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
321
            abort(404, "Cannot get stats (%s)" % str(e))
322
323
        return statval
324
325
    @compress
326
    def _api_all_limits(self):
327
        """Glances API RESTful implementation.
328
329
        Return the JSON representation of all the plugins limits
330
        HTTP/200 if OK
331
        HTTP/400 if plugin is not found
332
        HTTP/404 if others error
333
        """
334
        response.content_type = 'application/json; charset=utf-8'
335
336
        try:
337
            # Get the JSON value of the stat limits
338
            limits = json.dumps(self.stats.getAllLimitsAsDict())
339
        except Exception as e:
0 ignored issues
show
Catching very general exceptions such as Exception is usually not recommended.

Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.

So, unless you specifically plan to handle any error, consider adding a more specific exception.

Loading history...
Coding Style Naming introduced by
The name e does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
340
            abort(404, "Cannot get limits (%s)" % (str(e)))
341
        return limits
342
343
    @compress
344
    def _api_all_views(self):
345
        """Glances API RESTful implementation.
346
347
        Return the JSON representation of all the plugins views
348
        HTTP/200 if OK
349
        HTTP/400 if plugin is not found
350
        HTTP/404 if others error
351
        """
352
        response.content_type = 'application/json; charset=utf-8'
353
354
        try:
355
            # Get the JSON value of the stat view
356
            limits = json.dumps(self.stats.getAllViewsAsDict())
357
        except Exception as e:
0 ignored issues
show
Catching very general exceptions such as Exception is usually not recommended.

Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.

So, unless you specifically plan to handle any error, consider adding a more specific exception.

Loading history...
Coding Style Naming introduced by
The name e does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
358
            abort(404, "Cannot get views (%s)" % (str(e)))
359
        return limits
360
361
    @compress
362
    def _api(self, plugin):
363
        """Glances API RESTful implementation.
364
365
        Return the JSON representation of a given plugin
366
        HTTP/200 if OK
367
        HTTP/400 if plugin is not found
368
        HTTP/404 if others error
369
        """
370
        response.content_type = 'application/json; charset=utf-8'
371
372
        if plugin not in self.plugins_list:
373
            abort(400, "Unknown plugin %s (available plugins: %s)" % (plugin, self.plugins_list))
0 ignored issues
show
This line is too long as per the coding-style (97/80).

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

Loading history...
374
375
        # Update the stat
376
        self.__update__()
377
378
        try:
379
            # Get the JSON value of the stat ID
380
            statval = self.stats.get_plugin(plugin).get_stats()
381
        except Exception as e:
0 ignored issues
show
Catching very general exceptions such as Exception is usually not recommended.

Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.

So, unless you specifically plan to handle any error, consider adding a more specific exception.

Loading history...
Coding Style Naming introduced by
The name e does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
382
            abort(404, "Cannot get plugin %s (%s)" % (plugin, str(e)))
383
        return statval
384
385
    @compress
386
    def _api_history(self, plugin, nb=0):
0 ignored issues
show
Coding Style Naming introduced by
The name nb does not conform to the argument naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
387
        """Glances API RESTful implementation.
388
389
        Return the JSON representation of a given plugin history
390
        Limit to the last nb items (all if nb=0)
391
        HTTP/200 if OK
392
        HTTP/400 if plugin is not found
393
        HTTP/404 if others error
394
        """
395
        response.content_type = 'application/json; charset=utf-8'
396
397
        if plugin not in self.plugins_list:
398
            abort(400, "Unknown plugin %s (available plugins: %s)" % (plugin, self.plugins_list))
0 ignored issues
show
This line is too long as per the coding-style (97/80).

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

Loading history...
399
400
        # Update the stat
401
        self.__update__()
402
403
        try:
404
            # Get the JSON value of the stat ID
405
            statval = self.stats.get_plugin(plugin).get_stats_history(nb=int(nb))
0 ignored issues
show
This line is too long as per the coding-style (81/80).

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

Loading history...
406
        except Exception as e:
0 ignored issues
show
Catching very general exceptions such as Exception is usually not recommended.

Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.

So, unless you specifically plan to handle any error, consider adding a more specific exception.

Loading history...
Coding Style Naming introduced by
The name e does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
407
            abort(404, "Cannot get plugin history %s (%s)" % (plugin, str(e)))
408
        return statval
409
410
    @compress
411
    def _api_limits(self, plugin):
412
        """Glances API RESTful implementation.
413
414
        Return the JSON limits of a given plugin
415
        HTTP/200 if OK
416
        HTTP/400 if plugin is not found
417
        HTTP/404 if others error
418
        """
419
        response.content_type = 'application/json; charset=utf-8'
420
421
        if plugin not in self.plugins_list:
422
            abort(400, "Unknown plugin %s (available plugins: %s)" % (plugin, self.plugins_list))
0 ignored issues
show
This line is too long as per the coding-style (97/80).

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

Loading history...
423
424
        # Update the stat
425
        # self.__update__()
426
427
        try:
428
            # Get the JSON value of the stat limits
429
            ret = self.stats.get_plugin(plugin).limits
430
        except Exception as e:
0 ignored issues
show
Catching very general exceptions such as Exception is usually not recommended.

Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.

So, unless you specifically plan to handle any error, consider adding a more specific exception.

Loading history...
Coding Style Naming introduced by
The name e does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
431
            abort(404, "Cannot get limits for plugin %s (%s)" % (plugin, str(e)))
0 ignored issues
show
This line is too long as per the coding-style (81/80).

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

Loading history...
432
        return ret
433
434
    @compress
435
    def _api_views(self, plugin):
436
        """Glances API RESTful implementation.
437
438
        Return the JSON views of a given plugin
439
        HTTP/200 if OK
440
        HTTP/400 if plugin is not found
441
        HTTP/404 if others error
442
        """
443
        response.content_type = 'application/json; charset=utf-8'
444
445
        if plugin not in self.plugins_list:
446
            abort(400, "Unknown plugin %s (available plugins: %s)" % (plugin, self.plugins_list))
0 ignored issues
show
This line is too long as per the coding-style (97/80).

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

Loading history...
447
448
        # Update the stat
449
        # self.__update__()
450
451
        try:
452
            # Get the JSON value of the stat views
453
            ret = self.stats.get_plugin(plugin).get_views()
454
        except Exception as e:
0 ignored issues
show
Catching very general exceptions such as Exception is usually not recommended.

Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.

So, unless you specifically plan to handle any error, consider adding a more specific exception.

Loading history...
Coding Style Naming introduced by
The name e does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
455
            abort(404, "Cannot get views for plugin %s (%s)" % (plugin, str(e)))
456
        return ret
457
458
    @compress
459
    def _api_itemvalue(self, plugin, item, value=None, history=False, nb=0):
0 ignored issues
show
Coding Style Naming introduced by
The name nb does not conform to the argument naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Too many arguments (6/5)
Loading history...
460
        """Father method for _api_item and _api_value."""
461
        response.content_type = 'application/json; charset=utf-8'
462
463
        if plugin not in self.plugins_list:
464
            abort(400, "Unknown plugin %s (available plugins: %s)" % (plugin, self.plugins_list))
0 ignored issues
show
This line is too long as per the coding-style (97/80).

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

Loading history...
465
466
        # Update the stat
467
        self.__update__()
468
469
        if value is None:
470
            if history:
471
                ret = self.stats.get_plugin(plugin).get_stats_history(item, nb=int(nb))
0 ignored issues
show
This line is too long as per the coding-style (87/80).

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

Loading history...
472
            else:
473
                ret = self.stats.get_plugin(plugin).get_stats_item(item)
474
475
            if ret is None:
476
                abort(404, "Cannot get item %s%s in plugin %s" % (item, 'history ' if history else '', plugin))
0 ignored issues
show
This line is too long as per the coding-style (111/80).

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

Loading history...
477
        else:
478
            if history:
479
                # Not available
480
                ret = None
481
            else:
482
                ret = self.stats.get_plugin(plugin).get_stats_value(item, value)
483
484
            if ret is None:
485
                abort(404, "Cannot get item %s(%s=%s) in plugin %s" % ('history ' if history else '', item, value, plugin))
0 ignored issues
show
This line is too long as per the coding-style (123/80).

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

Loading history...
486
487
        return ret
488
489
    @compress
490
    def _api_item(self, plugin, item):
491
        """Glances API RESTful implementation.
492
493
        Return the JSON representation of the couple plugin/item
494
        HTTP/200 if OK
495
        HTTP/400 if plugin is not found
496
        HTTP/404 if others error
497
498
        """
499
        return self._api_itemvalue(plugin, item)
500
501
    @compress
502
    def _api_item_history(self, plugin, item, nb=0):
0 ignored issues
show
Coding Style Naming introduced by
The name nb does not conform to the argument naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
503
        """Glances API RESTful implementation.
504
505
        Return the JSON representation of the couple plugin/history of item
506
        HTTP/200 if OK
507
        HTTP/400 if plugin is not found
508
        HTTP/404 if others error
509
510
        """
511
        return self._api_itemvalue(plugin, item, history=True, nb=int(nb))
512
513
    @compress
514
    def _api_value(self, plugin, item, value):
515
        """Glances API RESTful implementation.
516
517
        Return the process stats (dict) for the given item=value
518
        HTTP/200 if OK
519
        HTTP/400 if plugin is not found
520
        HTTP/404 if others error
521
        """
522
        return self._api_itemvalue(plugin, item, value)
523
524
    @compress
525
    def _api_config(self):
526
        """Glances API RESTful implementation.
527
528
        Return the JSON representation of the Glances configuration file
529
        HTTP/200 if OK
530
        HTTP/404 if others error
531
        """
532
        response.content_type = 'application/json; charset=utf-8'
533
534
        try:
535
            # Get the JSON value of the config' dict
536
            args_json = json.dumps(self.config.as_dict())
537
        except Exception as e:
0 ignored issues
show
Catching very general exceptions such as Exception is usually not recommended.

Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.

So, unless you specifically plan to handle any error, consider adding a more specific exception.

Loading history...
Coding Style Naming introduced by
The name e does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
538
            abort(404, "Cannot get config (%s)" % str(e))
539
        return args_json
540
541
    @compress
542
    def _api_config_item(self, item):
543
        """Glances API RESTful implementation.
544
545
        Return the JSON representation of the Glances configuration item
546
        HTTP/200 if OK
547
        HTTP/400 if item is not found
548
        HTTP/404 if others error
549
        """
550
        response.content_type = 'application/json; charset=utf-8'
551
552
        config_dict = self.config.as_dict()
553
        if item not in config_dict:
554
            abort(400, "Unknown configuration item %s" % item)
555
556
        try:
557
            # Get the JSON value of the config' dict
558
            args_json = json.dumps(config_dict[item])
559
        except Exception as e:
0 ignored issues
show
Catching very general exceptions such as Exception is usually not recommended.

Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.

So, unless you specifically plan to handle any error, consider adding a more specific exception.

Loading history...
Coding Style Naming introduced by
The name e does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
560
            abort(404, "Cannot get config item (%s)" % str(e))
561
        return args_json
562
563
    @compress
564
    def _api_args(self):
565
        """Glances API RESTful implementation.
566
567
        Return the JSON representation of the Glances command line arguments
568
        HTTP/200 if OK
569
        HTTP/404 if others error
570
        """
571
        response.content_type = 'application/json; charset=utf-8'
572
573
        try:
574
            # Get the JSON value of the args' dict
575
            # Use vars to convert namespace to dict
576
            # Source: https://docs.python.org/%s/library/functions.html#vars
577
            args_json = json.dumps(vars(self.args))
578
        except Exception as e:
0 ignored issues
show
Catching very general exceptions such as Exception is usually not recommended.

Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.

So, unless you specifically plan to handle any error, consider adding a more specific exception.

Loading history...
Coding Style Naming introduced by
The name e does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
579
            abort(404, "Cannot get args (%s)" % str(e))
580
        return args_json
581
582
    @compress
583
    def _api_args_item(self, item):
584
        """Glances API RESTful implementation.
585
586
        Return the JSON representation of the Glances command line arguments item
0 ignored issues
show
This line is too long as per the coding-style (81/80).

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

Loading history...
587
        HTTP/200 if OK
588
        HTTP/400 if item is not found
589
        HTTP/404 if others error
590
        """
591
        response.content_type = 'application/json; charset=utf-8'
592
593
        if item not in self.args:
594
            abort(400, "Unknown argument item %s" % item)
595
596
        try:
597
            # Get the JSON value of the args' dict
598
            # Use vars to convert namespace to dict
599
            # Source: https://docs.python.org/%s/library/functions.html#vars
600
            args_json = json.dumps(vars(self.args)[item])
601
        except Exception as e:
0 ignored issues
show
Catching very general exceptions such as Exception is usually not recommended.

Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.

So, unless you specifically plan to handle any error, consider adding a more specific exception.

Loading history...
Coding Style Naming introduced by
The name e does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
602
            abort(404, "Cannot get args item (%s)" % str(e))
603
        return args_json
604
605
606
class EnableCors(object):
0 ignored issues
show
This class should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
607
    name = 'enable_cors'
608
    api = 2
609
610
    def apply(self, fn, context):
0 ignored issues
show
Coding Style Naming introduced by
The name fn does not conform to the argument naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
The argument context seems to be unused.
Loading history...
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
611
        def _enable_cors(*args, **kwargs):
612
            # set CORS headers
613
            response.headers['Access-Control-Allow-Origin'] = '*'
614
            response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, OPTIONS'
0 ignored issues
show
This line is too long as per the coding-style (88/80).

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

Loading history...
615
            response.headers['Access-Control-Allow-Headers'] = 'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token'
0 ignored issues
show
This line is too long as per the coding-style (125/80).

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

Loading history...
616
617
            if request.method != 'OPTIONS':
618
                # actual request; reply with the actual response
619
                return fn(*args, **kwargs)
620
621
        return _enable_cors
622