Skip to content

Commit f3fa8f8

Browse files
committed
Refactor template storage handling to improve secondary storage copy limit logic and update related tests
1 parent 3e3545e commit f3fa8f8

3 files changed

Lines changed: 29 additions & 6 deletions

File tree

engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/TemplateServiceImpl.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -421,8 +421,9 @@ protected boolean shouldDownloadTemplateToStore(VMTemplateVO template, DataStore
421421
return true;
422422
}
423423

424-
logger.info("Skipping download of template [{}] to image store [{}].", template.getUniqueName(), store.getName());
425-
return false;
424+
logger.debug("Copying template [{}] to image store [{}] to reach the configured secondary storage copy limit in zone [{}].",
425+
template.getUniqueName(), store.getName(), zoneId);
426+
return true;
426427
}
427428

428429
@Override
@@ -652,7 +653,7 @@ public void handleTemplateSync(DataStore store) {
652653
availHypers.add(HypervisorType.None); // bug 9809: resume ISO
653654
// download.
654655
for (VMTemplateVO tmplt : toBeDownloaded) {
655-
// if this is private template, skip sync to a new image store
656+
// skip stores excluded by heuristic rules or already at the configured copy limit
656657
if (!shouldDownloadTemplateToStore(tmplt, store)) {
657658
continue;
658659
}

engine/storage/image/src/test/java/org/apache/cloudstack/storage/image/TemplateServiceImplTest.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,23 @@ public void shouldDownloadTemplateToStoreTestDownloadsPrivateNoRefTemplate() {
153153
}
154154

155155
@Test
156-
public void shouldDownloadTemplateToStoreTestSkipsPrivateExistingTemplate() {
156+
public void shouldDownloadTemplateToStoreTestReplicatesPrivateTemplateUnderCopyLimit() {
157+
DataStore storeWithCopy = Mockito.mock(DataStore.class);
158+
Mockito.doReturn(10L).when(storeWithCopy).getId();
159+
Mockito.when(templateManagerMock.getSecStorageCopyLimit(tmpltMock, zoneScopeMock.getScopeId())).thenReturn(2);
160+
Mockito.doReturn(List.of(storeWithCopy)).when(dataStoreManagerMock).getImageStoresByScope(Mockito.any());
161+
Mockito.doReturn(List.of(Mockito.mock(TemplateDataStoreVO.class))).when(templateDataStoreDao).listByTemplateStore(2L, 10L);
157162
Mockito.when(templateDataStoreDao.findByTemplateZone(tmpltMock.getId(), zoneScopeMock.getScopeId(), DataStoreRole.Image)).thenReturn(Mockito.mock(TemplateDataStoreVO.class));
163+
Assert.assertTrue(templateService.shouldDownloadTemplateToStore(tmpltMock, dataStoreMock));
164+
}
165+
166+
@Test
167+
public void shouldDownloadTemplateToStoreTestSkipsPrivateTemplateAtCopyLimit() {
168+
DataStore storeWithCopy = Mockito.mock(DataStore.class);
169+
Mockito.doReturn(10L).when(storeWithCopy).getId();
170+
Mockito.when(templateManagerMock.getSecStorageCopyLimit(tmpltMock, zoneScopeMock.getScopeId())).thenReturn(1);
171+
Mockito.doReturn(List.of(storeWithCopy)).when(dataStoreManagerMock).getImageStoresByScope(Mockito.any());
172+
Mockito.doReturn(List.of(Mockito.mock(TemplateDataStoreVO.class))).when(templateDataStoreDao).listByTemplateStore(2L, 10L);
158173
Assert.assertFalse(templateService.shouldDownloadTemplateToStore(tmpltMock, dataStoreMock));
159174
}
160175

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,10 @@ protected boolean isZoneAndImageStoreAvailable(DataStore imageStore, Long zoneId
204204
}
205205

206206
/**
207-
* If the template/ISO is marked as private, then it is allocated to a random secondary storage; otherwise, allocates to every storage pool in every zone given by the
208-
* {@link TemplateProfile#getZoneIdList()}.
207+
* Allocates the template/ISO to a single image store - the one the file will be uploaded to. The upload can only
208+
* target one secondary store, so additional copies (up to the configured secstorage.public/private.template.copy.max)
209+
* are propagated later by template sync instead of being pre-allocated here as empty placeholder entries that never
210+
* receive the data.
209211
*/
210212
protected void postUploadAllocation(List<DataStore> imageStores, VMTemplateVO template, List<TemplateOrVolumePostUploadCommand> payloads) {
211213
Map<Long, Integer> zoneCopyCount = new HashMap<>();
@@ -248,6 +250,11 @@ protected void postUploadAllocation(List<DataStore> imageStores, VMTemplateVO te
248250
payload.setRequiresHvm(template.requiresHvm());
249251
payload.setDescription(template.getDisplayText());
250252
payloads.add(payload);
253+
254+
// The file can only be uploaded to a single secondary store. Allocate just this one; additional copies
255+
// up to the configured secondary storage copy limit are propagated afterwards by template sync, so we do
256+
// not create empty placeholder template_store_ref rows on the other stores.
257+
break;
251258
}
252259
}
253260

0 commit comments

Comments
 (0)