diff --git a/engine/api/src/org/apache/cloudstack/engine/cloud/entity/api/VolumeEntity.java b/engine/api/src/org/apache/cloudstack/engine/cloud/entity/api/VolumeEntity.java index 4f883c0b51b..47fb638401b 100755 --- a/engine/api/src/org/apache/cloudstack/engine/cloud/entity/api/VolumeEntity.java +++ b/engine/api/src/org/apache/cloudstack/engine/cloud/entity/api/VolumeEntity.java @@ -83,4 +83,5 @@ public interface VolumeEntity extends CloudStackEntity { StorageEntity getDataStore(); boolean createVolumeFromTemplate(long dataStoreId, VolumeDiskType diskType, TemplateEntity template); + boolean createVolume(long dataStoreId, VolumeDiskType diskType); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/command/CommandResult.java b/engine/storage/src/org/apache/cloudstack/storage/command/CommandResult.java index 5fe8a7e3134..998f35dd06b 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/command/CommandResult.java +++ b/engine/storage/src/org/apache/cloudstack/storage/command/CommandResult.java @@ -41,6 +41,9 @@ public class CommandResult { public void setResult(String result) { this.result = result; + if (result != null) { + this.success = false; + } } } \ No newline at end of file diff --git a/engine/storage/src/org/apache/cloudstack/storage/command/CreateVolumeCommand.java b/engine/storage/src/org/apache/cloudstack/storage/command/CreateVolumeCommand.java index 3d8880ff55e..e42d2651f51 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/command/CreateVolumeCommand.java +++ b/engine/storage/src/org/apache/cloudstack/storage/command/CreateVolumeCommand.java @@ -22,7 +22,7 @@ import org.apache.cloudstack.storage.to.VolumeTO; import com.cloud.agent.api.Command; -public class CreateVolumeCommand extends Command { +public class CreateVolumeCommand extends Command implements StorageSubSystemCommand { protected VolumeTO volumeInfo; public CreateVolumeCommand(VolumeTO volumeInfo) { diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStore.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStore.java index a945e289081..fca97916032 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStore.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStore.java @@ -38,7 +38,7 @@ public interface PrimaryDataStore extends PrimaryDataStoreInfo { boolean deleteVolume(VolumeInfo volume); - VolumeInfo createVolume(VolumeInfo vo, VolumeDiskType diskType); + void createVolumeAsync(VolumeInfo vo, VolumeDiskType diskType, AsyncCompletionCallback callback); VolumeInfo createVoluemFromBaseImage(VolumeInfo volume, TemplateOnPrimaryDataStoreInfo templateStore); diff --git a/engine/storage/src/org/apache/cloudstack/storage/volume/VolumeEntityImpl.java b/engine/storage/src/org/apache/cloudstack/storage/volume/VolumeEntityImpl.java index 8883e8e61bb..5449534deec 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/volume/VolumeEntityImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/volume/VolumeEntityImpl.java @@ -35,12 +35,14 @@ import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.datastore.PrimaryDataStoreEntityImpl; import org.apache.cloudstack.storage.image.TemplateEntityImpl; import org.apache.cloudstack.storage.image.TemplateInfo; +import org.apache.cloudstack.storage.volume.VolumeService.VolumeApiResult; import com.cloud.utils.exception.CloudRuntimeException; public class VolumeEntityImpl implements VolumeEntity { private VolumeInfo volumeInfo; private final VolumeService vs; + private VolumeApiResult result; protected VolumeEntityImpl() { this.vs = null; @@ -217,11 +219,38 @@ public class VolumeEntityImpl implements VolumeEntity { } - public Object createVolumeFromTemplateAsyncCallback(AsyncCompletionCallback callback, Object context) { + private Void createVolumeFromTemplateAsyncCallback(AsyncCompletionCallback callback, Object context) { synchronized (volumeInfo) { volumeInfo.notify(); } return null; } + @Override + public boolean createVolume(long dataStoreId, VolumeDiskType diskType) { + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + caller.setCallback(caller.getTarget().createVolumeCallback(null, null)); + vs.createVolumeAsync(volumeInfo, dataStoreId, diskType, caller); + try { + synchronized (volumeInfo) { + volumeInfo.wait(); + } + if (result.isSuccess()) { + return true; + } else { + throw new CloudRuntimeException("Failed to create volume:" + result.getResult()); + } + } catch (InterruptedException e) { + throw new CloudRuntimeException("wait volume info failed", e); + } + } + + private Void createVolumeCallback(AsyncCallbackDispatcher callback, Object context) { + synchronized (volumeInfo) { + this.result = callback.getResult(); + volumeInfo.notify(); + } + return null; + } + } diff --git a/engine/storage/src/org/apache/cloudstack/storage/volume/VolumeService.java b/engine/storage/src/org/apache/cloudstack/storage/volume/VolumeService.java index 716c26013b0..fcf6f987032 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/volume/VolumeService.java +++ b/engine/storage/src/org/apache/cloudstack/storage/volume/VolumeService.java @@ -24,9 +24,21 @@ import org.apache.cloudstack.engine.subsystem.api.storage.disktype.VolumeDiskTyp import org.apache.cloudstack.engine.subsystem.api.storage.type.VolumeType; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.EndPoint; +import org.apache.cloudstack.storage.command.CommandResult; import org.apache.cloudstack.storage.image.TemplateInfo; public interface VolumeService { + + public class VolumeApiResult extends CommandResult { + private final VolumeInfo volume; + public VolumeApiResult(VolumeInfo volume) { + this.volume = volume; + } + + public VolumeInfo getVolume() { + return this.volume; + } + } /** * */ @@ -39,7 +51,7 @@ public interface VolumeService { * * @return the volume object */ - VolumeInfo createVolume(VolumeInfo volume, long dataStoreId, VolumeDiskType diskType); + void createVolumeAsync(VolumeInfo volume, long dataStoreId, VolumeDiskType diskType, AsyncCompletionCallback callback); /** * Delete volume @@ -75,5 +87,5 @@ public interface VolumeService { VolumeEntity getVolumeEntity(long volumeId); void createVolumeFromTemplateAsync(VolumeInfo volume, long dataStoreId, VolumeDiskType diskType, TemplateInfo template, - AsyncCompletionCallback callback); + AsyncCompletionCallback callback); } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/DefaultPrimaryDataStore.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/DefaultPrimaryDataStore.java index 13b6f4a16a5..3d3ce68cc55 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/DefaultPrimaryDataStore.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/DefaultPrimaryDataStore.java @@ -34,6 +34,8 @@ import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.utils.component.ComponentInject; +import com.cloud.utils.exception.CloudRuntimeException; + import edu.emory.mathcs.backport.java.util.Collections; public class DefaultPrimaryDataStore implements PrimaryDataStore { @@ -155,8 +157,7 @@ public class DefaultPrimaryDataStore implements PrimaryDataStore { @Override public boolean isVolumeDiskTypeSupported(VolumeDiskType diskType) { - // TODO Auto-generated method stub - return false; + return true; } @Override @@ -170,14 +171,13 @@ public class DefaultPrimaryDataStore implements PrimaryDataStore { } @Override - public VolumeObject createVolume(VolumeInfo vi, VolumeDiskType diskType) { + public void createVolumeAsync(VolumeInfo vi, VolumeDiskType diskType, AsyncCompletionCallback callback) { if (!isVolumeDiskTypeSupported(diskType)) { - return null; + throw new CloudRuntimeException("disk type " + diskType + " is not supported"); } VolumeObject vo = (VolumeObject) vi; vo.setVolumeDiskType(diskType); - this.driver.createVolume(vo); - return vo; + this.driver.createVolumeAsync(vo, callback); } @Override diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/DefaultPrimaryDataStoreDriverImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/DefaultPrimaryDataStoreDriverImpl.java index 9506d7cc3ad..e88d707e26c 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/DefaultPrimaryDataStoreDriverImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/DefaultPrimaryDataStoreDriverImpl.java @@ -41,18 +41,49 @@ public class DefaultPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver this.dataStore = dataStore; } + private class CreateVolumeContext extends AsyncRpcConext { + private final VolumeObject volume; + /** + * @param callback + */ + public CreateVolumeContext(AsyncCompletionCallback callback, VolumeObject volume) { + super(callback); + this.volume = volume; + } + + public VolumeObject getVolume() { + return this.volume; + } + + } + @Override - public boolean createVolume(VolumeObject vol) { - // The default driver will send createvolume command to one of hosts - // which can access its datastore + public void createVolumeAsync(VolumeObject vol, AsyncCompletionCallback callback) { List endPoints = vol.getDataStore().getEndPoints(); + EndPoint ep = endPoints.get(0); VolumeInfo volInfo = vol; CreateVolumeCommand createCmd = new CreateVolumeCommand(this.dataStore.getVolumeTO(volInfo)); - Answer answer = sendOutCommand(createCmd, endPoints); + + CreateVolumeContext context = new CreateVolumeContext(callback, vol); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + caller.setContext(context) + .setCallback(caller.getTarget().createVolumeAsyncCallback(null, null)); - CreateVolumeAnswer volAnswer = (CreateVolumeAnswer) answer; - vol.setPath(volAnswer.getVolumeUuid()); - return true; + ep.sendMessageAsync(createCmd, caller); + } + + protected Void createVolumeAsyncCallback(AsyncCallbackDispatcher callback, CreateVolumeContext context) { + CommandResult result = new CommandResult(); + CreateVolumeAnswer volAnswer = (CreateVolumeAnswer) callback.getResult(); + if (volAnswer.getResult()) { + VolumeObject volume = context.getVolume(); + volume.setPath(volAnswer.getVolumeUuid()); + } else { + result.setResult(volAnswer.getDetails()); + } + + context.getParentCallback().complete(result); + return null; } @Override diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/PrimaryDataStoreDriver.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/PrimaryDataStoreDriver.java index 04694aa888a..96e629e2447 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/PrimaryDataStoreDriver.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/PrimaryDataStoreDriver.java @@ -10,7 +10,7 @@ import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreInfo; import org.apache.cloudstack.storage.volume.VolumeObject; public interface PrimaryDataStoreDriver { - boolean createVolume(VolumeObject vol); + void createVolumeAsync(VolumeObject vol, AsyncCompletionCallback callback); void createVolumeFromBaseImageAsync(VolumeObject volume, TemplateOnPrimaryDataStoreInfo template, AsyncCompletionCallback callback); 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 b5687fd62da..d5d26819181 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 @@ -59,28 +59,58 @@ public class VolumeServiceImpl implements VolumeService { public VolumeServiceImpl() { } + private class CreateVolumeContext extends AsyncRpcConext { + + private VolumeObject volume; + /** + * @param callback + */ + public CreateVolumeContext(AsyncCompletionCallback callback, VolumeObject volume) { + super(callback); + this.volume = volume; + } + + public VolumeObject getVolume() { + return this.volume; + } + + } + @Override - public VolumeInfo createVolume(VolumeInfo volume, long dataStoreId, VolumeDiskType diskType) { + public void createVolumeAsync(VolumeInfo volume, long dataStoreId, VolumeDiskType diskType, AsyncCompletionCallback callback) { PrimaryDataStore dataStore = dataStoreMgr.getPrimaryDataStore(dataStoreId); if (dataStore == null) { throw new CloudRuntimeException("Can't find dataStoreId: " + dataStoreId); } if (dataStore.exists(volume)) { - return volume; + throw new CloudRuntimeException("Volume: " + volume.getId() + " already exists on primary data store: " + dataStoreId); } VolumeObject vo = (VolumeObject) volume; vo.stateTransit(Volume.Event.CreateRequested); - try { - VolumeInfo vi = dataStore.createVolume(vo, diskType); + CreateVolumeContext context = new CreateVolumeContext(callback, vo); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + caller.setCallback(caller.getTarget().createVolumeCallback(null, null)) + .setContext(context); + + dataStore.createVolumeAsync(vo, diskType, caller); + } + + protected Void createVolumeCallback(AsyncCallbackDispatcher callback, CreateVolumeContext context) { + CommandResult result = callback.getResult(); + VolumeObject vo = context.getVolume(); + VolumeApiResult volResult = new VolumeApiResult(vo); + if (result.isSuccess()) { vo.stateTransit(Volume.Event.OperationSucceeded); - return vi; - } catch (Exception e) { + } else { vo.stateTransit(Volume.Event.OperationFailed); - throw new CloudRuntimeException(e.toString()); + volResult.setResult(result.getResult()); } + + context.getParentCallback().complete(volResult); + return null; } @DB @@ -240,7 +270,6 @@ public class VolumeServiceImpl implements VolumeService { } AsyncCompletionCallback parentCall = context.getParentCallback(); - parentCall.complete(vo); return null; } diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java index d2d229b4870..a891ffec165 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java @@ -12,7 +12,7 @@ import org.apache.cloudstack.storage.volume.VolumeObject; public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { @Override - public boolean createVolume(VolumeObject vol) { + public boolean createVolumeAsync(VolumeObject vol) { // TODO Auto-generated method stub return false; }