Use data motion service for PrepareTemplateCmd to move template from

secondary storage to primary.
This commit is contained in:
Min Chen 2013-04-20 20:44:31 -07:00
parent 86913ab4d3
commit 0229c75b50
3 changed files with 121 additions and 90 deletions

View File

@ -24,6 +24,7 @@ import org.apache.cloudstack.framework.async.AsyncCallFuture;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.storage.StoragePool;
public interface TemplateService {
@ -43,8 +44,8 @@ public interface TemplateService {
AsyncCallFuture<TemplateApiResult> createTemplateFromSnapshotAsync(SnapshotInfo snapshot, TemplateInfo template, DataStore store);
AsyncCallFuture<TemplateApiResult> createTemplateFromVolumeAsync(VolumeInfo volume, TemplateInfo template, DataStore store);
AsyncCallFuture<TemplateApiResult> deleteTemplateAsync(TemplateInfo template);
AsyncCallFuture<TemplateApiResult> copyTemplate(TemplateInfo srcTemplate,
DataStore destStore);
AsyncCallFuture<TemplateApiResult> copyTemplate(TemplateInfo srcTemplate, DataStore destStore);
AsyncCallFuture<TemplateApiResult> prepareTemplateOnPrimary(TemplateInfo srcTemplate, StoragePool pool );
void handleSysTemplateDownload(HypervisorType hostHyper, Long dcId);
void handleTemplateSync(DataStore store);

View File

@ -74,12 +74,14 @@ import com.cloud.exception.ResourceAllocationException;
import com.cloud.host.HostVO;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.storage.StoragePool;
import com.cloud.storage.VMTemplateStoragePoolVO;
import com.cloud.storage.VMTemplateStorageResourceAssoc;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.VMTemplateZoneVO;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.storage.dao.VMTemplatePoolDao;
import com.cloud.storage.dao.VMTemplateZoneDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.storage.download.DownloadMonitor;
@ -87,6 +89,7 @@ import com.cloud.storage.secondary.SecondaryStorageVmManager;
import com.cloud.user.AccountManager;
import com.cloud.user.ResourceLimitService;
import com.cloud.utils.UriUtils;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.fsm.NoTransitionException;
import com.cloud.vm.UserVmVO;
import com.cloud.vm.dao.UserVmDao;
@ -132,6 +135,7 @@ public class TemplateServiceImpl implements TemplateService {
VolumeDao _volumeDao;
@Inject
TemplateDataFactory _templateFactory;
@Inject VMTemplatePoolDao _tmpltPoolDao;
@ -559,7 +563,7 @@ public class TemplateServiceImpl implements TemplateService {
.setContext(context);
this._motionSrv.copyAsync(srcTemplate, destTemplate, caller);
} catch (Exception e) {
s_logger.debug("Failed to copy volume", e);
s_logger.debug("Failed to copy template", e);
res.setResult(e.toString());
future.complete(res);
}
@ -597,6 +601,74 @@ public class TemplateServiceImpl implements TemplateService {
return null;
}
protected Void prepareTemplateCallBack(AsyncCallbackDispatcher<TemplateServiceImpl, CopyCommandResult> callback,
CopyTemplateContext<TemplateApiResult> context) {
TemplateInfo srcTemplate = context.getSrcTemplate();
TemplateInfo destTemplate = context.getDestTemplate();
CopyCommandResult result = callback.getResult();
AsyncCallFuture<TemplateApiResult> future = context.getFuture();
TemplateApiResult res = new TemplateApiResult(destTemplate);
try {
if (result.isFailed()) {
res.setResult(result.getResult());
destTemplate.processEvent(Event.OperationFailed);
srcTemplate.processEvent(Event.OperationFailed);
// remove entry from template_spool_ref
VMTemplateStoragePoolVO destTmpltPool = _tmpltPoolDao.findByPoolTemplate(context.getDestStore().getId(), destTemplate.getId());
_vmTemplateStoreDao.remove(destTmpltPool.getId());
future.complete(res);
return null;
}
srcTemplate.processEvent(Event.OperationSuccessed);
// update other information in template_spool_ref through templateObject event processing.
destTemplate.processEvent(Event.OperationSuccessed);
future.complete(res);
return null;
} catch (Exception e) {
s_logger.debug("Failed to process prepare template callback", e);
res.setResult(e.toString());
future.complete(res);
}
return null;
}
@Override
public AsyncCallFuture<TemplateApiResult> prepareTemplateOnPrimary(TemplateInfo srcTemplate, StoragePool pool) {
AsyncCallFuture<TemplateApiResult> future = new AsyncCallFuture<TemplateApiResult>();
TemplateApiResult res = new TemplateApiResult(srcTemplate);
long poolId = pool.getId();
long templateId = srcTemplate.getId();
try{
// create one entry in template_spool_ref
VMTemplateStoragePoolVO templateStoragePoolRef = _tmpltPoolDao.findByPoolTemplate(poolId, templateId);
if (templateStoragePoolRef == null) {
templateStoragePoolRef = new VMTemplateStoragePoolVO(poolId, templateId);
templateStoragePoolRef = _tmpltPoolDao.persist(templateStoragePoolRef);
}
DataStore destStore = (DataStore)pool;
TemplateInfo destTemplate = this._templateFactory.getTemplate(templateStoragePoolRef.getTemplateId(), destStore);
destTemplate.processEvent(Event.CreateOnlyRequested);
srcTemplate.processEvent(Event.CopyingRequested);
CopyTemplateContext<TemplateApiResult> context = new CopyTemplateContext<TemplateApiResult>(null, future, srcTemplate,
destTemplate,
destStore
);
AsyncCallbackDispatcher<TemplateServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
caller.setCallback(caller.getTarget().prepareTemplateCallBack(null, null))
.setContext(context);
this._motionSrv.copyAsync(srcTemplate, destTemplate, caller);
} catch (Exception e) {
s_logger.debug("Failed to prepare template on storage pool", e);
res.setResult(e.toString());
future.complete(res);
}
return future;
}
class CopyTemplateContext<T> extends AsyncRpcConext<T> {
final TemplateInfo srcTemplate;
final TemplateInfo destTemplate;

View File

@ -666,7 +666,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
long templateId = template.getId();
long dcId = pool.getDataCenterId();
VMTemplateStoragePoolVO templateStoragePoolRef = null;
VMTemplateHostVO templateHostRef = null;
TemplateDataStoreVO templateStoreRef = null;
long templateStoragePoolRefId;
String origUrl = null;
@ -684,113 +684,71 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
}
}
templateHostRef = findVmTemplateHost(templateId, pool);
templateStoreRef = findVmTemplateImageStore(templateId, pool);
if (templateHostRef == null || templateHostRef.getDownloadState() != Status.DOWNLOADED) {
String result = downloadTemplateFromSwiftToSecondaryStorage(dcId, templateId);
if (result != null) {
s_logger.error("Unable to find a secondary storage host who has completely downloaded the template.");
return null;
}
result = _s3Mgr.downloadTemplateFromS3ToSecondaryStorage(dcId,
templateId, _primaryStorageDownloadWait);
if (result != null) {
s_logger.error("Unable to find a secondary storage host who has completely downloaded the template.");
return null;
}
templateHostRef = findVmTemplateHost(templateId, pool);
if (templateHostRef == null || templateHostRef.getDownloadState() != Status.DOWNLOADED) {
s_logger.error("Unable to find a secondary storage host who has completely downloaded the template.");
return null;
}
if (templateStoreRef == null) {
s_logger.error("Unable to find a secondary storage host who has completely downloaded the template.");
return null;
}
HostVO sh = _hostDao.findById(templateHostRef.getHostId());
List<StoragePoolHostVO> vos = _poolHostDao.listByHostStatus(poolId, com.cloud.host.Status.Up);
if (vos == null || vos.isEmpty()){
throw new CloudRuntimeException("Cannot download " + templateId + " to poolId " + poolId + " since there is no host in the Up state connected to this pool");
}
/*
HostVO sh = _hostDao.findById(templateStoreRef.getHostId());
origUrl = sh.getStorageUrl();
if (origUrl == null) {
throw new CloudRuntimeException("Unable to find the orig.url from host " + sh.toString());
}
*/
if (templateStoragePoolRef == null) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Downloading template " + templateId + " to pool " + poolId);
}
templateStoragePoolRef = new VMTemplateStoragePoolVO(poolId, templateId);
DataStore srcSecStore = this.dataStoreMgr.getDataStore(templateStoreRef.getDataStoreId(), DataStoreRole.Image);
TemplateInfo srcTemplate = this.tmplFactory.getTemplate(templateId, srcSecStore);
AsyncCallFuture<TemplateApiResult> future = this.tmpltSvr.prepareTemplateOnPrimary(srcTemplate, pool);
try {
templateStoragePoolRef = _tmpltPoolDao.persist(templateStoragePoolRef);
templateStoragePoolRefId = templateStoragePoolRef.getId();
} catch (Exception e) {
s_logger.debug("Assuming we're in a race condition: " + e.getMessage());
templateStoragePoolRef = _tmpltPoolDao.findByPoolTemplate(poolId, templateId);
if (templateStoragePoolRef == null) {
throw new CloudRuntimeException("Unable to persist a reference for pool " + poolId + " and template " + templateId);
TemplateApiResult result = future.get();
if (result.isFailed()) {
s_logger.debug("prepare template failed:" + result.getResult());
return null;
}
templateStoragePoolRefId = templateStoragePoolRef.getId();
return _tmpltPoolDao.findByPoolTemplate(poolId, templateId);
}
} else {
templateStoragePoolRefId = templateStoragePoolRef.getId();
}
List<StoragePoolHostVO> vos = _poolHostDao.listByHostStatus(poolId, com.cloud.host.Status.Up);
if (vos == null || vos.isEmpty()){
throw new CloudRuntimeException("Cannot download " + templateId + " to poolId " + poolId + " since there is no host in the Up state connected to this pool");
}
templateStoragePoolRef = _tmpltPoolDao.acquireInLockTable(templateStoragePoolRefId, _storagePoolMaxWaitSeconds);
if (templateStoragePoolRef == null) {
throw new CloudRuntimeException("Unable to acquire lock on VMTemplateStoragePool: " + templateStoragePoolRefId);
}
try {
if (templateStoragePoolRef.getDownloadState() == Status.DOWNLOADED) {
return templateStoragePoolRef;
catch (Exception ex) {
s_logger.debug("failed to copy template from image store:" + srcSecStore.getName() + " to primary storage");
}
String url = origUrl + "/" + templateHostRef.getInstallPath();
PrimaryStorageDownloadCommand dcmd = new PrimaryStorageDownloadCommand(template.getUniqueName(), url, template.getFormat(),
template.getAccountId(), pool, _primaryStorageDownloadWait);
HostVO secondaryStorageHost = _hostDao.findById(templateHostRef.getHostId());
assert(secondaryStorageHost != null);
dcmd.setSecondaryStorageUrl(secondaryStorageHost.getStorageUrl());
for (int retry = 0; retry < 2; retry ++){
Collections.shuffle(vos); // Shuffling to pick a random host in the vm deployment retries
StoragePoolHostVO vo = vos.get(0);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Downloading " + templateId + " via " + vo.getHostId());
}
dcmd.setLocalPath(vo.getLocalPath());
// set 120 min timeout for this command
PrimaryStorageDownloadAnswer answer = (PrimaryStorageDownloadAnswer)_agentMgr.easySend(
_hvGuruMgr.getGuruProcessedCommandTargetHost(vo.getHostId(), dcmd), dcmd);
if (answer != null && answer.getResult() ) {
templateStoragePoolRef.setDownloadPercent(100);
templateStoragePoolRef.setDownloadState(Status.DOWNLOADED);
templateStoragePoolRef.setLocalDownloadPath(answer.getInstallPath());
templateStoragePoolRef.setInstallPath(answer.getInstallPath());
templateStoragePoolRef.setTemplateSize(answer.getTemplateSize());
_tmpltPoolDao.update(templateStoragePoolRef.getId(), templateStoragePoolRef);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Template " + templateId + " is downloaded via " + vo.getHostId());
}
return templateStoragePoolRef;
} else {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Template " + templateId + " download to pool " + vo.getPoolId() + " failed due to " + (answer!=null?answer.getDetails():"return null")); }
}
}
} finally {
_tmpltPoolDao.releaseFromLockTable(templateStoragePoolRefId);
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Template " + templateId + " is not found on and can not be downloaded to pool " + poolId);
}
return null;
}
private TemplateDataStoreVO findVmTemplateImageStore(long templateId,
StoragePool pool) {
long dcId = pool.getDataCenterId();
List<DataStore> secStores = this.dataStoreMgr.getImageStoresByScope(new ZoneScope(dcId));
if ( secStores == null ){
s_logger.error("No image store found to download template " + templateId + " primary storage!");
return null;
}
for (DataStore store : secStores ){
List<TemplateDataStoreVO> templStores = this._tmplStoreDao.listByTemplateStoreDownloadStatus(templateId, store.getId(), VMTemplateStorageResourceAssoc.Status.DOWNLOADED);
if (templStores != null && !templStores.isEmpty()) {
Collections.shuffle(templStores);
return templStores.get(0);
}
}
return null;
}
@Override