Show parent snapshot (along with the chain size) for incremental snapshots (#12468)

* Show parent snapshot (along with the chain size) for incremental snapshots

* review

* review changes
This commit is contained in:
Suresh Kumar Anaparti 2026-01-29 11:46:10 +05:30 committed by GitHub
parent 7786cf93c2
commit 65e9bebc69
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 56 additions and 4 deletions

View File

@ -51,6 +51,7 @@ public class ListCapabilitiesCmd extends BaseCmd {
response.setDiskOffMaxSize((Long)capabilities.get("customDiskOffMaxSize"));
response.setRegionSecondaryEnabled((Boolean)capabilities.get("regionSecondaryEnabled"));
response.setKVMSnapshotEnabled((Boolean)capabilities.get("KVMSnapshotEnabled"));
response.setSnapshotShowChainSize((Boolean)capabilities.get("SnapshotShowChainSize"));
response.setAllowUserViewDestroyedVM((Boolean)capabilities.get("allowUserViewDestroyedVM"));
response.setAllowUserExpungeRecoverVM((Boolean)capabilities.get("allowUserExpungeRecoverVM"));
response.setAllowUserExpungeRecoverVolume((Boolean)capabilities.get("allowUserExpungeRecoverVolume"));

View File

@ -73,6 +73,10 @@ public class CapabilitiesResponse extends BaseResponse {
@Param(description = "True if Snapshot is supported for KVM host, false otherwise")
private boolean kvmSnapshotEnabled;
@SerializedName("snapshotshowchainsize")
@Param(description = "True to show the parent and chain size (sum of physical size of snapshot and all its parents) for incremental snapshots", since = "4.22.1")
private boolean snapshotShowChainSize;
@SerializedName("apilimitmax")
@Param(description = "Max allowed number of api requests within the specified interval")
private Integer apiLimitMax;
@ -197,6 +201,10 @@ public class CapabilitiesResponse extends BaseResponse {
this.kvmSnapshotEnabled = kvmSnapshotEnabled;
}
public void setSnapshotShowChainSize(boolean snapshotShowChainSize) {
this.snapshotShowChainSize = snapshotShowChainSize;
}
public void setApiLimitInterval(Integer apiLimitInterval) {
this.apiLimitInterval = apiLimitInterval;
}

View File

@ -155,6 +155,14 @@ public class SnapshotResponse extends BaseResponseWithTagInformation implements
@Param(description = "download progress of a snapshot", since = "4.19.0")
private Map<String, String> downloadDetails;
@SerializedName("parent")
@Param(description = "The parent ID of the Snapshot", since = "4.22.1")
private String parent;
@SerializedName("parentname")
@Param(description = "The parent name of the Snapshot", since = "4.22.1")
private String parentName;
public SnapshotResponse() {
tags = new LinkedHashSet<ResourceTagResponse>();
}
@ -313,4 +321,12 @@ public class SnapshotResponse extends BaseResponseWithTagInformation implements
public void setDownloadDetails(Map<String, String> downloadDetails) {
this.downloadDetails = downloadDetails;
}
public void setParent(String parent) {
this.parent = parent;
}
public void setParentName(String parentName) {
this.parentName = parentName;
}
}

View File

@ -109,6 +109,8 @@ public class SnapshotJoinDaoImpl extends GenericDaoBaseWithTagInformation<Snapsh
if (showChainSize && snapshotInfo.getParent() != null) {
long chainSize = calculateChainSize(snapshotInfo);
snapshotResponse.setChainSize(chainSize);
snapshotResponse.setParent(snapshotInfo.getParent().getUuid());
snapshotResponse.setParentName(snapshotInfo.getParent().getName());
}
}
}

View File

