add deletevolume and createdata disk

This commit is contained in:
Edison Su 2013-01-03 18:55:55 -08:00
parent ed17281f0d
commit 9410cd1f3c
19 changed files with 256 additions and 72 deletions

View File

@ -35,7 +35,8 @@ public interface Volume extends ControlledEntity, BasedOn, StateObject<Volume.St
Migrating("The volume is migrating to other storage pool"), Migrating("The volume is migrating to other storage pool"),
Snapshotting("There is a snapshot created on this volume, not backed up to secondary storage yet"), Snapshotting("There is a snapshot created on this volume, not backed up to secondary storage yet"),
Expunging("The volume is being expunging"), Expunging("The volume is being expunging"),
Destroy("The volume is destroyed, and can't be recovered."), Destroy("The volume is destroyed, and can't be recovered."),
Destroying("The volume is destroying, and can't be recovered."),
UploadOp ("The volume upload operation is in progress or in short the volume is on secondary storage"); UploadOp ("The volume upload operation is in progress or in short the volume is on secondary storage");
String _description; String _description;

View File

@ -42,4 +42,5 @@ public interface VolumeInfo {
public Date getUpdatedDate(); public Date getUpdatedDate();
public String getOwner(); public String getOwner();
public String getName(); public String getName();
public boolean isAttachedVM();
} }

View File

@ -125,6 +125,7 @@ public class volumeServiceTest extends CloudStackTestNGBase {
Long podId; Long podId;
HostVO host; HostVO host;
String primaryName = "my primary data store"; String primaryName = "my primary data store";
PrimaryDataStoreInfo primaryStore;
@Test(priority = -1) @Test(priority = -1)
public void setUp() { public void setUp() {
@ -270,21 +271,29 @@ public class volumeServiceTest extends CloudStackTestNGBase {
} }
} }
private VolumeVO createVolume(long templateId, long dataStoreId) { private VolumeVO createVolume(Long templateId, long dataStoreId) {
VolumeVO volume = new VolumeVO(1000, new RootDisk().toString(), UUID.randomUUID().toString(), templateId); VolumeVO volume = new VolumeVO(1000, new RootDisk().toString(), UUID.randomUUID().toString(), templateId);
volume.setPoolId(dataStoreId); volume.setPoolId(dataStoreId);
volume = volumeDao.persist(volume); volume = volumeDao.persist(volume);
return volume; return volume;
} }
@Test(priority=2) @Test(priority=2)
public void createVolumeFromTemplate() { public void createVolumeFromTemplate() {
TemplateEntity te = createTemplate(); TemplateEntity te = createTemplate();
PrimaryDataStoreInfo dataStoreInfo = createPrimaryDataStore(); primaryStore = createPrimaryDataStore();
VolumeVO volume = createVolume(te.getId(), dataStoreInfo.getId()); VolumeVO volume = createVolume(te.getId(), primaryStore.getId());
VolumeEntity ve = volumeService.getVolumeEntity(volume.getId()); VolumeEntity ve = volumeService.getVolumeEntity(volume.getId());
ve.createVolumeFromTemplate(dataStoreInfo.getId(), new VHD(), te); ve.createVolumeFromTemplate(primaryStore.getId(), new VHD(), te);
ve.destroy();
}
@Test(priority=3)
public void createDataDisk() {
VolumeVO volume = createVolume(null, primaryStore.getId());
VolumeEntity ve = volumeService.getVolumeEntity(volume.getId());
ve.createVolume(primaryStore.getId(), new VHD());
ve.destroy();
} }
//@Test(priority=3) //@Test(priority=3)

View File

@ -17,6 +17,7 @@
<context:component-scan base-package="com.cloud.utils.component" /> <context:component-scan base-package="com.cloud.utils.component" />
<context:component-scan base-package="com.cloud.host.dao" /> <context:component-scan base-package="com.cloud.host.dao" />
<context:component-scan base-package="com.cloud.dc.dao" /> <context:component-scan base-package="com.cloud.dc.dao" />
<context:component-scan base-package="com.cloud.cluster.agentlb.dao" />
<context:component-scan base-package=" com.cloud.upgrade.dao" /> <context:component-scan base-package=" com.cloud.upgrade.dao" />
<tx:annotation-driven transaction-manager="transactionManager" /> <tx:annotation-driven transaction-manager="transactionManager" />

