Python Module Reference

The suite is deliberately thin at the test-method level: a test class creates resources and asserts on results, while everything reusable lives in utilities/, libs/, exceptions/, cli/, and scripts/hooks/. This page is the map of those modules and their public entry points.

Most test authors never import these modules directly. They consume them through fixtures in conftest.py — source_provider, prepared_plan, source_provider_inventory, target_namespace, virtctl_binary, fixture_store, cleanup_migrated_vms — and through the plan/verification helpers in the test class itself.

Note: These modules drive live OpenShift and MTV environments. Repository automation only validates collection and setup: tox.toml runs uv run pytest --setup-plan and uv run pytest --collect-only, and the container image defaults to uv run pytest --collect-only.

At a Glance

Module What it handles Main entry points
utilities/utils.py cluster client, provider loading, provider CRs, config coercion get_cluster_client(), load_source_providers(), create_source_provider(), get_value_from_py_config()
utilities/resources.py tracked creation of every OpenShift/MTV resource create_and_store_resource(), unregister_teardown_resource(), get_or_create_namespace()
utilities/mtv_migration.py storage maps, network maps, plans, migrations get_storage_migration_map(), get_network_migration_map(), create_plan_resource(), execute_migration(), wait_for_migration_complate()
utilities/post_migration.py end-to-end and focused VM validation check_vms() plus the check_* / verify_* helpers
utilities/guest_ip_mode.py per-network guest IP mode verification on migrated VMs: dhcp (Windows and Linux) and none (Linux only); NetworkMap and DNS-data checks for overrides. preserve is verified by check_static_ip_preservation() verify_network_ip_modes(), verify_network_map_network_ip_mode(), verify_preserve_mode_dns_data()
utilities/copyoffload_migration.py copy-offload orchestration and XCOPY verification execute_copyoffload_migration(), verify_xcopy_used(), verify_populator_throttling(), verify_dedicated_migration_host()
utilities/deep_inspection.py Deep Inspection Conversion CR lifecycle create_conversion_resource(), wait_for_conversion_complete(), verify_di_results()
utilities/shared_disk.py shared-disk verification on migrated VMs verify_shared_disk_data(), label_shared_disk_on_source_windows(), verify_shared_disk_data_windows()
utilities/aap.py AWX/AAP deployment for hook tests deploy_awx_via_helm(), create_awx_job_template(), teardown_awx()
utilities/hooks.py Forklift Hook CR creation and failure validation create_hook_if_configured(), validate_hook_failure_and_check_vms()
utilities/provider_inventory.py Forklift inventory refresh and clone waits wait_for_cloned_vms_in_forklift_inventory(), validate_source_vms_exist()
utilities/pytest_utils.py failure data collection, session teardown, JUnit enrichment collect_created_resources(), session_teardown(), enrich_junit_xml()
utilities/ssh_utils.py SSH into migrated VMs via virtctl port-forward plus python-rrmngmnt VMSSHConnection, SSHConnectionManager, create_vm_ssh_connection()
utilities/upgrade.py MTV operator upgrade run run_mtv_upgrade()
libs/providers/ one adapter per source provider type VMWareProvider, OvirtProvider, OpenStackProvider, OCPProvider, OVAProvider, HyperVProvider
exceptions/exceptions.py every custom exception the suite raises 24 exception classes, all in one module

Core Setup

utilities/utils.py

The module that turns configuration into live connections. load_source_providers() reads .providers.json, get_cluster_client() builds the OpenShift DynamicClient, and get_value_from_py_config() coerces string booleans such as "true" into real booleans so the rest of the suite treats settings consistently.

It also owns provider resource creation: create_source_provider() handles the per-provider differences (Secret keys, CA certificate fetching, copy-offload settings) for every supported source type, and create_source_cnv_vms() builds the target VMs from plan data.

Other public helpers: resolve_providers_json_path(), generate_class_hash_prefix(), gen_network_map_list(), get_per_nic_networks(), populate_vm_ids(), extract_vm_from_plan(), get_cluster_version(), get_cluster_version_str(), get_mtv_version(), has_mtv_minimum_version(), delete_all_vms(), generate_ca_cert_file(), background().

Provider shortcuts used by fixtures: vmware_provider(), rhv_provider(), openstack_provider(), ova_provider(), ocp_provider(), hyperv_provider().

