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 ec027fe9e84..2fc6d3d1f1e 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 @@ -18,6 +18,7 @@ */ package org.apache.cloudstack.engine.subsystem.api.storage; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult; import org.apache.cloudstack.framework.async.AsyncCallFuture; @@ -25,10 +26,25 @@ import org.apache.cloudstack.framework.async.AsyncCallFuture; import com.cloud.hypervisor.Hypervisor.HypervisorType; public interface TemplateService { - AsyncCallFuture createTemplateAsync(TemplateInfo template, DataStore store); - AsyncCallFuture createTemplateFromSnapshotAsync(SnapshotInfo snapshot, TemplateInfo template, DataStore store); - AsyncCallFuture createTemplateFromVolumeAsync(VolumeInfo volume, TemplateInfo template, DataStore store); - AsyncCallFuture deleteTemplateAsync(TemplateInfo template); + + public class TemplateApiResult extends CommandResult { + private final TemplateInfo template; + public TemplateApiResult(TemplateInfo template) { + this.template = template; + } + + public TemplateInfo getTemplate() { + return this.template; + } + } + + + AsyncCallFuture createTemplateAsync(TemplateInfo template, DataStore store); + 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); 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 0a249607e46..ccdcc5ac516 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 @@ -28,15 +28,20 @@ import java.util.Set; import javax.inject.Inject; import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; +import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; +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.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService; import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateEvent; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService.TemplateApiResult; + import com.cloud.storage.template.TemplateProp; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; @@ -68,8 +73,11 @@ import com.cloud.exception.AgentUnavailableException; 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.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.VMTemplateZoneDao; @@ -93,6 +101,8 @@ public class TemplateServiceImpl implements TemplateService { @Inject DataStoreManager _storeMgr; @Inject + DataMotionService _motionSrv; + @Inject ResourceLimitService _resourceLimitMgr; @Inject AccountManager _accountMgr; @@ -120,33 +130,18 @@ public class TemplateServiceImpl implements TemplateService { UserVmDao _userVmDao; @Inject VolumeDao _volumeDao; + @Inject + TemplateDataFactory _templateFactory; - class CreateTemplateContext extends AsyncRpcConext { - final TemplateInfo srcTemplate; - final DataStore store; - final AsyncCallFuture future; - final DataObject templateOnStore; - public CreateTemplateContext(AsyncCompletionCallback callback, TemplateInfo srcTemplate, - AsyncCallFuture future, - DataStore store, - DataObject templateOnStore - ) { - super(callback); - this.srcTemplate = srcTemplate; - this.future = future; - this.store = store; - this.templateOnStore = templateOnStore; - } - } - class DeleteTemplateContext extends AsyncRpcConext { + class TemplateOpContext extends AsyncRpcConext { final TemplateObject template; - final AsyncCallFuture future; + final AsyncCallFuture future; - public DeleteTemplateContext(AsyncCompletionCallback callback, TemplateObject template, - AsyncCallFuture future) { + public TemplateOpContext(AsyncCompletionCallback callback, TemplateObject template, + AsyncCallFuture future) { super(callback); this.template = template; this.future = future; @@ -156,7 +151,7 @@ public class TemplateServiceImpl implements TemplateService { return template; } - public AsyncCallFuture getFuture() { + public AsyncCallFuture getFuture() { return future; } @@ -164,21 +159,17 @@ public class TemplateServiceImpl implements TemplateService { } @Override - public AsyncCallFuture createTemplateAsync( + public AsyncCallFuture createTemplateAsync( TemplateInfo template, DataStore store) { - TemplateObject to = (TemplateObject) template; - AsyncCallFuture future = new AsyncCallFuture(); + AsyncCallFuture future = new AsyncCallFuture(); // persist template_store_ref entry DataObject templateOnStore = store.create(template); // update template_store_ref state templateOnStore.processEvent(ObjectInDataStoreStateMachine.Event.CreateOnlyRequested); - CreateTemplateContext context = new CreateTemplateContext(null, - template, - future, - store, - templateOnStore - ); + TemplateOpContext context = new TemplateOpContext(null, + (TemplateObject)templateOnStore, future); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); caller.setCallback(caller.getTarget().createTemplateCallback(null, null)).setContext(context); store.getDriver().createAsync(templateOnStore, caller); @@ -470,15 +461,14 @@ public class TemplateServiceImpl implements TemplateService { protected Void createTemplateCallback(AsyncCallbackDispatcher callback, - CreateTemplateContext context) { - TemplateObject template = (TemplateObject)context.srcTemplate; - AsyncCallFuture future = context.future; - CommandResult result = new CommandResult(); - DataObject templateOnStore = context.templateOnStore; + TemplateOpContext context) { + TemplateObject template = (TemplateObject)context.getTemplate(); + AsyncCallFuture future = context.getFuture(); + TemplateApiResult result = new TemplateApiResult(template); CreateCmdResult callbackResult = callback.getResult(); if (callbackResult.isFailed()) { try { - templateOnStore.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed); + template.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed); template.stateTransit(TemplateEvent.OperationFailed); } catch (NoTransitionException e) { s_logger.debug("Failed to update template state", e); @@ -489,7 +479,7 @@ public class TemplateServiceImpl implements TemplateService { } try { - templateOnStore.processEvent(ObjectInDataStoreStateMachine.Event.OperationSuccessed); + template.processEvent(ObjectInDataStoreStateMachine.Event.OperationSuccessed); template.stateTransit(TemplateEvent.OperationSucceeded); } catch (NoTransitionException e) { s_logger.debug("Failed to transit state", e); @@ -503,22 +493,22 @@ public class TemplateServiceImpl implements TemplateService { } @Override - public AsyncCallFuture deleteTemplateAsync( + public AsyncCallFuture deleteTemplateAsync( TemplateInfo template) { TemplateObject to = (TemplateObject) template; // update template_store_ref status to.processEvent(ObjectInDataStoreStateMachine.Event.DestroyRequested); - AsyncCallFuture future = new AsyncCallFuture(); + AsyncCallFuture future = new AsyncCallFuture(); - DeleteTemplateContext context = new DeleteTemplateContext(null, to, future); + TemplateOpContext context = new TemplateOpContext(null, to, future); AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); caller.setCallback(caller.getTarget().deleteTemplateCallback(null, null)).setContext(context); to.getDataStore().getDriver().deleteAsync(to, caller); return future; } - public Void deleteTemplateCallback(AsyncCallbackDispatcher callback, DeleteTemplateContext context) { - CommandResult result = callback.getResult(); + public Void deleteTemplateCallback(AsyncCallbackDispatcher callback, TemplateOpContext context) { + TemplateApiResult result = callback.getResult(); TemplateObject vo = context.getTemplate(); // we can only update state in template_store_ref table if (result.isSuccess()) { @@ -531,19 +521,114 @@ public class TemplateServiceImpl implements TemplateService { } @Override - public AsyncCallFuture createTemplateFromSnapshotAsync( + public AsyncCallFuture createTemplateFromSnapshotAsync( SnapshotInfo snapshot, TemplateInfo template, DataStore store) { // TODO Auto-generated method stub return null; } @Override - public AsyncCallFuture createTemplateFromVolumeAsync( + public AsyncCallFuture createTemplateFromVolumeAsync( VolumeInfo volume, TemplateInfo template, DataStore store) { // TODO Auto-generated method stub return null; } + @Override + public AsyncCallFuture copyTemplate(TemplateInfo srcTemplate, + DataStore destStore) { + AsyncCallFuture future = new AsyncCallFuture(); + TemplateApiResult res = new TemplateApiResult(srcTemplate); + try{ + // create one entry in template_store_ref + TemplateDataStoreVO destTmpltStore = _vmTemplateStoreDao.findByStoreTemplate(destStore.getId(), srcTemplate.getId()); + if (destTmpltStore == null) { + destTmpltStore = new TemplateDataStoreVO(destStore.getId(), srcTemplate.getId()); + destTmpltStore.setCopy(true); + _vmTemplateStoreDao.persist(destTmpltStore); + } + TemplateInfo destTemplate = this._templateFactory.getTemplate(destTmpltStore.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().copyTemplateCallBack(null, null)) + .setContext(context); + this._motionSrv.copyAsync(srcTemplate, destTemplate, caller); + } catch (Exception e) { + s_logger.debug("Failed to copy volume", e); + res.setResult(e.toString()); + future.complete(res); + } + return future; + } + protected Void copyTemplateCallBack(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_store_ref + TemplateDataStoreVO destTmpltStore = _vmTemplateStoreDao.findByStoreTemplate(context.getDestStore().getId(), destTemplate.getId()); + _vmTemplateStoreDao.remove(destTmpltStore.getId()); + future.complete(res); + return null; + } + srcTemplate.processEvent(Event.OperationSuccessed); + destTemplate.processEvent(Event.OperationSuccessed); + future.complete(res); + return null; + } catch (Exception e) { + s_logger.debug("Failed to process copy template callback", e); + res.setResult(e.toString()); + future.complete(res); + } + + return null; + } + + class CopyTemplateContext extends AsyncRpcConext { + final TemplateInfo srcTemplate; + final TemplateInfo destTemplate; + final DataStore destStore; + final AsyncCallFuture future; + + /** + * @param callback + */ + public CopyTemplateContext(AsyncCompletionCallback callback, AsyncCallFuture future, TemplateInfo srcTemplate, + TemplateInfo destTemplate, DataStore destStore) { + super(callback); + this.srcTemplate = srcTemplate; + this.destTemplate = destTemplate; + this.destStore = destStore; + this.future = future; + } + + public TemplateInfo getSrcTemplate() { + return srcTemplate; + } + + public TemplateInfo getDestTemplate() { + return destTemplate; + } + + public DataStore getDestStore() { + return destStore; + } + + public AsyncCallFuture getFuture() { + return future; + } + } } diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java index 86234c18ff0..37f0e47955e 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java @@ -41,6 +41,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService.TemplateApiResult; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService; @@ -93,7 +94,7 @@ public class volumeServiceTest extends CloudStackTestNGBase { VMTemplateDao imageDataDao; @Inject VolumeDao2 volumeDao; - @Inject + @Inject HostDao hostDao; @Inject HostPodDao podDao; @@ -119,7 +120,7 @@ public class volumeServiceTest extends CloudStackTestNGBase { HostVO host; String primaryName = "my primary data store"; DataStore primaryStore; - + @Test(priority = -1) public void setUp() { ComponentContext.initComponentsLifeCycle(); @@ -137,7 +138,7 @@ public class volumeServiceTest extends CloudStackTestNGBase { return; } //create data center - DataCenterVO dc = new DataCenterVO(UUID.randomUUID().toString(), "test", "8.8.8.8", null, "10.0.0.1", null, "10.0.0.1/24", + DataCenterVO dc = new DataCenterVO(UUID.randomUUID().toString(), "test", "8.8.8.8", null, "10.0.0.1", null, "10.0.0.1/24", null, null, NetworkType.Basic, null, null, true, true, null, null); dc = dcDao.persist(dc); dcId = dc.getId(); @@ -172,7 +173,7 @@ public class volumeServiceTest extends CloudStackTestNGBase { host = hostDao.persist(host); //primaryStore = createPrimaryDataStore(); - + //CreateVolumeAnswer createVolumeFromImageAnswer = new CreateVolumeAnswer(UUID.randomUUID().toString()); /*try { @@ -188,7 +189,7 @@ public class volumeServiceTest extends CloudStackTestNGBase { //Mockito.when(primaryStoreDao.findById(Mockito.anyLong())).thenReturn(primaryStore); } - + @Override protected void injectMockito() { if (host == null) { @@ -225,10 +226,10 @@ public class volumeServiceTest extends CloudStackTestNGBase { image.setPrepopulate(true); image.setCrossZones(true); image.setExtractable(true); - + //image.setImageDataStoreId(storeId); image = imageDataDao.persist(image); - + return image; } @@ -237,7 +238,7 @@ public class volumeServiceTest extends CloudStackTestNGBase { DataStore store = createImageStore(); VMTemplateVO image = createImageData(); TemplateInfo template = imageDataFactory.getTemplate(image.getId(), store); - AsyncCallFuture future = imageService.createTemplateAsync(template, store); + AsyncCallFuture future = imageService.createTemplateAsync(template, store); future.get(); template = imageDataFactory.getTemplate(image.getId(), store); /*imageProviderMgr.configure("image Provider", new HashMap()); @@ -259,7 +260,7 @@ public class volumeServiceTest extends CloudStackTestNGBase { public void createTemplateTest() { createTemplate(); } - + @Test public void testCreatePrimaryStorage() { DataStoreProvider provider = dataStoreProviderMgr.getDataStoreProvider("sample primary data store provider"); @@ -282,13 +283,13 @@ public class volumeServiceTest extends CloudStackTestNGBase { params.put("roles", DataStoreRole.Primary.toString()); params.put("uuid", UUID.nameUUIDFromBytes(this.getPrimaryStorageUrl().getBytes()).toString()); params.put("providerName", String.valueOf(provider.getName())); - + DataStoreLifeCycle lifeCycle = provider.getDataStoreLifeCycle(); this.primaryStore = lifeCycle.initialize(params); ClusterScope scope = new ClusterScope(clusterId, podId, dcId); lifeCycle.attachCluster(this.primaryStore, scope); } - + private DataStore createImageStore() { DataStoreProvider provider = dataStoreProviderMgr.getDataStoreProvider("sample image data store provider"); Map params = new HashMap(); @@ -306,7 +307,7 @@ public class volumeServiceTest extends CloudStackTestNGBase { public void testcreateImageStore() { createImageStore(); } - + public DataStore createPrimaryDataStore() { try { @@ -324,16 +325,16 @@ public class volumeServiceTest extends CloudStackTestNGBase { params.put("roles", DataStoreRole.Primary.toString()); params.put("uuid", UUID.nameUUIDFromBytes(this.getPrimaryStorageUrl().getBytes()).toString()); params.put("providerName", String.valueOf(provider.getName())); - + DataStoreLifeCycle lifeCycle = provider.getDataStoreLifeCycle(); DataStore store = lifeCycle.initialize(params); ClusterScope scope = new ClusterScope(clusterId, podId, dcId); lifeCycle.attachCluster(store, scope); - + /* PrimaryDataStoreProvider provider = primaryDataStoreProviderMgr.getDataStoreProvider("sample primary data store provider"); primaryDataStoreProviderMgr.configure("primary data store mgr", new HashMap()); - + List ds = primaryStoreDao.findPoolByName(this.primaryName); if (ds.size() >= 1) { PrimaryDataStoreVO store = ds.get(0); @@ -341,8 +342,8 @@ public class volumeServiceTest extends CloudStackTestNGBase { return provider.getDataStore(store.getId()); } } - - + + Map params = new HashMap(); params.put("url", this.getPrimaryStorageUrl()); params.put("dcId", dcId.toString()); @@ -385,8 +386,8 @@ public class volumeServiceTest extends CloudStackTestNGBase { e.printStackTrace(); } } - - //@Test(priority=3) + + //@Test(priority=3) public void createDataDisk() { DataStore primaryStore = this.primaryStore; VolumeVO volume = createVolume(null, primaryStore.getId()); @@ -402,8 +403,8 @@ public class volumeServiceTest extends CloudStackTestNGBase { e.printStackTrace(); } } - - //@Test(priority=3) + + //@Test(priority=3) public void createAndDeleteDataDisk() { DataStore primaryStore = this.primaryStore; VolumeVO volume = createVolume(null, primaryStore.getId()); @@ -418,7 +419,7 @@ public class volumeServiceTest extends CloudStackTestNGBase { // TODO Auto-generated catch block e.printStackTrace(); } - + //delete the volume vol = volumeFactory.getVolume(volume.getId(), primaryStore); future = volumeService.expungeVolumeAsync(vol); diff --git a/server/src/com/cloud/template/HypervisorTemplateAdapter.java b/server/src/com/cloud/template/HypervisorTemplateAdapter.java index 8906eaf9c62..34efdcb40ca 100755 --- a/server/src/com/cloud/template/HypervisorTemplateAdapter.java +++ b/server/src/com/cloud/template/HypervisorTemplateAdapter.java @@ -36,6 +36,7 @@ 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.TemplateDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService.TemplateApiResult; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO; @@ -180,7 +181,7 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase implements Te throw new CloudRuntimeException("Unable to find image store to download template "+ profile.getTemplate()); } for (DataStore imageStore : imageStores) { - AsyncCallFuture future = this.imageService + AsyncCallFuture future = this.imageService .createTemplateAsync(this.imageFactory.getTemplate(template.getId(), imageStore), imageStore); try { future.get(); @@ -226,10 +227,10 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase implements Te for (DataStore imageStore : imageStores) { s_logger.info("Delete template from image store: " + imageStore.getName()); - AsyncCallFuture future = this.imageService + AsyncCallFuture future = this.imageService .deleteTemplateAsync(this.imageFactory.getTemplate(template.getId(), imageStore)); try { - CommandResult result = future.get(); + TemplateApiResult result = future.get(); success = result.isSuccess(); if ( !success ) break; diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index 619cd7ece4c..21d3f06725c 100755 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -64,6 +64,8 @@ import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService.TemplateApiResult; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; @@ -945,49 +947,63 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, Transaction txn = Transaction.currentTxn(); txn.start(); - //Copy will just find one eligible image store for the destination zone and copy template there, not propagate to all image stores + TemplateInfo srcTemplate = this.tmplFactory.getTemplate(template.getId(), srcSecStore); + // Copy will just find one eligible image store for the destination zone + // and copy template there, not propagate to all image stores // for that zone - for ( DataStore dstSecStore : dstSecStores ) { + for (DataStore dstSecStore : dstSecStores) { TemplateDataStoreVO dstTmpltStore = null; try { - dstTmpltStore = this._tmplStoreDao.findByStoreTemplate(dstSecStore.getId(), tmpltId, true); - if (dstTmpltStore != null) { - dstTmpltStore = _tmplStoreDao.lockRow(dstTmpltStore.getId(), true); - if (dstTmpltStore != null && dstTmpltStore.getDownloadState() == Status.DOWNLOADED) { - if (dstTmpltStore.getDestroyed() == false) { - return true; // already downloaded on this image store - } else { - dstTmpltStore.setDestroyed(false); - _tmplStoreDao.update(dstTmpltStore.getId(), dstTmpltStore); - return true; - } - } else if (dstTmpltStore != null && dstTmpltStore.getDownloadState() == Status.DOWNLOAD_ERROR){ - if (dstTmpltStore.getDestroyed() == true) { - dstTmpltStore.setDestroyed(false); - dstTmpltStore.setDownloadState(Status.NOT_DOWNLOADED); - dstTmpltStore.setDownloadPercent(0); - dstTmpltStore.setCopy(true); - dstTmpltStore.setErrorString(""); - dstTmpltStore.setJobId(null); - _tmplStoreDao.update(dstTmpltStore.getId(), dstTmpltStore); - } - } - } + dstTmpltStore = this._tmplStoreDao.findByStoreTemplate(dstSecStore.getId(), tmpltId, true); + if (dstTmpltStore != null) { + dstTmpltStore = _tmplStoreDao.lockRow(dstTmpltStore.getId(), true); + if (dstTmpltStore != null && dstTmpltStore.getDownloadState() == Status.DOWNLOADED) { + if (dstTmpltStore.getDestroyed() == false) { + return true; // already downloaded on this image + // store + } else { + dstTmpltStore.setDestroyed(false); + _tmplStoreDao.update(dstTmpltStore.getId(), dstTmpltStore); + return true; + } + } else if (dstTmpltStore != null && dstTmpltStore.getDownloadState() == Status.DOWNLOAD_ERROR) { + if (dstTmpltStore.getDestroyed() == true) { + dstTmpltStore.setDestroyed(false); + dstTmpltStore.setDownloadState(Status.NOT_DOWNLOADED); + dstTmpltStore.setDownloadPercent(0); + dstTmpltStore.setCopy(true); + dstTmpltStore.setErrorString(""); + dstTmpltStore.setJobId(null); + _tmplStoreDao.update(dstTmpltStore.getId(), dstTmpltStore); + } + } + } } finally { - txn.commit(); + txn.commit(); } - if(_downloadMonitor.copyTemplate(template, srcSecStore, dstSecStore) ) { + AsyncCallFuture future = this.tmpltSvr.copyTemplate(srcTemplate, dstSecStore); + try { + TemplateApiResult result = future.get(); + if (result.isFailed()) { + s_logger.debug("copy template failed:" + result.getResult()); + return false; + } + // if(_downloadMonitor.copyTemplate(template, srcSecStore, + // dstSecStore) ) { _tmpltDao.addTemplateToZone(template, dstZoneId); - if(account.getId() != Account.ACCOUNT_ID_SYSTEM){ + if (account.getId() != Account.ACCOUNT_ID_SYSTEM) { UsageEventUtils.publishUsageEvent(copyEventType, account.getId(), dstZoneId, tmpltId, null, null, null, srcTmpltStore.getSize(), template.getClass().getName(), template.getUuid()); - } - return true; + } + return true; + } catch (Exception ex) { + s_logger.debug("failed to copy template to image store:" + dstSecStore.getName() + " ,will try next one"); } } return false; + } @@ -1002,17 +1018,6 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, Long destZoneId = cmd.getDestinationZoneId(); Account caller = UserContext.current().getCaller(); - /* - if (_swiftMgr.isSwiftEnabled()) { - throw new CloudRuntimeException("copytemplate API is disabled in Swift setup, templates in Swift can be accessed by all Zones"); - } - - if (_s3Mgr.isS3Enabled()) { - throw new CloudRuntimeException( - "copytemplate API is disabled in S3 setup -- S3 templates are accessible in all zones."); - } - */ - //Verify parameters if (sourceZoneId == destZoneId) { throw new InvalidParameterValueException("Please specify different source and destination zones."); @@ -1769,7 +1774,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, if (store.size() > 1) { throw new CloudRuntimeException("muliple image data store, don't know which one to use"); } - AsyncCallFuture future = null; + AsyncCallFuture future = null; if (snapshotId != null) { SnapshotInfo snapInfo = this.snapshotFactory.getSnapshot(snapshotId); future = this.tmpltSvr.createTemplateFromSnapshotAsync(snapInfo, tmplInfo, store.get(0));