mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Migrate public templates that have URLs on data migration across secondary storages (#10364)
Co-authored-by: Fabricio Duarte <fabricio.duarte@scclouds.com.br>
This commit is contained in:
parent
6de084ca97
commit
ac6b1b382c
@ -17,6 +17,7 @@
|
|||||||
package com.cloud.storage;
|
package com.cloud.storage;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.cloudstack.api.InternalIdentity;
|
import org.apache.cloudstack.api.InternalIdentity;
|
||||||
|
|
||||||
@ -25,6 +26,8 @@ public interface VMTemplateStorageResourceAssoc extends InternalIdentity {
|
|||||||
UNKNOWN, DOWNLOAD_ERROR, NOT_DOWNLOADED, DOWNLOAD_IN_PROGRESS, DOWNLOADED, ABANDONED, UPLOADED, NOT_UPLOADED, UPLOAD_ERROR, UPLOAD_IN_PROGRESS, CREATING, CREATED, BYPASSED
|
UNKNOWN, DOWNLOAD_ERROR, NOT_DOWNLOADED, DOWNLOAD_IN_PROGRESS, DOWNLOADED, ABANDONED, UPLOADED, NOT_UPLOADED, UPLOAD_ERROR, UPLOAD_IN_PROGRESS, CREATING, CREATED, BYPASSED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<Status> PENDING_DOWNLOAD_STATES = List.of(Status.NOT_DOWNLOADED, Status.DOWNLOAD_IN_PROGRESS);
|
||||||
|
|
||||||
String getInstallPath();
|
String getInstallPath();
|
||||||
|
|
||||||
long getTemplateId();
|
long getTemplateId();
|
||||||
|
|||||||
@ -208,9 +208,7 @@ public class DataMigrationUtility {
|
|||||||
List<TemplateInfo> files = new LinkedList<>();
|
List<TemplateInfo> files = new LinkedList<>();
|
||||||
for (TemplateDataStoreVO template : templates) {
|
for (TemplateDataStoreVO template : templates) {
|
||||||
VMTemplateVO templateVO = templateDao.findById(template.getTemplateId());
|
VMTemplateVO templateVO = templateDao.findById(template.getTemplateId());
|
||||||
if (template.getState() == ObjectInDataStoreStateMachine.State.Ready && templateVO != null &&
|
if (shouldMigrateTemplate(template, templateVO)) {
|
||||||
(!templateVO.isPublicTemplate() || (templateVO.isPublicTemplate() && templateVO.getUrl() == null)) &&
|
|
||||||
templateVO.getHypervisorType() != Hypervisor.HypervisorType.Simulator && templateVO.getParentTemplateId() == null) {
|
|
||||||
files.add(templateFactory.getTemplate(template.getTemplateId(), srcDataStore));
|
files.add(templateFactory.getTemplate(template.getTemplateId(), srcDataStore));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -231,6 +229,34 @@ public class DataMigrationUtility {
|
|||||||
return getAllReadyTemplates(srcDataStore, childTemplates, templates);
|
return getAllReadyTemplates(srcDataStore, childTemplates, templates);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether a template should be migrated. A template should be migrated if:
|
||||||
|
* <ol>
|
||||||
|
* <li>its state is ready, and</li>
|
||||||
|
* <li>its hypervisor type is not simulator, and</li>
|
||||||
|
* <li>it is not a child template.</li>
|
||||||
|
* </ol>
|
||||||
|
*/
|
||||||
|
protected boolean shouldMigrateTemplate(TemplateDataStoreVO template, VMTemplateVO templateVO) {
|
||||||
|
if (template.getState() != State.Ready) {
|
||||||
|
logger.debug("Template [{}] should not be migrated as it is not ready.", template);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (templateVO.getHypervisorType() == Hypervisor.HypervisorType.Simulator) {
|
||||||
|
logger.debug("Template [{}] should not be migrated as its hypervisor type is simulator.", template);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (templateVO.getParentTemplateId() != null) {
|
||||||
|
logger.debug("Template [{}] should not be migrated as it has a parent template.", template);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug("Template [{}] should be migrated.", template);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns parent snapshots and snapshots that do not have any children; snapshotChains comprises of the snapshot chain info
|
/** Returns parent snapshots and snapshots that do not have any children; snapshotChains comprises of the snapshot chain info
|
||||||
* for each parent snapshot and the cumulative size of the chain - this is done to ensure that all the snapshots in a chain
|
* for each parent snapshot and the cumulative size of the chain - this is done to ensure that all the snapshots in a chain
|
||||||
* are migrated to the same datastore
|
* are migrated to the same datastore
|
||||||
|
|||||||
@ -0,0 +1,88 @@
|
|||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you under the Apache License, Version 2.0 (the
|
||||||
|
// "License"); you may not use this file except in compliance
|
||||||
|
// with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing,
|
||||||
|
// software distributed under the License is distributed on an
|
||||||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
package org.apache.cloudstack.engine.orchestration;
|
||||||
|
|
||||||
|
import com.cloud.hypervisor.Hypervisor;
|
||||||
|
import com.cloud.storage.VMTemplateVO;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.Spy;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class DataMigrationUtilityTest extends TestCase {
|
||||||
|
|
||||||
|
@Spy
|
||||||
|
private DataMigrationUtility dataMigrationUtility;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private VMTemplateVO templateVoMock;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private TemplateDataStoreVO templateDataStoreVoMock;
|
||||||
|
|
||||||
|
private void prepareForShouldMigrateTemplateTests() {
|
||||||
|
Mockito.when(templateDataStoreVoMock.getState()).thenReturn(ObjectInDataStoreStateMachine.State.Ready);
|
||||||
|
Mockito.when(templateVoMock.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
|
||||||
|
Mockito.when(templateVoMock.getParentTemplateId()).thenReturn(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldMigrateTemplateTestReturnsFalseWhenTemplateIsNotReady() {
|
||||||
|
prepareForShouldMigrateTemplateTests();
|
||||||
|
Mockito.when(templateDataStoreVoMock.getState()).thenReturn(ObjectInDataStoreStateMachine.State.Migrating);
|
||||||
|
|
||||||
|
boolean result = dataMigrationUtility.shouldMigrateTemplate(templateDataStoreVoMock, templateVoMock);
|
||||||
|
|
||||||
|
Assert.assertFalse(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldMigrateTemplateTestReturnsFalseWhenHypervisorTypeIsSimulator() {
|
||||||
|
prepareForShouldMigrateTemplateTests();
|
||||||
|
Mockito.when(templateVoMock.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.Simulator);
|
||||||
|
|
||||||
|
boolean result = dataMigrationUtility.shouldMigrateTemplate(templateDataStoreVoMock, templateVoMock);
|
||||||
|
|
||||||
|
Assert.assertFalse(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldMigrateTemplateTestReturnsFalseWhenTemplateHasParentTemplate() {
|
||||||
|
prepareForShouldMigrateTemplateTests();
|
||||||
|
Mockito.when(templateVoMock.getParentTemplateId()).thenReturn(1L);
|
||||||
|
|
||||||
|
boolean result = dataMigrationUtility.shouldMigrateTemplate(templateDataStoreVoMock, templateVoMock);
|
||||||
|
|
||||||
|
Assert.assertFalse(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldMigrateTemplateTestReturnsTrueWhenTemplateIsReadyAndDoesNotHaveParentTemplateAndHypervisorTypeIsNotSimulator() {
|
||||||
|
prepareForShouldMigrateTemplateTests();
|
||||||
|
|
||||||
|
boolean result = dataMigrationUtility.shouldMigrateTemplate(templateDataStoreVoMock, templateVoMock);
|
||||||
|
|
||||||
|
Assert.assertTrue(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -24,6 +24,9 @@ import java.util.concurrent.ExecutionException;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import com.cloud.storage.VMTemplateStorageResourceAssoc;
|
||||||
|
import com.cloud.storage.download.DownloadListener;
|
||||||
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
|
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionService;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionService;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
|
||||||
@ -118,26 +121,21 @@ public class SecondaryStorageServiceImpl implements SecondaryStorageService {
|
|||||||
}
|
}
|
||||||
} else if (srcDataObject instanceof TemplateInfo && templateChain != null && templateChain.containsKey(srcDataObject)) {
|
} else if (srcDataObject instanceof TemplateInfo && templateChain != null && templateChain.containsKey(srcDataObject)) {
|
||||||
for (TemplateInfo templateInfo : templateChain.get(srcDataObject).first()) {
|
for (TemplateInfo templateInfo : templateChain.get(srcDataObject).first()) {
|
||||||
|
if (templateIsOnDestination(templateInfo, destDatastore)) {
|
||||||
|
res.setResult("Template already exists on destination.");
|
||||||
|
res.setSuccess(true);
|
||||||
|
logger.debug("Deleting template {} from source data store [{}].", srcDataObject.getTO().toString(),
|
||||||
|
srcDataObject.getDataStore().getTO().toString());
|
||||||
|
srcDataObject.getDataStore().delete(srcDataObject);
|
||||||
|
future.complete(res);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
destDataObject = destDatastore.create(templateInfo);
|
destDataObject = destDatastore.create(templateInfo);
|
||||||
templateInfo.processEvent(ObjectInDataStoreStateMachine.Event.MigrateDataRequested);
|
templateInfo.processEvent(ObjectInDataStoreStateMachine.Event.MigrateDataRequested);
|
||||||
destDataObject.processEvent(ObjectInDataStoreStateMachine.Event.MigrateDataRequested);
|
destDataObject.processEvent(ObjectInDataStoreStateMachine.Event.MigrateDataRequested);
|
||||||
migrateJob(future, templateInfo, destDataObject, destDatastore);
|
migrateJob(future, templateInfo, destDataObject, destDatastore);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// Check if template in destination store, if yes, do not proceed
|
|
||||||
if (srcDataObject instanceof TemplateInfo) {
|
|
||||||
logger.debug("Checking if template present at destination");
|
|
||||||
TemplateDataStoreVO templateStoreVO = templateStoreDao.findByStoreTemplate(destDatastore.getId(), srcDataObject.getId());
|
|
||||||
if (templateStoreVO != null) {
|
|
||||||
String msg = "Template already exists in destination store";
|
|
||||||
logger.debug(msg);
|
|
||||||
res.setResult(msg);
|
|
||||||
res.setSuccess(true);
|
|
||||||
future.complete(res);
|
|
||||||
return future;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
destDataObject = destDatastore.create(srcDataObject);
|
destDataObject = destDatastore.create(srcDataObject);
|
||||||
srcDataObject.processEvent(ObjectInDataStoreStateMachine.Event.MigrateDataRequested);
|
srcDataObject.processEvent(ObjectInDataStoreStateMachine.Event.MigrateDataRequested);
|
||||||
destDataObject.processEvent(ObjectInDataStoreStateMachine.Event.MigrateDataRequested);
|
destDataObject.processEvent(ObjectInDataStoreStateMachine.Event.MigrateDataRequested);
|
||||||
@ -160,6 +158,69 @@ public class SecondaryStorageServiceImpl implements SecondaryStorageService {
|
|||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a boolean indicating whether a template is ready on the provided data store. If the template is being downloaded,
|
||||||
|
* waits until the download finishes.
|
||||||
|
* @param srcDataObject the template.
|
||||||
|
* @param destDatastore the data store.
|
||||||
|
*/
|
||||||
|
protected boolean templateIsOnDestination(DataObject srcDataObject, DataStore destDatastore) {
|
||||||
|
if (!(srcDataObject instanceof TemplateInfo)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String templateAsString = srcDataObject.getTO().toString();
|
||||||
|
String destDatastoreAsString = destDatastore.getTO().toString();
|
||||||
|
TemplateDataStoreVO templateStoreVO;
|
||||||
|
|
||||||
|
long timer = getTemplateDownloadTimeout();
|
||||||
|
long msToSleep = 10000L;
|
||||||
|
int previousDownloadPercentage = -1;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
templateStoreVO = templateStoreDao.findByStoreTemplate(destDatastore.getId(), srcDataObject.getId());
|
||||||
|
if (templateStoreVO == null) {
|
||||||
|
logger.debug("{} is not present at destination [{}].", templateAsString, destDatastoreAsString);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
VMTemplateStorageResourceAssoc.Status downloadState = templateStoreVO.getDownloadState();
|
||||||
|
if (downloadState == null || !VMTemplateStorageResourceAssoc.PENDING_DOWNLOAD_STATES.contains(downloadState)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (previousDownloadPercentage == templateStoreVO.getDownloadPercent()) {
|
||||||
|
timer -= msToSleep;
|
||||||
|
} else {
|
||||||
|
timer = getTemplateDownloadTimeout();
|
||||||
|
}
|
||||||
|
if (timer <= 0) {
|
||||||
|
throw new CloudRuntimeException(String.format("Timeout while waiting for %s to be downloaded to image store [%s]. " +
|
||||||
|
"The download percentage has not changed for %d milliseconds.", templateAsString, destDatastoreAsString, getTemplateDownloadTimeout()));
|
||||||
|
}
|
||||||
|
waitForTemplateDownload(msToSleep, templateAsString, destDatastoreAsString);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (templateStoreVO.getState() == ObjectInDataStoreStateMachine.State.Ready) {
|
||||||
|
logger.debug("{} already exists on destination [{}].", templateAsString, destDatastoreAsString);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected long getTemplateDownloadTimeout() {
|
||||||
|
return DownloadListener.DOWNLOAD_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void waitForTemplateDownload(long msToSleep, String templateAsString, String destDatastoreAsString) {
|
||||||
|
logger.debug("{} is being downloaded to destination [{}]; we will verify in {} milliseconds if the download has finished.",
|
||||||
|
templateAsString, destDatastoreAsString, msToSleep);
|
||||||
|
try {
|
||||||
|
Thread.sleep(msToSleep);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
logger.warn("[ignored] interrupted while waiting for template {} download to finish before trying to migrate it to data store [{}].",
|
||||||
|
templateAsString, destDatastoreAsString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void migrateJob(AsyncCallFuture<DataObjectResult> future, DataObject srcDataObject, DataObject destDataObject, DataStore destDatastore) throws ExecutionException, InterruptedException {
|
protected void migrateJob(AsyncCallFuture<DataObjectResult> future, DataObject srcDataObject, DataObject destDataObject, DataStore destDatastore) throws ExecutionException, InterruptedException {
|
||||||
MigrateDataContext<DataObjectResult> context = new MigrateDataContext<DataObjectResult>(null, future, srcDataObject, destDataObject, destDatastore);
|
MigrateDataContext<DataObjectResult> context = new MigrateDataContext<DataObjectResult>(null, future, srcDataObject, destDataObject, destDatastore);
|
||||||
AsyncCallbackDispatcher<SecondaryStorageServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
|
AsyncCallbackDispatcher<SecondaryStorageServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
|
||||||
|
|||||||
@ -0,0 +1,138 @@
|
|||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you under the Apache License, Version 2.0 (the
|
||||||
|
// "License"); you may not use this file except in compliance
|
||||||
|
// with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing,
|
||||||
|
// software distributed under the License is distributed on an
|
||||||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
package org.apache.cloudstack.storage.image;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.to.DataStoreTO;
|
||||||
|
import com.cloud.storage.VMTemplateStorageResourceAssoc;
|
||||||
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
|
||||||
|
import org.apache.cloudstack.storage.to.TemplateObjectTO;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.Spy;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class SecondaryStorageServiceImplTest extends TestCase {
|
||||||
|
|
||||||
|
@Spy
|
||||||
|
@InjectMocks
|
||||||
|
private SecondaryStorageServiceImpl secondaryStorageService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
TemplateDataStoreDao templateDataStoreDaoMock;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
TemplateDataStoreVO templateDataStoreVoMock;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
TemplateInfo templateInfoMock;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
TemplateObjectTO templateObjectToMock;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
DataStore dataStoreMock;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
DataStoreTO dataStoreToMock;
|
||||||
|
|
||||||
|
private void prepareForTemplateIsOnDestinationTests() {
|
||||||
|
long dataStoreId = 1;
|
||||||
|
long templateId = 2;
|
||||||
|
|
||||||
|
Mockito.when(dataStoreMock.getId()).thenReturn(dataStoreId);
|
||||||
|
Mockito.when(dataStoreMock.getTO()).thenReturn(dataStoreToMock);
|
||||||
|
Mockito.when(templateInfoMock.getId()).thenReturn(templateId);
|
||||||
|
Mockito.when(templateInfoMock.getTO()).thenReturn(templateObjectToMock);
|
||||||
|
Mockito.doReturn(templateDataStoreVoMock).when(templateDataStoreDaoMock).findByStoreTemplate(dataStoreId, templateId);
|
||||||
|
Mockito.when(templateDataStoreVoMock.getState()).thenReturn(ObjectInDataStoreStateMachine.State.Ready);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void templateIsOnDestinationTestReturnsFalseWhenTemplateStoreRefDoesNotExist() {
|
||||||
|
prepareForTemplateIsOnDestinationTests();
|
||||||
|
Mockito.doReturn(null).when(templateDataStoreDaoMock).findByStoreTemplate(Mockito.anyLong(), Mockito.anyLong());
|
||||||
|
|
||||||
|
boolean result = secondaryStorageService.templateIsOnDestination(templateInfoMock, dataStoreMock);
|
||||||
|
|
||||||
|
Assert.assertFalse(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void templateIsOnDestinationTestReturnsTrueWhenTemplateIsReady() {
|
||||||
|
prepareForTemplateIsOnDestinationTests();
|
||||||
|
|
||||||
|
boolean result = secondaryStorageService.templateIsOnDestination(templateInfoMock, dataStoreMock);
|
||||||
|
|
||||||
|
Assert.assertTrue(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void templateIsOnDestinationTestReturnsFalseWhenTemplateIsNotReady() {
|
||||||
|
prepareForTemplateIsOnDestinationTests();
|
||||||
|
Mockito.when(templateDataStoreVoMock.getState()).thenReturn(ObjectInDataStoreStateMachine.State.Creating);
|
||||||
|
|
||||||
|
boolean result = secondaryStorageService.templateIsOnDestination(templateInfoMock, dataStoreMock);
|
||||||
|
|
||||||
|
Assert.assertFalse(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void templateIsOnDestinationTestReturnsTrueIfTemplateIsDownloadedSuccessfully() {
|
||||||
|
prepareForTemplateIsOnDestinationTests();
|
||||||
|
Mockito.when(templateDataStoreVoMock.getDownloadState()).thenReturn(VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS);
|
||||||
|
Mockito.doAnswer(I -> Mockito.when(templateDataStoreVoMock.getDownloadState()).thenReturn(VMTemplateStorageResourceAssoc.Status.DOWNLOADED)).when(secondaryStorageService).waitForTemplateDownload(Mockito.anyLong(), Mockito.anyString(), Mockito.anyString());
|
||||||
|
|
||||||
|
boolean result = secondaryStorageService.templateIsOnDestination(templateInfoMock, dataStoreMock);
|
||||||
|
|
||||||
|
Assert.assertTrue(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void templateIsOnDestinationTestReturnsFalseIfTemplateIsNotDownloadedSuccessfully() {
|
||||||
|
prepareForTemplateIsOnDestinationTests();
|
||||||
|
Mockito.when(templateDataStoreVoMock.getDownloadState()).thenReturn(VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS);
|
||||||
|
Mockito.doAnswer(I -> {
|
||||||
|
Mockito.when(templateDataStoreVoMock.getDownloadState()).thenReturn(VMTemplateStorageResourceAssoc.Status.DOWNLOAD_ERROR);
|
||||||
|
Mockito.when(templateDataStoreVoMock.getState()).thenReturn(ObjectInDataStoreStateMachine.State.Failed);
|
||||||
|
return "mocked download fail";
|
||||||
|
}).when(secondaryStorageService).waitForTemplateDownload(Mockito.anyLong(), Mockito.anyString(), Mockito.anyString());
|
||||||
|
|
||||||
|
boolean result = secondaryStorageService.templateIsOnDestination(templateInfoMock, dataStoreMock);
|
||||||
|
|
||||||
|
Assert.assertFalse(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = CloudRuntimeException.class)
|
||||||
|
public void templateIsOnDestinationTestThrowsExceptionIfDownloadTimesOut() {
|
||||||
|
prepareForTemplateIsOnDestinationTests();
|
||||||
|
Mockito.when(templateDataStoreVoMock.getDownloadState()).thenReturn(VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS);
|
||||||
|
Mockito.doReturn(0L).when(secondaryStorageService).getTemplateDownloadTimeout();
|
||||||
|
|
||||||
|
secondaryStorageService.templateIsOnDestination(templateInfoMock, dataStoreMock);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -151,11 +151,6 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation<Templa
|
|||||||
activeTmpltSearch.and("store_id", activeTmpltSearch.entity().getDataStoreId(), SearchCriteria.Op.EQ);
|
activeTmpltSearch.and("store_id", activeTmpltSearch.entity().getDataStoreId(), SearchCriteria.Op.EQ);
|
||||||
activeTmpltSearch.and("type", activeTmpltSearch.entity().getTemplateType(), SearchCriteria.Op.EQ);
|
activeTmpltSearch.and("type", activeTmpltSearch.entity().getTemplateType(), SearchCriteria.Op.EQ);
|
||||||
activeTmpltSearch.and("templateState", activeTmpltSearch.entity().getTemplateState(), SearchCriteria.Op.EQ);
|
activeTmpltSearch.and("templateState", activeTmpltSearch.entity().getTemplateState(), SearchCriteria.Op.EQ);
|
||||||
activeTmpltSearch.and().op("public", activeTmpltSearch.entity().isPublicTemplate(), SearchCriteria.Op.EQ);
|
|
||||||
activeTmpltSearch.or().op("publicNoUrl", activeTmpltSearch.entity().isPublicTemplate(), SearchCriteria.Op.EQ);
|
|
||||||
activeTmpltSearch.and("url", activeTmpltSearch.entity().getUrl(), SearchCriteria.Op.NULL);
|
|
||||||
activeTmpltSearch.cp();
|
|
||||||
activeTmpltSearch.cp();
|
|
||||||
activeTmpltSearch.done();
|
activeTmpltSearch.done();
|
||||||
|
|
||||||
publicTmpltSearch = createSearchBuilder();
|
publicTmpltSearch = createSearchBuilder();
|
||||||
@ -687,8 +682,6 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation<Templa
|
|||||||
sc.setParameters("store_id", storeId);
|
sc.setParameters("store_id", storeId);
|
||||||
sc.setParameters("type", TemplateType.USER);
|
sc.setParameters("type", TemplateType.USER);
|
||||||
sc.setParameters("templateState", VirtualMachineTemplate.State.Active);
|
sc.setParameters("templateState", VirtualMachineTemplate.State.Active);
|
||||||
sc.setParameters("public", Boolean.FALSE);
|
|
||||||
sc.setParameters("publicNoUrl",Boolean.TRUE);
|
|
||||||
return searchIncludingRemoved(sc, null, null, false);
|
return searchIncludingRemoved(sc, null, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -76,7 +76,7 @@ public abstract class DownloadActiveState extends DownloadState {
|
|||||||
getDownloadListener().log("handleTimeout, updateMs=" + updateMs + ", curr state= " + getName(), Level.TRACE);
|
getDownloadListener().log("handleTimeout, updateMs=" + updateMs + ", curr state= " + getName(), Level.TRACE);
|
||||||
}
|
}
|
||||||
String newState = getName();
|
String newState = getName();
|
||||||
if (updateMs > 5 * DownloadListener.STATUS_POLL_INTERVAL) {
|
if (updateMs > DownloadListener.DOWNLOAD_TIMEOUT) {
|
||||||
newState = Status.DOWNLOAD_ERROR.toString();
|
newState = Status.DOWNLOAD_ERROR.toString();
|
||||||
getDownloadListener().log("timeout: transitioning to download error state, currstate=" + getName(), Level.DEBUG);
|
getDownloadListener().log("timeout: transitioning to download error state, currstate=" + getName(), Level.DEBUG);
|
||||||
} else if (updateMs > 3 * DownloadListener.STATUS_POLL_INTERVAL) {
|
} else if (updateMs > 3 * DownloadListener.STATUS_POLL_INTERVAL) {
|
||||||
|
|||||||
@ -100,6 +100,7 @@ public class DownloadListener implements Listener {
|
|||||||
protected Logger logger = LogManager.getLogger(getClass());
|
protected Logger logger = LogManager.getLogger(getClass());
|
||||||
public static final int SMALL_DELAY = 100;
|
public static final int SMALL_DELAY = 100;
|
||||||
public static final long STATUS_POLL_INTERVAL = 10000L;
|
public static final long STATUS_POLL_INTERVAL = 10000L;
|
||||||
|
public static final long DOWNLOAD_TIMEOUT = 5 * STATUS_POLL_INTERVAL;
|
||||||
|
|
||||||
public static final String DOWNLOADED = Status.DOWNLOADED.toString();
|
public static final String DOWNLOADED = Status.DOWNLOADED.toString();
|
||||||
public static final String NOT_DOWNLOADED = Status.NOT_DOWNLOADED.toString();
|
public static final String NOT_DOWNLOADED = Status.NOT_DOWNLOADED.toString();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user