How to convert VM from Proxmox To VMware

fcarpintero

New Member
Feb 3, 2023
1
0
1
Hi Community,

Is there official documentation on how to convert a VM from Proxmox to VMware and what tools/converters are used that is CLI or a third party product etc.

Regards!
 
OP asked about PVE > ESX, not the other way around.

Not sure if vmware converter can handle it, but qemu-img certainly seems to be the favorite in various blogs.


Blockbridge : Ultra low latency all-NVME shared storage for Proxmox - https://www.blockbridge.com/proxmox
oh sorry.

If you have a file storage , you can use move disk to convert to vmdk. (works also online if you want to reduce downtime).

qm move_disk <vmid> <disk> <filestorage> --format vmdk

ex:

qm move_disk 100 scsi0 myfilestorage --format vmdk
 
I would consider using the GUI. In your VM select the disk and then at the top of the screen you have 'Disk Actions', one of which is to 'move' the disk and you can select vmdk.
 
  • Like
Reactions: ali rafie
To export a qcow2 to VMDK

Bash:
wget https://cdimage.debian.org/images/cloud/bookworm-backports/latest/debian-12-backports-nocloud-amd64.qcow2
qemu-img convert -f qcow2 -O vmdk ./debian-12-backports-nocloud-amd64.qcow2 ./debian-12-backports-nocloud-amd64.vmdk

To export a disk to VMDK (Source: https://www.reddit.com/r/Proxmox/comments/mg44yy/comment/gsrwgcg/)

Bash:
qemu-img convert -f raw -O vmdk /dev/mapper/mylvm-vm-101-disk-1 /outputdir/image.vmdk

Let's import the into a VM (Source: https://forum.proxmox.com/threads/create-a-vm-from-qcow2.136128/post-603253)

Bash:
qm importdisk $VMID ./debian-12-backports-nocloud-amd64.qcow2 $STORAGE_POOL_NAME

Assign the disk to a storage, and edit the boot order to include the drive.

Export back the VM (ZFS)
Bash:
zfs list -t volume
qemu-img convert -f raw -O vmdk /dev/zvol/rpool/data/vm-12005-disk-0 ./my-vm.vmdk
 
or simply use my script:

tell me how it works ;)

Bash:
#!/bin/bash

# proxmox-vm_vmware.sh - Convert Proxmox VM to VMware format
# Author: 0zzy
# Date: 2023-09-10
# Version: 1.0
# License: MIT
#
# Description: This script converts a Proxmox VM to VMware format.
#              It can convert to VMware VMX, OVF, or OVA format.
#              It requires the ovftool command-line tool.
#              It uses the qemu-img command-line tool to convert disks.
#              It uses the jq command-line tool to parse
#
# To use the Script, run the following command:
# chmod +x proxmox-vm_vmware.sh
#
# Then run it with the required VM ID:
# ./proxmox-vm_vmware.sh -i VMID
# Example: ./proxmox-vm_vmware.sh -i 100
#
# Or with additional options:
# ./proxmox-vm_vmware.sh -i 100 -n MyVM -d /path/to/output -f ova


set -e

# Function to display usage information
function show_usage() {
    echo "Usage: $0 -i VMID [-n VM_NAME] [-d DESTINATION] [-f FORMAT]"
    echo
    echo "Options:"
    echo "  -i VMID         Proxmox VM ID to convert"
    echo "  -n VM_NAME      Name for the converted VM (default: uses original VM name)"
    echo "  -d DESTINATION  Destination directory for converted files (default: current directory)"
    echo "  -f FORMAT       VMware format (vmx, ovf, ova) (default: vmx)"
    echo "  -h              Show this help message"
    exit 1
}

# Function to check if a command exists
function check_command() {
    if ! command -v "$1" &> /dev/null; then
        echo "Error: Required command '$1' not found. Please install it."
        exit 1
    fi
}

# Function to log messages
function log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}

# Parse command line arguments
VMID=""
VM_NAME=""
DESTINATION="$(pwd)"
FORMAT="vmx"

