diff --git a/gns3server/modules/docker/docker_vm.py b/gns3server/modules/docker/docker_vm.py index 3ae58910..85d74cf9 100644 --- a/gns3server/modules/docker/docker_vm.py +++ b/gns3server/modules/docker/docker_vm.py @@ -159,6 +159,10 @@ class DockerVM(BaseVM): binds.append("{}:/gns3:ro".format(get_resource("modules/docker/resources"))) + # We mount our own etc/network + network_config = self._create_network_config() + binds.append("{}:/etc/network:rw".format(network_config)) + volumes = image_infos.get("ContainerConfig", {}).get("Volumes") if volumes is None: return binds @@ -169,6 +173,37 @@ class DockerVM(BaseVM): return binds + def _create_network_config(self): + """ + If network config is empty we create a sample config + """ + path = os.path.join(self.working_dir, "etc", "network") + os.makedirs(path, exist_ok=True) + os.makedirs(os.path.join(path, "if-up.d")) + os.makedirs(os.path.join(path, "if-down.d")) + + if not os.path.exists(os.path.join(path, "interfaces")): + with open(os.path.join(path, "interfaces"), "w+") as f: + f.write("""# +# This is a sample network config uncomment lines to configure the network +# + +""") + for adapter in range(0, self.adapters): + f.write(""" +# Static config for eth{adapter} +#auto eth{adapter} +#iface eth{adapter} inet static +#\taddress 192.168.{adapter}.2 +#\tnetmask 255.255.255.0 +#\tgateway 192.168.{adapter}.1 +#\tup echo nameserver 192.168.{adapter}.1 > /etc/resolv.conf + +# DHCP config for eth{adapter} +# auto eth{adapter} +# iface eth{adapter} inet dhcp""".format(adapter=adapter)) + return path + @asyncio.coroutine def create(self): """Creates the Docker container.""" @@ -199,7 +234,6 @@ class DockerVM(BaseVM): "Entrypoint": image_infos.get("Config", {"Entrypoint": []})["Entrypoint"] } - if params["Entrypoint"] is None: params["Entrypoint"] = [] if self._start_command: @@ -287,7 +321,7 @@ class DockerVM(BaseVM): # We can not use the API because docker doesn't expose a websocket api for exec # https://github.com/GNS3/gns3-gui/issues/1039 process = yield from asyncio.subprocess.create_subprocess_exec( - "docker", "exec", "-i", self._cid, "/bin/sh", "-i", + "docker", "exec", "-i", self._cid, "/gns3/bin/busybox", "sh", "-i", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT, stdin=asyncio.subprocess.PIPE) diff --git a/gns3server/modules/docker/resources/bin/busybox b/gns3server/modules/docker/resources/bin/busybox index e6ac1ed3..a9acbe24 100755 Binary files a/gns3server/modules/docker/resources/bin/busybox and b/gns3server/modules/docker/resources/bin/busybox differ diff --git a/gns3server/modules/docker/resources/init.sh b/gns3server/modules/docker/resources/init.sh index 091be2fb..bdaa1c42 100755 --- a/gns3server/modules/docker/resources/init.sh +++ b/gns3server/modules/docker/resources/init.sh @@ -52,12 +52,8 @@ sed -n 's/^ *\(eth[0-9]*\):.*/\1/p' < /proc/net/dev | while read dev; do ip link set dev $dev up done -if [ -n "$INTERFACES" ]; then - mkdir -p /etc/network/if-up.d /etc/network/if-pre-up.d - mkdir -p /etc/network/if-down.d /etc/network/if-post-down.d - echo -e "$INTERFACES" > /etc/network/interfaces - ifup -a -f -fi + +ifup -a -f # continue normal docker startup PATH="$OLD_PATH" diff --git a/tests/modules/docker/test_docker_vm.py b/tests/modules/docker/test_docker_vm.py index 2d6113f5..0a6a3a82 100644 --- a/tests/modules/docker/test_docker_vm.py +++ b/tests/modules/docker/test_docker_vm.py @@ -89,7 +89,10 @@ def test_create(loop, project, manager): "HostConfig": { "CapAdd": ["ALL"], - "Binds": ["{}:/gns3:ro".format(get_resource("modules/docker/resources"))], + "Binds": [ + "{}:/gns3:ro".format(get_resource("modules/docker/resources")), + "{}:/etc/network:rw".format(os.path.join(vm.working_dir, "etc", "network")) + ], "Privileged": True }, "Volumes": {}, @@ -126,6 +129,7 @@ def test_create_vnc(loop, project, manager): "CapAdd": ["ALL"], "Binds": [ "{}:/gns3:ro".format(get_resource("modules/docker/resources")), + "{}:/etc/network:rw".format(os.path.join(vm.working_dir, "etc", "network")), '/tmp/.X11-unix/:/tmp/.X11-unix/' ], "Privileged": True @@ -161,7 +165,10 @@ def test_create_start_cmd(loop, project, manager): "HostConfig": { "CapAdd": ["ALL"], - "Binds": ["{}:/gns3:ro".format(get_resource("modules/docker/resources"))], + "Binds": [ + "{}:/gns3:ro".format(get_resource("modules/docker/resources")), + "{}:/etc/network:rw".format(os.path.join(vm.working_dir, "etc", "network")) + ], "Privileged": True }, "Volumes": {}, @@ -194,7 +201,10 @@ def test_create_environment(loop, project, manager): "HostConfig": { "CapAdd": ["ALL"], - "Binds": ["{}:/gns3:ro".format(get_resource("modules/docker/resources"))], + "Binds": [ + "{}:/gns3:ro".format(get_resource("modules/docker/resources")), + "{}:/etc/network:rw".format(os.path.join(vm.working_dir, "etc", "network")) + ], "Privileged": True }, "Env": ["YES=1", "NO=0"], @@ -241,7 +251,10 @@ def test_create_image_not_available(loop, project, manager): "HostConfig": { "CapAdd": ["ALL"], - "Binds": ["{}:/gns3:ro".format(get_resource("modules/docker/resources"))], + "Binds": [ + "{}:/gns3:ro".format(get_resource("modules/docker/resources")), + "{}:/etc/network:rw".format(os.path.join(vm.working_dir, "etc", "network")) + ], "Privileged": True }, "Volumes": {}, @@ -452,7 +465,10 @@ def test_update(loop, vm): "HostConfig": { "CapAdd": ["ALL"], - "Binds": ["{}:/gns3:ro".format(get_resource("modules/docker/resources"))], + "Binds": [ + "{}:/gns3:ro".format(get_resource("modules/docker/resources")), + "{}:/etc/network:rw".format(os.path.join(vm.working_dir, "etc", "network")) + ], "Privileged": True }, "Volumes": {}, @@ -490,7 +506,10 @@ def test_update_running(loop, vm): "HostConfig": { "CapAdd": ["ALL"], - "Binds": ["{}:/gns3:ro".format(get_resource("modules/docker/resources"))], + "Binds": [ + "{}:/gns3:ro".format(get_resource("modules/docker/resources")), + "{}:/etc/network:rw".format(os.path.join(vm.working_dir, "etc", "network")) + ], "Privileged": True }, "Volumes": {}, @@ -763,6 +782,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")), + "{}:/etc/network:rw".format(os.path.join(vm.working_dir, "etc", "network")), "{}:{}".format(dst, "/test/experimental") ] @@ -789,3 +809,17 @@ def test_start_aux(vm, loop): with asyncio_patch("asyncio.subprocess.create_subprocess_exec", return_value=MagicMock()) as mock_exec: loop.run_until_complete(asyncio.async(vm._start_aux())) + + +def test_create_network_interfaces(vm): + + vm.adapters = 5 + network_config = vm._create_network_config() + assert os.path.exists(os.path.join(network_config, "interfaces")) + assert os.path.exists(os.path.join(network_config, "if-up.d")) + + with open(os.path.join(network_config, "interfaces")) as f: + content = f.read() + assert "eth0" in content + assert "eth4" in content + assert "eth5" not in content