/*
* 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;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.mutable.MutableBoolean;
import org.apache.commons.lang.mutable.MutableInt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.driver.dellsc.helpers.DellSCCloning;
import com.emc.storageos.driver.dellsc.helpers.DellSCConnectionManager;
import com.emc.storageos.driver.dellsc.helpers.DellSCConsistencyGroups;
import com.emc.storageos.driver.dellsc.helpers.DellSCDiscovery;
import com.emc.storageos.driver.dellsc.helpers.DellSCMirroring;
import com.emc.storageos.driver.dellsc.helpers.DellSCProvisioning;
import com.emc.storageos.driver.dellsc.helpers.DellSCSnapshots;
import com.emc.storageos.driver.dellsc.scapi.StorageCenterAPI;
import com.emc.storageos.driver.dellsc.scapi.StorageCenterAPIException;
import com.emc.storageos.driver.dellsc.scapi.objects.ScReplayProfile;
import com.emc.storageos.driver.dellsc.scapi.objects.ScVolume;
import com.emc.storageos.storagedriver.BlockStorageDriver;
import com.emc.storageos.storagedriver.DefaultStorageDriver;
import com.emc.storageos.storagedriver.DriverTask;
import com.emc.storageos.storagedriver.DriverTask.TaskStatus;
import com.emc.storageos.storagedriver.HostExportInfo;
import com.emc.storageos.storagedriver.RegistrationData;
import com.emc.storageos.storagedriver.model.Initiator;
import com.emc.storageos.storagedriver.model.StorageObject;
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.VolumeConsistencyGroup;
import com.emc.storageos.storagedriver.model.VolumeMirror;
import com.emc.storageos.storagedriver.model.VolumeSnapshot;
import com.emc.storageos.storagedriver.storagecapabilities.CapabilityInstance;
import com.emc.storageos.storagedriver.storagecapabilities.StorageCapabilities;
/**
* Storage Driver for Dell SC Series storage arrays.
*/
public class DellSCStorageDriver extends DefaultStorageDriver implements BlockStorageDriver {
private static final Logger LOG = LoggerFactory.getLogger(DellSCStorageDriver.class);
static final String DRIVER_NAME = "dellscsystem";
static final String DRIVER_VERSION = "1.0.0";
private DellSCProvisioning provisioningHelper = new DellSCProvisioning();
private DellSCSnapshots snapshotHelper = new DellSCSnapshots();
private DellSCConsistencyGroups cgHelper = new DellSCConsistencyGroups();
private DellSCDiscovery discoveryHelper = new DellSCDiscovery(DRIVER_NAME, DRIVER_VERSION);
private DellSCCloning cloneHelper = new DellSCCloning();
private DellSCMirroring mirrorHelper = new DellSCMirroring();
@Override
public synchronized void setDriverRegistry(com.emc.storageos.storagedriver.Registry driverRegistry) {
super.setDriverRegistry(driverRegistry);
// Make sure our helper class gets updated with the right info
DellSCConnectionManager.getInstance().setDriverRegistry(driverRegistry);
}
//
// Driver common functionality
//
/**
* Get driver registration data.
*
* @return The registration data.
*/
@Override
public RegistrationData getRegistrationData() {
LOG.info("Getting registration data.");
return new RegistrationData("Dell SC Storage", DRIVER_NAME, null);
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.storagedriver.BlockStorageDriver#validateStorageProviderConnection(com.emc.storageos.storagedriver.model.
* StorageProvider)
*/
@Override
public boolean validateStorageProviderConnection(StorageProvider storageProvider) {
LOG.info("Validating storage provider connection.");
try {
DellSCConnectionManager.getInstance().getConnection(
storageProvider.getProviderHost(),
storageProvider.getPortNumber(),
storageProvider.getUsername(),
storageProvider.getPassword(), false);
LOG.info("Connection to {} validated", storageProvider.getProviderHost());
return true;
} catch (StorageCenterAPIException e) {
LOG.error(String.format("Failed to connect to storage provider %s: %s",
storageProvider.getProviderHost(), e));
}
return false;
}
/**
* Return driver task with a given id.
*
* @param taskId The task ID.
* @return The requested task or Null if it does not exist.
*/
@Override
public DriverTask getTask(String taskId) {
// Will need to implement if/when we support async tasks
LOG.info("Getting task {}", taskId);
return null;
}
/**
* Get storage object with a given type with specified native ID which belongs to specified storage system.
*
* @param storageSystemId The storage system native ID.
* @param objectId The object ID.
* @param type The class instance.
* @param <T> The storage object type.
* @return Storage object or Null if it does not exist.
*/
@SuppressWarnings("unchecked")
@Override
public <T extends StorageObject> T getStorageObject(String storageSystemId, String objectId, Class<T> type) {
String requestedType = type.getSimpleName();
LOG.info("Request for {} object {} from {}", requestedType, objectId, storageSystemId);
DellSCUtil util = DellSCUtil.getInstance();
try {
StorageCenterAPI api = DellSCConnectionManager.getInstance().getConnection(storageSystemId);
if (requestedType.equals(StorageVolume.class.getSimpleName())) {
ScVolume volume = api.getVolume(objectId);
Map<ScReplayProfile, List<String>> cgInfo = util.getGCInfo(api, storageSystemId);
return (T) util.getStorageVolumeFromScVolume(api, volume, cgInfo);
} else if (requestedType.equals(VolumeConsistencyGroup.class.getSimpleName())) {
return (T) util.getVolumeConsistencyGroupFromReplayProfile(
api.getConsistencyGroup(objectId), null);
} else if (requestedType.equals(VolumeSnapshot.class.getSimpleName())) {
return (T) util.getVolumeSnapshotFromReplay(api.getReplay(objectId), null);
} else if (requestedType.equals(StoragePool.class.getSimpleName())) {
return (T) util.getStoragePoolFromStorageType(api, api.getStorageType(objectId), null);
}
} catch (StorageCenterAPIException | DellSCDriverException e) {
String message = String.format("Error getting requested storage object: %s", e);
LOG.warn(message);
}
LOG.warn("Requested object of type {} not found.", requestedType);
return null;
}
@Override
public DriverTask stopManagement(StorageSystem storageSystem) {
LOG.info("Stop management called for storage system {}", storageSystem.getNativeId());
DriverTask task = new DellSCDriverTask("stopManagement");
task.setStatus(TaskStatus.READY);
return task;
}
//
// Provisioning operations
//
/**
* Create storage volumes with a given set of capabilities.
* Before completion of the request, set all required data for provisioned
* volumes in "volumes" parameter.
*
* @param volumes Input/output argument for volumes.
* @param storageCapabilities Input argument for capabilities. Defines
* storage capabilities of volumes to create.
* @return The volume creation task.
*/
@Override
public DriverTask createVolumes(List<StorageVolume> volumes, StorageCapabilities storageCapabilities) {
LOG.info("Creating {} new volumes", volumes.size());
return provisioningHelper.createVolumes(volumes, storageCapabilities);
}
/**
* Expand volume to a new size.
* Before completion of the request, set all required data for expanded
* volume in "volume" parameter.
*
* @param storageVolume Volume to expand. Type: Input/Output argument.
* @param newCapacity Requested capacity. Type: input argument.
* @return The volume expansion task.
*/
@Override
public DriverTask expandVolume(StorageVolume storageVolume, long newCapacity) {
LOG.info("Expanding volume {} to {}", storageVolume.getNativeId(), newCapacity);
return provisioningHelper.expandVolume(storageVolume, newCapacity);
}
/**
* Delete volume.
*
* @param volume The volume to delete.
* @return The volume deletion task.
*/
@Override
public DriverTask deleteVolume(StorageVolume volume) {
LOG.info("Deleting volume {}", volume.getNativeId());
return provisioningHelper.deleteVolume(volume);
}
//
// Snapshot operations
//
/**
* Create volume snapshots.
*
* @param snapshots The list of snapshots to create.
* @param storageCapabilities The requested capabilities of the snapshots.
* @return The snapshot creation task.
*/
@Override
public DriverTask createVolumeSnapshot(List<VolumeSnapshot> snapshots, StorageCapabilities storageCapabilities) {
LOG.info("Creating {} snapshots...", snapshots.size());
return snapshotHelper.createVolumeSnapshot(snapshots, storageCapabilities);
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.storagedriver.DefaultStorageDriver#restoreSnapshot(java.util.List)
*/
@Override
public DriverTask restoreSnapshot(List<VolumeSnapshot> list) {
LOG.info("Restoring snapshots");
return snapshotHelper.restoreSnapshot(list);
}
/**
* Delete a snapshot.
*
* @param snapshot The snapshot to delete.
* @return The delete task.
*/
@Override
public DriverTask deleteVolumeSnapshot(VolumeSnapshot snapshot) {
LOG.info("Deleting volume snapshot {}.", snapshot);
return snapshotHelper.deleteVolumeSnapshot(snapshot);
}
//
// Clone operations
//
/**
* Create a clone of a volume.
*
* @param list The clones to create.
* @param storageCapabilities The requested capabilities for the clones.
* @return The clone task.
*/
@Override
public DriverTask createVolumeClone(List<VolumeClone> list, StorageCapabilities storageCapabilities) {
return cloneHelper.createVolumeClone(list);
}
/**
* Detach volume clones.
*
* @param list The clones to detach.
* @return The detach task.
*/
@Override
public DriverTask detachVolumeClone(List<VolumeClone> list) {
return cloneHelper.detachVolumeClone(list);
}
/**
* Restore a cloned volume.
*
* @param list The volume clones.
* @return The driver task.
*/
@Override
public DriverTask restoreFromClone(List<VolumeClone> list) {
return cloneHelper.restoreFromClone(list);
}
/**
* Delete volume clone.
*
* @param clone The clone to delete.
* @return The delete task.
*/
@Override
public DriverTask deleteVolumeClone(VolumeClone clone) {
return cloneHelper.deleteVolumeClone(clone);
}
//
// Mirror operations
//
/**
* Create volume mirrors.
*
* @param list The volume mirrors to create.
* @param storageCapabilities The requested capabilities.
* @return The creation task.
*/
@Override
public DriverTask createVolumeMirror(List<VolumeMirror> list, StorageCapabilities storageCapabilities) {
return mirrorHelper.createVolumeMirror(list);
}
/**
* Delete volume mirror.
*
* @param mirror The mirror to delete.
* @return The delete task.
*/
@Override
public DriverTask deleteVolumeMirror(VolumeMirror mirror) {
return mirrorHelper.deleteVolumeMirror(mirror);
}
/**
* Split volume mirrors.
*
* @param list The mirrors to split.
* @return The split task.
*/
@Override
public DriverTask splitVolumeMirror(List<VolumeMirror> list) {
return mirrorHelper.splitVolumeMirror(list);
}
/**
* Resume volume mirrors.
*
* @param list The mirrors to resume.
* @return The mirror task.
*/
@Override
public DriverTask resumeVolumeMirror(List<VolumeMirror> list) {
return mirrorHelper.resumeVolumeMirror(list);
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.storagedriver.DefaultStorageDriver#restoreVolumeMirror(java.util.List)
*/
@Override
public DriverTask restoreVolumeMirror(List<VolumeMirror> list) {
return mirrorHelper.restoreVolumeMirror(list);
}
//
// Export/unexport operations
//
/**
* Export volumes to initiators through a given set of ports. If ports are
* not provided, use port requirements from ExportPathsServiceOption
* storage capability.
*
* @param initiators The initiators to export to.
* @param volumes The volumes to export.
* @param volumeToHLUMap Map of volume nativeID to requested HLU. HLU
* value of -1 means that HLU is not defined and will
* be assigned by array.
* @param recommendedPorts List of storage ports recommended for the export.
* Optional.
* @param availablePorts List of ports available for the export.
* @param capabilities The storage capabilities.
* @param usedRecommendedPorts True if driver used recommended and only
* recommended ports for the export, false
* otherwise.
* @param selectedPorts Ports selected for the export (if recommended ports
* have not been used).
* @return The export task.
*/
@Override
public DriverTask exportVolumesToInitiators(List<Initiator> initiators, List<StorageVolume> volumes,
Map<String, String> volumeToHLUMap, List<StoragePort> recommendedPorts,
List<StoragePort> availablePorts, StorageCapabilities capabilities,
MutableBoolean usedRecommendedPorts, List<StoragePort> selectedPorts) {
return provisioningHelper.exportVolumesToInitiators(
initiators,
volumes,
volumeToHLUMap,
recommendedPorts,
availablePorts,
capabilities,
usedRecommendedPorts,
selectedPorts);
}
/**
* Remove volume exports to initiators.
*
* @param initiators The initiators to remove from.
* @param volumes The volumes to remove.
* @return The unexport task.
*/
@Override
public DriverTask unexportVolumesFromInitiators(List<Initiator> initiators, List<StorageVolume> volumes) {
return provisioningHelper.unexportVolumesFromInitiators(initiators, volumes);
}
/*
* (non-Javadoc)
*
* @see
* com.emc.storageos.storagedriver.DefaultStorageDriver#getVolumeExportInfoForHosts(com.emc.storageos.storagedriver.model.StorageVolume)
*/
@Override
public Map<String, HostExportInfo> getVolumeExportInfoForHosts(StorageVolume storageVolume) {
LOG.info("Getting volume export info for host");
return provisioningHelper.getVolumeExportInfo(storageVolume.getNativeId(), storageVolume.getStorageSystemId());
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.storagedriver.DefaultStorageDriver#getSnapshotExportInfoForHosts(com.emc.storageos.storagedriver.model.
* VolumeSnapshot)
*/
@Override
public Map<String, HostExportInfo> getSnapshotExportInfoForHosts(VolumeSnapshot volumeSnapshot) {
LOG.info("Getting snapshot export info for host");
// We don't export snapshots
return new HashMap<>(0);
}
/*
* (non-Javadoc)
*
* @see
* com.emc.storageos.storagedriver.DefaultStorageDriver#getCloneExportInfoForHosts(com.emc.storageos.storagedriver.model.VolumeClone)
*/
@Override
public Map<String, HostExportInfo> getCloneExportInfoForHosts(VolumeClone volumeClone) {
LOG.info("Getting clone export info for host");
return provisioningHelper.getVolumeExportInfo(volumeClone.getNativeId(), volumeClone.getStorageSystemId());
}
/*
* (non-Javadoc)
*
* @see
* com.emc.storageos.storagedriver.DefaultStorageDriver#getMirrorExportInfoForHosts(com.emc.storageos.storagedriver.model.VolumeMirror)
*/
@Override
public Map<String, HostExportInfo> getMirrorExportInfoForHosts(VolumeMirror volumeMirror) {
LOG.info("Getting mirror export info for host");
// We don't export mirrors
return new HashMap<>(0);
}
//
// Consistency group related operations
//
/**
* Create a consistency group.
*
* @param volumeConsistencyGroup The group to create.
* @return The consistency group creation task.
*/
@Override
public DriverTask createConsistencyGroup(VolumeConsistencyGroup volumeConsistencyGroup) {
LOG.info("Creating consistency group {}", volumeConsistencyGroup.getDisplayName());
return cgHelper.createConsistencyGroup(volumeConsistencyGroup);
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.storagedriver.DefaultStorageDriver#addVolumesToConsistencyGroup(java.util.List,
* com.emc.storageos.storagedriver.storagecapabilities.StorageCapabilities)
*/
@Override
public DriverTask addVolumesToConsistencyGroup(List<StorageVolume> volumes, StorageCapabilities capabilities) {
LOG.info("Adding volumes to consistency group");
return cgHelper.addVolumesToConsistencyGroup(volumes, capabilities);
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.storagedriver.DefaultStorageDriver#removeVolumesFromConsistencyGroup(java.util.List,
* com.emc.storageos.storagedriver.storagecapabilities.StorageCapabilities)
*/
@Override
public DriverTask removeVolumesFromConsistencyGroup(List<StorageVolume> volumes, StorageCapabilities capabilities) {
LOG.info("Removing volumes from consistency group");
return cgHelper.removeVolumesFromConsistencyGroup(volumes, capabilities);
}
/**
* Delete a consistency group.
*
* @param volumeConsistencyGroup The group to delete.
* @return The consistency group delete task.
*/
@Override
public DriverTask deleteConsistencyGroup(VolumeConsistencyGroup volumeConsistencyGroup) {
LOG.info("Deleting consistency group");
return cgHelper.deleteConsistencyGroup(volumeConsistencyGroup);
}
/**
* Create consistency group snapshots.
*
* @param volumeConsistencyGroup The consistency group.
* @param snapshots The snapshots.
* @param capabilities The requested capabilities.
* @return The create task.
*/
@Override
public DriverTask createConsistencyGroupSnapshot(VolumeConsistencyGroup volumeConsistencyGroup,
List<VolumeSnapshot> snapshots,
List<CapabilityInstance> capabilities) {
LOG.info("Creating consistency group snapshot");
return cgHelper.createConsistencyGroupSnapshot(volumeConsistencyGroup, snapshots, capabilities);
}
/**
* Delete a consistency group snapshot set.
*
* @param snapshots The snapshots to delete.
* @return The delete task.
*/
@Override
public DriverTask deleteConsistencyGroupSnapshot(List<VolumeSnapshot> snapshots) {
LOG.info("Deleting consistency group snapshot");
DellSCDriverTask task = new DellSCDriverTask("deleteConsistencyGroupSnapshot");
StringBuilder errBuffer = new StringBuilder();
int deletedCount = 0;
for (VolumeSnapshot snapshot : snapshots) {
DriverTask subTask = snapshotHelper.deleteVolumeSnapshot(snapshot);
if (subTask.getStatus() == TaskStatus.FAILED) {
errBuffer.append(String.format("%s%n", subTask.getMessage()));
} else {
deletedCount++;
}
}
task.setMessage(errBuffer.toString());
if (deletedCount == snapshots.size()) {
task.setStatus(TaskStatus.READY);
} else if (deletedCount == 0) {
task.setStatus(TaskStatus.FAILED);
} else {
task.setStatus(TaskStatus.PARTIALLY_FAILED);
}
return task;
}
/**
* Create clone of consistency group.
*
* @param volumeConsistencyGroup The consistency group.
* @param volumes The volumes to clone.
* @param capabilities The requested capabilities.
* @return The clone creation task.
*/
@Override
public DriverTask createConsistencyGroupClone(VolumeConsistencyGroup volumeConsistencyGroup,
List<VolumeClone> volumes,
List<CapabilityInstance> capabilities) {
LOG.info("Creating consistency group clone for group {}", volumeConsistencyGroup.getDisplayName());
// No difference for us cloning group or single volumes
return cloneHelper.createVolumeClone(volumes);
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.storagedriver.DefaultStorageDriver#createConsistencyGroupMirror(com.emc.storageos.storagedriver.model.
* VolumeConsistencyGroup, java.util.List, java.util.List)
*/
@Override
public DriverTask createConsistencyGroupMirror(VolumeConsistencyGroup volumeConsistencyGroup, List<VolumeMirror> mirrors,
List<CapabilityInstance> capabilities) {
LOG.info("Creating consistency group mirrors for group {}", volumeConsistencyGroup.getDisplayName());
return mirrorHelper.createVolumeMirror(mirrors);
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.storagedriver.DefaultStorageDriver#deleteConsistencyGroupMirror(java.util.List)
*/
@Override
public DriverTask deleteConsistencyGroupMirror(List<VolumeMirror> mirrors) {
DellSCDriverTask task = new DellSCDriverTask("deleteConsistencyGroupMirror");
StringBuilder errBuffer = new StringBuilder();
int deletedCount = 0;
for (VolumeMirror mirror : mirrors) {
DriverTask subTask = mirrorHelper.deleteVolumeMirror(mirror);
if (subTask.getStatus() == TaskStatus.FAILED) {
errBuffer.append(String.format("%s%n", subTask.getMessage()));
} else {
deletedCount++;
}
}
task.setMessage(errBuffer.toString());
if (deletedCount == mirrors.size()) {
task.setStatus(TaskStatus.READY);
} else if (deletedCount == 0) {
task.setStatus(TaskStatus.FAILED);
} else {
task.setStatus(TaskStatus.PARTIALLY_FAILED);
}
return task;
}
//
// Discovery functions
//
/**
* Discover storage systems and their capabilities.
*
* @param storageSystem Storage system to discover.
* @return The discovery task.
*/
@Override
public DriverTask discoverStorageSystem(StorageSystem storageSystem) {
return discoveryHelper.discoverStorageSystem(storageSystem);
}
/**
* Discover storage pools and their capabilities.
*
* @param storageSystem The storage system on which to discover.
* @param storagePools The storage pools.
* @return The discovery task.
*/
@Override
public DriverTask discoverStoragePools(StorageSystem storageSystem, List<StoragePool> storagePools) {
return discoveryHelper.discoverStoragePools(storageSystem, storagePools);
}
/**
* Discover storage ports and their capabilities.
*
* @param storageSystem The storage system on which to discover.
* @param storagePorts The storage ports.
* @return The discovery task.
*/
@Override
public DriverTask discoverStoragePorts(StorageSystem storageSystem, List<StoragePort> storagePorts) {
return discoveryHelper.discoverStoragePorts(storageSystem, storagePorts);
}
/*
* (non-Javadoc)
*
* @see
* com.emc.storageos.storagedriver.DefaultStorageDriver#discoverStorageProvider(com.emc.storageos.storagedriver.model.StorageProvider,
* java.util.List)
*/
@Override
public DriverTask discoverStorageProvider(StorageProvider storageProvider, List<StorageSystem> storageSystems) {
return discoveryHelper.discoverStorageProvider(storageProvider, storageSystems);
}
/**
* 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.
*/
@Override
public DriverTask getStorageVolumes(StorageSystem storageSystem,
List<StorageVolume> storageVolumes,
MutableInt token) {
return discoveryHelper.getStorageVolumes(storageSystem, storageVolumes, token);
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.storagedriver.DefaultStorageDriver#getVolumeSnapshots(com.emc.storageos.storagedriver.model.StorageVolume)
*/
@Override
public List<VolumeSnapshot> getVolumeSnapshots(StorageVolume storageVolume) {
return discoveryHelper.getVolumeSnapshots(storageVolume);
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.storagedriver.DefaultStorageDriver#getVolumeClones(com.emc.storageos.storagedriver.model.StorageVolume)
*/
@Override
public List<VolumeClone> getVolumeClones(StorageVolume storageVolume) {
return discoveryHelper.getVolumeClones(storageVolume);
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.storagedriver.DefaultStorageDriver#getVolumeMirrors(com.emc.storageos.storagedriver.model.StorageVolume)
*/
@Override
public List<VolumeMirror> getVolumeMirrors(StorageVolume storageVolume) {
return discoveryHelper.getVolumeMirrors(storageVolume);
}
}