Supported Providers And Scenarios
mtv-api-tests is an integration test suite for real MTV migrations into OpenShift Virtualization. The support matrix in this repository comes from three places: provider profiles
in .providers.json, scenario definitions in tests/tests_config/config.py, and pytest markers in pytest.ini. Collection-time skipping in conftest.py then narrows the matrix
further, based on the provider you actually configure.
Supported Source Providers
The source_provider setting points to a named profile in .providers.json. That means you can keep multiple profiles for the same platform, such as different vSphere versions or
labs, and select the one you want by profile name.
"$schema": "https://raw.githubusercontent.com/RedHatQE/mtv-api-tests/main/providers_schema.json",
"vsphere": {
"type": "vsphere",
"version": "<SERVER VERSION>",
"fqdn": "SERVER FQDN/IP",
"api_url": "<SERVER FQDN/IP>/sdk",
"username": "USERNAME",
"password": "PASSWORD", # pragma: allowlist secret
"guest_vm_linux_user": "LINUX VMS USERNAME",
"guest_vm_linux_password": "LINUX VMS PASSWORD", # pragma: allowlist secret
"guest_vm_win_user": "WINDOWS VMS USERNAME",
"guest_vm_win_password": "WINDOWS VMS PASSWORD", # pragma: allowlist secret
"luks_passphrase": "LUKS DISK ENCRYPTION PASSPHRASE", # pragma: allowlist secret
"vddk_init_image": "<PATH TO VDDK INIT IMAGE>",
"endpoint_type": "vcenter",
},
Copy-offload is the same provider type with an extra section:
"vsphere-copy-offload": {
"type": "vsphere",
"version": "<SERVER VERSION>",
"fqdn": "SERVER FQDN/IP",
"api_url": "<SERVER FQDN/IP>/sdk",
"username": "USERNAME",
"password": "PASSWORD", # pragma: allowlist secret
"guest_vm_linux_user": "LINUX VMS USERNAME",
"guest_vm_linux_password": "LINUX VMS PASSWORD", # pragma: allowlist secret
"guest_vm_win_user": "WINDOWS VMS USERNAME",
"guest_vm_win_password": "WINDOWS VMS PASSWORD", # pragma: allowlist secret
"copyoffload": {
The shipped example file also includes vsphere-esxi, ovirt, openstack, openshift, ova, and hyperv profiles.
The type values come from the Forklift provider-type constants: vsphere, openshift, ovirt, ova, openstack, and
hyperv. The provider adapters in libs/providers/ map one-to-one onto them.
| Source provider | type value |
Cold migration | Warm migration | Copy-offload | Notes |
|---|---|---|---|---|---|
| VMware vSphere (vCenter) | vsphere |
Yes | Yes | Yes | This is the broadest coverage area in the suite. Copy-offload is a vSphere profile with an extra copyoffload section. |
| VMware ESXi | vsphere with "endpoint_type": "esxi" |
Yes | Yes | No | A standalone host cannot clone, so clone_provider names the vCenter profile that clones. |
| RHV / oVirt | ovirt |
Yes | Yes | No | Cold, warm, comprehensive, and post-hook scenarios exist for RHV. |
| OpenStack | openstack |
Yes | No | No | Warm tests are skipped for this provider family. |
| OpenShift | openshift |
Yes | No | No | Supported as a source provider for OCP-to-OCP migrations, but not for warm scenarios. |
| OVA | ova |
Yes | No | No | Cold-style scenarios only. OVA VMs are never cloned; the destination name gets a session UUID prefix. |
| Hyper-V | hyperv |
Yes | No | No | Cold and comprehensive scenarios, including static IP preservation checks. |
Note:
vsphere-copy-offloadandvsphere-esxiare not separate provider families. Both aretype: "vsphere"; the difference is configuration, not provider type.Warning: Warm migration is not available for every source provider. The collection hook in
conftest.pyskips everywarmitem when the configured source provider cannot do warm migrations.
warm_unsupported = (
Provider.ProviderType.OPENSTACK,
Provider.ProviderType.OPENSHIFT,
Provider.ProviderType.OVA,
Provider.ProviderType.HYPERV,
)
if source_provider_type in warm_unsupported:
warm_skip = pytest.mark.skip(reason=f"{source_provider_type} warm migration is not supported.")
for item in items:
if "warm" in item.keywords:
Copy-offload, shared-disk, deep-inspection, AAP hook, and LUKS tests are vSphere-only, and ca_crt tests are skipped for
openshift and ova sources, because those providers do not carry a CA certificate in their provider secret.
A separate branch of the same hook enforces that:
ca_cert_unsupported = (
Provider.ProviderType.OPENSHIFT,
Provider.ProviderType.OVA,
)
if source_provider_type in ca_cert_unsupported:
ca_cert_skip = pytest.mark.skip(
reason=f"{source_provider_type} does not use CA certificates in provider secrets"
)
for item in items:
if "ca_crt" in item.keywords:
item.add_marker(ca_cert_skip)
if source_provider_type != Provider.ProviderType.VSPHERE:
vsphere_only_skip = pytest.mark.skip(reason="Test is only applicable to vSphere source providers")
for item in items:
if any(
kw in item.keywords for kw in ("copyoffload", "shared_disk", "deep_inspection", "aap", "luks")
):
item.add_marker(vsphere_only_skip)
A third capability gate of the same hook covers add_nic, which is a plan config flag rather than a marker, so the hook
resolves each item's parametrized plan config once and reuses it across the gates and the item rename loop below.
Whether a provider supports add_nic is supports_add_nic() in libs/base_provider.py:
# Skip tests whose plan config requests `add_nic` on a non-vSphere provider.
# `add_nic` is a plan config flag, not a marker, so resolve each item's config.
if not supports_add_nic(source_provider_type):
add_nic_skip = pytest.mark.skip(
reason=f"add_nic is vSphere-only; skipping for provider '{source_provider_type}'"
)
for item, test_config in resolved_plan_configs:
if test_config is None:
continue
# `virtual_machines` is a required plan-config field: direct access fails the
# collection run with a clear KeyError instead of a later fixture error.
if any(vm.get("add_nic") for vm in test_config["virtual_machines"]):
item.add_marker(add_nic_skip)
Migration Modes
This suite exercises three practical migration modes:
- Cold migration: the default path, represented by scenarios where
warm_migrationisFalse. - Warm migration: the precopy and cutover path, represented by scenarios where
warm_migrationisTrue. - Copy-offload: the accelerated vSphere path, represented by scenarios where
copyoffloadisTrue.
A simple warm scenario in the built-in test matrix looks like this:
"test_sanity_warm_mtv_migration": {
"virtual_machines": [
{
"name": "mtv-tests-rhel8",
"source_vm_power": "on",
"guest_agent": True,
},
],
"warm_migration": True,
"preserve_static_ips": True,
There is no separate cold marker. In this repository, "cold" is the normal case when warm_migration is not enabled.
Copy-offload specifics
Copy-offload is the most specialized mode in the suite. It is vSphere-only, and the repository includes both cold copy-offload coverage and a dedicated warm copy-offload scenario.
The accepted storage_vendor_product values are defined in utilities/copyoffload_constants.py:
ontapvantaraprimera3parpureFlashArraypowerflexpowermaxpowerstoreinfiniboxflashsystem
storage_vendor_product and datastore_id are always required, and base copy-offload storage credentials are always required:
storage_hostnamestorage_usernamestorage_password
Some vendors also require extra fields:
ontap:ontap_svmvantara:vantara_storage_id,vantara_storage_port,vantara_hostgroup_id_listpureFlashArray:pure_cluster_prefixpowerflex:powerflex_system_idpowermax:powermax_symmetrix_idprimera3par,powerstore,infinibox,flashsystem: no extra vendor-specific fields beyond the base storage credentials
Optional fields unlock specific scenarios:
secondary_datastore_id: required by the multi-datastore testsnon_xcopy_datastore_id: required by the mixed XCOPY/non-XCOPY datastore testdedicated_migration_hosts: required by the dedicated-migration-host tests, which setStorageMapoffloadPlugin.vsphereXcopyConfig.dedicatedMigrationHostsrdm_lun_uuid: LUN used by the RDM disk testsstorage_secret_extra: extra SecretstringDatakeys not covered by the vendor fields, or theCOPYOFFLOAD_STORAGE_SECRET_EXTRAenvironment variable
If you use SSH-based ESXi cloning for copy-offload, the suite also expects esxi_clone_method: "ssh" plus esxi_host, esxi_user, and esxi_password.
Tip: Copy-offload credentials can come from
.providers.jsonor fromCOPYOFFLOAD_...environment variables. Environment variables win, which is useful when you do not want secrets stored in files.
def get_copyoffload_credential(
credential_name: str,
copyoffload_config: dict[str, Any],
) -> str | None:
"""
Get a copyoffload credential from environment variable or config file.
Environment variables take precedence over config file values.
Environment variable names are constructed as COPYOFFLOAD_{credential_name.upper()}.
Args:
credential_name: Name of the credential (e.g., "storage_hostname", "ontap_svm",
"vantara_hostgroup_id_list")
copyoffload_config: Copyoffload configuration dictionary
Returns:
str | None: Credential value from env var or config, or None if not found
Examples:
- "storage_hostname" → "COPYOFFLOAD_STORAGE_HOSTNAME"
- "ontap_svm" → "COPYOFFLOAD_ONTAP_SVM"
- "vantara_hostgroup_id_list" → "COPYOFFLOAD_VANTARA_HOSTGROUP_ID_LIST"
"""
env_var_name = f"COPYOFFLOAD_{credential_name.upper()}"
return os.getenv(env_var_name) or copyoffload_config.get(credential_name)
Plan flags that shape source-side preparation
Several scenario keys do not appear in the Plan CR. They change how the suite prepares the source side before the migration starts:
| Plan flag | What it does |
|---|---|
rdm_as_lun |
Maps RDM disks as LUN devices on the SCSI bus instead of as virtual disks. Used by the RDM copy-offload scenarios. |
per_nic_network_map |
Creates one NetworkMap entry per NIC instead of deduplicating identical mappings. |
clone_to_same_host |
Pins every VM after the first to the ESXi host used for the first clone. Required for per-host inflight throttling. |
disable_drs_for_vms |
Applies a per-VM DRS override after cloning so vCenter cannot relocate the VM. Requires a VMware clone provider, and is rejected for OVA sources. |
pin_to_non_dedicated_host |
Resolves an ESXi host outside dedicated_migration_hosts and pins the clones to it, so dedicated-host verification can never pass by coincidence. |
Pytest Markers
The repository defines these markers in pytest.ini:
markers =
tier0: Core functionality tests (smoke tests)
tier1: Extended functionality tests
remote: Remote cluster migration tests
warm: Warm migration tests
copyoffload: Copy-offload (XCOPY) tests
copyoffload_sanity: Copy-offload sanity tests - core scenarios for quick validation
copyoffload_snapshots: Copy-offload snapshot tests (vSphere only)
shared_disk: Shared disk migration tests (vSphere only)
incremental: marks tests as incremental (xfail on previous failure)
min_mtv_version: mark test to require minimum MTV version (e.g., @pytest.mark.min_mtv_version("2.6.0"))
ova: OVA provider-specific tests
vsphere: vSphere provider-specific tests
esxi: ESXi provider-specific tests
rhv: RHV provider-specific tests
hyperv: Hyper-V provider-specific tests
openstack: OpenStack provider-specific tests
openshift: OpenShift provider-specific tests
deep_inspection: Deep Inspection / Conversion CR tests (vSphere only)
ca_crt: CA certificate field (ca.crt) provider secret tests
aap: AAP (Ansible Automation Platform) hook integration tests (vSphere only)
upgrade: MTV operator upgrade tests
In practice:
tier0is the smoke or core regression slice, andtier1covers extended functionality.warm,remote, andcopyoffloadare the main user-facing selectors for scenario families.copyoffload_sanityselects the curated quick copy-offload subset, andcopyoffload_snapshotsselects the snapshot-based copy-offload classes.shared_disk,deep_inspection,aap, andca_crtselect feature suites that have no single-mode marker of their own.vsphere,esxi,rhv,hyperv,openstack,openshift, andovamark which providers a test is written for. They also drive collection-time skipping.upgradeselects the MTV operator upgrade scenarios.-
incrementalis execution behavior, not a functional feature area. These class-based tests move step by step through StorageMap, NetworkMap, Plan, migration execution, and validation. -
min_mtv_versionis available when a scenario needs a newer MTV version.
Note:
comprehensiveis a scenario family in this repository, not a pytest marker. You select it by file or class, not with-m comprehensive.Note: Remote scenarios are opt-in. They are skipped unless
remote_ocp_clusteris set.
Major Scenario Families
| Family | How you identify it | What it covers |
|---|---|---|
| Tier0 | @pytest.mark.tier0 |
Core smoke coverage: sanity cold and warm, comprehensive cold and warm, OVA, shared-disk RHEL, cluster-role warm, post-hook failure |
| Tier1 | @pytest.mark.tier1 |
Extended coverage: XFS, LUKS, dual-NIC, CA certificate, insecure skip-verify, deep inspection, AAP hooks, shared-disk Windows |
| Warm | @pytest.mark.warm |
Standard warm flows, a 2-disks/2-NICs case, remote warm, comprehensive warm, XFS warm, plan-driven deep inspection, warm copy-offload |
| Remote | @pytest.mark.remote |
Remote OpenShift destination scenarios for cold, warm, and cluster-role flows |
| Comprehensive | Dedicated files and classes | Plan options such as static IP preservation, custom VM namespaces, PVC naming templates, labels, affinity, node placement |
| Copy-offload | @pytest.mark.copyoffload |
XCOPY coverage across disk types, snapshots, datastores, RDM disks, naming, dedicated migration hosts, scale, concurrency |
| Shared disk | @pytest.mark.shared_disk |
migrateSharedDisks ownership between an owner VM and a consumer VM, for RHEL and Windows guests |
| Deep inspection | @pytest.mark.deep_inspection |
The Conversion CR lifecycle: standalone, cancel, validation conditions, and plan-driven concerns blocking migration |
| LUKS | tests/luks/ plus -k luks |
LUKS-encrypted disk migration, plus the expected failure path with a wrong passphrase |
| XFS | xfs_compatibility scenario key |
XFS v4 compatibility for cold and warm migrations, verified with xfs_info in the guest |
| Hooks | tests/hooks/ |
A pre-hook success plus post-hook failure scenario, and an AAP-based hook scenario |
| Plan lifecycle | tests/plan_lifecycle/ |
PVC and DataVolume cleanup after a failed plan is archived |
| Upgrade | @pytest.mark.upgrade |
Migration resources created pre-upgrade, migrated after the MTV operator upgrade |
Scenario families are intentionally allowed to overlap. For example, comprehensive warm coverage is both tier0 and warm,
warm copy-offload belongs to both warm and copyoffload, and the sanity warm class carries tier0, warm, and upgrade.
Tier0 coverage
The tier0 slice in this repository is broader than a single smoke test. It includes:
TestSanityColdMtvMigrationTestSanityWarmMtvMigrationTestColdMigrationComprehensiveTestWarmMigrationComprehensiveTestOvaColdMigrationTestSharedDiskRhelMigrationTestClusterroleWarmWithSccMigrationTestPostHookRetainFailedVm
Two of those need something extra before they run: the OVA class needs an ova source provider, and
TestClusterroleWarmWithSccMigration is remote and is skipped without remote_ocp_cluster.
The last case matters because it covers a failure path: the migration is expected to fail in the post-hook stage while
the migrated VMs are retained for verification.
Remote coverage
The built-in remote scenarios are:
TestColdRemoteOcpTestWarmRemoteOcpTestClusterroleWarmMtvMigrationTestClusterroleWarmWithSccMigration
These are gated by the remote marker and the remote_ocp_cluster setting. If you do not provide that setting, pytest skips them instead of failing later during migration setup.
Comprehensive coverage
The comprehensive tests are the best place to look when you want end-to-end coverage of plan options beyond "can the VM migrate."
A warm comprehensive scenario is configured like this:
"test_warm_migration_comprehensive": {
"virtual_machines": [
{
"name": "mtv-win2022-ip-3disks",
"source_vm_power": "on",
"guest_agent": True,
},
],
"warm_migration": True,
"target_power_state": "on",
"preserve_static_ips": True,
"enable_nested_virtualization": False,
"vm_target_namespace": f"mtv-vms-warm-comprehensive-{uuid.uuid4().hex[:4]}",
"multus_namespace": "default", # Cross-namespace NAD access
# Keys must be Provider.ProviderType string values (e.g. "vsphere") or "default".
# vsphere uses .FileName; default truncates VmName to stay within 63 chars.
"pvc_name_template": {
"vsphere": '{{ .FileName | trimSuffix ".vmdk" | replace "_" "-" }}-{{.DiskIndex}}',
"default": '{{ .VmName | trunc 32 | trimSuffix "-" }}-{{ .VmName | trunc -4 }}-disk-{{.DiskIndex}}',
},
"pvc_name_template_use_generate_name": True,
"target_labels": {
"mtv-comprehensive-test": None, # None = auto-generate with session_uuid
"static-label": "static-value",
},
"target_affinity": {
"podAffinity": {
"preferredDuringSchedulingIgnoredDuringExecution": [
{
"podAffinityTerm": {
"labelSelector": {"matchLabels": {"app": "comprehensive-test"}},
"topologyKey": "kubernetes.io/hostname",
},
"weight": 75,
}
]
}
},
"guest_agent_timeout": 600,
},
The cold comprehensive scenario follows the same idea, but adds cold-specific scheduling and naming checks such as
target_node_selector, fixed PVC naming, and warm_migration: False.
Copy-offload coverage
tests/copyoffload/test_copyoffload_migration.py is the largest single scenario matrix in the repository. It covers:
- Thin, thick-lazy, and thick-eager disk migrations
- Snapshot-based cases, including a 2 TB VM with snapshots
- Multi-disk and multi-datastore layouts
- Mixed XCOPY and non-XCOPY datastore behavior, including fallback paths
- RDM virtual disks and RDM physical disks, cold and warm
- Independent persistent and independent nonpersistent disks
- A VM with 10 mixed thin and thick disks
- Nonconforming source VM names
- Dedicated migration hosts, including the invalid-host-id failure case
- Populator and VM inflight throttling
- Warm copy-offload
- Scale coverage with 5 VMs in one run
- Simultaneous copy-offload plans
- Concurrent XCOPY and VDDK plans in the same suite
copyoffload_sanity selects a seven-class subset for quick validation: thick-eager snapshots, RDM virtual disk,
multi-datastore, mixed datastore, 10 mixed disks, warm copy-offload, and the 5-VM scale run.
Warning: Copy-offload is intentionally strict about prerequisites. The suite fails early if the source provider is not vSphere or if required copy-offload fields are missing.
Feature suites worth knowing about
-
LUKS.
tests/luks/migrates a LUKS-encrypted VM and then verifiescrypto_LUKSfrom inside the migrated guest. A second class feeds a wrong passphrase and expects the migration to fail. The passphrase comes fromluks_passphrasein.providers.json, with a per-VM override in the scenario. -
XFS.
tests/cold/test_cold_migration_xfs.pyandtests/warm/test_warm_migration_xfs.pysetxfs_compatibility: Trueand verify the guest filesystem with anxfs_checkcommand, expectingcrc=0inxfs_infooutput. -
Shared disk.
tests/shared_disk/migrates an owner VM withmigrateSharedDisks: Trueand a consumer VM with itFalse, then verifies the shared disk data on both. -
Deep inspection.
tests/deep_inspection/drives ForkliftConversionresources: standalone conversion with cancel and validation-condition cases, plus a plan-driven case where inspection concerns must block a warm migration. -
Plan lifecycle.
tests/plan_lifecycle/test_plan_archive_pvc_cleanup.pyfails a plan in the post-hook stage, archives it, and waits for the leftover PVCs and DataVolumes to disappear. -
Upgrade.
tests/upgrade/test_upgrade_migration.pycreates StorageMap, NetworkMap, and Plan on the pre-upgrade operator, upgrades MTV from an external upgrade repository, and then migrates. It needsupgrade_repo_url,upgrade_repo_ref,upgrade_script_path, and the target version settings. -
Hooks and AAP.
tests/hooks/covers a pre-hook that must succeed followed by a post-hook that must fail, with the migrated VMs retained for verification, plus an AAP-based hook scenario where the suite installs or uses an AAP deployment, syncs the test playbooks project, and creates the hook.
Practical Tip
Tip: Before running live migrations, use
uv run pytest --collect-onlyto confirm what your current provider profile and markers will collect. The repository already uses that pattern intox.toml, and the container image defaults to it.
[env.pytest-check]
commands = [
[
"uv",
"run",
"pytest",
"--setup-plan",
],
[
"uv",
"run",
"pytest",
"--collect-only",
],
]
If you only remember one rule for this page, make it this: vSphere has the broadest coverage, copy-offload is vSphere-only,
warm migration is not supported for every provider, and tier0, tier1, warm, remote, copyoffload, shared_disk,
deep_inspection, and upgrade are the markers you will use most often to slice the suite.