CLOUDSTACK-4744: enhanced root admin API updateVolume with state/storageId parameters as a part of "Better control over first party objects" feature.

Also fixed existing bugs for the API:

* corrected action event to be VOLUME.UPDATE (was VOLUME.ATTACH)
* all parameters to update, should be optional - fixed that. If nothing is specified, the db object will remain with its original fields
This commit is contained in:
Alena Prokharchyk 2013-09-28 20:42:52 -07:00
parent b998fba4da
commit 43770e0cb2
5 changed files with 72 additions and 24 deletions

View File

@ -188,6 +188,8 @@ public class EventTypes {
public static final String EVENT_VOLUME_DETAIL_UPDATE = "VOLUME.DETAIL.UPDATE";
public static final String EVENT_VOLUME_DETAIL_ADD = "VOLUME.DETAIL.ADD";
public static final String EVENT_VOLUME_DETAIL_REMOVE = "VOLUME.DETAIL.REMOVE";
public static final String EVENT_VOLUME_UPDATE = "VOLUME.UPDATE";
// Domains
public static final String EVENT_DOMAIN_CREATE = "DOMAIN.CREATE";

View File

@ -84,7 +84,7 @@ public interface VolumeApiService {
Snapshot allocSnapshot(Long volumeId, Long policyId)
throws ResourceAllocationException;
Volume updateVolume(UpdateVolumeCmd updateVolumeCmd);
Volume updateVolume(long volumeId, String path, String state, Long storageId);
/**
* Extracts the volume to a particular location.

View File

@ -23,15 +23,14 @@ import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.api.response.StoragePoolResponse;
import org.apache.cloudstack.api.response.VolumeResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.log4j.Logger;
import com.cloud.event.EventTypes;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.storage.Volume;
import com.cloud.user.Account;
@APICommand(name = "updateVolume", description="Updates the volume.", responseObject=VolumeResponse.class)
public class UpdateVolumeCmd extends BaseAsyncCmd {
@ -42,13 +41,18 @@ public class UpdateVolumeCmd extends BaseAsyncCmd {
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=VolumeResponse.class,
required=true, description="the ID of the disk volume")
@Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=VolumeResponse.class, description="the ID of the disk volume")
private Long id;
@Parameter(name=ApiConstants.PATH, type=CommandType.STRING,
required=true, description="the path of the volume")
@Parameter(name=ApiConstants.PATH, type=CommandType.STRING, description="The path of the volume")
private String path;
@Parameter(name=ApiConstants.STORAGE_ID, type=CommandType.UUID, entityType=StoragePoolResponse.class,
description="Destination storage pool UUID for the volume", since="4.3")
private Long storageId;
@Parameter(name=ApiConstants.STATE, type=CommandType.STRING, description="The state of the volume", since="4.3")
private String state;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
@ -61,6 +65,15 @@ public class UpdateVolumeCmd extends BaseAsyncCmd {
public Long getId() {
return id;
}
public Long getStorageId() {
return storageId;
}
public String getState() {
return state;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
@ -83,25 +96,37 @@ public class UpdateVolumeCmd extends BaseAsyncCmd {
public long getEntityOwnerId() {
Volume volume = _responseGenerator.findVolumeById(getId());
if (volume == null) {
return Account.ACCOUNT_ID_SYSTEM; // bad id given, parent this command to SYSTEM so ERROR events are tracked
throw new InvalidParameterValueException("Invalid volume id was provided");
}
return volume.getAccountId();
}
@Override
public String getEventType() {
return EventTypes.EVENT_VOLUME_ATTACH;
return EventTypes.EVENT_VOLUME_UPDATE;
}
@Override
public String getEventDescription() {
return "adding detail to the volume: " + getId();
StringBuffer desc = new StringBuffer();
desc.append(" with");
if (getPath() != null) {
desc.append(" path " + getPath());
}
if (getStorageId() != null) {
desc.append(", storage id " + getStorageId());
}
if (getState() != null) {
desc.append(", state " + getState());
}
return "Updating volume: " + getId() + desc.toString();
}
@Override
public void execute(){
CallContext.current().setEventDetails("Volume Id: "+getId());
Volume result = _volumeService.updateVolume(this);
Volume result = _volumeService.updateVolume(getId(), getPath(), getState(), getStorageId());
if (result != null) {
VolumeResponse response = _responseGenerator.createVolumeResponse(result);
response.setResponseName(getCommandName());

View File

@ -35,6 +35,7 @@ import javax.persistence.Transient;
import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.db.GenericDao;
import com.cloud.vm.VirtualMachine.State;
@Entity
@Table(name = "volumes")
@ -573,4 +574,10 @@ public class VolumeVO implements Volume {
public void setIsoId(long isoId) {
this.isoId =isoId;
}
// don't use this directly, use volume state machine instead
// This method is used by UpdateVolume as a part of "Better control over first class objects in CS"
public void setState(State state) {
this.state = state;
}
}

View File

@ -25,8 +25,6 @@ import java.util.concurrent.ExecutionException;
import javax.inject.Inject;
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
@ -34,7 +32,6 @@ import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.ExtractVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.UpdateVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
@ -67,6 +64,7 @@ import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO;
import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity;
import org.apache.log4j.Logger;
import com.cloud.agent.AgentManager;
import com.cloud.agent.api.Answer;
@ -1108,16 +1106,32 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
}
@Override
public Volume updateVolume(UpdateVolumeCmd cmd) {
Long volumeId = cmd.getId();
String path = cmd.getPath();
if (path == null) {
throw new InvalidParameterValueException("Failed to update the volume as path was null");
@ActionEvent(eventType = EventTypes.EVENT_VOLUME_UPDATE, eventDescription = "updating volume", async = true)
public Volume updateVolume(long volumeId, String path, String state, Long storageId) {
VolumeVO volume = _volumeDao.findById(volumeId);
if (path != null) {
volume.setPath(path);
}
VolumeVO volume = ApiDBUtils.findVolumeById(volumeId);
volume.setPath(path);
if (state != null) {
try {
Volume.State volumeState = Volume.State.valueOf(state);
volume.setState(volumeState);
}
catch(IllegalArgumentException ex) {
throw new InvalidParameterValueException("Invalid volume state specified");
}
}
if (storageId != null) {
StoragePool pool = _storagePoolDao.findById(storageId);
if (pool.getDataCenterId() != volume.getDataCenterId()) {
throw new InvalidParameterValueException("Invalid storageId specified; refers to the pool outside of the volume's zone");
}
volume.setPoolId(pool.getId());
}
_volumeDao.update(volumeId, volume);
return volume;