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 |
||
23 | import os |
||
24 | import sys |
||
25 | import tempfile |
||
26 | from io import open |
||
27 | import webbrowser |
||
28 | import zlib |
||
29 | |||
30 | from glances.compat import b |
||
31 | from glances.timer import Timer |
||
32 | from glances.logger import logger |
||
33 | |||
34 | try: |
||
35 | from bottle import Bottle, static_file, abort, response, request, auth_basic, template, TEMPLATE_PATH |
||
36 | except ImportError: |
||
37 | logger.critical('Bottle module not found. Glances cannot start in web server mode.') |
||
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( |
||
47 | request.method, |
||
48 | request.url, |
||
49 | ['{}: {}'.format(h, request.headers.get(h)) for h in request.headers.keys()] |
||
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): |
||
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
|
|||
113 | |||
114 | # Paths for templates |
||
115 | TEMPLATE_PATH.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)), 'static/templates')) |
||
116 | |||
117 | def load_config(self, config): |
||
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) |
||
123 | logger.debug('Number of processes to display in the WebUI: {}'.format(n)) |
||
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): |
||
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: |
||
137 | from glances.password import GlancesPassword |
||
138 | pwd = GlancesPassword() |
||
139 | return pwd.check_password(self.args.password, pwd.sha256_hash(password)) |
||
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", |
||
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", |
||
167 | callback=self._api_history) |
||
168 | self._app.route('/api/%s/<plugin>/history/<nb:int>' % self.API_VERSION, method="GET", |
||
169 | callback=self._api_history) |
||
170 | self._app.route('/api/%s/<plugin>/limits' % self.API_VERSION, method="GET", |
||
171 | callback=self._api_limits) |
||
172 | self._app.route('/api/%s/<plugin>/views' % self.API_VERSION, method="GET", |
||
173 | callback=self._api_views) |
||
174 | self._app.route('/api/%s/<plugin>/<item>' % self.API_VERSION, method="GET", |
||
175 | callback=self._api_item) |
||
176 | self._app.route('/api/%s/<plugin>/<item>/history' % self.API_VERSION, method="GET", |
||
177 | callback=self._api_item_history) |
||
178 | self._app.route('/api/%s/<plugin>/<item>/history/<nb:int>' % self.API_VERSION, method="GET", |
||
179 | callback=self._api_item_history) |
||
180 | self._app.route('/api/%s/<plugin>/<item>/<value>' % self.API_VERSION, method="GET", |
||
181 | callback=self._api_value) |
||
182 | bindmsg = 'Glances RESTful API Server started on {}api/{}/'.format(self.bind_url, |
||
183 | self.API_VERSION) |
||
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) |
||
190 | self._app.route('/<filepath:path>', method="GET", callback=self._resource) |
||
191 | bindmsg = 'Glances Web User Interface started on {}'.format(self.bind_url) |
||
192 | logger.info(bindmsg) |
||
193 | else: |
||
194 | logger.info('The WebUI is disable (--disable-webui)') |
||
195 | |||
196 | print(bindmsg) |
||
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() |
||
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: |
||
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: |
||
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: |
||
310 | return f.read() |
||
311 | except IOError: |
||
312 | logger.debug("Debug file (%s) not found" % fname) |
||
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
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: |
||
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: |
||
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)) |
||
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: |
||
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): |
||
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)) |
||
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)) |
||
406 | except Exception as e: |
||
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)) |
||
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: |
||
431 | abort(404, "Cannot get limits for plugin %s (%s)" % (plugin, str(e))) |
||
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)) |
||
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: |
||
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): |
||
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)) |
||
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)) |
||
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)) |
||
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)) |
||
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): |
||
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: |
||
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: |
||
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: |
||
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 |
||
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: |
||
602 | abort(404, "Cannot get args item (%s)" % str(e)) |
||
603 | return args_json |
||
604 | |||
605 | |||
606 | class EnableCors(object): |
||
607 | name = 'enable_cors' |
||
608 | api = 2 |
||
609 | |||
610 | def apply(self, fn, context): |
||
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' |
||
615 | response.headers['Access-Control-Allow-Headers'] = 'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token' |
||
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 |
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.