Repository navigation
Refuse snapshot operations cleanly when the snapshot's volume is gone - #14646
bhouse-nexthop wants to merge 1 commit into
Conversation
revertSnapshot looked up the snapshot's volume with findById(), which does not return removed volumes, and used it without a null check. Any snapshot of a deleted volume therefore failed with an NPE on VolumeVO.getState(). It now fails with an error saying the volume no longer exists. The same pattern elsewhere: - copySnapshot without sourcezoneid took the source zone from the volume, found the same way. For a deleted volume it now falls back to the snapshot's own zone, which is the zone it was taken in. - createVolume and createTemplate from a snapshot look the volume up including removed rows, but still failed with an NPE when the row itself is missing. They now refuse with a clear error. Fixes apache#14644 Signed-off-by: Brad House <bhouse@nexthop.ai>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## 4.22 #14646 +/- ##
=========================================
Coverage 18.32% 18.32%
Complexity 16644 16644
=========================================
Files 5939 5939
Lines 537768 537774 +6
Branches 65929 65933 +4
=========================================
+ Hits 98551 98562 +11
+ Misses 428008 427990 -18
- Partials 11209 11222 +13
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Test report: snapshot operations when the snapshot's volume is goneSummary: for a snapshot whose volume was deleted, Environment
Case 1: the volume was deleted (
Before this PR, Case 2: the volume row is missing (as in #14599)
After the refusals there was no template record and no volume left with the requested names. The template refusal happens before a template record is written, as the PR says.
Result: pass. Side note, not from this PR: taking a snapshot of a detached volume on the zone-wide RBD pool logged a caught NPE at DEBUG: Not covered
|
Description
revertSnapshotfailed withCannot invoke "com.cloud.storage.VolumeVO.getState()" because "volume" is nullfor any snapshot whose volume has been deleted. A few other snapshot APIs had the same missing null check.Fixes #14644
Changes
revertSnapshot(SnapshotManagerImpl): the volume is looked up withfindById(), which does not return removed volumes. When it is null, the call now fails withCannot revert snapshot <uuid>, because its volume no longer exists. Nothing else in the revert changes.copySnapshotwithoutsourcezoneid(getCheckedSnapshotForCopy): the source zone came from the volume, found the same way, and NPEd for a deleted volume. It now falls back to the snapshot's owndata_center_id, which is the zone the snapshot was taken in, since a volume does not change zones. The volume is now only looked up when no source zone is given. Withsourcezoneidpassed, the copy already worked for such snapshots; the rest of the copy does not use the volume.createVolumefrom a snapshot (allocVolume) andcreateTemplatefrom a snapshot (createPrivateTemplateRecord): these already look the volume up including removed rows, so a deleted volume is fine. They NPEd only when the volume row itself is missing (the case in listSnapshots fails with NPE in snapshot strategy canHandle when a snapshot's volume row no longer exists #14599). They now refuse with a clear error in that case. ForcreateTemplatethe check runs while creating the template record, before the job that would otherwise fail increatePrivateTemplate, so no template record is left behind.This complements #14600, which stops
listSnapshotsfrom failing on the same kind of snapshot. Neither PR depends on the other.Not changed here
Deploying a VM from a snapshot whose volume row is missing still fails, in
VolumeOrchestrator.allocateTemplatedVolume, which reads the size from the volume.UserVmManagerImplaccepts that case when a template id is given, so the right fix there is to make the deploy work, not to refuse it. That needs a live test, so I've left it for a separate change.Types of changes
Feature/Enhancement Scale or Bug Severity
Bug Severity
How Has This Been Tested?
The
revertSnapshotNPE was seen on a KVM + Ceph RBD lab while testing #14600. This fix has not yet been run there; it is covered by unit tests.New tests:
SnapshotManagerTest.testRevertSnapshotVolumeGone: the error is raised and the strategy's revert is never called.SnapshotManagerImplTest.testGetCheckedSnapshotForCopyVolumeRemoved: no volume, so the source zone comes from the snapshot.VolumeApiServiceImplTest.allocVolumeFromSnapshotWhoseVolumeRowIsGoneIsRefused.TemplateManagerImplTest.testCreatePrivateTemplateRecordSnapshotVolumeRowGone: refused, and no template is persisted.Without the fix, the first three fail with the NPEs from the issue. The fourth fails further on, because the record path went past the missing volume.
Updated tests:
testCreatePrivateTemplateRecordForRegionStorerelied on the volume lookup returning null. It now returns a volume, so the test goes through the normal path.testGetCheckedSnapshotForCopyDestContainsSourcepasses a source zone, so it no longer stubs a volume lookup that isn't made.SnapshotManagerTest,SnapshotManagerImplTest,TemplateManagerImplTestandVolumeApiServiceImplTestall pass (259 tests). Checkstyle is clean forserver.How did you try to break this feature and the system with this change?
copySnapshotI checked that the copy path after the zone lookup does not use the volume.canCopyOnPrimaryalready skips a missing volume, and with storage replicationaddStoragePoolsForCopyToPrimaryalready refuses one withCould not find volume of a snapshot.