Search in sources :

Example 1 with VolumeActionRequest

use of com.emc.storageos.cinder.model.VolumeActionRequest in project coprhd-controller by CoprHD.

the class ExportService method actionOnVolume.

/**
 * Action could be either export or unexport volume
 *
 * NOTE: This is an asynchronous operation.
 *
 * @prereq none
 *
 * @param param POST data containing the volume action information.
 * The different kinds of operations that are part of the export are
 * Reserve, unreserve, terminate, begin detach, detach, attach, init connection,
 * extend, set bootable, set Readonly
 *
 * os-reserve: reserve a volume for initiating the attach operation.
 * os-unreserve: unreserve the volume to indicate the attach operation being performed is over.
 * os-begin_detaching: Initiate the detach operation by setting the status to detaching.
 * os-detach: Set the detach related status in the db.
 * os-terminate_connection: detach int hebackend.
 * os-initialize_connection: create export of the volume to the nova node.
 * os-attach: perform the mount of the volume that has been exported to the nova instance.
 * os-extend: extend size of volume.
 * os-reset_status: reset the status of the volume.
 * os-set_bootable: set bootable flag on volume.
 * os-update_readonly_flag: update the volume as readonly.
 *
 * @brief Export/Unexport volume
 * @return A reference to a BlockTaskList containing a list of
 *         TaskResourceRep references specifying the task data for the
 *         volume creation tasks.
 * @throws InternalException
 * @throws InterruptedException
 */
@POST
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{volume_id}/action")
@CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.TENANT_ADMIN }, acls = { ACL.ANY })
public Object actionOnVolume(@PathParam("tenant_id") String openstackTenantId, @PathParam("volume_id") String volumeId, String input) throws InternalException, InterruptedException {
    // Step 1: Parameter validation
    // Eventually we should use the project id that comes from the API
    _log.info("String format input is  = {}", input);
    _log.info("Action on volume: id = {}", volumeId);
    boolean bReserve = false;
    boolean bUnReserve = false;
    boolean bTerminate = false;
    boolean bBeginDetach = false;
    boolean bDetach = false;
    boolean bAttach = false;
    boolean bInitCon = false;
    boolean bExtend = false;
    boolean bBootable = false;
    boolean bReadonly = false;
    if (input.contains(ExportOperations.OS_RESERVE.getOperation()))
        bReserve = true;
    if (input.contains(ExportOperations.OS_UNRESERVE.getOperation()))
        bUnReserve = true;
    if (input.contains(ExportOperations.OS_TERMINATE_CONNECTION.getOperation()))
        bTerminate = true;
    if (input.contains(ExportOperations.OS_BEGIN_DETACHING.getOperation()))
        bBeginDetach = true;
    if (input.contains(ExportOperations.OS_DETACH.getOperation()))
        bDetach = true;
    if (input.contains(ExportOperations.OS_ATTACH.getOperation()))
        bAttach = true;
    if (input.contains(ExportOperations.OS_INITIALIZE_CONNECTION.getOperation()))
        bInitCon = true;
    if (input.contains(ExportOperations.OS_EXTEND.getOperation())) {
        // for expand volume
        // expand size has to be numeric and  null size can't be accepted
        // for expand volume verify passed extendsize is in numeric format
        // otherwise it will result in Bad Request for improper input
        String[] extendStrings = input.split(":");
        String sizeString = extendStrings[2].replaceAll("}", "");
        _log.debug("extend string size value  = {}", sizeString);
        if ((sizeString == null) || !isNumeric(sizeString.trim())) {
            _log.info("Improper extend size ={}", sizeString.trim());
            return CinderApiUtils.createErrorResponse(400, "Bad request : improper volume extend size ");
        }
        bExtend = true;
    }
    if (input.contains(ExportOperations.OS_SET_BOOTABLE.getOperation()))
        bBootable = true;
    if (input.contains(ExportOperations.OS_UPDATE_READONLY.getOperation()))
        bReadonly = true;
    if (input.contains(ExportOperations.OS_RESET_STATUS.getOperation())) {
        Volume vol = findVolume(volumeId, openstackTenantId);
        if (vol != null) {
            return changeVolumeStatus(vol, input);
        } else {
            return Response.status(404).build();
        }
    }
    _log.info(String.format("bReserve:  %b , bUnReserve:  %b, bTerminate:%b, bBeginDetach:%b , bDetach:%b , " + "bAttach:%b , bInitCon:%b , bExtend:%b, bReadonly:%b", bReserve, bUnReserve, bTerminate, bBeginDetach, bDetach, bAttach, bInitCon, bExtend, bReadonly));
    // TODO : handle xml format requests also and cater to the operations
    Gson gson = new Gson();
    VolumeActionRequest action = gson.fromJson(input, VolumeActionRequest.class);
    Volume vol = findVolume(volumeId, openstackTenantId);
    if (vol == null) {
        _log.info("Invalid volume id ={} ", volumeId);
        return CinderApiUtils.createErrorResponse(404, "Not Found :  Invaild volume id");
    }
    // Step 2: Check if the user has rights for volume modification
    verifyUserCanModifyVolume(vol);
    _log.debug("User can modify volume");
    // if ( (action.attach.connector!=null) && (action.attach.connector.ip!=null) && (action.attach.connector.ip.length() > 0)){
    if ((bInitCon) && (action.attach.connector != null) && (action.attach.connector.ip != null) && (action.attach.connector.ip.length() > 0)) {
        String chosenProtocol = getProtocol(vol, action.attach.connector);
        boolean bIsSuccess = processAttachRequest(vol, action.attach, openstackTenantId, chosenProtocol);
        if (bIsSuccess) {
            if (chosenProtocol.equals("iSCSI")) {
                return populateIscsiConnectionInfo(vol);
            } else if (chosenProtocol.equals("FC")) {
                return populateFcConnectionInfo(chosenProtocol, vol, action, openstackTenantId);
            }
        } else {
            vol.getExtensions().put("status", "OPENSTACK_ATTACHING_TIMED_OUT");
            _dbClient.updateObject(vol);
            _log.info("After fifteen tries, the ITLs are not found yet and hence failing initilize connection");
        }
        throw APIException.internalServerErrors.genericApisvcError("Export failed", new Exception("Initialize_connection operation failed due to timeout"));
    } else if (bDetach) {
        getVolExtensions(vol).put("status", ComponentStatus.AVAILABLE.getStatus().toLowerCase());
        _dbClient.updateObject(vol);
        return Response.status(202).build();
    } else if (bBeginDetach) {
        if (getVolExtensions(vol).containsKey("status") && getVolExtensions(vol).get("status").equals(ComponentStatus.IN_USE.getStatus().toLowerCase())) {
            getVolExtensions(vol).put("status", ComponentStatus.DETACHING.getStatus().toLowerCase());
            _dbClient.updateObject(vol);
            return Response.status(202).build();
        } else {
            _log.info("Volume is already in detached state.");
            throw APIException.internalServerErrors.genericApisvcError("Unexport failed", new Exception("Volume not in attached state"));
        }
    } else if (bTerminate) {
        StringMap extensionsMap = getVolExtensions(vol);
        if (extensionsMap.containsKey("status") && (extensionsMap.get("status").equals(ComponentStatus.DETACHING.getStatus().toLowerCase()) || extensionsMap.get("status").equals(ComponentStatus.IN_USE.getStatus().toLowerCase()))) {
            extensionsMap.put("status", ComponentStatus.DETACHING.getStatus().toLowerCase());
            _dbClient.updateObject(vol);
            String chosenProtocol = getProtocol(vol, action.detach.connector);
            processDetachRequest(vol, action.detach, openstackTenantId, chosenProtocol);
            extensionsMap.put("status", ComponentStatus.AVAILABLE.getStatus().toLowerCase());
            extensionsMap.remove("OPENSTACK_NOVA_INSTANCE_ID");
            extensionsMap.remove("OPENSTACK_NOVA_INSTANCE_MOUNTPOINT");
            extensionsMap.remove("OPENSTACK_ATTACH_MODE");
            _dbClient.updateObject(vol);
            return Response.status(202).build();
        } else {
            _log.info("Volume not in a state for terminate connection.");
            throw APIException.internalServerErrors.genericApisvcError("Unexport failed", new Exception("Volume not in state for termination"));
        }
    } else // (action.attachToInstance.instance_uuid.length() > 0)){
    if (bAttach) {
        _log.info("IN THE IF CONDITION OF THE ATTACH VOLUME TO INSTANCE");
        if ((action.attachToInstance != null) && (action.attachToInstance.instance_uuid != null) && (action.attachToInstance.instance_uuid.length() > 0)) {
            processAttachToInstance(vol, action.attachToInstance, openstackTenantId);
            return Response.status(202).build();
        } else {
            throw APIException.badRequests.parameterIsNullOrEmpty("Instance");
        }
    } else if (bReserve) {
        _log.info("IN THE IF CONDITION OF RESERVE");
        if (getVolExtensions(vol).containsKey("status") && getVolExtensions(vol).get("status").equals(ComponentStatus.ATTACHING.getStatus().toLowerCase())) {
            _log.debug("Reserved Volume cannot be  reserved again");
            return CinderApiUtils.createErrorResponse(400, "Bad request :  volume is already reserved");
        }
        processReserveRequest(vol, openstackTenantId);
        return Response.status(202).build();
    } else if (bUnReserve) {
        processUnReserveRequest(vol, openstackTenantId);
        return Response.status(202).build();
    } else if (bBootable) {
        _log.debug("set Volume bootable Flag");
        if (action.bootVol != null) {
            setBootable(vol, action.bootVol, openstackTenantId);
            return Response.status(200).build();
        } else {
            throw APIException.badRequests.parameterIsNullOrEmpty("Volume");
        }
    } else if (bReadonly) {
        _log.debug("Set Readonly Flag for Volume");
        if (action.readonlyVol != null) {
            setReadOnlyFlag(vol, action.readonlyVol, openstackTenantId);
            return Response.status(200).build();
        } else {
            throw APIException.badRequests.parameterIsNullOrEmpty("Volume");
        }
    } else if (bExtend) {
        // extend volume size
        _log.info("Extend existing volume size");
        if (action.extendVol != null) {
            if (volumeId == null) {
                _log.info("Source volume id is empty ");
                return CinderApiUtils.createErrorResponse(404, "Not Found :  source volume id is empty");
            }
            long extend_size = action.extendVol.new_size * GB;
            if (extend_size <= vol.getCapacity()) {
                _log.info(String.format("expandVolume: VolumeId id: %s, Current size: %d, New size: %d ", volumeId, vol.getCapacity(), extend_size));
                return CinderApiUtils.createErrorResponse(400, "Bad request :  New size should be larger than old");
            }
            // action.extendVol.new_size
            extendExistingVolume(vol, extend_size, openstackTenantId, volumeId);
            return Response.status(202).build();
        } else {
            throw APIException.badRequests.parameterIsNullOrEmpty("Volume");
        }
    }
    throw APIException.badRequests.parameterIsNotValid("Action Type");
}
Also used : StringMap(com.emc.storageos.db.client.model.StringMap) VolumeActionRequest(com.emc.storageos.cinder.model.VolumeActionRequest) Volume(com.emc.storageos.db.client.model.Volume) Gson(com.google.gson.Gson) APIException(com.emc.storageos.svcs.errorhandling.resources.APIException) InternalException(com.emc.storageos.svcs.errorhandling.resources.InternalException) ControllerException(com.emc.storageos.volumecontroller.ControllerException) Path(javax.ws.rs.Path) POST(javax.ws.rs.POST) Consumes(javax.ws.rs.Consumes) Produces(javax.ws.rs.Produces) CheckPermission(com.emc.storageos.security.authorization.CheckPermission)

Aggregations

VolumeActionRequest (com.emc.storageos.cinder.model.VolumeActionRequest)1 StringMap (com.emc.storageos.db.client.model.StringMap)1 Volume (com.emc.storageos.db.client.model.Volume)1 CheckPermission (com.emc.storageos.security.authorization.CheckPermission)1 APIException (com.emc.storageos.svcs.errorhandling.resources.APIException)1 InternalException (com.emc.storageos.svcs.errorhandling.resources.InternalException)1 ControllerException (com.emc.storageos.volumecontroller.ControllerException)1 Gson (com.google.gson.Gson)1 Consumes (javax.ws.rs.Consumes)1 POST (javax.ws.rs.POST)1 Path (javax.ws.rs.Path)1 Produces (javax.ws.rs.Produces)1