hyper2kvm

Comprehensive CLI Reference

hyper2kvm.py is a production-minded tool for converting VMware workloads into KVM/QEMU-friendly disk images (qcow2/raw/vdi) while applying the fixes that actually make migrations succeed: stable /etc/fstab, bootloader/root= alignment, initramfs regeneration, VMware tools cleanup, Windows virtio enablement, plus “prove it boots” smoke tests.

This document is the interface contract for the CLI as implemented by your current build_parser() + YAML-driven validator. It does not add new flags. It’s written fresh for the new model: config selects the operation, CLI optionally overrides.


Prerequisites

Before using hyper2kvm commands, ensure you have:

Table of Contents


Design Principles

Config-first, automation-friendly

Safety is a feature

Works in the mess

Designed for real VMware → KVM pain: snapshot chains, unstable by-path naming, boot plumbing, mixed distros, Windows storage enablement, and verification.


How to Run (New Model)

Standard run (config chooses operation)

sudo python hyper2kvm.py --config job.yaml
```bash

### Merge configs (base + overrides)

```bash
sudo python hyper2kvm.py --config base.yaml --config override.yaml
```bash

### Override a knob from CLI (config still drives the run)

```bash
sudo python hyper2kvm.py --config job.yaml --output-dir /var/tmp/out -vv
```bash

### Inspect merged config (does not require cmd)

```bash
sudo python hyper2kvm.py --config job.yaml --dump-config
```bash

### Inspect final parsed args (requires cmd because validation runs)

```bash
sudo python hyper2kvm.py --config job.yaml --dump-args
```bash

---

## Required Config Keys

### `cmd`

Every run must specify a command via config (or via CLI `--cmd` override):

* **Config key:** `cmd`
* **CLI override:** `--cmd`

Supported `cmd` values enforced by `validate_args()`:

* `local` - Convert local VMDK file (alias: `migrate`)
* `migrate` - Alias for `local` command (for user convenience)
* `fetch-and-fix` - Fetch from ESXi via SSH and convert
* `ova` - Extract and convert OVA archive
* `ovf` - Extract and convert OVF package
* `vhd` - Convert VHD/Azure disk
* `ami` - Extract and convert AMI/cloud tarball
* `raw` - Extract and convert raw disk image/tarball
* `live-fix` - Apply fixes to running VM via SSH
* `libvirt-xml` - Parse libvirt XML and generate manifest
* `vsphere` - vSphere/vCenter operations
* `azure` - Azure VM migration operations
* `daemon` - Watch directory for incoming VMs
* `generate-systemd` - Generate systemd service unit

### `vs_action` (only when `cmd: vsphere`)

vSphere mode requires:

* **Config key:** `vs_action`
* **CLI override:** `--vs-action`

---

## Quick Start Examples (Config-Driven)

### 1) Local VMDK → qcow2 with fixes + compression (recommended)

**job.yaml**

```yaml
cmd: local
vmdk: /path/to/vm.vmdk

output_dir: ./out
flatten: true
to_output: vm-fixed.qcow2
out_format: qcow2
compress: true
compress_level: 6
checksum: true

fstab_mode: stabilize-all
regen_initramfs: true
remove_vmware_tools: true
print_fstab: true

