From 089d25c79d8abfc957243c7b4ffc6be9c077ada7 Mon Sep 17 00:00:00 2001 From: grossmj Date: Wed, 22 Aug 2018 16:54:43 +0700 Subject: [PATCH] Forbid controller and compute servers to be different versions. Report last compute server error to clients and display in the server summary. --- gns3server/controller/compute.py | 36 +++++++++++++++---- gns3server/controller/gns3vm/__init__.py | 2 ++ gns3server/schemas/compute.py | 4 +++ gns3server/version.py | 2 +- tests/controller/test_compute.py | 1 + tests/handlers/api/controller/test_compute.py | 1 + 6 files changed, 38 insertions(+), 8 deletions(-) diff --git a/gns3server/controller/compute.py b/gns3server/controller/compute.py index c07eb8f7..da81b6e9 100644 --- a/gns3server/controller/compute.py +++ b/gns3server/controller/compute.py @@ -29,7 +29,7 @@ from ..utils import parse_version from ..utils.images import list_images from ..utils.asyncio import locked_coroutine from ..controller.controller_error import ControllerError -from ..version import __version__ +from ..version import __version__, __version_info__ import logging @@ -95,6 +95,7 @@ class Compute: self._set_auth(user, password) self._cpu_usage_percent = None self._memory_usage_percent = None + self._last_error = None self._capabilities = { "version": None, "node_types": [] @@ -301,7 +302,8 @@ class Compute: "connected": self._connected, "cpu_usage_percent": self._cpu_usage_percent, "memory_usage_percent": self._memory_usage_percent, - "capabilities": self._capabilities + "capabilities": self._capabilities, + "last_error": self._last_error } @asyncio.coroutine @@ -404,7 +406,7 @@ class Compute: Check if remote server is accessible """ - if not self._connected and not self._closed: + if not self._connected and not self._closed and self.host: try: log.info("Connecting to compute '{}'".format(self._id)) response = yield from self._run_http_query("GET", "/capabilities") @@ -428,16 +430,36 @@ class Compute: raise aiohttp.web.HTTPConflict(text="Invalid server url for server {}".format(self._id)) if "version" not in response.json: + msg = "The server {} is not a GNS3 server".format(self._id) + log.error(msg) self._http_session.close() - raise aiohttp.web.HTTPConflict(text="The server {} is not a GNS3 server".format(self._id)) + raise aiohttp.web.HTTPConflict(text=msg) self._capabilities = response.json - if parse_version(__version__)[:2] != parse_version(response.json["version"])[:2]: - self._http_session.close() - raise aiohttp.web.HTTPConflict(text="The server {} versions are not compatible {} != {}".format(self._id, __version__, response.json["version"])) + + if response.json["version"].split("-")[0] != __version__.split("-")[0]: + msg = "GNS3 controller version {} is not the same as compute server {} version {}".format(__version__, + self._name, + response.json["version"]) + if __version_info__[3] == 0: + # Stable release + log.error(msg) + self._http_session.close() + self._last_error = msg + raise aiohttp.web.HTTPConflict(text=msg) + elif parse_version(__version__)[:2] != parse_version(response.json["version"])[:2]: + # We don't allow different major version to interact even with dev build + log.error(msg) + self._http_session.close() + self._last_error = msg + raise aiohttp.web.HTTPConflict(text=msg) + else: + msg = "{}\nUsing different versions may result in unexpected problems. Please use at your own risk.".format(msg) + self._controller.notification.emit("log.warning", {"message": msg}) self._notifications = asyncio.gather(self._connect_notification()) self._connected = True self._connection_failure = 0 + self._last_error = None self._controller.notification.emit("compute.updated", self.__json__()) @asyncio.coroutine diff --git a/gns3server/controller/gns3vm/__init__.py b/gns3server/controller/gns3vm/__init__.py index acd9f7c3..7f5dcd76 100644 --- a/gns3server/controller/gns3vm/__init__.py +++ b/gns3server/controller/gns3vm/__init__.py @@ -336,6 +336,8 @@ class GNS3VM: self._controller.notification.emit("log.warning", {"message": msg}) except ComputeError as e: log.warning("Could not check the VM is in the same subnet as the local server: {}".format(e)) + except aiohttp.web.HTTPConflict as e: + log.warning("Could not check the VM is in the same subnet as the local server: {}".format(e.text)) @locked_coroutine def _suspend(self): diff --git a/gns3server/schemas/compute.py b/gns3server/schemas/compute.py index 2e8d08bc..c1ea3362 100644 --- a/gns3server/schemas/compute.py +++ b/gns3server/schemas/compute.py @@ -104,6 +104,10 @@ COMPUTE_OBJECT_SCHEMA = { "maximum": 100, "minimum": 0 }, + "last_error": { + "description": "Last error on the compute", + "type": ["string", "null"] + }, "capabilities": CAPABILITIES_SCHEMA }, "additionalProperties": False, diff --git a/gns3server/version.py b/gns3server/version.py index 84c99de2..3d8ef14e 100644 --- a/gns3server/version.py +++ b/gns3server/version.py @@ -23,7 +23,7 @@ # or negative for a release candidate or beta (after the base version # number has been incremented) -__version__ = "2.1.10dev1" +__version__ = "2.1.10dev2" __version_info__ = (2, 1, 10, 99) # If it's a git checkout try to add the commit diff --git a/tests/controller/test_compute.py b/tests/controller/test_compute.py index 47840bc9..98b0aa18 100644 --- a/tests/controller/test_compute.py +++ b/tests/controller/test_compute.py @@ -277,6 +277,7 @@ def test_json(compute): "cpu_usage_percent": None, "memory_usage_percent": None, "connected": True, + "last_error": None, "capabilities": { "version": None, "node_types": [] diff --git a/tests/handlers/api/controller/test_compute.py b/tests/handlers/api/controller/test_compute.py index 57cbdfb7..36b3f5ac 100644 --- a/tests/handlers/api/controller/test_compute.py +++ b/tests/handlers/api/controller/test_compute.py @@ -131,6 +131,7 @@ def test_compute_list(http_controller, controller): 'name': 'My super server', 'cpu_usage_percent': None, 'memory_usage_percent': None, + 'last_error': None, 'capabilities': { 'version': None, 'node_types': []