Skip to content

Commit 6f23a2d

Browse files
committed
properly point to the right source and destination volume paths during restore operation
1 parent fe764c0 commit 6f23a2d

File tree

5 files changed

+48
-40
lines changed

5 files changed

+48
-40
lines changed

core/src/main/java/org/apache/cloudstack/backup/RestoreBackupCommand.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,14 @@
2323
import com.cloud.agent.api.LogLevel;
2424
import com.cloud.vm.VirtualMachine;
2525

26-
import java.util.List;
26+
import java.util.Map;
2727

2828
public class RestoreBackupCommand extends Command {
2929
private String vmName;
3030
private String backupPath;
3131
private String backupRepoType;
3232
private String backupRepoAddress;
33-
private List<String> volumePaths;
33+
private Map<String, String> volumePathsAndUuids;
3434
private String diskType;
3535
private Boolean vmExists;
3636
private String restoreVolumeUUID;
@@ -72,12 +72,12 @@ public void setBackupRepoAddress(String backupRepoAddress) {
7272
this.backupRepoAddress = backupRepoAddress;
7373
}
7474

75-
public List<String> getVolumePaths() {
76-
return volumePaths;
75+
public Map<String, String> getVolumePathsAndUuids() {
76+
return volumePathsAndUuids;
7777
}
7878

79-
public void setVolumePaths(List<String> volumePaths) {
80-
this.volumePaths = volumePaths;
79+
public void setVolumePathsAndUuids(Map<String, String> volumePathsAndUuids) {
80+
this.volumePathsAndUuids = volumePathsAndUuids;
8181
}
8282

8383
public Boolean isVmExists() {

core/src/main/java/org/apache/cloudstack/backup/TakeBackupCommand.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@
2222
import com.cloud.agent.api.Command;
2323
import com.cloud.agent.api.LogLevel;
2424

25-
import java.util.List;
25+
import java.util.Map;
2626

2727
public class TakeBackupCommand extends Command {
2828
private String vmName;
2929
private String backupPath;
3030
private String backupRepoType;
3131
private String backupRepoAddress;
32-
private List<String> volumePaths;
32+
private Map<String, String> volumePathsAndUuids;
3333
@LogLevel(LogLevel.Log4jLevel.Off)
3434
private String mountOptions;
3535

@@ -79,12 +79,12 @@ public void setMountOptions(String mountOptions) {
7979
this.mountOptions = mountOptions;
8080
}
8181

82-
public List<String> getVolumePaths() {
83-
return volumePaths;
82+
public Map<String, String> getVolumePathsAndUuids() {
83+
return volumePathsAndUuids;
8484
}
8585

86-
public void setVolumePaths(List<String> volumePaths) {
87-
this.volumePaths = volumePaths;
86+
public void setVolumePathsAndUuids(Map<String, String> volumePathsAndUuids) {
87+
this.volumePathsAndUuids = volumePathsAndUuids;
8888
}
8989

9090
@Override

plugins/backup/nas/src/main/java/org/apache/cloudstack/backup/NASBackupProvider.java

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,8 @@ public boolean takeBackup(final VirtualMachine vm) {
164164
if (VirtualMachine.State.Stopped.equals(vm.getState())) {
165165
List<VolumeVO> vmVolumes = volumeDao.findByInstance(vm.getId());
166166
vmVolumes.sort(Comparator.comparing(Volume::getDeviceId));
167-
List<String> volumePaths = getVolumePaths(vmVolumes, Collections.emptyList());
168-
command.setVolumePaths(volumePaths);
167+
Map<String, String> volumePaths = getVolumePaths(vmVolumes, Collections.emptyList());
168+
command.setVolumePathsAndUuids(volumePaths);
169169
}
170170

171171
BackupAnswer answer = null;
@@ -229,7 +229,7 @@ public boolean restoreVMFromBackup(VirtualMachine vm, Backup backup) {
229229
restoreCommand.setBackupRepoAddress(backupRepository.getAddress());
230230
restoreCommand.setMountOptions(backupRepository.getMountOptions());
231231
restoreCommand.setVmName(vm.getName());
232-
restoreCommand.setVolumePaths(getVolumePaths(volumes, backedVolumes));
232+
restoreCommand.setVolumePathsAndUuids(getVolumePaths(volumes, backedVolumes));
233233
restoreCommand.setVmExists(vm.getRemoved() == null);
234234
restoreCommand.setVmState(vm.getState());
235235

@@ -244,8 +244,8 @@ public boolean restoreVMFromBackup(VirtualMachine vm, Backup backup) {
244244
return answer.getResult();
245245
}
246246

247-
private List<String> getVolumePaths(List<VolumeVO> volumes, List<Backup.VolumeInfo> backedVolumes) {
248-
List<String> volumePaths = new ArrayList<>();
247+
private Map<String, String> getVolumePaths(List<VolumeVO> volumes, List<Backup.VolumeInfo> backedVolumes) {
248+
Map<String, String> volumePaths = new HashMap<>();
249249
for (VolumeVO volume : volumes) {
250250
StoragePoolVO storagePool = primaryDataStoreDao.findById(volume.getPoolId());
251251
if (Objects.isNull(storagePool)) {
@@ -259,20 +259,25 @@ private List<String> getVolumePaths(List<VolumeVO> volumes, List<Backup.VolumeIn
259259
} else {
260260
volumePathPrefix = String.format("/mnt/%s", storagePool.getUuid());
261261
}
262+
// Build current volume path (destination for restore)
263+
String currentVolumePath = String.format("%s/%s", volumePathPrefix, volume.getPath());
264+
265+
// Find backed volume path (used for backup filename lookup)
266+
String backedVolumePath = volume.getPath();
262267
boolean hasBackedVolumes = backedVolumes != null && !backedVolumes.isEmpty();
263268
if (hasBackedVolumes) {
264269
Optional<Backup.VolumeInfo> opt = backedVolumes.stream()
265270
.filter(bv -> bv.getUuid().equals(volume.getUuid())).findFirst();
266271
if (opt.isPresent()) {
267272
Backup.VolumeInfo backedVolume = opt.get();
268273
if (backedVolume.getPath() != null && !backedVolume.getPath().isEmpty()) {
269-
volumePaths.add(String.format("%s/%s", volumePathPrefix, backedVolume.getPath()));
270-
continue;
274+
// Use the backed volume path (path at time of backup) for filename lookup
275+
backedVolumePath = backedVolume.getPath();
271276
}
272277
}
273278
}
274279

275-
volumePaths.add(String.format("%s/%s", volumePathPrefix, volume.getPath()));
280+
volumePaths.put(currentVolumePath, backedVolumePath);
276281
}
277282

278283
return volumePaths;
@@ -313,7 +318,7 @@ public Pair<Boolean, String> restoreBackedUpVolume(Backup backup, String volumeU
313318
restoreCommand.setBackupRepoType(backupRepository.getType());
314319
restoreCommand.setBackupRepoAddress(backupRepository.getAddress());
315320
restoreCommand.setVmName(vmNameAndState.first());
316-
restoreCommand.setVolumePaths(Collections.singletonList(String.format("%s/%s", dataStore.getLocalPath(), volumeUUID)));
321+
restoreCommand.setVolumePathsAndUuids(Collections.singletonMap(String.format("%s/%s", dataStore.getLocalPath(), volumeUUID), volumeUUID));
317322
restoreCommand.setDiskType(volume.getVolumeType().name().toLowerCase(Locale.ROOT));
318323
restoreCommand.setMountOptions(backupRepository.getMountOptions());
319324
restoreCommand.setVmExists(null);

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRestoreBackupCommandWrapper.java

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@
3535
import java.io.IOException;
3636
import java.nio.file.Files;
3737
import java.nio.file.Paths;
38-
import java.util.List;
3938
import java.util.Locale;
39+
import java.util.Map;
4040
import java.util.Objects;
4141

4242
@ResourceWrapper(handles = RestoreBackupCommand.class)
@@ -58,21 +58,22 @@ public Answer execute(RestoreBackupCommand command, LibvirtComputingResource ser
5858
String mountOptions = command.getMountOptions();
5959
Boolean vmExists = command.isVmExists();
6060
String diskType = command.getDiskType();
61-
List<String> volumePaths = command.getVolumePaths();
61+
Map<String, String> volumePathsAndUuids = command.getVolumePathsAndUuids();
6262
String restoreVolumeUuid = command.getRestoreVolumeUUID();
6363

6464
String newVolumeId = null;
6565
try {
6666
if (Objects.isNull(vmExists)) {
67-
String volumePath = volumePaths.get(0);
67+
Map.Entry<String, String> firstEntry = volumePathsAndUuids.entrySet().iterator().next();
68+
String volumePath = firstEntry.getKey();
6869
int lastIndex = volumePath.lastIndexOf("/");
6970
newVolumeId = volumePath.substring(lastIndex + 1);
7071
restoreVolume(backupPath, backupRepoType, backupRepoAddress, volumePath, diskType, restoreVolumeUuid,
7172
new Pair<>(vmName, command.getVmState()), mountOptions);
7273
} else if (Boolean.TRUE.equals(vmExists)) {
73-
restoreVolumesOfExistingVM(volumePaths, backupPath, backupRepoType, backupRepoAddress, mountOptions);
74+
restoreVolumesOfExistingVM(volumePathsAndUuids, backupPath, backupRepoType, backupRepoAddress, mountOptions);
7475
} else {
75-
restoreVolumesOfDestroyedVMs(volumePaths, vmName, backupPath, backupRepoType, backupRepoAddress, mountOptions);
76+
restoreVolumesOfDestroyedVMs(volumePathsAndUuids, vmName, backupPath, backupRepoType, backupRepoAddress, mountOptions);
7677
}
7778
} catch (CloudRuntimeException e) {
7879
String errorMessage = "Failed to restore backup for VM: " + vmName + ".";
@@ -86,16 +87,17 @@ public Answer execute(RestoreBackupCommand command, LibvirtComputingResource ser
8687
return new BackupAnswer(command, true, newVolumeId);
8788
}
8889

89-
private void restoreVolumesOfExistingVM(List<String> volumePaths, String backupPath,
90+
private void restoreVolumesOfExistingVM(Map<String,String> volumePaths, String backupPath,
9091
String backupRepoType, String backupRepoAddress, String mountOptions) {
9192
String diskType = "root";
9293
String mountDirectory = mountBackupDirectory(backupRepoAddress, backupRepoType, mountOptions);
9394
try {
94-
for (int idx = 0; idx < volumePaths.size(); idx++) {
95-
String volumePath = volumePaths.get(idx);
96-
Pair<String, String> bkpPathAndVolUuid = getBackupPath(mountDirectory, volumePath, backupPath, diskType, null);
95+
for (Map.Entry<String, String> entry : volumePaths.entrySet()) {
96+
String currentVolumePath = entry.getKey();
97+
String backedVolumePath = entry.getValue();
98+
Pair<String, String> bkpPathAndVolUuid = getBackupPath(mountDirectory, backedVolumePath, backupPath, diskType, null);
9799
diskType = "datadisk";
98-
if (!replaceVolumeWithBackup(volumePath, bkpPathAndVolUuid.first())) {
100+
if (!replaceVolumeWithBackup(currentVolumePath, bkpPathAndVolUuid.first())) {
99101
throw new CloudRuntimeException(String.format("Unable to restore backup for volume [%s].", bkpPathAndVolUuid.second()));
100102
}
101103
}
@@ -106,16 +108,17 @@ private void restoreVolumesOfExistingVM(List<String> volumePaths, String backupP
106108

107109
}
108110

109-
private void restoreVolumesOfDestroyedVMs(List<String> volumePaths, String vmName, String backupPath,
111+
private void restoreVolumesOfDestroyedVMs(Map<String, String> volumePaths, String vmName, String backupPath,
110112
String backupRepoType, String backupRepoAddress, String mountOptions) {
111113
String mountDirectory = mountBackupDirectory(backupRepoAddress, backupRepoType, mountOptions);
112114
String diskType = "root";
113115
try {
114-
for (int i = 0; i < volumePaths.size(); i++) {
115-
String volumePath = volumePaths.get(i);
116-
Pair<String, String> bkpPathAndVolUuid = getBackupPath(mountDirectory, volumePath, backupPath, diskType, null);
116+
for (Map.Entry<String, String> entry : volumePaths.entrySet()) {
117+
String currentVolumePath = entry.getKey();
118+
String backedVolumePath = entry.getValue();
119+
Pair<String, String> bkpPathAndVolUuid = getBackupPath(mountDirectory, backedVolumePath, backupPath, diskType, null);
117120
diskType = "datadisk";
118-
if (!replaceVolumeWithBackup(volumePath, bkpPathAndVolUuid.first())) {
121+
if (!replaceVolumeWithBackup(currentVolumePath, bkpPathAndVolUuid.first())) {
119122
throw new CloudRuntimeException(String.format("Unable to restore backup for volume [%s].", bkpPathAndVolUuid.second()));
120123
}
121124
}

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtTakeBackupCommandWrapper.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919

2020
package com.cloud.hypervisor.kvm.resource.wrapper;
2121

22-
import com.amazonaws.util.CollectionUtils;
2322
import com.cloud.agent.api.Answer;
2423
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
2524
import com.cloud.resource.CommandWrapper;
@@ -32,6 +31,7 @@
3231
import java.util.ArrayList;
3332
import java.util.Arrays;
3433
import java.util.List;
34+
import java.util.Map;
3535
import java.util.Objects;
3636

3737
@ResourceWrapper(handles = TakeBackupCommand.class)
@@ -43,7 +43,7 @@ public Answer execute(TakeBackupCommand command, LibvirtComputingResource libvir
4343
final String backupRepoType = command.getBackupRepoType();
4444
final String backupRepoAddress = command.getBackupRepoAddress();
4545
final String mountOptions = command.getMountOptions();
46-
final List<String> diskPaths = command.getVolumePaths();
46+
final Map<String, String> diskPathsAndUuids = command.getVolumePathsAndUuids();
4747

4848
List<String[]> commands = new ArrayList<>();
4949
commands.add(new String[]{
@@ -54,7 +54,7 @@ public Answer execute(TakeBackupCommand command, LibvirtComputingResource libvir
5454
"-s", backupRepoAddress,
5555
"-m", Objects.nonNull(mountOptions) ? mountOptions : "",
5656
"-p", backupPath,
57-
"-d", (Objects.nonNull(diskPaths) && !diskPaths.isEmpty()) ? String.join(",", diskPaths) : ""
57+
"-d", (Objects.nonNull(diskPathsAndUuids) && !diskPathsAndUuids.isEmpty()) ? String.join(",", diskPathsAndUuids.keySet()) : ""
5858
});
5959

6060
Pair<Integer, String> result = Script.executePipedCommands(commands, libvirtComputingResource.getCmdsTimeout());
@@ -65,7 +65,7 @@ public Answer execute(TakeBackupCommand command, LibvirtComputingResource libvir
6565
}
6666

6767
long backupSize = 0L;
68-
if (CollectionUtils.isNullOrEmpty(diskPaths)) {
68+
if (diskPathsAndUuids == null || diskPathsAndUuids.isEmpty()) {
6969
List<String> outputLines = Arrays.asList(result.second().trim().split("\n"));
7070
if (!outputLines.isEmpty()) {
7171
backupSize = Long.parseLong(outputLines.get(outputLines.size() - 1).trim());

0 commit comments

Comments
 (0)