1
|
|
|
# -*- coding: utf-8 -*- |
2
|
|
|
# |
3
|
|
|
# This file is part of Glances. |
4
|
|
|
# |
5
|
|
|
# Copyright (C) 2017 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
|
|
|
|
29
|
|
|
from glances.timer import Timer |
30
|
|
|
from glances.logger import logger |
31
|
|
|
|
32
|
|
|
try: |
33
|
|
|
from bottle import Bottle, static_file, abort, response, request, auth_basic |
34
|
|
|
except ImportError: |
35
|
|
|
logger.critical('Bottle module not found. Glances cannot start in web server mode.') |
36
|
|
|
sys.exit(2) |
37
|
|
|
|
38
|
|
|
|
39
|
|
|
class GlancesBottle(object): |
40
|
|
|
|
41
|
|
|
"""This class manages the Bottle Web server.""" |
42
|
|
|
|
43
|
|
|
def __init__(self, config=None, args=None): |
44
|
|
|
# Init config |
45
|
|
|
self.config = config |
46
|
|
|
|
47
|
|
|
# Init args |
48
|
|
|
self.args = args |
49
|
|
|
|
50
|
|
|
# Init stats |
51
|
|
|
# Will be updated within Bottle route |
52
|
|
|
self.stats = None |
53
|
|
|
|
54
|
|
|
# cached_time is the minimum time interval between stats updates |
55
|
|
|
# i.e. HTTP/Restful calls will not retrieve updated info until the time |
56
|
|
|
# since last update is passed (will retrieve old cached info instead) |
57
|
|
|
self.timer = Timer(0) |
58
|
|
|
|
59
|
|
|
# Load configuration file |
60
|
|
|
self.load_config(config) |
61
|
|
|
|
62
|
|
|
# Init Bottle |
63
|
|
|
self._app = Bottle() |
64
|
|
|
# Enable CORS (issue #479) |
65
|
|
|
self._app.install(EnableCors()) |
66
|
|
|
# Password |
67
|
|
|
if args.password != '': |
68
|
|
|
self._app.install(auth_basic(self.check_auth)) |
69
|
|
|
# Define routes |
70
|
|
|
self._route() |
71
|
|
|
|
72
|
|
|
# Path where the statics files are stored |
73
|
|
|
self.STATIC_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'static/public') |
74
|
|
|
|
75
|
|
|
def load_config(self, config): |
76
|
|
|
"""Load the outputs section of the configuration file.""" |
77
|
|
|
# Limit the number of processes to display in the WebUI |
78
|
|
|
if config is not None and config.has_section('outputs'): |
79
|
|
|
logger.debug('Read number of processes to display in the WebUI') |
80
|
|
|
n = config.get_value('outputs', 'max_processes_display', default=None) |
81
|
|
|
logger.debug('Number of processes to display in the WebUI: {}'.format(n)) |
82
|
|
|
|
83
|
|
|
def __update__(self): |
84
|
|
|
# Never update more than 1 time per cached_time |
85
|
|
|
if self.timer.finished(): |
86
|
|
|
self.stats.update() |
87
|
|
|
self.timer = Timer(self.args.cached_time) |
88
|
|
|
|
89
|
|
|
def app(self): |
90
|
|
|
return self._app() |
91
|
|
|
|
92
|
|
|
def check_auth(self, username, password): |
93
|
|
|
"""Check if a username/password combination is valid.""" |
94
|
|
|
if username == self.args.username: |
95
|
|
|
from glances.password import GlancesPassword |
96
|
|
|
pwd = GlancesPassword() |
97
|
|
|
return pwd.check_password(self.args.password, pwd.sha256_hash(password)) |
98
|
|
|
else: |
99
|
|
|
return False |
100
|
|
|
|
101
|
|
|
def _route(self): |
102
|
|
|
"""Define route.""" |
103
|
|
|
self._app.route('/', method="GET", callback=self._index) |
104
|
|
|
self._app.route('/<refresh_time:int>', method=["GET"], callback=self._index) |
105
|
|
|
|
106
|
|
|
# REST API |
107
|
|
|
self._app.route('/api/2/config', method="GET", callback=self._api_config) |
108
|
|
|
self._app.route('/api/2/config/<item>', method="GET", callback=self._api_config_item) |
109
|
|
|
self._app.route('/api/2/args', method="GET", callback=self._api_args) |
110
|
|
|
self._app.route('/api/2/args/<item>', method="GET", callback=self._api_args_item) |
111
|
|
|
self._app.route('/api/2/help', method="GET", callback=self._api_help) |
112
|
|
|
self._app.route('/api/2/pluginslist', method="GET", callback=self._api_plugins) |
113
|
|
|
self._app.route('/api/2/all', method="GET", callback=self._api_all) |
114
|
|
|
self._app.route('/api/2/all/limits', method="GET", callback=self._api_all_limits) |
115
|
|
|
self._app.route('/api/2/all/views', method="GET", callback=self._api_all_views) |
116
|
|
|
self._app.route('/api/2/<plugin>', method="GET", callback=self._api) |
117
|
|
|
self._app.route('/api/2/<plugin>/history', method="GET", callback=self._api_history) |
118
|
|
|
self._app.route('/api/2/<plugin>/history/<nb:int>', method="GET", callback=self._api_history) |
119
|
|
|
self._app.route('/api/2/<plugin>/limits', method="GET", callback=self._api_limits) |
120
|
|
|
self._app.route('/api/2/<plugin>/views', method="GET", callback=self._api_views) |
121
|
|
|
self._app.route('/api/2/<plugin>/<item>', method="GET", callback=self._api_item) |
122
|
|
|
self._app.route('/api/2/<plugin>/<item>/history', method="GET", callback=self._api_item_history) |
123
|
|
|
self._app.route('/api/2/<plugin>/<item>/history/<nb:int>', method="GET", callback=self._api_item_history) |
124
|
|
|
self._app.route('/api/2/<plugin>/<item>/<value>', method="GET", callback=self._api_value) |
125
|
|
|
|
126
|
|
|
self._app.route('/<filepath:path>', method="GET", callback=self._resource) |
127
|
|
|
|
128
|
|
|
def start(self, stats): |
129
|
|
|
"""Start the bottle.""" |
130
|
|
|
# Init stats |
131
|
|
|
self.stats = stats |
132
|
|
|
|
133
|
|
|
# Init plugin list |
134
|
|
|
self.plugins_list = self.stats.getAllPlugins() |
135
|
|
|
|
136
|
|
|
# Bind the Bottle TCP address/port |
137
|
|
|
bindurl = 'http://{}:{}/'.format(self.args.bind_address, |
138
|
|
|
self.args.port) |
139
|
|
|
bindmsg = 'Glances web server started on {}'.format(bindurl) |
140
|
|
|
logger.info(bindmsg) |
141
|
|
|
print(bindmsg) |
142
|
|
|
if self.args.open_web_browser: |
143
|
|
|
# Implementation of the issue #946 |
144
|
|
|
# Try to open the Glances Web UI in the default Web browser if: |
145
|
|
|
# 1) --open-web-browser option is used |
146
|
|
|
# 2) Glances standalone mode is running on Windows OS |
147
|
|
|
webbrowser.open(bindurl, new=2, autoraise=1) |
148
|
|
|
self._app.run(host=self.args.bind_address, port=self.args.port, quiet=not self.args.debug) |
149
|
|
|
|
150
|
|
|
def end(self): |
151
|
|
|
"""End the bottle.""" |
152
|
|
|
pass |
153
|
|
|
|
154
|
|
|
def _index(self, refresh_time=None): |
155
|
|
|
"""Bottle callback for index.html (/) file.""" |
156
|
|
|
# Update the stat |
157
|
|
|
self.__update__() |
158
|
|
|
|
159
|
|
|
# Display |
160
|
|
|
return static_file("index.html", root=self.STATIC_PATH) |
161
|
|
|
|
162
|
|
|
def _resource(self, filepath): |
163
|
|
|
"""Bottle callback for resources files.""" |
164
|
|
|
# Return the static file |
165
|
|
|
return static_file(filepath, root=self.STATIC_PATH) |
166
|
|
|
|
167
|
|
|
def _api_help(self): |
168
|
|
|
"""Glances API RESTFul implementation. |
169
|
|
|
|
170
|
|
|
Return the help data or 404 error. |
171
|
|
|
""" |
172
|
|
|
response.content_type = 'application/json' |
173
|
|
|
|
174
|
|
|
# Update the stat |
175
|
|
|
view_data = self.stats.get_plugin("help").get_view_data() |
176
|
|
|
try: |
177
|
|
|
plist = json.dumps(view_data, sort_keys=True) |
178
|
|
|
except Exception as e: |
179
|
|
|
abort(404, "Cannot get help view data (%s)" % str(e)) |
180
|
|
|
return plist |
181
|
|
|
|
182
|
|
|
def _api_plugins(self): |
183
|
|
|
""" |
184
|
|
|
@api {get} /api/2/pluginslist Get plugins list |
185
|
|
|
@apiVersion 2.0 |
186
|
|
|
@apiName pluginslist |
187
|
|
|
@apiGroup plugin |
188
|
|
|
|
189
|
|
|
@apiSuccess {String[]} Plugins list. |
190
|
|
|
|
191
|
|
|
@apiSuccessExample Success-Response: |
192
|
|
|
HTTP/1.1 200 OK |
193
|
|
|
[ |
194
|
|
|
"load", |
195
|
|
|
"help", |
196
|
|
|
"ip", |
197
|
|
|
"memswap", |
198
|
|
|
"processlist", |
199
|
|
|
... |
200
|
|
|
] |
201
|
|
|
|
202
|
|
|
@apiError Cannot get plugin list. |
203
|
|
|
|
204
|
|
|
@apiErrorExample Error-Response: |
205
|
|
|
HTTP/1.1 404 Not Found |
206
|
|
|
""" |
207
|
|
|
response.content_type = 'application/json' |
208
|
|
|
|
209
|
|
|
# Update the stat |
210
|
|
|
self.__update__() |
211
|
|
|
|
212
|
|
|
try: |
213
|
|
|
plist = json.dumps(self.plugins_list) |
214
|
|
|
except Exception as e: |
215
|
|
|
abort(404, "Cannot get plugin list (%s)" % str(e)) |
216
|
|
|
return plist |
217
|
|
|
|
218
|
|
|
def _api_all(self): |
219
|
|
|
"""Glances API RESTFul implementation. |
220
|
|
|
|
221
|
|
|
Return the JSON representation of all the plugins |
222
|
|
|
HTTP/200 if OK |
223
|
|
|
HTTP/400 if plugin is not found |
224
|
|
|
HTTP/404 if others error |
225
|
|
|
""" |
226
|
|
|
response.content_type = 'application/json' |
227
|
|
|
|
228
|
|
|
if self.args.debug: |
229
|
|
|
fname = os.path.join(tempfile.gettempdir(), 'glances-debug.json') |
230
|
|
|
try: |
231
|
|
|
with open(fname) as f: |
232
|
|
|
return f.read() |
233
|
|
|
except IOError: |
234
|
|
|
logger.debug("Debug file (%s) not found" % fname) |
235
|
|
|
|
236
|
|
|
# Update the stat |
237
|
|
|
self.__update__() |
238
|
|
|
|
239
|
|
|
try: |
240
|
|
|
# Get the JSON value of the stat ID |
241
|
|
|
statval = json.dumps(self.stats.getAllAsDict()) |
242
|
|
|
except Exception as e: |
243
|
|
|
abort(404, "Cannot get stats (%s)" % str(e)) |
244
|
|
|
return statval |
245
|
|
|
|
246
|
|
|
def _api_all_limits(self): |
247
|
|
|
"""Glances API RESTFul implementation. |
248
|
|
|
|
249
|
|
|
Return the JSON representation of all the plugins limits |
250
|
|
|
HTTP/200 if OK |
251
|
|
|
HTTP/400 if plugin is not found |
252
|
|
|
HTTP/404 if others error |
253
|
|
|
""" |
254
|
|
|
response.content_type = 'application/json' |
255
|
|
|
|
256
|
|
|
try: |
257
|
|
|
# Get the JSON value of the stat limits |
258
|
|
|
limits = json.dumps(self.stats.getAllLimitsAsDict()) |
259
|
|
|
except Exception as e: |
260
|
|
|
abort(404, "Cannot get limits (%s)" % (str(e))) |
261
|
|
|
return limits |
262
|
|
|
|
263
|
|
|
def _api_all_views(self): |
264
|
|
|
"""Glances API RESTFul implementation. |
265
|
|
|
|
266
|
|
|
Return the JSON representation of all the plugins views |
267
|
|
|
HTTP/200 if OK |
268
|
|
|
HTTP/400 if plugin is not found |
269
|
|
|
HTTP/404 if others error |
270
|
|
|
""" |
271
|
|
|
response.content_type = 'application/json' |
272
|
|
|
|
273
|
|
|
try: |
274
|
|
|
# Get the JSON value of the stat view |
275
|
|
|
limits = json.dumps(self.stats.getAllViewsAsDict()) |
276
|
|
|
except Exception as e: |
277
|
|
|
abort(404, "Cannot get views (%s)" % (str(e))) |
278
|
|
|
return limits |
279
|
|
|
|
280
|
|
|
def _api(self, plugin): |
281
|
|
|
"""Glances API RESTFul implementation. |
282
|
|
|
|
283
|
|
|
Return the JSON representation of a given plugin |
284
|
|
|
HTTP/200 if OK |
285
|
|
|
HTTP/400 if plugin is not found |
286
|
|
|
HTTP/404 if others error |
287
|
|
|
""" |
288
|
|
|
response.content_type = 'application/json' |
289
|
|
|
|
290
|
|
|
if plugin not in self.plugins_list: |
291
|
|
|
abort(400, "Unknown plugin %s (available plugins: %s)" % (plugin, self.plugins_list)) |
292
|
|
|
|
293
|
|
|
# Update the stat |
294
|
|
|
self.__update__() |
295
|
|
|
|
296
|
|
|
try: |
297
|
|
|
# Get the JSON value of the stat ID |
298
|
|
|
statval = self.stats.get_plugin(plugin).get_stats() |
299
|
|
|
except Exception as e: |
300
|
|
|
abort(404, "Cannot get plugin %s (%s)" % (plugin, str(e))) |
301
|
|
|
return statval |
302
|
|
|
|
303
|
|
|
def _api_history(self, plugin, nb=0): |
304
|
|
|
"""Glances API RESTFul implementation. |
305
|
|
|
|
306
|
|
|
Return the JSON representation of a given plugin history |
307
|
|
|
Limit to the last nb items (all if nb=0) |
308
|
|
|
HTTP/200 if OK |
309
|
|
|
HTTP/400 if plugin is not found |
310
|
|
|
HTTP/404 if others error |
311
|
|
|
""" |
312
|
|
|
response.content_type = 'application/json' |
313
|
|
|
|
314
|
|
|
if plugin not in self.plugins_list: |
315
|
|
|
abort(400, "Unknown plugin %s (available plugins: %s)" % (plugin, self.plugins_list)) |
316
|
|
|
|
317
|
|
|
# Update the stat |
318
|
|
|
self.__update__() |
319
|
|
|
|
320
|
|
|
try: |
321
|
|
|
# Get the JSON value of the stat ID |
322
|
|
|
statval = self.stats.get_plugin(plugin).get_stats_history(nb=int(nb)) |
323
|
|
|
except Exception as e: |
324
|
|
|
abort(404, "Cannot get plugin history %s (%s)" % (plugin, str(e))) |
325
|
|
|
return statval |
326
|
|
|
|
327
|
|
|
def _api_limits(self, plugin): |
328
|
|
|
"""Glances API RESTFul implementation. |
329
|
|
|
|
330
|
|
|
Return the JSON limits of a given plugin |
331
|
|
|
HTTP/200 if OK |
332
|
|
|
HTTP/400 if plugin is not found |
333
|
|
|
HTTP/404 if others error |
334
|
|
|
""" |
335
|
|
|
response.content_type = 'application/json' |
336
|
|
|
|
337
|
|
|
if plugin not in self.plugins_list: |
338
|
|
|
abort(400, "Unknown plugin %s (available plugins: %s)" % (plugin, self.plugins_list)) |
339
|
|
|
|
340
|
|
|
# Update the stat |
341
|
|
|
# self.__update__() |
342
|
|
|
|
343
|
|
|
try: |
344
|
|
|
# Get the JSON value of the stat limits |
345
|
|
|
ret = self.stats.get_plugin(plugin).limits |
346
|
|
|
except Exception as e: |
347
|
|
|
abort(404, "Cannot get limits for plugin %s (%s)" % (plugin, str(e))) |
348
|
|
|
return ret |
349
|
|
|
|
350
|
|
|
def _api_views(self, plugin): |
351
|
|
|
"""Glances API RESTFul implementation. |
352
|
|
|
|
353
|
|
|
Return the JSON views of a given plugin |
354
|
|
|
HTTP/200 if OK |
355
|
|
|
HTTP/400 if plugin is not found |
356
|
|
|
HTTP/404 if others error |
357
|
|
|
""" |
358
|
|
|
response.content_type = 'application/json' |
359
|
|
|
|
360
|
|
|
if plugin not in self.plugins_list: |
361
|
|
|
abort(400, "Unknown plugin %s (available plugins: %s)" % (plugin, self.plugins_list)) |
362
|
|
|
|
363
|
|
|
# Update the stat |
364
|
|
|
# self.__update__() |
365
|
|
|
|
366
|
|
|
try: |
367
|
|
|
# Get the JSON value of the stat views |
368
|
|
|
ret = self.stats.get_plugin(plugin).get_views() |
369
|
|
|
except Exception as e: |
370
|
|
|
abort(404, "Cannot get views for plugin %s (%s)" % (plugin, str(e))) |
371
|
|
|
return ret |
372
|
|
|
|
373
|
|
|
def _api_itemvalue(self, plugin, item, value=None, history=False, nb=0): |
374
|
|
|
"""Father method for _api_item and _api_value""" |
375
|
|
|
response.content_type = 'application/json' |
376
|
|
|
|
377
|
|
|
if plugin not in self.plugins_list: |
378
|
|
|
abort(400, "Unknown plugin %s (available plugins: %s)" % (plugin, self.plugins_list)) |
379
|
|
|
|
380
|
|
|
# Update the stat |
381
|
|
|
self.__update__() |
382
|
|
|
|
383
|
|
|
if value is None: |
384
|
|
|
if history: |
385
|
|
|
ret = self.stats.get_plugin(plugin).get_stats_history(item, nb=int(nb)) |
386
|
|
|
else: |
387
|
|
|
ret = self.stats.get_plugin(plugin).get_stats_item(item) |
388
|
|
|
|
389
|
|
|
if ret is None: |
390
|
|
|
abort(404, "Cannot get item %s%s in plugin %s" % (item, 'history ' if history else '', plugin)) |
391
|
|
|
else: |
392
|
|
|
if history: |
393
|
|
|
# Not available |
394
|
|
|
ret = None |
395
|
|
|
else: |
396
|
|
|
ret = self.stats.get_plugin(plugin).get_stats_value(item, value) |
397
|
|
|
|
398
|
|
|
if ret is None: |
399
|
|
|
abort(404, "Cannot get item %s(%s=%s) in plugin %s" % ('history ' if history else '', item, value, plugin)) |
400
|
|
|
|
401
|
|
|
return ret |
402
|
|
|
|
403
|
|
|
def _api_item(self, plugin, item): |
404
|
|
|
"""Glances API RESTFul implementation. |
405
|
|
|
|
406
|
|
|
Return the JSON representation of the couple plugin/item |
407
|
|
|
HTTP/200 if OK |
408
|
|
|
HTTP/400 if plugin is not found |
409
|
|
|
HTTP/404 if others error |
410
|
|
|
|
411
|
|
|
""" |
412
|
|
|
return self._api_itemvalue(plugin, item) |
413
|
|
|
|
414
|
|
|
def _api_item_history(self, plugin, item, nb=0): |
415
|
|
|
"""Glances API RESTFul implementation. |
416
|
|
|
|
417
|
|
|
Return the JSON representation of the couple plugin/history of item |
418
|
|
|
HTTP/200 if OK |
419
|
|
|
HTTP/400 if plugin is not found |
420
|
|
|
HTTP/404 if others error |
421
|
|
|
|
422
|
|
|
""" |
423
|
|
|
return self._api_itemvalue(plugin, item, history=True, nb=int(nb)) |
424
|
|
|
|
425
|
|
|
def _api_value(self, plugin, item, value): |
426
|
|
|
"""Glances API RESTFul implementation. |
427
|
|
|
|
428
|
|
|
Return the process stats (dict) for the given item=value |
429
|
|
|
HTTP/200 if OK |
430
|
|
|
HTTP/400 if plugin is not found |
431
|
|
|
HTTP/404 if others error |
432
|
|
|
""" |
433
|
|
|
return self._api_itemvalue(plugin, item, value) |
434
|
|
|
|
435
|
|
|
def _api_config(self): |
436
|
|
|
"""Glances API RESTFul implementation. |
437
|
|
|
|
438
|
|
|
Return the JSON representation of the Glances configuration file |
439
|
|
|
HTTP/200 if OK |
440
|
|
|
HTTP/404 if others error |
441
|
|
|
""" |
442
|
|
|
response.content_type = 'application/json' |
443
|
|
|
|
444
|
|
|
try: |
445
|
|
|
# Get the JSON value of the config' dict |
446
|
|
|
args_json = json.dumps(self.config.as_dict()) |
447
|
|
|
except Exception as e: |
448
|
|
|
abort(404, "Cannot get config (%s)" % str(e)) |
449
|
|
|
return args_json |
450
|
|
|
|
451
|
|
|
def _api_config_item(self, item): |
452
|
|
|
"""Glances API RESTFul implementation. |
453
|
|
|
|
454
|
|
|
Return the JSON representation of the Glances configuration item |
455
|
|
|
HTTP/200 if OK |
456
|
|
|
HTTP/400 if item is not found |
457
|
|
|
HTTP/404 if others error |
458
|
|
|
""" |
459
|
|
|
response.content_type = 'application/json' |
460
|
|
|
|
461
|
|
|
config_dict = self.config.as_dict() |
462
|
|
|
if item not in config_dict: |
463
|
|
|
abort(400, "Unknown configuration item %s" % item) |
464
|
|
|
|
465
|
|
|
try: |
466
|
|
|
# Get the JSON value of the config' dict |
467
|
|
|
args_json = json.dumps(config_dict[item]) |
468
|
|
|
except Exception as e: |
469
|
|
|
abort(404, "Cannot get config item (%s)" % str(e)) |
470
|
|
|
return args_json |
471
|
|
|
|
472
|
|
|
def _api_args(self): |
473
|
|
|
"""Glances API RESTFul implementation. |
474
|
|
|
|
475
|
|
|
Return the JSON representation of the Glances command line arguments |
476
|
|
|
HTTP/200 if OK |
477
|
|
|
HTTP/404 if others error |
478
|
|
|
""" |
479
|
|
|
response.content_type = 'application/json' |
480
|
|
|
|
481
|
|
|
try: |
482
|
|
|
# Get the JSON value of the args' dict |
483
|
|
|
# Use vars to convert namespace to dict |
484
|
|
|
# Source: https://docs.python.org/2/library/functions.html#vars |
485
|
|
|
args_json = json.dumps(vars(self.args)) |
486
|
|
|
except Exception as e: |
487
|
|
|
abort(404, "Cannot get args (%s)" % str(e)) |
488
|
|
|
return args_json |
489
|
|
|
|
490
|
|
|
def _api_args_item(self, item): |
491
|
|
|
"""Glances API RESTFul implementation. |
492
|
|
|
|
493
|
|
|
Return the JSON representation of the Glances command line arguments item |
494
|
|
|
HTTP/200 if OK |
495
|
|
|
HTTP/400 if item is not found |
496
|
|
|
HTTP/404 if others error |
497
|
|
|
""" |
498
|
|
|
response.content_type = 'application/json' |
499
|
|
|
|
500
|
|
|
if item not in self.args: |
501
|
|
|
abort(400, "Unknown argument item %s" % item) |
502
|
|
|
|
503
|
|
|
try: |
504
|
|
|
# Get the JSON value of the args' dict |
505
|
|
|
# Use vars to convert namespace to dict |
506
|
|
|
# Source: https://docs.python.org/2/library/functions.html#vars |
507
|
|
|
args_json = json.dumps(vars(self.args)[item]) |
508
|
|
|
except Exception as e: |
509
|
|
|
abort(404, "Cannot get args item (%s)" % str(e)) |
510
|
|
|
return args_json |
511
|
|
|
|
512
|
|
|
|
513
|
|
|
class EnableCors(object): |
514
|
|
|
name = 'enable_cors' |
515
|
|
|
api = 2 |
516
|
|
|
|
517
|
|
|
def apply(self, fn, context): |
518
|
|
|
def _enable_cors(*args, **kwargs): |
519
|
|
|
# set CORS headers |
520
|
|
|
response.headers['Access-Control-Allow-Origin'] = '*' |
521
|
|
|
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, OPTIONS' |
522
|
|
|
response.headers['Access-Control-Allow-Headers'] = 'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token' |
523
|
|
|
|
524
|
|
|
if request.method != 'OPTIONS': |
525
|
|
|
# actual request; reply with the actual response |
526
|
|
|
return fn(*args, **kwargs) |
527
|
|
|
|
528
|
|
|
return _enable_cors |
529
|
|
|
|