diff --git a/roles/backup_and_restore_scenario/README.md b/roles/backup_and_restore_scenario/README.md index 062090e..cedeabe 100644 --- a/roles/backup_and_restore_scenario/README.md +++ b/roles/backup_and_restore_scenario/README.md @@ -31,19 +31,20 @@ The role does not ship opinionated defaults. The caller must provide the following variables (typically via `-e @your_vars.yml` or under `vars:` in the playbook): -| Variable | Description | -|----------|-------------| -| `oc_api_url` | OpenShift/Kubernetes API server URL of the target cluster. | -| `oc_api_token` | Bearer token used to authenticate against the OpenShift API. | -| `appvault_name` | Trident Protect AppVault used to store the backup. | -| `application_name` | Trident Protect Application that is backed up. | -| `vm_namespace` | Namespace containing the source VMs. | -| `on_demand_backup_name` | Name of the on-demand Backup CR to create. | -| `restore_namespace` | Namespace into which VMs will be restored. | -| `backuprestore_name` | Name of the BackupRestore CR used for restoration. | -| `vm_list` | List of VM names (used during validation/restore). | -| `pvc_list` | List of PVC names associated with the VMs. | -| `vm_label` | Label value applied to VMs and PVCs. | +| Variable | Description | Default | +|----------|-------------|---------| +| `oc_api_url` | OpenShift/Kubernetes API server URL of the target cluster. | Required | +| `oc_api_token` | Bearer token used to authenticate against the OpenShift API. | Required | +| `validate_certs` | Whether to validate TLS certificates when connecting to the OpenShift/Kubernetes API. | `false` | +| `appvault_name` | Trident Protect AppVault used to store the backup. | Required | +| `application_name` | Trident Protect Application that is backed up. | Required | +| `vm_namespace` | Namespace containing the source VMs. | Required | +| `on_demand_backup_name` | Name of the on-demand Backup CR to create. | Required | +| `restore_namespace` | Namespace into which VMs will be restored. | Required | +| `backuprestore_name` | Name of the BackupRestore CR used for restoration. | Required | +| `vm_list` | List of VM names (used during validation/restore). | Required | +| `pvc_list` | List of PVC names associated with the VMs. | Required | +| `vm_label` | Label value applied to VMs and PVCs. | Required | > Note: Sensitive values (API tokens, S3 credentials) should be stored in an > Ansible Vault file rather than committed in plain text. diff --git a/roles/backup_and_restore_scenario/defaults/main.yml b/roles/backup_and_restore_scenario/defaults/main.yml index 5d939a9..97682b0 100644 --- a/roles/backup_and_restore_scenario/defaults/main.yml +++ b/roles/backup_and_restore_scenario/defaults/main.yml @@ -1,4 +1,3 @@ --- # defaults file for backup_and_restore_scenario -# This role has no opinionated defaults; all variables are expected to be -# provided by the caller (see README.md for the full list). +validate_certs: false diff --git a/roles/backup_and_restore_scenario/tasks/main.yml b/roles/backup_and_restore_scenario/tasks/main.yml index 964d2f7..90617cb 100644 --- a/roles/backup_and_restore_scenario/tasks/main.yml +++ b/roles/backup_and_restore_scenario/tasks/main.yml @@ -4,15 +4,36 @@ # OpenShift cluster and that the common tasks in roles/trident-protect/trident-protect-common have been # executed to configure the prerequisites like AppVault and Application. +# Verify required variables are defined and not empty +- name: Verify required variables are defined and not empty + ansible.builtin.fail: + msg: "{{ item }} is not defined or empty" + when: "vars[item] is not defined or (vars[item] | default('') | string | length == 0)" + loop: + - oc_api_url + - oc_api_token + - appvault_name + - application_name + - vm_namespace + - on_demand_backup_name + - restore_namespace + - backuprestore_name + +# Define anchor for OpenShift/Kubernetes API login info +- name: Define anchor for OpenShift/Kubernetes API login info + ansible.builtin.set_fact: + k8s_auth: &k8s_auth + host: "{{ oc_api_url | default(omit) }}" + api_key: "{{ oc_api_token | default(omit) }}" + validate_certs: "{{ validate_certs | default(false) }}" + # Create on-demand backup of specific VMs in a namespace by using corresponding application - name: >- Create on-demand backup of specific VMs by using corresponding application - {{ application_name | default('') ~ ' / ' ~ vm_namespace | default('') }} kubernetes.core.k8s: + <<: *k8s_auth state: present - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false namespace: "{{ vm_namespace | default('') }}" definition: apiVersion: protect.trident.netapp.io/v1 @@ -36,9 +57,7 @@ # Note: Adjust retries and delay as needed based on expected backup duration - name: Wait for the backup to complete kubernetes.core.k8s_info: - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false + <<: *k8s_auth api_version: protect.trident.netapp.io/v1 namespace: "{{ vm_namespace | default('') }}" kind: Backup @@ -60,9 +79,7 @@ # Verify that the backup was created successfully - name: Verify that the on-demand backup was created successfully - {{ on_demand_backup_name | default('') }} kubernetes.core.k8s_info: - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false + <<: *k8s_auth api_version: protect.trident.netapp.io/v1 kind: Backup namespace: "{{ vm_namespace | default('') }}" @@ -88,10 +105,8 @@ # Create a new namespace for restoration - name: Create a new restore namespace - {{ restore_namespace | default('') }} kubernetes.core.k8s: + <<: *k8s_auth state: present - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false definition: apiVersion: v1 kind: Namespace @@ -105,10 +120,8 @@ # Create a BackupRestore object to restore the VMs from the on-demand backup to a different namespace - name: Create a BackupRestore object to restore the VMs from the on-demand backup - {{ restore_namespace | default('') }} kubernetes.core.k8s: + <<: *k8s_auth state: present - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false namespace: "{{ restore_namespace | default('') }}" definition: apiVersion: protect.trident.netapp.io/v1 @@ -134,9 +147,7 @@ # Wait for the restore to complete - name: Wait for the restore to complete kubernetes.core.k8s_info: - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false + <<: *k8s_auth api_version: protect.trident.netapp.io/v1 namespace: "{{ restore_namespace | default('') }}" kind: BackupRestore @@ -158,9 +169,7 @@ # Verify that the BackupRestore object was created successfully - name: Verify that the BackupRestore was created successfully - {{ backuprestore_name | default('') }} kubernetes.core.k8s_info: - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false + <<: *k8s_auth api_version: protect.trident.netapp.io/v1 kind: BackupRestore namespace: "{{ restore_namespace | default('') }}" @@ -184,9 +193,7 @@ # Verify that the VMs have been restored successfully to the new namespace - name: Verify VMs restored to namespace - {{ restore_namespace | default('') }} kubernetes.core.k8s_info: - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false + <<: *k8s_auth api_version: kubevirt.io/v1 kind: VirtualMachine namespace: "{{ restore_namespace | default('') }}" @@ -199,9 +206,7 @@ # Verify that the PVCs have been restored successfully to the new namespace - name: Verify PVCs restored to namespace - {{ restore_namespace | default('') }} kubernetes.core.k8s_info: - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false + <<: *k8s_auth api_version: v1 kind: PersistentVolumeClaim namespace: "{{ restore_namespace | default('') }}" diff --git a/roles/backup_and_restore_scenario/tests/test.yml b/roles/backup_and_restore_scenario/tests/test.yml index 907c35e..c35015c 100644 --- a/roles/backup_and_restore_scenario/tests/test.yml +++ b/roles/backup_and_restore_scenario/tests/test.yml @@ -8,5 +8,19 @@ # README.md for a full list. oc_api_url: https://api.example.openshift.com:6443 oc_api_token: + validate_certs: false + appvault_name: appvault-ontap + application_name: my-application + vm_namespace: vm-namespace + on_demand_backup_name: on-demand-backup + restore_namespace: restore-namespace + backuprestore_name: backup-restore + vm_list: + - vm-1 + - vm-2 + pvc_list: + - pvc-1 + - pvc-2 + vm_label: app=my-vm roles: - backup_and_restore_scenario diff --git a/roles/create_snapshot_schedule/README.md b/roles/create_snapshot_schedule/README.md index 6524166..2d2f232 100644 --- a/roles/create_snapshot_schedule/README.md +++ b/roles/create_snapshot_schedule/README.md @@ -31,20 +31,21 @@ The role does not ship opinionated defaults. The caller must provide the following variables (typically via `-e @your_vars.yml` or under `vars:` in the playbook): -| Variable | Description | -|----------|-------------| -| `oc_api_url` | OpenShift/Kubernetes API server URL of the target cluster. | -| `oc_api_token` | Bearer token used to authenticate against the OpenShift API. | -| `appvault_name` | AppVault referenced by the Schedule CR. | -| `application_name` | Trident Protect Application targeted by the schedule. | -| `vm_namespace` | Namespace where the Schedule CR is created. | -| `snapshot_schedule_name` | Name of the Schedule CR to create. | -| `snapshot_retention_count` | Number of snapshots to retain. | -| `snapshot_granularity` | Granularity of the snapshot schedule (Hourly, Daily, Weekly, Monthly). | -| `snapshot_hour` | Hour of day for Daily/Weekly/Monthly snapshots (0-23). | -| `snapshot_minute` | Minute of hour for snapshots (0-59). | -| `snapshot_day_of_month` | Day of the month for Monthly snapshots (1-31). | -| `snapshot_day_of_week` | Day of the week for Weekly snapshots (0-6). | +| Variable | Description | Default | +|----------|-------------|---------| +| `oc_api_url` | OpenShift/Kubernetes API server URL of the target cluster. | Required | +| `oc_api_token` | Bearer token used to authenticate against the OpenShift API. | Required | +| `validate_certs` | Whether to validate TLS certificates when connecting to the OpenShift/Kubernetes API. | `false` | +| `appvault_name` | AppVault referenced by the Schedule CR. | Required | +| `application_name` | Trident Protect Application targeted by the schedule. | Required | +| `vm_namespace` | Namespace where the Schedule CR is created. | Required | +| `snapshot_schedule_name` | Name of the Schedule CR to create. | Required | +| `snapshot_retention_count` | Number of snapshots to retain. | Required | +| `snapshot_granularity` | Granularity of the snapshot schedule (Hourly, Daily, Weekly, Monthly). | Required | +| `snapshot_hour` | Hour of day for Daily/Weekly/Monthly snapshots (0-23). | Required | +| `snapshot_minute` | Minute of hour for snapshots (0-59). | Required | +| `snapshot_day_of_month` | Day of the month for Monthly snapshots (1-31). | Required | +| `snapshot_day_of_week` | Day of the week for Weekly snapshots (0-6). | Required | > Note: Sensitive values (API tokens, S3 credentials) should be stored in an > Ansible Vault file rather than committed in plain text. diff --git a/roles/create_snapshot_schedule/defaults/main.yml b/roles/create_snapshot_schedule/defaults/main.yml index db080ce..f0d8741 100644 --- a/roles/create_snapshot_schedule/defaults/main.yml +++ b/roles/create_snapshot_schedule/defaults/main.yml @@ -1,4 +1,3 @@ --- # defaults file for create_snapshot_schedule -# This role has no opinionated defaults; all variables are expected to be -# provided by the caller (see README.md for the full list). +validate_certs: false diff --git a/roles/create_snapshot_schedule/tasks/main.yml b/roles/create_snapshot_schedule/tasks/main.yml index ad8fcdb..20457bc 100644 --- a/roles/create_snapshot_schedule/tasks/main.yml +++ b/roles/create_snapshot_schedule/tasks/main.yml @@ -1,15 +1,36 @@ --- # Ansible tasks to create Snapshot schedules for VMs in OpenShift Virtualization using Trident protect +# Verify required variables are defined and not empty +- name: Verify required variables are defined and not empty + ansible.builtin.fail: + msg: "{{ item }} is not defined or empty" + when: "vars[item] is not defined or (vars[item] | default('') | string | length == 0)" + loop: + - oc_api_url + - oc_api_token + - snapshot_schedule_name + - application_name + - appvault_name + - vm_namespace + - snapshot_granularity + - snapshot_retention_count + +# Define anchor for OpenShift/Kubernetes API login info +- name: Define anchor for OpenShift/Kubernetes API login info + ansible.builtin.set_fact: + k8s_auth: &k8s_auth + host: "{{ oc_api_url | default(omit) }}" + api_key: "{{ oc_api_token | default(omit) }}" + validate_certs: "{{ validate_certs | default(false) }}" + # Create snapshot schedule for specific VMs in a namespace by using corresponding application - name: >- Create snapshot schedule for specific VMs by using corresponding application - {{ application_name | default('') ~ ' / ' ~ vm_namespace | default('') }} kubernetes.core.k8s: + <<: *k8s_auth state: present - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false namespace: "{{ vm_namespace | default('') }}" definition: apiVersion: protect.trident.netapp.io/v1 @@ -40,13 +61,11 @@ # Verify the newly created snapshot schedule is in place - name: Get snapshot schedule from namespace - {{ snapshot_schedule_name | default('') ~ ' / ' ~ vm_namespace | default('') }} kubernetes.core.k8s_info: + <<: *k8s_auth api_version: protect.trident.netapp.io/v1 kind: Schedule name: "{{ snapshot_schedule_name | default('') }}" namespace: "{{ vm_namespace | default('') }}" - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false register: schedule_output when: - snapshot_schedule_name is defined and snapshot_schedule_name != "" diff --git a/roles/create_snapshot_schedule/tests/test.yml b/roles/create_snapshot_schedule/tests/test.yml index fce55d7..c33c192 100644 --- a/roles/create_snapshot_schedule/tests/test.yml +++ b/roles/create_snapshot_schedule/tests/test.yml @@ -8,5 +8,16 @@ # README.md for a full list. oc_api_url: https://api.example.openshift.com:6443 oc_api_token: + validate_certs: false + snapshot_schedule_name: snapshot-schedule + application_name: my-application + appvault_name: appvault-ontap + vm_namespace: vm-namespace + snapshot_granularity: Hourly + snapshot_retention_count: 5 + snapshot_hour: 0 + snapshot_minute: 0 + snapshot_day_of_month: 1 + snapshot_day_of_week: 1 roles: - create_snapshot_schedule diff --git a/roles/dr_amr_config/README.md b/roles/dr_amr_config/README.md index 05dd8ec..0231fb8 100644 --- a/roles/dr_amr_config/README.md +++ b/roles/dr_amr_config/README.md @@ -29,18 +29,19 @@ The role does not ship opinionated defaults. The caller must provide the following variables (typically via `-e @your_vars.yml` or under `vars:` in the playbook): -| Variable | Description | -|----------|-------------| -| `src_oc_api_url` | Source OpenShift cluster API server URL (DR scenarios). | -| `src_oc_api_token` | Source OpenShift cluster bearer token (DR scenarios). | -| `dst_oc_api_url` | Destination OpenShift cluster API server URL (DR scenarios). | -| `dst_oc_api_token` | Destination OpenShift cluster bearer token (DR scenarios). | -| `src_appvault_name` | AppVault on the source cluster. | -| `dst_appvault_name` | AppVault on the destination cluster. | -| `src_application_name` | Source Application referenced by the AMR. | -| `src_vm_namespace` | Source namespace. | -| `dst_vm_namespace` | Destination namespace where replicated VMs are materialized. | -| `appmirrorrelationship_specs` | Dict with `name`, `storage_class`, and `recurrence_rule` (`dtstart`, `rrule`) for the AMR CR. | +| Variable | Description | Default | +|----------|-------------|---------| +| `src_oc_api_url` | Source OpenShift cluster API server URL (DR scenarios). | Required | +| `src_oc_api_token` | Source OpenShift cluster bearer token (DR scenarios). | Required | +| `dst_oc_api_url` | Destination OpenShift cluster API server URL (DR scenarios). | Required | +| `dst_oc_api_token` | Destination OpenShift cluster bearer token (DR scenarios). | Required | +| `validate_certs` | Whether to validate TLS certificates when connecting to the OpenShift/Kubernetes API. | `false` | +| `src_appvault_name` | AppVault on the source cluster. | Required | +| `dst_appvault_name` | AppVault on the destination cluster. | Required | +| `src_application_name` | Source Application referenced by the AMR. | Required | +| `src_vm_namespace` | Source namespace. | Required | +| `dst_vm_namespace` | Destination namespace where replicated VMs are materialized. | Required | +| `appmirrorrelationship_specs` | Dict with `name`, `storage_class`, and `recurrence_rule` (`dtstart`, `rrule`) for the AMR CR. | Required | > Note: Sensitive values (API tokens, S3 credentials) should be stored in an > Ansible Vault file rather than committed in plain text. @@ -54,8 +55,8 @@ playbook): gather_facts: false connection: local vars: - oc_api_url: "https://api.aa02-ocp.example.com:6443" - oc_api_token: "{{ OC_API_TOKEN }}" + src_oc_api_url: "https://api.src.example.openshift.com:6443" + src_oc_api_token: "{{ SRC_OC_API_TOKEN }}" # ... add the role-specific variables listed above ... roles: - dr_amr_config diff --git a/roles/dr_amr_config/defaults/main.yml b/roles/dr_amr_config/defaults/main.yml index 12d3f44..e87b77d 100644 --- a/roles/dr_amr_config/defaults/main.yml +++ b/roles/dr_amr_config/defaults/main.yml @@ -1,4 +1,3 @@ --- # defaults file for dr_amr_config -# This role has no opinionated defaults; all variables are expected to be -# provided by the caller (see README.md for the full list). +validate_certs: false diff --git a/roles/dr_amr_config/tasks/main.yml b/roles/dr_amr_config/tasks/main.yml index 84f0b56..cd1255f 100644 --- a/roles/dr_amr_config/tasks/main.yml +++ b/roles/dr_amr_config/tasks/main.yml @@ -3,15 +3,40 @@ # This role should be executed AFTER the dr_amr_prerequisites role has been run and snapshots are available on the source cluster. # For scheduled snapshots, ensure the schedule has created at least one snapshot before running this role. +# Verify required variables are defined and not empty +- name: Verify required variables are defined and not empty + ansible.builtin.fail: + msg: "{{ item }} is not defined or empty" + when: "vars[item] is not defined or (vars[item] | default('') | string | length == 0)" + loop: + - src_oc_api_url + - src_oc_api_token + - dst_oc_api_url + - dst_oc_api_token + +# Define anchor for source OpenShift/Kubernetes API login info +- name: Define anchor for source OpenShift/Kubernetes API login info + ansible.builtin.set_fact: + src_k8s_auth: &src_k8s_auth + host: "{{ src_oc_api_url | default(omit) }}" + api_key: "{{ src_oc_api_token | default(omit) }}" + validate_certs: "{{ validate_certs | default(false) }}" + +# Define anchor for destination OpenShift/Kubernetes API login info +- name: Define anchor for destination OpenShift/Kubernetes API login info + ansible.builtin.set_fact: + dst_k8s_auth: &dst_k8s_auth + host: "{{ dst_oc_api_url | default(omit) }}" + api_key: "{{ dst_oc_api_token | default(omit) }}" + validate_certs: "{{ validate_certs | default(false) }}" + # Prerequisites check - Verify that snapshots exist on the source cluster before proceeding with AMR creation - name: Check for available snapshots for source application/namespace - {{ src_application_name ~ ' / ' ~ src_vm_namespace }} kubernetes.core.k8s_info: + <<: *src_k8s_auth kind: Snapshot api_version: protect.trident.netapp.io/v1 namespace: "{{ src_vm_namespace }}" - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false register: src_snapshots_all changed_when: false tags: @@ -89,13 +114,11 @@ # Fetch the source application UID from the source OpenShift cluster - name: Get source application UID from the source OpenShift cluster kubernetes.core.k8s_info: + <<: *src_k8s_auth kind: Application api_version: protect.trident.netapp.io/v1 name: "{{ src_application_name }}" namespace: "{{ src_vm_namespace }}" - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false register: src_application_info changed_when: false failed_when: src_application_info.resources | length == 0 @@ -114,10 +137,8 @@ # On the destination OpenShift cluster, create an AppMirrorRelationship CR to replicate VMs from source to destination - name: Create an AppMirrorRelationship CR on destination OpenShift cluster to replicate VMs from source to destination kubernetes.core.k8s: + <<: *dst_k8s_auth state: present - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false wait: false definition: apiVersion: protect.trident.netapp.io/v1 @@ -144,13 +165,11 @@ # View the AppMirrorRelationship details on the destination OpenShift cluster - name: Get AppMirrorRelationship details to verify creation on the destination OpenShift cluster kubernetes.core.k8s_info: + <<: *dst_k8s_auth kind: AppMirrorRelationship api_version: protect.trident.netapp.io/v1 name: "{{ appmirrorrelationship_specs.name }}" namespace: "{{ dst_vm_namespace }}" - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false register: dst_appmirrorrelationship_info changed_when: false failed_when: dst_appmirrorrelationship_info.resources | length == 0 @@ -167,13 +186,11 @@ # Wait for the AppMirrorRelationship to reach the Established state - name: Wait for AppMirrorRelationship to reach Established state - {{ appmirrorrelationship_specs.name }} kubernetes.core.k8s_info: + <<: *dst_k8s_auth kind: AppMirrorRelationship api_version: protect.trident.netapp.io/v1 name: "{{ appmirrorrelationship_specs.name }}" namespace: "{{ dst_vm_namespace }}" - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false register: dst_amr_state until: > dst_amr_state.resources | length > 0 and diff --git a/roles/dr_amr_config/tests/test.yml b/roles/dr_amr_config/tests/test.yml index e8de6f2..fe01dc0 100644 --- a/roles/dr_amr_config/tests/test.yml +++ b/roles/dr_amr_config/tests/test.yml @@ -6,7 +6,20 @@ vars: # Provide all required variables for the role here. See the role # README.md for a full list. - oc_api_url: https://api.example.openshift.com:6443 - oc_api_token: + src_oc_api_url: https://api.src.example.openshift.com:6443 + src_oc_api_token: + dst_oc_api_url: https://api.dst.example.openshift.com:6443 + dst_oc_api_token: + validate_certs: false + src_appvault_name: src-appvault-ontap + dst_appvault_name: dst-appvault-ontap + src_application_name: my-application + src_vm_namespace: src-vm-namespace + dst_vm_namespace: dst-vm-namespace + appmirrorrelationship_specs: + name: app-mirror-relationship + namespaceMapping: + - source: src-vm-namespace + destination: dst-vm-namespace roles: - dr_amr_config diff --git a/roles/dr_amr_prerequisites/README.md b/roles/dr_amr_prerequisites/README.md index 2ac4f02..9d66942 100644 --- a/roles/dr_amr_prerequisites/README.md +++ b/roles/dr_amr_prerequisites/README.md @@ -27,26 +27,27 @@ The role does not ship opinionated defaults. The caller must provide the following variables (typically via `-e @your_vars.yml` or under `vars:` in the playbook): -| Variable | Description | -|----------|-------------| -| `src_oc_api_url` | Source OpenShift cluster API server URL (DR scenarios). | -| `src_oc_api_token` | Source OpenShift cluster bearer token (DR scenarios). | -| `dst_oc_api_url` | Destination OpenShift cluster API server URL (DR scenarios). | -| `dst_oc_api_token` | Destination OpenShift cluster bearer token (DR scenarios). | -| `src_ontap_s3_specs` | Dict with `secret_name`, `access_key`, `secret_key`, `s3_bucket_name`, `s3_endpoint` for the source ONTAP S3 backend. | -| `dst_ontap_s3_specs` | Dict with `secret_name`, `access_key`, `secret_key`, `s3_bucket_name`, `s3_endpoint` for the destination ONTAP S3 backend. | -| `src_appvault_name` | AppVault name for the source application. | -| `dst_appvault_name` | AppVault name for the destination application. | -| `src_vm_namespace` | Namespace on the source cluster containing VMs to replicate. | -| `dst_vm_namespace` | Namespace on the destination cluster where replicated VMs land. | -| `src_vm_list` | List of source VM names to label/include. | -| `src_pvc_list` | List of PVC names associated with the source VMs. | -| `src_vm_label` | Label value applied to source VMs and PVCs. | -| `src_application_name` | Application CR name for the source VMs. | -| `src_on_demand_snapshot` | Set to `true` to take an on-demand snapshot before AMR. | -| `src_on_demand_snapshot_specs` | Dict with `name` and `reclaim_policy` for the on-demand snapshot. | -| `src_scheduled_snapshot` | Set to `true` to create a Schedule on the source cluster. | -| `src_snapshot_schedule_specs` | Dict with `name`, `snapshot_reclaim_policy`, `retention_count`, `recurrence_rule` (`dtstart`, `rrule`). | +| Variable | Description | Default | +|----------|-------------|---------| +| `src_oc_api_url` | Source OpenShift cluster API server URL (DR scenarios). | Required | +| `src_oc_api_token` | Source OpenShift cluster bearer token (DR scenarios). | Required | +| `dst_oc_api_url` | Destination OpenShift cluster API server URL (DR scenarios). | Required | +| `dst_oc_api_token` | Destination OpenShift cluster bearer token (DR scenarios). | Required | +| `validate_certs` | Whether to validate TLS certificates when connecting to the OpenShift/Kubernetes API. | `false` | +| `src_ontap_s3_specs` | Dict with `secret_name`, `access_key`, `secret_key`, `s3_bucket_name`, `s3_endpoint` for the source ONTAP S3 backend. | Required | +| `dst_ontap_s3_specs` | Dict with `secret_name`, `access_key`, `secret_key`, `s3_bucket_name`, `s3_endpoint` for the destination ONTAP S3 backend. | Required | +| `src_appvault_name` | AppVault name for the source application. | Required | +| `dst_appvault_name` | AppVault name for the destination application. | Required | +| `src_vm_namespace` | Namespace on the source cluster containing VMs to replicate. | Required | +| `dst_vm_namespace` | Namespace on the destination cluster where replicated VMs land. | Required | +| `src_vm_list` | List of source VM names to label/include. | Required | +| `src_pvc_list` | List of PVC names associated with the source VMs. | Required | +| `src_vm_label` | Label value applied to source VMs and PVCs. | Required | +| `src_application_name` | Application CR name for the source VMs. | Required | +| `src_on_demand_snapshot` | Set to `true` to take an on-demand snapshot before AMR. | `false` | +| `src_on_demand_snapshot_specs` | Dict with `name` and `reclaim_policy` for the on-demand snapshot. Required when `src_on_demand_snapshot` is `true`. | — | +| `src_scheduled_snapshot` | Set to `true` to create a Schedule on the source cluster. | `false` | +| `src_snapshot_schedule_specs` | Dict with `name`, `snapshot_reclaim_policy`, `retention_count`, `recurrence_rule` (`dtstart`, `rrule`). Required when `src_scheduled_snapshot` is `true`. | — | > Note: Sensitive values (API tokens, S3 credentials) should be stored in an > Ansible Vault file rather than committed in plain text. @@ -60,8 +61,8 @@ playbook): gather_facts: false connection: local vars: - oc_api_url: "https://api.aa02-ocp.example.com:6443" - oc_api_token: "{{ OC_API_TOKEN }}" + src_oc_api_url: "https://api.src.example.openshift.com:6443" + src_oc_api_token: "{{ SRC_OC_API_TOKEN }}" # ... add the role-specific variables listed above ... roles: - dr_amr_prerequisites diff --git a/roles/dr_amr_prerequisites/defaults/main.yml b/roles/dr_amr_prerequisites/defaults/main.yml index 5ccfdca..b518298 100644 --- a/roles/dr_amr_prerequisites/defaults/main.yml +++ b/roles/dr_amr_prerequisites/defaults/main.yml @@ -1,4 +1,5 @@ --- # defaults file for dr_amr_prerequisites -# This role has no opinionated defaults; all variables are expected to be -# provided by the caller (see README.md for the full list). +validate_certs: false +src_scheduled_snapshot: false +src_on_demand_snapshot: false diff --git a/roles/dr_amr_prerequisites/tasks/main.yml b/roles/dr_amr_prerequisites/tasks/main.yml index 995a96b..154de5a 100644 --- a/roles/dr_amr_prerequisites/tasks/main.yml +++ b/roles/dr_amr_prerequisites/tasks/main.yml @@ -6,6 +6,33 @@ # The below tasks are executed on the source OpenShift cluster. Ensure that you have access to the source cluster before running these tasks. # These tasks create necessary resources such as Kubernetes Secrets, AppVaults, Applications, and Snapshots on the source cluster. +# Verify required variables are defined and not empty +- name: Verify required variables are defined and not empty + ansible.builtin.fail: + msg: "{{ item }} is not defined or empty" + when: "vars[item] is not defined or (vars[item] | default('') | string | length == 0)" + loop: + - src_oc_api_url + - src_oc_api_token + - dst_oc_api_url + - dst_oc_api_token + +# Define anchor for source OpenShift/Kubernetes API login info +- name: Define anchor for source OpenShift/Kubernetes API login info + ansible.builtin.set_fact: + src_k8s_auth: &src_k8s_auth + host: "{{ src_oc_api_url | default(omit) }}" + api_key: "{{ src_oc_api_token | default(omit) }}" + validate_certs: "{{ validate_certs | default(false) }}" + +# Define anchor for destination OpenShift/Kubernetes API login info +- name: Define anchor for destination OpenShift/Kubernetes API login info + ansible.builtin.set_fact: + dst_k8s_auth: &dst_k8s_auth + host: "{{ dst_oc_api_url | default(omit) }}" + api_key: "{{ dst_oc_api_token | default(omit) }}" + validate_certs: "{{ validate_certs | default(false) }}" + # Preflight validation - Validate variables for secret creation and AppVault setup on the source cluster - name: Validate variables for secret creation and AppVault setup on the source cluster ansible.builtin.assert: @@ -31,12 +58,10 @@ # Verify trident-protect namespace exists on the source cluster - name: Verify trident-protect namespace exists on the source OpenShift cluster kubernetes.core.k8s_info: + <<: *src_k8s_auth kind: Namespace api_version: v1 name: trident-protect - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false register: src_tp_ns_check failed_when: src_tp_ns_check.resources | length == 0 changed_when: false @@ -48,10 +73,8 @@ # Create Kubernetes Secret to store source ONTAP S3 credentials - name: Create Kubernetes Secret to store source ONTAP S3 credentials kubernetes.core.k8s: + <<: *src_k8s_auth state: present - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false definition: apiVersion: v1 kind: Secret @@ -69,13 +92,11 @@ # Verify the creation of Kubernetes Secret on the source cluster - name: Get source ONTAP S3 Secret details kubernetes.core.k8s_info: + <<: *src_k8s_auth kind: Secret api_version: v1 name: "{{ src_ontap_s3_specs.secret_name }}" namespace: trident-protect - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false register: src_ontap_s3_secret_info failed_when: src_ontap_s3_secret_info.resources | length == 0 changed_when: false @@ -86,10 +107,8 @@ # On the source OpenShift cluster, create an AppVault for the source VMs - name: Create an AppVault for the source VMs on the source OpenShift cluster kubernetes.core.k8s: + <<: *src_k8s_auth state: present - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false definition: apiVersion: protect.trident.netapp.io/v1 kind: AppVault @@ -119,13 +138,11 @@ # View the AppVault details for the source VMs - name: Get source AppVault details kubernetes.core.k8s_info: + <<: *src_k8s_auth kind: AppVault api_version: protect.trident.netapp.io/v1 name: "{{ src_appvault_name }}" namespace: trident-protect - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false register: src_appvault_info changed_when: false tags: @@ -156,9 +173,7 @@ - name: Verify source VMs namespace exists - {{ src_vm_namespace }} kubernetes.core.k8s_info: - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false + <<: *src_k8s_auth api_version: v1 kind: Namespace name: "{{ src_vm_namespace }}" @@ -177,10 +192,8 @@ Label VMs in source namespace for which snapshot needs to be taken and replicated. This label is used in the Application CR to select VMs for replication - {{ src_vm_namespace }} kubernetes.core.k8s: + <<: *src_k8s_auth state: present - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false kind: VirtualMachine name: "{{ item }}" namespace: "{{ src_vm_namespace }}" @@ -198,10 +211,8 @@ Label PVCs in source namespace for which snapshot needs to be taken and replicated. This label is used in the Application CR to select PVCs for replication - {{ src_vm_namespace }} kubernetes.core.k8s: + <<: *src_k8s_auth state: present - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false kind: PersistentVolumeClaim name: "{{ item }}" namespace: "{{ src_vm_namespace }}" @@ -218,9 +229,7 @@ # Verify labels on VMs and PVCs in source namespace - name: Verify labels on VMs in source namespace {{ src_vm_namespace }} kubernetes.core.k8s_info: - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false + <<: *src_k8s_auth namespace: "{{ src_vm_namespace }}" kind: VirtualMachine name: "{{ item }}" @@ -242,9 +251,7 @@ - name: Verify labels on PVCs in source namespace {{ src_vm_namespace }} kubernetes.core.k8s_info: - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false + <<: *src_k8s_auth namespace: "{{ src_vm_namespace }}" kind: PersistentVolumeClaim name: "{{ item }}" @@ -267,10 +274,8 @@ # On the source OpenShift cluster, create the source application CR for the VMs using label selector - name: Create the source application CR for the VMs using label selector on the source OpenShift cluster kubernetes.core.k8s: + <<: *src_k8s_auth state: present - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false definition: apiVersion: protect.trident.netapp.io/v1 kind: Application @@ -289,13 +294,11 @@ # Verify the source application CR creation - name: Get source Application CR details to verify creation kubernetes.core.k8s_info: + <<: *src_k8s_auth kind: Application api_version: protect.trident.netapp.io/v1 name: "{{ src_application_name }}" namespace: "{{ src_vm_namespace }}" - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false register: src_application_info changed_when: false tags: @@ -331,10 +334,8 @@ # Note that here snapshot schedule is created for specific VMs in a namespace by using corresponding application. - name: Create a snapshot schedule on the source OpenShift cluster for source application - {{ src_application_name }} kubernetes.core.k8s: + <<: *src_k8s_auth state: present - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false definition: apiVersion: protect.trident.netapp.io/v1 kind: Schedule @@ -359,13 +360,11 @@ # Verify the snapshot schedule creation - name: Get source snapshot schedule details to verify creation kubernetes.core.k8s_info: + <<: *src_k8s_auth kind: Schedule api_version: protect.trident.netapp.io/v1 name: "{{ src_snapshot_schedule_specs.name }}" namespace: "{{ src_vm_namespace }}" - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false register: src_snapshot_schedule_info changed_when: false when: src_scheduled_snapshot | default(false) @@ -400,10 +399,8 @@ # This snapshot is used as the basis for replication on the destination cluster. - name: Create an on-demand snapshot on the source OpenShift cluster for source application - {{ src_application_name }} kubernetes.core.k8s: + <<: *src_k8s_auth state: present - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false definition: apiVersion: protect.trident.netapp.io/v1 kind: Snapshot @@ -421,13 +418,11 @@ # Verify the on-demand snapshot creation - name: Get source on-demand snapshot details to verify creation kubernetes.core.k8s_info: + <<: *src_k8s_auth kind: Snapshot api_version: protect.trident.netapp.io/v1 name: "{{ src_on_demand_snapshot_specs.name }}" namespace: "{{ src_vm_namespace }}" - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false register: src_on_demand_snapshot_info changed_when: false when: src_on_demand_snapshot | default(false) @@ -474,10 +469,8 @@ # On the destination OpenShift cluster, create a new namespace for destination VMs if it does not exist - name: Create destination namespace on the destination OpenShift cluster - {{ dst_vm_namespace }} kubernetes.core.k8s: + <<: *dst_k8s_auth state: present - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false definition: apiVersion: v1 kind: Namespace @@ -490,12 +483,10 @@ # Verify trident-protect namespace exists on the destination OpenShift cluster - name: Verify trident-protect namespace exists on the destination OpenShift cluster kubernetes.core.k8s_info: + <<: *dst_k8s_auth kind: Namespace api_version: v1 name: trident-protect - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false register: dst_tp_ns_check failed_when: dst_tp_ns_check.resources | length == 0 changed_when: false @@ -509,10 +500,8 @@ # Create Kubernetes Secret to store source ONTAP S3 credentials on the destination OpenShift cluster - name: Create Kubernetes Secret to store source ONTAP S3 credentials on the destination OpenShift cluster kubernetes.core.k8s: + <<: *dst_k8s_auth state: present - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false definition: apiVersion: v1 kind: Secret @@ -530,13 +519,11 @@ # Verify the creation of secret to store source ONTAP S3 credentials on the destination cluster - name: Verify the creation of secret to store source ONTAP S3 credentials on the destination cluster kubernetes.core.k8s_info: + <<: *dst_k8s_auth kind: Secret api_version: v1 name: "{{ src_ontap_s3_specs.secret_name }}" namespace: trident-protect - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false register: dst_src_ontap_s3_secret_info failed_when: dst_src_ontap_s3_secret_info.resources | length == 0 changed_when: false @@ -547,10 +534,8 @@ # On the destination OpenShift cluster, create a source application AppVault CR - name: Create source application AppVault CR on the destination OpenShift cluster kubernetes.core.k8s: + <<: *dst_k8s_auth state: present - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false definition: apiVersion: protect.trident.netapp.io/v1 kind: AppVault @@ -580,13 +565,11 @@ # View the source application AppVault details on the destination OpenShift cluster - name: Get source application AppVault details on the destination OpenShift cluster kubernetes.core.k8s_info: + <<: *dst_k8s_auth kind: AppVault api_version: protect.trident.netapp.io/v1 name: "{{ src_appvault_name }}" namespace: trident-protect - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false register: dst_src_appvault_info changed_when: false tags: @@ -603,10 +586,8 @@ # Create Kubernetes Secret to store destination ONTAP S3 credentials on the destination OpenShift cluster - name: Create Kubernetes Secret to store destination ONTAP S3 credentials on the destination OpenShift cluster kubernetes.core.k8s: + <<: *dst_k8s_auth state: present - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false definition: apiVersion: v1 kind: Secret @@ -624,13 +605,11 @@ # Verify the creation of secret to store destination ONTAP S3 credentials on the destination cluster - name: Verify the creation of secret to store destination ONTAP S3 credentials on the destination cluster kubernetes.core.k8s_info: + <<: *dst_k8s_auth kind: Secret api_version: v1 name: "{{ dst_ontap_s3_specs.secret_name }}" namespace: trident-protect - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false register: dst_ontap_s3_secret_info failed_when: dst_ontap_s3_secret_info.resources | length == 0 changed_when: false @@ -641,10 +620,8 @@ # Create a destination AppVault CR for the destination application on the destination OpenShift cluster - name: Create a destination AppVault CR for the destination application on the destination OpenShift cluster kubernetes.core.k8s: + <<: *dst_k8s_auth state: present - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false definition: apiVersion: protect.trident.netapp.io/v1 kind: AppVault @@ -674,13 +651,11 @@ # View the destination application AppVault details on the destination OpenShift cluster - name: Get destination application AppVault details on the destination OpenShift cluster kubernetes.core.k8s_info: + <<: *dst_k8s_auth kind: AppVault api_version: protect.trident.netapp.io/v1 name: "{{ dst_appvault_name }}" namespace: trident-protect - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false register: dst_appvault_info changed_when: false tags: diff --git a/roles/dr_amr_prerequisites/tests/test.yml b/roles/dr_amr_prerequisites/tests/test.yml index f7db0d2..877d049 100644 --- a/roles/dr_amr_prerequisites/tests/test.yml +++ b/roles/dr_amr_prerequisites/tests/test.yml @@ -6,7 +6,44 @@ vars: # Provide all required variables for the role here. See the role # README.md for a full list. - oc_api_url: https://api.example.openshift.com:6443 - oc_api_token: + src_oc_api_url: https://api.src.example.openshift.com:6443 + src_oc_api_token: + dst_oc_api_url: https://api.dst.example.openshift.com:6443 + dst_oc_api_token: + validate_certs: false + src_appvault_name: src-appvault-ontap + dst_appvault_name: dst-appvault-ontap + src_application_name: my-application + src_vm_namespace: src-vm-namespace + dst_vm_namespace: dst-vm-namespace + src_vm_list: + - vm-1 + - vm-2 + src_pvc_list: + - pvc-1 + - pvc-2 + src_vm_label: app=my-vm + src_scheduled_snapshot: true + src_on_demand_snapshot: false + src_snapshot_schedule_specs: + name: snapshot-schedule + snapshot_reclaim_policy: Delete + retention_count: 5 + recurrence_rule: + dtstart: 20240101T000000Z + rrule: FREQ=HOURLY;INTERVAL=1 + src_on_demand_snapshot_specs: + name: on-demand-snapshot + reclaim_policy: Delete + src_ontap_s3_specs: + endpoint: https://s3.example.com + bucket: src-trident-protect-bucket + credentials_secret_name: src-s3-secret + credentials_secret_namespace: trident-protect + dst_ontap_s3_specs: + endpoint: https://s3.dst.example.com + bucket: dst-trident-protect-bucket + credentials_secret_name: dst-s3-secret + credentials_secret_namespace: trident-protect roles: - dr_amr_prerequisites diff --git a/roles/dr_failback_establish_forward_amr/README.md b/roles/dr_failback_establish_forward_amr/README.md index b3e292c..9a57a73 100644 --- a/roles/dr_failback_establish_forward_amr/README.md +++ b/roles/dr_failback_establish_forward_amr/README.md @@ -28,18 +28,19 @@ The role does not ship opinionated defaults. The caller must provide the following variables (typically via `-e @your_vars.yml` or under `vars:` in the playbook): -| Variable | Description | -|----------|-------------| -| `src_oc_api_url` | Source OpenShift cluster API server URL (DR scenarios). | -| `src_oc_api_token` | Source OpenShift cluster bearer token (DR scenarios). | -| `dst_oc_api_url` | Destination OpenShift cluster API server URL (DR scenarios). | -| `dst_oc_api_token` | Destination OpenShift cluster bearer token (DR scenarios). | -| `appmirrorrelationship_specs` | AMR specs used to recreate the forward relationship. | -| `src_appvault_name` | AppVault on the original source cluster. | -| `dst_appvault_name` | AppVault on the original destination cluster. | -| `src_application_name` | Source application name. | -| `src_vm_namespace` | Original source namespace. | -| `dst_vm_namespace` | Original destination namespace. | +| Variable | Description | Default | +|----------|-------------|---------| +| `src_oc_api_url` | Source OpenShift cluster API server URL (DR scenarios). | Required | +| `src_oc_api_token` | Source OpenShift cluster bearer token (DR scenarios). | Required | +| `dst_oc_api_url` | Destination OpenShift cluster API server URL (DR scenarios). | Required | +| `dst_oc_api_token` | Destination OpenShift cluster bearer token (DR scenarios). | Required | +| `validate_certs` | Whether to validate TLS certificates when connecting to the OpenShift/Kubernetes API. | `false` | +| `appmirrorrelationship_specs` | AMR specs used to recreate the forward relationship. | Required | +| `src_appvault_name` | AppVault on the original source cluster. | Required | +| `dst_appvault_name` | AppVault on the original destination cluster. | Required | +| `src_application_name` | Source application name. | Required | +| `src_vm_namespace` | Original source namespace. | Required | +| `dst_vm_namespace` | Original destination namespace. | Required | > Note: Sensitive values (API tokens, S3 credentials) should be stored in an > Ansible Vault file rather than committed in plain text. @@ -53,8 +54,8 @@ playbook): gather_facts: false connection: local vars: - oc_api_url: "https://api.aa02-ocp.example.com:6443" - oc_api_token: "{{ OC_API_TOKEN }}" + src_oc_api_url: "https://api.src.example.openshift.com:6443" + src_oc_api_token: "{{ SRC_OC_API_TOKEN }}" # ... add the role-specific variables listed above ... roles: - dr_failback_establish_forward_amr diff --git a/roles/dr_failback_establish_forward_amr/defaults/main.yml b/roles/dr_failback_establish_forward_amr/defaults/main.yml index 61c0ccf..e322cea 100644 --- a/roles/dr_failback_establish_forward_amr/defaults/main.yml +++ b/roles/dr_failback_establish_forward_amr/defaults/main.yml @@ -1,4 +1,3 @@ --- # defaults file for dr_failback_establish_forward_amr -# This role has no opinionated defaults; all variables are expected to be -# provided by the caller (see README.md for the full list). +validate_certs: false diff --git a/roles/dr_failback_establish_forward_amr/tasks/main.yml b/roles/dr_failback_establish_forward_amr/tasks/main.yml index e64e682..33b687c 100644 --- a/roles/dr_failback_establish_forward_amr/tasks/main.yml +++ b/roles/dr_failback_establish_forward_amr/tasks/main.yml @@ -3,15 +3,40 @@ # This role should be executed AFTER the dr_failback_prepare_forward_amr role has been executed # to ensure all pre-requisites are met to establish AMR b/w the original source and destination clusters. +# Verify required variables are defined and not empty +- name: Verify required variables are defined and not empty + ansible.builtin.fail: + msg: "{{ item }} is not defined or empty" + when: "vars[item] is not defined or (vars[item] | default('') | string | length == 0)" + loop: + - src_oc_api_url + - src_oc_api_token + - dst_oc_api_url + - dst_oc_api_token + +# Define anchor for source OpenShift/Kubernetes API login info +- name: Define anchor for source OpenShift/Kubernetes API login info + ansible.builtin.set_fact: + src_k8s_auth: &src_k8s_auth + host: "{{ src_oc_api_url | default(omit) }}" + api_key: "{{ src_oc_api_token | default(omit) }}" + validate_certs: "{{ validate_certs | default(false) }}" + +# Define anchor for destination OpenShift/Kubernetes API login info +- name: Define anchor for destination OpenShift/Kubernetes API login info + ansible.builtin.set_fact: + dst_k8s_auth: &dst_k8s_auth + host: "{{ dst_oc_api_url | default(omit) }}" + api_key: "{{ dst_oc_api_token | default(omit) }}" + validate_certs: "{{ validate_certs | default(false) }}" + # Prerequisites check - Verify that snapshots exist on the original source cluster before proceeding with AMR creation - name: Check for available snapshots on the original source cluster for application/namespace - {{ src_application_name ~ ' / ' ~ dst_vm_namespace }} kubernetes.core.k8s_info: + <<: *src_k8s_auth kind: Snapshot api_version: protect.trident.netapp.io/v1 namespace: "{{ src_vm_namespace }}" - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false register: src_snapshots_all changed_when: false tags: @@ -85,13 +110,11 @@ # Fetch the source application UID from the original source OpenShift cluster - name: Get source application UID from the original source OpenShift cluster for AMR creation on the original destination cluster kubernetes.core.k8s_info: + <<: *src_k8s_auth kind: Application api_version: protect.trident.netapp.io/v1 name: "{{ src_application_name }}" namespace: "{{ src_vm_namespace }}" - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false register: src_app_uid_info changed_when: false failed_when: src_app_uid_info.resources | length == 0 @@ -110,10 +133,8 @@ # On the original destination OpenShift cluster, create an AppMirrorRelationship CR to replicate VMs from source to destination - name: Create an AppMirrorRelationship CR on original destination OpenShift cluster to replicate VMs from source to destination kubernetes.core.k8s: + <<: *dst_k8s_auth state: present - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false wait: false definition: apiVersion: protect.trident.netapp.io/v1 @@ -140,13 +161,11 @@ # View the AppMirrorRelationship details on the original destination OpenShift cluster - name: Get AppMirrorRelationship details to verify creation on the original destination OpenShift cluster kubernetes.core.k8s_info: + <<: *dst_k8s_auth kind: AppMirrorRelationship api_version: protect.trident.netapp.io/v1 name: "{{ appmirrorrelationship_specs.name }}" namespace: "{{ dst_vm_namespace }}" - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false register: dst_appmirrorrelationship_info changed_when: false failed_when: dst_appmirrorrelationship_info.resources | length == 0 @@ -163,13 +182,11 @@ # Wait for the AppMirrorRelationship to reach the Established state - name: Wait for AppMirrorRelationship to reach Established state - {{ appmirrorrelationship_specs.name }} kubernetes.core.k8s_info: + <<: *dst_k8s_auth kind: AppMirrorRelationship api_version: protect.trident.netapp.io/v1 name: "{{ appmirrorrelationship_specs.name }}" namespace: "{{ dst_vm_namespace }}" - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false register: dst_amr_state until: > dst_amr_state.resources | length > 0 and diff --git a/roles/dr_failback_establish_forward_amr/tests/test.yml b/roles/dr_failback_establish_forward_amr/tests/test.yml index 345b791..2aee303 100644 --- a/roles/dr_failback_establish_forward_amr/tests/test.yml +++ b/roles/dr_failback_establish_forward_amr/tests/test.yml @@ -6,7 +6,20 @@ vars: # Provide all required variables for the role here. See the role # README.md for a full list. - oc_api_url: https://api.example.openshift.com:6443 - oc_api_token: + src_oc_api_url: https://api.src.example.openshift.com:6443 + src_oc_api_token: + dst_oc_api_url: https://api.dst.example.openshift.com:6443 + dst_oc_api_token: + validate_certs: false + src_appvault_name: src-appvault-ontap + dst_appvault_name: dst-appvault-ontap + src_application_name: my-application + src_vm_namespace: src-vm-namespace + dst_vm_namespace: dst-vm-namespace + appmirrorrelationship_specs: + name: app-mirror-relationship + namespaceMapping: + - source: src-vm-namespace + destination: dst-vm-namespace roles: - dr_failback_establish_forward_amr diff --git a/roles/dr_failback_prepare_forward_amr/README.md b/roles/dr_failback_prepare_forward_amr/README.md index 66465d0..cbad50c 100644 --- a/roles/dr_failback_prepare_forward_amr/README.md +++ b/roles/dr_failback_prepare_forward_amr/README.md @@ -29,18 +29,23 @@ The role does not ship opinionated defaults. The caller must provide the following variables (typically via `-e @your_vars.yml` or under `vars:` in the playbook): -| Variable | Description | -|----------|-------------| -| `src_oc_api_url` | Source OpenShift cluster API server URL (DR scenarios). | -| `src_oc_api_token` | Source OpenShift cluster bearer token (DR scenarios). | -| `dst_oc_api_url` | Destination OpenShift cluster API server URL (DR scenarios). | -| `dst_oc_api_token` | Destination OpenShift cluster bearer token (DR scenarios). | -| `appmirrorrelationship_specs` | AMR specs (uses `name`). | -| `src_appvault_name` | AppVault on the original source cluster. | -| `dst_appvault_name` | AppVault on the original destination cluster. | -| `src_vm_namespace` | Original source namespace. | -| `dst_vm_namespace` | Original destination namespace. | -| `src_application_name` | Source application name. | +| Variable | Description | Default | +|----------|-------------|---------| +| `src_oc_api_url` | Source OpenShift cluster API server URL (DR scenarios). | Required | +| `src_oc_api_token` | Source OpenShift cluster bearer token (DR scenarios). | Required | +| `dst_oc_api_url` | Destination OpenShift cluster API server URL (DR scenarios). | Required | +| `dst_oc_api_token` | Destination OpenShift cluster bearer token (DR scenarios). | Required | +| `validate_certs` | Whether to validate TLS certificates when connecting to the OpenShift/Kubernetes API. | `false` | +| `appmirrorrelationship_specs` | AMR specs (uses `name`). | Required | +| `src_appvault_name` | AppVault on the original source cluster. | Required | +| `dst_appvault_name` | AppVault on the original destination cluster. | Required | +| `src_vm_namespace` | Original source namespace. | Required | +| `dst_vm_namespace` | Original destination namespace. | Required | +| `src_application_name` | Source application name. | Required | +| `src_scheduled_snapshot` | Set to `true` to create a snapshot Schedule on the source cluster before forward AMR. | `false` | +| `src_snapshot_schedule_specs` | Dict with `name`, `snapshot_reclaim_policy`, `retention_count`, `recurrence_rule` (`dtstart`, `rrule`). Required when `src_scheduled_snapshot` is `true`. | — | +| `src_on_demand_snapshot` | Set to `true` to take an on-demand snapshot before forward AMR. | `false` | +| `src_on_demand_snapshot_specs` | Dict with `name` and `reclaim_policy` for the on-demand snapshot. Required when `src_on_demand_snapshot` is `true`. | — | > Note: Sensitive values (API tokens, S3 credentials) should be stored in an > Ansible Vault file rather than committed in plain text. @@ -54,8 +59,8 @@ playbook): gather_facts: false connection: local vars: - oc_api_url: "https://api.aa02-ocp.example.com:6443" - oc_api_token: "{{ OC_API_TOKEN }}" + src_oc_api_url: "https://api.src.example.openshift.com:6443" + src_oc_api_token: "{{ SRC_OC_API_TOKEN }}" # ... add the role-specific variables listed above ... roles: - dr_failback_prepare_forward_amr diff --git a/roles/dr_failback_prepare_forward_amr/defaults/main.yml b/roles/dr_failback_prepare_forward_amr/defaults/main.yml index 3453362..68ace9b 100644 --- a/roles/dr_failback_prepare_forward_amr/defaults/main.yml +++ b/roles/dr_failback_prepare_forward_amr/defaults/main.yml @@ -1,4 +1,5 @@ --- # defaults file for dr_failback_prepare_forward_amr -# This role has no opinionated defaults; all variables are expected to be -# provided by the caller (see README.md for the full list). +validate_certs: false +src_scheduled_snapshot: false +src_on_demand_snapshot: false diff --git a/roles/dr_failback_prepare_forward_amr/tasks/main.yml b/roles/dr_failback_prepare_forward_amr/tasks/main.yml index ad29391..e579dfb 100644 --- a/roles/dr_failback_prepare_forward_amr/tasks/main.yml +++ b/roles/dr_failback_prepare_forward_amr/tasks/main.yml @@ -3,18 +3,43 @@ # This role should be executed AFTER the dr_failback_promote role has been executed to ensure the AMR has been promoted on the # new destination (original source) cluster using the shutdown snapshot as the promoted snapshot. +# Verify required variables are defined and not empty +- name: Verify required variables are defined and not empty + ansible.builtin.fail: + msg: "{{ item }} is not defined or empty" + when: "vars[item] is not defined or (vars[item] | default('') | string | length == 0)" + loop: + - src_oc_api_url + - src_oc_api_token + - dst_oc_api_url + - dst_oc_api_token + +# Define anchor for source OpenShift/Kubernetes API login info +- name: Define anchor for source OpenShift/Kubernetes API login info + ansible.builtin.set_fact: + src_k8s_auth: &src_k8s_auth + host: "{{ src_oc_api_url | default(omit) }}" + api_key: "{{ src_oc_api_token | default(omit) }}" + validate_certs: "{{ validate_certs | default(false) }}" + +# Define anchor for destination OpenShift/Kubernetes API login info +- name: Define anchor for destination OpenShift/Kubernetes API login info + ansible.builtin.set_fact: + dst_k8s_auth: &dst_k8s_auth + host: "{{ dst_oc_api_url | default(omit) }}" + api_key: "{{ dst_oc_api_token | default(omit) }}" + validate_certs: "{{ validate_certs | default(false) }}" + # Remove any protection schedules remaining on the new destination cluster (original source cluster) that were used for replication # to the original destination cluster to ensure there are no conflicts or unintended replication activities during the failback process. - name: Remove any remaining protection schedules on the new destination cluster (original source cluster) kubernetes.core.k8s: + <<: *src_k8s_auth kind: Schedule api_version: protect.trident.netapp.io/v1 state: absent name: "{{ src_snapshot_schedule_specs.name }}" namespace: "{{ src_vm_namespace }}" - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false tags: - disable_protection_schedules @@ -22,13 +47,11 @@ # before proceeding with any further failback preparation tasks. - name: Verify all protection schedules are removed from the new destination cluster (original source cluster) kubernetes.core.k8s_info: + <<: *src_k8s_auth kind: Schedule api_version: protect.trident.netapp.io/v1 name: "{{ src_snapshot_schedule_specs.name }}" namespace: "{{ src_vm_namespace }}" - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false register: src_schedule_info failed_when: src_schedule_info.resources | length > 0 tags: @@ -37,10 +60,8 @@ # On the new destination cluster (original source cluster), delete the AppMirrorRelationship CR. This causes the destination to become the source. - name: Delete the AppMirrorRelationship CR on the new destination cluster (original source cluster) kubernetes.core.k8s: + <<: *src_k8s_auth state: absent - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false definition: apiVersion: protect.trident.netapp.io/v1 kind: AppMirrorRelationship @@ -53,13 +74,11 @@ # Wait for the AMR to be fully deleted before proceeding to reverse resync config. - name: Wait for AppMirrorRelationship to be fully deleted on the new destination cluster (original source cluster) before proceeding with reverse resync config kubernetes.core.k8s_info: + <<: *src_k8s_auth kind: AppMirrorRelationship api_version: protect.trident.netapp.io/v1 name: "{{ appmirrorrelationship_specs.name }}" namespace: "{{ src_vm_namespace }}" - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false register: src_amr_delete_check until: src_amr_delete_check.resources | length == 0 retries: 30 @@ -102,10 +121,8 @@ # on the destination cluster. - name: Create a snapshot schedule on the original source OpenShift cluster for source application - {{ src_application_name }} kubernetes.core.k8s: + <<: *src_k8s_auth state: present - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false definition: apiVersion: protect.trident.netapp.io/v1 kind: Schedule @@ -130,13 +147,11 @@ # Verify the snapshot schedule creation - name: Get source snapshot schedule details to verify creation kubernetes.core.k8s_info: + <<: *src_k8s_auth kind: Schedule api_version: protect.trident.netapp.io/v1 name: "{{ src_snapshot_schedule_specs.name }}" namespace: "{{ src_vm_namespace }}" - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false register: original_src_snapshot_schedule_info changed_when: false when: src_scheduled_snapshot | default(false) | bool @@ -173,10 +188,8 @@ # replication on the destination cluster. - name: Create an on-demand snapshot on the original source OpenShift cluster for source application - {{ src_application_name }} kubernetes.core.k8s: + <<: *src_k8s_auth state: present - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false definition: apiVersion: protect.trident.netapp.io/v1 kind: Snapshot @@ -194,13 +207,11 @@ # Wait for on-demand snapshot to reach Completed state before proceeding - name: Wait for source on-demand snapshot to reach Completed state on the original source OpenShift cluster kubernetes.core.k8s_info: + <<: *src_k8s_auth kind: Snapshot api_version: protect.trident.netapp.io/v1 name: "{{ src_on_demand_snapshot_specs.name }}" namespace: "{{ src_vm_namespace }}" - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false register: original_src_on_demand_snapshot_info until: > original_src_on_demand_snapshot_info.resources | length > 0 and diff --git a/roles/dr_failback_prepare_forward_amr/tests/test.yml b/roles/dr_failback_prepare_forward_amr/tests/test.yml index 6b34c25..29732be 100644 --- a/roles/dr_failback_prepare_forward_amr/tests/test.yml +++ b/roles/dr_failback_prepare_forward_amr/tests/test.yml @@ -6,7 +6,32 @@ vars: # Provide all required variables for the role here. See the role # README.md for a full list. - oc_api_url: https://api.example.openshift.com:6443 - oc_api_token: + src_oc_api_url: https://api.src.example.openshift.com:6443 + src_oc_api_token: + dst_oc_api_url: https://api.dst.example.openshift.com:6443 + dst_oc_api_token: + validate_certs: false + src_appvault_name: src-appvault-ontap + dst_appvault_name: dst-appvault-ontap + src_application_name: my-application + src_vm_namespace: src-vm-namespace + dst_vm_namespace: dst-vm-namespace + appmirrorrelationship_specs: + name: app-mirror-relationship + namespaceMapping: + - source: src-vm-namespace + destination: dst-vm-namespace + src_scheduled_snapshot: false + src_on_demand_snapshot: false + src_snapshot_schedule_specs: + name: snapshot-schedule + snapshot_reclaim_policy: Delete + retention_count: 5 + recurrence_rule: + dtstart: 20240101T000000Z + rrule: FREQ=HOURLY;INTERVAL=1 + src_on_demand_snapshot_specs: + name: on-demand-snapshot + reclaim_policy: Delete roles: - dr_failback_prepare_forward_amr diff --git a/roles/dr_failback_promote/README.md b/roles/dr_failback_promote/README.md index 8fe0d78..3f20ca1 100644 --- a/roles/dr_failback_promote/README.md +++ b/roles/dr_failback_promote/README.md @@ -29,15 +29,16 @@ The role does not ship opinionated defaults. The caller must provide the following variables (typically via `-e @your_vars.yml` or under `vars:` in the playbook): -| Variable | Description | -|----------|-------------| -| `src_oc_api_url` | Source OpenShift cluster API server URL (DR scenarios). | -| `src_oc_api_token` | Source OpenShift cluster bearer token (DR scenarios). | -| `dst_oc_api_url` | Destination OpenShift cluster API server URL (DR scenarios). | -| `dst_oc_api_token` | Destination OpenShift cluster bearer token (DR scenarios). | -| `appmirrorrelationship_specs` | AMR specs (uses `name`). | -| `src_vm_namespace` | Original source namespace. | -| `dst_vm_namespace` | Original destination namespace. | +| Variable | Description | Default | +|----------|-------------|---------| +| `src_oc_api_url` | Source OpenShift cluster API server URL (DR scenarios). | Required | +| `src_oc_api_token` | Source OpenShift cluster bearer token (DR scenarios). | Required | +| `dst_oc_api_url` | Destination OpenShift cluster API server URL (DR scenarios). | Required | +| `dst_oc_api_token` | Destination OpenShift cluster bearer token (DR scenarios). | Required | +| `validate_certs` | Whether to validate TLS certificates when connecting to the OpenShift/Kubernetes API. | `false` | +| `appmirrorrelationship_specs` | AMR specs (uses `name`). | Required | +| `src_vm_namespace` | Original source namespace. | Required | +| `dst_vm_namespace` | Original destination namespace. | Required | > Note: Sensitive values (API tokens, S3 credentials) should be stored in an > Ansible Vault file rather than committed in plain text. @@ -51,8 +52,8 @@ playbook): gather_facts: false connection: local vars: - oc_api_url: "https://api.aa02-ocp.example.com:6443" - oc_api_token: "{{ OC_API_TOKEN }}" + src_oc_api_url: "https://api.src.example.openshift.com:6443" + src_oc_api_token: "{{ SRC_OC_API_TOKEN }}" # ... add the role-specific variables listed above ... roles: - dr_failback_promote diff --git a/roles/dr_failback_promote/defaults/main.yml b/roles/dr_failback_promote/defaults/main.yml index 5e30f57..cecb423 100644 --- a/roles/dr_failback_promote/defaults/main.yml +++ b/roles/dr_failback_promote/defaults/main.yml @@ -1,4 +1,3 @@ --- # defaults file for dr_failback_promote -# This role has no opinionated defaults; all variables are expected to be -# provided by the caller (see README.md for the full list). +validate_certs: false diff --git a/roles/dr_failback_promote/tasks/main.yml b/roles/dr_failback_promote/tasks/main.yml index c25e413..93667eb 100644 --- a/roles/dr_failback_promote/tasks/main.yml +++ b/roles/dr_failback_promote/tasks/main.yml @@ -6,18 +6,43 @@ # Make sure the original source cluster is ready to take over as primary again and execute any necessary cleanup tasks on the destination # cluster before running this role. +# Verify required variables are defined and not empty +- name: Verify required variables are defined and not empty + ansible.builtin.fail: + msg: "{{ item }} is not defined or empty" + when: "vars[item] is not defined or (vars[item] | default('') | string | length == 0)" + loop: + - src_oc_api_url + - src_oc_api_token + - dst_oc_api_url + - dst_oc_api_token + +# Define anchor for source OpenShift/Kubernetes API login info +- name: Define anchor for source OpenShift/Kubernetes API login info + ansible.builtin.set_fact: + src_k8s_auth: &src_k8s_auth + host: "{{ src_oc_api_url | default(omit) }}" + api_key: "{{ src_oc_api_token | default(omit) }}" + validate_certs: "{{ validate_certs | default(false) }}" + +# Define anchor for destination OpenShift/Kubernetes API login info +- name: Define anchor for destination OpenShift/Kubernetes API login info + ansible.builtin.set_fact: + dst_k8s_auth: &dst_k8s_auth + host: "{{ dst_oc_api_url | default(omit) }}" + api_key: "{{ dst_oc_api_token | default(omit) }}" + validate_certs: "{{ validate_certs | default(false) }}" + # Disable protection schedules for the VM on the source (original destination) cluster to prevent any replication activities during the # failback preparation process. - name: Disable protection schedules for the VM on the source (original destination) cluster kubernetes.core.k8s: + <<: *dst_k8s_auth kind: Schedule api_version: protect.trident.netapp.io/v1 state: absent name: "{{ src_snapshot_schedule_specs.name }}" namespace: "{{ dst_vm_namespace }}" - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false tags: - disable_schedule @@ -25,13 +50,11 @@ # before proceeding with any further failback preparation tasks. - name: Verify protection schedules are disabled for the VM on the source (original destination) cluster kubernetes.core.k8s_info: + <<: *dst_k8s_auth kind: Schedule api_version: protect.trident.netapp.io/v1 name: "{{ src_snapshot_schedule_specs.name }}" namespace: "{{ dst_vm_namespace }}" - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false register: dst_schedule_info failed_when: dst_schedule_info.resources | length > 0 tags: @@ -41,10 +64,8 @@ # This snapshot will be used as the source for the failback process to restore the VM back to the original source cluster. - name: Create a shutdown snapshot on the source (original destination) cluster for failback kubernetes.core.k8s: + <<: *dst_k8s_auth state: present - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false definition: apiVersion: protect.trident.netapp.io/v1 kind: ShutdownSnapshot @@ -61,13 +82,11 @@ # Verify that the shutdown snapshot has been successfully created on the source (original destination) cluster before proceeding with the failback process. - name: Verify shutdown snapshot creation on the source (original destination) cluster kubernetes.core.k8s_info: + <<: *dst_k8s_auth kind: ShutdownSnapshot api_version: protect.trident.netapp.io/v1 name: "{{ shutdown_snapshot_name }}" namespace: "{{ dst_vm_namespace }}" - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false register: shutdown_snapshot_verify_info until: > shutdown_snapshot_verify_info.resources | length > 0 and @@ -94,13 +113,11 @@ - name: Get source application UID from the source OpenShift cluster (original destination cluster) for AMR promotion on the new destination cluster (original source cluster) kubernetes.core.k8s_info: + <<: *dst_k8s_auth kind: Application api_version: protect.trident.netapp.io/v1 name: "{{ src_application_name }}" namespace: "{{ dst_vm_namespace }}" - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false register: new_src_application_info changed_when: false failed_when: new_src_application_info.resources | length == 0 @@ -119,10 +136,8 @@ # Perform a fail over to the destination (original source) cluster using the ShutdownSnapshot as the promoted snapshot. - name: Perform failover to the destination (original source) cluster using the ShutdownSnapshot as the promoted snapshot kubernetes.core.k8s: + <<: *src_k8s_auth state: present - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false wait: false definition: apiVersion: protect.trident.netapp.io/v1 @@ -150,13 +165,11 @@ # View the AppMirrorRelationship details on the new destination OpenShift cluster (original source cluster) - name: Get AppMirrorRelationship details to verify promotion on the new destination OpenShift cluster (original source cluster) kubernetes.core.k8s_info: + <<: *src_k8s_auth kind: AppMirrorRelationship api_version: protect.trident.netapp.io/v1 name: "{{ appmirrorrelationship_specs.name }}" namespace: "{{ src_vm_namespace }}" - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false register: new_dst_appmirrorrelationship_info changed_when: false retries: 10 @@ -178,13 +191,11 @@ # Wait for the AppMirrorRelationship to reach the Promoted state - name: Wait for AppMirrorRelationship to reach Promoted state - {{ appmirrorrelationship_specs.name }} kubernetes.core.k8s_info: + <<: *src_k8s_auth kind: AppMirrorRelationship api_version: protect.trident.netapp.io/v1 name: "{{ appmirrorrelationship_specs.name }}" namespace: "{{ src_vm_namespace }}" - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false register: new_dst_amr_state until: > new_dst_amr_state.resources | length > 0 and diff --git a/roles/dr_failback_promote/tests/test.yml b/roles/dr_failback_promote/tests/test.yml index 1ab343d..41a5b76 100644 --- a/roles/dr_failback_promote/tests/test.yml +++ b/roles/dr_failback_promote/tests/test.yml @@ -6,7 +6,17 @@ vars: # Provide all required variables for the role here. See the role # README.md for a full list. - oc_api_url: https://api.example.openshift.com:6443 - oc_api_token: + src_oc_api_url: https://api.src.example.openshift.com:6443 + src_oc_api_token: + dst_oc_api_url: https://api.dst.example.openshift.com:6443 + dst_oc_api_token: + validate_certs: false + src_vm_namespace: src-vm-namespace + dst_vm_namespace: dst-vm-namespace + appmirrorrelationship_specs: + name: app-mirror-relationship + namespaceMapping: + - source: src-vm-namespace + destination: dst-vm-namespace roles: - dr_failback_promote diff --git a/roles/dr_failover/README.md b/roles/dr_failover/README.md index 5c39443..294e0eb 100644 --- a/roles/dr_failover/README.md +++ b/roles/dr_failover/README.md @@ -30,18 +30,19 @@ The role does not ship opinionated defaults. The caller must provide the following variables (typically via `-e @your_vars.yml` or under `vars:` in the playbook): -| Variable | Description | -|----------|-------------| -| `src_oc_api_url` | Source OpenShift cluster API server URL (DR scenarios). | -| `src_oc_api_token` | Source OpenShift cluster bearer token (DR scenarios). | -| `dst_oc_api_url` | Destination OpenShift cluster API server URL (DR scenarios). | -| `dst_oc_api_token` | Destination OpenShift cluster bearer token (DR scenarios). | -| `appmirrorrelationship_specs` | AMR specs (uses `name`). | -| `src_vm_namespace` | Source namespace (used during simulated disaster). | -| `dst_vm_namespace` | Destination namespace where VMs are failed over. | -| `src_vm_list` | List of source VMs. | -| `src_vm_label` | Label used to filter source VMs/PVCs. | -| `simulate_disaster` | Set to `true` to stop and delete source VMs to simulate a disaster. | +| Variable | Description | Default | +|----------|-------------|---------| +| `src_oc_api_url` | Source OpenShift cluster API server URL (DR scenarios). | Required | +| `src_oc_api_token` | Source OpenShift cluster bearer token (DR scenarios). | Required | +| `dst_oc_api_url` | Destination OpenShift cluster API server URL (DR scenarios). | Required | +| `dst_oc_api_token` | Destination OpenShift cluster bearer token (DR scenarios). | Required | +| `validate_certs` | Whether to validate TLS certificates when connecting to the OpenShift/Kubernetes API. | `false` | +| `appmirrorrelationship_specs` | AMR specs (uses `name`). | Required | +| `src_vm_namespace` | Source namespace (used during simulated disaster). | Required | +| `dst_vm_namespace` | Destination namespace where VMs are failed over. | Required | +| `src_vm_list` | List of source VMs. | Required | +| `src_vm_label` | Label used to filter source VMs/PVCs. | Required | +| `simulate_disaster` | Set to `true` to stop and delete source VMs to simulate a disaster. | `false` | > Note: Sensitive values (API tokens, S3 credentials) should be stored in an > Ansible Vault file rather than committed in plain text. @@ -55,8 +56,8 @@ playbook): gather_facts: false connection: local vars: - oc_api_url: "https://api.aa02-ocp.example.com:6443" - oc_api_token: "{{ OC_API_TOKEN }}" + src_oc_api_url: "https://api.src.example.openshift.com:6443" + src_oc_api_token: "{{ SRC_OC_API_TOKEN }}" # ... add the role-specific variables listed above ... roles: - dr_failover diff --git a/roles/dr_failover/defaults/main.yml b/roles/dr_failover/defaults/main.yml index 9f14569..3b27d32 100644 --- a/roles/dr_failover/defaults/main.yml +++ b/roles/dr_failover/defaults/main.yml @@ -1,4 +1,4 @@ --- # defaults file for dr_failover -# This role has no opinionated defaults; all variables are expected to be -# provided by the caller (see README.md for the full list). +validate_certs: false +simulate_disaster: false diff --git a/roles/dr_failover/tasks/main.yml b/roles/dr_failover/tasks/main.yml index a25e2c9..c97fe65 100644 --- a/roles/dr_failover/tasks/main.yml +++ b/roles/dr_failover/tasks/main.yml @@ -12,18 +12,43 @@ # If the snapshot schedule continues running after VM deletion, it will create snapshots with no VMs, # and the AMR will use the latest (empty) snapshot, resulting in no VMs being restored on the destination cluster. +# Verify required variables are defined and not empty +- name: Verify required variables are defined and not empty + ansible.builtin.fail: + msg: "{{ item }} is not defined or empty" + when: "vars[item] is not defined or (vars[item] | default('') | string | length == 0)" + loop: + - src_oc_api_url + - src_oc_api_token + - dst_oc_api_url + - dst_oc_api_token + +# Define anchor for source OpenShift/Kubernetes API login info +- name: Define anchor for source OpenShift/Kubernetes API login info + ansible.builtin.set_fact: + src_k8s_auth: &src_k8s_auth + host: "{{ src_oc_api_url | default(omit) }}" + api_key: "{{ src_oc_api_token | default(omit) }}" + validate_certs: "{{ validate_certs | default(false) }}" + +# Define anchor for destination OpenShift/Kubernetes API login info +- name: Define anchor for destination OpenShift/Kubernetes API login info + ansible.builtin.set_fact: + dst_k8s_auth: &dst_k8s_auth + host: "{{ dst_oc_api_url | default(omit) }}" + api_key: "{{ dst_oc_api_token | default(omit) }}" + validate_certs: "{{ validate_certs | default(false) }}" + # Disaster simulation - This is a placeholder task to simulate disaster on the source cluster. In a real scenario, # this would be an actual disaster event (e.g., source VMs deleted). # Step 1: Delete/suspend snapshot schedules to prevent empty snapshots from being created after VM deletion - name: Check if Schedule exists for source VMs before disaster simulation kubernetes.core.k8s_info: + <<: *src_k8s_auth kind: Schedule api_version: protect.trident.netapp.io/v1 name: "{{ src_snapshot_schedule_specs.name }}" namespace: "{{ src_vm_namespace }}" - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false register: src_snapshot_schedule_check changed_when: false when: @@ -47,14 +72,12 @@ - name: Delete Schedule to prevent empty snapshots after VM deletion kubernetes.core.k8s: + <<: *src_k8s_auth kind: Schedule api_version: protect.trident.netapp.io/v1 name: "{{ src_snapshot_schedule_specs.name }}" namespace: "{{ src_vm_namespace }}" state: absent - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false when: - simulate_disaster | bool - src_snapshot_schedule_check is defined @@ -81,14 +104,12 @@ # Step 2: Identify VMs to delete - name: Get list of VMs before failover in source namespace/label - {{ src_vm_namespace ~ ' / ' ~ src_vm_label }} kubernetes.core.k8s_info: + <<: *src_k8s_auth kind: VirtualMachine api_version: kubevirt.io/v1 namespace: "{{ src_vm_namespace }}" label_selectors: - category={{ src_vm_label }} - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false register: src_vms_before_failover changed_when: false when: simulate_disaster | bool @@ -98,6 +119,7 @@ # Step 3: Stop running VMs gracefully before deletion - name: Stop all running VMs in source namespace to simulate disaster - {{ src_vm_namespace ~ ' / ' ~ src_vm_label }} kubernetes.core.k8s: + <<: *src_k8s_auth kind: VirtualMachine api_version: kubevirt.io/v1 namespace: "{{ src_vm_namespace }}" @@ -107,9 +129,6 @@ definition: spec: runStrategy: Halted - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false loop: "{{ src_vms_before_failover.resources }}" when: - simulate_disaster | bool @@ -121,13 +140,11 @@ - name: Wait for VMs to stop gracefully kubernetes.core.k8s_info: + <<: *src_k8s_auth kind: VirtualMachine api_version: kubevirt.io/v1 namespace: "{{ src_vm_namespace }}" name: "{{ item.metadata.name }}" - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false loop: "{{ src_vms_before_failover.resources }}" register: vm_stop_status until: > @@ -150,14 +167,12 @@ # Step 4: Delete VMs to complete disaster simulation - name: Delete all VMs in source namespace to simulate disaster - {{ src_vm_namespace ~ ' / ' ~ src_vm_label }} kubernetes.core.k8s: + <<: *src_k8s_auth kind: VirtualMachine api_version: kubevirt.io/v1 namespace: "{{ src_vm_namespace }}" name: "{{ item.metadata.name }}" state: absent - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false loop: "{{ src_vms_before_failover.resources }}" when: - simulate_disaster | bool @@ -169,14 +184,12 @@ - name: Wait for VMs to be deleted and verify deletion kubernetes.core.k8s_info: + <<: *src_k8s_auth kind: VirtualMachine api_version: kubevirt.io/v1 namespace: "{{ src_vm_namespace }}" label_selectors: - category={{ src_vm_label }} - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false register: src_vms_after_disaster until: src_vms_after_disaster.resources | length == 0 retries: 30 @@ -233,13 +246,11 @@ # This is critical because in a real disaster scenario, the source cluster may be unavailable - name: Get existing AppMirrorRelationship to retrieve source application UID kubernetes.core.k8s_info: + <<: *dst_k8s_auth kind: AppMirrorRelationship api_version: protect.trident.netapp.io/v1 name: "{{ appmirrorrelationship_specs.name }}" namespace: "{{ dst_vm_namespace }}" - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false register: existing_amr_info changed_when: false failed_when: existing_amr_info.resources | length == 0 @@ -258,10 +269,8 @@ # The VMs will be in the same state as they were on the source cluster at the time of the last successful replication (last snapshot). - name: Fail over replicated VMs to the destination OpenShift cluster by promoting the AppMirrorRelationship (AMR) kubernetes.core.k8s: + <<: *dst_k8s_auth state: present - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false wait: true definition: apiVersion: protect.trident.netapp.io/v1 @@ -288,13 +297,11 @@ # View the AppMirrorRelationship details on the destination OpenShift cluster - name: Get AppMirrorRelationship details to verify it has been promoted kubernetes.core.k8s_info: + <<: *dst_k8s_auth kind: AppMirrorRelationship api_version: protect.trident.netapp.io/v1 name: "{{ appmirrorrelationship_specs.name }}" namespace: "{{ dst_vm_namespace }}" - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false register: dst_appmirrorrelationship_info changed_when: false failed_when: dst_appmirrorrelationship_info.resources | length == 0 @@ -311,13 +318,11 @@ # Wait for the AppMirrorRelationship to reach the Promoted state - name: Wait for AppMirrorRelationship to reach Promoted state - {{ appmirrorrelationship_specs.name }} kubernetes.core.k8s_info: + <<: *dst_k8s_auth kind: AppMirrorRelationship api_version: protect.trident.netapp.io/v1 name: "{{ appmirrorrelationship_specs.name }}" namespace: "{{ dst_vm_namespace }}" - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false register: dst_amr_state until: > dst_amr_state.resources | length > 0 and @@ -340,14 +345,12 @@ # Verify that VMs are actually restored on the destination cluster after AMR promotion - name: Wait for VMs to be restored on destination cluster after failover kubernetes.core.k8s_info: + <<: *dst_k8s_auth kind: VirtualMachine api_version: kubevirt.io/v1 namespace: "{{ dst_vm_namespace }}" label_selectors: - category={{ src_vm_label }} - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false register: dst_vms_after_failover until: dst_vms_after_failover.resources | length > 0 retries: 60 diff --git a/roles/dr_failover/tests/test.yml b/roles/dr_failover/tests/test.yml index 1856ae3..a182066 100644 --- a/roles/dr_failover/tests/test.yml +++ b/roles/dr_failover/tests/test.yml @@ -6,7 +6,19 @@ vars: # Provide all required variables for the role here. See the role # README.md for a full list. - oc_api_url: https://api.example.openshift.com:6443 - oc_api_token: + src_oc_api_url: https://api.src.example.openshift.com:6443 + src_oc_api_token: + dst_oc_api_url: https://api.dst.example.openshift.com:6443 + dst_oc_api_token: + validate_certs: false + src_vm_namespace: src-vm-namespace + dst_vm_namespace: dst-vm-namespace + src_vm_list: + - vm-1 + - vm-2 + src_vm_label: app=my-vm + simulate_disaster: false + appmirrorrelationship_specs: + name: app-mirror-relationship roles: - dr_failover diff --git a/roles/dr_reverse_resync_config/README.md b/roles/dr_reverse_resync_config/README.md index 9593073..1154c6c 100644 --- a/roles/dr_reverse_resync_config/README.md +++ b/roles/dr_reverse_resync_config/README.md @@ -29,18 +29,19 @@ The role does not ship opinionated defaults. The caller must provide the following variables (typically via `-e @your_vars.yml` or under `vars:` in the playbook): -| Variable | Description | -|----------|-------------| -| `src_oc_api_url` | Source OpenShift cluster API server URL (DR scenarios). | -| `src_oc_api_token` | Source OpenShift cluster bearer token (DR scenarios). | -| `dst_oc_api_url` | Destination OpenShift cluster API server URL (DR scenarios). | -| `dst_oc_api_token` | Destination OpenShift cluster bearer token (DR scenarios). | -| `appmirrorrelationship_specs` | AMR specs (uses `name`, `storage_class`, `recurrence_rule`). | -| `src_appvault_name` | AppVault on the original source cluster. | -| `dst_appvault_name` | AppVault on the original destination cluster. | -| `src_application_name` | Source application name. | -| `src_vm_namespace` | Original source namespace. | -| `dst_vm_namespace` | Original destination namespace (acts as new source). | +| Variable | Description | Default | +|----------|-------------|---------| +| `src_oc_api_url` | Source OpenShift cluster API server URL (DR scenarios). | Required | +| `src_oc_api_token` | Source OpenShift cluster bearer token (DR scenarios). | Required | +| `dst_oc_api_url` | Destination OpenShift cluster API server URL (DR scenarios). | Required | +| `dst_oc_api_token` | Destination OpenShift cluster bearer token (DR scenarios). | Required | +| `validate_certs` | Whether to validate TLS certificates when connecting to the OpenShift/Kubernetes API. | `false` | +| `appmirrorrelationship_specs` | AMR specs (uses `name`, `storage_class`, `recurrence_rule`). | Required | +| `src_appvault_name` | AppVault on the original source cluster. | Required | +| `dst_appvault_name` | AppVault on the original destination cluster. | Required | +| `src_application_name` | Source application name. | Required | +| `src_vm_namespace` | Original source namespace. | Required | +| `dst_vm_namespace` | Original destination namespace (acts as new source). | Required | > Note: Sensitive values (API tokens, S3 credentials) should be stored in an > Ansible Vault file rather than committed in plain text. @@ -54,8 +55,8 @@ playbook): gather_facts: false connection: local vars: - oc_api_url: "https://api.aa02-ocp.example.com:6443" - oc_api_token: "{{ OC_API_TOKEN }}" + src_oc_api_url: "https://api.src.example.openshift.com:6443" + src_oc_api_token: "{{ SRC_OC_API_TOKEN }}" # ... add the role-specific variables listed above ... roles: - dr_reverse_resync_config diff --git a/roles/dr_reverse_resync_config/defaults/main.yml b/roles/dr_reverse_resync_config/defaults/main.yml index 5be5e3a..f65c4aa 100644 --- a/roles/dr_reverse_resync_config/defaults/main.yml +++ b/roles/dr_reverse_resync_config/defaults/main.yml @@ -1,4 +1,3 @@ --- # defaults file for dr_reverse_resync_config -# This role has no opinionated defaults; all variables are expected to be -# provided by the caller (see README.md for the full list). +validate_certs: false diff --git a/roles/dr_reverse_resync_config/tasks/main.yml b/roles/dr_reverse_resync_config/tasks/main.yml index d43dbcc..d3b6310 100644 --- a/roles/dr_reverse_resync_config/tasks/main.yml +++ b/roles/dr_reverse_resync_config/tasks/main.yml @@ -11,17 +11,42 @@ # CR files with Cluster A as source and Cluster B as destination. For the reverse resync, you would need to update those CR files to # set Cluster B as the new source and Cluster A as the new destination, and then apply those updated CR files in this step. +# Verify required variables are defined and not empty +- name: Verify required variables are defined and not empty + ansible.builtin.fail: + msg: "{{ item }} is not defined or empty" + when: "vars[item] is not defined or (vars[item] | default('') | string | length == 0)" + loop: + - src_oc_api_url + - src_oc_api_token + - dst_oc_api_url + - dst_oc_api_token + +# Define anchor for source OpenShift/Kubernetes API login info +- name: Define anchor for source OpenShift/Kubernetes API login info + ansible.builtin.set_fact: + src_k8s_auth: &src_k8s_auth + host: "{{ src_oc_api_url | default(omit) }}" + api_key: "{{ src_oc_api_token | default(omit) }}" + validate_certs: "{{ validate_certs | default(false) }}" + +# Define anchor for destination OpenShift/Kubernetes API login info +- name: Define anchor for destination OpenShift/Kubernetes API login info + ansible.builtin.set_fact: + dst_k8s_auth: &dst_k8s_auth + host: "{{ dst_oc_api_url | default(omit) }}" + api_key: "{{ dst_oc_api_token | default(omit) }}" + validate_certs: "{{ validate_certs | default(false) }}" + # Prerequisites check - Verify that snapshots exist on the new source cluster before proceeding with AMR creation - name: >- Check for available snapshots on the new source (original destination) cluster for application/namespace - {{ src_application_name ~ ' / ' ~ dst_vm_namespace }} kubernetes.core.k8s_info: + <<: *dst_k8s_auth kind: Snapshot api_version: protect.trident.netapp.io/v1 namespace: "{{ dst_vm_namespace }}" - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false register: src_snapshots_all changed_when: false tags: @@ -96,13 +121,11 @@ - name: Get source application UID from the source OpenShift cluster (original destination cluster) for AMR creation on the new destination cluster (original source cluster) kubernetes.core.k8s_info: + <<: *dst_k8s_auth kind: Application api_version: protect.trident.netapp.io/v1 name: "{{ src_application_name }}" namespace: "{{ dst_vm_namespace }}" - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false register: new_src_application_info changed_when: false failed_when: new_src_application_info.resources | length == 0 @@ -121,10 +144,8 @@ # On the new destination OpenShift cluster (original source cluster), create an AppMirrorRelationship CR to replicate VMs from source to destination - name: Create an AppMirrorRelationship CR on new destination OpenShift cluster (original source cluster) to replicate VMs from source to destination kubernetes.core.k8s: + <<: *src_k8s_auth state: present - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false wait: false definition: apiVersion: protect.trident.netapp.io/v1 @@ -151,13 +172,11 @@ # View the AppMirrorRelationship details on the new destination OpenShift cluster (original source cluster) - name: Get AppMirrorRelationship details to verify creation on the new destination OpenShift cluster (original source cluster) kubernetes.core.k8s_info: + <<: *src_k8s_auth kind: AppMirrorRelationship api_version: protect.trident.netapp.io/v1 name: "{{ appmirrorrelationship_specs.name }}" namespace: "{{ src_vm_namespace }}" - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false register: new_dst_appmirrorrelationship_info changed_when: false failed_when: new_dst_appmirrorrelationship_info.resources | length == 0 @@ -176,13 +195,11 @@ # Wait for the AppMirrorRelationship to reach the Established state - name: Wait for AppMirrorRelationship to reach Established state - {{ appmirrorrelationship_specs.name }} kubernetes.core.k8s_info: + <<: *src_k8s_auth kind: AppMirrorRelationship api_version: protect.trident.netapp.io/v1 name: "{{ appmirrorrelationship_specs.name }}" namespace: "{{ src_vm_namespace }}" - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false register: new_dst_amr_state until: > new_dst_amr_state.resources | length > 0 and diff --git a/roles/dr_reverse_resync_config/tests/test.yml b/roles/dr_reverse_resync_config/tests/test.yml index 36344a4..e14f769 100644 --- a/roles/dr_reverse_resync_config/tests/test.yml +++ b/roles/dr_reverse_resync_config/tests/test.yml @@ -6,7 +6,20 @@ vars: # Provide all required variables for the role here. See the role # README.md for a full list. - oc_api_url: https://api.example.openshift.com:6443 - oc_api_token: + src_oc_api_url: https://api.src.example.openshift.com:6443 + src_oc_api_token: + dst_oc_api_url: https://api.dst.example.openshift.com:6443 + dst_oc_api_token: + validate_certs: false + src_appvault_name: src-appvault-ontap + dst_appvault_name: dst-appvault-ontap + src_application_name: my-application + src_vm_namespace: src-vm-namespace + dst_vm_namespace: dst-vm-namespace + appmirrorrelationship_specs: + name: app-mirror-relationship + namespaceMapping: + - source: src-vm-namespace + destination: dst-vm-namespace roles: - dr_reverse_resync_config diff --git a/roles/dr_reverse_resync_prerequisites/README.md b/roles/dr_reverse_resync_prerequisites/README.md index be55a99..7733566 100644 --- a/roles/dr_reverse_resync_prerequisites/README.md +++ b/roles/dr_reverse_resync_prerequisites/README.md @@ -28,24 +28,25 @@ The role does not ship opinionated defaults. The caller must provide the following variables (typically via `-e @your_vars.yml` or under `vars:` in the playbook): -| Variable | Description | -|----------|-------------| -| `src_oc_api_url` | Source OpenShift cluster API server URL (DR scenarios). | -| `src_oc_api_token` | Source OpenShift cluster bearer token (DR scenarios). | -| `dst_oc_api_url` | Destination OpenShift cluster API server URL (DR scenarios). | -| `dst_oc_api_token` | Destination OpenShift cluster bearer token (DR scenarios). | -| `src_ontap_s3_specs` | Source ONTAP S3 specs dict (re-used to recreate Secret/AppVault on the new source cluster). | -| `dst_ontap_s3_specs` | Destination ONTAP S3 specs dict. | -| `src_appvault_name` | AppVault name for the source application. | -| `dst_appvault_name` | AppVault name for the destination application. | -| `src_application_name` | Source application name. | -| `src_vm_namespace` | Original source namespace. | -| `dst_vm_namespace` | Destination namespace (new source after failover). | -| `src_on_demand_snapshot` | Set to `true` for an on-demand snapshot of the new source. | -| `src_on_demand_snapshot_specs` | On-demand snapshot specs dict. | -| `src_scheduled_snapshot` | Set to `true` to create a snapshot Schedule on the new source. | -| `src_snapshot_schedule_specs` | Snapshot schedule specs dict. | -| `shutdown_snapshot_name` | Name of the shutdown snapshot to create on the new source before failback. | +| Variable | Description | Default | +|----------|-------------|---------| +| `src_oc_api_url` | Source OpenShift cluster API server URL (DR scenarios). | Required | +| `src_oc_api_token` | Source OpenShift cluster bearer token (DR scenarios). | Required | +| `dst_oc_api_url` | Destination OpenShift cluster API server URL (DR scenarios). | Required | +| `dst_oc_api_token` | Destination OpenShift cluster bearer token (DR scenarios). | Required | +| `validate_certs` | Whether to validate TLS certificates when connecting to the OpenShift/Kubernetes API. | `false` | +| `src_ontap_s3_specs` | Source ONTAP S3 specs dict (re-used to recreate Secret/AppVault on the new source cluster). | Required | +| `dst_ontap_s3_specs` | Destination ONTAP S3 specs dict. | Required | +| `src_appvault_name` | AppVault name for the source application. | Required | +| `dst_appvault_name` | AppVault name for the destination application. | Required | +| `src_application_name` | Source application name. | Required | +| `src_vm_namespace` | Original source namespace. | Required | +| `dst_vm_namespace` | Destination namespace (new source after failover). | Required | +| `src_on_demand_snapshot` | Set to `true` for an on-demand snapshot of the new source. | `false` | +| `src_on_demand_snapshot_specs` | On-demand snapshot specs dict (`name`, `reclaim_policy`). Required when `src_on_demand_snapshot` is `true`. | — | +| `src_scheduled_snapshot` | Set to `true` to create a snapshot Schedule on the new source. | `false` | +| `src_snapshot_schedule_specs` | Snapshot schedule specs dict (`name`, `snapshot_reclaim_policy`, `retention_count`, `recurrence_rule`). Required when `src_scheduled_snapshot` is `true`. | — | +| `shutdown_snapshot_name` | Name of the shutdown snapshot to create on the new source before failback. | Required | > Note: Sensitive values (API tokens, S3 credentials) should be stored in an > Ansible Vault file rather than committed in plain text. @@ -59,8 +60,8 @@ playbook): gather_facts: false connection: local vars: - oc_api_url: "https://api.aa02-ocp.example.com:6443" - oc_api_token: "{{ OC_API_TOKEN }}" + src_oc_api_url: "https://api.src.example.openshift.com:6443" + src_oc_api_token: "{{ SRC_OC_API_TOKEN }}" # ... add the role-specific variables listed above ... roles: - dr_reverse_resync_prerequisites diff --git a/roles/dr_reverse_resync_prerequisites/defaults/main.yml b/roles/dr_reverse_resync_prerequisites/defaults/main.yml index 7b562d0..73dbf40 100644 --- a/roles/dr_reverse_resync_prerequisites/defaults/main.yml +++ b/roles/dr_reverse_resync_prerequisites/defaults/main.yml @@ -1,4 +1,5 @@ --- # defaults file for dr_reverse_resync_prerequisites -# This role has no opinionated defaults; all variables are expected to be -# provided by the caller (see README.md for the full list). +validate_certs: false +src_scheduled_snapshot: false +src_on_demand_snapshot: false diff --git a/roles/dr_reverse_resync_prerequisites/tasks/main.yml b/roles/dr_reverse_resync_prerequisites/tasks/main.yml index 3037f02..aaf2eb8 100644 --- a/roles/dr_reverse_resync_prerequisites/tasks/main.yml +++ b/roles/dr_reverse_resync_prerequisites/tasks/main.yml @@ -2,17 +2,42 @@ # Ansible tasks for setting up prerequisites to reverse resync a failed over replication relationship using Trident Protect. # This role should be executed AFTER the dr_failover role has been executed and the failed over VMs are running successfully on the destination cluster. +# Verify required variables are defined and not empty +- name: Verify required variables are defined and not empty + ansible.builtin.fail: + msg: "{{ item }} is not defined or empty" + when: "vars[item] is not defined or (vars[item] | default('') | string | length == 0)" + loop: + - src_oc_api_url + - src_oc_api_token + - dst_oc_api_url + - dst_oc_api_token + +# Define anchor for source OpenShift/Kubernetes API login info +- name: Define anchor for source OpenShift/Kubernetes API login info + ansible.builtin.set_fact: + src_k8s_auth: &src_k8s_auth + host: "{{ src_oc_api_url | default(omit) }}" + api_key: "{{ src_oc_api_token | default(omit) }}" + validate_certs: "{{ validate_certs | default(false) }}" + +# Define anchor for destination OpenShift/Kubernetes API login info +- name: Define anchor for destination OpenShift/Kubernetes API login info + ansible.builtin.set_fact: + dst_k8s_auth: &dst_k8s_auth + host: "{{ dst_oc_api_url | default(omit) }}" + api_key: "{{ dst_oc_api_token | default(omit) }}" + validate_certs: "{{ validate_certs | default(false) }}" + # Pre-condition check: Verify that failed over VMs are running on the destination cluster before proceeding. - name: Verify failed over VMs are running on the destination cluster before proceeding with reverse resync prerequisites kubernetes.core.k8s_info: + <<: *dst_k8s_auth kind: VirtualMachine api_version: kubevirt.io/v1 namespace: "{{ dst_vm_namespace }}" label_selectors: - category={{ src_vm_label }} - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false register: dst_vms_running_check changed_when: false failed_when: dst_vms_running_check.resources | length == 0 @@ -30,14 +55,12 @@ # This is required to avoid snapshot creation during reverse resync which can cause reverse resync failure. - name: Delete Snapshot schedule on the original source cluster if any before executing the reverse resync prerequisites tasks kubernetes.core.k8s: + <<: *src_k8s_auth kind: Schedule api_version: protect.trident.netapp.io/v1 name: "{{ src_snapshot_schedule_specs.name }}" namespace: "{{ src_vm_namespace }}" state: absent - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false when: - src_scheduled_snapshot | default(false) | bool - src_snapshot_schedule_specs is defined @@ -48,10 +71,8 @@ # On the original destination cluster, delete the AppMirrorRelationship CR (which is in Promoted state). This causes the destination to become the source. - name: Delete the AppMirrorRelationship (AMR) on the original destination cluster to prepare for reverse resync kubernetes.core.k8s: + <<: *dst_k8s_auth state: absent - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false definition: apiVersion: protect.trident.netapp.io/v1 kind: AppMirrorRelationship @@ -64,13 +85,11 @@ # Wait for the AMR to be fully deleted before proceeding to reverse resync config. - name: Wait for AppMirrorRelationship to be fully deleted on the destination cluster kubernetes.core.k8s_info: + <<: *dst_k8s_auth kind: AppMirrorRelationship api_version: protect.trident.netapp.io/v1 name: "{{ appmirrorrelationship_specs.name }}" namespace: "{{ dst_vm_namespace }}" - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false register: dst_amr_delete_check until: dst_amr_delete_check.resources | length == 0 retries: 30 @@ -110,12 +129,10 @@ # Verify trident-protect namespace exists on the new destination (original source) cluster - name: Verify trident-protect namespace exists on the new destination (original source) OpenShift cluster kubernetes.core.k8s_info: + <<: *src_k8s_auth kind: Namespace api_version: v1 name: trident-protect - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false register: new_dst_tp_ns_check failed_when: new_dst_tp_ns_check.resources | length == 0 changed_when: false @@ -127,10 +144,8 @@ # Create Kubernetes Secret to store source ONTAP S3 credentials on the new destination (original source cluster) OpenShift cluster - name: Create Kubernetes Secret to store source ONTAP S3 credentials on the new destination (original source cluster) OpenShift cluster kubernetes.core.k8s: + <<: *src_k8s_auth state: present - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false definition: apiVersion: v1 kind: Secret @@ -148,13 +163,11 @@ # Verify the creation of secret to store source ONTAP S3 credentials on the new destination (original source) cluster - name: Verify the creation of secret to store source ONTAP S3 credentials on the new destination (original source) cluster kubernetes.core.k8s_info: + <<: *src_k8s_auth kind: Secret api_version: v1 name: "{{ dst_ontap_s3_specs.secret_name }}" namespace: trident-protect - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false register: new_dst_src_ontap_s3_secret_info failed_when: new_dst_src_ontap_s3_secret_info.resources | length == 0 changed_when: false @@ -164,10 +177,8 @@ # On the new destination (original source) OpenShift cluster, create a source application AppVault CR - name: Create source application AppVault CR on the new destination (original source) OpenShift cluster kubernetes.core.k8s: + <<: *src_k8s_auth state: present - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false definition: apiVersion: protect.trident.netapp.io/v1 kind: AppVault @@ -197,13 +208,11 @@ # View the source application AppVault details on the new destination (original source) OpenShift cluster - name: Get source application AppVault details on the new destination (original source) OpenShift cluster kubernetes.core.k8s_info: + <<: *src_k8s_auth kind: AppVault api_version: protect.trident.netapp.io/v1 name: "{{ dst_appvault_name }}" namespace: trident-protect - host: "{{ src_oc_api_url }}" - api_key: "{{ src_oc_api_token }}" - validate_certs: false register: new_dst_src_appvault_info failed_when: new_dst_src_appvault_info.resources | length == 0 changed_when: false @@ -254,10 +263,8 @@ # On the new source OpenShift cluster, take a snapshot of the source application. This snapshot is used as the basis for replication on the destination cluster. - name: Create a snapshot schedule on the new source OpenShift cluster for source application - {{ src_application_name }} kubernetes.core.k8s: + <<: *dst_k8s_auth state: present - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false definition: apiVersion: protect.trident.netapp.io/v1 kind: Schedule @@ -282,13 +289,11 @@ # Verify the snapshot schedule creation - name: Get source snapshot schedule details to verify creation kubernetes.core.k8s_info: + <<: *dst_k8s_auth kind: Schedule api_version: protect.trident.netapp.io/v1 name: "{{ src_snapshot_schedule_specs.name }}" namespace: "{{ dst_vm_namespace }}" - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false register: new_src_snapshot_schedule_info changed_when: false when: src_scheduled_snapshot | default(false) | bool @@ -327,10 +332,8 @@ # for replication on the destination cluster. - name: Create an on-demand snapshot on the new source OpenShift cluster for source application - {{ src_application_name }} kubernetes.core.k8s: + <<: *dst_k8s_auth state: present - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false definition: apiVersion: protect.trident.netapp.io/v1 kind: Snapshot @@ -348,13 +351,11 @@ # Wait for on-demand snapshot to reach Completed state before proceeding - name: Wait for source on-demand snapshot to reach Completed state on the new source OpenShift cluster kubernetes.core.k8s_info: + <<: *dst_k8s_auth kind: Snapshot api_version: protect.trident.netapp.io/v1 name: "{{ src_on_demand_snapshot_specs.name }}" namespace: "{{ dst_vm_namespace }}" - host: "{{ dst_oc_api_url }}" - api_key: "{{ dst_oc_api_token }}" - validate_certs: false register: new_src_on_demand_snapshot_info until: > new_src_on_demand_snapshot_info.resources | length > 0 and diff --git a/roles/dr_reverse_resync_prerequisites/tests/test.yml b/roles/dr_reverse_resync_prerequisites/tests/test.yml index 126b162..0e68e11 100644 --- a/roles/dr_reverse_resync_prerequisites/tests/test.yml +++ b/roles/dr_reverse_resync_prerequisites/tests/test.yml @@ -6,7 +6,38 @@ vars: # Provide all required variables for the role here. See the role # README.md for a full list. - oc_api_url: https://api.example.openshift.com:6443 - oc_api_token: + src_oc_api_url: https://api.src.example.openshift.com:6443 + src_oc_api_token: + dst_oc_api_url: https://api.dst.example.openshift.com:6443 + dst_oc_api_token: + validate_certs: false + src_appvault_name: src-appvault-ontap + dst_appvault_name: dst-appvault-ontap + src_application_name: my-application + src_vm_namespace: src-vm-namespace + dst_vm_namespace: dst-vm-namespace + src_scheduled_snapshot: true + src_on_demand_snapshot: false + src_snapshot_schedule_specs: + name: snapshot-schedule + snapshot_reclaim_policy: Delete + retention_count: 5 + recurrence_rule: + dtstart: 20240101T000000Z + rrule: FREQ=HOURLY;INTERVAL=1 + src_on_demand_snapshot_specs: + name: on-demand-snapshot + reclaim_policy: Delete + shutdown_snapshot_name: shutdown-snapshot + src_ontap_s3_specs: + endpoint: https://s3.example.com + bucket: src-trident-protect-bucket + credentials_secret_name: src-s3-secret + credentials_secret_namespace: trident-protect + dst_ontap_s3_specs: + endpoint: https://s3.dst.example.com + bucket: dst-trident-protect-bucket + credentials_secret_name: dst-s3-secret + credentials_secret_namespace: trident-protect roles: - dr_reverse_resync_prerequisites diff --git a/roles/snapshot_and_restore_scenario/README.md b/roles/snapshot_and_restore_scenario/README.md index f7d8e33..7ce9b47 100644 --- a/roles/snapshot_and_restore_scenario/README.md +++ b/roles/snapshot_and_restore_scenario/README.md @@ -36,17 +36,18 @@ The role does not ship opinionated defaults. The caller must provide the following variables (typically via `-e @your_vars.yml` or under `vars:` in the playbook): -| Variable | Description | -|----------|-------------| -| `oc_api_url` | OpenShift/Kubernetes API server URL of the target cluster. | -| `oc_api_token` | Bearer token used to authenticate against the OpenShift API. | -| `appvault_name` | AppVault used by the snapshot/restore. | -| `application_name` | Application whose snapshots are restored. | -| `vm_namespace` | Namespace where VMs are restored in place. | -| `vm_list` | List of VM names that will be deleted before restore. | -| `pvc_list` | List of PVC names that will be deleted before restore. | -| `vm_label` | Label value used to filter VMs/PVCs during verification. | -| `snapshotinplacerestore_name` | Name of the SnapshotInplaceRestore CR. | +| Variable | Description | Default | +|----------|-------------|---------| +| `oc_api_url` | OpenShift/Kubernetes API server URL of the target cluster. | Required | +| `oc_api_token` | Bearer token used to authenticate against the OpenShift API. | Required | +| `validate_certs` | Whether to validate TLS certificates when connecting to the OpenShift/Kubernetes API. | `false` | +| `appvault_name` | AppVault used by the snapshot/restore. | Required | +| `application_name` | Application whose snapshots are restored. | Required | +| `vm_namespace` | Namespace where VMs are restored in place. | Required | +| `vm_list` | List of VM names that will be deleted before restore. | Required | +| `pvc_list` | List of PVC names that will be deleted before restore. | Required | +| `vm_label` | Label value used to filter VMs/PVCs during verification. | Required | +| `snapshotinplacerestore_name` | Name of the SnapshotInplaceRestore CR. | Required | > Note: Sensitive values (API tokens, S3 credentials) should be stored in an > Ansible Vault file rather than committed in plain text. diff --git a/roles/snapshot_and_restore_scenario/defaults/main.yml b/roles/snapshot_and_restore_scenario/defaults/main.yml index ac50f79..fb614d4 100644 --- a/roles/snapshot_and_restore_scenario/defaults/main.yml +++ b/roles/snapshot_and_restore_scenario/defaults/main.yml @@ -1,4 +1,3 @@ --- # defaults file for snapshot_and_restore_scenario -# This role has no opinionated defaults; all variables are expected to be -# provided by the caller (see README.md for the full list). +validate_certs: false diff --git a/roles/snapshot_and_restore_scenario/tasks/main.yml b/roles/snapshot_and_restore_scenario/tasks/main.yml index deb760e..e4f8cd1 100644 --- a/roles/snapshot_and_restore_scenario/tasks/main.yml +++ b/roles/snapshot_and_restore_scenario/tasks/main.yml @@ -7,12 +7,31 @@ # before running the restore tasks here. # Note: Ensure that the snapshot schedule has created at least one snapshot before running the restore tasks here. +# Verify required variables are defined and not empty +- name: Verify required variables are defined and not empty + ansible.builtin.fail: + msg: "{{ item }} is not defined or empty" + when: "vars[item] is not defined or (vars[item] | default('') | string | length == 0)" + loop: + - oc_api_url + - oc_api_token + - appvault_name + - application_name + - vm_namespace + - snapshotinplacerestore_name + +# Define anchor for OpenShift/Kubernetes API login info +- name: Define anchor for OpenShift/Kubernetes API login info + ansible.builtin.set_fact: + k8s_auth: &k8s_auth + host: "{{ oc_api_url | default(omit) }}" + api_key: "{{ oc_api_token | default(omit) }}" + validate_certs: "{{ validate_certs | default(false) }}" + # View the snapshots created by the snapshot schedule - name: Get snapshots created by the snapshot schedule in namespace - {{ vm_namespace | default('') }} kubernetes.core.k8s_info: - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false + <<: *k8s_auth api_version: protect.trident.netapp.io/v1 kind: Snapshot namespace: "{{ vm_namespace | default('') }}" @@ -70,10 +89,8 @@ # OR you can use the below tasks to automate the deletion of VMs and their associated resources. - name: Delete specific VMs to simulate corruption or accidental deletion in namespace - {{ vm_namespace | default('') }} kubernetes.core.k8s: + <<: *k8s_auth state: absent - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false api_version: kubevirt.io/v1 namespace: "{{ vm_namespace | default('') }}" kind: VirtualMachine @@ -88,10 +105,8 @@ - name: Delete specific PVCs to simulate corruption or accidental deletion in namespace - {{ vm_namespace | default('') }} kubernetes.core.k8s: + <<: *k8s_auth state: absent - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false api_version: v1 namespace: "{{ vm_namespace | default('') }}" kind: PersistentVolumeClaim @@ -107,9 +122,7 @@ # Verify that the VMs and their associated resources have been deleted from the original namespace - name: Verify that the VMs have been deleted from namespace - {{ vm_namespace | default('') }} kubernetes.core.k8s_info: - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false + <<: *k8s_auth api_version: kubevirt.io/v1 kind: VirtualMachine namespace: "{{ vm_namespace | default('') }}" @@ -125,9 +138,7 @@ - name: Verify that the PVCs have been deleted from namespace - {{ vm_namespace | default('') }} kubernetes.core.k8s_info: - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false + <<: *k8s_auth api_version: v1 kind: PersistentVolumeClaim namespace: "{{ vm_namespace | default('') }}" @@ -231,10 +242,8 @@ # Create a SnapshotInplaceRestore object to restore VMs to the original namespace using the latest snapshot's appArchivePath - name: Create a SnapshotInplaceRestore object using appArchivePath to restore VMs to namespace - {{ vm_namespace | default('') }} kubernetes.core.k8s: + <<: *k8s_auth state: present - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false namespace: "{{ vm_namespace | default('') }}" definition: apiVersion: protect.trident.netapp.io/v1 @@ -256,9 +265,7 @@ # Wait for the restore to complete - name: Wait for the restore to complete kubernetes.core.k8s_info: - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false + <<: *k8s_auth api_version: protect.trident.netapp.io/v1 namespace: "{{ vm_namespace | default('') }}" kind: SnapshotInplaceRestore @@ -280,9 +287,7 @@ # Verify that the SnapshotInplaceRestore object was created successfully - name: Get SnapshotInplaceRestore objects in namespace - {{ vm_namespace | default('') }} kubernetes.core.k8s_info: - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false + <<: *k8s_auth api_version: protect.trident.netapp.io/v1 kind: SnapshotInplaceRestore namespace: "{{ vm_namespace | default('') }}" @@ -315,9 +320,7 @@ # Verify that the VMs and their associated resources have been restored to the original namespace - name: Verify that the VMs have been restored to namespace - {{ vm_namespace | default('') }} kubernetes.core.k8s_info: - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false + <<: *k8s_auth api_version: kubevirt.io/v1 kind: VirtualMachine namespace: "{{ vm_namespace | default('') }}" @@ -333,9 +336,7 @@ - name: Verify that the PVCs have been restored to namespace - {{ vm_namespace | default('') }} kubernetes.core.k8s_info: - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false + <<: *k8s_auth api_version: v1 kind: PersistentVolumeClaim namespace: "{{ vm_namespace | default('') }}" diff --git a/roles/snapshot_and_restore_scenario/tests/test.yml b/roles/snapshot_and_restore_scenario/tests/test.yml index db6c6ea..ec86ea5 100644 --- a/roles/snapshot_and_restore_scenario/tests/test.yml +++ b/roles/snapshot_and_restore_scenario/tests/test.yml @@ -8,5 +8,17 @@ # README.md for a full list. oc_api_url: https://api.example.openshift.com:6443 oc_api_token: + validate_certs: false + appvault_name: appvault-ontap + application_name: my-application + vm_namespace: vm-namespace + vm_list: + - vm-1 + - vm-2 + pvc_list: + - pvc-1 + - pvc-2 + vm_label: app=my-vm + snapshotinplacerestore_name: snapshot-restore roles: - snapshot_and_restore_scenario diff --git a/roles/trident_protect_common/README.md b/roles/trident_protect_common/README.md index 94adae9..9af3ab2 100644 --- a/roles/trident_protect_common/README.md +++ b/roles/trident_protect_common/README.md @@ -19,21 +19,22 @@ The role does not ship opinionated defaults. The caller must provide the following variables (typically via `-e @your_vars.yml` or under `vars:` in the playbook): -| Variable | Description | -|----------|-------------| -| `oc_api_url` | OpenShift/Kubernetes API server URL of the target cluster. | -| `oc_api_token` | Bearer token used to authenticate against the OpenShift API. | -| `appvault_secret_name` | Name of the Kubernetes Secret holding ONTAP S3 credentials. | -| `s3_access_key` | ONTAP S3 access key (stored in the Secret). | -| `s3_secret_key` | ONTAP S3 secret key (stored in the Secret). | -| `appvault_name` | Name of the Trident Protect AppVault to create. | -| `ontap_s3_bucket_name` | ONTAP S3 bucket name backing the AppVault. | -| `ontap_s3_endpoint` | ONTAP S3 endpoint (LIF IP/FQDN) backing the AppVault. | -| `vm_namespace` | Namespace where the target VMs live. | -| `vm_list` | List of VM names to label and include in the Application. | -| `pvc_list` | List of PVC names associated with the VMs. | -| `vm_label` | Label value applied to VMs and PVCs (`category=`). | -| `application_name` | Trident Protect Application CR name for the VMs. | +| Variable | Description | Default | +|----------|-------------|---------| +| `oc_api_url` | OpenShift/Kubernetes API server URL of the target cluster. | Required | +| `oc_api_token` | Bearer token used to authenticate against the OpenShift API. | Required | +| `validate_certs` | Whether to validate TLS certificates when connecting to the OpenShift/Kubernetes API. | `false` | +| `appvault_secret_name` | Name of the Kubernetes Secret holding ONTAP S3 credentials. | Required | +| `s3_access_key` | ONTAP S3 access key (stored in the Secret). | Required | +| `s3_secret_key` | ONTAP S3 secret key (stored in the Secret). | Required | +| `appvault_name` | Name of the Trident Protect AppVault to create. | Required | +| `ontap_s3_bucket_name` | ONTAP S3 bucket name backing the AppVault. | Required | +| `ontap_s3_endpoint` | ONTAP S3 endpoint (LIF IP/FQDN) backing the AppVault. | Required | +| `vm_namespace` | Namespace where the target VMs live. | Required | +| `vm_list` | List of VM names to label and include in the Application. | Required | +| `pvc_list` | List of PVC names associated with the VMs. | Required | +| `vm_label` | Label value applied to VMs and PVCs (`category=`). | Required | +| `application_name` | Trident Protect Application CR name for the VMs. | Required | > Note: Sensitive values (API tokens, S3 credentials) should be stored in an > Ansible Vault file rather than committed in plain text. diff --git a/roles/trident_protect_common/defaults/main.yml b/roles/trident_protect_common/defaults/main.yml index 101440e..56eae5f 100644 --- a/roles/trident_protect_common/defaults/main.yml +++ b/roles/trident_protect_common/defaults/main.yml @@ -1,4 +1,3 @@ --- # defaults file for trident_protect_common -# This role has no opinionated defaults; all variables are expected to be -# provided by the caller (see README.md for the full list). +validate_certs: false diff --git a/roles/trident_protect_common/tasks/main.yml b/roles/trident_protect_common/tasks/main.yml index 73c4495..1dafb34 100644 --- a/roles/trident_protect_common/tasks/main.yml +++ b/roles/trident_protect_common/tasks/main.yml @@ -1,12 +1,27 @@ --- # Trident protect common tasks for both Backup/Restore and Snapshot/Restore scenarios +# Verify required variables are defined and not empty +- name: Verify required variables are defined and not empty + ansible.builtin.fail: + msg: "{{ item }} is not defined or empty" + when: "vars[item] is not defined or (vars[item] | default('') | string | length == 0)" + loop: + - oc_api_url + - oc_api_token + +# Define anchor for OpenShift/Kubernetes API login info +- name: Define anchor for OpenShift/Kubernetes API login info + ansible.builtin.set_fact: + k8s_auth: &k8s_auth + host: "{{ oc_api_url | default(omit) }}" + api_key: "{{ oc_api_token | default(omit) }}" + validate_certs: "{{ validate_certs | default(false) }}" + # Verify Trident Protect installation - name: Check if trident-protect namespace exists kubernetes.core.k8s_info: - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false + <<: *k8s_auth kind: Namespace name: trident-protect register: tp_namespace_check @@ -16,9 +31,7 @@ - name: Verify Trident Protect is installed (check controller manager deployment) kubernetes.core.k8s_info: - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false + <<: *k8s_auth kind: Deployment namespace: trident-protect name: trident-protect-controller-manager @@ -30,10 +43,8 @@ # Create Kubernetes Secret to store ONTAP S3 credentials - name: Create Kubernetes Secret to store ONTAP S3 credentials kubernetes.core.k8s: + <<: *k8s_auth state: present - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false namespace: trident-protect # Must be in the Trident protect namespace definition: apiVersion: v1 @@ -54,9 +65,7 @@ # Verify the newly created Secret in Trident protect namespace - name: Verify ONTAP S3 Secret creation in trident-protect namespace kubernetes.core.k8s_info: - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false + <<: *k8s_auth kind: Secret namespace: trident-protect name: "{{ appvault_secret_name | default('') }}" @@ -77,10 +86,8 @@ # Create Trident protect AppVault for ONTAP S3 - name: Create Trident protect AppVault for ONTAP S3 kubernetes.core.k8s: + <<: *k8s_auth state: present - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false namespace: trident-protect # Must be in the Trident protect namespace definition: apiVersion: protect.trident.netapp.io/v1 @@ -115,9 +122,7 @@ # Verify the newly created AppVault in Trident protect namespace - name: Verify AppVault creation in trident-protect namespace kubernetes.core.k8s_info: - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false + <<: *k8s_auth kind: AppVault api_version: protect.trident.netapp.io/v1 namespace: trident-protect @@ -139,9 +144,7 @@ # Check if VM namespace exists before labeling - name: Check if namespace exists - {{ vm_namespace | default('') }} kubernetes.core.k8s_info: - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false + <<: *k8s_auth kind: Namespace name: "{{ vm_namespace | default('') }}" register: vm_namespace_check @@ -154,10 +157,8 @@ # Label VMs in a namespace - name: Label VMs in namespace - {{ vm_namespace | default('') }} kubernetes.core.k8s: + <<: *k8s_auth state: present - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false namespace: "{{ vm_namespace | default('') }}" api_version: kubevirt.io/v1 kind: VirtualMachine @@ -179,10 +180,8 @@ # Label PVCs associated with VMs in a namespace - name: Label PVCs in namespace - {{ vm_namespace | default('') }} kubernetes.core.k8s: + <<: *k8s_auth state: present - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false namespace: "{{ vm_namespace | default('') }}" api_version: v1 kind: PersistentVolumeClaim @@ -204,9 +203,7 @@ # Verify that the VMs got the labels - name: Verify labels for VMs in namespace - {{ vm_namespace | default('') }} kubernetes.core.k8s_info: - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false + <<: *k8s_auth api_version: kubevirt.io/v1 kind: VirtualMachine namespace: "{{ vm_namespace | default('') }}" @@ -223,9 +220,7 @@ # Verify that the PVCs got the labels - name: Verify labels for PVCs in namespace - {{ vm_namespace | default('') }} kubernetes.core.k8s_info: - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false + <<: *k8s_auth api_version: v1 kind: PersistentVolumeClaim namespace: "{{ vm_namespace | default('') }}" @@ -266,10 +261,8 @@ # Create an application for specific VMs using the label selector - name: Create an application using the label selector for specific VMs in namespace - {{ vm_namespace | default('') }} kubernetes.core.k8s: + <<: *k8s_auth state: present - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false namespace: "{{ vm_namespace | default('') }}" definition: apiVersion: protect.trident.netapp.io/v1 @@ -292,9 +285,7 @@ # Verify the newly created application in the specified namespace - name: Verify Application creation in namespace - {{ vm_namespace | default('') }} kubernetes.core.k8s_info: - host: "{{ oc_api_url }}" - api_key: "{{ oc_api_token }}" - validate_certs: false + <<: *k8s_auth api_version: protect.trident.netapp.io/v1 kind: Application namespace: "{{ vm_namespace | default('') }}" diff --git a/roles/trident_protect_common/tests/test.yml b/roles/trident_protect_common/tests/test.yml index a8eaede..3b0266e 100644 --- a/roles/trident_protect_common/tests/test.yml +++ b/roles/trident_protect_common/tests/test.yml @@ -8,5 +8,21 @@ # README.md for a full list. oc_api_url: https://api.example.openshift.com:6443 oc_api_token: + validate_certs: false + appvault_secret_name: s3-secret + s3_access_key: + s3_secret_key: + appvault_name: appvault-ontap + ontap_s3_bucket_name: trident-protect-bucket + ontap_s3_endpoint: https://s3.example.com + vm_namespace: vm-namespace + vm_list: + - vm-1 + - vm-2 + pvc_list: + - pvc-1 + - pvc-2 + vm_label: app=my-vm + application_name: my-application roles: - trident_protect_common