Skip to content

Commit 61ebd10

Browse files
committed
docs(tests): add test coverage and documentation for revertable snapshots
Add comprehensive test coverage for the revertable snapshot feature: - tests_basic_revertable.yml: Test global snapshot_lvm_revertable parameter - tests_set_revertable.yml: Test revertable parameter in snapshot sets - Update get_snapset_status.yml to extract revert entry information Add documentation in README.md: - Document snapshot_lvm_revertable parameter and requirements - Add example showing bootable and revertable used together - Explain boot-time rollback mechanism Tests follow the existing bootable test patterns and include proper version checks and rescue blocks for older snapm versions. Signed-off-by: Todd Gill <tgill@redhat.com>
1 parent 97436bd commit 61ebd10

5 files changed

Lines changed: 284 additions & 2 deletions

File tree

README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,30 @@ that it applies, for example:
120120
The mount_origin flag defaults to false, so it is not necessary when the user is mounting the
121121
snapshot rather than the origin.
122122
123+
To create a snapshot set with a revert boot entry for disaster recovery, the set would be
124+
defined with the "revertable" field:
125+
126+
```yaml
127+
snapshot_lvm_set:
128+
name: snapset1
129+
bootable: true
130+
revertable: true
131+
volumes:
132+
- name: snapshot VG1 LV1
133+
vg: test_vg1
134+
lv: lv1
135+
percent_space_required: 20
136+
- name: snapshot VG2 LV3
137+
vg: test_vg2
138+
lv: lv3
139+
percent_space_required: 15
140+
```
141+
142+
When `revertable: true` is set, a revert boot entry will be created in the boot menu.
143+
Booting into this entry will automatically merge the snapshots back into their origin volumes,
144+
providing a boot-time rollback mechanism. Both bootable and revertable can be set independently
145+
or together.
146+
123147
### snapshot_lvm_snapset_name
124148

125149
This variable is required. snapshot_lvm_snapset_name is a string that will be
@@ -256,6 +280,16 @@ support snapshot manager (snapm). When set to true, and passed to the
256280
'snapshot' command, the snapshot created will have a corresponding boot
257281
entry. The boot entry will be removed when the snapset is removed.
258282

283+
### snapshot_lvm_revertable
284+
285+
Boolean - default is false. Only supported on operating systems that
286+
support snapshot manager (snapm) version 0.5.0 or later. When set to true,
287+
and passed to the 'snapshot' command, the snapshot created will have a
288+
corresponding revert boot entry. Booting into the revert entry will trigger
289+
an automatic revert operation, merging the snapshot back into the origin
290+
volume. This provides a boot-time rollback mechanism for disaster recovery.
291+
The revert boot entry will be removed when the snapset is removed.
292+
259293
### snapshot_use_copr (EXPERIMENTAL)
260294

261295
Boolean - default is unset - if you want to enable the copr repo to use the

module_utils/snapshot_lsr/snapmgr.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,11 @@ def mgr_snapshot_cmd(module, module_args, snapset_json):
303303
manager = snap_manager.Manager()
304304

305305
try:
306-
# Build kwargs for create_snapshot_set based on available parameters
306+
# Build kwargs for create_snapshot_set based on available parameters.
307+
# Use kwargs dict to conditionally pass optional parameters based on
308+
# snapm version support. This avoids needing separate code paths for
309+
# each combination (e.g., boot-only, revert-only, both, neither).
310+
# Each version check adds its parameter to kwargs if supported.
307311
kwargs = {}
308312
if has_boot_parameter():
309313
kwargs["boot"] = bootable

tests/get_snapset_status.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@
1313
- name: Define reusable variables
1414
ansible.builtin.set_fact:
1515
is_bootable: "{{ _raw_data.Bootable | bool }}"
16-
boot_entries_list: "{{ _raw_data.BootEntries.values() | list }}"
16+
boot_entries_list: "{{ (_raw_data.BootEntries | d({})).values() | list }}"
17+
is_revertable: "{{ (_raw_data.BootEntries | d({})).RevertEntry is defined and (_raw_data.BootEntries | d({})).RevertEntry | length > 0 }}"

tests/tests_basic_revertable.yml

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
---
2+
- name: Basic snapshot test with revertable boot entry
3+
hosts: all
4+
vars:
5+
# only use vgs matching this pattern
6+
snapshot_lvm_vg_include: "^test_"
7+
test_disk_min_size: "1g"
8+
test_disk_count: 10
9+
test_storage_pools:
10+
- name: test_vg1
11+
disks: "{{ range(0, 3) | map('extract', unused_disks) | list }}"
12+
volumes:
13+
- name: lv1
14+
size: "15%"
15+
- name: lv2
16+
size: "50%"
17+
- name: test_vg2
18+
disks: "{{ range(3, 6) | map('extract', unused_disks) | list }}"
19+
volumes:
20+
- name: lv3
21+
size: "10%"
22+
- name: lv4
23+
size: "20%"
24+
- name: test_vg3
25+
disks: "{{ range(6, 10) | map('extract', unused_disks) | list }}"
26+
volumes:
27+
- name: lv5
28+
size: "30%"
29+
- name: lv6
30+
size: "25%"
31+
- name: lv7
32+
size: "10%"
33+
- name: lv8
34+
size: "10%"
35+
tasks:
36+
- name: Run tests
37+
block:
38+
- name: Setup
39+
include_tasks: tasks/setup.yml
40+
41+
- name: Run the snapshot role to create snapshot LVs with revert boot entry
42+
include_tasks: tasks/run_role_with_clear_facts.yml
43+
vars:
44+
snapshot_lvm_percent_space_required: 15
45+
snapshot_lvm_all_vgs: true
46+
snapshot_lvm_snapset_name: snapset1
47+
snapshot_lvm_action: snapshot
48+
snapshot_lvm_revertable: true
49+
50+
- name: Assert changes for creation
51+
assert:
52+
that: snapshot_cmd["changed"]
53+
54+
- name: Verify the snapshot LVs are created
55+
include_tasks: tasks/run_role_with_clear_facts.yml
56+
vars:
57+
snapshot_lvm_all_vgs: true
58+
snapshot_lvm_snapset_name: snapset1
59+
snapshot_lvm_verify_only: true
60+
snapshot_lvm_action: check
61+
62+
- name: Run the snapshot role again to check idempotence
63+
include_tasks: tasks/run_role_with_clear_facts.yml
64+
vars:
65+
snapshot_lvm_percent_space_required: 15
66+
snapshot_lvm_all_vgs: true
67+
snapshot_lvm_snapset_name: snapset1
68+
snapshot_lvm_action: snapshot
69+
70+
- name: Assert no changes for creation
71+
assert:
72+
that: not snapshot_cmd["changed"]
73+
74+
- name: Verify again to check idempotence
75+
include_tasks: tasks/run_role_with_clear_facts.yml
76+
vars:
77+
snapshot_lvm_all_vgs: true
78+
snapshot_lvm_snapset_name: snapset1
79+
snapshot_lvm_verify_only: true
80+
snapshot_lvm_action: check
81+
82+
- name: Assert no changes for verify
83+
assert:
84+
that: not snapshot_cmd["changed"]
85+
86+
- name: Run the snapshot role remove the snapshot LVs
87+
include_tasks: tasks/run_role_with_clear_facts.yml
88+
vars:
89+
snapshot_lvm_snapset_name: snapset1
90+
snapshot_lvm_action: remove
91+
92+
- name: Assert changes for removal
93+
assert:
94+
that: snapshot_cmd["changed"]
95+
96+
- name: Use the snapshot_lvm_verify option to make sure remove is done
97+
include_tasks: tasks/run_role_with_clear_facts.yml
98+
vars:
99+
snapshot_lvm_snapset_name: snapset1
100+
snapshot_lvm_verify_only: true
101+
snapshot_lvm_action: remove
102+
103+
- name: Remove again to check idempotence
104+
include_tasks: tasks/run_role_with_clear_facts.yml
105+
vars:
106+
snapshot_lvm_snapset_name: snapset1
107+
snapshot_lvm_action: remove
108+
109+
- name: Assert no changes for remove
110+
assert:
111+
that: not snapshot_cmd["changed"]
112+
113+
- name: Verify remove again to check idempotence
114+
include_tasks: tasks/run_role_with_clear_facts.yml
115+
vars:
116+
snapshot_lvm_snapset_name: snapset1
117+
snapshot_lvm_verify_only: true
118+
snapshot_lvm_action: remove
119+
120+
- name: Assert no changes for remove verify
121+
assert:
122+
that: not snapshot_cmd["changed"]
123+
124+
rescue:
125+
- name: Do not fail if snapm is too old for test
126+
assert:
127+
that: ansible_failed_result.msg is search(msg1) or ansible_failed_result.msg is search(msg2)
128+
vars:
129+
msg1: "Package snapm version .* is too old"
130+
msg2: "Package snapm version 0.5 or later is required to use revertable snapsets"
131+
132+
always:
133+
- name: Cleanup
134+
include_tasks: tasks/cleanup.yml
135+
tags: tests::cleanup

tests/tests_set_revertable.yml

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
---
2+
- name: Snapshot a set of volumes with snapshot_lvm_revertable set to true
3+
hosts: all
4+
vars:
5+
test_disk_min_size: "1g"
6+
test_disk_count: 10
7+
test_storage_pools:
8+
- name: test_vg1
9+
disks: "{{ range(0, 3) | map('extract', unused_disks) | list }}"
10+
volumes:
11+
- name: lv1
12+
size: "15%"
13+
- name: lv2
14+
size: "50%"
15+
- name: test_vg2
16+
disks: "{{ range(3, 6) | map('extract', unused_disks) | list }}"
17+
volumes:
18+
- name: lv3
19+
size: "10%"
20+
- name: lv4
21+
size: "20%"
22+
- name: test_vg3
23+
disks: "{{ range(6, 10) | map('extract', unused_disks) | list }}"
24+
volumes:
25+
- name: lv5
26+
size: "30%"
27+
- name: lv6
28+
size: "25%"
29+
- name: lv7
30+
size: "10%"
31+
- name: lv8
32+
size: "10%"
33+
snapshot_test_set:
34+
name: snapset1
35+
volumes:
36+
- name: snapshot VG1 LV1
37+
vg: test_vg1
38+
lv: lv1
39+
percent_space_required: 20
40+
- name: snapshot VG2 LV3
41+
vg: test_vg2
42+
lv: lv3
43+
percent_space_required: 15
44+
- name: snapshot VG2 LV4
45+
vg: test_vg2
46+
lv: lv4
47+
percent_space_required: 15
48+
- name: snapshot VG3 LV7
49+
vg: test_vg3
50+
lv: lv7
51+
percent_space_required: 15
52+
tasks:
53+
- name: Load test variables
54+
include_vars:
55+
file: vars/rh_distros_vars.yml
56+
when: __snapshot_is_ostree is not defined
57+
58+
- name: Run tests
59+
block:
60+
- name: Setup
61+
include_tasks: tasks/setup.yml
62+
63+
- name: Run the snapshot role to create snapshot set of LVs with revert entry
64+
include_tasks: tasks/run_role_with_clear_facts.yml
65+
vars:
66+
snapshot_lvm_action: snapshot
67+
snapshot_lvm_revertable: true
68+
snapshot_lvm_set: "{{ snapshot_test_set }}"
69+
70+
- name: Assert changes for create snapset
71+
assert:
72+
that: snapshot_cmd["changed"]
73+
74+
- name: Get snapset details
75+
ansible.builtin.include_tasks: get_snapset_status.yml
76+
vars:
77+
snapset_name: "{{ snapshot_test_set.name }}"
78+
79+
- name: Fail if not revertable
80+
assert:
81+
that: is_revertable
82+
83+
- name: Remove the snapshot set
84+
include_tasks: tasks/run_role_with_clear_facts.yml
85+
vars:
86+
snapshot_lvm_action: remove
87+
snapshot_lvm_set: "{{ snapshot_test_set }}"
88+
89+
- name: Remove again to check idempotence
90+
include_tasks: tasks/run_role_with_clear_facts.yml
91+
vars:
92+
snapshot_lvm_action: remove
93+
snapshot_lvm_set: "{{ snapshot_test_set }}"
94+
95+
- name: Assert no changes for remove snapset
96+
assert:
97+
that: not snapshot_cmd["changed"]
98+
rescue:
99+
- name: Do not fail if snapm is too old for test
100+
assert:
101+
that: ansible_failed_result.msg is search(msg1) or ansible_failed_result.msg is search(msg2)
102+
vars:
103+
msg1: "Package snapm version .* is too old"
104+
msg2: "Package snapm version 0.5 or later is required to use revertable snapsets"
105+
always:
106+
- name: Cleanup
107+
include_tasks: tasks/cleanup.yml
108+
tags: tests::cleanup

0 commit comments

Comments
 (0)