/** * Abiquo community edition * cloud management application for hybrid clouds * Copyright (C) 2008-2010 - Abiquo Holdings S.L. * * This application is free software; you can redistribute it and/or * modify it under the terms of the GNU LESSER GENERAL PUBLIC * LICENSE as published by the Free Software Foundation under * version 3 of the License * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * LESSER GENERAL PUBLIC LICENSE v.3 for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ package com.abiquo.api.resources.cloud; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.DefaultValue; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.UriInfo; import org.apache.wink.common.annotations.Parent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import com.abiquo.api.exceptions.APIError; import com.abiquo.api.exceptions.BadRequestException; import com.abiquo.api.exceptions.InternalServerErrorException; import com.abiquo.api.resources.AbstractResource; import com.abiquo.api.resources.TaskResourceUtils; import com.abiquo.api.services.TaskService; import com.abiquo.api.services.cloud.VirtualDatacenterService; import com.abiquo.api.services.cloud.VirtualMachineLock; import com.abiquo.api.services.cloud.VirtualMachineService; import com.abiquo.api.util.IRESTBuilder; import com.abiquo.model.transport.AcceptedRequestDto; import com.abiquo.model.transport.SeeOtherDto; import com.abiquo.scheduler.SchedulerLock; import com.abiquo.server.core.appslibrary.VirtualMachineTemplate; import com.abiquo.server.core.cloud.Hypervisor; import com.abiquo.server.core.cloud.NodeVirtualImage; import com.abiquo.server.core.cloud.VirtualDatacenter; import com.abiquo.server.core.cloud.VirtualMachine; import com.abiquo.server.core.cloud.VirtualMachineDto; import com.abiquo.server.core.cloud.VirtualMachineInstanceDto; import com.abiquo.server.core.cloud.VirtualMachineState; import com.abiquo.server.core.cloud.VirtualMachineStateDto; import com.abiquo.server.core.cloud.VirtualMachineStateTransition; import com.abiquo.server.core.cloud.VirtualMachineTaskDto; import com.abiquo.server.core.cloud.VirtualMachineWithNodeDto; import com.abiquo.server.core.cloud.VirtualMachineWithNodeExtendedDto; import com.abiquo.server.core.enterprise.Enterprise; import com.abiquo.server.core.enterprise.User; import com.abiquo.server.core.infrastructure.Machine; import com.abiquo.server.core.infrastructure.Rack; import com.abiquo.server.core.infrastructure.network.IpPoolManagement; import com.abiquo.server.core.task.Task; import com.abiquo.server.core.task.TaskDto; import com.abiquo.server.core.task.TasksDto; import com.abiquo.server.core.task.enums.TaskOwnerType; @Parent(VirtualMachinesResource.class) @Controller @Path(VirtualMachineResource.VIRTUAL_MACHINE_PARAM) public class VirtualMachineResource extends AbstractResource { public static final String VIRTUAL_MACHINE = "virtualmachine"; public static final String VIRTUAL_MACHINE_PARAM = "{" + VIRTUAL_MACHINE + "}"; public static final String VIRTUAL_MACHINE_DEPLOY_PATH = "action/deploy"; public static final String VIRTUAL_MACHINE_DEPLOY_REL = "deploy"; public static final String VIRTUAL_MACHINE_UNDEPLOY_PATH = "action/undeploy"; public static final String VIRTUAL_MACHINE_UNDEPLOY_REL = "undeploy"; public static final String VIRTUAL_MACHINE_ACTION_RESET = "action/reset"; public static final String VIRTUAL_MACHINE_STATE_PATH = "state"; public static final String VIRTUAL_MACHINE_STATE_REL = "state"; // Chef constants to help link builders. Method implementation are premium. public static final String VIRTUAL_MACHINE_RUNLIST_PATH = "config/runlist"; public static final String VIRTUAL_MACHINE_RUNLIST_REL = "runlist"; public static final String VIRTUAL_MACHINE_BOOTSTRAP_PATH = "config/bootstrap"; public static final String VIRTUAL_MACHINE_BOOTSTRAP_REL = "bootstrap"; public static final String VIRTUAL_MACHINE_ACTION_DEPLOY_REL = "deploy"; public static final String VIRTUAL_MACHINE_ACTION_SNAPSHOT_REL = "instance"; public static final String VIRTUAL_MACHINE_ACTION_SNAPSHOT = "action/instance"; public static final String VIRTUAL_MACHINE_ACTION_UNDEPLOY_REL = "undeploy"; public static final String VIRTUAL_MACHINE_ACTION_RESET_REL = "reset"; public static final String FORCE_UNDEPLOY = "force"; public static final String FORCE = "force"; @Autowired private VirtualMachineService vmService; @Autowired private VirtualDatacenterService vdcService; @Autowired private TaskService taskService; @Autowired private VirtualMachineLock vmLock; /** * Return the virtual machine if exists. * * @title Retrieve a virtual machine * @param vdcId identifier of the virtual datacenter. * @param vappId identifier of the virtual appliance. * @param vmId identifier of the virtual machine * @param restBuilder to build the links * @return the {@link VirtualMachineDto} transfer object for the virtual machine. * @throws Exception */ @GET @Produces(VirtualMachineDto.MEDIA_TYPE) public VirtualMachineDto getVirtualMachine( @PathParam(VirtualDatacenterResource.VIRTUAL_DATACENTER) @NotNull @Min(1) final Integer vdcId, @PathParam(VirtualApplianceResource.VIRTUAL_APPLIANCE) @NotNull @Min(1) final Integer vappId, @PathParam(VirtualMachineResource.VIRTUAL_MACHINE) @NotNull @Min(1) final Integer vmId, @Context final IRESTBuilder restBuilder) throws Exception { VirtualMachine vm = vmService.getVirtualMachine(vdcId, vappId, vmId); VirtualDatacenter vdc = vdcService.getVirtualDatacenter(vdcId); return createTransferObject(vm, vdc, vappId, restBuilder, getVolumeIds(vm), getDiskIds(vm), vm.getIps()); } /*** * @title Modify a virtual machine * @param vdcId VirtualDatacenter id * @param vappId VirtualAppliance id * @param vmId VirtualMachine id * @param restBuilder injected restbuilder context parameter * @return a link where you can keep track of the progress and the virtual machine. * @throws Exception AcceptedRequestDto */ @PUT @Consumes(VirtualMachineDto.MEDIA_TYPE) @Produces(AcceptedRequestDto.MEDIA_TYPE) public AcceptedRequestDto<String> updateVirtualMachine( @PathParam(VirtualDatacenterResource.VIRTUAL_DATACENTER) @NotNull @Min(1) final Integer vdcId, @PathParam(VirtualApplianceResource.VIRTUAL_APPLIANCE) @NotNull @Min(1) final Integer vappId, @PathParam(VirtualMachineResource.VIRTUAL_MACHINE) @NotNull @Min(1) final Integer vmId, @QueryParam(FORCE) @DefaultValue("false") final Boolean force, final VirtualMachineDto dto, @Context final IRESTBuilder restBuilder, @Context final UriInfo uriInfo) throws Exception { VirtualMachineState originalState = vmLock.lockVirtualMachineBeforeReconfiguring(vdcId, vappId, vmId); try { String taskId = vmService.reconfigureVirtualMachine(vdcId, vappId, vmId, dto, originalState, force); if (taskId == null) { // If there is no async task the VM must be unlocked here vmLock.unlockVirtualMachine(vmId, originalState); // If the link is null no Task was performed return null; } return buildAcceptedRequestDtoWithTaskLink(taskId, uriInfo); } catch (Exception ex) { // Make sure virtual machine is unlocked if reconfigure fails vmLock.unlockVirtualMachine(vmId, originalState); throw ex; } } /** * Updates this virtual Machine Node information (e.g. name) * * @title Modify the virtual machine Node information * @param vdcId * @param vappId * @param vmId * @param dto * @param restBuilder * @param uriInfo * @return * @throws Exception */ @PUT @Consumes(VirtualMachineWithNodeDto.MEDIA_TYPE) @Produces(AcceptedRequestDto.MEDIA_TYPE) public AcceptedRequestDto<String> updateVirtualMachineNode( @PathParam(VirtualDatacenterResource.VIRTUAL_DATACENTER) @NotNull @Min(1) final Integer vdcId, @PathParam(VirtualApplianceResource.VIRTUAL_APPLIANCE) @NotNull @Min(1) final Integer vappId, @PathParam(VirtualMachineResource.VIRTUAL_MACHINE) @NotNull @Min(1) final Integer vmId, @QueryParam(FORCE) @DefaultValue("false") final Boolean force, final VirtualMachineWithNodeDto dto, @Context final IRESTBuilder restBuilder, @Context final UriInfo uriInfo) throws Exception { vmService.updateNodeVirtualImageInfo(vdcId, vappId, vmId, dto); return updateVirtualMachine(vdcId, vappId, vmId, force, dto, restBuilder, uriInfo); } /** * Change the {@link VirtualMachineState} the virtual machine * * @title Change the state of a virtual machine * @wiki The allowed states are: OFF, PAUSED, ON. * @param vdcId VirtualDatacenter id * @param vappId VirtualAppliance id * @param vmId VirtualMachine id * @param state allowed * <ul> * <li><b>OFF</b></li> * <li><b>ON</b></li> * <li><b>PAUSED</b></li> * </ul> * @param restBuilder injected restbuilder context parameter * @return a link where you can keep * track of the progress and a message. * @throws Exception */ @PUT @Path(VIRTUAL_MACHINE_STATE_PATH) @Produces(AcceptedRequestDto.MEDIA_TYPE) @Consumes(VirtualMachineStateDto.MEDIA_TYPE) public AcceptedRequestDto<String> powerStateVirtualMachine( @PathParam(VirtualDatacenterResource.VIRTUAL_DATACENTER) final Integer vdcId, @PathParam(VirtualApplianceResource.VIRTUAL_APPLIANCE) final Integer vappId, @PathParam(VirtualMachineResource.VIRTUAL_MACHINE) final Integer vmId, final VirtualMachineStateDto state, @Context final IRESTBuilder restBuilder, @Context final UriInfo uriInfo) throws Exception { VirtualMachineState newState = validateState(state); // Lock the virtual machine VirtualMachineState originalState = vmLock.lockVirtualMachineBeforeChangingState(vdcId, vappId, vmId, newState); VirtualMachineStateTransition transition = VirtualMachineStateTransition.getValidVmStateChangeTransition(originalState, newState); try { String taskId = vmService.applyVirtualMachineState(vmId, vappId, vdcId, transition); // If the link is null no Task was performed if (taskId == null) { throw new InternalServerErrorException(APIError.STATUS_INTERNAL_SERVER_ERROR); } return buildAcceptedRequestDtoWithTaskLinkNoAction(taskId, uriInfo); } catch (Exception ex) { // Make sure virtual machine is unlocked if power state change fails vmLock.unlockVirtualMachine(vmId, originalState); throw ex; } } /** * Retrieve the {@link VirtualMachineState} the virtual machine * * @title Retrieve the state of the virtual machine * @param vdcId VirtualDatacenter id * @param vappId VirtualAppliance id * @param vmId VirtualMachine id * @param restBuilder injected restbuilder context parameter * @return state * @throws Exception */ @GET @Path(VIRTUAL_MACHINE_STATE_PATH) @Produces(VirtualMachineStateDto.MEDIA_TYPE) public VirtualMachineStateDto stateVirtualMachine( @PathParam(VirtualDatacenterResource.VIRTUAL_DATACENTER) final Integer vdcId, @PathParam(VirtualApplianceResource.VIRTUAL_APPLIANCE) final Integer vappId, @PathParam(VirtualMachineResource.VIRTUAL_MACHINE) final Integer vmId, @Context final IRESTBuilder restBuilder) throws Exception { VirtualMachine vm = vmService.getVirtualMachine(vdcId, vappId, vmId); VirtualMachineStateDto stateDto = virtualMachineStateToDto(vdcId, vappId, vmId, restBuilder, vm); return stateDto; } private VirtualMachineStateDto virtualMachineStateToDto(final Integer vdcId, final Integer vappId, final Integer vmId, final IRESTBuilder restBuilder, final VirtualMachine vm) { VirtualMachineStateDto stateDto = new VirtualMachineStateDto(); stateDto.setState(vm.getState()); stateDto.addLinks(restBuilder.buildVirtualMachineStateLinks(vappId, vdcId, vmId)); return stateDto; } /** * Validate that the state is allowed. <br> * * @param state<ul> * <li><b>OFF</b></li> * <li><b>ON</b></li> * <li><b>PAUSED</b></li> * </ul> * @return State */ private VirtualMachineState validateState(final VirtualMachineStateDto state) { if (!VirtualMachineState.ON.equals(state.getState()) && !VirtualMachineState.OFF.equals(state.getState()) && !VirtualMachineState.PAUSED.equals(state.getState())) { throw new BadRequestException(APIError.VIRTUAL_MACHINE_EDIT_STATE); } return state.getState(); } /** * Deletes the virtual machine.<br> * A {@link VirtualMachine} can only be deleted if is in one allowed are NOT_ALLOCATED and * UNKNOWN. allowed * <ul> * <li><b>NOT_ALLOCATED</b></li> * <li><b>UNKNOWN</b></li> * </ul> * * @title Delete a virtual machine * @wiki If the virtual machine exists in the hypervisor it will be removed from the hypervisor * as well. * @param vdcId VirtualDatacenter id * @param vappId VirtualAppliance id * @param vmId VirtualMachine id * @param restBuilder injected restbuilder context parameter * @throws Exception */ @DELETE public void deleteVirtualMachine( @PathParam(VirtualDatacenterResource.VIRTUAL_DATACENTER) final Integer vdcId, @PathParam(VirtualApplianceResource.VIRTUAL_APPLIANCE) final Integer vappId, @PathParam(VirtualMachineResource.VIRTUAL_MACHINE) final Integer vmId, @Context final IRESTBuilder restBuilder) throws Exception { // Check virtual machine state and lock it before starting VirtualMachineState originalState = vmLock.lockVirtualMachineBeforeDeleting(vdcId, vappId, vmId); try { vmService.deleteVirtualMachine(vmId, vappId, vdcId, originalState); // If everything goes fine, there is no need to unlock the VM since it will be deleted // by the handler or here if it was not deployed } catch (Exception ex) { // Make sure virtual machine is unlocked if deploy fails vmLock.unlockVirtualMachine(vmId, originalState); throw ex; } } /** * Deploys a {@link VirtualMachine}. This involves some steps. <br> * <ul> * <li>Select a machine to allocate the virtual machine</li> * <li>Check limits</li> * <li>Check resources</li> * <li>Check remote services</li> * <li>In premium call initiator</li> * <li>Subscribe to VSM</li> * <li>Build the Task DTO</li> * <li>Enqueue in tarantino</li> * <li>Register in redis</li> * <li>Add Task DTO to rabbitmq</li> * <li>Enable the resource <code>Progress<code></li> * </ul> * * @title Deploy a virtual machine * @wiki Deploys the virtual machine with the given options. There is also possible to do not * specify any options and assume the defaults. This call returns a 202 HTTP code * (accepted) and a URI where you can keep track of the deploy. The options are not * mandatory. The options are : -forceEnterpriseSoftLimits This flag forces a check on the * enterprise soft limits when calculating the available resources. If this check fails * the deploy won't be performed. * @param vdcId VirtualDatacenter id * @param vappId VirtualAppliance id * @param vmId VirtualMachine id * @param restBuilder injected restbuilder context parameter * @param forceSoftLimits dto of options * @return a link where you can keep track of the progress and a message. * @throws Exception */ @POST @Path(VIRTUAL_MACHINE_DEPLOY_PATH) @Consumes(VirtualMachineTaskDto.MEDIA_TYPE) @Produces(AcceptedRequestDto.MEDIA_TYPE) public AcceptedRequestDto<String> deployVirtualMachine( @PathParam(VirtualDatacenterResource.VIRTUAL_DATACENTER) final Integer vdcId, @PathParam(VirtualApplianceResource.VIRTUAL_APPLIANCE) final Integer vappId, @PathParam(VirtualMachineResource.VIRTUAL_MACHINE) final Integer vmId, final VirtualMachineTaskDto forceSoftLimits, @Context final IRESTBuilder restBuilder, @Context final UriInfo uriInfo) throws Exception { final String lockMsg = "Allocate vm " + vmId; // Check virtual machine state and lock it before starting VirtualMachineState originalState = vmLock.lockVirtualMachineBeforeDeploying(vdcId, vappId, vmId); try { SchedulerLock.acquire(lockMsg); String taskId = vmService.deployVirtualMachine(vmId, vappId, vdcId, forceSoftLimits .isForceEnterpriseSoftLimits()); return buildAcceptedRequestDtoWithTaskLink(taskId, uriInfo); } catch (Exception ex) { // Make sure virtual machine is unlocked if deploy fails vmLock.unlockVirtualMachine(vmId, originalState); throw ex; } finally { SchedulerLock.release(lockMsg); } } /** * Deploys a {@link VirtualMachine}. This involves some steps. <br> * <ul> * <li>Select a machine to allocate the virtual machine</li> * <li>Check limits</li> * <li>Check resources</li> * <li>Check remote services</li> * <li>In premium call initiator</li> * <li>Subscribe to VSM</li> * <li>Build the Task DTO</li> * <li>Enqueue in tarantino</li> * <li>Register in redis</li> * <li>Add Task DTO to rabbitmq</li> * <li>Enable the resource <code>Progress<code></li> * </ul> * * @title Deploy a virtual machine * @wiki Deploys the virtual machine with the given options. There is also possible to do not * specify any options and assume the defaults. This call returns a 202 HTTP code * (accepted) and a URI where you can keep track of the deploy. The options are not * mandatory. The options are : -forceEnterpriseSoftLimits This flag forces a check on the * enterprise soft limits when calculating the available resources. If this check fails * the deploy won't be performed. * @param vdcId VirtualDatacenter id * @param vappId VirtualAppliance id * @param vmId VirtualMachine id * @param restBuilder injected restbuilder context parameter * @return a link where you can keep track of the progress and a message. * @throws Exception */ @POST @Path(VIRTUAL_MACHINE_DEPLOY_PATH) @Produces(AcceptedRequestDto.MEDIA_TYPE) public AcceptedRequestDto<String> deployVirtualMachine( @PathParam(VirtualDatacenterResource.VIRTUAL_DATACENTER) final Integer vdcId, @PathParam(VirtualApplianceResource.VIRTUAL_APPLIANCE) final Integer vappId, @PathParam(VirtualMachineResource.VIRTUAL_MACHINE) final Integer vmId, @Context final IRESTBuilder restBuilder, @Context final UriInfo uriInfo) throws Exception { VirtualMachineTaskDto force = new VirtualMachineTaskDto(); force.setForceEnterpriseSoftLimits(false); return deployVirtualMachine(vdcId, vappId, vmId, force, restBuilder, uriInfo); } /** * Undeploys a {@link VirtualMachine}. This involves some steps. <br> * <ul> * <li>Deallocate the virtual machine</li> * <li>Delete the relations to the {@link Hypervisor}, {@link Datastore}</li> * <li>Set to NOT_DEPLOYED</li> * <li>Unsuscribe to VSM</li> * <li>Enqueue in tarantino</li> * <li>Register in redis</li> * <li>Add Task DTO to rabbitmq</li> * <li>Enable the resource <code>Progress<code></li> * </ul> * * @title Undeploy the virtual machine * @wiki Perform an undeploy. This means that after the call, the virtual machine in Abiquo will * be in the NOT_ALLOCATED state. If the undeploy is successful, the virtual machine will * be deleted from the hypervisor. If the virtual machine is in the ON state, Abiquo will * perform a power off before the deconfigure. You can also set the force undeploy * parameter in the virtual machine task entity. If this is set to true, the imported * virtual machines are also deleted. This call returns a 202 HTTP code (accepted) and a * URI where you can keep track of the undeploy. The possible option for an undeploy is * -forceUndeploy. If this flag is set to false we do not undeploy imported virtual * machines. * @param vdcId VirtualDatacenter id * @param vappId VirtualAppliance id * @param vmId VirtualMachine id * @param restBuilder injected restbuilder context parameter * @return a link where you can keep track of the progress and a message. * @throws Exception */ @POST @Path(VIRTUAL_MACHINE_UNDEPLOY_PATH) @Consumes(VirtualMachineTaskDto.MEDIA_TYPE) @Produces(AcceptedRequestDto.MEDIA_TYPE) public AcceptedRequestDto<String> undeployVirtualMachine( @PathParam(VirtualDatacenterResource.VIRTUAL_DATACENTER) final Integer vdcId, @PathParam(VirtualApplianceResource.VIRTUAL_APPLIANCE) final Integer vappId, @PathParam(VirtualMachineResource.VIRTUAL_MACHINE) final Integer vmId, final VirtualMachineTaskDto taskOptions, @Context final IRESTBuilder restBuilder, @Context final UriInfo uriInfo) throws Exception { Boolean forceUndeploy; if (taskOptions.getForceUndeploy() == null) { forceUndeploy = Boolean.FALSE; } else { forceUndeploy = taskOptions.getForceUndeploy(); } // Lock the virtual machine before undeploying VirtualMachineState originalState = vmLock.lockVirtualMachineBeforeUndeploying(vdcId, vappId, vmId); try { String taskId = vmService.undeployVirtualMachine(vmId, vappId, vdcId, forceUndeploy, originalState); // If the link is null no Task was performed if (taskId == null) { throw new InternalServerErrorException(APIError.STATUS_INTERNAL_SERVER_ERROR); } return buildAcceptedRequestDtoWithTaskLink(taskId, uriInfo); } catch (Exception ex) { // Make sure virtual machine is unlocked if undeploy fails vmLock.unlockVirtualMachine(vmId, originalState); throw ex; } } /** * Snapshot a {@link VirtualMachine}.> * * @title Snapshot a virtual machine * @wiki Instance the virtual machine with the given name. This call returns a 202 HTTP code * (accepted) and a URI where you can keep track of the deploy. The options are mandatory. * The options are : -instanceName The final name of the instance * @param vdcId VirtualDatacenter id * @param vappId VirtualAppliance id * @param vmId VirtualMachine id * @param restBuilder injected restbuilder context parameter * @return a link where you can keep track of the progress and a message. * @throws Exception */ @POST @Path(VIRTUAL_MACHINE_ACTION_SNAPSHOT) @Consumes(VirtualMachineInstanceDto.MEDIA_TYPE) @Produces(AcceptedRequestDto.MEDIA_TYPE) public AcceptedRequestDto<String> snapshotVirtualMachine( @PathParam(VirtualDatacenterResource.VIRTUAL_DATACENTER) final Integer vdcId, @PathParam(VirtualApplianceResource.VIRTUAL_APPLIANCE) final Integer vappId, @PathParam(VirtualMachineResource.VIRTUAL_MACHINE) final Integer vmId, final VirtualMachineInstanceDto snapshotData, @Context final IRESTBuilder restBuilder, @Context final UriInfo uriInfo) throws Exception { VirtualMachineState originalState = vmLock.lockVirtualMachineBeforeSnapshotting(vdcId, vappId, vmId); try { String taskId = vmService.instanceVirtualMachine(vmId, vappId, vdcId, snapshotData .getInstanceName(), originalState); if (taskId == null) { throw new InternalServerErrorException(APIError.STATUS_INTERNAL_SERVER_ERROR); } return buildAcceptedRequestDtoWithTaskLink(taskId, uriInfo); } catch (Exception ex) { // Make sure virtual machine is unlocked if snapshot fails vmLock.unlockVirtualMachine(vmId, originalState); throw ex; } } /** * Converts to the transfer object for the VirtualMachine POJO when the request is from the * /cloud URI * * @param v virtual machine * @param vdcId identifier of the virtual datacenter * @param vappId identifier of the virtual appliance * @param restBuilder {@link IRESTBuilder} object injected by context. * @return the generate {@link VirtualMachineDto} object. * @throws Exception */ public static VirtualMachineWithNodeDto createNodeTransferObject(final NodeVirtualImage v, final Integer vdcId, final Integer vappId, final IRESTBuilder restBuilder, final Integer[] volumeIds, final Integer[] diskIds, final List<IpPoolManagement> ips) throws Exception { VirtualMachineWithNodeDto dto = new VirtualMachineWithNodeDto(); dto.setUuid(v.getVirtualMachine().getUuid()); dto.setCpu(v.getVirtualMachine().getCpu()); dto.setDescription(v.getVirtualMachine().getDescription()); dto.setHdInBytes(v.getVirtualMachine().getHdInBytes()); dto.setHighDisponibility(v.getVirtualMachine().getHighDisponibility()); dto.setId(v.getVirtualMachine().getId()); dto.setIdState(v.getVirtualMachine().getState().id()); dto.setIdType(v.getVirtualMachine().getIdType()); dto.setName(v.getVirtualMachine().getName()); dto.setPassword(v.getVirtualMachine().getPassword()); dto.setRam(v.getVirtualMachine().getRam()); dto.setState(v.getVirtualMachine().getState()); dto.setVdrpIP(v.getVirtualMachine().getVdrpIP()); dto.setVdrpPort(v.getVirtualMachine().getVdrpPort()); dto.setNodeId(v.getId()); dto.setNodeName(v.getName()); dto.setX(v.getX()); dto.setY(v.getY()); final Hypervisor hypervisor = v.getVirtualMachine().getHypervisor(); final Machine machine = hypervisor == null ? null : hypervisor.getMachine(); final Rack rack = machine == null ? null : machine.getRack(); final Enterprise enterprise = v.getVirtualMachine().getEnterprise() == null ? null : v.getVirtualMachine() .getEnterprise(); final User user = v.getVirtualMachine().getUser() == null ? null : v.getVirtualMachine().getUser(); final VirtualMachineTemplate virtualImage = v.getVirtualImage() == null ? null : v.getVirtualImage(); final VirtualDatacenter vdc = v.getVirtualAppliance().getVirtualDatacenter(); if (!v.getVirtualMachine().isCaptured()) { if (v.getVirtualMachine().isStateful()) { dto.addLink(restBuilder.buildVirtualMachineTemplateLink(virtualImage .getEnterprise().getId(), v.getVirtualAppliance().getVirtualDatacenter() .getDatacenter().getId(), virtualImage.getId())); } else { dto.addLink(restBuilder.buildVirtualMachineTemplateLink(virtualImage .getEnterprise().getId(), virtualImage.getRepository().getDatacenter().getId(), virtualImage.getId())); } } else { if (v.getVirtualMachine().getState().equals(VirtualMachineState.NOT_ALLOCATED)) { // captured and managed virtual machines but with pm removed dto.addLink(restBuilder.buildVirtualMachineTemplateLink(virtualImage .getEnterprise().getId(), v.getVirtualAppliance().getVirtualDatacenter() .getDatacenter().getId(), v.getVirtualImage().getId())); } else { // captured virtual machines dto.addLink(restBuilder.buildVirtualMachineTemplateLink(virtualImage .getEnterprise().getId(), v.getVirtualMachine().getHypervisor().getMachine() .getRack().getDatacenter().getId(), v.getVirtualImage().getId())); } } dto.addLinks(restBuilder.buildVirtualMachineCloudAdminLinks(vdcId, vappId, v .getVirtualMachine(), rack == null ? null : rack.getDatacenter().getId(), rack == null ? null : rack.getId(), machine == null ? null : machine.getId(), enterprise == null ? null : enterprise.getId(), user == null ? null : user.getId(), v.getVirtualMachine() .isChefEnabled(), volumeIds, diskIds, ips, vdc.getHypervisorType(), v .getVirtualAppliance())); TaskResourceUtils.addTasksLink(dto, dto.getEditLink()); return dto; } public static VirtualMachineWithNodeExtendedDto createNodeExtendedTransferObject( final NodeVirtualImage v, final Integer vdcId, final Integer vappId, final IRESTBuilder restBuilder, final Integer[] volumeIds, final Integer[] diskIds, final List<IpPoolManagement> ips) throws Exception { User userVm = v.getVirtualMachine().getUser(); VirtualMachineWithNodeDto dto = createNodeTransferObject(v, vdcId, vappId, restBuilder, volumeIds, diskIds, ips); VirtualMachineWithNodeExtendedDto extendedDto = null; if (userVm == null) { // DELETED USER extendedDto = new VirtualMachineWithNodeExtendedDto(dto, "", "", ""); } else { extendedDto = new VirtualMachineWithNodeExtendedDto(dto, userVm.getName(), userVm.getSurname(), userVm.getEnterprise().getName()); } return extendedDto; } @Deprecated // use the integer based version public static VirtualMachineDto createTransferObject(final VirtualMachine v, final VirtualDatacenter vdc, final IRESTBuilder restBuilder) { VirtualMachineDto dto = new VirtualMachineDto(); dto.setCpu(v.getCpu()); dto.setDescription(v.getDescription()); dto.setHdInBytes(v.getHdInBytes()); dto.setHighDisponibility(v.getHighDisponibility()); dto.setId(v.getId()); dto.setIdState(v.getState().id()); dto.setIdType(v.getIdType()); dto.setName(v.getName()); dto.setPassword(v.getPassword()); dto.setRam(v.getRam()); dto.setState(v.getState()); dto.setVdrpIP(v.getVdrpIP()); dto.setVdrpPort(v.getVdrpPort()); final Hypervisor hypervisor = v.getHypervisor(); final Machine machine = hypervisor == null ? null : hypervisor.getMachine(); final Rack rack = machine == null ? null : machine.getRack(); final Enterprise enterprise = v.getEnterprise() == null ? null : v.getEnterprise(); final User user = v.getUser() == null ? null : v.getUser(); dto.addLinks(restBuilder.buildVirtualMachineAdminLinks(rack == null ? null : rack .getDatacenter().getId(), rack == null ? null : rack.getId(), machine == null ? null : machine.getId(), enterprise == null ? null : enterprise.getId(), user == null ? null : user.getId(), vdc.getHypervisorType(), null, v.getId())); final VirtualMachineTemplate vmtemplate = v.getVirtualMachineTemplate(); if (vmtemplate.getRepository() != null) { dto.addLink(restBuilder.buildVirtualMachineTemplateLink(vmtemplate.getEnterprise() .getId(), vmtemplate.getRepository().getDatacenter().getId(), vmtemplate.getId())); } else { if (vmtemplate.isStateful()) { // stateful virtual machines (template hasn't got repository) dto.addLink(restBuilder.buildVirtualMachineTemplateLink(vmtemplate.getEnterprise() .getId(), vdc.getDatacenter().getId(), vmtemplate.getId())); } else { // imported virtual machines dto.addLink(restBuilder.buildVirtualMachineTemplateLink(vmtemplate.getEnterprise() .getId(), v.getHypervisor().getMachine().getRack().getDatacenter().getId(), vmtemplate.getId())); } } TaskResourceUtils.addTasksLink(dto, dto.getEditLink()); return dto; } public static VirtualMachineDto createTransferObject(final VirtualMachine v, final VirtualDatacenter vdc, final Integer vappId, final IRESTBuilder restBuilder, final Integer[] volumeIds, final Integer diskIds[], final List<IpPoolManagement> ips) { VirtualMachineDto dto = new VirtualMachineDto(); dto.setUuid(v.getUuid()); dto.setCpu(v.getCpu()); dto.setDescription(v.getDescription()); dto.setHdInBytes(v.getHdInBytes()); dto.setHighDisponibility(v.getHighDisponibility()); dto.setId(v.getId()); dto.setIdState(v.getState().id()); if (v.getIdType() == 0) { dto.setIdType(com.abiquo.server.core.cloud.VirtualMachine.NOT_MANAGED); } else { dto.setIdType(com.abiquo.server.core.cloud.VirtualMachine.MANAGED); } dto.setName(v.getName()); dto.setPassword(v.getPassword()); dto.setRam(v.getRam()); dto.setState(v.getState()); dto.setVdrpIP(v.getVdrpIP()); dto.setVdrpPort(v.getVdrpPort()); final Hypervisor hypervisor = v.getHypervisor(); final Machine machine = hypervisor == null ? null : hypervisor.getMachine(); final Rack rack = machine == null ? null : machine.getRack(); final Enterprise enterprise = v.getEnterprise() == null ? null : v.getEnterprise(); final User user = v.getUser() == null ? null : v.getUser(); dto.addLinks(restBuilder.buildVirtualMachineCloudAdminLinks(vdc.getId(), vappId, v, rack == null ? null : rack.getDatacenter().getId(), rack == null ? null : rack.getId(), machine == null ? null : machine.getId(), enterprise == null ? null : enterprise .getId(), user == null ? null : user.getId(), v.isChefEnabled(), volumeIds, diskIds, ips, vdc.getHypervisorType(), null)); final VirtualMachineTemplate vmtemplate = v.getVirtualMachineTemplate(); if (vmtemplate.getRepository() != null) { dto.addLink(restBuilder.buildVirtualMachineTemplateLink(vmtemplate.getEnterprise() .getId(), vmtemplate.getRepository().getDatacenter().getId(), vmtemplate.getId())); } else { if (vmtemplate.isStateful()) { // stateful virtual machines (template hasn't got repository) dto.addLink(restBuilder.buildVirtualMachineTemplateLink(vmtemplate.getEnterprise() .getId(), vdc.getDatacenter().getId(), vmtemplate.getId())); } else { // imported virtual machines dto.addLink(restBuilder.buildVirtualMachineTemplateLink(vmtemplate.getEnterprise() .getId(), v.getHypervisor().getMachine().getRack().getDatacenter().getId(), vmtemplate.getId())); } } return dto; } /** * Return the virtual machine if exists. * * @title Retrieve a virtual machine with the node * @param vdcId identifier of the virtual datacenter. * @param vappId identifier of the virtual appliance. * @param vmId identifier of the virtual machine * @param restBuilder to build the links * @return the {@link VirtualMachineWithNodeDto} transfer object for the virtual machine with * the node. * @throws Exception */ @GET @Produces(VirtualMachineWithNodeDto.MEDIA_TYPE) public VirtualMachineWithNodeDto getVirtualMachineWithNode( @PathParam(VirtualDatacenterResource.VIRTUAL_DATACENTER) @NotNull @Min(1) final Integer vdcId, @PathParam(VirtualApplianceResource.VIRTUAL_APPLIANCE) @NotNull @Min(1) final Integer vappId, @PathParam(VirtualMachineResource.VIRTUAL_MACHINE) @NotNull @Min(1) final Integer vmId, @Context final IRESTBuilder restBuilder) throws Exception { NodeVirtualImage node = vmService.getNodeVirtualImage(vdcId, vappId, vmId); return createNodeTransferObject(node, vdcId, vappId, restBuilder, getVolumeIds(node .getVirtualMachine()), getDiskIds(node.getVirtualMachine()), node.getVirtualMachine() .getIps()); } /** * Returns all tasks for a machine * * @title Retrive all tasks * @wiki Displays the tasks on the virtual machine. Tasks are a set of jobs (operations on * hypervisors). Any of these tasks may still be in progress. * @param vdcId identifier of the virtual datacenter * @param vappId identifier of the virtual appliance * @param vmId identifier of the virtual machine * @param uriInfo * @return a {TasksDto} with all tasks for the machine * @throws Exception */ @GET @Produces(TasksDto.MEDIA_TYPE) @Path(TaskResourceUtils.TASKS_PATH) public TasksDto getTasks( @PathParam(VirtualDatacenterResource.VIRTUAL_DATACENTER) @NotNull @Min(1) final Integer vdcId, @PathParam(VirtualApplianceResource.VIRTUAL_APPLIANCE) @NotNull @Min(1) final Integer vappId, @PathParam(VirtualMachineResource.VIRTUAL_MACHINE) @NotNull @Min(1) final Integer vmId, @Context final UriInfo uriInfo) throws Exception { vmService.getVirtualMachine(vdcId, vappId, vmId); List<Task> tasks = taskService.findTasks(TaskOwnerType.VIRTUAL_MACHINE, vmId.toString()); return TaskResourceUtils.transform(tasks, uriInfo); } /** * Returns a task for a virtual machine * * @title Retrieve a task * @wiki Displays a specific task on the virtual machine. Tasks are a set of jobs (operations on * hypervisors). Any of these tasks may still be in progress. Every task has a UUID. * @param vdcId identifier of the virtual datacenter * @param vappId identifier of the virtual appliance * @param vmId identifier of the virtual machine * @param taskId identifier of the task * @param uriInfo * @return a {TaksDto} with the task of the machine * @throws Exception */ @GET @Produces(TaskDto.MEDIA_TYPE) @Path(TaskResourceUtils.TASK_PATH) public TaskDto getTask( @PathParam(VirtualDatacenterResource.VIRTUAL_DATACENTER) @NotNull @Min(1) final Integer vdcId, @PathParam(VirtualApplianceResource.VIRTUAL_APPLIANCE) @NotNull @Min(1) final Integer vappId, @PathParam(VirtualMachineResource.VIRTUAL_MACHINE) @NotNull @Min(1) final Integer vmId, @PathParam(TaskResourceUtils.TASK) @NotNull final String taskId, @Context final UriInfo uriInfo) throws Exception { vmService.getVirtualMachine(vdcId, vappId, vmId); if (taskId.equalsIgnoreCase(TaskResourceUtils.UNTRACEABLE_TASK)) { return buildSeeOtherDto(uriInfo); } Task task = taskService.findTask(vmId.toString(), taskId); return TaskResourceUtils.transform(task, uriInfo); } protected Integer[] getVolumeIds(final VirtualMachine vm) { return null; // Community impl } protected Integer[] getDiskIds(final VirtualMachine vm) { return null; // Community impl } /** * Reset a {@link VirtualMachine}. * * @title Reset a virtual machine * @param vdcId VirtualDatacenter id * @param vappId VirtualAppliance id * @param vmId VirtualMachine id * @param restBuilder injected restbuilder context parameter * @return a link where you can keep track of the progress and a message. * @throws Exception */ @POST @Path(VIRTUAL_MACHINE_ACTION_RESET) @Produces(AcceptedRequestDto.MEDIA_TYPE) public AcceptedRequestDto<String> resetVirtualMachine( @PathParam(VirtualDatacenterResource.VIRTUAL_DATACENTER) final Integer vdcId, @PathParam(VirtualApplianceResource.VIRTUAL_APPLIANCE) final Integer vappId, @PathParam(VirtualMachineResource.VIRTUAL_MACHINE) final Integer vmId, @Context final IRESTBuilder restBuilder, @Context final UriInfo uriInfo) throws Exception { VirtualMachineState originalState = vmLock.lockVirtualMachineBeforeResetting(vdcId, vappId, vmId); try { String taskId = vmService.resetVirtualMachine(vmId, vappId, vdcId, VirtualMachineStateTransition.RESET); // If the link is null no Task was performed if (taskId == null) { throw new InternalServerErrorException(APIError.STATUS_INTERNAL_SERVER_ERROR); } return buildAcceptedRequestDtoWithTaskLink(taskId, uriInfo); } catch (Exception ex) { // Make sure virtual machine is unlocked if reset fails vmLock.unlockVirtualMachine(vmId, originalState); throw ex; } } /** * @param taskId * @param uriInfo * @return AcceptedRequestDto<String> */ protected AcceptedRequestDto<String> buildAcceptedRequestDtoWithTaskLink(final String taskId, final UriInfo uriInfo) { // Build task link String link = uriInfo.getRequestUri().toString(); link = link.replaceAll("action.*", ""); link = link.replaceAll("(/)*$", ""); link = link.replaceAll("\\?force=(true|false)", ""); link = link.concat(TaskResourceUtils.TASKS_PATH).concat("/").concat(taskId); // Build AcceptedRequestDto AcceptedRequestDto<String> a202 = new AcceptedRequestDto<String>(); a202.setStatusUrlLink(link); a202.setEntity("You can keep track of the progress in the link"); return a202; } /** * This function expects a uri. With its <b>numerical</b> id as a last segment. The final slash * is optional and additional uri segments as well. If presents all segments after the id will * be deleted. <br> * <br> * <b>This function does not work with UUID as id<br> * <br> * </b> TODO UUID <br> * <br> * <code> * http://example.com/api/cloud/virtualdatacenters/2/virtualappliances/4/virtualmachines/1/state -> http://example.com/api/cloud/virtualdatacenters/2/virtualappliances/4/virtualmachines/1/tasks/taskId <br> * * http://example.com/api/cloud/virtualdatacenters/2/virtualappliances/4/virtualmachines/1 -> http://example.com/api/cloud/virtualdatacenters/2/virtualappliances/4/virtualmachines/1/tasks/taskId <br> * * http://example.com/api/cloud/virtualdatacenters/2/virtualappliances/4/virtualmachines/1/ -> http://example.com/api/cloud/virtualdatacenters/2/virtualappliances/4/virtualmachines/1/tasks/taskId <br> * * http://example.com/api/cloud/virtualdatacenters/2/virtualappliances/4/virtualmachines/1/action/undeploy -> http://example.com/api/cloud/virtualdatacenters/2/virtualappliances/4/virtualmachines/1/tasks/taskId <br> * * http://example.com/api/cloud/virtualdatacenters/2/virtualappliances/4/state -> http://example.com/api/cloud/virtualdatacenters/2/virtualappliances/4/tasks/taskId <br> * * http://example.com/api/cloud/virtualdatacenters/2/virtualappliances/4 -> http://example.com/api/cloud/virtualdatacenters/2/virtualappliances/4/tasks/taskId <br> * * http://example.com/api/cloud/virtualdatacenters/2/virtualappliances/4/ -> http://example.com/api/cloud/virtualdatacenters/2/virtualappliances/4/tasks/taskId <br> * * http://example.com/api/cloud/virtualdatacenters/2/virtualappliances/4/undeploy -> http://example.com/api/cloud/virtualdatacenters/2/virtualappliances//tasks/taskId <br> * * * <b>Even with invalid urls</b> * http://example.com/api/cloud/virtualdatacenters/2/virtualappliances/4/virtualmachines/1j/ -> http://example.com/api/cloud/virtualdatacenters/2/virtualappliances/4/virtualmachines/1/tasks/taskId <br> * <code> * * @param taskId * @param uriInfo * @return AcceptedRequestDto<String> */ protected AcceptedRequestDto<String> buildAcceptedRequestDtoWithTaskLinkNoAction( final String taskId, final UriInfo uriInfo) { // Build task link String link = uriInfo.getRequestUri().toString(); Pattern regex = Pattern.compile("(.*/\\d+)[/]?.*$"); Matcher regexMatcher = regex.matcher(link); if (regexMatcher.find()) { link = regexMatcher.replaceAll(regexMatcher.group(1).concat(TaskResourceUtils.TASKS_PATH) .concat("/").concat(taskId)); } // Build AcceptedRequestDto AcceptedRequestDto<String> a202 = new AcceptedRequestDto<String>(); a202.setStatusUrlLink(link); a202.setEntity("You can keep track of the progress in the link"); return a202; } protected SeeOtherDto buildSeeOtherDto(final UriInfo uriInfo) { // Build state link String link = uriInfo.getRequestUri().toString(); link = TaskResourceUtils.removeTaskSegments(link); link = link.concat("/").concat(VIRTUAL_MACHINE_STATE_PATH); // Build SeeOtherDto return new SeeOtherDto(link); } }