/*
* Copyright (c) 2013 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.impl.block.taskcompleter;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.URIUtil;
import com.emc.storageos.db.client.model.ExportGroup;
import com.emc.storageos.db.client.model.ExportMask;
import com.emc.storageos.db.client.model.Initiator;
import com.emc.storageos.db.client.model.Operation;
import com.emc.storageos.db.client.model.StorageSystem;
import com.emc.storageos.db.client.model.StringSet;
import com.emc.storageos.db.client.model.StringSetMap;
import com.emc.storageos.exceptions.DeviceControllerException;
import com.emc.storageos.svcs.errorhandling.model.ServiceCoded;
import com.emc.storageos.svcs.errorhandling.model.ServiceError;
import com.emc.storageos.util.ExportUtils;
import com.emc.storageos.workflow.WorkflowService;
public class ExportMaskRemoveInitiatorCompleter extends ExportTaskCompleter {
private static final Logger _log = LoggerFactory.getLogger(ExportMaskRemoveInitiatorCompleter.class);
private List<URI> _initiatorURIs;
public ExportMaskRemoveInitiatorCompleter(URI egUri, URI emUri, List<URI> initiatorURIs,
String task) {
super(ExportGroup.class, egUri, emUri, task);
_initiatorURIs = new ArrayList<URI>();
_initiatorURIs.addAll(initiatorURIs);
}
@Override
public void ready(DbClient dbClient) throws DeviceControllerException {
try {
ExportGroup exportGroup = dbClient.queryObject(ExportGroup.class, getId());
ExportMask exportMask = (getMask() != null) ?
dbClient.queryObject(ExportMask.class, getMask()) : null;
if (exportMask != null) {
List<Initiator> initiators =
dbClient.queryObject(Initiator.class, _initiatorURIs);
List<URI> targetPorts = ExportUtils.getRemoveInitiatorStoragePorts(exportMask, initiators, dbClient);
exportMask.removeInitiators(initiators);
exportMask.removeFromUserCreatedInitiators(initiators);
if (exportMask.getInitiators() == null ||
exportMask.getInitiators().isEmpty()) {
exportGroup.removeExportMask(exportMask.getId());
dbClient.markForDeletion(exportMask);
dbClient.updateObject(exportGroup);
} else {
if (targetPorts != null && !targetPorts.isEmpty()) {
for (URI targetPort : targetPorts) {
exportMask.removeTarget(targetPort);
}
}
removeUnusedTargets(exportMask);
dbClient.updateObject(exportMask);
}
_log.info(String.format(
"Done ExportMaskRemoveInitiator - Id: %s, OpId: %s, status: %s",
getId().toString(), getOpId(), Operation.Status.ready.name()));
}
} catch (Exception e) {
_log.error(String.format(
"Failed updating status for ExportMaskRemoveInitiator - Id: %s, OpId: %s",
getId().toString(), getOpId()), e);
} finally {
super.ready(dbClient);
}
}
@Override
protected void complete(DbClient dbClient, Operation.Status status, ServiceCoded coded) throws DeviceControllerException {
try {
ExportGroup exportGroup = dbClient.queryObject(ExportGroup.class, getId());
ExportMask exportMask = (getMask() != null) ?
dbClient.queryObject(ExportMask.class, getMask()) : null;
boolean isRollback = WorkflowService.getInstance().isStepInRollbackState(getOpId());
if ((status == Operation.Status.error) && (isRollback) && (coded instanceof ServiceError)) {
ServiceError error = (ServiceError) coded;
String originalMessage = error.getMessage();
StorageSystem storageSystem = exportMask != null ? dbClient.queryObject(StorageSystem.class, exportMask.getStorageDevice())
: null;
List<Initiator> initiators = dbClient.queryObject(Initiator.class, _initiatorURIs);
StringBuffer initiatorsJoined = new StringBuffer();
if (initiators != null && !initiators.isEmpty()) {
Iterator<Initiator> initIter = initiators.iterator();
while (initIter.hasNext()) {
Initiator initiator = initIter.next();
initiatorsJoined.append(initiator.forDisplay());
if (initIter.hasNext()) {
initiatorsJoined.append(",");
}
}
}
String additionMessage = String.format(
"Rollback encountered problems removing initiator(s) %s from export mask %s on storage system %s and may require manual clean up",
initiatorsJoined.toString(), exportMask.getMaskName(),
storageSystem != null ? storageSystem.forDisplay() : "Unknown");
String updatedMessage = String.format("%s\n%s", originalMessage, additionMessage);
error.setMessage(updatedMessage);
}
if (exportMask != null && (status == Operation.Status.ready || isRollback)) {
List<Initiator> initiators =
dbClient.queryObject(Initiator.class, _initiatorURIs);
List<URI> targetPorts = ExportUtils.getRemoveInitiatorStoragePorts(exportMask, initiators, dbClient);
exportMask.removeInitiators(initiators);
exportMask.removeFromUserCreatedInitiators(initiators);
if (exportMask.getExistingInitiators() != null &&
exportMask.getExistingInitiators().isEmpty()){
exportMask.setExistingInitiators(null);
}
if (exportMask.getInitiators() == null || exportMask.getInitiators().isEmpty()) {
exportGroup.removeExportMask(exportMask.getId());
dbClient.removeObject(exportMask);
dbClient.updateObject(exportGroup);
} else {
if (targetPorts != null && !targetPorts.isEmpty()) {
for (URI targetPort : targetPorts) {
exportMask.removeTarget(targetPort);
}
}
removeUnusedTargets(exportMask);
dbClient.updateObject(exportMask);
}
_log.info(String.format(
"Done ExportMaskRemoveInitiator - Id: %s, OpId: %s, status: %s",
getId().toString(), getOpId(), status.name()));
}
} catch (Exception e) {
_log.error(String.format(
"Failed updating status for ExportMaskRemoveInitiator - Id: %s, OpId: %s",
getId().toString(), getOpId()), e);
} finally {
super.complete(dbClient, status, coded);
}
}
/*
* Remove unused storage Ports from export mask
*/
private void removeUnusedTargets(ExportMask exportMask) {
StringSet initiators = exportMask.getInitiators();
StringSetMap zoningMap = exportMask.getZoningMap();
Set<String> zonedTarget = new HashSet<String>();
boolean isRollback = WorkflowService.getInstance().isStepInRollbackState(getOpId());
for (String initiator : initiators) {
StringSet zoneEntry = zoningMap.get(initiator);
if (zoneEntry != null) {
zonedTarget.addAll(zoneEntry);
} else {
_log.warn(String.format(
"removeUnusedTargets() - tried looking up initiator [%s] in zoningMap for "
+ "Export Mask [%s - %s], but no entry found - continue...", initiator,
exportMask.getMaskName(), exportMask.getId()));
}
}
Set<String> targets = new HashSet<String>();
if (exportMask.getStoragePorts() != null) {
targets.addAll(exportMask.getStoragePorts());
}
if (isRollback) {
StringSet emStoragePorts = new StringSet();
if (exportMask.getStoragePorts() != null) {
emStoragePorts = exportMask.getStoragePorts();
} else {
_log.warn(String.format(
"removeUnusedTargets() - could not find any storage ports for"
+ "Export Mask [%s - %s].",
exportMask.getMaskName(), exportMask.getId()));
}
targets = new HashSet<String>(emStoragePorts);
}
if (!targets.removeAll(zonedTarget)) {
for (String zonedPort : zonedTarget) {
exportMask.addTarget(URIUtil.uri(zonedPort));
}
}
for (String targetPort : targets) {
exportMask.removeTarget(URIUtil.uri(targetPort));
}
}
public boolean removeInitiator(URI initiator) {
return _initiatorURIs.remove(initiator);
}
}