while getopts "i:n:d:f:h" opt; do
    case $opt in
        i) VMID="$OPTARG" ;;
        n) VM_NAME="$OPTARG" ;;
        d) DESTINATION="$OPTARG" ;;
        f) FORMAT="$OPTARG" ;;
        h) show_usage ;;
        *) show_usage ;;
    esac
done

# Check if VMID is provided
if [ -z "$VMID" ]; then
    echo "Error: VM ID is required"
    show_usage
fi

# Check required tools
check_command qemu-img
check_command jq

# Check if we're running on a Proxmox host
if [ ! -f /etc/pve/qemu-server/${VMID}.conf ]; then
    echo "Error: VM with ID ${VMID} not found on this Proxmox host"
    exit 1
fi

# Create temporary working directory
TEMP_DIR=$(mktemp -d)
log "Created temporary directory: $TEMP_DIR"

# Cleanup function
function cleanup() {
    log "Cleaning up temporary files..."
    rm -rf "$TEMP_DIR"
}

# Register cleanup function to run on exit
trap cleanup EXIT

# Get VM details
if [ -z "$VM_NAME" ]; then
    VM_NAME=$(grep -E "^name:" /etc/pve/qemu-server/${VMID}.conf | cut -d' ' -f2)
    if [ -z "$VM_NAME" ]; then
        VM_NAME="vm-${VMID}"
    fi
fi

log "Converting Proxmox VM ${VMID} (${VM_NAME}) to VMware format"

# Create destination directory if it doesn't exist
mkdir -p "$DESTINATION"

# Get disk information
DISKS=$(grep -E "^(scsi|sata|ide)[0-9]+:" /etc/pve/qemu-server/${VMID}.conf | grep -v "cdrom")

# Check if VM is running
if qm status $VMID | grep -q running; then
    log "Warning: VM is currently running. It's recommended to shut it down before conversion."
    read -p "Do you want to continue anyway? (y/N): " CONTINUE
    if [[ ! "$CONTINUE" =~ ^[Yy]$ ]]; then
        log "Conversion aborted"
        exit 0
    fi
fi

# Process each disk
DISK_COUNT=0
VMX_DISK_ENTRIES=""

log "Processing VM disks..."
while read -r DISK_LINE; do
    # Extract disk details
    DISK_ID=$(echo "$DISK_LINE" | cut -d: -f1)
    
    # Extract just the disk path, ignoring additional parameters
    DISK_PATH=$(echo "$DISK_LINE" | cut -d' ' -f2 | cut -d, -f1)
    
    log "Processing disk: $DISK_ID with path: $DISK_PATH"
    
    if [[ "$DISK_PATH" == *":"* ]]; then
        # Handle storage:disk format
        STORAGE=$(echo "$DISK_PATH" | cut -d: -f1)
        DISK_FILE=$(echo "$DISK_PATH" | cut -d: -f2)
        
        log "Getting full path for storage: $STORAGE, disk: $DISK_FILE"
        FULL_PATH=$(pvesm path "$STORAGE:$DISK_FILE")
    else
        # Handle direct path
        FULL_PATH="$DISK_PATH"
    fi
    
    log "Full disk path: $FULL_PATH"
    
    # Get disk format
    DISK_FORMAT=$(qemu-img info "$FULL_PATH" | grep "file format" | cut -d' ' -f3)
    log "Disk format: $DISK_FORMAT"
    
    # Convert disk to VMDK
    VMDK_NAME="${VM_NAME}-disk${DISK_COUNT}.vmdk"
    log "Converting disk $DISK_ID ($FULL_PATH) to VMDK format..."
    qemu-img convert -f "$DISK_FORMAT" -O vmdk "$FULL_PATH" "$TEMP_DIR/$VMDK_NAME"
    
    # Copy to destination
    cp "$TEMP_DIR/$VMDK_NAME" "$DESTINATION/"
    
    # Add to VMX entries
    VMX_DISK_ENTRIES+="scsi${DISK_COUNT}.present = \"TRUE\"\n"
    VMX_DISK_ENTRIES+="scsi${DISK_COUNT}.fileName = \"${VMDK_NAME}\"\n"
    
    DISK_COUNT=$((DISK_COUNT + 1))
