diff --git a/gns3server/controller/project.py b/gns3server/controller/project.py index 507dc4b3..b9f053c7 100644 --- a/gns3server/controller/project.py +++ b/gns3server/controller/project.py @@ -439,6 +439,12 @@ class Project: :returns: ZipStream object """ z = zipstream.ZipFile() + + # First we process the .gns3 in order to be sure we don't have an error + for file in os.listdir(self._path): + if file.endswith(".gns3"): + self._export_project_file(os.path.join(self._path, file), z, include_images) + for root, dirs, files in os.walk(self._path, topdown=True): # Remove snapshots and capture if os.path.split(root)[-1:][0] == "project-files": @@ -457,9 +463,8 @@ class Project: log.warn(msg) self.emit("log.warning", {"message": msg}) continue - # We rename the .gns3 project.gns3 to avoid the task to the client to guess the file name if file.endswith(".gns3"): - self._export_project_file(path, z, include_images) + pass else: z.write(path, os.path.relpath(path, self._path), compress_type=zipfile.ZIP_DEFLATED) return z @@ -468,6 +473,8 @@ class Project: """ Take a project file (.gns3) and patch it for the export + We rename the .gns3 project.gns3 to avoid the task to the client to guess the file name + :param path: Path of the .gns3 """ @@ -478,12 +485,15 @@ class Project: topology = json.load(f) if "topology" in topology and "nodes" in topology["topology"]: for node in topology["topology"]["nodes"]: + if node["node_type"] in ["virtualbox", "vmware", "cloud"]: + raise aiohttp.web.HTTPConflict(text="Topology with a {} could not be exported".format(node["node_type"])) + if "properties" in node and node["node_type"] != "Docker": for prop, value in node["properties"].items(): if prop.endswith("image"): node["properties"][prop] = os.path.basename(value) if include_images is True: - images.append(value) + images.add(value) for image in images: self._export_images(image, z) diff --git a/gns3server/handlers/api/controller/project_handler.py b/gns3server/handlers/api/controller/project_handler.py index fffdcacc..c6baf615 100644 --- a/gns3server/handlers/api/controller/project_handler.py +++ b/gns3server/handlers/api/controller/project_handler.py @@ -231,14 +231,21 @@ class ProjectHandler: controller = Controller.instance() project = controller.get_project(request.match_info["project_id"]) - response.content_type = 'application/gns3project' - response.headers['CONTENT-DISPOSITION'] = 'attachment; filename="{}.gns3project"'.format(project.name) - response.enable_chunked_encoding() - # Very important: do not send a content length otherwise QT closes the connection (curl can consume the feed) - response.content_length = None - response.start(request) + + started = False for data in project.export(include_images=bool(request.GET.get("include_images", "0"))): + # We need to do that now because export could failed and raise an HTTP error + # that why response start need to be the later possible + if not started: + response.content_type = 'application/gns3project' + response.headers['CONTENT-DISPOSITION'] = 'attachment; filename="{}.gns3project"'.format(project.name) + response.enable_chunked_encoding() + # Very important: do not send a content length otherwise QT closes the connection (curl can consume the feed) + response.content_length = None + response.start(request) + started = True + response.write(data) yield from response.drain() diff --git a/tests/controller/test_project.py b/tests/controller/test_project.py index 71136e1d..21694660 100644 --- a/tests/controller/test_project.py +++ b/tests/controller/test_project.py @@ -351,6 +351,30 @@ def test_export(tmpdir, project): assert 'vm-1/dynamips/test_log.txt' not in myzip.namelist() +def test_export_disallow_some_type(tmpdir, project): + """ + Fix absolute image path + """ + + path = project.path + + topology = { + "topology": { + "nodes": [ + { + "node_type": "virtualbox" + } + ] + } + } + + with open(os.path.join(path, "test.gns3"), 'w+') as f: + json.dump(topology, f) + + with pytest.raises(aiohttp.web.HTTPConflict): + z = project.export() + + def test_export_fix_path(tmpdir, project): """ Fix absolute image path