mirror of
https://github.com/nicolargo/glances.git
synced 2026-03-13 19:39:08 -04:00
Add view (MVC speeking) for the plugins. Add API methods and Unitary test.
This commit is contained in:
1
NEWS
1
NEWS
@@ -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:
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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):
|
||||
"""
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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')
|
||||
|
||||
Reference in New Issue
Block a user