mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-03 14:01:15 +02:00
iExport files from remote server, Fixes: gui/#2271
This commit is contained in:
1 parent
135c529d4b
commit
b48f5df53f
8 files changed
+262
-35
No files matched your search
@@ -58,7 +58,8 @@ def export_project(project, temporary_dir, include_images=False, keep_compute_id
|
||||
# First we process the .gns3 in order to be sure we don't have an error
|
||||
for file in os.listdir(project._path):
|
||||
if file.endswith(".gns3"):
|
||||
_export_project_file(project, os.path.join(project._path, file), z, include_images, keep_compute_id, allow_all_nodes)
|
||||
images = yield from _export_project_file(project, os.path.join(project._path, file),
|
||||
z, include_images, keep_compute_id, allow_all_nodes, temporary_dir)
|
||||
|
||||
for root, dirs, files in os.walk(project._path, topdown=True):
|
||||
files = [f for f in files if not _filter_files(os.path.join(root, f))]
|
||||
@@ -78,6 +79,8 @@ def export_project(project, temporary_dir, include_images=False, keep_compute_id
|
||||
else:
|
||||
z.write(path, os.path.relpath(path, project._path), compress_type=zipfile.ZIP_DEFLATED)
|
||||
|
||||
downloaded_files = set()
|
||||
|
||||
for compute in project.computes:
|
||||
if compute.id != "local":
|
||||
compute_files = yield from compute.list_files(project)
|
||||
@@ -94,6 +97,8 @@ def export_project(project, temporary_dir, include_images=False, keep_compute_id
|
||||
response.close()
|
||||
f.close()
|
||||
z.write(temp_path, arcname=compute_file["path"], compress_type=zipfile.ZIP_DEFLATED)
|
||||
downloaded_files.add(compute_file['path'])
|
||||
|
||||
return z
|
||||
|
||||
|
||||
@@ -121,7 +126,8 @@ def _filter_files(path):
|
||||
return False
|
||||
|
||||
|
||||
def _export_project_file(project, path, z, include_images, keep_compute_id, allow_all_nodes):
|
||||
@asyncio.coroutine
|
||||
def _export_project_file(project, path, z, include_images, keep_compute_id, allow_all_nodes, temporary_dir):
|
||||
"""
|
||||
Take a project file (.gns3) and patch it for the export
|
||||
|
||||
@@ -131,7 +137,7 @@ def _export_project_file(project, path, z, include_images, keep_compute_id, allo
|
||||
"""
|
||||
|
||||
# Image file that we need to include in the exported archive
|
||||
images = set()
|
||||
images = []
|
||||
|
||||
with open(path) as f:
|
||||
topology = json.load(f)
|
||||
@@ -139,6 +145,8 @@ def _export_project_file(project, path, z, include_images, keep_compute_id, allo
|
||||
if "topology" in topology:
|
||||
if "nodes" in topology["topology"]:
|
||||
for node in topology["topology"]["nodes"]:
|
||||
compute_id = node.get('compute_id', 'local')
|
||||
|
||||
if node["node_type"] == "virtualbox" and node.get("properties", {}).get("linked_clone"):
|
||||
raise aiohttp.web.HTTPConflict(text="Topology with a linked {} clone could not be exported. Use qemu instead.".format(node["node_type"]))
|
||||
if not allow_all_nodes and node["node_type"] in ["virtualbox", "vmware", "cloud"]:
|
||||
@@ -149,22 +157,42 @@ def _export_project_file(project, path, z, include_images, keep_compute_id, allo
|
||||
|
||||
if "properties" in node and node["node_type"] != "docker":
|
||||
for prop, value in node["properties"].items():
|
||||
if prop.endswith("image"):
|
||||
if not keep_compute_id: # If we keep the original compute we can keep the image path
|
||||
node["properties"][prop] = os.path.basename(value)
|
||||
if include_images is True:
|
||||
images.add(value)
|
||||
if not prop.endswith("image"):
|
||||
continue
|
||||
|
||||
if value is None or value.strip() == '':
|
||||
continue
|
||||
|
||||
if not keep_compute_id: # If we keep the original compute we can keep the image path
|
||||
node["properties"][prop] = os.path.basename(value)
|
||||
|
||||
if include_images is True:
|
||||
images.append({
|
||||
'compute_id': compute_id,
|
||||
'image': value,
|
||||
'image_type': node['node_type']
|
||||
})
|
||||
|
||||
if not keep_compute_id:
|
||||
topology["topology"]["computes"] = [] # Strip compute informations because could contain secret info like password
|
||||
topology["topology"]["computes"] = [] # Strip compute information because could contain secret info like password
|
||||
|
||||
for image in images:
|
||||
_export_images(project, image, z)
|
||||
local_images = set([i['image'] for i in images if i['compute_id'] == 'local'])
|
||||
|
||||
for image in local_images:
|
||||
_export_local_images(project, image, z)
|
||||
|
||||
remote_images = set([
|
||||
(i['compute_id'], i['image_type'], i['image'])
|
||||
for i in images if i['compute_id'] != 'local'])
|
||||
|
||||
for compute_id, image_type, image in remote_images:
|
||||
yield from _export_remote_images(project, compute_id, image_type, image, z, temporary_dir)
|
||||
|
||||
z.writestr("project.gns3", json.dumps(topology).encode())
|
||||
|
||||
return images
|
||||
|
||||
def _export_images(project, image, z):
|
||||
def _export_local_images(project, image, z):
|
||||
"""
|
||||
Take a project file (.gns3) and export images to the zip
|
||||
|
||||
@@ -191,4 +219,45 @@ def _export_images(project, image, z):
|
||||
arcname = os.path.join("images", directory, os.path.basename(image))
|
||||
z.write(path, arcname)
|
||||
return
|
||||
raise aiohttp.web.HTTPConflict(text="Topology could not be exported because the image {} is not available. If you use multiple server, we need a copy of the image on the main server.".format(image))
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def _export_remote_images(project, compute_id, image_type, image, project_zipfile, temporary_dir):
|
||||
"""
|
||||
Export specific image from remote compute
|
||||
:param project:
|
||||
:param compute_id:
|
||||
:param image_type:
|
||||
:param image:
|
||||
:param project_zipfile:
|
||||
:return:
|
||||
"""
|
||||
|
||||
log.info("Obtaining image `{}` from `{}`".format(image, compute_id))
|
||||
|
||||
try:
|
||||
compute = [compute for compute in project.computes if compute.id == compute_id][0]
|
||||
except IndexError:
|
||||
raise aiohttp.web.HTTPConflict(
|
||||
text="Cannot export image from `{}` compute. Compute doesn't exist.".format(compute_id))
|
||||
|
||||
(fd, temp_path) = tempfile.mkstemp(dir=temporary_dir)
|
||||
f = open(fd, "wb", closefd=True)
|
||||
response = yield from compute.download_image(image_type, image)
|
||||
|
||||
if response.status != 200:
|
||||
raise aiohttp.web.HTTPConflict(
|
||||
text="Cannot export image from `{}` compute. Compute sent `{}` status.".format(
|
||||
compute_id, response.status))
|
||||
|
||||
while True:
|
||||
data = yield from response.content.read(512)
|
||||
if not data:
|
||||
break
|
||||
f.write(data)
|
||||
response.close()
|
||||
f.close()
|
||||
arcname = os.path.join("images", image_type, image)
|
||||
log.info("Saved {}".format(arcname))
|
||||
project_zipfile.write(temp_path, arcname=arcname, compress_type=zipfile.ZIP_DEFLATED)
|
||||
|
||||
Reference in new issue
Block a user