Skip to content

Commit 9a62239

Browse files
committed
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.
1 parent 84b5bff commit 9a62239

3 files changed

Lines changed: 79 additions & 27 deletions

File tree

engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,26 @@ public void createTemplateAsync(TemplateInfo template, DataStore store,
172172
return;
173173
}
174174

175-
TemplateOpContext<TemplateApiResult> context = new TemplateOpContext<TemplateApiResult>(callback,
176-
templateOnStore, null);
177-
178-
AsyncCallbackDispatcher<TemplateServiceImpl, CreateCmdResult> caller = AsyncCallbackDispatcher.create(this);
179-
caller.setCallback(caller.getTarget().createTemplateCallback(null, null)).setContext(context);
180-
store.getDriver().createAsync(store, templateOnStore, caller);
175+
try {
176+
TemplateOpContext<TemplateApiResult> context = new TemplateOpContext<TemplateApiResult>(callback,
177+
templateOnStore, null);
178+
179+
AsyncCallbackDispatcher<TemplateServiceImpl, CreateCmdResult> caller = AsyncCallbackDispatcher.create(this);
180+
caller.setCallback(caller.getTarget().createTemplateCallback(null, null)).setContext(context);
181+
store.getDriver().createAsync(store, templateOnStore, caller);
182+
} catch (CloudRuntimeException ex) {
183+
// clean up already persisted template_store_ref entry in case of createTemplateCallback is never called
184+
TemplateDataStoreVO templateStoreVO = _vmTemplateStoreDao.findByStoreTemplate(store.getId(), template.getId());
185+
if (templateStoreVO != null) {
186+
TemplateInfo tmplObj = _templateFactory.getTemplate(template, store);
187+
tmplObj.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed);
188+
}
189+
TemplateApiResult result = new TemplateApiResult(template);
190+
result.setResult(ex.getMessage());
191+
if (callback != null) {
192+
callback.complete(result);
193+
}
194+
}
181195
}
182196

183197
@Override
@@ -732,11 +746,23 @@ public AsyncCallFuture<TemplateApiResult> copyTemplate(TemplateInfo srcTemplate,
732746
if (s_logger.isDebugEnabled()) {
733747
s_logger.debug("Invoke datastore driver createAsync to create template on destination store");
734748
}
735-
TemplateOpContext<TemplateApiResult> context = new TemplateOpContext<TemplateApiResult>(null,
736-
(TemplateObject) templateOnStore, future);
737-
AsyncCallbackDispatcher<TemplateServiceImpl, CreateCmdResult> caller = AsyncCallbackDispatcher.create(this);
738-
caller.setCallback(caller.getTarget().copyTemplateCrossZoneCallBack(null, null)).setContext(context);
739-
destStore.getDriver().createAsync(destStore, templateOnStore, caller);
749+
try {
750+
TemplateOpContext<TemplateApiResult> context = new TemplateOpContext<TemplateApiResult>(null,
751+
(TemplateObject)templateOnStore, future);
752+
AsyncCallbackDispatcher<TemplateServiceImpl, CreateCmdResult> caller = AsyncCallbackDispatcher.create(this);
753+
caller.setCallback(caller.getTarget().copyTemplateCrossZoneCallBack(null, null)).setContext(context);
754+
destStore.getDriver().createAsync(destStore, templateOnStore, caller);
755+
} catch (CloudRuntimeException ex) {
756+
// clean up already persisted template_store_ref entry in case of createTemplateCallback is never called
757+
TemplateDataStoreVO templateStoreVO = _vmTemplateStoreDao.findByStoreTemplate(destStore.getId(), srcTemplate.getId());
758+
if (templateStoreVO != null) {
759+
TemplateInfo tmplObj = _templateFactory.getTemplate(srcTemplate, destStore);
760+
tmplObj.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed);
761+
}
762+
TemplateApiResult res = new TemplateApiResult((TemplateObject)templateOnStore);
763+
res.setResult(ex.getMessage());
764+
future.complete(res);
765+
}
740766
return future;
741767
}
742768

engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
4141
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
4242
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event;
43+
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore;
4344
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
4445
import org.apache.cloudstack.engine.subsystem.api.storage.Scope;
4546
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
@@ -55,7 +56,6 @@
5556
import org.apache.cloudstack.storage.command.CommandResult;
5657
import org.apache.cloudstack.storage.command.CopyCmdAnswer;
5758
import org.apache.cloudstack.storage.command.DeleteCommand;
58-
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore;
5959
import org.apache.cloudstack.storage.datastore.PrimaryDataStoreProviderManager;
6060
import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao;
6161
import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO;
@@ -165,12 +165,24 @@ public AsyncCallFuture<VolumeApiResult> createVolumeAsync(VolumeInfo volume, Dat
165165
DataObject volumeOnStore = dataStore.create(volume);
166166
volumeOnStore.processEvent(Event.CreateOnlyRequested);
167167

168-
CreateVolumeContext<VolumeApiResult> context = new CreateVolumeContext<VolumeApiResult>(null, volumeOnStore,
169-
future);
170-
AsyncCallbackDispatcher<VolumeServiceImpl, CreateCmdResult> caller = AsyncCallbackDispatcher.create(this);
171-
caller.setCallback(caller.getTarget().createVolumeCallback(null, null)).setContext(context);
172-
173-
dataStore.getDriver().createAsync(dataStore, volumeOnStore, caller);
168+
try {
169+
CreateVolumeContext<VolumeApiResult> context = new CreateVolumeContext<VolumeApiResult>(null, volumeOnStore,
170+
future);
171+
AsyncCallbackDispatcher<VolumeServiceImpl, CreateCmdResult> caller = AsyncCallbackDispatcher.create(this);
172+
caller.setCallback(caller.getTarget().createVolumeCallback(null, null)).setContext(context);
173+
174+
dataStore.getDriver().createAsync(dataStore, volumeOnStore, caller);
175+
} catch (CloudRuntimeException ex) {
176+
// clean up already persisted volume_store_ref entry in case of createVolumeCallback is never called
177+
VolumeDataStoreVO volStoreVO = _volumeStoreDao.findByStoreVolume(dataStore.getId(), volume.getId());
178+
if (volStoreVO != null) {
179+
VolumeInfo volObj = volFactory.getVolume(volume, dataStore);
180+
volObj.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed);
181+
}
182+
VolumeApiResult volResult = new VolumeApiResult((VolumeObject)volumeOnStore);
183+
volResult.setResult(ex.getMessage());
184+
future.complete(volResult);
185+
}
174186
return future;
175187
}
176188

@@ -1022,13 +1034,25 @@ public AsyncCallFuture<VolumeApiResult> registerVolume(VolumeInfo volume, DataSt
10221034

10231035
volumeOnStore.processEvent(Event.CreateOnlyRequested);
10241036

1025-
CreateVolumeContext<VolumeApiResult> context = new CreateVolumeContext<VolumeApiResult>(null, volumeOnStore,
1026-
future);
1027-
AsyncCallbackDispatcher<VolumeServiceImpl, CreateCmdResult> caller = AsyncCallbackDispatcher.create(this);
1028-
caller.setCallback(caller.getTarget().registerVolumeCallback(null, null));
1029-
caller.setContext(context);
1030-
1031-
store.getDriver().createAsync(store, volumeOnStore, caller);
1037+
try {
1038+
CreateVolumeContext<VolumeApiResult> context = new CreateVolumeContext<VolumeApiResult>(null, volumeOnStore,
1039+
future);
1040+
AsyncCallbackDispatcher<VolumeServiceImpl, CreateCmdResult> caller = AsyncCallbackDispatcher.create(this);
1041+
caller.setCallback(caller.getTarget().registerVolumeCallback(null, null));
1042+
caller.setContext(context);
1043+
1044+
store.getDriver().createAsync(store, volumeOnStore, caller);
1045+
} catch (CloudRuntimeException ex) {
1046+
// clean up already persisted volume_store_ref entry in case of createVolumeCallback is never called
1047+
VolumeDataStoreVO volStoreVO = _volumeStoreDao.findByStoreVolume(store.getId(), volume.getId());
1048+
if (volStoreVO != null) {
1049+
VolumeInfo volObj = volFactory.getVolume(volume, store);
1050+
volObj.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed);
1051+
}
1052+
VolumeApiResult res = new VolumeApiResult((VolumeObject)volumeOnStore);
1053+
res.setResult(ex.getMessage());
1054+
future.complete(res);
1055+
}
10321056
return future;
10331057
}
10341058

server/src/com/cloud/storage/download/DownloadMonitorImpl.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
import com.cloud.template.VirtualMachineTemplate;
6868
import com.cloud.utils.component.ComponentContext;
6969
import com.cloud.utils.component.ManagerBase;
70+
import com.cloud.utils.exception.CloudRuntimeException;
7071

7172
@Component
7273
@Local(value = { DownloadMonitor.class })
@@ -169,8 +170,9 @@ private void initiateTemplateDownload(DataObject template, AsyncCompletionCallba
169170
}
170171
EndPoint ep = _epSelector.select(template);
171172
if (ep == null) {
172-
s_logger.warn("There is no secondary storage VM for downloading template to image store " + store.getName());
173-
return;
173+
String errMsg = "There is no secondary storage VM for downloading template to image store " + store.getName();
174+
s_logger.warn(errMsg);
175+
throw new CloudRuntimeException(errMsg);
174176
}
175177
DownloadListener dl = new DownloadListener(ep, store, template, _timer, this, dcmd,
176178
callback);

0 commit comments

Comments
 (0)