Search in sources :

Example 36 with VPlexApiClient

use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.

the class VPlexDeviceController method portRebalance.

@Override
public void portRebalance(URI vplex, URI exportGroupURI, URI varray, URI exportMaskURI, Map<URI, List<URI>> adjustedPaths, Map<URI, List<URI>> removedPaths, boolean isAdd, String stepId) throws Exception {
    // Retrieve the ExportGroup and ExportMask and validate
    ExportGroup exportGroup = _dbClient.queryObject(ExportGroup.class, exportGroupURI);
    ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
    if (exportGroup == null || exportMask == null || exportGroup.getInactive() || exportMask.getInactive() || !exportGroup.hasMask(exportMaskURI)) {
        String reason = String.format("Bad exportGroup %s or exportMask %s", exportGroupURI, exportMaskURI);
        _log.error(reason);
        ServiceCoded coded = WorkflowException.exceptions.workflowConstructionError(reason);
        WorkflowStepCompleter.stepFailed(stepId, coded);
        return;
    }
    // Check if the ExportMask is in the desired varray (in cross-coupled ExportGroups)
    if (!ExportMaskUtils.exportMaskInVarray(_dbClient, exportMask, varray)) {
        _log.info(String.format("ExportMask %s (%s) not in specified varray %s", exportMask.getMaskName(), exportMask.getId(), varray));
        WorkflowStepCompleter.stepSucceeded(stepId, String.format("No operation done: Mask not in specified varray %s", varray));
        return;
    }
    // Refresh the ExportMask so we have the latest data.
    StorageSystem vplexSystem = getDataObject(StorageSystem.class, vplex, _dbClient);
    VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
    String vplexClusterName = VPlexUtil.getVplexClusterName(exportMask, vplex, client, _dbClient);
    VPlexStorageViewInfo storageView = client.getStorageView(vplexClusterName, exportMask.getMaskName());
    _log.info("Processing and Refreshing ExportMask {}", exportMask.getMaskName());
    Map<String, String> targetPortToPwwnMap = VPlexControllerUtils.getTargetPortToPwwnMap(client, vplexClusterName);
    VPlexControllerUtils.refreshExportMask(_dbClient, storageView, exportMask, targetPortToPwwnMap, _networkDeviceController);
    // Determine hosts in ExportMask
    Set<URI> hostsInExportMask = new HashSet<URI>();
    Set<String> hostNames = ExportMaskUtils.getHostNamesInMask(exportMask, _dbClient);
    Set<Initiator> initiatorsInMask = ExportMaskUtils.getInitiatorsForExportMask(_dbClient, exportMask, null);
    for (Initiator initiator : initiatorsInMask) {
        if (initiator.getHost() != null) {
            hostsInExportMask.add(initiator.getHost());
        }
    }
    boolean sharedMask = (hostsInExportMask.size() > 1);
    if (isAdd) {
        // Processing added paths only
        Workflow workflow = _workflowService.getNewWorkflow(this, "portRebalance", false, stepId);
        // Determine initiators and targets to be added.
        // These are initiators not in mask that are in a host in the mask.
        // Earlier versions of the Vplex code may not have had all the initiators in the mask, as
        // earlier code only put initiators in the Storage View for which ports were added.
        // Targets to be added may be on existing initiators or newly added initiators.
        List<URI> initiatorsToAdd = new ArrayList<URI>();
        List<URI> targetsToAdd = new ArrayList<URI>();
        for (URI initiatorURI : adjustedPaths.keySet()) {
            if (!exportMask.hasInitiator(initiatorURI.toString())) {
                // Initiator not in ExportMask
                Initiator initiator = _dbClient.queryObject(Initiator.class, initiatorURI);
                if (initiator != null && !initiator.getInactive()) {
                    if (hostsInExportMask.contains(initiator.getHost())) {
                        initiatorsToAdd.add(initiatorURI);
                        for (URI targetURI : adjustedPaths.get(initiatorURI)) {
                            if (!exportMask.hasTargets(Arrays.asList(targetURI)) && !targetsToAdd.contains(targetURI)) {
                                targetsToAdd.add(targetURI);
                            }
                        }
                    }
                }
            } else {
                // Initiator already in ExportMask, look for additional targets
                for (URI targetURI : adjustedPaths.get(initiatorURI)) {
                    if (!exportMask.hasTargets(Arrays.asList(targetURI)) && !targetsToAdd.contains(targetURI)) {
                        targetsToAdd.add(targetURI);
                    }
                }
            }
        }
        _log.info("Targets to add: " + targetsToAdd.toString());
        _log.info("Initiators to add: " + initiatorsToAdd.toString());
        // Invoke either storageViewAddInitiators if there are initiators to be added (it will add targets also),
        // or storageViewAddStoragePorts if no initiators to be added (which adds only targets).
        Workflow.Method addPathsMethod = null;
        if (!initiatorsToAdd.isEmpty() || !targetsToAdd.isEmpty()) {
            String addInitiatorStepId = workflow.createStepId();
            ExportMaskAddInitiatorCompleter completer = new ExportMaskAddInitiatorCompleter(exportGroupURI, exportMaskURI, initiatorsToAdd, targetsToAdd, addInitiatorStepId);
            ;
            if (!initiatorsToAdd.isEmpty()) {
                addPathsMethod = storageViewAddInitiatorsMethod(vplex, exportGroupURI, exportMaskURI, initiatorsToAdd, targetsToAdd, sharedMask, completer);
            } else if (!targetsToAdd.isEmpty()) {
                addPathsMethod = storageViewAddStoragePortsMethod(vplex, exportGroupURI, exportMaskURI, targetsToAdd, completer);
            }
            String description = String.format("Adding paths to ExportMask %s Hosts %s", exportMask.getMaskName(), hostNames.toString());
            workflow.createStep("addPaths", description, null, vplex, vplexSystem.getSystemType(), this.getClass(), addPathsMethod, null, false, addInitiatorStepId);
            ExportMaskAddPathsCompleter workflowCompleter = new ExportMaskAddPathsCompleter(exportGroupURI, exportMaskURI, stepId);
            workflow.executePlan(workflowCompleter, description + " completed successfully");
            return;
        }
    } else {
        // Processing the paths to be removed only, Paths not in the removedPaths map will be retained.
        // Note that we only remove ports (targets), never initiators.
        Workflow workflow = _workflowService.getNewWorkflow(this, "portRebalance", false, stepId);
        // Compute the targets to be removed.
        Set<URI> targetsToBeRemoved = ExportMaskUtils.getAllPortsInZoneMap(removedPaths);
        Collection<URI> targetsInMask = Collections2.transform(exportMask.getStoragePorts(), CommonTransformerFunctions.FCTN_STRING_TO_URI);
        targetsToBeRemoved.retainAll(targetsInMask);
        Set<URI> targetsToBeRetained = ExportMaskUtils.getAllPortsInZoneMap(adjustedPaths);
        targetsToBeRemoved.removeAll(targetsToBeRetained);
        List<URI> portsToBeRemoved = new ArrayList<URI>(targetsToBeRemoved);
        _log.info("Targets to be removed: " + portsToBeRemoved.toString());
        // Call storageViewRemoveStoragePorts to remove any necessary targets.
        Workflow.Method removePathsMethod = null;
        if (!portsToBeRemoved.isEmpty()) {
            String removeInitiatorStepId = workflow.createStepId();
            removePathsMethod = storageViewRemoveStoragePortsMethod(vplex, exportGroupURI, exportMaskURI, portsToBeRemoved, null);
            String description = String.format("Removing paths to ExportMask %s Hosts %s", exportMask.getMaskName(), hostNames.toString());
            workflow.createStep("removePaths", description, null, vplex, vplexSystem.getSystemType(), this.getClass(), removePathsMethod, null, false, removeInitiatorStepId);
            ExportMaskRemovePathsCompleter workflowCompleter = new ExportMaskRemovePathsCompleter(exportGroupURI, exportMaskURI, stepId);
            workflowCompleter.setRemovedStoragePorts(portsToBeRemoved);
            workflow.executePlan(workflowCompleter, description + " completed successfully");
            return;
        }
    }
    // Apparently nothing to do, return success
    WorkflowStepCompleter.stepSucceeded(stepId, "No operation performed on VPLEX mask");
}
Also used : VPlexStorageViewInfo(com.emc.storageos.vplex.api.VPlexStorageViewInfo) ExportMask(com.emc.storageos.db.client.model.ExportMask) ExportMaskAddPathsCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportMaskAddPathsCompleter) ArrayList(java.util.ArrayList) ExportMaskAddInitiatorCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportMaskAddInitiatorCompleter) Workflow(com.emc.storageos.workflow.Workflow) NamedURI(com.emc.storageos.db.client.model.NamedURI) URI(java.net.URI) ExportGroup(com.emc.storageos.db.client.model.ExportGroup) Initiator(com.emc.storageos.db.client.model.Initiator) ServiceCoded(com.emc.storageos.svcs.errorhandling.model.ServiceCoded) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient) ExportMaskRemovePathsCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportMaskRemovePathsCompleter) StorageSystem(com.emc.storageos.db.client.model.StorageSystem) HashSet(java.util.HashSet)

