From 43770e0cb25c7ea2fd3a12dab652d5f312635ec6 Mon Sep 17 00:00:00 2001 From: Alena Prokharchyk Date: Sat, 28 Sep 2013 20:42:52 -0700 Subject: [PATCH] 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 --- api/src/com/cloud/event/EventTypes.java | 2 + .../com/cloud/storage/VolumeApiService.java | 2 +- .../command/user/volume/UpdateVolumeCmd.java | 47 ++++++++++++++----- .../src/com/cloud/storage/VolumeVO.java | 7 +++ .../cloud/storage/VolumeApiServiceImpl.java | 38 ++++++++++----- 5 files changed, 72 insertions(+), 24 deletions(-) diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index b3aa91a442a..ec9604e3f90 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -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"; diff --git a/api/src/com/cloud/storage/VolumeApiService.java b/api/src/com/cloud/storage/VolumeApiService.java index 0194c817cac..e8fb8de9aca 100644 --- a/api/src/com/cloud/storage/VolumeApiService.java +++ b/api/src/com/cloud/storage/VolumeApiService.java @@ -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. diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/UpdateVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/UpdateVolumeCmd.java index ad7c9920ad4..bc17b2e22c0 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/UpdateVolumeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/UpdateVolumeCmd.java @@ -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()); diff --git a/engine/schema/src/com/cloud/storage/VolumeVO.java b/engine/schema/src/com/cloud/storage/VolumeVO.java index ea3d6bffa67..43a8d4c571b 100755 --- a/engine/schema/src/com/cloud/storage/VolumeVO.java +++ b/engine/schema/src/com/cloud/storage/VolumeVO.java @@ -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; + } } diff --git a/server/src/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/com/cloud/storage/VolumeApiServiceImpl.java index 16eecd60bc3..b573786e0bf 100644 --- a/server/src/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/com/cloud/storage/VolumeApiServiceImpl.java @@ -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;