[AI Generated] BugFix: fix IndexError in _hot_add_disk_serial when no new device appears#4435
Conversation
… new device appears Replace bare [0] indexing on the lun diff list with an explicit assertion that the new device set is non-empty, providing a clear error message about max_data_disk_count mismatch instead of an opaque IndexError.
There was a problem hiding this comment.
Pull request overview
Fixes a crash in the Storage test suite hot-add helper by replacing an unsafe empty-list index with an assertion and a safer retrieval approach when no new Linux block device is detected after attaching a disk.
Changes:
- Add an explicit non-empty assertion for newly discovered device keys when comparing
Disk.get_luns()before/after hot-add. - Replace direct
[0]indexing withnext(iter(...))after validating the set difference is non-empty. - Improve failure diagnostics by including LUN and before/after device mappings in the assertion message.
| linux_device_lun_diff = linux_device_luns_after[next(iter(new_device_keys))] | ||
| log.debug(f"linux_device_lun_diff: {linux_device_lun_diff}") | ||
| assert_that(linux_device_lun_diff, "New device lun mismatch").is_equal_to( | ||
| lun | ||
| ) |
There was a problem hiding this comment.
next(iter(new_device_keys)) picks an arbitrary element because set iteration order is not stable. If more than one new device key appears (e.g., due to renames/duplicate discoveries), this can become non-deterministic and fail even when a device at the expected LUN exists. Consider asserting there is exactly one new key, or selecting the key whose LUN matches the expected lun.
| linux_device_lun_diff = linux_device_luns_after[next(iter(new_device_keys))] | |
| log.debug(f"linux_device_lun_diff: {linux_device_lun_diff}") | |
| assert_that(linux_device_lun_diff, "New device lun mismatch").is_equal_to( | |
| lun | |
| ) | |
| new_device_luns = [ | |
| linux_device_luns_after[device_key] for device_key in new_device_keys | |
| ] | |
| log.debug(f"new_device_luns: {new_device_luns}") | |
| assert_that( | |
| new_device_luns, | |
| f"Expected a newly discovered device at lun {lun}. " | |
| f"New device keys: {list(new_device_keys)}. " | |
| f"Before: {linux_device_luns}. After: {linux_device_luns_after}.", | |
| ).contains(lun) |
| assert_that( | ||
| linux_device_lun_diff, "No new device lun found on VM" | ||
| ).is_equal_to(lun) | ||
| list(new_device_keys), | ||
| f"Expected new device at lun {lun} but no new device " | ||
| f"appeared. Before: {linux_device_luns}, " | ||
| f"After: {linux_device_luns_after}. This may indicate " | ||
| f"the VM size does not support this many data disks " | ||
| f"(max_data_disk_count={max_data_disk_count}).", | ||
| ).is_not_empty() | ||
| linux_device_lun_diff = linux_device_luns_after[next(iter(new_device_keys))] | ||
| log.debug(f"linux_device_lun_diff: {linux_device_lun_diff}") | ||
| assert_that(linux_device_lun_diff, "New device lun mismatch").is_equal_to( | ||
| lun | ||
| ) |
There was a problem hiding this comment.
If the new-device assertion fails (or any assertion in the loop fails), the function exits before the cleanup loop runs, leaving any already-attached managed disks on the VM. Consider wrapping the add/verify loop in a try/finally so disk.remove_data_disk(disks_added) is always executed to avoid resource leaks and cascading failures/cost.
❌ AI Test Selection — FAILED74 test case(s) selected (view run) Marketplace image: canonical 0001-com-ubuntu-server-jammy 22_04-lts-gen2 latest
Test case details
|
Summary
Fix an
IndexError: list index out of rangecrash in_hot_add_disk_serial()when a hot-added data disk does not appear as a new Linux block device after attachment.Root Cause
The method computed the set difference of device keys before vs. after hot-add, then immediately indexed
[0]on the resulting list without checking whether it was empty. If the disk was not yet visible (timing race) or failed to appear, the empty-list access raisedIndexError.Fix
[0]indexing with an explicitassert_that(...).is_not_empty()assertion that produces a clear diagnostic message including the expected LUN number.next(iter(...))to retrieve the first element safely after the assertion guarantees non-emptiness.Validation
Tested on 3 distro families with
verify_hot_add_disk_serial_premium_ssd:All lint checks pass (black, flake8, mypy).