/*
* Copyright (c) 2008-2015 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.api.service.impl.resource.blockingestorchestration;
import java.net.URI;
import java.util.Iterator;
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.PropertySetterUtil;
import com.emc.storageos.api.service.impl.resource.utils.VolumeIngestionUtil;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.URIUtil;
import com.emc.storageos.db.client.constraint.AlternateIdConstraint;
import com.emc.storageos.db.client.constraint.URIQueryResultList;
import com.emc.storageos.db.client.model.BlockConsistencyGroup;
import com.emc.storageos.db.client.model.BlockObject;
import com.emc.storageos.db.client.model.BlockSnapshot;
import com.emc.storageos.db.client.model.BlockSnapshotSession;
import com.emc.storageos.db.client.model.DiscoveredDataObject;
import com.emc.storageos.db.client.model.NamedURI;
import com.emc.storageos.db.client.model.StringSet;
import com.emc.storageos.db.client.model.StringSetMap;
import com.emc.storageos.db.client.model.VirtualPool;
import com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedVolume;
import com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedVolume.SupportedVolumeInformation;
import com.emc.storageos.db.client.util.NullColumnValueGetter;
import com.emc.storageos.volumecontroller.impl.NativeGUIDGenerator;
public class BlockSnapIngestOrchestrator extends BlockIngestOrchestrator {
private static final Logger _logger = LoggerFactory.getLogger(BlockSnapIngestOrchestrator.class);
@Override
public <T extends BlockObject> T ingestBlockObjects(IngestionRequestContext requestContext, Class<T> clazz)
throws IngestionException {
UnManagedVolume unManagedVolume = requestContext.getCurrentUnmanagedVolume();
boolean unManagedVolumeExported = requestContext.getVolumeContext().isVolumeExported();
BlockSnapshot snapShot = null;
String snapNativeGuid = unManagedVolume.getNativeGuid().replace(NativeGUIDGenerator.UN_MANAGED_VOLUME,
NativeGUIDGenerator.VOLUME);
snapShot = VolumeIngestionUtil.checkSnapShotExistsInDB(snapNativeGuid, _dbClient);
// Check if ingested volume has exportmasks pending for ingestion.
if (isExportIngestionPending(snapShot, unManagedVolume.getId(), unManagedVolumeExported)) {
return clazz.cast(snapShot);
}
if (null == snapShot) {
// @TODO Need to revisit this. In 8.x provider, Replication Group is
// automatically created when a volume is associated to a
// StorageGroup.
// checkUnManagedVolumeAddedToCG(unManagedVolume, virtualArray,
// tenant, project, vPool);
checkVolumeExportState(unManagedVolume, unManagedVolumeExported);
VolumeIngestionUtil.checkUnManagedResourceIngestable(unManagedVolume);
snapShot = createSnapshot(requestContext, snapNativeGuid);
// See if this is a linked target for existing block snapshot sessions.
if (!NullColumnValueGetter.isNullValue(snapShot.getSettingsInstance())) {
URIQueryResultList queryResults = new URIQueryResultList();
_dbClient.queryByConstraint(
AlternateIdConstraint.Factory.getBlockSnapshotSessionBySessionInstance(snapShot.getSettingsInstance()),
queryResults);
Iterator<URI> queryResultsIter = queryResults.iterator();
while (queryResultsIter.hasNext()) {
BlockSnapshotSession snapSession = _dbClient.queryObject(BlockSnapshotSession.class, queryResultsIter.next());
StringSet linkedTargets = snapSession.getLinkedTargets();
if ((linkedTargets != null)) {
linkedTargets.add(snapShot.getId().toString());
} else {
linkedTargets = new StringSet();
linkedTargets.add(snapShot.getId().toString());
snapSession.setLinkedTargets(linkedTargets);
}
_dbClient.updateObject(snapSession);
}
}
}
// Run this logic always when Volume is NO_PUBLIC_ACCESS
if (markUnManagedVolumeInactive(requestContext, snapShot)) {
_logger.info("All the related replicas and parent of unManagedVolume {} has been ingested ", unManagedVolume.getNativeGuid());
// mark inactive if this is not to be exported. Else, mark as inactive after successful export
if (!unManagedVolumeExported) {
unManagedVolume.setInactive(true);
requestContext.getUnManagedVolumesToBeDeleted().add(unManagedVolume);
}
} else {
_logger.info("Not all the parent/replicas of unManagedVolume {} have been ingested , hence marking as internal",
unManagedVolume.getNativeGuid());
snapShot.addInternalFlags(INTERNAL_VOLUME_FLAGS);
}
return clazz.cast(snapShot);
}
/**
* There is no validation required for snaps. Hence returning void argument.
*/
@Override
protected void validateAutoTierPolicy(String autoTierPolicyId, UnManagedVolume unManagedVolume, VirtualPool vPool) {
return;
}
private BlockSnapshot createSnapshot(IngestionRequestContext requestContext, String nativeGuid) throws IngestionException {
UnManagedVolume unManagedVolume = requestContext.getCurrentUnmanagedVolume();
BlockSnapshot snapShot = new BlockSnapshot();
snapShot.setId(URIUtil.createId(BlockSnapshot.class));
snapShot.setNativeGuid(nativeGuid);
updateBlockObjectNativeIds(snapShot, unManagedVolume);
StringSetMap unManagedVolumeInformation = unManagedVolume.getVolumeInformation();
String deviceLabel = PropertySetterUtil.extractValueFromStringSet(
SupportedVolumeInformation.DEVICE_LABEL.toString(), unManagedVolumeInformation);
if (null == deviceLabel || deviceLabel.trim().isEmpty()) {
deviceLabel = nativeGuid;
}
// In case of XIO snaps, the snapshots belong to a snapset which represents the snapshot CG. This will be
// populated in SNAPSHOT_CONSISTENCY_GROUP_NAME
// The same is applicable to external device snapshots
String snapsetName = PropertySetterUtil.extractValueFromStringSet(
SupportedVolumeInformation.SNAPSHOT_CONSISTENCY_GROUP_NAME.toString(), unManagedVolumeInformation);
if (null == snapsetName || snapsetName.trim().isEmpty()) {
snapsetName = deviceLabel;
}
snapShot.setSnapsetLabel(snapsetName);
snapShot.setStorageController(requestContext.getStorageSystem().getId());
String systemType = requestContext.getStorageSystem().checkIfVmax3() ?
DiscoveredDataObject.Type.vmax3.name() : requestContext.getStorageSystem().getSystemType();
snapShot.setSystemType(systemType);
snapShot.setVirtualArray(requestContext.getVarray(unManagedVolume).getId());
snapShot.setProject(new NamedURI(requestContext.getProject().getId(), snapShot.getLabel()));
snapShot.setWWN(unManagedVolume.getWwn());
String allocatedCapacity = PropertySetterUtil.extractValueFromStringSet(
SupportedVolumeInformation.ALLOCATED_CAPACITY.toString(), unManagedVolume.getVolumeInformation());
String provisionedCapacity = PropertySetterUtil.extractValueFromStringSet(
SupportedVolumeInformation.PROVISIONED_CAPACITY.toString(), unManagedVolume.getVolumeInformation());
snapShot.setAllocatedCapacity(Long.parseLong(allocatedCapacity));
snapShot.setProvisionedCapacity(Long.parseLong(provisionedCapacity));
String syncActive = PropertySetterUtil.extractValueFromStringSet(
SupportedVolumeInformation.IS_SYNC_ACTIVE.toString(), unManagedVolume.getVolumeInformation());
Boolean isSyncActive = (null != syncActive) ? Boolean.parseBoolean(syncActive) : false;
snapShot.setIsSyncActive(isSyncActive);
String readOnly = PropertySetterUtil.extractValueFromStringSet(
SupportedVolumeInformation.IS_READ_ONLY.toString(), unManagedVolume.getVolumeInformation());
Boolean isReadOnly = (null != readOnly) ? Boolean.parseBoolean(readOnly) : false;
snapShot.setIsReadOnly(isReadOnly);
String settingsInstance = PropertySetterUtil.extractValueFromStringSet(
SupportedVolumeInformation.SETTINGS_INSTANCE.toString(), unManagedVolume.getVolumeInformation());
snapShot.setSettingsInstance(settingsInstance);
String needsCopyToTarget = PropertySetterUtil.extractValueFromStringSet(
SupportedVolumeInformation.NEEDS_COPY_TO_TARGET.toString(), unManagedVolumeInformation);
Boolean isNeedsCopyToTarget = (null != needsCopyToTarget) ? Boolean.parseBoolean(needsCopyToTarget) : false;
snapShot.setNeedsCopyToTarget(isNeedsCopyToTarget);
String techType = PropertySetterUtil.extractValueFromStringSet(SupportedVolumeInformation.TECHNOLOGY_TYPE.toString(),
unManagedVolumeInformation);
snapShot.setTechnologyType(techType);
BlockConsistencyGroup cg = getConsistencyGroup(unManagedVolume, snapShot, requestContext, _dbClient);
if (null != cg) {
requestContext.getVolumeContext().getCGObjectsToCreateMap().put(cg.getLabel(), cg);
decorateCGInfoInVolumes(cg, snapShot, requestContext, unManagedVolume);
}
return snapShot;
}
/**
* Following steps are performed as part of this method execution.
* 1. Checks whether unManagedVolume is protected by RP or VPLEX, if yes we willn't create backend CG.
* 2. For regular volumes in unManaged CG, we will create CG when ingesting last volume in unmanaged CG.
* 3. When ingesting last regular volume in unmanaged CG, we will check whether CG already exists in DB for the same project & tenant.
* If yes, we will reuse it.
* Otherwise, we will create new BlockConsistencyGroup for the unmanaged consistencyGroup.
*
*/
@Override
protected BlockConsistencyGroup getConsistencyGroup(UnManagedVolume unManagedVolume, BlockObject blockObj,
IngestionRequestContext context, DbClient dbClient) {
if (VolumeIngestionUtil.checkUnManagedResourceAddedToConsistencyGroup(unManagedVolume)) {
return VolumeIngestionUtil.getBlockObjectConsistencyGroup(unManagedVolume, blockObj, context, dbClient);
}
return null;
}
}