/* * Copyright (c) 2016 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.validators.xtremio; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.db.client.model.ExportMask; import com.emc.storageos.db.client.model.Initiator; import com.emc.storageos.db.client.model.StorageSystem; import com.emc.storageos.db.client.util.CommonTransformerFunctions; import com.emc.storageos.db.client.util.NullColumnValueGetter; import com.emc.storageos.exceptions.DeviceControllerException; import com.emc.storageos.util.NetworkUtil; import com.emc.storageos.volumecontroller.impl.utils.ExportMaskUtils; import com.emc.storageos.volumecontroller.impl.validators.ValidatorLogger; import com.emc.storageos.volumecontroller.impl.xtremio.prov.utils.XtremIOProvUtils; import com.emc.storageos.xtremio.restapi.XtremIOClient; import com.emc.storageos.xtremio.restapi.model.response.XtremIOInitiator; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Collections2; import com.google.common.collect.Lists; import com.google.common.collect.Sets; public class XtremIOExportMaskInitiatorsValidator extends AbstractXtremIOValidator { private static final Logger log = LoggerFactory.getLogger(XtremIOExportMaskInitiatorsValidator.class); private ArrayListMultimap<String, Initiator> initiatorToIGMap; private ArrayListMultimap<String, Initiator> knownInitiatorToIGMap; public XtremIOExportMaskInitiatorsValidator(StorageSystem storage, ExportMask exportMask) { super(storage, exportMask); } public void setInitiatorToIGMap(ArrayListMultimap<String, Initiator> initiatorToIGMap) { this.initiatorToIGMap = initiatorToIGMap; } public void setKnownInitiatorToIGMap(ArrayListMultimap<String, Initiator> knownInitiatorToIGMap) { this.knownInitiatorToIGMap = knownInitiatorToIGMap; } /** * Get list of initiators associated with the IG. * * a. If there are unknown initiators in IG, fail the operation * b. i) If Cluster export: * - - - If there are additional initiators other than the ones in ExportMask: * - - - check if all of them belong to different host but same cluster (Single IG with all cluster initiators) * - ii) Host export: Check additional initiators belong to same host or different host * - - -- If different host, fail the operation * * Reason for failing: We do not want to cause DU by choosing an operation when additional initiators * are present in the IG. Better fail the operation explaining the situation instead of resulting in DU. */ @Override public boolean validate() throws Exception { log.info("Initiating initiators validation of XtremIO ExportMask: " + id); try { XtremIOClient client = XtremIOProvUtils.getXtremIOClient(getDbClient(), storage, getClientFactory()); String xioClusterName = client.getClusterDetails(storage.getSerialNumber()).getName(); if (knownInitiatorToIGMap == null) { knownInitiatorToIGMap = ArrayListMultimap.create(); } // Don't validate against backing masks or RP if (ExportMaskUtils.isBackendExportMask(getDbClient(), exportMask)) { log.info("validation against backing mask for VPLEX or RP is disabled."); return true; } List<Initiator> knownInitiatorsInIGs = new ArrayList<Initiator>(); List<String> allInitiatorsInIGs = new ArrayList<String>(); List<XtremIOInitiator> initiators = client.getXtremIOInitiatorsInfo(xioClusterName); for (XtremIOInitiator initiator : initiators) { String igNameInInitiator = initiator.getInitiatorGroup().get(1); if (initiatorToIGMap.keySet().contains(igNameInInitiator)) { allInitiatorsInIGs.add(Initiator.normalizePort(initiator.getPortAddress())); Initiator knownInitiator = NetworkUtil.getInitiator(initiator.getPortAddress(), getDbClient()); if (knownInitiator != null) { knownInitiatorsInIGs.add(knownInitiator); knownInitiatorToIGMap.put(igNameInInitiator, knownInitiator); } } } log.info("Initiators present in IG: {}", allInitiatorsInIGs); // Fail the operation if there are unknown initiators in the IG (not registered in ViPR) if (knownInitiatorsInIGs.size() < allInitiatorsInIGs.size()) { Collection<String> knownInitiatorNames = Collections2.transform(knownInitiatorsInIGs, CommonTransformerFunctions.fctnInitiatorToPortName()); Set<String> differences = Sets.difference(Sets.newHashSet(allInitiatorsInIGs), Sets.newHashSet(knownInitiatorNames)); for (String diff : differences) { getLogger().logDiff(exportMask.getId().toString(), "initiators", ValidatorLogger.NO_MATCHING_ENTRY, diff); } checkForErrors(); } for (String igName : initiatorToIGMap.keySet()) { List<Initiator> requestedInitiatorsInIG = initiatorToIGMap.get(igName); List<Initiator> initiatorsInIG = knownInitiatorToIGMap.get(igName); String hostName = null; String clusterName = null; for (Initiator initiator : requestedInitiatorsInIG) { if (null != initiator.getHostName()) { // initiators already grouped by Host hostName = initiator.getHostName(); clusterName = initiator.getClusterName(); break; } } Collection<String> knownInitiators = Collections2.transform(Lists.newArrayList(initiatorsInIG), CommonTransformerFunctions.fctnInitiatorToPortName()); Collection<String> requestedInitiators = Collections2.transform(requestedInitiatorsInIG, CommonTransformerFunctions.fctnInitiatorToPortName()); log.info("Validation requested initiators: {}", requestedInitiators); log.info("Validation discovered initiators: {}", knownInitiators); knownInitiators.removeAll(requestedInitiators); log.info("Validation unknown initiators in IG: {}", knownInitiators); if (!knownInitiators.isEmpty()) { List<String> listToIgnore = new ArrayList<String>(); log.info( "There are other initiators present in the IG - {}. Checking if they all belong to same host or different host but same cluster.", knownInitiators); log.info("Host name: {}, Cluster name: {}", hostName, clusterName); // check if the other initiators belong to different host for (Initiator ini : initiatorsInIG) { if (NullColumnValueGetter.isNotNullValue(clusterName) && ini.getHostName() != null && !ini.getHostName().equalsIgnoreCase(hostName)) { // check if they belong to same cluster if (ini.getClusterName() != null && clusterName != null && !clusterName.isEmpty() && ini.getClusterName().equalsIgnoreCase(clusterName)) { listToIgnore.add(Initiator.normalizePort(ini.getInitiatorPort())); } } else if (ini.getHostName() != null && ini.getHostName().equalsIgnoreCase(hostName)) { listToIgnore.add(Initiator.normalizePort(ini.getInitiatorPort())); } } log.info("Validation initiators that belong to same host or cluster: {}", listToIgnore); knownInitiators.removeAll(listToIgnore); log.info("Validation remaining initiators that are not managed by controller: {}", knownInitiators); for (String knownInitiator : knownInitiators) { getLogger().logDiff(exportMask.getId().toString(), "initiators", ValidatorLogger.NO_MATCHING_ENTRY, knownInitiator); } } } } catch (Exception ex) { log.error("Unexpected exception validating ExportMask initiators: " + ex.getMessage(), ex); if (getConfig().isValidationEnabled()) { throw DeviceControllerException.exceptions.unexpectedCondition( "Unexpected exception validating ExportMask initiators: " + ex.getMessage()); } } checkForErrors(); log.info("Completed initiator validation of XtremIO ExportMask: " + id); return true; } }