verbose: 1
report: ./out/report.md
```bash

Run:

```bash
sudo python hyper2kvm.py --config job.yaml
```bash

### 2) Dry-run preview (no writes)

```bash
sudo python hyper2kvm.py --config job.yaml --dry-run -vv
```bash

### 3) Base + override

```bash
sudo python hyper2kvm.py --config base.yaml --config rhel10.yaml
```bash

---

## Global Options (CLI flags)

These flags exist on the CLI and can also be supplied via config using their argparse dest names (same spelling with underscores).

### Configuration & introspection

* `--config` *(repeatable, default `[]`)*
  One or more YAML/JSON config files. Later overrides earlier.

* `--dump-config` *(store_true)*
  Print merged normalized config and exit.

* `--dump-args` *(store_true)*
  Print parsed args and exit.

* `--version`
  Print version and exit.

### Logging & verbosity

* `-v, --verbose` *(count, default 0)*
  Increase verbosity (`-v`, `-vv`).

* `--log-file` *(default None)*
  Write logs to a file.

### Operation selection (new project control)

* `--cmd` *(default None)*
  Operation mode. Normally comes from config `cmd`.

* `--vs-action` *(default None)*
  vSphere action. Normally comes from config `vs_action`.

### Paths & behavior

* `--output-dir` *(default `./out`)*
  Root output directory.

* `--workdir` *(default None)*
  Working directory (implementation uses `<output-dir>/work` if unset).

* `--dry-run` *(store_true)*
  Do not modify guest/convert output.

* `--no-backup` *(store_true)*
  Skip backups inside guest.

* `--print-fstab` *(store_true)*
  Print `/etc/fstab` before+after.

---

## Flatten & Conversion Outputs

* `--flatten` *(store_true)*
  Flatten snapshot chain into a single working image first.

* `--flatten-format` *(default `qcow2`, choices: `qcow2|raw`)*
  Flatten output format.

* `--to-output` *(default None)*
  Convert final working image to this path (relative to output-dir if not absolute).

* `--out-format` *(default `qcow2`, choices: `qcow2|raw|vdi`)*
  Final output format.

* `--compress` *(store_true)*
  Enable qcow2 compression.

* `--compress-level` *(int 1–9, default None)*
  Compression level.

* `--checksum` *(store_true)*
  Compute SHA256 checksum of output.

---

## Fixing Behavior

* `--fstab-mode` *(choices from `FstabMode`, default `stabilize-all`)*
  How `/etc/fstab` is rewritten.

* `--no-grub` *(store_true)*
  Skip GRUB root= update and device.map cleanup.

* `--regen-initramfs` / `--no-regen-initramfs` *(default True)*
  Enable/disable initramfs + grub regen (best effort).

* `--remove-vmware-tools` *(store_true)*
  Remove VMware tools (Linux only).

* `--cloud-init-config` *(default None)*
  Cloud-init config (YAML/JSON) to inject.

* `--virtio-drivers-dir` *(default None)*
  Path to virtio-win drivers directory for Windows injection.

* `--resize` *(default None)*
  Resize root filesystem (enlarge only, e.g. `+10G` or `50G`).

* `--report` *(default None)*
  Write Markdown report.

---

## Recovery and Performance Knobs

* `--enable-recovery` *(store_true)*
  Enable checkpoint recovery.

* `--parallel-processing` *(store_true)*
  Process multiple disks in parallel.

---

## LUKS Knobs

* `--luks-passphrase` *(default: env `VMDK2KVM_LUKS_PASSPHRASE`)*
* `--luks-passphrase-env` *(default None)*
* `--luks-keyfile` *(default None)*
* `--luks-mapper-prefix` *(default `hyper2kvm-crypt`)*
* `--luks-enable` *(store_true)*

---

## Smoke Tests

* `--libvirt-test` *(store_true)*
* `--qemu-test` *(store_true)*
* `--vm-name` *(default `converted-vm`)*
* `--memory` *(int, default 2048 MiB)*
* `--vcpus` *(int, default 2)*
* `--uefi` *(store_true)*
* `--timeout` *(int, default 60)*
* `--keep-domain` *(store_true)*
* `--headless` *(store_true)*

---

## Daemon Mode

* `--daemon` *(store_true)*
* `--watch-dir` *(default None)*

(When running daemon-style, `cmd: daemon` should be set in config.)

---

## OVA/OVF Helper Knobs

* `--log-virt-filesystems` *(store_true)*
* `--ova-convert-to-qcow2` *(store_true)*
* `--ova-qcow2-dir` *(default None)*
* `--ova-convert-compress` *(store_true)*
* `--ova-convert-compress-level` *(int 1–9, default None)*

---

## AMI / Cloud Tarball Helper Knobs

* `--extract-nested-tar` / `--no-extract-nested-tar` *(default True)*
* `--convert-payload-to-qcow2` *(store_true)*
* `--payload-qcow2-dir` *(default None)*
* `--payload-convert-compress` *(store_true)*
* `--payload-convert-compress-level` *(int 1–9, default None)*

---

## Inputs (Selected by `cmd`)

These are available globally and expected depending on `cmd`:

### `cmd: local`

**Alias:** `migrate` (both commands work identically)

* `--vmdk` *(required via config or CLI)*

Example:

```bash
# Using "local" command
sudo python hyper2kvm.py --config job.yaml --vmdk /path/to/vm.vmdk

