diff --git a/README.rst b/README.rst index 90d977b8..11f2cab1 100644 --- a/README.rst +++ b/README.rst @@ -29,6 +29,11 @@ In addition of Python dependencies listed in a section below, other software may * mtools is recommended to support data transfer to/from QEMU VMs using virtual disks. * i386-libraries of libc and libcrypto are optional (Linux only), they are only needed to run IOU based nodes. +Docker support +************** + +Docker support needs the script program (`bsdutils` or `util-linux` package), when running a docker VM and a static busybox during installation (python3 setup.py install / pip3 install / package creation). + Branches -------- diff --git a/gns3server/compute/docker/docker_vm.py b/gns3server/compute/docker/docker_vm.py index 7fbebda2..30612f5e 100644 --- a/gns3server/compute/docker/docker_vm.py +++ b/gns3server/compute/docker/docker_vm.py @@ -520,10 +520,14 @@ class DockerVM(BaseNode): # https://github.com/GNS3/gns3-gui/issues/1039 try: process = await asyncio.subprocess.create_subprocess_exec( - "docker", "exec", "-i", self._cid, "/gns3/bin/busybox", "script", "-qfc", "while true; do TERM=vt100 /gns3/bin/busybox sh; done", "/dev/null", + "script", + "-qfc", + f"docker exec -i -t {self._cid} /gns3/bin/busybox sh -c 'while true; do TERM=vt100 /gns3/bin/busybox sh; done'", + "/dev/null", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT, - stdin=asyncio.subprocess.PIPE) + stdin=asyncio.subprocess.PIPE + ) except OSError as e: raise DockerError("Could not start auxiliary console process: {}".format(e)) server = AsyncioTelnetServer(reader=process.stdout, writer=process.stdin, binary=True, echo=True) diff --git a/gns3server/compute/docker/resources/bin/busybox b/gns3server/compute/docker/resources/bin/busybox deleted file mode 100755 index 68ebef5e..00000000 Binary files a/gns3server/compute/docker/resources/bin/busybox and /dev/null differ diff --git a/gns3server/compute/docker/resources/bin/udhcpc b/gns3server/compute/docker/resources/bin/udhcpc new file mode 100644 index 00000000..16c064d0 --- /dev/null +++ b/gns3server/compute/docker/resources/bin/udhcpc @@ -0,0 +1,15 @@ +#!/gns3/bin/busybox sh + +SCRIPT="/gns3/etc/udhcpc/default.script" + +if [ "$(cat "/proc/$PPID/comm" 2>/dev/null)" = ifup ]; then + # remove "-n" argument + for arg do + shift + [ "$arg" = "-n" ] || set -- "$@" "$arg" + done + # add default parameters + set -- -t 3 -T 2 -A 1 -b "$@" +fi + +exec /tmp/gns3/bin/udhcpc -s "$SCRIPT" "$@" diff --git a/setup.py b/setup.py index 17cbbb42..9b0a8655 100644 --- a/setup.py +++ b/setup.py @@ -16,6 +16,10 @@ # along with this program. If not, see . import sys +import os +import shutil +import subprocess + from setuptools import setup, find_packages from setuptools.command.test import test as TestCommand @@ -39,6 +43,28 @@ class PyTest(TestCommand): sys.exit(errcode) +BUSYBOX_PATH = "gns3server/compute/docker/resources/bin/busybox" + + +def copy_busybox(): + if not sys.platform.startswith("linux"): + return + if os.path.isfile(BUSYBOX_PATH): + return + for bb_cmd in ("busybox-static", "busybox.static", "busybox"): + bb_path = shutil.which(bb_cmd) + if bb_path: + if subprocess.call(["ldd", bb_path], + stdin=subprocess.DEVNULL, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL): + shutil.copy2(bb_path, BUSYBOX_PATH, follow_symlinks=True) + break + else: + raise SystemExit("No static busybox found") + + +copy_busybox() dependencies = open("requirements.txt", "r").read().splitlines() setup( diff --git a/tests/compute/docker/test_docker_vm.py b/tests/compute/docker/test_docker_vm.py index 1effa9b0..4ea89dff 100644 --- a/tests/compute/docker/test_docker_vm.py +++ b/tests/compute/docker/test_docker_vm.py @@ -1343,7 +1343,15 @@ async def test_start_aux(vm): with asyncio_patch("asyncio.subprocess.create_subprocess_exec", return_value=MagicMock()) as mock_exec: await vm._start_aux() - mock_exec.assert_called_with('docker', 'exec', '-i', 'e90e34656842', '/gns3/bin/busybox', 'script', '-qfc', 'while true; do TERM=vt100 /gns3/bin/busybox sh; done', '/dev/null', stderr=asyncio.subprocess.STDOUT, stdin=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE) + mock_exec.assert_called_with( + "script", + "-qfc", + "docker exec -i -t e90e34656842 /gns3/bin/busybox sh -c 'while true; do TERM=vt100 /gns3/bin/busybox sh; done'", + "/dev/null", + stderr=asyncio.subprocess.STDOUT, + stdin=asyncio.subprocess.PIPE, + stdout=asyncio.subprocess.PIPE + ) async def test_create_network_interfaces(vm):