diff options
author | Nicolargo <nicolas@nicolargo.com> | 2014-07-06 20:49:02 +0200 |
---|---|---|
committer | Nicolargo <nicolas@nicolargo.com> | 2014-07-06 20:49:02 +0200 |
commit | 2749e967bbbf30f1326705335af9887bb947f72f (patch) | |
tree | 11cbb5c8c864cf7c91187ac09155a87cabdba2bd | |
parent | e0d9fe530d59236b413dacee304240ba9e13e37d (diff) |
First version of the RESTFULL API
-rw-r--r-- | glances/outputs/glances_bottle.py | 67 | ||||
-rw-r--r-- | glances/plugins/glances_plugin.py | 42 |
2 files changed, 106 insertions, 3 deletions
diff --git a/glances/outputs/glances_bottle.py b/glances/outputs/glances_bottle.py index 2e34c9b9..c513e9e8 100644 --- a/glances/outputs/glances_bottle.py +++ b/glances/outputs/glances_bottle.py @@ -27,11 +27,12 @@ from glances.core.glances_globals import logger # Import mandatory Bottle lib try: - from bottle import Bottle, template, static_file, TEMPLATE_PATH + from bottle import Bottle, template, static_file, TEMPLATE_PATH, abort except ImportError: logger.critical('Bottle module not found. Glances cannot start in web server mode.') print(_("Install it using pip: # pip install bottle")) sys.exit(2) +import json class GlancesBottle(object): @@ -82,12 +83,21 @@ class GlancesBottle(object): self._app.route('/<refresh_time:int>', method=["GET", "POST"], callback=self._index) self._app.route('/<filename:re:.*\.css>', method="GET", callback=self._css) self._app.route('/<filename:re:.*\.js>', method="GET", callback=self._js) + # REST API + self._app.route('/api/pluginslist', method="GET", callback=self._api_plugins) + self._app.route('/api/:plugin', method="GET", callback=self._api) + self._app.route('/api/:plugin/:item', method="GET", callback=self._api_item) + self._app.route('/api/:plugin/:item/:value', method="GET", callback=self._api_value) def start(self, stats): """Start the bottle.""" # Init stats self.stats = stats + # Init plugin list + self.plugins_list = self.stats.getAllPlugins() + + # Bind the Bottle TCP address/port bindmsg = _("Glances web server started on http://{}:{}/").format(self.args.bind_address, self.args.port) logger.info(bindmsg) print(bindmsg) @@ -119,6 +129,61 @@ class GlancesBottle(object): # Return the static file return static_file(filename, root=os.path.join(self.STATIC_PATH, 'js')) + def _api_plugins(self): + """ + Glances API RESTFULL implementation + Return the plugin list + or 404 error + """ + try: + plist = json.dumps(self.plugins_list) + except Exception as e: + abort(404, "Can not get plugin list (%s)" % str(e)) + return plist + + def _api(self, plugin): + """ + Glances API RESTFULL implementation + Return the JSON representation of a given plugin + or 404 error + """ + if plugin not in self.plugins_list: + abort(404, "Unknown plugin %s (available plugins: %s)" % (plugin, self.plugins_list)) + try: + # Get the JSON value of the stat ID + statval = self.stats.get_plugin(plugin).get_stats() + except Exception as e: + abort(404, "Can not get plugin %s (%s)" % (plugin, str(e))) + return statval + + def _api_item(self, plugin, item): + """ + Glances API RESTFULL implementation + Return the JSON represenation of the couple plugin/item + or 404 error + """ + if plugin not in self.plugins_list: + abort(404, "Unknown plugin %s (available plugins: %s)" % (plugin, self.plugins_list)) + plist = self.stats.get_plugin(plugin).get_stats_item(item) + if plist is None: + abort(404, "Can not get item %s in plugin %s" % (item, plugin)) + else: + return plist + + def _api_value(self, plugin, item, value): + """ + Glances API RESTFULL implementation + Return the process stats (dict) for the given item=value + or 404 error + """ + if plugin not in self.plugins_list: + abort(404, "Unknown plugin %s (available plugins: %s)" % (plugin, self.plugins_list)) + pdict = self.stats.get_plugin(plugin).get_stats_value(item, value) + if pdict is None: + abort(404, "Can not get item(%s)=value(%s) in plugin %s" % (item, value, plugin)) + else: + return pdict + def display(self, stats, refresh_time=None): """Display stats on the web page. diff --git a/glances/plugins/glances_plugin.py b/glances/plugins/glances_plugin.py index a78d5986..4ed3d61b 100644 --- a/glances/plugins/glances_plugin.py +++ b/glances/plugins/glances_plugin.py @@ -25,9 +25,10 @@ I am your father... # Import system libs import json +from operator import itemgetter # Import Glances lib -from glances.core.glances_globals import glances_logs +from glances.core.glances_globals import glances_logs, logger class GlancesPlugin(object): @@ -146,9 +147,46 @@ class GlancesPlugin(object): return self.stats def get_stats(self): - """Return the stats object in JSON format for the XML-RPC API.""" + """Return the stats object in JSON format""" return json.dumps(self.stats) + def get_stats_item(self, item): + """ + Return the stats object for a specific item (in JSON format) + Stats should be a list of dict (processlist, network...) + """ + if type(self.stats) is not list: + if type(self.stats) is dict: + try: + return json.dumps(self.stats[item]) + except KeyError as e: + logger.error(_("Can not get item %s (%s)") % (item, e)) + else: + return None + else: + try: + # Source: http://stackoverflow.com/questions/4573875/python-get-index-of-dictionary-item-in-list + return json.dumps(map(itemgetter(item), self.stats)) + except (KeyError, ValueError) as e: + logger.error(_("Can not get item %s (%s)") % (item, e)) + return None + + def get_stats_value(self, item, value): + """ + Return the stats object for a specific item=value (in JSON format) + Stats should be a list of dict (processlist, network...) + """ + if type(self.stats) is not list: + return None + else: + if value.isdigit(): + value = int(value) + try: + return json.dumps([i for i in self.stats if i[item] == value]) + except (KeyError, ValueError) as e: + logger.error(_("Can not get item(%s)=value(%s) (%s)") % (item, value,e)) + return None + def load_limits(self, config): """Load the limits from the configuration file.""" if (hasattr(config, 'has_section') and |