mirror of https://github.com/apache/cloudstack.git
Fix issue when restoring backup after migration of volume (#12549)
This commit is contained in:
parent
d8230c9598
commit
ae5308bdd2
|
|
@ -31,9 +31,9 @@ public class RestoreBackupCommand extends Command {
|
|||
private String backupRepoType;
|
||||
private String backupRepoAddress;
|
||||
private List<String> volumePaths;
|
||||
private List<String> backupFiles;
|
||||
private String diskType;
|
||||
private Boolean vmExists;
|
||||
private String restoreVolumeUUID;
|
||||
private VirtualMachine.State vmState;
|
||||
|
||||
protected RestoreBackupCommand() {
|
||||
|
|
@ -80,6 +80,14 @@ public class RestoreBackupCommand extends Command {
|
|||
this.volumePaths = volumePaths;
|
||||
}
|
||||
|
||||
public List<String> getBackupFiles() {
|
||||
return backupFiles;
|
||||
}
|
||||
|
||||
public void setBackupFiles(List<String> backupFiles) {
|
||||
this.backupFiles = backupFiles;
|
||||
}
|
||||
|
||||
public Boolean isVmExists() {
|
||||
return vmExists;
|
||||
}
|
||||
|
|
@ -104,14 +112,6 @@ public class RestoreBackupCommand extends Command {
|
|||
this.mountOptions = mountOptions;
|
||||
}
|
||||
|
||||
public String getRestoreVolumeUUID() {
|
||||
return restoreVolumeUUID;
|
||||
}
|
||||
|
||||
public void setRestoreVolumeUUID(String restoreVolumeUUID) {
|
||||
this.restoreVolumeUUID = restoreVolumeUUID;
|
||||
}
|
||||
|
||||
public VirtualMachine.State getVmState() {
|
||||
return vmState;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@ import java.util.Locale;
|
|||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
|
@ -230,6 +229,7 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
|||
restoreCommand.setMountOptions(backupRepository.getMountOptions());
|
||||
restoreCommand.setVmName(vm.getName());
|
||||
restoreCommand.setVolumePaths(getVolumePaths(volumes));
|
||||
restoreCommand.setBackupFiles(getBackupFiles(backedVolumes));
|
||||
restoreCommand.setVmExists(vm.getRemoved() == null);
|
||||
restoreCommand.setVmState(vm.getState());
|
||||
|
||||
|
|
@ -244,6 +244,14 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
|||
return answer.getResult();
|
||||
}
|
||||
|
||||
private List<String> getBackupFiles(List<Backup.VolumeInfo> backedVolumes) {
|
||||
List<String> backupFiles = new ArrayList<>();
|
||||
for (Backup.VolumeInfo backedVolume : backedVolumes) {
|
||||
backupFiles.add(backedVolume.getPath());
|
||||
}
|
||||
return backupFiles;
|
||||
}
|
||||
|
||||
private List<String> getVolumePaths(List<VolumeVO> volumes) {
|
||||
List<String> volumePaths = new ArrayList<>();
|
||||
for (VolumeVO volume : volumes) {
|
||||
|
|
@ -271,8 +279,11 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
|||
final StoragePoolHostVO dataStore = storagePoolHostDao.findByUuid(dataStoreUuid);
|
||||
final HostVO hostVO = hostDao.findByIp(hostIp);
|
||||
|
||||
Optional<Backup.VolumeInfo> matchingVolume = getBackedUpVolumeInfo(backupSourceVm.getBackupVolumeList(), volumeUuid);
|
||||
Long backedUpVolumeSize = matchingVolume.isPresent() ? matchingVolume.get().getSize() : 0L;
|
||||
Backup.VolumeInfo matchingVolume = getBackedUpVolumeInfo(backup.getBackedUpVolumes(), volumeUuid);
|
||||
if (matchingVolume == null) {
|
||||
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));
|
||||
}
|
||||
Long backedUpVolumeSize = matchingVolume.getSize();
|
||||
|
||||
LOG.debug("Restoring vm volume {} from backup {} on the NAS Backup Provider", volume, backup);
|
||||
BackupRepository backupRepository = getBackupRepository(backupSourceVm, backup);
|
||||
|
|
@ -300,11 +311,11 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
|||
restoreCommand.setBackupRepoAddress(backupRepository.getAddress());
|
||||
restoreCommand.setVmName(vmNameAndState.first());
|
||||
restoreCommand.setVolumePaths(Collections.singletonList(String.format("%s/%s", dataStore.getLocalPath(), volumeUUID)));
|
||||
restoreCommand.setBackupFiles(Collections.singletonList(matchingVolume.getPath()));
|
||||
restoreCommand.setDiskType(volume.getVolumeType().name().toLowerCase(Locale.ROOT));
|
||||
restoreCommand.setMountOptions(backupRepository.getMountOptions());
|
||||
restoreCommand.setVmExists(null);
|
||||
restoreCommand.setVmState(vmNameAndState.second());
|
||||
restoreCommand.setRestoreVolumeUUID(volumeUuid);
|
||||
|
||||
BackupAnswer answer = null;
|
||||
try {
|
||||
|
|
@ -339,10 +350,11 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
|||
return backupRepository;
|
||||
}
|
||||
|
||||
private Optional<Backup.VolumeInfo> getBackedUpVolumeInfo(List<Backup.VolumeInfo> backedUpVolumes, String volumeUuid) {
|
||||
private Backup.VolumeInfo getBackedUpVolumeInfo(List<Backup.VolumeInfo> backedUpVolumes, String volumeUuid) {
|
||||
return backedUpVolumes.stream()
|
||||
.filter(v -> v.getUuid().equals(volumeUuid))
|
||||
.findFirst();
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ import org.apache.cloudstack.backup.BackupAnswer;
|
|||
import org.apache.cloudstack.backup.RestoreBackupCommand;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
|
@ -59,20 +58,21 @@ public class LibvirtRestoreBackupCommandWrapper extends CommandWrapper<RestoreBa
|
|||
Boolean vmExists = command.isVmExists();
|
||||
String diskType = command.getDiskType();
|
||||
List<String> volumePaths = command.getVolumePaths();
|
||||
String restoreVolumeUuid = command.getRestoreVolumeUUID();
|
||||
List<String> backupFiles = command.getBackupFiles();
|
||||
|
||||
String newVolumeId = null;
|
||||
try {
|
||||
if (Objects.isNull(vmExists)) {
|
||||
String volumePath = volumePaths.get(0);
|
||||
String backupFile = backupFiles.get(0);
|
||||
int lastIndex = volumePath.lastIndexOf("/");
|
||||
newVolumeId = volumePath.substring(lastIndex + 1);
|
||||
restoreVolume(backupPath, backupRepoType, backupRepoAddress, volumePath, diskType, restoreVolumeUuid,
|
||||
restoreVolume(backupPath, backupRepoType, backupRepoAddress, volumePath, diskType, backupFile,
|
||||
new Pair<>(vmName, command.getVmState()), mountOptions);
|
||||
} else if (Boolean.TRUE.equals(vmExists)) {
|
||||
restoreVolumesOfExistingVM(volumePaths, backupPath, backupRepoType, backupRepoAddress, mountOptions);
|
||||
restoreVolumesOfExistingVM(volumePaths, backupPath, backupFiles, backupRepoType, backupRepoAddress, mountOptions);
|
||||
} else {
|
||||
restoreVolumesOfDestroyedVMs(volumePaths, vmName, backupPath, backupRepoType, backupRepoAddress, mountOptions);
|
||||
restoreVolumesOfDestroyedVMs(volumePaths, vmName, backupPath, backupFiles, backupRepoType, backupRepoAddress, mountOptions);
|
||||
}
|
||||
} catch (CloudRuntimeException e) {
|
||||
String errorMessage = "Failed to restore backup for VM: " + vmName + ".";
|
||||
|
|
@ -86,17 +86,18 @@ public class LibvirtRestoreBackupCommandWrapper extends CommandWrapper<RestoreBa
|
|||
return new BackupAnswer(command, true, newVolumeId);
|
||||
}
|
||||
|
||||
private void restoreVolumesOfExistingVM(List<String> volumePaths, String backupPath,
|
||||
private void restoreVolumesOfExistingVM(List<String> volumePaths, String backupPath, List<String> backupFiles,
|
||||
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);
|
||||
String backupFile = backupFiles.get(idx);
|
||||
String bkpPath = getBackupPath(mountDirectory, backupPath, backupFile, diskType);
|
||||
diskType = "datadisk";
|
||||
if (!replaceVolumeWithBackup(volumePath, bkpPathAndVolUuid.first())) {
|
||||
throw new CloudRuntimeException(String.format("Unable to restore backup for volume [%s].", bkpPathAndVolUuid.second()));
|
||||
if (!replaceVolumeWithBackup(volumePath, bkpPath)) {
|
||||
throw new CloudRuntimeException(String.format("Unable to restore backup from volume [%s].", volumePath));
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
|
|
@ -106,17 +107,18 @@ public class LibvirtRestoreBackupCommandWrapper extends CommandWrapper<RestoreBa
|
|||
|
||||
}
|
||||
|
||||
private void restoreVolumesOfDestroyedVMs(List<String> volumePaths, String vmName, String backupPath,
|
||||
private void restoreVolumesOfDestroyedVMs(List<String> volumePaths, String vmName, String backupPath, List<String> backupFiles,
|
||||
String backupRepoType, String backupRepoAddress, String mountOptions) {
|
||||
String mountDirectory = mountBackupDirectory(backupRepoAddress, backupRepoType, mountOptions);
|
||||
String diskType = "root";
|
||||
try {
|
||||
for (int i = 0; i < volumePaths.size(); i++) {
|
||||
String volumePath = volumePaths.get(i);
|
||||
Pair<String, String> bkpPathAndVolUuid = getBackupPath(mountDirectory, volumePath, backupPath, diskType, null);
|
||||
for (int idx = 0; idx < volumePaths.size(); idx++) {
|
||||
String volumePath = volumePaths.get(idx);
|
||||
String backupFile = backupFiles.get(idx);
|
||||
String bkpPath = getBackupPath(mountDirectory, backupPath, backupFile, diskType);
|
||||
diskType = "datadisk";
|
||||
if (!replaceVolumeWithBackup(volumePath, bkpPathAndVolUuid.first())) {
|
||||
throw new CloudRuntimeException(String.format("Unable to restore backup for volume [%s].", bkpPathAndVolUuid.second()));
|
||||
if (!replaceVolumeWithBackup(volumePath, bkpPath)) {
|
||||
throw new CloudRuntimeException(String.format("Unable to restore backup from volume [%s].", volumePath));
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
|
|
@ -126,13 +128,13 @@ public class LibvirtRestoreBackupCommandWrapper extends CommandWrapper<RestoreBa
|
|||
}
|
||||
|
||||
private void restoreVolume(String backupPath, String backupRepoType, String backupRepoAddress, String volumePath,
|
||||
String diskType, String volumeUUID, Pair<String, VirtualMachine.State> vmNameAndState, String mountOptions) {
|
||||
String diskType, String backupFile, Pair<String, VirtualMachine.State> vmNameAndState, String mountOptions) {
|
||||
String mountDirectory = mountBackupDirectory(backupRepoAddress, backupRepoType, mountOptions);
|
||||
Pair<String, String> bkpPathAndVolUuid;
|
||||
String bkpPath;
|
||||
try {
|
||||
bkpPathAndVolUuid = getBackupPath(mountDirectory, volumePath, backupPath, diskType, volumeUUID);
|
||||
if (!replaceVolumeWithBackup(volumePath, bkpPathAndVolUuid.first())) {
|
||||
throw new CloudRuntimeException(String.format("Unable to restore backup for volume [%s].", bkpPathAndVolUuid.second()));
|
||||
bkpPath = getBackupPath(mountDirectory, backupPath, backupFile, diskType);
|
||||
if (!replaceVolumeWithBackup(volumePath, bkpPath)) {
|
||||
throw new CloudRuntimeException(String.format("Unable to restore backup from volume [%s].", volumePath));
|
||||
}
|
||||
if (VirtualMachine.State.Running.equals(vmNameAndState.second())) {
|
||||
if (!attachVolumeToVm(vmNameAndState.first(), volumePath)) {
|
||||
|
|
@ -188,13 +190,11 @@ public class LibvirtRestoreBackupCommandWrapper extends CommandWrapper<RestoreBa
|
|||
}
|
||||
}
|
||||
|
||||
private Pair<String, String> getBackupPath(String mountDirectory, String volumePath, String backupPath, String diskType, String volumeUuid) {
|
||||
private String getBackupPath(String mountDirectory, String backupPath, String backupFile, String diskType) {
|
||||
String bkpPath = String.format(FILE_PATH_PLACEHOLDER, mountDirectory, backupPath);
|
||||
int lastIndex = volumePath.lastIndexOf(File.separator);
|
||||
String volUuid = Objects.isNull(volumeUuid) ? volumePath.substring(lastIndex + 1) : volumeUuid;
|
||||
String backupFileName = String.format("%s.%s.qcow2", diskType.toLowerCase(Locale.ROOT), volUuid);
|
||||
String backupFileName = String.format("%s.%s.qcow2", diskType.toLowerCase(Locale.ROOT), backupFile);
|
||||
bkpPath = String.format(FILE_PATH_PLACEHOLDER, bkpPath, backupFileName);
|
||||
return new Pair<>(bkpPath, volUuid);
|
||||
return bkpPath;
|
||||
}
|
||||
|
||||
private boolean replaceVolumeWithBackup(String volumePath, String backupPath) {
|
||||
|
|
|
|||
|
|
@ -826,7 +826,7 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager {
|
|||
throw new CloudRuntimeException(String.format("Error restoring volume [%s] of VM [%s] to host [%s] using backup provider [%s] due to: [%s].",
|
||||
backedUpVolumeUuid, vm.getUuid(), host.getUuid(), backupProvider.getName(), result.second()));
|
||||
}
|
||||
if (!attachVolumeToVM(vm.getDataCenterId(), result.second(), vmFromBackup.getBackupVolumeList(),
|
||||
if (!attachVolumeToVM(vm.getDataCenterId(), result.second(), backup.getBackedUpVolumes(),
|
||||
backedUpVolumeUuid, vm, datastore.getUuid(), backup)) {
|
||||
throw new CloudRuntimeException(String.format("Error attaching volume [%s] to VM [%s]." + backedUpVolumeUuid, vm.getUuid()));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue