diff --git a/gns3server/compute/docker/__init__.py b/gns3server/compute/docker/__init__.py index 18ad331f..b85f473a 100644 --- a/gns3server/compute/docker/__init__.py +++ b/gns3server/compute/docker/__init__.py @@ -36,6 +36,7 @@ log = logging.getLogger(__name__) # Be carefull to keep it consistent DOCKER_MINIMUM_API_VERSION = "1.25" DOCKER_MINIMUM_VERSION = "1.13" +DOCKER_PREFERRED_API_VERSION = "1.30" class Docker(BaseManager): @@ -50,6 +51,7 @@ class Docker(BaseManager): self.ubridge_lock = asyncio.Lock() self._connector = None self._session = None + self._api_version = DOCKER_MINIMUM_API_VERSION @asyncio.coroutine def _check_connection(self): @@ -61,8 +63,17 @@ class Docker(BaseManager): except (aiohttp.errors.ClientOSError, FileNotFoundError): self._connected = False raise DockerError("Can't connect to docker daemon") - if parse_version(version["ApiVersion"]) < parse_version(DOCKER_MINIMUM_API_VERSION): - raise DockerError("Docker version is {}. GNS3 requires a minimum version of {}".format(version["Version"], DOCKER_MINIMUM_VERSION)) + + docker_version = parse_version(version['ApiVersion']) + + if docker_version < parse_version(DOCKER_MINIMUM_API_VERSION): + raise DockerError( + "Docker version is {}. GNS3 requires a minimum version of {}".format( + version["Version"], DOCKER_MINIMUM_VERSION)) + + preferred_api_version = parse_version(DOCKER_PREFERRED_API_VERSION) + if docker_version >= preferred_api_version: + self._api_version = DOCKER_PREFERRED_API_VERSION def connector(self): if self._connector is None or self._connector.closed: @@ -165,7 +176,7 @@ class Docker(BaseManager): :returns: Websocket """ - url = "http://docker/v" + DOCKER_MINIMUM_API_VERSION + "/" + path + url = "http://docker/v" + self._api_version + "/" + path connection = yield from aiohttp.ws_connect(url, connector=self.connector(), origin="http://docker", diff --git a/tests/compute/docker/test_docker.py b/tests/compute/docker/test_docker.py index 095a25de..db43c84c 100644 --- a/tests/compute/docker/test_docker.py +++ b/tests/compute/docker/test_docker.py @@ -17,10 +17,10 @@ import pytest import asyncio -from unittest.mock import MagicMock +from unittest.mock import MagicMock, patch from tests.utils import asyncio_patch, AsyncioMagicMock -from gns3server.compute.docker import Docker +from gns3server.compute.docker import Docker, DOCKER_PREFERRED_API_VERSION, DOCKER_MINIMUM_API_VERSION from gns3server.compute.docker.docker_error import DockerError, DockerHttp404Error @@ -162,3 +162,40 @@ def test_pull_image(loop): with asyncio_patch("gns3server.compute.docker.Docker.http_query", return_value=mock_query) as mock: images = loop.run_until_complete(asyncio.async(Docker.instance().pull_image("ubuntu"))) mock.assert_called_with("POST", "images/create", params={"fromImage": "ubuntu"}, timeout=None) + + +def test_docker_check_connection_docker_minimum_version(vm, loop): + response = { + 'ApiVersion': '1.01', + 'Version': '1.12' + } + + with patch("gns3server.compute.docker.Docker.connector"), \ + asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response): + vm._connected = False + with pytest.raises(DockerError): + loop.run_until_complete(asyncio.async(vm._check_connection())) + + +def test_docker_check_connection_docker_preferred_version_against_newer(vm, loop): + response = { + 'ApiVersion': '1.31' + } + + with patch("gns3server.compute.docker.Docker.connector"), \ + asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response): + vm._connected = False + loop.run_until_complete(asyncio.async(vm._check_connection())) + assert vm._api_version == DOCKER_PREFERRED_API_VERSION + + +def test_docker_check_connection_docker_preferred_version_against_older(vm, loop): + response = { + 'ApiVersion': '1.27', + } + + with patch("gns3server.compute.docker.Docker.connector"), \ + asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response): + vm._connected = False + loop.run_until_complete(asyncio.async(vm._check_connection())) + assert vm._api_version == DOCKER_MINIMUM_API_VERSION \ No newline at end of file