Add view (MVC speeking) for the plugins. Add API methods and Unitary test.

This commit is contained in:
Nicolargo
2015-01-18 18:21:26 +01:00
parent 8a94bc65bb
commit 2d6675fa3b
11 changed files with 136 additions and 23 deletions

1
NEWS
View File

@@ -16,6 +16,7 @@ Enhancements and news features:
* Add the Docker plugin (issue #440)
* It is possible, through the configuration file, to define if an alarm should be logged or not (using the _log option) (issue #437)
* You can now set alarm for Disk IO
* API: add getAllLimits and getAllViews methods (issue#481)
Bugs corrected:

View File

@@ -160,7 +160,11 @@ class GlancesInstance(object):
def getAllLimits(self):
# Return all the plugins limits
return json.dumps(self.stats.getAllLimits())
return json.dumps(self.stats.getAllLimitsAsDict())
def getAllViews(self):
# Return all the plugins views
return json.dumps(self.stats.getAllViewsAsDict())
def getAllMonitored(self):
# Return the processes monitored list

View File

@@ -190,6 +190,17 @@ class GlancesStats(object):
ret[p] = self._plugins[p].get_limits()
return ret
def getAllViews(self):
"""Return the plugins views"""
return [self._plugins[p].get_views() for p in self._plugins]
def getAllViewsAsDict(self):
"""Return all the stats views (dict)"""
ret = {}
for p in self._plugins:
ret[p] = self._plugins[p].get_views()
return ret
def get_plugin_list(self):
"""Return the plugin list."""
self._plugins

View File

@@ -70,8 +70,10 @@ class GlancesBottle(object):
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/all/limits', method="GET", callback=self._api_all_limits)
self._app.route('/api/2/all/views', method="GET", callback=self._api_all_views)
self._app.route('/api/2/:plugin', method="GET", callback=self._api)
self._app.route('/api/2/:plugin/limits', method="GET", callback=self._api_limits)
self._app.route('/api/2/:plugin/views', method="GET", callback=self._api_views)
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)
@@ -151,7 +153,7 @@ class GlancesBottle(object):
self.stats.update()
try:
# Get the JSON value of the stat ID
# Get the JSON value of the stat value
statval = json.dumps(self.stats.getAllAsDict())
except Exception as e:
abort(404, "Cannot get stats (%s)" % str(e))
@@ -168,12 +170,29 @@ class GlancesBottle(object):
response.content_type = 'application/json'
try:
# Get the JSON value of the stat ID
# Get the JSON value of the stat limits
limits = json.dumps(self.stats.getAllLimitsAsDict())
except Exception as e:
abort(404, "Cannot get limits (%s)" % (str(e)))
return limits
def _api_all_views(self):
"""
Glances API RESTFul implementation
Return the JSON representation of all the plugins views
HTTP/200 if OK
HTTP/400 if plugin is not found
HTTP/404 if others error
"""
response.content_type = 'application/json'
try:
# Get the JSON value of the stat view
limits = json.dumps(self.stats.getAllViewsAsDict())
except Exception as e:
abort(404, "Cannot get views (%s)" % (str(e)))
return limits
def _api(self, plugin):
"""
Glances API RESTFul implementation
@@ -214,11 +233,34 @@ class GlancesBottle(object):
# self.stats.update()
try:
# Get the JSON value of the stat ID
limits = self.stats.get_plugin(plugin).get_limits()
# Get the JSON value of the stat limits
ret = self.stats.get_plugin(plugin).get_limits()
except Exception as e:
abort(404, "Cannot get limits for plugin %s (%s)" % (plugin, str(e)))
return limits
return ret
def _api_views(self, plugin):
"""
Glances API RESTFul implementation
Return the JSON views of a given plugin
HTTP/200 if OK
HTTP/400 if plugin is not found
HTTP/404 if others error
"""
response.content_type = 'application/json'
if plugin not in 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 views
ret = self.stats.get_plugin(plugin).get_views()
except Exception as e:
abort(404, "Cannot get views for plugin %s (%s)" % (plugin, str(e)))
return ret
def _api_item(self, plugin, item):
"""

View File

@@ -134,7 +134,7 @@ class Plugin(GlancesPlugin):
# Add specifics informations
# Alert
for i in sorted(self.stats, key=operator.itemgetter(self.get_key())):
for i in self.stats:
disk_real_name = i['disk_name']
self.views[i[self.get_key()]]['read_bytes']['decoration'] = self.get_alert(int(i['read_bytes'] // i['time_since_update']),
header=disk_real_name + '_rx')

View File

@@ -180,7 +180,7 @@ class Plugin(GlancesPlugin):
# Add specifics informations
# Alert
for i in sorted(self.stats, key=operator.itemgetter(self.get_key())):
for i in self.stats:
self.views[i[self.get_key()]]['used']['decoration'] = self.get_alert(i['used'], max=i['size'], header=i['mnt_point'])
def msg_curse(self, args=None, max_width=None):

View File

@@ -195,7 +195,7 @@ class Plugin(GlancesPlugin):
# Add specifics informations
# Alert
for i in sorted(self.stats, key=operator.itemgetter(self.get_key())):
for i in self.stats:
ifrealname = i['interface_name'].split(':')[0]
self.views[i[self.get_key()]]['rx']['decoration'] = self.get_alert(int(i['rx'] // i['time_since_update'] * 8),
header=ifrealname + '_rx')

View File

@@ -72,6 +72,9 @@ class Plugin(GlancesPlugin):
# No standard way for the moment...
pass
# Update the view
self.update_views()
return self.stats
def msg_curse(self, args=None):

View File

@@ -172,13 +172,10 @@ class Plugin(GlancesPlugin):
msg = '{0:18}'.format(label)
ret.append(self.curse_add_line(msg))
msg = '{0:>5}'.format(i['value'])
try:
ret.append(self.curse_add_line(
msg, self.get_views(item=i[self.get_key()],
key='value',
option='decoration')))
except TypeError:
pass
ret.append(self.curse_add_line(
msg, self.get_views(item=i[self.get_key()],
key='value',
option='decoration')))
return ret

View File

@@ -124,8 +124,6 @@ class TestGlances(unittest.TestCase):
plist = requests.get("%s/%s" % (URL, method))
print(plist.json())
for p in plist.json():
print("HTTP RESTFul request: %s/%s" % (URL, p))
req = requests.get("%s/%s" % (URL, p))
@@ -175,6 +173,43 @@ class TestGlances(unittest.TestCase):
self.assertTrue(req.ok)
self.assertIsInstance(req.json(), types.DictType)
def test_007_all_views(self):
"""All"""
method = "all/views"
print('INFO: [TEST_007] Get all views')
print("HTTP RESTFul request: %s/%s" % (URL, method))
req = requests.get("%s/%s" % (URL, method))
self.assertTrue(req.ok)
self.assertIsInstance(req.json(), types.DictType)
def test_008_plugins_limits(self):
"""Plugins limits"""
method = "pluginslist"
print('INFO: [TEST_008] Plugins limits')
plist = requests.get("%s/%s" % (URL, method))
for p in plist.json():
print("HTTP RESTFul request: %s/%s/limits" % (URL, p))
req = requests.get("%s/%s/limits" % (URL, p))
self.assertTrue(req.ok)
self.assertIsInstance(req.json(), types.DictType)
def test_009_plugins_views(self):
"""Plugins views"""
method = "pluginslist"
print('INFO: [TEST_009] Plugins views')
plist = requests.get("%s/%s" % (URL, method))
for p in plist.json():
print("HTTP RESTFul request: %s/%s/views" % (URL, p))
req = requests.get("%s/%s/views" % (URL, p))
self.assertTrue(req.ok)
self.assertIsInstance(req.json(), types.DictType)
def test_999_stop_server(self):
"""Stop the Glances Web Server"""
print('INFO: [TEST_999] Stop the Glances Web Server')

View File

@@ -31,7 +31,7 @@ import json
import types
try:
from xmlrpc.client import ServerProxy
except ImportError:
except ImportError:
# Python 2
from xmlrpclib import ServerProxy
@@ -50,7 +50,8 @@ pid = None
# Unitary test is only available from a GNU/Linus machine
if not is_linux:
print('ERROR: XML/RPC API unitaries tests should be ran on GNU/Linux operating system')
print(
'ERROR: XML/RPC API unitaries tests should be ran on GNU/Linux operating system')
sys.exit(2)
else:
print('Unitary tests for {0} {1}'.format(appname, version))
@@ -77,6 +78,7 @@ client = ServerProxy(URL)
# Unitest class
# ==============
class TestGlances(unittest.TestCase):
"""Test Glances class."""
@@ -88,16 +90,16 @@ class TestGlances(unittest.TestCase):
def test_000_start_server(self):
"""Start the Glances Web Server"""
print('INFO: [TEST_000] Start the Glances Web Server')
global pid
cmdline = "/usr/bin/python -m glances -s -p %s" % SERVER_PORT
print("Run the Glances Server on port %s" % SERVER_PORT)
args = shlex.split(cmdline)
pid = subprocess.Popen(args)
print("Please wait...")
time.sleep(1)
self.assertTrue(pid is not None)
def test_001_all(self):
@@ -195,6 +197,24 @@ class TestGlances(unittest.TestCase):
req = json.loads(client.getProcessList())
self.assertIsInstance(req, types.ListType)
def test_010_all_limits(self):
"""All limits"""
method = "getAllLimits()"
print('INFO: [TEST_010] Method: %s' % method)
req = json.loads(client.getAllLimits())
self.assertIsInstance(req, types.DictType)
self.assertIsInstance(req['cpu'], types.DictType)
def test_011_all_views(self):
"""All views"""
method = "getAllViews()"
print('INFO: [TEST_011] Method: %s' % method)
req = json.loads(client.getAllViews())
self.assertIsInstance(req, types.DictType)
self.assertIsInstance(req['cpu'], types.DictType)
def test_999_stop_server(self):
"""Stop the Glances Web Server"""
print('INFO: [TEST_999] Stop the Glances Server')