summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Hennion <nicolas@nicolargo.com>2014-07-07 15:54:26 +0200
committerNicolas Hennion <nicolas@nicolargo.com>2014-07-07 15:54:26 +0200
commit09ec93a9d96ca3e7a471423b326c5dbfeccd5780 (patch)
tree28852a6c732fa9b3bb232cccb84da0a084d23982
parent2749e967bbbf30f1326705335af9887bb947f72f (diff)
Add methods to the Restfull/API
-rw-r--r--docs/glances-doc.rst13
-rw-r--r--glances/core/glances_stats.py12
-rw-r--r--glances/outputs/glances_bottle.py78
-rw-r--r--glances/plugins/glances_plugin.py6
4 files changed, 88 insertions, 21 deletions
diff --git a/docs/glances-doc.rst b/docs/glances-doc.rst
index c41e49d0..f6dfa97b 100644
--- a/docs/glances-doc.rst
+++ b/docs/glances-doc.rst
@@ -592,13 +592,15 @@ CSV files have two lines per stats:
- Stats description
- Stats (comma separated)
-API Documentation
-=================
+APIs Documentations
+===================
+
+Glances includes a `XML-RPC server`_ and a `RESTFULL-JSON`_ API which and can be used by another client software.
-Glances uses a `XML-RPC server`_ and can be used by another client software.
+APIs documentations are available at:
-API documentation is available at
-https://github.com/nicolargo/glances/wiki/The-Glances-2.x-API-How-to.
+- XML-RPC: https://github.com/nicolargo/glances/wiki/The-Glances-2.x-API-How-to
+- RESTFULL-JSON: https://github.com/nicolargo/glances/wiki/The-Glances-RESTFULL-JSON-API
Support
=======
@@ -614,3 +616,4 @@ Feel free to contribute!
.. _psutil: https://code.google.com/p/psutil/
.. _XML-RPC server: http://docs.python.org/2/library/simplexmlrpcserver.html
+.. _RESTFULL-JSON: http://jsonapi.org/ \ No newline at end of file
diff --git a/glances/core/glances_stats.py b/glances/core/glances_stats.py
index 5cb1d521..6b282692 100644
--- a/glances/core/glances_stats.py
+++ b/glances/core/glances_stats.py
@@ -127,9 +127,13 @@ class GlancesStats(object):
self.__update__(input_stats)
def getAll(self):
- """Return all the stats."""
+ """Return all the stats (list)"""
return [self._plugins[p].get_raw() for p in self._plugins]
+ def getAllAsDict(self):
+ """Return all the stats (dict)"""
+ return {p: self._plugins[p].get_raw() for p in self._plugins}
+
def get_plugin_list(self):
"""Return the plugin list."""
self._plugins
@@ -163,9 +167,13 @@ class GlancesStatsServer(GlancesStats):
self.all_stats[p] = self._plugins[p].get_raw()
def getAll(self):
- """Return the stats as a dict."""
+ """Return the stats as a list"""
return self.all_stats
+ def getAllAsDict(self):
+ """Return the stats as a dict"""
+ return {p: self.all_stats[p] for p in self._plugins}
+
def getAllPlugins(self):
"""Return the plugins list."""
return [p for p in self._plugins]
diff --git a/glances/outputs/glances_bottle.py b/glances/outputs/glances_bottle.py
index c513e9e8..f96e9e75 100644
--- a/glances/outputs/glances_bottle.py
+++ b/glances/outputs/glances_bottle.py
@@ -27,7 +27,7 @@ from glances.core.glances_globals import logger
# Import mandatory Bottle lib
try:
- from bottle import Bottle, template, static_file, TEMPLATE_PATH, abort
+ from bottle import Bottle, template, static_file, TEMPLATE_PATH, abort, response
except ImportError:
logger.critical('Bottle module not found. Glances cannot start in web server mode.')
print(_("Install it using pip: # pip install bottle"))
@@ -84,10 +84,11 @@ class GlancesBottle(object):
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)
+ self._app.route('/api/2/pluginslist', method="GET", callback=self._api_plugins)
+ self._app.route('/api/2/all', method="GET", callback=self._api_all)
+ self._app.route('/api/2/:plugin', method="GET", callback=self._api)
+ self._app.route('/api/2/:plugin/:item', method="GET", callback=self._api_item)
+ self._app.route('/api/2/:plugin/:item/:value', method="GET", callback=self._api_value)
def start(self, stats):
"""Start the bottle."""
@@ -109,6 +110,7 @@ class GlancesBottle(object):
def _index(self, refresh_time=None):
"""Bottle callback for index.html (/) file."""
+ response.content_type = 'text/html'
# Manage parameter
if refresh_time is None:
refresh_time = self.args.time
@@ -121,11 +123,13 @@ class GlancesBottle(object):
def _css(self, filename):
"""Bottle callback for *.css files."""
+ response.content_type = 'text/html'
# Return the static file
return static_file(filename, root=os.path.join(self.STATIC_PATH, 'css'))
def _js(self, filename):
"""Bottle callback for *.js files."""
+ response.content_type = 'text/html'
# Return the static file
return static_file(filename, root=os.path.join(self.STATIC_PATH, 'js'))
@@ -135,20 +139,53 @@ class GlancesBottle(object):
Return the plugin list
or 404 error
"""
+ response.content_type = 'application/vnd.api+json'
+
+ # Update the stat
+ self.stats.update()
+
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_all(self):
+ """
+ Glances API RESTFULL implementation
+ Return the JSON representation of all the plugins
+ HTTP/200 if OK
+ HTTP/400 if plugin is not found
+ HTTP/404 if others error
+ """
+ response.content_type = 'application/vnd.api+json'
+
+ # Update the stat
+ self.stats.update()
+
+ try:
+ # Get the JSON value of the stat ID
+ statval = json.dumps(self.stats.getAllAsDict())
+ except Exception as e:
+ abort(404, "Can not get stats (%s)" % str(e))
+ return statval
+
def _api(self, plugin):
"""
Glances API RESTFULL implementation
Return the JSON representation of a given plugin
- or 404 error
+ HTTP/200 if OK
+ HTTP/400 if plugin is not found
+ HTTP/404 if others error
"""
+ response.content_type = 'application/vnd.api+json'
+
if plugin not in self.plugins_list:
- abort(404, "Unknown plugin %s (available plugins: %s)" % (plugin, self.plugins_list))
+ abort(400, "Unknown plugin %s (available plugins: %s)" % (plugin, self.plugins_list))
+
+ # Update the stat
+ self.stats.update()
+
try:
# Get the JSON value of the stat ID
statval = self.stats.get_plugin(plugin).get_stats()
@@ -160,11 +197,21 @@ class GlancesBottle(object):
"""
Glances API RESTFULL implementation
Return the JSON represenation of the couple plugin/item
- or 404 error
+ HTTP/200 if OK
+ HTTP/400 if plugin is not found
+ HTTP/404 if others error
+
"""
+ response.content_type = 'application/vnd.api+json'
+
if plugin not in self.plugins_list:
- abort(404, "Unknown plugin %s (available plugins: %s)" % (plugin, self.plugins_list))
+ abort(400, "Unknown plugin %s (available plugins: %s)" % (plugin, self.plugins_list))
+
+ # Update the stat
+ self.stats.update()
+
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:
@@ -174,11 +221,20 @@ class GlancesBottle(object):
"""
Glances API RESTFULL implementation
Return the process stats (dict) for the given item=value
- or 404 error
+ HTTP/200 if OK
+ HTTP/400 if plugin is not found
+ HTTP/404 if others error
"""
+ response.content_type = 'application/vnd.api+json'
+
if plugin not in self.plugins_list:
- abort(404, "Unknown plugin %s (available plugins: %s)" % (plugin, self.plugins_list))
+ abort(400, "Unknown plugin %s (available plugins: %s)" % (plugin, self.plugins_list))
+
+ # Update the stat
+ self.stats.update()
+
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:
diff --git a/glances/plugins/glances_plugin.py b/glances/plugins/glances_plugin.py
index 4ed3d61b..c0189f24 100644
--- a/glances/plugins/glances_plugin.py
+++ b/glances/plugins/glances_plugin.py
@@ -158,7 +158,7 @@ class GlancesPlugin(object):
if type(self.stats) is not list:
if type(self.stats) is dict:
try:
- return json.dumps(self.stats[item])
+ return json.dumps({ item: self.stats[item] })
except KeyError as e:
logger.error(_("Can not get item %s (%s)") % (item, e))
else:
@@ -166,7 +166,7 @@ class GlancesPlugin(object):
else:
try:
# Source: http://stackoverflow.com/questions/4573875/python-get-index-of-dictionary-item-in-list
- return json.dumps(map(itemgetter(item), self.stats))
+ return json.dumps({ item: map(itemgetter(item), self.stats) })
except (KeyError, ValueError) as e:
logger.error(_("Can not get item %s (%s)") % (item, e))
return None
@@ -182,7 +182,7 @@ class GlancesPlugin(object):
if value.isdigit():
value = int(value)
try:
- return json.dumps([i for i in self.stats if i[item] == value])
+ return json.dumps({ value: [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