/*
* Copyright (c) 2014 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.db.client.upgrade.callbacks;
import java.net.URI;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.constraint.AlternateIdConstraint;
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.StringMap;
import com.emc.storageos.db.client.model.StringSet;
import com.emc.storageos.db.client.upgrade.BaseCustomMigrationCallback;
import com.emc.storageos.db.client.util.NullColumnValueGetter;
import com.emc.storageos.db.client.util.StringSetUtil;
import com.emc.storageos.svcs.errorhandling.resources.MigrationCallbackException;
public class InitiatorHostMigration extends BaseCustomMigrationCallback {
public static final Long FLAG_DEFAULT = 2L;
private static final Logger log = LoggerFactory.getLogger(InitiatorHostMigration.class);
// Hold references to valid initiator URI based on port
private Map<String, Initiator> portToUri = new HashMap<String, Initiator>();
@Override
public void process() throws MigrationCallbackException {
processInitiatorCleanup();
}
private void processInitiatorCleanup() {
// Hold list of initiator URIs to be deleted
Set<URI> initiatorToDelete = new HashSet<URI>();
// Grab all export
List<URI> exports = dbClient.queryByType(ExportGroup.class, true);
for (URI eUri : exports) {
ExportGroup eg = dbClient.queryObject(ExportGroup.class, eUri);
boolean updated = false;
// skip if not host or cluster export
if (eg.forInitiator() || eg.forHost() || eg.forCluster()) {
// Grab export Initiators
StringSet exportInitiators = eg.getInitiators();
// search through initiators for null Host URI
for (URI uri : StringSetUtil.stringSetToUriList(exportInitiators)) {
Initiator oldInitiator = dbClient.queryObject(Initiator.class, uri);
if (oldInitiator != null) {
if (NullColumnValueGetter.isNullURI(oldInitiator.getHost())) {
// Get valid initiator based on port
Initiator newInitiator = getInitiatorByPort(oldInitiator.getInitiatorPort());
if (newInitiator != null) {
// Duplicate found, add to delete list
initiatorToDelete.add(oldInitiator.getId());
updateExportGroupInitiators(eg, oldInitiator, newInitiator);
updated = true;
updateExportMask(eg, oldInitiator, newInitiator);
} else {
log.warn("Found initiator: " + oldInitiator.getId() +
" with null Host uri in export group: " + eg.getId() +
" - Additional info: [wwwpn: " + oldInitiator.getInitiatorPort() +
" wwnn: " + oldInitiator.getInitiatorNode() +
" hostname: " + oldInitiator.getHostName());
}
}
}
}
if (updated) {
dbClient.updateObject(eg);
}
}
}
// Cleanup should be complete, initiators can now be marked for deletion
for (URI uri : initiatorToDelete) {
Initiator initiator = dbClient.queryObject(Initiator.class, uri);
log.info("Setting " + initiator.getId() + " for deletion due to Null Host URI.");
dbClient.markForDeletion(initiator);
}
}
private Initiator getInitiatorByPort(String port) {
if (port == null || port.isEmpty()) {
return null;
}
// check map for initiator
Initiator initiator = portToUri.get(port);
if (initiator != null) {
return initiator;
}
// Finds the Initiator that includes the initiator port specified, if any.
List<URI> uris = dbClient.queryByConstraint(AlternateIdConstraint.Factory.getInitiatorPortInitiatorConstraint(port));
// look for initiator with valid host URI
for (URI iUri : uris) {
Initiator i = dbClient.queryObject(Initiator.class, iUri);
if (i != null) {
if (!NullColumnValueGetter.isNullURI(i.getHost())) {
// add port name to URI map
portToUri.put(port, i);
return i;
}
}
}
return null;
}
private void updateExportGroupInitiators(ExportGroup eg, Initiator oldInitiator, Initiator newInitiator) {
log.info("Updating export group: " + eg.getId() +
" replacing old initiator: " + oldInitiator.getId() +
" with new initiator: " + newInitiator.getId());
// remove the old initiator from export due to null host URI
eg.removeInitiator(oldInitiator);
// Add valid initiator
eg.addInitiator(newInitiator);
}
private void updateExportMask(ExportGroup eg, Initiator oldInitiator, Initiator newInitiator) {
if (eg != null && eg.getExportMasks() != null) {
StringSet exportMasks = eg.getExportMasks();
for (URI maskUri : StringSetUtil.stringSetToUriList(exportMasks)) {
ExportMask mask = dbClient.queryObject(ExportMask.class, maskUri);
if (mask != null) {
udpateExportMaskInitiators(mask, oldInitiator, newInitiator);
updateExportMaskUserAddedInitiators(mask, oldInitiator, newInitiator);
updateExportMaskZoningMap(mask, oldInitiator, newInitiator);
dbClient.updateObject(mask);
}
}
}
}
private void udpateExportMaskInitiators(ExportMask mask, Initiator oldInitiator, Initiator newInitiator) {
// update export mask initiator
StringSet maskInitiators = mask.getInitiators();
if (maskInitiators != null && maskInitiators.contains(oldInitiator.getId().toString())) {
log.info("Updating export mask: " + mask.getId() +
" replacing old initiator: " + oldInitiator.getId() +
" with new initiators: " + newInitiator.getId());
mask.getInitiators().remove(oldInitiator.getId().toString());
mask.addInitiator(newInitiator);
}
}
private void updateExportMaskUserAddedInitiators(ExportMask mask, Initiator oldInitiator, Initiator newInitiator) {
// update user added initiators
StringMap userInitiators = mask.getUserAddedInitiators();
StringSet userKeys = StringSetUtil.getStringSetFromStringMapKeySet(userInitiators);
for (String key : userKeys) {
String val = userInitiators.get(key);
// if the value matches the old initiator
if (val.equals(oldInitiator.getId().toString())) {
log.info("Updating export mask: " + mask.getId() +
" replacing old user added initiator: " + oldInitiator.getId() +
" with new user added initiator: " + newInitiator.getId());
// update the user initiator entry
mask.getUserAddedInitiators().put(key, newInitiator.getId().toString());
}
}
}
private void updateExportMaskZoningMap(ExportMask mask, Initiator oldInitiator, Initiator newInitiator) {
// update zoning map
if (mask.getZoningMap() != null) {
Set<String> zoningKeys = mask.getZoningMap().keySet();
if (zoningKeys.contains(oldInitiator.getId().toString())) {
// grab associated storage port from existing initiator
StringSet storagePorts = mask.getZoningMap().get(oldInitiator.getId().toString());
log.info("Updating export mask: " + mask.getId() +
" with new zoning map entry: " + newInitiator.getId() + " : " + storagePorts.toString() +
" - Swapped entry: " + oldInitiator.getId() + " for: " + newInitiator.getId());
// add new zoning map entry linked to storagePorts
mask.addZoningMapEntry(newInitiator.getId().toString(), storagePorts);
// remove old zoning map entry
mask.removeZoningMapEntry(oldInitiator.getId().toString());
}
}
}
}