Skip to content

Commit e081111

Browse files
abh1sardhslove
authored andcommitted
Delete template from storage pool instantly if no volume is using it (apache#11782)
1 parent 8e3095a commit e081111

File tree

7 files changed

+84
-18
lines changed

7 files changed

+84
-18
lines changed

engine/components-api/src/main/java/com/cloud/template/TemplateManager.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@ public interface TemplateManager {
5757
+ "will validate if the provided URL is resolvable during the register of templates/ISOs before persisting them in the database.",
5858
true);
5959

60+
ConfigKey<Boolean> TemplateDeleteFromPrimaryStorage = new ConfigKey<Boolean>("Advanced",
61+
Boolean.class,
62+
"template.delete.from.primary.storage", "true",
63+
"Template when deleted will be instantly deleted from the Primary Storage",
64+
true,
65+
ConfigKey.Scope.Global);
66+
6067
static final String VMWARE_TOOLS_ISO = "vmware-tools.iso";
6168
static final String XS_TOOLS_ISO = "xs-tools.iso";
6269

@@ -104,6 +111,8 @@ public interface TemplateManager {
104111
*/
105112
List<VMTemplateStoragePoolVO> getUnusedTemplatesInPool(StoragePoolVO pool);
106113

114+
void evictTemplateFromStoragePoolsForZones(Long templateId, List<Long> zoneId);
115+
107116
/**
108117
* Deletes a template in the specified storage pool.
109118
*

engine/schema/src/main/java/com/cloud/storage/dao/VMTemplatePoolDao.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ public interface VMTemplatePoolDao extends GenericDao<VMTemplateStoragePoolVO, L
3535

3636
List<VMTemplateStoragePoolVO> listByPoolIdAndState(long poolId, ObjectInDataStoreStateMachine.State state);
3737

38+
List<VMTemplateStoragePoolVO> listByPoolIdsAndTemplate(List<Long> poolIds, Long templateId);
39+
3840
List<VMTemplateStoragePoolVO> listByTemplateStatus(long templateId, VMTemplateStoragePoolVO.Status downloadState);
3941

4042
List<VMTemplateStoragePoolVO> listByTemplateStatus(long templateId, VMTemplateStoragePoolVO.Status downloadState, long poolId);

engine/schema/src/main/java/com/cloud/storage/dao/VMTemplatePoolDaoImpl.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,16 @@ public VMTemplateStoragePoolVO findByPoolTemplate(long poolId, long templateId,
150150
return findOneIncludingRemovedBy(sc);
151151
}
152152

153+
@Override
154+
public List<VMTemplateStoragePoolVO> listByPoolIdsAndTemplate(List<Long> poolIds, Long templateId) {
155+
SearchCriteria<VMTemplateStoragePoolVO> sc = PoolTemplateSearch.create();
156+
if (CollectionUtils.isNotEmpty(poolIds)) {
157+
sc.setParameters("pool_id", poolIds.toArray());
158+
}
159+
sc.setParameters("template_id", templateId);
160+
return listBy(sc);
161+
}
162+
153163
@Override
154164
public List<VMTemplateStoragePoolVO> listByTemplateStatus(long templateId, VMTemplateStoragePoolVO.Status downloadState) {
155165
SearchCriteria<VMTemplateStoragePoolVO> sc = TemplateStatusSearch.create();

engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,4 +173,5 @@ Pair<List<Long>, Integer> searchForIdsAndCount(Long storagePoolId, String storag
173173

174174
List<StoragePoolVO> findPoolsByStorageTypeAndZone(Storage.StoragePoolType storageType, Long zoneId);
175175

176+
List<StoragePoolVO> listByDataCenterIds(List<Long> dataCenterIds);
176177
}

engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase<StoragePoolVO, Long>
6666
private final GenericSearchBuilder<StoragePoolVO, Long> StatusCountSearch;
6767
private final SearchBuilder<StoragePoolVO> ClustersSearch;
6868
private final SearchBuilder<StoragePoolVO> IdsSearch;
69+
private final SearchBuilder<StoragePoolVO> DcsSearch;
6970

7071
@Inject
7172
private StoragePoolDetailsDao _detailsDao;
@@ -168,6 +169,9 @@ public PrimaryDataStoreDaoImpl() {
168169
IdsSearch.and("ids", IdsSearch.entity().getId(), SearchCriteria.Op.IN);
169170
IdsSearch.done();
170171

172+
DcsSearch = createSearchBuilder();
173+
DcsSearch.and("dataCenterId", DcsSearch.entity().getDataCenterId(), SearchCriteria.Op.IN);
174+
DcsSearch.done();
171175
}
172176

173177
@Override
@@ -952,6 +956,16 @@ public List<StoragePoolVO> findPoolsByStorageTypeAndZone(Storage.StoragePoolType
952956
return listBy(sc);
953957
}
954958

959+
@Override
960+
public List<StoragePoolVO> listByDataCenterIds(List<Long> dataCenterIds) {
961+
if (CollectionUtils.isEmpty(dataCenterIds)) {
962+
return Collections.emptyList();
963+
}
964+
SearchCriteria<StoragePoolVO> sc = DcsSearch.create();
965+
sc.setParameters("dataCenterId", dataCenterIds.toArray());
966+
return listBy(sc);
967+
}
968+
955969
private SearchCriteria<StoragePoolVO> createStoragePoolSearchCriteria(Long storagePoolId, String storagePoolName,
956970
Long zoneId, String path, Long podId, Long clusterId, Long hostId, String address, ScopeType scopeType,
957971
StoragePoolStatus status, String keyword, String storageAccessGroup) {

server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ public boolean delete(TemplateProfile profile) {
496496

497497
boolean dataDiskDeletetionResult = true;
498498
List<VMTemplateVO> dataDiskTemplates = templateDao.listByParentTemplatetId(template.getId());
499-
if (dataDiskTemplates != null && dataDiskTemplates.size() > 0) {
499+
if (CollectionUtils.isNotEmpty(dataDiskTemplates)) {
500500
logger.info("Template: {} has Datadisk template(s) associated with it. Delete Datadisk templates before deleting the template", template);
501501
for (VMTemplateVO dataDiskTemplate : dataDiskTemplates) {
502502
logger.info("Delete Datadisk template: {} from image store: {}", dataDiskTemplate, imageStore);
@@ -562,6 +562,9 @@ public boolean delete(TemplateProfile profile) {
562562
if (success) {
563563
if ((imageStores != null && imageStores.size() > 1) && (profile.getZoneIdList() != null)) {
564564
//if template is stored in more than one image stores, and the zone id is not null, then don't delete other templates.
565+
if (templateMgr.TemplateDeleteFromPrimaryStorage.value()) {
566+
templateMgr.evictTemplateFromStoragePoolsForZones(template.getId(), profile.getZoneIdList());
567+
}
565568
return cleanupTemplate(template, success);
566569
}
567570

@@ -574,7 +577,7 @@ public boolean delete(TemplateProfile profile) {
574577

575578
// find all eligible image stores for this template
576579
List<DataStore> iStores = templateMgr.getImageStoreByTemplate(template.getId(), null);
577-
if (iStores == null || iStores.size() == 0) {
580+
if (CollectionUtils.isEmpty(iStores)) {
578581
// remove any references from template_zone_ref
579582
List<VMTemplateZoneVO> templateZones = templateZoneDao.listByTemplateId(template.getId());
580583
if (templateZones != null) {
@@ -595,6 +598,10 @@ public boolean delete(TemplateProfile profile) {
595598

596599
}
597600

601+
if (templateMgr.TemplateDeleteFromPrimaryStorage.value()) {
602+
templateMgr.evictTemplateFromStoragePoolsForZones(template.getId(), profile.getZoneIdList());
603+
}
604+
598605
// remove its related ACL permission
599606
Pair<Class<?>, Long> templateClassForId = new Pair<>(VirtualMachineTemplate.class, template.getId());
600607
_messageBus.publish(_name, EntityManager.MESSAGE_REMOVE_ENTITY_EVENT, PublishScope.LOCAL, templateClassForId);

server/src/main/java/com/cloud/template/TemplateManagerImpl.java

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,33 +1034,53 @@ public boolean delete(long userId, long templateId, Long zoneId) {
10341034
return adapter.delete(new TemplateProfile(userId, template, zoneId));
10351035
}
10361036

1037+
private Boolean templateIsUnusedInPool(VMTemplateStoragePoolVO templatePoolVO) {
1038+
VMTemplateVO template = _tmpltDao.findByIdIncludingRemoved(templatePoolVO.getTemplateId());
1039+
1040+
// If this is a routing template, consider it in use
1041+
if (template.getTemplateType() == TemplateType.SYSTEM) {
1042+
return false;
1043+
}
1044+
1045+
// If the template is not yet downloaded to the pool, consider it in use
1046+
if (templatePoolVO.getDownloadState() != Status.DOWNLOADED) {
1047+
return false;
1048+
}
1049+
1050+
if (template.getFormat() == ImageFormat.ISO || _volumeDao.isAnyVolumeActivelyUsingTemplateOnPool(template.getId(), templatePoolVO.getPoolId())) {
1051+
return false;
1052+
}
1053+
return true;
1054+
}
1055+
10371056
@Override
10381057
public List<VMTemplateStoragePoolVO> getUnusedTemplatesInPool(StoragePoolVO pool) {
10391058
List<VMTemplateStoragePoolVO> unusedTemplatesInPool = new ArrayList<VMTemplateStoragePoolVO>();
10401059
List<VMTemplateStoragePoolVO> allTemplatesInPool = _tmpltPoolDao.listByPoolId(pool.getId());
10411060

10421061
for (VMTemplateStoragePoolVO templatePoolVO : allTemplatesInPool) {
1043-
VMTemplateVO template = _tmpltDao.findByIdIncludingRemoved(templatePoolVO.getTemplateId());
1044-
1045-
// If this is a routing template, consider it in use
1046-
if (template.getTemplateType() == TemplateType.SYSTEM) {
1047-
continue;
1048-
}
1049-
1050-
// If the template is not yet downloaded to the pool, consider it in
1051-
// use
1052-
if (templatePoolVO.getDownloadState() != Status.DOWNLOADED) {
1053-
continue;
1054-
}
1055-
1056-
if (template.getFormat() != ImageFormat.ISO && !_volumeDao.isAnyVolumeActivelyUsingTemplateOnPool(template.getId(), pool.getId())) {
1062+
if (templateIsUnusedInPool(templatePoolVO)) {
10571063
unusedTemplatesInPool.add(templatePoolVO);
10581064
}
10591065
}
1060-
10611066
return unusedTemplatesInPool;
10621067
}
10631068

1069+
@Override
1070+
public void evictTemplateFromStoragePoolsForZones(Long templateId, List<Long> zoneIds) {
1071+
List<Long> poolIds = new ArrayList<>();
1072+
if (CollectionUtils.isNotEmpty(zoneIds)) {
1073+
List<StoragePoolVO> pools = _poolDao.listByDataCenterIds(zoneIds);
1074+
poolIds = pools.stream().map(StoragePoolVO::getId).collect(Collectors.toList());
1075+
}
1076+
List<VMTemplateStoragePoolVO> templateStoragePoolVOS = _tmpltPoolDao.listByPoolIdsAndTemplate(poolIds, templateId);
1077+
for (VMTemplateStoragePoolVO templateStoragePoolVO: templateStoragePoolVOS) {
1078+
if (templateIsUnusedInPool(templateStoragePoolVO)) {
1079+
evictTemplateFromStoragePool(templateStoragePoolVO);
1080+
}
1081+
}
1082+
}
1083+
10641084
@Override
10651085
@DB
10661086
public void evictTemplateFromStoragePool(VMTemplateStoragePoolVO templatePoolVO) {
@@ -2564,7 +2584,10 @@ public String getConfigComponentName() {
25642584

25652585
@Override
25662586
public ConfigKey<?>[] getConfigKeys() {
2567-
return new ConfigKey<?>[] {AllowPublicUserTemplates, TemplatePreloaderPoolSize, ValidateUrlIsResolvableBeforeRegisteringTemplate};
2587+
return new ConfigKey<?>[] {AllowPublicUserTemplates,
2588+
TemplatePreloaderPoolSize,
2589+
ValidateUrlIsResolvableBeforeRegisteringTemplate,
2590+
TemplateDeleteFromPrimaryStorage};
25682591
}
25692592

25702593
public List<TemplateAdapter> getTemplateAdapters() {

0 commit comments

Comments
 (0)