Constants: DEFAULT_PROVIDERS_JSON_PATH.

The module also defines VirtualMachineFromInstanceType, a VirtualMachine subclass that builds a full VM spec from instancetype/preference plus a few parameters.

utilities/resources.py

Resource lifecycle foundation. create_and_store_resource() fills in the client, derives a name from name/kind_dict/yaml_file or generates one from the session base name, appends -warm/-cold to Plan and Migration names, truncates to 63 characters, deploys and waits, and records the resource in fixture_store["teardown"] so teardown, resources.json, and leftover detection know about it.

get_or_create_namespace() builds on it and applies the suite's standard namespace labels. unregister_teardown_resource() removes a resource you deleted yourself from teardown tracking — required when a test archives and deletes a Plan mid-run.

Tip: Use create_and_store_resource() for anything that creates a cluster object during a test. That is what makes later teardown and leftover detection work.

utilities/logger.py

setup_logging() configures the suite logger; separator() prints a visual break between long-running phases.

utilities/naming.py

Name generation and sanitisation: generate_name_with_uuid(), sanitize_kubernetes_name(), resolve_destination_vm_name(), sanitize_test_name_for_path(). resolve_destination_vm_name() matters during teardown because MTV can rename a migrated VM.

Migration Orchestration

utilities/mtv_migration.py

The module most test authors reuse first. It owns StorageMap, NetworkMap, Plan, and Migration creation plus the waits for their states.

Function Purpose
get_storage_migration_map() build and deploy the StorageMap
get_network_migration_map() build and deploy the NetworkMap
create_plan_resource() build and deploy the Plan, including plan flags
execute_migration() create the Migration and poll it to completion
get_migration_for_plan() locate the Migration CR belonging to a Plan
wait_for_migration_complate() poll a migration, with an optional per-poll status callback
wait_for_dual_migration_completion() wait for two plans migrating concurrently
wait_for_concurrent_migration_execution() start several migrations and wait for all of them
get_plan_migration_status() / get_vm_suffix() status parsing helpers
resolve_pvc_name_template() resolve the per-provider PVC name template
verify_vm_disk_count() assert the migrated disk count matches the source

utilities/migration_utils.py

Cancel, archive, and cleanup flows: cancel_migration(), archive_plan(), get_orphan_resource_names(), check_dv_pvc_pv_deleted(), append_leftovers(), get_cutover_value().

utilities/copyoffload_migration.py

The largest feature module (2470 lines). It owns credential resolution, cloud-init readiness, XCOPY verification, concurrency tracking, and dedicated-host behaviour.

Area Functions
Credentials get_copyoffload_credential(), parse_storage_secret_extra_env(), get_storage_secret_extra(), merge_storage_secret_extra() (env overrides config; extras override vendor keys)
Execution execute_copyoffload_migration(), execute_migration_monitoring_populator_inflight(), execute_migration_monitoring_vm_and_populator_inflight(), apply_copyoffload_vm_name_override(), get_migration_uid()
Log capture capture_populate_pod_logs(), create_log_capture_callback()
Cloud-init wait_for_vmware_cloud_init_all_vms(), wait_for_cloud_init()
Verification verify_xcopy_used(), verify_xcopy_used_per_datastore(), verify_populator_throttling(), verify_populator_inflight_observed(), verify_vm_inflight_throttling(), verify_dedicated_migration_host(), resolve_invalid_dedicated_host_id(), verify_populate_pod_failure_reason()
Host selection get_configured_dedicated_hosts(), resolve_non_dedicated_esxi_host()

Internal trackers _PopulatorConcurrencyTracker and _VmConcurrencyTracker record peak per-host concurrency while the migration is polled.

Constants include STORAGE_SECRET_EXTRA_ENV (the environment variable that injects extra Secret keys) and PVC_NAME_LABEL.

utilities/copyoffload_plan_secret.py

plan_uses_copyoffload(), wait_for_plan_secret(), wait_for_copyoffload_plan_secret() — poll for the populator secret Forklift creates when a copy-offload migration starts. Constants: PLAN_SECRET_WAIT_TIMEOUT, PLAN_NAME_LABEL, POPULATOR_LABEL, COPY_OFFLOAD_PVC_NAME_TEMPLATE.

