Merging 2.1 into 2.2

This commit is contained in:
grossmj committed 2019-02-22 18:04:49 +07:00
commit 5754747a90
16 files changed
+102 -46

No files matched your search

+1 -1
View File
@@ -55,7 +55,7 @@ class Drawing:
return self._id
@property
def ressource_filename(self):
def resource_filename(self):
"""
If the svg content has been dump to an external file return is name otherwise None
"""
+14 -4
View File
@@ -30,7 +30,7 @@ import logging
log = logging.getLogger(__name__)
async def export_project(project, temporary_dir, include_images=False, keep_compute_id=False, allow_all_nodes=False):
async def export_project(project, temporary_dir, include_images=False, keep_compute_id=False, allow_all_nodes=False, reset_mac_addresses=False):
"""
Export a project to a zip file.
@@ -41,6 +41,7 @@ async def export_project(project, temporary_dir, include_images=False, keep_comp
:param include images: save OS images to the zip file
:param keep_compute_id: If false replace all compute id by local (standard behavior for .gns3project to make it portable)
:param allow_all_nodes: Allow all nodes type to be include in the zip even if not portable
:param reset_mac_addresses: Reset MAC addresses for every nodes.
:returns: ZipStream object
"""
@@ -60,10 +61,10 @@ async def export_project(project, temporary_dir, include_images=False, keep_comp
# 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"):
await _patch_project_file(project, os.path.join(project._path, file), zstream, include_images, keep_compute_id, allow_all_nodes, temporary_dir)
await _patch_project_file(project, os.path.join(project._path, file), zstream, include_images, keep_compute_id, allow_all_nodes, temporary_dir, reset_mac_addresses)
# Export the local files
for root, dirs, files in os.walk(project._path, topdown=True):
for root, dirs, files in os.walk(project._path, topdown=True, followlinks=False):
files = [f for f in files if _is_exportable(os.path.join(root, f))]
for file in files:
path = os.path.join(root, file)
@@ -124,6 +125,7 @@ def _patch_mtime(path):
new_mtime = file_date.replace(year=1980).timestamp()
os.utime(path, (st.st_atime, new_mtime))
def _is_exportable(path):
"""
:returns: True if file should not be included in the final archive
@@ -133,6 +135,10 @@ def _is_exportable(path):
if path.endswith("snapshots"):
return False
# do not export symlinks
if os.path.islink(path):
return False
# do not export directories of snapshots
if "{sep}snapshots{sep}".format(sep=os.path.sep) in path:
return False
@@ -153,7 +159,7 @@ def _is_exportable(path):
return True
async def _patch_project_file(project, path, zstream, include_images, keep_compute_id, allow_all_nodes, temporary_dir):
async def _patch_project_file(project, path, zstream, include_images, keep_compute_id, allow_all_nodes, temporary_dir, reset_mac_addresses):
"""
Patch a project file (.gns3) to export a project.
The .gns3 file is renamed to project.gns3
@@ -186,6 +192,10 @@ async def _patch_project_file(project, path, zstream, include_images, keep_compu
if "properties" in node and node["node_type"] != "docker":
for prop, value in node["properties"].items():
# reset the MAC address
if reset_mac_addresses and prop in ("mac_addr", "mac_address"):
node["properties"][prop] = None
if node["node_type"] == "iou":
if not prop == "path":
continue
@@ -69,13 +69,15 @@ class VMwareGNS3VM(BaseGNS3VM):
if ram % 4 != 0:
raise GNS3VMError("Allocated memory {} for the GNS3 VM must be a multiple of 4".format(ram))
available_vcpus = psutil.cpu_count(logical=False)
available_vcpus = psutil.cpu_count()
if vcpus > available_vcpus:
raise GNS3VMError("You have allocated too many vCPUs for the GNS3 VM! (max available is {} vCPUs)".format(available_vcpus))
cores_per_sockets = int(available_vcpus / psutil.cpu_count(logical=False))
try:
pairs = VMware.parse_vmware_file(self._vmx_path)
pairs["numvcpus"] = str(vcpus)
pairs["cpuid.coresPerSocket"] = str(cores_per_sockets)
pairs["memsize"] = str(ram)
VMware.write_vmx_file(self._vmx_path, pairs)
log.info("GNS3 VM vCPU count set to {} and RAM amount set to {}".format(vcpus, ram))
+6 -2
View File
@@ -182,9 +182,11 @@ async def _move_files_to_compute(compute, project_id, directory, files_path):
location = os.path.join(directory, files_path)
if os.path.exists(location):
for (dirpath, dirnames, filenames) in os.walk(location):
for (dirpath, dirnames, filenames) in os.walk(location, followlinks=False):
for filename in filenames:
path = os.path.join(dirpath, filename)
if os.path.islink(path):
continue
dst = os.path.relpath(path, directory)
await _upload_file(compute, project_id, path, dst)
await wait_run_in_executor(shutil.rmtree, os.path.join(directory, files_path))
@@ -210,9 +212,11 @@ def _import_images(controller, path):
image_dir = controller.images_path()
root = os.path.join(path, "images")
for (dirpath, dirnames, filenames) in os.walk(root):
for (dirpath, dirnames, filenames) in os.walk(root, followlinks=False):
for filename in filenames:
path = os.path.join(dirpath, filename)
if os.path.islink(path):
continue
dst = os.path.join(image_dir, os.path.relpath(path, root))
os.makedirs(os.path.dirname(dst), exist_ok=True)
shutil.move(path, dst)
+14 -10
View File
@@ -740,25 +740,27 @@ class Project:
# We don't care if a compute is down at this step
except (ComputeError, aiohttp.web.HTTPError, aiohttp.ClientResponseError, TimeoutError):
pass
self._cleanPictures()
self._clean_pictures()
self._status = "closed"
if not ignore_notification:
self.controller.notification.project_emit("project.closed", self.__json__())
self.reset()
def _cleanPictures(self):
def _clean_pictures(self):
"""
Delete unused images
Delete unused pictures.
"""
# Project have been deleted
if not os.path.exists(self.path):
# Project have been deleted or is loading or is not opened
if not os.path.exists(self.path) or self._loading or self._status != "opened":
return
try:
pictures = set(os.listdir(self.pictures_directory))
for drawing in self._drawings.values():
try:
pictures.remove(drawing.ressource_filename)
resource_filename = drawing.resource_filename
if resource_filename:
pictures.remove(resource_filename)
except KeyError:
pass
@@ -770,10 +772,12 @@ class Project:
except KeyError:
pass
for pict in pictures:
os.remove(os.path.join(self.pictures_directory, pict))
for pic_filename in pictures:
path = os.path.join(self.pictures_directory, pic_filename)
log.info("Deleting unused picture '{}'".format(path))
os.remove(path)
except OSError as e:
log.warning(str(e))
log.warning("Could not delete unused pictures: {}".format(e))
async def delete(self):
@@ -962,7 +966,7 @@ class Project:
assert self._status != "closed"
try:
with tempfile.TemporaryDirectory() as tmpdir:
zipstream = await export_project(self, tmpdir, keep_compute_id=True, allow_all_nodes=True)
zipstream = await export_project(self, tmpdir, keep_compute_id=True, allow_all_nodes=True, reset_mac_addresses=True)
project_path = os.path.join(tmpdir, "project.gns3p")
await wait_run_in_executor(self._create_duplicate_project_file, project_path, zipstream)
with open(project_path, "rb") as f: