Restore images & projects tarballs

This commit is contained in:
Julien Duponchelle 2015-07-21 16:14:03 +02:00
parent 270017d945
commit fc14deee1b
5 changed files with 118 additions and 22 deletions

View File

@ -62,23 +62,29 @@ class UploadHandler:
response.redirect("/upload") response.redirect("/upload")
return return
if data["type"] not in ["IOU", "IOURC", "QEMU", "IOS"]: if data["type"] not in ["IOU", "IOURC", "QEMU", "IOS", "IMAGES", "PROJECTS"]:
raise aiohttp.web.HTTPForbidden("You are not authorized to upload this kind of image {}".format(data["type"])) raise aiohttp.web.HTTPForbidden(text="You are not authorized to upload this kind of image {}".format(data["type"]))
if data["type"] == "IOURC":
destination_dir = os.path.expanduser("~/")
destination_path = os.path.join(destination_dir, ".iourc")
else:
destination_dir = os.path.join(UploadHandler.image_directory(), data["type"])
destination_path = os.path.join(destination_dir, data["file"].filename)
try: try:
os.makedirs(destination_dir, exist_ok=True) if data["type"] == "IMAGES":
with open(destination_path, "wb+") as f: UploadHandler._restore_directory(data["file"], UploadHandler.image_directory())
chunk = data["file"].file.read() elif data["type"] == "PROJECTS":
f.write(chunk) UploadHandler._restore_directory(data["file"], UploadHandler.project_directory())
st = os.stat(destination_path) else:
os.chmod(destination_path, st.st_mode | stat.S_IXUSR) if data["type"] == "IOURC":
destination_dir = os.path.expanduser("~/")
destination_path = os.path.join(destination_dir, ".iourc")
else:
destination_dir = os.path.join(UploadHandler.image_directory(), data["type"])
destination_path = os.path.join(destination_dir, data["file"].filename)
os.makedirs(destination_dir, exist_ok=True)
with open(destination_path, "wb+") as f:
chunk = data["file"].file.read()
f.write(chunk)
st = os.stat(destination_path)
os.chmod(destination_path, st.st_mode | stat.S_IXUSR)
except OSError as e: except OSError as e:
print(e)
response.html("Could not upload file: {}".format(e)) response.html("Could not upload file: {}".format(e))
response.set_status(200) response.set_status(200)
return return
@ -86,7 +92,7 @@ class UploadHandler:
@classmethod @classmethod
@Route.get( @Route.get(
r"/upload/backup/images.tar", r"/backup/images.tar",
description="Backup GNS3 images", description="Backup GNS3 images",
api_version=None api_version=None
) )
@ -95,16 +101,34 @@ class UploadHandler:
@classmethod @classmethod
@Route.get( @Route.get(
r"/upload/backup/projects.tar", r"/backup/projects.tar",
description="Backup GNS3 projects", description="Backup GNS3 projects",
api_version=None api_version=None
) )
def backup_images(request, response): def backup_images(request, response):
yield from UploadHandler._backup_directory(request, response, UploadHandler.project_directory()) yield from UploadHandler._backup_directory(request, response, UploadHandler.project_directory())
@staticmethod
def _restore_directory(file, directory):
"""
Extract from HTTP stream the content of a tar
"""
destination_path = os.path.join(directory, "archive.tar")
os.makedirs(directory, exist_ok=True)
with open(destination_path, "wb+") as f:
chunk = file.file.read()
f.write(chunk)
t = tarfile.open(destination_path)
t.extractall(directory)
t.close()
os.remove(destination_path)
@staticmethod @staticmethod
@asyncio.coroutine @asyncio.coroutine
def _backup_directory(request, response, directory): def _backup_directory(request, response, directory):
"""
Return a tar archive from a directory
"""
response.content_type = 'application/x-gtar' response.content_type = 'application/x-gtar'
response.set_status(200) response.set_status(200)
response.enable_chunked_encoding() response.enable_chunked_encoding()

View File

@ -6,6 +6,6 @@
<ul> <ul>
<li><a href="http://community.gns3.com">Community</a></li> <li><a href="http://community.gns3.com">Community</a></li>
<li><a href="http://api.gns3.net">API documentation</a></li> <li><a href="http://api.gns3.net">API documentation</a></li>
<li><a href="/upload">Upload images</a></li> <li><a href="/upload">Upload images & backup</a></li>
</ul> </ul>
{% endblock %} {% endblock %}

View File

@ -5,11 +5,13 @@
</head> </head>
<body> <body>
<div> <div>
<a href="/upload">Home</a> <a href="/">Home</a>
| |
<a href="/upload/backup/images.tar">Backup images</a> <a href="/upload">Upload</a>
|
<a href="/backup/images.tar">Backup images</a>
| |
<a href="/upload/backup/projects.tar">Backup projects</a> <a href="/backup/projects.tar">Backup projects</a>
</div> </div>
{% block body %}{% endblock %} {% block body %}{% endblock %}
</body> </body>

View File

