/*
* Copyright (c) 2012 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.impl.block.taskcompleter;
import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.model.BlockSnapshot;
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.exceptions.DeviceControllerException;
import com.emc.storageos.svcs.errorhandling.model.ServiceCoded;
import com.emc.storageos.volumecontroller.impl.ControllerUtils;
/**
* Task completer invoked when SMI-S request to unlink a target from
* an array snapshot completes.
*/
@SuppressWarnings("serial")
public class BlockSnapshotSessionUnlinkTargetCompleter extends BlockSnapshotSessionCompleter {
// Whether or not the target is deleted when unlinked.
private final Boolean _deleteTarget;
// A logger.
private static final Logger s_logger = LoggerFactory.getLogger(BlockSnapshotSessionUnlinkTargetCompleter.class);
/**
* Constructor
*
* @param snapSessionURI The id of the BlockSnapshotSession instance in the database.
* @param snapshotURI The id of the BlockSnapshot instance representing the target.
* @param deleteTarget True if the target volume should be deleted.
* @param stepId The id of the WF step in which the target is being unlinked.
*/
public BlockSnapshotSessionUnlinkTargetCompleter(URI snapSessionURI, URI snapshotURI, Boolean deleteTarget, String stepId) {
this(snapSessionURI, Lists.newArrayList(snapshotURI), deleteTarget, stepId);
}
/**
* Constructor
*
* @param snapSessionURI The id of the BlockSnapshotSession instance in the database.
* @param snapshotURIs The id of the BlockSnapshot instance representing the target.
* @param deleteTarget True if the target volume should be deleted.
* @param stepId The id of the WF step in which the target is being unlinked.
*/
public BlockSnapshotSessionUnlinkTargetCompleter(URI snapSessionURI, List<URI> snapshotURIs, Boolean deleteTarget, String stepId) {
super(snapSessionURI, stepId);
_snapshotURIs = snapshotURIs;
_deleteTarget = deleteTarget;
}
/**
* {@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 for the session.
for (URI snapshotURI : _snapshotURIs) {
processSnapshot(snapshotURI, dbClient);
}
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 unlink targets from snapshot session step {} with status: {}", getOpId(), status.name());
} catch (Exception e) {
s_logger.error("Failed updating status for unlink targets from snapshot session step {}", getOpId(), e);
} finally {
super.complete(dbClient, status, coded);
}
}
private void processSnapshot(URI snapshotURI, DbClient dbClient) {
BlockSnapshot snapshotObj = dbClient.queryObject(BlockSnapshot.class, snapshotURI);
BlockSnapshotSession snapSession = dbClient.queryObject(BlockSnapshotSession.class, getId());
StringSet linkedTargets = snapSession.getLinkedTargets();
List<BlockSnapshot> snapshots = getRelatedSnapshots(snapshotObj, dbClient);
for (BlockSnapshot snapshot : snapshots) {
snapshot.setInactive(true);
if ((linkedTargets != null) && (linkedTargets.contains(snapshot.getId().toString()))) {
linkedTargets.remove(snapshot.getId().toString());
}
}
// Note that even if the target is not deleted, mark the associated
// BlockSnapshot inactive. Since the target is no longer associated
// with an array snapshot, it is really no longer a BlockSnapshot
// instance in ViPR. In the unlink job we have created a ViPR Volume
// to represent the former snapshot target volume. So here we mark the
// BlockSnapshot inactive so it is garbage collected.
dbClient.updateObject(snapshots);
dbClient.updateObject(snapSession);
}
/**
* Gets if the target is to be deleted.
*
* @return true if the target is to be deleted, false otherwise.
*/
public boolean getDeleteTarget() {
return _deleteTarget;
}
}