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


##########
core/src/main/java/org/apache/cloudstack/backup/TakeBackupCommand.java:
##########
@@ -22,14 +22,14 @@
 import com.cloud.agent.api.Command;
 import com.cloud.agent.api.LogLevel;
 
-import java.util.List;
+import java.util.Map;
 
 public class TakeBackupCommand extends Command {
     private String vmName;
     private String backupPath;
     private String backupRepoType;
     private String backupRepoAddress;
-    private List<String> volumePaths;
+    private Map<String, String> volumePathsAndUuids;
     @LogLevel(LogLevel.Log4jLevel.Off)

Review Comment:
   Changing the agent command payload from `volumePaths` (List) to 
`volumePathsAndUuids` (Map) is a wire-compatibility break for mixed-version 
management server/agent deployments: older agents will ignore the new field and 
see no disk paths for stopped-VM backups. If rolling upgrades are supported, 
keep the old field for backward compatibility (populate both, and have the 
agent wrapper fall back), or introduce a new Command class/versioned field.



##########
plugins/backup/nas/src/main/java/org/apache/cloudstack/backup/NASBackupProvider.java:
##########
@@ -244,8 +244,8 @@ public boolean restoreVMFromBackup(VirtualMachine vm, 
Backup backup) {
         return answer.getResult();
     }
 
-    private List<String> getVolumePaths(List<VolumeVO> volumes) {
-        List<String> volumePaths = new ArrayList<>();
+    private Map<String, String> getVolumePaths(List<VolumeVO> volumes, 
List<Backup.VolumeInfo> backedVolumes) {
+        Map<String, String> volumePaths = new HashMap<>();
         for (VolumeVO volume : volumes) {
             StoragePoolVO storagePool = 
primaryDataStoreDao.findById(volume.getPoolId());

Review Comment:
   `getVolumePaths` builds a `HashMap`, but both backup (nasbackup.sh) and 
restore logic rely on the first iterated disk being the ROOT volume (deviceId 
0). `HashMap` iteration order is undefined and can reorder volumes, causing 
root/datadisk filenames to be generated/looked up incorrectly. Use an 
insertion-ordered structure (e.g., `LinkedHashMap`) and ensure volumes are 
inserted in deviceId order (root first).



##########
core/src/main/java/org/apache/cloudstack/backup/RestoreBackupCommand.java:
##########
@@ -23,14 +23,14 @@
 import com.cloud.agent.api.LogLevel;
 import com.cloud.vm.VirtualMachine;
 
-import java.util.List;
+import java.util.Map;
 
 public class RestoreBackupCommand extends Command  {
     private String vmName;
     private String backupPath;
     private String backupRepoType;
     private String backupRepoAddress;
-    private List<String> volumePaths;
+    private Map<String, String> volumePathsAndUuids;
     private String diskType;

Review Comment:
   Changing the agent command payload from `volumePaths` (List) to 
`volumePathsAndUuids` (Map) breaks compatibility with older KVM agents during 
upgrades (they will ignore the new field and restore will have no volumes to 
process). If mixed-version operation is expected, consider keeping/populating 
the old field as a fallback or introducing a new Command class to version the 
contract.



##########
plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtTakeBackupCommandWrapper.java:
##########
@@ -54,7 +54,7 @@ public Answer execute(TakeBackupCommand command, 
LibvirtComputingResource libvir
                 "-s", backupRepoAddress,
                 "-m", Objects.nonNull(mountOptions) ? mountOptions : "",
                 "-p", backupPath,
-                "-d", (Objects.nonNull(diskPaths) && !diskPaths.isEmpty()) ? 
String.join(",", diskPaths) : ""
+                "-d", (Objects.nonNull(diskPathsAndUuids) && 
!diskPathsAndUuids.isEmpty()) ? String.join(",", diskPathsAndUuids.keySet()) : 
""
         });

Review Comment:
   The `-d` argument order controls whether nasbackup.sh names the first disk 
as `root.<uuid>.qcow2` and the rest as `datadisk.<uuid>.qcow2`. 
`String.join(",", diskPathsAndUuids.keySet())` inherits whatever iteration 
order the `Map` has, which can be non-deterministic and lead to misnamed 
backups. Ensure the disk paths are provided in a deterministic deviceId order 
(root first), e.g., by using an ordered collection or explicitly ordering 
before joining.



##########
core/src/main/java/org/apache/cloudstack/backup/RestoreBackupCommand.java:
##########
@@ -23,14 +23,14 @@
 import com.cloud.agent.api.LogLevel;
 import com.cloud.vm.VirtualMachine;
 
-import java.util.List;
+import java.util.Map;
 
 public class RestoreBackupCommand extends Command  {
     private String vmName;
     private String backupPath;
     private String backupRepoType;
     private String backupRepoAddress;
-    private List<String> volumePaths;
+    private Map<String, String> volumePathsAndUuids;
     private String diskType;

Review Comment:
   The name `volumePathsAndUuids` is misleading: the restore flow uses this as 
current volume path -> backed-up volume *path* (for filename lookup), not 
UUIDs. This ambiguity is part of the agent-command API surface and can easily 
cause future bugs. Consider renaming or documenting key/value meaning 
explicitly.



##########
plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRestoreBackupCommandWrapper.java:
##########
@@ -86,16 +87,17 @@ public Answer execute(RestoreBackupCommand command, 
LibvirtComputingResource ser
         return new BackupAnswer(command, true, newVolumeId);
     }
 
-    private void restoreVolumesOfExistingVM(List<String> volumePaths, String 
backupPath,
+    private void restoreVolumesOfExistingVM(Map<String,String> volumePaths, 
String backupPath,
                                              String backupRepoType, String 
backupRepoAddress, String mountOptions) {
         String diskType = "root";
         String mountDirectory = mountBackupDirectory(backupRepoAddress, 
backupRepoType, mountOptions);
         try {
-            for (int idx = 0; idx < volumePaths.size(); idx++) {
-                String volumePath = volumePaths.get(idx);
-                Pair<String, String> bkpPathAndVolUuid = 
getBackupPath(mountDirectory, volumePath, backupPath, diskType, null);
+            for (Map.Entry<String, String> entry : volumePaths.entrySet()) {
+                String currentVolumePath = entry.getKey();
+                String backedVolumePath = entry.getValue();
+                Pair<String, String> bkpPathAndVolUuid = 
getBackupPath(mountDirectory, backedVolumePath, backupPath, diskType, null);
                 diskType = "datadisk";
-                if (!replaceVolumeWithBackup(volumePath, 
bkpPathAndVolUuid.first())) {
+                if (!replaceVolumeWithBackup(currentVolumePath, 
bkpPathAndVolUuid.first())) {

Review Comment:
   `restoreVolumesOfExistingVM` derives `diskType` as `root` for the first 
iterated entry and `datadisk` for the rest. With a generic `Map`, entry 
iteration order is not guaranteed, so this can look for `root.<uuid>.qcow2` 
using a datadisk UUID (or vice versa) and fail restore. Pass an ordered 
collection (or explicit per-volume diskType/deviceId) so ROOT is handled 
deterministically.



##########
core/src/main/java/org/apache/cloudstack/backup/TakeBackupCommand.java:
##########
@@ -22,14 +22,14 @@
 import com.cloud.agent.api.Command;
 import com.cloud.agent.api.LogLevel;
 
-import java.util.List;
+import java.util.Map;
 
 public class TakeBackupCommand extends Command {
     private String vmName;
     private String backupPath;
     private String backupRepoType;
     private String backupRepoAddress;
-    private List<String> volumePaths;
+    private Map<String, String> volumePathsAndUuids;
     @LogLevel(LogLevel.Log4jLevel.Off)

Review Comment:
   The name `volumePathsAndUuids` is misleading: current usage passes a mapping 
of current volume path -> backed-up volume *path* (used for backup filename 
lookup), not UUIDs. This makes the command contract easy to misuse. Consider 
renaming to reflect semantics or add Javadoc clarifying what the map key/value 
represent.



-- 
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