async def test_export_disallow_some_type(tmpdir, project): """ Disallow export for some node type """ path = project.path topology = {"topology": {"nodes": [{"node_type": "vmware"}]}} with open(os.path.join(path, "test.gns3"), 'w+') as f: json.dump(topology, f) with pytest.raises(aiohttp.web.HTTPConflict): with aiozipstream.ZipFile() as z: await export_project(z, project, str(tmpdir)) with aiozipstream.ZipFile() as z: await export_project(z, project, str(tmpdir), allow_all_nodes=True) # VirtualBox is always disallowed topology = { "topology": { "nodes": [{ "node_type": "virtualbox", "properties": { "linked_clone": True } }] } } with open(os.path.join(path, "test.gns3"), 'w+') as f: json.dump(topology, f) with pytest.raises(aiohttp.web.HTTPConflict): with aiozipstream.ZipFile() as z: await export_project(z, project, str(tmpdir), allow_all_nodes=True)
async def test_export_with_ignoring_snapshots(tmpdir, project): with open(os.path.join(project.path, "test.gns3"), 'w+') as f: data = { "topology": { "computes": [{ "compute_id": "6b7149c8-7d6e-4ca0-ab6b-daa8ab567be0", "host": "127.0.0.1", "name": "Remote 1", "port": 8001, "protocol": "http" }], "nodes": [{ "compute_id": "6b7149c8-7d6e-4ca0-ab6b-daa8ab567be0", "node_type": "vpcs" }] } } json.dump(data, f) # create snapshot directory snapshots_dir = os.path.join(project.path, 'snapshots') os.makedirs(snapshots_dir) Path(os.path.join(snapshots_dir, 'snap.gns3project')).touch() with aiozipstream.ZipFile() as z: await export_project(z, project, str(tmpdir), keep_compute_id=True) await write_file(str(tmpdir / 'zipfile.zip'), z) with zipfile.ZipFile(str(tmpdir / 'zipfile.zip')) as myzip: assert not os.path.join('snapshots', 'snap.gns3project') in [ f.filename for f in myzip.filelist ]
async def test_export_keep_compute_id(tmpdir, project): """ If we want to restore the same computes we could ask to keep them in the file """ with open(os.path.join(project.path, "test.gns3"), 'w+') as f: data = { "topology": { "computes": [{ "compute_id": "6b7149c8-7d6e-4ca0-ab6b-daa8ab567be0", "host": "127.0.0.1", "name": "Remote 1", "port": 8001, "protocol": "http" }], "nodes": [{ "compute_id": "6b7149c8-7d6e-4ca0-ab6b-daa8ab567be0", "node_type": "vpcs" }] } } json.dump(data, f) with aiozipstream.ZipFile() as z: await export_project(z, project, str(tmpdir), keep_compute_id=True) await write_file(str(tmpdir / 'zipfile.zip'), z) with zipfile.ZipFile(str(tmpdir / 'zipfile.zip')) as myzip: with myzip.open("project.gns3") as myfile: topo = json.loads(myfile.read().decode())["topology"] assert topo["nodes"][0][ "compute_id"] == "6b7149c8-7d6e-4ca0-ab6b-daa8ab567be0" assert len(topo["computes"]) == 1
async def test_export_with_images(tmpdir, project): """ Fix absolute image path """ path = project.path os.makedirs(str(tmpdir / "IOS")) with open(str(tmpdir / "IOS" / "test.image"), "w+") as f: f.write("AAA") topology = { "topology": { "nodes": [{ "properties": { "image": "test.image" }, "node_type": "dynamips" }] } } with open(os.path.join(path, "test.gns3"), 'w+') as f: json.dump(topology, f) with aiozipstream.ZipFile() as z: with patch( "gns3server.compute.Dynamips.get_images_directory", return_value=str(tmpdir / "IOS"), ): await export_project(z, project, str(tmpdir), include_images=True) await write_file(str(tmpdir / 'zipfile.zip'), z) with zipfile.ZipFile(str(tmpdir / 'zipfile.zip')) as myzip: myzip.getinfo("images/IOS/test.image")
def test_export_vm(tmpdir, project, async_run): """ If data is on a remote server export it locally before sending it in the archive. """ compute = MagicMock() compute.id = "vm" compute.list_files = AsyncioMagicMock(return_value=[{"path": "vm-1/dynamips/test"}]) # Fake file that will be download from the vm mock_response = AsyncioMagicMock() mock_response.content = AsyncioBytesIO() async_run(mock_response.content.write(b"HELLO")) mock_response.content.seek(0) compute.download_file = AsyncioMagicMock(return_value=mock_response) project._project_created_on_compute.add(compute) 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 aiozipstream.ZipFile() as z: async_run(export_project(z, project, str(tmpdir))) assert compute.list_files.called async_run(write_file(str(tmpdir / 'zipfile.zip'), z)) 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"
async def export_project(request, response): controller = Controller.instance() project = await controller.get_loaded_project( request.match_info["project_id"]) if request.query.get("include_snapshots", "no").lower() == "yes": include_snapshots = True else: include_snapshots = False if request.query.get("include_images", "no").lower() == "yes": include_images = True else: include_images = False compression_query = request.query.get("compression", "zip").lower() if compression_query == "zip": compression = zipfile.ZIP_DEFLATED elif compression_query == "none": compression = zipfile.ZIP_STORED elif compression_query == "bzip2": compression = zipfile.ZIP_BZIP2 elif compression_query == "lzma": compression = zipfile.ZIP_LZMA try: begin = time.time() with tempfile.TemporaryDirectory() as tmp_dir: with aiozipstream.ZipFile(compression=compression) as zstream: await export_project(zstream, project, tmp_dir, include_snapshots=include_snapshots, include_images=include_images) # We need to do that now because export could failed and raise an HTTP error # that why response start need to be the later possible response.content_type = 'application/gns3project' response.headers[ 'CONTENT-DISPOSITION'] = 'attachment; filename="{}.gns3project"'.format( project.name) response.enable_chunked_encoding() await response.prepare(request) async for chunk in zstream: await response.write(chunk) log.info("Project '{}' exported in {:.4f} seconds".format( project.name, time.time() - begin)) # Will be raise if you have no space left or permission issue on your temporary directory # RuntimeError: something was wrong during the zip process except (ValueError, OSError, RuntimeError) as e: raise aiohttp.web.HTTPNotFound( text="Cannot export project: {}".format(str(e)))
async def test_export_disallow_running(tmpdir, project, node): """ Disallow export when a node is running """ path = project.path topology = {"topology": {"nodes": [{"node_type": "dynamips"}]}} with open(os.path.join(path, "test.gns3"), 'w+') as f: json.dump(topology, f) node._status = "started" with pytest.raises(aiohttp.web.HTTPConflict): with aiozipstream.ZipFile() as z: await export_project(z, project, str(tmpdir))
def test_export_fix_path(tmpdir, project, async_run): """ Fix absolute image path, except for Docker """ path = project.path topology = { "topology": { "nodes": [ { "properties": { "image": "/tmp/c3725-adventerprisek9-mz.124-25d.image" }, "node_type": "dynamips" }, { "properties": { "image": "gns3/webterm:lastest" }, "node_type": "docker" } ] } } with open(os.path.join(path, "test.gns3"), 'w+') as f: json.dump(topology, f) with aiozipstream.ZipFile() as z: async_run(export_project(z, project, str(tmpdir))) async_run(write_file(str(tmpdir / 'zipfile.zip'), z)) with zipfile.ZipFile(str(tmpdir / 'zipfile.zip')) as myzip: with myzip.open("project.gns3") as myfile: content = myfile.read().decode() topology = json.loads(content) assert topology["topology"]["nodes"][0]["properties"]["image"] == "c3725-adventerprisek9-mz.124-25d.image" assert topology["topology"]["nodes"][1]["properties"]["image"] == "gns3/webterm:lastest"
async def test_export(tmpdir, project): path = project.path os.makedirs(os.path.join(path, "vm-1", "dynamips")) os.makedirs(str(tmpdir / "IOS")) with open(str(tmpdir / "IOS" / "test.image"), "w+") as f: f.write("AAA") # The .gns3 should be renamed project.gns3 in order to simplify import with open(os.path.join(path, "test.gns3"), 'w+') as f: data = { "topology": { "computes": [{ "compute_id": "6b7149c8-7d6e-4ca0-ab6b-daa8ab567be0", "host": "127.0.0.1", "name": "Remote 1", "port": 8001, "protocol": "http" }], "nodes": [{ "compute_id": "6b7149c8-7d6e-4ca0-ab6b-daa8ab567be0", "node_type": "dynamips", "properties": { "image": "test.image" } }] } } json.dump(data, f) 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") with aiozipstream.ZipFile() as z: with patch( "gns3server.compute.Dynamips.get_images_directory", return_value=str(tmpdir / "IOS"), ): await export_project(z, project, str(tmpdir), include_images=False) await write_file(str(tmpdir / 'zipfile.zip'), z) 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 'images/IOS/test.image' not in myzip.namelist() with myzip.open("project.gns3") as myfile: topo = json.loads(myfile.read().decode())["topology"] assert topo["nodes"][0][ "compute_id"] == "local" # All node should have compute_id local after export assert topo["computes"] == []
async def test_export_images_from_vm(tmpdir, project): """ If data is on a remote server export it locally before sending it in the archive. """ compute = MagicMock() compute.id = "vm" compute.list_files = AsyncioMagicMock( return_value=[{ "path": "vm-1/dynamips/test" }]) # Fake file that will be download from the vm mock_response = AsyncioMagicMock() mock_response.content = AsyncioBytesIO() await mock_response.content.write(b"HELLO") mock_response.content.seek(0) mock_response.status = 200 compute.download_file = AsyncioMagicMock(return_value=mock_response) mock_response = AsyncioMagicMock() mock_response.content = AsyncioBytesIO() await mock_response.content.write(b"IMAGE") mock_response.content.seek(0) mock_response.status = 200 compute.download_image = AsyncioMagicMock(return_value=mock_response) project._project_created_on_compute.add(compute) path = project.path os.makedirs(os.path.join(path, "vm-1", "dynamips")) topology = { "topology": { "nodes": [{ "compute_id": "vm", "properties": { "image": "test.image" }, "node_type": "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(json.dumps(topology)) with aiozipstream.ZipFile() as z: await export_project(z, project, str(tmpdir), include_images=True) assert compute.list_files.called await write_file(str(tmpdir / 'zipfile.zip'), z) 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" with myzip.open("images/dynamips/test.image") as myfile: content = myfile.read() assert content == b"IMAGE"