Add ova2vzdump: OVA -> Proxmox vzdump (.vma.zst) converter
Dockerized converter that turns VirtualBox/VMware OVA appliances into native Proxmox vzdump backups restorable via qmrestore, without needing a PVE host. - OVF parser (CPU/RAM/disks/NICs, SCSI/SATA/IDE controllers) - Streaming OVA extractor - qemu-server.conf generator with required #qmdump#map lines - Orchestrator: qemu-img convert -> vma create -> zstd - Click CLI: convert, create-test-ova, gui subcommands - Flask web UI with Convert + Create-test-OVA tabs, SSE progress - Dockerfile: Debian bookworm + pve-no-subscription for vma/qemu-img, pre-caches Alpine tiny raw image (sha512-verified) for bootable test-OVA generation - End-to-end verified: generated OVA imports into VirtualBox, converted vzdump restores on Proxmox and the VM boots Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Thin CLI wrapper so folks can run the test-OVA builder without having
|
||||
the package installed in their active env. Prefer `ova2vzdump create-test-ova`
|
||||
when possible."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
|
||||
|
||||
from ova2vzdump.test_ova import create_test_ova # noqa: E402
|
||||
|
||||
|
||||
def main() -> None:
|
||||
ap = argparse.ArgumentParser(description=__doc__)
|
||||
ap.add_argument("output", type=Path)
|
||||
ap.add_argument("--name", default="test-vm")
|
||||
ap.add_argument("--size-mib", type=int, default=64)
|
||||
ap.add_argument("--bootable", action="store_true",
|
||||
help="Package pre-cached bootable Alpine image")
|
||||
ap.add_argument("--force", action="store_true",
|
||||
help="Overwrite existing output file")
|
||||
args = ap.parse_args()
|
||||
|
||||
r = create_test_ova(
|
||||
output=args.output, vm_name=args.name, size_mib=args.size_mib,
|
||||
bootable=args.bootable, force=args.force,
|
||||
)
|
||||
if r.reused:
|
||||
print(f"reused existing {r.path} ({r.bytes} bytes) "
|
||||
"(pass --force to rebuild)")
|
||||
else:
|
||||
kind = "bootable Alpine" if r.bootable else "empty stub"
|
||||
print(f"wrote {r.path} ({r.bytes} bytes, {kind})")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user