diff --git a/README.md b/README.md index bce391f..d6004f8 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ This collection includes the following roles for managing OpenShift Virtualizati * [create_mf_aap_token](roles/create_mf_aap_token/README.md) - create_mf_aap_token * [mtv_management](roles/mtv_management/README.md) - Management of the Migration Toolkit for Virtualization (MTV). * [mtv_migrate](roles/mtv_migrate/README.md) - Migration of Virtual Machines from Source to Destination. +* [mtv_warm_cutover](roles/mtv_warm_cutover/README.md) - Trigger cutover for warm migrations to finish the migration process. * [network_mgmt](roles/network_mgmt/README.md) - Management of network related components. * [operator_management](roles/operator_management/README.md) - Management of OpenShift Operators. * [validate_migration](roles/validate_migration/README.md) - Verification of an Ansible for OpenShift Virtualization Migration environment. diff --git a/playbooks/mtv_warm_cutover.yml b/playbooks/mtv_warm_cutover.yml new file mode 100644 index 0000000..f38da45 --- /dev/null +++ b/playbooks/mtv_warm_cutover.yml @@ -0,0 +1,11 @@ +--- + +- name: Finish Warm Migration Cutover + hosts: localhost + connection: local + gather_facts: false + tasks: + - name: Invoke Warm Migration Cutover + ansible.builtin.include_role: + name: infra.openshift_virtualization_migration.mtv_warm_cutover +... diff --git a/roles/mtv_warm_cutover/README.md b/roles/mtv_warm_cutover/README.md new file mode 100644 index 0000000..9358a7a --- /dev/null +++ b/roles/mtv_warm_cutover/README.md @@ -0,0 +1,238 @@ +# mtv_warm_cutover + +## mtv_warm_cutover + +``` +Role belongs to infra/openshift_virtualization_migration +Namespace - infra +Collection - openshift_virtualization_migration +Version - 1.25.0 +Repository - https://github.com/redhat-cop/openshift_virtualization_migration +``` + +Description: Trigger cutover for warm migrations to finish the migration process. + +### Argument Specifications + +
+🧩 Argument Specifications in `meta/argument_specs` + +#### Key: main + +* **Description**: MTV Warm Cutover - Trigger cutover for warm migrations +* **Options**: + * **mtv_warm_cutover_default_namespace**: + * **Required**: false + * **Type**: str + * **Default**: openshift-mtv + * **Description**: Default namespace for MTV resources + * **mtv_warm_cutover_force_cutover**: + * **Required**: false + * **Type**: bool + * **Default**: False + * **Description**: Allow overriding an existing cutover timestamp on a Migration. Can be overridden per migration request via the force_cutover key. + * **mtv_warm_cutover_request**: + * **Required**: True + * **Type**: list + * **Default**: none + * **Description**: List of warm migration cutover requests + * **mtv_warm_cutover_verify_complete**: + * **Required**: false + * **Type**: bool + * **Default**: True + * **Description**: Wait until cutover migrations complete. Can be overridden per migration request via the verify_complete key. + * **mtv_warm_cutover_verify_delay**: + * **Required**: false + * **Type**: int + * **Default**: 20 + * **Description**: Seconds to wait between retries + * **mtv_warm_cutover_verify_retries**: + * **Required**: false + * **Type**: int + * **Default**: 360 + * **Description**: Number of retries when waiting for cutover completion + +
+ +### Defaults + +**These are static variables with lower priority** + +#### File: defaults/main.yml + +| Var | Type | Value |Choices |Required | Title | +|--------------|--------------|-------------|-------------|-------------|-------------| +| [`mtv_warm_cutover_default_namespace`](defaults/main.yml#L23) | str | `openshift-mtv` | None | False | MTV Namespace | +| [`mtv_warm_cutover_force_cutover`](defaults/main.yml#L29) | bool | `False` | None | False | Force Cutover Override | +| [`mtv_warm_cutover_request`](defaults/main.yml#L7) | list | `[]` | None | True | Warm Cutover Request | +| [`mtv_warm_cutover_verify_complete`](defaults/main.yml#L35) | bool | `True` | None | False | Verify Cutover Complete | +| [`mtv_warm_cutover_verify_delay`](defaults/main.yml#L43) | int | `20` | None | False | Verify Complete Delay | +| [`mtv_warm_cutover_verify_retries`](defaults/main.yml#L39) | int | `360` | None | False | Verify Complete Retries | + +🖇️ Full descriptions for vars in defaults/main.yml +
+`mtv_warm_cutover_default_namespace`: Default namespace for MTV resources +
+`mtv_warm_cutover_force_cutover`: >- +
+`mtv_warm_cutover_request`: List of warm migration cutover requests +
+`mtv_warm_cutover_verify_complete`: >- +
+`mtv_warm_cutover_verify_delay`: Seconds to wait between retries +
+`mtv_warm_cutover_verify_retries`: Number of retries when waiting for cutover completion +
+
+ +### Tasks + +#### File: tasks/main.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Verify mtv_warm_cutover_request Variable Provided | `ansible.builtin.assert` | False | +| Process Warm Cutover Requests | `ansible.builtin.include_tasks` | False | + +#### File: tasks/_apply_cutover.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| _apply_cutover ¦ Check if Cutover Already Defined | `ansible.builtin.set_fact` | False | +| _apply_cutover ¦ Fail When Cutover Already Set (No Force) | `ansible.builtin.fail` | True | +| _apply_cutover ¦ Override Existing Cutover Timestamp | `kubernetes.core.k8s_json_patch` | True | +| _apply_cutover ¦ Report Cutover Overridden | `ansible.builtin.debug` | True | +| _apply_cutover ¦ Patch Migration with Cutover Timestamp | `kubernetes.core.k8s_json_patch` | True | +| _apply_cutover ¦ Report Cutover Triggered | `ansible.builtin.debug` | True | +| _apply_cutover ¦ Wait for Migration to Complete | `kubernetes.core.k8s_info` | True | +| _apply_cutover ¦ Verify Migration Succeeded | `ansible.builtin.assert` | True | + +#### File: tasks/_process_cutover.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| _process_cutover ¦ Set Working Namespace | `ansible.builtin.set_fact` | False | +| _process_cutover ¦ Query Migrations by Name | `kubernetes.core.k8s_info` | True | +| _process_cutover ¦ Query Migrations by Label Selector | `kubernetes.core.k8s_info` | True | +| _process_cutover ¦ Query Migrations by Plan Name | `kubernetes.core.k8s_info` | True | +| _process_cutover ¦ Filter Migrations for Plan | `ansible.builtin.set_fact` | True | +| _process_cutover ¦ Build Migration List from Named Queries | `ansible.builtin.set_fact` | True | +| _process_cutover ¦ Build Migration List from Selector | `ansible.builtin.set_fact` | True | +| _process_cutover ¦ Build Migration List from Plan | `ansible.builtin.set_fact` | True | +| _process_cutover ¦ Verify Migrations Found | `ansible.builtin.assert` | False | +| _process_cutover ¦ Determine Cutover Timestamp | `ansible.builtin.set_fact` | False | +| _process_cutover ¦ Resolve Per-Request Overrides | `ansible.builtin.set_fact` | False | +| _process_cutover ¦ Trigger Cutover on Migrations | `ansible.builtin.include_tasks` | False | + +## Task Flow Graphs + +### Graph for _apply_cutover.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| _apply_cutover___Check_if_Cutover_Already_Defined0[ apply cutover check if cutover already defined]:::task + _apply_cutover___Check_if_Cutover_Already_Defined0-->|Task| _apply_cutover___Fail_When_Cutover_Already_Set__No_Force_1[ apply cutover fail when cutover already set no
force
When: **mtv warm cutover already set bool and not mtv
warm cutover effective force bool**]:::task + _apply_cutover___Fail_When_Cutover_Already_Set__No_Force_1-->|Task| _apply_cutover___Override_Existing_Cutover_Timestamp2[ apply cutover override existing cutover
timestamp
When: **mtv warm cutover already set bool and mtv warm
cutover effective force bool**]:::task + _apply_cutover___Override_Existing_Cutover_Timestamp2-->|Task| _apply_cutover___Report_Cutover_Overridden3[ apply cutover report cutover overridden
When: **mtv warm cutover already set bool and mtv warm
cutover effective force bool**]:::task + _apply_cutover___Report_Cutover_Overridden3-->|Task| _apply_cutover___Patch_Migration_with_Cutover_Timestamp4[ apply cutover patch migration with cutover
timestamp
When: **not mtv warm cutover already set bool**]:::task + _apply_cutover___Patch_Migration_with_Cutover_Timestamp4-->|Task| _apply_cutover___Report_Cutover_Triggered5[ apply cutover report cutover triggered
When: **not mtv warm cutover already set bool**]:::task + _apply_cutover___Report_Cutover_Triggered5-->|Task| _apply_cutover___Wait_for_Migration_to_Complete6[ apply cutover wait for migration to complete
When: **mtv warm cutover effective verify bool**]:::task + _apply_cutover___Wait_for_Migration_to_Complete6-->|Task| _apply_cutover___Verify_Migration_Succeeded7[ apply cutover verify migration succeeded
When: **mtv warm cutover effective verify bool**]:::task + _apply_cutover___Verify_Migration_Succeeded7-->End +``` + +### Graph for _process_cutover.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| _process_cutover___Set_Working_Namespace0[ process cutover set working namespace]:::task + _process_cutover___Set_Working_Namespace0-->|Task| _process_cutover___Query_Migrations_by_Name1[ process cutover query migrations by name
When: **mtv warm cutover item names default true
length 0**]:::task + _process_cutover___Query_Migrations_by_Name1-->|Task| _process_cutover___Query_Migrations_by_Label_Selector2[ process cutover query migrations by label
selector
When: **mtv warm cutover item names default true
length 0 and mtv warm cutover item label
selectors default true length 0**]:::task + _process_cutover___Query_Migrations_by_Label_Selector2-->|Task| _process_cutover___Query_Migrations_by_Plan_Name3[ process cutover query migrations by plan name
When: **mtv warm cutover item names default true
length 0 and mtv warm cutover item label
selectors default true length 0 and
mtv warm cutover item plan name default true
length 0**]:::task + _process_cutover___Query_Migrations_by_Plan_Name3-->|Task| _process_cutover___Filter_Migrations_for_Plan4[ process cutover filter migrations for plan
When: **mtv warm cutover by plan query is not skipped**]:::task + _process_cutover___Filter_Migrations_for_Plan4-->|Task| _process_cutover___Build_Migration_List_from_Named_Queries5[ process cutover build migration list from named
queries
When: **mtv warm cutover by name is not skipped**]:::task + _process_cutover___Build_Migration_List_from_Named_Queries5-->|Task| _process_cutover___Build_Migration_List_from_Selector6[ process cutover build migration list from
selector
When: **mtv warm cutover by selector is not skipped**]:::task + _process_cutover___Build_Migration_List_from_Selector6-->|Task| _process_cutover___Build_Migration_List_from_Plan7[ process cutover build migration list from plan
When: **mtv warm cutover by plan is defined and mtv warm
cutover by plan is not skipped**]:::task + _process_cutover___Build_Migration_List_from_Plan7-->|Task| _process_cutover___Verify_Migrations_Found8[ process cutover verify migrations found]:::task + _process_cutover___Verify_Migrations_Found8-->|Task| _process_cutover___Determine_Cutover_Timestamp9[ process cutover determine cutover timestamp]:::task + _process_cutover___Determine_Cutover_Timestamp9-->|Task| _process_cutover___Resolve_Per_Request_Overrides10[ process cutover resolve per request overrides]:::task + _process_cutover___Resolve_Per_Request_Overrides10-->|Include task| _process_cutover___Trigger_Cutover_on_Migrations__apply_cutover_yml_11[ process cutover trigger cutover on migrations
include_task: apply cutover yml]:::includeTasks + _process_cutover___Trigger_Cutover_on_Migrations__apply_cutover_yml_11-->End +``` + +### Graph for main.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| Verify_mtv_warm_cutover_request_Variable_Provided0[verify mtv warm cutover request variable provided]:::task + Verify_mtv_warm_cutover_request_Variable_Provided0-->|Include task| Process_Warm_Cutover_Requests__process_cutover_yml_1[process warm cutover requests
include_task: process cutover yml]:::includeTasks + Process_Warm_Cutover_Requests__process_cutover_yml_1-->End +``` + +## Playbook + +```yml +--- +- name: Test + hosts: localhost + remote_user: root + roles: + - mtv_warm_cutover +... + +``` + +## Playbook graph + +```mermaid +flowchart TD + hosts[localhost]-->|Role| mtv_warm_cutover[mtv warm cutover] +``` + +## Author Information + +OpenShift Virtualization Migration Contributors + +## License + +GPL-3.0-only + +## Minimum Ansible Version + +2.16.0 + +## Platforms + +No platforms specified. + + \ No newline at end of file diff --git a/roles/mtv_warm_cutover/defaults/main.yml b/roles/mtv_warm_cutover/defaults/main.yml new file mode 100644 index 0000000..56c5fa0 --- /dev/null +++ b/roles/mtv_warm_cutover/defaults/main.yml @@ -0,0 +1,45 @@ +--- +# defaults file for mtv_warm_cutover + +# title: Warm Cutover Request +# required: True +# description: List of warm migration cutover requests +mtv_warm_cutover_request: [] +# - namespace: # Namespace containing the Migration resources. +# names: # List of Migration resource names to trigger cutover for. \ +# Optional when using label_selectors or plan_name. +# - +# label_selectors: # Label selectors to match Migration resources. +# - = +# plan_name: # Name of the Plan to find associated Migrations for cutover. +# cutover: # ISO 8601 timestamp for scheduled cutover \ +# (e.g., '2026-04-07T02:00:00Z'). If empty, uses current time. +# force_cutover: # Override an existing cutover timestamp (default: false) +# verify_complete: # Wait until cutover migration completes (overrides global default) + +# title: MTV Namespace +# required: False +# description: Default namespace for MTV resources +mtv_warm_cutover_default_namespace: openshift-mtv +# title: Force Cutover Override +# required: False +# description: >- +# Allow overriding an existing cutover timestamp on a Migration. +# Can be overridden per migration request via the force_cutover key. +mtv_warm_cutover_force_cutover: false +# title: Verify Cutover Complete +# required: False +# description: >- +# Wait until cutover migrations complete. +# Can be overridden per migration request via the verify_complete key. +mtv_warm_cutover_verify_complete: true +# title: Verify Complete Retries +# required: False +# description: Number of retries when waiting for cutover completion +mtv_warm_cutover_verify_retries: 360 +# title: Verify Complete Delay +# required: False +# description: Seconds to wait between retries +mtv_warm_cutover_verify_delay: 20 + +... diff --git a/roles/mtv_warm_cutover/meta/argument_specs.yml b/roles/mtv_warm_cutover/meta/argument_specs.yml new file mode 100644 index 0000000..71facdb --- /dev/null +++ b/roles/mtv_warm_cutover/meta/argument_specs.yml @@ -0,0 +1,67 @@ +--- +argument_specs: + main: + short_description: MTV Warm Cutover - Trigger cutover for warm migrations + options: + mtv_warm_cutover_request: + description: List of warm migration cutover requests + type: list + required: true + elements: dict + options: + namespace: + description: Namespace containing the Migration resources + type: str + names: + description: >- + List of Migration resource names to trigger cutover for. + Optional when using label_selectors or plan_name. + type: list + elements: str + label_selectors: + description: Label selectors to match Migration resources + type: list + elements: str + plan_name: + description: Name of the Plan to find associated Migrations for cutover + type: str + cutover: + description: >- + ISO 8601 timestamp for scheduled cutover + (e.g., '2026-04-07T02:00:00Z'). If omitted, uses current time. + type: str + force_cutover: + description: >- + Override an existing cutover timestamp on a Migration. + Overrides the global mtv_warm_cutover_force_cutover default. + type: bool + verify_complete: + description: >- + Wait until the cutover migration completes. + Overrides the global mtv_warm_cutover_verify_complete default. + type: bool + mtv_warm_cutover_default_namespace: + description: Default namespace for MTV resources + type: str + default: openshift-mtv + mtv_warm_cutover_force_cutover: + description: >- + Allow overriding an existing cutover timestamp on a Migration. + Can be overridden per migration request via the force_cutover key. + type: bool + default: false + mtv_warm_cutover_verify_complete: + description: >- + Wait until cutover migrations complete. + Can be overridden per migration request via the verify_complete key. + type: bool + default: true + mtv_warm_cutover_verify_retries: + description: Number of retries when waiting for cutover completion + type: int + default: 360 + mtv_warm_cutover_verify_delay: + description: Seconds to wait between retries + type: int + default: 20 +... diff --git a/roles/mtv_warm_cutover/meta/main.yml b/roles/mtv_warm_cutover/meta/main.yml new file mode 100644 index 0000000..1829f4b --- /dev/null +++ b/roles/mtv_warm_cutover/meta/main.yml @@ -0,0 +1,10 @@ +--- +galaxy_info: + author: "" + description: Trigger cutover for warm migrations to finish the migration process. + company: Red Hat + license: GPL-3.0-only + min_ansible_version: 2.16.0 + galaxy_tags: [] +dependencies: [] +... diff --git a/roles/mtv_warm_cutover/tasks/_apply_cutover.yml b/roles/mtv_warm_cutover/tasks/_apply_cutover.yml new file mode 100644 index 0000000..1d79b9f --- /dev/null +++ b/roles/mtv_warm_cutover/tasks/_apply_cutover.yml @@ -0,0 +1,102 @@ +--- + +- name: _apply_cutover | Check if Cutover Already Defined + ansible.builtin.set_fact: + mtv_warm_cutover_already_set: >- + {{ mtv_warm_cutover_migration.spec.cutover is defined and + mtv_warm_cutover_migration.spec.cutover | default("", true) | length > 0 }} + +- name: _apply_cutover | Fail When Cutover Already Set (No Force) + when: + - mtv_warm_cutover_already_set | bool + - not (mtv_warm_cutover_effective_force | bool) + ansible.builtin.fail: + msg: >- + Migration '{{ mtv_warm_cutover_migration.metadata.name }}' + already has cutover set to + '{{ mtv_warm_cutover_migration.spec.cutover }}'. + Set force_cutover: true to override. + +- name: _apply_cutover | Override Existing Cutover Timestamp + when: + - mtv_warm_cutover_already_set | bool + - mtv_warm_cutover_effective_force | bool + kubernetes.core.k8s_json_patch: + api_version: forklift.konveyor.io/v1beta1 + kind: Migration + namespace: "{{ mtv_warm_cutover_migration.metadata.namespace }}" + name: "{{ mtv_warm_cutover_migration.metadata.name }}" + patch: + - op: replace + path: /spec/cutover + value: "{{ mtv_warm_cutover_timestamp }}" + register: mtv_warm_cutover_patch_result + +- name: _apply_cutover | Report Cutover Overridden + when: + - mtv_warm_cutover_already_set | bool + - mtv_warm_cutover_effective_force | bool + ansible.builtin.debug: + msg: >- + Cutover overridden for Migration + '{{ mtv_warm_cutover_migration.metadata.name }}' + from '{{ mtv_warm_cutover_migration.spec.cutover }}' + to {{ mtv_warm_cutover_timestamp }} + +- name: _apply_cutover | Patch Migration with Cutover Timestamp + when: not (mtv_warm_cutover_already_set | bool) + kubernetes.core.k8s_json_patch: + api_version: forklift.konveyor.io/v1beta1 + kind: Migration + namespace: "{{ mtv_warm_cutover_migration.metadata.namespace }}" + name: "{{ mtv_warm_cutover_migration.metadata.name }}" + patch: + - op: add + path: /spec/cutover + value: "{{ mtv_warm_cutover_timestamp }}" + register: mtv_warm_cutover_patch_result + +- name: _apply_cutover | Report Cutover Triggered + when: not (mtv_warm_cutover_already_set | bool) + ansible.builtin.debug: + msg: >- + Cutover triggered for Migration + '{{ mtv_warm_cutover_migration.metadata.name }}' + at {{ mtv_warm_cutover_timestamp }} + +- name: _apply_cutover | Wait for Migration to Complete + when: mtv_warm_cutover_effective_verify | bool + kubernetes.core.k8s_info: + api_version: forklift.konveyor.io/v1beta1 + kind: Migration + namespace: "{{ mtv_warm_cutover_migration.metadata.namespace }}" + name: "{{ mtv_warm_cutover_migration.metadata.name }}" + register: mtv_warm_cutover_status + until: > + mtv_warm_cutover_status is defined and + 'resources' in mtv_warm_cutover_status and + mtv_warm_cutover_status.resources | length == 1 and + 'status' in mtv_warm_cutover_status.resources | first and + 'completed' in (mtv_warm_cutover_status.resources | first).status and + (mtv_warm_cutover_status.resources | first).status.completed + | trim | length > 0 + retries: "{{ mtv_warm_cutover_verify_retries }}" + delay: "{{ mtv_warm_cutover_verify_delay }}" + +- name: _apply_cutover | Verify Migration Succeeded + when: mtv_warm_cutover_effective_verify | bool + ansible.builtin.assert: + that: + - >- + (mtv_warm_cutover_status.resources | first).status.conditions + | selectattr('type', 'defined') + | selectattr('status', 'defined') + | selectattr('type', 'equalto', 'Succeeded') + | selectattr('status', 'equalto', 'True') + | list | length == 1 + fail_msg: >- + Migration '{{ mtv_warm_cutover_migration.metadata.name }}' + cutover did not succeed + quiet: true + +... diff --git a/roles/mtv_warm_cutover/tasks/_process_cutover.yml b/roles/mtv_warm_cutover/tasks/_process_cutover.yml new file mode 100644 index 0000000..8d1dc65 --- /dev/null +++ b/roles/mtv_warm_cutover/tasks/_process_cutover.yml @@ -0,0 +1,109 @@ +--- + +- name: _process_cutover | Set Working Namespace + ansible.builtin.set_fact: + mtv_warm_cutover_namespace: >- + {{ mtv_warm_cutover_item.namespace + | default(mtv_warm_cutover_default_namespace) }} + +- name: _process_cutover | Query Migrations by Name + when: mtv_warm_cutover_item.names | default([], true) | length > 0 + kubernetes.core.k8s_info: + api_version: forklift.konveyor.io/v1beta1 + kind: Migration + namespace: "{{ mtv_warm_cutover_namespace }}" + name: "{{ mtv_warm_cutover_migration_name }}" + register: mtv_warm_cutover_by_name + loop: "{{ mtv_warm_cutover_item.names }}" + loop_control: + loop_var: mtv_warm_cutover_migration_name + label: "{{ mtv_warm_cutover_migration_name }}" + +- name: _process_cutover | Query Migrations by Label Selector + when: + - mtv_warm_cutover_item.names | default([], true) | length == 0 + - mtv_warm_cutover_item.label_selectors | default([], true) | length > 0 + kubernetes.core.k8s_info: + api_version: forklift.konveyor.io/v1beta1 + kind: Migration + namespace: "{{ mtv_warm_cutover_namespace }}" + label_selectors: "{{ mtv_warm_cutover_item.label_selectors }}" + register: mtv_warm_cutover_by_selector + +- name: _process_cutover | Query Migrations by Plan Name + when: + - mtv_warm_cutover_item.names | default([], true) | length == 0 + - mtv_warm_cutover_item.label_selectors | default([], true) | length == 0 + - mtv_warm_cutover_item.plan_name | default("", true) | length > 0 + kubernetes.core.k8s_info: + api_version: forklift.konveyor.io/v1beta1 + kind: Migration + namespace: "{{ mtv_warm_cutover_namespace }}" + register: mtv_warm_cutover_by_plan_query + +- name: _process_cutover | Filter Migrations for Plan + when: mtv_warm_cutover_by_plan_query is not skipped + ansible.builtin.set_fact: + mtv_warm_cutover_by_plan: + resources: >- + {{ mtv_warm_cutover_by_plan_query.resources + | selectattr('spec.plan.name', 'equalto', mtv_warm_cutover_item.plan_name) + | list }} + +- name: _process_cutover | Build Migration List from Named Queries + when: mtv_warm_cutover_by_name is not skipped + ansible.builtin.set_fact: + mtv_warm_cutover_migrations: >- + {{ mtv_warm_cutover_by_name.results + | selectattr('resources', 'defined') + | map(attribute='resources') + | flatten }} + +- name: _process_cutover | Build Migration List from Selector + when: mtv_warm_cutover_by_selector is not skipped + ansible.builtin.set_fact: + mtv_warm_cutover_migrations: >- + {{ mtv_warm_cutover_by_selector.resources | default([]) }} + +- name: _process_cutover | Build Migration List from Plan + when: + - mtv_warm_cutover_by_plan is defined + - mtv_warm_cutover_by_plan is not skipped + ansible.builtin.set_fact: + mtv_warm_cutover_migrations: >- + {{ mtv_warm_cutover_by_plan.resources | default([]) }} + +- name: _process_cutover | Verify Migrations Found + ansible.builtin.assert: + that: + - mtv_warm_cutover_migrations | default([], true) | length > 0 + fail_msg: >- + No Migration resources found in namespace + '{{ mtv_warm_cutover_namespace }}' + matching the provided criteria + quiet: true + +- name: _process_cutover | Determine Cutover Timestamp + ansible.builtin.set_fact: + mtv_warm_cutover_timestamp: >- + {{ mtv_warm_cutover_item.cutover + | default(now(utc=true, fmt='%Y-%m-%dT%H:%M:%SZ')) }} + +- name: _process_cutover | Resolve Per-Request Overrides + ansible.builtin.set_fact: + mtv_warm_cutover_effective_force: >- + {{ mtv_warm_cutover_item.force_cutover + | default(mtv_warm_cutover_force_cutover) | bool }} + mtv_warm_cutover_effective_verify: >- + {{ mtv_warm_cutover_item.verify_complete + | default(mtv_warm_cutover_verify_complete) | bool }} + +- name: _process_cutover | Trigger Cutover on Migrations + ansible.builtin.include_tasks: + file: _apply_cutover.yml + loop: "{{ mtv_warm_cutover_migrations }}" + loop_control: + loop_var: mtv_warm_cutover_migration + label: "{{ mtv_warm_cutover_migration.metadata.name }}" + +... diff --git a/roles/mtv_warm_cutover/tasks/main.yml b/roles/mtv_warm_cutover/tasks/main.yml new file mode 100644 index 0000000..7134ffc --- /dev/null +++ b/roles/mtv_warm_cutover/tasks/main.yml @@ -0,0 +1,20 @@ +--- + +- name: Verify mtv_warm_cutover_request Variable Provided + ansible.builtin.assert: + that: + - mtv_warm_cutover_request | default("", true) | length > 0 + fail_msg: "'mtv_warm_cutover_request' Variable Not Provided" + quiet: true + +- name: Process Warm Cutover Requests + ansible.builtin.include_tasks: + file: _process_cutover.yml + loop: "{{ mtv_warm_cutover_request }}" + loop_control: + loop_var: mtv_warm_cutover_item + label: >- + Namespace: {{ mtv_warm_cutover_item.namespace + | default(mtv_warm_cutover_default_namespace) }} + +... diff --git a/roles/mtv_warm_cutover/tests/inventory b/roles/mtv_warm_cutover/tests/inventory new file mode 100644 index 0000000..2fbb50c --- /dev/null +++ b/roles/mtv_warm_cutover/tests/inventory @@ -0,0 +1 @@ +localhost diff --git a/roles/mtv_warm_cutover/tests/test.yml b/roles/mtv_warm_cutover/tests/test.yml new file mode 100644 index 0000000..fa741e2 --- /dev/null +++ b/roles/mtv_warm_cutover/tests/test.yml @@ -0,0 +1,7 @@ +--- +- name: Test + hosts: localhost + remote_user: root + roles: + - mtv_warm_cutover +...