-
Notifications
You must be signed in to change notification settings - Fork 3
feat(mtv-warm-cutover): add warm migration cutover #19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| ... |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| --- | ||
| # 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> # Namespace containing the Migration resources. | ||
| # names: # List of Migration resource names to trigger cutover for. \ | ||
| # Optional when using label_selectors or plan_name. | ||
| # - <migration_name> | ||
| # label_selectors: # Label selectors to match Migration resources. | ||
| # - <key>=<value> | ||
| # 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. | ||
|
|
||
| # title: MTV Namespace | ||
| # required: False | ||
| # description: Default namespace for MTV resources | ||
| mtv_warm_cutover_default_namespace: openshift-mtv | ||
| # title: Verify Cutover Complete | ||
| # required: False | ||
| # description: Wait until cutover migrations complete | ||
| 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 | ||
|
|
||
| ... |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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.15.0 | ||
| galaxy_tags: [] | ||
| dependencies: [] | ||
| ... | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| --- | ||
|
|
||
| - name: _apply_cutover | Verify Migration Is a Warm Migration | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we fail if a cutover is already defined? Can we skip over patching it? |
||
| ansible.builtin.assert: | ||
| that: | ||
| - >- | ||
| mtv_warm_cutover_migration.spec.cutover is not defined or | ||
| mtv_warm_cutover_migration.spec.cutover | default("", true) | length == 0 | ||
| fail_msg: >- | ||
| Migration '{{ mtv_warm_cutover_migration.metadata.name }}' already has | ||
| a cutover timestamp set | ||
| ('{{ mtv_warm_cutover_migration.spec.cutover | default("") }}') | ||
| quiet: true | ||
|
|
||
| - name: _apply_cutover | Patch Migration with Cutover Timestamp | ||
| 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 }}" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where is |
||
| register: mtv_warm_cutover_patch_result | ||
|
|
||
| - name: _apply_cutover | Report Cutover Triggered | ||
| 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_verify_complete | 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_verify_complete | 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 | ||
|
|
||
| ... | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| --- | ||
|
|
||
| - 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 | 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 }}" | ||
|
|
||
| ... |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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) }} | ||
|
|
||
| ... |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| localhost |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| --- | ||
| - name: Test | ||
| hosts: localhost | ||
| remote_user: root | ||
| roles: | ||
| - mtv_warm_cutover | ||
| ... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be 2.16.0 now?