Merge pull request #481 from GNS3/import_linux

Flatten the project at export and support import for Linux
This commit is contained in:
Jeremy Grossmann 2016-04-06 11:55:46 -06:00
commit 6bc54b17c7
3 changed files with 136 additions and 7 deletions

View File

@ -405,7 +405,7 @@ class ProjectHandler:
if not packet: if not packet:
break break
temp.write(packet) temp.write(packet)
project.import_zip(temp) project.import_zip(temp, gns3vm=bool(request.GET.get("gns3vm", "1")))
except OSError as e: except OSError as e:
raise aiohttp.web.HTTPInternalServerError(text="Could not import the project: {}".format(e)) raise aiohttp.web.HTTPInternalServerError(text="Could not import the project: {}".format(e))

View File

@ -529,7 +529,7 @@ class Project:
# directory # directory
for root, dirs, files in os.walk(self._path, topdown=True): for root, dirs, files in os.walk(self._path, topdown=True):
# Remove snapshots # Remove snapshots
if "project-files" in root: if os.path.split(root)[-1:][0] == "project-files":
dirs[:] = [d for d in dirs if d != "snapshots"] dirs[:] = [d for d in dirs if d != "snapshots"]
# Ignore log files and OS noise # Ignore log files and OS noise
@ -540,27 +540,80 @@ class Project:
# We rename the .gns3 project.gns3 to avoid the task to the client to guess the file name # We rename the .gns3 project.gns3 to avoid the task to the client to guess the file name
if file.endswith(".gns3"): if file.endswith(".gns3"):
z.write(path, "project.gns3") z.write(path, "project.gns3")
else:
# We merge the data from all server in the same project-files directory
vm_directory = os.path.join(self._path, "servers", "vm")
if os.path.commonprefix([root, vm_directory]) == vm_directory:
z.write(path, os.path.relpath(path, vm_directory))
else: else:
z.write(path, os.path.relpath(path, self._path)) z.write(path, os.path.relpath(path, self._path))
return z return z
def import_zip(self, stream): def import_zip(self, stream, gns3vm=True):
""" """
Import a project contain in a zip file Import a project contain in a zip file
:params: A io.BytesIO of the zifile :param stream: A io.BytesIO of the zipfile
:param gns3vm: True move docker, iou and qemu to the GNS3 VM
""" """
with zipfile.ZipFile(stream) as myzip: with zipfile.ZipFile(stream) as myzip:
myzip.extractall(self.path) myzip.extractall(self.path)
project_file = os.path.join(self.path, "project.gns3") project_file = os.path.join(self.path, "project.gns3")
if os.path.exists(project_file): if os.path.exists(project_file):
with open(project_file) as f: with open(project_file) as f:
topology = json.load(f) topology = json.load(f)
topology["project_id"] = self.id topology["project_id"] = self.id
topology["name"] = self.name topology["name"] = self.name
topology.setdefault("topology", {})
topology["topology"].setdefault("nodes", [])
topology["topology"]["servers"] = [
{
"id": 1,
"local": True,
"vm": False
}
]
# By default all node run on local server
for node in topology["topology"]["nodes"]:
node["server_id"] = 1
if gns3vm:
# Move to servers/vm directory the data that should be import on remote server
modules_to_vm = {
"qemu": "QemuVM",
"iou": "IOUDevice",
"docker": "DockerVM"
}
vm_directory = os.path.join(self.path, "servers", "vm", "project-files")
vm_server_use = False
for module, device_type in modules_to_vm.items():
module_directory = os.path.join(self.path, "project-files", module)
if os.path.exists(module_directory):
os.makedirs(vm_directory, exist_ok=True)
shutil.move(module_directory, os.path.join(vm_directory, module))
# Patch node to use the GNS3 VM
for node in topology["topology"]["nodes"]:
if node["type"] == device_type:
node["server_id"] = 2
vm_server_use = True
# We use the GNS3 VM. We need to add the server to the list
if vm_server_use:
topology["topology"]["servers"].append({
"id": 2,
"vm": True,
"local": False
})
# Write the modified topology
with open(project_file, "w") as f: with open(project_file, "w") as f:
json.dump(topology, f, indent=4) json.dump(topology, f, indent=4)
# Rename to a human distinctive name
shutil.move(project_file, os.path.join(self.path, self.name + ".gns3")) shutil.move(project_file, os.path.join(self.path, self.name + ".gns3"))

View File

