/*
* Copyright (c) 2014 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.impl.plugins;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
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.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.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.StorageSystem;
import com.emc.storageos.db.client.model.StorageTier;
import com.emc.storageos.db.client.model.StringSet;
import com.emc.storageos.db.exceptions.DatabaseException;
import com.emc.storageos.plugins.AccessProfile;
import com.emc.storageos.plugins.BaseCollectionException;
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.DiskGroup;
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.VNXeEthernetPort;
import com.emc.storageos.vnxe.models.VNXeFCPort;
import com.emc.storageos.vnxe.models.VNXeFileInterface;
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.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.utils.DiscoveryUtils;
import com.emc.storageos.volumecontroller.impl.utils.ImplicitPoolMatcher;
import com.emc.storageos.volumecontroller.impl.vnxe.VNXeUnManagedObjectDiscoverer;
/**
* VNXeCommunicationInterface class is an implementation of
* CommunicationInterface which is responsible to discover for VNXe using
* KittyHawk API.
*
*/
public class VNXeCommunicationInterface extends
ExtendedCommunicationInterfaceImpl {
private static final Logger _logger = LoggerFactory
.getLogger(VNXeCommunicationInterface.class);
private static final String NEW = "new";
private static final String EXISTING = "existing";
// Reference to the Vnxe client factory allows us to get a Vnxe client
// and execute requests to the Vnxe storage system.
private VNXeApiClientFactory _clientFactory;
private VNXeUnManagedObjectDiscoverer unManagedObjectDiscoverer;
public VNXeCommunicationInterface() {
};
public VNXeApiClientFactory getVnxeApiClientFactory() {
return _clientFactory;
}
public void setVnxeApiClientFactory(VNXeApiClientFactory _clientFactory) {
this._clientFactory = _clientFactory;
}
public void setUnManagedObjectDiscoverer(
VNXeUnManagedObjectDiscoverer volumeDiscoverer) {
this.unManagedObjectDiscoverer = volumeDiscoverer;
}
/**
* Implementation for scan for Vnxe storage systems.
*
* @param accessProfile
*
* @throws BaseCollectionException
*/
@Override
public void scan(AccessProfile accessProfile)
throws BaseCollectionException {
}
/**
* Implementation for discovery for Vnxe storage systems, file related only
* for now
*
* @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 Vnxe storage system from the database.
viprStorageSystem = _dbClient.queryObject(StorageSystem.class,
storageSystemURI);
_logger.info(String.format(
"Discover Vnxe storage system %s at IP:%s, PORT:%s",
storageSystemURI.toString(),
accessProfile.getIpAddress(),
accessProfile.getPortNumber()));
// Get the vnxe service client for getting information about the
// Vnxe
// storage system.
VNXeApiClient client = getVnxeClient(accessProfile);
_logger.debug("Got handle to Vnxe 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 = false;
if (system != null) {
viprStorageSystem.setSerialNumber(system.getSerialNumber());
String guid = NativeGUIDGenerator
.generateNativeGuid(viprStorageSystem);
viprStorageSystem.setNativeGuid(guid);
viprStorageSystem.setLabel(guid);
viprStorageSystem
.setCompatibilityStatus(DiscoveredDataObject.CompatibilityStatus.COMPATIBLE
.name());
viprStorageSystem.setReachableStatus(true);
isFASTVPEnabled = client.isFASTVPEnabled();
viprStorageSystem.setAutoTieringEnabled(isFASTVPEnabled);
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);
_dbClient.persistObject(viprStorageSystem);
_completer.statusPending(_dbClient,
"Completed discovery of system properties");
} else {
_logger.error("Failed to retrieve VNXe system info!");
viprStorageSystem.setReachableStatus(false);
}
// get version for the storage system
BasicSystemInfo info = client.getBasicSystemInfo();
if (info != null) {
viprStorageSystem.setFirmwareVersion(info
.getSoftwareVersion());
}
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.persistObject(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.persistObject(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.persistObject(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.persistObject(ports.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.persistObject(ports.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 VNXe 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.persistObject(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");
/**
* 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.persistObject(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.persistObject(tiers.get(EXISTING));
}
}
detailedStatusMessage = String
.format("Discovery completed successfully for Storage System: %s",
storageSystemURI.toString());
}
} catch (Exception e) {
detailedStatusMessage = String.format(
"Discovery failed for VNXe %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.persistObject(viprStorageSystem);
} catch (DatabaseException ex) {
_logger.error("Error while persisting object to DB", ex);
}
}
}
}
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.persistObject(storageSystem);
if (accessProfile.getnamespace().equals(
StorageSystem.Discovery_Namespaces.UNMANAGED_FILESYSTEMS
.toString())) {
unManagedObjectDiscoverer.discoverUnManagedFileSystems(
accessProfile, _dbClient, _coordinator,
_partitionManager);
unManagedObjectDiscoverer.discoverAllExportRules(accessProfile,
_dbClient, _partitionManager);
unManagedObjectDiscoverer.discoverAllCifsShares(accessProfile,
_dbClient, _partitionManager);
} else if (accessProfile.getnamespace().equals(
StorageSystem.Discovery_Namespaces.UNMANAGED_VOLUMES
.toString())) {
unManagedObjectDiscoverer.discoverUnManagedVolumes(
accessProfile, _dbClient, _coordinator,
_partitionManager);
}
// discovery succeeds
detailedStatusMessage = String
.format("UnManaged Object Discovery completed successfully for VNXe: %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.persistObject(storageSystem);
} catch (Exception ex) {
_logger.error(
"Error while updating unmanaged object discovery status for system.",
ex);
}
}
}
}
/**
* Get the Vnxe service client for making requests to the Vnxe based on the
* passed profile.
*
* @param accessProfile
* A reference to the access profile.
*
* @return A reference to the Vnxe service client.
*/
private VNXeApiClient getVnxeClient(AccessProfile accessProfile) {
VNXeApiClient client = _clientFactory.getClient(
accessProfile.getIpAddress(), accessProfile.getPortNumber(),
accessProfile.getUserName(), accessProfile.getPassword());
return client;
}
/**
* Returns the list of storage pools for the specified VNXe storage system.
*
* @param system
* storage system information.
* @param client
* VNXe 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;
if (results.iterator().hasNext()) {
StoragePool tmpPool = _dbClient.queryObject(
StoragePool.class, results.iterator().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.setOperationalStatus(vnxePool.getStatus());
pool.setPoolServiceType(PoolServiceType.block_file
.toString());
pool.setStorageDevice(system.getId());
pool.setProtocols(supportedProtocols);
pool.setNativeId(vnxePool.getId());
pool.setPoolName(vnxePool.getName());
pool.setCompatibilityStatus(DiscoveredDataObject.CompatibilityStatus.COMPATIBLE
.name());
StringSet raidLevels = new StringSet();
RaidTypeEnum raid = vnxePool.getRaidTypeEnum();
if (raid != null) {
raidLevels.add(vnxePool.getRaidTypeEnum().name());
pool.setSupportedRaidLevels(raidLevels);
}
// 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.setAutoTieringEnabled(getPoolAutoTieringEnabled(
vnxePool, system));
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);
pool.setOperationalStatus(vnxePool.getStatus());
if (ImplicitPoolMatcher.checkPoolPropertiesChanged(pool.getProtocols(), supportedProtocols)) {
isModified = true;
}
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));
existingPools.add(pool);
}
List<PoolTier> poolTiers = vnxePool.getTiers();
StringSet diskTypes = new StringSet();
for (PoolTier poolTier : poolTiers) {
List<RaidGroup> raidGroups = poolTier.getRaidGroups();
for (RaidGroup raidGroup : raidGroups) {
VNXeBase diskGroup = raidGroup.getDiskGroup();
if (diskGroup != null) {
DiskGroup diskgroupObj = client
.getDiskGroup(diskGroup.getId());
diskTypes.add(diskgroupObj.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());
}
// return storagePools;
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>();
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) {
_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);
if (results.iterator().hasNext()) {
StorageHADomain tmpDomain = _dbClient.queryObject(
StorageHADomain.class, results.iterator().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().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());
haDomain.setFileSharingProtocols(protocols);
newNasServers.add(haDomain);
} else {
haDomain.setFileSharingProtocols(protocols);
existingNasServers.add(haDomain);
}
nasServerIdMap.put(nasServer.getId(), haDomain.getId());
}
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());
}
// return portGroups;
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>();
_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);
if (results.iterator().hasNext()) {
_logger.info("cross verifying for duplicate port");
StoragePort tmpPort = _dbClient.queryObject(StoragePort.class,
results.iterator().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());
}
_logger.info("Storage port discovery for storage system {} complete",
system.getId());
storagePorts.put(NEW, newStoragePorts);
storagePorts.put(EXISTING, existingStoragePorts);
return storagePorts;
}
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);
if (results.iterator().hasNext()) {
StorageHADomain tmpDomain = _dbClient.queryObject(
StorageHADomain.class, results.iterator().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);
}
spIdMap.put(sp.getId(), haDomain.getId());
}
_logger.info(
"Storage processors discovery for storage system {} complete.",
system.getId());
for (StorageHADomain newDomain : newSPs) {
_logger.info("New NasServer : {} : {}", newDomain.getNativeGuid(),
newDomain.getId());
}
for (StorageHADomain domain : existingSPs) {
_logger.info("Existing NasServer : {} : {}",
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.getStorageProcessorId();
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);
if (results.iterator().hasNext()) {
_logger.info("cross verifying for duplicate port");
StoragePort tmpPort = _dbClient.queryObject(StoragePort.class,
results.iterator().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);
List<Integer> opstatus = eport.getOperationalStatus();
Integer ok = 2;
if (opstatus.contains(ok)) {
port.setOperationalStatus(StoragePort.OperationalStatus.OK
.name());
} else {
port.setOperationalStatus(StoragePort.OperationalStatus.NOT_OK
.name());
}
VNXeIscsiPortal portal = node.getIscsiPortal();
if (portal != null) {
port.setIpAddress(portal.getIpAddress());
} else {
port.setOperationalStatus(StoragePort.OperationalStatus.NOT_OK
.name());
}
_logger.info(
"Creating new storage port using NativeGuid : {}, IQN:",
portNativeGuid, node.getName());
newStoragePorts.add(port);
} else {
existingStoragePorts.add(port);
}
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.getStorageProcessorId();
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);
if (results.iterator().hasNext()) {
_logger.debug("cross verifying for duplicate port");
StoragePort tmpPort = _dbClient.queryObject(StoragePort.class,
results.iterator().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);
List<Integer> opstatus = fcPort.getOperationalStatus();
Integer ok = 2;
if (opstatus.contains(ok)) {
port.setOperationalStatus(StoragePort.OperationalStatus.OK
.name());
} else {
port.setOperationalStatus(StoragePort.OperationalStatus.NOT_OK
.name());
}
_logger.info(
"Creating new storage port using NativeGuid : {}, WWN:",
portNativeGuid, fcPort.getWwn());
newStoragePorts.add(port);
} else {
existingStoragePorts.add(port);
}
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;
}
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);
if (results.iterator().hasNext()) {
_logger.info("Getting the storage tier.");
StorageTier tmpTier = _dbClient.queryObject(StorageTier.class,
results.iterator().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.getName());
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;
}
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 {
_logger.info("Start collecting statistics for ip address {}",
accessProfile.getIpAddress());
_logger.info("End collecting statistics for ip address {}",
accessProfile.getIpAddress());
}
private boolean getPoolAutoTieringEnabled(VNXePool vnxePool,
StorageSystem system) {
boolean enabled = false;
if (system.getAutoTieringEnabled()) {
List<PoolTier> tiers = vnxePool.getTiers();
int numOfTiers = 0;
for (PoolTier tier : tiers) {
if (tier.getSizeTotal() > 0) {
numOfTiers++;
}
}
if (numOfTiers > 1) {
enabled = true;
} else {
enabled = false;
}
}
return enabled;
}
}