utilities/copyoffload_constants.py

SUPPORTED_VENDORS, POPULATOR_INFLIGHT_LIMIT, VM_INFLIGHT_LIMIT, VM_POPULATOR_INFLIGHT_LIMIT, SOURCE_HOST_LABEL, POPULATOR_THROTTLED_EVENT_REASON, FORKLIFT_CONTROLLER_NAME.

utilities/copyoffload_datastore.py

resolve_datastore_moid_from_disk_config() and format_custom_datastore_not_found_message() resolve a disk's datastore, with explicit errors for the symbolic secondary and non-XCOPY datastore placeholders (ERR_SECONDARY_DS_NOT_CONFIGURED, ERR_NON_XCOPY_DS_NOT_CONFIGURED, ERR_EMPTY_DISK_DATASTORE_ID).

utilities/forklift_controller_populator.py

Reads and sets the in-flight limits on the forklift-volume-populator-controller Deployment: get_populator_inflight_from_deployment(), populator_inflight_limit(), wait_for_populator_inflight_deployment(), get_vm_inflight_from_deployment(), vm_inflight_limit(), wait_for_vm_inflight_deployment(), plus the cross-worker file-lock helpers ensure_secure_shared_lock_dir(), get_forkliftcontroller_populator_inflight_lock_path(), get_forkliftcontroller_vm_populator_inflight_lock_path().

utilities/hooks.py

validate_hook_config(), validate_custom_playbook(), create_hook_for_plan(), validate_all_vms_same_step(), validate_expected_hook_failure(), validate_hook_failure_and_check_vms(), create_hook_if_configured().

utilities/deep_inspection.py

Deep Inspection (Conversion CR) lifecycle for both standalone and plan-driven DI: create_di_connection_secret(), create_conversion_resource(), wait_for_conversion_phase(), wait_for_conversion_complete(), cancel_conversion(), wait_for_conversion_pods(), wait_for_conversion_pods_cleanup(), wait_for_di_snapshot(), wait_for_di_snapshot_cleanup(), verify_di_results(), verify_captured_di_results(), verify_di_concerns_block_migration(), get_plan_conversion_crs(), wait_for_critical_conditions(), create_di_capture_callback().

utilities/upgrade.py

run_mtv_upgrade() runs the MTV operator upgrade used by the upgrade suite, with process-group timeouts so a stuck upgrade cannot hang the run.

Validation

utilities/post_migration.py

Validation of migrated VMs (2083 lines). check_vms() is the entry point used by test_check_vms; everything else is a focused check it composes.

Area Functions
Connectivity get_ssh_credentials_from_provider_config(), check_ssh_connectivity(), check_vm_command_output()
Compute check_cpu(), check_cpu_features(), check_memory(), check_vbs_status()
Boot/BIOS check_boot_configuration(), check_serial_preservation()
State check_vms_power_state(), check_false_vm_power_off(), check_guest_agent(), check_snapshots(), check_disconnected_nic_state()
Network check_network(), get_nic_by_mac(), get_all_destinations(), check_nic_name_preservation(), check_static_ip_preservation()
Storage check_storage(), check_pvc_names(), verify_data_integrity(), verify_luks_encryption(), verify_rdm_disk_bus_types()
Placement check_vm_node_placement(), check_vm_labels(), check_vm_affinity(), check_ssl_configuration()

Static-IP preservation applies to vSphere and Hyper-V sources and supports both Windows (ipconfig /all) and Linux (nmcli device show) guests.

utilities/shared_disk.py

verify_shared_disk_data() mounts, writes, and reads a shared disk from both migrated VMs (Linux, 6-step pattern). label_shared_disk_on_source_windows() labels the shared NTFS volume on the source through the VMware Guest Operations API before migration, and verify_shared_disk_data_windows() verifies it afterwards (Windows, 7-step pattern).

utilities/ssh_utils.py

SSH into migrated VMs through virtctl port-forward plus python-rrmngmnt, so it works when cluster nodes have no external IPs. VMSSHConnection wraps a connection, SSHConnectionManager manages one connection per VM for fixtures, create_vm_ssh_connection() builds a single connection, and run_cmd_in_vm() runs a command in the guest.

utilities/virtctl.py

