/*
* Copyright (c) 2008-2014 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.impl.smis.ibm.xiv;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.cim.CIMArgument;
import javax.cim.CIMInstance;
import javax.cim.CIMObjectPath;
import javax.wbem.CloseableIterator;
import javax.wbem.WBEMException;
import javax.wbem.client.EnumerateResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.cimadapter.connections.cim.CimObjectPathCreator;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.model.BlockConsistencyGroup;
import com.emc.storageos.db.client.model.BlockConsistencyGroup.Types;
import com.emc.storageos.db.client.model.BlockObject;
import com.emc.storageos.db.client.model.BlockSnapshot;
import com.emc.storageos.db.client.model.ExportMask;
import com.emc.storageos.db.client.model.Host;
import com.emc.storageos.db.client.model.Initiator;
import com.emc.storageos.db.client.model.StoragePool;
import com.emc.storageos.db.client.model.StorageSystem;
import com.emc.storageos.db.client.model.StringSet;
import com.emc.storageos.db.client.model.TenantOrg;
import com.emc.storageos.db.client.model.Volume;
import com.emc.storageos.db.client.util.NameGenerator;
import com.emc.storageos.db.client.util.NullColumnValueGetter;
import com.emc.storageos.db.exceptions.DatabaseException;
import com.emc.storageos.exceptions.DeviceControllerErrors;
import com.emc.storageos.exceptions.DeviceControllerException;
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.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.ExportMaskPolicy;
import com.emc.storageos.volumecontroller.impl.block.taskcompleter.MultiVolumeTaskCompleter;
import com.emc.storageos.volumecontroller.impl.block.taskcompleter.VolumeTaskCompleter;
import com.emc.storageos.volumecontroller.impl.job.QueueJob;
import com.emc.storageos.volumecontroller.impl.smis.CIMPropertyFactory;
import com.emc.storageos.volumecontroller.impl.smis.ExportMaskOperations;
import com.emc.storageos.volumecontroller.impl.smis.SmisConstants;
import com.emc.storageos.volumecontroller.impl.smis.ibm.IBMCIMObjectPathFactory;
import com.emc.storageos.volumecontroller.impl.smis.ibm.IBMSmisConstants;
import com.emc.storageos.volumecontroller.impl.smis.job.SmisWaitForSynchronizedJob;
import com.emc.storageos.volumecontroller.impl.utils.VirtualPoolCapabilityValuesWrapper;
/**
* IBM XIV SMI-S block controller implementation.
*
* Key characteristics of IBM XIV array:
*
* 1. CIM method may return without exception, but with error code
* a. return code is checked
* b. depending on different situations, may throw exception, or ignore the error code
*
* 2. all CIM methods are synchronous (there is no job returned from CIM call)
* a. XIVSmisStorageDevicePostProcessor is called to handle CIM call result,
* which is handled via SmisXXXJob in case of asynchronous call.
* b. for some methods (remove members from CG, or create group snapshots),
* result may not be available immediately after a successful return,
* in such cases, workaround are made (see IBMSmisSynchSubTaskJob).
*
* 3. all XIV volumes are thin provisioned regardless the pool type
*
* 4. all volumes in a CG has to be on the same storage pool
* a. user cannot specify storage pool in CG creation, CG's storage pool association
* is set implicitly by member volumes
* b. creating an empty CG on array will result a CG associated to a storage pool
* that system selected. User cannot change the association afterwards.
*
* 5. in mapping, target ports cannot be specified
* a. target ports can be configured by zoning, so zoning must be done before masking
*
* 6. one host could have only one mapping representation on array side
* a. a mapping on array side may not have any initiator/target port/LUN (empty mapping)
* b. there could be multiple volumes in the mapping
* c. one volume can be mapped to multiple hosts
* d. host name is used on array side if no conflict,
* otherwise, array side name will be set as tag of the host in ViPR
*
* 7. XIV Open API doesn't support creating/exporting to a cluster (an array side cluster)
* a. a set of volumes can be mapping to multiple hosts via ViPR cluster
*
*/
public class XIVSmisStorageDevice extends DefaultBlockStorageDevice {
private static final Logger _log = LoggerFactory
.getLogger(XIVSmisStorageDevice.class);
private static final String EMPTY_CG_NAME = " ";
private DbClient _dbClient;
protected XIVSmisCommandHelper _helper;
private IBMCIMObjectPathFactory _cimPath;
private NameGenerator _nameGenerator;
// TODO - place holder for now
private XIVSmisStorageDevicePreProcessor _smisStorageDevicePreProcessor;
private XIVSmisStorageDevicePostProcessor _smisStorageDevicePostProcessor;
private ExportMaskOperations _exportMaskOperationsHelper;
private SnapshotOperations _snapshotOperations;
private CloneOperations _cloneOperations;
private boolean isForceSnapshotGroupRemoval = false;
public void setCimObjectPathFactory(
final IBMCIMObjectPathFactory cimObjectPathFactory) {
_cimPath = cimObjectPathFactory;
}
public void setDbClient(final DbClient dbClient) {
_dbClient = dbClient;
}
public void setSmisCommandHelper(
final XIVSmisCommandHelper smisCommandHelper) {
_helper = smisCommandHelper;
}
public void setNameGenerator(final NameGenerator nameGenerator) {
_nameGenerator = nameGenerator;
}
public void setSmisStorageDevicePreProcessor(
final XIVSmisStorageDevicePreProcessor smisStorageDevicePreProcessor) {
_smisStorageDevicePreProcessor = smisStorageDevicePreProcessor;
}
public void setSmisStorageDevicePostProcessor(
final XIVSmisStorageDevicePostProcessor smisStorageDevicePostProcessor) {
_smisStorageDevicePostProcessor = smisStorageDevicePostProcessor;
}
public void setExportMaskOperationsHelper(final ExportMaskOperations exportMaskOperationsHelper) {
_exportMaskOperationsHelper = exportMaskOperationsHelper;
}
public void setSnapshotOperations(final SnapshotOperations snapshotOperations) {
_snapshotOperations = snapshotOperations;
}
public void setCloneOperations(final CloneOperations cloneOperations) {
_cloneOperations = cloneOperations;
}
public void setIsForceSnapshotGroupRemoval(boolean isForceSnapshotGroupRemoval) {
this.isForceSnapshotGroupRemoval = isForceSnapshotGroupRemoval;
}
/*
* (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(final StorageSystem storageSystem,
final StoragePool storagePool, final String opId,
final List<Volume> volumes,
final VirtualPoolCapabilityValuesWrapper capabilities,
final TaskCompleter taskCompleter) throws DeviceControllerException {
Set<URI> volumeURIs = new HashSet<URI>(0);
StringBuilder logMsgBuilder = new StringBuilder(String.format(
"Create Volume Start - Array:%s, Pool:%s",
storageSystem.getLabel(), storagePool.getNativeId()));
Volume firstVolume = volumes.get(0);
Long capacity = firstVolume.getCapacity();
boolean isThinlyProvisioned = firstVolume.getThinlyProvisioned();
String tenantName = "";
try {
TenantOrg tenant = _dbClient.queryObject(TenantOrg.class,
firstVolume.getTenant().getURI());
tenantName = tenant.getLabel();
} catch (DatabaseException e) {
_log.error("Error lookup TenantOrg object", e);
}
List<String> labels = new ArrayList<String>(volumes.size());
for (Volume volume : volumes) {
String label = volume.getLabel();
logMsgBuilder.append("\nVolume: ").append(label);
labels.add(_nameGenerator.generate(tenantName, label, volume
.getId().toString(), '-',
SmisConstants.MAX_VOLUME_NAME_LENGTH));
}
_log.info(logMsgBuilder.toString());
try {
CIMObjectPath configSvcPath = _cimPath
.getConfigSvcPath(storageSystem);
CIMArgument[] inArgs = _helper.getCreateVolumesInputArguments(
storageSystem, storagePool, labels, capacity,
volumes.size(), isThinlyProvisioned);
CIMArgument[] outArgs = new CIMArgument[5];
_helper.invokeMethod(storageSystem, configSvcPath,
SmisConstants.CREATE_OR_MODIFY_ELEMENTS_FROM_STORAGE_POOL,
inArgs, outArgs);
volumeURIs = _smisStorageDevicePostProcessor
.processVolumeCreation(storageSystem, storagePool.getId(),
volumes, outArgs);
if (!volumeURIs.isEmpty()) {
// see SmisAbstractCreateVolumeJob.addVolumeToConsistencyGroup
// All the volumes will be in the same consistency group
final URI consistencyGroupId = firstVolume.getConsistencyGroup();
if (consistencyGroupId != null) {
addVolumesToCG(storageSystem, consistencyGroupId, new ArrayList<URI>(volumeURIs));
}
}
taskCompleter.ready(_dbClient);
} catch (final InternalException e) {
_log.error("Problem in doCreateVolumes: ", e);
taskCompleter.error(_dbClient, e);
} catch (WBEMException e) {
_log.error("Problem making SMI-S call: ", e);
ServiceError serviceError = DeviceControllerErrors.smis
.unableToCallStorageProvider(e.getMessage());
taskCompleter.error(_dbClient, serviceError);
} catch (Exception e) {
_log.error("Problem in doCreateVolumes: ", e);
ServiceError serviceError = DeviceControllerErrors.smis
.methodFailed("doCreateVolumes", e.getMessage());
taskCompleter.error(_dbClient, serviceError);
}
List<Volume> volumesToSave = new ArrayList<Volume>();
for (URI id : taskCompleter.getIds()) {
if (!volumeURIs.contains(id)) {
logMsgBuilder.append("\n");
logMsgBuilder.append(String.format(
"Task %s failed to create volume: %s", opId,
id.toString()));
Volume volume = _dbClient.queryObject(Volume.class, id);
volume.setInactive(true);
volumesToSave.add(volume);
}
}
if (!volumesToSave.isEmpty()) {
_dbClient.persistObject(volumesToSave);
}
logMsgBuilder = new StringBuilder(String.format(
"Create Volumes End - Array:%s, Pool:%s",
storageSystem.getLabel(), storagePool.getNativeId()));
for (Volume volume : volumes) {
logMsgBuilder
.append(String.format("%nVolume:%s", volume.getLabel()));
}
_log.info(logMsgBuilder.toString());
}
/*
* (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(final StorageSystem storageSystem,
final StoragePool pool, final Volume volume, final Long size,
final TaskCompleter taskCompleter) throws DeviceControllerException {
_log.info(String
.format("Expand Volume Start - Array: %s, Pool: %s, Volume: %s, New size: %d",
storageSystem.getLabel(), pool.getNativeId(),
volume.getLabel(), size));
try {
CIMObjectPath configSvcPath = _cimPath
.getConfigSvcPath(storageSystem);
CIMArgument[] inArgs = _helper.getExpandVolumeInputArguments(
storageSystem, volume, size);
CIMArgument[] outArgs = new CIMArgument[5];
_helper.invokeMethod(storageSystem, configSvcPath,
SmisConstants.CREATE_OR_MODIFY_ELEMENT_FROM_STORAGE_POOL,
inArgs, outArgs);
_smisStorageDevicePostProcessor.processVolumeExpansion(
storageSystem, pool.getId(), volume.getId(), outArgs);
taskCompleter.ready(_dbClient);
} catch (WBEMException e) {
_log.error("Problem making SMI-S call: ", e);
ServiceError error = DeviceControllerErrors.smis
.unableToCallStorageProvider(e.getMessage());
taskCompleter.error(_dbClient, error);
} catch (Exception e) {
_log.error("Problem in doExpandVolume: ", e);
ServiceError error = DeviceControllerErrors.smis.methodFailed(
"doExpandVolume", e.getMessage());
taskCompleter.error(_dbClient, error);
}
_log.info(String.format(
"Expand Volume End - Array: %s, Pool: %s, Volume: %s",
storageSystem.getLabel(), pool.getNativeId(), volume.getLabel()));
}
/*
* (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)
*
* Note: assume volumes could be from different consistency groups
*/
@Override
public void doDeleteVolumes(final StorageSystem storageSystem,
final String opId, final List<Volume> volumes,
final TaskCompleter taskCompleter) throws DeviceControllerException {
try {
List<String> volumeNativeIds = new ArrayList<String>();
StringBuilder logMsgBuilder = new StringBuilder(String.format(
"Delete Volume Start - Array:%s", storageSystem.getLabel()));
MultiVolumeTaskCompleter multiVolumeTaskCompleter = (MultiVolumeTaskCompleter) taskCompleter;
for (Volume volume : volumes) {
logMsgBuilder.append(String.format("%nVolume:%s",
volume.getLabel()));
if (volume.getConsistencyGroup() != null) {
BlockConsistencyGroup cg = _dbClient.queryObject(BlockConsistencyGroup.class, volume.getConsistencyGroup());
if (cg != null && cg.getTypes() != null && cg.getTypes().contains(BlockConsistencyGroup.Types.LOCAL.name())) {
removeVolumeFromConsistencyGroup(storageSystem, cg, volume);
}
}
CIMInstance volumeInstance = _helper.checkExists(storageSystem,
volume, false, false);
if (volumeInstance == 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;
}
// Compare the volume labels of the to-be-deleted and existing
// volumes
/**
* This will fail in the case when the user just changes the
* label of the volume...till we subscribe to indications from
* the provider, we will live with that.
*/
String volToDeleteLabel = volume.getDeviceLabel();
String volInstanceLabel = CIMPropertyFactory.getPropertyValue(
volumeInstance, SmisConstants.CP_ELEMENT_NAME);
if (volToDeleteLabel != null && volInstanceLabel != null
&& !volToDeleteLabel.equals(volInstanceLabel)) {
// related volume state (if any) has been deleted. skip
// processing, if already
// deleted from array.
_log.info("VolToDeleteLabel {} : volInstancelabel {}",
volToDeleteLabel, volInstanceLabel);
_log.info(String.format("Volume %s already deleted: ",
volume.getNativeId()));
volume.setInactive(true);
// clear the associated consistency groups from the volume
volume.setConsistencyGroup(NullColumnValueGetter.getNullURI());
// TODO - is this needed, or just persistObject? use bulk
// update
_dbClient.updateAndReindexObject(volume);
VolumeTaskCompleter deleteTaskCompleter = multiVolumeTaskCompleter
.skipTaskCompleter(volume.getId());
deleteTaskCompleter.ready(_dbClient);
continue;
}
volumeNativeIds.add(volume.getNativeId());
}
_log.info(logMsgBuilder.toString());
// execute SMI-S Call , only if any Volumes left for deletion.
if (!multiVolumeTaskCompleter.isVolumeTaskCompletersEmpty()) {
CIMObjectPath configSvcPath = _cimPath
.getConfigSvcPath(storageSystem);
CIMArgument[] inArgs = _helper.getDeleteVolumesInputArguments(
storageSystem, volumeNativeIds.toArray(new String[volumeNativeIds.size()]));
CIMArgument[] outArgs = new CIMArgument[5];
_helper.invokeMethod(storageSystem, configSvcPath,
SmisConstants.RETURN_ELEMENTS_TO_STORAGE_POOL, inArgs,
outArgs);
_smisStorageDevicePostProcessor.processVolumeDeletion(
storageSystem, volumes, outArgs,
multiVolumeTaskCompleter);
}
// If we are here, there are no more 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 (WBEMException e) {
_log.error("Problem making SMI-S call: ", e);
ServiceError error = DeviceControllerErrors.smis
.unableToCallStorageProvider(e.getMessage());
taskCompleter.error(_dbClient, error);
} catch (DeviceControllerException e) {
taskCompleter.error(_dbClient, e);
} catch (Exception e) {
_log.error("Problem in doDeleteVolume: ", e);
ServiceError error = DeviceControllerErrors.smis.methodFailed(
"doDeleteVolume", e.getMessage());
taskCompleter.error(_dbClient, error);
}
StringBuilder logMsgBuilder = new StringBuilder(String.format(
"Delete Volume End - Array: %s", storageSystem.getLabel()));
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)
*
* @param targets not used
*/
@Override
public void doExportCreate(final StorageSystem storage, final ExportMask exportMask,
final Map<URI, Integer> volumeMap, final List<Initiator> initiators,
final List<URI> targets, final TaskCompleter taskCompleter)
throws DeviceControllerException {
_log.info("{} doExportCreate START ...", storage.getLabel());
VolumeURIHLU[] volumeLunArray = ControllerUtils.getVolumeURIHLUArray(
storage.getSystemType(), volumeMap, _dbClient);
_exportMaskOperationsHelper.createExportMask(storage, exportMask.getId(), volumeLunArray,
targets, initiators, taskCompleter);
_log.info("{} doExportCreate END ...", storage.getLabel());
}
@Override
public void doExportDelete(final StorageSystem storage, final ExportMask exportMask,
List<URI> volumeURIs, List<URI> initiatorURIs, final TaskCompleter taskCompleter) throws DeviceControllerException {
_log.info("{} doExportDelete START ...", storage.getLabel());
_exportMaskOperationsHelper.deleteExportMask(storage, exportMask.getId(),
new ArrayList<URI>(), new ArrayList<URI>(), new ArrayList<Initiator>(),
taskCompleter);
_log.info("{} doExportDelete END ...", storage.getLabel());
}
@Override
public void doExportAddVolume(final StorageSystem storage, final ExportMask exportMask,
final URI volume, final Integer lun, List<Initiator> initiators, final TaskCompleter taskCompleter)
throws DeviceControllerException {
_log.info("{} doExportAddVolume START ...", storage.getLabel());
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.getLabel());
}
@Override
public void doExportAddVolumes(final StorageSystem storage, final ExportMask exportMask,
List<Initiator> initiators, final Map<URI, Integer> volumes, final TaskCompleter taskCompleter)
throws DeviceControllerException {
_log.info("{} doExportAddVolume START ...", storage.getLabel());
VolumeURIHLU[] volumeLunArray = ControllerUtils.getVolumeURIHLUArray(
storage.getSystemType(), volumes, _dbClient);
_exportMaskOperationsHelper.addVolumes(storage, exportMask.getId(), volumeLunArray,
initiators, taskCompleter);
_log.info("{} doExportAddVolume END ...", storage.getLabel());
}
@Override
public void doExportRemoveVolume(final StorageSystem storage, final ExportMask exportMask,
final URI volume, List<Initiator> initiators, final TaskCompleter taskCompleter) throws DeviceControllerException {
_log.info("{} doExportRemoveVolume START ...", storage.getLabel());
_exportMaskOperationsHelper.removeVolumes(storage, exportMask.getId(),
Arrays.asList(volume), initiators, taskCompleter);
_log.info("{} doExportRemoveVolume END ...", storage.getLabel());
}
@Override
public void doExportRemoveVolumes(final StorageSystem storage, final ExportMask exportMask,
final List<URI> volumes, List<Initiator> initiators, final TaskCompleter taskCompleter)
throws DeviceControllerException {
_log.info("{} doExportRemoveVolume START ...", storage.getLabel());
_exportMaskOperationsHelper.removeVolumes(storage, exportMask.getId(), volumes,
initiators, taskCompleter);
_log.info("{} doExportRemoveVolume END ...", storage.getLabel());
}
@Override
public void doExportAddInitiator(final StorageSystem storage, final ExportMask exportMask,
List<URI> volumeURIs, final Initiator initiator, final List<URI> targets, final TaskCompleter taskCompleter)
throws DeviceControllerException {
_log.info("{} doExportAddInitiator START ...", storage.getLabel());
_exportMaskOperationsHelper.addInitiators(storage, exportMask.getId(),
volumeURIs, Arrays.asList(initiator), targets, taskCompleter);
_log.info("{} doExportAddInitiator END ...", storage.getLabel());
}
@Override
public void doExportAddInitiators(final StorageSystem storage, final ExportMask exportMask,
List<URI> volumeURIs, final List<Initiator> initiators,
final List<URI> targets, final TaskCompleter taskCompleter) throws DeviceControllerException {
_log.info("{} doExportAddInitiator START ...", storage.getLabel());
_exportMaskOperationsHelper.addInitiators(storage, exportMask.getId(), volumeURIs, initiators,
targets, taskCompleter);
_log.info("{} doExportAddInitiator END ...", storage.getLabel());
}
@Override
public void doExportRemoveInitiator(final StorageSystem storage, final ExportMask exportMask,
List<URI> volumes, final Initiator initiator, final List<URI> targets, final TaskCompleter taskCompleter)
throws DeviceControllerException {
_log.info("{} doExportRemoveInitiator START ...", storage.getLabel());
_exportMaskOperationsHelper.removeInitiators(storage, exportMask.getId(),
volumes, Arrays.asList(initiator), targets, taskCompleter);
_log.info("{} doExportRemoveInitiator END ...", storage.getLabel());
}
@Override
public void doExportRemoveInitiators(final StorageSystem storage, final ExportMask exportMask,
List<URI> volumes, final List<Initiator> initiators,
final List<URI> targets, final TaskCompleter taskCompleter) throws DeviceControllerException {
_log.info("{} doExportRemoveInitiator START ...", storage.getLabel());
_exportMaskOperationsHelper.removeInitiators(storage, exportMask.getId(), volumes,
initiators, targets, taskCompleter);
_log.info("{} doExportRemoveInitiator END ...", storage.getLabel());
}
/**
* Return a mapping of the port name to the URI of the ExportMask in which
* it is contained.
*
* @param storage
* [in] - StorageSystem object representing the array
* @param initiatorNames
* [in] - Port identifiers (WWPN or iSCSI name)
* @param mustHaveAllPorts
* [in] Indicates if true, *all* the passed in initiators have to be in the existing
* matching mask. If false, a mask with *any* of the specified initiators will be
* considered a hit.
* @return Map of port name to Set of ExportMask URIs
*/
@Override
public Map<String, Set<URI>> findExportMasks(final StorageSystem storage,
final List<String> initiatorNames, final boolean mustHaveAllPorts) throws DeviceControllerException {
return _exportMaskOperationsHelper.findExportMasks(storage, initiatorNames,
mustHaveAllPorts);
}
@Override
public ExportMask refreshExportMask(final StorageSystem storage, final ExportMask mask) throws DeviceControllerException {
return _exportMaskOperationsHelper.refreshExportMask(storage, mask);
}
@Override
public boolean validateStorageProviderConnection(String ipAddress,
Integer portNumber) {
return _helper.validateStorageProviderConnection(ipAddress, portNumber);
}
@Override
public void doConnect(final StorageSystem storage) {
try {
_helper.getConnection(storage);
} catch (Exception e) {
throw new IllegalStateException("No cim connection for "
+ storage.getIpAddress(), e);
}
}
@Override
public void doDisconnect(final StorageSystem storage) {
}
@Override
public void doCreateSnapshot(final StorageSystem storage,
final List<URI> snapshotList, final Boolean createInactive,
Boolean readOnly, final TaskCompleter taskCompleter) throws DeviceControllerException {
try {
List<BlockSnapshot> snapshots = _dbClient.queryObject(
BlockSnapshot.class, snapshotList);
if (ControllerUtils.checkSnapshotsInConsistencyGroup(snapshots, _dbClient, taskCompleter)) {
_snapshotOperations.createGroupSnapshots(storage, snapshotList,
createInactive, readOnly, taskCompleter);
} else {
URI snapshot = snapshots.get(0).getId();
_snapshotOperations.createSingleVolumeSnapshot(storage,
snapshot, createInactive, readOnly, taskCompleter);
}
} catch (DatabaseException e) {
String message = String
.format("IO exception when trying to create snapshot(s) on array %s",
storage.getSerialNumber());
_log.error(message, e);
ServiceError error = DeviceControllerErrors.smis.methodFailed(
"doCreateSnapshot", e.getMessage());
taskCompleter.error(_dbClient, error);
}
}
@Override
public void doRestoreFromSnapshot(final StorageSystem storage,
final URI volume, final URI snapshot,
final TaskCompleter taskCompleter) throws DeviceControllerException {
try {
List<BlockSnapshot> snapshots = _dbClient.queryObject(
BlockSnapshot.class, Arrays.asList(snapshot));
if (ControllerUtils.checkSnapshotsInConsistencyGroup(snapshots, _dbClient, taskCompleter)) {
_snapshotOperations.restoreGroupSnapshots(storage, volume,
snapshot, taskCompleter);
} else {
_snapshotOperations.restoreSingleVolumeSnapshot(storage,
volume, snapshot, taskCompleter);
}
} catch (DatabaseException e) {
String message = String
.format("IO exception when trying to restore snapshot(s) on array %s",
storage.getSerialNumber());
_log.error(message, e);
ServiceError error = DeviceControllerErrors.smis.methodFailed(
"doRestoreFromSnapshot", e.getMessage());
taskCompleter.error(_dbClient, error);
}
}
@Override
public void doDeleteSnapshot(final StorageSystem storage,
final URI snapshot, final TaskCompleter taskCompleter)
throws DeviceControllerException {
try {
List<BlockSnapshot> snapshots = _dbClient.queryObject(
BlockSnapshot.class, Arrays.asList(snapshot));
if (ControllerUtils.checkSnapshotsInConsistencyGroup(snapshots, _dbClient, taskCompleter)) {
_snapshotOperations.deleteGroupSnapshots(storage, snapshot,
taskCompleter);
} else {
_snapshotOperations.deleteSingleVolumeSnapshot(storage,
snapshot, taskCompleter);
}
} catch (DatabaseException e) {
String message = String
.format("IO exception when trying to delete snapshot(s) on array %s",
storage.getSerialNumber());
_log.error(message, e);
ServiceError error = DeviceControllerErrors.smis.methodFailed(
"doDeleteSnapshot", e.getMessage());
taskCompleter.error(_dbClient, error);
}
}
@Override
public void doCreateClone(final StorageSystem storage,
final URI sourceVolume, final URI cloneVolume,
final Boolean createInactive, final TaskCompleter taskCompleter) {
_cloneOperations.createSingleClone(storage, sourceVolume, cloneVolume,
createInactive, taskCompleter);
}
@Override
public void doActivateFullCopy(final StorageSystem storageSystem,
final URI fullCopy, final TaskCompleter completer) {
_cloneOperations
.activateSingleClone(storageSystem, fullCopy, completer);
}
@Override
public void doDetachClone(final StorageSystem storage,
final URI cloneVolume, final TaskCompleter taskCompleter) {
_cloneOperations.detachSingleClone(storage, cloneVolume, taskCompleter);
}
/*
* (non-Javadoc)
*
* @see
* com.emc.storageos.volumecontroller.AbstractBlockStorageDevice#doCreateConsistencyGroup(com.emc.storageos.db.client.model.
* StorageSystem
* , java.net.URI, com.emc.storageos.volumecontroller.TaskCompleter)
*
* Note: this won't create CG on array side, it just associate CG with array
* CG will be created on array side when adding first volumes to
*/
@Override
public void doCreateConsistencyGroup(final StorageSystem storage,
final URI consistencyGroupId, String replicationGroupName, final TaskCompleter taskCompleter)
throws DeviceControllerException {
// cannot create CG here, as there is no way to specify storage pool
// need to create CG with member volumes in addVolumesToCG
try {
BlockConsistencyGroup consistencyGroup = _dbClient.queryObject(
BlockConsistencyGroup.class, consistencyGroupId);
// just try to find out if there CG name is already used on array, so to fail the CG creation here
// rather than after volumes are created
String label = consistencyGroup.getLabel();
String query = String.format(
"Select * From %s Where ElementName=\"%s\"",
IBMSmisConstants.CP_CONSISTENCY_GROUP, label);
CIMObjectPath cgPath = CimObjectPathCreator.createInstance(
IBMSmisConstants.CP_CONSISTENCY_GROUP,
Constants.IBM_NAMESPACE, null);
List<CIMInstance> cgInstances = _helper.executeQuery(storage,
cgPath, query, "WQL");
if (cgInstances.isEmpty()) {
consistencyGroup.addSystemConsistencyGroup(storage.getId().toString(), EMPTY_CG_NAME);
consistencyGroup.setStorageController(storage.getId());
consistencyGroup.addConsistencyGroupTypes(Types.LOCAL.name());
_dbClient.persistObject(consistencyGroup);
}
taskCompleter.ready(_dbClient);
} catch (Exception e) {
_log.error("Failed to create consistency group: " + e);
ServiceError error = DeviceControllerErrors.smis.methodFailed(
"doCreateConsistencyGroup", e.getMessage());
taskCompleter.error(_dbClient, error);
}
}
@Override
public void doDeleteConsistencyGroup(final StorageSystem storage,
final URI consistencyGroupId, String replicationGroupName, Boolean keepRGName, Boolean markInactive,
final TaskCompleter taskCompleter)
throws DeviceControllerException {
BlockConsistencyGroup consistencyGroup = _dbClient.queryObject(
BlockConsistencyGroup.class, consistencyGroupId);
try {
// Check if the consistency group does exist
String groupName = _helper
.getConsistencyGroupName(consistencyGroup, storage);
if (groupName != null && !groupName.equals(EMPTY_CG_NAME)) {
CIMObjectPath cgPath = _cimPath.getConsistencyGroupPath(
storage, groupName);
CIMInstance cgPathInstance = _helper.checkExists(storage,
cgPath, false, false);
if (cgPathInstance != null) {
@SuppressWarnings("rawtypes")
CIMArgument[] inArgs = _helper
.getDeleteReplicationGroupInputArguments(storage,
cgPath);
_helper.callReplicationSvc(storage,
IBMSmisConstants.DELETE_GROUP, inArgs,
new CIMArgument[5]);
}
}
// Set the consistency group to inactive
if (groupName != null) {
consistencyGroup.removeSystemConsistencyGroup(storage.getId().toString(), groupName);
}
if (markInactive) {
consistencyGroup.setInactive(true);
}
_dbClient.persistObject(consistencyGroup);
// Set task to ready
taskCompleter.ready(_dbClient);
} catch (Exception e) {
_log.info("Failed to delete consistency group: " + e);
// Set task to error
ServiceError error = DeviceControllerErrors.smis.methodFailed(
"doDeleteConsistencyGroup", e.getMessage());
taskCompleter.error(_dbClient, error);
}
}
@Override
public void doDeleteConsistencyGroup(StorageSystem storage, final URI consistencyGroupId,
String replicationGroupName, Boolean keepRGName, Boolean markInactive,
String sourceReplicationGroup, final TaskCompleter taskCompleter) throws DeviceControllerException {
doDeleteConsistencyGroup(storage, consistencyGroupId, replicationGroupName, keepRGName, markInactive, taskCompleter);
}
/*
* (non-Javadoc)
*
* @see
* com.emc.storageos.volumecontroller.AbstractBlockStorageDevice#doAddToConsistencyGroup(com.emc.storageos.db.client.model.StorageSystem
* , java.net.URI, java.util.List, com.emc.storageos.volumecontroller.TaskCompleter)
* Note - all block objects should be on the same storage pool
*/
@Override
public void doAddToConsistencyGroup(final StorageSystem storage,
final URI consistencyGroupId, String replicationGroupName, final List<URI> blockObjects,
final TaskCompleter taskCompleter) throws DeviceControllerException {
BlockConsistencyGroup consistencyGroup = _dbClient.queryObject(
BlockConsistencyGroup.class, consistencyGroupId);
try {
addVolumesToCG(storage, consistencyGroupId, blockObjects);
List<BlockObject> objectsToSave = new ArrayList<BlockObject>();
for (URI blockObjectURI : blockObjects) {
BlockObject blockObject = BlockObject.fetch(_dbClient,
blockObjectURI);
if (blockObject != null) {
blockObject.setConsistencyGroup(consistencyGroupId);
objectsToSave.add(blockObject);
}
}
if (!objectsToSave.isEmpty()) {
_dbClient.updateAndReindexObject(objectsToSave);
}
taskCompleter.ready(_dbClient);
} catch (DeviceControllerException e) {
// if there is no consistency group with the given name, set the
// operation to error
taskCompleter.error(_dbClient, e);
} catch (Exception e) {
// remove any references to the consistency group
List<BlockObject> objectsToSave = new ArrayList<BlockObject>();
for (URI blockObjectURI : blockObjects) {
BlockObject blockObject = BlockObject.fetch(_dbClient,
blockObjectURI);
if (blockObject != null) {
if (blockObject.getConsistencyGroup() != null) {
blockObject.setConsistencyGroup(NullColumnValueGetter.getNullURI());
}
objectsToSave.add(blockObject);
}
}
if (!objectsToSave.isEmpty()) {
_dbClient.persistObject(objectsToSave);
}
taskCompleter.error(_dbClient, DeviceControllerException.exceptions
.failedToAddMembersToConsistencyGroup(
consistencyGroup.getLabel(),
consistencyGroup.getCgNameOnStorageSystem(storage.getId()), e.getMessage()));
}
}
@Override
public void doRemoveFromConsistencyGroup(final StorageSystem storage,
final URI consistencyGroupId, final List<URI> blockObjects,
final TaskCompleter taskCompleter) throws DeviceControllerException {
BlockConsistencyGroup consistencyGroup = _dbClient.queryObject(
BlockConsistencyGroup.class, consistencyGroupId);
try {
// check if the consistency group already exists
String groupName = _helper
.getConsistencyGroupName(consistencyGroup, storage);
CIMObjectPath cgPath = _cimPath.getConsistencyGroupPath(storage,
groupName);
CIMInstance cgPathInstance = _helper.checkExists(storage, cgPath,
false, false);
if (cgPathInstance != null) {
String[] blockObjectIds = _helper.getBlockObjectNativeIds(blockObjects);
removeVolumesFromCG(storage, consistencyGroup, cgPath, blockObjectIds);
}
// remove any references to the consistency group
List<BlockObject> objectsToSave = new ArrayList<BlockObject>();
for (URI blockObjectURI : blockObjects) {
BlockObject blockObject = BlockObject.fetch(_dbClient,
blockObjectURI);
if (blockObject != null) {
if (blockObject.getConsistencyGroup() != null) {
blockObject.setConsistencyGroup(NullColumnValueGetter.getNullURI());
}
}
objectsToSave.add(blockObject);
}
_dbClient.persistObject(objectsToSave);
taskCompleter.ready(_dbClient);
} catch (DeviceControllerException e) {
taskCompleter.error(_dbClient, e);
} catch (Exception e) {
taskCompleter.error(_dbClient, DeviceControllerException.exceptions
.failedToRemoveMembersToConsistencyGroup(
consistencyGroup.getLabel(),
consistencyGroup.getCgNameOnStorageSystem(storage.getId()), e.getMessage()));
}
}
@Override
public void doWaitForSynchronized(final Class<? extends BlockObject> clazz,
final StorageSystem storageObj, final URI target,
final TaskCompleter completer) {
_log.info("START waitForSynchronized for {}", target);
CIMObjectPath path = IBMSmisConstants.NULL_IBM_CIM_OBJECT_PATH;
try {
if (!clazz.equals(Volume.class)) {
BlockObject targetObj = _dbClient.queryObject(clazz, target);
path = _cimPath.getBlockObjectPath(storageObj,
targetObj);
}
ControllerServiceImpl.enqueueJob(new QueueJob(
new SmisWaitForSynchronizedJob(clazz, path, storageObj
.getId(), completer)));
} catch (Exception e) {
_log.info("Problem making SMI-S call: " + e);
ServiceError serviceError = DeviceControllerException.errors
.jobFailed(e);
completer.error(_dbClient, serviceError);
}
}
@Override
public void doWaitForGroupSynchronized(StorageSystem storageObj, List<URI> target, TaskCompleter completer) {
throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
}
@Override
public Integer checkSyncProgress(final URI storage, final URI source,
final URI target) throws DeviceControllerException {
_log.info("checkSyncProgress for source: {} target: {}", source, target);
String percentSyncValue = null;
try {
StorageSystem storageSystem = _dbClient.queryObject(
StorageSystem.class, storage);
BlockObject targetObject = BlockObject.fetch(_dbClient, target);
CIMObjectPath syncObject = _cimPath.getSyncObject(storageSystem,
targetObject);
CIMInstance syncInstance = _helper.getInstance(storageSystem,
syncObject, false, false, SmisConstants.PS_PERCENT_SYNCED);
percentSyncValue = CIMPropertyFactory.getPropertyValue(
syncInstance, SmisConstants.CP_PERCENT_SYNCED);
if (_log.isDebugEnabled()) {
_log.debug("Got progress {}", percentSyncValue);
}
return Integer.parseInt(percentSyncValue);
} catch (Exception e) {
String msg = String.format(
"Failed to check synchronization progress for %s (%s)",
target, percentSyncValue);
_log.error(msg, e);
}
return null;
}
/**
* Method will remove the volume from the consistency group to which it
* currently belongs.
*
* @param storage
* [required] - StorageSystem object
* @param volume
* [required] - Volume object
*/
private void removeVolumeFromConsistencyGroup(final StorageSystem storage, BlockConsistencyGroup cg,
final Volume volume) throws Exception {
CloseableIterator<CIMObjectPath> assocVolNamesIter = null;
try {
String groupName = _helper.getConsistencyGroupName(volume, storage);
CIMObjectPath cgPath = _cimPath.getConsistencyGroupPath(storage,
groupName);
CIMInstance cgInstance = _helper.checkExists(storage, cgPath,
false, false);
if (cgInstance != null) {
boolean volumeIsInGroup = false;
assocVolNamesIter = _helper.getAssociatorNames(storage, cgPath,
null, SmisConstants.CIM_STORAGE_VOLUME, null, null); // TODO add association name
while (assocVolNamesIter.hasNext()) {
CIMObjectPath assocVolPath = assocVolNamesIter.next();
String deviceId = assocVolPath
.getKey(SmisConstants.CP_DEVICE_ID).getValue()
.toString();
if (deviceId.equalsIgnoreCase(volume.getNativeId())) {
volumeIsInGroup = true;
break;
}
}
if (volumeIsInGroup) {
removeVolumesFromCG(storage, cg, cgPath, new String[] { volume.getNativeId() });
} else {
_log.info(
"Volume {} is no longer in the replication group {}",
volume.getNativeId(), cgPath.toString());
}
} else {
_log.warn(
"The Consistency Group {} does not exist on the array.",
groupName);
}
} catch (Exception e) {
_log.error("Problem making SMI-S call: ", e);
throw e;
} finally {
if (assocVolNamesIter != null) {
assocVolNamesIter.close();
}
}
}
private synchronized void addVolumesToCG(StorageSystem storageSystem, URI consistencyGroupId, List<URI> volumeURIs) throws Exception {
BlockConsistencyGroup consistencyGroup = _dbClient.queryObject(BlockConsistencyGroup.class, consistencyGroupId);
if (null != consistencyGroup) {
String groupName = _helper.getConsistencyGroupName(consistencyGroup, storageSystem);
if (groupName.equals(EMPTY_CG_NAME)) {
// may also check if CG instance exists on array, or not, if not, re-create it here need to create CG group
// here with member volumes this will ensure the new CG is associated to right pool without member volumes,
// there is no way to control which pool the CG will be associated to
CIMArgument[] inArgs = _helper.getCreateReplicationGroupInputArguments(storageSystem, consistencyGroup.getLabel(),
volumeURIs);
CIMArgument[] outArgs = new CIMArgument[5];
_helper.callReplicationSvc(storageSystem, SmisConstants.CREATE_GROUP, inArgs, outArgs);
// grab the CG name from the instance ID and store it in the db
final CIMObjectPath cgPath = _cimPath.getCimObjectPathFromOutputArgs(outArgs, SmisConstants.CP_REPLICATION_GROUP);
final String deviceName = _helper.getReplicationGroupName(cgPath);
// the order of adding and removing system consistency group makes different somehow, removing before adding won't work
consistencyGroup.addSystemConsistencyGroup(storageSystem.getId().toString(), deviceName);
consistencyGroup.removeSystemConsistencyGroup(storageSystem.getId().toString(), EMPTY_CG_NAME);
_dbClient.updateObject(consistencyGroup);
} else {
// existing CG, add volumes to the CG
CIMObjectPath cgPath = _cimPath.getConsistencyGroupPath(storageSystem, groupName);
CIMInstance cgPathInstance = _helper.checkExists(storageSystem, cgPath, false, false);
// if there is no consistency group with the given name, set the operation to error
if (cgPathInstance == null) {
throw DeviceControllerException.exceptions.consistencyGroupNotFound(consistencyGroup.getLabel(),
consistencyGroup.getCgNameOnStorageSystem(storageSystem.getId()));
}
_helper.addVolumesToConsistencyGroup(storageSystem, new ArrayList<URI>(volumeURIs), cgPath);
}
}
}
private void removeVolumesFromCG(StorageSystem storage, BlockConsistencyGroup cg,
CIMObjectPath cgPath, String[] blockObjectIds) throws Exception {
CIMObjectPath[] volumePaths = _cimPath.getVolumePaths(storage, blockObjectIds);
@SuppressWarnings("rawtypes")
CIMArgument[] inArgs = null;
// get all the snapshot groups
CIMObjectPath[] syncObjectPaths = _helper.getGroupSyncObjectPaths(
storage, cgPath);
if (syncObjectPaths.length > 0) {
if (isForceSnapshotGroupRemoval) {
inArgs = _helper.getDeleteListSynchronizationInputArguments(
storage, syncObjectPaths);
// delete snapshot groups
_helper.callReplicationSvc(storage,
IBMSmisConstants.MODIFY_LIST_SYNCHRONIZATION, inArgs,
new CIMArgument[5]);
} else {
String instanceId = (String) cgPath.getKey(
SmisConstants.CP_INSTANCE_ID).getValue();
String cgName = _helper.getReplicationGroupName(cgPath);
throw DeviceControllerException.exceptions
.failedToRemoveMembersToConsistencyGroup(cgName,
instanceId, "Consistency group has snapshot(s)");
}
}
inArgs = _helper.getRemoveMembersInputArguments(cgPath, volumePaths);
Exception removeMembersException = null;
try {
// remove from consistency group
_helper.callReplicationSvc(storage, SmisConstants.REMOVE_MEMBERS,
inArgs, new CIMArgument[5]);
} catch (Exception e) {
_log.info("Exception on removeVolumesFromConsistencyGroup: " + e.getMessage());
removeMembersException = e;
}
Set<String> volumeSet = new HashSet<String>(Arrays.asList(blockObjectIds));
Set<String> members = null;
try {
members = _helper.getCGMembers(storage, cgPath, volumeSet);
} catch (Exception e) {
_log.info("Exception on getCGMembers: " + e.getMessage());
if (removeMembersException != null) {
throw removeMembersException;
} else {
throw e;
}
}
String groupName = _helper.getConsistencyGroupName(cg, storage);
boolean cgExists = true;
if (members == null) {
// no CG member on array side, it should have already been deleted
cgExists = false;
} else if (members.isEmpty()) {
// this shouldn't happen, delete CG
_log.info("Delete CG " + groupName);
inArgs = _helper.getDeleteReplicationGroupInputArguments(storage, cgPath);
_helper.callReplicationSvc(storage, IBMSmisConstants.DELETE_GROUP, inArgs, new CIMArgument[5]);
cgExists = false;
}
if (!cgExists) {
// now remove array association of the CG in ViPR
// the intention is that the CG can be re-used, and not restricted by previous pool
_log.info("CG is empty on array. Remove array association from the CG");
cg.removeSystemConsistencyGroup(storage.getId().toString(), groupName);
// clear the LOCAL type
StringSet types = cg.getTypes();
if (types != null) {
types.remove(Types.LOCAL.name());
cg.setTypes(types);
}
_dbClient.persistObject(cg);
}
}
@Override
public ExportMaskPolicy getExportMaskPolicy(StorageSystem storage,
ExportMask mask) {
// TODO Auto-generated method stub
return null;
}
/**
* {@inheritDoc}
*/
@Override
public Map<URI, List<Integer>> doFindHostHLUs(StorageSystem storage, Collection<URI> initiatorURIs) throws DeviceControllerException {
Map<URI, List<Integer>> initiatorToHLUMap = new HashMap<URI, List<Integer>>();
for (URI initiatorURI : initiatorURIs) {
List<Integer> initiatorHLUs = new ArrayList<Integer>();
initiatorToHLUMap.put(initiatorURI, initiatorHLUs);
Initiator initiator = _dbClient.queryObject(Initiator.class, initiatorURI);
final String normalizedPortName = Initiator.normalizePort(initiator.getInitiatorPort());
CloseableIterator<CIMInstance> scsiPCInstances = null;
CloseableIterator<CIMInstance> pcforseunitInstances = null;
try {
String query = String.format("Select * From %s Where ElementName=\"%s\"", IBMSmisConstants.CP_STORAGE_HARDWARE_ID,
normalizedPortName);
CIMObjectPath pcHwdIDPath = CimObjectPathCreator.createInstance(IBMSmisConstants.CP_STORAGE_HARDWARE_ID,
Constants.IBM_NAMESPACE, null);
List<CIMInstance> hwidInstances = _helper.executeQuery(storage, pcHwdIDPath, query, "WQL");
if (null != hwidInstances && !hwidInstances.isEmpty()) {
CIMObjectPath hwidObjectPath = hwidInstances.get(0).getObjectPath();
scsiPCInstances = _helper.getAssociatorInstances(storage, hwidObjectPath, null,
IBMSmisConstants.CP_SCSI_PROTOCOL_CONTROLLER, IBMSmisConstants.CP_COLLECTION, IBMSmisConstants.CP_MEMBER,
SmisConstants.PS_ELEMENT_NAME);
while (null != scsiPCInstances && scsiPCInstances.hasNext()) {
CIMInstance scsiPCInstance = scsiPCInstances.next();
CIMObjectPath scsiPCObjectPath = scsiPCInstance.getObjectPath();
pcforseunitInstances = _helper.getReferenceInstances(storage, scsiPCObjectPath,
IBMSmisConstants.CP_PROTOCOLCONTROLLER_FOR_SEUNIT, null, new String[] { IBMSmisConstants.DEVICE_NUMBER });
while (null != pcforseunitInstances && pcforseunitInstances.hasNext()) {
CIMInstance instance = pcforseunitInstances.next();
final String deviceNumber = CIMPropertyFactory.getPropertyValue(instance, IBMSmisConstants.DEVICE_NUMBER);
if (null != deviceNumber && !deviceNumber.isEmpty()) {
initiatorHLUs.add(Integer.parseInt(deviceNumber));
}
}
_log.info("HLU list for Initiator Port {} : {}", normalizedPortName, initiatorHLUs);
}
}
} catch (WBEMException e) {
DeviceControllerException.exceptions.smis.hluRetrievalFailed("Error occured during retrieval of HLUs for a Host", e);
} finally {
if (scsiPCInstances != null) {
scsiPCInstances.close();
}
if (pcforseunitInstances != null) {
pcforseunitInstances.close();
}
}
}
return initiatorToHLUMap;
}
}