Example 37 with VPlexApiClient

use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.

the class VPlexDeviceController method createMirrors.

/**
 * Do the creation of a VPlex Mirror device and attach it as a mirror to the Virtual Volume.
 * This is called as a Workflow Step.
 * NOTE: The parameters here must match createMirrorsMethod above (except stepId).
 *
 * @param vplexURI
 *            URI of the VPlex StorageSystem
 * @param vplexMirrorURIs
 *            URI of the mirrors to be created.
 * @param workflowTaskId
 *            The workflow taskId.
 * @param stepId
 *            The stepId used for completion.
 *
 * @throws WorkflowException
 *             When an error occurs updating the workflow step
 *             state.
 */
public void createMirrors(URI vplexURI, List<URI> vplexMirrorURIs, String workflowTaskId, String stepId) throws WorkflowException {
    List<VolumeInfo> rollbackData = new ArrayList<VolumeInfo>();
    List<URI> createdVplexMirrorURIs = new ArrayList<URI>();
    VplexMirrorTaskCompleter completer = new VplexMirrorTaskCompleter(VplexMirror.class, vplexMirrorURIs, workflowTaskId);
    try {
        WorkflowStepCompleter.stepExecuting(stepId);
        // Get the API client.
        StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
        VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
        // Make a map of StorageSystem ids to Storage System
        Map<URI, StorageSystem> storageMap = new HashMap<URI, StorageSystem>();
        // Make a map of Mirrors to Storage Volumes.
        Map<VplexMirror, Volume> mirrorMap = new HashMap<VplexMirror, Volume>();
        for (URI vplexMirrorURI : vplexMirrorURIs) {
            VplexMirror vplexMirror = getDataObject(VplexMirror.class, vplexMirrorURI, _dbClient);
            // Find the underlying Storage Volume, there will be only one associated storage volume
            for (String associatedVolume : vplexMirror.getAssociatedVolumes()) {
                Volume storageVolume = getDataObject(Volume.class, new URI(associatedVolume), _dbClient);
                URI storageSystemId = storageVolume.getStorageController();
                if (storageMap.containsKey(storageSystemId) == false) {
                    StorageSystem storage = _dbClient.queryObject(StorageSystem.class, storageSystemId);
                    storageMap.put(storageSystemId, storage);
                }
                mirrorMap.put(vplexMirror, storageVolume);
            }
        }
        // Now make a call to the VPlexAPIClient.createDeviceAndAttachAsMirror for each vplex mirror.
        StringBuilder buf = new StringBuilder();
        buf.append("Vplex: " + vplexURI + " created mirror(s): ");
        for (VplexMirror vplexMirror : mirrorMap.keySet()) {
            URI vplexMirrorId = vplexMirror.getId();
            Volume sourceVplexVolume = getDataObject(Volume.class, vplexMirror.getSource().getURI(), _dbClient);
            VPlexVirtualVolumeInfo vplexVolumeInfo = new VPlexVirtualVolumeInfo();
            vplexVolumeInfo.setName(sourceVplexVolume.getDeviceLabel());
            vplexVolumeInfo.setPath(sourceVplexVolume.getNativeId());
            if (null == sourceVplexVolume.getAssociatedVolumes() || sourceVplexVolume.getAssociatedVolumes().isEmpty()) {
                _log.error("VPLEX volume {} has no backend volumes.", sourceVplexVolume.forDisplay());
                throw InternalServerErrorException.internalServerErrors.noAssociatedVolumesForVPLEXVolume(sourceVplexVolume.forDisplay());
            }
            if (sourceVplexVolume.getAssociatedVolumes().size() > 1) {
                vplexVolumeInfo.setLocality(VPlexApiConstants.DISTRIBUTED_VIRTUAL_VOLUME);
            } else {
                vplexVolumeInfo.setLocality(VPlexApiConstants.LOCAL_VIRTUAL_VOLUME);
            }
            _log.info(String.format("Creating mirror: %s (%s)", vplexMirror.getLabel(), vplexMirrorId));
            Volume storageVolume = mirrorMap.get(vplexMirror);
            long totalProvisioned = storageVolume.getProvisionedCapacity();
            StorageSystem storage = storageMap.get(storageVolume.getStorageController());
            List<String> itls = VPlexControllerUtils.getVolumeITLs(storageVolume);
            VolumeInfo vinfo = new VolumeInfo(storage.getNativeGuid(), storage.getSystemType(), storageVolume.getWWN().toUpperCase().replaceAll(":", ""), storageVolume.getNativeId(), storageVolume.getThinlyProvisioned().booleanValue(), itls);
            // Update rollback information.
            rollbackData.add(vinfo);
            List<VolumeInfo> vinfos = new ArrayList<VolumeInfo>();
            vinfos.add(vinfo);
            _workflowService.storeStepData(stepId, rollbackData);
            // Make the call to create device and attach it as mirror to the source virtual volume device.
            VPlexDeviceInfo vInfo = client.createDeviceAndAttachAsMirror(vplexVolumeInfo, vinfos, true, false);
            buf.append(vInfo.getName() + " ");
            _log.info(String.format("Created mirror : %s path: %s : for virtual volume %s device label %s", vInfo.getName(), vInfo.getPath(), sourceVplexVolume.getLabel(), sourceVplexVolume.getDeviceLabel()));
            vplexMirror.setNativeId(vInfo.getPath());
            vplexMirror.setDeviceLabel(vInfo.getName());
            // For Vplex virtual volumes set allocated capacity to 0 (cop-18608)
            vplexMirror.setAllocatedCapacity(0L);
            vplexMirror.setProvisionedCapacity(totalProvisioned);
            if (vplexVolumeInfo.isThinEnabled() != sourceVplexVolume.getThinlyProvisioned()) {
                _log.info("Thin provisioned setting changed after mirror operation to " + vplexVolumeInfo.isThinEnabled());
                sourceVplexVolume.setThinlyProvisioned(vplexVolumeInfo.isThinEnabled());
                _dbClient.updateObject(sourceVplexVolume);
            }
            vplexMirror.setThinlyProvisioned(vplexVolumeInfo.isThinEnabled());
            _dbClient.updateObject(vplexMirror);
            // Record VPLEX volume created event.
            createdVplexMirrorURIs.add(vplexMirrorId);
            recordBourneVplexMirrorEvent(vplexMirrorId, OperationTypeEnum.CREATE_VOLUME_MIRROR.getEvType(true), Operation.Status.ready, OperationTypeEnum.CREATE_VOLUME_MIRROR.getDescription());
        }
        completer.ready(_dbClient);
        WorkflowStepCompleter.stepSucceded(stepId);
    } catch (VPlexApiException vae) {
        _log.error("Exception creating Mirror for the Virtual Volume: " + vae.getMessage(), vae);
        // not created.
        for (URI vplexMirrorURI : vplexMirrorURIs) {
            if (!createdVplexMirrorURIs.contains(vplexMirrorURI)) {
                recordBourneVplexMirrorEvent(vplexMirrorURI, OperationTypeEnum.CREATE_VOLUME_MIRROR.getEvType(false), Operation.Status.error, OperationTypeEnum.CREATE_VOLUME_MIRROR.getDescription());
            }
        }
        failStep(completer, stepId, vae);
    } catch (Exception ex) {
        _log.error("Exception creating Mirror for the Virtual Volume: " + ex.getMessage(), ex);
        // not created.
        for (URI vplexMirrorURI : vplexMirrorURIs) {
            if (!createdVplexMirrorURIs.contains(vplexMirrorURI)) {
                recordBourneVplexMirrorEvent(vplexMirrorURI, OperationTypeEnum.CREATE_VOLUME_MIRROR.getEvType(false), Operation.Status.error, OperationTypeEnum.CREATE_VOLUME_MIRROR.getDescription());
            }
        }
        ServiceError serviceError = VPlexApiException.errors.createMirrorsFailed(ex);
        failStep(completer, stepId, serviceError);
    }
}
Also used : ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) VolumeInfo(com.emc.storageos.vplex.api.clientdata.VolumeInfo) VPlexVirtualVolumeInfo(com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo) NamedURI(com.emc.storageos.db.client.model.NamedURI) URI(java.net.URI) VPlexVirtualVolumeInfo(com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo) VplexMirrorTaskCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.VplexMirrorTaskCompleter) InternalException(com.emc.storageos.svcs.errorhandling.resources.InternalException) InternalServerErrorException(com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) ControllerException(com.emc.storageos.volumecontroller.ControllerException) IOException(java.io.IOException) URISyntaxException(java.net.URISyntaxException) WorkflowException(com.emc.storageos.workflow.WorkflowException) DatabaseException(com.emc.storageos.db.exceptions.DatabaseException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) Volume(com.emc.storageos.db.client.model.Volume) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient) VPlexDeviceInfo(com.emc.storageos.vplex.api.VPlexDeviceInfo) VplexMirror(com.emc.storageos.db.client.model.VplexMirror) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Example 38 with VPlexApiClient

