-
Notifications
You must be signed in to change notification settings - Fork 181
Snapshot: add mew manual snapshot cases #6727
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
WalkthroughAdds a new Libvirt test for manual snapshot creation: a config file defining test parameters and two variants (one_manual_snapshot, three_manual_snapshots) and a Python test module that prepares a VM with extra QCOW2 disks, creates manual snapshots with per-disk snapshot options, validates qemu-img bitmap/checkpoint info, checks VM state transitions (pause/resume) around snapshot actions, and performs cleanup. Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (1)
libvirt/tests/src/snapshot/create_manual_snapshot.py (1)
104-106: Consider a more precise check for the "auto" flag.The check
"auto" in linecould produce false positives if a bitmap name or other field contains the substring "auto". Consider checking specifically for the flags line format.# Check for auto flag - elif "auto" in line: + elif line.startswith("flags:") and "auto" in line: current_bitmap_has_auto = True
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
libvirt/tests/cfg/snapshot/create_manual_snapshot.cfg(1 hunks)libvirt/tests/src/snapshot/create_manual_snapshot.py(1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: meinaLi
Repo: autotest/tp-libvirt PR: 6628
File: libvirt/tests/src/virtual_disks/virtual_disks_io_error.py:128-129
Timestamp: 2025-10-24T06:35:25.679Z
Learning: In libvirt tests, `virsh.snapshot_delete()` without the `--metadata` flag automatically deletes both snapshot metadata and external disk files. Explicit `os.remove()` is only needed when using `virsh.snapshot_delete()` with the `--metadata` flag, which removes only metadata.
📚 Learning: 2025-10-24T06:35:25.679Z
Learnt from: meinaLi
Repo: autotest/tp-libvirt PR: 6628
File: libvirt/tests/src/virtual_disks/virtual_disks_io_error.py:128-129
Timestamp: 2025-10-24T06:35:25.679Z
Learning: In libvirt tests, `virsh.snapshot_delete()` without the `--metadata` flag automatically deletes both snapshot metadata and external disk files. Explicit `os.remove()` is only needed when using `virsh.snapshot_delete()` with the `--metadata` flag, which removes only metadata.
Applied to files:
libvirt/tests/src/snapshot/create_manual_snapshot.py
🧬 Code graph analysis (1)
libvirt/tests/src/snapshot/create_manual_snapshot.py (2)
provider/virtual_disk/disk_base.py (2)
get_source_list(56-93)add_vm_disk(95-112)provider/snapshot/snapshot_base.py (1)
SnapshotTest(16-101)
🪛 Ruff (0.14.8)
libvirt/tests/src/snapshot/create_manual_snapshot.py
54-54: Unused function argument: disk_paths
(ARG001)
226-226: Do not catch blind exception: Exception
(BLE001)
235-235: Do not catch blind exception: Exception
(BLE001)
242-242: Local variable snap_name is assigned to but never used
Remove assignment to unused variable snap_name
(F841)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Python 3.12
- GitHub Check: Python 3.11
- GitHub Check: Python 3.8
- GitHub Check: Python 3.9
🔇 Additional comments (5)
libvirt/tests/cfg/snapshot/create_manual_snapshot.cfg (1)
1-18: LGTM!The configuration is well-structured with appropriate version gating for libvirt 11.9.0 and clear variant definitions for the two test scenarios. The diskspec options correctly differentiate between the single manual snapshot case (vda=no, vdb=manual, vdc=external) and the multiple manual snapshots case (all disks=manual).
libvirt/tests/src/snapshot/create_manual_snapshot.py (4)
19-51: LGTM!The guest preparation logic correctly creates additional disk images and attaches them to the VM, skipping vda (the base system disk).
117-160: LGTM!The validation logic correctly differentiates between test variants and properly checks for bitmap presence and auto flags on the expected disks.
163-188: LGTM!The state transition validation correctly verifies the VM is paused after manual snapshot creation and resumes successfully.
217-237: Verify or explicitly document snapshot overlay cleanup withtest_obj.teardown_test().The test creates snapshots with
--no-metadata --disk-onlyoptions, which generates external snapshot overlay files. The teardown removes the original test disk images and callstest_obj.teardown_test(), which invokeslibvirt.clean_up_snapshots()from the virttest framework.However, the teardown does not explicitly list or delete snapshots before relying on
clean_up_snapshots(). According to libvirt behavior,virsh.snapshot_delete()without the--metadataflag automatically removes external snapshot files, soclean_up_snapshots()should handle this. Consider adding a comment or explicit snapshot deletion in the teardown to clarify this dependency, or verify in testing that no orphaned snapshot overlay files remain after teardown completes.
Automate cases: VIRT-306532 - [Disk snapshot][manual mode] Use virsh cmd to create disk snapshot with multiple 'manual' disk snapshot modes This case is to verify the consistency and usability of 'manual' disk snapshot mode from libvirt-11.9.0-1 Signed-off-by: Meina Li <[email protected]>
97b02ef to
02ca254
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (3)
libvirt/tests/src/snapshot/create_manual_snapshot.py (3)
54-70: Consider checkingsnapshot_create_asresult and failing early on error.Right now the return value of
virsh.snapshot_create_as()is ignored; if the command fails, the test will continue and later assertions may be misleading.You can make failures clearer by asserting on the exit status:
- virsh.snapshot_create_as(vm_name, full_snap_options, **virsh_dargs) - test.log.debug(f"Created snapshot {snap_name} with options: {full_snap_options}") + result = virsh.snapshot_create_as(vm_name, full_snap_options, **virsh_dargs) + test.log.debug(f"Snapshot create cmd: virsh snapshot-create-as {vm_name} {full_snap_options}") + if result.exit_status != 0: + test.fail(f"Failed to create snapshot {snap_name}: {result.stderr_text}") + test.log.debug(f"Created snapshot {snap_name} with options: {full_snap_options}")This keeps the behavior deterministic when virsh fails.
116-159:check_image_infologic matches cfg variants; consider negative checks as a future enhancement.The mapping from
only_one_manual/with_multiple_manualtoexpected_auto_disksand the use ofdisk_pathslook correct and consistent with the cfg (vda,vdb,vdc).If you want stricter validation later, you could also assert that non-expected disks do not contain the checkpoint bitmap or auto flag, but that’s not required for this PR.
216-236: Teardown: broad exception catches and missingvirsh_dargson checkpoint ops.Two minor points in
teardown_test():
- Broad
except Exceptionfor both checkpoint deletion andos.remove()may hide unexpected issues during cleanup.checkpoint_list/checkpoint_deleteare called without**virsh_dargs, so their behavior (debugging, status handling) is slightly inconsistent with the rest of the file.If you want to tighten this up while keeping teardown robust:
- try: - checkpoints = virsh.checkpoint_list(vm_name) - if checkpoint_name in checkpoints.stdout: - virsh.checkpoint_delete(vm_name, checkpoint_name) - except Exception as e: - test.log.debug(f"Error cleaning checkpoint: {e}") + try: + checkpoints = virsh.checkpoint_list(vm_name, **virsh_dargs) + if checkpoint_name in checkpoints.stdout: + virsh.checkpoint_delete(vm_name, checkpoint_name, **virsh_dargs) + except Exception as e: # consider narrowing to specific virsh/disk errors + test.log.debug(f"Error cleaning checkpoint {checkpoint_name}: {e}") @@ - for disk_name in test_disks: - img_path = disk_paths.get(disk_name) - if img_path and os.path.exists(img_path): - try: - os.remove(img_path) - except Exception as e: - test.log.debug(f"Error removing image {img_path}: {e}") + for disk_name in test_disks: + img_path = disk_paths.get(disk_name) + if img_path and os.path.exists(img_path): + try: + os.remove(img_path) + except OSError as e: + test.log.debug(f"Error removing image {img_path}: {e}")Narrowing the second
excepttoOSErroraddresses the static-analysis concern there; for the checkpoint path, you can decide which specific error types you’re comfortable swallowing in teardown.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
libvirt/tests/cfg/snapshot/create_manual_snapshot.cfg(1 hunks)libvirt/tests/src/snapshot/create_manual_snapshot.py(1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: meinaLi
Repo: autotest/tp-libvirt PR: 6628
File: libvirt/tests/src/virtual_disks/virtual_disks_io_error.py:128-129
Timestamp: 2025-10-24T06:35:25.679Z
Learning: In libvirt tests, `virsh.snapshot_delete()` without the `--metadata` flag automatically deletes both snapshot metadata and external disk files. Explicit `os.remove()` is only needed when using `virsh.snapshot_delete()` with the `--metadata` flag, which removes only metadata.
📚 Learning: 2025-10-24T06:35:25.679Z
Learnt from: meinaLi
Repo: autotest/tp-libvirt PR: 6628
File: libvirt/tests/src/virtual_disks/virtual_disks_io_error.py:128-129
Timestamp: 2025-10-24T06:35:25.679Z
Learning: In libvirt tests, `virsh.snapshot_delete()` without the `--metadata` flag automatically deletes both snapshot metadata and external disk files. Explicit `os.remove()` is only needed when using `virsh.snapshot_delete()` with the `--metadata` flag, which removes only metadata.
Applied to files:
libvirt/tests/src/snapshot/create_manual_snapshot.py
🧬 Code graph analysis (1)
libvirt/tests/src/snapshot/create_manual_snapshot.py (2)
provider/virtual_disk/disk_base.py (2)
get_source_list(56-93)add_vm_disk(95-112)provider/snapshot/snapshot_base.py (1)
SnapshotTest(16-101)
🪛 Ruff (0.14.8)
libvirt/tests/src/snapshot/create_manual_snapshot.py
225-225: Do not catch blind exception: Exception
(BLE001)
234-234: Do not catch blind exception: Exception
(BLE001)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Python 3.12
- GitHub Check: Python 3.9
- GitHub Check: Python 3.11
- GitHub Check: Python 3.8
🔇 Additional comments (4)
libvirt/tests/src/snapshot/create_manual_snapshot.py (2)
19-51: Guest preparation and disk wiring look consistent with cfg.
prepare_guest()correctly aligns with the cfg: it derivesvdafromDiskBase.get_source_list, createsvdb/vdcunderdata_dir.get_tmp_dir(), and wires them viadisk_dictanddisk_obj.add_vm_disk(). Thedisk_pathsmap you return matches howcheck_image_info()andteardown_test()consume it, so this part looks good.
162-188: VM state checks are straightforward; confirm expected paused state semantics.The use of
virsh.domstateto assert"paused"after snapshot and"running"aftervirsh.resumeis clear and makes failures easy to diagnose.Just ensure that, for the libvirt/QEMU versions you’re targeting, the snapshot flow for this manual mode is actually expected to pause the guest (vs. e.g. staying
runningor using a different state string), otherwise the check may be too strict.libvirt/tests/cfg/snapshot/create_manual_snapshot.cfg (2)
1-1: Double‑check whether the top‑level cfg key should have a leading dash.The header line is:
- snapshot_create.manual_snapshot:In many tp-libvirt cfg files, the leading
-is typically used undervariants:rather than on the top‑level test key. If that’s the case here, this line might need to be:snapshot_create.manual_snapshot:to be parsed as a test entry instead of a list item.
Please compare with existing
snapshot_create.*cfgs in this repo to confirm the intended syntax.
5-18: Cfg parameters align well with the Python test implementation.The cfg fields (
disk_list,disk_type,disk_dict,checkpoint_name,snap_name,snap_options,only_one_manual,with_multiple_manual, anddiskspec_options) line up correctly withcreate_manual_snapshot.py:
disk_list/disk_dictuse the%splaceholder as expected byprepare_guest().only_one_manualandwith_multiple_manualmatch the flags consumed bycheck_image_info().snap_optionsand per‑variantdiskspec_optionsare combined increate_snapshots()as intended.This wiring looks consistent and should make the two variants behave as described.
| def check_bitmap_auto_flag(result, checkpoint_name): | ||
| """ | ||
| Check if bitmap has auto flag in qemu-img info output. | ||
|
|
||
| :param result: qemu-img info output string | ||
| :param checkpoint_name: name of the checkpoint to check | ||
| :return: True if auto flag found, False otherwise | ||
| """ | ||
| lines = result.split('\n') | ||
| in_bitmaps_section = False | ||
| current_bitmap_has_auto = False | ||
| current_bitmap_name = None | ||
|
|
||
| for line in lines: | ||
| line = line.strip() | ||
|
|
||
| # Check if we're in the bitmaps section | ||
| if line == "bitmaps:": | ||
| in_bitmaps_section = True | ||
| continue | ||
|
|
||
| # If not in bitmaps section, skip | ||
| if not in_bitmaps_section: | ||
| continue | ||
|
|
||
| # Check for start of a new bitmap entry | ||
| if re.match(r'^\[\d+\]:$', line): | ||
| # Reset for new bitmap | ||
| current_bitmap_has_auto = False | ||
| current_bitmap_name = None | ||
| # Check for auto flag | ||
| elif "auto" in line: | ||
| current_bitmap_has_auto = True | ||
| # Check for bitmap name | ||
| elif line.startswith("name:"): | ||
| name_value = line.split("name:", 1)[1].strip() | ||
| current_bitmap_name = name_value | ||
| # If this is the target checkpoint and it has auto flag, return True | ||
| if current_bitmap_name == checkpoint_name and current_bitmap_has_auto: | ||
| return True | ||
| return False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bitmap auto flag detection can miss matches if name precedes auto in the output.
The current logic only checks for a match when processing a name: line if current_bitmap_has_auto is already True. If qemu-img info outputs name: before the line containing auto, the function never detects the match even though the bitmap has the auto flag, causing false negatives. Additionally, the last bitmap entry is never checked after the loop completes.
The suggested refactor correctly addresses the primary issue by checking at the start of each new bitmap entry (to finalize the previous one) and again at the end of the loop. However, use a more specific pattern to detect the auto flag—such as line.startswith("auto:") or re.search(r'auto:\s*true', line)—rather than just "auto" in line, which could produce false positives if "auto" appears in other contexts (e.g., flags: auto_grow).
🤖 Prompt for AI Agents
In libvirt/tests/src/snapshot/create_manual_snapshot.py around lines 73 to 113,
the bitmap `auto` detection misses cases when the `name:` line appears before
the `auto` line and never validates the final bitmap; update the loop to (1)
finalize/check the previous bitmap when a new bitmap entry starts (so if we
encounter a new index we evaluate the prior bitmap's name+auto state), (2) use a
stricter detection for the auto flag (e.g., match lines starting with "auto:" or
use a regex like r'auto:\s*true' instead of `"auto" in line`), and (3) after the
loop completes, perform a final check of the last bitmap's name+auto state and
return True if it matches the target checkpoint; otherwise return False.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think no need to update it because the auto is always before the name:.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
qemu-img info bitmap output format auto flag
💡 Result:
Short answer:
-
qemu-img info can show qcow2 bitmap entries under "Format specific information". Use --output (or --output=OFMT) to choose human or json output (OFMT = human | json). [1][4]
-
The bitmap "flags" field lists values such as "in-use" and "auto". "auto" means the bitmap is enabled to track all writes to the virtual disk (i.e., it must reflect all changes by any writer). "in-use" means the bitmap was not flushed/synced and may be inconsistent. These meanings come from the qcow2 spec / QMP docs. [2][3]
References:
- qemu-img documentation (info / --output). [1]
- qcow2 image format — bitmap flags and semantics (auto/in_use). [2]
- QEMU QMP / qcow2 bitmap flags descriptions. [3]
- qemu-img patch/example showing bitmap output in qemu-img info. [4]
🌐 Web query:
qemu-img info bitmaps example output format structure
💡 Result:
qemu-img info (human or JSON) includes a "Format specific information" section that lists persistent bitmaps for formats that support them (e.g., qcow2). Structure and key fields:
-
Top-level placement
- In human output: under "Format specific information:" with a "bitmaps:" subsection. [1]
- In JSON output: bitmaps appear in the ImageInfo object (as format-specific fields). [1]
-
Per-bitmaps (human output example structure)
- bitmaps:
[i]:
flags:
[0]: in-use
[1]: auto
name:
unknown flags:
granularity: - "flags" lists individual flag names; "name" is the bitmap identifier; "granularity" is the bitmap granularity in bytes. Example shown in upstream discussion: two bitmap entries with flags, names and granularity. [2]
- bitmaps:
-
JSON fields (semantics)
- Entries include booleans/meta indicating whether sectors contain data/zero/present when listing mappings; qemu-img --output=json uses the ImageInfo QAPI type and includes data/zero/present for mapping ranges. Use --output=json to get machine-parseable fields. [1]
References:
[1] QEMU/qemu-img documentation (qemu-img info output description and --output=json/ImageInfo).
[2] qemu-block mailing-list patch example showing human output bitmaps block with flags/name/granularity.
@meinaLi, you're correct about the output order! Based on the qemu-img info format documentation, the flags: section (which contains auto) does consistently appear before the name: field in each bitmap entry, so the current logic handles that ordering properly.
However, there are two other considerations:
-
Last bitmap entry: After the loop completes, the final bitmap's name and auto flag are never checked. If the last bitmap in the output matches
checkpoint_nameand has the auto flag, the function would returnFalseinstead ofTrue. -
Detection specificity: The check
"auto" in linecould potentially match unintended text. Using something more specific likeline.strip() == "auto"or checking within the flags context would be more robust.
If you're confident the current implementation works correctly for your test scenarios, that's fine. These are just observations for potential edge cases.
🧠 Learnings used
Learnt from: meinaLi
Repo: autotest/tp-libvirt PR: 6628
File: libvirt/tests/src/virtual_disks/virtual_disks_io_error.py:128-129
Timestamp: 2025-10-24T06:35:25.679Z
Learning: In libvirt tests, `virsh.snapshot_delete()` without the `--metadata` flag automatically deletes both snapshot metadata and external disk files. Explicit `os.remove()` is only needed when using `virsh.snapshot_delete()` with the `--metadata` flag, which removes only metadata.
Automate cases:
VIRT-306532 - [Disk snapshot][manual mode] Use virsh cmd to create disk snapshot with multiple 'manual' disk snapshot modes
This case is to verify the consistency and usability of 'manual' disk snapshot mode from libvirt-11.9.0-1
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.