done <<< "$DISKS"

# Get memory and CPU information
MEMORY=$(grep -E "^memory:" /etc/pve/qemu-server/${VMID}.conf | cut -d' ' -f2)
MEMORY=${MEMORY:-2048}  # Default to 2GB if not specified
CORES=$(grep -E "^cores:" /etc/pve/qemu-server/${VMID}.conf | cut -d' ' -f2)
CORES=${CORES:-1}  # Default to 1 core if not specified
SOCKETS=$(grep -E "^sockets:" /etc/pve/qemu-server/${VMID}.conf | cut -d' ' -f2)
SOCKETS=${SOCKETS:-1}  # Default to 1 socket if not specified

# Create VMX file
if [ "$FORMAT" = "vmx" ] || [ "$FORMAT" = "ovf" ] || [ "$FORMAT" = "ova" ]; then
    log "Creating VMX file..."
    cat > "$TEMP_DIR/${VM_NAME}.vmx" << EOF
.encoding = "UTF-8"
config.version = "8"
virtualHW.version = "19"
pciBridge0.present = "TRUE"
pciBridge4.present = "TRUE"
pciBridge4.virtualDev = "pcieRootPort"
pciBridge4.functions = "8"
pciBridge5.present = "TRUE"
pciBridge5.virtualDev = "pcieRootPort"
pciBridge5.functions = "8"
pciBridge6.present = "TRUE"
pciBridge6.virtualDev = "pcieRootPort"
pciBridge6.functions = "8"
pciBridge7.present = "TRUE"
pciBridge7.virtualDev = "pcieRootPort"
pciBridge7.functions = "8"
vmci0.present = "TRUE"
displayName = "${VM_NAME}"
numvcpus = "$((CORES * SOCKETS))"
memsize = "${MEMORY}"
scsi0.virtualDev = "lsisas1068"
scsi0.present = "TRUE"
$(echo -e "$VMX_DISK_ENTRIES")
ethernet0.virtualDev = "vmxnet3"
ethernet0.present = "TRUE"
ethernet0.connectionType = "bridged"
ethernet0.startConnected = "TRUE"
ethernet0.addressType = "generated"
bios.bootDelay = "5000"
powerType.powerOff = "soft"
powerType.powerOn = "hard"
powerType.suspend = "hard"
powerType.reset = "soft"
tools.syncTime = "FALSE"
EOF

    # Copy VMX file to destination
    cp "$TEMP_DIR/${VM_NAME}.vmx" "$DESTINATION/"
    log "VMX file created at $DESTINATION/${VM_NAME}.vmx"
fi

# Convert to OVF/OVA if requested
if [ "$FORMAT" = "ovf" ] || [ "$FORMAT" = "ova" ]; then
    log "Converting to $FORMAT format..."
    check_command ovftool
    
    if [ "$FORMAT" = "ovf" ]; then
        ovftool "$DESTINATION/${VM_NAME}.vmx" "$DESTINATION/${VM_NAME}.ovf"
        log "OVF file created at $DESTINATION/${VM_NAME}.ovf"
    else
        ovftool "$DESTINATION/${VM_NAME}.vmx" "$DESTINATION/${VM_NAME}.ova"
        log "OVA file created at $DESTINATION/${VM_NAME}.ova"
        
        # Remove VMX and VMDK files as they're now in the OVA
        rm "$DESTINATION/${VM_NAME}.vmx"
        for ((i=0; i<DISK_COUNT; i++)); do
            rm "$DESTINATION/${VM_NAME}-disk${i}.vmdk"
        done
    fi
fi

log "Conversion completed successfully!"
log "VM files are available in: $DESTINATION"