/* * Copyright (c) 2008-2013 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.plugins; import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import javax.cim.CIMInstance; import javax.cim.CIMObjectPath; import javax.wbem.WBEMException; import javax.wbem.client.WBEMClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.cimadapter.connections.cim.CimConnection; import com.emc.storageos.cimadapter.connections.cim.CimObjectPathCreator; import com.emc.storageos.db.client.model.DiscoveredDataObject.Type; import com.emc.storageos.db.client.model.Stat; 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.StorageSystem; import com.emc.storageos.db.client.model.StringSet; import com.emc.storageos.db.client.util.NullColumnValueGetter; import com.emc.storageos.db.exceptions.DatabaseException; import com.emc.storageos.plugins.AccessProfile; import com.emc.storageos.plugins.BaseCollectionException; import com.emc.storageos.plugins.StorageSystemViewObject; import com.emc.storageos.plugins.common.Constants; import com.emc.storageos.plugins.common.domainmodel.Namespace; import com.emc.storageos.plugins.common.domainmodel.NamespaceList; import com.emc.storageos.plugins.metering.smis.SMIPluginException; import com.emc.storageos.volumecontroller.impl.plugins.discovery.smis.processor.detailedDiscovery.LocalReplicaObject; import com.emc.storageos.volumecontroller.impl.plugins.discovery.smis.processor.detailedDiscovery.RemoteMirrorObject; import com.emc.storageos.volumecontroller.impl.plugins.metering.smis.SMIExecutor; import com.emc.storageos.volumecontroller.impl.smis.CIMConnectionFactory; import com.google.common.collect.Sets; /** * This class is responsible for collecting statistics information from SMI * Providers. Isilon plugin should implement this interface * ICommunicationInterface,and have their own logic of collecting statistics * information. */ public class SMICommunicationInterface extends ExtendedCommunicationInterfaceImpl { private static final Logger _logger = LoggerFactory .getLogger(SMICommunicationInterface.class); private SMIExecutor executor; private WBEMClient _wbemClient; private boolean debug; private NamespaceList namespaces; /** * To-Do : Argument Changes, to accomodate ProSphere usage */ @Override public void collectStatisticsInformation(AccessProfile accessProfile) throws BaseCollectionException { try { _logger.info("Access Profile Details :" + accessProfile.toString()); _wbemClient = getCIMClient(accessProfile); initMap(accessProfile); StorageSystem storageSystem = queryStorageSystem(accessProfile); String providerVersion = getProviderVersionString(storageSystem); if (null != providerVersion) { _keyMap.put(Constants.VERSION, providerVersion); _keyMap.put(Constants.IS_NEW_SMIS_PROVIDER, isSMIS8XProvider(providerVersion)); } Namespace _ns = null; _ns = (Namespace) namespaces.getNsList().get(METERING); _logger.info("CIMClient initialized successfully"); executor.setKeyMap(_keyMap); executor.execute(_ns); dumpStatRecords(); injectStats(); } catch (Exception e) { throw new SMIPluginException(e.getMessage()); } finally { releaseResources(); } } /** * Initialize the Map * * @param _keyMap * @param cacheVolumes * @param cachePools * @param accessProfile */ private void initMap(AccessProfile accessProfile) { _keyMap.put(Constants._computerSystem, CimObjectPathCreator.createInstance(Constants._cimSystem, accessProfile.getInteropNamespace())); _keyMap.put(Constants._cimClient, _wbemClient); _keyMap.put(Constants._serialID, accessProfile.getserialID()); _keyMap.put(Constants.dbClient, _dbClient); if (_networkDeviceController != null) { _keyMap.put(Constants.networkDeviceController, _networkDeviceController); } _keyMap.put(Constants._Volumes, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants._nativeGUIDs, Sets.newHashSet()); _keyMap.put(Constants._Stats, new LinkedList<Stat>()); _keyMap.put(Constants._InteropNamespace, accessProfile.getInteropNamespace()); _keyMap.put(Constants._debug, debug); _keyMap.put(Constants.ACCESSPROFILE, accessProfile); List<String> manifestCollectionList = new LinkedList<String>(); manifestCollectionList.add(Constants.MANIFEST_COLLECTION_NAME); _keyMap.put(Constants.MANIFEST_EXISTS, manifestCollectionList); _keyMap.put(Constants.PROPS, accessProfile.getProps()); // Add storagePool Object path & LinkedList<CIMObjectPath> to Map _keyMap.put(Constants._storagePool, CimObjectPathCreator.createInstance(Constants._cimPool, accessProfile.getInteropNamespace())); _keyMap.put(Constants.STORAGEPOOLS, new LinkedList<CIMObjectPath>()); } /** * Return a WBEMClient instance based on the access profile found in the discovery context. * * NOTE: https://coprhd.atlassian.net/browse/COP-20454 * The reason this method is added and used is because it calls the ConnectionManager * to retrieve the client. When this is done, client connection will be refreshed so * that the Connection reaper (if it enabled/running) will not close the connection while * it's being used in a discovery Processor. * * @param discoveryContext [IN] - Discovery context map containing parameters and discovery results * @return WBEMClient based on the AccessProfile found in the discovery context. */ public static WBEMClient getCIMClient(Map<String, Object> discoveryContext) { AccessProfile accessProfile = (AccessProfile) discoveryContext.get(Constants.ACCESSPROFILE); assert (accessProfile != null); return getCIMClient(accessProfile); } /** * Creates a new WEBClient for a given IP, based on AccessProfile * * @param accessProfile * : AccessProfile for the providers * @throws WBEMException * : if WBEMException while creating the WBEMClient * @throws SMIPluginException * @return WBEMClient : initialized instance of WBEMClientCIMXML */ private static WBEMClient getCIMClient(AccessProfile accessProfile) throws SMIPluginException { WBEMClient cimClient = null; try { final CIMConnectionFactory connectionFactory = (CIMConnectionFactory) accessProfile .getCimConnectionFactory(); CimConnection cxn = connectionFactory.getConnection( accessProfile.getIpAddress(), accessProfile.getProviderPort()); if (cxn == null) { throw new SMIPluginException(String.format( "Not able to get CimConnection to SMISProvider %s on port %s", accessProfile.getIpAddress(), accessProfile.getProviderPort()), SMIPluginException.ERRORCODE_NO_WBEMCLIENT); } cimClient = cxn.getCimClient(); if (null == cimClient) { throw new SMIPluginException("Not able to get CIMOM client", SMIPluginException.ERRORCODE_NO_WBEMCLIENT); } } catch (final IllegalStateException ex) { _logger.error("Not able to get CIMOM Client instance for ip {} due to ", accessProfile.getIpAddress(), ex); throw new SMIPluginException(SMIPluginException.ERRORCODE_NO_WBEMCLIENT, ex.fillInStackTrace(), ex.getMessage()); } return cimClient; } /** * Stop the Plugin Thread, by gracefully clearing its resources. */ @Override public void cleanup() { _logger.info("Stopping the Plugin Thread and clearing Resources"); releaseResources(); } /** * releaseResources */ private void releaseResources() { execServiceShut(); _keyMap.clear(); namespaces = null; } /** * Shut Down Executor */ private void execServiceShut() { ExecutorService execService = executor.getExecService(); /* * Threads spawned using ExecutorService, mostly stuck in Blocking IOs, * not responsible to interruption. Currently, we don't have the handle * to get the underlying socket, so that altleast we can close it. The * alternate way used to handle this scenario, is to introduce timeout * to Blocking Calls.We have used set timeout value, for each SMI Call * to Provider, by this way we would be able to step out, if the SMI * call got stuck in-between. shutDownNow is used instead of shutdown, * as the call to Stop has arrived after a expected finish time of say x * minutes, and there is no point in waiting for the threads which got * spawned by Executor Service to complete. Hence, shutDownNow is * used.As timeout has been introduced in Blocking Calls, this should * not raise a concern on threads getting abruptly shutting down To-Do: * Find out ways to get the underlying socket, so that we can gracefully * clean those threads, instead of abruptly shutting down. */ execService.shutdown(); try { execService.awaitTermination(120, TimeUnit.SECONDS); } catch (Exception e) { // To-DO: filter it for timeout sException // No need to throw any exception _logger.info("TimeOut occured after waiting Client Threads to finish"); } } public void setExecutor(SMIExecutor executor) { this.executor = executor; } public SMIExecutor getExecutor() { return executor; } public void setDebug(boolean debugValue) { debug = debugValue; } public void setNamespaces(NamespaceList namespaces) { this.namespaces = namespaces; } public NamespaceList getNamespaces() { return namespaces; } /** * {@inheritDoc} */ @Override public void scan(AccessProfile accessProfile) throws BaseCollectionException { URI providerURI = null; StorageProvider providerObj = null; String detailedStatusMessage = "Unknown Status"; try { _logger.info("Access Profile Details :" + accessProfile.toString()); providerURI = accessProfile.getSystemId(); providerObj = _dbClient.queryObject(StorageProvider.class, providerURI); _keyMap = new ConcurrentHashMap<String, Object>(); _wbemClient = getCIMClient(accessProfile); _logger.info("CIMClient initialized successfully"); _keyMap.put(Constants.PROPS, accessProfile.getProps()); if (accessProfile.getCache() == null) { accessProfile.setCache(new HashMap<String, StorageSystemViewObject>()); } _keyMap.put(Constants._computerSystem, new ArrayList<CIMObjectPath>()); _keyMap.put(Constants.REGISTEREDPROFILE, CimObjectPathCreator.createInstance( Constants.PROFILECLASS, "interop")); _keyMap.put(Constants._cimClient, _wbemClient); _keyMap.put(Constants.dbClient, _dbClient); _keyMap.put(Constants.COORDINATOR_CLIENT, _coordinator); if (_networkDeviceController != null) { _keyMap.put(Constants.networkDeviceController, _networkDeviceController); } _keyMap.put(Constants._InteropNamespace, accessProfile.getInteropNamespace()); _keyMap.put(Constants.ACCESSPROFILE, accessProfile); _keyMap.put(Constants.SYSTEMCACHE, accessProfile.getCache()); executor.setKeyMap(_keyMap); executor.execute((Namespace) namespaces.getNsList().get(SCAN)); // scan succeeds detailedStatusMessage = String.format("Scan job completed successfully for " + "SMISProvider: %s", providerURI.toString()); } catch (Exception e) { detailedStatusMessage = String.format("Scan job failed for SMISProvider: %s because %s", providerURI.toString(), e.getMessage()); throw new SMIPluginException(detailedStatusMessage); } finally { if (providerObj != null) { try { // set detailed message providerObj.setLastScanStatusMessage(detailedStatusMessage); _dbClient.persistObject(providerObj); } catch (DatabaseException ex) { _logger.error("Error while persisting object to DB", ex); } } releaseResources(); } } /** * {@inheritDoc} */ @Override public void discover(AccessProfile accessProfile) throws BaseCollectionException { URI storageSystemURI = null; StorageSystem storageSystem = null; String detailedStatusMessage = "Unknown Status"; long startTime = System.currentTimeMillis(); try { _logger.info("Access Profile Details :" + accessProfile.toString()); storageSystemURI = accessProfile.getSystemId(); storageSystem = queryStorageSystem(accessProfile); _keyMap = new ConcurrentHashMap<String, Object>(); _wbemClient = getCIMClient(accessProfile); _logger.info("CIMClient initialized successfully"); _keyMap.put(Constants._cimClient, _wbemClient); _keyMap.put(Constants.dbClient, _dbClient); _keyMap.put(Constants.COORDINATOR_CLIENT, _coordinator); if (_networkDeviceController != null) { _keyMap.put(Constants.networkDeviceController, _networkDeviceController); } _keyMap.put(Constants.PROPS, accessProfile.getProps()); _keyMap.put(Constants._InteropNamespace, accessProfile.getInteropNamespace()); _keyMap.put(Constants.ACCESSPROFILE, accessProfile); _keyMap.put(Constants.SYSTEMID, accessProfile.getSystemId()); _keyMap.put(Constants._serialID, accessProfile.getserialID()); _keyMap.put(Constants.STORAGEPOOLS, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.PROTOCOLS, new HashSet<String>()); _keyMap.put(Constants.STORAGEETHERNETPORTS, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.IPENDPOINTS, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.STORAGEVOLUMES, new LinkedList<CIMObjectPath>()); String providerVersion = getProviderVersionString(storageSystem); if (null != providerVersion) { _keyMap.put(Constants.VERSION, providerVersion); _keyMap.put(Constants.IS_NEW_SMIS_PROVIDER, isSMIS8XProvider(providerVersion)); } Map<URI, StoragePool> poolsToMatchWithVpool = new HashMap<URI, StoragePool>(); _keyMap.put(Constants.MODIFIED_STORAGEPOOLS, poolsToMatchWithVpool); // need this nested structure to be able to minimize the changes on existing code. List<List<StoragePort>> portsToRunNetworkConnectivity = new ArrayList<List<StoragePort>>(); _keyMap.put(Constants.STORAGE_PORTS, portsToRunNetworkConnectivity); List<StoragePort> discoveredPorts = new ArrayList<StoragePort>(); _keyMap.put(Constants.DISCOVERED_PORTS, discoveredPorts); _keyMap.put(Constants.SLO_NAMES, new HashSet<String>()); if (Type.ibmxiv.name().equals(accessProfile.getSystemType())) { initIBMDiscoveryKeyMap(accessProfile); } else { initEMCDiscoveryKeyMap(accessProfile); } executor.setKeyMap(_keyMap); executor.execute((Namespace) namespaces.getNsList().get(DISCOVER)); } catch (Exception e) { detailedStatusMessage = String.format("Discovery failed for Storage System: %s because %s", storageSystemURI.toString(), e.getMessage()); _logger.error(detailedStatusMessage, e); throw new SMIPluginException(detailedStatusMessage); } finally { if (storageSystem != null) { try { // set detailed message storageSystem.setLastDiscoveryStatusMessage(detailedStatusMessage); _dbClient.persistObject(storageSystem); } catch (DatabaseException ex) { _logger.error("Error while persisting object to DB", ex); } } releaseResources(); long totalTime = System.currentTimeMillis() - startTime; _logger.info(String.format("Discovery of Storage System %s took %f seconds", storageSystemURI.toString(), (double) totalTime / (double) 1000)); } } private StorageSystem queryStorageSystem(AccessProfile accessProfile) throws IOException { return _dbClient.queryObject(StorageSystem.class, accessProfile.getSystemId()); } private void initEMCDiscoveryKeyMap(AccessProfile accessProfile) { _keyMap.put(Constants._computerSystem, CimObjectPathCreator.createInstance( Constants.EmcStorageSystem, accessProfile.getInteropNamespace())); _keyMap.put(Constants.TIER, CimObjectPathCreator.createInstance( Constants.EMC_STORAGE_TIER, accessProfile.getInteropNamespace())); _keyMap.put(Constants.CONFIGURATIONSERVICE, CimObjectPathCreator.createInstance( Constants.EMCCONTROLLERCONFIGURATIONSERVICE, accessProfile.getInteropNamespace())); _keyMap.put(Constants.TIERPOLICYSERVICE, CimObjectPathCreator.createInstance( Constants.EMCTIERPOLICYSERVICE, accessProfile.getInteropNamespace())); _keyMap.put(Constants.STORAGE_VOLUME_VIEWS, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.DEVICEANDTHINPOOLS, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.THINPOOLS, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.STORAGEPROCESSORS, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.POOLCAPABILITIES, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.STORAGETIERS, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.REPLICATIONGROUPS, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.VMAXFASTPOLICIES, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.VNXFASTPOLICIES, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.VNXPOOLCAPABILITIES, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.VNXPOOLCAPABILITIES_TIER, new LinkedList<String>()); _keyMap.put(Constants.VNXPOOLSETTINGS, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.VNXPOOLS, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.VMAXPOOLS, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.VMAX2POOLS, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.VMAX2_THIN_POOLS, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.TIERDOMAINS, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.MASKING_VIEWS, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.VNXPOOLSETTINGINSTANCES, new LinkedList<CIMInstance>()); _keyMap.put(Constants.MASKING_GROUPS, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.ENDPOINTS_RAGROUP, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.VOLUME_RAGROUP, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.UN_VOLUMES_RAGP, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.SRDF_LINKS, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.STORAGE_GROUPS, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.AUTO_TIER_VOLUMES, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.EVENT_MANAGER, accessProfile.getRecordableEventManager()); Set<URI> systemsToRunRPConnectivity = new HashSet<URI>(); _keyMap.put(Constants.SYSTEMS_RUN_RP_CONNECTIVITY, systemsToRunRPConnectivity); Map<String, RemoteMirrorObject> unManagedVolToRaGroupMap = new HashMap<String, RemoteMirrorObject>(); _keyMap.put(Constants.UN_VOLUME_RAGROUP_MAP, unManagedVolToRaGroupMap); Map<String, String> policyToGroupMap = new HashMap<String, String>(); _keyMap.put(Constants.POLICY_STORAGE_GROUP_MAPPING, policyToGroupMap); Map<String, String> volumesWithSLO = new HashMap<String, String>(); _keyMap.put(Constants.VOLUMES_WITH_SLOS, volumesWithSLO); Map<String, String> volumeToSpaceConsumedMap = new HashMap<String, String>(); _keyMap.put(Constants.VOLUME_SPACE_CONSUMED_MAP, volumeToSpaceConsumedMap); Map<String, Set<String>> vmax2ThinPoolToBoundVolumesMap = new HashMap<String, Set<String>>(); _keyMap.put(Constants.VMAX2_THIN_POOL_TO_BOUND_VOLUMES, vmax2ThinPoolToBoundVolumesMap); // modifiedSettingInstances _keyMap.put(Constants.MODIFIED_SETTING_INSTANCES, new LinkedList<CIMInstance>()); _keyMap.put(Constants.SYSTEMCREATEDDEVICEGROUPNAMES, new LinkedList<String>()); _keyMap.put(Constants.USED_IN_CHECKING_GROUPNAMES_EXISTENCE, new LinkedList<String>()); _keyMap.put(Constants.USED_IN_CHECKING_GROUPNAMES_TO_FASTPOLICY, new LinkedList<String>()); _keyMap.put(Constants.REPLICATIONSERVICE, new LinkedList<CIMObjectPath>()); _keyMap.put("connectivityCollection", new LinkedList<CIMObjectPath>()); Map<String, URI> raGroupMap = new HashMap<String, URI>(); _keyMap.put(Constants.RAGROUP, raGroupMap); // deviceMaskingGroups _keyMap.put(Constants.DEVICEMASKINGROUPS, new LinkedList<CIMObjectPath>()); _keyMap.put(Constants.FASTPOLICY, CimObjectPathCreator.createInstance( Constants.CIMFASTPOLICYRULE, accessProfile.getInteropNamespace())); // deviceMaskingGroups Map<String, Set<String>> policytopoolMapping = new HashMap<String, Set<String>>(); _keyMap.put(Constants.POLICY_TO_POOLS_MAPPING, policytopoolMapping); Map<String, StringSet> volumeToStorageGroupMapping = new HashMap<String, StringSet>(); _keyMap.put(Constants.VOLUME_STORAGE_GROUP_MAPPING, volumeToStorageGroupMapping); Map<String, Set<Integer>> initiatorToHLU = new HashMap<String, Set<Integer>>(); _keyMap.put(Constants.INITIATOR_HLU_MAP, initiatorToHLU); // unmanaged volume (local mirrors/snapshots) discovery Map<String, LocalReplicaObject> unManagedVolToLocalReplicaMap = new HashMap<String, LocalReplicaObject>(); _keyMap.put(Constants.UN_VOLUME_LOCAL_REPLICA_MAP, unManagedVolToLocalReplicaMap); Map<String, Map<String, String>> snapshotToSynchronizationAspectMap = new HashMap<String, Map<String, String>>(); _keyMap.put(Constants.SNAPSHOT_NAMES_SYNCHRONIZATION_ASPECT_MAP, snapshotToSynchronizationAspectMap); Map<String, StringSet> volumeToExportMasksHLUMap = new HashMap<String, StringSet>(); _keyMap.put(Constants.UN_VOLUME_EXPORT_MASK_HLUS_MAP, volumeToExportMasksHLUMap); } private void initIBMDiscoveryKeyMap(AccessProfile accessProfile) { _keyMap.put(Constants._computerSystem, CimObjectPathCreator.createInstance( Constants.IBM_STORAGE_SYSTEM, accessProfile.getInteropNamespace())); } /** * Return the provider version. * * @param storageSystem * @return */ private String getProviderVersionString(StorageSystem storageSystem) throws IOException { String providerVersion = null; if (!NullColumnValueGetter.isNullURI(storageSystem.getActiveProviderURI())) { StorageProvider provider = _dbClient.queryObject(StorageProvider.class, storageSystem.getActiveProviderURI()); if (null != provider && null != provider.getVersionString()) { providerVersion = provider.getVersionString().replaceFirst("[^\\d]", ""); } } return providerVersion; } /** * Verify the version specified in the KeyMap and return true if major version is < 8. * If Version string is not set in keyamp, then return true. * * @param keyMap * @return */ private boolean isSMIS8XProvider(String providerVersion) { String provStr[] = providerVersion.split(Constants.SMIS_DOT_REGEX); return Integer.parseInt(provStr[0]) >= 8; } /** * {@inheritDoc} */ @Override public void discoverArrayAffinity(AccessProfile accessProfile) { _logger.info("Calling discoverArrayAffinity"); URI storageSystemURI = accessProfile.getSystemId(); String detailedStatusMessage = "Array Affinity Discovery completed successfully for Storage System: %s"; long startTime = System.currentTimeMillis(); try { _logger.info("Access Profile Details :" + accessProfile.toString()); _keyMap = new ConcurrentHashMap<String, Object>(); _wbemClient = getCIMClient(accessProfile); _logger.info("CIMClient initialized successfully"); _keyMap.put(Constants._cimClient, _wbemClient); _keyMap.put(Constants.dbClient, _dbClient); _keyMap.put(Constants.COORDINATOR_CLIENT, _coordinator); _keyMap.put(Constants.PROPS, accessProfile.getProps()); _keyMap.put(Constants._InteropNamespace, accessProfile.getInteropNamespace()); _keyMap.put(Constants.ACCESSPROFILE, accessProfile); _keyMap.put(Constants.SYSTEMID, accessProfile.getSystemId()); _keyMap.put(Constants._serialID, accessProfile.getserialID()); _keyMap.put(Constants.MASKING_VIEWS, new LinkedList<CIMObjectPath>()); StorageSystem storageSystem = queryStorageSystem(accessProfile); String providerVersion = getProviderVersionString(storageSystem); if (null != providerVersion) { _keyMap.put(Constants.VERSION, providerVersion); _keyMap.put(Constants.IS_NEW_SMIS_PROVIDER, isSMIS8XProvider(providerVersion)); } executor.setKeyMap(_keyMap); executor.execute((Namespace) namespaces.getNsList().get(DISCOVER)); } catch (Exception e) { detailedStatusMessage = "Array Affinity Discovery failed for Storage System: %s because " + e.getMessage(); _logger.error(String.format(detailedStatusMessage, storageSystemURI.toString()), e); throw new SMIPluginException(String.format(detailedStatusMessage, storageSystemURI.toString())); } finally { try { String systemIdsStr = accessProfile.getProps().get(Constants.SYSTEM_IDS); String[] systemIds = systemIdsStr.split(Constants.ID_DELIMITER); List<StorageSystem> systemsToUpdate = new ArrayList<StorageSystem>(); for (String systemId : systemIds) { StorageSystem system = _dbClient.queryObject(StorageSystem.class, URI.create(systemId)); // set detailed message system.setLastArrayAffinityStatusMessage(String.format(detailedStatusMessage, systemId)); systemsToUpdate.add(system); } _dbClient.updateObject(systemsToUpdate); } catch (DatabaseException ex) { _logger.error("Error while persisting object to DB", ex); } releaseResources(); long totalTime = System.currentTimeMillis() - startTime; _logger.info(String.format("Array Affinity discovery of Storage System %s took %f seconds", storageSystemURI.toString(), (double) totalTime / (double) 1000)); } } }