Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ public interface TemplateManager {

TemplateType validateTemplateType(BaseCmd cmd, boolean isAdmin, boolean isCrossZones);

DataStore verifyHeuristicRulesForZone(VMTemplateVO template, Long zoneId);

List<DatadiskTO> getTemplateDisksOnImageStore(VirtualMachineTemplate template, DataStoreRole role, String configurationId);

static Boolean getValidateUrlIsResolvableBeforeRegisteringTemplateValue() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,21 +290,41 @@ public void handleSysTemplateDownload(HypervisorType hostHyper, Long dcId) {
}
}

protected boolean isSkipTemplateStoreDownload(VMTemplateVO template, Long zoneId) {
if (template.isPublicTemplate()) {
protected boolean shouldDownloadTemplateToStore(VMTemplateVO template, DataStore store) {
Long zoneId = store.getScope().getScopeId();
DataStore directedStore = _tmpltMgr.verifyHeuristicRulesForZone(template, zoneId);
if (directedStore != null && store.getId() != directedStore.getId()) {
logger.info("Template [{}] will not be download to image store [{}], as a heuristic rule is directing it to another store.",
template.getUniqueName(), store.getName());
return false;
}

if (template.isPublicTemplate()) {
logger.debug("Download of template [{}] to image store [{}] cannot be skipped, as it is public.", template.getUniqueName(),
store.getName());
return true;
}

if (template.isFeatured()) {
return false;
logger.debug("Download of template [{}] to image store [{}] cannot be skipped, as it is featured.", template.getUniqueName(),
store.getName());
return true;
}

if (TemplateType.SYSTEM.equals(template.getTemplateType())) {
return false;
logger.debug("Download of template [{}] to image store [{}] cannot be skipped, as it is a system VM template.",
template.getUniqueName(),store.getName());
return true;
}

if (zoneId != null && _vmTemplateStoreDao.findByTemplateZone(template.getId(), zoneId, DataStoreRole.Image) == null) {
logger.debug("Template {} is not present on any image store for the zone ID: {}, its download cannot be skipped", template, zoneId);
return false;
logger.debug("Download of template [{}] to image store [{}] cannot be skipped, as it is not present on any image store of zone [{}].",
template.getUniqueName(), store.getName(), zoneId);
return true;
}
return true;

logger.info("Skipping download of template [{}] to image store [{}].", template.getUniqueName(), store.getName());
return false;
}

@Override
Expand Down Expand Up @@ -531,8 +551,7 @@ public void handleTemplateSync(DataStore store) {
// download.
for (VMTemplateVO tmplt : toBeDownloaded) {
// if this is private template, skip sync to a new image store
if (isSkipTemplateStoreDownload(tmplt, zoneId)) {
logger.info("Skip sync downloading private template {} to a new image store", tmplt);
if (!shouldDownloadTemplateToStore(tmplt, store)) {
continue;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package org.apache.cloudstack.storage.image;

import com.cloud.storage.template.TemplateProp;
import com.cloud.template.TemplateManager;
import org.apache.cloudstack.engine.orchestration.service.StorageOrchestrationService;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
Expand Down Expand Up @@ -70,6 +71,9 @@ public class TemplateServiceImplTest {
@Mock
TemplateObject templateInfoMock;

@Mock
DataStore dataStoreMock;

@Mock
DataStore sourceStoreMock;

Expand All @@ -82,6 +86,9 @@ public class TemplateServiceImplTest {
@Mock
StorageOrchestrationService storageOrchestrator;

@Mock
TemplateManager templateManagerMock;

Map<String, TemplateProp> templatesInSourceStore = new HashMap<>();

@Before
Expand All @@ -96,45 +103,45 @@ public void setUp() {
Mockito.doReturn(null).when(templateService).listTemplate(destStoreMock);
Mockito.doReturn("install-path").when(templateInfoMock).getInstallPath();
Mockito.doReturn(templateInfoMock).when(templateDataFactoryMock).getTemplate(2L, sourceStoreMock);
Mockito.doReturn(3L).when(dataStoreMock).getId();
Mockito.doReturn(zoneScopeMock).when(dataStoreMock).getScope();
}

@Test
public void shouldDownloadTemplateToStoreTestSkipsTemplateDirectedToAnotherStorage() {
DataStore destinedStore = Mockito.mock(DataStore.class);
Mockito.doReturn(dataStoreMock.getId() + 1L).when(destinedStore).getId();
Mockito.when(templateManagerMock.verifyHeuristicRulesForZone(tmpltMock, zoneScopeMock.getScopeId())).thenReturn(destinedStore);
Assert.assertFalse(templateService.shouldDownloadTemplateToStore(tmpltMock, dataStoreMock));
}

@Test
public void testIsSkipTemplateStoreDownloadPublicTemplate() {
VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class);
Mockito.when(templateVO.isPublicTemplate()).thenReturn(true);
Assert.assertFalse(templateService.isSkipTemplateStoreDownload(templateVO, 1L));
public void shouldDownloadTemplateToStoreTestDownloadsPublicTemplate() {
Mockito.when(tmpltMock.isPublicTemplate()).thenReturn(true);
Assert.assertTrue(templateService.shouldDownloadTemplateToStore(tmpltMock, dataStoreMock));
}

@Test
public void testIsSkipTemplateStoreDownloadFeaturedTemplate() {
VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class);
Mockito.when(templateVO.isFeatured()).thenReturn(true);
Assert.assertFalse(templateService.isSkipTemplateStoreDownload(templateVO, 1L));
public void shouldDownloadTemplateToStoreTestDownloadsFeaturedTemplate() {
Mockito.when(tmpltMock.isFeatured()).thenReturn(true);
Assert.assertTrue(templateService.shouldDownloadTemplateToStore(tmpltMock, dataStoreMock));
}

@Test
public void testIsSkipTemplateStoreDownloadSystemTemplate() {
VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class);
Mockito.when(templateVO.getTemplateType()).thenReturn(Storage.TemplateType.SYSTEM);
Assert.assertFalse(templateService.isSkipTemplateStoreDownload(templateVO, 1L));
public void shouldDownloadTemplateToStoreTestDownloadsSystemTemplate() {
Mockito.when(tmpltMock.getTemplateType()).thenReturn(Storage.TemplateType.SYSTEM);
Assert.assertTrue(templateService.shouldDownloadTemplateToStore(tmpltMock, dataStoreMock));
}

@Test
public void testIsSkipTemplateStoreDownloadPrivateNoRefTemplate() {
VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class);
long id = 1L;
Mockito.when(templateVO.getId()).thenReturn(id);
Mockito.when(templateDataStoreDao.findByTemplateZone(id, id, DataStoreRole.Image)).thenReturn(null);
Assert.assertFalse(templateService.isSkipTemplateStoreDownload(templateVO, id));
public void shouldDownloadTemplateToStoreTestDownloadsPrivateNoRefTemplate() {
Assert.assertTrue(templateService.shouldDownloadTemplateToStore(tmpltMock, dataStoreMock));
}

@Test
public void testIsSkipTemplateStoreDownloadPrivateExistingTemplate() {
VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class);
long id = 1L;
Mockito.when(templateVO.getId()).thenReturn(id);
Mockito.when(templateDataStoreDao.findByTemplateZone(id, id, DataStoreRole.Image)).thenReturn(Mockito.mock(TemplateDataStoreVO.class));
Assert.assertTrue(templateService.isSkipTemplateStoreDownload(templateVO, id));
public void shouldDownloadTemplateToStoreTestSkipsPrivateExistingTemplate() {
Mockito.when(templateDataStoreDao.findByTemplateZone(tmpltMock.getId(), zoneScopeMock.getScopeId(), DataStoreRole.Image)).thenReturn(Mockito.mock(TemplateDataStoreVO.class));
Assert.assertFalse(templateService.shouldDownloadTemplateToStore(tmpltMock, dataStoreMock));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@
import org.apache.cloudstack.framework.async.AsyncRpcContext;
import org.apache.cloudstack.framework.messagebus.MessageBus;
import org.apache.cloudstack.framework.messagebus.PublishScope;
import org.apache.cloudstack.secstorage.heuristics.HeuristicType;
import org.apache.cloudstack.storage.command.TemplateOrVolumePostUploadCommand;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
Expand Down Expand Up @@ -308,7 +307,7 @@ protected void createTemplateWithinZones(TemplateProfile profile, VMTemplateVO t


for (long zoneId : zonesIds) {
DataStore imageStore = verifyHeuristicRulesForZone(template, zoneId);
DataStore imageStore = templateMgr.verifyHeuristicRulesForZone(template, zoneId);

if (imageStore == null) {
List<DataStore> imageStores = getImageStoresThrowsExceptionIfNotFound(zoneId, profile);
Expand All @@ -327,16 +326,6 @@ protected List<DataStore> getImageStoresThrowsExceptionIfNotFound(long zoneId, T
return imageStores;
}

protected DataStore verifyHeuristicRulesForZone(VMTemplateVO template, Long zoneId) {
HeuristicType heuristicType;
if (ImageFormat.ISO.equals(template.getFormat())) {
heuristicType = HeuristicType.ISO;
} else {
heuristicType = HeuristicType.TEMPLATE;
}
return heuristicRuleHelper.getImageStoreIfThereIsHeuristicRule(zoneId, heuristicType, template);
}

protected void standardImageStoreAllocation(List<DataStore> imageStores, VMTemplateVO template) {
Set<Long> zoneSet = new HashSet<Long>();
Collections.shuffle(imageStores);
Expand Down Expand Up @@ -432,7 +421,7 @@ public List<TemplateOrVolumePostUploadCommand> doInTransaction(TransactionStatus
}

Long zoneId = zoneIdList.get(0);
DataStore imageStore = verifyHeuristicRulesForZone(template, zoneId);
DataStore imageStore = templateMgr.verifyHeuristicRulesForZone(template, zoneId);
List<TemplateOrVolumePostUploadCommand> payloads = new LinkedList<>();

if (imageStore == null) {
Expand Down
11 changes: 11 additions & 0 deletions server/src/main/java/com/cloud/template/TemplateManagerImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -2347,6 +2347,17 @@ public TemplateType validateTemplateType(BaseCmd cmd, boolean isAdmin, boolean i
return templateType;
}

@Override
public DataStore verifyHeuristicRulesForZone(VMTemplateVO template, Long zoneId) {
HeuristicType heuristicType;
if (ImageFormat.ISO.equals(template.getFormat())) {
heuristicType = HeuristicType.ISO;
} else {
heuristicType = HeuristicType.TEMPLATE;
}
return heuristicRuleHelper.getImageStoreIfThereIsHeuristicRule(zoneId, heuristicType, template);
}

void validateDetails(VMTemplateVO template, Map<String, String> details) {
if (MapUtils.isEmpty(details)) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@
import org.apache.cloudstack.framework.events.Event;
import org.apache.cloudstack.framework.events.EventDistributor;
import org.apache.cloudstack.framework.messagebus.MessageBus;
import org.apache.cloudstack.secstorage.heuristics.HeuristicType;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
import org.apache.cloudstack.storage.heuristics.HeuristicRuleHelper;
Expand Down Expand Up @@ -339,7 +338,7 @@ public void createTemplateWithinZonesTestZoneIdsNotNullShouldNotCallListAllZones

Mockito.when(templateProfileMock.getZoneIdList()).thenReturn(zoneIds);
Mockito.doReturn(null).when(_adapter).getImageStoresThrowsExceptionIfNotFound(Mockito.any(Long.class), Mockito.any(TemplateProfile.class));
Mockito.doReturn(null).when(_adapter).verifyHeuristicRulesForZone(Mockito.any(VMTemplateVO.class), Mockito.anyLong());
Mockito.doReturn(null).when(_templateMgr).verifyHeuristicRulesForZone(Mockito.any(VMTemplateVO.class), Mockito.anyLong());
Mockito.doNothing().when(_adapter).standardImageStoreAllocation(Mockito.isNull(), Mockito.any(VMTemplateVO.class));

_adapter.createTemplateWithinZones(templateProfileMock, vmTemplateVOMock);
Expand All @@ -355,7 +354,7 @@ public void createTemplateWithinZonesTestZoneDoesNotHaveActiveHeuristicRulesShou

Mockito.when(templateProfileMock.getZoneIdList()).thenReturn(zoneIds);
Mockito.doReturn(null).when(_adapter).getImageStoresThrowsExceptionIfNotFound(Mockito.any(Long.class), Mockito.any(TemplateProfile.class));
Mockito.doReturn(null).when(_adapter).verifyHeuristicRulesForZone(Mockito.any(VMTemplateVO.class), Mockito.anyLong());
Mockito.doReturn(null).when(_templateMgr).verifyHeuristicRulesForZone(Mockito.any(VMTemplateVO.class), Mockito.anyLong());
Mockito.doNothing().when(_adapter).standardImageStoreAllocation(Mockito.isNull(), Mockito.any(VMTemplateVO.class));

_adapter.createTemplateWithinZones(templateProfileMock, vmTemplateVOMock);
Expand All @@ -371,7 +370,7 @@ public void createTemplateWithinZonesTestZoneWithHeuristicRuleShouldCallValidate
List<Long> zoneIds = List.of(1L);

Mockito.when(templateProfileMock.getZoneIdList()).thenReturn(zoneIds);
Mockito.doReturn(dataStoreMock).when(_adapter).verifyHeuristicRulesForZone(Mockito.any(VMTemplateVO.class), Mockito.anyLong());
Mockito.doReturn(dataStoreMock).when(_templateMgr).verifyHeuristicRulesForZone(Mockito.any(VMTemplateVO.class), Mockito.anyLong());
Mockito.doNothing().when(_adapter).validateSecondaryStorageAndCreateTemplate(Mockito.any(List.class), Mockito.any(VMTemplateVO.class), Mockito.isNull());

_adapter.createTemplateWithinZones(templateProfileMock, vmTemplateVOMock);
Expand Down Expand Up @@ -409,26 +408,6 @@ public void getImageStoresThrowsExceptionIfNotFoundTestNonEmptyImageStoreShouldN
_adapter.getImageStoresThrowsExceptionIfNotFound(zoneId, templateProfileMock);
}

@Test
public void verifyHeuristicRulesForZoneTestTemplateIsISOFormatShouldCheckForISOHeuristicType() {
VMTemplateVO vmTemplateVOMock = Mockito.mock(VMTemplateVO.class);

Mockito.when(vmTemplateVOMock.getFormat()).thenReturn(ImageFormat.ISO);
_adapter.verifyHeuristicRulesForZone(vmTemplateVOMock, 1L);

Mockito.verify(heuristicRuleHelperMock, Mockito.times(1)).getImageStoreIfThereIsHeuristicRule(1L, HeuristicType.ISO, vmTemplateVOMock);
}

@Test
public void verifyHeuristicRulesForZoneTestTemplateNotISOFormatShouldCheckForTemplateHeuristicType() {
VMTemplateVO vmTemplateVOMock = Mockito.mock(VMTemplateVO.class);

Mockito.when(vmTemplateVOMock.getFormat()).thenReturn(ImageFormat.QCOW2);
_adapter.verifyHeuristicRulesForZone(vmTemplateVOMock, 1L);

Mockito.verify(heuristicRuleHelperMock, Mockito.times(1)).getImageStoreIfThereIsHeuristicRule(1L, HeuristicType.TEMPLATE, vmTemplateVOMock);
}

@Test
public void isZoneAndImageStoreAvailableTestZoneIdIsNullShouldReturnFalse() {
DataStore dataStoreMock = Mockito.mock(DataStore.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,26 @@ public void testDeleteTemplateWithTemplateType() {
Assert.assertNull(type);
}

@Test
public void verifyHeuristicRulesForZoneTestTemplateIsISOFormatShouldCheckForISOHeuristicType() {
VMTemplateVO vmTemplateVOMock = Mockito.mock(VMTemplateVO.class);

Mockito.when(vmTemplateVOMock.getFormat()).thenReturn(Storage.ImageFormat.ISO);
templateManager.verifyHeuristicRulesForZone(vmTemplateVOMock, 1L);

Mockito.verify(heuristicRuleHelperMock, Mockito.times(1)).getImageStoreIfThereIsHeuristicRule(1L, HeuristicType.ISO, vmTemplateVOMock);
}

@Test
public void verifyHeuristicRulesForZoneTestTemplateNotISOFormatShouldCheckForTemplateHeuristicType() {
VMTemplateVO vmTemplateVOMock = Mockito.mock(VMTemplateVO.class);

Mockito.when(vmTemplateVOMock.getFormat()).thenReturn(Storage.ImageFormat.QCOW2);
templateManager.verifyHeuristicRulesForZone(vmTemplateVOMock, 1L);

Mockito.verify(heuristicRuleHelperMock, Mockito.times(1)).getImageStoreIfThereIsHeuristicRule(1L, HeuristicType.TEMPLATE, vmTemplateVOMock);
}

@Configuration
@ComponentScan(basePackageClasses = {TemplateManagerImpl.class},
includeFilters = {@ComponentScan.Filter(value = TestConfiguration.Library.class, type = FilterType.CUSTOM)},
Expand Down
Loading