/*
* Copyright (c) 2013 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.impl.hds.prov;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.constraint.AlternateIdConstraint;
import com.emc.storageos.db.client.constraint.URIQueryResultList;
import com.emc.storageos.db.client.model.AutoTieringPolicy.HitachiTieringPolicy;
import com.emc.storageos.db.client.model.BlockObject;
import com.emc.storageos.db.client.model.ExportMask;
import com.emc.storageos.db.client.model.Initiator;
import com.emc.storageos.db.client.model.StoragePool;
import com.emc.storageos.db.client.model.StorageProvider;
import com.emc.storageos.db.client.model.StorageSystem;
import com.emc.storageos.db.client.model.TenantOrg;
import com.emc.storageos.db.client.model.VirtualPool;
import com.emc.storageos.db.client.model.Volume;
import com.emc.storageos.db.client.model.Volume.ReplicationState;
import com.emc.storageos.db.client.util.NameGenerator;
import com.emc.storageos.db.exceptions.DatabaseException;
import com.emc.storageos.exceptions.DeviceControllerErrors;
import com.emc.storageos.exceptions.DeviceControllerException;
import com.emc.storageos.hds.HDSConstants;
import com.emc.storageos.hds.HDSException;
import com.emc.storageos.hds.api.HDSApiClient;
import com.emc.storageos.hds.api.HDSApiFactory;
import com.emc.storageos.hds.api.HDSApiProtectionManager;
import com.emc.storageos.hds.model.LDEV;
import com.emc.storageos.hds.model.LogicalUnit;
import com.emc.storageos.hds.model.ReplicationInfo;
import com.emc.storageos.hds.model.StorageArray;
import com.emc.storageos.plugins.common.Constants;
import com.emc.storageos.svcs.errorhandling.model.ServiceError;
import com.emc.storageos.svcs.errorhandling.resources.InternalException;
import com.emc.storageos.volumecontroller.CloneOperations;
import com.emc.storageos.volumecontroller.DefaultBlockStorageDevice;
import com.emc.storageos.volumecontroller.Job;
import com.emc.storageos.volumecontroller.MetaVolumeOperations;
import com.emc.storageos.volumecontroller.SnapshotOperations;
import com.emc.storageos.volumecontroller.TaskCompleter;
import com.emc.storageos.volumecontroller.impl.ControllerServiceImpl;
import com.emc.storageos.volumecontroller.impl.ControllerUtils;
import com.emc.storageos.volumecontroller.impl.VolumeURIHLU;
import com.emc.storageos.volumecontroller.impl.block.taskcompleter.CleanupMetaVolumeMembersCompleter;
import com.emc.storageos.volumecontroller.impl.block.taskcompleter.MetaVolumeTaskCompleter;
import com.emc.storageos.volumecontroller.impl.block.taskcompleter.MultiVolumeTaskCompleter;
import com.emc.storageos.volumecontroller.impl.block.taskcompleter.VolumeExpandCompleter;
import com.emc.storageos.volumecontroller.impl.block.taskcompleter.VolumeTaskCompleter;
import com.emc.storageos.volumecontroller.impl.hds.prov.job.HDSCleanupMetaVolumeMembersJob;
import com.emc.storageos.volumecontroller.impl.hds.prov.job.HDSCreateMultiVolumeJob;
import com.emc.storageos.volumecontroller.impl.hds.prov.job.HDSCreateVolumeJob;
import com.emc.storageos.volumecontroller.impl.hds.prov.job.HDSDeleteVolumeJob;
import com.emc.storageos.volumecontroller.impl.hds.prov.job.HDSJob;
import com.emc.storageos.volumecontroller.impl.hds.prov.job.HDSModifyVolumeJob;
import com.emc.storageos.volumecontroller.impl.hds.prov.job.HDSReplicationSyncJob;
import com.emc.storageos.volumecontroller.impl.hds.prov.job.HDSReplicationSyncJob.ReplicationStatus;
import com.emc.storageos.volumecontroller.impl.hds.prov.job.HDSVolumeExpandJob;
import com.emc.storageos.volumecontroller.impl.hds.prov.utils.HDSUtils;
import com.emc.storageos.volumecontroller.impl.job.QueueJob;
import com.emc.storageos.volumecontroller.impl.smis.ExportMaskOperations;
import com.emc.storageos.volumecontroller.impl.smis.MetaVolumeRecommendation;
import com.emc.storageos.volumecontroller.impl.smis.MirrorOperations;
import com.emc.storageos.volumecontroller.impl.utils.VirtualPoolCapabilityValuesWrapper;
import com.emc.storageos.workflow.WorkflowService;
/**
* Hitachi Data System specific provisioning implementation class.
* This class is responsible to do all provisioning operations by interacting with XML API Server which is running on
* HiCommand Device Manager.
*
*/
public class HDSStorageDevice extends DefaultBlockStorageDevice {
private static final Logger log = LoggerFactory.getLogger(HDSStorageDevice.class);
private DbClient dbClient;
private NameGenerator nameGenerator;
private HDSApiFactory hdsApiFactory;
private ExportMaskOperations exportMaskOperationsHelper;
private MetaVolumeOperations metaVolumeOperations;
private CloneOperations cloneOperations;
private MirrorOperations mirrorOperations;
private SnapshotOperations snapshotOperations;
private static String QUICK_FORMAT_TYPE = "quick";
public void setDbClient(DbClient dbClient) {
this.dbClient = dbClient;
}
public void setNameGenerator(NameGenerator nameGenerator) {
this.nameGenerator = nameGenerator;
}
/**
* @param hdsApiFactory the hdsApiFactory to set
*/
public void setHdsApiFactory(HDSApiFactory hdsApiFactory) {
this.hdsApiFactory = hdsApiFactory;
}
public void setExportMaskOperationsHelper(ExportMaskOperations exportMaskOperationsHelper) {
this.exportMaskOperationsHelper = exportMaskOperationsHelper;
}
public void setMetaVolumeOperations(final MetaVolumeOperations metaVolumeOperations) {
this.metaVolumeOperations = metaVolumeOperations;
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.BlockStorageDevice#doCreateVolumes(com.emc.storageos.db.client.model.StorageSystem,
* com.emc.storageos.db.client.model.StoragePool, java.lang.String, java.util.List,
* com.emc.storageos.volumecontroller.impl.utils.VirtualPoolCapabilityValuesWrapper, com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void doCreateVolumes(StorageSystem storageSystem, StoragePool storagePool,
String opId, List<Volume> volumes,
VirtualPoolCapabilityValuesWrapper capabilities, TaskCompleter taskCompleter)
throws DeviceControllerException {
String label = null;
Long capacity = null;
boolean isThinVolume = false;
boolean opCreationFailed = false;
StringBuilder logMsgBuilder = new StringBuilder(String.format(
"Create Volume Start - Array:%s, Pool:%s", storageSystem.getSerialNumber(),
storagePool.getNativeGuid()));
for (Volume volume : volumes) {
logMsgBuilder.append(String.format("%nVolume:%s , IsThinlyProvisioned: %s",
volume.getLabel(), volume.getThinlyProvisioned()));
if ((label == null) && (volumes.size() == 1)) {
String tenantName = "";
try {
TenantOrg tenant = dbClient.queryObject(TenantOrg.class, volume.getTenant().getURI());
tenantName = tenant.getLabel();
} catch (DatabaseException e) {
log.error("Error lookup TenantOrb object", e);
}
label = nameGenerator.generate(tenantName, volume.getLabel(), volume.getId().toString(),
'-', HDSConstants.MAX_VOLUME_NAME_LENGTH);
}
if (capacity == null) {
capacity = volume.getCapacity();
}
isThinVolume = volume.getThinlyProvisioned();
}
log.info(logMsgBuilder.toString());
try {
multiVolumeCheckForHitachiModel(volumes, storageSystem);
HDSApiClient hdsApiClient = hdsApiFactory.getClient(
HDSUtils.getHDSServerManagementServerInfo(storageSystem),
storageSystem.getSmisUserName(), storageSystem.getSmisPassword());
String systemObjectID = HDSUtils.getSystemObjectID(storageSystem);
String poolObjectID = HDSUtils.getPoolObjectID(storagePool);
String asyncTaskMessageId = null;
// isThinVolume = true, creates VirtualVolumes
// isThinVolume = false, creates LogicalUnits
if (isThinVolume) {
asyncTaskMessageId = hdsApiClient.createThinVolumes(systemObjectID,
storagePool.getNativeId(), capacity, volumes.size(), label,
QUICK_FORMAT_TYPE, storageSystem.getModel());
} else if (!isThinVolume) {
asyncTaskMessageId = hdsApiClient.createThickVolumes(systemObjectID,
poolObjectID, capacity, volumes.size(), label, null, storageSystem.getModel(), null);
}
if (asyncTaskMessageId != null) {
HDSJob createHDSJob = (volumes.size() > 1) ? new HDSCreateMultiVolumeJob(
asyncTaskMessageId, volumes.get(0).getStorageController(), storagePool.getId(),
volumes.size(), taskCompleter) : new HDSCreateVolumeJob(
asyncTaskMessageId, volumes.get(0).getStorageController(), storagePool.getId(),
taskCompleter);
ControllerServiceImpl.enqueueJob(new QueueJob(createHDSJob));
}
} catch (final InternalException e) {
log.error("Problem in doCreateVolumes: ", e);
opCreationFailed = true;
taskCompleter.error(dbClient, e);
} catch (final Exception e) {
log.error("Problem in doCreateVolumes: ", e);
opCreationFailed = true;
ServiceError serviceError = DeviceControllerErrors.hds.methodFailed("doCreateVolumes", e.getMessage());
taskCompleter.error(dbClient, serviceError);
}
if (opCreationFailed) {
for (Volume vol : volumes) {
vol.setInactive(true);
dbClient.persistObject(vol);
}
}
logMsgBuilder = new StringBuilder(String.format(
"Create Volumes End - Array:%s, Pool:%s", storageSystem.getSerialNumber(),
storagePool.getNativeGuid()));
for (Volume volume : volumes) {
logMsgBuilder.append(String.format("%nVolume:%s", volume.getLabel()));
}
log.info(logMsgBuilder.toString());
}
/**
* Few Hitachi models doesn't support multivolume creation in single request.
* We shouldn't allow user to use bulk volume creation.
*
* @param volumes
* @param storageSystem
*/
private void multiVolumeCheckForHitachiModel(List<Volume> volumes,
StorageSystem storageSystem) throws HDSException {
if (volumes.size() > 1
&& HDSUtils.checkForAMSSeries(storageSystem)) {
throw HDSException.exceptions.unsupportedOperationOnThisModel();
}
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.BlockStorageDevice#doExpandVolume(com.emc.storageos.db.client.model.StorageSystem,
* com.emc.storageos.db.client.model.StoragePool, com.emc.storageos.db.client.model.Volume, java.lang.Long,
* com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void doExpandVolume(StorageSystem storageSystem, StoragePool storagePool, Volume volume,
Long size, TaskCompleter taskCompleter) throws DeviceControllerException {
log.info(String.format(
"Expand Volume Start - Array: %s, Pool: %s, Volume: %s, New size: %d",
storageSystem.getSerialNumber(), storagePool.getNativeGuid(), volume.getLabel(), size));
try {
HDSApiClient hdsApiClient = hdsApiFactory.getClient(
HDSUtils.getHDSServerManagementServerInfo(storageSystem),
storageSystem.getSmisUserName(), storageSystem.getSmisPassword());
String systemObjectID = HDSUtils.getSystemObjectID(storageSystem);
String asyncTaskMessageId = null;
if (volume.getThinlyProvisioned()) {
asyncTaskMessageId = hdsApiClient.modifyThinVolume(systemObjectID,
HDSUtils.getLogicalUnitObjectId(volume.getNativeId(), storageSystem), size, storageSystem.getModel());
}
if (null != asyncTaskMessageId) {
HDSJob expandVolumeJob = new HDSVolumeExpandJob(asyncTaskMessageId,
storageSystem.getId(), storagePool.getId(), taskCompleter,
"ExpandVolume");
ControllerServiceImpl.enqueueJob(new QueueJob(expandVolumeJob));
}
} catch (final InternalException e) {
log.error("Problem in doExpandVolume: ", e);
taskCompleter.error(dbClient, e);
} catch (final Exception e) {
log.error("Problem in doExpandVolume: ", e);
ServiceError serviceError = DeviceControllerErrors.hds.methodFailed("doExpandVolume", e.getMessage());
taskCompleter.error(dbClient, serviceError);
}
log.info(String.format("Expand Volume End - Array: %s, Pool: %s, Volume: %s",
storageSystem.getSerialNumber(), storagePool.getNativeGuid(), volume.getLabel()));
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.BlockStorageDevice#doExpandAsMetaVolume(com.emc.storageos.db.client.model.StorageSystem,
* com.emc.storageos.db.client.model.StoragePool, com.emc.storageos.db.client.model.Volume, long,
* com.emc.storageos.volumecontroller.impl.smis.MetaVolumeRecommendation, com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void doExpandAsMetaVolume(StorageSystem storageSystem,
StoragePool storagePool, Volume metaHead, long size,
MetaVolumeRecommendation recommendation, VolumeExpandCompleter volumeCompleter)
throws DeviceControllerException {
StringBuilder logMsgBuilder = new StringBuilder(String.format(
"Expand Meta Volume Start - Array:%s, Pool:%s %n Volume: %s, id: %s",
storageSystem.getSerialNumber(), storagePool.getNativeId(), metaHead.getLabel(),
metaHead.getId()));
log.info(logMsgBuilder.toString());
long metaMemberCapacity = recommendation.getMetaMemberSize();
int metaMemberCount = (int) recommendation.getMetaMemberCount();
MetaVolumeTaskCompleter metaVolumeTaskCompleter = new MetaVolumeTaskCompleter(
volumeCompleter);
try {
// Step 1: create meta members.
List<String> newMetaMembers = metaVolumeOperations
.createMetaVolumeMembers(storageSystem, storagePool,
metaHead, metaMemberCount, metaMemberCapacity,
metaVolumeTaskCompleter);
log.info("ldevMetaMembers created successfully: {}", newMetaMembers);
if (metaVolumeTaskCompleter.getLastStepStatus() == Job.JobStatus.SUCCESS) {
metaVolumeOperations.expandMetaVolume(storageSystem, storagePool, metaHead, newMetaMembers, metaVolumeTaskCompleter);
} else {
ServiceError serviceError = DeviceControllerErrors.hds.jobFailed("LDEV Meta Member creation failed");
volumeCompleter.error(dbClient, serviceError);
}
} catch (final InternalException e) {
log.error("Problem in doExpandAsMetaVolume: ", e);
volumeCompleter.error(dbClient, e);
} catch (final Exception e) {
log.error("Problem in doExpandAsMetaVolume: ", e);
ServiceError serviceError = DeviceControllerErrors.hds.methodFailed("doExpandAsMetaVolume", e.getMessage());
volumeCompleter.error(dbClient, serviceError);
}
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.BlockStorageDevice#doDeleteVolumes(com.emc.storageos.db.client.model.StorageSystem,
* java.lang.String, java.util.List, com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void doDeleteVolumes(StorageSystem storageSystem, String opId,
List<Volume> volumes, TaskCompleter taskCompleter)
throws DeviceControllerException {
try {
StringBuilder logMsgBuilder = new StringBuilder(String.format(
"Delete Volume Start - Array:%s", storageSystem.getSerialNumber()));
MultiVolumeTaskCompleter multiVolumeTaskCompleter = (MultiVolumeTaskCompleter) taskCompleter;
Set<String> thickLogicalUnitIdList = new HashSet<String>();
Set<String> thinLogicalUnitIdList = new HashSet<String>();
HDSApiClient hdsApiClient = hdsApiFactory.getClient(
HDSUtils.getHDSServerManagementServerInfo(storageSystem),
storageSystem.getSmisUserName(), storageSystem.getSmisPassword());
String systemObjectId = HDSUtils.getSystemObjectID(storageSystem);
log.info("volumes size: {}", volumes.size());
for (Volume volume : volumes) {
logMsgBuilder.append(String.format("%nVolume:%s", volume.getLabel()));
String logicalUnitObjectId = HDSUtils.getLogicalUnitObjectId(
volume.getNativeId(), storageSystem);
LogicalUnit logicalUnit = hdsApiClient.getLogicalUnitInfo(systemObjectId,
logicalUnitObjectId);
if (logicalUnit == null) {
// related volume state (if any) has been deleted. skip
// processing, if already deleted from array.
log.info(String.format("Volume %s already deleted: ",
volume.getNativeId()));
volume.setInactive(true);
dbClient.persistObject(volume);
VolumeTaskCompleter deleteTaskCompleter = multiVolumeTaskCompleter
.skipTaskCompleter(volume.getId());
deleteTaskCompleter.ready(dbClient);
continue;
}
if (volume.getThinlyProvisioned()) {
thinLogicalUnitIdList.add(logicalUnitObjectId);
} else {
thickLogicalUnitIdList.add(logicalUnitObjectId);
}
}
log.info(logMsgBuilder.toString());
if (!multiVolumeTaskCompleter.isVolumeTaskCompletersEmpty()) {
if (null != thickLogicalUnitIdList && !thickLogicalUnitIdList.isEmpty()) {
String asyncThickLUsJobId = hdsApiClient.deleteThickLogicalUnits(systemObjectId,
thickLogicalUnitIdList, storageSystem.getModel());
if (null != asyncThickLUsJobId) {
ControllerServiceImpl.enqueueJob(new QueueJob(new HDSDeleteVolumeJob(
asyncThickLUsJobId, volumes.get(0).getStorageController(),
taskCompleter)));
}
}
if (null != thinLogicalUnitIdList && !thinLogicalUnitIdList.isEmpty()) {
String asyncThinHDSJobId = hdsApiClient.deleteThinLogicalUnits(
systemObjectId, thinLogicalUnitIdList, storageSystem.getModel());
// Not sure whether this really works as tracking two jobs
// in single operation.
if (null != asyncThinHDSJobId) {
ControllerServiceImpl.enqueueJob(new QueueJob(
new HDSDeleteVolumeJob(asyncThinHDSJobId, volumes.get(0)
.getStorageController(), taskCompleter)));
}
}
} else {
// If we are here, there are no volumes to delete, we have
// invoked ready() for the VolumeDeleteCompleter, and told
// the multiVolumeTaskCompleter to skip these completers.
// In this case, the multiVolumeTaskCompleter complete()
// method will not be invoked and the result is that the
// workflow that initiated this delete request will never
// be updated. So, here we just call complete() on the
// multiVolumeTaskCompleter to ensure the workflow status is
// updated.
multiVolumeTaskCompleter.ready(dbClient);
}
} catch (Exception e) {
log.error("Problem in doDeleteVolume: ", e);
ServiceError error = DeviceControllerErrors.hds.methodFailed(
"doDeleteVolume", e.getMessage());
taskCompleter.error(dbClient, error);
}
StringBuilder logMsgBuilder = new StringBuilder(String.format(
"Delete Volume End - Array: %s", storageSystem.getSerialNumber()));
for (Volume volume : volumes) {
logMsgBuilder.append(String.format("%nVolume:%s", volume.getLabel()));
}
log.info(logMsgBuilder.toString());
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.BlockStorageDevice#doExportCreate(com.emc.storageos.db.client.model.StorageSystem,
* com.emc.storageos.db.client.model.ExportMask, java.util.Map, java.util.List, java.util.List,
* com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void doExportCreate(StorageSystem storage, ExportMask exportMask,
Map<URI, Integer> volumeMap, List<Initiator> initiators, List<URI> targets,
TaskCompleter taskCompleter) throws DeviceControllerException {
log.info("{} doExportCreate START ...", storage.getSerialNumber());
VolumeURIHLU[] volumeLunArray = ControllerUtils.getVolumeURIHLUArray(storage.getSystemType(), volumeMap, dbClient);
exportMaskOperationsHelper.createExportMask(storage, exportMask.getId(), volumeLunArray, targets, initiators, taskCompleter);
log.info("{} doExportCreate END ...", storage.getSerialNumber());
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.BlockStorageDevice#doExportDelete(com.emc.storageos.db.client.model.StorageSystem,
* com.emc.storageos.db.client.model.ExportMask, com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void doExportDelete(StorageSystem storage, ExportMask exportMask,
List<URI> volumeURIs, List<URI> initiatorURIs, TaskCompleter taskCompleter) throws DeviceControllerException {
log.info("{} doExportDelete START ...", storage.getSerialNumber());
exportMaskOperationsHelper.deleteExportMask(storage, exportMask.getId(), new ArrayList<URI>(),
new ArrayList<URI>(), new ArrayList<Initiator>(), taskCompleter);
log.info("{} doExportDelete END ...", storage.getSerialNumber());
}
@Override
public void doExportAddVolume(StorageSystem storage,
ExportMask exportMask,
URI volume, Integer lun,
List<Initiator> initiators, TaskCompleter taskCompleter) throws DeviceControllerException {
log.info("{} doExportAddVolume START ...", storage.getSerialNumber());
Map<URI, Integer> map = new HashMap<URI, Integer>();
map.put(volume, lun);
VolumeURIHLU[] volumeLunArray = ControllerUtils.getVolumeURIHLUArray(storage.getSystemType(), map, dbClient);
exportMaskOperationsHelper.addVolumes(storage, exportMask.getId(), volumeLunArray, initiators, taskCompleter);
log.info("{} doExportAddVolume END ...", storage.getSerialNumber());
}
@Override
public void doExportAddVolumes(StorageSystem storage, ExportMask exportMask,
List<Initiator> initiators,
Map<URI, Integer> volumes, TaskCompleter taskCompleter) throws DeviceControllerException {
log.info("{} doExportAddVolume START ...", storage.getSerialNumber());
VolumeURIHLU[] volumeLunArray = ControllerUtils.getVolumeURIHLUArray(storage.getSystemType(), volumes, dbClient);
exportMaskOperationsHelper.addVolumes(storage, exportMask.getId(),
volumeLunArray, initiators, taskCompleter);
log.info("{} doExportAddVolume END ...", storage.getSerialNumber());
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.BlockStorageDevice#doExportRemoveVolume(com.emc.storageos.db.client.model.StorageSystem,
* com.emc.storageos.db.client.model.ExportMask, java.net.URI, com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void doExportRemoveVolume(StorageSystem storage, ExportMask exportMask,
URI volume, List<Initiator> initiators, TaskCompleter taskCompleter) throws DeviceControllerException {
log.info("{} doExportRemoveVolume START ...", storage.getSerialNumber());
exportMaskOperationsHelper.removeVolumes(storage, exportMask.getId(), Arrays.asList(volume), initiators, taskCompleter);
log.info("{} doExportRemoveVolume END ...", storage.getSerialNumber());
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.BlockStorageDevice#doExportRemoveVolumes(com.emc.storageos.db.client.model.StorageSystem,
* com.emc.storageos.db.client.model.ExportMask, java.util.List, com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void doExportRemoveVolumes(StorageSystem storage, ExportMask exportMask,
List<URI> volumes, List<Initiator> initiators, TaskCompleter taskCompleter)
throws DeviceControllerException {
log.info("{} doExportRemoveVolume START ...", storage.getSerialNumber());
exportMaskOperationsHelper.removeVolumes(storage, exportMask.getId(), volumes,
initiators, taskCompleter);
log.info("{} doExportRemoveVolume END ...", storage.getSerialNumber());
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.BlockStorageDevice#doExportAddInitiator(com.emc.storageos.db.client.model.StorageSystem,
* com.emc.storageos.db.client.model.ExportMask, com.emc.storageos.db.client.model.Initiator, java.util.List,
* com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void doExportAddInitiator(StorageSystem storage, ExportMask exportMask,
List<URI> volumeURIs, Initiator initiator, List<URI> targets, TaskCompleter taskCompleter)
throws DeviceControllerException {
log.info("{} doExportAddInitiator START ...", storage.getSerialNumber());
exportMaskOperationsHelper.addInitiators(storage, exportMask.getId(), volumeURIs, Arrays.asList(initiator), targets, taskCompleter);
log.info("{} doExportAddInitiator END ...", storage.getSerialNumber());
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.BlockStorageDevice#doExportAddInitiators(com.emc.storageos.db.client.model.StorageSystem,
* com.emc.storageos.db.client.model.ExportMask, java.util.List, java.util.List, com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void doExportAddInitiators(StorageSystem storage, ExportMask exportMask,
List<URI> volumeURIs, List<Initiator> initiators, List<URI> targets, TaskCompleter taskCompleter)
throws DeviceControllerException {
log.info("{} doExportAddInitiator START ...", storage.getSerialNumber());
exportMaskOperationsHelper.addInitiators(storage, exportMask.getId(), volumeURIs,
initiators, targets, taskCompleter);
log.info("{} doExportAddInitiator END ...", storage.getSerialNumber());
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.BlockStorageDevice#doExportRemoveInitiator(com.emc.storageos.db.client.model.StorageSystem,
* com.emc.storageos.db.client.model.ExportMask, com.emc.storageos.db.client.model.Initiator, java.util.List,
* com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void doExportRemoveInitiator(StorageSystem storage, ExportMask exportMask,
List<URI> volumes, Initiator initiator, List<URI> targets, TaskCompleter taskCompleter)
throws DeviceControllerException {
log.info("{} doExportRemoveInitiator START ...", storage.getSerialNumber());
exportMaskOperationsHelper.removeInitiators(storage, exportMask.getId(),
volumes, Arrays.asList(initiator), targets, taskCompleter);
log.info("{} doExportRemoveInitiator END ...", storage.getSerialNumber());
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.BlockStorageDevice#doExportRemoveInitiators(com.emc.storageos.db.client.model.StorageSystem,
* com.emc.storageos.db.client.model.ExportMask, java.util.List, java.util.List, com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void doExportRemoveInitiators(StorageSystem storage, ExportMask exportMask,
List<URI> volumes, List<Initiator> initiators, List<URI> targets, TaskCompleter taskCompleter)
throws DeviceControllerException {
log.info("{} doExportRemoveInitiator START ...", storage.getSerialNumber());
exportMaskOperationsHelper.removeInitiators(storage, exportMask.getId(),
volumes, initiators, targets, taskCompleter);
log.info("{} doExportRemoveInitiator END ...", storage.getSerialNumber());
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.BlockStorageDevice#doCreateSnapshot(com.emc.storageos.db.client.model.StorageSystem,
* java.util.List, java.lang.Boolean, java.lang.Boolean, com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void doCreateSnapshot(StorageSystem storage, List<URI> snapshotList,
Boolean createInactive, Boolean readOnly, TaskCompleter taskCompleter)
throws DeviceControllerException {
// CG support is not yet implemented for HDS
snapshotOperations.createSingleVolumeSnapshot(storage, snapshotList.get(0), createInactive, readOnly, taskCompleter);
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.BlockStorageDevice#doDeleteSnapshot(com.emc.storageos.db.client.model.StorageSystem,
* java.net.URI, com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void doDeleteSnapshot(StorageSystem storage, URI snapshot,
TaskCompleter taskCompleter) throws DeviceControllerException {
snapshotOperations.deleteSingleVolumeSnapshot(storage, snapshot, taskCompleter);
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.BlockStorageDevice#doRestoreFromSnapshot(com.emc.storageos.db.client.model.StorageSystem,
* java.net.URI, java.net.URI, com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void doRestoreFromSnapshot(StorageSystem storage, URI volume, URI snapshot,
TaskCompleter taskCompleter) throws DeviceControllerException {
snapshotOperations.restoreSingleVolumeSnapshot(storage, volume, snapshot, taskCompleter);
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.BlockStorageDevice#doCreateMirror(com.emc.storageos.db.client.model.StorageSystem,
* java.net.URI, java.lang.Boolean, com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void doCreateMirror(StorageSystem storage, URI mirror, Boolean createInactive,
TaskCompleter taskCompleter) throws DeviceControllerException {
log.info("Started doCreateMirror");
mirrorOperations.createSingleVolumeMirror(storage, mirror, createInactive, taskCompleter);
log.info("Completed doCreateMirror");
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.BlockStorageDevice#doFractureMirror(com.emc.storageos.db.client.model.StorageSystem,
* java.net.URI, java.lang.Boolean, com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void doFractureMirror(StorageSystem storage, URI mirror, Boolean sync,
TaskCompleter taskCompleter) throws DeviceControllerException {
log.info("Started doFractureMirror");
mirrorOperations.fractureSingleVolumeMirror(storage, mirror, sync, taskCompleter);
log.info("Completed doFractureMirror");
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.BlockStorageDevice#doDetachMirror(com.emc.storageos.db.client.model.StorageSystem,
* java.net.URI, com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void doDetachMirror(StorageSystem storage, URI mirror,
TaskCompleter taskCompleter) throws DeviceControllerException {
log.info("Started doDetachMirror");
mirrorOperations.detachSingleVolumeMirror(storage, mirror, taskCompleter);
log.info("Completed doDetachMirror");
}
/*
* (non-Javadoc)
*
* @see
* com.emc.storageos.volumecontroller.BlockStorageDevice#doResumeNativeContinuousCopy(com.emc.storageos.db.client.model.StorageSystem,
* java.net.URI, com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void doResumeNativeContinuousCopy(StorageSystem storage, URI mirror,
TaskCompleter taskCompleter) throws DeviceControllerException {
log.info("Started doResumeNativeContinuousCopy");
mirrorOperations.resumeSingleVolumeMirror(storage, mirror, taskCompleter);
log.info("Completed doResumeNativeContinuousCopy");
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.BlockStorageDevice#doDeleteMirror(com.emc.storageos.db.client.model.StorageSystem,
* java.net.URI, com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void doDeleteMirror(StorageSystem storage, URI mirror,
TaskCompleter taskCompleter) throws DeviceControllerException {
log.info("Started doDeleteMirror");
mirrorOperations.deleteSingleVolumeMirror(storage, mirror, taskCompleter);
log.info("Completed doDeleteMirror");
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.BlockStorageDevice#doCreateClone(com.emc.storageos.db.client.model.StorageSystem,
* java.net.URI, java.net.URI, java.lang.Boolean, com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void doCreateClone(StorageSystem storageSystem, URI sourceVolumeURI,
URI cloneVolumeURI, Boolean createInactive, TaskCompleter taskCompleter) {
log.info("Inside doCreateClone");
cloneOperations.createSingleClone(storageSystem, sourceVolumeURI, cloneVolumeURI, createInactive, taskCompleter);
log.info("Completed doCreateClone");
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.BlockStorageDevice#doDetachClone(com.emc.storageos.db.client.model.StorageSystem,
* java.net.URI, com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void doDetachClone(StorageSystem storage, URI cloneVolume,
TaskCompleter taskCompleter) {
log.info("Started detach clone operation");
cloneOperations.detachSingleClone(storage, cloneVolume, taskCompleter);
log.info("Completed detach clone operation");
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.BlockStorageDevice#doCreateConsistencyGroup(com.emc.storageos.db.client.model.StorageSystem,
* java.net.URI, com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void doCreateConsistencyGroup(StorageSystem storage, URI consistencyGroup, String replicationGroupName,
TaskCompleter taskCompleter) throws DeviceControllerException {
// throw new DeviceControllerException("UnSupported Operation");
taskCompleter.ready(dbClient);
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.BlockStorageDevice#findExportMasks(com.emc.storageos.db.client.model.StorageSystem,
* java.util.List, boolean)
*/
@Override
public Map<String, Set<URI>> findExportMasks(StorageSystem storage,
List<String> initiatorNames, boolean mustHaveAllPorts) throws DeviceControllerException {
return exportMaskOperationsHelper.findExportMasks(storage, initiatorNames, mustHaveAllPorts);
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.BlockStorageDevice#refreshExportMask(com.emc.storageos.db.client.model.StorageSystem,
* com.emc.storageos.db.client.model.ExportMask)
*/
@Override
public ExportMask refreshExportMask(StorageSystem storage, ExportMask mask) throws DeviceControllerException {
return exportMaskOperationsHelper.refreshExportMask(storage, mask);
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.BlockStorageDevice#doActivateFullCopy(com.emc.storageos.db.client.model.StorageSystem,
* java.net.URI, com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void doActivateFullCopy(StorageSystem storageSystem, URI fullCopy,
TaskCompleter completer) {
log.info("Activate FullCopy started");
cloneOperations.activateSingleClone(storageSystem, fullCopy, completer);
log.info("Activate FullCopy completed");
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.BlockStorageDevice#doCleanupMetaMembers(com.emc.storageos.db.client.model.StorageSystem,
* com.emc.storageos.db.client.model.Volume,
* com.emc.storageos.volumecontroller.impl.block.taskcompleter.CleanupMetaVolumeMembersCompleter)
*/
@Override
public void doCleanupMetaMembers(StorageSystem storageSystem, Volume volume,
CleanupMetaVolumeMembersCompleter cleanupCompleter)
throws DeviceControllerException {
// Remove meta member volumes from storage device
try {
log.info(String.format("doCleanupMetaMembers Start - Array: %s, Volume: %s",
storageSystem.getSerialNumber(), volume.getLabel()));
// Load meta volume members from WF data
String sourceStepId = cleanupCompleter.getSourceStepId();
HDSApiClient hdsApiClient = hdsApiFactory.getClient(
HDSUtils.getHDSServerManagementServerInfo(storageSystem),
storageSystem.getUsername(), storageSystem.getSmisPassword());
List<String> metaMembers = (ArrayList<String>) WorkflowService.getInstance()
.loadStepData(sourceStepId);
if (metaMembers != null && !metaMembers.isEmpty()) {
log.info(String.format(
"doCleanupMetaMembers: Members stored for meta volume: %n %s",
metaMembers));
// Check if volumes still exist in array and if it is not composite member (already
// added to the meta volume)
Set<String> volumeIds = new HashSet<String>();
for (String logicalUnitObjectId : metaMembers) {
LogicalUnit logicalUnit = hdsApiClient.getLogicalUnitInfo(HDSUtils.getSystemObjectID(storageSystem),
logicalUnitObjectId);
if (logicalUnit != null) {
log.debug("doCleanupMetaMembers: Volume: " + logicalUnitObjectId
+ ", Usage of volume: " + logicalUnit.getComposite());
if (logicalUnit.getComposite() != HDSConstants.COMPOSITE_ELEMENT_MEMBER) {
volumeIds.add(logicalUnitObjectId);
}
}
}
if (volumeIds.isEmpty()) {
log.info("doCleanupMetaMembers: No meta members to cleanup in array.");
cleanupCompleter.ready(dbClient);
} else {
log.info(String
.format("doCleanupMetaMembers: Members to cleanup in array: %n %s",
volumeIds));
// Prepare parameters and call method to delete meta members from array
HDSCleanupMetaVolumeMembersJob hdsJobCompleter = null;
// When "cleanup" is separate workflow step, call async (for example rollback
// step in volume expand)
// Otherwise, call synchronously (for example when cleanup is part of meta
// volume create rollback)
String asyncMessageId = hdsApiClient.deleteThickLogicalUnits(HDSUtils.getSystemObjectID(storageSystem), volumeIds,
storageSystem.getModel());
if (cleanupCompleter.isWFStep()) {
if (asyncMessageId != null) {
ControllerServiceImpl.enqueueJob(new QueueJob(
new HDSCleanupMetaVolumeMembersJob(asyncMessageId, storageSystem.getId(),
volume.getId(), cleanupCompleter)));
}
} else {
// invoke synchronously
hdsJobCompleter = new HDSCleanupMetaVolumeMembersJob(
asyncMessageId, storageSystem.getId(), volume.getId(),
cleanupCompleter);
((HDSMetaVolumeOperations) metaVolumeOperations)
.invokeMethodSynchronously(hdsApiFactory, asyncMessageId,
hdsJobCompleter);
}
}
} else {
log.info("doCleanupMetaMembers: No meta members stored for meta volume. Nothing to cleanup in array.");
cleanupCompleter.ready(dbClient);
}
} catch (Exception e) {
log.error("Problem in doCleanupMetaMembers: ", e);
ServiceError error = DeviceControllerErrors.smis.methodFailed("doCleanupMetaMembers",
e.getMessage());
cleanupCompleter.error(dbClient, error);
}
log.info(String.format("doCleanupMetaMembers End - Array: %s, Volume: %s",
storageSystem.getSerialNumber(), volume.getLabel()));
}
/*
* (non-Javadoc)
*
* @see
* com.emc.storageos.volumecontroller.BlockStorageDevice#doWaitForSynchronized
* (java.lang.Class, com.emc.storageos.db.client.model.StorageSystem,
* java.net.URI, com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void doWaitForSynchronized(Class<? extends BlockObject> clazz,
StorageSystem storageObj, URI target, TaskCompleter completer) {
log.info("START waitForSynchronized for {}", target);
try {
Volume targetObj = dbClient.queryObject(Volume.class, target);
// Source could be either Volume or BlockSnapshot
BlockObject sourceObj = BlockObject.fetch(dbClient,
targetObj.getAssociatedSourceVolume());
// We split the pair which causes the data to be synchronized.
// When the split is complete that data is synchronized.
HDSApiClient hdsApiClient = hdsApiFactory.getClient(
HDSUtils.getHDSServerManagementServerInfo(storageObj),
storageObj.getSmisUserName(), storageObj.getSmisPassword());
HDSApiProtectionManager hdsApiProtectionManager = hdsApiClient
.getHdsApiProtectionManager();
String replicationGroupObjectID = hdsApiProtectionManager
.getReplicationGroupObjectId();
ReplicationInfo replicationInfo = hdsApiProtectionManager
.getReplicationInfoFromSystem(sourceObj.getNativeId(),
targetObj.getNativeId()).first;
hdsApiProtectionManager.modifyShadowImagePair(replicationGroupObjectID,
replicationInfo.getObjectID(),
HDSApiProtectionManager.ShadowImageOperationType.split, storageObj.getModel());
// Update state in case we are waiting for synchronization
// after creation of a new full copy that was not created
// inactive.
String state = targetObj.getReplicaState();
if (!ReplicationState.SYNCHRONIZED.name().equals(state)) {
targetObj.setSyncActive(true);
targetObj.setReplicaState(ReplicationState.SYNCHRONIZED.name());
dbClient.persistObject(targetObj);
}
// Queue job to wait for replication status to move to split.
ControllerServiceImpl.enqueueJob(new QueueJob(new HDSReplicationSyncJob(
storageObj.getId(), sourceObj.getNativeId(), targetObj.getNativeId(),
ReplicationStatus.SPLIT, completer)));
} catch (Exception e) {
log.error("Exception occurred while waiting for synchronization", e);
ServiceError serviceError = DeviceControllerException.errors.jobFailed(e);
completer.error(dbClient, serviceError);
}
log.info("completed doWaitForSynchronized");
}
@Override
public boolean validateStorageProviderConnection(String ipAddress, Integer portNumber) {
boolean isConnectionValid = false;
try {
StringBuffer providerID = new StringBuffer(ipAddress).append(
HDSConstants.HYPHEN_OPERATOR).append(portNumber);
URIQueryResultList providerUriList = new URIQueryResultList();
dbClient.queryByConstraint(AlternateIdConstraint.Factory
.getStorageProviderByProviderIDConstraint(providerID.toString()),
providerUriList);
if (providerUriList.iterator().hasNext()) {
StorageProvider provider = dbClient.queryObject(StorageProvider.class,
providerUriList.iterator().next());
HDSApiClient hdsApiClient = hdsApiFactory.getClient(
HDSUtils.getHDSServerManagementServerInfo(provider),
provider.getUserName(), provider.getPassword());
List<StorageArray> storageArrayList = hdsApiClient
.getStorageSystemsInfo();
if (null != storageArrayList && !storageArrayList.isEmpty()) {
isConnectionValid = true;
}
}
} catch (Exception ex) {
log.error(
"Problem in checking provider live connection for ipaddress: {} due to",
ipAddress, ex);
}
return isConnectionValid;
}
@Override
public void updatePolicyAndLimits(StorageSystem storage, ExportMask exportMask,
List<URI> volumeURIs, VirtualPool newVpool, boolean rollback,
TaskCompleter taskCompleter) throws Exception {
exportMaskOperationsHelper.updateStorageGroupPolicyAndLimits(
storage, exportMask, volumeURIs, newVpool, rollback, taskCompleter);
}
public void setCloneOperations(CloneOperations cloneOperations) {
this.cloneOperations = cloneOperations;
}
@Override
public void doModifyVolumes(StorageSystem storage, StoragePool storagePool, String opId, List<Volume> volumes,
TaskCompleter taskCompleter) throws DeviceControllerException {
StringBuilder logMsgBuilder = new StringBuilder(String.format("Modify Volume Start - Array:%s, Pool:%s",
storage.getSerialNumber(), storagePool.getNativeGuid()));
String systemObjectID = HDSUtils.getSystemObjectID(storage);
for (Volume volume : volumes) {
try {
HDSApiClient hdsApiClient = hdsApiFactory.getClient(HDSUtils.getHDSServerManagementServerInfo(storage),
storage.getSmisUserName(), storage.getSmisPassword());
logMsgBuilder.append(String.format("%nVolume:%s , IsThinlyProvisioned: %s, tieringPolicy: %s",
volume.getLabel(), volume.getThinlyProvisioned(), volume.getAutoTieringPolicyUri()));
LogicalUnit logicalUnit = hdsApiClient.getLogicalUnitInfo(systemObjectID,
HDSUtils.getLogicalUnitObjectId(volume.getNativeId(), storage));
String policyName = ControllerUtils.getAutoTieringPolicyName(volume.getId(), dbClient);
String autoTierPolicyName = null;
if (policyName.equals(Constants.NONE)) {
autoTierPolicyName = null;
} else {
autoTierPolicyName = HitachiTieringPolicy.getPolicy(
policyName.replaceAll(HDSConstants.SLASH_OPERATOR, HDSConstants.UNDERSCORE_OPERATOR))
.getKey();
}
if (null != logicalUnit && null != logicalUnit.getLdevList() && !logicalUnit.getLdevList().isEmpty()) {
Iterator<LDEV> ldevItr = logicalUnit.getLdevList().iterator();
if (ldevItr.hasNext()) {
LDEV ldev = ldevItr.next();
String asyncMessageId = hdsApiClient.modifyThinVolumeTieringPolicy(systemObjectID,
logicalUnit.getObjectID(), ldev.getObjectID(), autoTierPolicyName, storage.getModel());
if (null != asyncMessageId) {
HDSJob modifyHDSJob = new HDSModifyVolumeJob(asyncMessageId, volume.getStorageController(),
taskCompleter, HDSModifyVolumeJob.VOLUME_MODIFY_JOB);
ControllerServiceImpl.enqueueJob(new QueueJob(modifyHDSJob));
}
}
} else {
String errorMsg = String.format("No LDEV's found for volume: %s", volume.getId());
log.info(errorMsg);
ServiceError serviceError = DeviceControllerErrors.hds.methodFailed("doModifyVolumes", errorMsg);
taskCompleter.error(dbClient, serviceError);
}
} catch (final InternalException e) {
log.error("Problem in doModifyVolumes: ", e);
taskCompleter.error(dbClient, e);
} catch (final Exception e) {
log.error("Problem in doModifyVolumes: ", e);
ServiceError serviceError = DeviceControllerErrors.hds.methodFailed("doModifyVolumes", e.getMessage());
taskCompleter.error(dbClient, serviceError);
}
}
}
public void setMirrorOperations(MirrorOperations mirrorOperations) {
this.mirrorOperations = mirrorOperations;
}
public void setSnapshotOperations(SnapshotOperations snapshotOperations) {
this.snapshotOperations = snapshotOperations;
}
@Override
public void doRestoreFromClone(StorageSystem storageSystem, URI cloneURI,
TaskCompleter taskCompleter) {
log.info("Restore from full copy {} started", cloneURI);
cloneOperations.restoreFromSingleClone(storageSystem, cloneURI, taskCompleter);
log.info("Restore from full copy completed");
}
@Override
public void doResyncClone(StorageSystem storageSystem, URI cloneURI,
TaskCompleter taskCompleter) {
log.info("Resynchronize full copy {} started", cloneURI);
cloneOperations.resyncSingleClone(storageSystem, cloneURI, taskCompleter);
log.info("Resynchronize full copy completed");
}
}