/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package com.emc.storageos.api.mapper; import static com.emc.storageos.api.mapper.DbObjectMapper.mapDataObjectFields; import static com.emc.storageos.api.mapper.DbObjectMapper.toNamedRelatedResource; import static com.emc.storageos.api.mapper.DbObjectMapper.toRelatedResource; import static com.emc.storageos.svcs.errorhandling.resources.ServiceCode.toServiceCode; import static com.emc.storageos.svcs.errorhandling.resources.ServiceErrorFactory.toServiceErrorRestRep; import java.net.URI; import java.util.ArrayList; import java.util.List; import java.util.Set; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.model.DataObject; import com.emc.storageos.db.client.model.Operation; import com.emc.storageos.db.client.model.Task; import com.emc.storageos.db.client.model.TenantOrg; import com.emc.storageos.db.client.model.Workflow; import com.emc.storageos.db.client.model.util.TaskUtils; import com.emc.storageos.db.client.util.NullColumnValueGetter; import com.emc.storageos.model.NamedRelatedResourceRep; import com.emc.storageos.model.ResourceTypeEnum; import com.emc.storageos.model.TaskList; import com.emc.storageos.model.TaskResourceRep; import com.emc.storageos.svcs.errorhandling.resources.APIException; import com.google.common.collect.Lists; public class TaskMapper { private static Logger log = LoggerFactory.getLogger(TaskMapper.class); private static TaskMapperConfig configInstance = null; public static class TaskMapperConfig { private DbClient dbClient; public TaskMapperConfig() { } public DbClient getDbClient() { return dbClient; } public void setDbClient(DbClient dbClient) { this.dbClient = dbClient; } @PostConstruct public void setupStatic() { if (TaskMapper.configInstance != null) { log.warn("Updating TaskMapper configuration static when one is already set"); } TaskMapper.configInstance = this; } @PreDestroy public void destroyStatic() { TaskMapper.configInstance = null; } } private static TaskMapperConfig getConfig() { if (configInstance == null) { throw new RuntimeException("TaskMapperConfiguration instance has not been set"); } return configInstance; } public static TaskResourceRep toTask(DataObject resource, String taskId) { if (resource.getOpStatus() == null) { throw APIException.badRequests.requiredParameterMissingOrEmpty("status"); } Operation op = resource.getOpStatus().get(taskId); if (op == null) { throw APIException.badRequests.invalidParameterNoOperationForTaskId(taskId); } return toTask(resource, taskId, op); } public static TaskResourceRep toTask(Task task) { TaskResourceRep taskResourceRep = new TaskResourceRep(); mapDataObjectFields(task, taskResourceRep); taskResourceRep.setId(task.getId()); taskResourceRep.setResource(toNamedRelatedResource(task.getResource())); // Check to see if there are any associated resources List<NamedRelatedResourceRep> associatedRefs = Lists.newArrayList(); for (URI assocId : task.getAssociatedResourcesList()) { DataObject associatedObject = getConfig().getDbClient().queryObject(assocId); if (associatedObject != null) { associatedRefs.add(toNamedRelatedResource(associatedObject)); } else { log.warn(String.format("For task %s could not find associated object %s", task.getId(), assocId)); } } taskResourceRep.setAssociatedResources(associatedRefs); if (!StringUtils.isBlank(task.getRequestId())) { taskResourceRep.setOpId(task.getRequestId()); } if (task.getWorkflow() != null) { taskResourceRep.setWorkflow(toRelatedResource(ResourceTypeEnum.WORKFLOW, task.getWorkflow())); } if (!task.getTenant().equals(TenantOrg.SYSTEM_TENANT)) { taskResourceRep.setTenant(DbObjectMapper.toRelatedResource(ResourceTypeEnum.TENANT, task.getTenant())); } // Operation taskResourceRep.setState(task.getStatus()); if (task.getServiceCode() != null) { taskResourceRep.setServiceError(toServiceErrorRestRep(toServiceCode(task.getServiceCode()), task.getMessage())); } else { taskResourceRep.setMessage(task.getMessage()); if (!task.getWarningMessages().isEmpty()) { taskResourceRep.setWarningMessages(new ArrayList<String>(task.getWarningMessages())); } } taskResourceRep.setDescription(task.getDescription()); // COP-23486 // // This is a workaround to migration post-commit delete source volumes. We would like to be able to // mark this Task as one that cannot be rolled back, however at the time there is no framework to // detect the state of not being able to rollback, so we will catch this specific situation from the // message so we can "flip the flag" of allowable operations by the UI. taskResourceRep.setAllowedOperations(Task.AllowedOperations.none_specified.name()); if (task.getWorkflow() != null) { Workflow wf = configInstance.getDbClient().queryObject(Workflow.class, task.getWorkflow()); if (wf != null && NullColumnValueGetter.isNotNullValue(wf.getCompletionMessage()) && wf.getCompletionMessage().contains("post-migration delete of original source backing volumes")) { taskResourceRep.setAllowedOperations(Task.AllowedOperations.retry_only.name()); } } taskResourceRep.setStartTime(task.getStartTime()); taskResourceRep.setEndTime(task.getEndTime()); taskResourceRep.setProgress(task.getProgress() != null ? task.getProgress() : 0); taskResourceRep.setQueuedStartTime(task.getQueuedStartTime()); taskResourceRep.setQueueName(task.getQueueName()); return taskResourceRep; } /** * Generate a task that is a complete state. This could be used for cases where the operation * does not need to go the controller. That is, it's completed within in the API layer. * * @param resource * [in] - DataObject, ViPR model object * @param taskId * [in] - String task identifier * @param operation * [in] - Operation * @return TaskResourceRep representing a Task that is completed. */ public static TaskResourceRep toCompletedTask(DataObject resource, String taskId, Operation operation) { Task task = operation.getTask(resource.getId()); if (task != null) { task.setProgress(100); task.setStatus(Operation.Status.ready.name()); getConfig().getDbClient().persistObject(task); return toTask(task); } else { // It wasn't recently serialized, so fallback to looking for the task in the DB task = TaskUtils.findTaskForRequestId(getConfig().getDbClient(), resource.getId(), taskId); if (task != null) { task.setProgress(100); task.setStatus(Operation.Status.ready.name()); getConfig().getDbClient().persistObject(task); return toTask(task); } else { throw new IllegalStateException(String.format( "Task not found for resource %s, op %s in either the operation or the database", resource.getId(), taskId)); } } } public static TaskResourceRep toTask(DataObject resource, String taskId, Operation operation) { // If the Operation has been serialized in this request, then it should have the corresponding task embedded in // it Task task = operation.getTask(resource.getId()); if (task != null) { return toTask(task); } else { // It wasn't recently serialized, so fallback to looking for the task in the DB task = TaskUtils.findTaskForRequestId(getConfig().getDbClient(), resource.getId(), taskId); if (task != null) { return toTask(task); } else { throw new IllegalStateException(String.format( "Task not found for resource %s, op %s in either the operation or the database", resource.getId(), taskId)); } } } public static TaskResourceRep toTask(DataObject resource, List<? extends DataObject> assocResources, String taskId, Operation operation) { TaskResourceRep task = toTask(resource, taskId, operation); List<NamedRelatedResourceRep> associatedReps = new ArrayList<NamedRelatedResourceRep>(); for (DataObject assoc : assocResources) { associatedReps.add(toNamedRelatedResource(assoc)); } task.setAssociatedResources(associatedReps); return task; } public static TaskList toTaskList(DataObject resource) { TaskList list = new TaskList(); if (resource.getOpStatus() != null) { Set<String> task_set = resource.getOpStatus().keySet(); for (String task : task_set) { list.getTaskList().add(toTask(resource, task)); } } return list; } public static TaskList toTaskList(List<Task> tasks) { TaskList taskList = new TaskList(); for (Task task : tasks) { taskList.addTask(toTask(task)); } return taskList; } }