Skip to content

Commit 748a899

Browse files
committed
fix: problem with bootable flag not getting passed properly to snapm
Add check to test that uses snapm to validate the snapset attribute is set to bootable. Signed-off-by: Todd Gill <[email protected]>
1 parent e155bf7 commit 748a899

File tree

9 files changed

+200
-37
lines changed

9 files changed

+200
-37
lines changed

library/snapshot.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,10 +343,10 @@ def run_module():
343343
if module.params["snapshot_lvm_vg_include"]:
344344
vg_include = re.compile(module.params["snapshot_lvm_vg_include"])
345345

346-
if len(module.params["snapshot_lvm_set"].get("volumes")) > 0:
346+
if len(module.params.get("snapshot_lvm_set", {}).get("volumes", [])) > 0:
347347
cmd_result, snapset_dict = validate_snapset_json(
348348
cmd,
349-
module.params["snapshot_lvm_set"],
349+
module.params,
350350
False,
351351
)
352352
else:

module_utils/snapshot_lsr/consts.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ class SnapshotStatus:
5959
ERROR_UMOUNT_NOT_MOUNTED = 40
6060
ERROR_CREATE_FAILED = 41
6161
ERROR_SNAPM_INTERNAL_ERROR = 42
62+
ERROR_BOOTABLE_NOT_SUPPORTED = 43
63+
ERROR_BOOTABLE_CONFLICT = 44
6264

6365

6466
COMMAND_ENV = {"LC_ALL": "C", "LVM_COMMAND_PROFILE": "lvmdbusd"}

module_utils/snapshot_lsr/lvm.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1209,6 +1209,16 @@ def snapshot_create_set(module, snapset_json, check_mode):
12091209

12101210
def snapshot_set(module, snapset_json, check_mode):
12111211
changed = False
1212+
1213+
# If this function has been called with bootable snapshot requested, return error
1214+
# because snapm is required for bootable snapshots.
1215+
if any((snapset_json["snapshot_lvm_bootable"], snapset_json["bootable"])):
1216+
return (
1217+
SnapshotStatus.ERROR_BOOTABLE_NOT_SUPPORTED,
1218+
"Bootable snapshots are not supported without snapm",
1219+
changed,
1220+
)
1221+
12121222
rc, message = verify_snapset_source_lvs_exist(module, snapset_json)
12131223
if rc != SnapshotStatus.SNAPSHOT_OK:
12141224
return rc, message, changed

module_utils/snapshot_lsr/snapmgr.py

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ def mgr_check_verify_lvs_set(manager, module, snapset_json):
188188

189189

190190
def mgr_snapshot_cmd(module, module_args, snapset_json):
191+
bootable = None
191192
snapset_name = snapset_json["name"]
192193
logger.info("mgr_snapshot_cmd: %s", snapset_name)
193194
changed = False
@@ -200,10 +201,28 @@ def mgr_snapshot_cmd(module, module_args, snapset_json):
200201

201202
snapset_name = snapset_json["name"]
202203
volume_list = snapset_json["volumes"]
203-
if "bootable" in snapset_json:
204-
bootable = snapset_json["bootable"]
205-
else:
206-
bootable = False
204+
205+
# Bootable global variable is set
206+
if module_args["snapshot_lvm_bootable"]:
207+
bootable = module_args["snapshot_lvm_bootable"]
208+
209+
# Global is not set, check the snapset
210+
if bootable is None:
211+
if "bootable" in snapset_json:
212+
bootable = snapset_json["bootable"]
213+
else:
214+
bootable = False
215+
else: # Global is set, check for conflict
216+
if (
217+
"bootable" in snapset_json
218+
and snapset_json["bootable"] is not None
219+
and bootable != snapset_json["bootable"]
220+
):
221+
return {
222+
"return_code": SnapshotStatus.ERROR_BOOTABLE_CONFLICT,
223+
"errors": "Conflicting values for bootable",
224+
"changed": False,
225+
}
207226

208227
source_list = mgr_get_source_list_for_create(volume_list)
209228

module_utils/snapshot_lsr/validate.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,12 @@ def validate_json_umount(snapset_dict):
332332
return SnapshotStatus.SNAPSHOT_OK, ""
333333

334334

335-
def validate_snapset_json(cmd, snapset_dict, verify_only):
335+
def validate_snapset_json(cmd, module_args, verify_only):
336+
337+
snapset_dict = module_args["snapshot_lvm_set"]
338+
339+
if module_args["snapshot_lvm_bootable"]:
340+
snapset_dict["snapshot_lvm_bootable"] = module_args["snapshot_lvm_bootable"]
336341

337342
if cmd == SnapshotCommand.SNAPSHOT:
338343
rc, message = validate_json_request(snapset_dict, True)

tests/get_snapset_status.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# get_snapset_status.yml
2+
- name: Invoke snapm for {{ snapset_name }}
3+
ansible.builtin.command: snapm snapset show {{ snapset_name | quote }} -j
4+
register: snapm_raw
5+
changed_when: false
6+
7+
- name: Parse and set facts
8+
ansible.builtin.set_fact:
9+
# Extracting the first dictionary from the JSON list
10+
_raw_data: "{{ snapm_raw.stdout | from_json | first }}"
11+
12+
- name: Define reusable variables
13+
ansible.builtin.set_fact:
14+
is_bootable: "{{ _raw_data.Bootable | bool }}"
15+
boot_entries_list: "{{ _raw_data.BootEntries.values() | list }}"

tests/library/find_unused_disk.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@
8080
from ansible.module_utils.basic import AnsibleModule
8181
from ansible.module_utils.size import Size
8282

83-
8483
SYS_CLASS_BLOCK = "/sys/class/block/"
8584
IGNORED_DEVICES = [re.compile(r"^/dev/nullb\d+$")]
8685

tests/tests_basic_bootable.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
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
42+
include_role:
43+
name: linux-system-roles.snapshot
44+
vars:
45+
snapshot_lvm_percent_space_required: 15
46+
snapshot_lvm_all_vgs: true
47+
snapshot_lvm_snapset_name: snapset1
48+
snapshot_lvm_action: snapshot
49+
snapshot_lvm_bootable: true
50+
51+
- name: Assert changes for creation
52+
assert:
53+
that: snapshot_cmd["changed"]
54+
55+
- name: Verify the snapshot LVs are created
56+
include_role:
57+
name: linux-system-roles.snapshot
58+
vars:
59+
snapshot_lvm_all_vgs: true
60+
snapshot_lvm_snapset_name: snapset1
61+
snapshot_lvm_verify_only: true
62+
snapshot_lvm_action: check
63+
64+
- name: Run the snapshot role again to check idempotence
65+
include_role:
66+
name: linux-system-roles.snapshot
67+
vars:
68+
snapshot_lvm_percent_space_required: 15
69+
snapshot_lvm_all_vgs: true
70+
snapshot_lvm_snapset_name: snapset1
71+
snapshot_lvm_action: snapshot
72+
73+
- name: Assert no changes for creation
74+
assert:
75+
that: not snapshot_cmd["changed"]
76+
77+
- name: Verify again to check idempotence
78+
include_role:
79+
name: linux-system-roles.snapshot
80+
vars:
81+
snapshot_lvm_all_vgs: true
82+
snapshot_lvm_snapset_name: snapset1
83+
snapshot_lvm_verify_only: true
84+
snapshot_lvm_action: check
85+
86+
- name: Assert no changes for verify
87+
assert:
88+
that: not snapshot_cmd["changed"]
89+
90+
- name: Run the snapshot role remove the snapshot LVs
91+
include_role:
92+
name: linux-system-roles.snapshot
93+
vars:
94+
snapshot_lvm_snapset_name: snapset1
95+
snapshot_lvm_action: remove
96+
97+
- name: Assert changes for removal
98+
assert:
99+
that: snapshot_cmd["changed"]
100+
101+
- name: Use the snapshot_lvm_verify option to make sure remove is done
102+
include_role:
103+
name: linux-system-roles.snapshot
104+
vars:
105+
snapshot_lvm_snapset_name: snapset1
106+
snapshot_lvm_verify_only: true
107+
snapshot_lvm_action: remove
108+
109+
- name: Remove again to check idempotence
110+
include_role:
111+
name: linux-system-roles.snapshot
112+
vars:
113+
snapshot_lvm_snapset_name: snapset1
114+
snapshot_lvm_action: remove
115+
116+
- name: Assert no changes for remove
117+
assert:
118+
that: not snapshot_cmd["changed"]
119+
120+
- name: Verify remove again to check idempotence
121+
include_role:
122+
name: linux-system-roles.snapshot
123+
vars:
124+
snapshot_lvm_snapset_name: snapset1
125+
snapshot_lvm_verify_only: true
126+
snapshot_lvm_action: remove
127+
128+
- name: Assert no changes for remove verify
129+
assert:
130+
that: not snapshot_cmd["changed"]
131+
132+
always:
133+
- name: Cleanup
134+
include_tasks: tasks/cleanup.yml
135+
tags: tests::cleanup

tests/tests_set_bootable.yml

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
vg: test_vg3
5050
lv: lv7
5151
percent_space_required: 15
52-
snapshot_lvm_bootable: true
5352
tasks:
5453
- name: Load test variables
5554
include_vars:
@@ -66,49 +65,28 @@
6665
name: linux-system-roles.snapshot
6766
vars:
6867
snapshot_lvm_action: snapshot
68+
snapshot_lvm_bootable: true
6969
snapshot_lvm_set: "{{ snapshot_test_set }}"
7070

7171
- name: Assert changes for create snapset
7272
assert:
7373
that: snapshot_cmd["changed"]
7474

75-
- name: Run the snapshot role to verify the set of snapshots for the LVs
76-
include_role:
77-
name: linux-system-roles.snapshot
78-
vars:
79-
snapshot_lvm_action: check
80-
snapshot_lvm_set: "{{ snapshot_test_set }}"
81-
snapshot_lvm_verify_only: true
82-
83-
- name: Create snapset again for idempotence
84-
include_role:
85-
name: linux-system-roles.snapshot
75+
- name: Get snapset details
76+
ansible.builtin.include_tasks: get_snapset_status.yml
8677
vars:
87-
snapshot_lvm_action: snapshot
88-
snapshot_lvm_set: "{{ snapshot_test_set }}"
78+
snapset_name: "{{ snapshot_test_set.name }}"
8979

90-
- name: Assert no changes for create snapset
80+
- name: Fail if not bootable
9181
assert:
92-
that: not snapshot_cmd["changed"]
93-
94-
- name: Run the snapshot role remove the set
95-
include_role:
96-
name: linux-system-roles.snapshot
97-
vars:
98-
snapshot_lvm_action: remove
99-
snapshot_lvm_set: "{{ snapshot_test_set }}"
100-
101-
- name: Assert changes for remove snapset
102-
assert:
103-
that: snapshot_cmd["changed"]
82+
that: is_bootable
10483

105-
- name: Run the snapshot role to verify the set is removed
84+
- name: Remove the snapshot set
10685
include_role:
10786
name: linux-system-roles.snapshot
10887
vars:
10988
snapshot_lvm_action: remove
11089
snapshot_lvm_set: "{{ snapshot_test_set }}"
111-
snapshot_lvm_verify_only: true
11290

11391
- name: Remove again to check idempotence
11492
include_role:

0 commit comments

Comments
 (0)