Export non remote server work

This commit is contained in:
Julien Duponchelle committed 2016-07-20 14:50:15 +02:00
1 parent 7c4c03cf17
commit 08c35f5558
6 files changed
+252 -85

No files matched your search

+3 -4
View File
@@ -406,7 +406,7 @@ class Project:
The file will be read chunk by chunk when you iterate on
the zip.
It will ignore some files like snapshots and
It will ignore some files like snapshots and tmp
:returns: ZipStream object
"""
@@ -443,12 +443,11 @@ class Project:
z.write(path, os.path.relpath(path, self._path), compress_type=zipfile.ZIP_DEFLATED)
return z
def _export_images(self, image, type, z):
def _export_images(self, image, z):
"""
Take a project file (.gns3) and export images to the zip
:param image: Image path
:param type: Type of image
:param z: Zipfile instance for the export
"""
from . import MODULES
@@ -488,7 +487,7 @@ class Project:
if prop.endswith("image"):
node["properties"][prop] = os.path.basename(value)
if include_images is True:
self._export_images(value, node["type"], z)
self._export_images(value, z)
z.writestr("project.gns3", json.dumps(topology).encode())
def import_zip(self, stream, gns3vm=True):
+92
View File
@@ -20,6 +20,8 @@ import json
import asyncio
import aiohttp
import shutil
import zipstream
import zipfile
from uuid import UUID, uuid4
@@ -426,6 +428,96 @@ class Project:
drawing = yield from self.add_drawing(**drawing_data)
self._status = "opened"
def export(self, include_images=False):
"""
Export the project as zip. It's a ZipStream object.
The file will be read chunk by chunk when you iterate on
the zip.
It will ignore some files like snapshots and
:returns: ZipStream object
"""
z = zipstream.ZipFile()
for root, dirs, files in os.walk(self._path, topdown=True):
# Remove snapshots and capture
if os.path.split(root)[-1:][0] == "project-files":
dirs[:] = [d for d in dirs if d not in ("snapshots", "tmp")]
# Ignore log files and OS noise
files = [f for f in files if not f.endswith('_log.txt') and not f.endswith('.log') and f != '.DS_Store']
for file in files:
path = os.path.join(root, file)
# Try open the file
try:
open(path).close()
except OSError as e:
msg = "Could not export file {}: {}".format(path, e)
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)
else:
z.write(path, os.path.relpath(path, self._path), compress_type=zipfile.ZIP_DEFLATED)
return z
def _export_project_file(self, path, z, include_images):
"""
Take a project file (.gns3) and patch it for the export
:param path: Path of the .gns3
"""
# Image file that we need to include in the exported archive
images = set()
with open(path) as f:
topology = json.load(f)
if "topology" in topology and "nodes" in topology["topology"]:
for node in topology["topology"]["nodes"]:
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)
for image in images:
self._export_images(image, z)
z.writestr("project.gns3", json.dumps(topology).encode())
def _export_images(self, image, z):
"""
Take a project file (.gns3) and export images to the zip
:param image: Image path
:param z: Zipfile instance for the export
"""
from ..compute import MODULES
for module in MODULES:
try:
img_directory = module.instance().get_images_directory()
except NotImplementedError:
# Some modules don't have images
continue
directory = os.path.split(img_directory)[-1:][0]
if os.path.exists(image):
path = image
else:
path = os.path.join(img_directory, image)
# FIXME: av
if os.path.exists(path):
arcname = os.path.join("images", directory, os.path.basename(image))
z.write(path, arcname)
break
def dump(self):
"""
Dump topology to disk
@@ -214,3 +214,32 @@ class ProjectHandler:
break
ws.send_str(notification)
return ws
@Route.get(
r"/projects/{project_id}/export",
description="Export a project as a portable archive",
parameters={
"project_id": "Project UUID",
},
raw=True,
status_codes={
200: "File returned",
404: "The project doesn't exist"
})
def export_project(request, response):
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)
for data in project.export(include_images=bool(request.GET.get("include_images", "0"))):
response.write(data)
yield from response.drain()
yield from response.write_eof()