/*
* Copyright (c) 2016 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.impl.plugins;
import static com.emc.storageos.volumecontroller.impl.NativeGUIDGenerator.generateNativeGuid;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.URIUtil;
import com.emc.storageos.db.client.constraint.AlternateIdConstraint;
import com.emc.storageos.db.client.constraint.URIQueryResultList;
import com.emc.storageos.db.client.model.AutoTieringPolicy;
import com.emc.storageos.db.client.model.CifsServerMap;
import com.emc.storageos.db.client.model.DiscoveredDataObject;
import com.emc.storageos.db.client.model.DiscoveredDataObject.DiscoveryStatus;
import com.emc.storageos.db.client.model.DiscoveredDataObject.RegistrationStatus;
import com.emc.storageos.db.client.model.NasCifsServer;
import com.emc.storageos.db.client.model.StorageHADomain;
import com.emc.storageos.db.client.model.StoragePool;
import com.emc.storageos.db.client.model.StoragePool.PoolServiceType;
import com.emc.storageos.db.client.model.StoragePort;
import com.emc.storageos.db.client.model.StorageProtocol;
import com.emc.storageos.db.client.model.StorageProvider;
import com.emc.storageos.db.client.model.StorageSystem;
import com.emc.storageos.db.client.model.StorageTier;
import com.emc.storageos.db.client.model.StringMap;
import com.emc.storageos.db.client.model.StringSet;
import com.emc.storageos.db.client.model.VirtualNAS;
import com.emc.storageos.db.client.model.VirtualNAS.VirtualNasState;
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.vnxe.VNXeApiClient;
import com.emc.storageos.vnxe.VNXeApiClientFactory;
import com.emc.storageos.vnxe.VNXeException;
import com.emc.storageos.vnxe.VNXeUtils;
import com.emc.storageos.vnxe.models.BasicSystemInfo;
import com.emc.storageos.vnxe.models.Disk;
import com.emc.storageos.vnxe.models.DiskGroup;
import com.emc.storageos.vnxe.models.Health;
import com.emc.storageos.vnxe.models.PoolTier;
import com.emc.storageos.vnxe.models.RaidGroup;
import com.emc.storageos.vnxe.models.RaidTypeEnum;
import com.emc.storageos.vnxe.models.VNXeBase;
import com.emc.storageos.vnxe.models.VNXeCifsServer;
import com.emc.storageos.vnxe.models.VNXeCifsShare;
import com.emc.storageos.vnxe.models.VNXeEthernetPort;
import com.emc.storageos.vnxe.models.VNXeFCPort;
import com.emc.storageos.vnxe.models.VNXeFileInterface;
import com.emc.storageos.vnxe.models.VNXeFileSystem;
import com.emc.storageos.vnxe.models.VNXeFileSystemSnap;
import com.emc.storageos.vnxe.models.VNXeIscsiNode;
import com.emc.storageos.vnxe.models.VNXeIscsiPortal;
import com.emc.storageos.vnxe.models.VNXeNasServer;
import com.emc.storageos.vnxe.models.VNXeNfsServer;
import com.emc.storageos.vnxe.models.VNXeNfsShare;
import com.emc.storageos.vnxe.models.VNXePool;
import com.emc.storageos.vnxe.models.VNXeStorageProcessor;
import com.emc.storageos.vnxe.models.VNXeStorageSystem;
import com.emc.storageos.vnxe.models.VNXeStorageTier;
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.metering.smis.processor.MetricsKeys;
import com.emc.storageos.volumecontroller.impl.utils.DiscoveryUtils;
import com.emc.storageos.volumecontroller.impl.utils.ImplicitPoolMatcher;
import com.emc.storageos.volumecontroller.impl.vnxunity.VNXUnityArrayAffinityDiscoverer;
import com.emc.storageos.volumecontroller.impl.vnxunity.VNXUnityUnManagedObjectDiscoverer;
/**
* VNXUnityCommunicationInterface class is an implementation of
* CommunicationInterface which is responsible to discover for VNXUnity using
* ThunderBird API.
*
*/
public class VNXUnityCommunicationInterface extends ExtendedCommunicationInterfaceImpl {
private static final Logger _logger = LoggerFactory.getLogger(VNXUnityCommunicationInterface.class);
private static final String NEW = "new";
private static final String EXISTING = "existing";
private static final String TRUE = "true";
private static final String FALSE = "false";
private static final int LOCK_WAIT_SECONDS = 300;
private static final String UNITY_300 = "Unity 300";
private static final String UNITY_400 = "Unity 400";
private static final String UNITY_500 = "Unity 500";
private static final String UNITY_600 = "Unity 600";
private static final String UNITY_VSA = "UnityVSA";
private static final Long MAX_EXPORTS = 600L;
private static final Long MAX_STORAGE_OBJECTS = 1000L;
private static final Long MAX_CAPACITY_TB = 788L;
private static final Long MAX_EXPORTS_UNITY300 = 600L;
private static final Long MAX_STORAGE_OBJECTS_UNITY300 = 1000L;
private static final Long MAX_CAPACITY_UNITY300_TB = 788L;
private static final Long MAX_EXPORTS_UNITY400 = 600L;
private static final Long MAX_STORAGE_OBJECTS_UNITY400 = 2000L;
private static final Long MAX_CAPACITY_UNITY400_TB = 1313L;
private static final Long MAX_EXPORTS_UNITY500 = 4500L;
private static final Long MAX_STORAGE_OBJECTS_UNITY500 = 1250L;
private static final Long MAX_CAPACITY_UNITY500_TB = 1838L;
private static final Long MAX_EXPORTS_UNITY600 = 4500L;
private static final Long MAX_STORAGE_OBJECTS_UNITY600 = 2500L;
private static final Long MAX_CAPACITY_UNITY600_TB = 2635L;
private static final Long MAX_EXPORTS_UNITYVSA = 300L;
private static final Long MAX_STORAGE_OBJECTS_UNITYVSA = 64L;
private static final Long MAX_CAPACITY_UNITYVSA_TB = 50L;
private static final Long GB_IN_BYTES = 1073741824L;
private static final Long GB_IN_KB = 1048576L;
private static final Long MB_IN_BYTES = 1048576L;
private static final Long KB_IN_BYTES = 1024L;
private static final Long TB_IN_GB = 1024L;
// Reference to the VNX unity client factory allows us to get a VNX unity
// client and execute requests to the VNX Unity storage system.
private VNXeApiClientFactory clientFactory;
private VNXUnityUnManagedObjectDiscoverer unityUnManagedObjectDiscoverer;
private VNXUnityArrayAffinityDiscoverer unityArrayAffinityDiscoverer;
public VNXUnityCommunicationInterface() {
};
public VNXeApiClientFactory geClientFactory() {
return clientFactory;
}
public void setClientFactory(VNXeApiClientFactory clientFactory) {
this.clientFactory = clientFactory;
}
public void setUnManagedObjectDiscoverer(VNXUnityUnManagedObjectDiscoverer volumeDiscoverer) {
this.unityUnManagedObjectDiscoverer = volumeDiscoverer;
}
public void setArrayAffinityDiscoverer(VNXUnityArrayAffinityDiscoverer arrayAffinityDiscoverer) {
this.unityArrayAffinityDiscoverer = arrayAffinityDiscoverer;
}
/**
* Implementation for scan for Vnx Unity storage systems.
*
* @param accessProfile
*
* @throws BaseCollectionException
*/
@Override
public void scan(AccessProfile accessProfile) throws BaseCollectionException {
_logger.info("Starting scan of Unity StorageProvider. IP={}", accessProfile.getIpAddress());
StorageProvider.ConnectionStatus cxnStatus = StorageProvider.ConnectionStatus.CONNECTED;
StorageProvider provider = _dbClient.queryObject(StorageProvider.class, accessProfile.getSystemId());
_locker.acquireLock(accessProfile.getIpAddress(), LOCK_WAIT_SECONDS);
try {
VNXeApiClient apiClient = getVnxUnityClient(accessProfile);
if (apiClient != null) {
Map<String, StorageSystemViewObject> storageSystemsCache = accessProfile.getCache();
BasicSystemInfo unitySystem = apiClient.getBasicSystemInfo();
String unityType = StorageSystem.Type.unity.name();
String version = unitySystem.getApiVersion();
String compatibility = StorageSystem.CompatibilityStatus.COMPATIBLE.name();
provider.setCompatibilityStatus(compatibility);
provider.setVersionString(version);
VNXeStorageSystem system = apiClient.getStorageSystem();
_logger.info("Found Unity: {} ", system.getSerialNumber());
String id = system.getSerialNumber();
String nativeGuid = generateNativeGuid(unityType, id);
StorageSystemViewObject viewObject = storageSystemsCache.get(nativeGuid);
if (viewObject == null) {
viewObject = new StorageSystemViewObject();
}
viewObject.setDeviceType(unityType);
viewObject.addprovider(accessProfile.getSystemId().toString());
viewObject.setProperty(StorageSystemViewObject.MODEL, unitySystem.getModel());
viewObject.setProperty(StorageSystemViewObject.SERIAL_NUMBER, id);
storageSystemsCache.put(nativeGuid, viewObject);
}
} catch (Exception e) {
cxnStatus = StorageProvider.ConnectionStatus.NOTCONNECTED;
_logger.error(String.format("Exception was encountered when attempting to scan Unity Instance %s",
accessProfile.getIpAddress()), e);
throw VNXeException.exceptions.scanFailed(accessProfile.getIpAddress(), e);
} finally {
provider.setConnectionStatus(cxnStatus.name());
_dbClient.updateObject(provider);
_logger.info("Completed scan of Unity StorageProvider. IP={}", accessProfile.getIpAddress());
_locker.releaseLock(accessProfile.getIpAddress());
}
}
/**
* Implementation for VNX Unity storage systems discovery, both of block and
* file
*
* @param accessProfile
*
* @throws VNXeException
*/
@Override
public void discover(AccessProfile accessProfile) throws VNXeException {
URI storageSystemURI = accessProfile.getSystemId();
StorageSystem viprStorageSystem = null;
String detailedStatusMessage = "Unknown Status";
try {
_logger.info("Access Profile Details : IpAddress : {}, PortNumber : {}", accessProfile.getIpAddress(),
accessProfile.getPortNumber());
if (null != accessProfile.getnamespace() && (accessProfile.getnamespace()
.equals(StorageSystem.Discovery_Namespaces.UNMANAGED_VOLUMES.toString())
|| accessProfile.getnamespace()
.equals(StorageSystem.Discovery_Namespaces.UNMANAGED_FILESYSTEMS.toString()))) {
discoverUnmanagedObjects(accessProfile);
} else {
// Get the VNX Unity storage system from the database.
viprStorageSystem = _dbClient.queryObject(StorageSystem.class, storageSystemURI);
_logger.info(String.format("Discover VnxUnity storage system %s at IP:%s, PORT:%s",
storageSystemURI.toString(), accessProfile.getIpAddress(), accessProfile.getPortNumber()));
// Get the vnx unity service client for getting information
// about the Vnx Unity storage system.
VNXeApiClient client = getVnxUnityClient(accessProfile);
_logger.debug("Got handle to Vnx unity service client");
// Get the serial number and the native guid and set into the
// storage system.
_logger.info("Discovering storage system properties.");
VNXeStorageSystem system = client.getStorageSystem();
boolean isFASTVPEnabled = client.isFASTVPEnabled();
viprStorageSystem = discoverStorageSystemInfo(client, accessProfile, system, isFASTVPEnabled, viprStorageSystem);
StringSet arraySupportedProtocols = new StringSet();
// Discover the NasServers
Map<String, URI> nasServerIdMap = new HashMap<String, URI>();
Map<String, List<StorageHADomain>> nasServers = discoverNasServers(viprStorageSystem, client,
nasServerIdMap, arraySupportedProtocols);
_logger.info("No of newly discovered NasServers {}", nasServers.get(NEW).size());
_logger.info("No of existing discovered NasServers {}", nasServers.get(EXISTING).size());
if (!nasServers.get(NEW).isEmpty()) {
_dbClient.createObject(nasServers.get(NEW));
}
if (!nasServers.get(EXISTING).isEmpty()) {
_dbClient.updateObject(nasServers.get(EXISTING));
}
_completer.statusPending(_dbClient, "Completed NAS Server discovery");
// Discover FileInterfaces
List<StoragePort> allExistingPorts = new ArrayList<StoragePort>();
List<StoragePort> allNewPorts = new ArrayList<StoragePort>();
Map<String, List<StoragePort>> ports = discoverFileStoragePorts(viprStorageSystem, client,
nasServerIdMap);
if (ports.get(NEW) != null && !ports.get(NEW).isEmpty()) {
allNewPorts.addAll(ports.get(NEW));
_dbClient.createObject(ports.get(NEW));
}
if (ports.get(EXISTING) != null && !ports.get(EXISTING).isEmpty()) {
allExistingPorts.addAll(ports.get(EXISTING));
_dbClient.updateObject(ports.get(EXISTING));
}
_completer.statusPending(_dbClient, "Completed file ports discovery");
// discover storage processors
Map<String, URI> spIdMap = new HashMap<String, URI>();
Map<String, List<StorageHADomain>> sps = discoverStorageProcessors(viprStorageSystem, client, spIdMap);
if (!sps.get(NEW).isEmpty()) {
_dbClient.createObject(sps.get(NEW));
}
if (!sps.get(EXISTING).isEmpty()) {
_dbClient.updateObject(sps.get(EXISTING));
}
_completer.statusPending(_dbClient, "Completed storage processor discovery");
// discover iscsi ports
Map<String, List<StoragePort>> iscsiPorts = discoverIscsiPorts(viprStorageSystem, client, spIdMap);
boolean hasIscsiPorts = false;
if (iscsiPorts.get(NEW) != null && !iscsiPorts.get(NEW).isEmpty()) {
allNewPorts.addAll(iscsiPorts.get(NEW));
hasIscsiPorts = true;
_dbClient.createObject(iscsiPorts.get(NEW));
}
if (iscsiPorts.get(EXISTING) != null && !iscsiPorts.get(EXISTING).isEmpty()) {
allExistingPorts.addAll(iscsiPorts.get(EXISTING));
hasIscsiPorts = true;
_dbClient.updateObject(iscsiPorts.get(EXISTING));
}
if (hasIscsiPorts) {
arraySupportedProtocols.add(StorageProtocol.Block.iSCSI.name());
}
_completer.statusPending(_dbClient, "Completed iscsi ports discovery");
// discover fc ports
Map<String, List<StoragePort>> fcPorts = discoverFcPorts(viprStorageSystem, client, spIdMap);
boolean hasFcPorts = false;
if (fcPorts.get(NEW) != null && !fcPorts.get(NEW).isEmpty()) {
allNewPorts.addAll(fcPorts.get(NEW));
hasFcPorts = true;
_dbClient.createObject(fcPorts.get(NEW));
}
if (fcPorts.get(EXISTING) != null && !fcPorts.get(EXISTING).isEmpty()) {
allExistingPorts.addAll(fcPorts.get(EXISTING));
hasFcPorts = true;
_dbClient.updateObject(fcPorts.get(EXISTING));
}
if (hasFcPorts) {
arraySupportedProtocols.add(StorageProtocol.Block.FC.name());
}
_completer.statusPending(_dbClient, "Completed FC ports discovery");
List<StoragePort> allPorts = new ArrayList<StoragePort>(allNewPorts);
allPorts.addAll(allExistingPorts);
// check if any port not visible in this discovery
List<StoragePort> notVisiblePorts = DiscoveryUtils.checkStoragePortsNotVisible(allPorts, _dbClient,
viprStorageSystem.getId());
if (notVisiblePorts != null && !notVisiblePorts.isEmpty()) {
allExistingPorts.addAll(notVisiblePorts);
}
/**
* Discover the VNX Unity pool information.
*/
_logger.info("Discovering storage pools.");
List<StoragePool> poolsToMatchWithVpool = new ArrayList<StoragePool>();
List<StoragePool> allPools = new ArrayList<StoragePool>();
Map<String, List<StoragePool>> pools = discoverStoragePools(viprStorageSystem, client,
arraySupportedProtocols, poolsToMatchWithVpool);
_logger.info("No of newly discovered pools {}", pools.get(NEW).size());
_logger.info("No of existing discovered pools {}", pools.get(EXISTING).size());
if (!pools.get(NEW).isEmpty()) {
allPools.addAll(pools.get(NEW));
_dbClient.createObject(pools.get(NEW));
StoragePoolAssociationHelper.setStoragePoolVarrays(viprStorageSystem.getId(), pools.get(NEW),
_dbClient);
}
if (!pools.get(EXISTING).isEmpty()) {
allPools.addAll(pools.get(EXISTING));
_dbClient.updateObject(pools.get(EXISTING));
}
List<StoragePool> notVisiblePools = DiscoveryUtils.checkStoragePoolsNotVisible(allPools, _dbClient,
viprStorageSystem.getId());
if (notVisiblePools != null && !notVisiblePools.isEmpty()) {
poolsToMatchWithVpool.addAll(notVisiblePools);
}
StoragePortAssociationHelper.runUpdatePortAssociationsProcess(allNewPorts, allExistingPorts, _dbClient,
_coordinator, poolsToMatchWithVpool);
_completer.statusPending(_dbClient, "Completed pool discovery");
// This associates the VNas with the virtual array
StoragePortAssociationHelper.runUpdateVirtualNasAssociationsProcess(allExistingPorts, null, _dbClient);
_logger.info("update virtual nas association for unity");
/**
* Discover AutoTieringPolicies and StorageTiers if FASTVP
* enabled.
*/
if (isFASTVPEnabled) {
_logger.info("FASTVP is enabled");
HashMap<String, List<AutoTieringPolicy>> policies = discoverAutoTierPolicies(viprStorageSystem,
client);
if (!policies.get(NEW).isEmpty()) {
_dbClient.createObject(policies.get(NEW));
}
if (!policies.get(EXISTING).isEmpty()) {
_dbClient.updateObject(policies.get(EXISTING));
}
HashMap<String, List<StorageTier>> tiers = discoverStorageTier(viprStorageSystem, client);
if (!tiers.get(NEW).isEmpty()) {
_dbClient.createObject(tiers.get(NEW));
}
if (!tiers.get(EXISTING).isEmpty()) {
_dbClient.updateObject(tiers.get(EXISTING));
}
}
detailedStatusMessage = String.format("Discovery completed successfully for Storage System: %s",
storageSystemURI.toString());
}
} catch (Exception e) {
detailedStatusMessage = String.format("Discovery failed for VNX Unity %s: %s", storageSystemURI.toString(),
e.getLocalizedMessage());
_logger.error(detailedStatusMessage, e);
throw VNXeException.exceptions.discoveryError("Discovery error", e);
} finally {
if (viprStorageSystem != null) {
try {
// set detailed message
viprStorageSystem.setLastDiscoveryStatusMessage(detailedStatusMessage);
_dbClient.updateObject(viprStorageSystem);
} catch (DatabaseException ex) {
_logger.error("Error while persisting object to DB", ex);
}
}
}
}
private StorageSystem discoverStorageSystemInfo(VNXeApiClient client, AccessProfile accessProfile,
VNXeStorageSystem system, Boolean isFASTVPEnabled, StorageSystem viprStorageSystem) {
if (system != null) {
viprStorageSystem.setSerialNumber(system.getSerialNumber());
String guid = NativeGUIDGenerator.generateNativeGuid(viprStorageSystem);
viprStorageSystem.setNativeGuid(guid);
viprStorageSystem.setCompatibilityStatus(DiscoveredDataObject.CompatibilityStatus.COMPATIBLE.name());
viprStorageSystem.setReachableStatus(true);
viprStorageSystem.setAutoTieringEnabled(isFASTVPEnabled);
viprStorageSystem.setModel(system.getModel());
StringSet supportedActions = new StringSet();
supportedActions.add(StorageSystem.AsyncActions.CreateElementReplica.name());
supportedActions.add(StorageSystem.AsyncActions.CreateGroupReplica.name());
viprStorageSystem.setSupportedAsynchronousActions(supportedActions);
StringSet supportedReplica = new StringSet();
supportedReplica.add(StorageSystem.SupportedReplicationTypes.LOCAL.name());
viprStorageSystem.setSupportedReplicationTypes(supportedReplica);
viprStorageSystem.setSupportSoftLimit(true);
viprStorageSystem.setIpAddress(accessProfile.getIpAddress());
viprStorageSystem.setUsername(accessProfile.getUserName());
viprStorageSystem.setPortNumber(accessProfile.getPortNumber());
viprStorageSystem.setPassword(accessProfile.getPassword());
_completer.statusPending(_dbClient, "Completed discovery of system properties");
} else {
_logger.error("Failed to retrieve VNX Unity system info!");
viprStorageSystem.setReachableStatus(false);
}
// get version for the storage system
BasicSystemInfo info = client.getBasicSystemInfo();
if (info != null) {
viprStorageSystem.setFirmwareVersion(info.getSoftwareVersion());
}
_dbClient.updateObject(viprStorageSystem);
return viprStorageSystem;
}
/**
* Discover Unmanaged objects for the specified VNX File storage array
*
* @param accessProfile
* Access profile of the storage system
*/
private void discoverUnmanagedObjects(AccessProfile accessProfile) {
StorageSystem storageSystem = null;
String detailedStatusMessage = null;
try {
storageSystem = _dbClient.queryObject(StorageSystem.class, accessProfile.getSystemId());
if (null == storageSystem) {
return;
}
storageSystem.setDiscoveryStatus(DiscoveredDataObject.DataCollectionJobStatus.IN_PROGRESS.toString());
_dbClient.updateObject(storageSystem);
if (accessProfile.getnamespace()
.equals(StorageSystem.Discovery_Namespaces.UNMANAGED_FILESYSTEMS.toString())) {
unityUnManagedObjectDiscoverer.discoverUnManagedFileSystems(accessProfile, _dbClient, _coordinator,
_partitionManager);
unityUnManagedObjectDiscoverer.discoverAllExportRules(accessProfile, _dbClient, _partitionManager);
unityUnManagedObjectDiscoverer.discoverAllCifsShares(accessProfile, _dbClient, _partitionManager);
unityUnManagedObjectDiscoverer.discoverAllTreeQuotas(accessProfile, _dbClient, _partitionManager);
} else if (accessProfile.getnamespace()
.equals(StorageSystem.Discovery_Namespaces.UNMANAGED_VOLUMES.toString())) {
unityUnManagedObjectDiscoverer.discoverUnManagedVolumes(accessProfile, _dbClient, _coordinator,
_partitionManager);
}
// discovery succeeds
detailedStatusMessage = String.format("UnManaged Object Discovery completed successfully for VNX Unity: %s",
storageSystem.getId().toString());
_logger.info(detailedStatusMessage);
} catch (Exception e) {
detailedStatusMessage = String.format("Discovery of unmanaged volumes failed for system %s because %s",
storageSystem.getId().toString(), e.getLocalizedMessage());
_logger.error(detailedStatusMessage, e);
throw VNXeException.exceptions.discoveryError("Unmanaged objectobject discovery error", e);
} finally {
if (storageSystem != null) {
try {
// set detailed message
storageSystem.setLastDiscoveryStatusMessage(detailedStatusMessage);
_dbClient.updateObject(storageSystem);
} catch (Exception ex) {
_logger.error("Error while updating unmanaged object discovery status for system.", ex);
}
}
}
}
/**
* {@inheritDoc}
*
* @param accessProfile
* @throws VNXeException
*/
@Override
public void discoverArrayAffinity(AccessProfile accessProfile) throws VNXeException {
_logger.info("Calling discoverArrayAffinity");
long startTime = System.currentTimeMillis();
URI systemURI = accessProfile.getSystemId();
StorageSystem system = null;
String detailedStatusMessage = "Unknown Status";
try {
_logger.info("Access Profile Details : IpAddress : {}, PortNumber : {}", accessProfile.getIpAddress(),
accessProfile.getPortNumber());
// Get the VNX Unity storage system from the database.
system = _dbClient.queryObject(StorageSystem.class, systemURI);
if (system == null || system.getInactive()) {
_logger.warn("System {} is no longer active", systemURI);
return;
}
_logger.info(String.format("Array Affinity Discover on VNX Unity storage system %s at IP: %s, PORT: %s",
systemURI.toString(), accessProfile.getIpAddress(), accessProfile.getPortNumber()));
system.setArrayAffinityStatus(DiscoveredDataObject.DataCollectionJobStatus.IN_PROGRESS.toString());
_dbClient.updateObject(system);
unityArrayAffinityDiscoverer.discoverArrayAffinity(accessProfile, _dbClient, _partitionManager);
_logger.info("Finished array affinity discovery");
detailedStatusMessage = String.format("Array Affinity Discovery completed successfully for Storage System: %s",
systemURI.toString());
} catch (Exception e) {
detailedStatusMessage = String.format("Array Affinity Discovery failed for VNX Unity %s: %s", systemURI.toString(),
e.getLocalizedMessage());
_logger.error(detailedStatusMessage, e);
throw VNXeException.exceptions.discoveryError("Array Affinity Discovery error", e);
} finally {
if (system != null) {
try {
// set detailed message
system.setLastArrayAffinityStatusMessage(detailedStatusMessage);
_dbClient.updateObject(system);
} catch (DatabaseException ex) {
_logger.error("Error while persisting object to DB", ex);
}
}
long totalTime = System.currentTimeMillis() - startTime;
_logger.info(String.format("Array Affinity discovery of Storage System %s took %f seconds", systemURI.toString(), (double) totalTime
/ (double) 1000));
}
}
/**
* Get the Vnx Unity service client for making requests to the VNX Unity
* based on the passed profile.
*
* @param accessProfile
* A reference to the access profile.
*
* @return A reference to the Vnx unity service client.
*/
private VNXeApiClient getVnxUnityClient(AccessProfile accessProfile) {
VNXeApiClient client = clientFactory.getUnityClient(accessProfile.getIpAddress(), accessProfile.getPortNumber(),
accessProfile.getUserName(), accessProfile.getPassword());
return client;
}
/**
* Returns the list of storage pools for the specified VNX Unity storage
* system.
*
* @param system
* storage system information.
* @param client
* VNX Unity service client
* @param supportedProtocols
* calculated supportedProtocols for the array
* @return Map of New and Existing known storage pools.
* @throws VNXeException
*/
private Map<String, List<StoragePool>> discoverStoragePools(StorageSystem system, VNXeApiClient client,
StringSet supportedProtocols, List<StoragePool> poolsToMatchWithVpool) throws VNXeException {
Map<String, List<StoragePool>> storagePools = new HashMap<String, List<StoragePool>>();
List<StoragePool> newPools = new ArrayList<StoragePool>();
List<StoragePool> existingPools = new ArrayList<StoragePool>();
_logger.info("Start storage pool discovery for storage system {}", system.getId());
try {
List<VNXePool> pools = client.getPools();
for (VNXePool vnxePool : pools) {
StoragePool pool = null;
URIQueryResultList results = new URIQueryResultList();
String poolNativeGuid = NativeGUIDGenerator.generateNativeGuid(system, vnxePool.getId(), NativeGUIDGenerator.POOL);
_dbClient.queryByConstraint(AlternateIdConstraint.Factory.getStoragePoolByNativeGuidConstraint(poolNativeGuid), results);
boolean isModified = false;
Iterator<URI> it = results.iterator();
if (it.hasNext()) {
StoragePool tmpPool = _dbClient.queryObject(StoragePool.class, it.next());
if (tmpPool.getStorageDevice().equals(system.getId())) {
pool = tmpPool;
_logger.info("Found StoragePool {} at {}", pool.getPoolName(), poolNativeGuid);
}
}
if (pool == null) {
pool = new StoragePool();
pool.setId(URIUtil.createId(StoragePool.class));
pool.setLabel(poolNativeGuid);
pool.setNativeGuid(poolNativeGuid);
pool.setPoolServiceType(PoolServiceType.block_file.toString());
pool.setStorageDevice(system.getId());
pool.setNativeId(vnxePool.getId());
pool.setPoolName(vnxePool.getName());
pool.setCompatibilityStatus(DiscoveredDataObject.CompatibilityStatus.COMPATIBLE.name());
pool.setDiscoveryStatus(DiscoveredDataObject.DiscoveryStatus.VISIBLE.name());
// Supported resource type indicates what type of file
// systems are supported.
pool.setSupportedResourceTypes(StoragePool.SupportedResourceTypes.THIN_AND_THICK.toString());
pool.setPoolClassName(StoragePool.PoolClassNames.VNXe_Pool.name());
pool.setPoolServiceType(StoragePool.PoolServiceType.block_file.name());
pool.setRegistrationStatus(RegistrationStatus.REGISTERED.toString());
_logger.info("Creating new storage pool using NativeGuid : {}", poolNativeGuid);
newPools.add(pool);
} else {
// update pool attributes
_logger.info("updating the pool: {}", poolNativeGuid);
if (ImplicitPoolMatcher.checkPoolPropertiesChanged(pool.getProtocols(), supportedProtocols)) {
isModified = true;
}
existingPools.add(pool);
}
Health poolHealth = vnxePool.getHealth();
if (poolHealth != null) {
int value = poolHealth.getValue();
if (value == Health.HealthEnum.OK.getValue() || value == Health.HealthEnum.OK_BUT.getValue()) {
pool.setOperationalStatus(StoragePool.PoolOperationalStatus.READY.name());
} else {
pool.setOperationalStatus(StoragePool.PoolOperationalStatus.NOTREADY.name());
}
}
pool.setProtocols(supportedProtocols);
StringSet raidLevels = new StringSet();
RaidTypeEnum raid = vnxePool.getRaidTypeEnum();
if (raid != null) {
raidLevels.add(vnxePool.getRaidTypeEnum().name());
pool.setSupportedRaidLevels(raidLevels);
}
pool.setAutoTieringEnabled(getPoolAutoTieringEnabled(vnxePool, system));
List<PoolTier> poolTiers = vnxePool.getTiers();
StringSet diskTypes = new StringSet();
if (poolTiers != null) {
for (PoolTier poolTier : poolTiers) {
List<RaidGroup> raidGroups = poolTier.getRaidGroups();
if (raidGroups != null) {
for (RaidGroup raidGroup : raidGroups) {
VNXeBase diskGroup = raidGroup.getDiskGroup();
if (diskGroup != null) {
DiskGroup diskgroupObj = client.getDiskGroup(diskGroup.getId());
diskTypes.add(diskgroupObj.getDiskTechnologyEnum().name());
}
}
}
}
}
// Get drive types from disks
List<Disk> disks = client.getDisksForPool(vnxePool.getId());
if (disks != null) {
for (Disk disk : disks) {
if (disk.getDiskTechnologyEnum() != null) {
diskTypes.add(disk.getDiskTechnologyEnum().name());
}
}
}
pool.setSupportedDriveTypes(diskTypes);
double size = vnxePool.getSizeTotal();
if (size > 0) {
pool.setTotalCapacity(VNXeUtils.convertDoubleSizeToViPRLong(size)); // Convert to kb
}
long free = VNXeUtils.convertDoubleSizeToViPRLong(vnxePool.getSizeFree());
if (free > 0) {
pool.setFreeCapacity(free);
pool.setMaximumThinVolumeSize(free);
pool.setMaximumThickVolumeSize(free);
}
long subscribed = VNXeUtils.convertDoubleSizeToViPRLong(vnxePool.getSizeSubscribed());
pool.setSubscribedCapacity(subscribed);
if (isModified
|| ImplicitPoolMatcher.checkPoolPropertiesChanged(pool.getCompatibilityStatus(),
DiscoveredDataObject.CompatibilityStatus.COMPATIBLE.name())
|| ImplicitPoolMatcher.checkPoolPropertiesChanged(pool.getDiscoveryStatus(),
DiscoveryStatus.VISIBLE.name())) {
poolsToMatchWithVpool.add(pool);
}
pool.setDiscoveryStatus(DiscoveryStatus.VISIBLE.name());
pool.setCompatibilityStatus(DiscoveredDataObject.CompatibilityStatus.COMPATIBLE.name());
}
} catch (VNXeException e) {
_logger.error("Discovery of storage pools failed for storage system {} for {}", system.getId(),
e.getMessage());
throw e;
}
for (StoragePool newPool : newPools) {
_logger.info("New Storage Pool : " + newPool);
_logger.info("New Storage Pool : {} : {}", newPool.getNativeGuid(), newPool.getId());
}
for (StoragePool pool : existingPools) {
_logger.info("Old Storage Pool : " + pool);
_logger.info("Old Storage Pool : {} : {}", pool.getNativeGuid(), pool.getId());
}
storagePools.put(NEW, newPools);
storagePools.put(EXISTING, existingPools);
_logger.info("Number of pools found {} : ", storagePools.size());
_logger.info("Storage pool discovery for storage system {} complete", system.getId());
return storagePools;
}
/**
* Discover the NasServer (Port Groups) for the specified VNXe storage
* array.
*
* @param system
* storage system information
* @param client
* VNXeServiceClient
* @param nasServerIdMap
* all valid nasServer id map
* @param arraySupportedProtocol
* array supported protocol
* @return Map of New and Existing NasServers
* @throws VNXeException
*/
private HashMap<String, List<StorageHADomain>> discoverNasServers(StorageSystem system, VNXeApiClient client,
Map<String, URI> nasServerIdMap, StringSet arraySupportedProtocols) throws VNXeException {
HashMap<String, List<StorageHADomain>> allNasServers = new HashMap<String, List<StorageHADomain>>();
List<StorageHADomain> newNasServers = new ArrayList<StorageHADomain>();
List<StorageHADomain> existingNasServers = new ArrayList<StorageHADomain>();
List<VirtualNAS> newVirtualNas = new ArrayList<VirtualNAS>();
List<VirtualNAS> existingVirtualNas = new ArrayList<VirtualNAS>();
boolean isNFSSupported = false;
boolean isCIFSSupported = false;
boolean isBothSupported = false;
_logger.info("Start NasServer discovery for storage system {}", system.getId());
List<VNXeNasServer> nasServers = client.getNasServers();
List<VNXeCifsServer> cifsServers = client.getCifsServers();
List<VNXeNfsServer> nfsServers = client.getNfsServers();
for (VNXeNasServer nasServer : nasServers) {
StorageHADomain haDomain = null;
if (null == nasServer) {
_logger.debug("Null data mover in list of port groups.");
continue;
}
if ((nasServer.getMode() == VNXeNasServer.NasServerModeEnum.DESTINATION)
|| nasServer.getIsReplicationDestination()) {
_logger.debug("Found a replication destination NasServer");
continue;
}
if (nasServer.getIsSystem()) {
// skip system nasServer
continue;
}
StringSet protocols = new StringSet();
// Check if port group was previously discovered
URIQueryResultList results = new URIQueryResultList();
String adapterNativeGuid = NativeGUIDGenerator.generateNativeGuid(system, nasServer.getName(),
NativeGUIDGenerator.ADAPTER);
_dbClient.queryByConstraint(AlternateIdConstraint.Factory.getStorageHADomainByNativeGuidConstraint(adapterNativeGuid), results);
Iterator<URI> it = results.iterator();
if (it.hasNext()) {
StorageHADomain tmpDomain = _dbClient.queryObject(StorageHADomain.class, it.next());
if (tmpDomain.getStorageDeviceURI().equals(system.getId())) {
haDomain = tmpDomain;
_logger.debug("Found duplicate {} ", nasServer.getName());
}
}
// get the supported protocol on the nasServer
if (cifsServers != null && !cifsServers.isEmpty()) {
for (VNXeCifsServer cifsServer : cifsServers) {
if (cifsServer.getNasServer().getId().equals(nasServer.getId())) {
protocols.add(StorageProtocol.File.CIFS.name());
isCIFSSupported = true;
break;
}
}
}
if (nfsServers != null && !nfsServers.isEmpty()) {
for (VNXeNfsServer nfsServer : nfsServers) {
if (nfsServer.getNasServer() != null) {
if (nfsServer.getNasServer().getId().equals(nasServer.getId())) {
protocols.add(StorageProtocol.File.NFS.name());
isNFSSupported = true;
break;
}
}
}
}
if (protocols.size() == 2) {
// this nasServer support both
isBothSupported = true;
}
// If the nasServer was not previously discovered
if (haDomain == null) {
haDomain = new StorageHADomain();
haDomain.setId(URIUtil.createId(StorageHADomain.class));
haDomain.setNativeGuid(adapterNativeGuid);
haDomain.setStorageDeviceURI(system.getId());
haDomain.setAdapterName(nasServer.getName());
haDomain.setName(nasServer.getName());
haDomain.setSerialNumber(nasServer.getId());
newNasServers.add(haDomain);
} else {
existingNasServers.add(haDomain);
}
haDomain.setFileSharingProtocols(protocols);
haDomain.setVirtual(true);
nasServerIdMap.put(nasServer.getId(), haDomain.getId());
CifsServerMap cifsServersMap = new CifsServerMap();
for (VNXeCifsServer cifsServer : cifsServers) {
if (cifsServer.getNasServer().getId().equals(nasServer.getId())) {
_logger.info("Cifs Server {} for {} ", cifsServer.getName(), nasServer.getName());
if (!cifsServer.getFileInterfaces().isEmpty()) {
_logger.info("{} has CIFS Enabled since interfaces are found ", nasServer.getName(),
cifsServer.getName() + ":" + cifsServer.getFileInterfaces());
protocols.add(StorageProtocol.File.CIFS.name());
NasCifsServer nasCifsServer = new NasCifsServer();
nasCifsServer.setId(cifsServer.getId());
nasCifsServer.setMoverIdIsVdm(true);
nasCifsServer.setName(cifsServer.getName());
nasCifsServer.setDomain(cifsServer.getDomain());
cifsServersMap.put(cifsServer.getName(), nasCifsServer);
}
}
}
VirtualNAS vNas = findvNasByNativeId(system, nasServer.getId());
// If the nasServer was not previously discovered
if (vNas == null) {
vNas = new VirtualNAS();
vNas.setId(URIUtil.createId(VirtualNAS.class));
String nasNativeGuid = NativeGUIDGenerator.generateNativeGuid(system, nasServer.getId(),
NativeGUIDGenerator.VIRTUAL_NAS);
vNas.setNativeGuid(nasNativeGuid);
vNas.setStorageDeviceURI(system.getId());
vNas.setNasName(nasServer.getName());
vNas.setNativeId(nasServer.getId());
newVirtualNas.add(vNas);
} else {
existingVirtualNas.add(vNas);
}
vNas.setProtocols(protocols);
vNas.setNasState(VirtualNasState.LOADED.name());
vNas.setCifsServersMap(cifsServersMap);
}
// Persist the NAS servers!!!
if (existingVirtualNas != null && !existingVirtualNas.isEmpty()) {
_logger.info("discoverNasServers - modified VirtualNAS servers size {}", existingVirtualNas.size());
_dbClient.updateObject(existingVirtualNas);
}
if (newVirtualNas != null && !newVirtualNas.isEmpty()) {
_logger.info("discoverNasServers - new VirtualNAS servers size {}", newVirtualNas.size());
_dbClient.createObject(newVirtualNas);
}
if (isBothSupported) {
arraySupportedProtocols.add(StorageProtocol.File.NFS.name());
arraySupportedProtocols.add(StorageProtocol.File.CIFS.name());
} else if (isNFSSupported && isCIFSSupported) {
arraySupportedProtocols.add(StorageProtocol.File.NFS_OR_CIFS.name());
} else if (isNFSSupported) {
arraySupportedProtocols.add(StorageProtocol.File.NFS.name());
} else if (isCIFSSupported) {
arraySupportedProtocols.add(StorageProtocol.File.CIFS.name());
}
_logger.info("NasServer discovery for storage system {} complete.", system.getId());
for (StorageHADomain newDomain : newNasServers) {
_logger.info("New NasServer : {} : {}", newDomain.getNativeGuid(), newDomain.getId());
}
for (StorageHADomain domain : existingNasServers) {
_logger.info("Existing NasServer : {} : {}", domain.getNativeGuid(), domain.getId());
}
allNasServers.put(NEW, newNasServers);
allNasServers.put(EXISTING, existingNasServers);
return allNasServers;
}
/**
* Discover file interfaces for specified VNXe Storage Array
*
* @param system
* storage system.
* @param client
* VNXe service client
* @param nasServerIdSet
* all valid NAS Server ids
* @return Map of New and Existing Storage Ports
* @throws VNXeException
*/
private HashMap<String, List<StoragePort>> discoverFileStoragePorts(StorageSystem system, VNXeApiClient client,
Map<String, URI> nasServerIdMap) throws VNXeException {
HashMap<String, List<StoragePort>> storagePorts = new HashMap<String, List<StoragePort>>();
List<StoragePort> newStoragePorts = new ArrayList<StoragePort>();
List<StoragePort> existingStoragePorts = new ArrayList<StoragePort>();
List<VirtualNAS> modifiedServers = new ArrayList<VirtualNAS>();
_logger.info("Start storage port discovery for storage system {}", system.getId());
// Retrieve the list of data movers interfaces for the VNX File device.
List<VNXeFileInterface> interfaces = client.getFileInterfaces();
if (interfaces == null || interfaces.isEmpty()) {
_logger.info("No file interfaces found for the system: {} ", system.getId());
return storagePorts;
}
_logger.info("Number file interfaces found: {}", interfaces.size());
// Create the list of storage ports.
for (VNXeFileInterface intf : interfaces) {
StoragePort port = null;
// Check for valid nasServer
VNXeBase nasServer = intf.getNasServer();
if (nasServer == null) {
continue;
}
String nasServerId = nasServer.getId();
URI haDomainUri = nasServerIdMap.get(nasServerId);
if (haDomainUri == null) {
continue;
}
// Check if storage port was already discovered
String portNativeGuid = NativeGUIDGenerator.generateNativeGuid(system, intf.getIpAddress(), NativeGUIDGenerator.PORT);
URIQueryResultList results = new URIQueryResultList();
_dbClient.queryByConstraint(AlternateIdConstraint.Factory.getStoragePortByNativeGuidConstraint(portNativeGuid), results);
Iterator<URI> it = results.iterator();
if (it.hasNext()) {
_logger.info("cross verifying for duplicate port");
StoragePort tmpPort = _dbClient.queryObject(StoragePort.class, it.next());
_logger.info(String.format(
"StorageDevice found for port %s - Actual StorageDevice %s : PortGroup found for port %s - Actual PortGroup %s",
tmpPort.getStorageDevice(), system.getId(), tmpPort.getPortGroup(), nasServerId));
if (tmpPort.getStorageDevice().equals(system.getId()) && tmpPort.getPortGroup().equals(nasServerId)) {
port = tmpPort;
_logger.info("found duplicate dm intf {}", intf.getName());
}
}
// If data mover interface was not previously discovered, add new
// storage port
if (port == null) {
port = new StoragePort();
port.setId(URIUtil.createId(StoragePort.class));
port.setLabel(portNativeGuid);
port.setTransportType("IP");
port.setNativeGuid(portNativeGuid);
port.setStorageDevice(system.getId());
port.setRegistrationStatus(RegistrationStatus.REGISTERED.toString());
port.setPortName(intf.getName());
port.setPortNetworkId(intf.getIpAddress());
port.setPortGroup(nasServerId);
port.setStorageHADomain(haDomainUri);
_logger.info("Creating new storage port using NativeGuid : {}, IP : {}", portNativeGuid,
intf.getIpAddress());
newStoragePorts.add(port);
} else {
existingStoragePorts.add(port);
}
port.setDiscoveryStatus(DiscoveryStatus.VISIBLE.name());
port.setCompatibilityStatus(DiscoveredDataObject.CompatibilityStatus.COMPATIBLE.name());
// Associate Storage Port to Virtual NAS
VirtualNAS vNas = findvNasByNativeId(system, nasServerId);
if (vNas != null) {
if (vNas.getStoragePorts() != null && !vNas.getStoragePorts().isEmpty()) {
if (vNas.getStoragePorts().contains(port.getId())) {
vNas.getStoragePorts().remove(port.getId());
}
}
vNas.getStoragePorts().add(port.getId().toString());
modifiedServers.add(vNas);
_logger.info("VirtualNAS : {} : port : {} got modified", vNas.getId(), port.getPortName());
}
}
// Persist the modified virtual nas servers
if (modifiedServers != null && !modifiedServers.isEmpty()) {
_logger.info("Modified VirtualNAS servers size {}", modifiedServers.size());
_dbClient.updateObject(modifiedServers);
}
_logger.info("Storage port discovery for storage system {} complete", system.getId());
storagePorts.put(NEW, newStoragePorts);
storagePorts.put(EXISTING, existingStoragePorts);
return storagePorts;
}
/**
* Find the Virtual NAS by Native ID for the specified VNX unity storage
* array
*
* @param system
* storage system information including credentials.
* @param Native
* id of the specified Virtual NAS
* @return Virtual NAS Server
*/
private VirtualNAS findvNasByNativeId(StorageSystem system, String nativeId) {
URIQueryResultList results = new URIQueryResultList();
VirtualNAS vNas = null;
// Set storage port details to vNas
String nasNativeGuid = NativeGUIDGenerator.generateNativeGuid(system, nativeId, NativeGUIDGenerator.VIRTUAL_NAS);
_dbClient.queryByConstraint(AlternateIdConstraint.Factory.getVirtualNASByNativeGuidConstraint(nasNativeGuid), results);
Iterator<URI> iter = results.iterator();
while (iter.hasNext()) {
VirtualNAS tmpVnas = _dbClient.queryObject(VirtualNAS.class, iter.next());
if (tmpVnas != null && !tmpVnas.getInactive()) {
vNas = tmpVnas;
_logger.info("found virtual NAS {}", tmpVnas.getNativeGuid() + ":" + tmpVnas.getNasName());
break;
}
}
return vNas;
}
/**
* Discover storage processors for the specified VNX unity storage array
*
* @param system
* storage system information including credentials.
* @param client
* The unity api client
* @param spIdMap
* Map of storage processor native ids
* @return map of all storage processors as StorageHADomain
*/
private HashMap<String, List<StorageHADomain>> discoverStorageProcessors(StorageSystem system, VNXeApiClient client,
Map<String, URI> spIdMap) throws VNXeException {
HashMap<String, List<StorageHADomain>> result = new HashMap<String, List<StorageHADomain>>();
List<StorageHADomain> newSPs = new ArrayList<StorageHADomain>();
List<StorageHADomain> existingSPs = new ArrayList<StorageHADomain>();
_logger.info("Start storage processor discovery for storage system {}", system.getId());
List<VNXeStorageProcessor> sps = client.getStorageProcessors();
for (VNXeStorageProcessor sp : sps) {
StorageHADomain haDomain = null;
if (null == sp) {
_logger.debug("Null sp in the list of storage processors.");
continue;
}
// Check if sp was previously discovered
URIQueryResultList results = new URIQueryResultList();
String adapterNativeGuid = NativeGUIDGenerator.generateNativeGuid(system, sp.getId(), NativeGUIDGenerator.ADAPTER);
_dbClient.queryByConstraint(AlternateIdConstraint.Factory.getStorageHADomainByNativeGuidConstraint(adapterNativeGuid), results);
Iterator<URI> it = results.iterator();
if (it.hasNext()) {
StorageHADomain tmpDomain = _dbClient.queryObject(StorageHADomain.class, it.next());
if (tmpDomain.getStorageDeviceURI().equals(system.getId())) {
haDomain = tmpDomain;
_logger.debug("Found existing {} ", sp.getId());
}
}
// If the sp was not previously discovered
if (haDomain == null) {
haDomain = new StorageHADomain();
haDomain.setId(URIUtil.createId(StorageHADomain.class));
haDomain.setNativeGuid(adapterNativeGuid);
haDomain.setStorageDeviceURI(system.getId());
haDomain.setAdapterName(sp.getId());
haDomain.setName(sp.getId());
haDomain.setSerialNumber(sp.getEmcSerialNumber());
newSPs.add(haDomain);
} else {
existingSPs.add(haDomain);
}
if (sp.getSlotNumber() != null) {
haDomain.setSlotNumber(sp.getSlotNumber().toString());
}
spIdMap.put(sp.getId(), haDomain.getId());
}
_logger.info("Storage processors discovery for storage system {} complete.", system.getId());
for (StorageHADomain newDomain : newSPs) {
_logger.info("New storage processor : {} : {}", newDomain.getNativeGuid(), newDomain.getId());
}
for (StorageHADomain domain : existingSPs) {
_logger.info("Existing storage processor : {} : {}", domain.getNativeGuid(), domain.getId());
}
result.put(NEW, newSPs);
result.put(EXISTING, existingSPs);
return result;
}
/**
* Discover iscsiPorts
*
* @param system
* @param client
* @param spIdMap
* storage processors VNXeId and ViPR URI map
* @return
* @throws VNXeException
*/
private HashMap<String, List<StoragePort>> discoverIscsiPorts(StorageSystem system, VNXeApiClient client,
Map<String, URI> spIdMap) throws VNXeException {
HashMap<String, List<StoragePort>> storagePorts = new HashMap<String, List<StoragePort>>();
List<StoragePort> newStoragePorts = new ArrayList<StoragePort>();
List<StoragePort> existingStoragePorts = new ArrayList<StoragePort>();
_logger.info("Start iSCSI storage port discovery for storage system {}", system.getId());
// Retrieve the list of iscsi ports
List<VNXeIscsiNode> ports = client.getAllIscsiPorts();
if (ports == null || ports.isEmpty()) {
_logger.info("No iSCSI ports found for the system: {} ", system.getId());
return storagePorts;
}
_logger.info("Number iSCSI ports found: {}", ports.size());
// Create the list of storage ports.
for (VNXeIscsiNode node : ports) {
StoragePort port = null;
VNXeEthernetPort eport = node.getEthernetPort();
if (eport == null) {
_logger.info("No ethernet port found for the iscsi node: {}", node.getId());
continue;
}
VNXeBase spId = eport.getStorageProcessor();
if (spId == null) {
_logger.info("No storage processor info for the iscsi node: {}", node.getId());
continue;
}
String spIdStr = spId.getId();
URI haDomainUri = spIdMap.get(spIdStr);
if (haDomainUri == null) {
_logger.info("The sp {} has not been discovered.", spIdStr);
continue;
}
// Check if storage port was already discovered
String portNativeGuid = NativeGUIDGenerator.generateNativeGuid(system, node.getName(), NativeGUIDGenerator.PORT);
URIQueryResultList results = new URIQueryResultList();
_dbClient.queryByConstraint(AlternateIdConstraint.Factory.getStoragePortByNativeGuidConstraint(portNativeGuid), results);
Iterator<URI> it = results.iterator();
if (it.hasNext()) {
_logger.info("cross verifying for duplicate port");
StoragePort tmpPort = _dbClient.queryObject(StoragePort.class, it.next());
_logger.info(
String.format("Actual StorageDevice %s : PortGroup found for port %s - Actual PortGroup %s", system.getId(),
tmpPort.getPortNetworkId(), tmpPort.getPortGroup()));
if (tmpPort.getStorageDevice().equals(system.getId()) && tmpPort.getPortGroup().equals(spIdStr)) {
port = tmpPort;
_logger.info("found duplicate iscsi port {}", node.getName());
}
}
// If iscsi port was not previously discovered, add new storage port
if (port == null) {
port = new StoragePort();
port.setId(URIUtil.createId(StoragePort.class));
port.setLabel(portNativeGuid);
port.setTransportType("IP");
port.setNativeGuid(portNativeGuid);
port.setStorageDevice(system.getId());
port.setRegistrationStatus(RegistrationStatus.REGISTERED.toString());
port.setPortName(eport.getId());
port.setPortNetworkId(node.getName());
port.setPortGroup(spIdStr);
port.setStorageHADomain(haDomainUri);
VNXeIscsiPortal portal = node.getIscsiPortal();
if (portal != null) {
port.setIpAddress(portal.getIpAddress());
}
_logger.info("Creating new storage port using NativeGuid : {}, IQN:", portNativeGuid, node.getName());
newStoragePorts.add(port);
} else {
existingStoragePorts.add(port);
}
Health health = node.getEthernetPort().getHealth();
if (health != null && health.getValue() == Health.HealthEnum.OK.getValue()) {
port.setOperationalStatus(StoragePort.OperationalStatus.OK.name());
} else {
port.setOperationalStatus(StoragePort.OperationalStatus.NOT_OK.name());
}
port.setDiscoveryStatus(DiscoveryStatus.VISIBLE.name());
port.setCompatibilityStatus(DiscoveredDataObject.CompatibilityStatus.COMPATIBLE.name());
}
_logger.info("iSCSI port discovery for storage system {} complete", system.getId());
storagePorts.put(NEW, newStoragePorts);
storagePorts.put(EXISTING, existingStoragePorts);
return storagePorts;
}
/**
* Discover fcPorts
*
* @param system
* @param client
* @param spIdMap
* storage processors VNXeId and ViPR URI map
* @return
* @throws VNXeException
*/
private HashMap<String, List<StoragePort>> discoverFcPorts(StorageSystem system, VNXeApiClient client,
Map<String, URI> spIdMap) throws VNXeException {
HashMap<String, List<StoragePort>> storagePorts = new HashMap<String, List<StoragePort>>();
List<StoragePort> newStoragePorts = new ArrayList<StoragePort>();
List<StoragePort> existingStoragePorts = new ArrayList<StoragePort>();
_logger.info("Start FC storage port discovery for storage system {}", system.getId());
// Retrieve the list of iscsi ports
List<VNXeFCPort> ports = client.getAllFcPorts();
if (ports == null || ports.isEmpty()) {
_logger.info("No FC ports found for the system: {} ", system.getId());
storagePorts.put(NEW, newStoragePorts);
storagePorts.put(EXISTING, existingStoragePorts);
return storagePorts;
}
// Create the list of storage ports.
for (VNXeFCPort fcPort : ports) {
StoragePort port = null;
VNXeBase spId = fcPort.getStorageProcessor();
if (spId == null) {
_logger.info("No storage processor info for the fcPort: {}", fcPort.getId());
continue;
}
String spIdStr = spId.getId();
URI haDomainUri = spIdMap.get(spIdStr);
if (haDomainUri == null) {
_logger.info("The sp {} has not been discovered.", spIdStr);
continue;
}
// Check if storage port was already discovered
String portNativeGuid = NativeGUIDGenerator.generateNativeGuid(system, fcPort.getWwn(), NativeGUIDGenerator.PORT);
URIQueryResultList results = new URIQueryResultList();
_dbClient.queryByConstraint(AlternateIdConstraint.Factory.getStoragePortByNativeGuidConstraint(portNativeGuid), results);
Iterator<URI> it = results.iterator();
if (it.hasNext()) {
_logger.debug("cross verifying for duplicate port");
StoragePort tmpPort = _dbClient.queryObject(StoragePort.class, it.next());
_logger.info(String.format("Actual StorageDevice %s : PortGroup found for port %s - Actual PortGroup %s", system.getId(),
tmpPort.getPortNetworkId(), tmpPort.getPortGroup()));
if (tmpPort.getStorageDevice().equals(system.getId()) && tmpPort.getPortGroup().equals(spIdStr)) {
port = tmpPort;
_logger.debug("found duplicate fc port {}", fcPort.getWwn());
}
}
// If the fc port was not previously discovered, add new storage
// port
if (port == null) {
port = new StoragePort();
port.setId(URIUtil.createId(StoragePort.class));
port.setLabel(portNativeGuid);
port.setTransportType("FC");
port.setNativeGuid(portNativeGuid);
port.setStorageDevice(system.getId());
port.setRegistrationStatus(RegistrationStatus.REGISTERED.toString());
port.setPortName(fcPort.getId());
port.setPortNetworkId(fcPort.getPortWwn());
port.setPortGroup(spIdStr);
port.setStorageHADomain(haDomainUri);
_logger.info("Creating new storage port using NativeGuid : {}, WWN:", portNativeGuid, fcPort.getWwn());
newStoragePorts.add(port);
} else {
existingStoragePorts.add(port);
}
Health portHealth = fcPort.getHealth();
if (portHealth != null) {
int healthValue = portHealth.getValue();
if (healthValue == Health.HealthEnum.OK.getValue()) {
port.setOperationalStatus(StoragePort.OperationalStatus.OK.name());
} else {
port.setOperationalStatus(StoragePort.OperationalStatus.NOT_OK.name());
}
}
port.setDiscoveryStatus(DiscoveryStatus.VISIBLE.name());
port.setCompatibilityStatus(DiscoveredDataObject.CompatibilityStatus.COMPATIBLE.name());
}
_logger.info("FC port discovery for storage system {} complete", system.getId());
storagePorts.put(NEW, newStoragePorts);
storagePorts.put(EXISTING, existingStoragePorts);
return storagePorts;
}
/**
* Discover StorageTiers
*
* @param system
* @param client
* @return
* @throws VNXeException
*/
private HashMap<String, List<StorageTier>> discoverStorageTier(StorageSystem system, VNXeApiClient client)
throws VNXeException {
HashMap<String, List<StorageTier>> storageTiers = new HashMap<String, List<StorageTier>>();
List<StorageTier> newTiers = new ArrayList<StorageTier>();
List<StorageTier> existingTiers = new ArrayList<StorageTier>();
List<VNXeStorageTier> tiers = client.getStorageTiers();
String systemNativeGuid = NativeGUIDGenerator.generateNativeGuid(system);
for (VNXeStorageTier tier : tiers) {
String nativeId = tier.getId();
StorageTier tierObj = null;
String tierNativeGuid = NativeGUIDGenerator.generateStorageTierNativeGuidForVmaxTier(systemNativeGuid, nativeId);
URIQueryResultList results = new URIQueryResultList();
_dbClient.queryByConstraint(AlternateIdConstraint.Factory.getStorageTierByIdConstraint(tierNativeGuid), results);
Iterator<URI> it = results.iterator();
if (it.hasNext()) {
_logger.info("Getting the storage tier.");
StorageTier tmpTier = _dbClient.queryObject(StorageTier.class, it.next());
_logger.info(String.format("Actual StorageDevice %s : storage tier : %s", system.getId(), tmpTier.getNativeGuid()));
tierObj = tmpTier;
}
boolean isNewTier = false;
if (null == tierObj) {
tierObj = new StorageTier();
tierObj.setId(URIUtil.createId(StorageTier.class));
tierObj.setNativeGuid(tierNativeGuid);
isNewTier = true;
}
tierObj.setLabel(tier.getId());
tierObj.setTotalCapacity(VNXeUtils.convertDoubleSizeToViPRLong(tier.getSizeTotal()));
if (isNewTier) {
newTiers.add(tierObj);
} else {
existingTiers.add(tierObj);
}
}
storageTiers.put(NEW, newTiers);
storageTiers.put(EXISTING, existingTiers);
return storageTiers;
}
/**
* Discover autoTier policies
*
* @param system
* @param apiClient
* @return
*/
private HashMap<String, List<AutoTieringPolicy>> discoverAutoTierPolicies(StorageSystem system,
VNXeApiClient apiClient) {
HashMap<String, List<AutoTieringPolicy>> policies = new HashMap<String, List<AutoTieringPolicy>>();
List<AutoTieringPolicy> newPolicies = new ArrayList<AutoTieringPolicy>();
List<AutoTieringPolicy> updatePolicies = new ArrayList<AutoTieringPolicy>();
String[] tierPolicies = apiClient.getAutoTierPolicies();
String systemNativeGuid = NativeGUIDGenerator.generateNativeGuid(system);
for (String policyName : tierPolicies) {
String policyNativeGuid = NativeGUIDGenerator.generateAutoTierPolicyNativeGuid(systemNativeGuid, policyName,
NativeGUIDGenerator.FASTPOLICY);
URIQueryResultList result = new URIQueryResultList();
_dbClient.queryByConstraint(AlternateIdConstraint.Factory.getAutoTieringPolicyByNativeGuidConstraint(policyNativeGuid), result);
AutoTieringPolicy policy = null;
if (result.iterator().hasNext()) {
policy = _dbClient.queryObject(AutoTieringPolicy.class, result.iterator().next());
}
boolean newPolicy = false;
if (null == policy) {
newPolicy = true;
policy = new AutoTieringPolicy();
policy.setId(URIUtil.createId(AutoTieringPolicy.class));
policy.setStorageSystem(system.getId());
policy.setNativeGuid(policyNativeGuid);
policy.setSystemType(system.getSystemType());
}
policy.setLabel(policyName);
policy.setPolicyName(policyName);
policy.setPolicyEnabled(true);
policy.setProvisioningType(AutoTieringPolicy.ProvisioningType.All.name());
if (newPolicy) {
newPolicies.add(policy);
} else {
updatePolicies.add(policy);
}
}
policies.put(NEW, newPolicies);
policies.put(EXISTING, updatePolicies);
return policies;
}
@Override
public void collectStatisticsInformation(AccessProfile accessProfile) throws VNXeException {
URI storageSystemId = accessProfile.getSystemId();
StorageSystem storageSystem = null;
try {
_logger.info("Start collecting statistics for ip address {}",
accessProfile.getIpAddress());
VNXeApiClient client = getVnxUnityClient(accessProfile);
long latestSampleTime = accessProfile.getLastSampleTime();
storageSystem = _dbClient.queryObject(StorageSystem.class, storageSystemId);
String serialNumber = storageSystem.getSerialNumber();
String deviceType = storageSystem.getSystemType();
// compute static load processor code
computeStaticLoadMetrics(accessProfile);
// TODO: Do we need usage stats?
_logger.info("End collecting statistics for ip address {}",
accessProfile.getIpAddress());
} catch (Exception e) {
_logger.error("CollectStatisticsInformation failed. Storage system: " + storageSystemId, e);
throw VNXeException.exceptions.discoveryError("Failed to collect statistics ", e);
}
}
/**
* Compute static load metrics.
*
* @param accessProfile
* @return
*/
private void computeStaticLoadMetrics(AccessProfile accessProfile) throws BaseCollectionException {
URI storageSystemId = accessProfile.getSystemId();
StorageSystem storageSystem = null;
try {
storageSystem = _dbClient.queryObject(StorageSystem.class, storageSystemId);
_logger.info("started computeStaticLoadMetrics for storagesystem: {}", storageSystem.getLabel());
VNXeApiClient client = getVnxUnityClient(accessProfile);
List<VNXeNasServer> nasServers = client.getNasServers();
for (VNXeNasServer nasServer : nasServers) {
if ((nasServer.getMode() == VNXeNasServer.NasServerModeEnum.DESTINATION)
|| nasServer.getIsReplicationDestination()) {
_logger.debug("Found a replication destination NasServer");
continue;
}
if (nasServer.getIsSystem()) {
// skip system nasServer
continue;
}
VirtualNAS virtualNAS = findvNasByNativeId(storageSystem, nasServer.getId());
if (virtualNAS != null) {
_logger.info("Process db metrics for nas server : {}", nasServer.getName());
StringMap dbMetrics = virtualNAS.getMetrics();
if (dbMetrics == null) {
dbMetrics = new StringMap();
}
// process db metrics
StringMap tmpDbMetrics = populateDbMetrics(nasServer, client);
dbMetrics.putAll(tmpDbMetrics);
// set dbMetrics in db
virtualNAS.setMetrics(dbMetrics);
_dbClient.updateObject(virtualNAS);
}
}
} catch (Exception e) {
_logger.error("CollectStatisticsInformation failed. Storage system: {}", storageSystemId, e);
}
}
/**
* Calculate nas server metrics
*
* @param nasServer
* @param apiClient
* @return StringMap containing calculated metrics
*/
private StringMap populateDbMetrics(final VNXeNasServer nasServer, VNXeApiClient client) {
StringMap dbMetrics = new StringMap();
long totalProvCap = 0L;
long totalFsCount = 0L;
// get total exports
int nfsSharesCount = 0;
int cifsSharesCount = 0;
List<VNXeFileSystem> fileSystemList = client.getFileSystemsForNasServer(nasServer.getId());
if (fileSystemList != null && !fileSystemList.isEmpty()) {
for (VNXeFileSystem fs : fileSystemList) {
totalProvCap = totalProvCap + fs.getSizeTotal();
totalFsCount++;
List<VNXeNfsShare> nfsShares = client.getNfsSharesForFileSystem(fs.getId());
if (nfsShares != null && !nfsShares.isEmpty()) {
nfsSharesCount = nfsSharesCount + nfsShares.size();
}
List<VNXeCifsShare> cifsShares = client.getCifsSharesForFileSystem(fs.getId());
if (cifsShares != null && !cifsShares.isEmpty()) {
cifsSharesCount = cifsSharesCount + cifsShares.size();
}
List<VNXeFileSystemSnap> snapshotsList = client.getFileSystemSnaps(fs.getId());
if (snapshotsList != null && !snapshotsList.isEmpty()) {
for (VNXeFileSystemSnap snap : snapshotsList) {
totalProvCap = totalProvCap + snap.getSize();
totalFsCount++;
List<VNXeNfsShare> snapNfsShares = client.getNfsSharesForSnap(snap.getId());
if (snapNfsShares != null && !snapNfsShares.isEmpty()) {
nfsSharesCount = nfsSharesCount + snapNfsShares.size();
}
List<VNXeCifsShare> snapCifsShares = client.getCifsSharesForSnap(snap.getId());
if (snapCifsShares != null && !snapCifsShares.isEmpty()) {
cifsSharesCount = cifsSharesCount + snapCifsShares.size();
}
}
}
}
}
if (totalProvCap > 0) {
totalProvCap = (totalProvCap / KB_IN_BYTES);
}
_logger.info("Total fs Count {} for nas server : {}", String.valueOf(totalFsCount), nasServer.getName());
_logger.info("Total fs Capacity {} for nas server : {}", String.valueOf(totalProvCap), nasServer.getName());
// Set max limits in dbMetrics
StringMap maxDbMetrics = getMaxDbMetrics(client);
dbMetrics.putAll(maxDbMetrics);
// set total nfs and cifs exports for this nas server
dbMetrics.put(MetricsKeys.totalNfsExports.name(), String.valueOf(nfsSharesCount));
dbMetrics.put(MetricsKeys.totalCifsShares.name(), String.valueOf(cifsSharesCount));
// set total fs objects and their sum of capacity for this nas server
dbMetrics.put(MetricsKeys.storageObjects.name(), String.valueOf(totalFsCount));
dbMetrics.put(MetricsKeys.usedStorageCapacity.name(), String.valueOf(totalProvCap));
Long maxExports = MetricsKeys.getLong(MetricsKeys.maxExports, dbMetrics);
Long maxStorObjs = MetricsKeys.getLong(MetricsKeys.maxStorageObjects, dbMetrics);
Long maxCapacity = MetricsKeys.getLong(MetricsKeys.maxStorageCapacity, dbMetrics);
Long totalExports = Long.valueOf(nfsSharesCount + cifsSharesCount);
// setting overLoad factor (true or false)
String overLoaded = FALSE;
if (totalExports >= maxExports || totalProvCap >= maxCapacity || totalFsCount >= maxStorObjs) {
overLoaded = TRUE;
}
double percentageLoadExports = 0.0;
// percentage calculator
if (totalExports > 0.0) {
percentageLoadExports = ((double) (totalExports) / maxExports) * 100;
}
double percentageLoadStorObj = ((double) (totalProvCap) / maxCapacity) * 100;
double percentageLoad = (percentageLoadExports + percentageLoadStorObj) / 2;
dbMetrics.put(MetricsKeys.percentLoad.name(), String.valueOf(percentageLoad));
dbMetrics.put(MetricsKeys.overLoaded.name(), overLoaded);
return dbMetrics;
}
/**
* get the Max limits for static db metrics
*
* @param system
* @return dbMetrics
*/
private StringMap getMaxDbMetrics(final VNXeApiClient client) {
StringMap dbMetrics = new StringMap();
// Set the Limit Metric keys
// default values
Long MaxTotalExports = MAX_EXPORTS;
long MaxCapacityInTB = MAX_CAPACITY_TB;
Long MaxStorObjects = MAX_STORAGE_OBJECTS;
BasicSystemInfo unitySystem = client.getBasicSystemInfo();
String model = unitySystem.getModel();
if (model.equals(UNITY_300)) {
MaxTotalExports = MAX_EXPORTS_UNITY300;
MaxCapacityInTB = MAX_CAPACITY_UNITY300_TB;
MaxStorObjects = MAX_STORAGE_OBJECTS_UNITY300;
} else if (model.equals(UNITY_400)) {
MaxTotalExports = MAX_EXPORTS_UNITY400;
MaxCapacityInTB = MAX_CAPACITY_UNITY400_TB;
MaxStorObjects = MAX_STORAGE_OBJECTS_UNITY400;
} else if (model.equals(UNITY_500)) {
MaxTotalExports = MAX_EXPORTS_UNITY500;
MaxCapacityInTB = MAX_CAPACITY_UNITY500_TB;
MaxStorObjects = MAX_STORAGE_OBJECTS_UNITY500;
} else if (model.equals(UNITY_600)) {
MaxTotalExports = MAX_EXPORTS_UNITY600;
MaxCapacityInTB = MAX_CAPACITY_UNITY600_TB;
MaxStorObjects = MAX_STORAGE_OBJECTS_UNITY600;
} else if (model.equals(UNITY_VSA)) {
MaxTotalExports = MAX_EXPORTS_UNITYVSA;
MaxCapacityInTB = MAX_CAPACITY_UNITYVSA_TB;
MaxStorObjects = MAX_STORAGE_OBJECTS_UNITYVSA;
} else {
_logger.info("Cannot determine Max nas server limits for Unity model: {}. Using defaults", model);
}
dbMetrics.put(MetricsKeys.maxExports.name(), String.valueOf(MaxTotalExports));
dbMetrics.put(MetricsKeys.maxStorageObjects.name(), String.valueOf(MaxStorObjects));
// set the max capacity in KB
dbMetrics.put(MetricsKeys.maxStorageCapacity.name(), String.valueOf(MaxCapacityInTB * TB_IN_GB * GB_IN_KB));
return dbMetrics;
}
/**
* Check if the pool's autotiering is enabled. if there are more than one tier in the pool, then it is enabled.
*
* @param vnxePool
* @param system
* @return true or false
*/
private boolean getPoolAutoTieringEnabled(VNXePool vnxePool, StorageSystem system) {
boolean enabled = false;
if (system.getAutoTieringEnabled()) {
List<PoolTier> tiers = vnxePool.getTiers();
int numOfTiers = 0;
if (tiers != null && !tiers.isEmpty()) {
for (PoolTier tier : tiers) {
if (tier.getSizeTotal() > 0) {
numOfTiers++;
}
}
}
enabled = numOfTiers > 1;
}
return enabled;
}
}