diff --git a/gns3server/modules/docker/docker_vm.py b/gns3server/modules/docker/docker_vm.py index a1d615de..dd21691b 100644 --- a/gns3server/modules/docker/docker_vm.py +++ b/gns3server/modules/docker/docker_vm.py @@ -34,7 +34,7 @@ from ..adapters.ethernet_adapter import EthernetAdapter from ..nios.nio_udp import NIOUDP from ...utils.asyncio.telnet_server import AsyncioTelnetServer from ...utils.asyncio import wait_for_file_creation - +from ...utils.get_resource import get_resource from ...ubridge.ubridge_error import UbridgeError, UbridgeNamespaceError @@ -156,6 +156,9 @@ class DockerVM(BaseVM): :returns: Return the path that we need to map to local folders """ binds = [] + + binds.append("{}:/gns3:ro".format(get_resource("modules/docker/resources"))) + volumes = image_infos.get("ContainerConfig", {}).get("Volumes") if volumes is None: return binds @@ -163,6 +166,7 @@ class DockerVM(BaseVM): source = os.path.join(self.working_dir, os.path.relpath(volume, "/")) os.makedirs(source, exist_ok=True) binds.append("{}:{}".format(source, volume)) + return binds @asyncio.coroutine @@ -190,10 +194,17 @@ class DockerVM(BaseVM): "Binds": self._mount_binds(image_infos) }, "Volumes": {}, - "Env": [] + "Env": [], + "Cmd": image_infos.get("ContainerConfig", {"Cmd": []})["Cmd"] } + + params["Cmd"].insert(0, "/bin/sh") + params["Cmd"].insert(1, "/gns3/init.sh") if self._start_command: - params.update({"Cmd": shlex.split(self._start_command)}) + params["Cmd"] += shlex.split(self._start_command) + else: + if len(params["Cmd"]) == 2: + params["Cmd"] += ["/bin/sh"] if self._environment: params["Env"] += [e.strip() for e in self._environment.split("\n")] diff --git a/gns3server/modules/docker/resources/init.sh b/gns3server/modules/docker/resources/init.sh new file mode 100644 index 00000000..d120e395 --- /dev/null +++ b/gns3server/modules/docker/resources/init.sh @@ -0,0 +1,46 @@ +#!/bin/sh +# +# Copyright (C) 2016 GNS3 Technologies Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# +# This script is injected into the container and launch before +# the start command of the container +# + +# Wait 2 seconds to settle the network interfaces +sleep 2 + +# /etc/hosts +[ -s /etc/hosts ] || cat > /etc/hosts << __EOF__ +127.0.1.1 $HOSTNAME +127.0.0.1 localhost +::1 localhost ip6-localhost ip6-loopback +fe00::0 ip6-localnet +ff00::0 ip6-mcastprefix +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters +__EOF__ + +# configure loopback interface +ip link set dev lo up + +# configure eth interfaces +sed -n 's/^ *\(eth[0-9]*\):.*/\1/p' < /proc/net/dev | while read dev; do + ip link set dev $dev up +done + +# continue normal docker startup +/bin/sh -c "$@" diff --git a/tests/modules/docker/test_docker_vm.py b/tests/modules/docker/test_docker_vm.py index 6c635692..0a21f255 100644 --- a/tests/modules/docker/test_docker_vm.py +++ b/tests/modules/docker/test_docker_vm.py @@ -25,6 +25,7 @@ from gns3server.ubridge.ubridge_error import UbridgeNamespaceError from gns3server.modules.docker.docker_vm import DockerVM from gns3server.modules.docker.docker_error import * from gns3server.modules.docker import Docker +from gns3server.utils.get_resource import get_resource from unittest.mock import patch, MagicMock, PropertyMock, call @@ -88,7 +89,7 @@ def test_create(loop, project, manager): "HostConfig": { "CapAdd": ["ALL"], - "Binds": [], + "Binds": ["{}:/gns3:ro".format(get_resource("modules/docker/resources"))], "Privileged": True }, "Volumes": {}, @@ -96,7 +97,8 @@ def test_create(loop, project, manager): "Name": "test", "Hostname": "test", "Image": "ubuntu", - "Env": [] + "Env": [], + "Cmd": ["/bin/sh", "/gns3/init.sh", "/bin/sh"] }) assert vm._cid == "e90e34656806" @@ -121,7 +123,10 @@ def test_create_vnc(loop, project, manager): "HostConfig": { "CapAdd": ["ALL"], - "Binds": ['/tmp/.X11-unix/:/tmp/.X11-unix/'], + "Binds": [ + "{}:/gns3:ro".format(get_resource("modules/docker/resources")), + '/tmp/.X11-unix/:/tmp/.X11-unix/' + ], "Privileged": True }, "Volumes": {}, @@ -129,7 +134,8 @@ def test_create_vnc(loop, project, manager): "Name": "test", "Hostname": "test", "Image": "ubuntu", - "Env": ['DISPLAY=:42'] + "Env": ['DISPLAY=:42'], + "Cmd": ["/bin/sh", "/gns3/init.sh", "/bin/sh"] }) assert vm._start_vnc.called assert vm._cid == "e90e34656806" @@ -153,11 +159,11 @@ def test_create_start_cmd(loop, project, manager): "HostConfig": { "CapAdd": ["ALL"], - "Binds": [], + "Binds": ["{}:/gns3:ro".format(get_resource("modules/docker/resources"))], "Privileged": True }, "Volumes": {}, - "Cmd": ["/bin/ls"], + "Cmd": ["/bin/sh", "/gns3/init.sh", "/bin/ls"], "NetworkDisabled": True, "Name": "test", "Hostname": "test", @@ -185,7 +191,7 @@ def test_create_environment(loop, project, manager): "HostConfig": { "CapAdd": ["ALL"], - "Binds": [], + "Binds": ["{}:/gns3:ro".format(get_resource("modules/docker/resources"))], "Privileged": True }, "Env": ["YES=1", "NO=0"], @@ -193,7 +199,8 @@ def test_create_environment(loop, project, manager): "NetworkDisabled": True, "Name": "test", "Hostname": "test", - "Image": "ubuntu" + "Image": "ubuntu", + "Cmd": ["/bin/sh", "/gns3/init.sh", "/bin/sh"] }) assert vm._cid == "e90e34656806" @@ -230,7 +237,7 @@ def test_create_image_not_available(loop, project, manager): "HostConfig": { "CapAdd": ["ALL"], - "Binds": [], + "Binds": ["{}:/gns3:ro".format(get_resource("modules/docker/resources"))], "Privileged": True }, "Volumes": {}, @@ -238,7 +245,8 @@ def test_create_image_not_available(loop, project, manager): "Name": "test", "Hostname": "test", "Image": "ubuntu", - "Env": [] + "Env": [], + "Cmd": ["/bin/sh", "/gns3/init.sh", "/bin/sh"] }) assert vm._cid == "e90e34656806" mock_pull.assert_called_with("ubuntu") @@ -439,7 +447,7 @@ def test_update(loop, vm): "HostConfig": { "CapAdd": ["ALL"], - "Binds": [], + "Binds": ["{}:/gns3:ro".format(get_resource("modules/docker/resources"))], "Privileged": True }, "Volumes": {}, @@ -447,7 +455,8 @@ def test_update(loop, vm): "Name": "test", "Hostname": "test", "Image": "ubuntu", - "Env": [] + "Env": [], + "Cmd": ["/bin/sh", "/gns3/init.sh", "/bin/sh"] }) assert vm.console == original_console @@ -475,7 +484,7 @@ def test_update_running(loop, vm): "HostConfig": { "CapAdd": ["ALL"], - "Binds": [], + "Binds": ["{}:/gns3:ro".format(get_resource("modules/docker/resources"))], "Privileged": True }, "Volumes": {}, @@ -483,7 +492,8 @@ def test_update_running(loop, vm): "Name": "test", "Hostname": "test", "Image": "ubuntu", - "Env": [] + "Env": [], + "Cmd": ["/bin/sh", "/gns3/init.sh", "/bin/sh"] }) assert vm.console == original_console @@ -745,6 +755,7 @@ def test_mount_binds(vm, tmpdir): dst = os.path.join(vm.working_dir, "test/experimental") assert vm._mount_binds(image_infos) == [ + "{}:/gns3:ro".format(get_resource("modules/docker/resources")), "{}:{}".format(dst, "/test/experimental") ]