FVMW is a lightweight mock vCenter/ESXi API server that allows stock OpenShift MTV (Migration Toolkit for Virtualization) to perform end-to-end VM migration demos without a real VMware environment.
Built on govmomi/vcsim (Apache 2.0), it presents a fully functional vSphere SOAP API with configurable inventory, disk export, and VMX file serving. The default inventory matches the OpenShift Virtualization Roadshow demo so migration instructions work unchanged.
- Simulates a vCenter-compatible API on a single shared endpoint
- Full vSphere SOAP API with datacenter, cluster, host, datastore, network, folder, and VMs
- Serves flat VMDK disk images via the
/folder/endpoint for virt-v2v disk transfer - Generates VMX files for libvirt domain XML parsing
- XML response rewriter fixes vcsim compatibility issues with libvirt's ESX driver
- Multiple users share the same VMDK images via a CephFS PVC
- Per-user VM names (e.g.
database-user1) viaFVMW_USER_SUFFIXenv var
One shared endpoint serves all users. Each authenticated user gets their own
4 VM names in /RS00/vm/Roadshow/:
| VM | Guest OS | Memory | CPUs | Disk | Controller |
|---|---|---|---|---|---|
database-{user} |
CentOS 8 (64-bit) | 2048MB | 1 | 5GB | pvscsi |
winweb01-{user} |
Windows Server 2022 (64-bit) | 6144MB | 2 | 21GB | lsilogic-sas |
winweb02-{user} |
Windows Server 2022 (64-bit) | 6144MB | 2 | 21GB | lsilogic-sas |
haproxy-{user} |
Other 2.6.x Linux (64-bit) | 4096MB | 2 | 4GB | pvscsi |
Infrastructure: Datacenter RS00, Cluster vcs-rs-00, Network segment-migrating-to-ocpvirt
# Build
make build
# Start locally (VPX or ESX mode)
./scripts/test-local.sh start # VPX mode
./scripts/test-local.sh start esx # ESX mode
./scripts/test-local.sh test # Run govc tests
./scripts/test-local.sh stop
# Open read-only vCenter-like UI
# (login: user1/password, user2/password, etc.)
xdg-open "http://127.0.0.1:18443/ui/"# 1. Configure local secrets
cp local.env.example local.env
vi local.env
# 2. One-time bootstrap (with cluster-admin)
oc login <cluster>
cd deploy/ansible
ansible-playbook bootstrap.yml -e @../../local.env
# 3. Set up build pipeline (uses SA kubeconfig from bootstrap)
ansible-playbook build.yml -e @../../local.env
# 4. Prepare disk images (one-time, see Disk Preparation below)
# 5. Deploy per-user instances
ansible-playbook deploy.yml -e @../../local.envSee deploy/ansible/README.md for full details.
For deploying fvmw itself (Deployment/Service/Route/PVC/Secret) to
additional clusters, a Helm chart is available at
charts/fvmw:
helm install fvmw charts/fvmw \
--namespace fvmw --create-namespace \
--set clusterDomain=apps.mycluster.example.com \
--set fvmw.password=changemeDisk preparation (steps 3-4 above) is still done separately via
deploy/ansible/prepare-disks.yml, or by pointing disks.existingClaim at
an already-populated PVC.
Shared Endpoint:
vcenter.<cluster-domain> Route (edge TLS)
|
fvmw Pod
+----------------------+
| apiType: VirtualCenter
| DC: RS00
| Cluster: vcs-rs-00
| VMs: *-user1, *-user2, ...
+----------------------+
Shared CephFS PVC (/disks):
database.vmdk, database-flat.vmdk
winweb01.vmdk, winweb01-flat.vmdk
winweb02.vmdk, winweb02-flat.vmdk
haproxy.vmdk, haproxy-flat.vmdk
MTV Migration Flow:
1. Provider -> vcenter route -> fvmw (inventory sync)
2. virt-v2v -> vcenter route -> fvmw (VM discovery + VMX metadata)
3. virt-v2v -> vcenter route -> fvmw (download flat VMDK via /folder/)
4. virt-v2v converts disk -> creates KubeVirt VM
VMDK images must be on the shared PVC in monolithicFlat format. To prepare:
# 1. Export VMDKs from a real vCenter (streamOptimized format)
govc export.ovf -vm /DC/vm/database /tmp/export/
# 2. Upload to PVC via a helper pod
oc cp /tmp/export/database-disk-0.vmdk fvmw/helper-pod:/disks/database.vmdk
# 3. Convert to flat format inside the cluster
oc exec helper-pod -- qemu-img convert -O vmdk -o subformat=monolithicFlat \
/disks/database.vmdk /disks/database-flat.vmdkBoth the original (streamOptimized) and flat VMDKs remain on the PVC. The -flat.vmdk files are served via the /folder/ endpoint for virt-v2v.
| Variable | Default | Description |
|---|---|---|
FVMW_LISTEN_ADDR |
:8080 |
HTTP listen address |
FVMW_DISK_PATH |
/disks |
Path to VMDK files |
FVMW_EXTERNAL_HOST |
(none) | Route hostname for ExportVm disk URLs |
FVMW_HOST |
(none) | Hostname published in inventory (set to shared endpoint) |
FVMW_NUM_USERS |
60 |
Number of generated users (user1..userN) |
FVMW_PASSWORD |
password |
Shared password used by generated users |
FVMW_USERNAME |
administrator@vsphere.local |
Legacy single-user login username |
FVMW_USER_SUFFIX |
(none) | Appended to VM names (e.g. -user1) |
FVMW_ESX_MODE |
(none) | Legacy ESXi-only mode |
FVMW_ESXI_PREFIX |
(none) | Optional hostname prefix that rewrites apiType to HostAgent |
FVMW_TRACE |
(none) | Set to 1 for SOAP request/response logging |
- Create an MTV VMware Provider pointing to
https://vcenter.<cluster>/sdk - MTV connects and syncs inventory via the vSphere SOAP API (handled by vcsim)
- Provider shows 4 VMs in
RS00/Roadshow/with correct guest OS types - Create NetworkMapping (pod networking) + StorageMapping (ceph-rbd)
- Create + execute Migration Plan (select
database-{user},winweb01-{user},winweb02-{user}) - virt-v2v connects to the shared endpoint and downloads VMX + flat VMDK files
- virt-v2v converts the disk and creates a KubeVirt VM in OpenShift Virtualization
Apache 2.0 (govmomi/vcsim dependency is also Apache 2.0)