/*
* Copyright (c) 2015 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.impl.plugins.discovery.smis.processor.SRDF;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.cim.CIMInstance;
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.constraint.ContainmentConstraint;
import com.emc.storageos.db.client.model.RemoteDirectorGroup;
import com.emc.storageos.db.client.model.RemoteDirectorGroup.ConnectivityStatus;
import com.emc.storageos.db.client.model.StorageProvider;
import com.emc.storageos.db.client.model.StorageSystem;
import com.emc.storageos.db.client.model.StorageSystem.SupportedReplicationTypes;
import com.emc.storageos.db.client.model.StringSet;
import com.emc.storageos.db.client.util.NullColumnValueGetter;
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.plugins.discovery.smis.processor.StorageProcessor;
//Processor used in finding out active SRDF RA Groups
public class RemoteConnectivityCollectionProcessor extends StorageProcessor {
private static final Logger _log = LoggerFactory.getLogger(RemoteConnectivityCollectionProcessor.class);
private static final String ACTIVE = "Active";
private static final String CONNECTIVITY_STATUS = "ConnectivityStatus";
private static final String SYMMETRIX = "SYMMETRIX";
private static final String TWO = "2";
private static final String ELEMENT_NAME = "ElementName";
private DbClient _dbClient;
private Set<String> raGroupIds = new HashSet<String>();
private List<RemoteDirectorGroup> newlyAddedGroups = new ArrayList<RemoteDirectorGroup>();
private List<RemoteDirectorGroup> modifiedGroups = new ArrayList<RemoteDirectorGroup>();
@Override
public void processResult(Operation operation, Object resultObj,
Map<String, Object> keyMap) throws BaseCollectionException {
StorageSystem device = null;
try {
_dbClient = (DbClient) keyMap.get(Constants.dbClient);
AccessProfile profile = (AccessProfile) keyMap.get(Constants.ACCESSPROFILE);
device = getStorageSystem(_dbClient, profile.getSystemId());
@SuppressWarnings("unchecked")
Iterator<CIMInstance> iterator = (Iterator<CIMInstance>) resultObj;
Set<String> remoteConnectedStorageSystems = new HashSet<String>();
boolean srdfSupported = false;
while (iterator.hasNext()) {
srdfSupported = true;
CIMInstance instance = iterator.next();
RemoteDirectorGroup remoteRAGroup = checkRAGroupExistsInDB(_dbClient, instance);
remoteRAGroup = createRAGroup(instance, remoteRAGroup, device);
raGroupIds.add(remoteRAGroup.getNativeGuid());
addRemoteConnectedStorageSystems(instance, device, remoteConnectedStorageSystems);
addPath(keyMap, operation.getResult(), instance.getObjectPath());
}
updateSupportedCopyModes(srdfSupported, device);
updateRemoteConnectedStorageSystems(device, remoteConnectedStorageSystems);
_dbClient.persistObject(device);
if (!newlyAddedGroups.isEmpty()) {
_dbClient.createObject(newlyAddedGroups);
}
if (!modifiedGroups.isEmpty()) {
_dbClient.persistObject(modifiedGroups);
}
performRAGroupsBookKeeping(raGroupIds, device.getId());
} catch (Exception e) {
_log.error("Finding out Active RA Groups Failed.SRDF will not be supported on this Array {} ", device.getNativeGuid(), e);
} finally {
raGroupIds = null;
newlyAddedGroups = null;
modifiedGroups = null;
}
}
private void updateSupportedCopyModes(boolean srdfSupported, StorageSystem device) {
if (srdfSupported) {
StringSet replicationModes = new StringSet();
replicationModes.add(SupportedReplicationTypes.SRDF.toString());
replicationModes.add(SupportedReplicationTypes.LOCAL.toString());
if (checkSupportedSRDFActiveModeProvider(device)) {
replicationModes.add(SupportedReplicationTypes.SRDFMetro.toString());
}
device.setSupportedReplicationTypes(replicationModes);
}
}
private boolean checkSupportedSRDFActiveModeProvider(StorageSystem storageSystem) {
if (storageSystem.checkIfVmax3() && storageSystem.getUsingSmis80()) {
try {
StorageProvider storageProvider = _dbClient.queryObject(StorageProvider.class, storageSystem.getActiveProviderURI());
String providerVersion = storageProvider.getVersionString();
String versionSubstring = providerVersion.split("\\.")[1];
return (Integer.parseInt(versionSubstring) >= 2);
} catch (Exception e) {
_log.error("Exception get provider version for the storage system {} {}.", storageSystem.getLabel(),
storageSystem.getId());
return false;
}
} else {
return false;
}
}
private void updateRemoteConnectedStorageSystems(StorageSystem device,
Set<String> remoteConnectedStorageSystems) {
if (null == device.getRemotelyConnectedTo()
|| device.getRemotelyConnectedTo().isEmpty()) {
device.setRemotelyConnectedTo(new StringSet(remoteConnectedStorageSystems));
} else {
device.getRemotelyConnectedTo().replace(remoteConnectedStorageSystems);
}
}
/**
* if the RAGroup had been deleted from the Array, the rediscovery cycle should set the RAGroup to inactive.
*
* @param policyNames
* @param storageSystemURI
* @throws IOException
*/
private void performRAGroupsBookKeeping(Set<String> raGroupIds, URI storageSystemURI)
throws IOException {
@SuppressWarnings("deprecation")
List<URI> raGroupsInDB = _dbClient
.queryByConstraint(ContainmentConstraint.Factory
.getStorageDeviceRemoteGroupsConstraint(storageSystemURI));
for (URI raGroupUri : raGroupsInDB) {
RemoteDirectorGroup raGroup = _dbClient.queryObject(
RemoteDirectorGroup.class, raGroupUri);
if (null == raGroup || raGroup.getInactive()) {
continue;
}
if (!raGroupIds.contains(raGroup.getNativeGuid())) {
_log.info("RA Group set to inactive", raGroup);
raGroup.setSourceStorageSystemUri(NullColumnValueGetter.getNullURI());
raGroup.setInactive(true);
_dbClient.updateAndReindexObject(raGroup);
}
}
}
private RemoteDirectorGroup createRAGroup(CIMInstance instance, RemoteDirectorGroup raGroup, StorageSystem system) {
boolean newRAGroup = false;
if (null == raGroup) {
newRAGroup = true;
raGroup = new RemoteDirectorGroup();
raGroup.setId(URIUtil.createId(RemoteDirectorGroup.class));
raGroup.setNativeGuid(NativeGUIDGenerator
.generateRAGroupNativeGuid(instance));
raGroup.setSourceGroupId(getSourceGroupId(system, instance));
raGroup.setRemoteGroupId(getRemoteGroupId(system, instance));
}
// moved outside, as during 1st time discovery, if the remote system was not detected,
// we could end up in not updating this field during re-discovery, even though the remote system had been detected in ViPR later.
raGroup.setSourceStorageSystemUri(system.getId());
raGroup.setRemoteStorageSystemUri(getRemoteConnectedSystemURI(system, instance));
raGroup.setLabel(getCIMPropertyValue(instance, ELEMENT_NAME));
raGroup.setActive(Boolean.parseBoolean(getCIMPropertyValue(instance, ACTIVE)));
raGroup.setConnectivityStatus(ConnectivityStatus
.getConnectivityStatus(getCIMPropertyValue(instance, CONNECTIVITY_STATUS)));
if (newRAGroup) {
newlyAddedGroups.add(raGroup);
} else {
modifiedGroups.add(raGroup);
}
return raGroup;
}
private String getSourceGroupId(StorageSystem system, CIMInstance instance) {
String instanceId = (String) instance.getPropertyValue(Constants.INSTANCEID);
String[] idArray = instanceId.split(Constants.PATH_DELIMITER_REGEX);
String sourceGroupId = null;
if (system.getUsingSmis80()) {
if (system.getNativeGuid().contains(idArray[1])) {
sourceGroupId = idArray[2];
} else {
sourceGroupId = idArray[4];
}
} else {
if (system.getNativeGuid().contains(idArray[3])) {
sourceGroupId = idArray[4];
} else {
sourceGroupId = idArray[6];
}
}
_log.info("Generated Source Group Id {} from Instance ID {}", sourceGroupId, instanceId);
return sourceGroupId;
}
private String getRemoteGroupId(StorageSystem system, CIMInstance instance) {
String instanceId = (String) instance.getPropertyValue(Constants.INSTANCEID);
String[] idArray = instanceId.split(Constants.PATH_DELIMITER_REGEX);
String remoteGroupId = null;
if (system.getUsingSmis80()) {
if (system.getNativeGuid().contains(idArray[1])) {
remoteGroupId = idArray[4];
} else {
remoteGroupId = idArray[2];
}
} else {
if (system.getNativeGuid().contains(idArray[3])) {
remoteGroupId = idArray[6];
} else {
remoteGroupId = idArray[4];
}
}
_log.info("Generated Remote Group Id {} from Instance ID {}", remoteGroupId, instanceId);
return remoteGroupId;
}
private URI getRemoteConnectedSystemURI(StorageSystem system, CIMInstance instance) {
String instanceId = (String) instance.getPropertyValue(Constants.INSTANCEID);
String[] idArray = instanceId.split(Constants.PATH_DELIMITER_REGEX);
String remoteArrayNativeGuid = null;
if (system.getUsingSmis80()) {
if (system.getNativeGuid().contains(idArray[1])) {
remoteArrayNativeGuid = SYMMETRIX + Constants.PLUS + idArray[3];
} else {
remoteArrayNativeGuid = SYMMETRIX + Constants.PLUS + idArray[1];
}
} else {
if (system.getNativeGuid().contains(idArray[3])) {
remoteArrayNativeGuid = SYMMETRIX + Constants.PLUS + idArray[5];
} else {
remoteArrayNativeGuid = SYMMETRIX + Constants.PLUS + idArray[3];
}
}
_log.debug("Remote Array Native Guid {}", remoteArrayNativeGuid);
List<URI> remoteSystemuris = _dbClient.queryByConstraint(AlternateIdConstraint.Factory
.getStorageSystemByNativeGuidConstraint(remoteArrayNativeGuid));
if (!remoteSystemuris.isEmpty()) {
return remoteSystemuris.get(0);
}
return NullColumnValueGetter.getNullURI();
}
private void addRemoteConnectedStorageSystems(CIMInstance instance,
StorageSystem system, Set<String> remoteConnectedStorageSystems) {
// there is no other field which gives direct values, hence need to use
// split
// Format : SYMMETRIX+000195701573+NAME+000195701505+27+000195701573+27
boolean isActive = Boolean.parseBoolean(instance.getPropertyValue(ACTIVE).toString());
String connectivityStatus = instance.getPropertyValue(CONNECTIVITY_STATUS).toString();
if (isActive && TWO.equalsIgnoreCase(connectivityStatus)) {
URI remoteSystemUri = getRemoteConnectedSystemURI(system, instance);
if (null != remoteSystemUri) {
remoteConnectedStorageSystems.add(remoteSystemUri.toString());
}
}
}
@Override
protected void setPrerequisiteObjects(List<Object> inputArgs)
throws BaseCollectionException {
// TODO Auto-generated method stub
}
}