Is your feature request related to a problem? Please describe.
vcsim's ReconfigVM_Task handler never reads or reflects VirtualMachineConfigSpec.VirtualNuma into VirtualMachineConfigInfo.NumaInfo. Confirmed via grep -n "VirtualNuma\|NumaInfo" simulator/virtual_machine.go on v0.55.0-alpha.0.0.20260622155957-a8a7db14910d — zero matches. A ReconfigVM_Task that sets an explicit VirtualNuma.CoresPerNumaNode is accepted with no fault, but a subsequent read of config.numaInfo never shows the value — it stays permanently nil, regardless of power state or how many times the identical Reconfigure is repeated.
This diverges from real vSphere. I verified against vSphere 8.0 U1+ (hw version vmx-23, 2-vCPU VM) with a small pyVmomi script: an explicit CoresPerNumaNode is reflected in config.numaInfo.coresPerNumaNode immediately after the Reconfigure task completes — even while the VM is powered off — and it persists correctly across power-on/power-off cycles:
| Step |
NumaInfo.CoresPerNumaNode |
AutoCoresPerNumaNode |
| Before any change |
None |
True |
| After Reconfigure, still powered off |
2 |
False |
| After identical Reconfigure repeated, still off |
2 |
False |
| After power-on |
2 |
False |
| After power-off again |
2 |
False |
After Reconfigure with coresPerNumaNode=0 (rollback to auto) |
None |
True |
Because vcsim never reflects this, any controller that reconciles VirtualNuma/NumaInfo against vcsim by diffing desired vs. live config.numaInfo can never observe convergence — it keeps re-issuing an identical, silently no-op-from-vcsim's-perspective ReconfigVM_Task forever. There's no fault or error, so it only surfaces as a runaway reconcile loop in the consuming project's own tests or safety limits.
Describe the solution you'd like
In the ReconfigVM_Task handler in simulator/virtual_machine.go, when spec.VirtualNuma != nil:
- If
CoresPerNumaNode is set and non-zero, set vm.Config.NumaInfo = &types.VirtualMachineVirtualNumaInfo{CoresPerNumaNode: spec.VirtualNuma.CoresPerNumaNode, AutoCoresPerNumaNode: types.NewBool(false)}.
- If
CoresPerNumaNode == 0, clear the override (NumaInfo = nil or AutoCoresPerNumaNode: true), matching the documented semantics on VirtualMachineVirtualNuma.CoresPerNumaNode ("If set to be zero, it clears any manual override and autosize vNUMA node").
This would make config.numaInfo observable immediately after Reconfigure, matching real vSphere's behavior, and let vcsim-based tests exercise reconcile loops that depend on this field converging.
Describe alternatives you've considered
- Working around this entirely in the consuming project's tests (e.g. dropping vNUMA-topology assertions from vcsim-based tests, or reaching into the simulator's model directly via
Map.Handler/Map.Get to patch config.numaInfo after Reconfigure). This avoids touching vcsim but has to be re-applied by every test that touches this field, and doesn't help anyone else hitting the same gap.
- Leaving
differs()-style convergence checks in consuming controllers to stop trusting live NumaInfo and instead track "last applied" state themselves (e.g. via an annotation). Rejected for our use case specifically because a controller that stops relying on live vSphere state to detect convergence can't tell a real silent rejection by vSphere apart from a successful apply — it would mask genuine reconfigure failures, not just work around a test-environment gap.
Additional context
The VirtualMachineVirtualNuma and VirtualMachineVirtualNumaInfo types are gated to API version 8.0.0.1 (vim:"8.0.0.1" in vim25/types/types.go), consistent with vSphere 8.0 Update 1+. Hardware version requirement observed/enforced on the consuming side is vmx-20+.
Is your feature request related to a problem? Please describe.
vcsim'sReconfigVM_Taskhandler never reads or reflectsVirtualMachineConfigSpec.VirtualNumaintoVirtualMachineConfigInfo.NumaInfo. Confirmed viagrep -n "VirtualNuma\|NumaInfo" simulator/virtual_machine.goonv0.55.0-alpha.0.0.20260622155957-a8a7db14910d— zero matches. AReconfigVM_Taskthat sets an explicitVirtualNuma.CoresPerNumaNodeis accepted with no fault, but a subsequent read ofconfig.numaInfonever shows the value — it stays permanentlynil, regardless of power state or how many times the identical Reconfigure is repeated.This diverges from real vSphere. I verified against vSphere 8.0 U1+ (hw version vmx-23, 2-vCPU VM) with a small pyVmomi script: an explicit
CoresPerNumaNodeis reflected inconfig.numaInfo.coresPerNumaNodeimmediately after the Reconfigure task completes — even while the VM is powered off — and it persists correctly across power-on/power-off cycles:NumaInfo.CoresPerNumaNodeAutoCoresPerNumaNodeNoneTrue2False2False2False2FalsecoresPerNumaNode=0(rollback to auto)NoneTrueBecause vcsim never reflects this, any controller that reconciles
VirtualNuma/NumaInfoagainst vcsim by diffing desired vs. liveconfig.numaInfocan never observe convergence — it keeps re-issuing an identical, silently no-op-from-vcsim's-perspectiveReconfigVM_Taskforever. There's no fault or error, so it only surfaces as a runaway reconcile loop in the consuming project's own tests or safety limits.Describe the solution you'd like
In the
ReconfigVM_Taskhandler insimulator/virtual_machine.go, whenspec.VirtualNuma != nil:CoresPerNumaNodeis set and non-zero, setvm.Config.NumaInfo = &types.VirtualMachineVirtualNumaInfo{CoresPerNumaNode: spec.VirtualNuma.CoresPerNumaNode, AutoCoresPerNumaNode: types.NewBool(false)}.CoresPerNumaNode == 0, clear the override (NumaInfo = nilorAutoCoresPerNumaNode: true), matching the documented semantics onVirtualMachineVirtualNuma.CoresPerNumaNode("If set to be zero, it clears any manual override and autosize vNUMA node").This would make
config.numaInfoobservable immediately after Reconfigure, matching real vSphere's behavior, and let vcsim-based tests exercise reconcile loops that depend on this field converging.Describe alternatives you've considered
Map.Handler/Map.Getto patchconfig.numaInfoafter Reconfigure). This avoids touching vcsim but has to be re-applied by every test that touches this field, and doesn't help anyone else hitting the same gap.differs()-style convergence checks in consuming controllers to stop trusting liveNumaInfoand instead track "last applied" state themselves (e.g. via an annotation). Rejected for our use case specifically because a controller that stops relying on live vSphere state to detect convergence can't tell a real silent rejection by vSphere apart from a successful apply — it would mask genuine reconfigure failures, not just work around a test-environment gap.Additional context
The
VirtualMachineVirtualNumaandVirtualMachineVirtualNumaInfotypes are gated to API version8.0.0.1(vim:"8.0.0.1"invim25/types/types.go), consistent with vSphere 8.0 Update 1+. Hardware version requirement observed/enforced on the consuming side is vmx-20+.