View File

@ -23,7 +23,7 @@ public class CommandResult {
private String result; private String result;
public CommandResult() { public CommandResult() {
this.success = false; this.success = true;
this.result = ""; this.result = "";
} }

View File

@ -32,6 +32,10 @@ public class CreateVolumeAnswer extends Answer {
super(cmd); super(cmd);
this.volumeUuid = volumeUuid; this.volumeUuid = volumeUuid;
} }
public CreateVolumeAnswer(Command cmd, boolean status, String result) {
super(cmd, status, result);
}
public String getVolumeUuid() { public String getVolumeUuid() {
return this.volumeUuid; return this.volumeUuid;

View File

@ -23,11 +23,11 @@ import org.apache.cloudstack.storage.to.VolumeTO;
import com.cloud.agent.api.Command; import com.cloud.agent.api.Command;
public class CreateVolumeCommand extends Command implements StorageSubSystemCommand { public class CreateVolumeCommand extends Command implements StorageSubSystemCommand {
protected VolumeTO volumeInfo; protected VolumeTO volumeTO;
public CreateVolumeCommand(VolumeTO volumeInfo) { public CreateVolumeCommand(VolumeTO volumeTO) {
super(); super();
this.volumeInfo = volumeInfo; this.volumeTO = volumeTO;
} }
protected CreateVolumeCommand() { protected CreateVolumeCommand() {
@ -39,5 +39,9 @@ public class CreateVolumeCommand extends Command implements StorageSubSystemComm
// TODO Auto-generated method stub // TODO Auto-generated method stub
return false; return false;
} }
public VolumeTO getVolume() {
return this.volumeTO;
}
} }

View File

@ -18,17 +18,17 @@
*/ */
package org.apache.cloudstack.storage.command; package org.apache.cloudstack.storage.command;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.storage.to.VolumeTO;
import com.cloud.agent.api.Command; import com.cloud.agent.api.Command;
public class DeleteVolume extends Command { public class DeleteVolumeCommand extends Command implements StorageSubSystemCommand {
private VolumeTO volume;
public DeleteVolume(VolumeInfo volume) { public DeleteVolumeCommand(VolumeTO volume) {
this.volume = volume;
} }
protected DeleteVolume() { protected DeleteVolumeCommand() {
} }
@Override @Override
@ -36,5 +36,9 @@ public class DeleteVolume extends Command {
// TODO Auto-generated method stub // TODO Auto-generated method stub
return false; return false;
} }
public VolumeTO getVolume() {
return this.volume;
}
} }

View File

@ -36,7 +36,7 @@ public interface PrimaryDataStore extends PrimaryDataStoreInfo {
List<VolumeInfo> getVolumes(); List<VolumeInfo> getVolumes();
boolean deleteVolume(VolumeInfo volume); void deleteVolumeAsync(VolumeInfo volume, AsyncCompletionCallback<CommandResult> callback);
void createVolumeAsync(VolumeInfo vo, VolumeDiskType diskType, AsyncCompletionCallback<CommandResult> callback); void createVolumeAsync(VolumeInfo vo, VolumeDiskType diskType, AsyncCompletionCallback<CommandResult> callback);

View File

@ -11,6 +11,7 @@ public class VolumeTO {
private final VolumeDiskType diskType; private final VolumeDiskType diskType;
private PrimaryDataStoreTO dataStore; private PrimaryDataStoreTO dataStore;
private final String name; private final String name;
private final long size;
public VolumeTO(VolumeInfo volume) { public VolumeTO(VolumeInfo volume) {
this.uuid = volume.getUuid(); this.uuid = volume.getUuid();
this.path = volume.getPath(); this.path = volume.getPath();
@ -22,6 +23,7 @@ public class VolumeTO {
this.dataStore = null; this.dataStore = null;
} }
this.name = volume.getName(); this.name = volume.getName();
this.size = volume.getSize();
} }
public String getUuid() { public String getUuid() {
@ -51,4 +53,8 @@ public class VolumeTO {
public String getName() { public String getName() {
return this.name; return this.name;
} }
public long getSize() {
return this.size;
}
} }

View File

@ -146,10 +146,6 @@ public class VolumeEntityImpl implements VolumeEntity {
} }
@Override
public void destroy() {
//vs.deleteVolume(volumeInfo);
}
@Override @Override
public long getSize() { public long getSize() {
@ -190,7 +186,7 @@ public class VolumeEntityImpl implements VolumeEntity {
} }
private Void createVolumeFromTemplateAsyncCallback(AsyncCallbackDispatcher<VolumeEntityImpl, VolumeInfo> callback, Object context) { public Object createVolumeFromTemplateAsyncCallback(AsyncCallbackDispatcher<VolumeEntityImpl, VolumeInfo> callback, Object context) {
synchronized (volumeInfo) { synchronized (volumeInfo) {
volumeInfo.notify(); volumeInfo.notify();
} }
@ -216,7 +212,33 @@ public class VolumeEntityImpl implements VolumeEntity {
} }
} }
private Void createVolumeCallback(AsyncCallbackDispatcher<VolumeApiResult, VolumeApiResult> callback, Object context) { public Void createVolumeCallback(AsyncCallbackDispatcher<VolumeApiResult, VolumeApiResult> callback, Object context) {
synchronized (volumeInfo) {
this.result = callback.getResult();
volumeInfo.notify();
}
return null;
}
@Override
public void destroy() {
AsyncCallbackDispatcher<VolumeEntityImpl, VolumeApiResult> caller = AsyncCallbackDispatcher.create(this);
caller.setCallback(caller.getTarget().destroyCallback(null, null));
vs.deleteVolumeAsync(volumeInfo, caller);
try {
synchronized (volumeInfo) {
volumeInfo.wait();
}
if (!result.isSuccess()) {
throw new CloudRuntimeException("Failed to create volume:" + result.getResult());
}
} catch (InterruptedException e) {
throw new CloudRuntimeException("wait volume info failed", e);
}
}
public Void destroyCallback(AsyncCallbackDispatcher<VolumeApiResult, VolumeApiResult> callback, Object context) {
synchronized (volumeInfo) { synchronized (volumeInfo) {
this.result = callback.getResult(); this.result = callback.getResult();
volumeInfo.notify(); volumeInfo.notify();

View File

@ -111,8 +111,13 @@ public class DefaultPrimaryDataStore implements PrimaryDataStore {
} }
@Override @Override
public boolean deleteVolume(VolumeInfo volume) { public void deleteVolumeAsync(VolumeInfo volume, AsyncCompletionCallback<CommandResult> callback) {
return this.driver.deleteVolume((VolumeObject)volume); CommandResult result = new CommandResult();
if (volume.isAttachedVM()) {
result.setResult("Can't delete volume: " + volume.getId() + ", if it's attached to a VM");
callback.complete(result);
}
this.driver.deleteVolumeAsync((VolumeObject)volume, callback);
} }
@Override @Override

View File

@ -12,7 +12,7 @@ import org.apache.cloudstack.storage.command.CommandResult;
import org.apache.cloudstack.storage.command.CreateVolumeAnswer; import org.apache.cloudstack.storage.command.CreateVolumeAnswer;
import org.apache.cloudstack.storage.command.CreateVolumeCommand; import org.apache.cloudstack.storage.command.CreateVolumeCommand;
import org.apache.cloudstack.storage.command.CreateVolumeFromBaseImageCommand; import org.apache.cloudstack.storage.command.CreateVolumeFromBaseImageCommand;
import org.apache.cloudstack.storage.command.DeleteVolume; import org.apache.cloudstack.storage.command.DeleteVolumeCommand;
import org.apache.cloudstack.storage.datastore.PrimaryDataStore; import org.apache.cloudstack.storage.datastore.PrimaryDataStore;
import org.apache.cloudstack.storage.to.ImageOnPrimayDataStoreTO; import org.apache.cloudstack.storage.to.ImageOnPrimayDataStoreTO;
import org.apache.cloudstack.storage.to.VolumeTO; import org.apache.cloudstack.storage.to.VolumeTO;
@ -72,7 +72,7 @@ public class DefaultPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
ep.sendMessageAsync(createCmd, caller); ep.sendMessageAsync(createCmd, caller);
} }
protected Void createVolumeAsyncCallback(AsyncCallbackDispatcher<DefaultPrimaryDataStoreDriverImpl, Answer> callback, CreateVolumeContext<CommandResult> context) { public Void createVolumeAsyncCallback(AsyncCallbackDispatcher<DefaultPrimaryDataStoreDriverImpl, Answer> callback, CreateVolumeContext<CommandResult> context) {
CommandResult result = new CommandResult(); CommandResult result = new CommandResult();
CreateVolumeAnswer volAnswer = (CreateVolumeAnswer) callback.getResult(); CreateVolumeAnswer volAnswer = (CreateVolumeAnswer) callback.getResult();
if (volAnswer.getResult()) { if (volAnswer.getResult()) {
@ -85,14 +85,27 @@ public class DefaultPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
context.getParentCallback().complete(result); context.getParentCallback().complete(result);
return null; return null;
} }
@Override @Override
public boolean deleteVolume(VolumeObject vo) { public void deleteVolumeAsync(VolumeObject vo, AsyncCompletionCallback<CommandResult> callback) {
DeleteVolume cmd = new DeleteVolume((VolumeInfo)vo); DeleteVolumeCommand cmd = new DeleteVolumeCommand(this.dataStore.getVolumeTO(vo));
List<EndPoint> endPoints = vo.getDataStore().getEndPoints(); List<EndPoint> endPoints = vo.getDataStore().getEndPoints();
sendOutCommand(cmd, endPoints); EndPoint ep = endPoints.get(0);
AsyncRpcConext<CommandResult> context = new AsyncRpcConext<CommandResult>(callback);
return true; AsyncCallbackDispatcher<DefaultPrimaryDataStoreDriverImpl, Answer> caller = AsyncCallbackDispatcher.create(this);
caller.setCallback(caller.getTarget().deleteVolumeCallback(null, null))
.setContext(context);
ep.sendMessageAsync(cmd, caller);
}
public Void deleteVolumeCallback(AsyncCallbackDispatcher<DefaultPrimaryDataStoreDriverImpl, Answer> callback, AsyncRpcConext<CommandResult> context) {
CommandResult result = new CommandResult();
Answer answer = callback.getResult();
if (!answer.getResult()) {
result.setResult(answer.getDetails());
}
context.getParentCallback().complete(result);
return null;
} }
@Override @Override
@ -106,33 +119,6 @@ public class DefaultPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
// TODO Auto-generated method stub // TODO Auto-generated method stub
return true; return true;
} }
protected Answer sendOutCommand(Command cmd, List<EndPoint> endPoints) {
Answer answer = null;
int retries = 3;
int i = 0;
for (EndPoint ep : endPoints) {
answer = ep.sendMessage(cmd);
if (answer == null || answer.getDetails() != null) {
if (i < retries) {
s_logger.debug("create volume failed, retrying: " + i);
}
i++;
} else {
break;
}
}
if (answer == null || answer.getDetails() != null) {
if (answer == null) {
throw new CloudRuntimeException("Failed to created volume");
} else {
throw new CloudRuntimeException(answer.getDetails());
}
}
return answer;
}
private class CreateVolumeFromBaseImageContext<T> extends AsyncRpcConext<T> { private class CreateVolumeFromBaseImageContext<T> extends AsyncRpcConext<T> {
private final VolumeObject volume; private final VolumeObject volume;

View File

@ -14,7 +14,7 @@ public interface PrimaryDataStoreDriver {
void createVolumeFromBaseImageAsync(VolumeObject volume, TemplateOnPrimaryDataStoreInfo template, AsyncCompletionCallback<CommandResult> callback); void createVolumeFromBaseImageAsync(VolumeObject volume, TemplateOnPrimaryDataStoreInfo template, AsyncCompletionCallback<CommandResult> callback);
boolean deleteVolume(VolumeObject vo); void deleteVolumeAsync(VolumeObject vo, AsyncCompletionCallback<CommandResult> callback);
String grantAccess(VolumeObject vol, EndPoint ep); String grantAccess(VolumeObject vol, EndPoint ep);

View File

@ -54,18 +54,18 @@ public class VolumeManagerImpl implements VolumeManager {
private void initStateMachine() { private void initStateMachine() {
s_fsm.addTransition(Volume.State.Allocated, Event.CreateRequested, Volume.State.Creating); s_fsm.addTransition(Volume.State.Allocated, Event.CreateRequested, Volume.State.Creating);
s_fsm.addTransition(Volume.State.Allocated, Event.DestroyRequested, Volume.State.Destroy); s_fsm.addTransition(Volume.State.Allocated, Event.DestroyRequested, Volume.State.Destroying);
s_fsm.addTransition(Volume.State.Creating, Event.OperationRetry, Volume.State.Creating); s_fsm.addTransition(Volume.State.Creating, Event.OperationRetry, Volume.State.Creating);
s_fsm.addTransition(Volume.State.Creating, Event.OperationFailed, Volume.State.Allocated); s_fsm.addTransition(Volume.State.Creating, Event.OperationFailed, Volume.State.Allocated);
s_fsm.addTransition(Volume.State.Creating, Event.OperationSucceeded, Volume.State.Ready); s_fsm.addTransition(Volume.State.Creating, Event.OperationSucceeded, Volume.State.Ready);
s_fsm.addTransition(Volume.State.Creating, Event.DestroyRequested, Volume.State.Destroy); s_fsm.addTransition(Volume.State.Creating, Event.DestroyRequested, Volume.State.Destroying);
s_fsm.addTransition(Volume.State.Creating, Event.CreateRequested, Volume.State.Creating); s_fsm.addTransition(Volume.State.Creating, Event.CreateRequested, Volume.State.Creating);
s_fsm.addTransition(Volume.State.Allocated, Event.UploadRequested, Volume.State.UploadOp); s_fsm.addTransition(Volume.State.Allocated, Event.UploadRequested, Volume.State.UploadOp);
s_fsm.addTransition(Volume.State.UploadOp, Event.CopyRequested, Volume.State.Creating);// CopyRequested for volume from sec to primary storage s_fsm.addTransition(Volume.State.UploadOp, Event.CopyRequested, Volume.State.Creating);// CopyRequested for volume from sec to primary storage
s_fsm.addTransition(Volume.State.Creating, Event.CopySucceeded, Volume.State.Ready); s_fsm.addTransition(Volume.State.Creating, Event.CopySucceeded, Volume.State.Ready);
s_fsm.addTransition(Volume.State.Creating, Event.CopyFailed, Volume.State.UploadOp);// Copying volume from sec to primary failed. s_fsm.addTransition(Volume.State.Creating, Event.CopyFailed, Volume.State.UploadOp);// Copying volume from sec to primary failed.
s_fsm.addTransition(Volume.State.UploadOp, Event.DestroyRequested, Volume.State.Destroy); s_fsm.addTransition(Volume.State.UploadOp, Event.DestroyRequested, Volume.State.Destroying);
s_fsm.addTransition(Volume.State.Ready, Event.DestroyRequested, Volume.State.Destroy); s_fsm.addTransition(Volume.State.Ready, Event.DestroyRequested, Volume.State.Destroying);
s_fsm.addTransition(Volume.State.Destroy, Event.ExpungingRequested, Volume.State.Expunging); s_fsm.addTransition(Volume.State.Destroy, Event.ExpungingRequested, Volume.State.Expunging);
s_fsm.addTransition(Volume.State.Ready, Event.SnapshotRequested, Volume.State.Snapshotting); s_fsm.addTransition(Volume.State.Ready, Event.SnapshotRequested, Volume.State.Snapshotting);
s_fsm.addTransition(Volume.State.Snapshotting, Event.OperationSucceeded, Volume.State.Ready); s_fsm.addTransition(Volume.State.Snapshotting, Event.OperationSucceeded, Volume.State.Ready);
@ -74,6 +74,9 @@ public class VolumeManagerImpl implements VolumeManager {
s_fsm.addTransition(Volume.State.Migrating, Event.OperationSucceeded, Volume.State.Ready); s_fsm.addTransition(Volume.State.Migrating, Event.OperationSucceeded, Volume.State.Ready);
s_fsm.addTransition(Volume.State.Migrating, Event.OperationFailed, Volume.State.Ready); s_fsm.addTransition(Volume.State.Migrating, Event.OperationFailed, Volume.State.Ready);
s_fsm.addTransition(Volume.State.Destroy, Event.OperationSucceeded, Volume.State.Destroy); s_fsm.addTransition(Volume.State.Destroy, Event.OperationSucceeded, Volume.State.Destroy);
s_fsm.addTransition(Volume.State.Destroying, Event.OperationSucceeded, Volume.State.Destroy);
s_fsm.addTransition(Volume.State.Destroying, Event.OperationFailed, Volume.State.Destroying);
s_fsm.addTransition(Volume.State.Destroying, Event.DestroyRequested, Volume.State.Destroying);
} }
@Override @Override

View File

@ -158,4 +158,9 @@ public class VolumeObject implements VolumeInfo {
public String getName() { public String getName() {
return this.volumeVO.getName(); return this.volumeVO.getName();
} }
@Override
public boolean isAttachedVM() {
return (this.volumeVO.getInstanceId() == null) ? false : true;
}
} }

View File

@ -98,7 +98,7 @@ public class VolumeServiceImpl implements VolumeService {
dataStore.createVolumeAsync(vo, diskType, caller); dataStore.createVolumeAsync(vo, diskType, caller);
} }
protected Void createVolumeCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CommandResult> callback, CreateVolumeContext<VolumeApiResult> context) { public Void createVolumeCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CommandResult> callback, CreateVolumeContext<VolumeApiResult> context) {
CommandResult result = callback.getResult(); CommandResult result = callback.getResult();
VolumeObject vo = context.getVolume(); VolumeObject vo = context.getVolume();
VolumeApiResult volResult = new VolumeApiResult(vo); VolumeApiResult volResult = new VolumeApiResult(vo);
@ -112,11 +112,55 @@ public class VolumeServiceImpl implements VolumeService {
context.getParentCallback().complete(volResult); context.getParentCallback().complete(volResult);
return null; return null;
} }
private class DeleteVolumeContext<T> extends AsyncRpcConext<T> {
private final VolumeObject volume;
/**
* @param callback
*/
public DeleteVolumeContext(AsyncCompletionCallback<T> callback, VolumeObject volume) {
super(callback);
this.volume = volume;
}
public VolumeObject getVolume() {
return this.volume;
}
}
@DB @DB
@Override @Override
public void deleteVolumeAsync(VolumeInfo volume, AsyncCompletionCallback<VolumeApiResult> callback) { public void deleteVolumeAsync(VolumeInfo volume, AsyncCompletionCallback<VolumeApiResult> callback) {
VolumeObject vo = (VolumeObject)volume;
PrimaryDataStore dataStore = vo.getDataStore();
vo.stateTransit(Volume.Event.DestroyRequested);
if (dataStore == null) {
vo.stateTransit(Volume.Event.OperationSucceeded);
volDao.remove(vo.getId());
return;
}
DeleteVolumeContext<VolumeApiResult> context = new DeleteVolumeContext<VolumeApiResult>(callback, vo);
AsyncCallbackDispatcher<VolumeServiceImpl, CommandResult> caller = AsyncCallbackDispatcher.create(this);
caller.setCallback(caller.getTarget().deleteVolumeCallback(null, null))
.setContext(context);
dataStore.deleteVolumeAsync(volume, caller);
}
public Void deleteVolumeCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CommandResult> callback, DeleteVolumeContext<VolumeApiResult> context) {
CommandResult result = callback.getResult();
VolumeObject vo = context.getVolume();
VolumeApiResult apiResult = new VolumeApiResult(vo);
if (result.isSuccess()) {
vo.stateTransit(Volume.Event.OperationSucceeded);
volDao.remove(vo.getId());
} else {
vo.stateTransit(Volume.Event.OperationFailed);
apiResult.setResult(result.getResult());
}
context.getParentCallback().complete(apiResult);
return null;
} }
@Override @Override

View File

@ -34,7 +34,9 @@ import org.apache.cloudstack.storage.command.CopyTemplateToPrimaryStorageCmd;
import org.apache.cloudstack.storage.command.CopyTemplateToPrimaryStorageAnswer; import org.apache.cloudstack.storage.command.CopyTemplateToPrimaryStorageAnswer;
import org.apache.cloudstack.storage.command.CreatePrimaryDataStoreCmd; import org.apache.cloudstack.storage.command.CreatePrimaryDataStoreCmd;
import org.apache.cloudstack.storage.command.CreateVolumeAnswer; import org.apache.cloudstack.storage.command.CreateVolumeAnswer;
import org.apache.cloudstack.storage.command.CreateVolumeCommand;
import org.apache.cloudstack.storage.command.CreateVolumeFromBaseImageCommand; import org.apache.cloudstack.storage.command.CreateVolumeFromBaseImageCommand;
import org.apache.cloudstack.storage.command.DeleteVolumeCommand;
import org.apache.cloudstack.storage.command.StorageSubSystemCommand; import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
import org.apache.cloudstack.storage.datastore.protocol.DataStoreProtocol; import org.apache.cloudstack.storage.datastore.protocol.DataStoreProtocol;
import org.apache.cloudstack.storage.to.ImageDataStoreTO; import org.apache.cloudstack.storage.to.ImageDataStoreTO;
@ -72,6 +74,7 @@ import com.xensource.xenapi.PBD;
import com.xensource.xenapi.Pool; import com.xensource.xenapi.Pool;
import com.xensource.xenapi.SR; import com.xensource.xenapi.SR;
import com.xensource.xenapi.Types; import com.xensource.xenapi.Types;
import com.xensource.xenapi.VBD;
import com.xensource.xenapi.Types.BadServerResponse; import com.xensource.xenapi.Types.BadServerResponse;
import com.xensource.xenapi.Types.XenAPIException; import com.xensource.xenapi.Types.XenAPIException;
import com.xensource.xenapi.VDI; import com.xensource.xenapi.VDI;
@ -93,11 +96,96 @@ public class XenServerStorageResource {
return execute((CreatePrimaryDataStoreCmd) command); return execute((CreatePrimaryDataStoreCmd) command);
} else if (command instanceof CreateVolumeFromBaseImageCommand) { } else if (command instanceof CreateVolumeFromBaseImageCommand) {
return execute((CreateVolumeFromBaseImageCommand)command); return execute((CreateVolumeFromBaseImageCommand)command);
} else if (command instanceof CreateVolumeCommand) {
return execute((CreateVolumeCommand) command);
} else if (command instanceof DeleteVolumeCommand) {
return execute((DeleteVolumeCommand)command);
} }
return new Answer((Command)command, false, "not implemented yet"); return new Answer((Command)command, false, "not implemented yet");
} }
public Answer execute(CreateVolumeFromBaseImageCommand cmd) { protected SR getSRByNameLabel(Connection conn, String nameLabel) throws BadServerResponse, XenAPIException, XmlRpcException {
Set<SR> srs = SR.getByNameLabel(conn, nameLabel);
if (srs.size() != 1) {
throw new CloudRuntimeException("storage uuid: " + nameLabel + " is not unique");
}
SR poolsr = srs.iterator().next();
return poolsr;
}
protected VDI createVdi(Connection conn, String vdiName, SR sr, long size) throws BadServerResponse, XenAPIException, XmlRpcException {
VDI.Record vdir = new VDI.Record();
vdir.nameLabel = vdiName;
vdir.SR = sr;
vdir.type = Types.VdiType.USER;
vdir.virtualSize = size;
VDI vdi = VDI.create(conn, vdir);
return vdi;
}
protected void deleteVDI(Connection conn, VDI vdi) throws BadServerResponse, XenAPIException, XmlRpcException {
vdi.destroy(conn);
}
protected CreateVolumeAnswer execute(CreateVolumeCommand cmd) {
VolumeTO volume = cmd.getVolume();
PrimaryDataStoreTO primaryDataStore = volume.getDataStore();
Connection conn = hypervisorResource.getConnection();
VDI vdi = null;
boolean result = false;
String errorMsg = null;
try {
SR primaryDataStoreSR = getSRByNameLabel(conn, primaryDataStore.getUuid());
vdi = createVdi(conn, volume.getName(), primaryDataStoreSR, volume.getSize());
VDI.Record record = vdi.getRecord(conn);
result = true;
return new CreateVolumeAnswer(cmd, record.uuid);
} catch (BadServerResponse e) {
s_logger.debug("Failed to create volume", e);
errorMsg = e.toString();
} catch (XenAPIException e) {
s_logger.debug("Failed to create volume", e);
errorMsg = e.toString();
} catch (XmlRpcException e) {
s_logger.debug("Failed to create volume", e);
errorMsg = e.toString();
} finally {
if (!result && vdi != null) {
try {
deleteVDI(conn, vdi);
} catch (Exception e) {
s_logger.debug("Faled to delete vdi: " + vdi.toString());
}
}
}
return new CreateVolumeAnswer(cmd, false, errorMsg);
}
protected Answer execute(DeleteVolumeCommand cmd) {
VolumeTO volume = cmd.getVolume();
Connection conn = hypervisorResource.getConnection();
String errorMsg = null;
try {
VDI vdi = VDI.getByUuid(conn, volume.getUuid());
deleteVDI(conn, vdi);
return new Answer(cmd);
} catch (BadServerResponse e) {
s_logger.debug("Failed to delete volume", e);
errorMsg = e.toString();
} catch (XenAPIException e) {
s_logger.debug("Failed to delete volume", e);
errorMsg = e.toString();
} catch (XmlRpcException e) {
s_logger.debug("Failed to delete volume", e);
errorMsg = e.toString();
}
return new Answer(cmd, false, errorMsg);
}
protected Answer execute(CreateVolumeFromBaseImageCommand cmd) {
VolumeTO volume = cmd.getVolume(); VolumeTO volume = cmd.getVolume();
ImageOnPrimayDataStoreTO baseImage = cmd.getImage(); ImageOnPrimayDataStoreTO baseImage = cmd.getImage();
Connection conn = hypervisorResource.getConnection(); Connection conn = hypervisorResource.getConnection();

View File

@ -11,11 +11,6 @@ import org.apache.cloudstack.storage.volume.VolumeObject;
public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
@Override
public boolean deleteVolume(VolumeObject vo) {
// TODO Auto-generated method stub
return false;
}
@Override @Override
public String grantAccess(VolumeObject vol, EndPoint ep) { public String grantAccess(VolumeObject vol, EndPoint ep) {
@ -77,4 +72,10 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
} }
@Override
public void deleteVolumeAsync(VolumeObject vo, AsyncCompletionCallback<CommandResult> callback) {
// TODO Auto-generated method stub
}
} }