From 3dc4ea46d69b8740a5f5d9318cc0f512488c44fc Mon Sep 17 00:00:00 2001 From: grossmj Date: Sun, 19 Jul 2020 14:16:07 +0930 Subject: [PATCH] Add total RAM, CPUs and disk size to servers summary as well as disk usage in percent. Fixes https://github.com/GNS3/gns3-server/issues/1532 --- gns3server/controller/compute.py | 11 +++++++++++ .../api/compute/capabilities_handler.py | 5 +++++ .../handlers/api/compute/project_handler.py | 3 ++- .../handlers/api/compute/server_handler.py | 3 ++- gns3server/notification_queue.py | 2 ++ gns3server/schemas/capabilities.py | 14 +++++++++++++- gns3server/schemas/compute.py | 6 ++++++ tests/controller/test_compute.py | 4 ++++ .../handlers/api/compute/test_capabilities.py | 18 ++++++++++++++++-- tests/handlers/api/controller/test_compute.py | 4 ++++ tests/test_config.py | 8 ++++---- 11 files changed, 69 insertions(+), 9 deletions(-) diff --git a/gns3server/controller/compute.py b/gns3server/controller/compute.py index 39eb961b..95884c62 100644 --- a/gns3server/controller/compute.py +++ b/gns3server/controller/compute.py @@ -80,9 +80,13 @@ class Compute: self._set_auth(user, password) self._cpu_usage_percent = None self._memory_usage_percent = None + self._disk_usage_percent = None self._last_error = None self._capabilities = { "version": None, + "cpus": None, + "memory": None, + "disk_size": None, "node_types": [] } self.name = name @@ -270,6 +274,10 @@ class Compute: def memory_usage_percent(self): return self._memory_usage_percent + @property + def disk_usage_percent(self): + return self._disk_usage_percent + def __json__(self, topology_dump=False): """ :param topology_dump: Filter to keep only properties require for saving on disk @@ -292,6 +300,7 @@ class Compute: "connected": self._connected, "cpu_usage_percent": self._cpu_usage_percent, "memory_usage_percent": self._memory_usage_percent, + "disk_usage_percent": self._disk_usage_percent, "capabilities": self._capabilities, "last_error": self._last_error } @@ -437,6 +446,7 @@ class Compute: if action == "ping": self._cpu_usage_percent = event["cpu_usage_percent"] self._memory_usage_percent = event["memory_usage_percent"] + self._disk_usage_percent = event["disk_usage_percent"] #FIXME: slow down number of compute events self._controller.notification.controller_emit("compute.updated", self.__json__()) else: @@ -461,6 +471,7 @@ class Compute: self._cpu_usage_percent = None self._memory_usage_percent = None + self._disk_usage_percent = None self._controller.notification.controller_emit("compute.updated", self.__json__()) def _getUrl(self, path): diff --git a/gns3server/handlers/api/compute/capabilities_handler.py b/gns3server/handlers/api/compute/capabilities_handler.py index e183d6aa..00f8a76c 100644 --- a/gns3server/handlers/api/compute/capabilities_handler.py +++ b/gns3server/handlers/api/compute/capabilities_handler.py @@ -16,11 +16,13 @@ # along with this program. If not, see . import sys +import psutil from gns3server.web.route import Route from gns3server.schemas.capabilities import CAPABILITIES_SCHEMA from gns3server.version import __version__ from gns3server.compute import MODULES +from gns3server.utils.path import get_default_project_directory class CapabilitiesHandler: @@ -38,5 +40,8 @@ class CapabilitiesHandler: response.json({ "version": __version__, "platform": sys.platform, + "cpus": psutil.cpu_count(logical=True), + "memory": psutil.virtual_memory().total, + "disk_size": psutil.disk_usage(get_default_project_directory()).total, "node_types": node_types }) diff --git a/gns3server/handlers/api/compute/project_handler.py b/gns3server/handlers/api/compute/project_handler.py index d8eb0e11..1bfe1bac 100644 --- a/gns3server/handlers/api/compute/project_handler.py +++ b/gns3server/handlers/api/compute/project_handler.py @@ -20,12 +20,12 @@ import asyncio import json import os import psutil -import tempfile from gns3server.web.route import Route from gns3server.compute.project_manager import ProjectManager from gns3server.compute import MODULES from gns3server.utils.cpu_percent import CpuPercent +from gns3server.utils.path import get_default_project_directory from gns3server.schemas.project import ( PROJECT_OBJECT_SCHEMA, @@ -211,6 +211,7 @@ class ProjectHandler: # Non blocking call in order to get cpu usage. First call will return 0 stats["cpu_usage_percent"] = CpuPercent.get(interval=None) stats["memory_usage_percent"] = psutil.virtual_memory().percent + stats["disk_usage_percent"] = psutil.disk_usage(get_default_project_directory()).percent return {"action": "ping", "event": stats} @Route.get( diff --git a/gns3server/handlers/api/compute/server_handler.py b/gns3server/handlers/api/compute/server_handler.py index 74d64d10..767d93f9 100644 --- a/gns3server/handlers/api/compute/server_handler.py +++ b/gns3server/handlers/api/compute/server_handler.py @@ -25,6 +25,7 @@ from gns3server.schemas.server_statistics import SERVER_STATISTICS_SCHEMA from gns3server.compute.port_manager import PortManager from gns3server.utils.cpu_percent import CpuPercent from gns3server.version import __version__ +from gns3server.utils.path import get_default_project_directory from aiohttp.web import HTTPConflict @@ -61,7 +62,7 @@ class ServerHandler: load_average_percent = [int(x / psutil.cpu_count() * 100) for x in psutil.getloadavg()] memory_percent = int(psutil.virtual_memory().percent) swap_percent = int(psutil.swap_memory().percent) - disk_usage_percent = int(psutil.disk_usage('/').percent) + disk_usage_percent = int(psutil.disk_usage(get_default_project_directory()).percent) except psutil.Error as e: raise HTTPConflict(text="Psutil error detected: {}".format(e)) response.json({"memory_total": memory_total, diff --git a/gns3server/notification_queue.py b/gns3server/notification_queue.py index d81a2a2b..6298bf1b 100644 --- a/gns3server/notification_queue.py +++ b/gns3server/notification_queue.py @@ -20,6 +20,7 @@ import json import psutil from gns3server.utils.cpu_percent import CpuPercent +from gns3server.utils.path import get_default_project_directory class NotificationQueue(asyncio.Queue): @@ -55,6 +56,7 @@ class NotificationQueue(asyncio.Queue): # Non blocking call in order to get cpu usage. First call will return 0 msg["cpu_usage_percent"] = CpuPercent.get(interval=None) msg["memory_usage_percent"] = psutil.virtual_memory().percent + msg["disk_usage_percent"] = psutil.disk_usage(get_default_project_directory()).percent return msg async def get_json(self, timeout): diff --git a/gns3server/schemas/capabilities.py b/gns3server/schemas/capabilities.py index 2c9896ae..61378299 100644 --- a/gns3server/schemas/capabilities.py +++ b/gns3server/schemas/capabilities.py @@ -36,7 +36,19 @@ CAPABILITIES_SCHEMA = { "platform": { "type": "string", "description": "Platform where the compute is running" - } + }, + "cpus": { + "description": "Number of CPUs on this compute. Read only", + "type": ["integer", "null"], + }, + "memory": { + "description": "Amount of memory on this compute. Read only", + "type": ["integer", "null"], + }, + "disk_size": { + "description": "Disk size on this compute. Read only", + "type": ["integer", "null"], + }, }, "additionalProperties": False } diff --git a/gns3server/schemas/compute.py b/gns3server/schemas/compute.py index 12716dad..3de0fb70 100644 --- a/gns3server/schemas/compute.py +++ b/gns3server/schemas/compute.py @@ -104,6 +104,12 @@ COMPUTE_OBJECT_SCHEMA = { "maximum": 100, "minimum": 0 }, + "disk_usage_percent": { + "description": "Disk usage of the compute. Read only", + "type": ["number", "null"], + "maximum": 100, + "minimum": 0 + }, "last_error": { "description": "Last error on the compute", "type": ["string", "null"] diff --git a/tests/controller/test_compute.py b/tests/controller/test_compute.py index d7f5329c..57c54c8b 100644 --- a/tests/controller/test_compute.py +++ b/tests/controller/test_compute.py @@ -292,10 +292,14 @@ async def test_json(compute): "user": "test", "cpu_usage_percent": None, "memory_usage_percent": None, + "disk_usage_percent": None, "connected": True, "last_error": None, "capabilities": { "version": None, + "cpus": None, + "memory": None, + "disk_size": None, "node_types": [] } } diff --git a/tests/handlers/api/compute/test_capabilities.py b/tests/handlers/api/compute/test_capabilities.py index ff651bb3..bb7ba5a8 100644 --- a/tests/handlers/api/compute/test_capabilities.py +++ b/tests/handlers/api/compute/test_capabilities.py @@ -18,8 +18,10 @@ import sys import pytest +import psutil from gns3server.version import __version__ +from gns3server.utils.path import get_default_project_directory @pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows") @@ -27,7 +29,13 @@ async def test_get(compute_api, windows_platform): response = await compute_api.get('/capabilities') assert response.status == 200 - assert response.json == {'node_types': ['cloud', 'ethernet_hub', 'ethernet_switch', 'nat', 'vpcs', 'virtualbox', 'dynamips', 'frame_relay_switch', 'atm_switch', 'qemu', 'vmware', 'traceng', 'docker', 'iou'], 'version': __version__, 'platform': sys.platform} + assert response.json == {'node_types': ['cloud', 'ethernet_hub', 'ethernet_switch', 'nat', 'vpcs', 'virtualbox', 'dynamips', 'frame_relay_switch', 'atm_switch', 'qemu', 'vmware', 'traceng', 'docker', 'iou'], + 'version': __version__, + 'platform': sys.platform, + 'cpus': psutil.cpu_count(logical=True), + 'memory': psutil.virtual_memory().total, + 'disk_size': psutil.disk_usage(get_default_project_directory()).total, + } @pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows") @@ -35,4 +43,10 @@ async def test_get_on_gns3vm(compute_api, on_gns3vm): response = await compute_api.get('/capabilities') assert response.status == 200 - assert response.json == {'node_types': ['cloud', 'ethernet_hub', 'ethernet_switch', 'nat', 'vpcs', 'virtualbox', 'dynamips', 'frame_relay_switch', 'atm_switch', 'qemu', 'vmware', 'traceng', 'docker', 'iou'], 'version': __version__, 'platform': sys.platform} + assert response.json == {'node_types': ['cloud', 'ethernet_hub', 'ethernet_switch', 'nat', 'vpcs', 'virtualbox', 'dynamips', 'frame_relay_switch', 'atm_switch', 'qemu', 'vmware', 'traceng', 'docker', 'iou'], + 'version': __version__, + 'platform': sys.platform, + 'cpus': psutil.cpu_count(logical=True), + 'memory': psutil.virtual_memory().total, + 'disk_size': psutil.disk_usage(get_default_project_directory()).total, + } diff --git a/tests/handlers/api/controller/test_compute.py b/tests/handlers/api/controller/test_compute.py index 07c04680..dfed6730 100644 --- a/tests/handlers/api/controller/test_compute.py +++ b/tests/handlers/api/controller/test_compute.py @@ -133,9 +133,13 @@ async def test_compute_list(controller_api): 'name': 'My super server', 'cpu_usage_percent': None, 'memory_usage_percent': None, + 'disk_usage_percent': None, 'last_error': None, 'capabilities': { 'version': None, + 'cpus': None, + 'memory': None, + 'disk_size': None, 'node_types': [] } } diff --git a/tests/test_config.py b/tests/test_config.py index cdaa346e..f670ad54 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -53,7 +53,7 @@ def write_config(tmpdir, settings): return path -def test_get_section_config(tmpdir): +def test_get_section_config(loop, tmpdir): config = load_config(tmpdir, { "Server": { @@ -63,7 +63,7 @@ def test_get_section_config(tmpdir): assert dict(config.get_section_config("Server")) == {"host": "127.0.0.1"} -def test_set_section_config(tmpdir): +def test_set_section_config(loop, tmpdir): config = load_config(tmpdir, { "Server": { @@ -77,7 +77,7 @@ def test_set_section_config(tmpdir): assert dict(config.get_section_config("Server")) == {"host": "192.168.1.1", "local": "true"} -def test_set(tmpdir): +def test_set(loop, tmpdir): config = load_config(tmpdir, { "Server": { @@ -90,7 +90,7 @@ def test_set(tmpdir): assert dict(config.get_section_config("Server")) == {"host": "192.168.1.1"} -def test_reload(tmpdir): +def test_reload(loop, tmpdir): config = load_config(tmpdir, { "Server": {