# Using "migrate" alias (same result)
command: migrate
vmdk: /path/to/vm.vmdk

cmd: ova

cmd: ovf

cmd: vhd

cmd: ami

Extract and convert AMI/cloud tarball containing disk payload.

cmd: raw

Alternatively accepts:

Example:

command: raw
raw: /images/ubuntu-2204-cloudimg.img
output_dir: ./out
to_output: ubuntu-2204.qcow2
out_format: qcow2
compress: true

cmd: fetch-and-fix

Requires SSH/SCP source:

Additional knobs:

cmd: live-fix

Additional knobs:

cmd: libvirt-xml

Parse libvirt domain XML and generate Artifact Manifest v1.

Additional options:

Example:

command: libvirt-xml
libvirt_xml: /etc/libvirt/qemu/production-db.xml
output_dir: ./out
manifest_filename: production-db-manifest.json
compute_checksums: true

The generated manifest can be used for batch migrations:

hyper2kvm --manifest ./out/production-db-manifest.json

cmd: generate-systemd


vSphere / vCenter (cmd: vsphere)

Connection flags (required)

Credentials:

TLS / URL:

Action selection

In the new model, vs_action comes from config (or --vs-action override).

Supported vs_action values in your parser:

Action-scoped flags (available globally)

Snapshot/CBT:

Download-only:

Required fields by action (enforced by validator)

Example: list VM names (config-driven)

vs-list.yaml

cmd: vsphere
vs_action: list_vm_names

vcenter: vcenter.example.com
vc_user: administrator@vsphere.local
vc_password_env: VC_PASSWORD
vc_insecure: true

json: true
verbose: 1
```bash

Run:

```bash
sudo python hyper2kvm.py --config vs-list.yaml
```bash

### Example: download a VM disk

**vs-dl.yaml**

```yaml
cmd: vsphere
vs_action: download_vm_disk

vcenter: vcenter.example.com
vc_user: administrator@vsphere.local
vc_password_env: VC_PASSWORD
vc_insecure: true

vm_name: myVM
disk: "0"
local_path: ./downloads/myVM-disk0.vmdk
chunk_size: 1048576
json: true
```bash

Run:

```bash
sudo python hyper2kvm.py --config vs-dl.yaml
```bash

---

## Dependency Notes (practical)

* Needs Python 3
* Conversion pipeline typically expects: `qemu-img`, `libguestfs`
* YAML configs require PyYAML
* vSphere mode requires pyvmomi (and any HTTP libs your implementation uses)

---

## Troubleshooting

### Common Issues

#### Issue: Command fails with permission denied

**Symptoms:**
- Error: "Permission denied" when accessing disk images
- Cannot write to output directory

**Solution:**
```bash
# Run with sudo
sudo python -m hyper2kvm --config your-config.yaml

# Or fix permissions
sudo chown $(whoami) /path/to/output/directory

Issue: libguestfs fails to mount disk

Symptoms:

Solution:

# Test libguestfs
sudo libguestfs-test-tool

# Check KVM permissions
sudo usermod -aG kvm $(whoami)
# Log out and back in

# Verify disk image
qemu-img info /path/to/disk.vmdk

For more issues, see Failure Modes.

Next Steps

Continue your migration journey:

Getting Help

Found an issue? Report it on GitHub