@ -4799,6 +4799,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
final long diskOffMinSize = VolumeOrchestrationService.CustomDiskOfferingMinSize.value();
final long diskOffMaxSize = VolumeOrchestrationService.CustomDiskOfferingMaxSize.value();
final boolean KVMSnapshotEnabled = SnapshotManager.KVMSnapshotEnabled.value();
final boolean SnapshotShowChainSize = SnapshotManager.snapshotShowChainSize.value();
final boolean userPublicTemplateEnabled = TemplateManager.AllowPublicUserTemplates.valueIn(caller.getId());
@ -4839,6 +4840,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
capabilities.put("customDiskOffMaxSize", diskOffMaxSize);
capabilities.put("regionSecondaryEnabled", regionSecondaryEnabled);
capabilities.put("KVMSnapshotEnabled", KVMSnapshotEnabled);
capabilities.put("SnapshotShowChainSize", SnapshotShowChainSize);
capabilities.put("allowUserViewDestroyedVM", allowUserViewDestroyedVM);
capabilities.put("allowUserExpungeRecoverVM", allowUserExpungeRecoverVM);
capabilities.put("allowUserExpungeRecoverVolume", allowUserExpungeRecoverVolume);

View File

@ -739,6 +739,20 @@
>{{ text }}</router-link>
<span v-else>{{ text }}</span>
</template>
<template v-if="column.key === 'parentname' && ['snapshot'].includes($route.path.split('/')[1])">
<router-link
v-if="record.parent && $router.resolve('/snapshot/' + record.parent).matched[0].redirect !== '/exception/404'"
:to="{ path: '/snapshot/' + record.parent }"
>{{ text }}</router-link>
<span v-else>{{ text }}</span>
</template>
<template v-if="column.key === 'parentName' && ['vmsnapshot'].includes($route.path.split('/')[1])">
<router-link
v-if="record.parent && $router.resolve('/vmsnapshot/' + record.parent).matched[0].redirect !== '/exception/404'"
:to="{ path: '/vmsnapshot/' + record.parent }"
>{{ text }}</router-link>
<span v-else>{{ text }}</span>
</template>
<template v-if="column.key === 'templateversion'">
<span> {{ record.version }} </span>
</template>

View File

@ -92,7 +92,7 @@ export default {
}
],
searchFilters: () => {
var filters = ['name', 'zoneid', 'domainid', 'account', 'state', 'tags', 'serviceofferingid', 'diskofferingid', 'isencrypted']
const filters = ['name', 'zoneid', 'domainid', 'account', 'state', 'tags', 'serviceofferingid', 'diskofferingid', 'isencrypted']
if (['Admin', 'DomainAdmin'].includes(store.getters.userInfo.roletype)) {
filters.push('storageid')
}
@ -311,7 +311,10 @@ export default {
permission: ['listSnapshots'],
resourceType: 'Snapshot',
columns: () => {
var fields = ['name', 'state', 'volumename', 'intervaltype', 'physicalsize', 'created']
const fields = ['name', 'state', 'volumename', 'intervaltype', 'physicalsize', 'created']
if (store.getters.features.snapshotshowchainsize) {
fields.splice(fields.indexOf('created'), 0, 'chainsize', 'parentname')
}
if (['Admin', 'DomainAdmin'].includes(store.getters.userInfo.roletype)) {
fields.push('account')
if (store.getters.listAllProjects) {
@ -324,7 +327,13 @@ export default {
fields.push('zonename')
return fields
},
details: ['name', 'id', 'volumename', 'volumetype', 'snapshottype', 'intervaltype', 'physicalsize', 'virtualsize', 'chainsize', 'account', 'domain', 'created'],
details: () => {
const fields = ['name', 'id', 'volumename', 'volumetype', 'snapshottype', 'intervaltype', 'physicalsize', 'virtualsize', 'account', 'domain', 'created']
if (store.getters.features.snapshotshowchainsize) {
fields.splice(fields.indexOf('account'), 0, 'chainsize', 'parentname')
}
return fields
},
tabs: [
{
name: 'details',
@ -346,7 +355,7 @@ export default {
}
],
searchFilters: () => {
var filters = ['name', 'domainid', 'account', 'tags', 'zoneid']
const filters = ['name', 'domainid', 'account', 'tags', 'zoneid']
if (['Admin', 'DomainAdmin'].includes(store.getters.userInfo.roletype)) {
filters.push('storageid')
filters.push('imagestoreid')