use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.

the class VPlexDeviceController method rollbackCommitMigration.

/**
 * Rollback when a migration commit fails.
 *
 * @param migrationURIs
 *            The URIs for all migrations.
 * @param newVpoolURI
 *            The URI of the new Vpool after migration commit
 * @param newVarrayURI
 *            The URI of the new Varray after migration commit
 * @param commitStepId
 *            The commit step id.
 * @param stepId
 *            The rollback step id.
 *
 * @throws WorkflowException
 */
public void rollbackCommitMigration(List<URI> migrationURIs, URI newVpoolURI, URI newVarrayURI, String commitStepId, String stepId) throws WorkflowException {
    // Update step state to executing.
    WorkflowStepCompleter.stepExecuting(stepId);
    try {
        // Determine if any migration was successfully committed.
        boolean migrationCommitted = false;
        Iterator<URI> migrationIter = migrationURIs.iterator();
        while (migrationIter.hasNext()) {
            URI migrationURI = migrationIter.next();
            Migration migration = _dbClient.queryObject(Migration.class, migrationURI);
            Volume volume = _dbClient.queryObject(Volume.class, migration.getVolume());
            // Check migration database record for committed state
            if (VPlexMigrationInfo.MigrationStatus.COMMITTED.getStatusValue().equals(migration.getMigrationStatus())) {
                migrationCommitted = true;
                updateMigratedVirtualVolumeVpoolAndVarray(volume, newVpoolURI, newVarrayURI);
                _dbClient.updateObject(volume);
                inventoryDeleteMigrationSource(migration.getSource(), volume);
                continue;
            }
            // Check vplex hardware migration records for committed state
            VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, volume.getStorageController(), _dbClient);
            VPlexMigrationInfo migrationInfo = client.getMigrationInfo(migration.getLabel());
            if (migrationInfo.getStatus().equalsIgnoreCase(VPlexMigrationInfo.MigrationStatus.COMMITTED.name())) {
                migrationCommitted = true;
                migration.setMigrationStatus(VPlexMigrationInfo.MigrationStatus.COMMITTED.name());
                _dbClient.updateObject(migration);
                associateVplexVolumeWithMigratedTarget(migration, migration.getVolume());
                updateMigratedVirtualVolumeVpoolAndVarray(volume, newVpoolURI, newVarrayURI);
                _dbClient.updateObject(volume);
                inventoryDeleteMigrationSource(migration.getSource(), volume);
                continue;
            }
        }
        // creation step will cancel the migration.
        if (migrationCommitted) {
            _log.info("The migration has already been committed or the migration state can not be determined, failing rollback");
            // Don't allow rollback to go further than the first error.
            _workflowService.setWorkflowRollbackContOnError(stepId, false);
            ServiceError serviceError = VPlexApiException.errors.cantRollbackCommittedMigration();
            WorkflowStepCompleter.stepFailed(stepId, serviceError);
        } else {
            _log.info("No Migrations are not committed");
            WorkflowStepCompleter.stepSucceded(stepId);
        }
    } catch (Exception e) {
        _log.info("Exception determining commit rollback state", e);
        // Don't allow rollback to go further than the first error.
        _workflowService.setWorkflowRollbackContOnError(stepId, false);
        ServiceError serviceError = VPlexApiException.errors.cantRollbackExceptionDeterminingCommitState(e);
        WorkflowStepCompleter.stepFailed(stepId, serviceError);
    }
}
Also used : VPlexMigrationInfo(com.emc.storageos.vplex.api.VPlexMigrationInfo) ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) Volume(com.emc.storageos.db.client.model.Volume) Migration(com.emc.storageos.db.client.model.Migration) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient) NamedURI(com.emc.storageos.db.client.model.NamedURI) URI(java.net.URI) InternalException(com.emc.storageos.svcs.errorhandling.resources.InternalException) InternalServerErrorException(com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) ControllerException(com.emc.storageos.volumecontroller.ControllerException) IOException(java.io.IOException) URISyntaxException(java.net.URISyntaxException) WorkflowException(com.emc.storageos.workflow.WorkflowException) DatabaseException(com.emc.storageos.db.exceptions.DatabaseException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException)

