From 369023bd878dc90d36f3fe64bc10667a9868c080 Mon Sep 17 00:00:00 2001 From: Abhisar Sinha <63767682+abh1sar@users.noreply.github.com> Date: Mon, 6 Apr 2026 17:15:37 +0530 Subject: [PATCH 1/3] Introduce configurable timeout to Create NAS backup --- .../org/apache/cloudstack/backup/TakeBackupCommand.java | 9 +++++++++ .../org/apache/cloudstack/backup/NASBackupProvider.java | 8 ++++++++ .../wrapper/LibvirtTakeBackupCommandWrapper.java | 3 ++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/apache/cloudstack/backup/TakeBackupCommand.java b/core/src/main/java/org/apache/cloudstack/backup/TakeBackupCommand.java index 5402b6b24760..d93ccc621024 100644 --- a/core/src/main/java/org/apache/cloudstack/backup/TakeBackupCommand.java +++ b/core/src/main/java/org/apache/cloudstack/backup/TakeBackupCommand.java @@ -35,6 +35,7 @@ public class TakeBackupCommand extends Command { private Boolean quiesce; @LogLevel(LogLevel.Log4jLevel.Off) private String mountOptions; + private Integer timeout; public TakeBackupCommand(String vmName, String backupPath) { super(); @@ -106,6 +107,14 @@ public void setQuiesce(Boolean quiesce) { this.quiesce = quiesce; } + public Integer getTimeout() { + return this.timeout == null ? 0 : this.timeout; + } + + public void setTimeout(Integer timeout) { + this.timeout = timeout; + } + @Override public boolean executeInSequence() { return true; diff --git a/plugins/backup/nas/src/main/java/org/apache/cloudstack/backup/NASBackupProvider.java b/plugins/backup/nas/src/main/java/org/apache/cloudstack/backup/NASBackupProvider.java index d4068d498d45..bf996c2eb9b9 100644 --- a/plugins/backup/nas/src/main/java/org/apache/cloudstack/backup/NASBackupProvider.java +++ b/plugins/backup/nas/src/main/java/org/apache/cloudstack/backup/NASBackupProvider.java @@ -85,6 +85,13 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co true, BackupFrameworkEnabled.key()); + ConfigKey NASBackupCreateBackupTimeout = new ConfigKey<>("Advanced", Integer.class, + "nas.backup.create.backup.timeout", + "14400", + "Timeout in seconds for the create backup command.", + true, + BackupFrameworkEnabled.key()); + @Inject private BackupDao backupDao; @@ -205,6 +212,7 @@ public Pair takeBackup(final VirtualMachine vm, Boolean quiesce command.setBackupRepoAddress(backupRepository.getAddress()); command.setMountOptions(backupRepository.getMountOptions()); command.setQuiesce(quiesceVM); + command.setTimeout(NASBackupCreateBackupTimeout.value()); if (VirtualMachine.State.Stopped.equals(vm.getState())) { List vmVolumes = volumeDao.findByInstance(vm.getId()); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtTakeBackupCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtTakeBackupCommandWrapper.java index 11fa605908a6..3c4438e09979 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtTakeBackupCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtTakeBackupCommandWrapper.java @@ -51,6 +51,7 @@ public Answer execute(TakeBackupCommand command, LibvirtComputingResource libvir final String mountOptions = command.getMountOptions(); List volumePools = command.getVolumePools(); final List volumePaths = command.getVolumePaths(); + Long timeout = (long) (command.getTimeout() * 1000); KVMStoragePoolManager storagePoolMgr = libvirtComputingResource.getStoragePoolMgr(); List diskPaths = new ArrayList<>(); @@ -81,7 +82,7 @@ public Answer execute(TakeBackupCommand command, LibvirtComputingResource libvir "-d", diskPaths.isEmpty() ? "" : String.join(",", diskPaths) }); - Pair result = Script.executePipedCommands(commands, libvirtComputingResource.getCmdsTimeout()); + Pair result = Script.executePipedCommands(commands, timeout); if (result.first() != 0) { logger.debug("Failed to take VM backup: " + result.second()); From 30fe99a077972e14b6cc362ad19e88b50aaccca3 Mon Sep 17 00:00:00 2001 From: Abhisar Sinha <63767682+abh1sar@users.noreply.github.com> Date: Mon, 6 Apr 2026 21:25:40 +0530 Subject: [PATCH 2/3] use timeout set via "commands.timeout" --- .../org/apache/cloudstack/backup/TakeBackupCommand.java | 9 --------- .../org/apache/cloudstack/backup/NASBackupProvider.java | 8 -------- .../wrapper/LibvirtRestoreBackupCommandWrapper.java | 6 +++--- .../wrapper/LibvirtTakeBackupCommandWrapper.java | 2 +- 4 files changed, 4 insertions(+), 21 deletions(-) diff --git a/core/src/main/java/org/apache/cloudstack/backup/TakeBackupCommand.java b/core/src/main/java/org/apache/cloudstack/backup/TakeBackupCommand.java index d93ccc621024..5402b6b24760 100644 --- a/core/src/main/java/org/apache/cloudstack/backup/TakeBackupCommand.java +++ b/core/src/main/java/org/apache/cloudstack/backup/TakeBackupCommand.java @@ -35,7 +35,6 @@ public class TakeBackupCommand extends Command { private Boolean quiesce; @LogLevel(LogLevel.Log4jLevel.Off) private String mountOptions; - private Integer timeout; public TakeBackupCommand(String vmName, String backupPath) { super(); @@ -107,14 +106,6 @@ public void setQuiesce(Boolean quiesce) { this.quiesce = quiesce; } - public Integer getTimeout() { - return this.timeout == null ? 0 : this.timeout; - } - - public void setTimeout(Integer timeout) { - this.timeout = timeout; - } - @Override public boolean executeInSequence() { return true; diff --git a/plugins/backup/nas/src/main/java/org/apache/cloudstack/backup/NASBackupProvider.java b/plugins/backup/nas/src/main/java/org/apache/cloudstack/backup/NASBackupProvider.java index bf996c2eb9b9..d4068d498d45 100644 --- a/plugins/backup/nas/src/main/java/org/apache/cloudstack/backup/NASBackupProvider.java +++ b/plugins/backup/nas/src/main/java/org/apache/cloudstack/backup/NASBackupProvider.java @@ -85,13 +85,6 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co true, BackupFrameworkEnabled.key()); - ConfigKey NASBackupCreateBackupTimeout = new ConfigKey<>("Advanced", Integer.class, - "nas.backup.create.backup.timeout", - "14400", - "Timeout in seconds for the create backup command.", - true, - BackupFrameworkEnabled.key()); - @Inject private BackupDao backupDao; @@ -212,7 +205,6 @@ public Pair takeBackup(final VirtualMachine vm, Boolean quiesce command.setBackupRepoAddress(backupRepository.getAddress()); command.setMountOptions(backupRepository.getMountOptions()); command.setQuiesce(quiesceVM); - command.setTimeout(NASBackupCreateBackupTimeout.value()); if (VirtualMachine.State.Stopped.equals(vm.getState())) { List vmVolumes = volumeDao.findByInstance(vm.getId()); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRestoreBackupCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRestoreBackupCommandWrapper.java index 714e3844b347..cb5513d5d0e9 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRestoreBackupCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRestoreBackupCommandWrapper.java @@ -73,7 +73,7 @@ public Answer execute(RestoreBackupCommand command, LibvirtComputingResource ser List restoreVolumePools = command.getRestoreVolumePools(); List restoreVolumePaths = command.getRestoreVolumePaths(); Integer mountTimeout = command.getMountTimeout() * 1000; - int timeout = command.getWait(); + int timeout = command.getWait() > 0 ? command.getWait() * 1000 : serverResource.getCmdsTimeout(); KVMStoragePoolManager storagePoolMgr = serverResource.getStoragePoolMgr(); List backupFiles = command.getBackupFiles(); @@ -252,7 +252,7 @@ private boolean replaceVolumeWithBackup(KVMStoragePoolManager storagePoolMgr, Pr private boolean replaceVolumeWithBackup(KVMStoragePoolManager storagePoolMgr, PrimaryDataStoreTO volumePool, String volumePath, String backupPath, int timeout, boolean createTargetVolume) { if (volumePool.getPoolType() != Storage.StoragePoolType.RBD) { - int exitValue = Script.runSimpleBashScriptForExitValue(String.format(RSYNC_COMMAND, backupPath, volumePath)); + int exitValue = Script.runSimpleBashScriptForExitValue(String.format(RSYNC_COMMAND, backupPath, volumePath), timeout, false); return exitValue == 0; } @@ -263,7 +263,7 @@ private boolean replaceRbdVolumeWithBackup(KVMStoragePoolManager storagePoolMgr, KVMStoragePool volumeStoragePool = storagePoolMgr.getStoragePool(volumePool.getPoolType(), volumePool.getUuid()); QemuImg qemu; try { - qemu = new QemuImg(timeout * 1000, true, false); + qemu = new QemuImg(timeout, true, false); if (!createTargetVolume) { KVMPhysicalDisk rdbDisk = volumeStoragePool.getPhysicalDisk(volumePath); logger.debug("Restoring RBD volume: {}", rdbDisk.toString()); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtTakeBackupCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtTakeBackupCommandWrapper.java index 3c4438e09979..42953aa9f835 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtTakeBackupCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtTakeBackupCommandWrapper.java @@ -51,8 +51,8 @@ public Answer execute(TakeBackupCommand command, LibvirtComputingResource libvir final String mountOptions = command.getMountOptions(); List volumePools = command.getVolumePools(); final List volumePaths = command.getVolumePaths(); - Long timeout = (long) (command.getTimeout() * 1000); KVMStoragePoolManager storagePoolMgr = libvirtComputingResource.getStoragePoolMgr(); + int timeout = command.getWait() > 0 ? command.getWait() * 1000 : libvirtComputingResource.getCmdsTimeout(); List diskPaths = new ArrayList<>(); if (Objects.nonNull(volumePaths)) { From 22eb3624f50064b819cac45542fc035d555079bb Mon Sep 17 00:00:00 2001 From: Abhisar Sinha <63767682+abh1sar@users.noreply.github.com> Date: Mon, 6 Apr 2026 22:30:30 +0530 Subject: [PATCH 3/3] fix test failures --- ...ibvirtRestoreBackupCommandWrapperTest.java | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRestoreBackupCommandWrapperTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRestoreBackupCommandWrapperTest.java index d72dc0d8ac36..d24f22b6ebb5 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRestoreBackupCommandWrapperTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRestoreBackupCommandWrapperTest.java @@ -370,7 +370,15 @@ public void testExecuteWithRsyncFailure() throws Exception { try (MockedStatic