def _mount_binds(self, image_info): """ :returns: Return the path that we need to map to local folders """ resources = get_resource("compute/docker/resources") if not os.path.exists(resources): raise DockerError("{} is missing can't start Docker containers".format(resources)) binds = ["{}:/gns3:ro".format(resources)] # We mount our own etc/network try: network_config = self._create_network_config() except OSError as e: raise DockerError("Could not create network config in the container: {}".format(e)) binds.append("{}:/gns3volumes/etc/network:rw".format(network_config)) self._volumes = ["/etc/network"] volumes = list((image_info.get("Config", {}).get("Volumes") or {}).keys()) for volume in self._extra_volumes: if not volume.strip() or volume[0] != "/" or volume.find("..") >= 0: raise DockerError("Persistent volume '{}' has invalid format. It must start with a '/' and not contain '..'.".format(volume)) volumes.extend(self._extra_volumes) # define lambdas for validation checks nf = lambda x: re.sub(r"//+", "/", (x if x.endswith("/") else x + "/")) incompatible = lambda v1, v2: nf(v1).startswith(nf(v2)) or nf(v2).startswith(nf(v1)) for volume in volumes: if [ v for v in self._volumes if incompatible(v, volume) ] : raise DockerError("Duplicate persistent volume {} detected.\n\nVolumes specified in docker image as well as user specified persistent volumes must be unique.".format(volume)) source = os.path.join(self.working_dir, os.path.relpath(volume, "/")) os.makedirs(source, exist_ok=True) binds.append("{}:/gns3volumes{}".format(source, volume)) self._volumes.append(volume) return binds
def _mount_binds(self, image_infos): """ :returns: Return the path that we need to map to local folders """ ressources = get_resource("compute/docker/resources") if not os.path.exists(ressources): raise DockerError("{} is missing can't start Docker containers".format(ressources)) binds = ["{}:/gns3:ro".format(ressources)] # We mount our own etc/network network_config = self._create_network_config() binds.append("{}:/gns3volumes/etc/network:rw".format(network_config)) self._volumes = ["/etc/network"] volumes = image_infos.get("Config", {}).get("Volumes") if volumes is None: return binds for volume in volumes.keys(): source = os.path.join(self.working_dir, os.path.relpath(volume, "/")) os.makedirs(source, exist_ok=True) binds.append("{}:/gns3volumes{}".format(source, volume)) self._volumes.append(volume) return binds
def _mount_binds(self, image_infos): """ :returns: Return the path that we need to map to local folders """ ressources = get_resource("compute/docker/resources") if not os.path.exists(ressources): raise DockerError( "{} is missing can't start Docker containers".format( ressources)) binds = ["{}:/gns3:ro".format(ressources)] # We mount our own etc/network network_config = self._create_network_config() binds.append("{}:/gns3volumes/etc/network:rw".format(network_config)) self._volumes = ["/etc/network"] volumes = image_infos.get("Config", {}).get("Volumes") if volumes is None: return binds for volume in volumes.keys(): source = os.path.join(self.working_dir, os.path.relpath(volume, "/")) os.makedirs(source, exist_ok=True) binds.append("{}:/gns3volumes{}".format(source, volume)) self._volumes.append(volume) return binds
def test_create_environment(loop, project, manager): """ Allow user to pass an environnement. User can't override our internal variables """ response = {"Id": "e90e34656806", "Warnings": []} with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{ "image": "ubuntu" }]): with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu") vm.environment = "YES=1\nNO=0\nGNS3_MAX_ETHERNET=eth2" loop.run_until_complete(asyncio. async (vm.create())) mock.assert_called_with( "POST", "containers/create", data={ "Tty": True, "OpenStdin": True, "StdinOnce": False, "HostConfig": { "CapAdd": ["ALL"], "Binds": [ "{}:/gns3:ro".format( get_resource("compute/docker/resources")), "{}:/gns3volumes/etc/network:rw".format( os.path.join(vm.working_dir, "etc", "network")) ], "Privileged": True }, "Env": [ "container=docker", "GNS3_MAX_ETHERNET=eth0", "GNS3_VOLUMES=/etc/network", "YES=1", "NO=0" ], "Volumes": {}, "NetworkDisabled": True, "Name": "test", "Hostname": "test", "Image": "ubuntu:latest", "Entrypoint": ["/gns3/init.sh"], "Cmd": ["/bin/sh"] }) assert vm._cid == "e90e34656806"
async def webui(request, response): filename = request.match_info["filename"] filename = os.path.normpath(filename).strip("/") filename = os.path.join('static', 'web-ui', filename) # Raise error if user try to escape if filename[0] == ".": raise aiohttp.web.HTTPForbidden() static = get_resource(filename) if static is None or not os.path.exists(static): static = get_resource(os.path.join('static', 'web-ui', 'index.html')) # guesstype prefers to have text/html type than application/javascript # which results with warnings in Firefox 66 on Windows # Ref. gns3-server#1559 _, ext = os.path.splitext(static) mimetype = ext == '.js' and 'application/javascript' or None await response.stream_file(static, status=200, set_content_type=mimetype)
def test_create_image_not_available(loop, project, manager): call = 0 @asyncio.coroutine def informations(): nonlocal call if call == 0: call += 1 raise DockerHttp404Error("missing") else: return {} response = { "Id": "e90e34656806", "Warnings": [] } vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu:latest") vm._get_image_informations = MagicMock() vm._get_image_informations.side_effect = informations with asyncio_patch("gns3server.modules.docker.DockerVM.pull_image", return_value=True) as mock_pull: with asyncio_patch("gns3server.modules.docker.Docker.query", return_value=response) as mock: loop.run_until_complete(asyncio.async(vm.create())) mock.assert_called_with("POST", "containers/create", data={ "Tty": True, "OpenStdin": True, "StdinOnce": False, "HostConfig": { "CapAdd": ["ALL"], "Binds": [ "{}:/gns3:ro".format(get_resource("modules/docker/resources")), "{}:/gns3volumes/etc/network:rw".format(os.path.join(vm.working_dir, "etc", "network")) ], "Privileged": True }, "Volumes": {}, "NetworkDisabled": True, "Name": "test", "Hostname": "test", "Image": "ubuntu:latest", "Env": [ "container=docker", "GNS3_MAX_ETHERNET=eth0", "GNS3_VOLUMES=/etc/network" ], "Entrypoint": ["/gns3/init.sh"], "Cmd": ["/bin/sh"] }) assert vm._cid == "e90e34656806" mock_pull.assert_called_with("ubuntu:latest")
async def webui(request, response): filename = request.match_info["filename"] filename = os.path.normpath(filename).strip("/") filename = os.path.join('static', 'web-ui', filename) # Raise error if user try to escape if filename[0] == "." or '/../' in filename: raise aiohttp.web.HTTPForbidden() static = get_resource(filename) if static is None or not os.path.exists(static): static = get_resource(os.path.join('static', 'web-ui', 'index.html')) # guesstype prefers to have text/html type than application/javascript # which results with warnings in Firefox 66 on Windows # Ref. gns3-server#1559 _, ext = os.path.splitext(static) mimetype = ext == '.js' and 'application/javascript' or None await response.stream_file(static, status=200, set_content_type=mimetype)
def test_create_image_not_available(loop, project, manager): call = 0 @asyncio.coroutine def information(): nonlocal call if call == 0: call += 1 raise DockerHttp404Error("missing") else: return {} response = { "Id": "e90e34656806", "Warnings": [] } vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu") vm._get_image_information = MagicMock() vm._get_image_information.side_effect = information with asyncio_patch("gns3server.compute.docker.DockerVM.pull_image", return_value=True) as mock_pull: with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: loop.run_until_complete(asyncio.async(vm.create())) mock.assert_called_with("POST", "containers/create", data={ "Tty": True, "OpenStdin": True, "StdinOnce": False, "HostConfig": { "CapAdd": ["ALL"], "Binds": [ "{}:/gns3:ro".format(get_resource("compute/docker/resources")), "{}:/gns3volumes/etc/network:rw".format(os.path.join(vm.working_dir, "etc", "network")) ], "Privileged": True }, "Volumes": {}, "NetworkDisabled": True, "Name": "test", "Hostname": "test", "Image": "ubuntu:latest", "Env": [ "container=docker", "GNS3_MAX_ETHERNET=eth0", "GNS3_VOLUMES=/etc/network" ], "Entrypoint": ["/gns3/init.sh"], "Cmd": ["/bin/sh"] }) assert vm._cid == "e90e34656806" mock_pull.assert_called_with("ubuntu:latest")
def test_mount_binds(vm, tmpdir): image_infos = {"Config": {"Volumes": {"/test/experimental": {}}}} dst = os.path.join(vm.working_dir, "test/experimental") assert vm._mount_binds(image_infos) == [ "{}:/gns3:ro".format(get_resource("compute/docker/resources")), "{}:/gns3volumes/etc/network:rw".format( os.path.join(vm.working_dir, "etc", "network")), "{}:/gns3volumes{}".format(dst, "/test/experimental") ] assert vm._volumes == ["/etc/network", "/test/experimental"] assert os.path.exists(dst)
def test_create_start_cmd(loop, project, manager): response = {"Id": "e90e34656806", "Warnings": []} with asyncio_patch("gns3server.modules.docker.Docker.list_images", return_value=[{ "image": "ubuntu:latest" }]) as mock_list_images: with asyncio_patch("gns3server.modules.docker.Docker.query", return_value=response) as mock: vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu:latest") vm._start_command = "/bin/ls" loop.run_until_complete(asyncio. async (vm.create())) mock.assert_called_with( "POST", "containers/create", data={ "Tty": True, "OpenStdin": True, "StdinOnce": False, "HostConfig": { "CapAdd": ["ALL"], "Binds": [ "{}:/gns3:ro".format( get_resource("modules/docker/resources")), "{}:/gns3volumes/etc/network:rw".format( os.path.join(vm.working_dir, "etc", "network")) ], "Privileged": True }, "Volumes": {}, "Entrypoint": ["/gns3/init.sh"], "Cmd": ["/bin/ls"], "NetworkDisabled": True, "Name": "test", "Hostname": "test", "Image": "ubuntu:latest", "Env": [ "container=docker", "GNS3_MAX_ETHERNET=eth0", "GNS3_VOLUMES=/etc/network" ] }) assert vm._cid == "e90e34656806"
def _mount_binds(self, image_info): """ :returns: Return the path that we need to map to local folders """ resources = get_resource("compute/docker/resources") if not os.path.exists(resources): raise DockerError( "{} is missing can't start Docker containers".format( resources)) binds = ["{}:/gns3:ro".format(resources)] # We mount our own etc/network try: self._create_network_config() except OSError as e: raise DockerError( "Could not create network config in the container: {}".format( e)) volumes = ["/etc/network"] volumes.extend((image_info.get("Config", {}).get("Volumes") or {}).keys()) for volume in self._extra_volumes: if not volume.strip() or volume[0] != "/" or volume.find( "..") >= 0: raise DockerError( "Persistent volume '{}' has invalid format. It must start with a '/' and not contain '..'." .format(volume)) volumes.extend(self._extra_volumes) self._volumes = [] # define lambdas for validation checks nf = lambda x: re.sub(r"//+", "/", (x if x.endswith("/") else x + "/")) generalises = lambda v1, v2: nf(v2).startswith(nf(v1)) for volume in volumes: # remove any mount that is equal or more specific, then append this one self._volumes = list( filter(lambda v: not generalises(volume, v), self._volumes)) # if there is nothing more general, append this mount if not [v for v in self._volumes if generalises(v, volume)]: self._volumes.append(volume) for volume in self._volumes: source = os.path.join(self.working_dir, os.path.relpath(volume, "/")) os.makedirs(source, exist_ok=True) binds.append("{}:/gns3volumes{}".format(source, volume)) return binds
def _mount_binds(self, image_info): """ :returns: Return the path that we need to map to local folders """ resources = get_resource("compute/docker/resources") if not os.path.exists(resources): raise DockerError( "{} is missing can't start Docker containers".format( resources)) binds = ["{}:/gns3:ro".format(resources)] # We mount our own etc/network try: network_config = self._create_network_config() except OSError as e: raise DockerError( "Could not create network config in the container: {}".format( e)) binds.append("{}:/gns3volumes/etc/network:rw".format(network_config)) self._volumes = ["/etc/network"] volumes = list((image_info.get("Config", {}).get("Volumes") or {}).keys()) for volume in self._extra_volumes: if not volume.strip() or volume[0] != "/" or volume.find( "..") >= 0: raise DockerError( "Persistent volume '{}' has invalid format. It must start with a '/' and not contain '..'." .format(volume)) volumes.extend(self._extra_volumes) # define lambdas for validation checks nf = lambda x: re.sub(r"//+", "/", (x if x.endswith("/") else x + "/")) incompatible = lambda v1, v2: nf(v1).startswith(nf(v2)) or nf( v2).startswith(nf(v1)) for volume in volumes: if [v for v in self._volumes if incompatible(v, volume)]: raise DockerError( "Duplicate persistent volume {} detected.\n\nVolumes specified in docker image as well as user specified persistent volumes must be unique." .format(volume)) source = os.path.join(self.working_dir, os.path.relpath(volume, "/")) os.makedirs(source, exist_ok=True) binds.append("{}:/gns3volumes{}".format(source, volume)) self._volumes.append(volume) return binds
def test_create_vnc(loop, project, manager): response = { "Id": "e90e34656806", "Warnings": [] } with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "ubuntu"}]) as mock_list_images: with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu", console_type="vnc", console=5900) vm._start_vnc = MagicMock() vm._display = 42 loop.run_until_complete(asyncio.async(vm.create())) mock.assert_called_with("POST", "containers/create", data={ "Tty": True, "OpenStdin": True, "StdinOnce": False, "HostConfig": { "CapAdd": ["ALL"], "Binds": [ "{}:/gns3:ro".format(get_resource("compute/docker/resources")), "{}:/gns3volumes/etc/network:rw".format(os.path.join(vm.working_dir, "etc", "network")), '/tmp/.X11-unix/:/tmp/.X11-unix/' ], "Privileged": True }, "Volumes": {}, "NetworkDisabled": True, "Name": "test", "Hostname": "test", "Image": "ubuntu:latest", "Env": [ "container=docker", "GNS3_MAX_ETHERNET=eth0", "GNS3_VOLUMES=/etc/network", "QT_GRAPHICSSYSTEM=native", "DISPLAY=:42" ], "Entrypoint": ["/gns3/init.sh"], "Cmd": ["/bin/sh"] }) assert vm._start_vnc.called assert vm._cid == "e90e34656806" assert vm._console_type == "vnc"
def test_update_running(loop, vm): response = { "Id": "e90e34656806", "Warnings": [] } original_console = vm.console vm.start = MagicMock() with asyncio_patch("gns3server.modules.docker.Docker.list_images", return_value=[{"image": "ubuntu:latest"}]) as mock_list_images: with asyncio_patch("gns3server.modules.docker.DockerVM._get_container_state", return_value="running"): with asyncio_patch("gns3server.modules.docker.Docker.query", return_value=response) as mock_query: loop.run_until_complete(asyncio.async(vm.update())) mock_query.assert_any_call("DELETE", "containers/e90e34656842", params={"force": 1, "v": 1}) mock_query.assert_any_call("POST", "containers/create", data={ "Tty": True, "OpenStdin": True, "StdinOnce": False, "HostConfig": { "CapAdd": ["ALL"], "Binds": [ "{}:/gns3:ro".format(get_resource("modules/docker/resources")), "{}:/gns3volumes/etc/network:rw".format(os.path.join(vm.working_dir, "etc", "network")) ], "Privileged": True }, "Volumes": {}, "NetworkDisabled": True, "Name": "test", "Hostname": "test", "Image": "ubuntu:latest", "Env": [ "container=docker", "GNS3_MAX_ETHERNET=eth0", "GNS3_VOLUMES=/etc/network" ], "Entrypoint": ["/gns3/init.sh"], "Cmd": ["/bin/sh"] }) assert vm.console == original_console assert vm.start.called
def test_update_running(loop, vm): response = { "Id": "e90e34656806", "Warnings": [] } original_console = vm.console vm.start = MagicMock() with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "ubuntu"}]) as mock_list_images: with asyncio_patch("gns3server.compute.docker.DockerVM._get_container_state", return_value="running"): with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock_query: loop.run_until_complete(asyncio.async(vm.update())) mock_query.assert_any_call("DELETE", "containers/e90e34656842", params={"force": 1, "v": 1}) mock_query.assert_any_call("POST", "containers/create", data={ "Tty": True, "OpenStdin": True, "StdinOnce": False, "HostConfig": { "CapAdd": ["ALL"], "Binds": [ "{}:/gns3:ro".format(get_resource("compute/docker/resources")), "{}:/gns3volumes/etc/network:rw".format(os.path.join(vm.working_dir, "etc", "network")) ], "Privileged": True }, "Volumes": {}, "NetworkDisabled": True, "Name": "test", "Hostname": "test", "Image": "ubuntu:latest", "Env": [ "container=docker", "GNS3_MAX_ETHERNET=eth0", "GNS3_VOLUMES=/etc/network" ], "Entrypoint": ["/gns3/init.sh"], "Cmd": ["/bin/sh"] }) assert vm.console == original_console assert vm.start.called
def test_create_vnc(loop, project, manager): response = { "Id": "e90e34656806", "Warnings": [] } with asyncio_patch("gns3server.modules.docker.Docker.list_images", return_value=[{"image": "ubuntu:latest"}]) as mock_list_images: with asyncio_patch("gns3server.modules.docker.Docker.query", return_value=response) as mock: vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu:latest", console_type="vnc", console=5900) vm._start_vnc = MagicMock() vm._display = 42 loop.run_until_complete(asyncio.async(vm.create())) mock.assert_called_with("POST", "containers/create", data={ "Tty": True, "OpenStdin": True, "StdinOnce": False, "HostConfig": { "CapAdd": ["ALL"], "Binds": [ "{}:/gns3:ro".format(get_resource("modules/docker/resources")), "{}:/gns3volumes/etc/network:rw".format(os.path.join(vm.working_dir, "etc", "network")), '/tmp/.X11-unix/:/tmp/.X11-unix/' ], "Privileged": True }, "Volumes": {}, "NetworkDisabled": True, "Name": "test", "Hostname": "test", "Image": "ubuntu:latest", "Env": [ "container=docker", "GNS3_MAX_ETHERNET=eth0", "GNS3_VOLUMES=/etc/network", "QT_GRAPHICSSYSTEM=native", "DISPLAY=:42" ], "Entrypoint": ["/gns3/init.sh"], "Cmd": ["/bin/sh"] }) assert vm._start_vnc.called assert vm._cid == "e90e34656806" assert vm._console_type == "vnc"
def test_mount_binds(vm, tmpdir): image_infos = { "ContainerConfig": { "Volumes": { "/test/experimental": {} } } } dst = os.path.join(vm.working_dir, "test/experimental") assert vm._mount_binds(image_infos) == [ "{}:/gns3:ro".format(get_resource("modules/docker/resources")), "{}:/gns3volumes/etc/network:rw".format(os.path.join(vm.working_dir, "etc", "network")), "{}:/gns3volumes{}".format(dst, "/test/experimental") ] assert vm._volumes == ["/etc/network", "/test/experimental"] assert os.path.exists(dst)
def test_create_with_extra_volumes(loop, project, manager): response = { "Id": "e90e34656806", "Warnings": [], "Config" : { "Volumes" : { "/vol/1": None }, }, } with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "ubuntu"}]) as mock_list_images: with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu:latest", extra_volumes=["/vol/2"]) loop.run_until_complete(asyncio.ensure_future(vm.create())) mock.assert_called_with("POST", "containers/create", data={ "Tty": True, "OpenStdin": True, "StdinOnce": False, "HostConfig": { "CapAdd": ["ALL"], "Binds": [ "{}:/gns3:ro".format(get_resource("compute/docker/resources")), "{}:/gns3volumes/etc/network:rw".format(os.path.join(vm.working_dir, "etc", "network")), "{}:/gns3volumes/vol/1".format(os.path.join(vm.working_dir, "vol", "1")), "{}:/gns3volumes/vol/2".format(os.path.join(vm.working_dir, "vol", "2")), ], "Privileged": True }, "Volumes": {}, "NetworkDisabled": True, "Name": "test", "Hostname": "test", "Image": "ubuntu:latest", "Env": [ "container=docker", "GNS3_MAX_ETHERNET=eth0", "GNS3_VOLUMES=/etc/network:/vol/1:/vol/2" ], "Entrypoint": ["/gns3/init.sh"], "Cmd": ["/bin/sh"] }) assert vm._cid == "e90e34656806"
def test_get_path(): symbols = Symbols() symbols.theme = "Classic" assert symbols.get_path(':/symbols/classic/firewall.svg') == get_resource( "symbols/classic/firewall.svg")
def test_get_path(): symbols = Symbols() assert symbols.get_path(':/symbols/firewall.svg') == get_resource("symbols/firewall.svg")
def test_get_path(): symbols = Symbols() assert symbols.get_path(':/symbols/firewall.svg') == get_resource( "symbols/firewall.svg")
def test_get_path(): symbols = Symbols() symbols.theme = "Classic" assert symbols.get_path(':/symbols/classic/firewall.svg') == get_resource("symbols/classic/firewall.svg")