From 0229c75b50a008a86ded801ff98617adb24c56da Mon Sep 17 00:00:00 2001 From: Min Chen Date: Sat, 20 Apr 2013 20:44:31 -0700 Subject: [PATCH] Use data motion service for PrepareTemplateCmd to move template from secondary storage to primary. --- .../api/storage/TemplateService.java | 5 +- .../storage/image/TemplateServiceImpl.java | 74 +++++++++- .../cloud/template/TemplateManagerImpl.java | 132 ++++++------------ 3 files changed, 121 insertions(+), 90 deletions(-) diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateService.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateService.java index 2fc6d3d1f1e..d7010fd9e2f 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateService.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateService.java @@ -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 createTemplateFromSnapshotAsync(SnapshotInfo snapshot, TemplateInfo template, DataStore store); AsyncCallFuture createTemplateFromVolumeAsync(VolumeInfo volume, TemplateInfo template, DataStore store); AsyncCallFuture deleteTemplateAsync(TemplateInfo template); - AsyncCallFuture copyTemplate(TemplateInfo srcTemplate, - DataStore destStore); + AsyncCallFuture copyTemplate(TemplateInfo srcTemplate, DataStore destStore); + AsyncCallFuture prepareTemplateOnPrimary(TemplateInfo srcTemplate, StoragePool pool ); void handleSysTemplateDownload(HypervisorType hostHyper, Long dcId); void handleTemplateSync(DataStore store); diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java index ccdcc5ac516..04003bfb577 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java @@ -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 callback, + CopyTemplateContext context) { + TemplateInfo srcTemplate = context.getSrcTemplate(); + TemplateInfo destTemplate = context.getDestTemplate(); + CopyCommandResult result = callback.getResult(); + AsyncCallFuture 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 prepareTemplateOnPrimary(TemplateInfo srcTemplate, StoragePool pool) { + AsyncCallFuture future = new AsyncCallFuture(); + 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 context = new CopyTemplateContext(null, future, srcTemplate, + destTemplate, + destStore + ); + AsyncCallbackDispatcher 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 extends AsyncRpcConext { final TemplateInfo srcTemplate; final TemplateInfo destTemplate; diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index 21d3f06725c..a8d524b7cb5 100755 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -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 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 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 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 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 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