diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPoint.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPoint.java deleted file mode 100644 index cecc6f5e8f2..00000000000 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPoint.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.apache.cloudstack.engine.subsystem.api.storage; - -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.Command; - -public interface EndPoint { - public Answer sendMessage(Command cmd); -} diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java index 27ea41c1a63..e53b6a27481 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java @@ -23,6 +23,7 @@ import java.util.List; import org.apache.cloudstack.engine.datacenter.entity.api.DataCenterResourceEntity.State; import org.apache.cloudstack.engine.subsystem.api.storage.disktype.VolumeDiskType; +import org.apache.cloudstack.storage.EndPoint; import com.cloud.hypervisor.Hypervisor.HypervisorType; diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageServiceImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageServiceImpl.java index 38f669b051f..6499db1c366 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageServiceImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageServiceImpl.java @@ -21,7 +21,7 @@ package org.apache.cloudstack.storage.image; import javax.inject.Inject; import org.apache.cloudstack.engine.cloud.entity.api.TemplateEntity; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; +import org.apache.cloudstack.storage.EndPoint; import org.apache.cloudstack.storage.image.downloader.ImageDownloader; import org.apache.cloudstack.storage.image.manager.ImageDataStoreManager; import org.apache.cloudstack.storage.image.provider.ImageDataStoreProviderManager; diff --git a/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/DefaultImageMotionStrategy.java b/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/DefaultImageMotionStrategy.java index 625cdc91f77..be541b51300 100644 --- a/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/DefaultImageMotionStrategy.java +++ b/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/DefaultImageMotionStrategy.java @@ -18,13 +18,20 @@ */ package org.apache.cloudstack.storage.image.motion; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; +import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; +import org.apache.cloudstack.framework.async.AsyncCallbackHandler; +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.command.CopyTemplateToPrimaryStorage; +import org.apache.cloudstack.storage.command.CopyTemplateToPrimaryStorageAnswer; import org.apache.cloudstack.storage.to.ImageOnPrimayDataStoreTO; import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreInfo; import org.springframework.stereotype.Component; +import com.cloud.agent.api.Answer; + @Component public class DefaultImageMotionStrategy implements ImageMotionStrategy { @@ -48,4 +55,30 @@ public class DefaultImageMotionStrategy implements ImageMotionStrategy { return true; } + @Override + public void copyTemplateAsync(TemplateOnPrimaryDataStoreInfo templateStore, EndPoint ep, AsyncCompletionCallback callback) { + ImageOnPrimayDataStoreTO imageTo = new ImageOnPrimayDataStoreTO(templateStore); + CopyTemplateToPrimaryStorage copyCommand = new CopyTemplateToPrimaryStorage(imageTo); + AsyncCallbackDispatcher caller = new AsyncCallbackDispatcher(this).setParentCallback(callback) + .setOperationName("defaultImageStrategy.copytemplate.callback") + .setContextParam("templateStore", templateStore); + ep.sendMessageAsync(copyCommand, caller); + } + + @AsyncCallbackHandler(operationName="defaultImageStrategy.copytemplate.callback") + public void copyTemplateCallBack(AsyncCallbackDispatcher callback) { + AsyncCallbackDispatcher parentCall = callback.getParentCallback(); + CopyTemplateToPrimaryStorageAnswer answer = callback.getResult(); + CommandResult result = new CommandResult(); + + result.setSucess(answer.getResult()); + result.setResult(answer.getDetails()); + if (answer.getResult()) { + TemplateOnPrimaryDataStoreInfo templateStore = callback.getContextParam("templateStore"); + templateStore.setPath(answer.getPath()); + } + + parentCall.complete(result); + } + } diff --git a/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/ImageMotionServiceImpl.java b/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/ImageMotionServiceImpl.java index 85db4dcff20..85baba6f614 100644 --- a/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/ImageMotionServiceImpl.java +++ b/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/ImageMotionServiceImpl.java @@ -22,7 +22,11 @@ import java.util.List; import javax.inject.Inject; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; +import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; +import org.apache.cloudstack.framework.async.AsyncCallbackHandler; +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.ImageService; import org.apache.cloudstack.storage.image.TemplateInfo; import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreInfo; @@ -67,4 +71,36 @@ public class ImageMotionServiceImpl implements ImageMotionService { imageService.grantTemplateAccess(template, ep); return ims.copyTemplate(templateStore, ep); } + + @Override + public void copyTemplateAsync(TemplateOnPrimaryDataStoreInfo templateStore, AsyncCompletionCallback callback) { + ImageMotionStrategy ims = null; + for (ImageMotionStrategy strategy : motionStrategies) { + if (strategy.canHandle(templateStore)) { + ims = strategy; + break; + } + } + + if (ims == null) { + throw new CloudRuntimeException("Can't find proper image motion strategy"); + } + + EndPoint ep = ims.getEndPoint(templateStore); + volumeService.grantAccess(templateStore, ep); + TemplateInfo template = templateStore.getTemplate(); + imageService.grantTemplateAccess(template, ep); + + AsyncCallbackDispatcher caller = new AsyncCallbackDispatcher(this) + .setParentCallback(callback) + .setOperationName("imagemotionService.copytemplate.callback"); + + ims.copyTemplateAsync(templateStore, ep, caller); + } + + @AsyncCallbackHandler(operationName="imagemotionService.copytemplate.callback") + public void copyTemplateAsyncCallback(AsyncCallbackDispatcher callback) { + AsyncCallbackDispatcher parentCaller = callback.getParentCallback(); + parentCaller.complete(callback.getResult()); + } } diff --git a/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/ImageMotionStrategy.java b/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/ImageMotionStrategy.java index e1df9e29293..f1f4c7b8319 100644 --- a/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/ImageMotionStrategy.java +++ b/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/ImageMotionStrategy.java @@ -18,8 +18,10 @@ */ package org.apache.cloudstack.storage.image.motion; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; +import org.apache.cloudstack.framework.async.AsyncCompletionCallback; +import org.apache.cloudstack.storage.EndPoint; import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreInfo; +import org.apache.cloudstack.storage.command.CommandResult; public interface ImageMotionStrategy { public boolean canHandle(TemplateOnPrimaryDataStoreInfo templateStore); @@ -27,4 +29,6 @@ public interface ImageMotionStrategy { public EndPoint getEndPoint(TemplateOnPrimaryDataStoreInfo templateStore); public boolean copyTemplate(TemplateOnPrimaryDataStoreInfo templateStore, EndPoint ep); + + public void copyTemplateAsync(TemplateOnPrimaryDataStoreInfo templateStore, EndPoint ep, AsyncCompletionCallback callback); } diff --git a/engine/storage/pom.xml b/engine/storage/pom.xml index 95eeade65b8..e8a2eb75193 100644 --- a/engine/storage/pom.xml +++ b/engine/storage/pom.xml @@ -40,6 +40,11 @@ cloud-engine-components-api ${project.version} + + org.apache.cloudstack + cloud-framework-ipc + ${project.version} + org.apache.cloudstack cloud-engine-api diff --git a/engine/storage/src/org/apache/cloudstack/storage/EndPoint.java b/engine/storage/src/org/apache/cloudstack/storage/EndPoint.java new file mode 100644 index 00000000000..e92877c6a84 --- /dev/null +++ b/engine/storage/src/org/apache/cloudstack/storage/EndPoint.java @@ -0,0 +1,11 @@ +package org.apache.cloudstack.storage; + +import org.apache.cloudstack.framework.async.AsyncCompletionCallback; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; + +public interface EndPoint { + public Answer sendMessage(Command cmd); + public void sendMessageAsync(Command cmd, AsyncCompletionCallback callback); +} diff --git a/engine/storage/src/org/apache/cloudstack/storage/HypervisorHostEndPoint.java b/engine/storage/src/org/apache/cloudstack/storage/HypervisorHostEndPoint.java index a7c1041767f..5b422590bd5 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/HypervisorHostEndPoint.java +++ b/engine/storage/src/org/apache/cloudstack/storage/HypervisorHostEndPoint.java @@ -20,7 +20,9 @@ package org.apache.cloudstack.storage; import javax.inject.Inject; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; +import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; +import org.apache.cloudstack.framework.async.AsyncCallbackHandler; +import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; @@ -31,12 +33,16 @@ import com.cloud.exception.OperationTimedoutException; public class HypervisorHostEndPoint implements EndPoint { private static final Logger s_logger = Logger.getLogger(HypervisorHostEndPoint.class); - private long hostId; + private final long hostId; + private final String hostAddress; @Inject AgentManager agentMgr; + @Inject + HypervsiorHostEndPointRpcServer rpcServer; - public HypervisorHostEndPoint(long hostId) { + public HypervisorHostEndPoint(long hostId, String hostAddress) { this.hostId = hostId; + this.hostAddress = hostAddress; } @Override @@ -53,5 +59,18 @@ public class HypervisorHostEndPoint implements EndPoint { } return answer; } + + @Override + public void sendMessageAsync(Command cmd, AsyncCompletionCallback callback) { + AsyncCallbackDispatcher dispatcher = new AsyncCallbackDispatcher(this).setContextParam("parentCallback", callback). + setOperationName("hypervisorEndpoint.sendMessage.callback"); + rpcServer.sendCommandAsync(this.hostAddress, cmd, dispatcher); + } + + @AsyncCallbackHandler(operationName="hypervisorEndpoint.sendMessage.callback") + public void sendMessageCallback(AsyncCallbackDispatcher callback) { + AsyncCallbackDispatcher parentDispatcher = callback.getContextParam("parentCallback"); + parentDispatcher.complete(callback.getResult()); + } } diff --git a/engine/storage/src/org/apache/cloudstack/storage/HypervsiorHostEndPointRpcServer.java b/engine/storage/src/org/apache/cloudstack/storage/HypervsiorHostEndPointRpcServer.java new file mode 100644 index 00000000000..c1b5760a4d4 --- /dev/null +++ b/engine/storage/src/org/apache/cloudstack/storage/HypervsiorHostEndPointRpcServer.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.storage; + +import javax.inject.Inject; + +import org.apache.cloudstack.framework.async.AsyncCompletionCallback; +import org.apache.cloudstack.framework.rpc.RpcCallbackListener; +import org.apache.cloudstack.framework.rpc.RpcException; +import org.apache.cloudstack.framework.rpc.RpcProvider; +import org.apache.cloudstack.framework.rpc.RpcServiceDispatcher; +import org.springframework.stereotype.Component; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; + +@Component +public class HypervsiorHostEndPointRpcServer { + @Inject + private RpcProvider _rpcProvider; + public HypervsiorHostEndPointRpcServer() { + _rpcProvider.registerRpcServiceEndpoint(RpcServiceDispatcher.getDispatcher(this)); + } + + public void sendCommandAsync(String host, final Command command, final AsyncCompletionCallback callback) { + _rpcProvider.newCall(host).addCallbackListener(new RpcCallbackListener() { + @Override + public void onSuccess(Answer result) { + callback.complete(result); + } + + @Override + public void onFailure(RpcException e) { + Answer answer = new Answer(command, false, e.toString()); + callback.complete(answer); + } + }).apply(); + } +} diff --git a/engine/storage/src/org/apache/cloudstack/storage/command/CommandResult.java b/engine/storage/src/org/apache/cloudstack/storage/command/CommandResult.java new file mode 100644 index 00000000000..5fe8a7e3134 --- /dev/null +++ b/engine/storage/src/org/apache/cloudstack/storage/command/CommandResult.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.storage.command; + +public class CommandResult { + private boolean success; + private String result; + + public CommandResult() { + this.success = false; + this.result = ""; + } + + public boolean isSuccess() { + return this.success; + } + + public void setSucess(boolean success) { + this.success = success; + } + + public String getResult() { + return this.result; + } + + public void setResult(String result) { + this.result = result; + } +} + \ No newline at end of file diff --git a/engine/storage/src/org/apache/cloudstack/storage/command/CopyTemplateToPrimaryStorageAnswer.java b/engine/storage/src/org/apache/cloudstack/storage/command/CopyTemplateToPrimaryStorageAnswer.java index 5a91117d386..f67c102cdc6 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/command/CopyTemplateToPrimaryStorageAnswer.java +++ b/engine/storage/src/org/apache/cloudstack/storage/command/CopyTemplateToPrimaryStorageAnswer.java @@ -3,5 +3,13 @@ package org.apache.cloudstack.storage.command; import com.cloud.agent.api.Answer; public class CopyTemplateToPrimaryStorageAnswer extends Answer { - + private final String path; + + public CopyTemplateToPrimaryStorageAnswer(String path) { + this.path = path; + } + + public String getPath() { + return this.path; + } } 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 befb9d694ad..9005bc083d3 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStore.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStore.java @@ -20,10 +20,12 @@ package org.apache.cloudstack.storage.datastore; import java.util.List; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.disktype.VolumeDiskType; +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; import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreInfo; @@ -37,7 +39,9 @@ public interface PrimaryDataStore extends PrimaryDataStoreInfo { VolumeInfo createVolume(VolumeInfo vo, VolumeDiskType diskType); VolumeInfo createVoluemFromBaseImage(VolumeInfo volume, TemplateOnPrimaryDataStoreInfo templateStore); - + + void createVoluemFromBaseImageAsync(VolumeInfo volume, TemplateOnPrimaryDataStoreInfo templateStore, AsyncCompletionCallback callback); + List getEndPoints(); boolean exists(VolumeInfo vi); diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/ImageService.java b/engine/storage/src/org/apache/cloudstack/storage/image/ImageService.java index d657715eab5..feff9c69e05 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/image/ImageService.java +++ b/engine/storage/src/org/apache/cloudstack/storage/image/ImageService.java @@ -19,7 +19,7 @@ package org.apache.cloudstack.storage.image; import org.apache.cloudstack.engine.cloud.entity.api.TemplateEntity; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; +import org.apache.cloudstack.storage.EndPoint; public interface ImageService { TemplateEntity registerTemplate(long templateId, long imageStoreId); diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/motion/ImageMotionService.java b/engine/storage/src/org/apache/cloudstack/storage/image/motion/ImageMotionService.java index 9f481155418..1f60e4a7ce7 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/image/motion/ImageMotionService.java +++ b/engine/storage/src/org/apache/cloudstack/storage/image/motion/ImageMotionService.java @@ -18,10 +18,13 @@ */ package org.apache.cloudstack.storage.image.motion; +import org.apache.cloudstack.framework.async.AsyncCompletionCallback; +import org.apache.cloudstack.storage.command.CommandResult; import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreInfo; public interface ImageMotionService { boolean copyTemplate(TemplateOnPrimaryDataStoreInfo templateStore); + void copyTemplateAsync(TemplateOnPrimaryDataStoreInfo templateStore, AsyncCompletionCallback callback); boolean copyIso(String isoUri, String destIsoUri); } 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 ab77e9955d5..716c26013b0 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/volume/VolumeService.java +++ b/engine/storage/src/org/apache/cloudstack/storage/volume/VolumeService.java @@ -19,10 +19,11 @@ package org.apache.cloudstack.storage.volume; import org.apache.cloudstack.engine.cloud.entity.api.VolumeEntity; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.disktype.VolumeDiskType; 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.image.TemplateInfo; public interface VolumeService { @@ -73,5 +74,6 @@ public interface VolumeService { VolumeEntity getVolumeEntity(long volumeId); - VolumeInfo createVolumeFromTemplate(VolumeInfo volume, long dataStoreId, VolumeDiskType diskType, TemplateInfo template); + void createVolumeFromTemplateAsync(VolumeInfo volume, long dataStoreId, VolumeDiskType diskType, TemplateInfo template, + 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 5029a48bb18..37162e7e335 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 @@ -6,12 +6,12 @@ import java.util.List; import javax.inject.Inject; import org.apache.cloudstack.engine.datacenter.entity.api.DataCenterResourceEntity.State; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreProvider; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.disktype.VolumeDiskType; +import org.apache.cloudstack.storage.EndPoint; import org.apache.cloudstack.storage.HypervisorHostEndPoint; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreVO; import org.apache.cloudstack.storage.datastore.driver.DefaultPrimaryDataStoreDriverImpl; @@ -101,7 +101,7 @@ public class DefaultPrimaryDataStore implements PrimaryDataStore { List endpoints = new ArrayList(); List hosts = hostDao.findHypervisorHostInCluster(clusterId); for (HostVO host : hosts) { - HypervisorHostEndPoint ep = new HypervisorHostEndPoint(host.getId()); + HypervisorHostEndPoint ep = new HypervisorHostEndPoint(host.getId(), host.getPrivateIpAddress()); ComponentInject.inject(ep); endpoints.add(ep); } 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 7c109e7688d..8588ca3bca6 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 @@ -3,8 +3,8 @@ package org.apache.cloudstack.storage.datastore.driver; import java.util.List; import java.util.Map; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.storage.EndPoint; import org.apache.cloudstack.storage.command.CreateVolumeAnswer; import org.apache.cloudstack.storage.command.CreateVolumeCommand; import org.apache.cloudstack.storage.command.CreateVolumeFromBaseImageCommand; 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 685bb691184..0b25e9b35cf 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 @@ -2,7 +2,7 @@ package org.apache.cloudstack.storage.datastore.driver; import java.util.Map; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; +import org.apache.cloudstack.storage.EndPoint; import org.apache.cloudstack.storage.datastore.PrimaryDataStore; import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreInfo; import org.apache.cloudstack.storage.volume.VolumeObject; 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 2340185bb96..f119a59e84a 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 @@ -22,11 +22,15 @@ import javax.inject.Inject; import org.apache.cloudstack.engine.cloud.entity.api.TemplateEntity; import org.apache.cloudstack.engine.cloud.entity.api.VolumeEntity; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.disktype.VolumeDiskType; import org.apache.cloudstack.engine.subsystem.api.storage.type.BaseImage; import org.apache.cloudstack.engine.subsystem.api.storage.type.VolumeType; +import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; +import org.apache.cloudstack.framework.async.AsyncCallbackHandler; +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.datastore.PrimaryDataStore; import org.apache.cloudstack.storage.datastore.manager.PrimaryDataStoreManager; import org.apache.cloudstack.storage.image.TemplateEntityImpl; @@ -132,7 +136,7 @@ public class VolumeServiceImpl implements VolumeService { return null; } - protected TemplateOnPrimaryDataStoreObject createBaseImage(PrimaryDataStore dataStore, TemplateInfo template) { + protected void createBaseImageAsync(PrimaryDataStore dataStore, TemplateInfo template, AsyncCompletionCallback callback) { TemplateOnPrimaryDataStoreObject templateOnPrimaryStoreObj = (TemplateOnPrimaryDataStoreObject) templatePrimaryStoreMgr.createTemplateOnPrimaryDataStore(template, dataStore); templateOnPrimaryStoreObj.stateTransit(TemplateOnPrimaryDataStoreStateMachine.Event.CreateRequested); templateOnPrimaryStoreObj.updateStatus(Status.CREATING); @@ -146,27 +150,38 @@ public class VolumeServiceImpl implements VolumeService { } templateOnPrimaryStoreObj.updateStatus(Status.DOWNLOAD_IN_PROGRESS); - try { - imageMotion.copyTemplate(templateOnPrimaryStoreObj); - templateOnPrimaryStoreObj.updateStatus(Status.DOWNLOADED); - templateOnPrimaryStoreObj.stateTransit(TemplateOnPrimaryDataStoreStateMachine.Event.OperationSuccessed); - } catch (Exception e) { - templateOnPrimaryStoreObj.updateStatus(Status.ABANDONED); - templateOnPrimaryStoreObj.stateTransit(TemplateOnPrimaryDataStoreStateMachine.Event.OperationFailed); - throw new CloudRuntimeException(e.toString()); - } - return templateOnPrimaryStoreObj; + AsyncCallbackDispatcher caller = new AsyncCallbackDispatcher(this) + .setParentCallback(callback) + .setOperationName("volumeservice.createbaseimage.callback") + .setContextParam("templateOnPrimary", templateOnPrimaryStoreObj); + + imageMotion.copyTemplateAsync(templateOnPrimaryStoreObj, caller); } - @Override - public VolumeInfo createVolumeFromTemplate(VolumeInfo volume, long dataStoreId, VolumeDiskType diskType, TemplateInfo template) { - PrimaryDataStore pd = dataStoreMgr.getPrimaryDataStore(dataStoreId); - TemplateOnPrimaryDataStoreInfo templateOnPrimaryStore = pd.getTemplate(template); - if (templateOnPrimaryStore == null) { - templateOnPrimaryStore = createBaseImage(pd, template); + @AsyncCallbackHandler(operationName="volumeservice.createbaseimage.callback") + public void createBaseImageCallback(AsyncCallbackDispatcher callback) { + CommandResult result = callback.getResult(); + TemplateOnPrimaryDataStoreObject templateOnPrimaryStoreObj = callback.getContextParam("templateOnPrimary"); + if (result.isSuccess()) { + templateOnPrimaryStoreObj.updateStatus(Status.DOWNLOADED); + templateOnPrimaryStoreObj.stateTransit(TemplateOnPrimaryDataStoreStateMachine.Event.OperationSuccessed); + } else { + templateOnPrimaryStoreObj.updateStatus(Status.ABANDONED); + templateOnPrimaryStoreObj.stateTransit(TemplateOnPrimaryDataStoreStateMachine.Event.OperationFailed); } - + + AsyncCallbackDispatcher parentCaller = callback.getParentCallback(); + VolumeInfo volume = parentCaller.getContextParam("volume"); + PrimaryDataStore pd = parentCaller.getContextParam("primary"); + AsyncCallbackDispatcher caller = new AsyncCallbackDispatcher(this) + .setParentCallback(parentCaller) + .setOperationName("volumeservice.createvolumefrombaseimage.callback"); + + createVolumeFromBaseImageAsync(volume, templateOnPrimaryStoreObj, pd, caller); + } + + protected void createVolumeFromBaseImageAsync(VolumeInfo volume, TemplateOnPrimaryDataStoreInfo templateOnPrimaryStore, PrimaryDataStore pd, AsyncCompletionCallback callback) { VolumeObject vo = (VolumeObject) volume; try { vo.stateTransit(Volume.Event.CreateRequested); @@ -174,14 +189,54 @@ public class VolumeServiceImpl implements VolumeService { throw new CloudRuntimeException(e.toString()); } - try { - volume = pd.createVoluemFromBaseImage(volume, templateOnPrimaryStore); - vo.stateTransit(Volume.Event.OperationSucceeded); - } catch (Exception e) { + + AsyncCallbackDispatcher caller = new AsyncCallbackDispatcher(this) + .setParentCallback(callback) + .setOperationName("volumeservice.createVolumeFromBaseImageCallback") + .setContextParam("volume", vo); + + pd.createVoluemFromBaseImageAsync(volume, templateOnPrimaryStore, caller); + } + + @AsyncCallbackHandler(operationName="volumeservice.createVolumeFromBaseImageCallback") + public void createVolumeFromBaseImageCallback(AsyncCallbackDispatcher callback) { + VolumeObject vo = callback.getContextParam("volume"); + CommandResult result = callback.getResult(); + if (result.isSuccess()) { + vo.stateTransit(Volume.Event.OperationSucceeded); + } else { vo.stateTransit(Volume.Event.OperationFailed); - throw new CloudRuntimeException(e.toString()); } - return volume; + + AsyncCallbackDispatcher parentCall = callback.getParentCallback(); + parentCall.complete(vo); + } + + @AsyncCallbackHandler(operationName="volumeservice.createvolumefrombaseimage.callback") + public void createVolumeFromBaseImageAsyncCallback(AsyncCallbackDispatcher callback) { + AsyncCallbackDispatcher parentCall = callback.getParentCallback(); + VolumeObject vo = callback.getResult(); + parentCall.complete(vo); + } + + @Override + public void createVolumeFromTemplateAsync(VolumeInfo volume, long dataStoreId, VolumeDiskType diskType, TemplateInfo template, AsyncCompletionCallback callback) { + PrimaryDataStore pd = dataStoreMgr.getPrimaryDataStore(dataStoreId); + TemplateOnPrimaryDataStoreInfo templateOnPrimaryStore = pd.getTemplate(template); + if (templateOnPrimaryStore == null) { + AsyncCallbackDispatcher caller = new AsyncCallbackDispatcher(this).setParentCallback(callback) + .setOperationName("volumeservice.createbaseimage.callback") + .setContextParam("volume", volume) + .setContextParam("primary", pd); + createBaseImageAsync(pd, template, caller); + return; + } + + AsyncCallbackDispatcher caller = new AsyncCallbackDispatcher(this) + .setParentCallback(callback) + .setOperationName("volumeservice.createvolumefrombaseimage.callback"); + + createVolumeFromBaseImageAsync(volume, templateOnPrimaryStore, pd, caller); } @Override diff --git a/engine/storage/volume/test/org/apache/cloudstack/storage/volume/test/Server.java b/engine/storage/volume/test/org/apache/cloudstack/storage/volume/test/Server.java new file mode 100644 index 00000000000..a863cc85237 --- /dev/null +++ b/engine/storage/volume/test/org/apache/cloudstack/storage/volume/test/Server.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.storage.volume.test; + +import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; +import org.apache.cloudstack.framework.async.AsyncCallbackHandler; + +public class Server { + Server1 svr; + public Server() { + svr = new Server1(); + } + void foo() { + svr.foo1("foo", new AsyncCallbackDispatcher(this).setOperationName("callback").setContextParam("name", "foo")); + } + @AsyncCallbackHandler(operationName="callback") + void foocallback(AsyncCallbackDispatcher callback) { + System.out.println(callback.getContextParam("name")); + String result = callback.getResult(); + System.out.println(result); + } + +} diff --git a/engine/storage/volume/test/org/apache/cloudstack/storage/volume/test/Server1.java b/engine/storage/volume/test/org/apache/cloudstack/storage/volume/test/Server1.java new file mode 100644 index 00000000000..bf56e6e4b33 --- /dev/null +++ b/engine/storage/volume/test/org/apache/cloudstack/storage/volume/test/Server1.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.storage.volume.test; + +import org.apache.cloudstack.framework.async.AsyncCompletionCallback; + +public class Server1 { + public void foo1(String name, AsyncCompletionCallback callback) { + callback.complete("success"); + } +} diff --git a/engine/storage/volume/test/org/apache/cloudstack/storage/volume/test/TestInProcessAsync.java b/engine/storage/volume/test/org/apache/cloudstack/storage/volume/test/TestInProcessAsync.java new file mode 100644 index 00000000000..67418717989 --- /dev/null +++ b/engine/storage/volume/test/org/apache/cloudstack/storage/volume/test/TestInProcessAsync.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.storage.volume.test; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations="classpath:/resource/testContext.xml") +public class TestInProcessAsync { + Server svr; + @Before + public void setup() { + svr = new Server(); + } + + @Test + public void testRpc() { + svr.foo(); + } +} diff --git a/engine/storage/volume/test/resource/testContext.xml b/engine/storage/volume/test/resource/testContext.xml index 562bef8d078..83fe842c722 100644 --- a/engine/storage/volume/test/resource/testContext.xml +++ b/engine/storage/volume/test/resource/testContext.xml @@ -18,8 +18,9 @@ - - + + + @@ -31,4 +32,30 @@ + + + + org.apache.cloudstack.framework + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/framework/ipc/pom.xml b/framework/ipc/pom.xml index 7caf3601747..435cfeed756 100644 --- a/framework/ipc/pom.xml +++ b/framework/ipc/pom.xml @@ -34,5 +34,6 @@ install src + src diff --git a/framework/ipc/src/org/apache/cloudstack/framework/async/AsyncCallbackDispatcher.java b/framework/ipc/src/org/apache/cloudstack/framework/async/AsyncCallbackDispatcher.java index 72bf9d20aad..23c0b81a344 100644 --- a/framework/ipc/src/org/apache/cloudstack/framework/async/AsyncCallbackDispatcher.java +++ b/framework/ipc/src/org/apache/cloudstack/framework/async/AsyncCallbackDispatcher.java @@ -28,7 +28,7 @@ import java.util.Map; @SuppressWarnings("rawtypes") public class AsyncCallbackDispatcher implements AsyncCompletionCallback { private static Map, Map> s_handlerCache = new HashMap, Map>(); - + private final String parentCallbackKey = "parentCallback"; private Map _contextMap = new HashMap(); private String _operationName; private Object _targetObject; @@ -45,6 +45,15 @@ public class AsyncCallbackDispatcher implements AsyncCompletionCallback { return this; } + public AsyncCallbackDispatcher setParentCallback(AsyncCompletionCallback parentCallback) { + _contextMap.put(parentCallbackKey, parentCallback); + return this; + } + + public AsyncCallbackDispatcher getParentCallback() { + return (AsyncCallbackDispatcher)_contextMap.get(parentCallbackKey); + } + public AsyncCallbackDispatcher attachDriver(AsyncCallbackDriver driver) { assert(driver != null); _driver = driver; diff --git a/framework/ipc/test/org/apache/cloudstack/framework/sampleserver/SampleManagerComponent2.java b/framework/ipc/test/org/apache/cloudstack/framework/sampleserver/SampleManagerComponent2.java index 9fa06f51251..dc482c035fb 100644 --- a/framework/ipc/test/org/apache/cloudstack/framework/sampleserver/SampleManagerComponent2.java +++ b/framework/ipc/test/org/apache/cloudstack/framework/sampleserver/SampleManagerComponent2.java @@ -69,4 +69,8 @@ public class SampleManagerComponent2 { @EventHandler(topic="storage.prepare") void onPrepareNetwork(String sender, String topic, Object args) { } + + void test() { + + } } 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 50765787fb0..915e671e53c 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 @@ -2,7 +2,7 @@ package org.apache.cloudstack.storage.datastore.driver; import java.util.Map; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; +import org.apache.cloudstack.storage.EndPoint; import org.apache.cloudstack.storage.datastore.PrimaryDataStore; import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreInfo; import org.apache.cloudstack.storage.volume.VolumeObject;