Example 39 with VPlexApiClient

use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.

the class VPlexDeviceController method attachMirror.

/**
 * Called to reattach the remote mirror for a distributed VPLEX volume upon
 * successfully restoring a native snapshot of the backend source volume.
 *
 * @param vplexURI
 *            The URI of the VPLEX system.
 * @param vplexVolumeURI
 *            The URI of the distributed VPLEX volume.
 * @param cgURI
 *            The URI of the volume's CG or null.
 * @param detachStepId
 *            The Id of the detach mirror step.
 * @param stepId
 *            The workflow step identifier.
 */
public void attachMirror(URI vplexURI, URI vplexVolumeURI, URI cgURI, String detachStepId, String stepId) {
    _log.info("Executing attach mirror to VPLEX volume {} on VPLEX {}", new Object[] { vplexVolumeURI, vplexURI });
    String mirrorDeviceName = "";
    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 volume");
        // Attach the mirror.
        @SuppressWarnings("unchecked") Map<String, String> detachStepData = (Map<String, String>) _workflowService.loadStepData(detachStepId);
        mirrorDeviceName = detachStepData.get(DETACHED_DEVICE);
        client.reattachMirrorToDistributedVolume(vplexVolumeName, mirrorDeviceName);
        _log.info("Attached the mirror");
        // On a subsequent failure, we don't want rollback to try to
        // reattach the mirror as it must have been successful here.
        // If the reattach fails, rollback will just end up trying again.
        detachStepData.put(REATTACH_MIRROR, Boolean.FALSE.toString());
        _workflowService.storeStepData(detachStepId, detachStepData);
        // If on detach it was required to temporarily modify the distributed device name
        // then we restore the correct name now after the volume is back together.
        String modifiedName = null;
        String successWarningMessage = null;
        String restoreDeviceName = detachStepData.get(RESTORE_DEVICE_NAME);
        if (restoreDeviceName != null) {
            try {
                modifiedName = restoreDeviceName.substring(0, VPlexApiConstants.MAX_DEVICE_NAME_LENGTH_FOR_ATTACH_MIRROR);
                client.renameDistributedDevice(modifiedName, restoreDeviceName);
                _log.info("Restored name of distributed device from {} to {}", modifiedName, restoreDeviceName);
            } catch (Exception e) {
                // We don't fail the workflow step in this case, but instead just log a message
                // indicating this error. The distributed device for the volume will just have
                // the modified name.
                successWarningMessage = String.format("Failed renaming the distributed device %s back " + " to its orginal name %s after reattaching remote mirror", modifiedName, restoreDeviceName);
                _log.warn(successWarningMessage);
            }
            // Remove the entry in the step data. We do this regardless of success
            // or failure so that we don't try and rename again in a rollback
            // scenario.
            detachStepData.remove(RESTORE_DEVICE_NAME);
        }
        // If the volume is in a CG, we can now add it back.
        if (cgURI != null) {
            ConsistencyGroupManager consistencyGroupManager = getConsistencyGroupManager(vplexVolume);
            consistencyGroupManager.addVolumeToCg(cgURI, vplexVolume, client, false);
            // No need to try and add it back in rollback if something
            // fails in the step after this point. If the add fails
            // here, rollback will just try again.
            detachStepData.put(ADD_BACK_TO_CG, Boolean.FALSE.toString());
            _workflowService.storeStepData(detachStepId, detachStepData);
            _log.info("Added volume back to consistency group.");
        }
        // Update workflow step state to success.
        if (successWarningMessage != null) {
            WorkflowStepCompleter.stepSucceeded(stepId, successWarningMessage);
        } else {
            WorkflowStepCompleter.stepSucceded(stepId);
        }
        _log.info("Updated workflow step state to success");
    } catch (VPlexApiException vae) {
        _log.error("Exception attaching mirror for VPLEX distributed volume" + vae.getMessage(), vae);
        WorkflowStepCompleter.stepFailed(stepId, vae);
    } catch (Exception e) {
        _log.error("Exception attaching mirror for VPLEX distributed volume " + e.getMessage(), e);
        WorkflowStepCompleter.stepFailed(stepId, VPlexApiException.exceptions.failedAttachingVPlexVolumeMirror(mirrorDeviceName, vplexVolumeURI.toString(), e));
    }
}
Also used : Volume(com.emc.storageos.db.client.model.Volume) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient) Map(java.util.Map) OpStatusMap(com.emc.storageos.db.client.model.OpStatusMap) HashMap(java.util.HashMap) StringMap(com.emc.storageos.db.client.model.StringMap) InternalException(com.emc.storageos.svcs.errorhandling.resources.InternalException) InternalServerErrorException(com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) ControllerException(com.emc.storageos.volumecontroller.ControllerException) IOException(java.io.IOException) URISyntaxException(java.net.URISyntaxException) WorkflowException(com.emc.storageos.workflow.WorkflowException) DatabaseException(com.emc.storageos.db.exceptions.DatabaseException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Example 40 with VPlexApiClient

use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.

the class VPlexDeviceController method exportGroupRemoveInitiators.

/*
     * (non-Javadoc)
     *
     * @see com.emc.storageos.volumecontroller.impl.vplex.VplexController#exportRemoveInitiator(java.net.URI,
     * java.net.URI, java.net.URI,
     * java.lang.String)
     */
@Override
public void exportGroupRemoveInitiators(URI vplexURI, URI exportURI, List<URI> initiatorURIs, String opId) throws ControllerException {
    try {
        StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
        ExportGroup exportGroup = getDataObject(ExportGroup.class, exportURI, _dbClient);
        ExportRemoveInitiatorCompleter completer = new ExportRemoveInitiatorCompleter(exportURI, initiatorURIs, opId);
        Workflow workflow = _workflowService.getNewWorkflow(this, "exportRemoveInitiator", true, opId);
        // true if Workflow has a Step
        boolean hasStep = false;
        Initiator firstInitiator = _dbClient.queryObject(Initiator.class, initiatorURIs.get(0));
        StringBuffer errorMessages = new StringBuffer();
        boolean isValidationNeeded = validatorConfig.isValidationEnabled() && !ExportUtils.checkIfInitiatorsForRP(Arrays.asList(firstInitiator));
        _log.info("Orchestration level validation needed : {}", isValidationNeeded);
        _log.info("starting remove initiators for export group: " + exportGroup.toString());
        _log.info("request is to remove these initiators: " + initiatorURIs);
        initiatorURIs = VPlexUtil.filterInitiatorsForVplex(_dbClient, initiatorURIs);
        // get a map of host URI to a list of Initiators in that Host
        Map<URI, List<Initiator>> hostInitiatorsMap = VPlexUtil.makeHostInitiatorsMap(initiatorURIs, _dbClient);
        VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
        // Loop, processing each host separately.
        for (URI hostURI : hostInitiatorsMap.keySet()) {
            _log.info("setting up initiator removal for host " + hostURI);
            // Get the initiators (and initiator URIs) for this host
            List<Initiator> initiators = hostInitiatorsMap.get(hostURI);
            // Find the ExportMask for my host.
            List<ExportMask> exportMasks = getExportMaskForHost(exportGroup, hostURI, vplexURI);
            if (exportMasks == null || exportMasks.isEmpty()) {
                // If there is no ExportMask for this host, there is nothing to do.
                _log.info("No export mask found for hostURI: " + hostURI);
                continue;
            }
            String lastStep = null;
            List<URI> initiatorsAlreadyRemovedFromExportGroup = new ArrayList<URI>();
            for (ExportMask exportMask : exportMasks) {
                _log.info("adding remove initiators steps for " + "export mask / storage view: " + exportMask.getMaskName());
                String vplexClusterName = VPlexUtil.getVplexClusterName(exportMask, vplexURI, client, _dbClient);
                Map<String, String> targetPortToPwwnMap = VPlexControllerUtils.getTargetPortToPwwnMap(client, vplexClusterName);
                VPlexStorageViewInfo storageView = client.getStorageView(vplexClusterName, exportMask.getMaskName());
                _log.info("Refreshing ExportMask {}", exportMask.getMaskName());
                VPlexControllerUtils.refreshExportMask(_dbClient, storageView, exportMask, targetPortToPwwnMap, _networkDeviceController);
                // initiator filter logic is move inside addStepsForRemoveInitiators and addStepsForInitiatorRemoval as
                // it is not required for zone related operation.
                // validate the remove initiator operation against the export mask volumes
                List<URI> volumeURIList = (exportMask.getUserAddedVolumes() != null) ? URIUtil.toURIList(exportMask.getUserAddedVolumes().values()) : new ArrayList<URI>();
                if (volumeURIList.isEmpty()) {
                    _log.warn("volume URI list for validating remove initiators is empty...");
                }
                ExportMaskValidationContext ctx = new ExportMaskValidationContext();
                ctx.setStorage(vplex);
                ctx.setExportMask(exportMask);
                ctx.setBlockObjects(volumeURIList, _dbClient);
                ctx.setAllowExceptions(!WorkflowService.getInstance().isStepInRollbackState(opId));
                validator.removeInitiators(ctx).validate();
                lastStep = addStepsForRemoveInitiators(vplex, workflow, completer, exportGroup, exportMask, initiators, hostURI, initiatorsAlreadyRemovedFromExportGroup, errorMessages, lastStep);
                if (lastStep != null) {
                    hasStep = true;
                }
            }
        }
        String message = errorMessages.toString();
        if (isValidationNeeded && !message.isEmpty()) {
            _log.error("Error Message {}", errorMessages);
            List<String> initiatorNames = new ArrayList<String>();
            for (URI initiatorURI : initiatorURIs) {
                Initiator initiator = _dbClient.queryObject(Initiator.class, initiatorURI);
                if (initiator != null) {
                    String normalizedName = Initiator.normalizePort(initiator.getInitiatorPort());
                    initiatorNames.add(normalizedName);
                } else {
                    _log.warn("no initiator found for URI {}", initiatorURI);
                }
            }
            throw DeviceControllerException.exceptions.removeInitiatorValidationError(Joiner.on(", ").join(initiatorNames), vplex.getLabel(), message);
        }
        // Fire off the workflow if there were initiators to delete. Otherwise just fire completer.
        if (hasStep) {
            workflow.executePlan(completer, "Successfully removed initiators: " + initiatorURIs.toString());
        } else {
            _log.info(String.format("No updates to ExportMasks needed... complete"));
            completer.ready(_dbClient);
        }
    } catch (VPlexApiException vae) {
        _log.error("Exception in exportRemoveInitiators: " + initiatorURIs.toString(), vae);
        WorkflowStepCompleter.stepFailed(opId, vae);
    } catch (Exception ex) {
        _log.error("Exception in exportRemoveInitiators: " + initiatorURIs.toString(), ex);
        String opName = ResourceOperationTypeEnum.DELETE_EXPORT_INITIATOR.getName();
        ServiceError serviceError = VPlexApiException.errors.exportGroupRemoveInitiatorsFailed(opName, ex);
        WorkflowStepCompleter.stepFailed(opId, serviceError);
    }
}
Also used : VPlexStorageViewInfo(com.emc.storageos.vplex.api.VPlexStorageViewInfo) ExportRemoveInitiatorCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportRemoveInitiatorCompleter) ArrayList(java.util.ArrayList) NamedURI(com.emc.storageos.db.client.model.NamedURI) URI(java.net.URI) Initiator(com.emc.storageos.db.client.model.Initiator) ApplicationAddVolumeList(com.emc.storageos.volumecontroller.ApplicationAddVolumeList) ArrayList(java.util.ArrayList) URIQueryResultList(com.emc.storageos.db.client.constraint.URIQueryResultList) List(java.util.List) StorageSystem(com.emc.storageos.db.client.model.StorageSystem) ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) ExportMask(com.emc.storageos.db.client.model.ExportMask) Workflow(com.emc.storageos.workflow.Workflow) InternalException(com.emc.storageos.svcs.errorhandling.resources.InternalException) InternalServerErrorException(com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) ControllerException(com.emc.storageos.volumecontroller.ControllerException) IOException(java.io.IOException) URISyntaxException(java.net.URISyntaxException) WorkflowException(com.emc.storageos.workflow.WorkflowException) DatabaseException(com.emc.storageos.db.exceptions.DatabaseException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) ExportGroup(com.emc.storageos.db.client.model.ExportGroup) ExportMaskValidationContext(com.emc.storageos.volumecontroller.impl.validators.contexts.ExportMaskValidationContext) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient)

