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 @@ -64,6 +64,7 @@
import org.apache.cloudstack.storage.command.DeleteCommand;
import org.apache.cloudstack.storage.datastore.DataObjectManager;
import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager;
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity;
Expand Down Expand Up @@ -163,6 +164,8 @@ public class TemplateServiceImpl implements TemplateService {
TemplateDataFactory imageFactory;
@Inject
StorageOrchestrationService storageOrchestrator;
@Inject
ImageStoreDao dataStoreDao;

class TemplateOpContext<T> extends AsyncRpcContext<T> {
final TemplateObject template;
Expand Down Expand Up @@ -295,10 +298,16 @@ public void handleSysTemplateDownload(HypervisorType hostHyper, Long dcId) {
}

protected boolean shouldDownloadTemplateToStore(VMTemplateVO template, DataStore store) {
if (dataStoreDao.findById(store.getId()).isReadonly()) {
logger.debug("Template [{}] will not be downloaded to image store [{}] because this store is marked as read-only.", template.getUniqueName(),
store.getName());
return false;
}

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.",
logger.info("Template [{}] will not be downloaded to image store [{}], as a heuristic rule is directing it to another store.",
template.getUniqueName(), store.getName());
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.engine.subsystem.api.storage.Scope;
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
import org.apache.cloudstack.storage.image.store.TemplateObject;
Expand Down Expand Up @@ -104,6 +106,12 @@ public class TemplateServiceImplTest {
@Mock
DataCenterDao _dcDao;

@Mock
ImageStoreDao imageStore;

@Mock
ImageStoreVO imageMock;

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

@Before
Expand All @@ -119,45 +127,59 @@ public void setUp() {
Mockito.doReturn(templateInfoMock).when(templateDataFactoryMock).getTemplate(2L, sourceStoreMock);
Mockito.doReturn(3L).when(dataStoreMock).getId();
Mockito.doReturn(zoneScopeMock).when(dataStoreMock).getScope();
Mockito.when(imageStore.findById(3L)).thenReturn(imageMock);
}

@Test
public void shouldDownloadTemplateToStoreTestSkipsTemplateDirectedToAnotherStorage() {
DataStore destinedStore = Mockito.mock(DataStore.class);
Mockito.when(imageMock.isReadonly()).thenReturn(false);
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 shouldDownloadTemplateToStoreTestDownloadsPublicTemplate() {
Mockito.when(imageMock.isReadonly()).thenReturn(false);
Mockito.when(tmpltMock.isPublicTemplate()).thenReturn(true);
Assert.assertTrue(templateService.shouldDownloadTemplateToStore(tmpltMock, dataStoreMock));
}

@Test
public void shouldDownloadTemplateToStoreTestDownloadsFeaturedTemplate() {
Mockito.when(imageMock.isReadonly()).thenReturn(false);
Mockito.when(tmpltMock.isFeatured()).thenReturn(true);
Assert.assertTrue(templateService.shouldDownloadTemplateToStore(tmpltMock, dataStoreMock));
}

@Test
public void shouldDownloadTemplateToStoreTestDownloadsSystemTemplate() {
Mockito.when(imageMock.isReadonly()).thenReturn(false);
Mockito.when(tmpltMock.getTemplateType()).thenReturn(Storage.TemplateType.SYSTEM);
Assert.assertTrue(templateService.shouldDownloadTemplateToStore(tmpltMock, dataStoreMock));
}

@Test
public void shouldDownloadTemplateToStoreTestDownloadsPrivateNoRefTemplate() {
Mockito.when(imageMock.isReadonly()).thenReturn(false);
Assert.assertTrue(templateService.shouldDownloadTemplateToStore(tmpltMock, dataStoreMock));
}

@Test
public void shouldDownloadTemplateToStoreTestSkipsPrivateExistingTemplate() {
Mockito.when(imageMock.isReadonly()).thenReturn(false);
Mockito.when(templateDataStoreDao.findByTemplateZone(tmpltMock.getId(), zoneScopeMock.getScopeId(), DataStoreRole.Image)).thenReturn(Mockito.mock(TemplateDataStoreVO.class));
Assert.assertFalse(templateService.shouldDownloadTemplateToStore(tmpltMock, dataStoreMock));
}

@Test
public void shouldDownloadTemplateToStoreTestSkipsWhenStorageIsReadOnly() {
Mockito.when(imageMock.isReadonly()).thenReturn(true);
Assert.assertFalse(templateService.shouldDownloadTemplateToStore(tmpltMock, dataStoreMock));

}

@Test
public void tryDownloadingTemplateToImageStoreTestDownloadsTemplateWhenUrlIsNotNull() {
Mockito.doReturn("url").when(tmpltMock).getUrl();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import org.apache.cloudstack.storage.command.CommandResult;
import org.apache.cloudstack.storage.command.CopyCommand;
import org.apache.cloudstack.storage.command.DeleteCommand;
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
Expand Down Expand Up @@ -126,6 +127,8 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
AgentManager agentMgr;
@Inject
DataStoreManager dataStoreManager;
@Inject
ImageStoreDao dataStoreDao;

protected String _proxy = null;

Expand Down Expand Up @@ -175,10 +178,13 @@ public void createAsync(DataStore dataStore, DataObject data, AsyncCompletionCal
AsyncCallbackDispatcher<BaseImageStoreDriverImpl, DownloadAnswer> caller = AsyncCallbackDispatcher.create(this);
caller.setContext(context);
if (data.getType() == DataObjectType.TEMPLATE) {
caller.setCallback(caller.getTarget().createTemplateAsyncCallback(null, null));
if (logger.isDebugEnabled()) {
logger.debug("Downloading template to data store {}", dataStore);
if (dataStoreDao.findById(dataStore.getId()).isReadonly()) {
logger.debug("Template [{}] will not be downloaded to image store [{}] because this store is marked as read-only.", data.getName(),
dataStore.getName());
return;
}
caller.setCallback(caller.getTarget().createTemplateAsyncCallback(null, null));
logger.debug("Downloading template [{}] to data store [{}].", data.getName(), dataStore.getName());
_downloadMonitor.downloadTemplateToStorage(data, caller);
} else if (data.getType() == DataObjectType.VOLUME) {
caller.setCallback(caller.getTarget().createVolumeAsyncCallback(null, null));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,11 @@ protected boolean isZoneAndImageStoreAvailable(DataStore imageStore, Long zoneId
return false;
}

if (_imgStoreDao.findById(imageStore.getId()).isReadonly()) {
logger.info("Image store [{}] is marked as read-only. Skip downloading template to this image store.", imageStore);
return false;
}

if (!_statsCollector.imageStoreHasEnoughCapacity(imageStore)) {
logger.info("Image store doesn't have enough capacity. Skip downloading template to this image store [{}].", imageStore);
return false;
Expand Down