/* * Copyright (c) 2008-2014 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.plugins.discovery.smis.processor.ibm.xiv; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; import javax.cim.CIMInstance; import javax.cim.UnsignedInteger16; 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.constraint.AlternateIdConstraint; import com.emc.storageos.db.client.model.DiscoveredDataObject; import com.emc.storageos.db.client.model.StorageHADomain; import com.emc.storageos.db.client.model.StoragePool; import com.emc.storageos.db.client.model.StoragePort; import com.emc.storageos.db.client.model.StorageHADomain.HADomainType; import com.emc.storageos.db.client.model.StoragePort.OperationalStatus; import com.emc.storageos.db.client.model.StoragePort.PortType; import com.emc.storageos.db.client.model.StorageSystem; import com.emc.storageos.db.client.util.WWNUtility; import com.emc.storageos.plugins.AccessProfile; import com.emc.storageos.plugins.BaseCollectionException; import com.emc.storageos.plugins.common.Constants; import com.emc.storageos.plugins.common.domainmodel.Operation; import com.emc.storageos.volumecontroller.impl.NativeGUIDGenerator; import com.emc.storageos.volumecontroller.impl.StoragePoolAssociationHelper; import com.emc.storageos.volumecontroller.impl.StoragePortAssociationHelper; import com.emc.storageos.volumecontroller.impl.plugins.discovery.smis.processor.StoragePortProcessor; import com.emc.storageos.volumecontroller.impl.plugins.discovery.smis.processor.StorageProcessor; import com.google.common.base.Joiner; /** * Processor responsible for handling Provider response data and creates * Physical StoragePorts */ public class XIVStoragePortProcessor extends StorageProcessor { private Logger _logger = LoggerFactory .getLogger(XIVStoragePortProcessor.class); private static final String PORTNAME = "ElementName"; private static final String DEVICEID = "DeviceID"; private static final String SPEED = "Speed"; private static final String LINKTECHNOLOGY = "LinkTechnology"; private static final String USAGERESTRICTION = "UsageRestriction"; private static final String FC = "FC"; private static final String IP = "IP"; private static final String ISCSI = "iSCSI"; private static final String OPERATIONALSTATUS = "OperationalStatus"; private static final String IDENTIFYING_INFO = "OtherIdentifyingInfo"; private static final String IPPORT_CLASS_NAME = "IBMTSDS_EthernetPort"; private static final int GB = 1024 * 1024 * 1024; private AccessProfile _profile = null; private List<StoragePort> _newPortList = null; private List<StoragePort> _updatePortList = null; private DbClient _dbClient = null; /** * {@inheritDoc} */ @SuppressWarnings("unchecked") @Override public void processResult(Operation operation, Object resultObj, Map<String, Object> keyMap) throws BaseCollectionException { try { final Iterator<CIMInstance> it = (Iterator<CIMInstance>) resultObj; _profile = (AccessProfile) keyMap.get(Constants.ACCESSPROFILE); Set<String> protocols = (Set<String>) keyMap .get(Constants.PROTOCOLS); _newPortList = new ArrayList<StoragePort>(); _updatePortList = new ArrayList<StoragePort>(); _dbClient = (DbClient) keyMap.get(Constants.dbClient); Map<URI, StoragePool> poolsToMatchWithVpool = (Map<URI, StoragePool>) keyMap.get(Constants.MODIFIED_STORAGEPOOLS); StorageSystem device = _dbClient.queryObject(StorageSystem.class, _profile.getSystemId()); while (it.hasNext()) { CIMInstance portInstance = null; StoragePort port = null; try { portInstance = it.next(); String protocol = getCIMPropertyValue(portInstance, LINKTECHNOLOGY); String className = portInstance.getClassName(); // FC Port - 4 if ("4".equals(protocol)) { port = checkStoragePortExistsInDB(portInstance, device, _dbClient); checkProtocolAlreadyExists(protocols, FC); createStoragePort(port, portInstance, _profile, true, FC, device); } else if (IPPORT_CLASS_NAME.equals(className)) { port = createStoragePort(null, portInstance, _profile, false, IP, device); checkProtocolAlreadyExists(protocols, ISCSI); keyMap.put(portInstance.getObjectPath().toString(), port); addPath(keyMap, operation.getResult(), portInstance.getObjectPath()); } else { _logger.debug("Unsupported Port : {}", getCIMPropertyValue(portInstance, DEVICEID)); } } catch (Exception e) { _logger.warn("Port Discovery failed for {}", getCIMPropertyValue(portInstance, DEVICEID), e); } } _dbClient.createObject(_newPortList); _dbClient.persistObject(_updatePortList); // ports used later to run Transport Zone connectivity List<List<StoragePort>> portsUsedToRunTZoneConnectivity = (List<List<StoragePort>>) keyMap.get(Constants.STORAGE_PORTS); portsUsedToRunTZoneConnectivity.add(_newPortList); portsUsedToRunTZoneConnectivity.add(_updatePortList); List<StoragePool> modifiedPools = StoragePoolAssociationHelper.getStoragePoolsFromPorts(_dbClient, _newPortList, _updatePortList); for (StoragePool pool : modifiedPools) { // pool matcher will be invoked on this pool if (!poolsToMatchWithVpool.containsKey(pool.getId())) { poolsToMatchWithVpool.put(pool.getId(), pool); } } _logger.debug("# Pools used in invoking PoolMatcher during StoragePortProcessor {}", Joiner.on("\t").join(poolsToMatchWithVpool.keySet())); // discovered ports used later to check for not visible ports List<StoragePort> discoveredPorts = (List<StoragePort>) keyMap.get(Constants.DISCOVERED_PORTS); discoveredPorts.addAll(_newPortList); discoveredPorts.addAll(_updatePortList); // if the port's end point is in a transport zone, associate the the // port to the // transport zone. Also update the storage pools and varray // association if needed. StoragePortAssociationHelper.updatePortAssociations(_newPortList, _dbClient); StoragePortAssociationHelper.updatePortAssociations( _updatePortList, _dbClient); } catch (Exception e) { _logger.error("Port Discovery failed -->{}", getMessage(e)); } finally { _newPortList = null; _updatePortList = null; } } /** * Verify whether protocolType already exists or not. If it doesn't exist * then add. * * @param protocols * @param protocolType */ private void checkProtocolAlreadyExists(Set<String> protocols, String protocolType) { if (!protocols.contains(protocolType)) { protocols.add(protocolType); } } /** * create StoragePort Record, if not present already, else update only the * properties. * * @param port * @param portInstance * @param profile * @param isFCPort * @param transportType * @param device * * @throws URISyntaxException * @throws IOException * * @return StoragePort */ private StoragePort createStoragePort(StoragePort port, CIMInstance portInstance, AccessProfile profile, boolean isFCPort, String transportType, StorageSystem device) throws URISyntaxException, IOException { if (null == port) { port = new StoragePort(); port.setId(URIUtil.createId(StoragePort.class)); // Ethernet will be updated later in ProtocolEndPoint Processor if (isFCPort) { port.setPortNetworkId(WWNUtility .getWWNWithColons(getCIMPropertyValue(portInstance, PORTID))); _newPortList.add(port); } port.setStorageDevice(profile.getSystemId()); String portNativeGuid = NativeGUIDGenerator.generateNativeGuid( _dbClient, port); port.setNativeGuid(portNativeGuid); port.setLabel(portNativeGuid); } else { if (isFCPort) { _updatePortList.add(port); } } setPortType(port, portInstance); port.setTransportType(transportType); String[] identifiers = getCIMPropertyArrayValue(portInstance, IDENTIFYING_INFO); String moduleName = null; if (isFCPort) { moduleName = identifiers[0]; String portName = getCIMPropertyValue(portInstance, PORTNAME); port.setPortName(portName); } else { moduleName = identifiers[1]; port.setPortName(identifiers[1] + ":" + identifiers[0]); // port type is not set for ethernet port in SMI if (port.getPortType().equals(StoragePort.PortType.Unknown.name())) { port.setPortType(StoragePort.PortType.frontend.name()); } } port.setPortGroup(moduleName); StorageHADomain adapter = getStorageAdapter(moduleName, device); port.setStorageHADomain(adapter.getId()); port.setCompatibilityStatus(DiscoveredDataObject.CompatibilityStatus.COMPATIBLE .name()); port.setDiscoveryStatus(DiscoveredDataObject.DiscoveryStatus.VISIBLE.name()); UnsignedInteger16[] operationalStatusCodes = (UnsignedInteger16[]) portInstance .getPropertyValue(OPERATIONALSTATUS); OperationalStatus operationalStatus = StoragePortProcessor.getPortOperationalStatus(operationalStatusCodes); if (OperationalStatus.NOT_OK.equals(operationalStatus)) { _logger.info( "StoragePort {} operationalStatus is NOT_OK. operationalStatusCodes collected from SMI-S :{}", port.getId(), operationalStatusCodes); } else { _logger.debug("operationalStatusCodes: {}", operationalStatusCodes); } port.setOperationalStatus(operationalStatus.name()); String portSpeed = getCIMPropertyValue(portInstance, SPEED); if (null != portSpeed) { // SMI returns port speed in bits per sec Long portSpeedInBitsPerSec = Long.parseLong(portSpeed); Long portSpeedInGbps = portSpeedInBitsPerSec / GB; port.setPortSpeed(portSpeedInGbps); } return port; } private void setPortType(StoragePort port, CIMInstance portInstance) { String portType = getCIMPropertyValue(portInstance, USAGERESTRICTION); if ("2".equalsIgnoreCase(portType)) { port.setPortType(PortType.frontend.name()); } else if ("3".equalsIgnoreCase(portType)) { port.setPortType(PortType.backend.name()); } else { port.setPortType(PortType.Unknown.name()); } } /** * Returns StorageAdapter instance. Create one, if not present already * * @param name adapter (module) name * @param device StorageSystem * @return instance of StorageHADomain * @throws URISyntaxException * @throws IOException */ private StorageHADomain getStorageAdapter(String name, StorageSystem device) throws URISyntaxException, IOException { StorageHADomain adapter = null; String nativeGuid = NativeGUIDGenerator.generateNativeGuid( device, name, NativeGUIDGenerator.ADAPTER); @SuppressWarnings("deprecation") List<URI> adapterURIs = _dbClient .queryByConstraint(AlternateIdConstraint.Factory .getStorageHADomainByNativeGuidConstraint(nativeGuid)); if (!adapterURIs.isEmpty()) { adapter = _dbClient.queryObject(StorageHADomain.class, adapterURIs.get(0)); } if (adapter == null) { adapter = new StorageHADomain(); adapter.setId(URIUtil.createId(StorageHADomain.class)); adapter.setStorageDeviceURI(device.getId()); adapter.setName(name); adapter.setAdapterName(name); adapter.setNativeGuid(nativeGuid); adapter.setAdapterType(HADomainType.FRONTEND.name()); adapter.setVirtual(true); // note serial number and number of ports is not set adapter.setProtocol("3"); // 3 is "mixed", to be consistent with EMC provider // slot number is used in port selection adapter.setSlotNumber(name.split(Pattern.quote(Constants.COLON))[2]); // e.g., name="1:Module:6", 6 is the module _dbClient.createObject(adapter); } return adapter; } }