/* * Copyright (c) 2012 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.hds.prov.utils; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; import org.milyn.payload.JavaResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.model.StoragePool; import com.emc.storageos.db.client.model.StoragePort; import com.emc.storageos.db.client.model.StorageProvider; import com.emc.storageos.db.client.model.StorageProvider.ConnectionStatus; import com.emc.storageos.db.client.model.StorageSystem; import com.emc.storageos.db.client.model.Volume; import com.emc.storageos.hds.HDSConstants; import com.emc.storageos.hds.HDSException; import com.emc.storageos.hds.api.HDSApiClient; import com.emc.storageos.hds.api.HDSApiFactory; import com.emc.storageos.hds.model.EchoCommand; import com.emc.storageos.hds.model.Error; import com.emc.storageos.hds.model.HostStorageDomain; import com.emc.storageos.hds.model.ISCSIName; import com.emc.storageos.hds.model.Pool; import com.emc.storageos.hds.model.WorldWideName; import com.emc.storageos.plugins.AccessProfile; import com.google.common.base.Function; import com.google.common.base.Splitter; import com.google.common.collect.Iterables; public class HDSUtils { private static final Logger log = LoggerFactory.getLogger(HDSUtils.class); public static void updateStoragePoolCapacity(DbClient dbClient, HDSApiClient client, StoragePool storagePool) { StorageSystem storageSystem = null; try { storageSystem = dbClient.queryObject(StorageSystem.class, storagePool.getStorageDevice()); log.info(String.format("Old storage pool capacity data for %n pool %s/%s --- %n free capacity: %s; subscribed capacity: %s", storageSystem.getId(), storagePool.getId(), storagePool.calculateFreeCapacityWithoutReservations(), storagePool.getSubscribedCapacity())); String poolObjectId = getPoolObjectID(storagePool); String systemObjectId = getSystemObjectID(storageSystem); Pool hdsStoragePool = client.getStoragePoolInfo(systemObjectId, poolObjectId); // Update storage pool and save to data base storagePool.setFreeCapacity(hdsStoragePool.getFreeCapacity()); // @TODO need to see how to get subscribed capacity of the hds pool // storagePool.setSubscribedCapacity(ControllerUtils.convertBytesToKBytes(subscribedCapacity)); log.info(String.format("New storage pool capacity data for pool %n %s/%s --- %n free capacity: %s; subscribed capacity: %s", storageSystem.getId(), storagePool.getId(), storagePool.getFreeCapacity(), storagePool.getSubscribedCapacity())); dbClient.persistObject(storagePool); } catch (Exception ex) { log.error( String.format( "Failed to update capacity of storage pool after volume provisioning operation. %n Storage system: %s, storage pool %s .", storageSystem.getId(), storagePool.getId()), ex); } } /** * Return pool objectID from Pool NativeGuid. * * @param storagePool * @return */ public static String getPoolObjectID(StoragePool storagePool) { Iterable<String> splitter = Splitter.on(HDSConstants.PLUS_OPERATOR).limit(4) .split(storagePool.getNativeGuid()); return Iterables.getLast(splitter); } /** * Return port objectID from Port NativeGuid. * * @param storagePort * @return */ public static String getPortObjectID(StoragePort storagePort) { Iterable<String> splitter = Splitter.on(HDSConstants.PLUS_OPERATOR).limit(4) .split(storagePort.getNativeGuid()); return Iterables.getLast(splitter); } /** * Return portid from Port NativeGuid. * * @param storagePort * @return */ public static String getPortID(StoragePort storagePort) { Iterable<String> splitter = Splitter.on(HDSConstants.DOT_OPERATOR).limit(4) .split(storagePort.getNativeGuid()); return Iterables.getLast(splitter); } /** * Generates the HiCommand Device Manager Server URI. * * Sample HDS mgmt server: http://lglak148:2001/service/StorageManager * * @param system : Storage System details * @return : URI of the Device Manager. * @throws URISyntaxException */ public static URI getHDSServerManagementServerInfo(StorageSystem system) throws URISyntaxException { String protocol = HDSConstants.HTTP_URL; if (Boolean.TRUE.equals(system.getSmisUseSSL())) { protocol = HDSConstants.HTTPS_URL; } String ipAddress = system.getSmisProviderIP(); int portNumber = system.getSmisPortNumber(); URI uri = new URI(protocol, null, ipAddress, portNumber, HDSConstants.HDS_DM_MGMT_URL_PATH, null, null); return uri; } /** * Generates the HiCommand Device Manager Server URI. * * Sample HDS mgmt server: http://lglak148:2001/service/StorageManager * * @param system : Storage System details * @return : URI of the Device Manager. * @throws URISyntaxException */ public static URI getHDSServerManagementServerInfo(StorageProvider storageProvider) throws URISyntaxException { String protocol = HDSConstants.HTTP_URL; if (Boolean.TRUE.equals(storageProvider.getUseSSL())) { protocol = HDSConstants.HTTPS_URL; } String ipAddress = storageProvider.getIPAddress(); int portNumber = storageProvider.getPortNumber(); URI uri = new URI(protocol, null, ipAddress, portNumber, HDSConstants.HDS_DM_MGMT_URL_PATH, null, null); log.debug("HiCommand DM server url to query: {}", uri); return uri; } /** * Generates the HiCommand Device Manager Server URI. * * Sample HDS mgmt server: http://lglak148:2001/service/StorageManager * * @param system : Storage System details * @return : URI of the Device Manager. * @throws URISyntaxException */ public static URI getHDSServerManagementServerInfo(AccessProfile accessProfile) throws URISyntaxException { String protocol = HDSConstants.HTTP_URL; if (Boolean.parseBoolean(accessProfile.getSslEnable())) { protocol = HDSConstants.HTTPS_URL; } String ipAddress = accessProfile.getIpAddress(); int portNumber = accessProfile.getPortNumber(); URI uri = new URI(protocol, null, ipAddress, portNumber, HDSConstants.HDS_DM_MGMT_URL_PATH, null, null); return uri; } /** * Return the storage system objectID. * * @param system * @return */ public static String getSystemObjectID(StorageSystem system) { Iterable<String> systemSplitter = Splitter.on(HDSConstants.PLUS_OPERATOR).limit(2).split(system.getNativeGuid()); return Iterables.getLast(systemSplitter); } public static String getSystemModelSerialNum(StorageSystem system) { Iterable<String> systemSplitter = Splitter.on(HDSConstants.DOT_OPERATOR).limit(2).split(system.getNativeGuid()); return Iterables.getLast(systemSplitter); } public static String getSystemArrayType(StorageSystem storageSystem) { return (storageSystem.getNativeGuid().split("\\."))[1]; } public static String getSystemSerialNumber(StorageSystem system) { Iterable<String> systemSplitter = Splitter.on(HDSConstants.DOT_OPERATOR).limit(4).split(system.getNativeGuid()); return Iterables.getLast(systemSplitter); } /** * makes simple rest call to device manager to validate the provider reachable state for passed hds providers * * @param hicommandProviderList List of HiCommandDevice Manager provider URIs * @param dbClient * @param hdsApiFactory * @return List of Active Storage Providers */ public static List<URI> refreshHDSConnections(final List<StorageProvider> hicommandProviderList, DbClient dbClient, HDSApiFactory hdsApiFactory) { List<URI> activeProviders = new ArrayList<URI>(); for (StorageProvider storageProvider : hicommandProviderList) { try { HDSApiClient hdsApiClient = hdsApiFactory.getClient( HDSUtils.getHDSServerManagementServerInfo(storageProvider), storageProvider.getUserName(), storageProvider.getPassword()); // Makes sure "Hi Command Device manager" is reachable hdsApiClient.getStorageSystemsInfo(); storageProvider.setConnectionStatus(ConnectionStatus.CONNECTED.name()); activeProviders.add(storageProvider.getId()); log.info("Storage Provider {} is reachable", storageProvider.getIPAddress()); } catch (Exception e) { log.error(e.getMessage(), e); storageProvider.setConnectionStatus(ConnectionStatus.NOTCONNECTED.name()); log.error("Storage Provider {} is not reachable", storageProvider.getIPAddress()); } finally { dbClient.persistObject(storageProvider); } } return activeProviders; } /** * Generate LogicalUnit ObjectId from volume nativeId & system. * Ex. LU.HM700.211643.87 * * @param nativeId * @return */ public static String getLogicalUnitObjectId(String nativeId, StorageSystem system) { StringBuffer luObjectId = new StringBuffer(HDSConstants.LU) .append(HDSConstants.DOT_OPERATOR); luObjectId.append(getSystemModelSerialNum(system)) .append(HDSConstants.DOT_OPERATOR).append(nativeId); return luObjectId.toString(); } /** * Generates the WWN of the volume manually. * This is a partial WWN which is a combination of serialNum + volumeId (in Hex format.) * * @param luObjectID * @param volumeNativeId * @return */ public static String generateHitachiWWN(String luObjectID, String volumeNativeId) { String arraySerialNum = luObjectID.split("\\.")[2]; String arraySerialNumInHex = null; if (luObjectID.contains(HDSConstants.HUSVM_MODEL)) { // for HUS VM, we should ignore the first digit. arraySerialNumInHex = Integer.toHexString(Integer.parseInt(arraySerialNum .substring(1))); } else if (luObjectID.contains(HDSConstants.VSP_G1000_MODEL)) { // for VSP G100, arraySerialNumInHex = Integer.toHexString(Integer.parseInt(arraySerialNum)); } else { arraySerialNumInHex = String.format("%08x", Integer .parseInt(arraySerialNum)); } StringBuffer generatedWWN = new StringBuffer(arraySerialNumInHex); String volumeIdInHexa = String.format("%08x", Integer .parseInt(volumeNativeId)); generatedWWN.append(volumeIdInHexa); return generatedWWN.toString().toUpperCase(); } /** * Generates the WWN of the volume manually for a given system and volume id. * This is a partial WWN which is a combination of serialNum + volumeId (in Hex format.) * * @param luObjectID * @param volumeNativeId * @return */ public static String generateHitachiVolumeWWN(StorageSystem storage, String volumeNativeId) { String arraySerialNumInHex = null; String serialNum = storage.getSerialNumber(); if (storage.getModel().equalsIgnoreCase(HDSConstants.HUSVM_ARRAYFAMILY_MODEL)) { // for HUS VM, we should ignore the first digit. arraySerialNumInHex = Integer.toHexString(Integer.parseInt(serialNum .substring(1))); } else if (storage.getModel().contains(HDSConstants.VSP_G1000_ARRAYFAMILY_MODEL)) { // for VSP G100, arraySerialNumInHex = Integer.toHexString(Integer.parseInt(serialNum)); } else { arraySerialNumInHex = String.format("%08x", Integer .parseInt(serialNum)); } StringBuffer generatedWWN = new StringBuffer(arraySerialNumInHex); String volumeIdInHexa = String.format("%08x", Integer .parseInt(volumeNativeId)); generatedWWN.append(volumeIdInHexa); return generatedWWN.toString().toUpperCase(); } /** * Utility method to check if there are any errors or not. * * @param javaResult * @throws Exception */ public static void verifyErrorPayload(JavaResult javaResult) throws Exception { EchoCommand command = javaResult.getBean(EchoCommand.class); if (null == command || null == command.getStatus() || HDSConstants.FAILED_STR.equalsIgnoreCase(command.getStatus())) { Error error = javaResult.getBean(Error.class); // log.info("Error response received from Hitachi server for messageID", command.getMessageID()); log.info("Hitachi command failed with error code:{} with message:{} for request:{}", new Object[] { error.getCode().toString(), error.getDescription(), error.getSource() }); throw HDSException.exceptions.errorResponseReceived( error.getCode(), error.getDescription()); } } public static boolean isVolumeModifyApplicable(URI volumeURI, DbClient dbClient) { Volume volume = dbClient.queryObject(Volume.class, volumeURI); return volume.getThinlyProvisioned() && null != volume.getAutoTieringPolicyUri(); } public static HDSApiClient getHDSApiClient(HDSApiFactory apiFactory, StorageSystem storageSystem) throws URISyntaxException { HDSApiClient apiClient = apiFactory.getClient( HDSUtils.getHDSServerManagementServerInfo(storageSystem), storageSystem.getSmisUserName(), storageSystem.getSmisPassword()); ; return apiClient; } /** * Check whether the given storageSystem is AMS series model or not. * * @param storageSystem * @return */ public static boolean checkForAMSSeries(StorageSystem storageSystem) { return (storageSystem.getModel() != null && storageSystem.getModel().startsWith(HDSConstants.AMS_SERIES_MODEL)); } /** * Check whether the given storageSystem is HUSXXX model or not. * * @param storageSystem * @return */ public static boolean checkForHUSSeries(StorageSystem storageSystem) { return (storageSystem.getModel() != null && storageSystem.getModel().startsWith(HDSConstants.HUS_SERIES_MODEL) && !storageSystem.getModel().equalsIgnoreCase(HDSConstants.HUSVM_MODEL)); } /** * Return the IPAddress from a given input string. * * @param name * @param limit * @return */ public static String extractIpAddress(String name, int limit, String delimiter) { Iterable<String> splitter = Splitter.on(delimiter).limit(limit) .split(name); return Iterables.getLast(splitter); } /** * Return a list of ISCSINames for the given list of initiatorName's. * * @return List of ISCSINames */ public static Function<String, ISCSIName> fctnPortNameToISCSIName() { return new Function<String, ISCSIName>() { @Override public ISCSIName apply(String portName) { return new ISCSIName(portName, null); } }; } /** * Return WorldWideName for the given portWWN string. * This utility will be used google collections2 framework * to convert List of port WWN's to list of WorldWideName objects. * * @return WorldWideName. */ public static Function<String, WorldWideName> fctnPortWWNToWorldWideName() { return new Function<String, WorldWideName>() { @Override public WorldWideName apply(String portWWN) { return new WorldWideName(portWWN); } }; } /** * Return a nickName for the given HSD object. * This utility is used by google collections2 framework * to convert List of HSD objects to a List of HSD nicknames. * * @return HSD nickName. */ public static Function<HostStorageDomain, String> fctnHSDToNickName() { return new Function<HostStorageDomain, String>() { @Override public String apply(HostStorageDomain hsd) { return hsd.getNickname(); } }; } }