/*
* Copyright (c) 2012 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.impl.plugins.discovery.smis;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.emc.storageos.coordinator.client.service.CoordinatorClient;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.model.DiscoveredDataObject;
import com.emc.storageos.db.client.model.StorageSystem.Discovery_Namespaces;
import com.emc.storageos.networkcontroller.impl.NetworkDeviceController;
import com.emc.storageos.plugins.AccessProfile;
import com.emc.storageos.plugins.BaseCollectionException;
import com.emc.storageos.plugins.common.Constants;
import com.emc.storageos.storagedriver.Registry;
import com.emc.storageos.volumecontroller.ControllerLockingService;
import com.emc.storageos.volumecontroller.TaskCompleter;
import com.emc.storageos.volumecontroller.impl.ControllerServiceImpl;
import com.emc.storageos.volumecontroller.impl.plugins.ExtendedCommunicationInterface;
/**
* Loads Spring Context based on Profile & DeviceType i.e. Scanner-block
* ,Discovery-block,Discovery-vnxfile Invokes Scan or Discover Method in
* plugins, which in turn updates information on Pools,Ports.
*/
class DataCollectionJobInvoker {
private static final Logger _logger = LoggerFactory.getLogger(DataCollectionJobInvoker.class);
private static final String DISCOVERY = "Discovery";
private DbClient _dbClient;
private final CoordinatorClient _coordinator;
private final NetworkDeviceController _networkDeviceController;
private final ControllerLockingService _locker;
private final AccessProfile _accessProfile;
private final TaskCompleter _completer;
private ExtendedCommunicationInterface _commInterface;
private final Map<String, String> _configInfo;
private final String _namespace;
private Registry _registry;
public DataCollectionJobInvoker(final AccessProfile accessProfile, final Map<String, String> configInfo,
final DbClient dbClient, final CoordinatorClient coordinator, NetworkDeviceController networkDeviceController,
final ControllerLockingService locker, String namespace, final TaskCompleter completer) {
_accessProfile = accessProfile;
_configInfo = configInfo;
_dbClient = dbClient;
_coordinator = coordinator;
_networkDeviceController = networkDeviceController;
_locker = locker;
_namespace = namespace;
_completer = completer;
}
private static Map<String, ApplicationContext> contextKeyToApplicationContextMap = Collections
.synchronizedMap(new HashMap<String, ApplicationContext>());
public void process(ApplicationContext parentApplicationContext) throws BaseCollectionException {
ApplicationContext context = null;
String contextDeviceType = fetchDeviceType(_accessProfile.getSystemType());
try {
String currentThreadName = String.format("%s|%s|%s|%s|%s", Thread.currentThread().getId(),
_accessProfile.getSystemType(), _accessProfile.getProfileName(), _accessProfile.getIpAddress(),
_completer.getOpId());
Thread.currentThread().setName(currentThreadName);
// Discovery-vnxFile | Discovery-block | Discovery-host |
// Discovery-vcenter
String contextkey = _accessProfile.getProfileName() + "-" + contextDeviceType;
if (ControllerServiceImpl.ARRAYAFFINITY_DISCOVERY.equals(_accessProfile.getProfileName())) {
if (_accessProfile.getProps() != null) {
String hosts = _accessProfile.getProps().get(Constants.HOST_IDS);
if (StringUtils.isNotEmpty(hosts)) {
// ArrayAffinity-block-host
contextkey = contextkey + "-" + Constants.HOST;
}
}
} else if (ControllerServiceImpl.isDiscoveryJobTypeSupported(_accessProfile.getProfileName())) {
// Discovery-vnxFile-all | Discovery-block-all |
// CS_Discovery-host-all | CS_Discovery-vcenter-all
contextkey = contextkey + "-" + _namespace.toLowerCase();
}
if (contextDeviceType.equalsIgnoreCase(DiscoveredDataObject.Type.rp.toString())) {
_logger.info("{} task Started using protection system {} using Namespace {}",
new Object[] { _accessProfile.getProfileName(), _accessProfile.getIpAddress(), contextkey });
} else {
_logger.info("{} task Started using Provider {} using Namespace {}",
new Object[] { _accessProfile.getProfileName(), _accessProfile.getIpAddress(), contextkey });
}
if (Constants.COMPUTE.equals(contextDeviceType) && contextKeyToApplicationContextMap.get(contextkey) != null) {
context = contextKeyToApplicationContextMap.get(contextkey);
} else {
// CTRL-10441 fix
String contextFile = getContextFile(contextkey);
if (null == contextFile) {
// No entry for context key in configinfo map, default to external device context key
String externalDeviceContextKey;
if (_accessProfile.getProfileName().equalsIgnoreCase(ControllerServiceImpl.SCANNER)) {
externalDeviceContextKey = _accessProfile.getProfileName() + "-" + Constants.EXTERNALDEVICE;
} else {
externalDeviceContextKey = _accessProfile.getProfileName() + "-" + Constants.EXTERNALDEVICE + "-"
+ _namespace.toLowerCase();
}
_logger.info("No entry defined for context key: {} . Default to external device context key: {}",
contextkey, externalDeviceContextKey);
contextkey = externalDeviceContextKey;
contextDeviceType = Constants.EXTERNALDEVICE;
contextFile = getContextFile(contextkey);
}
if (contextFile == null) {
_logger.info("No entry defined for context key: {} ", contextkey);
return;
}
context = new ClassPathXmlApplicationContext(new String[] { getContextFile(contextkey) },
parentApplicationContext);
if (Constants.COMPUTE.equals(contextDeviceType)) {
contextKeyToApplicationContextMap.put(contextkey, context);
}
}
_commInterface = (ExtendedCommunicationInterface) context.getBean(contextDeviceType);
invoke(_commInterface);
if (contextDeviceType.equalsIgnoreCase(DiscoveredDataObject.Type.rp.toString())) {
_logger.info("{} task Completed successfully using protection system {}", _accessProfile.getProfileName(),
_accessProfile.getIpAddress());
} else {
_logger.info("{} task Completed successfully using Provider {}", _accessProfile.getProfileName(),
_accessProfile.getIpAddress());
}
} finally {
if (!Constants.COMPUTE.equals(contextDeviceType) && context != null) {
((ConfigurableApplicationContext) context).close();
}
_commInterface = null;
}
}
/**
* Returns the context key based on its devicetype.
*
* @param deviceType
* @return
*/
private String fetchDeviceType(String deviceType) {
if (Constants._Block.equalsIgnoreCase(deviceType)
|| DiscoveredDataObject.Type.vnxblock.toString().equalsIgnoreCase(deviceType)
|| DiscoveredDataObject.Type.vmax.toString().equalsIgnoreCase(deviceType)) {
return Constants._Block;
} else if (Constants.COMPUTE.equalsIgnoreCase(deviceType)) {
return Constants.COMPUTE;
}
return deviceType;
}
/**
* Invoke Scan or Discover based on the profile.
*
* @param commInterface
* @throws BaseCollectionException
*/
private void invoke(ExtendedCommunicationInterface commInterface) throws BaseCollectionException {
commInterface.injectDBClient(_dbClient);
commInterface.injectCoordinatorClient(_coordinator);
commInterface.injectNetworkDeviceController(_networkDeviceController);
commInterface.injectControllerLockingService(_locker);
commInterface.injectTaskCompleter(_completer);
if (_accessProfile.getProfileName().equalsIgnoreCase(ControllerServiceImpl.SCANNER)) {
commInterface.scan(_accessProfile);
} else if (ControllerServiceImpl.isDiscoveryJobTypeSupported(_accessProfile.getProfileName())) {
commInterface.discover(_accessProfile);
} else if (_accessProfile.getProfileName().equalsIgnoreCase(ControllerServiceImpl.ARRAYAFFINITY_DISCOVERY)) {
commInterface.discoverArrayAffinity(_accessProfile);
} else if (_accessProfile.getProfileName().equalsIgnoreCase(ControllerServiceImpl.METERING)) {
invokeMetering();
} else {
// To-Do add metering too
throw new RuntimeException("Unsupported Profile Type :" + _accessProfile.getProfileName());
}
}
/**
* Inject correct dbUtil instance based on deviceType. It could have been
* put up as a bean in plugin-context.xml, but it would end up in having a
* DButil dependency onto export Libraries. Hence, instantiating locally.
*
* @throws BaseCollectionException
*/
private void invokeMetering() throws BaseCollectionException {
_commInterface.collectStatisticsInformation(_accessProfile);
}
/**
* get Context File based on Context-key (Scanner-block)
*
* @param contextKey
* @return
*/
private String getContextFile(String contextKey) {
String contextFile = null;
if (null != _configInfo.get(contextKey)) {
contextFile = _configInfo.get(contextKey);
} else {
_logger.warn("Profile name not defined:" + contextKey);
}
return contextFile;
}
public void setDBClient(DbClient dbClient) {
this._dbClient = dbClient;
}
}