/*
* Copyright (c) 2015 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.db.client.model.util;
import java.net.URI;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.constraint.AggregatedConstraint;
import com.emc.storageos.db.client.constraint.AggregationQueryResultList;
import com.emc.storageos.db.client.constraint.AlternateIdConstraint;
import com.emc.storageos.db.client.constraint.Constraint;
import com.emc.storageos.db.client.constraint.ContainmentConstraint;
import com.emc.storageos.db.client.constraint.NamedElementQueryResultList;
import com.emc.storageos.db.client.constraint.URIQueryResultList;
import com.emc.storageos.db.client.model.DataObject;
import com.emc.storageos.db.client.model.NamedURI;
import com.emc.storageos.db.client.model.Operation;
import com.emc.storageos.db.client.model.Task;
import com.google.common.collect.Lists;
public class TaskUtils {
public static Task findTaskForRequestId(DbClient dbClient, URI resourceId, String requestId) {
URIQueryResultList results = new URIQueryResultList();
dbClient.queryByConstraint(AlternateIdConstraint.Factory.getTasksByRequestIdConstraint(requestId), results);
Iterator<URI> it = results.iterator();
while (it.hasNext()) {
Task task = dbClient.queryObject(Task.class, it.next());
if (task.getResource().getURI().equals(resourceId)) {
return task;
}
}
return null;
}
public static Task findTaskForRequestIdAssociatedResource(DbClient dbClient, URI resourceId, String requestId) {
URIQueryResultList results = new URIQueryResultList();
dbClient.queryByConstraint(AlternateIdConstraint.Factory.getTasksByRequestIdConstraint(requestId), results);
Iterator<URI> it = results.iterator();
while (it.hasNext()) {
Task task = dbClient.queryObject(Task.class, it.next());
if (task.getAssociatedResourcesList().contains(resourceId)) {
return task;
}
}
return null;
}
public static List<Task> findTasksForRequestId(DbClient dbClient, String requestId) {
URIQueryResultList results = new URIQueryResultList();
dbClient.queryByConstraint(AlternateIdConstraint.Factory.getTasksByRequestIdConstraint(requestId), results);
List<Task> tasks = Lists.newArrayList();
Iterator<URI> it = results.iterator();
while (it.hasNext()) {
Task task = dbClient.queryObject(Task.class, it.next());
tasks.add(task);
}
return tasks;
}
public static List<Task> findResourceTasks(DbClient dbClient, URI resourceId) {
return getTasks(dbClient, ContainmentConstraint.Factory.getResourceTaskConstraint(resourceId));
}
/**
* cleans up all pending tasks for a resource and task type
*
* @param dbClient
* @param resourceId resource id
* @param taskName the task name to match task.getLabel()
* @param tenantId tenant that owns the resource
*/
public static void cleanupPendingTasks(DbClient dbClient, URI resourceId, String taskName, URI tenantId) {
cleanupPendingTasks(dbClient, resourceId, taskName, tenantId, null);
}
/**
* cleans up pending tasks for a resource and task type older than a specified time
* @param dbClient
* @param resourceId resource id
* @param taskName the task name to match task.getLabel()
* @param tenantId tenant that owns the resource
* @param olderThan tasks started before this will be cleared
*/
public static void cleanupPendingTasks(DbClient dbClient, URI resourceId, String taskName, URI tenantId, Calendar olderThan) {
Iterator<Task> pendingTasks = TaskUtils.findPendingTasksForResource(dbClient, resourceId, tenantId);
while (pendingTasks.hasNext()) {
Task task = pendingTasks.next();
if (task.getLabel().equals(taskName) && (olderThan == null || task.getStartTime().before(olderThan))) {
task.setProgress(100);
task.setEndTime(Calendar.getInstance());
task.setStatus(Task.Status.error.toString());
task.setMessage("Setting orphaned task to error state");
dbClient.updateObject(task);
}
}
}
/**
* returns pending tasks for a resource
*
* @param dbClient
* @param resourceId
* @return
*/
public static Iterator<Task> findPendingTasksForResource(DbClient dbClient, URI resourceId, URI tenantId) {
Constraint constraint = AggregatedConstraint.Factory.getAggregationConstraint(Task.class, "tenant",
tenantId.toString(), "taskStatus");
AggregationQueryResultList queryResults = new AggregationQueryResultList();
dbClient.queryByConstraint(constraint, queryResults);
Iterator<AggregationQueryResultList.AggregatedEntry> it = queryResults.iterator();
List<URI> pendingTasks = new ArrayList<URI>();
while (it.hasNext()) {
AggregationQueryResultList.AggregatedEntry entry = it.next();
if (entry.getValue().equals(Task.Status.pending.name())) {
pendingTasks.add(entry.getId());
}
}
List<Task> pendingTasksForResource = new ArrayList<Task>();
Iterator<Task> pendingItr = dbClient.queryIterativeObjects(Task.class, pendingTasks);
while (pendingItr.hasNext()) {
Task task = pendingItr.next();
if (task.getResource().getURI().equals(resourceId)) {
pendingTasksForResource.add(task);
}
}
return pendingTasksForResource.iterator();
}
public static List<NamedURI> findResourceTaskIds(DbClient dbClient, URI resourceId) {
NamedElementQueryResultList results = new NamedElementQueryResultList();
dbClient.queryByConstraint(ContainmentConstraint.Factory.getResourceTaskConstraint(resourceId), results);
List<NamedURI> uris = Lists.newArrayList();
Iterator<NamedElementQueryResultList.NamedElement> it = results.iterator();
while (it.hasNext()) {
NamedElementQueryResultList.NamedElement element = it.next();
uris.add(new NamedURI(element.getId(), element.getName()));
}
return uris;
}
/**
* This method will find all tasks associated with a tenant.
* NOTE: This method does NOT work well to scale if a single tenant is performing many
* thousands of operations. Consider other constraint criteria depending on your needs.
*
* @param dbClient
* db client
* @param tenantId
* tenant URI
* @return list of Task objects associated with that tenant
*/
public static ObjectQueryResult<Task> findTenantTasks(DbClient dbClient, URI tenantId) {
ContainmentConstraint constraint = ContainmentConstraint.Factory.getTenantOrgTaskConstraint(tenantId);
ObjectQueryResult<Task> queryResult = new ObjectQueryResult(dbClient, constraint);
queryResult.executeQuery();
return queryResult;
}
public static Operation createOperation(Task task) {
Operation op = new Operation();
// Operation is backed by Hashtable. Need to check for null values since Hashtable does not allow null values.
if (task.getLabel() != null) {
op.setName(task.getLabel());
}
if (task.getDescription() != null) {
op.setDescription(task.getDescription());
}
if (task.getMessage() != null) {
op.setMessage(task.getMessage());
}
if (task.getServiceCode() != null) {
op.setServiceCode(task.getServiceCode());
}
if (task.getAssociatedResources() != null) {
op.setAssociatedResourcesField(task.getAssociatedResources());
}
if (task.getProgress() != null) {
op.setProgress(task.getProgress());
}
if (task.getStartTime() != null) {
op.setStartTime(task.getStartTime());
}
if (task.getEndTime() != null) {
op.setEndTime(task.getEndTime());
}
if (task.getStatus() != null) {
op.setStatus(task.getStatus());
}
return op;
}
private static List<Task> getTasks(DbClient dbClient, Constraint constraint) {
URIQueryResultList results = new URIQueryResultList();
dbClient.queryByConstraint(constraint, results);
List<Task> tasks = Lists.newArrayList();
Iterator<URI> it = results.iterator();
while (it.hasNext()) {
Task task = dbClient.queryObject(Task.class, it.next());
if (task != null) {
tasks.add(task);
}
}
return tasks;
}
/** An efficient way of querying for Task objects based on the result of an index query */
public static class ObjectQueryResult<T extends DataObject> implements Iterator<T> {
private final ContainmentConstraint constraint;
private final DbClient dbClient;
private Iterator<URI> iterator;
public ObjectQueryResult(DbClient dbClient, ContainmentConstraint constraint) {
this.dbClient = dbClient;
this.constraint = constraint;
}
public void executeQuery() {
if (iterator != null) {
throw new IllegalStateException("Execute can only be called once!");
}
URIQueryResultList results = new URIQueryResultList();
dbClient.queryByConstraint(constraint, results);
this.iterator = results.iterator();
}
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public T next() {
return (T) dbClient.queryObject(iterator.next());
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
}