download_virtctl_from_cluster() fetches the matching virtctl binary — a virtctl already on PATH is never reused, only a previously downloaded binary in the cluster-versioned cache — and add_to_path() puts the downloaded directory on PATH for the session.

utilities/vmware_guest_operations.py

Commands executed inside vSphere guests via the Guest Operations API: run_command_in_vmware_guest(), detect_vmware_ip_origins_via_guest_ops(), detect_guest_nic_names(), create_data_integrity_marker().

utilities/worker_node_selection.py

Target worker node selection for placement tests: get_worker_nodes(), parse_prometheus_value(), parse_prometheus_memory_metrics(), select_node_by_available_memory().

utilities/esxi.py

Direct-ESXi host access for the endpoint_type: esxi source path: install_ssh_key_on_esxi(), remove_ssh_key_from_esxi(), raising ESXiError on failure.

utilities/provider_inventory.py

Inventory-side waits that keep plan data consistent with Forklift's view: force_inventory_refresh(), wait_for_added_nics_in_forklift_inventory(), wait_for_cloned_vms_in_forklift_inventory(), validate_source_vms_exist().

Teardown and Diagnostics

utilities/pytest_utils.py

is_dry_run() (--collect-only / --setup-plan), prepare_base_path(), setup_ai_analysis() (rootcoz-backed failure analysis; disabled without ROOTCOZ_SERVER_URL), collect_created_resources() (writes the tracked resource inventory), resolve_item_plan_config() (a collected item's plan config, failing fast when a non-parametrized item has no tests_params entry), teardown_resources(), session_teardown(), enrich_junit_xml().

utilities/must_gather.py

run_must_gather() runs the full diagnostic collection and run_plan_must_gather() the plan-targeted one; both report whether they succeeded and share image resolution. Missing resources and the wrapper's specific resource API discovery failure return False; missing or invalid image metadata and other configuration/programming errors propagate. Standalone setup/call collector errors stay in the failing item's typed stash until the teardown wrapper yields to fixture finalizers. The pending-gather flush, resource inventory writing and configured cleanup run before the inner session-finish hooks yield, so xdist worker shutdown cannot interrupt them; the summary and enabled AI enrichment run after those hooks, and errors are re-raised at the end with earlier errors chained. Independent finally blocks also attempt temporary-directory removal, the summary and enabled AI enrichment despite inventory or teardown errors. Cleanup errors propagate with earlier errors chained. Both teardown and session-finish use modern wrapper=True hooks so ordinary fixture exceptions do not emit old-style pluggy teardown warnings. Inventory write failures are logged by the existing inventory helper. collect_must_gather_for_item(), collect_class_must_gather(), collect_class_teardown_must_gather(), flush_pending_class_must_gathers() and the mark_class_pending_must_gather() / class_must_gather_collected() / mark_class_must_gather_collected() documented state API attempt at most one successful gather per failing class-plan instance per worker. Operational failures stay pending for retry; artifacts are not guaranteed if retries fail. class_plan_identity() uses the Class collector node ID, class-scoped callspec indices and worker ID, shared across ordinary methods but distinct across plan parameter sets. collect_class_must_gather(item, nextitem) runs before default fixture finalization at class-plan boundaries, including early exits with nextitem=None, and binds the current Plan or explicit None for collection and all retries, even if no failure is pending yet. initialize_class_plan_context() runs from a tryfirst protocol wrapper before setup, clearing stale Plan attributes on identity transitions but not across consecutive methods of the same plan. collect_must_gather_for_item() takes this explicit Plan context instead of rereading mutable class state. Earlier method teardown failures stay pending until a boundary; session finish retries exceptional remaining cases on surviving workers, without guaranteeing pre-cleanup state or crash recovery. Unbound fallback contexts read the class attribute only for the active identity; others bind None for a full gather.

utilities/aap.py

AWX/AAP deployment and REST API helpers for hook integration tests: is_awx_installed(), deploy_awx_via_helm(), create_awx_instance(), wait_for_awx_ready(), wait_for_awx_api_ready(), get_awx_admin_password(), get_awx_route_url(), create_awx_auth_token(), create_awx_project(), wait_for_awx_project_sync(), create_awx_inventory(), create_awx_job_template(), create_aap_token_secret(), teardown_awx().

Provider Abstraction (libs/)

libs/base_provider.py

BaseProvider is the abstract base every source adapter implements: connect() is context-manager managed — __enter__() calls it and __exit__() is a no-op that does not call disconnect(), so an adapter that opens a session must close it explicitly — and the abstract surface is connect(), disconnect(), test, vm_dict, clone_vm(), delete_vm(), get_vm_or_template_networks(). Shared behaviour includes _generate_clone_vm_name() and supports_skip_clone().

libs/providers/

Module Class Backing technology
vmware.py VMWareProvider pyvmomi / vSphere Automation SDK
rhv.py OvirtProvider ovirt-python-sdk
openstack.py OpenStackProvider openstacksdk
openshift.py OCPProvider openshift-python-wrapper against a source cluster
ova.py OVAProvider OVA import over NFS
hyperv.py HyperVProvider PowerShell Remoting (PSRP)

vmware.py also exposes format_insufficient_capacity_message() and format_capacity_validation_log(); module constant VSPHERE_NIC_DEVICE_KEY_OFFSET documents the vSphere device-key space used when adding NICs.

libs/forklift_inventory.py

create_forklift_inventory(client, mtv_namespace, provider) returns the inventory implementation matching the provider type: VsphereForkliftInventory, OvirtForkliftInventory, OpenstackForliftinventory, OpenshiftForkliftInventory, OvaForkliftInventory, HypervForkliftInventory — all subclasses of ForkliftInventory.

ForkliftInventory exposes get_data(), vms, get_vm(), wait_for_vm(), vms_names, networks, storages, vms_storages_mappings, vms_networks_mappings, and provider-specific sync checks (OpenStack volumes and networks).

Exceptions (exceptions/exceptions.py)

Every custom exception lives in this one module, enforced by the check-exceptions-location pre-commit hook.

Area Exceptions
Provider and cluster MissingProvidersFileError, ProviderEmptyContentError, MtvOperatorNotInstalledError, ForkliftPodsNotRunningError, RemoteClusterAndLocalCluterNamesError
VM lifecycle VmNotFoundError, VmCloneError, VmMissingVmxError, VmBadDatastoreError, VmPipelineError, VmMigrationStepMismatchError, InvalidVMNameError
Migration MigrationNotFoundError, MigrationStatusError, MigrationPlanExecError
Guest access GuestCommandError, SSHConnectionSetupError, PowerShellCommandError, ConversionError
Suite lifecycle SessionTeardownError, ResourceNameNotStartedWithSessionUUIDError, OvirtMTVDatacenterNotFoundError, OvirtMTVDatacenterStatusError, MtvUpgradeError

CLI (cli/mtv_api_tests/)

A Typer app installed as the mtv-api-tests console script.

Module Role
__init__.py main(), generate(), run(), and the RunMode enum (local / job)
generate.py interactive wizard that writes .providers.json and the Job YAML
run.py run tests locally (uv run pytest) or as an OpenShift Job
common.py shared prompts and discovery: provider/vendors/VMs/ESXi hosts/storage classes, cluster connection and MTV validation, build_providers_json(), write_providers_json(), mask_passwords(), generate_job_yaml()

run accepts --mode, --category, --source-provider, --destination-provider, --storage-class, -k/--test-filter, and --job-yaml.

Repository Tooling

scripts/hooks/

Eight local pre-commit hooks enforce the rules in AGENTS.md as AST checks, with a baseline ratchet (baseline.py + scripts/hooks/baselines/*.txt) so legacy violations do not block unrelated work:

Hook Rule
check_no_kubernetes_runtime.py no runtime kubernetes imports (except kubernetes.dynamic.exceptions)
check_no_dynamicclient_construct.py no direct DynamicClient(...) construction
check_no_except_exception.py no except Exception outside pytest hooks
check_no_runtimeerror.py no raise RuntimeError outside pytest hooks
check_exceptions_location.py exception subclasses belong in exceptions/exceptions.py
check_test_file_location.py no test_*.py directly under tests/
check_autouse_fixtures.py only autouse_fixtures may use autouse=True
check_no_module_load_source_providers.py no module-level load_source_providers() in tests/

tools/

tools/clean_cluster.py (clean_cluster_by_resources_file()) removes leftovers listed in a resources.json; tools/bm-dns-setup.sh and tools/update-branches.sh are operator helpers.