@ -297,13 +297,70 @@ def test_export(tmpdir):
assert 'vm-1/dynamips/test_log.txt' not in myzip.namelist() assert 'vm-1/dynamips/test_log.txt' not in myzip.namelist()
def test_export(tmpdir):
project = Project()
path = project.path
os.makedirs(os.path.join(path, "vm-1", "dynamips"))
# The .gns3 should be renamed project.gns3 in order to simplify import
with open(os.path.join(path, "test.gns3"), 'w+') as f:
f.write("{}")
with open(os.path.join(path, "vm-1", "dynamips", "test"), 'w+') as f:
f.write("HELLO")
with open(os.path.join(path, "vm-1", "dynamips", "test_log.txt"), 'w+') as f:
f.write("LOG")
os.makedirs(os.path.join(path, "project-files", "snapshots"))
with open(os.path.join(path, "project-files", "snapshots", "test"), 'w+') as f:
f.write("WORLD")
os.makedirs(os.path.join(path, "servers", "vm", "project-files", "docker"))
with open(os.path.join(path, "servers", "vm", "project-files", "docker", "busybox"), 'w+') as f:
f.write("DOCKER")
z = project.export()
with open(str(tmpdir / 'zipfile.zip'), 'wb') as f:
for data in z:
f.write(data)
with zipfile.ZipFile(str(tmpdir / 'zipfile.zip')) as myzip:
with myzip.open("vm-1/dynamips/test") as myfile:
content = myfile.read()
assert content == b"HELLO"
assert 'test.gns3' not in myzip.namelist()
assert 'project.gns3' in myzip.namelist()
assert 'project-files/snapshots/test' not in myzip.namelist()
assert 'vm-1/dynamips/test_log.txt' not in myzip.namelist()
assert 'servers/vm/project-files/docker/busybox' not in myzip.namelist()
assert 'project-files/docker/busybox' in myzip.namelist()
def test_import(tmpdir): def test_import(tmpdir):
project_id = str(uuid.uuid4()) project_id = str(uuid.uuid4())
project = Project(name="test", project_id=project_id) project = Project(name="test", project_id=project_id)
topology = {
"project_id": str(uuid.uuid4()),
"name": "testtest",
"topology": {
"nodes": [
{
"server_id": 3,
"type": "VPCSDevice"
},
{
"server_id": 3,
"type": "QemuVM"
}
]
}
}
with open(str(tmpdir / "project.gns3"), 'w+') as f: with open(str(tmpdir / "project.gns3"), 'w+') as f:
f.write('{"project_id": "ddd", "name": "test"}') json.dump(topology, f)
with open(str(tmpdir / "b.png"), 'w+') as f: with open(str(tmpdir / "b.png"), 'w+') as f:
f.write("B") f.write("B")
@ -311,14 +368,33 @@ def test_import(tmpdir):
with zipfile.ZipFile(zip_path, 'w') as myzip: with zipfile.ZipFile(zip_path, 'w') as myzip:
myzip.write(str(tmpdir / "project.gns3"), "project.gns3") myzip.write(str(tmpdir / "project.gns3"), "project.gns3")
myzip.write(str(tmpdir / "b.png"), "b.png") myzip.write(str(tmpdir / "b.png"), "b.png")
myzip.write(str(tmpdir / "b.png"), "project-files/dynamips/test")
myzip.write(str(tmpdir / "b.png"), "project-files/qemu/test")
with open(zip_path, "rb") as f: with open(zip_path, "rb") as f:
project.import_zip(f) project.import_zip(f)
assert os.path.exists(os.path.join(project.path, "b.png")) assert os.path.exists(os.path.join(project.path, "b.png"))
assert os.path.exists(os.path.join(project.path, "test.gns3")) assert os.path.exists(os.path.join(project.path, "test.gns3"))
assert os.path.exists(os.path.join(project.path, "project-files/dynamips/test"))
assert os.path.exists(os.path.join(project.path, "servers/vm/project-files/qemu/test"))
with open(os.path.join(project.path, "test.gns3")) as f: with open(os.path.join(project.path, "test.gns3")) as f:
content = json.load(f) content = json.load(f)
assert content["name"] == "test"
assert content["project_id"] == project_id assert content["project_id"] == project_id
assert content["name"] == project.name assert content["topology"]["servers"] == [
{
"id": 1,
"local": True,
"vm": False
},
{
"id": 2,
"local": False,
"vm": True
},
]
assert content["topology"]["nodes"][0]["server_id"] == 1
assert content["topology"]["nodes"][1]["server_id"] == 2