mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-03 05:51:15 +02:00
Export project with the GNS3VM
This commit is contained in:
8 files changed
+105
-37
No files matched your search
@@ -270,7 +270,23 @@ class Compute:
|
||||
}
|
||||
|
||||
@asyncio.coroutine
|
||||
def steam_file(self, project, path):
|
||||
def download_file(self, project, path):
|
||||
"""
|
||||
Read file of a project and download it
|
||||
|
||||
:param project: A project object
|
||||
:param path: The path of the file in the project
|
||||
:returns: A file stream
|
||||
"""
|
||||
|
||||
url = self._getUrl("/projects/{}/files/{}".format(project.id, path))
|
||||
response = yield from self._session().request("GET", url, auth=self._auth)
|
||||
if response.status == 404:
|
||||
raise aiohttp.web.HTTPNotFound(text="{} not found on compute".format(path))
|
||||
return response.content
|
||||
|
||||
@asyncio.coroutine
|
||||
def stream_file(self, project, path):
|
||||
"""
|
||||
Read file of a project and stream it
|
||||
|
||||
@@ -447,3 +463,13 @@ class Compute:
|
||||
if image not in [i['filename'] for i in images]:
|
||||
images.append({"filename": image, "path": image})
|
||||
return images
|
||||
|
||||
@asyncio.coroutine
|
||||
def list_files(self, project):
|
||||
"""
|
||||
List files in the project on computes
|
||||
"""
|
||||
path = "/projects/{}/files".format(project.id)
|
||||
res = yield from self.http_query("GET", path, timeout=120)
|
||||
return res.json
|
||||
|
||||
@@ -17,12 +17,15 @@
|
||||
|
||||
import os
|
||||
import json
|
||||
import asyncio
|
||||
import aiohttp
|
||||
import zipfile
|
||||
import tempfile
|
||||
import zipstream
|
||||
|
||||
|
||||
def export_project(project, include_images=False):
|
||||
@asyncio.coroutine
|
||||
def export_project(project, temporary_dir, 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
|
||||
@@ -30,6 +33,7 @@ def export_project(project, include_images=False):
|
||||
|
||||
It will ignore some files like snapshots and
|
||||
|
||||
:param temporary_dir: A temporary dir where to store intermediate data
|
||||
:returns: ZipStream object
|
||||
"""
|
||||
|
||||
@@ -45,12 +49,7 @@ def export_project(project, include_images=False):
|
||||
_export_project_file(project, os.path.join(project._path, file), z, include_images)
|
||||
|
||||
for root, dirs, files in os.walk(project._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']
|
||||
files = [f for f in files if not _filter_files(os.path.join(root, f))]
|
||||
|
||||
for file in files:
|
||||
path = os.path.join(root, file)
|
||||
@@ -66,9 +65,44 @@ def export_project(project, include_images=False):
|
||||
pass
|
||||
else:
|
||||
z.write(path, os.path.relpath(path, project._path), compress_type=zipfile.ZIP_DEFLATED)
|
||||
|
||||
for compute in project.computes:
|
||||
if compute.id == "vm":
|
||||
compute_files = yield from compute.list_files(project)
|
||||
for compute_file in compute_files:
|
||||
if not _filter_files(compute_file["path"]):
|
||||
(fp, temp_path) = tempfile.mkstemp(dir=temporary_dir)
|
||||
stream = yield from compute.download_file(project, compute_file["path"])
|
||||
while True:
|
||||
data = yield from stream.read(512)
|
||||
if not data:
|
||||
break
|
||||
fp.write(data)
|
||||
z.write(temp_path, arcname=compute_file["path"], compress_type=zipfile.ZIP_DEFLATED)
|
||||
return z
|
||||
|
||||
|
||||
def _filter_files(path):
|
||||
"""
|
||||
:returns: True if file should not be included in the final archive
|
||||
"""
|
||||
s = os.path.normpath(path).split(os.path.sep)
|
||||
try:
|
||||
i = s.index("project-files")
|
||||
if s[i + 1] in ("tmp", "captures", "snapshots"):
|
||||
return True
|
||||
except (ValueError, IndexError):
|
||||
pass
|
||||
|
||||
file_name = os.path.basename(path)
|
||||
# Ignore log files and OS noises
|
||||
if file_name.endswith('_log.txt') or file_name.endswith('.log') or file_name == '.DS_Store':
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
|
||||
def _export_project_file(project, path, z, include_images):
|
||||
"""
|
||||
Take a project file (.gns3) and patch it for the export
|
||||
|
||||
@@ -149,9 +149,9 @@ class Project:
|
||||
@property
|
||||
def computes(self):
|
||||
"""
|
||||
:return: Dictonnary of computes used by the project
|
||||
:return: List of computes used by the project
|
||||
"""
|
||||
return self._computes
|
||||
return self._project_created_on_compute
|
||||
|
||||
def remove_allocated_node_name(self, name):
|
||||
"""
|
||||
|
||||
@@ -138,4 +138,4 @@ class UDPLink(Link):
|
||||
"""
|
||||
if self._capture_node:
|
||||
compute = self._capture_node["node"].compute
|
||||
return compute.steam_file(self._project, "tmp/captures/" + self._capture_file_name)
|
||||
return compute.stream_file(self._project, "tmp/captures/" + self._capture_file_name)
|
||||
Reference in new issue
Block a user