From b94a4e2308eb2948d0216419171ec08d2e53ddb7 Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Mon, 27 Jul 2015 16:19:15 +0200 Subject: [PATCH] Add code for creating qemu image on server side Ref https://github.com/GNS3/gns3-gui/issues/558 --- gns3server/modules/qemu/__init__.py | 1 + gns3server/modules/qemu/qemu_vm.py | 45 +++++++++++++++++++++++++-- tests/modules/qemu/test_qemu_vm.py | 47 +++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 3 deletions(-) diff --git a/gns3server/modules/qemu/__init__.py b/gns3server/modules/qemu/__init__.py index 826bfbe5..1df45c09 100644 --- a/gns3server/modules/qemu/__init__.py +++ b/gns3server/modules/qemu/__init__.py @@ -186,3 +186,4 @@ class Qemu(BaseManager): Return the full path of the images directory on disk """ return os.path.join(os.path.expanduser(self.config.get_section_config("Server").get("images_path", "~/GNS3/images")), "QEMU") + diff --git a/gns3server/modules/qemu/qemu_vm.py b/gns3server/modules/qemu/qemu_vm.py index 561e521c..23ec38fd 100644 --- a/gns3server/modules/qemu/qemu_vm.py +++ b/gns3server/modules/qemu/qemu_vm.py @@ -1002,9 +1002,13 @@ class QemuVM(BaseVM): else: return [] - @asyncio.coroutine - def _disk_options(self): - options = [] + def _get_qemu_img(self): + """ + Search the qemu-img binary in the same binary of the qemu binary + for avoiding version incompatibily. + + :returns: qemu-img path or raise an error + """ qemu_img_path = "" qemu_path_dir = os.path.dirname(self.qemu_path) try: @@ -1017,6 +1021,13 @@ class QemuVM(BaseVM): if not qemu_img_path: raise QemuError("Could not find qemu-img in {}".format(qemu_path_dir)) + return qemu_img_path + + @asyncio.coroutine + def _disk_options(self): + options = [] + qemu_img_path = self._get_qemu_img() + if self._hda_disk_image: if not os.path.isfile(self._hda_disk_image) or not os.path.exists(self._hda_disk_image): if os.path.islink(self._hda_disk_image): @@ -1231,3 +1242,31 @@ class QemuVM(BaseVM): answer["kernel_image_md5sum"] = md5sum(self._kernel_image) return answer + + @asyncio.coroutine + def _create_disk(self, name, options): + """ + Create a qemu disk with qemu-img + + :param name: Image name without the extension + :param options: Disk image creation options + :returns: Image name with the extensions + """ + + img_type = options.pop("type") + img_size = options.pop("size") + img_name = "{}.{}".format(name, img_type) + + qemu_img = self._get_qemu_img() + command = [qemu_img, "create", "-f", img_type] + for option in sorted(options.keys()): + command.extend(["-o", "{}={}".format(option, options[option])]) + command.append(os.path.join(self.working_dir, img_name)) + command.append("{}M".format(img_size)) + try: + process = yield from asyncio.create_subprocess_exec(*command) + yield from process.wait() + except (OSError, subprocess.SubprocessError) as e: + raise QemuError("Could create disk image {}:{}".format(name, e)) + + return img_name diff --git a/tests/modules/qemu/test_qemu_vm.py b/tests/modules/qemu/test_qemu_vm.py index 70b22c8d..05c26cac 100644 --- a/tests/modules/qemu/test_qemu_vm.py +++ b/tests/modules/qemu/test_qemu_vm.py @@ -408,3 +408,50 @@ def test_options(vm): vm.options = "-usb" assert vm.options == "-usb" assert vm.kvm is False + + +def test_get_qemu_img(vm, tmpdir): + + open(str(tmpdir / "qemu-sytem-x86_64"), "w+").close() + open(str(tmpdir / "qemu-img"), "w+").close() + vm._qemu_path = str(tmpdir / "qemu-sytem-x86_64") + assert vm._get_qemu_img() == str(tmpdir / "qemu-img") + + +def test_get_qemu_img_not_exist(vm, tmpdir): + + open(str(tmpdir / "qemu-sytem-x86_64"), "w+").close() + vm._qemu_path = str(tmpdir / "qemu-sytem-x86_64") + with pytest.raises(QemuError): + vm._get_qemu_img() + + +def test_create_image(vm, loop, fake_qemu_img_binary): + options = { + "type": "qcow2", + "preallocation": "metadata", + "cluster_size": 64, + "refcount_bits": 12, + "lazy_refcounts": "off", + "size": 100 + } + with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process: + filename = loop.run_until_complete(asyncio.async(vm._create_disk("hda", options))) + args, kwargs = process.call_args + assert args == ( + fake_qemu_img_binary, + "create", + "-f", + "qcow2", + "-o", + "cluster_size=64", + "-o", + "lazy_refcounts=off", + "-o", + "preallocation=metadata", + "-o", + "refcount_bits=12", + os.path.join(vm.working_dir, "hda.qcow2"), + "100M" + ) + assert filename == "hda.qcow2"