/* * Copyright (c) 2016 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.plugins.discovery.smis.processor.export; import java.net.URI; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.cim.CIMInstance; import javax.cim.CIMObjectPath; import javax.wbem.client.WBEMClient; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.cimadapter.connections.cim.CimObjectPathCreator; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.constraint.ContainmentConstraint; import com.emc.storageos.db.client.model.ExportGroup; import com.emc.storageos.db.client.model.Host; import com.emc.storageos.db.client.model.Initiator; import com.emc.storageos.db.client.util.CustomQueryUtility; import com.emc.storageos.db.client.util.NullColumnValueGetter; import com.emc.storageos.plugins.AccessProfile; import com.emc.storageos.plugins.common.Constants; import com.emc.storageos.volumecontroller.impl.smis.SmisConstants; import com.emc.storageos.volumecontroller.impl.utils.DiscoveryUtils; /* * Refresh preferredPools for a host */ public class ArrayAffinityProcessor { private static final Logger _logger = LoggerFactory.getLogger(ArrayAffinityProcessor.class); private static final String CQL = "CQL"; /** * Update preferred pools of a host * * @param profile AccessProfile * @param cimClient WBEMClient * @param dbClient DbClient * @return true if there is mapped volume */ public void updatePreferredPools(AccessProfile profile, WBEMClient cimClient, DbClient dbClient) { _logger.info("Calling updatePreferredPools"); try { if (profile != null && profile.getProps() != null) { String hostIdsStr = profile.getProps().get(Constants.HOST_IDS); String systemIdsStr = profile.getProps().get(Constants.SYSTEM_IDS); String[] systemIds = systemIdsStr.split(Constants.ID_DELIMITER); Set<String> systemIdSet = new HashSet<String>(Arrays.asList(systemIds)); if (StringUtils.isNotEmpty(hostIdsStr)) { String[] hostIds = hostIdsStr.split(Constants.ID_DELIMITER); for (String hostId : hostIds) { _logger.info("Processing Host {}", hostId); Host host = dbClient.queryObject(Host.class, URI.create(hostId)); if (host != null && !host.getInactive()) { Map<String, String> preferredPoolURIs = getPreferredPoolMap(host.getId(), profile, cimClient, dbClient); if (ArrayAffinityDiscoveryUtils.updatePreferredPools(host, systemIdSet, dbClient, preferredPoolURIs)) { dbClient.updateObject(host); } } } } } } catch (Exception e) { _logger.warn("Exception on updatePreferredSystems {}", e.getMessage()); } } /** * Get preferred pool to export type map for a host * * @param hostId Id of Host instance * @param profile AccessProfile * @param cimClient WBEMClient * @param dbClient DbClient * @return preferred pool to export type map */ private Map<String, String> getPreferredPoolMap(URI hostId, AccessProfile profile, WBEMClient cimClient, DbClient dbClient) { Map<String, String> preferredPoolMap = new HashMap<String, String>(); List<Initiator> allInitiators = CustomQueryUtility .queryActiveResourcesByConstraint(dbClient, Initiator.class, ContainmentConstraint.Factory .getContainedObjectsConstraint( hostId, Initiator.class, Constants.HOST)); Set<CIMObjectPath> hardwareIdPaths = new HashSet<CIMObjectPath>(); for (Initiator initiator : allInitiators) { _logger.info("Processing initiator {}", initiator.getLabel()); String normalizedPortName = Initiator.normalizePort(initiator .getInitiatorPort()); String query = String .format("SELECT %s.%s FROM %s where %s.%s ='%s'", SmisConstants.CIM_STORAGE_HARDWARE_ID, SmisConstants.CP_INSTANCE_ID, SmisConstants.CIM_STORAGE_HARDWARE_ID, SmisConstants.CIM_STORAGE_HARDWARE_ID, SmisConstants.CP_ELEMENT_NAME, normalizedPortName); CIMObjectPath hardwareIdPath = CimObjectPathCreator.createInstance( SmisConstants.CIM_STORAGE_HARDWARE_ID, Constants.EMC_NAMESPACE, null); List<CIMInstance> hardwareIds = DiscoveryUtils.executeQuery(cimClient, hardwareIdPath, query, CQL); if (!hardwareIds.isEmpty()) { hardwareIdPaths.add(hardwareIds.get(0).getObjectPath()); } } Set<CIMObjectPath> maskPaths = new HashSet<CIMObjectPath>(); for (CIMObjectPath hardwareIdPath : hardwareIdPaths) { maskPaths.addAll(DiscoveryUtils.getAssociatorNames(cimClient, hardwareIdPath, null, SmisConstants.CIM_PROTOCOL_CONTROLLER, null, null)); } Set<CIMObjectPath> volumePathsInMasks = new HashSet<CIMObjectPath>(); Map<CIMObjectPath, String> volumeToPool = new HashMap<CIMObjectPath, String>(); for (CIMObjectPath path : maskPaths) { _logger.info("Processing masking view {}", path.toString()); List<CIMObjectPath> hardwareIdsInMask = DiscoveryUtils.getAssociatorNames(cimClient, path, null, SmisConstants.CIM_STORAGE_HARDWARE_ID, null, null); // check if the mask is shared or exclusive String maskType = hardwareIdPaths.containsAll(hardwareIdsInMask) ? ExportGroup.ExportGroupType.Host.name() : ExportGroup.ExportGroupType.Cluster.name(); List<CIMObjectPath> volumePaths = DiscoveryUtils.getAssociatorNames(cimClient, path, null, SmisConstants.CIM_STORAGE_VOLUME, null, null); for (CIMObjectPath volumePath : volumePaths) { if (ArrayAffinityDiscoveryUtils.isUnmanagedVolume(volumePath, dbClient)) { URI poolURI = ArrayAffinityDiscoveryUtils.getStoragePool(volumePath, cimClient, dbClient); if (!NullColumnValueGetter.isNullURI(poolURI)) { if (ExportGroup.ExportGroupType.Host.name().equals(maskType)) { volumePathsInMasks.add(volumePath); volumeToPool.put(volumePath, poolURI.toString()); } ArrayAffinityDiscoveryUtils.addPoolToPreferredPoolMap(preferredPoolMap, poolURI.toString(), maskType); } } } } for (CIMObjectPath volumePath : volumePathsInMasks) { // get masks from the volume path List<CIMObjectPath> masks = DiscoveryUtils.getAssociatorNames(cimClient, volumePath, null, SmisConstants.CIM_PROTOCOL_CONTROLLER, null, null); if (!maskPaths.containsAll(masks)) { // shared volumes _logger.info("Volume {} is shared by multiple hosts", volumePath); ArrayAffinityDiscoveryUtils.addPoolToPreferredPoolMap(preferredPoolMap, volumeToPool.get(volumePath), ExportGroup.ExportGroupType.Cluster.name()); } } return preferredPoolMap; } }