/*
* Copyright (c) 2015 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.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang.mutable.MutableInt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.api.service.impl.resource.blockingestorchestration.context.IngestionRequestContext;
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.UnManagedDiscoveredObjects.UnManagedExportMask;
import com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedProtectionSet;
import com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedVolume;
import com.emc.storageos.db.client.util.CommonTransformerFunctions;
import com.google.common.base.Joiner;
import com.google.common.collect.Collections2;
public class IngestExportStrategy {
private static final Logger _logger = LoggerFactory.getLogger(IngestStrategy.class);
private DbClient _dbClient;
private BlockIngestExportOrchestrator ingestExportOrchestrator;
public void setDbClient(DbClient dbClient) {
_dbClient = dbClient;
}
public void setIngestExportOrchestrator(BlockIngestExportOrchestrator ingestExportOrchestrator) {
this.ingestExportOrchestrator = ingestExportOrchestrator;
}
/**
* After volume object gets created successfully locally, now start
* running ingest associated masks of the volume
*/
public <T extends BlockObject> T ingestExportMasks(UnManagedVolume unManagedVolume,
T blockObject, IngestionRequestContext requestContext) throws IngestionException {
_logger.info("ingesting export masks for requestContext " + requestContext.getCurrentUnmanagedVolume());
if (null != requestContext.getExportGroup()) {
if (null != unManagedVolume.getUnmanagedExportMasks() && !unManagedVolume.getUnmanagedExportMasks().isEmpty()) {
List<URI> unManagedMaskUris = new ArrayList<URI>(Collections2.transform(
unManagedVolume.getUnmanagedExportMasks(), CommonTransformerFunctions.FCTN_STRING_TO_URI));
List<UnManagedExportMask> unManagedMasks = _dbClient.queryObject(UnManagedExportMask.class, unManagedMaskUris);
int originalSize = unManagedMasks.size();
MutableInt masksIngestedCount = new MutableInt(0);
// Ingest Associated Masks
ingestExportOrchestrator.ingestExportMasks(
requestContext, unManagedVolume, blockObject, unManagedMasks, masksIngestedCount);
_logger.info("{} of {} unmanaged export masks were ingested", masksIngestedCount, originalSize);
List<String> errorMessages = requestContext.getErrorMessagesForVolume(unManagedVolume.getNativeGuid());
// If the internal flags are set, return the block object
if (blockObject.checkInternalFlags(Flag.PARTIALLY_INGESTED)) {
_logger.info("block object {} is partially ingested", blockObject.forDisplay());
// check if none of the export masks are ingested
if (masksIngestedCount.intValue() == 0) {
if (null != errorMessages && !errorMessages.isEmpty()) {
throw IngestionException.exceptions.unmanagedVolumeMasksNotIngestedAdditionalInfo(
unManagedVolume.getLabel(), Joiner.on(", ").join(errorMessages));
} else {
throw IngestionException.exceptions.unmanagedVolumeMasksNotIngested(
unManagedVolume.getLabel());
}
} else {
// If the unmanaged volume is not marked for deletion, then it should be updated with the changes done.
requestContext.addDataObjectToUpdate(unManagedVolume, unManagedVolume);
_logger.info("all export masks of unmanaged volume {} have been ingested, "
+ "but the volume is still marked as partially ingested, returning block object {}",
unManagedVolume.forDisplay(), blockObject.forDisplay());
return blockObject;
}
}
if (unManagedVolume.getUnmanagedExportMasks().size() != originalSize) {
// delete this volume only if the masks are ingested.
if (VolumeIngestionUtil.canDeleteUnManagedVolume(unManagedVolume)) {
_logger.info("Marking UnManaged Volume {} inactive as it doesn't have any associated unmanaged export masks ",
unManagedVolume.getNativeGuid());
boolean isRPVolume = VolumeIngestionUtil.checkUnManagedResourceIsRecoverPointEnabled(unManagedVolume);
// if its RP volume and non RP exported, then check whether the RP CG is fully ingested
if (isRPVolume && VolumeIngestionUtil.checkUnManagedResourceIsNonRPExported(unManagedVolume)) {
_logger.info("unmanaged volume {} is both RecoverPoint protected and exported to another Host or Cluster",
unManagedVolume.forDisplay());
Set<DataObject> updateObjects = requestContext.getDataObjectsToBeUpdatedMap()
.get(unManagedVolume.getNativeGuid());
if (updateObjects == null) {
updateObjects = new HashSet<DataObject>();
requestContext.getDataObjectsToBeUpdatedMap().put(unManagedVolume.getNativeGuid(), updateObjects);
}
List<UnManagedVolume> ingestedUnManagedVolumes = requestContext.findAllUnManagedVolumesToBeDeleted();
ingestedUnManagedVolumes.add(unManagedVolume);
UnManagedProtectionSet umpset = VolumeIngestionUtil.getUnManagedProtectionSetForUnManagedVolume(requestContext,
unManagedVolume, _dbClient);
// If we are not able to find the unmanaged protection set from the unmanaged volume, it means that the
// unmanaged volume has already been ingested. In this case, try to get it from the managed volume
if (umpset == null) {
umpset = VolumeIngestionUtil.getUnManagedProtectionSetForManagedVolume(requestContext, blockObject,
_dbClient);
}
// If fully ingested, then setup the RP CG too.
if (VolumeIngestionUtil.validateAllVolumesInCGIngested(ingestedUnManagedVolumes, umpset, requestContext,
_dbClient)) {
VolumeIngestionUtil.validateRPVolumesAlignWithIngestVpool(requestContext, umpset, _dbClient);
VolumeIngestionUtil.setupRPCG(requestContext, umpset, unManagedVolume, updateObjects, _dbClient);
} else { // else mark the volume as internal. This will be marked visible when the RP CG is ingested
blockObject.addInternalFlags(BlockRecoverPointIngestOrchestrator.INTERNAL_VOLUME_FLAGS);
}
}
unManagedVolume.setInactive(true);
requestContext.getUnManagedVolumesToBeDeleted().add(unManagedVolume);
} else {
// If the unmanaged volume is not marked for deletion, then it should be updated with the changes done.
requestContext.addDataObjectToUpdate(unManagedVolume, unManagedVolume);
}
return blockObject;
} else {
if (null != errorMessages && !errorMessages.isEmpty()) {
Collections.sort(errorMessages);
throw IngestionException.exceptions.unmanagedVolumeMasksNotIngestedAdditionalInfo(
unManagedVolume.getLabel(), "\n\n" + Joiner.on("\n\n").join(errorMessages));
} else {
throw IngestionException.exceptions.unmanagedVolumeMasksNotIngested(
unManagedVolume.getLabel());
}
}
}
}
return blockObject;
}
}