@ -8,6 +8,8 @@
<option value="IOURC">IOU licence (iourc)</option> <option value="IOURC">IOU licence (iourc)</option>
<option value="IOS">IOS</option> <option value="IOS">IOS</option>
<option value="QEMU">Qemu</option> <option value="QEMU">Qemu</option>
<option value="IMAGES">GNS3 images backup (.tar)</option>
<option value="PROJECTS">GNS3 projects backup (.tar)</option>
</select> </select>
<br /> <br />
<br /> <br />

View File

@ -51,6 +51,74 @@ def test_upload(server, tmpdir):
assert "test2" in response.body.decode("utf-8") assert "test2" in response.body.decode("utf-8")
def test_upload_images_backup(server, tmpdir):
Config.instance().set("Server", "images_path", str(tmpdir / 'images'))
os.makedirs(str(tmpdir / 'images' / 'IOU'))
# An old IOU image that we need to replace
with open(str(tmpdir / 'images' / 'IOU' / 'b.img'), 'w+') as f:
f.write('bad')
os.makedirs(str(tmpdir / 'old' / 'QEMU'))
with open(str(tmpdir / 'old' / 'QEMU' / 'a.img'), 'w+') as f:
f.write('hello')
os.makedirs(str(tmpdir / 'old' / 'IOU'))
with open(str(tmpdir / 'old' / 'IOU' / 'b.img'), 'w+') as f:
f.write('world')
os.chdir(str(tmpdir / 'old'))
with tarfile.open(str(tmpdir / 'test.tar'), 'w') as tar:
tar.add('.', recursive=True)
body = aiohttp.FormData()
body.add_field('type', 'IMAGES')
body.add_field('file', open(str(tmpdir / 'test.tar'), 'rb'), content_type='application/x-gtar', filename='test.tar')
response = server.post('/upload', api_version=None, body=body, raw=True)
assert response.status == 200
with open(str(tmpdir / 'images' / 'QEMU' / 'a.img')) as f:
assert f.read() == 'hello'
with open(str(tmpdir / 'images' / 'IOU' / 'b.img')) as f:
assert f.read() == 'world'
assert 'a.img' in response.body.decode('utf-8')
assert 'b.img' in response.body.decode('utf-8')
assert not os.path.exists(str(tmpdir / 'images' / 'archive.tar'))
def test_upload_projects_backup(server, tmpdir):
Config.instance().set("Server", "projects_path", str(tmpdir / 'projects'))
os.makedirs(str(tmpdir / 'projects' / 'b'))
# An old b image that we need to replace
with open(str(tmpdir / 'projects' / 'b' / 'b.img'), 'w+') as f:
f.write('bad')
os.makedirs(str(tmpdir / 'old' / 'a'))
with open(str(tmpdir / 'old' / 'a' / 'a.img'), 'w+') as f:
f.write('hello')
os.makedirs(str(tmpdir / 'old' / 'b'))
with open(str(tmpdir / 'old' / 'b' / 'b.img'), 'w+') as f:
f.write('world')
os.chdir(str(tmpdir / 'old'))
with tarfile.open(str(tmpdir / 'test.tar'), 'w') as tar:
tar.add('.', recursive=True)
body = aiohttp.FormData()
body.add_field('type', 'PROJECTS')
body.add_field('file', open(str(tmpdir / 'test.tar'), 'rb'), content_type='application/x-gtar', filename='test.tar')
response = server.post('/upload', api_version=None, body=body, raw=True)
assert response.status == 200
with open(str(tmpdir / 'projects' / 'a' / 'a.img')) as f:
assert f.read() == 'hello'
with open(str(tmpdir / 'projects' / 'b' / 'b.img')) as f:
assert f.read() == 'world'
assert 'a.img' not in response.body.decode('utf-8')
assert 'b.img' not in response.body.decode('utf-8')
assert not os.path.exists(str(tmpdir / 'projects' / 'archive.tar'))
def test_backup_images(server, tmpdir, loop): def test_backup_images(server, tmpdir, loop):
Config.instance().set('Server', 'images_path', str(tmpdir)) Config.instance().set('Server', 'images_path', str(tmpdir))
@ -60,7 +128,7 @@ def test_backup_images(server, tmpdir, loop):
with open(str(tmpdir / 'QEMU' / 'b.img'), 'w+') as f: with open(str(tmpdir / 'QEMU' / 'b.img'), 'w+') as f:
f.write('world') f.write('world')
response = server.get('/upload/backup/images.tar', api_version=None, raw=True) response = server.get('/backup/images.tar', api_version=None, raw=True)
assert response.status == 200 assert response.status == 200
assert response.headers['CONTENT-TYPE'] == 'application/x-gtar' assert response.headers['CONTENT-TYPE'] == 'application/x-gtar'
@ -92,7 +160,7 @@ def test_backup_projects(server, tmpdir, loop):
with open(str(tmpdir / 'b' / 'b.gns3'), 'w+') as f: with open(str(tmpdir / 'b' / 'b.gns3'), 'w+') as f:
f.write('world') f.write('world')
response = server.get('/upload/backup/projects.tar', api_version=None, raw=True) response = server.get('/backup/projects.tar', api_version=None, raw=True)
assert response.status == 200 assert response.status == 200
assert response.headers['CONTENT-TYPE'] == 'application/x-gtar' assert response.headers['CONTENT-TYPE'] == 'application/x-gtar'