diff --git a/playbooks/validate_migration.yml b/playbooks/validate_migration.yml
new file mode 100644
index 0000000..cd6ff85
--- /dev/null
+++ b/playbooks/validate_migration.yml
@@ -0,0 +1,11 @@
+---
+
+- name: Validate Migration
+ hosts: localhost
+ connection: local
+ gather_facts: false
+ tasks:
+ - name: Invoke Validate Migration
+ ansible.builtin.include_role:
+ name: infra.openshift_virtualization_migration.validate_migration
+...
diff --git a/roles/validate_migration/README.md b/roles/validate_migration/README.md
index e894f69..cd2e9f5 100644
--- a/roles/validate_migration/README.md
+++ b/roles/validate_migration/README.md
@@ -26,8 +26,10 @@ Description: Verification of an Ansible for OpenShift Virtualization Migration e
| Var | Type | Value |Choices |Required | Title |
|--------------|--------------|-------------|-------------|-------------|-------------|
+| [`validate_migration_check_vm_running`](defaults/main.yml#L44) | bool | `True` | None | False | Check VM Running Status |
| [`validate_migration_cluster_name`](defaults/main.yml#L20) | str | `cluster01` | None | None | None |
| [`validate_migration_debug`](defaults/main.yml#L18) | bool | `True` | None | None | None |
+| [`validate_migration_expected_dv_phase`](defaults/main.yml#L52) | str | `Succeeded` | None | False | Expected DataVolume Phase |
| [`validate_migration_expected_provisioners`](defaults/main.yml#L3) | list | `[]` | None | None | None |
| [`validate_migration_expected_provisioners.0`](defaults/main.yml#L4) | str | `kubernetes.io/aws-ebs` | None | None | None |
| [`validate_migration_expected_provisioners.1`](defaults/main.yml#L5) | str | `kubernetes.io/azure-disk` | None | None | None |
@@ -40,14 +42,24 @@ Description: Verification of an Ansible for OpenShift Virtualization Migration e
| [`validate_migration_expected_provisioners.7`](defaults/main.yml#L11) | str | `openshift-storage.cephfs.csi.ceph.com` | None | None | None |
| [`validate_migration_expected_provisioners.8`](defaults/main.yml#L12) | str | `openshift-storage.rbd.csi.ceph.com` | None | None | None |
| [`validate_migration_expected_provisioners.9`](defaults/main.yml#L13) | str | `kubernetes.io/rbd` | None | None | None |
+| [`validate_migration_expected_vm_phase`](defaults/main.yml#L48) | str | `Running` | None | False | Expected VM Phase |
+| [`validate_migration_kubevirt_api_version`](defaults/main.yml#L56) | str | `kubevirt.io/v1` | None | False | KubeVirt API Version |
| [`validate_migration_namespace`](defaults/main.yml#L16) | str | `openshift-mtv` | None | None | None |
+| [`validate_migration_post_enabled`](defaults/main.yml#L32) | bool | `False` | None | False | Enable Post-Migration Validation |
+| [`validate_migration_post_label_selectors`](defaults/main.yml#L40) | list | `[]` | None | False | Post-Migration Label Selectors |
+| [`validate_migration_post_namespace`](defaults/main.yml#L36) | str | `` | None | False | Post-Migration Target Namespace |
+| [`validate_migration_pre_enabled`](defaults/main.yml#L26) | bool | `True` | None | False | Enable Pre-Migration Validation |
🖇️ Full descriptions for vars in defaults/main.yml
+`validate_migration_check_vm_running`: Verify VirtualMachineInstances are running
+
`validate_migration_cluster_name`: None
`validate_migration_debug`: None
+`validate_migration_expected_dv_phase`: Expected DataVolume phase
+
`validate_migration_expected_provisioners`: None
`validate_migration_expected_provisioners.0`: None
@@ -72,8 +84,20 @@ Description: Verification of an Ansible for OpenShift Virtualization Migration e
`validate_migration_expected_provisioners.9`: None
+`validate_migration_expected_vm_phase`: Expected VirtualMachineInstance phase
+
+`validate_migration_kubevirt_api_version`: KubeVirt API Version
+
`validate_migration_namespace`: None
+`validate_migration_post_enabled`: Enable post-migration validation checks
+
+`validate_migration_post_label_selectors`: Label selectors to filter VMs for validation
+
+`validate_migration_post_namespace`: Namespace containing migrated VMs to validate
+
+`validate_migration_pre_enabled`: Enable pre-migration infrastructure validation checks
+
### Tasks
@@ -82,10 +106,39 @@ Description: Verification of an Ansible for OpenShift Virtualization Migration e
| Name | Module | Has Conditions |
| ---- | ------ | --------- |
-| Include ocp_version tasks | `ansible.builtin.include_tasks` | False |
-| Include ocp_operators tasks | `ansible.builtin.include_tasks` | False |
-| Include ocp_storage_support tasks | `ansible.builtin.include_tasks` | False |
-| Include vmware_firewall_rules tasks | `ansible.builtin.include_tasks` | False |
+| Include ocp_version tasks | `ansible.builtin.include_tasks` | True |
+| Include ocp_operators tasks | `ansible.builtin.include_tasks` | True |
+| Include ocp_storage_support tasks | `ansible.builtin.include_tasks` | True |
+| Include vmware_firewall_rules tasks | `ansible.builtin.include_tasks` | True |
+| Include post-migration VM validation | `ansible.builtin.include_tasks` | True |
+| Include post-migration data volume validation | `ansible.builtin.include_tasks` | True |
+| Include post-migration network validation | `ansible.builtin.include_tasks` | True |
+| Include post-migration relationship validation | `ansible.builtin.include_tasks` | True |
+
+#### File: tasks/_validate_vm.yml
+
+| Name | Module | Has Conditions |
+| ---- | ------ | --------- |
+| _validate_vm ¦ Verify VM Has Required Spec Fields | `ansible.builtin.assert` | False |
+| _validate_vm ¦ Verify VM Has CPU Configuration | `ansible.builtin.assert` | False |
+| _validate_vm ¦ Verify VM Has Memory Configuration | `ansible.builtin.assert` | False |
+| _validate_vm ¦ Verify VM Has Volumes Defined | `ansible.builtin.assert` | False |
+| _validate_vm ¦ Verify VM Has Network Interfaces | `ansible.builtin.assert` | False |
+| _validate_vm ¦ Collect VirtualMachineInstance Status | `kubernetes.core.k8s_info` | True |
+| _validate_vm ¦ Verify VMI Is Running | `ansible.builtin.assert` | True |
+| _validate_vm ¦ Record Successful Validation | `ansible.builtin.set_fact` | False |
+
+#### File: tasks/_validate_vm_volumes.yml
+
+| Name | Module | Has Conditions |
+| ---- | ------ | --------- |
+| _validate_vm_volumes ¦ Extract DataVolume References from VM | `ansible.builtin.set_fact` | False |
+| _validate_vm_volumes ¦ Verify Referenced DataVolumes Exist | `block` | True |
+| _validate_vm_volumes ¦ Query Referenced DataVolumes | `kubernetes.core.k8s_info` | False |
+| _validate_vm_volumes ¦ Track Missing DataVolumes | `ansible.builtin.set_fact` | True |
+| _validate_vm_volumes ¦ Verify Referenced PVCs Exist | `block` | True |
+| _validate_vm_volumes ¦ Query Referenced PVCs | `kubernetes.core.k8s_info` | False |
+| _validate_vm_volumes ¦ Verify PVC Bindings | `ansible.builtin.assert` | False |
#### File: tasks/ocp_operators.yml
@@ -118,6 +171,54 @@ Description: Verification of an Ansible for OpenShift Virtualization Migration e
| ocp_version ¦ Get OCP version and check if it's 4.12 or higher | `kubernetes.core.k8s_info` | False |
| ocp_version ¦ Print OCP version | `ansible.builtin.debug` | False |
+#### File: tasks/post_migration_data_volumes.yml
+
+| Name | Module | Has Conditions |
+| ---- | ------ | --------- |
+| post_migration_data_volumes ¦ Collect DataVolumes in Target Namespace | `kubernetes.core.k8s_info` | False |
+| post_migration_data_volumes ¦ Verify DataVolumes Exist | `ansible.builtin.assert` | False |
+| post_migration_data_volumes ¦ Verify DataVolume Status Is Succeeded | `ansible.builtin.assert` | False |
+| post_migration_data_volumes ¦ Collect PVCs in Target Namespace | `kubernetes.core.k8s_info` | False |
+| post_migration_data_volumes ¦ Verify PVCs Are Bound | `ansible.builtin.assert` | False |
+| post_migration_data_volumes ¦ Verify DataVolume Storage Sizes | `ansible.builtin.debug` | False |
+| post_migration_data_volumes ¦ Report Data Volume Summary | `ansible.builtin.debug` | False |
+
+#### File: tasks/post_migration_networks.yml
+
+| Name | Module | Has Conditions |
+| ---- | ------ | --------- |
+| post_migration_networks ¦ Collect VirtualMachines for Network Validation | `kubernetes.core.k8s_info` | False |
+| post_migration_networks ¦ Validate VM Network Interfaces | `ansible.builtin.assert` | False |
+| post_migration_networks ¦ Verify Network-Interface Count Match | `ansible.builtin.assert` | False |
+| post_migration_networks ¦ Collect NetworkAttachmentDefinitions | `kubernetes.core.k8s_info` | False |
+| post_migration_networks ¦ Report Network Attachment Definitions | `ansible.builtin.debug` | True |
+| post_migration_networks ¦ Collect NetworkPolicies | `kubernetes.core.k8s_info` | False |
+| post_migration_networks ¦ Report Network Policies | `ansible.builtin.debug` | False |
+| post_migration_networks ¦ Report Network Validation Summary | `ansible.builtin.debug` | False |
+
+#### File: tasks/post_migration_relationships.yml
+
+| Name | Module | Has Conditions |
+| ---- | ------ | --------- |
+| post_migration_relationships ¦ Collect VMs for Relationship Validation | `kubernetes.core.k8s_info` | False |
+| post_migration_relationships ¦ Collect DataVolumes for Relationship Validation | `kubernetes.core.k8s_info` | False |
+| post_migration_relationships ¦ Initialize Relationship Tracking | `ansible.builtin.set_fact` | False |
+| post_migration_relationships ¦ Verify VM Volume References Exist | `ansible.builtin.include_tasks` | False |
+| post_migration_relationships ¦ Check for Orphaned DataVolumes | `ansible.builtin.set_fact` | True |
+| post_migration_relationships ¦ Warn About Orphaned DataVolumes | `ansible.builtin.debug` | True |
+| post_migration_relationships ¦ Report Missing DataVolumes | `ansible.builtin.debug` | True |
+| post_migration_relationships ¦ Report Relationship Summary | `ansible.builtin.debug` | False |
+
+#### File: tasks/post_migration_vms.yml
+
+| Name | Module | Has Conditions |
+| ---- | ------ | --------- |
+| post_migration_vms ¦ Initialize VM Validation Results | `ansible.builtin.set_fact` | False |
+| post_migration_vms ¦ Collect VirtualMachines in Target Namespace | `kubernetes.core.k8s_info` | False |
+| post_migration_vms ¦ Verify VirtualMachines Exist | `ansible.builtin.assert` | False |
+| post_migration_vms ¦ Validate Each VirtualMachine | `ansible.builtin.include_tasks` | False |
+| post_migration_vms ¦ Report VM Validation Summary | `ansible.builtin.debug` | False |
+
#### File: tasks/vmware_firewall_rules.yml
| Name | Module | Has Conditions |
@@ -128,6 +229,57 @@ Description: Verification of an Ansible for OpenShift Virtualization Migration e
## Task Flow Graphs
+### Graph for _validate_vm.yml
+
+```mermaid
+flowchart TD
+Start
+classDef block stroke:#3498db,stroke-width:2px;
+classDef task stroke:#4b76bb,stroke-width:2px;
+classDef includeTasks stroke:#16a085,stroke-width:2px;
+classDef importTasks stroke:#34495e,stroke-width:2px;
+classDef includeRole stroke:#2980b9,stroke-width:2px;
+classDef importRole stroke:#699ba7,stroke-width:2px;
+classDef includeVars stroke:#8e44ad,stroke-width:2px;
+classDef rescue stroke:#665352,stroke-width:2px;
+
+ Start-->|Task| _validate_vm___Verify_VM_Has_Required_Spec_Fields0[ validate vm verify vm has required spec fields]:::task
+ _validate_vm___Verify_VM_Has_Required_Spec_Fields0-->|Task| _validate_vm___Verify_VM_Has_CPU_Configuration1[ validate vm verify vm has cpu configuration]:::task
+ _validate_vm___Verify_VM_Has_CPU_Configuration1-->|Task| _validate_vm___Verify_VM_Has_Memory_Configuration2[ validate vm verify vm has memory configuration]:::task
+ _validate_vm___Verify_VM_Has_Memory_Configuration2-->|Task| _validate_vm___Verify_VM_Has_Volumes_Defined3[ validate vm verify vm has volumes defined]:::task
+ _validate_vm___Verify_VM_Has_Volumes_Defined3-->|Task| _validate_vm___Verify_VM_Has_Network_Interfaces4[ validate vm verify vm has network interfaces]:::task
+ _validate_vm___Verify_VM_Has_Network_Interfaces4-->|Task| _validate_vm___Collect_VirtualMachineInstance_Status5[ validate vm collect virtualmachineinstance
status
When: **validate migration check vm running bool**]:::task
+ _validate_vm___Collect_VirtualMachineInstance_Status5-->|Task| _validate_vm___Verify_VMI_Is_Running6[ validate vm verify vmi is running
When: **validate migration check vm running bool**]:::task
+ _validate_vm___Verify_VMI_Is_Running6-->|Task| _validate_vm___Record_Successful_Validation7[ validate vm record successful validation]:::task
+ _validate_vm___Record_Successful_Validation7-->End
+```
+
+### Graph for _validate_vm_volumes.yml
+
+```mermaid
+flowchart TD
+Start
+classDef block stroke:#3498db,stroke-width:2px;
+classDef task stroke:#4b76bb,stroke-width:2px;
+classDef includeTasks stroke:#16a085,stroke-width:2px;
+classDef importTasks stroke:#34495e,stroke-width:2px;
+classDef includeRole stroke:#2980b9,stroke-width:2px;
+classDef importRole stroke:#699ba7,stroke-width:2px;
+classDef includeVars stroke:#8e44ad,stroke-width:2px;
+classDef rescue stroke:#665352,stroke-width:2px;
+
+ Start-->|Task| _validate_vm_volumes___Extract_DataVolume_References_from_VM0[ validate vm volumes extract datavolume
references from vm]:::task
+ _validate_vm_volumes___Extract_DataVolume_References_from_VM0-->|Block Start| _validate_vm_volumes___Verify_Referenced_DataVolumes_Exist1_block_start_0[[ validate vm volumes verify referenced
datavolumes exist
When: **validate migration vm dv names length 0**]]:::block
+ _validate_vm_volumes___Verify_Referenced_DataVolumes_Exist1_block_start_0-->|Task| _validate_vm_volumes___Query_Referenced_DataVolumes0[ validate vm volumes query referenced
datavolumes]:::task
+ _validate_vm_volumes___Query_Referenced_DataVolumes0-->|Task| _validate_vm_volumes___Track_Missing_DataVolumes1[ validate vm volumes track missing datavolumes
When: **validate migration dv ref result resources
length 0**]:::task
+ _validate_vm_volumes___Track_Missing_DataVolumes1-.->|End of Block| _validate_vm_volumes___Verify_Referenced_DataVolumes_Exist1_block_start_0
+ _validate_vm_volumes___Track_Missing_DataVolumes1-->|Block Start| _validate_vm_volumes___Verify_Referenced_PVCs_Exist2_block_start_0[[ validate vm volumes verify referenced pvcs
exist
When: **validate migration vm pvc names length 0**]]:::block
+ _validate_vm_volumes___Verify_Referenced_PVCs_Exist2_block_start_0-->|Task| _validate_vm_volumes___Query_Referenced_PVCs0[ validate vm volumes query referenced pvcs]:::task
+ _validate_vm_volumes___Query_Referenced_PVCs0-->|Task| _validate_vm_volumes___Verify_PVC_Bindings1[ validate vm volumes verify pvc bindings]:::task
+ _validate_vm_volumes___Verify_PVC_Bindings1-.->|End of Block| _validate_vm_volumes___Verify_Referenced_PVCs_Exist2_block_start_0
+ _validate_vm_volumes___Verify_PVC_Bindings1-->End
+```
+
### Graph for main.yml
```mermaid
@@ -142,11 +294,15 @@ classDef importRole stroke:#699ba7,stroke-width:2px;
classDef includeVars stroke:#8e44ad,stroke-width:2px;
classDef rescue stroke:#665352,stroke-width:2px;
- Start-->|Include task| Include_ocp_version_tasks_ocp_version_yml_0[include ocp version tasks
include_task: ocp version yml]:::includeTasks
- Include_ocp_version_tasks_ocp_version_yml_0-->|Include task| Include_ocp_operators_tasks_ocp_operators_yml_1[include ocp operators tasks
include_task: ocp operators yml]:::includeTasks
- Include_ocp_operators_tasks_ocp_operators_yml_1-->|Include task| Include_ocp_storage_support_tasks_ocp_storage_support_yml_2[include ocp storage support tasks
include_task: ocp storage support yml]:::includeTasks
- Include_ocp_storage_support_tasks_ocp_storage_support_yml_2-->|Include task| Include_vmware_firewall_rules_tasks_vmware_firewall_rules_yml_3[include vmware firewall rules tasks
include_task: vmware firewall rules yml]:::includeTasks
- Include_vmware_firewall_rules_tasks_vmware_firewall_rules_yml_3-->End
+ Start-->|Include task| Include_ocp_version_tasks_ocp_version_yml_0[include ocp version tasks
When: **validate migration pre enabled bool**
include_task: ocp version yml]:::includeTasks
+ Include_ocp_version_tasks_ocp_version_yml_0-->|Include task| Include_ocp_operators_tasks_ocp_operators_yml_1[include ocp operators tasks
When: **validate migration pre enabled bool**
include_task: ocp operators yml]:::includeTasks
+ Include_ocp_operators_tasks_ocp_operators_yml_1-->|Include task| Include_ocp_storage_support_tasks_ocp_storage_support_yml_2[include ocp storage support tasks
When: **validate migration pre enabled bool**
include_task: ocp storage support yml]:::includeTasks
+ Include_ocp_storage_support_tasks_ocp_storage_support_yml_2-->|Include task| Include_vmware_firewall_rules_tasks_vmware_firewall_rules_yml_3[include vmware firewall rules tasks
When: **validate migration pre enabled bool**
include_task: vmware firewall rules yml]:::includeTasks
+ Include_vmware_firewall_rules_tasks_vmware_firewall_rules_yml_3-->|Include task| Include_post_migration_VM_validation_post_migration_vms_yml_4[include post migration vm validation
When: **validate migration post enabled bool**
include_task: post migration vms yml]:::includeTasks
+ Include_post_migration_VM_validation_post_migration_vms_yml_4-->|Include task| Include_post_migration_data_volume_validation_post_migration_data_volumes_yml_5[include post migration data volume validation
When: **validate migration post enabled bool**
include_task: post migration data volumes yml]:::includeTasks
+ Include_post_migration_data_volume_validation_post_migration_data_volumes_yml_5-->|Include task| Include_post_migration_network_validation_post_migration_networks_yml_6[include post migration network validation
When: **validate migration post enabled bool**
include_task: post migration networks yml]:::includeTasks
+ Include_post_migration_network_validation_post_migration_networks_yml_6-->|Include task| Include_post_migration_relationship_validation_post_migration_relationships_yml_7[include post migration relationship validation
When: **validate migration post enabled bool**
include_task: post migration relationships yml]:::includeTasks
+ Include_post_migration_relationship_validation_post_migration_relationships_yml_7-->End
```
### Graph for ocp_operators.yml
@@ -228,6 +384,102 @@ classDef rescue stroke:#665352,stroke-width:2px;
ocp_version___Print_OCP_version1-->End
```
+### Graph for post_migration_data_volumes.yml
+
+```mermaid
+flowchart TD
+Start
+classDef block stroke:#3498db,stroke-width:2px;
+classDef task stroke:#4b76bb,stroke-width:2px;
+classDef includeTasks stroke:#16a085,stroke-width:2px;
+classDef importTasks stroke:#34495e,stroke-width:2px;
+classDef includeRole stroke:#2980b9,stroke-width:2px;
+classDef importRole stroke:#699ba7,stroke-width:2px;
+classDef includeVars stroke:#8e44ad,stroke-width:2px;
+classDef rescue stroke:#665352,stroke-width:2px;
+
+ Start-->|Task| post_migration_data_volumes___Collect_DataVolumes_in_Target_Namespace0[post migration data volumes collect datavolumes
in target namespace]:::task
+ post_migration_data_volumes___Collect_DataVolumes_in_Target_Namespace0-->|Task| post_migration_data_volumes___Verify_DataVolumes_Exist1[post migration data volumes verify datavolumes
exist]:::task
+ post_migration_data_volumes___Verify_DataVolumes_Exist1-->|Task| post_migration_data_volumes___Verify_DataVolume_Status_Is_Succeeded2[post migration data volumes verify datavolume
status is succeeded]:::task
+ post_migration_data_volumes___Verify_DataVolume_Status_Is_Succeeded2-->|Task| post_migration_data_volumes___Collect_PVCs_in_Target_Namespace3[post migration data volumes collect pvcs in
target namespace]:::task
+ post_migration_data_volumes___Collect_PVCs_in_Target_Namespace3-->|Task| post_migration_data_volumes___Verify_PVCs_Are_Bound4[post migration data volumes verify pvcs are
bound]:::task
+ post_migration_data_volumes___Verify_PVCs_Are_Bound4-->|Task| post_migration_data_volumes___Verify_DataVolume_Storage_Sizes5[post migration data volumes verify datavolume
storage sizes]:::task
+ post_migration_data_volumes___Verify_DataVolume_Storage_Sizes5-->|Task| post_migration_data_volumes___Report_Data_Volume_Summary6[post migration data volumes report data volume
summary]:::task
+ post_migration_data_volumes___Report_Data_Volume_Summary6-->End
+```
+
+### Graph for post_migration_networks.yml
+
+```mermaid
+flowchart TD
+Start
+classDef block stroke:#3498db,stroke-width:2px;
+classDef task stroke:#4b76bb,stroke-width:2px;
+classDef includeTasks stroke:#16a085,stroke-width:2px;
+classDef importTasks stroke:#34495e,stroke-width:2px;
+classDef includeRole stroke:#2980b9,stroke-width:2px;
+classDef importRole stroke:#699ba7,stroke-width:2px;
+classDef includeVars stroke:#8e44ad,stroke-width:2px;
+classDef rescue stroke:#665352,stroke-width:2px;
+
+ Start-->|Task| post_migration_networks___Collect_VirtualMachines_for_Network_Validation0[post migration networks collect virtualmachines
for network validation]:::task
+ post_migration_networks___Collect_VirtualMachines_for_Network_Validation0-->|Task| post_migration_networks___Validate_VM_Network_Interfaces1[post migration networks validate vm network
interfaces]:::task
+ post_migration_networks___Validate_VM_Network_Interfaces1-->|Task| post_migration_networks___Verify_Network_Interface_Count_Match2[post migration networks verify network interface
count match]:::task
+ post_migration_networks___Verify_Network_Interface_Count_Match2-->|Task| post_migration_networks___Collect_NetworkAttachmentDefinitions3[post migration networks collect
networkattachmentdefinitions]:::task
+ post_migration_networks___Collect_NetworkAttachmentDefinitions3-->|Task| post_migration_networks___Report_Network_Attachment_Definitions4[post migration networks report network
attachment definitions
When: **validate migration nad list resources is defined**]:::task
+ post_migration_networks___Report_Network_Attachment_Definitions4-->|Task| post_migration_networks___Collect_NetworkPolicies5[post migration networks collect networkpolicies]:::task
+ post_migration_networks___Collect_NetworkPolicies5-->|Task| post_migration_networks___Report_Network_Policies6[post migration networks report network policies]:::task
+ post_migration_networks___Report_Network_Policies6-->|Task| post_migration_networks___Report_Network_Validation_Summary7[post migration networks report network
validation summary]:::task
+ post_migration_networks___Report_Network_Validation_Summary7-->End
+```
+
+### Graph for post_migration_relationships.yml
+
+```mermaid
+flowchart TD
+Start
+classDef block stroke:#3498db,stroke-width:2px;
+classDef task stroke:#4b76bb,stroke-width:2px;
+classDef includeTasks stroke:#16a085,stroke-width:2px;
+classDef importTasks stroke:#34495e,stroke-width:2px;
+classDef includeRole stroke:#2980b9,stroke-width:2px;
+classDef importRole stroke:#699ba7,stroke-width:2px;
+classDef includeVars stroke:#8e44ad,stroke-width:2px;
+classDef rescue stroke:#665352,stroke-width:2px;
+
+ Start-->|Task| post_migration_relationships___Collect_VMs_for_Relationship_Validation0[post migration relationships collect vms for
relationship validation]:::task
+ post_migration_relationships___Collect_VMs_for_Relationship_Validation0-->|Task| post_migration_relationships___Collect_DataVolumes_for_Relationship_Validation1[post migration relationships collect datavolumes
for relationship validation]:::task
+ post_migration_relationships___Collect_DataVolumes_for_Relationship_Validation1-->|Task| post_migration_relationships___Initialize_Relationship_Tracking2[post migration relationships initialize
relationship tracking]:::task
+ post_migration_relationships___Initialize_Relationship_Tracking2-->|Include task| post_migration_relationships___Verify_VM_Volume_References_Exist__validate_vm_volumes_yml_3[post migration relationships verify vm volume
references exist
include_task: validate vm volumes yml]:::includeTasks
+ post_migration_relationships___Verify_VM_Volume_References_Exist__validate_vm_volumes_yml_3-->|Task| post_migration_relationships___Check_for_Orphaned_DataVolumes4[post migration relationships check for orphaned
datavolumes
When: **validate migration rel dv metadata ownerreferences
default length 0**]:::task
+ post_migration_relationships___Check_for_Orphaned_DataVolumes4-->|Task| post_migration_relationships___Warn_About_Orphaned_DataVolumes5[post migration relationships warn about orphaned
datavolumes
When: **validate migration orphaned dvs length 0**]:::task
+ post_migration_relationships___Warn_About_Orphaned_DataVolumes5-->|Task| post_migration_relationships___Report_Missing_DataVolumes6[post migration relationships report missing
datavolumes
When: **validate migration missing dvs length 0**]:::task
+ post_migration_relationships___Report_Missing_DataVolumes6-->|Task| post_migration_relationships___Report_Relationship_Summary7[post migration relationships report relationship
summary]:::task
+ post_migration_relationships___Report_Relationship_Summary7-->End
+```
+
+### Graph for post_migration_vms.yml
+
+```mermaid
+flowchart TD
+Start
+classDef block stroke:#3498db,stroke-width:2px;
+classDef task stroke:#4b76bb,stroke-width:2px;
+classDef includeTasks stroke:#16a085,stroke-width:2px;
+classDef importTasks stroke:#34495e,stroke-width:2px;
+classDef includeRole stroke:#2980b9,stroke-width:2px;
+classDef importRole stroke:#699ba7,stroke-width:2px;
+classDef includeVars stroke:#8e44ad,stroke-width:2px;
+classDef rescue stroke:#665352,stroke-width:2px;
+
+ Start-->|Task| post_migration_vms___Initialize_VM_Validation_Results0[post migration vms initialize vm validation
results]:::task
+ post_migration_vms___Initialize_VM_Validation_Results0-->|Task| post_migration_vms___Collect_VirtualMachines_in_Target_Namespace1[post migration vms collect virtualmachines in
target namespace]:::task
+ post_migration_vms___Collect_VirtualMachines_in_Target_Namespace1-->|Task| post_migration_vms___Verify_VirtualMachines_Exist2[post migration vms verify virtualmachines exist]:::task
+ post_migration_vms___Verify_VirtualMachines_Exist2-->|Include task| post_migration_vms___Validate_Each_VirtualMachine__validate_vm_yml_3[post migration vms validate each virtualmachine
include_task: validate vm yml]:::includeTasks
+ post_migration_vms___Validate_Each_VirtualMachine__validate_vm_yml_3-->|Task| post_migration_vms___Report_VM_Validation_Summary4[post migration vms report vm validation summary]:::task
+ post_migration_vms___Report_VM_Validation_Summary4-->End
+```
+
### Graph for vmware_firewall_rules.yml
```mermaid
diff --git a/roles/validate_migration/defaults/main.yml b/roles/validate_migration/defaults/main.yml
index da560fb..5b3b296 100644
--- a/roles/validate_migration/defaults/main.yml
+++ b/roles/validate_migration/defaults/main.yml
@@ -18,4 +18,40 @@ validate_migration_namespace: openshift-mtv
validate_migration_debug: true
validate_migration_cluster_name: cluster01
+
+# Pre-migration infrastructure validation settings
+# title: Enable Pre-Migration Validation
+# required: False
+# description: Enable pre-migration infrastructure validation checks
+validate_migration_pre_enabled: true
+
+# Post-migration validation settings
+# title: Enable Post-Migration Validation
+# required: False
+# description: Enable post-migration validation checks
+validate_migration_post_enabled: false
+# title: Post-Migration Target Namespace
+# required: False
+# description: Namespace containing migrated VMs to validate
+validate_migration_post_namespace: ""
+# title: Post-Migration Label Selectors
+# required: False
+# description: Label selectors to filter VMs for validation
+validate_migration_post_label_selectors: []
+# title: Check VM Running Status
+# required: False
+# description: Verify VirtualMachineInstances are running
+validate_migration_check_vm_running: true
+# title: Expected VM Phase
+# required: False
+# description: Expected VirtualMachineInstance phase
+validate_migration_expected_vm_phase: "Running"
+# title: Expected DataVolume Phase
+# required: False
+# description: Expected DataVolume phase
+validate_migration_expected_dv_phase: "Succeeded"
+# title: KubeVirt API Version
+# required: False
+# description: KubeVirt API Version
+validate_migration_kubevirt_api_version: kubevirt.io/v1
...
diff --git a/roles/validate_migration/tasks/_validate_vm.yml b/roles/validate_migration/tasks/_validate_vm.yml
new file mode 100644
index 0000000..acea773
--- /dev/null
+++ b/roles/validate_migration/tasks/_validate_vm.yml
@@ -0,0 +1,88 @@
+---
+
+- name: _validate_vm | Verify VM Has Required Spec Fields
+ ansible.builtin.assert:
+ that:
+ - validate_migration_vm.spec is defined
+ - validate_migration_vm.spec.template is defined
+ - validate_migration_vm.spec.template.spec is defined
+ - validate_migration_vm.spec.template.spec.domain is defined
+ fail_msg: >-
+ VirtualMachine '{{ validate_migration_vm.metadata.name }}' is missing
+ required spec fields
+ quiet: true
+
+- name: _validate_vm | Verify VM Has CPU Configuration
+ ansible.builtin.assert:
+ that:
+ - >-
+ (validate_migration_vm.spec.template.spec.domain.cpu is defined) or
+ (validate_migration_vm.spec.instancetype is defined)
+ fail_msg: >-
+ VirtualMachine '{{ validate_migration_vm.metadata.name }}' has no CPU
+ configuration or instance type
+ quiet: true
+
+- name: _validate_vm | Verify VM Has Memory Configuration
+ ansible.builtin.assert:
+ that:
+ - >-
+ (validate_migration_vm.spec.template.spec.domain.resources is defined) or
+ (validate_migration_vm.spec.instancetype is defined)
+ fail_msg: >-
+ VirtualMachine '{{ validate_migration_vm.metadata.name }}' has no memory
+ configuration or instance type
+ quiet: true
+
+- name: _validate_vm | Verify VM Has Volumes Defined
+ ansible.builtin.assert:
+ that:
+ - validate_migration_vm.spec.template.spec.volumes | default([]) | length > 0
+ fail_msg: >-
+ VirtualMachine '{{ validate_migration_vm.metadata.name }}' has no volumes
+ defined
+ quiet: true
+
+- name: _validate_vm | Verify VM Has Network Interfaces
+ ansible.builtin.assert:
+ that:
+ - >-
+ validate_migration_vm.spec.template.spec.domain.devices.interfaces
+ | default([]) | length > 0
+ fail_msg: >-
+ VirtualMachine '{{ validate_migration_vm.metadata.name }}' has no network
+ interfaces defined
+ quiet: true
+
+- name: _validate_vm | Collect VirtualMachineInstance Status
+ when: validate_migration_check_vm_running | bool
+ kubernetes.core.k8s_info:
+ api_version: "{{ validate_migration_kubevirt_api_version }}"
+ kind: VirtualMachineInstance
+ namespace: "{{ validate_migration_vm.metadata.namespace }}"
+ name: "{{ validate_migration_vm.metadata.name }}"
+ register: validate_migration_vmi
+
+- name: _validate_vm | Verify VMI Is Running
+ when: validate_migration_check_vm_running | bool
+ ansible.builtin.assert:
+ that:
+ - validate_migration_vmi.resources | length > 0
+ - validate_migration_vmi.resources[0].status.phase == validate_migration_expected_vm_phase
+ fail_msg: >-
+ VirtualMachineInstance '{{ validate_migration_vm.metadata.name }}' is not
+ in '{{ validate_migration_expected_vm_phase }}' phase
+ quiet: true
+
+- name: _validate_vm | Record Successful Validation
+ ansible.builtin.set_fact:
+ validate_migration_vm_results: >-
+ {{ validate_migration_vm_results + [
+ {
+ 'name': validate_migration_vm.metadata.name,
+ 'namespace': validate_migration_vm.metadata.namespace,
+ 'status': 'passed'
+ }
+ ] }}
+
+...
diff --git a/roles/validate_migration/tasks/_validate_vm_volumes.yml b/roles/validate_migration/tasks/_validate_vm_volumes.yml
new file mode 100644
index 0000000..c6b53d9
--- /dev/null
+++ b/roles/validate_migration/tasks/_validate_vm_volumes.yml
@@ -0,0 +1,70 @@
+---
+
+- name: _validate_vm_volumes | Extract DataVolume References from VM
+ ansible.builtin.set_fact:
+ validate_migration_vm_dv_names: >-
+ {{ validate_migration_rel_vm.spec.template.spec.volumes | default([])
+ | selectattr('dataVolume', 'defined')
+ | map(attribute='dataVolume.name')
+ | list }}
+ validate_migration_vm_pvc_names: >-
+ {{ validate_migration_rel_vm.spec.template.spec.volumes | default([])
+ | selectattr('persistentVolumeClaim', 'defined')
+ | map(attribute='persistentVolumeClaim.claimName')
+ | list }}
+
+- name: _validate_vm_volumes | Verify Referenced DataVolumes Exist
+ when: validate_migration_vm_dv_names | length > 0
+ block:
+ - name: _validate_vm_volumes | Query Referenced DataVolumes
+ kubernetes.core.k8s_info:
+ api_version: cdi.kubevirt.io/v1beta1
+ kind: DataVolume
+ namespace: "{{ validate_migration_rel_vm.metadata.namespace }}"
+ name: "{{ validate_migration_dv_ref_name }}"
+ register: validate_migration_dv_ref_query
+ loop: "{{ validate_migration_vm_dv_names }}"
+ loop_control:
+ loop_var: validate_migration_dv_ref_name
+ label: "{{ validate_migration_dv_ref_name }}"
+
+ - name: _validate_vm_volumes | Track Missing DataVolumes
+ ansible.builtin.set_fact:
+ validate_migration_missing_dvs: >-
+ {{ validate_migration_missing_dvs
+ + [validate_migration_dv_ref_result.validate_migration_dv_ref_name] }}
+ when: validate_migration_dv_ref_result.resources | length == 0
+ loop: "{{ validate_migration_dv_ref_query.results }}"
+ loop_control:
+ loop_var: validate_migration_dv_ref_result
+ label: "{{ validate_migration_dv_ref_result.validate_migration_dv_ref_name }}"
+
+- name: _validate_vm_volumes | Verify Referenced PVCs Exist
+ when: validate_migration_vm_pvc_names | length > 0
+ block:
+ - name: _validate_vm_volumes | Query Referenced PVCs
+ kubernetes.core.k8s_info:
+ api_version: v1
+ kind: PersistentVolumeClaim
+ namespace: "{{ validate_migration_rel_vm.metadata.namespace }}"
+ name: "{{ validate_migration_pvc_ref_name }}"
+ register: validate_migration_pvc_ref_query
+ loop: "{{ validate_migration_vm_pvc_names }}"
+ loop_control:
+ loop_var: validate_migration_pvc_ref_name
+ label: "{{ validate_migration_pvc_ref_name }}"
+
+ - name: _validate_vm_volumes | Verify PVC Bindings
+ ansible.builtin.assert:
+ that:
+ - validate_migration_pvc_ref_result.resources | length > 0
+ fail_msg: >-
+ PVC '{{ validate_migration_pvc_ref_result.validate_migration_pvc_ref_name }}'
+ referenced by VM '{{ validate_migration_rel_vm.metadata.name }}' not found
+ quiet: true
+ loop: "{{ validate_migration_pvc_ref_query.results }}"
+ loop_control:
+ loop_var: validate_migration_pvc_ref_result
+ label: "{{ validate_migration_pvc_ref_result.validate_migration_pvc_ref_name }}"
+
+...
diff --git a/roles/validate_migration/tasks/main.yml b/roles/validate_migration/tasks/main.yml
index 4d1e097..5b4b670 100644
--- a/roles/validate_migration/tasks/main.yml
+++ b/roles/validate_migration/tasks/main.yml
@@ -1,11 +1,34 @@
---
# tasks file for validation
+
+# Pre-migration infrastructure validation
- name: Include ocp_version tasks
+ when: validate_migration_pre_enabled | bool
ansible.builtin.include_tasks: ocp_version.yml
- name: Include ocp_operators tasks
+ when: validate_migration_pre_enabled | bool
ansible.builtin.include_tasks: ocp_operators.yml
- name: Include ocp_storage_support tasks
+ when: validate_migration_pre_enabled | bool
ansible.builtin.include_tasks: ocp_storage_support.yml
- name: Include vmware_firewall_rules tasks
+ when: validate_migration_pre_enabled | bool
ansible.builtin.include_tasks: vmware_firewall_rules.yml
+
+# Post-migration validation
+- name: Include post-migration VM validation
+ when: validate_migration_post_enabled | bool
+ ansible.builtin.include_tasks: post_migration_vms.yml
+
+- name: Include post-migration data volume validation
+ when: validate_migration_post_enabled | bool
+ ansible.builtin.include_tasks: post_migration_data_volumes.yml
+
+- name: Include post-migration network validation
+ when: validate_migration_post_enabled | bool
+ ansible.builtin.include_tasks: post_migration_networks.yml
+
+- name: Include post-migration relationship validation
+ when: validate_migration_post_enabled | bool
+ ansible.builtin.include_tasks: post_migration_relationships.yml
...
diff --git a/roles/validate_migration/tasks/post_migration_data_volumes.yml b/roles/validate_migration/tasks/post_migration_data_volumes.yml
new file mode 100644
index 0000000..361c546
--- /dev/null
+++ b/roles/validate_migration/tasks/post_migration_data_volumes.yml
@@ -0,0 +1,72 @@
+---
+
+- name: post_migration_data_volumes | Collect DataVolumes in Target Namespace
+ kubernetes.core.k8s_info:
+ api_version: cdi.kubevirt.io/v1beta1
+ kind: DataVolume
+ namespace: "{{ validate_migration_post_namespace }}"
+ register: validate_migration_dv_list
+
+- name: post_migration_data_volumes | Verify DataVolumes Exist
+ ansible.builtin.assert:
+ that:
+ - validate_migration_dv_list.resources | length > 0
+ fail_msg: >-
+ No DataVolumes found in namespace '{{ validate_migration_post_namespace }}'
+ quiet: true
+
+- name: post_migration_data_volumes | Verify DataVolume Status Is Succeeded
+ ansible.builtin.assert:
+ that:
+ - validate_migration_dv.status.phase | default('') == validate_migration_expected_dv_phase
+ fail_msg: >-
+ DataVolume '{{ validate_migration_dv.metadata.name }}' phase is
+ '{{ validate_migration_dv.status.phase | default("Unknown") }}'
+ (expected '{{ validate_migration_expected_dv_phase }}')
+ quiet: true
+ loop: "{{ validate_migration_dv_list.resources }}"
+ loop_control:
+ loop_var: validate_migration_dv
+ label: "{{ validate_migration_dv.metadata.name }}"
+
+- name: post_migration_data_volumes | Collect PVCs in Target Namespace
+ kubernetes.core.k8s_info:
+ api_version: v1
+ kind: PersistentVolumeClaim
+ namespace: "{{ validate_migration_post_namespace }}"
+ register: validate_migration_pvc_list
+
+- name: post_migration_data_volumes | Verify PVCs Are Bound
+ ansible.builtin.assert:
+ that:
+ - validate_migration_pvc.status.phase == 'Bound'
+ fail_msg: >-
+ PVC '{{ validate_migration_pvc.metadata.name }}' is not Bound
+ (status: {{ validate_migration_pvc.status.phase | default('Unknown') }})
+ quiet: true
+ loop: "{{ validate_migration_pvc_list.resources }}"
+ loop_control:
+ loop_var: validate_migration_pvc
+ label: "{{ validate_migration_pvc.metadata.name }}"
+
+- name: post_migration_data_volumes | Verify DataVolume Storage Sizes
+ ansible.builtin.debug:
+ msg: >-
+ DataVolume '{{ validate_migration_dv.metadata.name }}'
+ size: {{ validate_migration_dv.spec.pvc.resources.requests.storage
+ | default(validate_migration_dv.spec.storage.resources.requests.storage
+ | default('N/A')) }}
+ status: {{ validate_migration_dv.status.phase | default('Unknown') }}
+ loop: "{{ validate_migration_dv_list.resources }}"
+ loop_control:
+ loop_var: validate_migration_dv
+ label: "{{ validate_migration_dv.metadata.name }}"
+
+- name: post_migration_data_volumes | Report Data Volume Summary
+ ansible.builtin.debug:
+ msg: >-
+ Data Volume Validation Complete:
+ {{ validate_migration_dv_list.resources | length }} DataVolumes,
+ {{ validate_migration_pvc_list.resources | length }} PVCs checked
+
+...
diff --git a/roles/validate_migration/tasks/post_migration_networks.yml b/roles/validate_migration/tasks/post_migration_networks.yml
new file mode 100644
index 0000000..eabddf8
--- /dev/null
+++ b/roles/validate_migration/tasks/post_migration_networks.yml
@@ -0,0 +1,83 @@
+---
+
+- name: post_migration_networks | Collect VirtualMachines for Network Validation
+ kubernetes.core.k8s_info:
+ api_version: "{{ validate_migration_kubevirt_api_version }}"
+ kind: VirtualMachine
+ namespace: "{{ validate_migration_post_namespace }}"
+ label_selectors: "{{ validate_migration_post_label_selectors | default(omit) }}"
+ register: validate_migration_net_vm_list
+
+- name: post_migration_networks | Validate VM Network Interfaces
+ ansible.builtin.assert:
+ that:
+ - >-
+ validate_migration_net_vm.spec.template.spec.domain.devices.interfaces
+ | default([]) | length > 0
+ - >-
+ validate_migration_net_vm.spec.template.spec.networks
+ | default([]) | length > 0
+ fail_msg: >-
+ VirtualMachine '{{ validate_migration_net_vm.metadata.name }}' has
+ incomplete network configuration
+ quiet: true
+ loop: "{{ validate_migration_net_vm_list.resources }}"
+ loop_control:
+ loop_var: validate_migration_net_vm
+ label: "{{ validate_migration_net_vm.metadata.name }}"
+
+- name: post_migration_networks | Verify Network-Interface Count Match
+ ansible.builtin.assert:
+ that:
+ - >-
+ (validate_migration_net_vm.spec.template.spec.domain.devices.interfaces | default([]) | length)
+ ==
+ (validate_migration_net_vm.spec.template.spec.networks | default([]) | length)
+ fail_msg: >-
+ VirtualMachine '{{ validate_migration_net_vm.metadata.name }}' has
+ mismatched interface/network count
+ quiet: true
+ loop: "{{ validate_migration_net_vm_list.resources }}"
+ loop_control:
+ loop_var: validate_migration_net_vm
+ label: "{{ validate_migration_net_vm.metadata.name }}"
+
+- name: post_migration_networks | Collect NetworkAttachmentDefinitions
+ kubernetes.core.k8s_info:
+ api_version: k8s.cni.cncf.io/v1
+ kind: NetworkAttachmentDefinition
+ namespace: "{{ validate_migration_post_namespace }}"
+ register: validate_migration_nad_list
+ failed_when: false
+
+- name: post_migration_networks | Report Network Attachment Definitions
+ when: validate_migration_nad_list.resources is defined
+ ansible.builtin.debug:
+ msg: >-
+ Found {{ validate_migration_nad_list.resources | length }}
+ NetworkAttachmentDefinition(s) in namespace
+ '{{ validate_migration_post_namespace }}'
+
+- name: post_migration_networks | Collect NetworkPolicies
+ kubernetes.core.k8s_info:
+ api_version: networking.k8s.io/v1
+ kind: NetworkPolicy
+ namespace: "{{ validate_migration_post_namespace }}"
+ register: validate_migration_netpol_list
+ failed_when: false
+
+- name: post_migration_networks | Report Network Policies
+ ansible.builtin.debug:
+ msg: >-
+ Found {{ validate_migration_netpol_list.resources | default([]) | length }}
+ NetworkPolicy(ies) in namespace '{{ validate_migration_post_namespace }}'
+
+- name: post_migration_networks | Report Network Validation Summary
+ ansible.builtin.debug:
+ msg: >-
+ Network Validation Complete:
+ {{ validate_migration_net_vm_list.resources | length }} VMs checked,
+ {{ validate_migration_nad_list.resources | default([]) | length }} NADs,
+ {{ validate_migration_netpol_list.resources | default([]) | length }} NetworkPolicies
+
+...
diff --git a/roles/validate_migration/tasks/post_migration_relationships.yml b/roles/validate_migration/tasks/post_migration_relationships.yml
new file mode 100644
index 0000000..1cb02ce
--- /dev/null
+++ b/roles/validate_migration/tasks/post_migration_relationships.yml
@@ -0,0 +1,67 @@
+---
+
+- name: post_migration_relationships | Collect VMs for Relationship Validation
+ kubernetes.core.k8s_info:
+ api_version: "{{ validate_migration_kubevirt_api_version }}"
+ kind: VirtualMachine
+ namespace: "{{ validate_migration_post_namespace }}"
+ label_selectors: "{{ validate_migration_post_label_selectors | default(omit) }}"
+ register: validate_migration_rel_vm_list
+
+- name: post_migration_relationships | Collect DataVolumes for Relationship Validation
+ kubernetes.core.k8s_info:
+ api_version: cdi.kubevirt.io/v1beta1
+ kind: DataVolume
+ namespace: "{{ validate_migration_post_namespace }}"
+ register: validate_migration_rel_dv_list
+
+- name: post_migration_relationships | Initialize Relationship Tracking
+ ansible.builtin.set_fact:
+ validate_migration_orphaned_dvs: []
+ validate_migration_missing_dvs: []
+
+- name: post_migration_relationships | Verify VM Volume References Exist
+ ansible.builtin.include_tasks:
+ file: _validate_vm_volumes.yml
+ loop: "{{ validate_migration_rel_vm_list.resources }}"
+ loop_control:
+ loop_var: validate_migration_rel_vm
+ label: "{{ validate_migration_rel_vm.metadata.name }}"
+
+- name: post_migration_relationships | Check for Orphaned DataVolumes
+ ansible.builtin.set_fact:
+ validate_migration_orphaned_dvs: >-
+ {{ validate_migration_orphaned_dvs + [validate_migration_rel_dv.metadata.name] }}
+ when: >-
+ validate_migration_rel_dv.metadata.ownerReferences | default([]) | length == 0
+ loop: "{{ validate_migration_rel_dv_list.resources }}"
+ loop_control:
+ loop_var: validate_migration_rel_dv
+ label: "{{ validate_migration_rel_dv.metadata.name }}"
+
+- name: post_migration_relationships | Warn About Orphaned DataVolumes
+ when: validate_migration_orphaned_dvs | length > 0
+ ansible.builtin.debug:
+ msg: >-
+ WARNING: {{ validate_migration_orphaned_dvs | length }} orphaned
+ DataVolume(s) found without owner references:
+ {{ validate_migration_orphaned_dvs | join(', ') }}
+
+- name: post_migration_relationships | Report Missing DataVolumes
+ when: validate_migration_missing_dvs | length > 0
+ ansible.builtin.debug:
+ msg: >-
+ WARNING: {{ validate_migration_missing_dvs | length }} DataVolume(s)
+ referenced by VMs but not found:
+ {{ validate_migration_missing_dvs | join(', ') }}
+
+- name: post_migration_relationships | Report Relationship Summary
+ ansible.builtin.debug:
+ msg: >-
+ Relationship Validation Complete:
+ {{ validate_migration_rel_vm_list.resources | length }} VMs,
+ {{ validate_migration_rel_dv_list.resources | length }} DataVolumes,
+ {{ validate_migration_orphaned_dvs | length }} orphaned DVs,
+ {{ validate_migration_missing_dvs | length }} missing DVs
+
+...
diff --git a/roles/validate_migration/tasks/post_migration_vms.yml b/roles/validate_migration/tasks/post_migration_vms.yml
new file mode 100644
index 0000000..6db789d
--- /dev/null
+++ b/roles/validate_migration/tasks/post_migration_vms.yml
@@ -0,0 +1,38 @@
+---
+
+- name: post_migration_vms | Initialize VM Validation Results
+ ansible.builtin.set_fact:
+ validate_migration_vm_results: []
+
+- name: post_migration_vms | Collect VirtualMachines in Target Namespace
+ kubernetes.core.k8s_info:
+ api_version: "{{ validate_migration_kubevirt_api_version }}"
+ kind: VirtualMachine
+ namespace: "{{ validate_migration_post_namespace }}"
+ label_selectors: "{{ validate_migration_post_label_selectors | default(omit) }}"
+ register: validate_migration_vm_list
+
+- name: post_migration_vms | Verify VirtualMachines Exist
+ ansible.builtin.assert:
+ that:
+ - validate_migration_vm_list.resources | length > 0
+ fail_msg: >-
+ No VirtualMachines found in namespace '{{ validate_migration_post_namespace }}'
+ quiet: true
+
+- name: post_migration_vms | Validate Each VirtualMachine
+ ansible.builtin.include_tasks:
+ file: _validate_vm.yml
+ loop: "{{ validate_migration_vm_list.resources }}"
+ loop_control:
+ loop_var: validate_migration_vm
+ label: >-
+ {{ validate_migration_vm.metadata.namespace }}/{{ validate_migration_vm.metadata.name }}
+
+- name: post_migration_vms | Report VM Validation Summary
+ ansible.builtin.debug:
+ msg: >-
+ VM Validation Complete: {{ validate_migration_vm_list.resources | length }} VMs checked
+ in namespace '{{ validate_migration_post_namespace }}'
+
+...