From 9a62239a92c5eafca6fafee1fbccd413bdfb91af Mon Sep 17 00:00:00 2001 From: Min Chen Date: Mon, 4 Nov 2013 12:31:31 -0800 Subject: [PATCH] CLOUDSTACK-5017: Throw CloudRuntimeException in case of template/volume download when ssvm is not ready so that caller can remove some leftover entries in template_store_ref and volume_store_ref. --- .../storage/image/TemplateServiceImpl.java | 46 ++++++++++++++---- .../storage/volume/VolumeServiceImpl.java | 48 ++++++++++++++----- .../storage/download/DownloadMonitorImpl.java | 6 ++- 3 files changed, 76 insertions(+), 24 deletions(-) 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 3e3c6d84b5c..308347d8a38 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 @@ -172,12 +172,26 @@ public class TemplateServiceImpl implements TemplateService { return; } - TemplateOpContext context = new TemplateOpContext(callback, - templateOnStore, null); + try { + TemplateOpContext context = new TemplateOpContext(callback, + templateOnStore, null); - AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); - caller.setCallback(caller.getTarget().createTemplateCallback(null, null)).setContext(context); - store.getDriver().createAsync(store, templateOnStore, caller); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + caller.setCallback(caller.getTarget().createTemplateCallback(null, null)).setContext(context); + store.getDriver().createAsync(store, templateOnStore, caller); + } catch (CloudRuntimeException ex) { + // clean up already persisted template_store_ref entry in case of createTemplateCallback is never called + TemplateDataStoreVO templateStoreVO = _vmTemplateStoreDao.findByStoreTemplate(store.getId(), template.getId()); + if (templateStoreVO != null) { + TemplateInfo tmplObj = _templateFactory.getTemplate(template, store); + tmplObj.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed); + } + TemplateApiResult result = new TemplateApiResult(template); + result.setResult(ex.getMessage()); + if (callback != null) { + callback.complete(result); + } + } } @Override @@ -732,11 +746,23 @@ public class TemplateServiceImpl implements TemplateService { if (s_logger.isDebugEnabled()) { s_logger.debug("Invoke datastore driver createAsync to create template on destination store"); } - TemplateOpContext context = new TemplateOpContext(null, - (TemplateObject) templateOnStore, future); - AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); - caller.setCallback(caller.getTarget().copyTemplateCrossZoneCallBack(null, null)).setContext(context); - destStore.getDriver().createAsync(destStore, templateOnStore, caller); + try { + TemplateOpContext context = new TemplateOpContext(null, + (TemplateObject)templateOnStore, future); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + caller.setCallback(caller.getTarget().copyTemplateCrossZoneCallBack(null, null)).setContext(context); + destStore.getDriver().createAsync(destStore, templateOnStore, caller); + } catch (CloudRuntimeException ex) { + // clean up already persisted template_store_ref entry in case of createTemplateCallback is never called + TemplateDataStoreVO templateStoreVO = _vmTemplateStoreDao.findByStoreTemplate(destStore.getId(), srcTemplate.getId()); + if (templateStoreVO != null) { + TemplateInfo tmplObj = _templateFactory.getTemplate(srcTemplate, destStore); + tmplObj.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed); + } + TemplateApiResult res = new TemplateApiResult((TemplateObject)templateOnStore); + res.setResult(ex.getMessage()); + future.complete(res); + } return future; } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java index 79e8cc87ca6..86e49f97a77 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java @@ -40,6 +40,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; import org.apache.cloudstack.engine.subsystem.api.storage.Scope; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; @@ -55,7 +56,6 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.storage.command.CommandResult; import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.command.DeleteCommand; -import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore; import org.apache.cloudstack.storage.datastore.PrimaryDataStoreProviderManager; import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao; import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO; @@ -165,12 +165,24 @@ public class VolumeServiceImpl implements VolumeService { DataObject volumeOnStore = dataStore.create(volume); volumeOnStore.processEvent(Event.CreateOnlyRequested); - CreateVolumeContext context = new CreateVolumeContext(null, volumeOnStore, - future); - AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); - caller.setCallback(caller.getTarget().createVolumeCallback(null, null)).setContext(context); + try { + CreateVolumeContext context = new CreateVolumeContext(null, volumeOnStore, + future); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + caller.setCallback(caller.getTarget().createVolumeCallback(null, null)).setContext(context); - dataStore.getDriver().createAsync(dataStore, volumeOnStore, caller); + dataStore.getDriver().createAsync(dataStore, volumeOnStore, caller); + } catch (CloudRuntimeException ex) { + // clean up already persisted volume_store_ref entry in case of createVolumeCallback is never called + VolumeDataStoreVO volStoreVO = _volumeStoreDao.findByStoreVolume(dataStore.getId(), volume.getId()); + if (volStoreVO != null) { + VolumeInfo volObj = volFactory.getVolume(volume, dataStore); + volObj.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed); + } + VolumeApiResult volResult = new VolumeApiResult((VolumeObject)volumeOnStore); + volResult.setResult(ex.getMessage()); + future.complete(volResult); + } return future; } @@ -1022,13 +1034,25 @@ public class VolumeServiceImpl implements VolumeService { volumeOnStore.processEvent(Event.CreateOnlyRequested); - CreateVolumeContext context = new CreateVolumeContext(null, volumeOnStore, - future); - AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); - caller.setCallback(caller.getTarget().registerVolumeCallback(null, null)); - caller.setContext(context); + try { + CreateVolumeContext context = new CreateVolumeContext(null, volumeOnStore, + future); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + caller.setCallback(caller.getTarget().registerVolumeCallback(null, null)); + caller.setContext(context); - store.getDriver().createAsync(store, volumeOnStore, caller); + store.getDriver().createAsync(store, volumeOnStore, caller); + } catch (CloudRuntimeException ex) { + // clean up already persisted volume_store_ref entry in case of createVolumeCallback is never called + VolumeDataStoreVO volStoreVO = _volumeStoreDao.findByStoreVolume(store.getId(), volume.getId()); + if (volStoreVO != null) { + VolumeInfo volObj = volFactory.getVolume(volume, store); + volObj.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed); + } + VolumeApiResult res = new VolumeApiResult((VolumeObject)volumeOnStore); + res.setResult(ex.getMessage()); + future.complete(res); + } return future; } diff --git a/server/src/com/cloud/storage/download/DownloadMonitorImpl.java b/server/src/com/cloud/storage/download/DownloadMonitorImpl.java index d455f1e673c..89b3407b60f 100755 --- a/server/src/com/cloud/storage/download/DownloadMonitorImpl.java +++ b/server/src/com/cloud/storage/download/DownloadMonitorImpl.java @@ -67,6 +67,7 @@ import com.cloud.storage.upload.UploadListener; import com.cloud.template.VirtualMachineTemplate; import com.cloud.utils.component.ComponentContext; import com.cloud.utils.component.ManagerBase; +import com.cloud.utils.exception.CloudRuntimeException; @Component @Local(value = { DownloadMonitor.class }) @@ -169,8 +170,9 @@ public class DownloadMonitorImpl extends ManagerBase implements DownloadMonitor } EndPoint ep = _epSelector.select(template); if (ep == null) { - s_logger.warn("There is no secondary storage VM for downloading template to image store " + store.getName()); - return; + String errMsg = "There is no secondary storage VM for downloading template to image store " + store.getName(); + s_logger.warn(errMsg); + throw new CloudRuntimeException(errMsg); } DownloadListener dl = new DownloadListener(ep, store, template, _timer, this, dcmd, callback);