use of com.emc.storageos.vplex.api.clientdata.PortInfo in project coprhd-controller by CoprHD.
the class VPlexDeviceController method storageViewAddInitiators.
/**
* Workflow Step to add initiator to Storage View.
* Note arguments (except stepId) must match storageViewAddInitiatorsMethod above.
*
* @param vplexURI
* -- URI of VPlex StorageSystem
* @param exportURI
* -- ExportGroup URI
* @param maskURI
* -- ExportMask URI. Optional.
* If non-null, only the indicated ExportMask will be processed.
* Otherwise, all ExportMasks will be processed.
* @param initiatorURIs
* -- List of initiator URIs to be added.
* @param targetURIs
* -- optional list of additional targets URIs (VPLEX FE ports) to be added.
* If non null, the targets (VPlex front end ports) indicated by the targetURIs will be added
* to the Storage View.
* @param completer the ExportMaskAddInitiatorCompleter
* @param stepId
* -- Workflow step id.
* @throws WorkflowException
*/
public void storageViewAddInitiators(URI vplexURI, URI exportURI, URI maskURI, List<URI> initiatorURIs, List<URI> targetURIs, boolean sharedExportMask, ExportMaskAddInitiatorCompleter completer, String stepId) throws DeviceControllerException {
try {
WorkflowStepCompleter.stepExecuting(stepId);
ExportOperationContext context = new VplexExportOperationContext();
// Prime the context object
completer.updateWorkflowStepContext(context);
StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
ExportGroup exportGroup = getDataObject(ExportGroup.class, exportURI, _dbClient);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
List<ExportMask> exportMasks = ExportMaskUtils.getExportMasks(_dbClient, exportGroup, vplexURI);
for (ExportMask exportMask : exportMasks) {
// If a specific ExportMask is to be processed, ignore any others.
if (maskURI != null && !exportMask.getId().equals(maskURI)) {
continue;
}
_log.info("Refreshing ExportMask {}", exportMask.getMaskName());
String vplexClusterName = VPlexUtil.getVplexClusterName(exportMask, vplexURI, client, _dbClient);
VPlexStorageViewInfo storageView = client.getStorageView(vplexClusterName, exportMask.getMaskName());
VPlexControllerUtils.refreshExportMask(_dbClient, storageView, exportMask, VPlexControllerUtils.getTargetPortToPwwnMap(client, vplexClusterName), _networkDeviceController);
// Determine host of ExportMask
Set<URI> exportMaskHosts = VPlexUtil.getExportMaskHosts(_dbClient, exportMask, sharedExportMask);
List<Initiator> inits = _dbClient.queryObject(Initiator.class, initiatorURIs);
if (sharedExportMask) {
for (Initiator initUri : inits) {
URI hostUri = VPlexUtil.getInitiatorHost(initUri);
if (null != hostUri) {
exportMaskHosts.add(hostUri);
}
}
}
// Invoke artificial failure to simulate invalid storageview name on vplex
InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_060);
// Add new targets if specified
if (targetURIs != null && targetURIs.isEmpty() == false) {
List<PortInfo> targetPortInfos = new ArrayList<PortInfo>();
List<URI> targetsAddedToStorageView = new ArrayList<URI>();
for (URI target : targetURIs) {
// Do not try to add a port twice.
if (exportMask.getStoragePorts().contains(target.toString())) {
continue;
}
// Log any ports not listed as a target in the Export Masks zoningMap
Set<String> zoningMapTargets = BlockStorageScheduler.getTargetIdsFromAssignments(exportMask.getZoningMap());
if (!zoningMapTargets.contains(target.toString())) {
_log.info(String.format("Target %s not in zoning map", target));
}
// Build the PortInfo structure for the port to be added
StoragePort port = getDataObject(StoragePort.class, target, _dbClient);
PortInfo pi = new PortInfo(port.getPortNetworkId().toUpperCase().replaceAll(":", ""), null, port.getPortName(), null);
targetPortInfos.add(pi);
targetsAddedToStorageView.add(target);
}
if (!targetPortInfos.isEmpty()) {
// Add the targets on the VPLEX
client.addTargetsToStorageView(exportMask.getMaskName(), targetPortInfos);
// Add the targets to the database.
for (URI target : targetsAddedToStorageView) {
exportMask.addTarget(target);
}
}
}
List<PortInfo> initiatorPortInfos = new ArrayList<PortInfo>();
List<String> initiatorPortWwns = new ArrayList<String>();
Map<PortInfo, Initiator> portInfosToInitiatorMap = new HashMap<PortInfo, Initiator>();
for (Initiator initiator : inits) {
// Only add this initiator if it's for the same host as other initiators in mask
if (!exportMaskHosts.contains(VPlexUtil.getInitiatorHost(initiator))) {
continue;
}
// Only add this initiator if it's not in the mask already after refresh
if (exportMask.hasInitiator(initiator.getId().toString())) {
continue;
}
PortInfo portInfo = new PortInfo(initiator.getInitiatorPort().toUpperCase().replaceAll(":", ""), initiator.getInitiatorNode().toUpperCase().replaceAll(":", ""), initiator.getLabel(), getVPlexInitiatorType(initiator));
initiatorPortInfos.add(portInfo);
initiatorPortWwns.add(initiator.getInitiatorPort());
portInfosToInitiatorMap.put(portInfo, initiator);
}
if (!initiatorPortInfos.isEmpty()) {
String lockName = null;
boolean lockAcquired = false;
try {
StringSet portIds = exportMask.getStoragePorts();
StoragePort exportMaskPort = getDataObject(StoragePort.class, URI.create(portIds.iterator().next()), _dbClient);
String clusterId = ConnectivityUtil.getVplexClusterOfPort(exportMaskPort);
lockName = _vplexApiLockManager.getLockName(vplexURI, clusterId);
lockAcquired = _vplexApiLockManager.acquireLock(lockName, LockTimeoutValue.get(LockType.VPLEX_API_LIB));
if (!lockAcquired) {
throw VPlexApiException.exceptions.couldNotObtainConcurrencyLock(vplex.getLabel());
}
// Add the initiators to the VPLEX
client.addInitiatorsToStorageView(exportMask.getMaskName(), vplexClusterName, initiatorPortInfos);
ExportOperationContext.insertContextOperation(completer, VplexExportOperationContext.OPERATION_ADD_INITIATORS_TO_STORAGE_VIEW, initiatorURIs);
} finally {
if (lockAcquired) {
_vplexApiLockManager.releaseLock(lockName);
}
}
}
}
InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_003);
completer.ready(_dbClient);
} catch (VPlexApiException vae) {
_log.error("VPlexApiException adding initiator to Storage View: " + vae.getMessage(), vae);
failStep(completer, stepId, vae);
} catch (Exception ex) {
_log.error("Exception adding initiator to Storage View: " + ex.getMessage(), ex);
String opName = ResourceOperationTypeEnum.ADD_STORAGE_VIEW_INITIATOR.getName();
ServiceError serviceError = VPlexApiException.errors.storageViewAddInitiatorFailed(opName, ex);
failStep(completer, stepId, serviceError);
}
}
use of com.emc.storageos.vplex.api.clientdata.PortInfo in project coprhd-controller by CoprHD.
the class VPlexDeviceController method createStorageView.
/**
* A Workflow Step to create a Storage View on the VPlex.
*
* @param vplexURI
* @param exportURI
* @param blockObjectMap
* - A list of Volume/Snapshot URIs to LUN ids.
* @param initiators
* @param stepId
* @throws ControllerException
*/
public void createStorageView(URI vplexURI, URI exportURI, URI exportMaskURI, Map<URI, Integer> blockObjectMap, List<URI> initiators, List<URI> targets, ExportMaskCreateCompleter completer, String stepId) throws ControllerException {
String lockName = null;
boolean lockAcquired = false;
try {
WorkflowStepCompleter.stepExecuting(stepId);
StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
ExportMask exportMask = getDataObject(ExportMask.class, exportMaskURI, _dbClient);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
// Setup the call to the VPlex API.
List<PortInfo> targetPortInfos = new ArrayList<PortInfo>();
for (URI target : targets) {
StoragePort port = getDataObject(StoragePort.class, target, _dbClient);
PortInfo pi = new PortInfo(port.getPortNetworkId().toUpperCase().replaceAll(":", ""), null, port.getPortName(), null);
targetPortInfos.add(pi);
if (lockName == null) {
String clusterId = ConnectivityUtil.getVplexClusterOfPort(port);
lockName = _vplexApiLockManager.getLockName(vplexURI, clusterId);
}
}
List<PortInfo> initiatorPortInfos = new ArrayList<PortInfo>();
for (URI init : initiators) {
Initiator initiator = getDataObject(Initiator.class, init, _dbClient);
PortInfo pi = new PortInfo(initiator.getInitiatorPort().toUpperCase().replaceAll(":", ""), initiator.getInitiatorNode().toUpperCase().replaceAll(":", ""), initiator.getLabel(), getVPlexInitiatorType(initiator));
initiatorPortInfos.add(pi);
}
List<BlockObject> blockObjects = new ArrayList<BlockObject>();
Map<String, Integer> boMap = new HashMap<String, Integer>();
for (URI vol : blockObjectMap.keySet()) {
Integer lun = blockObjectMap.get(vol);
if (lun == null) {
lun = ExportGroup.LUN_UNASSIGNED;
}
BlockObject bo = Volume.fetchExportMaskBlockObject(_dbClient, vol);
blockObjects.add(bo);
boMap.put(bo.getDeviceLabel(), lun);
}
lockAcquired = _vplexApiLockManager.acquireLock(lockName, LockTimeoutValue.get(LockType.VPLEX_API_LIB));
if (!lockAcquired) {
throw VPlexApiException.exceptions.couldNotObtainConcurrencyLock(vplex.getLabel());
}
VPlexStorageViewInfo svInfo = client.createStorageView(exportMask.getMaskName(), targetPortInfos, initiatorPortInfos, boMap);
// When VPLEX volumes or snapshots are exported to a storage view, they get a WWN,
// so set the WWN from the returned storage view information.
Map<URI, Integer> updatedBlockObjectMap = new HashMap<URI, Integer>();
for (BlockObject bo : blockObjects) {
String deviceLabel = bo.getDeviceLabel();
bo.setWWN(svInfo.getWWNForStorageViewVolume(deviceLabel));
_dbClient.updateObject(bo);
updatedBlockObjectMap.put(bo.getId(), svInfo.getHLUForStorageViewVolume(deviceLabel));
}
// We also need to update the volume/lun id map in the export mask
// to those assigned by the VPLEX.
_log.info("Updating volume/lun map in export mask {}", exportMask.getId());
_log.info("updatedBlockObjectMap: " + updatedBlockObjectMap.toString());
exportMask.addVolumes(updatedBlockObjectMap);
// Update user created volumes
exportMask.addToUserCreatedVolumes(blockObjects);
// update native id (this is the context path to the storage view on the vplex)
// e.g.: /clusters/cluster-1/exports/storage-views/V1_myserver_288
// this column being set to non-null can be used to indicate a storage view that
// has been successfully created on the VPLEX device
exportMask.setNativeId(svInfo.getPath());
_dbClient.updateObject(exportMask);
completer.ready(_dbClient);
} catch (VPlexApiException vae) {
_log.error("Exception creating VPlex Storage View: " + vae.getMessage(), vae);
if ((null != vae.getMessage()) && vae.getMessage().toUpperCase().contains(VPlexApiConstants.DUPLICATE_STORAGE_VIEW_ERROR_FRAGMENT.toUpperCase())) {
_log.error("storage view creation failure is due to duplicate storage view name");
ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
if (null != exportMask) {
_log.error("marking ExportMask inactive so that rollback will " + "not delete the existing storage view on the VPLEX");
_dbClient.removeObject(exportMask);
}
}
failStep(completer, stepId, vae);
} catch (Exception ex) {
_log.error("Exception creating VPlex Storage View: " + ex.getMessage(), ex);
String opName = ResourceOperationTypeEnum.CREATE_STORAGE_VIEW.getName();
ServiceError serviceError = VPlexApiException.errors.createStorageViewFailed(opName, ex);
failStep(completer, stepId, serviceError);
} finally {
if (lockAcquired) {
_vplexApiLockManager.releaseLock(lockName);
}
}
}
use of com.emc.storageos.vplex.api.clientdata.PortInfo in project coprhd-controller by CoprHD.
the class VPlexDeviceController method storageViewAddStoragePorts.
/**
* Workflow Step to add storage port(s) to Storage View.
* Note arguments (except stepId) must match storageViewAddStoragePortsMethod above.
*
* @param vplexURI
* -- URI of VPlex StorageSystem
* @param exportURI
* -- ExportGroup URI
* @param maskURI
* -- ExportMask URI.
* @param targetURIs
* -- list of targets URIs (VPLEX FE ports) to be added.
* If not null, the targets (VPlex front end ports) indicated by the targetURIs will be added
* to the Storage View making sure they do belong to zoningMap storagePorts.
* If null, then ports are calculated from the zoningMap.
* @param completer the ExportMaskAddInitiatorCompleter
* @param stepId
* -- Workflow step id.
* @throws WorkflowException
*/
public void storageViewAddStoragePorts(URI vplexURI, URI exportURI, URI maskURI, List<URI> targetURIs, ExportMaskAddInitiatorCompleter completer, String stepId) throws DeviceControllerException {
try {
WorkflowStepCompleter.stepExecuting(stepId);
ExportOperationContext context = new VplexExportOperationContext();
// Prime the context object
completer.updateWorkflowStepContext(context);
StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
ExportGroup exportGroup = getDataObject(ExportGroup.class, exportURI, _dbClient);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
List<ExportMask> exportMasks = ExportMaskUtils.getExportMasks(_dbClient, exportGroup, vplexURI);
for (ExportMask exportMask : exportMasks) {
// If a specific ExportMask is to be processed, ignore any others.
if (maskURI != null && !exportMask.getId().equals(maskURI)) {
continue;
}
ArrayList<URI> filteredTargetURIs = new ArrayList<URI>();
// Filter or get targets from the zoning map
if (exportMask.getZoningMap() != null) {
Set<String> zoningMapTargets = BlockStorageScheduler.getTargetIdsFromAssignments(exportMask.getZoningMap());
List<URI> zoningMapTargetURIs = StringSetUtil.stringSetToUriList(zoningMapTargets);
if (targetURIs == null || targetURIs.isEmpty()) {
// Add all storage ports from the zoning map
if (zoningMapTargetURIs != null && !zoningMapTargetURIs.isEmpty()) {
filteredTargetURIs.addAll(zoningMapTargetURIs);
}
} else {
// Log any ports not in the zoning map.
for (URI targetURI : targetURIs) {
filteredTargetURIs.add(targetURI);
if (zoningMapTargetURIs.contains(targetURI)) {
_log.info(String.format("Target %s not in zoning map", targetURI));
}
}
}
}
// Add new targets if specified
if (filteredTargetURIs != null && filteredTargetURIs.isEmpty() == false) {
List<PortInfo> targetPortInfos = new ArrayList<PortInfo>();
List<URI> targetsAddedToStorageView = new ArrayList<URI>();
for (URI target : filteredTargetURIs) {
// Do not try to add a port twice.
if (exportMask.getStoragePorts().contains(target.toString())) {
continue;
}
// Build the PortInfo structure for the port to be added
StoragePort port = getDataObject(StoragePort.class, target, _dbClient);
PortInfo pi = new PortInfo(port.getPortNetworkId().toUpperCase().replaceAll(":", ""), null, port.getPortName(), null);
targetPortInfos.add(pi);
targetsAddedToStorageView.add(target);
}
if (!targetPortInfos.isEmpty()) {
// Add the targets on the VPLEX
client.addTargetsToStorageView(exportMask.getMaskName(), targetPortInfos);
ExportOperationContext.insertContextOperation(completer, VplexExportOperationContext.OPERATION_ADD_TARGETS_TO_STORAGE_VIEW, targetsAddedToStorageView);
// Add the targets to the database.
for (URI target : targetsAddedToStorageView) {
exportMask.addTarget(target);
}
_dbClient.updateObject(exportMask);
}
}
}
InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_083);
completer.ready(_dbClient);
} catch (VPlexApiException vae) {
_log.error("VPlexApiException adding storagePorts to Storage View: " + vae.getMessage(), vae);
failStep(completer, stepId, vae);
} catch (Exception ex) {
_log.error("Exception adding storagePorts to Storage View: " + ex.getMessage(), ex);
String opName = ResourceOperationTypeEnum.ADD_STORAGE_VIEW_STORAGEPORTS.getName();
ServiceError serviceError = VPlexApiException.errors.storageViewAddStoragePortFailed(opName, ex);
failStep(completer, stepId, serviceError);
}
}
use of com.emc.storageos.vplex.api.clientdata.PortInfo in project coprhd-controller by CoprHD.
the class VPlexApiExportManager method findInitiatorsOnCluster.
/**
* Tries to find initiators on the the passed cluster corresponding to the
* passed port information.
*
* @param clusterName The name of the cluster.
* @param initiatorsToFind The port information.
*
* @return A list of VPlexInitiatorInfo representing the found initiators.
*
* @throws VPlexApiException When an error occurs finding initiators on the
* cluster.
*/
private List<VPlexInitiatorInfo> findInitiatorsOnCluster(String clusterName, List<PortInfo> initiatorsToFind) throws VPlexApiException {
List<VPlexInitiatorInfo> foundInitiators = new ArrayList<VPlexInitiatorInfo>();
// Get the initiators on the passed cluster.
VPlexApiDiscoveryManager discoveryMgr = _vplexApiClient.getDiscoveryManager();
List<VPlexInitiatorInfo> clusterInitiatorInfoList = discoveryMgr.getInitiatorInfoForCluster(clusterName, false);
// an initiator found on the cluster.
for (PortInfo portInfo : initiatorsToFind) {
String portWWN = portInfo.getPortWWN();
for (VPlexInitiatorInfo clusterInitiatorInfo : clusterInitiatorInfoList) {
// TBD: Check node WWNs as well? They are optional.
if (portWWN.equals(clusterInitiatorInfo.getPortWwn())) {
foundInitiators.add(clusterInitiatorInfo);
// Make sure a registration name is set. If the caller
// passed a specific port name, then it was or will be
// registered with that name. Otherwise, we give it a
// default name.
String portName = portInfo.getName();
if ((portName != null) && (portName.length() != 0)) {
clusterInitiatorInfo.setRegistrationName(portName);
} else {
clusterInitiatorInfo.setRegistrationName(VPlexApiConstants.REGISTERED_INITIATOR_PREFIX + clusterInitiatorInfo.getPortWwnRaw());
}
// Also, if the caller passed an initiator type make sure
// it is set so that it can be passed when the initiator
// is registered.
Initiator_Type initiatorType = Initiator_Type.valueOfType(portInfo.getType());
if (initiatorType == null) {
s_logger.info("Initiator port type {} not found, using default", portInfo.getType());
initiatorType = Initiator_Type.DEFAULT;
}
clusterInitiatorInfo.setInitiatorType(initiatorType);
break;
}
}
}
return foundInitiators;
}
use of com.emc.storageos.vplex.api.clientdata.PortInfo in project coprhd-controller by CoprHD.
the class VPlexApiExportManager method removeInitiatorsFromStorageView.
/**
* Removes the initiators identified by the passed port information from the
* storage view with the passed name.
*
* @param viewName The name of the storage view.
* @param clusterName The name of the VPLEX cluster that the storage view is on.
* @param initiatorToRemove The port information for the initiators to be
* removed.
*
* @throws VPlexApiException When an error occurs removing the initiators.
*/
void removeInitiatorsFromStorageView(String viewName, String clusterName, List<PortInfo> initiatorToRemove) throws VPlexApiException {
// In case of a VPlex cross connect initiators will be in both the clusters.
// So first find the storage view in both the VPlex clusters and then find
// Initiators in a specific cluster.
VPlexApiDiscoveryManager discoveryMgr = _vplexApiClient.getDiscoveryManager();
VPlexStorageViewInfo storageViewInfo = discoveryMgr.findStorageViewOnCluster(viewName, clusterName, false);
if (storageViewInfo == null) {
throw VPlexApiException.exceptions.couldNotFindStorageView(viewName);
}
// Find the initiators in a cluster where storage view is found.
List<VPlexInitiatorInfo> initiatorsFoundForRemoval = findInitiators(clusterName, initiatorToRemove);
if (initiatorsFoundForRemoval.size() != initiatorToRemove.size()) {
StringBuffer notFoundInitiators = new StringBuffer();
for (PortInfo portInfo : initiatorToRemove) {
if (notFoundInitiators.length() == 0) {
notFoundInitiators.append(portInfo.getPortWWN());
} else {
notFoundInitiators.append(" ,").append(portInfo.getPortWWN());
}
}
throw VPlexApiException.exceptions.couldNotFindInitiators(notFoundInitiators.toString());
}
// Remove the initiators from storage view.
removeStorageViewInitiators(storageViewInfo, initiatorsFoundForRemoval);
}
Aggregations