From 446f3ec9799cfd59e0678e5c3edb86d4c8bd3baa Mon Sep 17 00:00:00 2001 From: Claus Lohmar Date: Mon, 27 Jul 2026 14:02:46 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20skip=20qemu-img=20convert=20=E2=80=94?= =?UTF-8?q?=20import=20VMDK=20directly=20via=20qm=20importdisk,=20only=20c?= =?UTF-8?q?onvert=20if=20per-disk=20shrink=20requested?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/provisioner.py | 53 ++++++++---------------------------------- 1 file changed, 10 insertions(+), 43 deletions(-) diff --git a/backend/provisioner.py b/backend/provisioner.py index 4f69e4c..49c3be7 100644 --- a/backend/provisioner.py +++ b/backend/provisioner.py @@ -335,19 +335,16 @@ def _process_job(job_id: str, req: JobSubmissionRequest): except Exception: pass - # Convert with real-time progress - _convert_with_progress( - job_id, source_path, output_path, disk.format, - start_pct=10 + idx * 10, end_pct=55 + idx * 10, - ) - - # Delete source VMDK after conversion to free space - if source_path.exists() and source_path != src_path: - try: - source_path.unlink() - logger.info("Deleted source disk: %s", source_path) - except Exception: - pass + # Import directly — qm importdisk handles conversion natively + # Only convert if shrink was explicitly requested for this disk + need_shrink = getattr(spec, 'target_disk_size_gb', None) + if need_shrink and need_shrink < disk.size_gb: + _convert_with_progress( + job_id, source_path, output_path, disk.format, + start_pct=10 + idx * 10, end_pct=35 + idx * 10, + ) + else: + output_path = source_path # skip convert, point to original file else: size_gb = spec.size_gb or 32 logger.info("Creating empty disk %d: %d GiB", idx, size_gb) @@ -358,36 +355,6 @@ def _process_job(job_id: str, req: JobSubmissionRequest): disk_paths.append(output_path) - # ── Resize boot disk if needed ────────────────────────────── - boot_disk = disk_paths[0] if disk_paths else None - if boot_disk and boot_disk.exists(): - info_json = _run(["qemu-img", "info", "--output=json", str(boot_disk)]).stdout - info = json.loads(info_json) - current_bytes = info.get("virtual-size", 0) - current_gb = current_bytes / (1024 ** 3) - - target_gb = req.target_disk_size_gb - if target_gb is None: - logger.info("Disk size not specified — keeping current (%.1f GiB)", current_gb) - elif target_gb < current_gb: - _update_job(job_id, progress=60, - message=f"Shrinking disk to {target_gb} GiB...") - logger.info("Shrinking disk: %.1f GiB → %d GiB via virt-resize", current_gb, target_gb) - try: - temp = Path(str(boot_disk) + ".resized") - _run(["qemu-img", "create", "-f", "qcow2", str(temp), f"{target_gb}G"]) - _run(["virt-resize", "--shrink", "--resize-force", - str(boot_disk), str(temp)], timeout=7200) - os.remove(boot_disk) - os.rename(temp, boot_disk) - logger.info("Disk shrunk successfully via virt-resize") - except Exception: - logger.warning("virt-resize failed — falling back to qemu-img resize (may corrupt FS)") - _run(["qemu-img", "resize", "--shrink", str(boot_disk), f"{target_gb}G"]) - elif target_gb > current_gb: - logger.info("Expanding disk: %.1f GiB → %d GiB", current_gb, target_gb) - _run(["qemu-img", "resize", str(boot_disk), f"{target_gb}G"]) - # ── Detach any existing VM with this ID ───────────────────── existing = subprocess.run(["qm", "status", str(vmid)], capture_output=True, text=True)