From e805e45342ac1fe085bcae556349d5c34ce45673 Mon Sep 17 00:00:00 2001 From: Abhisar Sinha <63767682+abh1sar@users.noreply.github.com> Date: Thu, 31 Jul 2025 18:22:48 +0530 Subject: [PATCH] Show chain size in snapshot response for incremental snapshots (#11313) --- .../apache/cloudstack/api/ApiConstants.java | 1 + .../api/response/SnapshotResponse.java | 8 ++++++++ .../api/query/dao/SnapshotJoinDaoImpl.java | 19 +++++++++++++++++++ .../storage/snapshot/SnapshotManager.java | 4 ++++ .../storage/snapshot/SnapshotManagerImpl.java | 2 +- ui/public/locales/en.json | 1 + ui/src/components/view/DetailsTab.vue | 17 ++++++++++++++--- ui/src/config/section/storage.js | 2 +- 8 files changed, 49 insertions(+), 5 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index 3b36ce9100e..70d3763b0be 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -1143,6 +1143,7 @@ public class ApiConstants { public static final String NETWORK_SPANNED_ZONES = "zonesnetworkspans"; public static final String METADATA = "metadata"; public static final String PHYSICAL_SIZE = "physicalsize"; + public static final String CHAIN_SIZE = "chainsize"; public static final String OVM3_POOL = "ovm3pool"; public static final String OVM3_CLUSTER = "ovm3cluster"; public static final String OVM3_VIP = "ovm3vip"; diff --git a/api/src/main/java/org/apache/cloudstack/api/response/SnapshotResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/SnapshotResponse.java index 9f7a7f42dec..5d6756c950d 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/SnapshotResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/SnapshotResponse.java @@ -107,6 +107,10 @@ public class SnapshotResponse extends BaseResponseWithTagInformation implements @Param(description = "physical size of backedup snapshot on image store") private long physicalSize; + @SerializedName(ApiConstants.CHAIN_SIZE) + @Param(description = "chain size of snapshot including all parent snapshots. Shown only for incremental snapshots if snapshot.show.chain.size setting is set to true", since = "4.21.0") + private Long chainSize; + @SerializedName(ApiConstants.ZONE_ID) @Param(description = "id of the availability zone") private String zoneId; @@ -244,6 +248,10 @@ public class SnapshotResponse extends BaseResponseWithTagInformation implements this.physicalSize = physicalSize; } + public void setChainSize(long chainSize) { + this.chainSize = chainSize; + } + @Override public void setProjectId(String projectId) { this.projectId = projectId; diff --git a/server/src/main/java/com/cloud/api/query/dao/SnapshotJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/SnapshotJoinDaoImpl.java index 2944e69c22a..bca60383501 100644 --- a/server/src/main/java/com/cloud/api/query/dao/SnapshotJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/SnapshotJoinDaoImpl.java @@ -46,6 +46,7 @@ import com.cloud.storage.Snapshot; import com.cloud.storage.VMTemplateStorageResourceAssoc; import com.cloud.storage.Volume.Type; import com.cloud.storage.VolumeVO; +import com.cloud.storage.snapshot.SnapshotManager; import com.cloud.user.Account; import com.cloud.user.AccountService; import com.cloud.utils.db.Filter; @@ -96,9 +97,27 @@ public class SnapshotJoinDaoImpl extends GenericDaoBaseWithTagInformation snapshotDeltaMax = new ConfigKey<>(Integer.class, "snapshot.delta.max", "Snapshots", "16", "Max delta snapshots between two full snapshots. " + "Only valid for KVM and XenServer.", true, ConfigKey.Scope.Global, null); + ConfigKey snapshotShowChainSize = new ConfigKey<>(Boolean.class, "snapshot.show.chain.size", "Snapshots", "false", + "Whether to show chain size (sum of physical size of snapshot and all its parents) for incremental snapshots in the snapshot response", + true, ConfigKey.Scope.Global, null); + void deletePoliciesForVolume(Long volumeId); /** diff --git a/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java index 1e54fc6e224..5a4d6a68402 100755 --- a/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java +++ b/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java @@ -294,7 +294,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement @Override public ConfigKey[] getConfigKeys() { return new ConfigKey[] {BackupRetryAttempts, BackupRetryInterval, SnapshotHourlyMax, SnapshotDailyMax, SnapshotMonthlyMax, SnapshotWeeklyMax, usageSnapshotSelection, - SnapshotInfo.BackupSnapshotAfterTakingSnapshot, VmStorageSnapshotKvm, kvmIncrementalSnapshot, snapshotDeltaMax}; + SnapshotInfo.BackupSnapshotAfterTakingSnapshot, VmStorageSnapshotKvm, kvmIncrementalSnapshot, snapshotDeltaMax, snapshotShowChainSize}; } @Override diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 29b8166d887..97421ff8e50 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -509,6 +509,7 @@ "label.certificate.upload.failed": "Certificate upload failed", "label.certificate.upload.failed.description": "Failed to update SSL Certificate. Failed to pass certificate validation check.", "label.certificateid": "Certificate ID", +"label.chainsize": "Chain size", "label.change": "Change", "label.change.affinity": "Change affinity", "label.change.bgp.peers": "Change BGP peers", diff --git a/ui/src/components/view/DetailsTab.vue b/ui/src/components/view/DetailsTab.vue index 24c2043b90a..7829121fdb2 100644 --- a/ui/src/components/view/DetailsTab.vue +++ b/ui/src/components/view/DetailsTab.vue @@ -75,17 +75,22 @@
- {{ parseFloat(dataResource.size / (1024.0 * 1024.0 * 1024.0)).toFixed(2) }} GiB + {{ sizeInGiB(dataResource.size) }} GiB
- {{ parseFloat(dataResource.physicalsize / (1024.0 * 1024.0 * 1024.0)).toFixed(2) }} GiB + {{ sizeInGiB(dataResource.physicalsize) }} GiB
- {{ parseFloat(dataResource.virtualsize / (1024.0 * 1024.0 * 1024.0)).toFixed(2) }} GiB + {{ sizeInGiB(dataResource.virtualsize) }} GiB +
+
+
+
+ {{ sizeInGiB(dataResource.chainsize) }} GiB
@@ -473,6 +478,12 @@ export default { } return `label.${source}` + }, + sizeInGiB (sizeInBytes) { + if (!sizeInBytes || sizeInBytes === 0) { + return '0.00' + } + return parseFloat(sizeInBytes / (1024.0 * 1024.0 * 1024.0)).toFixed(2) } } } diff --git a/ui/src/config/section/storage.js b/ui/src/config/section/storage.js index b04d67a361e..3dd5a731666 100644 --- a/ui/src/config/section/storage.js +++ b/ui/src/config/section/storage.js @@ -324,7 +324,7 @@ export default { fields.push('zonename') return fields }, - details: ['name', 'id', 'volumename', 'volumetype', 'snapshottype', 'intervaltype', 'physicalsize', 'virtualsize', 'account', 'domain', 'created'], + details: ['name', 'id', 'volumename', 'volumetype', 'snapshottype', 'intervaltype', 'physicalsize', 'virtualsize', 'chainsize', 'account', 'domain', 'created'], tabs: [ { name: 'details',