Partitioning VMID space

jtru

New Member
Sep 11, 2025
9
2
3
johannes.truschnigg.info
We are in the process of planning and experimenting with a VMware -> PVE migration that will be performed at the start of next year. One concept we are struggling a bit with are the integer VMIDs that PVE uses to uniquely identify VMs/gues workloads.

To keep the different animals in our zoo tidily separate from each other, we would like to establish a strict convention for which particular sub-range of VMIDs is reserved for which kind of workload. The most trivial distinction is going to be templates (VMIDs between 100 and 999) vs. non-templates (VMIDs >=1000), but there's other things that we would like to keep separate, like user-facing VMs (VMIDs between 1000 and 9999) and purely internal infrastructure VMs (between 100000 and 999999, with prefixes in these IDs encoding various kinds of information).

What I am looking for to make this happen is a way to ask the PVE API not for "the next VMID that could be allocated", but for "the next VMID that could be allocated between lower bound n and upper bound n+m". Combing through docs, it seems like I could get that behavior by calling
Code:
pvesh set /cluster/options --next-id lower=$m,upper=$((m+n))
right before each allocation of a new VMID (while ensuring a pipelined, strictly ordered execution of API calls).

My question is: Is this a sound idea, or does changing this setting frequently (i.e., up to several dozens of times a day) have the potential to hurt a cluster's availability/stability in any way? Or is there an alternative, better way to achieve our desired outcome of a "partitioned" VMID continuum?
 
  • Like
Reactions: mpit
? Or is there an alternative, better way to achieve our desired outcome of a "partitioned" VMID continuum?
Since you are already maintaining an external map of category=lower-upper, I'd try to avoid frequent cluster changes. The easiest way is to add another field in your map for last used, or next free.

Another option is to generate next ID on the fly. Here is an example of shell way, you can, of course, re-implement it in your language of choice:
Code:
# Function: get_first_free_vmid
# Arguments: lower bound, upper bound
get_first_free_vmid() {
    local LOWER=$1
    local UPPER=$2

    if [ -z "$LOWER" ] || [ -z "$UPPER" ]; then
        echo "Usage: get_first_free_vmid <lower> <upper>" >&2
        return 1
    fi

    # Step 1: get existing VM IDs
    local EXISTING
    EXISTING=$(pvesh get /cluster/resources --type vm --output-format json \
        | jq -r '[.[] | .vmid | tonumber] | unique | @sh')

    # Step 2: generate candidate IDs
    local CANDIDATES
    CANDIDATES=$(seq "$LOWER" "$UPPER")

    # Step 3: find first available ID
    local FIRST_FREE=""
    for id in $CANDIDATES; do
        if ! echo "$EXISTING" | grep -qw "$id"; then
            FIRST_FREE=$id
            break
        fi
    done

    # Step 4: output result or error
    if [ -n "$FIRST_FREE" ]; then
        echo "$FIRST_FREE"
        return 0
    else
        echo "No free VM ID found in range $LOWER-$UPPER" >&2
        return 2
    fi
}

get_first_free_vmid $1 $2



Blockbridge : Ultra low latency all-NVME shared storage for Proxmox - https://www.blockbridge.com/proxmox
 
Last edited:
  • Like
Reactions: jtru