use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexMigrationJob method getVPlexAPIClient.
/**
* Get the HTTP client for making requests to the VPlex at the
* endpoint specified in the passed profile.
*
* @param jobContext The job context
* @param vplexSystem The VPlex storage system
*
* @return A reference to the VPlex API HTTP client.
* @throws URISyntaxException
*/
private VPlexApiClient getVPlexAPIClient(JobContext jobContext, StorageSystem vplexSystem) throws URISyntaxException {
// Create the URI to access the VPlex Management Station based
// on the IP and port for the passed VPlex system.
URI vplexEndpointURI = new URI("https", null, vplexSystem.getIpAddress(), vplexSystem.getPortNumber(), "/", null, null);
s_logger.debug("VPlex base URI is {}", vplexEndpointURI.toString());
VPlexApiFactory vplexApiFactory = jobContext.getVPlexApiFactory();
s_logger.debug("Got VPlex API factory");
VPlexApiClient client = vplexApiFactory.getClient(vplexEndpointURI, vplexSystem.getUsername(), vplexSystem.getPassword());
s_logger.debug("Got VPlex API client");
return client;
}
use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexDeviceController method commitMigration.
/**
* Invoked by the migration workflow to commit the migration after it has
* been completed.
*
* @param vplexURI
* The URI of the VPlex storage system.
* @param virtualVolumeURI
* The URI of the virtual volume.
* @param migrationURI
* The URI of the data migration.
* @param rename
* Indicates if the volume should be renamed after commit to
* conform to ViPR standard naming conventions.
* @param newVpoolURI - the new virtual pool for the virtual volume (or null if not changing)
* @param newVarrayURI - the new varray for the virtual volume (or null if not changing)
* @param stepId
* The workflow step identifier.
*
* @throws WorkflowException
*/
public void commitMigration(URI vplexURI, URI virtualVolumeURI, URI migrationURI, Boolean rename, URI newVpoolURI, URI newVarrayURI, String stepId) throws WorkflowException {
_log.info("Committing migration {}", migrationURI);
Migration migration = null;
VPlexApiClient client = null;
try {
// Update step state to executing.
WorkflowStepCompleter.stepExecuting(stepId);
// Get the migration.
migration = getDataObject(Migration.class, migrationURI, _dbClient);
// workflow, so check the status.
if (!VPlexMigrationInfo.MigrationStatus.COMMITTED.getStatusValue().equals(migration.getMigrationStatus())) {
// Get the VPlex API client.
StorageSystem vplexSystem = getDataObject(StorageSystem.class, vplexURI, _dbClient);
client = getVPlexAPIClient(_vplexApiFactory, vplexSystem, _dbClient);
_log.info("Got VPlex API client for system {}", vplexURI);
// Make a call to the VPlex API client to commit the migration.
// Note that for ingested VPLEX volumes created outside ViPR, we
// don't want to update the name.
List<VPlexMigrationInfo> migrationInfoList = new ArrayList<VPlexMigrationInfo>();
Volume virtualVolume = getDataObject(Volume.class, virtualVolumeURI, _dbClient);
try {
migrationInfoList = client.commitMigrations(virtualVolume.getDeviceLabel(), Arrays.asList(migration.getLabel()), true, true, rename.booleanValue());
_log.info("Committed migration {}", migration.getLabel());
} catch (VPlexApiException vae) {
_log.error("Exception committing VPlex migration: " + vae.getMessage(), vae);
boolean committed = false;
// Check the migration status. Maybe it committed even though we had an error.
VPlexMigrationInfo migrationInfo = client.getMigrationInfo(migration.getLabel());
if (migrationInfo.getStatus().equalsIgnoreCase(VPlexMigrationInfo.MigrationStatus.COMMITTED.name())) {
_log.info("Migration {} has committed despite exception", migration.getLabel());
migrationInfoList.clear();
migrationInfoList.add(migrationInfo);
committed = true;
} else {
_log.info("Migration {} status {}", migration.getLabel(), migrationInfo.getStatus());
}
if (!committed) {
// This was observed at customer site COP-21257
if (vae.getServiceCode() == ServiceCode.VPLEX_API_RESPONSE_TIMEOUT_ERROR) {
// We are going to throw an error, but we don't want to rollback completely
_workflowService.setWorkflowRollbackContOnError(stepId, false);
}
WorkflowStepCompleter.stepFailed(stepId, vae);
return;
}
}
// Below this point migration is committed, no turning back.
// Initialize the migration info in the database.
migration.setMigrationStatus(VPlexMigrationInfo.MigrationStatus.COMMITTED.getStatusValue());
_dbClient.updateObject(migration);
_log.info("Update migration status to committed");
// Update the virtual volume native id and associated
// volumes. Note that we don't update CoS until all
// commits are successful.
VPlexVirtualVolumeInfo updatedVirtualVolumeInfo = migrationInfoList.get(0).getVirtualVolumeInfo();
// update any properties that were changed after migration including deviceLabel, nativeGuid, and nativeId.
// also, if the updated volume isn't thin-enabled, it is thin-capable, and the target vpool supports thin
// provisioning, then a call should be made to the VPLEX to flip the thin-enabled flag on for this volume.
URI targetVolumeUri = migration.getTarget();
Volume targetVolume = getDataObject(Volume.class, targetVolumeUri, _dbClient);
if (updatedVirtualVolumeInfo != null) {
_log.info(String.format("New virtual volume is %s", updatedVirtualVolumeInfo.toString()));
// if the new virtual volume is thin-capable, but thin-enabled is not true,
// that means we need to ask the VPLEX to convert it to a thin-enabled volume.
// this doesn't happen automatically for thick-to-thin data migrations.
boolean isThinEnabled = updatedVirtualVolumeInfo.isThinEnabled();
if (!isThinEnabled && VPlexApiConstants.TRUE.equalsIgnoreCase(updatedVirtualVolumeInfo.getThinCapable())) {
if (verifyVplexSupportsThinProvisioning(vplexSystem)) {
if (null != targetVolume) {
_log.info(String.format("migration target Volume is %s", targetVolume.forDisplay()));
VirtualPool targetVirtualPool = getDataObject(VirtualPool.class, targetVolume.getVirtualPool(), _dbClient);
if (null != targetVirtualPool) {
_log.info(String.format("migration target VirtualPool is %s", targetVirtualPool.forDisplay()));
boolean doEnableThin = VirtualPool.ProvisioningType.Thin.toString().equalsIgnoreCase(targetVirtualPool.getSupportedProvisioningType());
if (doEnableThin) {
_log.info(String.format("the new VirtualPool is thin, requesting VPLEX to enable thin provisioning on %s", updatedVirtualVolumeInfo.getName()));
isThinEnabled = client.setVirtualVolumeThinEnabled(updatedVirtualVolumeInfo);
}
}
}
}
}
virtualVolume.setDeviceLabel(updatedVirtualVolumeInfo.getName());
virtualVolume.setNativeId(updatedVirtualVolumeInfo.getPath());
virtualVolume.setNativeGuid(updatedVirtualVolumeInfo.getPath());
virtualVolume.setThinlyProvisioned(isThinEnabled);
}
// Note that for ingested volumes, there will be no associated volumes
// at first.
StringSet assocVolumes = virtualVolume.getAssociatedVolumes();
if ((assocVolumes != null) && (!assocVolumes.isEmpty())) {
// For a distributed volume, there could be multiple
// migrations. When the first completes, there will
// be no associated volumes. However, when the second
// completes, there will be associated volumes. However,
// the migration source could be null.
URI sourceVolumeUri = migration.getSource();
if (sourceVolumeUri != null) {
assocVolumes.remove(sourceVolumeUri.toString());
// Retain any previous RP fields on the new target volume.
Volume sourceVolume = getDataObject(Volume.class, sourceVolumeUri, _dbClient);
if (sourceVolume != null) {
boolean targetUpdated = false;
if (NullColumnValueGetter.isNotNullValue(sourceVolume.getRpCopyName())) {
targetVolume.setRpCopyName(sourceVolume.getRpCopyName());
targetUpdated = true;
}
if (NullColumnValueGetter.isNotNullValue(sourceVolume.getInternalSiteName())) {
targetVolume.setInternalSiteName(sourceVolume.getInternalSiteName());
targetUpdated = true;
}
if (targetUpdated) {
_dbClient.updateObject(targetVolume);
}
}
}
assocVolumes.add(migration.getTarget().toString());
} else {
// NOTE: Now an ingested volume will have associated volumes.
// It will no longer be considered an ingested volume.
assocVolumes = new StringSet();
assocVolumes.add(migration.getTarget().toString());
virtualVolume.setAssociatedVolumes(assocVolumes);
}
updateMigratedVirtualVolumeVpoolAndVarray(virtualVolume, newVpoolURI, newVarrayURI);
_dbClient.updateObject(virtualVolume);
_log.info("Updated virtual volume.");
} else {
_log.info("The migration is already committed.");
// Note that we don't set the device label and native id. If the
// migration was committed outside of Bourne, the virtual volume
// will still have the old name. If it was committed through
// Bourne, these values would already have been update.
// Regardless, we have to update the vpool, and we update the
// associated volumes in case it was committed outside of
// Bourne.
associateVplexVolumeWithMigratedTarget(migration, virtualVolumeURI);
_log.info("Updated virtual volume.");
}
// Update the workflow step status.
StringBuilder successMsgBuilder = new StringBuilder();
successMsgBuilder.append("VPlex System: ");
successMsgBuilder.append(vplexURI);
successMsgBuilder.append(" migration: ");
successMsgBuilder.append(migrationURI);
successMsgBuilder.append(" was committed");
_log.info(successMsgBuilder.toString());
WorkflowStepCompleter.stepSucceded(stepId);
_log.info("Updated workflow step state to success");
} catch (VPlexApiException vae) {
_log.error("Exception committing VPlex migration: " + vae.getMessage(), vae);
WorkflowStepCompleter.stepFailed(stepId, vae);
} catch (Exception ex) {
_log.error("Exception committing VPlex migration: " + ex.getMessage(), ex);
String opName = ResourceOperationTypeEnum.COMMIT_VOLUME_MIGRATION.getName();
ServiceError serviceError = VPlexApiException.errors.commitMigrationFailed(opName, ex);
WorkflowStepCompleter.stepFailed(stepId, serviceError);
}
}
use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexDeviceController method pauseMigrationStep.
public void pauseMigrationStep(URI vplexURI, URI migrationURI, String stepId) {
WorkflowStepCompleter.stepExecuting(stepId);
try {
StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
Migration migration = getDataObject(Migration.class, migrationURI, _dbClient);
client.pauseMigrations(Arrays.asList(migration.getLabel()));
migration.setMigrationStatus(VPlexMigrationInfo.MigrationStatus.PAUSED.getStatusValue());
_dbClient.updateObject(migration);
WorkflowStepCompleter.stepSucceded(stepId);
} catch (Exception ex) {
_log.error("Exception pausing migration: ", ex);
String opName = ResourceOperationTypeEnum.PAUSE_MIGRATION.getName();
ServiceError serviceError = VPlexApiException.errors.operateMigrationFailed(opName, ex);
WorkflowStepCompleter.stepFailed(stepId, serviceError);
}
}
use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class VplexDBCkr method checkVolumesOnVplex.
public void checkVolumesOnVplex(URI vplexSystemURI, boolean deleteInvalidVolumes) {
URIQueryResultList result = new URIQueryResultList();
List<URI> deletevirtualvolumeURIs = new ArrayList<URI>();
int nerrors = 0;
int invalidVolumeCount = 0;
dbClient.queryByConstraint(ContainmentConstraint.Factory.getStorageDeviceVolumeConstraint(vplexSystemURI), result);
Iterator<URI> iter = result.iterator();
VPlexApiClient client = getVPlexApiClient(vplexSystemURI);
// Get all the virtual volumes. We elect for shallow here as it's quicker-
// we will spend time below getting details.
writeLog("Retrieving all virtual volumes... this will take some time...");
Map<String, VPlexVirtualVolumeInfo> vvInfoMap = client.getVirtualVolumes(true);
List<VPlexStorageViewInfo> storageViews = client.getStorageViewsLite();
writeLog("... done");
try {
while (iter.hasNext()) {
Volume volume = dbClient.queryObject(Volume.class, iter.next());
if (volume == null || volume.getInactive()) {
continue;
}
writeLog(String.format("Checking volume %s (%s)", volume.getLabel(), volume.getDeviceLabel()));
if (volume.getAssociatedVolumes() == null || volume.getAssociatedVolumes().isEmpty()) {
writeLog(String.format("Volume %s (%s) has no associated volumes... skipping", volume.getLabel(), volume.getDeviceLabel()));
continue;
}
VPlexVirtualVolumeInfo vvInfo = vvInfoMap.get(volume.getDeviceLabel());
if (vvInfo == null) {
writeLog(String.format("ERROR: Volume %s (%s) had no VirtualVolumeInfo in VPlex", volume.getLabel(), volume.getDeviceLabel()));
deletevirtualvolumeURIs.add(volume.getId());
nerrors++;
invalidVolumeCount++;
continue;
}
if ((null != vvInfo.getWwn()) && (null != volume.getWWN())) {
if (vvInfo.getName().equals(volume.getDeviceLabel())) {
if (vvInfo.getWwn().toUpperCase().equals(volume.getWWN().toUpperCase())) {
writeLog(String.format("Virtual Volume %s wwn %s matches VPLEX", vvInfo.getName(), vvInfo.getWwn()));
} else {
writeLog(String.format("ERROR: Virtual Volume %s wwn %s in VPLEX mismatch with viprdb %s", vvInfo.getName(), vvInfo.getWwn(), volume.getWWN()));
deletevirtualvolumeURIs.add(volume.getId());
invalidVolumeCount++;
nerrors++;
}
}
}
StringSet wwns = new StringSet();
for (String cluster : vvInfo.getClusters()) {
Map<String, VPlexStorageVolumeInfo> svInfoMap = client.getStorageVolumeInfoForDevice(vvInfo.getSupportingDevice(), vvInfo.getLocality(), cluster, false);
for (String wwn : svInfoMap.keySet()) {
// writeLog("adding wwn " + wwn.toUpperCase());
wwns.add(wwn.toUpperCase());
VPlexStorageVolumeInfo svInfo = svInfoMap.get(wwn);
writeLog(String.format("StorageVolume wwn %s name %s cluster %s", wwn, svInfo.getName(), cluster));
}
}
// Now check associated volumes against the wwns.
for (String associatedVolume : volume.getAssociatedVolumes()) {
Volume assocVolume = dbClient.queryObject(Volume.class, URI.create(associatedVolume));
if (assocVolume == null) {
writeLog("Associated volunme not found in database... skipping: " + associatedVolume);
continue;
}
if (wwns.contains(assocVolume.getWWN().toUpperCase())) {
writeLog(String.format("Volume %s wwn %s matches VPLEX", assocVolume.getLabel(), assocVolume.getWWN()));
} else {
writeLog(String.format("ERROR: Volume %s wwn %s is not present in VPLEX", assocVolume.getLabel(), assocVolume.getWWN()));
nerrors++;
}
}
List<ExportMask> exportMaskListInDB = isVolumeExported(volume.getId());
if (null != exportMaskListInDB) {
for (ExportMask exportMaskInDB : exportMaskListInDB) {
boolean found = false;
boolean storageviewfound = false;
for (VPlexStorageViewInfo storageView : storageViews) {
if (storageView.getName().equals(exportMaskInDB.getMaskName())) {
storageviewfound = true;
for (String volumeNameStr : storageView.getVirtualVolumes()) {
String[] tokens = volumeNameStr.split(",");
String volumeName = tokens[1];
if (volumeName.equals(volume.getDeviceLabel())) {
found = true;
break;
}
}
if (!found) {
writeLog(String.format("ERROR: volume %s is in exportmask %s in viprdb but not in vplex storageview %s", volume.getDeviceLabel(), exportMaskInDB.getMaskName(), storageView.getName()));
nerrors++;
}
break;
}
}
if (!storageviewfound) {
writeLog(String.format("ERROR: volume %s is in exportmask %s in viprdb but storageview not found in vplex", volume.getDeviceLabel(), exportMaskInDB.getMaskName()));
nerrors++;
}
}
}
for (VPlexStorageViewInfo storageView : storageViews) {
writeLog(String.format("Checking Storageview %s", storageView.getName()));
for (String volumeNameStr : storageView.getVirtualVolumes()) {
String[] tokens = volumeNameStr.split(",");
String volumeName = tokens[1];
if (volumeName.equals(volume.getDeviceLabel())) {
boolean storageviewfound = false;
if (null != exportMaskListInDB) {
for (ExportMask exportMaskInDB : exportMaskListInDB) {
if (storageView.getName().equals(exportMaskInDB.getMaskName())) {
storageviewfound = true;
break;
}
}
}
if (!storageviewfound) {
writeLog(String.format("ERROR: volume %s is in vplex storageview %s but not in viprdb exportmask", volumeName, storageView.getName()));
nerrors++;
}
}
}
}
}
if (deleteInvalidVolumes) {
writeLog("deleting invalid volumes");
// deleting virtual volumes that no longer exist in vplex
List<VolumeDescriptor> volumeDescriptors = getDescriptorsForVolumesToBeDeleted(vplexSystemURI, deletevirtualvolumeURIs, VolumeDeleteTypeEnum.VIPR_ONLY.name());
cleanupForViPROnlyDelete(volumeDescriptors);
// Mark them inactive. Note that some of the volumes may be mirrors,
// which have a different database type.
List<VolumeDescriptor> descriptorsForMirrors = VolumeDescriptor.getDescriptors(volumeDescriptors, VolumeDescriptor.Type.BLOCK_MIRROR);
dbClient.markForDeletion(dbClient.queryObject(BlockMirror.class, VolumeDescriptor.getVolumeURIs(descriptorsForMirrors)));
List<VolumeDescriptor> descriptorsForVolumes = VolumeDescriptor.filterByType(volumeDescriptors, null, new VolumeDescriptor.Type[] { VolumeDescriptor.Type.BLOCK_MIRROR });
dbClient.markForDeletion(dbClient.queryObject(Volume.class, VolumeDescriptor.getVolumeURIs(descriptorsForVolumes)));
// Update the task status for each volume
for (URI volumeURI : deletevirtualvolumeURIs) {
Volume volume = dbClient.queryObject(Volume.class, volumeURI);
dbClient.updateObject(volume);
}
}
} catch (Exception e) {
writeLog(String.format("Exception: while verifying virtual volumes", e));
}
// List<URI> maskUrislist = new ArrayList<URI>();;
// maskUrislist.add(URI.create("urn:storageos:ExportMask:3742e612-cc93-422b-a1a5-43490e0fe8ea:vdc1"));
// for (URI mskUri : maskUrislist) {
// boolean found = false;
// ExportMask exportMaskUri = dbClient.queryObject(ExportMask.class, mskUri);
// if (exportMaskUri == null || exportMaskUri.getInactive()) {
// continue;
// }
// writeLog(String.format("exportMaskUri in ViPR DB is %s", exportMaskUri.getMaskName()));
// for (VPlexStorageViewInfo storageView : storageViews) {
// if (storageView.getName().equals(exportMaskUri.getMaskName())) {
// found = true;
// }
// }
// if(!found) {
// writeLog(String.format("ERROR: exportMask not found in vplex %s",exportMaskUri.getMaskName()));
// nerrors++;
// }
// }
writeLog("Total errors for this VPLEX: " + nerrors);
}
use of com.emc.storageos.vplex.api.VPlexApiClient 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);
}
}
Aggregations