/** * 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.tasks.util; import java.security.InvalidParameterException; import java.util.Map; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.WordUtils; import com.abiquo.commons.amqp.impl.tarantino.domain.DiskSnapshot; import com.abiquo.commons.amqp.impl.tarantino.domain.HypervisorConnection; import com.abiquo.commons.amqp.impl.tarantino.domain.StateTransition; import com.abiquo.commons.amqp.impl.tarantino.domain.VirtualMachineDefinition; import com.abiquo.commons.amqp.impl.tarantino.domain.dto.DatacenterTasks; import com.abiquo.commons.amqp.impl.tarantino.domain.operations.ApplyVirtualMachineStateOp; import com.abiquo.commons.amqp.impl.tarantino.domain.operations.ReconfigureVirtualMachineOp; import com.abiquo.commons.amqp.impl.tarantino.domain.operations.RefreshVirtualMachineResourcesOp; import com.abiquo.commons.amqp.impl.tarantino.domain.operations.SnapshotVirtualMachineOp; import com.abiquo.server.core.cloud.VirtualMachineStateTransition; import com.abiquo.server.core.task.Job; import com.abiquo.server.core.task.Job.JobType; import com.abiquo.server.core.task.Task; import com.abiquo.server.core.task.enums.TaskType; /** * Builder with a fluent interface to simplify the creation of {@link DatacenterTasks} and * {@link Task}. * * @author serafin.sedano@abiquo.com * @author enric.ruiz@abiquo.com */ public class DatacenterTaskBuilder { protected VirtualMachineDefinition definition; protected HypervisorConnection hypervisor; protected Task asyncTask; protected DatacenterTasks tarantinoTask; public DatacenterTaskBuilder(final VirtualMachineDefinition definition, final HypervisorConnection hypervisor, final String userId) { init(definition, hypervisor, userId); } public DatacenterTaskBuilder(final String userId) { init(null, null, userId); } /** * Initializes and reset the builder. * * @param definition {@link VirtualMachineDefinition} to use * @param hypervisor {@link HypervisorConnection} to use * @return The {@link DatacenterTaskBuilder} self */ public DatacenterTaskBuilder init(final VirtualMachineDefinition definition, final HypervisorConnection hypervisor, final String userId) { this.tarantinoTask = new DatacenterTasks(); this.tarantinoTask.setDependent(Boolean.TRUE); this.asyncTask = new Task(); this.asyncTask.setTaskId(this.tarantinoTask.getId()); this.asyncTask.setUserId(userId); this.definition = definition; this.hypervisor = hypervisor; return this; } /** * End builder-method to get the {@link DatacenterTasks} for Tarantino. * * @return The {@link DatacenterTasks} for Tarantino */ public DatacenterTasks buildTarantinoTask() { return this.tarantinoTask; } /** * End builder-method to get the {@link Task} for Redis persistence. * * @return The {@link Task} for Redis persistence */ public Task buildAsyncTask(final String ownerId, final TaskType taskType) { if (StringUtils.isBlank(ownerId) || taskType == null) { throw new InvalidParameterException(); } this.asyncTask.setOwnerId(ownerId); this.asyncTask.setType(taskType); for (Job job : this.asyncTask.getJobs()) { String jobName = format(job.getType().name(), false); String taskName = format(this.asyncTask.getType().name(), true); String ownerName = format(this.asyncTask.getType().getOwnerType().name(), false); job.setDescription(String.format("%s task's %s on %s with id %s", taskName, jobName, ownerName, ownerId)); } return this.asyncTask; } private String format(final String name, final boolean capitalize) { String formatted = name.toLowerCase(); if (capitalize) { formatted = WordUtils.capitalize(formatted); } return formatted.replace("_", " "); } /** * Add new {@link VirtualMachineStateTransition}. This method must be used to add transitions * that only needs {@link VirtualMachineDefinition} and {@link HypervisorConnection} to be * created. * * @param transition The transition type to create * @return The {@link DatacenterTaskBuilder} self */ public DatacenterTaskBuilder add(final VirtualMachineStateTransition transition) { return add(this.definition, this.hypervisor, transition, null); } /** * Add new {@link VirtualMachineStateTransition}. This method must be used to add transitions * that only needs {@link VirtualMachineDefinition} and {@link HypervisorConnection} to be * created. * * @param transition The transition type to create * @param extraData map with extra data to add to the job. * @return The {@link DatacenterTaskBuilder} self */ public DatacenterTaskBuilder add(final VirtualMachineStateTransition transition, final Map<String, String> extraData) { return add(this.definition, this.hypervisor, transition, extraData); } /** * Add new {@link VirtualMachineStateTransition}. This method must be used to add transitions * that only needs {@link VirtualMachineDefinition} and {@link HypervisorConnection} to be * created. * * @param transition The transition type to create * @param extraData map to add to the job. * @return The {@link DatacenterTaskBuilder} self */ protected DatacenterTaskBuilder add(final VirtualMachineDefinition definition, final HypervisorConnection hypervisor, final VirtualMachineStateTransition transition, final Map<String, String> extraData) { switch (transition) { case PAUSE: case POWEROFF: case POWERON: case RESET: case RESUME: case CONFIGURE: case DECONFIGURE: ApplyVirtualMachineStateOp job = new ApplyVirtualMachineStateOp(); job.setVirtualMachine(definition); job.setHypervisorConnection(hypervisor); job.setTransaction(toCommonsTransition(transition)); this.tarantinoTask.addDatacenterJob(job); Job redisJob = createRedisJob(job.getId(), this.getTaskTypeFromTransition(transition)); if (extraData != null) { redisJob.getData().putAll(extraData); } this.asyncTask.getJobs().add(redisJob); break; case ALLOCATE: case DEALLOCATE: case SNAPSHOT: case RECONFIGURE: throw new InvalidParameterException(); } return this; } /** * Adds a new {@link ReconfigureVirtualMachineOp} to the Jobs collection. * * @param newDefinition The virtualmachine redefinition * @return The {@link DatacenterTaskBuilder} self */ public DatacenterTaskBuilder addReconfigure(final VirtualMachineDefinition newDefinition) { ReconfigureVirtualMachineOp job = new ReconfigureVirtualMachineOp(); job.setVirtualMachine(definition); job.setHypervisorConnection(hypervisor); job.setNewVirtualMachine(newDefinition); this.tarantinoTask.addDatacenterJob(job); this.asyncTask.getJobs().add(createRedisJob(job.getId(), JobType.RECONFIGURE)); return this; } /** * Adds a new {@link SnapshotVirtualMachineOp} to the Jobs collection. * * @param destinationDisk The destination disk for the snapshot * @return The {@link DatacenterTaskBuilder} self */ public DatacenterTaskBuilder addSnapshot(final DiskSnapshot destinationDisk) { SnapshotVirtualMachineOp job = new SnapshotVirtualMachineOp(); job.setVirtualMachine(definition); job.setHypervisorConnection(hypervisor); job.setDiskSnapshot(destinationDisk); this.tarantinoTask.addDatacenterJob(job); Job redisJob = createRedisJob(job.getId(), JobType.SNAPSHOT); redisJob.getData().put("name", destinationDisk.getName()); redisJob.getData().put("path", FilenameUtils.concat(destinationDisk.getPath(), destinationDisk.getSnapshotFilename())); this.asyncTask.getJobs().add(redisJob); return this; } /** * Adds a new {@link SnapshotVirtualMachineOp} to the Jobs collection. * * @param destinationDisk The destination disk for the snapshot * @return The {@link DatacenterTaskBuilder} self */ public DatacenterTaskBuilder addRefreshResources() { RefreshVirtualMachineResourcesOp job = new RefreshVirtualMachineResourcesOp(); job.setVirtualMachine(definition); job.setHypervisorConnection(hypervisor); this.tarantinoTask.addDatacenterJob(job); this.asyncTask.getJobs().add(createRedisJob(job.getId(), JobType.REFRESH)); return this; } /** * Encapsulates the {@link Job} creation. * * @param jobId The job ID to set * @param jobType The job type * @return A new instance of {@link Job} */ protected Job createRedisJob(final String jobId, final JobType jobType) { Job job = new Job(); job.setId(jobId); job.setParentTaskId(this.asyncTask.getTaskId()); job.setType(jobType); return job; } /** * Translate a {@link VirtualMachineStateTransition} to {@link StateTransition} * * @param transition The transition to translate * @return The {@link StateTransition} translation */ protected StateTransition toCommonsTransition(final VirtualMachineStateTransition transition) { switch (transition) { case ALLOCATE: return StateTransition.ALLOCATE; case CONFIGURE: return StateTransition.CONFIGURE; case DEALLOCATE: return StateTransition.DEALLOCATE; case DECONFIGURE: return StateTransition.DECONFIGURE; case PAUSE: return StateTransition.PAUSE; case POWEROFF: return StateTransition.POWEROFF; case POWERON: return StateTransition.POWERON; case RECONFIGURE: return StateTransition.RECONFIGURE; case RESET: return StateTransition.RESET; case RESUME: return StateTransition.RESUME; case SNAPSHOT: return StateTransition.SNAPSHOT; default: throw new InvalidParameterException("Error unknown transition: " + transition); } } /** * Return the {@link JobType} that is related to this {@link VirtualMachineStateTransition}. <br> * <br> * Null if empty. * * @param machineStateTransition the current. * @return JobType */ public JobType getTaskTypeFromTransition( final VirtualMachineStateTransition machineStateTransition) { switch (machineStateTransition) { case CONFIGURE: { return JobType.CONFIGURE; } case DECONFIGURE: { return JobType.DECONFIGURE; } case POWEROFF: { return JobType.POWER_OFF; } case POWERON: { return JobType.POWER_ON; } case PAUSE: { return JobType.PAUSE; } case RESUME: { return JobType.RESET; } case SNAPSHOT: { return JobType.SNAPSHOT; } case RECONFIGURE: { return JobType.RECONFIGURE; } case RESET: { return JobType.RESET; } default: { throw new InvalidParameterException("Error unknown transition: " + machineStateTransition); } } } }