/*
* Copyright (c) 2008-2014 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.impl.smis.ibm.xiv;
import java.net.URI;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
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 javax.cim.CIMArgument;
import javax.cim.CIMInstance;
import javax.cim.CIMObjectPath;
import javax.cim.CIMProperty;
import javax.wbem.CloseableIterator;
import javax.wbem.WBEMException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.emc.storageos.cimadapter.connections.cim.CimConnection;
import com.emc.storageos.cimadapter.connections.cim.CimObjectPathCreator;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.URIUtil;
import com.emc.storageos.db.client.constraint.AlternateIdConstraint;
import com.emc.storageos.db.client.constraint.ContainmentConstraint;
import com.emc.storageos.db.client.constraint.URIQueryResultList;
import com.emc.storageos.db.client.model.ExportGroup;
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.StoragePort;
import com.emc.storageos.db.client.model.StorageSystem;
import com.emc.storageos.db.client.model.StringMap;
import com.emc.storageos.db.client.model.StringSet;
import com.emc.storageos.db.client.model.VirtualPool;
import com.emc.storageos.db.client.util.CustomQueryUtility;
import com.emc.storageos.db.client.util.NullColumnValueGetter;
import com.emc.storageos.db.client.util.WWNUtility;
import com.emc.storageos.exceptions.DeviceControllerErrors;
import com.emc.storageos.exceptions.DeviceControllerException;
import com.emc.storageos.networkcontroller.impl.NetworkDeviceController;
import com.emc.storageos.plugins.common.Constants;
import com.emc.storageos.svcs.errorhandling.model.ServiceError;
import com.emc.storageos.util.ExportUtils;
import com.emc.storageos.volumecontroller.TaskCompleter;
import com.emc.storageos.volumecontroller.impl.VolumeURIHLU;
import com.emc.storageos.volumecontroller.impl.smis.CIMPropertyFactory;
import com.emc.storageos.volumecontroller.impl.smis.ExportMaskOperations;
import com.emc.storageos.volumecontroller.impl.smis.ExportMaskOperationsHelper;
import com.emc.storageos.volumecontroller.impl.smis.SmisConstants;
import com.emc.storageos.volumecontroller.impl.smis.SmisException;
import com.emc.storageos.volumecontroller.impl.smis.ibm.IBMCIMObjectPathFactory;
import com.emc.storageos.volumecontroller.impl.smis.ibm.IBMSmisConstants;
import com.emc.storageos.volumecontroller.impl.utils.ExportMaskUtils;
import com.emc.storageos.volumecontroller.impl.xiv.XIVRestOperationsHelper;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
/*
* (non-Javadoc)
* Handle all export use cases, like
* create an ExportMask
* delete an ExportMask
* add volumes to an ExportMask
* remove Volumes from an ExportMask
* add Initiators to an ExportMask
* remove Initiators from an ExportMask
* find ExportMasks by initiators
* refresh an ExportMask
*
* StorageHardwareID - initiator port
* SystemSpecificCollection - host
*/
public class XIVExportOperations implements ExportMaskOperations {
private static Logger _log = LoggerFactory
.getLogger(XIVExportOperations.class);
private XIVSmisCommandHelper _helper;
private DbClient _dbClient;
private IBMCIMObjectPathFactory _cimPath;
private XIVRestOperationsHelper _restAPIHelper;
@Autowired
private NetworkDeviceController _networkDeviceController;
public void setCimObjectPathFactory(
IBMCIMObjectPathFactory cimObjectPathFactory) {
_cimPath = cimObjectPathFactory;
}
public void setSmisCommandHelper(XIVSmisCommandHelper helper) {
_helper = helper;
}
public void setDbClient(DbClient dbClient) {
_dbClient = dbClient;
}
public void setRestOperationsHelper(XIVRestOperationsHelper helper) {
_restAPIHelper = helper;
}
private void createSMISExportMask(StorageSystem storage, URI exportMaskURI,
VolumeURIHLU[] volumeURIHLUs, List<URI> targetURIList,
List<Initiator> initiatorList, TaskCompleter taskCompleter)
throws DeviceControllerException {
_log.info("{} createExportMask START...", storage.getLabel());
try {
_log.info("createExportMask: Export mask id: {}", exportMaskURI);
_log.info("createExportMask: volume-HLU pairs: {}", Joiner.on(',').join(volumeURIHLUs));
_log.info("createExportMask: initiators: {}", Joiner.on(',').join(initiatorList));
_log.info("createExportMask: assignments: {}", Joiner.on(',').join(targetURIList));
CIMInstance controllerInst = null;
boolean createdBySystem = true;
Map<String, Initiator> initiatorMap = _helper.getInitiatorMap(initiatorList);
String[] initiatorNames = initiatorMap.keySet().toArray(new String[] {});
List<Initiator> userAddedInitiators = new ArrayList<Initiator>();
Map<String, CIMObjectPath> existingHwStorageIds = getStorageHardwareIds(storage);
// note - the initiator list maybe just a subset of all initiators on a host, need to
// get all the initiators from the host, and check here
// a special case is that there is a host on array side with i1 and i2,
// while there is a host with initiator i2 and i3 on ViPR side,
// we will not be able to match the two hosts if there is common initiator(s)
// if an HBA get moved from one host to another, it need to be removed on array side manually
List<Initiator> allInitiators;
Host host = null;
Initiator firstInitiator = initiatorList.get(0);
String label;
if (initiatorList.get(0).getHost() != null) {
allInitiators = CustomQueryUtility
.queryActiveResourcesByConstraint(_dbClient,
Initiator.class, ContainmentConstraint.Factory
.getContainedObjectsConstraint(firstInitiator.getHost(),
Initiator.class, "host"));
host = _dbClient.queryObject(Host.class, firstInitiator.getHost());
label = host.getLabel();
} else {
allInitiators = CustomQueryUtility
.queryActiveResourcesByAltId(_dbClient, Initiator.class, "hostname", firstInitiator.getHostName());
label = firstInitiator.getHostName();
}
for (Initiator initiator : allInitiators) {
String normalizedPortName = Initiator.normalizePort(initiator
.getInitiatorPort());
CIMObjectPath initiatorPath = existingHwStorageIds.get(normalizedPortName);
if (initiatorPath != null) {
_log.info(String.format("Initiator %s already exists",
initiator.getInitiatorPort()));
createdBySystem = false;
// get controller instance
controllerInst = getSCSIProtocolControllerInstanceByHwId(storage, initiatorPath);
if (controllerInst == null) {
_log.debug("createExportMask failed. No protocol controller created.");
ServiceError error = DeviceControllerErrors.smis
.noProtocolControllerCreated();
taskCompleter.error(_dbClient, error);
_log.info("{} createExportMask END...", storage.getLabel());
return;
}
// get initiators
Map<String, CIMObjectPath> initiatorPortPaths = _helper
.getInitiatorsFromScsiProtocolController(storage, controllerInst.getObjectPath());
Set<String> existingInitiatorPorts = initiatorPortPaths.keySet();
// check if initiators need to be added
List<String> initiatorsToAdd = new ArrayList<String>();
for (String port : initiatorNames) {
if (!existingInitiatorPorts.contains(port)) {
initiatorsToAdd.add(port);
userAddedInitiators.add(initiatorMap.get(port));
}
}
if (!initiatorsToAdd.isEmpty()) {
// add initiator to host on array side
CIMObjectPath specificCollectionPath = getSystemSpecificCollectionPathByHwId(storage, initiatorPath);
CIMArgument[] outArgs = new CIMArgument[5];
_helper.addHardwareIDsToCollection(storage, specificCollectionPath, initiatorsToAdd.toArray(new String[] {}),
outArgs);
if (outArgs[0] == null) {
Set<String> hwIds = hasHwIdsInCollection(storage, specificCollectionPath);
if (!hwIds.containsAll(initiatorsToAdd)) {
throw new Exception("Failed to add initiator: " + Joiner.on(',').join(initiatorsToAdd));
}
}
}
// don't care other initiators, they should belong to the
// same host/controller on both ViPR and array sides
break;
}
}
// no matched initiator on array side, now try to find host with the given name
if (controllerInst == null) {
String query = String.format(
"Select * From %s Where ElementName=\"%s\"",
IBMSmisConstants.CP_SYSTEM_SPECIFIC_COLLECTION, label);
CIMObjectPath hostPath = CimObjectPathCreator.createInstance(
IBMSmisConstants.CP_SYSTEM_SPECIFIC_COLLECTION,
Constants.IBM_NAMESPACE, null);
List<CIMInstance> hostInstances = _helper.executeQuery(storage,
hostPath, query, "WQL");
if (!hostInstances.isEmpty()) {
CIMObjectPath specificCollectionPath = hostInstances.get(0).getObjectPath();
if (!hasHwIdInCollection(storage, specificCollectionPath)) {
createdBySystem = false;
userAddedInitiators = initiatorList;
// re-use the empty host
CIMArgument[] outArgs = new CIMArgument[5];
_helper.addHardwareIDsToCollection(storage, specificCollectionPath, initiatorNames, outArgs);
if (outArgs[0] == null) {
Set<String> hwIds = hasHwIdsInCollection(storage, specificCollectionPath);
if (!hwIds.containsAll(new ArrayList<String>(Arrays.asList(initiatorNames)))) {
throw new Exception("Failed to add initiator: " + Joiner.on(',').join(initiatorNames));
}
}
controllerInst = getSCSIProtocolControllerInstanceByIdCollection(storage, specificCollectionPath);
if (controllerInst == null) {
_log.debug("createExportMask failed. No protocol controller created.");
ServiceError error = DeviceControllerErrors.smis
.noProtocolControllerCreated();
taskCompleter.error(_dbClient, error);
_log.info("{} createExportMask END...", storage.getLabel());
return;
}
}
}
}
// create new protocol controller
if (controllerInst == null) {
// create host first so that the desired host label could be used
CIMObjectPath sysSpecificCollectionPath = getSystemSpecificCollectionPath(
storage, label, initiatorNames);
if (sysSpecificCollectionPath == null) {
_log.debug("createExportMask failed. No host created.");
ServiceError error = DeviceControllerErrors.smis
.noProtocolControllerCreated();
taskCompleter.error(_dbClient, error);
_log.info("{} createExportMask END...", storage.getLabel());
return;
}
controllerInst = getSCSIProtocolControllerInstanceByIdCollection(
storage, sysSpecificCollectionPath);
}
if (controllerInst != null) {
String elementName = CIMPropertyFactory.getPropertyValue(controllerInst, SmisConstants.CP_ELEMENT_NAME);
// set host tag is needed
if (host != null) {
if (label.equals(elementName)) {
_helper.unsetTag(host, storage.getSerialNumber());
} else {
_helper.setTag(host, storage.getSerialNumber(), elementName);
}
}
CIMObjectPath controller = controllerInst.getObjectPath();
ExportMask exportMask = _dbClient.queryObject(ExportMask.class,
exportMaskURI);
if (!createdBySystem) {
exportMask.setCreatedBySystem(createdBySystem);
exportMask.addToUserCreatedInitiators(userAddedInitiators);
}
exportMask.setMaskName(elementName); // SCSIProtocolController.ElementName
// is the same as
// SystemSpecificCollection.ElementName
exportMask.setLabel(elementName);
CIMProperty<String> deviceId = (CIMProperty<String>) controller
.getKey(IBMSmisConstants.CP_DEVICE_ID);
exportMask.setNativeId(deviceId.getValue());
_dbClient.persistObject(exportMask);
CIMArgument[] inArgs = _helper.getExposePathsInputArguments(
volumeURIHLUs, null, controller);
CIMArgument[] outArgs = new CIMArgument[5];
// don't care if the volumes/initiators have already been in the
// mask
_helper.invokeMethod(storage,
_cimPath.getControllerConfigSvcPath(storage),
IBMSmisConstants.EXPOSE_PATHS, inArgs, outArgs);
CIMObjectPath[] protocolControllers = _cimPath
.getProtocolControllersFromOutputArgs(outArgs);
CIMObjectPath protocolController = protocolControllers[0];
// for debug only
if (_log.isDebugEnabled()) {
List<String> targetEndpoints = getTargetEndpoints(
protocolController, storage);
_log.debug(String.format(
"ProtocolController %s with target ports: %s",
protocolController.getObjectName(), Joiner.on(',')
.join(targetEndpoints)));
}
CimConnection cimConnection = _helper.getConnection(storage);
// Call populateDeviceNumberFromProtocolControllers only after
// initiators
// have been added. HLU's will not be reported till the Device
// is Host visible
ExportMaskOperationsHelper
.populateDeviceNumberFromProtocolControllers(_dbClient,
cimConnection, exportMaskURI, volumeURIHLUs,
protocolControllers, taskCompleter);
taskCompleter.ready(_dbClient);
} else {
_log.debug("createExportMask failed. No protocol controller created.");
ServiceError error = DeviceControllerErrors.smis
.noProtocolControllerCreated();
taskCompleter.error(_dbClient, error);
}
} catch (Exception e) {
_log.error("Unexpected error: createExportMask failed.", e);
ServiceError error = DeviceControllerErrors.smis.methodFailed(
"createExportMask", e.getMessage());
taskCompleter.error(_dbClient, error);
}
_log.info("{} createExportMask END...", storage.getLabel());
}
private void deleteSMISExportMask(StorageSystem storage, URI exportMaskURI,
List<URI> volumeURIList, List<URI> targetURIList,
List<Initiator> initiatorList, TaskCompleter taskCompleter)
throws DeviceControllerException {
_log.info("{} deleteExportMask START...", storage.getLabel());
try {
_log.info("Export mask id: {}", exportMaskURI);
// TODO DUPP:
// 1. Get the volume, targets, and initiators from the caller
// 2. Ensure (if possible) that those are the only volumes/initiators impacted by delete mask
if (volumeURIList != null) {
_log.info("deleteExportMask: volumes: {}", Joiner.on(',').join(volumeURIList));
}
if (targetURIList != null) {
_log.info("deleteExportMask: assignments: {}", Joiner.on(',').join(targetURIList));
}
if (initiatorList != null) {
_log.info("deleteExportMask: initiators: {}", Joiner.on(',').join(initiatorList));
}
ExportMask exportMask = _dbClient.queryObject(ExportMask.class,
exportMaskURI);
StringSet initiators = exportMask.getInitiators();
Host host = null;
if (initiators != null) {
Iterator<String> itr = initiators.iterator();
if (itr.hasNext()) {
Initiator initiator = _dbClient.queryObject(Initiator.class, URI.create(itr.next()));
if (initiator.getHost() != null) {
host = _dbClient.queryObject(Host.class, initiator.getHost());
}
}
}
String nativeId = exportMask.getNativeId();
if (Strings.isNullOrEmpty(nativeId)) {
_log.warn(String
.format("ExportMask %s does not have a nativeID, "
+ "indicating that this export may not have been created "
+ "successfully. Marking the delete operation ready.",
exportMaskURI.toString()));
} else if (!exportMask.getCreatedBySystem()) {
_log.info("Export mask {} is not created by system", exportMask.getLabel());
// shouldn't remove the mask
// check user added volumes, remove them from mask
// check user added initiators, remove them from mask
String[] volumesToRemove = null;
StringMap volumeMap = exportMask.getUserAddedVolumes();
if (volumeMap != null && !volumeMap.isEmpty()) {
volumesToRemove = volumeMap.keySet().toArray(
new String[] {});
}
String[] initiatorsToRemove = null;
StringMap initiatorMap = exportMask.getUserAddedInitiators();
if (initiatorMap != null && !initiatorMap.isEmpty()) {
initiatorsToRemove = initiatorMap.keySet().toArray(
new String[] {});
}
CIMArgument[] inArgs = _helper.getHidePathsInputArguments(
storage, exportMask, volumesToRemove,
initiatorsToRemove);
_helper.invokeMethod(storage,
_cimPath.getControllerConfigSvcPath(storage),
IBMSmisConstants.HIDE_PATHS, inArgs);
} else {
CIMObjectPath protocolController = _cimPath
.getSCSIProtocolControllerPath(storage, nativeId);
CIMInstance instance = _helper.checkExists(storage,
protocolController, true, true);
if (instance != null) {
CIMArgument[] inArgs = _helper
.getDeleteProtocolControllerInputArguments(protocolController);
_helper.invokeMethod(storage,
_cimPath.getControllerConfigSvcPath(storage),
IBMSmisConstants.DELETE_PROTOCOL_CONTROLLER, inArgs);
if (host == null) {
// get hosts from initiators
Map<String, CIMObjectPath> initiatorPortPaths = _helper
.getInitiatorsFromScsiProtocolController(storage, instance.getObjectPath());
Set<String> initiatorPorts = initiatorPortPaths.keySet();
for (String initiatorPort : initiatorPorts) {
Initiator initiator = ExportUtils.getInitiator(
WWNUtility.getWWNWithColons(initiatorPort),
_dbClient);
if (initiator != null && initiator.getHost() != null) {
host = _dbClient.queryObject(Host.class, initiator.getHost());
break;
}
}
}
}
}
// Perform post-mask-delete cleanup steps
if (host != null) {
_helper.unsetTag(host, storage.getSerialNumber());
}
ExportUtils.cleanupAssociatedMaskResources(_dbClient, exportMask);
exportMask.setMaskName(NullColumnValueGetter.getNullURI().toString());
exportMask.setLabel(NullColumnValueGetter.getNullURI().toString());
exportMask.setNativeId(NullColumnValueGetter.getNullURI().toString());
exportMask.setResource(NullColumnValueGetter.getNullURI().toString());
_dbClient.updateObject(exportMask);
taskCompleter.ready(_dbClient);
} catch (Exception e) {
_log.error("Unexpected error: deleteExportMask failed.", e);
ServiceError error = DeviceControllerErrors.smis.methodFailed(
"deleteExportMask", e.getMessage());
taskCompleter.error(_dbClient, error);
}
_log.info("{} deleteExportMask END...", storage.getLabel());
}
private void addVolumesUsingSMIS(StorageSystem storage, URI exportMaskURI,
VolumeURIHLU[] volumeURIHLUs, List<Initiator> initiatorList, TaskCompleter taskCompleter)
throws DeviceControllerException {
_log.info("{} addVolumes START...", storage.getLabel());
try {
_log.info("addVolumes: Export mask id: {}", exportMaskURI);
_log.info("addVolumes: volume-HLU pairs: {}", Joiner.on(',').join(volumeURIHLUs));
// TODO DUPP:
// 1. Get initiator list from the caller above for completeness
// 2. If possible, log if these volumes are going to be exported to additional initiators than what the
// request asked for
if (initiatorList != null) {
_log.info("addVolumes: initiators impacted: {}", Joiner.on(',').join(initiatorList));
}
CIMArgument[] inArgs = _helper.getExposePathsInputArguments(
storage, exportMaskURI, volumeURIHLUs, null);
CIMArgument[] outArgs = new CIMArgument[5];
_helper.invokeMethod(storage,
_cimPath.getControllerConfigSvcPath(storage),
IBMSmisConstants.EXPOSE_PATHS, inArgs, outArgs);
CIMObjectPath[] protocolControllers = _cimPath
.getProtocolControllersFromOutputArgs(outArgs);
CimConnection cimConnection = _helper.getConnection(storage);
ExportMaskOperationsHelper
.populateDeviceNumberFromProtocolControllers(_dbClient,
cimConnection, exportMaskURI, volumeURIHLUs,
protocolControllers, taskCompleter);
taskCompleter.ready(_dbClient);
} catch (Exception e) {
_log.error("Unexpected error: addVolumes failed.", e);
ServiceError error = DeviceControllerErrors.smis.methodFailed(
"addVolumes", e.getMessage());
taskCompleter.error(_dbClient, error);
}
_log.info("{} addVolumes END...", storage.getLabel());
}
public void removeVolumesUsingSMIS(StorageSystem storage, URI exportMaskURI,
List<URI> volumeURIList, List<Initiator> initiatorList, TaskCompleter taskCompleter)
throws DeviceControllerException {
_log.info("{} removeVolumes START...", storage.getLabel());
try {
_log.info("removeVolumes: Export mask id: {}", exportMaskURI);
_log.info("removeVolumes: volumes: {}", Joiner.on(',').join(volumeURIList));
// TODO DUPP:
// 1. Get initiator list from the caller
// 2. Verify that the initiators are the ONLY ones impacted by this remove volumes, otherwise fail.
if (initiatorList != null) {
_log.info("removeVolumes: impacted initiators: {}", Joiner.on(",").join(initiatorList));
}
CIMArgument[] inArgs = _helper.getHidePathsInputArguments(storage,
exportMaskURI, volumeURIList, null);
_helper.invokeMethod(storage,
_cimPath.getControllerConfigSvcPath(storage), IBMSmisConstants.HIDE_PATHS,
inArgs);
taskCompleter.ready(_dbClient);
} catch (Exception e) {
_log.error("Unexpected error: removeVolumes failed.", e);
ServiceError error = DeviceControllerErrors.smis.methodFailed(
"removeVolumes", e.getMessage());
taskCompleter.error(_dbClient, error);
}
_log.info("{} removeVolumes END...", storage.getLabel());
}
private void addInitiatorsUsingSMIS(StorageSystem storage, URI exportMaskURI,
List<URI> volumeURIs, List<Initiator> initiatorList, List<URI> targets,
TaskCompleter taskCompleter) throws DeviceControllerException {
_log.info("{} addInitiator START...", storage.getLabel());
try {
_log.info("addInitiators: Export mask id: {}", exportMaskURI);
// TODO DUPP:
// 1. Get the impacted volumes from the caller
// 2. Log any other volumes that are being exposed to the initiator
if (volumeURIs != null) {
_log.info("addInitiators: volumes : {}", Joiner.on(',').join(volumeURIs));
}
_log.info("addInitiators: initiators : {}", Joiner.on(',').join(initiatorList));
_log.info("addInitiators: targets : {}", Joiner.on(",").join(targets));
CIMArgument[] inArgs = _helper.getExposePathsInputArguments(
storage, exportMaskURI, null, initiatorList);
_helper.invokeMethod(storage,
_cimPath.getControllerConfigSvcPath(storage),
IBMSmisConstants.EXPOSE_PATHS, inArgs);
taskCompleter.ready(_dbClient);
} catch (Exception e) {
_log.error("Unexpected error: addInitiators failed.", e);
ServiceError error = DeviceControllerErrors.smis.methodFailed(
"addInitiators", e.getMessage());
taskCompleter.error(_dbClient, error);
}
_log.info("{} addInitiators END...", storage.getLabel());
}
// TOD -test
private void removeInitiatorsUsingSMIS(StorageSystem storage, URI exportMaskURI,
List<URI> volumeURIList, List<Initiator> initiatorList, List<URI> targets,
TaskCompleter taskCompleter) throws DeviceControllerException {
_log.info("{} removeInitiators START...", storage.getLabel());
try {
_log.info("removeInitiators: Export mask id: {}", exportMaskURI);
// TODO DUPP:
// 1. Get the impacted volumes from the caller
// 2. If any other volumes are impacted by removing this initiator, fail the operation
if (volumeURIList != null) {
_log.info("removeInitiators: volumes : {}", Joiner.on(',').join(volumeURIList));
}
_log.info("removeInitiators: initiators : {}", Joiner.on(',').join(initiatorList));
_log.info("removeInitiators: targets : {}", Joiner.on(',').join(targets));
if (initiatorList != null && !initiatorList.isEmpty()) {
ExportMask exportMask = _dbClient.queryObject(ExportMask.class,
exportMaskURI);
CIMObjectPath controllerPath = _cimPath
.getSCSIProtocolControllerPath(storage,
exportMask.getNativeId());
if (controllerPath != null) {
Map<String, CIMObjectPath> hwIdPaths = _helper
.getInitiatorsFromScsiProtocolController(storage,
controllerPath);
CIMObjectPath hwIdManagementSvc = _cimPath
.getStorageHardwareIDManagementService(storage);
String[] initiatorNames = _helper.getInitiatorNames(initiatorList);
for (String initiator : initiatorNames) {
CIMObjectPath hwIdPath = hwIdPaths.get(initiator);
if (hwIdPath != null) {
try {
CIMArgument[] deleteHwIdIn = _helper
.getDeleteStorageHardwareIDInputArgs(storage, hwIdPath);
_helper.invokeMethod(storage, hwIdManagementSvc,
SmisConstants.DELETE_STORAGE_HARDWARE_ID, deleteHwIdIn);
} catch (WBEMException e) {
_log.error("deleteStorageHWIDs -- WBEMException: ", e);
} catch (Exception e) {
_log.error("deleteStorageHWIDs -- Exception: " + e);
}
} else {
_log.info("Initiator {} is not on array", initiator);
}
}
CIMObjectPath idCollectionPath = getIdCollectionBySCSIProtocolController(
storage, controllerPath);
if (!hasHwIdInCollection(storage, idCollectionPath)) {
// update host label
Host host = _dbClient.queryObject(Host.class,
initiatorList.get(0).getHost());
_helper.unsetTag(host, storage.getSerialNumber());
}
} else {
_log.error("Protocol controller is null");
ServiceError error = DeviceControllerErrors.smis.noProtocolControllerCreated();
taskCompleter.error(_dbClient, error);
return;
}
}
taskCompleter.ready(_dbClient);
} catch (Exception e) {
_log.error("Unexpected error: removeInitiators failed.", e);
ServiceError error = DeviceControllerErrors.smis.methodFailed(
"removeInitiators", e.getMessage());
taskCompleter.error(_dbClient, error);
}
_log.info("{} removeInitiators END...", storage.getLabel());
}
/**
* This call can be used to look up the passed in initiator/port names and
* find (if any) to which export masks they belong on the 'storage' array.
*
*
* @param storage
* [in] - StorageSystem object representing the array
* @param initiatorNames
* [in] - normalized Port identifiers (WWPN or iSCSI name) (all initiators of all hosts involved)
* @param mustHaveAllPorts
* [in] NOT APPLICABLE FOR XIV
* @return Map of port name to Set of ExportMask URIs
*/
private Map<String, Set<URI>> findSMISExportMasks(StorageSystem storage,
List<String> initiatorNames, boolean mustHaveAllPorts) {
long startTime = System.currentTimeMillis();
Map<String, Set<URI>> matchingMasks = new HashMap<String, Set<URI>>();
CloseableIterator<CIMInstance> lunMaskingIter = null;
try {
StringBuilder builder = new StringBuilder();
lunMaskingIter = _helper.getSCSIProtocolControllers(storage);
while (lunMaskingIter.hasNext()) {
CIMInstance instance = lunMaskingIter.next();
String name = CIMPropertyFactory.getPropertyValue(instance,
SmisConstants.CP_NAME);
String deviceId = CIMPropertyFactory.getPropertyValue(instance,
SmisConstants.CP_DEVICE_ID);
// Get initiators for the masking instance
CIMObjectPath controllerPath = instance.getObjectPath();
Map<String, CIMObjectPath> initiatorPortPaths = _helper
.getInitiatorsFromScsiProtocolController(storage, controllerPath);
Set<String> initiatorPorts = initiatorPortPaths.keySet();
// Find out if the port is in this masking container
List<String> matchingInitiators = new ArrayList<String>();
for (String port : initiatorNames) {
if (initiatorPorts.contains(port)) {
matchingInitiators.add(port);
}
}
builder.append(String.format("XM:%s I:{%s}%n", name, Joiner.on(',').join(initiatorPorts)));
if (!matchingInitiators.isEmpty()) {
// Look up ExportMask by deviceId/name and storage URI
boolean foundMaskInDb = false;
ExportMask exportMask = null;
URIQueryResultList uriQueryList = new URIQueryResultList();
_dbClient.queryByConstraint(AlternateIdConstraint.Factory
.getExportMaskByNameConstraint(name), uriQueryList);
while (uriQueryList.iterator().hasNext()) {
URI uri = uriQueryList.iterator().next();
exportMask = _dbClient.queryObject(ExportMask.class,
uri);
if (exportMask != null
&& !exportMask.getInactive()
&& exportMask.getStorageDevice().equals(
storage.getId())) {
foundMaskInDb = true;
// We're expecting there to be only one export mask
// of a
// given name for any storage array.
break;
}
}
// If there was no export mask found in the database,
// then create a new one
if (!foundMaskInDb) {
exportMask = new ExportMask();
exportMask.setLabel(name);
exportMask.setMaskName(name);
exportMask.setNativeId(deviceId);
exportMask.setStorageDevice(storage.getId());
exportMask.setId(URIUtil.createId(ExportMask.class));
exportMask.setCreatedBySystem(false);
// Grab the storage ports that have been allocated for this existing mask
// the list will be empty if there is no real connectivity between the host and the array
List<String> storagePorts = _helper
.getStoragePortsFromScsiProtocolController(
storage, controllerPath);
List<String> storagePortURIs = storagePortNamesToURIs(storagePorts);
if (storagePortURIs.isEmpty()) {
_log.info("No storage port in the mask " + name);
} else {
exportMask.setStoragePorts(storagePortURIs);
builder.append(String.format(" ----> SP { %s }\n"
+ " URI{ %s }\n",
Joiner.on(',').join(storagePorts),
Joiner.on(',').join(storagePortURIs)));
}
}
// Get volumes for the masking instance
Map<String, Integer> volumeWWNs = _helper
.getVolumesFromScsiProtocolController(storage, controllerPath);
builder.append(String.format("XM:%s V:{%s}%n", name, Joiner.on(',').join(volumeWWNs.keySet())));
// Update the tracking containers
exportMask.addToExistingVolumesIfAbsent(volumeWWNs);
exportMask
.addToExistingInitiatorsIfAbsent(matchingInitiators);
builder.append(String.format(
"XM %s is matching. " + "EI: { %s }, EV: { %s }%n",
name,
Joiner.on(',').join(
exportMask.getExistingInitiators()),
Joiner.on(',').join(
exportMask.getExistingVolumes().keySet())));
if (foundMaskInDb) {
ExportMaskUtils.sanitizeExportMaskContainers(_dbClient, exportMask);
_dbClient.updateObject(exportMask);
} else {
_dbClient.createObject(exportMask);
}
// update hosts
Initiator initiator = ExportUtils.getInitiator(Initiator.toPortNetworkId(matchingInitiators.get(0)), _dbClient);
if (null != initiator && null != initiator.getHost()) {
Host host = _dbClient.queryObject(Host.class, initiator.getHost());
String label = host.getLabel();
if (label.equals(name)) {
_helper.unsetTag(host, storage.getSerialNumber());
} else {
_helper.setTag(host, storage.getSerialNumber(), name);
}
}
for (String it : matchingInitiators) {
Set<URI> maskURIs = matchingMasks.get(it);
if (maskURIs == null) {
maskURIs = new HashSet<URI>();
matchingMasks.put(it, maskURIs);
}
maskURIs.add(exportMask.getId());
}
}
}
_log.info(builder.toString());
} catch (Exception e) {
String msg = "Error when attempting to query LUN masking information: "
+ e.getMessage();
_log.error(
MessageFormat
.format("Encountered an SMIS error when attempting to query existing exports: {0}",
msg),
e);
throw SmisException.exceptions.queryExistingMasksFailure(msg, e);
} finally {
if (lunMaskingIter != null) {
lunMaskingIter.close();
}
long totalTime = System.currentTimeMillis() - startTime;
_log.info(String.format("findExportMasks took %f seconds", (double) totalTime / (double) 1000));
}
return matchingMasks;
}
@Override
public Set<Integer> findHLUsForInitiators(StorageSystem storage, List<String> initiatorNames, boolean mustHaveAllPorts) {
// TODO Auto-generated method stub
return null;
}
private ExportMask refreshSMISExportMask(StorageSystem storage, ExportMask mask) {
try {
CIMInstance instance = _helper.getSCSIProtocolController(storage,
mask);
if (instance != null) {
StringBuilder builder = new StringBuilder();
String name = CIMPropertyFactory.getPropertyValue(instance,
SmisConstants.CP_NAME);
// Get volumes and initiators for the masking instance
CIMObjectPath controllerPath = instance.getObjectPath();
Map<String, Integer> discoveredVolumes = _helper
.getVolumesFromScsiProtocolController(storage, controllerPath);
Map<String, CIMObjectPath> discoveredPortPaths = _helper
.getInitiatorsFromScsiProtocolController(storage, instance.getObjectPath());
Set<String> discoveredPorts = discoveredPortPaths.keySet();
Set existingInitiators = (mask.getExistingInitiators() != null) ? mask
.getExistingInitiators() : Collections.emptySet();
Set existingVolumes = (mask.getExistingVolumes() != null) ? mask
.getExistingVolumes().keySet() : Collections.emptySet();
builder.append(String.format("%nXM object: %s I{%s} V:{%s}%n",
name, Joiner.on(',').join(existingInitiators), Joiner
.on(',').join(existingVolumes)));
builder.append(String.format(
"XM discovered: %s I:{%s} V:{%s}%n", name,
Joiner.on(',').join(discoveredPorts), Joiner.on(',')
.join(discoveredVolumes.keySet())));
// Check the initiators and update the lists as necessary
boolean addInitiators = false;
List<String> initiatorsToAdd = new ArrayList<String>();
for (String port : discoveredPorts) {
String normalizedPort = Initiator.normalizePort(port);
if (!mask.hasExistingInitiator(normalizedPort)
&& !mask.hasUserInitiator(normalizedPort)) {
initiatorsToAdd.add(normalizedPort);
addInitiators = true;
}
}
boolean removeInitiators = false;
List<String> initiatorsToRemove = new ArrayList<String>();
if (mask.getExistingInitiators() != null
&& !mask.getExistingInitiators().isEmpty()) {
initiatorsToRemove.addAll(mask.getExistingInitiators());
initiatorsToRemove.removeAll(discoveredPorts);
removeInitiators = !initiatorsToRemove.isEmpty();
}
// Check the volumes and update the lists as necessary
Map<String, Integer> volumesToAdd = ExportMaskUtils.diffAndFindNewVolumes(mask, discoveredVolumes);
boolean addVolumes = !volumesToAdd.isEmpty();
boolean removeVolumes = false;
List<String> volumesToRemove = new ArrayList<String>();
if (mask.getExistingVolumes() != null
&& !mask.getExistingVolumes().isEmpty()) {
volumesToRemove.addAll(mask.getExistingVolumes().keySet());
volumesToRemove.removeAll(discoveredVolumes.keySet());
removeVolumes = !volumesToRemove.isEmpty();
}
boolean changeName = false;
if (!mask.getMaskName().equals(name)) {
changeName = true;
mask.setLabel(name);
mask.setMaskName(name);
// update host label
StringSet initiators = mask.getInitiators();
if (initiators != null) {
Iterator<String> itr = initiators.iterator();
if (itr.hasNext()) {
Initiator initiator = _dbClient.queryObject(Initiator.class, URI.create(itr.next()));
Host host = _dbClient.queryObject(Host.class, initiator.getHost());
String label = host.getLabel();
if (label.equals(name)) {
_helper.unsetTag(host, storage.getSerialNumber());
} else {
_helper.setTag(host, storage.getSerialNumber(), name);
}
}
}
}
builder.append(String.format(
"XM refresh: %s initiators; add:{%s} remove:{%s}%n",
name, Joiner.on(',').join(initiatorsToAdd),
Joiner.on(',').join(initiatorsToRemove)));
builder.append(String.format(
"XM refresh: %s volumes; add:{%s} remove:{%s}%n", name,
Joiner.on(',').join(volumesToAdd.keySet()),
Joiner.on(',').join(volumesToRemove)));
// Any changes indicated, then update the mask and persist it
if (addInitiators || removeInitiators || addVolumes
|| removeVolumes || changeName) {
builder.append("XM refresh: There are changes to mask, "
+ "updating it...\n");
mask.removeFromExistingInitiators(initiatorsToRemove);
mask.addToExistingInitiatorsIfAbsent(initiatorsToAdd);
mask.removeFromExistingVolumes(volumesToRemove);
mask.addToExistingVolumesIfAbsent(volumesToAdd);
ExportMaskUtils.sanitizeExportMaskContainers(_dbClient, mask);
_dbClient.updateAndReindexObject(mask);
} else {
builder.append("XM refresh: There are no changes to the mask\n");
}
_networkDeviceController.refreshZoningMap(mask,
initiatorsToRemove, Collections.EMPTY_LIST, (addInitiators || removeInitiators), true);
_log.info(builder.toString());
}
} catch (Exception e) {
boolean throwException = true;
if (e instanceof WBEMException) {
WBEMException we = (WBEMException) e;
// Only throw exception if code is not CIM_ERROR_NOT_FOUND
throwException = (we.getID() != WBEMException.CIM_ERR_NOT_FOUND);
}
if (throwException) {
String msg = "Error when attempting to query LUN masking information: "
+ e.getMessage();
_log.error(
MessageFormat
.format("Encountered an SMIS error when attempting to refresh existing exports: {0}",
msg),
e);
throw SmisException.exceptions.refreshExistingMaskFailure(msg,
e);
}
}
return mask;
}
/**
* Take in a list of storage port names (hex digits separated by colons),
* then returns a list of URIs representing the StoragePort URIs they
* represent.
*
* @param storagePorts
* [in] - Storage port name, hex digits separated by colons
* @return List of StoragePort URIs
*/
private List<String> storagePortNamesToURIs(List<String> storagePorts) {
List<String> storagePortURIStrings = new ArrayList<String>();
for (String port : storagePorts) {
URIQueryResultList uriQueryList = new URIQueryResultList();
_dbClient.queryByConstraint(AlternateIdConstraint.Factory
.getStoragePortEndpointConstraint(port), uriQueryList);
if (uriQueryList.iterator().hasNext()) {
storagePortURIStrings.add(uriQueryList.iterator().next()
.toString());
}
}
return storagePortURIStrings;
}
/**
* Returns a list of CIM_StorageHardwareID.ElementName values
* from the provider managing the specified 'storage' array.
*
* The values will be normalized. That is, in the case of WWN, it will be
* all upper-case with colons (if any) removed.
*
* @param storage
* [in] - StorageSystem object
* @return Map of String(initiator port name) to CIMObjectPath representing
* the Initiator in SMI-S
* @throws Exception
*/
private Map<String, CIMObjectPath> getStorageHardwareIds(
StorageSystem storage) throws Exception {
Map<String, CIMObjectPath> idsMap = new HashMap<>();
CloseableIterator<CIMInstance> seHwIter = null;
try {
// Multiple arrays can be managed by a single SMI-S instance. The
// CIM_StorageHardwareID is
// global to the provider, so we need to get the
// CIM_StorageHardware_ID object that are
// associated with a specific array.
CIMObjectPath hwManagementIDSvcPath = _cimPath
.getStorageHardwareIDManagementService(storage);
seHwIter = _helper.getAssociatorInstances(storage,
hwManagementIDSvcPath, null,
IBMSmisConstants.CP_STORAGE_HARDWARE_ID, null, null,
SmisConstants.PS_ELEMENT_NAME);
while (seHwIter.hasNext()) {
CIMInstance instance = seHwIter.next();
String port = CIMPropertyFactory.getPropertyValue(instance,
SmisConstants.CP_ELEMENT_NAME);
String elementName = Initiator.normalizePort(port);
idsMap.put(elementName, instance.getObjectPath());
}
} finally {
if (seHwIter != null) {
seHwIter.close();
}
}
return idsMap;
}
/*
* Returns SystemSpecificCollection associated with the initiator
*/
private CIMObjectPath getSystemSpecificCollectionPathByHwId(
StorageSystem storage, CIMObjectPath hardwareIDPath)
throws Exception {
CloseableIterator<CIMObjectPath> spcIter = null;
try {
spcIter = _helper.getAssociatorNames(storage, hardwareIDPath,
IBMSmisConstants.CP_SYS_SPECIFIC_COLLECTION_TO_SHWID,
IBMSmisConstants.CP_SYSTEM_SPECIFIC_COLLECTION,
IBMSmisConstants.CP_MEMBER, IBMSmisConstants.CP_COLLECTION);
while (spcIter.hasNext()) {
return spcIter.next();
}
} finally {
if (spcIter != null) {
spcIter.close();
}
}
return null;
}
/*
* Returns SCSIProtocolController associated with the initiator
*/
private CIMInstance getSCSIProtocolControllerInstanceByHwId(
StorageSystem storage, CIMObjectPath hardwareIDPath)
throws Exception {
CloseableIterator<CIMInstance> spcIter = null;
try {
spcIter = _helper.getAssociatorInstances(storage, hardwareIDPath,
IBMSmisConstants.CP_SHWID_TO_SPC,
IBMSmisConstants.CP_SCSI_PROTOCOL_CONTROLLER,
IBMSmisConstants.ANTECEDENT, IBMSmisConstants.CP_DEPENDENT, IBMSmisConstants.PS_ELEMENT_NAME);
while (spcIter.hasNext()) {
return spcIter.next();
}
} finally {
if (spcIter != null) {
spcIter.close();
}
}
return null;
}
/*
* create SystemSpecificCollection for the initiators
*
* Try to use the given element name first, if not success, retry without
* element name
*/
private CIMObjectPath getSystemSpecificCollectionPath(
StorageSystem storage, String elementName, String[] initiators)
throws Exception {
@SuppressWarnings("rawtypes")
CIMArgument[] outArgs = new CIMArgument[5];
CIMObjectPath hwIdManagementSvc = _cimPath
.getStorageHardwareIDManagementService(storage);
_helper.createHardwareIDCollection(storage, hwIdManagementSvc,
elementName, initiators, outArgs);
if (outArgs[0] == null) {
// must be return code 45504 (Host name already exists)
// now let system generate element name
_helper.createHardwareIDCollection(storage, hwIdManagementSvc,
null, initiators, outArgs);
}
return (CIMObjectPath) _cimPath.getFromOutputArgs(outArgs,
IBMSmisConstants.CP_HARDWARE_ID_COLLECTION);
}
/*
* Returns hardware Id in the collection
*/
private Set<String> hasHwIdsInCollection(
StorageSystem storage, CIMObjectPath sysSpecificCollectionPath)
throws Exception {
Set<String> hwIds = new HashSet<String>();
CloseableIterator<CIMInstance> shwIdIter = null;
try {
shwIdIter = _helper.getAssociatorInstances(storage,
sysSpecificCollectionPath,
IBMSmisConstants.CP_SYS_SPECIFIC_COLLECTION_TO_SHWID,
IBMSmisConstants.CP_STORAGE_HARDWARE_ID,
IBMSmisConstants.CP_COLLECTION, IBMSmisConstants.CP_MEMBER, SmisConstants.PS_ELEMENT_NAME);
while (shwIdIter.hasNext()) {
CIMInstance instance = shwIdIter.next();
String port = CIMPropertyFactory.getPropertyValue(instance,
SmisConstants.CP_ELEMENT_NAME);
String elementName = Initiator.normalizePort(port);
hwIds.add(elementName);
}
} finally {
if (shwIdIter != null) {
shwIdIter.close();
}
}
return hwIds;
}
/*
* Returns true if there is associated hardware Id in the collection
*/
private boolean hasHwIdInCollection(
StorageSystem storage, CIMObjectPath sysSpecificCollectionPath)
throws Exception {
CloseableIterator<CIMObjectPath> shwIdIter = null;
try {
shwIdIter = _helper.getAssociatorNames(storage,
sysSpecificCollectionPath,
IBMSmisConstants.CP_SYS_SPECIFIC_COLLECTION_TO_SHWID,
IBMSmisConstants.CP_STORAGE_HARDWARE_ID,
IBMSmisConstants.CP_COLLECTION, IBMSmisConstants.CP_MEMBER);
while (shwIdIter.hasNext()) {
return true;
}
} finally {
if (shwIdIter != null) {
shwIdIter.close();
}
}
return false;
}
/*
* Returns SCSIProtocolController associated with the storage hardware Id
* collection
*/
private CIMInstance getSCSIProtocolControllerInstanceByIdCollection(
StorageSystem storage, CIMObjectPath sysSpecificCollectionPath)
throws Exception {
CloseableIterator<CIMObjectPath> shwIdIter = null;
try {
shwIdIter = _helper.getAssociatorNames(storage,
sysSpecificCollectionPath,
IBMSmisConstants.CP_SYS_SPECIFIC_COLLECTION_TO_SHWID,
IBMSmisConstants.CP_STORAGE_HARDWARE_ID,
IBMSmisConstants.CP_COLLECTION, IBMSmisConstants.CP_MEMBER);
while (shwIdIter.hasNext()) {
return getSCSIProtocolControllerInstanceByHwId(storage,
shwIdIter.next());
}
} finally {
if (shwIdIter != null) {
shwIdIter.close();
}
}
return null;
}
/*
* Returns storage hardware Id collection associated with the controller
*/
private CIMObjectPath getIdCollectionBySCSIProtocolController(
StorageSystem storage, CIMObjectPath scsiProtocolControllerPath)
throws Exception {
CloseableIterator<CIMObjectPath> shwIdIter = null;
try {
shwIdIter = _helper.getAssociatorNames(storage,
scsiProtocolControllerPath,
IBMSmisConstants.CP_SHWID_TO_SPC,
IBMSmisConstants.CP_STORAGE_HARDWARE_ID,
IBMSmisConstants.CP_DEPENDENT, IBMSmisConstants.ANTECEDENT);
while (shwIdIter.hasNext()) {
return this.getSystemSpecificCollectionPathByHwId(storage,
shwIdIter.next());
}
} finally {
if (shwIdIter != null) {
shwIdIter.close();
}
}
return null;
}
/**
* Looks up the targets that are associated with the protocol controller (if any).
*
* @param protocolController
* [in] - CIMObjectPath representing protocol controller to lookup target endpoints (StoragePorts) for
* @param storage
* [in] - StorageSystem object representing the array
* @return List or StoragePort URIs that were found to be end points for the protocol controller
* @throws Exception
*/
private List<String> getTargetEndpoints(CIMObjectPath protocolController,
StorageSystem storage) throws Exception {
List<String> endpoints = new ArrayList<String>();
CloseableIterator<CIMInstance> fcPortIter = null;
try {
fcPortIter = _helper.getAssociatorInstances(storage, protocolController,
IBMSmisConstants.CP_PROTOCOL_CONTROLLER_FOR_PORT, IBMSmisConstants.CP_LOGICALPORT,
null, null, IBMSmisConstants.PS_PERMANENT_ADDRESS);
while (fcPortIter.hasNext()) {
CIMInstance instance = fcPortIter.next();
String targetPortId = CIMPropertyFactory.getPropertyValue(
instance, IBMSmisConstants.CP_PERMANENT_ADDRESS);
List<StoragePort> storagePorts = CustomQueryUtility
.queryActiveResourcesByAltId(_dbClient,
StoragePort.class, IBMSmisConstants.PORT_NETWORK_ID,
WWNUtility.getWWNWithColons(targetPortId));
for (StoragePort port : storagePorts) {
endpoints.add(port.getNativeGuid());
}
}
} finally {
if (fcPortIter != null) {
fcPortIter.close();
}
}
_log.info(String.format("SPC %s has these target endpoints: [ %s ]",
protocolController.toString(), Joiner.on(',').join(endpoints)));
return endpoints;
}
@Override
public void updateStorageGroupPolicyAndLimits(StorageSystem storage, ExportMask exportMask,
List<URI> volumeURIs, VirtualPool newVirtualPool, boolean rollback,
TaskCompleter taskCompleter) throws Exception {
throw DeviceControllerException.exceptions
.blockDeviceOperationNotSupported();
}
@Override
public Map<URI, Integer> getExportMaskHLUs(StorageSystem storage, ExportMask exportMask) {
return Collections.emptyMap();
}
private boolean isClusterExportMask(StorageSystem storage, URI exportMaskURI) {
boolean isClusteredHost = false;
List<ExportGroup> exportGroups = ExportUtils.getExportGroupsForMask(exportMaskURI, _dbClient);
Set<Boolean> valid = new HashSet<Boolean>();
for (ExportGroup exportGroup : exportGroups) {
valid.add(exportGroup.forCluster());
}
if (valid.size() == 1) {
List<URI> initiatorURIs = new ArrayList<URI>();
ExportMask mask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
for (String uri : mask.getInitiators()) {
initiatorURIs.add(URI.create(uri));
}
List<Initiator> initiators = _dbClient.queryObject(Initiator.class, initiatorURIs);
isClusteredHost = _restAPIHelper.isClusteredHost(storage, initiators);
}
return isClusteredHost;
}
/*
* (non-Javadoc) Creates an ExportMask with the given initiators & volumes.
*
* The export mask may have already been created.
*
* @param targetURIList not used
*
* @param initiatorList shouldn't be null/empty. Initiators in the list may
* have been created.
*/
@Override
public void createExportMask(StorageSystem storage, URI exportMaskURI,
VolumeURIHLU[] volumeURIHLUs, List<URI> targetURIList,
List<Initiator> initiatorList, TaskCompleter taskCompleter)
throws DeviceControllerException {
_log.info("{} createExportMask START...", storage.getLabel());
_log.info("createExportMask: mask id: {}", exportMaskURI);
_log.info("createExportMask: volume-HLU pairs: {}", volumeURIHLUs.toString());
_log.info("createExportMask: targets: {}", targetURIList);
_log.info("createExportMask: initiators: {}", initiatorList);
final ExportMask mask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
final String exportType = ExportMaskUtils.getExportType(_dbClient, mask);
if (_restAPIHelper.isClusteredHost(storage, initiatorList, exportType)){
_log.debug("Executing createExportMask using REST on Storage {}", storage.getLabel());
_restAPIHelper.createRESTExportMask(storage, exportMaskURI, volumeURIHLUs, targetURIList, initiatorList, taskCompleter);
} else {
_log.debug("Executing createExportMask using SMIS on Storage {}", storage.getLabel());
createSMISExportMask(storage, exportMaskURI, volumeURIHLUs, targetURIList, initiatorList, taskCompleter);
}
}
/*
* (non-Javadoc) Refresh Export Mask with the latest data
*
* @see
* com.emc.storageos.volumecontroller.impl.smis.ExportMaskOperations#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 {
if (isClusterExportMask(storage, mask.getId())) {
_log.debug("Executing refreshExportMask using REST on Storage {}", storage.getLabel());
_restAPIHelper.refreshRESTExportMask(storage, mask, _networkDeviceController);
} else {
_log.debug("Executing refreshExportMask using SMIS on Storage {}", storage.getLabel());
refreshSMISExportMask(storage, mask);
}
return mask;
}
/*
* (non-Javadoc) Delete Export Mask
*
* @see
* com.emc.storageos.volumecontroller.impl.smis.ExportMaskOperations#deleteExportMask(com.emc.storageos.db.client.
* model.StorageSystem, java.net.URI, java.util.List, java.util.List, java.util.List,
* com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void deleteExportMask(StorageSystem storage, URI exportMaskURI,
List<URI> volumeURIList, List<URI> targetURIList,
List<Initiator> initiatorList, TaskCompleter taskCompleter)
throws DeviceControllerException {
_log.info("{} deleteExportMask START...", storage.getLabel());
if (isClusterExportMask(storage, exportMaskURI)) {
_log.debug("Executing deleteExportMask using REST on Storage {}", storage.getLabel());
_restAPIHelper.deleteRESTExportMask(storage, exportMaskURI, volumeURIList, targetURIList, initiatorList, taskCompleter);
} else {
_log.debug("Executing deleteExportMask using SMIS on Storage {}", storage.getLabel());
deleteSMISExportMask(storage, exportMaskURI, volumeURIList, targetURIList, initiatorList, taskCompleter);
}
_log.info("{} deleteExportMask END...", storage.getLabel());
}
/*
* (non-Javadoc) Add volumes to an Export Mask
*
* @see
* com.emc.storageos.volumecontroller.impl.smis.ExportMaskOperations#addVolumes(com.emc.storageos.db.client.model.
* StorageSystem, java.net.URI, com.emc.storageos.volumecontroller.impl.VolumeURIHLU[],
* com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void addVolumes(StorageSystem storage, URI exportMaskURI, VolumeURIHLU[] volumeURIHLUs, List<Initiator> initiatorList,
TaskCompleter taskCompleter) {
_log.info("{} addVolumes START...", storage.getLabel());
_log.info("addVolumes: Export mask id: {}", exportMaskURI);
_log.info("addVolumes: volume-HLU pairs: {}", Joiner.on(',').join(volumeURIHLUs));
// TODO DUPP:
// 1. Get initiator list from the caller above for completeness
// 2. If possible, log if these volumes are going to be exported to additional initiators than what the
// request asked for
if (initiatorList != null) {
_log.info("addVolumes: initiators impacted: {}", Joiner.on(',').join(initiatorList));
}
if (isClusterExportMask(storage, exportMaskURI)) {
_log.debug("Executing addVolumes using REST on Storage {}", storage.getLabel());
_restAPIHelper.addVolumesUsingREST(storage, exportMaskURI, volumeURIHLUs, initiatorList, taskCompleter);
} else {
_log.debug("Executing addVolumes using SMIS on Storage {}", storage.getLabel());
addVolumesUsingSMIS(storage, exportMaskURI, volumeURIHLUs, initiatorList, taskCompleter);
}
_log.info("{} addVolumes END...", storage.getLabel());
}
/*
* (non-Javadoc) Remove Volumes from an Export mask
*
* @see
* com.emc.storageos.volumecontroller.impl.smis.ExportMaskOperations#removeVolumes(com.emc.storageos.db.client.
* model.
* StorageSystem, java.net.URI, java.util.List, com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void removeVolumes(StorageSystem storage, URI exportMaskURI,
List<URI> volumeURIList, List<Initiator> initiatorList,
TaskCompleter taskCompleter) throws DeviceControllerException {
_log.info("{} removeVolumes START...", storage.getLabel());
_log.info("removeVolumes: Export mask id: {}", exportMaskURI);
_log.info("removeVolumes: volumes: {}", Joiner.on(',').join(volumeURIList));
// TODO DUPP:
// 1. Get initiator list from the caller
// 2. Verify that the initiators are the ONLY ones impacted by this remove volumes, otherwise fail.
if (initiatorList != null) {
_log.info("removeVolumes: impacted initiators: {}", Joiner.on(",").join(initiatorList));
}
if (isClusterExportMask(storage, exportMaskURI)) {
_log.debug("Executing removeVolume using REST on Storage {}", storage.getLabel());
_restAPIHelper.removeVolumesUsingREST(storage, exportMaskURI, volumeURIList, initiatorList, taskCompleter);
} else {
_log.debug("Executing removeVolume using SMIS on Storage {}", storage.getLabel());
removeVolumesUsingSMIS(storage, exportMaskURI, volumeURIList, initiatorList, taskCompleter);
}
_log.info("{} removeVolumes END...", storage.getLabel());
}
/**
* This call can be used to look up the passed in initiator/port names and
* find (if any) to which export masks they belong on the 'storage' array.
*
*
* @param storage
* [in] - StorageSystem object representing the array
* @param initiatorNames
* [in] - normalized Port identifiers (WWPN or iSCSI name) (all initiators of all hosts involved)
* @param mustHaveAllPorts
* [in] NOT APPLICABLE FOR XIV
* @return Map of port name to Set of ExportMask URIs
*/
@Override
public Map<String, Set<URI>> findExportMasks(StorageSystem storage, List<String> initiatorNames, boolean mustHaveAllPorts) throws DeviceControllerException {
_log.info("{} findExportMasks START...", storage.getLabel());
Map<String, Set<URI>> result = new HashMap<String, Set<URI>>();
List<Initiator> initiators = new ArrayList<Initiator>();
for (String name : initiatorNames) {
initiators.add(ExportUtils.getInitiator(Initiator.toPortNetworkId(name), _dbClient));
}
if (_restAPIHelper.isClusteredHost(storage, initiators)) {
_log.debug("Executing findExportMasks using REST on Storage {}", storage.getLabel());
result = _restAPIHelper.findRESTExportMasks(storage, initiatorNames, mustHaveAllPorts);
} else {
_log.debug("Executing findExportMasks using SMIS on Storage {}", storage.getLabel());
result = findSMISExportMasks(storage, initiatorNames, mustHaveAllPorts);
}
_log.info("{} findExportMasks END...", storage.getLabel());
return result;
}
/*
* (non-Javadoc)
*
* @see
* com.emc.storageos.volumecontroller.impl.smis.ExportMaskOperations#addInitiators(com.emc.storageos.db.client.
* model.
* StorageSystem, java.net.URI, java.util.List, java.util.List, com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void addInitiators(StorageSystem storage, URI exportMaskURI, List<URI> volumeURIs, List<Initiator> initiatorList,
List<URI> targets,
TaskCompleter taskCompleter) throws DeviceControllerException {
_log.info("{} addInitiators START...", storage.getLabel());
// TODO DUPP:
// 1. Get the impacted volumes from the caller
// 2. Log any other volumes that are being exposed to the initiator
// 3. Make sure these initiators aren't in other storage groups!
if (volumeURIs != null) {
_log.info("addInitiators: volumes : {}", Joiner.on(',').join(volumeURIs));
}
_log.info("addInitiators: initiators : {}", Joiner.on(',').join(initiatorList));
_log.info("addInitiators: targets : {}", Joiner.on(",").join(targets));
if (isClusterExportMask(storage, exportMaskURI)) {
_log.debug("Executing addInitiators using REST on Storage {}", storage.getLabel());
_restAPIHelper.addInitiatorsUsingREST(storage, exportMaskURI, volumeURIs, initiatorList, taskCompleter);
} else {
_log.debug("Executing addInitiators using SMIS on Storage {}", storage.getLabel());
addInitiatorsUsingSMIS(storage, exportMaskURI, volumeURIs, initiatorList, targets, taskCompleter);
}
_log.info("{} addInitiators END...", storage.getLabel());
}
/*
* (non-Javadoc)
*
* @see
* com.emc.storageos.volumecontroller.impl.smis.ExportMaskOperations#removeInitiators(com.emc.storageos.db.client.
* model.StorageSystem, java.net.URI, java.util.List, java.util.List,
* com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void removeInitiators(StorageSystem storage, URI exportMaskURI, List<URI> volumeURIs, List<Initiator> initiatorList,
List<URI> targets,
TaskCompleter taskCompleter) throws DeviceControllerException {
_log.info("{} removeInitiators START...", storage.getLabel());
if (isClusterExportMask(storage, exportMaskURI)) {
_log.debug("Executing removeInitiators using REST on Storage {}", storage.getLabel());
_restAPIHelper.removeInitiatorsUsingREST(storage, exportMaskURI, volumeURIs, initiatorList, taskCompleter);
} else {
_log.debug("Executing removeInitiators using SMIS on Storage {}", storage.getLabel());
removeInitiatorsUsingSMIS(storage, exportMaskURI, volumeURIs, initiatorList, targets, taskCompleter);
}
_log.info("{} removeInitiators END...", storage.getLabel());
}
@Override
public void addPaths(StorageSystem storage, URI exportMask, Map<URI, List<URI>> newPaths, TaskCompleter taskCompleter)
throws DeviceControllerException {
throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
}
@Override
public void removePaths(StorageSystem storage, URI exportMask, Map<URI, List<URI>> adjustedPaths, Map<URI, List<URI>> removePaths, TaskCompleter taskCompleter)
throws DeviceControllerException {
throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
}
}