Skip to content

Commit eae78c1

Browse files
Pearl1594dhslove
authored andcommitted
Fix issue when restoring backup after migration of volume (apache#12549)
1 parent 5cef8e9 commit eae78c1

4 files changed

Lines changed: 90 additions & 61 deletions

File tree

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

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,10 @@ public class RestoreBackupCommand extends Command {
3434
private List<String> backupVolumesUUIDs;
3535
private List<PrimaryDataStoreTO> restoreVolumePools;
3636
private List<String> restoreVolumePaths;
37+
private List<String> volumePaths;
38+
private List<String> backupFiles;
3739
private String diskType;
3840
private Boolean vmExists;
39-
private String restoreVolumeUUID;
4041
private VirtualMachine.State vmState;
4142
private Integer mountTimeout;
4243
private String cacheMode;
@@ -93,6 +94,14 @@ public void setRestoreVolumePaths(List<String> restoreVolumePaths) {
9394
this.restoreVolumePaths = restoreVolumePaths;
9495
}
9596

97+
public List<String> getBackupFiles() {
98+
return backupFiles;
99+
}
100+
101+
public void setBackupFiles(List<String> backupFiles) {
102+
this.backupFiles = backupFiles;
103+
}
104+
96105
public Boolean isVmExists() {
97106
return vmExists;
98107
}
@@ -117,14 +126,6 @@ public void setMountOptions(String mountOptions) {
117126
this.mountOptions = mountOptions;
118127
}
119128

120-
public String getRestoreVolumeUUID() {
121-
return restoreVolumeUUID;
122-
}
123-
124-
public void setRestoreVolumeUUID(String restoreVolumeUUID) {
125-
this.restoreVolumeUUID = restoreVolumeUUID;
126-
}
127-
128129
public VirtualMachine.State getVmState() {
129130
return vmState;
130131
}

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

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@
7272
import java.util.Locale;
7373
import java.util.Map;
7474
import java.util.Objects;
75-
import java.util.Optional;
7675
import java.util.UUID;
7776
import java.util.stream.Collectors;
7877

@@ -322,6 +321,8 @@ private Pair<Boolean, String> restoreVMBackup(VirtualMachine vm, Backup backup)
322321
Pair<List<PrimaryDataStoreTO>, List<String>> volumePoolsAndPaths = getVolumePoolsAndPaths(restoreVolumes);
323322
restoreCommand.setRestoreVolumePools(volumePoolsAndPaths.first());
324323
restoreCommand.setRestoreVolumePaths(volumePoolsAndPaths.second());
324+
restoreCommand.setVolumePaths(getVolumePaths(volumes));
325+
restoreCommand.setBackupFiles(getBackupFiles(backedVolumes));
325326
restoreCommand.setVmExists(vm.getRemoved() == null);
326327
restoreCommand.setVmState(vm.getState());
327328
restoreCommand.setMountTimeout(NASBackupRestoreMountTimeout.value());
@@ -337,8 +338,36 @@ private Pair<Boolean, String> restoreVMBackup(VirtualMachine vm, Backup backup)
337338
return new Pair<>(answer.getResult(), answer.getDetails());
338339
}
339340

341+
private List<String> getBackupFiles(List<Backup.VolumeInfo> backedVolumes) {
342+
List<String> backupFiles = new ArrayList<>();
343+
for (Backup.VolumeInfo backedVolume : backedVolumes) {
344+
backupFiles.add(backedVolume.getPath());
345+
}
346+
return backupFiles;
347+
}
348+
349+
private List<String> getVolumePaths(List<VolumeVO> volumes) {
350+
List<String> volumePaths = new ArrayList<>();
351+
for (VolumeVO volume : volumes) {
352+
StoragePoolVO storagePool = primaryDataStoreDao.findById(volume.getPoolId());
353+
if (Objects.isNull(storagePool)) {
354+
throw new CloudRuntimeException("Unable to find storage pool associated to the volume");
355+
}
356+
String volumePathPrefix;
357+
if (ScopeType.HOST.equals(storagePool.getScope())) {
358+
volumePathPrefix = storagePool.getPath();
359+
} else if (Storage.StoragePoolType.SharedMountPoint.equals(storagePool.getPoolType())) {
360+
volumePathPrefix = storagePool.getPath();
361+
} else {
362+
volumePathPrefix = String.format("/mnt/%s", storagePool.getUuid());
363+
}
364+
volumePaths.add(String.format("%s/%s", volumePathPrefix, volume.getPath()));
365+
}
366+
return volumePaths;
367+
}
368+
340369
private Pair<List<PrimaryDataStoreTO>, List<String>> getVolumePoolsAndPaths(List<VolumeVO> volumes) {
341-
List<PrimaryDataStoreTO> volumePools = new ArrayList<>();
370+
List<PrimaryDataStoreTO> volumePools = new ArrayList<>();
342371
List<String> volumePaths = new ArrayList<>();
343372
for (VolumeVO volume : volumes) {
344373
StoragePoolVO storagePool = primaryDataStoreDao.findById(volume.getPoolId());
@@ -385,8 +414,14 @@ public Pair<Boolean, String> restoreBackedUpVolume(Backup backup, Backup.VolumeI
385414
final StoragePoolVO pool = primaryDataStoreDao.findByUuid(dataStoreUuid);
386415
final HostVO hostVO = hostDao.findByIp(hostIp);
387416

388-
LOG.debug("Restoring vm volume {} from backup {} on the NAS Backup Provider", backupVolumeInfo, backup);
389-
BackupRepository backupRepository = getBackupRepository(backup);
417+
Backup.VolumeInfo matchingVolume = getBackedUpVolumeInfo(backup.getBackedUpVolumes(), volumeUuid);
418+
if (matchingVolume == null) {
419+
throw new CloudRuntimeException(String.format("Unable to find volume %s in the list of backed up volumes for backup %s, cannot proceed with restore", volumeUuid, backup));
420+
}
421+
Long backedUpVolumeSize = matchingVolume.getSize();
422+
423+
LOG.debug("Restoring vm volume {} from backup {} on the NAS Backup Provider", volume, backup);
424+
BackupRepository backupRepository = getBackupRepository(backupSourceVm, backup);
390425

391426
VolumeVO restoredVolume = new VolumeVO(Volume.Type.DATADISK, null, backup.getZoneId(),
392427
backup.getDomainId(), backup.getAccountId(), 0, null,
@@ -426,6 +461,8 @@ public Pair<Boolean, String> restoreBackedUpVolume(Backup backup, Backup.VolumeI
426461
restoreCommand.setRestoreVolumeUUID(backupVolumeInfo.getUuid());
427462
restoreCommand.setMountTimeout(NASBackupRestoreMountTimeout.value());
428463
restoreCommand.setCacheMode(cacheMode);
464+
restoreCommand.setVolumePaths(Collections.singletonList(String.format("%s/%s", dataStore.getLocalPath(), volumeUUID)));
465+
restoreCommand.setBackupFiles(Collections.singletonList(matchingVolume.getPath()));
429466

430467
BackupAnswer answer;
431468
try {
@@ -455,10 +492,11 @@ private BackupRepository getBackupRepository(Backup backup) {
455492
return backupRepository;
456493
}
457494

458-
private Optional<Backup.VolumeInfo> getBackedUpVolumeInfo(List<Backup.VolumeInfo> backedUpVolumes, String volumeUuid) {
495+
private Backup.VolumeInfo getBackedUpVolumeInfo(List<Backup.VolumeInfo> backedUpVolumes, String volumeUuid) {
459496
return backedUpVolumes.stream()
460497
.filter(v -> v.getUuid().equals(volumeUuid))
461-
.findFirst();
498+
.findFirst()
499+
.orElse(null);
462500
}
463501

464502
@Override

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

Lines changed: 35 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
import org.apache.commons.lang3.StringUtils;
4242
import org.libvirt.LibvirtException;
4343

44-
import java.io.File;
4544
import java.io.IOException;
4645
import java.nio.file.Files;
4746
import java.nio.file.Paths;
@@ -77,21 +76,23 @@ public Answer execute(RestoreBackupCommand command, LibvirtComputingResource ser
7776
int timeout = command.getWait();
7877
String cacheMode = command.getCacheMode();
7978
KVMStoragePoolManager storagePoolMgr = serverResource.getStoragePoolMgr();
79+
List<String> volumePaths = command.getVolumePaths();
80+
List<String> backupFiles = command.getBackupFiles();
8081

8182
String newVolumeId = null;
8283
try {
8384
String mountDirectory = mountBackupDirectory(backupRepoAddress, backupRepoType, mountOptions, mountTimeout);
8485
if (Objects.isNull(vmExists)) {
85-
PrimaryDataStoreTO volumePool = restoreVolumePools.get(0);
86-
String volumePath = restoreVolumePaths.get(0);
86+
String volumePath = volumePaths.get(0);
87+
String backupFile = backupFiles.get(0);
8788
int lastIndex = volumePath.lastIndexOf("/");
8889
newVolumeId = volumePath.substring(lastIndex + 1);
89-
restoreVolume(storagePoolMgr, backupPath, volumePool, volumePath, diskType, restoreVolumeUuid,
90-
new Pair<>(vmName, command.getVmState()), mountDirectory, timeout, cacheMode);
90+
restoreVolume(backupPath, backupRepoType, backupRepoAddress, volumePath, diskType, backupFile,
91+
new Pair<>(vmName, command.getVmState()), mountOptions);
9192
} else if (Boolean.TRUE.equals(vmExists)) {
92-
restoreVolumesOfExistingVM(storagePoolMgr, restoreVolumePools, restoreVolumePaths, backedVolumeUUIDs, backupPath, mountDirectory, timeout);
93+
restoreVolumesOfExistingVM(volumePaths, backupPath, backupFiles, backupRepoType, backupRepoAddress, mountOptions);
9394
} else {
94-
restoreVolumesOfDestroyedVMs(storagePoolMgr, restoreVolumePools, restoreVolumePaths, vmName, backupPath, mountDirectory, timeout);
95+
restoreVolumesOfDestroyedVMs(volumePaths, vmName, backupPath, backupFiles, backupRepoType, backupRepoAddress, mountOptions);
9596
}
9697
} catch (CloudRuntimeException e) {
9798
String errorMessage = e.getMessage() != null ? e.getMessage() : "";
@@ -101,28 +102,17 @@ public Answer execute(RestoreBackupCommand command, LibvirtComputingResource ser
101102
return new BackupAnswer(command, true, newVolumeId);
102103
}
103104

104-
private void verifyBackupFile(String backupPath, String volUuid) {
105-
if (!checkBackupPathExists(backupPath)) {
106-
throw new CloudRuntimeException(String.format("Backup file for the volume [%s] does not exist.", volUuid));
107-
}
108-
if (!checkBackupFileImage(backupPath)) {
109-
throw new CloudRuntimeException(String.format("Backup qcow2 file for the volume [%s] is corrupt.", volUuid));
110-
}
111-
}
112-
113-
private void restoreVolumesOfExistingVM(KVMStoragePoolManager storagePoolMgr, List<PrimaryDataStoreTO> restoreVolumePools, List<String> restoreVolumePaths, List<String> backedVolumesUUIDs,
114-
String backupPath, String mountDirectory, int timeout) {
105+
private void restoreVolumesOfExistingVM(List<String> volumePaths, String backupPath, List<String> backupFiles,
106+
String backupRepoType, String backupRepoAddress, String mountOptions) {
115107
String diskType = "root";
116108
try {
117-
for (int idx = 0; idx < restoreVolumePaths.size(); idx++) {
118-
PrimaryDataStoreTO restoreVolumePool = restoreVolumePools.get(idx);
119-
String restoreVolumePath = restoreVolumePaths.get(idx);
120-
String backupVolumeUuid = backedVolumesUUIDs.get(idx);
121-
Pair<String, String> bkpPathAndVolUuid = getBackupPath(mountDirectory, null, backupPath, diskType, backupVolumeUuid);
109+
for (int idx = 0; idx < volumePaths.size(); idx++) {
110+
String volumePath = volumePaths.get(idx);
111+
String backupFile = backupFiles.get(idx);
112+
String bkpPath = getBackupPath(mountDirectory, backupPath, backupFile, diskType);
122113
diskType = "datadisk";
123-
verifyBackupFile(bkpPathAndVolUuid.first(), bkpPathAndVolUuid.second());
124-
if (!replaceVolumeWithBackup(storagePoolMgr, restoreVolumePool, restoreVolumePath, bkpPathAndVolUuid.first(), timeout)) {
125-
throw new CloudRuntimeException(String.format("Unable to restore contents from the backup volume [%s].", bkpPathAndVolUuid.second()));
114+
if (!replaceVolumeWithBackup(volumePath, bkpPath)) {
115+
throw new CloudRuntimeException(String.format("Unable to restore backup from volume [%s].", volumePath));
126116
}
127117
}
128118
} finally {
@@ -131,17 +121,18 @@ private void restoreVolumesOfExistingVM(KVMStoragePoolManager storagePoolMgr, Li
131121
}
132122
}
133123

134-
private void restoreVolumesOfDestroyedVMs(KVMStoragePoolManager storagePoolMgr, List<PrimaryDataStoreTO> volumePools, List<String> volumePaths, String vmName, String backupPath, String mountDirectory, int timeout) {
124+
private void restoreVolumesOfDestroyedVMs(List<String> volumePaths, String vmName, String backupPath, List<String> backupFiles,
125+
String backupRepoType, String backupRepoAddress, String mountOptions) {
126+
String mountDirectory = mountBackupDirectory(backupRepoAddress, backupRepoType, mountOptions);
135127
String diskType = "root";
136128
try {
137-
for (int i = 0; i < volumePaths.size(); i++) {
138-
PrimaryDataStoreTO volumePool = volumePools.get(i);
139-
String volumePath = volumePaths.get(i);
140-
Pair<String, String> bkpPathAndVolUuid = getBackupPath(mountDirectory, volumePath, backupPath, diskType, null);
129+
for (int idx = 0; idx < volumePaths.size(); idx++) {
130+
String volumePath = volumePaths.get(idx);
131+
String backupFile = backupFiles.get(idx);
132+
String bkpPath = getBackupPath(mountDirectory, backupPath, backupFile, diskType);
141133
diskType = "datadisk";
142-
verifyBackupFile(bkpPathAndVolUuid.first(), bkpPathAndVolUuid.second());
143-
if (!replaceVolumeWithBackup(storagePoolMgr, volumePool, volumePath, bkpPathAndVolUuid.first(), timeout)) {
144-
throw new CloudRuntimeException(String.format("Unable to restore contents from the backup volume [%s].", bkpPathAndVolUuid.second()));
134+
if (!replaceVolumeWithBackup(volumePath, bkpPath)) {
135+
throw new CloudRuntimeException(String.format("Unable to restore backup from volume [%s].", volumePath));
145136
}
146137
}
147138
} finally {
@@ -150,14 +141,14 @@ private void restoreVolumesOfDestroyedVMs(KVMStoragePoolManager storagePoolMgr,
150141
}
151142
}
152143

153-
private void restoreVolume(KVMStoragePoolManager storagePoolMgr, String backupPath, PrimaryDataStoreTO volumePool, String volumePath, String diskType, String volumeUUID,
154-
Pair<String, VirtualMachine.State> vmNameAndState, String mountDirectory, int timeout, String cacheMode) {
155-
Pair<String, String> bkpPathAndVolUuid;
144+
private void restoreVolume(String backupPath, String backupRepoType, String backupRepoAddress, String volumePath,
145+
String diskType, String backupFile, Pair<String, VirtualMachine.State> vmNameAndState, String mountOptions) {
146+
String mountDirectory = mountBackupDirectory(backupRepoAddress, backupRepoType, mountOptions);
147+
String bkpPath;
156148
try {
157-
bkpPathAndVolUuid = getBackupPath(mountDirectory, volumePath, backupPath, diskType, volumeUUID);
158-
verifyBackupFile(bkpPathAndVolUuid.first(), bkpPathAndVolUuid.second());
159-
if (!replaceVolumeWithBackup(storagePoolMgr, volumePool, volumePath, bkpPathAndVolUuid.first(), timeout, true)) {
160-
throw new CloudRuntimeException(String.format("Unable to restore contents from the backup volume [%s].", bkpPathAndVolUuid.second()));
149+
bkpPath = getBackupPath(mountDirectory, backupPath, backupFile, diskType);
150+
if (!replaceVolumeWithBackup(volumePath, bkpPath)) {
151+
throw new CloudRuntimeException(String.format("Unable to restore backup from volume [%s].", volumePath));
161152
}
162153
if (VirtualMachine.State.Running.equals(vmNameAndState.second())) {
163154
if (!attachVolumeToVm(storagePoolMgr, vmNameAndState.first(), volumePool, volumePath, cacheMode)) {
@@ -220,12 +211,11 @@ private void deleteTemporaryDirectory(String backupDirectory) {
220211
}
221212
}
222213

223-
private Pair<String, String> getBackupPath(String mountDirectory, String volumePath, String backupPath, String diskType, String volumeUuid) {
214+
private String getBackupPath(String mountDirectory, String backupPath, String backupFile, String diskType) {
224215
String bkpPath = String.format(FILE_PATH_PLACEHOLDER, mountDirectory, backupPath);
225-
String volUuid = Objects.isNull(volumeUuid) ? volumePath.substring(volumePath.lastIndexOf(File.separator) + 1) : volumeUuid;
226-
String backupFileName = String.format("%s.%s.qcow2", diskType.toLowerCase(Locale.ROOT), volUuid);
216+
String backupFileName = String.format("%s.%s.qcow2", diskType.toLowerCase(Locale.ROOT), backupFile);
227217
bkpPath = String.format(FILE_PATH_PLACEHOLDER, bkpPath, backupFileName);
228-
return new Pair<>(bkpPath, volUuid);
218+
return bkpPath;
229219
}
230220

231221
private boolean checkBackupFileImage(String backupPath) {

server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1598,7 +1598,7 @@ public boolean restoreBackupVolumeAndAttachToVM(final String backedUpVolumeUuid,
15981598
throw new CloudRuntimeException(String.format("Error restoring volume [%s] of VM [%s] to host [%s] using backup provider [%s] due to: [%s].",
15991599
backedUpVolumeUuid, vm.getUuid(), host.getUuid(), backupProvider.getName(), result.second()));
16001600
}
1601-
if (!attachVolumeToVM(vm.getDataCenterId(), result.second(), backupVolumeInfo,
1601+
if (!attachVolumeToVM(vm.getDataCenterId(), result.second(), backup.getBackedUpVolumes(),
16021602
backedUpVolumeUuid, vm, datastore.getUuid(), backup)) {
16031603
throw new CloudRuntimeException(String.format("Error attaching volume [%s] to VM [%s].", backedUpVolumeUuid, vm.getUuid()));
16041604
}

0 commit comments

Comments
 (0)