Copilot commented on code in PR #14266:
URL: https://github.com/apache/cloudstack/pull/14266#discussion_r4280691461


##########
plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRestoreBackupCommandWrapper.java:
##########
@@ -431,19 +431,24 @@ private boolean attachRbdVolumeToVm(KVMStoragePoolManager 
storagePoolMgr, String
     }
 
     private String getDeviceToAttachDisk(String vmName) {
-        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" };
-        // The commands are executed without a shell, so the awk program must 
be passed as a plain
-        // argument. Keeping the quotes a shell would have stripped makes awk 
fail with
-        // "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);
+        // --details adds a Device column (disk/cdrom) that the awk below 
filters on ($2=="disk")
+        // to exclude cdrom slots. cdrom entries (hdc, hdd) are listed after 
the virtio disks in
+        // domblklist's output, so without this filter, taking the last line 
would select a
+        // cdrom, not the actual disk.
+        String[] domblkCmd = new String[] { 
Script.getExecutableAbsolutePath("virsh"), "domblklist", "--domain", vmName, 
"--details" };
+        // Only virtio (vd*) targets are used: IDE/SATA disks cannot be 
hot-plugged.
+        String[] awkCmd = new String[] { 
Script.getExecutableAbsolutePath("awk"), "$2==\"disk\" && $3 ~ /^vd/ {print 
$3}" };
+        String[] tailCmd = new String[] { 
Script.getExecutableAbsolutePath("tail"), "-n", "1" };
+        Pair<Integer, String> result = 
Script.executePipedCommands(Arrays.asList(domblkCmd, awkCmd, tailCmd), 0);

Review Comment:
   Spawning a separate `tail` process is avoidable here; you can have awk print 
only the last matching target (e.g., store `$3` per match and print it in an 
`END` block). This reduces process overhead and simplifies the pipeline while 
keeping the same behavior.



##########
plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRestoreBackupCommandWrapper.java:
##########
@@ -431,19 +431,24 @@ private boolean attachRbdVolumeToVm(KVMStoragePoolManager 
storagePoolMgr, String
     }
 
     private String getDeviceToAttachDisk(String vmName) {
-        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" };
-        // The commands are executed without a shell, so the awk program must 
be passed as a plain
-        // argument. Keeping the quotes a shell would have stripped makes awk 
fail with
-        // "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);
+        // --details adds a Device column (disk/cdrom) that the awk below 
filters on ($2=="disk")
+        // to exclude cdrom slots. cdrom entries (hdc, hdd) are listed after 
the virtio disks in
+        // domblklist's output, so without this filter, taking the last line 
would select a
+        // cdrom, not the actual disk.

Review Comment:
   The comment about CD-ROM entries being “listed after the virtio disks” 
appears inconsistent with the PR description (CD-ROM targets like `hdc`/`hdd` 
sort alphabetically ahead of `vd*`). This is misleading for future maintainers; 
please update the comment to describe the actual ordering issue (or avoid 
stating an ordering guarantee and focus on “filter out cdrom rows” as the core 
requirement).



##########
plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRestoreBackupCommandWrapper.java:
##########
@@ -431,19 +431,24 @@ private boolean attachRbdVolumeToVm(KVMStoragePoolManager 
storagePoolMgr, String
     }
 
     private String getDeviceToAttachDisk(String vmName) {
-        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" };
-        // The commands are executed without a shell, so the awk program must 
be passed as a plain
-        // argument. Keeping the quotes a shell would have stripped makes awk 
fail with
-        // "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);
+        // --details adds a Device column (disk/cdrom) that the awk below 
filters on ($2=="disk")
+        // to exclude cdrom slots. cdrom entries (hdc, hdd) are listed after 
the virtio disks in
+        // domblklist's output, so without this filter, taking the last line 
would select a
+        // cdrom, not the actual disk.
+        String[] domblkCmd = new String[] { 
Script.getExecutableAbsolutePath("virsh"), "domblklist", "--domain", vmName, 
"--details" };
+        // Only virtio (vd*) targets are used: IDE/SATA disks cannot be 
hot-plugged.
+        String[] awkCmd = new String[] { 
Script.getExecutableAbsolutePath("awk"), "$2==\"disk\" && $3 ~ /^vd/ {print 
$3}" };
+        String[] tailCmd = new String[] { 
Script.getExecutableAbsolutePath("tail"), "-n", "1" };
+        Pair<Integer, String> result = 
Script.executePipedCommands(Arrays.asList(domblkCmd, awkCmd, tailCmd), 0);
+        if (result.first() == null || result.first() != 0) {
+            throw new CloudRuntimeException(String.format("Failed to determine 
the device to attach the restored volume to on VM [%s].", vmName));
+        }
         // executePipedCommands appends a line separator to every line it 
reads, so the device
         // name has to be trimmed before the last character can be incremented.
         String currentDevice = result.second() == null ? "" : 
result.second().trim();
-        if (result.first() == null || result.first() != 0 || 
StringUtils.isBlank(currentDevice)) {
-            throw new CloudRuntimeException(String.format("Failed to determine 
the device to attach the restored volume to on VM [%s].", vmName));
+        if (StringUtils.isBlank(currentDevice)) {
+            // The VM has no virtio disk yet (e.g. only an IDE or SCSI root 
disk), so vda is free.
+            return "vda";
         }
         char lastChar = currentDevice.charAt(currentDevice.length() - 1);
         char incrementedChar = (char) (lastChar + 1);

Review Comment:
   Incrementing only the last character of the target breaks for boundary cases 
like `vdz` (would become `{`) and doesn’t handle multi-letter suffixes (`vdaa`, 
etc.). It can also skip free names if there are gaps (e.g., existing `vda` and 
`vdc` will choose `vdd` even though `vdb` is free). A more robust approach is 
to parse all existing `vd*` targets into a set and then pick the first free 
name from `vda` upward (including rollover past `vdz`), rather than 
incrementing the last character.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to