/*
* Copyright 2016 Dell Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.emc.storageos.driver.dellsc.helpers;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.lang.mutable.MutableInt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.driver.dellsc.DellSCDriverException;
import com.emc.storageos.driver.dellsc.DellSCDriverTask;
import com.emc.storageos.driver.dellsc.DellSCUtil;
import com.emc.storageos.driver.dellsc.scapi.StorageCenterAPI;
import com.emc.storageos.driver.dellsc.scapi.StorageCenterAPIException;
import com.emc.storageos.driver.dellsc.scapi.objects.EmDataCollector;
import com.emc.storageos.driver.dellsc.scapi.objects.ScConfiguration;
import com.emc.storageos.driver.dellsc.scapi.objects.ScControllerPort;
import com.emc.storageos.driver.dellsc.scapi.objects.ScCopyMirrorMigrate;
import com.emc.storageos.driver.dellsc.scapi.objects.ScFaultDomain;
import com.emc.storageos.driver.dellsc.scapi.objects.ScReplay;
import com.emc.storageos.driver.dellsc.scapi.objects.ScReplayProfile;
import com.emc.storageos.driver.dellsc.scapi.objects.ScStorageType;
import com.emc.storageos.driver.dellsc.scapi.objects.ScVolume;
import com.emc.storageos.driver.dellsc.scapi.objects.StorageCenter;
import com.emc.storageos.storagedriver.DriverTask;
import com.emc.storageos.storagedriver.DriverTask.TaskStatus;
import com.emc.storageos.storagedriver.model.StorageObject.AccessStatus;
import com.emc.storageos.storagedriver.model.StoragePool;
import com.emc.storageos.storagedriver.model.StoragePort;
import com.emc.storageos.storagedriver.model.StorageProvider;
import com.emc.storageos.storagedriver.model.StorageSystem;
import com.emc.storageos.storagedriver.model.StorageVolume;
import com.emc.storageos.storagedriver.model.VolumeClone;
import com.emc.storageos.storagedriver.model.VolumeMirror;
import com.emc.storageos.storagedriver.model.VolumeMirror.SynchronizationState;
import com.emc.storageos.storagedriver.model.VolumeSnapshot;
/**
* Discovery related operations.
*/
public class DellSCDiscovery {
private static final Logger LOG = LoggerFactory.getLogger(DellSCDiscovery.class);
private static final String EMPTY_IPADDR = "0.0.0.0";
private DellSCConnectionManager connectionManager;
private String driverName;
private String driverVersion;
private DellSCUtil util;
/**
* Initialize the instance.
*
* @param driverName The driver name.
* @param driverVersion The driver version.
*/
public DellSCDiscovery(String driverName, String driverVersion) {
this.driverName = driverName;
this.driverVersion = driverVersion;
this.connectionManager = DellSCConnectionManager.getInstance();
this.util = DellSCUtil.getInstance();
}
/**
* Perform discovery for a storage provider.
*
* @param storageProvider The provider.
* @param storageSystems The storage systems collection to populate.
* @return The driver task.
*/
public DriverTask discoverStorageProvider(StorageProvider storageProvider, List<StorageSystem> storageSystems) {
DellSCDriverTask task = new DellSCDriverTask("discover");
try {
LOG.info("Getting information for storage provider [{}:{}] as user {}",
storageProvider.getProviderHost(),
storageProvider.getPortNumber(),
storageProvider.getUsername());
StorageCenterAPI api = connectionManager.getConnection(
storageProvider.getProviderHost(),
storageProvider.getPortNumber(),
storageProvider.getUsername(),
storageProvider.getPassword(), true);
LOG.info("Connected to DSM {} as user {}",
storageProvider.getProviderHost(), storageProvider.getUsername());
// Populate the provider information
storageProvider.setAccessStatus(AccessStatus.READ_WRITE);
storageProvider.setManufacturer("Dell");
storageProvider.setProviderVersion(driverVersion);
storageProvider.setIsSupportedVersion(true);
// Get some info about the DSM for debugging purposes
EmDataCollector em = api.getDSMInfo();
if (em != null) {
LOG.info("Connected to {} DSM version {}, Java version {}",
em.type, em.version, em.javaVersion);
storageProvider.setProviderVersion(em.version);
}
// Populate the basic SC information
StorageCenter[] scs = api.getStorageCenterInfo();
for (StorageCenter sc : scs) {
StorageSystem storageSystem = util.getStorageSystemFromStorageCenter(api, sc, null);
storageSystem.setSystemType(driverName);
storageSystems.add(storageSystem);
}
task.setStatus(DriverTask.TaskStatus.READY);
} catch (Exception e) {
String msg = String.format("Exception encountered getting storage provider information: %s", e);
LOG.error(msg);
task.setFailed(msg);
}
return task;
}
/**
* Discover storage systems and their capabilities.
*
* @param storageSystem Storage system to discover.
* @return The discovery task.
*/
public DriverTask discoverStorageSystem(StorageSystem storageSystem) {
DriverTask task = new DellSCDriverTask("discover");
try {
LOG.info("Getting information for storage system [{}] - {}",
storageSystem.getIpAddress(),
storageSystem.getSystemName());
String sn = storageSystem.getSerialNumber();
if (sn == null || sn.length() == 0) {
// Directly added system, no SSN yet so we use the name field
sn = storageSystem.getSystemName();
// Through the storage provider CoprHD overrides the system
// name with provider_name+serial_number
if (sn.contains("+")) {
String[] parts = sn.split("\\+");
sn = parts[1];
}
}
int port = storageSystem.getPortNumber();
if (port == 0) {
port = 3033;
}
StorageCenterAPI api = connectionManager.getConnection(
storageSystem.getIpAddress(),
port,
storageSystem.getUsername(),
storageSystem.getPassword(), false);
// Populate the SC information
StorageCenter sc = api.findStorageCenter(sn);
util.getStorageSystemFromStorageCenter(api, sc, storageSystem);
storageSystem.setSystemType(driverName);
task.setStatus(DriverTask.TaskStatus.READY);
} catch (Exception e) {
String msg = String.format("Exception encountered getting storage system information: %s", e);
LOG.error(msg);
task.setMessage(msg);
task.setStatus(DriverTask.TaskStatus.FAILED);
}
return task;
}
/**
* Discover storage pools and their capabilities.
*
* @param storageSystem The storage system on which to discover.
* @param storagePools The storage pools.
* @return The discovery task.
*/
public DriverTask discoverStoragePools(StorageSystem storageSystem, List<StoragePool> storagePools) {
LOG.info("Discovering storage pools for [{}] {} {}",
storageSystem.getSystemName(), storageSystem.getIpAddress(),
storageSystem.getNativeId());
DellSCDriverTask task = new DellSCDriverTask("discoverStoragePools");
try {
StorageCenterAPI api = connectionManager.getConnection(storageSystem.getNativeId());
ScStorageType[] storageTypes = api.getStorageTypes(storageSystem.getNativeId());
for (ScStorageType storageType : storageTypes) {
storagePools.add(util.getStoragePoolFromStorageType(api, storageType, null));
}
task.setStatus(DriverTask.TaskStatus.READY);
} catch (Exception e) {
String failureMessage = String.format("Error getting pool information: %s", e);
task.setFailed(failureMessage);
LOG.warn(failureMessage);
}
return task;
}
/**
* Discover storage ports and their capabilities.
*
* @param storageSystem The storage system on which to discover.
* @param storagePorts The storage ports.
* @return The discovery task.
*/
public DriverTask discoverStoragePorts(StorageSystem storageSystem, List<StoragePort> storagePorts) {
LOG.info("Discovering storage ports for [{}] {} {}",
storageSystem.getSystemName(), storageSystem.getIpAddress(),
storageSystem.getNativeId());
DellSCDriverTask task = new DellSCDriverTask("discoverStoragePorts");
try {
String ssn = storageSystem.getNativeId();
StorageCenterAPI api = connectionManager.getConnection(ssn);
Map<String, List<ScControllerPort>> ports = getPortList(api, ssn);
for (Entry<String, List<ScControllerPort>> entry : ports.entrySet()) {
for (ScControllerPort scPort : entry.getValue()) {
StoragePort port = util.getStoragePortForControllerPort(api, scPort, entry.getKey());
LOG.info("Discovered Port {}, storageSystem {}",
scPort.instanceId, scPort.scSerialNumber);
storagePorts.add(port);
}
}
task.setStatus(DriverTask.TaskStatus.READY);
} catch (Exception e) {
String failureMessage = String.format("Error getting port information: %s", e);
task.setFailed(failureMessage);
LOG.warn(failureMessage);
}
return task;
}
/**
* Gets the ScControllerPorts for a system.
*
* @param api The API connection.
* @param ssn The system serial number.
* @return The ports.
*/
private Map<String, List<ScControllerPort>> getPortList(StorageCenterAPI api, String ssn) {
Map<String, List<ScControllerPort>> ports = new HashMap<>();
try {
ScConfiguration scConfig = api.getScConfig(ssn);
ScFaultDomain[] faultDomains = api.getFaultDomains(ssn);
for (ScFaultDomain fd : faultDomains) {
// See what kind of fault domain this is
boolean virtualMode;
if (ScControllerPort.FC_TRANSPORT_TYPE.equals(fd.transportType)) {
virtualMode = "VirtualPort".equals(scConfig.fibreChannelTransportMode);
} else if (ScControllerPort.ISCSI_TRANSPORT_TYPE.equals(fd.transportType)) {
virtualMode = "VirtualPort".equals(scConfig.iscsiTransportMode);
} else {
// Not a currently supported transport type
continue;
}
// Now get the actual ports
if (!ports.containsKey(fd.name)) {
ports.put(fd.name, new ArrayList<>());
}
ScControllerPort[] fdPorts = api.getFaultDomainPorts(fd.instanceId, virtualMode);
for (ScControllerPort fdPort : fdPorts) {
// See if we need to inherit the IP settings from the fault domain
if (EMPTY_IPADDR.equals(fdPort.iscsiSubnetMask)) {
fdPort.iscsiSubnetMask = fd.subnetMask;
}
if (EMPTY_IPADDR.equals(fdPort.iscsiIpAddress)) {
fdPort.iscsiIpAddress = fd.targetIpv4Address;
}
ports.get(fd.name).add(fdPort);
}
}
} catch (Exception e) {
LOG.error(String.format("Error getting system controller ports: %s", e));
}
return ports;
}
/**
* Discover storage volumes.
*
* @param storageSystem The storage system on which to discover.
* @param storageVolumes The discovered storage volumes.
* @param token Used for paging. Input 0 indicates that the first page should be returned. Output 0 indicates
* that last page was returned
* @return The discovery task.
*/
public DriverTask getStorageVolumes(StorageSystem storageSystem,
List<StorageVolume> storageVolumes,
MutableInt token) {
LOG.info("Getting volumes from {}", storageSystem.getNativeId());
DellSCDriverTask task = new DellSCDriverTask("getVolumes");
try {
StorageCenterAPI api = connectionManager.getConnection(storageSystem.getNativeId());
Map<ScReplayProfile, List<String>> cgInfo = util.getGCInfo(api, storageSystem.getNativeId());
ScVolume[] volumes = api.getAllVolumes(storageSystem.getNativeId());
for (ScVolume volume : volumes) {
if (volume.inRecycleBin || volume.liveVolume || volume.cmmDestination || volume.replicationDestination) {
continue;
}
StorageVolume driverVol = util.getStorageVolumeFromScVolume(api, volume, cgInfo);
storageVolumes.add(driverVol);
}
task.setStatus(TaskStatus.READY);
} catch (DellSCDriverException | StorageCenterAPIException e) {
String msg = String.format("Error getting volume info: %s", e);
LOG.warn(msg);
task.setFailed(msg);
}
return task;
}
/**
* Gets all snapshots for a volume.
*
* @param storageVolume The volume.
* @return The snapshots.
*/
public List<VolumeSnapshot> getVolumeSnapshots(StorageVolume storageVolume) {
LOG.info("Getting snapshots for {}", storageVolume.getNativeId());
List<VolumeSnapshot> result = new ArrayList<>();
try {
StorageCenterAPI api = connectionManager.getConnection(storageVolume.getStorageSystemId());
ScReplay[] replays = api.getVolumeSnapshots(storageVolume.getNativeId());
for (ScReplay replay : replays) {
VolumeSnapshot snap = util.getVolumeSnapshotFromReplay(replay, null);
result.add(snap);
}
} catch (DellSCDriverException e) {
String msg = String.format("Error getting volume info: %s", e);
LOG.warn(msg);
}
return result;
}
/**
* Gets all clones of a volume.
*
* @param storageVolume The volume.
* @return The clones.
*/
public List<VolumeClone> getVolumeClones(StorageVolume storageVolume) {
LOG.info("Getting clones for volume {}", storageVolume.getNativeId());
// Clones are independent once created
return new ArrayList<>(0);
}
/**
* Gets all mirrors of a volume.
*
* @param storageVolume The volume.
* @return The mirrors.
*/
public List<VolumeMirror> getVolumeMirrors(StorageVolume storageVolume) {
LOG.info("Getting mirrors for volume {}", storageVolume.getNativeId());
List<VolumeMirror> result = new ArrayList<>();
try {
StorageCenterAPI api = connectionManager.getConnection(storageVolume.getStorageSystemId());
ScVolume scVolume = api.getVolume(storageVolume.getNativeId());
if (scVolume != null && scVolume.cmmSource) {
ScCopyMirrorMigrate[] cmms = api.getVolumeCopyMirrorMigrate(scVolume.instanceId);
for (ScCopyMirrorMigrate cmm : cmms) {
if ("Mirror".equals(cmm.type)) {
ScVolume targetVol = api.getVolume(cmm.destinationVolume.instanceId);
VolumeMirror mirror = new VolumeMirror();
mirror.setAccessStatus(AccessStatus.READ_WRITE);
mirror.setDeviceLabel(targetVol.name);
mirror.setDisplayName(targetVol.name);
mirror.setNativeId(targetVol.instanceId);
mirror.setParentId(cmm.sourceVolume.instanceId);
mirror.setStorageSystemId(storageVolume.getStorageSystemId());
SynchronizationState syncState = SynchronizationState.SYNCHRONIZED;
if (cmm.percentComplete != 100) {
syncState = SynchronizationState.COPYINPROGRESS;
}
mirror.setSyncState(syncState);
mirror.setWwn(targetVol.deviceId);
result.add(mirror);
}
}
}
} catch (DellSCDriverException e) {
String msg = String.format("Error getting mirrors for volume %s", storageVolume.getNativeId(), e);
LOG.warn(msg);
}
return result;
}
}