From 7e3ec0edb258a1dbf3c441e90c05705179c9933d Mon Sep 17 00:00:00 2001 From: Dajeong-Park Date: Thu, 23 Apr 2026 15:20:06 +0900 Subject: [PATCH 1/3] =?UTF-8?q?backingup=20=EC=83=81=ED=83=9C=EB=A1=9C=20?= =?UTF-8?q?=EB=82=A8=EC=9D=80=20=EB=B0=B1=EC=97=85=EB=B3=B8=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=EB=90=9C=EC=A7=80=20=ED=95=98=EB=A3=A8=EC=A7=80?= =?UTF-8?q?=EB=82=9C=20=EA=B2=BD=EC=9A=B0=20=EB=B0=B1=EC=97=94=EB=93=9C?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backup/CommvaultBackupProvider.java | 18 ++++++++++++++++++ .../cloudstack/backup/NASBackupProvider.java | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/plugins/backup/commvault/src/main/java/org/apache/cloudstack/backup/CommvaultBackupProvider.java b/plugins/backup/commvault/src/main/java/org/apache/cloudstack/backup/CommvaultBackupProvider.java index cff8b757f8ba..cd09345796b2 100644 --- a/plugins/backup/commvault/src/main/java/org/apache/cloudstack/backup/CommvaultBackupProvider.java +++ b/plugins/backup/commvault/src/main/java/org/apache/cloudstack/backup/CommvaultBackupProvider.java @@ -89,6 +89,7 @@ import java.util.stream.Collectors; import java.util.Collections; import java.util.Comparator; +import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.inject.Inject; @@ -104,6 +105,7 @@ public class CommvaultBackupProvider extends AdapterBase implements BackupProvid private static final int BASE_MT = 89; private static final Pattern VERSION_PATTERN = Pattern.compile("^(\\d+)\\s*SP\\s*(\\d+)(?:\\.(\\d+))?$", Pattern.CASE_INSENSITIVE); private static final String COMMVAULT_DIRECTORY = "/tmp/mold/backup"; + private static final long STALE_BACKUP_THRESHOLD_MS = TimeUnit.DAYS.toMillis(1); public ConfigKey CommvaultUrl = new ConfigKey<>("Advanced", String.class, "backup.plugin.commvault.url", "https://localhost/commandcenter/api", @@ -874,6 +876,18 @@ public void syncBackups(VirtualMachine vm) { } final CommvaultClient client = getClient(vm.getDataCenterId()); for (final Backup backup: backupDao.listByVmId(vm.getDataCenterId(), vm.getId())) { + if (Backup.Status.BackingUp.equals(backup.getStatus()) && isOlderThanOneDay(backup.getDate())) { + LOG.warn("Removing stale Commvault backup [{}] for VM [{}] stuck in BackingUp for over one day. External ID: [{}]", + backup.getUuid(), vm.getInstanceName(), backup.getExternalId()); + try { + if (deleteBackup(backup, true)) { + backupDao.remove(backup.getId()); + } + } catch (Exception e) { + LOG.warn("Failed to delete stale Commvault backup [{}] for VM [{}]", backup.getUuid(), vm.getInstanceName(), e); + } + continue; + } String externalId = backup.getExternalId(); String jobId = externalId.substring(externalId.lastIndexOf(',') + 1).trim(); String path = externalId.substring(0, externalId.lastIndexOf(',')); @@ -906,6 +920,10 @@ public void syncBackups(VirtualMachine vm) { return; } + private boolean isOlderThanOneDay(Date backupDate) { + return backupDate != null && backupDate.getTime() <= System.currentTimeMillis() - STALE_BACKUP_THRESHOLD_MS; + } + @Override public boolean checkBackupAgent(final Long zoneId) { Map checkResult = new HashMap<>(); 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 7ee7612230ee..8643697b9aff 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 @@ -72,6 +72,7 @@ import java.util.Locale; import java.util.Objects; import java.util.Optional; +import java.util.concurrent.TimeUnit; import java.util.UUID; import java.util.stream.Collectors; @@ -79,6 +80,7 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Configurable { private static final Logger LOG = LogManager.getLogger(NASBackupProvider.class); + private static final long STALE_BACKUP_THRESHOLD_MS = TimeUnit.DAYS.toMillis(1); ConfigKey NASBackupRestoreMountTimeout = new ConfigKey<>("Advanced", Integer.class, "nas.backup.restore.mount.timeout", @@ -607,6 +609,22 @@ public String getConfigComponentName() { @Override public void syncBackups(VirtualMachine vm) { + for (final Backup backup : backupDao.listByVmId(vm.getDataCenterId(), vm.getId())) { + if (!(backup instanceof BackupVO) || !Backup.Status.BackingUp.equals(backup.getStatus()) || !isOlderThanOneDay(backup.getDate())) { + continue; + } + LOG.warn("Removing stale NAS backup [{}] for VM [{}] stuck in BackingUp for over one day. Repository path: [{}]", + backup.getUuid(), vm.getInstanceName(), backup.getExternalId()); + try { + deleteBackup(backup, true); + } catch (Exception e) { + LOG.warn("Failed to delete stale NAS backup [{}] for VM [{}]", backup.getUuid(), vm.getInstanceName(), e); + } + } + } + + private boolean isOlderThanOneDay(Date backupDate) { + return backupDate != null && backupDate.getTime() <= System.currentTimeMillis() - STALE_BACKUP_THRESHOLD_MS; } @Override From 729af58b7ce545b169421d047518add363906994 Mon Sep 17 00:00:00 2001 From: Dajeong-Park Date: Fri, 24 Apr 2026 13:46:27 +0900 Subject: [PATCH 2/3] =?UTF-8?q?=EB=B0=B1=EC=97=85=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?=EC=A4=91=EB=B3=B5=EB=90=9C=20=EB=B6=80=EB=B6=84=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/cloudstack/backup/NASBackupProvider.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) 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 8643697b9aff..6087ea8f92e0 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 @@ -483,7 +483,7 @@ public boolean deleteBackup(Backup backup, boolean forced) { } if (answer != null && answer.getResult()) { - return backupDao.remove(backup.getId()); + return true; } logger.debug("There was an error removing the backup with id {}", backup.getId()); @@ -616,7 +616,9 @@ public void syncBackups(VirtualMachine vm) { LOG.warn("Removing stale NAS backup [{}] for VM [{}] stuck in BackingUp for over one day. Repository path: [{}]", backup.getUuid(), vm.getInstanceName(), backup.getExternalId()); try { - deleteBackup(backup, true); + if (deleteBackup(backup, true)) { + backupDao.remove(backup.getId()); + } } catch (Exception e) { LOG.warn("Failed to delete stale NAS backup [{}] for VM [{}]", backup.getUuid(), vm.getInstanceName(), e); } @@ -639,4 +641,4 @@ private boolean isOlderThanOneDay(Date backupDate) { @Override public boolean updateBackupPlan(final Long zoneId, final String retentionPeriod, final String externalId) { return true; } -} \ No newline at end of file +} From 8f29c77dcdfc069d9039a74e9cb50ec17787176d Mon Sep 17 00:00:00 2001 From: Dajeong-Park Date: Fri, 24 Apr 2026 14:51:33 +0900 Subject: [PATCH 3/3] =?UTF-8?q?=ED=95=B4=EB=8B=B9=20provider=EC=9D=98=20?= =?UTF-8?q?=EB=B0=B1=EC=97=85=EB=B3=B8=EB=A7=8C=20sync=ED=83=80=EB=8F=84?= =?UTF-8?q?=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cloudstack/backup/CommvaultBackupProvider.java | 8 ++++++++ .../apache/cloudstack/backup/NASBackupProvider.java | 12 ++++++++++++ 2 files changed, 20 insertions(+) diff --git a/plugins/backup/commvault/src/main/java/org/apache/cloudstack/backup/CommvaultBackupProvider.java b/plugins/backup/commvault/src/main/java/org/apache/cloudstack/backup/CommvaultBackupProvider.java index cd09345796b2..57cf988a3ae2 100644 --- a/plugins/backup/commvault/src/main/java/org/apache/cloudstack/backup/CommvaultBackupProvider.java +++ b/plugins/backup/commvault/src/main/java/org/apache/cloudstack/backup/CommvaultBackupProvider.java @@ -862,6 +862,11 @@ public String getDescription() { return "Commvault Backup Plugin"; } + private boolean isBackupManagedByThisProvider(Backup backup) { + BackupOffering offering = backupOfferingDao.findByIdIncludingRemoved(backup.getBackupOfferingId()); + return offering != null && Objects.equals(getName(), offering.getProvider()); + } + @Override public String getConfigComponentName() { return BackupService.class.getSimpleName(); @@ -876,6 +881,9 @@ public void syncBackups(VirtualMachine vm) { } final CommvaultClient client = getClient(vm.getDataCenterId()); for (final Backup backup: backupDao.listByVmId(vm.getDataCenterId(), vm.getId())) { + if (!isBackupManagedByThisProvider(backup)) { + continue; + } if (Backup.Status.BackingUp.equals(backup.getStatus()) && isOlderThanOneDay(backup.getDate())) { LOG.warn("Removing stale Commvault backup [{}] for VM [{}] stuck in BackingUp for over one day. External ID: [{}]", backup.getUuid(), vm.getInstanceName(), backup.getExternalId()); 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 6087ea8f92e0..d081e3502c60 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 @@ -50,6 +50,7 @@ import org.apache.cloudstack.backup.dao.BackupDao; +import org.apache.cloudstack.backup.dao.BackupOfferingDao; import org.apache.cloudstack.backup.dao.BackupRepositoryDao; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; @@ -92,6 +93,9 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co @Inject private BackupDao backupDao; + @Inject + private BackupOfferingDao backupOfferingDao; + @Inject private BackupRepositoryDao backupRepositoryDao; @@ -602,6 +606,11 @@ public String getDescription() { return "NAS Backup Plugin"; } + private boolean isBackupManagedByThisProvider(Backup backup) { + BackupOffering offering = backupOfferingDao.findByIdIncludingRemoved(backup.getBackupOfferingId()); + return offering != null && Objects.equals(getName(), offering.getProvider()); + } + @Override public String getConfigComponentName() { return BackupService.class.getSimpleName(); @@ -610,6 +619,9 @@ public String getConfigComponentName() { @Override public void syncBackups(VirtualMachine vm) { for (final Backup backup : backupDao.listByVmId(vm.getDataCenterId(), vm.getId())) { + if (!isBackupManagedByThisProvider(backup)) { + continue; + } if (!(backup instanceof BackupVO) || !Backup.Status.BackingUp.equals(backup.getStatus()) || !isOlderThanOneDay(backup.getDate())) { continue; }