diff --git a/gns3server/compute/base_manager.py b/gns3server/compute/base_manager.py index 392e595d..4cbe6f00 100644 --- a/gns3server/compute/base_manager.py +++ b/gns3server/compute/base_manager.py @@ -483,7 +483,9 @@ class BaseManager: path = os.path.relpath(os.path.join(root, filename), img_dir) images.append({ "filename": filename, - "path": path}) + "path": path, + "md5sum": md5sum(os.path.join(root, filename)), + "filesize": os.stat(os.path.join(root, filename)).st_size}) return images def get_images_directory(self): @@ -507,7 +509,7 @@ class BaseManager: os.makedirs(os.path.dirname(path), exist_ok=True) with open(tmp_path, 'wb+') as f: while True: - packet = yield from stream.read(512) + packet = yield from stream.read(4096) if not packet: break f.write(packet) diff --git a/gns3server/compute/dynamips/__init__.py b/gns3server/compute/dynamips/__init__.py index 4ac75819..36f98008 100644 --- a/gns3server/compute/dynamips/__init__.py +++ b/gns3server/compute/dynamips/__init__.py @@ -33,6 +33,7 @@ import glob log = logging.getLogger(__name__) from gns3server.utils.interfaces import interfaces, is_interface_up +from gns3server.utils.images import md5sum from gns3server.utils.asyncio import wait_run_in_executor from gns3server.utils import parse_version from uuid import UUID, uuid4 @@ -712,6 +713,9 @@ class Dynamips(BaseManager): continue # valid IOS images must start with the ELF magic number, be 32-bit, big endian and have an ELF version of 1 if elf_header_start == b'\x7fELF\x01\x02\x01': - path = os.path.relpath(path, image_dir) - images.append({"filename": filename, "path": path}) + images.append({"filename": filename, + "path": os.path.relpath(path, image_dir), + "md5sum": md5sum(path), + "filesize": os.stat(path).st_size + }) return images diff --git a/gns3server/controller/compute.py b/gns3server/controller/compute.py index 7a2873dc..fd1a7ebd 100644 --- a/gns3server/controller/compute.py +++ b/gns3server/controller/compute.py @@ -26,7 +26,7 @@ import os import io from ..utils import parse_version -from ..utils.images import scan_for_images +from ..utils.images import scan_for_images, md5sum from ..controller.controller_error import ControllerError from ..config import Config from ..version import __version__ @@ -446,7 +446,7 @@ class Compute: def send_data(f): while True: - chunk = f.read(1024) + chunk = f.read(4096) if not chunk: break yield chunk @@ -543,7 +543,11 @@ class Compute: for path in scan_for_images(type): image = os.path.basename(path) if image not in [i['filename'] for i in images]: - images.append({"filename": image, "path": image}) + images.append({"filename": image, + "path": image, + "md5sum": md5sum(path), + "filesize": os.stat(path).st_size + }) return images @asyncio.coroutine diff --git a/gns3server/schemas/node.py b/gns3server/schemas/node.py index 405bb9ff..91ebd719 100644 --- a/gns3server/schemas/node.py +++ b/gns3server/schemas/node.py @@ -53,6 +53,16 @@ NODE_LIST_IMAGES_SCHEMA = { "description": "Image path", "type": "string", "minLength": 1 + }, + "md5sum": { + "description": "md5sum of the image if available", + "type": ["string", "null"], + "minLength": 1 + }, + "filesize": { + "description": "size of the image if available", + "type": ["integer", "null"], + "minimum": 0 } }, "required": ["filename", "path"], diff --git a/gns3server/utils/images.py b/gns3server/utils/images.py index c58a263c..ce64fe40 100644 --- a/gns3server/utils/images.py +++ b/gns3server/utils/images.py @@ -92,7 +92,9 @@ def md5sum(path): try: with open(path + '.md5sum') as f: - return f.read() + md5 = f.read() + if len(md5) == 32: + return md5 # Unicode error is when user rename an image to .md5sum .... except (OSError, UnicodeDecodeError): pass diff --git a/tests/compute/test_manager.py b/tests/compute/test_manager.py index 647d63ce..4ff2df7f 100644 --- a/tests/compute/test_manager.py +++ b/tests/compute/test_manager.py @@ -226,8 +226,8 @@ def test_list_images(loop, qemu, tmpdir): with patch("gns3server.compute.Qemu.get_images_directory", return_value=str(tmpdir)): assert loop.run_until_complete(qemu.list_images()) == [ - {"filename": "a.bin", "path": "a.bin"}, - {"filename": "b.bin", "path": "b.bin"} + {"filename": "a.bin", "path": "a.bin", "md5sum": "c4ca4238a0b923820dcc509a6f75849b", "filesize": 1}, + {"filename": "b.bin", "path": "b.bin", "md5sum": "c4ca4238a0b923820dcc509a6f75849b", "filesize": 1} ] @@ -245,9 +245,9 @@ def test_list_images_recursives(loop, qemu, tmpdir): with patch("gns3server.compute.Qemu.get_images_directory", return_value=str(tmpdir)): assert loop.run_until_complete(qemu.list_images()) == [ - {"filename": "a.bin", "path": "a.bin"}, - {"filename": "b.bin", "path": "b.bin"}, - {"filename": "c.bin", "path": os.path.sep.join(["c", "c.bin"])} + {"filename": "a.bin", "path": "a.bin", "md5sum": "c4ca4238a0b923820dcc509a6f75849b", "filesize": 1}, + {"filename": "b.bin", "path": "b.bin", "md5sum": "c4ca4238a0b923820dcc509a6f75849b", "filesize": 1}, + {"filename": "c.bin", "path": os.path.sep.join(["c", "c.bin"]), "md5sum": "c4ca4238a0b923820dcc509a6f75849b", "filesize": 1} ] diff --git a/tests/controller/test_compute.py b/tests/controller/test_compute.py index bad0e6c4..24328ba2 100644 --- a/tests/controller/test_compute.py +++ b/tests/controller/test_compute.py @@ -350,13 +350,18 @@ def test_images(compute, async_run, images_dir): """ response = MagicMock() response.status = 200 - response.read = AsyncioMagicMock(return_value=json.dumps([{"filename": "linux.qcow2", "path": "linux.qcow2"}]).encode()) + response.read = AsyncioMagicMock(return_value=json.dumps([{ + "filename": "linux.qcow2", + "path": "linux.qcow2", + "md5sum": "d41d8cd98f00b204e9800998ecf8427e", + "filesize": 0}]).encode()) open(os.path.join(images_dir, "asa.qcow2"), "w+").close() with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock: images = async_run(compute.images("qemu")) mock.assert_called_with("GET", "https://example.com:84/v2/compute/qemu/images", auth=None, data=None, headers={'content-type': 'application/json'}, chunked=False) - assert images == [{"filename": "linux.qcow2", "path": "linux.qcow2"}, {"filename": "asa.qcow2", "path": "asa.qcow2"}] + assert images == [{"filename": "linux.qcow2", "path": "linux.qcow2", "md5sum": "d41d8cd98f00b204e9800998ecf8427e", "filesize": 0}, + {"filename": "asa.qcow2", "path": "asa.qcow2", "md5sum": "d41d8cd98f00b204e9800998ecf8427e", "filesize": 0}] def test_list_files(project, async_run, compute): diff --git a/tests/handlers/api/compute/test_dynamips.py b/tests/handlers/api/compute/test_dynamips.py index 30654c37..c7666fad 100644 --- a/tests/handlers/api/compute/test_dynamips.py +++ b/tests/handlers/api/compute/test_dynamips.py @@ -156,7 +156,11 @@ def test_images(http_compute, tmpdir, fake_dynamips, fake_file): with patch("gns3server.compute.Dynamips.get_images_directory", return_value=str(tmpdir), example=True): response = http_compute.get("/dynamips/images") assert response.status == 200 - assert response.json == [{"filename": "7200.bin", "path": "7200.bin"}] + assert response.json == [{"filename": "7200.bin", + "path": "7200.bin", + "filesize": 7, + "md5sum": "b0d5aa897d937aced5a6b1046e8f7e2e" + }] def test_upload_image(http_compute, tmpdir): diff --git a/tests/handlers/api/compute/test_iou.py b/tests/handlers/api/compute/test_iou.py index c0a1537f..16c344e3 100644 --- a/tests/handlers/api/compute/test_iou.py +++ b/tests/handlers/api/compute/test_iou.py @@ -307,7 +307,7 @@ def test_images(http_compute, fake_iou_bin): response = http_compute.get("/iou/images", example=True) assert response.status == 200 - assert response.json == [{"filename": "iou.bin", "path": "iou.bin"}] + assert response.json == [{"filename": "iou.bin", "path": "iou.bin", "filesize": 7, "md5sum": "e573e8f5c93c6c00783f20c7a170aa6c"}] def test_image_vm(http_compute, tmpdir): diff --git a/tests/handlers/api/compute/test_qemu.py b/tests/handlers/api/compute/test_qemu.py index 2f00c2b2..ec61dea7 100644 --- a/tests/handlers/api/compute/test_qemu.py +++ b/tests/handlers/api/compute/test_qemu.py @@ -226,7 +226,7 @@ def test_images(http_compute, tmpdir, fake_qemu_vm): response = http_compute.get("/qemu/images") assert response.status == 200 - assert response.json == [{"filename": "linux载.img", "path": "linux载.img"}] + assert response.json == [{"filename": "linux载.img", "path": "linux载.img", "md5sum": "c4ca4238a0b923820dcc509a6f75849b", "filesize": 1}] def test_upload_image(http_compute, tmpdir):