mirror of
https://github.com/GNS3/gns3-server
synced 2024-11-28 19:28:07 +00:00
Merge pull request #1105 from GNS3/bugfix-2136
Bugfix 2136 (gui) issue with UTF-8 characters and Docker
This commit is contained in:
commit
d17b4eb053
@ -36,6 +36,7 @@ log = logging.getLogger(__name__)
|
|||||||
# Be carefull to keep it consistent
|
# Be carefull to keep it consistent
|
||||||
DOCKER_MINIMUM_API_VERSION = "1.25"
|
DOCKER_MINIMUM_API_VERSION = "1.25"
|
||||||
DOCKER_MINIMUM_VERSION = "1.13"
|
DOCKER_MINIMUM_VERSION = "1.13"
|
||||||
|
DOCKER_PREFERRED_API_VERSION = "1.30"
|
||||||
|
|
||||||
|
|
||||||
class Docker(BaseManager):
|
class Docker(BaseManager):
|
||||||
@ -50,6 +51,7 @@ class Docker(BaseManager):
|
|||||||
self.ubridge_lock = asyncio.Lock()
|
self.ubridge_lock = asyncio.Lock()
|
||||||
self._connector = None
|
self._connector = None
|
||||||
self._session = None
|
self._session = None
|
||||||
|
self._api_version = DOCKER_MINIMUM_API_VERSION
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def _check_connection(self):
|
def _check_connection(self):
|
||||||
@ -61,8 +63,17 @@ class Docker(BaseManager):
|
|||||||
except (aiohttp.errors.ClientOSError, FileNotFoundError):
|
except (aiohttp.errors.ClientOSError, FileNotFoundError):
|
||||||
self._connected = False
|
self._connected = False
|
||||||
raise DockerError("Can't connect to docker daemon")
|
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):
|
def connector(self):
|
||||||
if self._connector is None or self._connector.closed:
|
if self._connector is None or self._connector.closed:
|
||||||
@ -165,7 +176,7 @@ class Docker(BaseManager):
|
|||||||
:returns: Websocket
|
: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,
|
connection = yield from aiohttp.ws_connect(url,
|
||||||
connector=self.connector(),
|
connector=self.connector(),
|
||||||
origin="http://docker",
|
origin="http://docker",
|
||||||
|
@ -500,8 +500,12 @@ class DockerVM(BaseNode):
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
msg = yield from ws.receive()
|
msg = yield from ws.receive()
|
||||||
if msg.tp == aiohttp.MsgType.text:
|
if msg.tp == aiohttp.MsgType.TEXT:
|
||||||
out.feed_data(msg.data.encode())
|
out.feed_data(msg.data.encode())
|
||||||
|
if msg.tp == aiohttp.MsgType.BINARY:
|
||||||
|
out.feed_data(msg.data)
|
||||||
|
elif msg.tp == aiohttp.MsgType.ERROR:
|
||||||
|
log.critical("Docker WebSocket Error: {}".format(msg.data))
|
||||||
else:
|
else:
|
||||||
out.feed_eof()
|
out.feed_eof()
|
||||||
ws.close()
|
ws.close()
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import asyncio
|
import asyncio
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
from tests.utils import asyncio_patch, AsyncioMagicMock
|
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
|
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:
|
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")))
|
images = loop.run_until_complete(asyncio.async(Docker.instance().pull_image("ubuntu")))
|
||||||
mock.assert_called_with("POST", "images/create", params={"fromImage": "ubuntu"}, timeout=None)
|
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
|
@ -20,6 +20,7 @@ import pytest
|
|||||||
import uuid
|
import uuid
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
from aiohttp._ws_impl import WSMsgType
|
||||||
from tests.utils import asyncio_patch, AsyncioMagicMock
|
from tests.utils import asyncio_patch, AsyncioMagicMock
|
||||||
|
|
||||||
from gns3server.ubridge.ubridge_error import UbridgeNamespaceError
|
from gns3server.ubridge.ubridge_error import UbridgeNamespaceError
|
||||||
@ -904,3 +905,27 @@ def test_fix_permission(vm, loop):
|
|||||||
loop.run_until_complete(vm._fix_permissions())
|
loop.run_until_complete(vm._fix_permissions())
|
||||||
mock_exec.assert_called_with('docker', 'exec', 'e90e34656842', '/gns3/bin/busybox', 'sh', '-c', '(/gns3/bin/busybox find "/etc" -depth -print0 | /gns3/bin/busybox xargs -0 /gns3/bin/busybox stat -c \'%a:%u:%g:%n\' > "/etc/.gns3_perms") && /gns3/bin/busybox chmod -R u+rX "/etc" && /gns3/bin/busybox chown {}:{} -R "/etc"'.format(os.getuid(), os.getgid()))
|
mock_exec.assert_called_with('docker', 'exec', 'e90e34656842', '/gns3/bin/busybox', 'sh', '-c', '(/gns3/bin/busybox find "/etc" -depth -print0 | /gns3/bin/busybox xargs -0 /gns3/bin/busybox stat -c \'%a:%u:%g:%n\' > "/etc/.gns3_perms") && /gns3/bin/busybox chmod -R u+rX "/etc" && /gns3/bin/busybox chown {}:{} -R "/etc"'.format(os.getuid(), os.getgid()))
|
||||||
assert process.wait.called
|
assert process.wait.called
|
||||||
|
|
||||||
|
|
||||||
|
def test_read_console_output_with_binary_mode(vm, loop):
|
||||||
|
class InputStreamMock(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.sent = False
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def receive(self):
|
||||||
|
if not self.sent:
|
||||||
|
self.sent = True
|
||||||
|
return MagicMock(tp=WSMsgType.BINARY, data=b"test")
|
||||||
|
else:
|
||||||
|
return MagicMock(tp=WSMsgType.CLOSE)
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
input_stream = InputStreamMock()
|
||||||
|
output_stream = MagicMock()
|
||||||
|
|
||||||
|
with asyncio_patch('gns3server.compute.docker.docker_vm.DockerVM.stop'):
|
||||||
|
loop.run_until_complete(asyncio.async(vm._read_console_output(input_stream, output_stream)))
|
||||||
|
output_stream.feed_data.assert_called_once_with(b"test")
|
||||||
|
Loading…
Reference in New Issue
Block a user