Aggregations

VPlexApiClient (com.emc.storageos.vplex.api.VPlexApiClient)81 VPlexApiException (com.emc.storageos.vplex.api.VPlexApiException)57 URISyntaxException (java.net.URISyntaxException)57 ControllerException (com.emc.storageos.volumecontroller.ControllerException)55 WorkflowException (com.emc.storageos.workflow.WorkflowException)55 InternalException (com.emc.storageos.svcs.errorhandling.resources.InternalException)54 StorageSystem (com.emc.storageos.db.client.model.StorageSystem)52 DeviceControllerException (com.emc.storageos.exceptions.DeviceControllerException)52 InternalServerErrorException (com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException)52 DatabaseException (com.emc.storageos.db.exceptions.DatabaseException)48 IOException (java.io.IOException)47 URI (java.net.URI)41 ServiceError (com.emc.storageos.svcs.errorhandling.model.ServiceError)40 Volume (com.emc.storageos.db.client.model.Volume)34 ArrayList (java.util.ArrayList)34 NamedURI (com.emc.storageos.db.client.model.NamedURI)26 HashMap (java.util.HashMap)18 ExportMask (com.emc.storageos.db.client.model.ExportMask)16 VPlexStorageViewInfo (com.emc.storageos.vplex.api.VPlexStorageViewInfo)16 VPlexVirtualVolumeInfo (com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo)16