From e632f2ac02d501192d2e961dd9f03ed8b7c59103 Mon Sep 17 00:00:00 2001 From: Ygal Blum Date: Thu, 28 Sep 2023 11:48:45 +0300 Subject: [PATCH 1/2] Revert - wait for all snapshots to drain before returning Add a check that the all snapshots were drained Add test Add changelog fragement Signed-off-by: Ygal Blum --- changelogs/fragments/.gitkeep | 0 .../fragments/revert-wait-for-drain.yml | 2 + roles/lvm_snapshots/tasks/revert.yml | 9 ++++ tests/fill-snapshot.yml | 40 ++++++++++++++ tests/test-drain-snapshot.yml | 53 +++++++++++++++++++ 5 files changed, 104 insertions(+) create mode 100644 changelogs/fragments/.gitkeep create mode 100644 changelogs/fragments/revert-wait-for-drain.yml create mode 100644 tests/fill-snapshot.yml create mode 100644 tests/test-drain-snapshot.yml diff --git a/changelogs/fragments/.gitkeep b/changelogs/fragments/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/changelogs/fragments/revert-wait-for-drain.yml b/changelogs/fragments/revert-wait-for-drain.yml new file mode 100644 index 0000000..a70c452 --- /dev/null +++ b/changelogs/fragments/revert-wait-for-drain.yml @@ -0,0 +1,2 @@ +minor_changes: + - Revert - wait for snapshot to drain before returning diff --git a/roles/lvm_snapshots/tasks/revert.yml b/roles/lvm_snapshots/tasks/revert.yml index f67881e..cd13893 100644 --- a/roles/lvm_snapshots/tasks/revert.yml +++ b/roles/lvm_snapshots/tasks/revert.yml @@ -22,3 +22,12 @@ path: "/root/boot-backup-{{ lvm_snapshots_set_name }}.tgz" state: absent when: lvm_snapshots_boot_backup + +- name: Wait for the snapshot to drain + ansible.builtin.command: "lvs --select 'lv_name = {{ item.origin }}' --reportformat json" + register: _lv_drain_check + until: (_lv_drain_check.stdout | from_json).report[0].lv[0].data_percent == "" + retries: 20 + delay: 30 + loop: "{{ lvm_snapshots_snapshots }}" + changed_when: false diff --git a/tests/fill-snapshot.yml b/tests/fill-snapshot.yml new file mode 100644 index 0000000..24a332e --- /dev/null +++ b/tests/fill-snapshot.yml @@ -0,0 +1,40 @@ +- name: Fill the volume + block: + - name: Set the retry count + ansible.builtin.set_fact: + _retry_count: "{{ (_retry_count | default('-1') | int) + 1 }}" + + - name: Generate the Sub-Directory name + ansible.builtin.set_fact: + _sub_dir_name: "{{ lookup('community.general.random_string', upper=false, numbers=false, special=false) }}" + + - name: Make a copy of the boot partition + ansible.builtin.copy: + src: /boot + dest: "{{ test_directory }}/{{ _sub_dir_name }}" + remote_src: true + mode: '0777' + + - name: Get the status of the snapshot + ansible.builtin.command: "lvs --select 'lv_name = {{ volume_name }}_{{ snapshot_set_name }}' --reportformat json" + register: _lv_status_check + changed_when: false + + - name: Store the snapshot data_percent + ansible.builtin.set_fact: + _snapshot_data_percent: "{{ ((_lv_status_check.stdout | from_json).report[0].lv[0].data_percent) }}" + + - name: Check if snapshot is full enough + ansible.builtin.assert: + that: _snapshot_data_percent|float > snapshot_fill_percent|float + quiet: true + + rescue: + - name: Check the retry count to avoid endless loop + ansible.builtin.assert: + that: (_retry_count|int) < (snapshot_max_retry|int) + fail_msg: "Ended after {{ snapshot_max_retry }} retries" + success_msg: "Volume is not full enought ({{ _snapshot_data_percent }}) - Run again..." + + - name: Include the same tasks file again + ansible.builtin.include_tasks: fill-snapshot.yml diff --git a/tests/test-drain-snapshot.yml b/tests/test-drain-snapshot.yml new file mode 100644 index 0000000..03898ef --- /dev/null +++ b/tests/test-drain-snapshot.yml @@ -0,0 +1,53 @@ +- name: Test revering to the snapshots + hosts: all + become: true + vars: + volume_group: test_vg + test_directory: "/mnt/test" + volume_name: test_lv + volumes: + - name: "{{ volume_name }}" + size: 4g + directory: "{{ test_directory }}" + snapshot_set_name: demo_snap + snapshot_fill_percent: 60 + snapshot_max_retry: 100 + tasks: + - name: Run pre-test steps + ansible.builtin.include_tasks: pre-test-tasks.yml + + - name: Create the snapshot + ansible.builtin.include_tasks: create-snapshot.yml + + - name: Fill the snapshot + ansible.builtin.include_tasks: fill-snapshot.yml + + - name: Revert to Snapshot + vars: + lvm_snapshots_action: revert + lvm_snapshots_set_name: "{{ snapshot_set_name }}" + ansible.builtin.include_role: + name: lvm_snapshots + + - name: Verify that the snapshot was completly drained + block: + - name: Verify that the snapshot no longer exists + vars: + volume_name: test_lv + ansible.builtin.include_tasks: verify-snapshot-not-exist.yml + - name: Verify that the snapshot was drained before returning + block: + - name: Get the status of the volume + ansible.builtin.command: "lvs --select 'lv_name = {{ volume_name }}' --reportformat json" + register: _lv_status_check + changed_when: false + - name: Store the snapshot data_percent + ansible.builtin.set_fact: + volume_data_percent: "{{ ((_lv_status_check.stdout | from_json).report[0].lv[0].data_percent) }}" + - name: Assert volume_data_percent is 0 + ansible.builtin.assert: + that: volume_data_percent|float == 0.0 + fail_msg: "Volume data percent is {{ volume_data_percent }} while it should be 0" + always: + - name: Cleanup + ansible.builtin.include_tasks: post-test-tasks.yml From b049d3f143ac622b605a785d62ace78806428efc Mon Sep 17 00:00:00 2001 From: Ygal Blum Date: Sun, 1 Oct 2023 09:37:23 +0300 Subject: [PATCH 2/2] Wait for drain - filter also by group name Add group name to the select filter to make sure the returned list has only one result Co-authored-by: Bob Mader --- roles/lvm_snapshots/tasks/revert.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/lvm_snapshots/tasks/revert.yml b/roles/lvm_snapshots/tasks/revert.yml index cd13893..4b2c83b 100644 --- a/roles/lvm_snapshots/tasks/revert.yml +++ b/roles/lvm_snapshots/tasks/revert.yml @@ -24,7 +24,7 @@ when: lvm_snapshots_boot_backup - name: Wait for the snapshot to drain - ansible.builtin.command: "lvs --select 'lv_name = {{ item.origin }}' --reportformat json" + ansible.builtin.command: "lvs --select 'vg_name = {{ item.vg_name }} && lv_name = {{ item.origin }}' --reportformat json" register: _lv_drain_check until: (_lv_drain_check.stdout | from_json).report[0].lv[0].data_percent == "" retries: 20