Skip to content

kvm: fix restore-attach picking a CD-ROM slot as the target device (NAS backup) - #14266

Open
slavkap wants to merge 2 commits into
apache:mainfrom
storpool:fix-restore-and-attach-datadisk
Open

slavkap wants to merge 2 commits into
apache:mainfrom
storpool:fix-restore-and-attach-datadisk

Conversation

@slavkap

@slavkap slavkap commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

Description

Problem

Restoring a single volume from backup and hot-attaching it to a running KVM VM (restoreVolumeFromBackupAndAttachToVM) fails, regardless of the volume's storage type (NFS, StorPool, RBD, LINSTOR).

####Root cause

getDeviceToAttachDisk() picks the target device name via:
virsh domblklist --domain <vm> | tail -n 3 | head -n 1 | awk '{print $1}'

This returns the third-from-last line, not the last one — it "works" only by coincidence. Every CloudStack KVM VM has two pre-allocated, empty CD-ROM drives (hdc, hdd, added by #13101) that sort alphabetically ahead of the real (virtio) disks, so the pipeline picks up a CD-ROM (or an already-attached disk, depending on disk count) instead of computing a truly free name. virsh attach-disk then rejects the bogus/duplicate target.

Fix

Add --details to domblklist and filter to Type == "disk" rows before picking the last one, so CD-ROMs are never selected.

Types of changes

  • Breaking change (fix or feature that would cause existing functionality to change)
  • New feature (non-breaking change which adds functionality)
  • Bug fix (non-breaking change which fixes an issue)
  • Enhancement (improves an existing feature and functionality)
  • Cleanup (Code refactoring and cleanup, that may add test cases)
  • Build/CI
  • Test (unit or integration test code)

Bug Severity

  • BLOCKER
  • Critical
  • Major
  • Minor
  • Trivial

Screenshots (if appropriate):

How Has This Been Tested?

Manually tested with NFS and StorPool as a primary storage

  getDeviceToAttachDisk found the next free disk device by piping
  `virsh domblklist` through `tail -n 3 | head -n 1`, just grabbing a
  row by position without checking what device it actually was.
  domblklist sorts targets alphabetically, so a VM's empty IDE cdrom
  slots can sort after the real disks and get picked up instead —
  e.g. selecting hdc and incrementing it to hdd, an already-existing
  IDE target, instead of the next free virtio disk. This made
  hot-attaching a restored volume to a running VM fail with virsh
  attach-disk erroring out on the bogus target.

  This surfaced after apache#13101 ("Multiple CD-ROM / ISO Support Per VM"),
  which pre-allocates a second empty cdrom slot (hdc, hdd) at boot for
  every VM. With two cdrom rows now sorting ahead of the VM's disks,
  the tail/head window shifted enough to land on a cdrom row instead
  of a real disk — before that change, a single cdrom slot didn't push
  the window that far.

  Add --details to domblklist and filter to rows with Type=="disk"
  before taking the last one, so cdrom slots are excluded and the
  device name is always derived from an actual disk.
Copilot AI balanced review requested due to automatic review settings September 29, 2026 13:22
@codecov

codecov Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 19.91%. Comparing base (510d0ec) to head (c737927).

Additional details and impacted files
@@            Coverage Diff            @@
##               main   #14266   +/-   ##
=========================================
  Coverage     19.91%   19.91%           
- Complexity    20194    20200    +6     
=========================================
  Files          6373     6373           
  Lines        577230   577229    -1     
  Branches      70696    70696           
=========================================
+ Hits         114942   114960   +18     
+ Misses       449722   449700   -22     
- Partials      12566    12569    +3     
Flag Coverage Δ
uitests 3.71% <ø> (ø)
unittests 21.18% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Copilot review overview

Review effort: Lite
Findings: 1 Medium severity · 2 Low severity

Open (3)
What changed in this PR

Fixes KVM restore+hot-attach by ensuring the next target device name is computed from actual disks (excluding CD-ROM slots) when parsing virsh domblklist output.

Changes:

  • Update getDeviceToAttachDisk() to call virsh domblklist --details and filter rows where Device == disk.
  • Adjust existing unit test to match the updated piped command ordering and awk program.
  • Add a unit test asserting --details is requested.
File Description
plugins/​hypervisors/​kvm/​src/​main/​java/​com/​cloud/​hypervisor/​kvm/​resource/​wrapper/​LibvirtRestoreBackupCommandWrapper.java Fixes device selection logic by filtering domblklist output to disk devices only.
plugins/​hypervisors/​kvm/​src/​test/​java/​com/​cloud/​hypervisor/​kvm/​resource/​wrapper/​LibvirtRestoreBackupCommandWrapperTest.java Updates/extends tests to validate the new domblklist --details + awk filtering behavior.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Copilot AI review requested due to automatic review settings September 29, 2026 15:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// --details adds a Type column so cdrom slots (hdc, hdd) can be filtered out — they sort
// alphabetically ahead of virtio disks, so without this the selected row is a cdrom, not
// an actual disk.
String[] domblkCmd = new String[] { Script.getExecutableAbsolutePath("virsh"), "domblklist", "--domain", vmName, "--details" };
// "invalid char" and produce no output.
String[] awkCmd = new String[] { Script.getExecutableAbsolutePath("awk"), "{print $1}" };
Pair<Integer, String> result = Script.executePipedCommands(Arrays.asList(domblkCmd, tailCmd, headCmd, awkCmd), 0);
String[] awkCmd = new String[] { Script.getExecutableAbsolutePath("awk"), "$2==\"disk\"{print $3}" };
// The commands are executed without a shell, so the program must carry no shell quotes.
Assert.assertEquals("awk", awkCmd[0]);
Assert.assertEquals("{print $1}", awkCmd[1]);
Assert.assertEquals("$2==\"disk\"{print $3}", awkCmd[1]);
String[] domblkCmd = new String[] { Script.getExecutableAbsolutePath("virsh"), "domblklist", "--domain", vmName };
String[] tailCmd = new String[] { Script.getExecutableAbsolutePath("tail"), "-n", "3" };
String[] headCmd = new String[] { Script.getExecutableAbsolutePath("head"), "-n", "1" };
// --details adds a Type column so cdrom slots (hdc, hdd) can be filtered out — they sort

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment here is not right. --details doesn't change the ordering in any way:


[root@ref-trl-12455-k-Mr9-abhisar-sinha-kvm1 ~]# virsh  domblklist --domain  i-2-5-VM --details
 Type   Device   Target   Source
----------------------------------------------------------------------------------------------------------
 file   disk     vda      /mnt/eaae5267-a60a-369d-a4da-a13db16e3aa2/250bd073-3a2c-4875-9ba0-29bf632801b7
 file   disk     vdb      /mnt/eaae5267-a60a-369d-a4da-a13db16e3aa2/6f259e43-74a5-461e-b857-e945bcff7b45
 file   disk     vdc      /mnt/eaae5267-a60a-369d-a4da-a13db16e3aa2/bca15b84-3acf-4b1d-8466-3866e563c21f
 file   cdrom    hdc      -
 file   cdrom    hdd      -

[root@ref-trl-12455-k-Mr9-abhisar-sinha-kvm1 ~]# virsh  domblklist --domain  i-2-5-VM 
 Target   Source
------------------------------------------------------------------------------------------
 vda      /mnt/eaae5267-a60a-369d-a4da-a13db16e3aa2/250bd073-3a2c-4875-9ba0-29bf632801b7
 vdb      /mnt/eaae5267-a60a-369d-a4da-a13db16e3aa2/6f259e43-74a5-461e-b857-e945bcff7b45
 vdc      /mnt/eaae5267-a60a-369d-a4da-a13db16e3aa2/bca15b84-3acf-4b1d-8466-3866e563c21f
 hdc      -
 hdd      -

[root@ref-trl-12455-k-Mr9-abhisar-sinha-kvm1 ~]# 

--details does add the type Device column (not Type) which awk $2==\"disk\" uses to filter by type.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants