/* * Copyright (c) 2012 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.block.taskcompleter; import java.net.URI; import java.util.List; import com.emc.storageos.db.client.model.BlockSnapshot; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.constraint.ContainmentConstraint; import com.emc.storageos.db.client.model.BlockSnapshotSession; import com.emc.storageos.db.client.model.Operation.Status; import com.emc.storageos.db.client.model.StringSet; import com.emc.storageos.db.client.util.CustomQueryUtility; import com.emc.storageos.exceptions.DeviceControllerException; import com.emc.storageos.svcs.errorhandling.model.ServiceCoded; /** * Task completer invoked when SMI-S request to re-link a target * volume to an array snapshot completes. */ @SuppressWarnings("serial") public class BlockSnapshotSessionRelinkTargetCompleter extends BlockSnapshotSessionCompleter { // The URI of the BlockSnapshotSession representing the target array snapshot. private final URI _snapshotURI; // A logger. private static final Logger s_logger = LoggerFactory.getLogger(BlockSnapshotSessionRelinkTargetCompleter.class); /** * Constructor * * @param tgtSnapSessionURI The id of the target BlockSnapshotSession instance in the database. * @param snapshotURI The id of the BlockSnapshot instance representing the target. * @param stepId The id of the WF step in which the target is being re-linked. */ public BlockSnapshotSessionRelinkTargetCompleter(URI tgtSnapSessionURI, URI snapshotURI, String stepId) { super(tgtSnapSessionURI, stepId); _snapshotURI = snapshotURI; } /** * {@inheritDoc} */ @Override protected void complete(DbClient dbClient, Status status, ServiceCoded coded) throws DeviceControllerException { try { switch (status) { case error: break; case ready: // Remove the linked targets from the linked targets list for their // current snapshot session and add them to the linked targets for // the target session. BlockSnapshotSession tgtSnapSession = dbClient.queryObject(BlockSnapshotSession.class, getId()); StringSet tgtSnapSessionTargets = tgtSnapSession.getLinkedTargets(); List<BlockSnapshotSession> snaphotSessionsList = CustomQueryUtility.queryActiveResourcesByConstraint(dbClient, BlockSnapshotSession.class, ContainmentConstraint.Factory.getLinkedTargetSnapshotSessionConstraint(_snapshotURI)); if (snaphotSessionsList.isEmpty()) { // The target is not linked to an active snapshot session. throw DeviceControllerException.exceptions.unexpectedCondition(String.format( "Cound not find active snapshot session for linked target %s", _snapshotURI)); } // A target can only be linked to a single session. BlockSnapshotSession currentSnapSession = snaphotSessionsList.get(0); BlockSnapshot snapshot = dbClient.queryObject(BlockSnapshot.class, _snapshotURI); List<BlockSnapshot> relatedSnapshots = getRelatedSnapshots(snapshot, dbClient); for (BlockSnapshot relatedSnapshot : relatedSnapshots) { // If the target was not re-linked to the same snapshot session // update the linked targets list for both the current and target // snapshot sessions. if (!currentSnapSession.getId().equals(getId())) { String snapshotId = relatedSnapshot.getId().toString(); // Remove from the current snapshot session. StringSet currentSnapSessionTargets = currentSnapSession.getLinkedTargets(); currentSnapSessionTargets.remove(snapshotId); dbClient.updateObject(currentSnapSession); // Add to the target snapshot session. if (tgtSnapSessionTargets == null) { tgtSnapSessionTargets = new StringSet(); tgtSnapSession.setLinkedTargets(tgtSnapSessionTargets); } tgtSnapSessionTargets.add(snapshotId); dbClient.updateObject(tgtSnapSession); } } break; default: String errMsg = String.format("Unexpected status %s for completer for step %s", status.name(), getOpId()); s_logger.info(errMsg); throw DeviceControllerException.exceptions.unexpectedCondition(errMsg); } s_logger.info("Done re-link target volume step {} with status: {}", getOpId(), status.name()); } catch (Exception e) { s_logger.error("Failed updating status for re-link target volume step {}", getOpId(), e); } finally { super.complete(dbClient, status, coded); } } }