/* * Copyright (c) 2008-2016 EMC Corporation * All Rights Reserved */ package com.emc.storageos.api.service.impl.resource.blockingestorchestration; import java.net.URI; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutorService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.api.service.impl.resource.UnManagedVolumeService; import com.emc.storageos.api.service.impl.resource.blockingestorchestration.context.VolumeIngestionContext; import com.emc.storageos.api.service.impl.resource.blockingestorchestration.context.impl.BaseIngestionRequestContext; import com.emc.storageos.api.service.impl.resource.utils.VolumeIngestionUtil; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.model.BlockObject; import com.emc.storageos.db.client.model.DataObject; import com.emc.storageos.db.client.model.DataObject.Flag; import com.emc.storageos.db.client.model.Operation.Status; import com.emc.storageos.db.client.model.Volume; import com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedVolume; import com.emc.storageos.db.client.util.ExceptionUtils; import com.emc.storageos.model.TaskList; import com.emc.storageos.model.TaskResourceRep; import com.emc.storageos.svcs.errorhandling.resources.APIException; import com.emc.storageos.svcs.errorhandling.resources.InternalException; public class IngestVolumesUnexportedSchedulingThread implements Runnable { private static final Logger _logger = LoggerFactory.getLogger(IngestVolumesUnexportedSchedulingThread.class); private final BaseIngestionRequestContext _requestContext; private final IngestStrategyFactory _ingestStrategyFactory; private final UnManagedVolumeService _unManagedVolumeService; private final DbClient _dbClient; private final Map<String, String> _taskMap; private static final String INGESTION_SUCCESSFUL_MSG = "Successfully ingested volume."; /** * Constructor. * * @param requestContext the BaseIngestionRequestContext * @param ingestStrategyFactory the IngestStrategyFactory * @param unManagedVolumeService the UnManagedVolumeService * @param dbClient the database client * @param taskMap a Map of UnManagedVolume ids to task ids */ public IngestVolumesUnexportedSchedulingThread(BaseIngestionRequestContext requestContext, IngestStrategyFactory ingestStrategyFactory, UnManagedVolumeService unManagedVolumeService, DbClient dbClient, Map<String, String> taskMap) { this._requestContext = requestContext; this._ingestStrategyFactory = ingestStrategyFactory; this._unManagedVolumeService = unManagedVolumeService; this._dbClient = dbClient; this._taskMap = taskMap; } @Override public void run() { _requestContext.reset(); while (_requestContext.hasNext()) { UnManagedVolume unManagedVolume = _requestContext.next(); String taskId = _taskMap.get(unManagedVolume.getId().toString()); try { _logger.info("Ingestion starting for unmanaged volume {}", unManagedVolume.getNativeGuid()); List<URI> volList = new ArrayList<URI>(); volList.add(_requestContext.getCurrentUnManagedVolumeUri()); VolumeIngestionUtil.checkIngestionRequestValidForUnManagedVolumes(volList, _requestContext.getVpool(unManagedVolume), _dbClient); IngestStrategy ingestStrategy = _ingestStrategyFactory.buildIngestStrategy(unManagedVolume, !IngestStrategyFactory.DISREGARD_PROTECTION); @SuppressWarnings("unchecked") BlockObject blockObject = ingestStrategy.ingestBlockObjects(_requestContext, VolumeIngestionUtil.getBlockObjectClass(unManagedVolume)); if (null == blockObject) { throw IngestionException.exceptions.generalVolumeException( unManagedVolume.getLabel(), "check the logs for more details"); } _logger.info("Ingestion completed successfully for unmanaged volume {}", unManagedVolume.getNativeGuid()); _requestContext.getBlockObjectsToBeCreatedMap().put(blockObject.getNativeGuid(), blockObject); _requestContext.getProcessedUnManagedVolumeMap().put( unManagedVolume.getNativeGuid(), _requestContext.getVolumeContext()); } catch (APIException ex) { _logger.error("APIException occurred", ex); _dbClient.error(UnManagedVolume.class, _requestContext.getCurrentUnManagedVolumeUri(), taskId, ex); _requestContext.getVolumeContext().rollback(); } catch (Exception ex) { _logger.error("Exception occurred", ex); _dbClient.error(UnManagedVolume.class, _requestContext.getCurrentUnManagedVolumeUri(), taskId, IngestionException.exceptions.generalVolumeException( unManagedVolume.getLabel(), ex.getLocalizedMessage())); _requestContext.getVolumeContext().rollback(); } } try { // update the task status for (String unManagedVolumeGUID : _requestContext.getProcessedUnManagedVolumeMap().keySet()) { VolumeIngestionContext volumeContext = _requestContext.getProcessedUnManagedVolumeMap().get(unManagedVolumeGUID); UnManagedVolume unManagedVolume = volumeContext.getUnmanagedVolume();String taskMessage = ""; String taskId = _taskMap.get(unManagedVolume.getId().toString()); boolean ingestedSuccessfully = false; if (unManagedVolume.getInactive()) { ingestedSuccessfully = true; taskMessage = INGESTION_SUCCESSFUL_MSG; } else { // check in the created objects for corresponding block object without any internal flags set BlockObject createdObject = _requestContext.findCreatedBlockObject(unManagedVolumeGUID.replace( VolumeIngestionUtil.UNMANAGEDVOLUME, VolumeIngestionUtil.VOLUME)); _logger.info("checking partial ingestion status of block object " + createdObject); if ((null != createdObject) && (!createdObject.checkInternalFlags(Flag.PARTIALLY_INGESTED) || // If this is an ingested RP volume in an uningested protection set, the ingest is successful. (createdObject instanceof Volume && ((Volume) createdObject).checkForRp() && ((Volume) createdObject) .getProtectionSet() == null)) || // If this is a successfully processed VPLEX backend volume, it will have the INTERNAL_OBJECT Flag (VolumeIngestionUtil.isVplexBackendVolume(unManagedVolume) && createdObject .checkInternalFlags(Flag.INTERNAL_OBJECT))) { _logger.info("successfully partially ingested block object {} ", createdObject.forDisplay()); ingestedSuccessfully = true; taskMessage = INGESTION_SUCCESSFUL_MSG; } else { _logger.info("block object {} was not (partially) ingested successfully", createdObject); ingestedSuccessfully = false; StringBuffer taskStatus = _requestContext.getTaskStatusMap().get(unManagedVolume.getNativeGuid()); if (taskStatus == null) { // No task status found. Put in a default message. taskMessage = String.format("Not all the parent/replicas of unmanaged volume %s have been ingested", unManagedVolume.getLabel()); } else { taskMessage = taskStatus.toString(); } } } if (ingestedSuccessfully) { _dbClient.ready(UnManagedVolume.class, unManagedVolume.getId(), taskId, taskMessage); } else { _dbClient.error(UnManagedVolume.class, unManagedVolume.getId(), taskId, IngestionException.exceptions.unmanagedVolumeIsNotVisible(unManagedVolume.getLabel(), taskMessage)); } // Commit any ingested CG _unManagedVolumeService.commitIngestedCG(_requestContext, unManagedVolume); // Commit the volume's internal resources volumeContext.commit(); // Commit this volume's updated data objects if any after ingestion Set<DataObject> updatedObjects = _requestContext.getDataObjectsToBeUpdatedMap().get(unManagedVolumeGUID); if (updatedObjects != null && !updatedObjects.isEmpty()) { for (DataObject dob : updatedObjects) { _logger.info("Ingestion Wrap Up: Updating DataObject {} (hash {})", dob.forDisplay(), dob.hashCode()); _dbClient.updateObject(dob); } } // Commit this volume's created data objects if any after ingestion Set<DataObject> createdObjects = _requestContext.getDataObjectsToBeCreatedMap().get(unManagedVolumeGUID); if (createdObjects != null && !createdObjects.isEmpty()) { for (DataObject dob : createdObjects) { _logger.info("Ingestion Wrap Up: Creating DataObject {} (hash {})", dob.forDisplay(), dob.hashCode()); _dbClient.createObject(dob); } } } } catch (InternalException e) { throw e; } catch (Exception e) { _logger.debug("Unexpected ingestion exception:", e); throw APIException.internalServerErrors.genericApisvcError(ExceptionUtils.getExceptionMessage(e), e); } for (BlockObject bo : _requestContext.getBlockObjectsToBeCreatedMap().values()) { _logger.info("Ingestion Wrap Up: Creating BlockObject {} (hash {})", bo.forDisplay(), bo.hashCode()); _dbClient.createObject(bo); } for (UnManagedVolume umv : _requestContext.getUnManagedVolumesToBeDeleted()) { _logger.info("Ingestion Wrap Up: Deleting UnManagedVolume {} (hash {})", umv.forDisplay(), umv.hashCode()); _dbClient.updateObject(umv); } // record the events after they have been persisted for (BlockObject volume : _requestContext.getBlockObjectsToBeCreatedMap().values()) { _unManagedVolumeService.recordVolumeOperation(_dbClient, _unManagedVolumeService.getOpByBlockObjectType(volume), Status.ready, volume.getId()); } } /** * Executes API Tasks on a separate thread by instantiating a IngestVolumesUnexportedSchedulingThread. * * @param executorService the ExecutorService * @param requestContext the BaseIngestionRequestContext * @param ingestStrategyFactory the IngestStrategyFactory * @param unManagedVolumeService the UnManagedVolumeService * @param dbClient the database client * @param taskMap a Map of UnManagedVolume ids to task ids * @param taskList a list of Tasks */ public static void executeApiTask(ExecutorService executorService, BaseIngestionRequestContext requestContext, IngestStrategyFactory ingestStrategyFactory, UnManagedVolumeService unManagedVolumeService, DbClient dbClient, Map<String, String> taskMap, TaskList taskList) { IngestVolumesUnexportedSchedulingThread schedulingThread = new IngestVolumesUnexportedSchedulingThread(requestContext, ingestStrategyFactory, unManagedVolumeService, dbClient, taskMap); try { executorService.execute(schedulingThread); } catch (Exception e) { String message = "Failed to start unmanaged volume ingestion tasks..."; _logger.error(message, e); for (TaskResourceRep taskRep : taskList.getTaskList()) { taskRep.setMessage(message); } } } }