abh1sar commented on code in PR #13074:
URL: https://github.com/apache/cloudstack/pull/13074#discussion_r3457076881


##########
plugins/backup/nas/src/main/java/org/apache/cloudstack/backup/NASBackupProvider.java:
##########
@@ -495,9 +863,42 @@ public boolean deleteBackup(Backup backup, boolean forced) 
{
             throw new CloudRuntimeException(String.format("Unable to find a 
running KVM host in zone %d to delete backup %s", backup.getZoneId(), 
backup.getUuid()));
         }
 
-        DeleteBackupCommand command = new 
DeleteBackupCommand(backup.getExternalId(), backupRepository.getType(),
-                backupRepository.getAddress(), 
backupRepository.getMountOptions());
+        // Backups outside any tracked chain (legacy or non-incremental 
providers) are
+        // deleted straight away — no children semantics apply.
+        if (readDetail(backup, NASBackupChainKeys.CHAIN_ID) == null) {
+            return deleteBackupFileAndRow(backup, backupRepository, host);
+        }
+
+        // Snapshot-style cascade: defer the on-NAS rm + DB row while there 
are live children,
+        // mark this backup as delete-pending, and let the leaf's deletion 
sweep it up later.
+        // See DefaultSnapshotStrategy#deleteSnapshotChain for the same 
pattern on incremental
+        // snapshots. forced=true means the caller wants the entire subtree 
gone right now.
+        if (forced) {
+            return cascadeDeleteSubtree(backup, backupRepository, host);
+        }
+

Review Comment:
   set vm's active checkpoint_id to null if the backup corresponding to the 
active_checkpoint_id is deleted.



##########
server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java:
##########
@@ -1701,6 +1701,14 @@ private boolean deleteCheckedBackup(Boolean forced, 
BackupProvider backupProvide
                      reservationDao, resourceLimitMgr)) {
             boolean result = backupProvider.deleteBackup(backup, forced);
             if (result) {
+                // Chain-aware providers (e.g. NAS) physically remove several 
backups per call
+                // (leaf + swept delete-pending ancestors) and decrement 
resource count/usage and
+                // remove each DB row themselves, exactly once per removed 
backup. Decrementing or
+                // removing again here would double-handle and destroy 
delete-pending tombstones,
+                // so defer entirely to the provider for those.
+                if (backupProvider.handlesChainDeleteResourceAccounting()) {
+                    return true;

Review Comment:
   call `checkAndGenerateUsageForLastBackupDeletedAfterOfferingRemove` before 
returning true



##########
plugins/backup/nas/src/main/java/org/apache/cloudstack/backup/NASBackupProvider.java:
##########
@@ -506,13 +907,215 @@ public boolean deleteBackup(Backup backup, boolean 
forced) {
         } catch (OperationTimedoutException e) {
             throw new CloudRuntimeException("Operation to delete backup timed 
out, please try again");
         }
+        if (answer == null || !answer.getResult()) {
+            logger.warn("Failed to delete backup file for {} ({}); leaving DB 
row intact",
+                    backup.getUuid(), backup.getExternalId());
+            return false;
+        }
+        backupDao.remove(backup.getId());
+        // Exactly-once resource accounting: decrement at the single point a 
backup row + file are
+        // physically removed. This runs for the leaf and for every swept 
delete-pending ancestor,
+        // so a chain delete decrements once per actually-removed backup. The 
manager skips its own
+        // accounting for this provider (see 
handlesChainDeleteResourceAccounting()).
+        long size = backup.getSize() != null ? backup.getSize() : 0L;
+        resourceLimitMgr.decrementResourceCount(backup.getAccountId(), 
Resource.ResourceType.backup);
+        resourceLimitMgr.decrementResourceCount(backup.getAccountId(), 
Resource.ResourceType.backup_storage, size);
+        return true;
+    }
 
-        if (answer != null && answer.getResult()) {
-            return backupDao.remove(backup.getId());
+    /**
+     * Mark {@code backup} as delete-pending in {@code backup_details}. 
Idempotent.
+     */
+    private void markDeletePending(Backup backup) {
+        BackupDetailVO existing = backupDetailsDao.findDetail(backup.getId(), 
NASBackupChainKeys.DELETE_PENDING);

Review Comment:
   Sorry, about going back on this but can we use a new `Backup.Status.Hidden` 
state similar to `Snapshot.State.Hidden` instead of the `DELETE_PENDING` detail?
   We'll also need a change in BackupManagerImpl.listBackups to not return 
backups that are `Hidden`
   Also, no other operations such as 
Restore/RestoreandAttachVolume/CreateInstanceFromBackup/Delete should be 
allowed on a `Hidden` backup



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to