/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package com.emc.storageos.api.service.impl.resource; import java.net.URI; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutorService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.model.ExportGroup; import com.emc.storageos.db.client.model.ExportPathParams; import com.emc.storageos.db.client.model.Project; import com.emc.storageos.db.client.model.VirtualArray; import com.emc.storageos.model.TaskResourceRep; import com.emc.storageos.model.block.export.ExportPathParameters; import com.emc.storageos.security.authorization.Role; import com.emc.storageos.svcs.errorhandling.model.ServiceCoded; import com.emc.storageos.svcs.errorhandling.resources.APIException; import com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException; import com.emc.storageos.volumecontroller.BlockExportController; /** * Background thread that runs the placement, scheduling, and controller dispatching of an export group creation * request. This allows the API to return a Task object quickly. */ class CreateExportGroupSchedulingThread implements Runnable { static final Logger _log = LoggerFactory.getLogger(CreateExportGroupSchedulingThread.class); private final ExportGroupService exportGroupService; private VirtualArray virtualArray; private Project project; private ExportGroup exportGroup; // Map of <storagesystem-id, Map<volume-id, HLU>> private Map<URI, Map<URI, Integer>> storageMap; private List<URI> hosts; private List<URI> clusters; private List<URI> initiators; private Map<URI, Integer> volumeMap; private String task; private TaskResourceRep taskRes; private ExportPathParameters pathParam; public CreateExportGroupSchedulingThread(ExportGroupService exportGroupService, VirtualArray virtualArray, Project project, ExportGroup exportGroup, Map<URI, Map<URI, Integer>> storageMap, List<URI> clusters, List<URI> hosts, List<URI> initiators, Map<URI, Integer> volumeMap, ExportPathParameters pathParam, String task, TaskResourceRep taskRes) { this.exportGroupService = exportGroupService; this.virtualArray = virtualArray; this.project = project; this.exportGroup = exportGroup; this.storageMap = storageMap; this.clusters = clusters; this.hosts = hosts; this.initiators = initiators; this.volumeMap = volumeMap; this.task = task; this.taskRes = taskRes; this.pathParam = pathParam; } @Override public void run() { _log.info("Starting scheduling for export group create thread..."); // Call out placementManager to get the recommendation for placement. try { // validate clients (initiators, hosts clusters) input and package them // This call may take a long time. List<URI> affectedInitiators = this.exportGroupService.validateClientsAndPopulate(exportGroup, project, virtualArray, storageMap.keySet(), clusters, hosts, initiators, volumeMap.keySet(), pathParam); _log.info("Initiators {} will be used.", affectedInitiators); // If ExportPathParameter block is present, and volumes are present, capture those arguments. if (pathParam!= null && !volumeMap.keySet().isEmpty()) { ExportPathParams exportPathParam = exportGroupService.validateAndCreateExportPathParam(pathParam, exportGroup, volumeMap.keySet()); exportGroupService.addBlockObjectsToPathParamMap(volumeMap.keySet(), exportPathParam.getId(), exportGroup); exportGroupService._dbClient.createObject(exportPathParam); } this.exportGroupService._dbClient.persistObject(exportGroup); // If initiators list is empty or storage map is empty, there's no work to do (yet). if (storageMap.isEmpty() || affectedInitiators.isEmpty()) { this.exportGroupService._dbClient.ready(ExportGroup.class, taskRes.getResource().getId(), taskRes.getOpId()); return; } // push it to storage devices BlockExportController exportController = this.exportGroupService.getExportController(); _log.info("createExportGroup request is submitted."); exportController.exportGroupCreate(exportGroup.getId(), volumeMap, affectedInitiators, task); } catch (Exception ex) { if (ex instanceof ServiceCoded) { this.exportGroupService._dbClient.error(ExportGroup.class, taskRes.getResource().getId(), taskRes.getOpId(), (ServiceCoded) ex); } else { this.exportGroupService._dbClient.error(ExportGroup.class, taskRes.getResource().getId(), taskRes.getOpId(), InternalServerErrorException.internalServerErrors .unexpectedErrorExportGroupPlacement(ex)); } _log.error(ex.getMessage(), ex); taskRes.setMessage(ex.getMessage()); // Mark the export group to be deleted this.exportGroupService._dbClient.markForDeletion(exportGroup); } _log.info("Ending export group create scheduling thread..."); } /** * Static method to kick off the execution of the API level task to create an export group. * * @param exportGroupService export group service ("this" from caller) * @param executorService executor service for bounded thread pooling management * @param dbClient dbclient * @param virtualArray virtual array * @param project project * @param exportGroup export group * @param storageMap storage map * @param clusters clusters * @param hosts hosts * @param initiators initiators * @param volumeMap volume map * @param pathParam ExportPathParameters from * @param task task * @param taskRes task resource object */ public static void executeApiTask(ExportGroupService exportGroupService, ExecutorService executorService, DbClient dbClient, VirtualArray virtualArray, Project project, ExportGroup exportGroup, Map<URI, Map<URI, Integer>> storageMap, List<URI> clusters, List<URI> hosts, List<URI> initiators, Map<URI, Integer> volumeMap, ExportPathParameters pathParam, String task, TaskResourceRep taskRes) { CreateExportGroupSchedulingThread schedulingThread = new CreateExportGroupSchedulingThread(exportGroupService, virtualArray, project, exportGroup, storageMap, clusters, hosts, initiators, volumeMap, pathParam, task, taskRes); try { executorService.execute(schedulingThread); } catch (Exception e) { String message = "Failed to execute export group creation API task for resource " + exportGroup.getId(); _log.error(message); taskRes.setMessage(message); // Set the export group to inactive exportGroup.setInactive(true); dbClient.updateAndReindexObject(exportGroup); } } }