/* * Copyright (c) 2012 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.block.taskcompleter; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.model.BlockSnapshot; import com.emc.storageos.db.client.model.Operation; import com.emc.storageos.db.client.model.Volume; import com.emc.storageos.exceptions.DeviceControllerException; import com.emc.storageos.svcs.errorhandling.model.ServiceCoded; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.URI; import java.util.ArrayList; import java.util.List; import com.emc.storageos.services.OperationTypeEnum; import com.emc.storageos.volumecontroller.impl.ControllerUtils; @SuppressWarnings("serial") public class BlockSnapshotDeleteCompleter extends BlockSnapshotTaskCompleter { private static final Logger _log = LoggerFactory.getLogger(BlockSnapshotDeleteCompleter.class); public static final String SNAPSHOT_DELETED_MSG = "Deleted snapshot %s on volume %s"; public static final String SNAPSHOT_DELETE_FAILED_MSG = "Failed to delete snapshot %s on volume %s"; // Make this private, so that we force the use of the createCompleter() method private BlockSnapshotDeleteCompleter(BlockSnapshot snapshot, String task) { super(BlockSnapshot.class, snapshot.getId(), task); } /** * This method is for creating the BlockSnapshotDeleteCompleter. This a bit unique from * the other completers because of the way that we need to complete the task. For the * case of CG snapshots, there will be multiple BlockSnapshots associated, even though * the request to delete the snapshot was against only one of the CG snaps. Here we will * make sure that the task completer has references to all the CG snaps, so that they * can be referred to in the completer. Main reason is that if a BlockSnapshot is marked * inactive, it can no longer be retrieved using AltIndex queries. * * @param dbClient [in] - DbClient for querying ViPR DB * @param snapshot [in] - BlockSnapshot object * @param task [in] - Task UUID for the snapshot delete operation * @return a new BlockSnapshotDeleteCompleter object */ public static BlockSnapshotDeleteCompleter createCompleter(DbClient dbClient, BlockSnapshot snapshot, String task) { BlockSnapshotDeleteCompleter completer = new BlockSnapshotDeleteCompleter(snapshot, task); if (snapshot.getConsistencyGroup() != null) { // For snapshot based on a consistency group, set status and send // events for all related snaps List<URI> snapIds = new ArrayList<URI>(); List<BlockSnapshot> snaps = ControllerUtils.getSnapshotsPartOfReplicationGroup(snapshot, dbClient); for (BlockSnapshot snap : snaps) { snapIds.add(snap.getId()); } completer.addIds(snapIds); } return completer; } @Override protected void complete(DbClient dbClient, Operation.Status status, ServiceCoded coded) throws DeviceControllerException { try { List<BlockSnapshot> blockSnapshots = dbClient.queryObject(BlockSnapshot.class, getIds()); for (BlockSnapshot snapshot : blockSnapshots) { Volume parent = dbClient.queryObject(Volume.class, snapshot.getParent().getURI()); switch (status) { case error: setErrorOnDataObject(dbClient, BlockSnapshot.class, snapshot.getId(), coded); setErrorOnDataObject(dbClient, Volume.class, parent.getId(), coded); break; case ready: setReadyOnDataObject(dbClient, BlockSnapshot.class, snapshot); setReadyOnDataObject(dbClient, Volume.class, parent.getId()); } recordBlockSnapshotOperation(dbClient, OperationTypeEnum.DELETE_VOLUME_SNAPSHOT, status, eventMessage(status, parent, snapshot), snapshot); _log.info("Done SnapshotDelete {}, with Status: {}", getOpId(), status.name()); } super.complete(dbClient, status, coded); } catch (Exception e) { _log.error("Failed updating status. SnapshotDelete {}, for task " + getOpId(), getId(), e); } } private String eventMessage(Operation.Status status, Volume volume, BlockSnapshot snapshot) { return (status == Operation.Status.ready) ? String.format(SNAPSHOT_DELETED_MSG, snapshot.getLabel(), volume.getLabel()) : String.format(SNAPSHOT_DELETE_FAILED_MSG, snapshot.getLabel(), volume.getLabel()); } }