use of com.emc.storageos.vplex.api.VPlexApiClient 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.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexDeviceController method rollbackCreateMirrors.
/**
* Rollback any mirror device previously created.
*
* @param vplexURI
* URI of the VPlex StorageSystem
* @param vplexMirrorURIs
* URI of the mirrors
* @param executeStepId
* step Id of the execute step; used to retrieve rollback data.
* @param stepId
* The stepId used for completion.
*
* @throws WorkflowException
* When an error occurs updating the workflow step
* state.
*/
public void rollbackCreateMirrors(URI vplexURI, List<URI> vplexMirrorURIs, String executeStepId, String stepId) throws WorkflowException {
try {
List<VolumeInfo> rollbackData = (List<VolumeInfo>) _workflowService.loadStepData(executeStepId);
if (rollbackData != null) {
WorkflowStepCompleter.stepExecuting(stepId);
// Get the API client.
StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
// For each mirror device attempted, try and rollback.
for (VolumeInfo rollbackInfo : rollbackData) {
client.deleteLocalDevice(rollbackInfo);
}
}
} catch (Exception ex) {
_log.error("Exception rolling back: " + ex.getLocalizedMessage());
} finally {
// cleanup vplex mirror object in Database
for (URI uri : vplexMirrorURIs) {
VplexMirror vplexMirror = _dbClient.queryObject(VplexMirror.class, uri);
if (vplexMirror != null) {
Volume sourceVplexVolume = _dbClient.queryObject(Volume.class, vplexMirror.getSource());
sourceVplexVolume.getMirrors().remove(vplexMirror.getId().toString());
_dbClient.updateObject(sourceVplexVolume);
_dbClient.removeObject(vplexMirror);
}
}
WorkflowStepCompleter.stepSucceded(stepId);
}
}
use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexCacheStatusJob method poll.
/**
* {@inheritDoc}
*/
public JobPollResult poll(JobContext jobContext, long trackingPeriodInMillis) {
s_logger.debug("Polled cache status job");
// Get the DB client from the job context.
DbClient dbClient = jobContext.getDbClient();
// Get the VPLEX volume associated with the cache invalidation job.
Volume vplexVolume = dbClient.queryObject(Volume.class, _taskCompleter.getId());
String vplexVolumeName = vplexVolume.getDeviceLabel();
s_logger.debug("VPLEX volume is {}", vplexVolume.getId());
// Get the VPlex storage system for that VPLEX volume.
StorageSystem vplexSystem = dbClient.queryObject(StorageSystem.class, vplexVolume.getStorageController());
s_logger.debug("VPlex system is {}", vplexSystem.getId());
try {
// Update the job info.
_pollResult.setJobName(vplexVolumeName);
_pollResult.setJobId(vplexSystem.getId().toString());
_pollResult.setJobPercentComplete(0);
s_logger.debug("Updated poll result");
// Get the VPlex API client for this VPlex storage system
// and get the cache invalidation status for the VPLEX volume.
VPlexApiClient vplexApiClient = VPlexControllerUtils.getVPlexAPIClient(jobContext.getVPlexApiFactory(), vplexSystem, dbClient);
s_logger.debug("Got VPlex APi Client");
VPlexCacheStatusInfo cacheStatusInfo = vplexApiClient.getCacheStatus(vplexVolumeName);
s_logger.debug("Got cache status info from VPlex");
// Examine the status.
InvalidateStatus invalidateStatus = cacheStatusInfo.getCacheInvalidateStatus();
if (InvalidateStatus.SUCCESS.equals(invalidateStatus)) {
// Completed successfully
s_logger.info("Cache Invalidate for Volume: {} completed sucessfully", vplexVolume.getId());
_pollResult.setJobPercentComplete(100);
_status = JobStatus.SUCCESS;
} else if (InvalidateStatus.FAILED.equals(invalidateStatus)) {
// Failed.
s_logger.info("Cache Invalidate for Volume : {} failed", vplexVolume.getId());
_pollResult.setJobPercentComplete(100);
_errorDescription = cacheStatusInfo.getCacheInvalidateFailedMessage();
_status = JobStatus.FAILED;
}
} catch (Exception e) {
_errorDescription = e.getMessage();
s_logger.error(String.format("Unexpected error getting cache status for volume %s on VPlex %s: %s", vplexVolume.getId(), vplexSystem.getId(), _errorDescription), e);
_status = JobStatus.FAILED;
} finally {
s_logger.debug("Updating status {}", _status);
updateStatus(jobContext);
}
_pollResult.setJobStatus(_status);
_pollResult.setErrorDescription(_errorDescription);
return _pollResult;
}
use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class ImplicitUnManagedObjectsMatcher method matchVirtualPoolWithUnManagedVolumeVPLEX.
/**
* Match virtual pool with unmanaged VPLEX volumes. Uses a different criteria than straight block matchers.
* Currently this method will only add virtual pools to an unmanaged volume. It will not remove them.
* This code is loosely based on VPlexCommunicationInterface.updateUnmanagedVolume() content, but is changed
* to suit this specific case where a single virtual pool is getting added/updated.
*
* @param modifiedUnManagedVolumes list of volumes to add to
* @param vpool virtual pool (new or updated)
* @param dbClient dbclient
*/
private static void matchVirtualPoolWithUnManagedVolumeVPLEX(List<UnManagedVolume> modifiedUnManagedVolumes, VirtualPool vpool, DbClient dbClient) {
// This method only applies to VPLEX vpools
if (!VirtualPool.vPoolSpecifiesHighAvailability(vpool)) {
return;
}
_log.info("START: matching virtual pool with unmanaged volume for VPLEX");
// Get all UnManagedVolumes where storageDevice is a StorageSystem where type = VPLEX
Joiner j = new Joiner(dbClient).join(StorageSystem.class, "ss").match("systemType", "vplex").join("ss", UnManagedVolume.class, "umv", "storageDevice").go();
// From the joiner, get the StorageSystems (which is a small amount of objects) and the UMVs (which is large, so get URIs and use iter)
Map<StorageSystem, List<URI>> ssToUmvMap = j.pushList("ss").pushUris("umv").map();
for (Entry<StorageSystem, List<URI>> ssToUmvEntry : ssToUmvMap.entrySet()) {
StorageSystem vplex = ssToUmvEntry.getKey();
// fetch the current mapping of VPLEX cluster ids to cluster names (e.g., "1"=>"cluster-1";"2"=>"cluster-2")
// the cluster names can be changed by the VPLEX admin, so we cannot rely on the default cluster-1 or cluster-2
Map<String, String> clusterIdToNameMap = null;
try {
VPlexApiClient client = VPlexControllerUtils.getVPlexAPIClient(VPlexApiFactory.getInstance(), vplex, dbClient);
clusterIdToNameMap = client.getClusterIdToNameMap();
} catch (Exception ex) {
_log.warn("Exception caught while getting cluster name info from VPLEX {}", vplex.forDisplay());
}
if (null == clusterIdToNameMap || clusterIdToNameMap.isEmpty()) {
_log.warn("Could not update virtual pool matches for VPLEX {} because cluster name info couldn't be retrieved", vplex.forDisplay());
continue;
}
// Create a map of virtual arrays to their respective VPLEX cluster (a varray is not allowed to have both VPLEX clusters)
Map<String, String> varrayToClusterIdMap = new HashMap<String, String>();
// Since there may be a lot of unmanaged volumes to process, we use the iterative query
Iterator<UnManagedVolume> volumeIter = dbClient.queryIterativeObjects(UnManagedVolume.class, ssToUmvEntry.getValue());
while (volumeIter.hasNext()) {
UnManagedVolume volume = volumeIter.next();
String highAvailability = null;
if (volume.getVolumeInformation().get(SupportedVolumeInformation.VPLEX_LOCALITY.toString()) != null) {
String haFound = volume.getVolumeInformation().get(SupportedVolumeInformation.VPLEX_LOCALITY.toString()).iterator().next();
if (haFound.equalsIgnoreCase(LOCAL)) {
highAvailability = VirtualPool.HighAvailabilityType.vplex_local.name();
} else {
highAvailability = VirtualPool.HighAvailabilityType.vplex_distributed.name();
}
}
_log.debug("finding valid virtual pools for UnManagedVolume {}", volume.getLabel());
// - The vpool is RPVPLEX and this is a VPLEX local volume (likely a journal)
if (!vpool.getHighAvailability().equals(highAvailability) && !(VirtualPool.vPoolSpecifiesRPVPlex(vpool) && highAvailability.equals(VirtualPool.HighAvailabilityType.vplex_local.name()))) {
_log.info(String.format(" virtual pool %s is not valid because " + "its high availability setting does not match the unmanaged volume %s", vpool.getLabel(), volume.forDisplay()));
continue;
}
// If the volume is in a CG, the vpool must specify multi-volume consistency.
Boolean mvConsistency = vpool.getMultivolumeConsistency();
if ((TRUE.equals(volume.getVolumeCharacterstics().get(SupportedVolumeCharacterstics.IS_VOLUME_ADDED_TO_CONSISTENCYGROUP.toString()))) && ((mvConsistency == null) || (mvConsistency == Boolean.FALSE))) {
_log.info(String.format(" virtual pool %s is not valid because it does not have the " + "multi-volume consistency flag set, and the unmanaged volume %s is in a consistency group", vpool.getLabel(), volume.forDisplay()));
continue;
}
StringSet volumeClusters = new StringSet();
if (volume.getVolumeInformation().get(SupportedVolumeInformation.VPLEX_CLUSTER_IDS.toString()) != null) {
volumeClusters.addAll(volume.getVolumeInformation().get(SupportedVolumeInformation.VPLEX_CLUSTER_IDS.toString()));
}
// VPool must be assigned to a varray corresponding to volume's clusters.
StringSet varraysForVpool = vpool.getVirtualArrays();
for (String varrayId : varraysForVpool) {
String varrayClusterId = varrayToClusterIdMap.get(varrayId);
if (null == varrayClusterId) {
varrayClusterId = ConnectivityUtil.getVplexClusterForVarray(URI.create(varrayId), vplex.getId(), dbClient);
varrayToClusterIdMap.put(varrayId, varrayClusterId);
}
if (!ConnectivityUtil.CLUSTER_UNKNOWN.equals(varrayClusterId)) {
String varrayClusterName = clusterIdToNameMap.get(varrayClusterId);
if (volumeClusters.contains(varrayClusterName)) {
if (volume.getSupportedVpoolUris() == null) {
volume.setSupportedVpoolUris(new StringSet());
}
volume.getSupportedVpoolUris().add(vpool.getId().toString());
List<UnManagedVolume> backendVols = VplexBackendIngestionContext.findBackendUnManagedVolumes(volume, dbClient);
if (backendVols != null) {
for (UnManagedVolume backendVol : backendVols) {
if (backendVol.getSupportedVpoolUris() == null) {
backendVol.setSupportedVpoolUris(new StringSet());
}
backendVol.getSupportedVpoolUris().add(vpool.getId().toString());
modifiedUnManagedVolumes.add(backendVol);
}
}
modifiedUnManagedVolumes.add(volume);
break;
}
}
}
if (!modifiedUnManagedVolumes.contains(volume)) {
_log.info(String.format(" virtual pool %s is not valid because " + "volume %s resides on a cluster that does not match the varray(s) associated with the vpool", vpool.getLabel(), volume.forDisplay()));
}
}
}
_log.info("END: matching virtual pool with unmanaged volume for VPLEX");
}
use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexDeviceController method invalidateCache.
/**
* Called to invalidate the read cache for a VPLEX volume when
* restoring a snapshot.
*
* @param vplexURI
* The URI of the VPLEX system.
* @param vplexVolumeURI
* The URI of a VPLEX volume.
* @param stepId
* The workflow step identifier.
*/
public void invalidateCache(URI vplexURI, URI vplexVolumeURI, String stepId) {
_log.info("Executing invalidate cache for volume {} on VPLEX {}", vplexVolumeURI, vplexURI);
try {
// Update workflow step.
WorkflowStepCompleter.stepExecuting(stepId);
// Get the API client.
StorageSystem vplexSystem = getDataObject(StorageSystem.class, vplexURI, _dbClient);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplexSystem, _dbClient);
_log.info("Got VPLEX API client");
// Get the VPLEX volume.
Volume vplexVolume = getDataObject(Volume.class, vplexVolumeURI, _dbClient);
String vplexVolumeName = vplexVolume.getDeviceLabel();
_log.info("Got VPLEX volumes");
// Invalidate the cache for the volume.
boolean stillInProgress = client.invalidateVirtualVolumeCache(vplexVolumeName);
_log.info("Invalidated the VPLEX volume cache");
// invalidation completes.
if (stillInProgress) {
CacheStatusTaskCompleter invalidateCompleter = new CacheStatusTaskCompleter(vplexVolumeURI, stepId);
VPlexCacheStatusJob cacheStatusJob = new VPlexCacheStatusJob(invalidateCompleter);
ControllerServiceImpl.enqueueJob(new QueueJob(cacheStatusJob));
_log.info("Queued job to monitor migration progress.");
} else {
// Update workflow step state to success.
WorkflowStepCompleter.stepSucceded(stepId);
_log.info("Updated workflow step state to success");
}
} catch (VPlexApiException vae) {
_log.error("Exception invalidating VPLEX volume cache " + vae.getMessage(), vae);
WorkflowStepCompleter.stepFailed(stepId, vae);
} catch (Exception e) {
_log.error("Exception invalidating VPLEX volume cache " + e.getMessage(), e);
WorkflowStepCompleter.stepFailed(stepId, VPlexApiException.exceptions.failedInvalidatingVolumeCache(vplexVolumeURI.toString(), e));
}
}
Aggregations