Finally, get async api call works for storage subsystem

This commit is contained in:
Edison Su 2012-12-17 18:12:46 -08:00
parent 716a5673d0
commit aefb657c41
32 changed files with 314 additions and 94 deletions

View File

@ -16,17 +16,19 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.cloudstack.storage.scope;
package org.apache.cloudstack.engine.subsystem.api.storage;
import org.apache.cloudstack.engine.subsystem.api.storage.Scope;
import org.apache.cloudstack.engine.subsystem.api.storage.ScopeType;
public class ClusterScope implements Scope {
private ScopeType type = ScopeType.CLUSTER;
private long clusterId;
private long podId;
private long zoneId;
public ClusterScope(long clusterId) {
public ClusterScope(long clusterId, long podId, long zoneId) {
this.clusterId = clusterId;
this.podId = podId;
this.zoneId = zoneId;
}
@Override
@ -38,5 +40,13 @@ public class ClusterScope implements Scope {
public long getScopeId() {
return this.clusterId;
}
public long getPodId() {
return this.podId;
}
public long getZoneId() {
return this.zoneId;
}
}

View File

@ -16,10 +16,8 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.cloudstack.storage.scope;
package org.apache.cloudstack.engine.subsystem.api.storage;
import org.apache.cloudstack.engine.subsystem.api.storage.Scope;
import org.apache.cloudstack.engine.subsystem.api.storage.ScopeType;
public class HostScope implements Scope {
private ScopeType type = ScopeType.HOST;

View File

@ -19,13 +19,12 @@
package org.apache.cloudstack.engine.subsystem.api.storage;
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;
import com.cloud.storage.Volume;
public interface PrimaryDataStoreInfo {
public boolean isHypervisorSupported(HypervisorType hypervisor);
@ -33,10 +32,10 @@ public interface PrimaryDataStoreInfo {
public boolean isVolumeDiskTypeSupported(VolumeDiskType diskType);
public long getCapacity();
public long getAvailableCapacity();
public List<EndPoint> getEndPoints();
public long getId();
public String getUuid();
public State getManagedState();
public Volume.State getManagedState();
public String getName();
public String getType();
public PrimaryDataStoreLifeCycle getLifeCycle();

View File

@ -23,7 +23,7 @@ import java.util.Map;
public interface PrimaryDataStoreLifeCycle {
public boolean initialize(Map<String, String> dsInfos);
public boolean attach(Scope scope);
public boolean attachCluster(ClusterScope scope);
public boolean dettach();

View File

@ -16,10 +16,8 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.cloudstack.storage.scope;
package org.apache.cloudstack.engine.subsystem.api.storage;
import org.apache.cloudstack.engine.subsystem.api.storage.Scope;
import org.apache.cloudstack.engine.subsystem.api.storage.ScopeType;
public class ZoneScope implements Scope {
private ScopeType type = ScopeType.ZONE;

View File

@ -18,7 +18,6 @@
*/
package org.apache.cloudstack.storage.image.motion;
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;
@ -26,12 +25,11 @@ 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.datastore.PrimaryDataStore;
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 {
@ -43,7 +41,7 @@ public class DefaultImageMotionStrategy implements ImageMotionStrategy {
@Override
public EndPoint getEndPoint(TemplateOnPrimaryDataStoreInfo templateStore) {
PrimaryDataStoreInfo pdi = templateStore.getPrimaryDataStore();
PrimaryDataStore pdi = templateStore.getPrimaryDataStore();
return pdi.getEndPoints().get(0);
}
@ -59,7 +57,7 @@ public class DefaultImageMotionStrategy implements ImageMotionStrategy {
public void copyTemplateAsync(TemplateOnPrimaryDataStoreInfo templateStore, EndPoint ep, AsyncCompletionCallback<CommandResult> callback) {
ImageOnPrimayDataStoreTO imageTo = new ImageOnPrimayDataStoreTO(templateStore);
CopyTemplateToPrimaryStorage copyCommand = new CopyTemplateToPrimaryStorage(imageTo);
AsyncCallbackDispatcher<Answer> caller = new AsyncCallbackDispatcher<Answer>(this).setParentCallback(callback)
AsyncCallbackDispatcher caller = new AsyncCallbackDispatcher(this).setParentCallback(callback)
.setOperationName("defaultImageStrategy.copytemplate.callback")
.setContextParam("templateStore", templateStore);
ep.sendMessageAsync(copyCommand, caller);
@ -71,13 +69,15 @@ public class DefaultImageMotionStrategy implements ImageMotionStrategy {
CopyTemplateToPrimaryStorageAnswer answer = callback.getResult();
CommandResult result = new CommandResult();
result.setSucess(answer.getResult());
result.setResult(answer.getDetails());
if (answer.getResult()) {
if (!answer.getResult()) {
result.setSucess(answer.getResult());
result.setResult(answer.getDetails());
} else {
TemplateOnPrimaryDataStoreInfo templateStore = callback.getContextParam("templateStore");
templateStore.setPath(answer.getPath());
result.setSucess(true);
}
parentCall.complete(result);
}

View File

@ -99,7 +99,7 @@ public class ImageMotionServiceImpl implements ImageMotionService {
}
@AsyncCallbackHandler(operationName="imagemotionService.copytemplate.callback")
public void copyTemplateAsyncCallback(AsyncCallbackDispatcher callback) {
public void copyTemplateAsyncCallback( AsyncCallbackDispatcher callback) {
AsyncCallbackDispatcher parentCaller = callback.getParentCallback();
parentCaller.complete(callback.getResult());
}

View File

@ -1,5 +1,6 @@
package org.apache.cloudstack.storage.test;
import org.apache.cloudstack.storage.HostEndpointRpcServer;
import org.mockito.Mockito;
import org.springframework.context.annotation.Bean;
@ -20,6 +21,11 @@ public class ChildTestConfiguration extends TestConfiguration {
public AgentManager agentMgr() {
return new DirectAgentManagerSimpleImpl();
}
@Bean
public HostEndpointRpcServer rpcServer() {
return new MockHypervsiorHostEndPointRpcServer();
}
/* @Override
@Bean
public PrimaryDataStoreDao primaryDataStoreDao() {

View File

@ -0,0 +1,69 @@
/*
* 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.test;
import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
import org.apache.cloudstack.storage.HostEndpointRpcServer;
import org.apache.cloudstack.storage.command.CopyTemplateToPrimaryStorage;
import org.apache.cloudstack.storage.command.CopyTemplateToPrimaryStorageAnswer;
import org.apache.cloudstack.storage.command.CreateVolumeAnswer;
import org.apache.cloudstack.storage.command.CreateVolumeFromBaseImageCommand;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
public class MockHypervsiorHostEndPointRpcServer implements HostEndpointRpcServer {
private ScheduledExecutorService executor;
public MockHypervsiorHostEndPointRpcServer() {
executor = Executors.newScheduledThreadPool(10);
}
protected class MockRpcCallBack implements Runnable {
private final Command cmd;
private final AsyncCompletionCallback<Answer> callback;
public MockRpcCallBack(Command cmd, final AsyncCompletionCallback<Answer> callback) {
this.cmd = cmd;
this.callback = callback;
}
@Override
public void run() {
try {
Answer answer = new Answer(cmd, false, "unknown command");
if (cmd instanceof CopyTemplateToPrimaryStorage) {
answer = new CopyTemplateToPrimaryStorageAnswer(cmd, UUID.randomUUID().toString());
} else if (cmd instanceof CreateVolumeFromBaseImageCommand) {
answer = new CreateVolumeAnswer(cmd, UUID.randomUUID().toString());
}
callback.complete(answer);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void sendCommandAsync(String host, final Command command, final AsyncCompletionCallback<Answer> callback) {
executor.schedule(new MockRpcCallBack(command, callback), 10, TimeUnit.SECONDS);
}
}

View File

@ -1,7 +1,5 @@
package org.apache.cloudstack.storage.test;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDaoImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -14,8 +12,4 @@ public class TestConfiguration {
public HostDao hostDao() {
return new HostDaoImpl();
}
@Bean
public PrimaryDataStoreDao primaryDataStoreDao() {
return new PrimaryDataStoreDaoImpl();
}
}

View File

@ -34,9 +34,11 @@ import javax.naming.ConfigurationException;
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.ClusterScope;
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.Scope;
import org.apache.cloudstack.engine.subsystem.api.storage.disktype.QCOW2;
import org.apache.cloudstack.engine.subsystem.api.storage.disktype.VHD;
import org.apache.cloudstack.engine.subsystem.api.storage.disktype.VMDK;
@ -131,6 +133,7 @@ public class volumeServiceTest {
AgentManager agentMgr;
Long dcId;
Long clusterId;
Long podId;
@Before
public void setUp() {
//create data center
@ -142,6 +145,7 @@ public class volumeServiceTest {
HostPodVO pod = new HostPodVO(UUID.randomUUID().toString(), dc.getId(), "192.168.56.1", "192.168.56.0/24", 8, "test");
pod = podDao.persist(pod);
podId = pod.getId();
//create xen cluster
ClusterVO cluster = new ClusterVO(dc.getId(), pod.getId(), "devcloud cluster");
cluster.setHypervisorType(HypervisorType.XenServer.toString());
@ -168,9 +172,9 @@ public class volumeServiceTest {
results.add(host);
Mockito.when(hostDao.listAll()).thenReturn(results);
Mockito.when(hostDao.findHypervisorHostInCluster(Mockito.anyLong())).thenReturn(results);
CreateVolumeAnswer createVolumeFromImageAnswer = new CreateVolumeAnswer(UUID.randomUUID().toString());
//CreateVolumeAnswer createVolumeFromImageAnswer = new CreateVolumeAnswer(UUID.randomUUID().toString());
try {
/*try {
Mockito.when(agentMgr.send(Mockito.anyLong(), Mockito.any(CreateVolumeFromBaseImageCommand.class))).thenReturn(createVolumeFromImageAnswer);
} catch (AgentUnavailableException e) {
// TODO Auto-generated catch block
@ -178,7 +182,7 @@ public class volumeServiceTest {
} catch (OperationTimedoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}*/
//Mockito.when(primaryStoreDao.findById(Mockito.anyLong())).thenReturn(primaryStore);
@ -238,6 +242,9 @@ public class volumeServiceTest {
params.put("clusterId", clusterId.toString());
params.put("name", "my primary data store");
PrimaryDataStoreInfo primaryDataStoreInfo = provider.registerDataStore(params);
PrimaryDataStoreLifeCycle lc = primaryDataStoreInfo.getLifeCycle();
ClusterScope scope = new ClusterScope(clusterId, podId, dcId);
lc.attachCluster(scope);
return primaryDataStoreInfo;
} catch (ConfigurationException e) {
return null;

View File

@ -38,5 +38,31 @@
</bean>
<bean class="org.apache.cloudstack.storage.test.ChildTestConfiguration" />
<bean id="onwireRegistry" class="org.apache.cloudstack.framework.serializer.OnwireClassRegistry"
init-method="scan" >
<property name="packages">
<list>
<value>org.apache.cloudstack.framework</value>
</list>
</property>
</bean>
<bean id="messageSerializer" class="org.apache.cloudstack.framework.serializer.JsonMessageSerializer">
<property name="onwireClassRegistry" ref="onwireRegistry" />
</bean>
<bean id="transportProvider" class="org.apache.cloudstack.framework.server.ServerTransportProvider" init-method="initialize">
<property name="workerPoolSize" value="5" />
<property name="nodeId" value="Node1" />
<property name="messageSerializer" ref="messageSerializer" />
</bean>
<bean id="rpcProvider" class="org.apache.cloudstack.framework.rpc.RpcProviderImpl" init-method="initialize">
<constructor-arg ref="transportProvider" />
<property name="messageSerializer" ref="messageSerializer" />
</bean>
<bean id="eventBus" class = "org.apache.cloudstack.framework.eventbus.EventBusBase" />
</beans>

View File

@ -0,0 +1,28 @@
/*
* 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 org.apache.cloudstack.framework.async.AsyncCompletionCallback;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
public interface HostEndpointRpcServer {
void sendCommandAsync(String host, final Command command, final AsyncCompletionCallback<Answer> callback);
}

View File

@ -38,7 +38,7 @@ public class HypervisorHostEndPoint implements EndPoint {
@Inject
AgentManager agentMgr;
@Inject
HypervsiorHostEndPointRpcServer rpcServer;
HostEndpointRpcServer rpcServer;
public HypervisorHostEndPoint(long hostId, String hostAddress) {
this.hostId = hostId;

View File

@ -31,13 +31,16 @@ import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
@Component
public class HypervsiorHostEndPointRpcServer {
@Inject
public class HypervsiorHostEndPointRpcServer implements HostEndpointRpcServer {
private RpcProvider _rpcProvider;
public HypervsiorHostEndPointRpcServer() {
@Inject
public HypervsiorHostEndPointRpcServer(RpcProvider rpcProvider) {
_rpcProvider = rpcProvider;
_rpcProvider.registerRpcServiceEndpoint(RpcServiceDispatcher.getDispatcher(this));
}
@Override
public void sendCommandAsync(String host, final Command command, final AsyncCompletionCallback<Answer> callback) {
_rpcProvider.newCall(host).addCallbackListener(new RpcCallbackListener<Answer>() {
@Override

View File

@ -1,11 +1,13 @@
package org.apache.cloudstack.storage.command;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
public class CopyTemplateToPrimaryStorageAnswer extends Answer {
private final String path;
public CopyTemplateToPrimaryStorageAnswer(String path) {
public CopyTemplateToPrimaryStorageAnswer(Command cmd, String path) {
super(cmd);
this.path = path;
}

View File

@ -19,6 +19,7 @@
package org.apache.cloudstack.storage.command;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
public class CreateVolumeAnswer extends Answer {
private String volumeUuid;
@ -27,7 +28,8 @@ public class CreateVolumeAnswer extends Answer {
super();
}
public CreateVolumeAnswer(String volumeUuid) {
public CreateVolumeAnswer(Command cmd, String volumeUuid) {
super(cmd);
this.volumeUuid = volumeUuid;
}

View File

@ -18,7 +18,7 @@
*/
package org.apache.cloudstack.storage.volume;
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo;
import org.apache.cloudstack.storage.datastore.PrimaryDataStore;
import org.apache.cloudstack.storage.image.TemplateInfo;
public interface TemplateOnPrimaryDataStoreInfo {
@ -26,7 +26,7 @@ public interface TemplateOnPrimaryDataStoreInfo {
public void setPath(String path);
public PrimaryDataStoreInfo getPrimaryDataStore();
public PrimaryDataStore getPrimaryDataStore();
public TemplateInfo getTemplate();
}

View File

@ -30,10 +30,14 @@ import org.apache.cloudstack.engine.datacenter.entity.api.StorageEntity;
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.AsyncCallbackDispatcher;
import org.apache.cloudstack.framework.async.AsyncCallbackHandler;
import org.apache.cloudstack.storage.datastore.PrimaryDataStoreEntityImpl;
import org.apache.cloudstack.storage.image.TemplateEntityImpl;
import org.apache.cloudstack.storage.image.TemplateInfo;
import com.cloud.utils.exception.CloudRuntimeException;
public class VolumeEntityImpl implements VolumeEntity {
private VolumeInfo volumeInfo;
private final VolumeService vs;
@ -192,8 +196,25 @@ public class VolumeEntityImpl implements VolumeEntity {
@Override
public boolean createVolumeFromTemplate(long dataStoreId, VolumeDiskType diskType, TemplateEntity template) {
TemplateInfo ti = ((TemplateEntityImpl)template).getTemplateInfo();
volumeInfo = vs.createVolumeFromTemplate(volumeInfo, dataStoreId, diskType, ti);
AsyncCallbackDispatcher caller = new AsyncCallbackDispatcher(this)
.setOperationName("volumeEntity.createVolumeFromTemplateAsyncCallback");
vs.createVolumeFromTemplateAsync(volumeInfo, dataStoreId, diskType, ti, caller);
try {
synchronized (volumeInfo) {
volumeInfo.wait();
}
} catch (InterruptedException e) {
throw new CloudRuntimeException("wait volume info failed", e);
}
return true;
}
@AsyncCallbackHandler(operationName="volumeEntity.createVolumeFromTemplateAsyncCallback")
public void createVolumeFromTemplateAsyncCallback(AsyncCallbackDispatcher callback) {
synchronized (volumeInfo) {
volumeInfo.notify();
}
}
}

View File

@ -165,6 +165,7 @@ public class TemplatePrimaryDataStoreVO implements StateObject<TemplateOnPrimary
this.poolId = poolId;
this.templateId = templateId;
this.downloadState = Status.NOT_DOWNLOADED;
this.state = TemplateOnPrimaryDataStoreStateMachine.State.Allocated;
this.markedForGC = false;
}

View File

@ -5,16 +5,18 @@ 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.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.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.HypervisorHostEndPoint;
import org.apache.cloudstack.storage.command.CommandResult;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreVO;
import org.apache.cloudstack.storage.datastore.driver.DefaultPrimaryDataStoreDriverImpl;
import org.apache.cloudstack.storage.datastore.driver.PrimaryDataStoreDriver;
import org.apache.cloudstack.storage.image.TemplateInfo;
import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreInfo;
@ -28,6 +30,7 @@ import org.apache.log4j.Logger;
import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.storage.Volume;
import com.cloud.utils.component.ComponentInject;
import edu.emory.mathcs.backport.java.util.Collections;
@ -185,9 +188,26 @@ public class DefaultPrimaryDataStore implements PrimaryDataStore {
public VolumeInfo createVoluemFromBaseImage(VolumeInfo volume, TemplateOnPrimaryDataStoreInfo template) {
VolumeObject vo = (VolumeObject) volume;
vo.setVolumeDiskType(template.getTemplate().getDiskType());
this.driver.createVolumeFromBaseImage(vo, template);
//this.driver.createVolumeFromBaseImage(vo, template);
return volume;
}
@Override
public void createVoluemFromBaseImageAsync(VolumeInfo volume, TemplateOnPrimaryDataStoreInfo templateStore, AsyncCompletionCallback<CommandResult> callback) {
VolumeObject vo = (VolumeObject) volume;
vo.setVolumeDiskType(templateStore.getTemplate().getDiskType());
AsyncCallbackDispatcher caller = new AsyncCallbackDispatcher(this)
.setParentCallback(callback)
.setOperationName("primarydatastore.createvolumefrombaseImage");
this.driver.createVolumeFromBaseImageAsync(vo, templateStore, caller);
}
@AsyncCallbackHandler(operationName="primarydatastore.createvolumefrombaseImage")
public void createVoluemFromBaseImageAsyncCallback(AsyncCallbackDispatcher callback) {
AsyncCallbackDispatcher parent = callback.getParentCallback();
CommandResult result = callback.getResult();
parent.complete(result);
}
@Override
public boolean installTemplate(TemplateOnPrimaryDataStoreInfo template) {
@ -202,7 +222,7 @@ public class DefaultPrimaryDataStore implements PrimaryDataStore {
}
@Override
public State getManagedState() {
public Volume.State getManagedState() {
// TODO Auto-generated method stub
return null;
}
@ -228,4 +248,6 @@ public class DefaultPrimaryDataStore implements PrimaryDataStore {
public PrimaryDataStoreProvider getProvider() {
return this.provider;
}
}

View File

@ -4,7 +4,11 @@ import java.util.List;
import java.util.Map;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
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.CreateVolumeAnswer;
import org.apache.cloudstack.storage.command.CreateVolumeCommand;
import org.apache.cloudstack.storage.command.CreateVolumeFromBaseImageCommand;
@ -98,19 +102,40 @@ public class DefaultPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
return answer;
}
@Override
public boolean createVolumeFromBaseImage(VolumeObject volume, TemplateOnPrimaryDataStoreInfo template) {
public void createVolumeFromBaseImageAsync(VolumeObject volume, TemplateOnPrimaryDataStoreInfo template, AsyncCompletionCallback<CommandResult> callback) {
VolumeTO vol = new VolumeTO(volume);
ImageOnPrimayDataStoreTO image = new ImageOnPrimayDataStoreTO(template);
CreateVolumeFromBaseImageCommand cmd = new CreateVolumeFromBaseImageCommand(vol, image);
List<EndPoint> endPoints = template.getPrimaryDataStore().getEndPoints();
Answer answer = sendOutCommand(cmd, endPoints);
CreateVolumeAnswer volAnswer = (CreateVolumeAnswer) answer;
volume.setPath(volAnswer.getVolumeUuid());
return true;
EndPoint ep = endPoints.get(0);
AsyncCallbackDispatcher caller = new AsyncCallbackDispatcher(this)
.setParentCallback(callback)
.setOperationName("primarydatastoredriver.createvolumefrombaseImage")
.setContextParam("volume", volume);
ep.sendMessageAsync(cmd, caller);
}
@AsyncCallbackHandler(operationName="primarydatastoredriver.createvolumefrombaseImage")
public void createVolumeFromBaseImageAsyncCallback(AsyncCallbackDispatcher callback) {
CreateVolumeAnswer answer = (CreateVolumeAnswer)callback.getResult();
CommandResult result = new CommandResult();
if (answer == null || answer.getDetails() != null) {
result.setSucess(false);
if (answer != null) {
result.setResult(answer.getDetails());
}
} else {
result.setSucess(true);
VolumeObject volume = callback.getContextParam("volume");
volume.setPath(answer.getVolumeUuid());
}
AsyncCallbackDispatcher parentCall = callback.getParentCallback();
parentCall.complete(result);
}
@Override
@ -142,4 +167,6 @@ public class DefaultPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
// TODO Auto-generated method stub
return false;
}
}

View File

@ -2,7 +2,9 @@ package org.apache.cloudstack.storage.datastore.driver;
import java.util.Map;
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.volume.TemplateOnPrimaryDataStoreInfo;
import org.apache.cloudstack.storage.volume.VolumeObject;
@ -10,7 +12,7 @@ import org.apache.cloudstack.storage.volume.VolumeObject;
public interface PrimaryDataStoreDriver {
boolean createVolume(VolumeObject vol);
boolean createVolumeFromBaseImage(VolumeObject volume, TemplateOnPrimaryDataStoreInfo template);
void createVolumeFromBaseImageAsync(VolumeObject volume, TemplateOnPrimaryDataStoreInfo template, AsyncCompletionCallback<CommandResult> callback);
boolean deleteVolume(VolumeObject vo);

View File

@ -18,23 +18,14 @@
*/
package org.apache.cloudstack.storage.datastore.lifecycle;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
import javax.inject.Inject;
import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
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.Scope;
import org.apache.cloudstack.engine.subsystem.api.storage.ScopeType;
import org.apache.cloudstack.storage.datastore.DataStoreStatus;
import org.apache.cloudstack.storage.datastore.PrimaryDataStore;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreProviderDao;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreVO;
import org.springframework.stereotype.Component;
public class DefaultPrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLifeCycle {
protected PrimaryDataStoreInfo dataStore;
@ -58,8 +49,12 @@ public class DefaultPrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLif
}
@Override
public boolean attach(Scope scope) {
//if (scope.getScopeType() == ScopeType.CLUSTER)
public boolean attachCluster(ClusterScope scope) {
PrimaryDataStoreVO dataStore = dataStoreDao.findById(this.dataStore.getId());
dataStore.setDataCenterId(scope.getZoneId());
dataStore.setPodId(scope.getPodId());
dataStore.setClusterId(scope.getScopeId());
dataStoreDao.update(this.dataStore.getId(), dataStore);
return false;
}

View File

@ -18,7 +18,7 @@
*/
package org.apache.cloudstack.storage.volume;
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo;
import org.apache.cloudstack.storage.datastore.PrimaryDataStore;
import org.apache.cloudstack.storage.image.TemplateInfo;
import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreStateMachine.Event;
import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreStateMachine.State;
@ -31,14 +31,14 @@ import com.cloud.utils.fsm.NoTransitionException;
import com.cloud.utils.fsm.StateMachine2;
public class TemplateOnPrimaryDataStoreObject implements TemplateOnPrimaryDataStoreInfo {
protected PrimaryDataStoreInfo dataStore;
protected PrimaryDataStore dataStore;
protected TemplateInfo template;
protected TemplatePrimaryDataStoreVO vo;
protected TemplatePrimaryDataStoreDao templateStoreDao;
protected TemplatePrimaryDataStoreManager mgr;
protected StateMachine2<State, Event, TemplatePrimaryDataStoreVO> stateMachine;
public TemplateOnPrimaryDataStoreObject(PrimaryDataStoreInfo primaryDataStore, TemplateInfo template, TemplatePrimaryDataStoreVO vo,
public TemplateOnPrimaryDataStoreObject(PrimaryDataStore primaryDataStore, TemplateInfo template, TemplatePrimaryDataStoreVO vo,
TemplatePrimaryDataStoreDao templateStoreDao, TemplatePrimaryDataStoreManager mgr) {
this.dataStore = primaryDataStore;
this.template = template;
@ -59,7 +59,7 @@ public class TemplateOnPrimaryDataStoreObject implements TemplateOnPrimaryDataSt
}
@Override
public PrimaryDataStoreInfo getPrimaryDataStore() {
public PrimaryDataStore getPrimaryDataStore() {
return this.dataStore;
}
@ -77,7 +77,7 @@ public class TemplateOnPrimaryDataStoreObject implements TemplateOnPrimaryDataSt
try {
this.stateMachine.transitTo(vo, event, null, templateStoreDao);
} catch (NoTransitionException e) {
throw new CloudRuntimeException(e.toString());
throw new CloudRuntimeException("Failed change state", e);
}
}
}

View File

@ -18,7 +18,7 @@
*/
package org.apache.cloudstack.storage.volume;
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo;
import org.apache.cloudstack.storage.datastore.PrimaryDataStore;
import org.apache.cloudstack.storage.image.TemplateInfo;
import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreStateMachine.Event;
import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreStateMachine.State;
@ -27,9 +27,9 @@ import org.apache.cloudstack.storage.volume.db.TemplatePrimaryDataStoreVO;
import com.cloud.utils.fsm.StateMachine2;
public interface TemplatePrimaryDataStoreManager {
public TemplateOnPrimaryDataStoreInfo createTemplateOnPrimaryDataStore(TemplateInfo template, PrimaryDataStoreInfo dataStore);
public TemplateOnPrimaryDataStoreInfo createTemplateOnPrimaryDataStore(TemplateInfo template, PrimaryDataStore dataStore);
public TemplateOnPrimaryDataStoreInfo findTemplateOnPrimaryDataStore(TemplateInfo template, PrimaryDataStoreInfo dataStore);
public TemplateOnPrimaryDataStoreInfo findTemplateOnPrimaryDataStore(TemplateInfo template, PrimaryDataStore dataStore);
public StateMachine2<State, Event, TemplatePrimaryDataStoreVO> getStateMachine();
}

View File

@ -21,6 +21,7 @@ package org.apache.cloudstack.storage.volume;
import javax.inject.Inject;
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo;
import org.apache.cloudstack.storage.datastore.PrimaryDataStore;
import org.apache.cloudstack.storage.image.TemplateInfo;
import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreStateMachine.Event;
import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreStateMachine.State;
@ -79,7 +80,7 @@ public class TemplatePrimaryDataStoreManagerImpl implements TemplatePrimaryDataS
return templateStoreVO;
}
@Override
public TemplateOnPrimaryDataStoreObject createTemplateOnPrimaryDataStore(TemplateInfo template, PrimaryDataStoreInfo dataStore) {
public TemplateOnPrimaryDataStoreObject createTemplateOnPrimaryDataStore(TemplateInfo template, PrimaryDataStore dataStore) {
TemplatePrimaryDataStoreVO templateStoreVO = null;
boolean freshNewTemplate = false;
templateStoreVO = templateStoreDao.findByTemplateIdAndPoolId(template.getId(), dataStore.getId());
@ -106,7 +107,7 @@ public class TemplatePrimaryDataStoreManagerImpl implements TemplatePrimaryDataS
}
@Override
public TemplateOnPrimaryDataStoreObject findTemplateOnPrimaryDataStore(TemplateInfo template, PrimaryDataStoreInfo dataStore) {
public TemplateOnPrimaryDataStoreObject findTemplateOnPrimaryDataStore(TemplateInfo template, PrimaryDataStore dataStore) {
SearchCriteriaService<TemplatePrimaryDataStoreVO, TemplatePrimaryDataStoreVO> sc = SearchCriteria2.create(TemplatePrimaryDataStoreVO.class);
sc.addAnd(sc.getEntity().getTemplateId(), Op.EQ, template.getId());
sc.addAnd(sc.getEntity().getPoolId(), Op.EQ, dataStore.getId());

View File

@ -19,6 +19,7 @@ import org.apache.log4j.Logger;
import com.cloud.storage.Volume;
import com.cloud.storage.Volume.State;
import com.cloud.utils.component.ComponentInject;
import com.cloud.utils.db.DB;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.fsm.NoTransitionException;
import com.cloud.utils.fsm.StateMachine2;

View File

@ -20,11 +20,9 @@ package org.apache.cloudstack.storage.volume;
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.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;
@ -33,15 +31,12 @@ 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;
import org.apache.cloudstack.storage.image.TemplateInfo;
import org.apache.cloudstack.storage.image.motion.ImageMotionService;
import org.apache.cloudstack.storage.volume.db.VolumeDao;
import org.apache.cloudstack.storage.volume.db.VolumeVO;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
import com.cloud.storage.Volume;
import com.cloud.utils.db.DB;
@ -136,7 +131,8 @@ public class VolumeServiceImpl implements VolumeService {
return null;
}
protected void createBaseImageAsync(PrimaryDataStore dataStore, TemplateInfo template, AsyncCompletionCallback<TemplateOnPrimaryDataStoreObject> callback) {
@DB
protected void createBaseImageAsync(VolumeInfo volume, PrimaryDataStore dataStore, TemplateInfo template, AsyncCompletionCallback<VolumeInfo> callback) {
TemplateOnPrimaryDataStoreObject templateOnPrimaryStoreObj = (TemplateOnPrimaryDataStoreObject) templatePrimaryStoreMgr.createTemplateOnPrimaryDataStore(template, dataStore);
templateOnPrimaryStoreObj.stateTransit(TemplateOnPrimaryDataStoreStateMachine.Event.CreateRequested);
templateOnPrimaryStoreObj.updateStatus(Status.CREATING);
@ -154,11 +150,14 @@ public class VolumeServiceImpl implements VolumeService {
AsyncCallbackDispatcher caller = new AsyncCallbackDispatcher(this)
.setParentCallback(callback)
.setOperationName("volumeservice.createbaseimage.callback")
.setContextParam("volume", volume)
.setContextParam("primary", dataStore)
.setContextParam("templateOnPrimary", templateOnPrimaryStoreObj);
imageMotion.copyTemplateAsync(templateOnPrimaryStoreObj, caller);
}
@DB
@AsyncCallbackHandler(operationName="volumeservice.createbaseimage.callback")
public void createBaseImageCallback(AsyncCallbackDispatcher callback) {
CommandResult result = callback.getResult();
@ -172,8 +171,8 @@ public class VolumeServiceImpl implements VolumeService {
}
AsyncCallbackDispatcher parentCaller = callback.getParentCallback();
VolumeInfo volume = parentCaller.getContextParam("volume");
PrimaryDataStore pd = parentCaller.getContextParam("primary");
VolumeInfo volume = callback.getContextParam("volume");
PrimaryDataStore pd = callback.getContextParam("primary");
AsyncCallbackDispatcher caller = new AsyncCallbackDispatcher(this)
.setParentCallback(parentCaller)
.setOperationName("volumeservice.createvolumefrombaseimage.callback");
@ -181,6 +180,7 @@ public class VolumeServiceImpl implements VolumeService {
createVolumeFromBaseImageAsync(volume, templateOnPrimaryStoreObj, pd, caller);
}
@DB
protected void createVolumeFromBaseImageAsync(VolumeInfo volume, TemplateOnPrimaryDataStoreInfo templateOnPrimaryStore, PrimaryDataStore pd, AsyncCompletionCallback<VolumeObject> callback) {
VolumeObject vo = (VolumeObject) volume;
try {
@ -198,6 +198,7 @@ public class VolumeServiceImpl implements VolumeService {
pd.createVoluemFromBaseImageAsync(volume, templateOnPrimaryStore, caller);
}
@DB
@AsyncCallbackHandler(operationName="volumeservice.createVolumeFromBaseImageCallback")
public void createVolumeFromBaseImageCallback(AsyncCallbackDispatcher callback) {
VolumeObject vo = callback.getContextParam("volume");
@ -212,6 +213,7 @@ public class VolumeServiceImpl implements VolumeService {
parentCall.complete(vo);
}
@DB
@AsyncCallbackHandler(operationName="volumeservice.createvolumefrombaseimage.callback")
public void createVolumeFromBaseImageAsyncCallback(AsyncCallbackDispatcher callback) {
AsyncCallbackDispatcher parentCall = callback.getParentCallback();
@ -219,16 +221,13 @@ public class VolumeServiceImpl implements VolumeService {
parentCall.complete(vo);
}
@DB
@Override
public void createVolumeFromTemplateAsync(VolumeInfo volume, long dataStoreId, VolumeDiskType diskType, TemplateInfo template, AsyncCompletionCallback<VolumeInfo> 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);
createBaseImageAsync(volume, pd, template, callback);
return;
}

View File

@ -18,7 +18,9 @@
*/
package org.apache.cloudstack.storage.volume.test;
import org.apache.cloudstack.storage.HostEndpointRpcServer;
import org.apache.cloudstack.storage.image.motion.ImageMotionService;
import org.apache.cloudstack.storage.test.MockHypervsiorHostEndPointRpcServer;
import org.mockito.Mockito;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -38,4 +40,9 @@ public class TestConfiguration {
public ClusterDao clusterDao() {
return Mockito.mock(ClusterDaoImpl.class);
}
@Bean
public HostEndpointRpcServer rpcServer() {
return new MockHypervsiorHostEndPointRpcServer();
}
}

View File

@ -104,7 +104,7 @@ public class AsyncCallbackDispatcher implements AsyncCompletionCallback {
} catch (IllegalAccessException e) {
throw new RuntimeException("IllegalAccessException when invoking RPC callback for command: " + callback.getOperationName());
} catch (InvocationTargetException e) {
throw new RuntimeException("InvocationTargetException when invoking RPC callback for command: " + callback.getOperationName());
throw new RuntimeException("InvocationTargetException when invoking RPC callback for command: " + callback.getOperationName(), e);
}
return true;

View File

@ -19,6 +19,8 @@ alter table vm_template add image_data_store_id bigint unsigned;
alter table storage_pool add storage_provider_id bigint unsigned;
alter table storage_pool add configurator_key varchar(255);
alter table storage_pool modify id bigint unsigned AUTO_INCREMENT UNIQUE NOT NULL;
alter table template_spool_ref add state varchar(255);
alter table template_spool_ref add update_count bigint unsigned;
alter table volumes add disk_type varchar(255);
alter table volumes drop foreign key `fk_volumes__account_id`;
CREATE TABLE `cloud`.`primary_data_store_provider` (