Search in sources :

Example 21 with WorkflowException

use of com.emc.storageos.workflow.WorkflowException in project coprhd-controller by CoprHD.

the class VPlexDeviceController method detachMirrorDevice.

/**
 * This method will detach mirror device from the vplex volume source device.
 * If discard is true it will leave the device and the underlying structure on VPlex.
 * True is used when this method is used in the context of deleting mirror.
 * If discarded is false it will convert the detached mirror into virtual volume with
 * the same name as the mirror device. False is used in the context of promoting mirror
 * to a vplex volume.
 *
 * @param vplexURI
 *            URI of the VPlex StorageSystem
 * @param vplexMirrorURI
 *            URI of the mirror to be detached.
 * @param discard
 *            true or false value, whether to discard device or not.
 * @param stepId
 *            The stepId used for completion.
 *
 * @throws WorkflowException
 *             When an error occurs updating the workflow step
 *             state.
 */
public void detachMirrorDevice(URI vplexURI, URI vplexMirrorURI, URI promotedVolumeURI, boolean discard, String stepId) throws WorkflowException {
    try {
        WorkflowStepCompleter.stepExecuting(stepId);
        VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplexURI, _dbClient);
        VplexMirror vplexMirror = getDataObject(VplexMirror.class, vplexMirrorURI, _dbClient);
        Volume sourceVplexVolume = getDataObject(Volume.class, vplexMirror.getSource().getURI(), _dbClient);
        if (vplexMirror.getDeviceLabel() != null) {
            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) {
                // Call to detach mirror device from Distributed Virtual Volume
                client.detachLocalMirrorFromDistributedVirtualVolume(sourceVplexVolume.getDeviceLabel(), vplexMirror.getDeviceLabel(), discard);
            } else {
                // Call to detach mirror device from Local Virtual Volume
                client.detachMirrorFromLocalVirtualVolume(sourceVplexVolume.getDeviceLabel(), vplexMirror.getDeviceLabel(), discard);
            }
            // Record VPLEX mirror detach event.
            recordBourneVplexMirrorEvent(vplexMirrorURI, OperationTypeEnum.DETACH_VOLUME_MIRROR.getEvType(true), Operation.Status.ready, OperationTypeEnum.DETACH_VOLUME_MIRROR.getDescription());
        } else {
            _log.info("It seems vplex mirror {} was never created, so move to the next step for cleanup.", vplexMirror.getLabel());
        }
        WorkflowStepCompleter.stepSucceded(stepId);
    } catch (VPlexApiException vae) {
        _log.error("Exception detaching Vplex Mirror {} ", vplexMirrorURI + vae.getMessage(), vae);
        if (promotedVolumeURI != null) {
            // If we are here due to promote mirror action then
            // delete the volume that was supposed to be promoted volume.
            Volume volume = _dbClient.queryObject(Volume.class, promotedVolumeURI);
            _dbClient.removeObject(volume);
        }
        recordBourneVplexMirrorEvent(vplexMirrorURI, OperationTypeEnum.DETACH_VOLUME_MIRROR.getEvType(true), Operation.Status.error, OperationTypeEnum.DETACH_VOLUME_MIRROR.getDescription());
        WorkflowStepCompleter.stepFailed(stepId, vae);
    } catch (Exception ex) {
        _log.error("Exception detaching Vplex Mirror {} ", vplexMirrorURI + ex.getMessage(), ex);
        if (promotedVolumeURI != null) {
            // If we are here due to promote mirror action then
            // delete the volume that was supposed to be promoted volume.
            Volume volume = _dbClient.queryObject(Volume.class, promotedVolumeURI);
            _dbClient.removeObject(volume);
        }
        String opName = ResourceOperationTypeEnum.DETACH_VPLEX_LOCAL_MIRROR.getName();
        ServiceError serviceError = VPlexApiException.errors.detachMirrorFailed(opName, ex);
        recordBourneVplexMirrorEvent(vplexMirrorURI, OperationTypeEnum.DETACH_VOLUME_MIRROR.getEvType(true), Operation.Status.error, OperationTypeEnum.DETACH_VOLUME_MIRROR.getDescription());
        WorkflowStepCompleter.stepFailed(stepId, serviceError);
    }
}
Also used : ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) Volume(com.emc.storageos.db.client.model.Volume) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient) VplexMirror(com.emc.storageos.db.client.model.VplexMirror) 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 22 with WorkflowException

use of com.emc.storageos.workflow.WorkflowException in project coprhd-controller by CoprHD.

the class VPlexDeviceController method zoneAddInitiatorStep.

/**
 * Workflow step to add an initiator. Calls NetworkDeviceController.
 * Arguments here should match zoneAddInitiatorStepMethod above except for stepId.
 *
 * @param exportURI
 * @param initiatorURIs
 * @param varrayURI
 * @throws WorkflowException
 */
public void zoneAddInitiatorStep(URI vplexURI, URI exportURI, List<URI> initiatorURIs, URI varrayURI, String stepId) throws WorkflowException {
    String initListStr = "";
    try {
        WorkflowStepCompleter.stepExecuting(stepId);
        initListStr = Joiner.on(',').join(initiatorURIs);
        ExportGroup exportGroup = getDataObject(ExportGroup.class, exportURI, _dbClient);
        _log.info(String.format("Adding initiators %s to ExportGroup %s (%s)", initListStr, exportGroup.getLabel(), exportGroup.getId()));
        List<Initiator> initiators = _dbClient.queryObject(Initiator.class, initiatorURIs);
        List<ExportMask> exportMasks = ExportMaskUtils.getExportMasks(_dbClient, exportGroup, vplexURI);
        Map<URI, List<URI>> maskToInitiatorsMap = new HashMap<URI, List<URI>>();
        ExportMask sharedExportMask = VPlexUtil.getSharedExportMaskInDb(exportGroup, vplexURI, _dbClient, varrayURI, null, null);
        for (ExportMask exportMask : exportMasks) {
            boolean shared = false;
            if (sharedExportMask != null) {
                if (sharedExportMask.getId().equals(exportMask.getId())) {
                    shared = true;
                }
            }
            maskToInitiatorsMap.put(exportMask.getId(), new ArrayList<URI>());
            Set<URI> exportMaskHosts = VPlexUtil.getExportMaskHosts(_dbClient, exportMask, shared);
            // Only add initiators to this ExportMask that are on the host of the Export Mask
            for (Initiator initiator : initiators) {
                if (exportMaskHosts.contains(VPlexUtil.getInitiatorHost(initiator))) {
                    maskToInitiatorsMap.get(exportMask.getId()).add(initiator.getId());
                }
            }
        }
        _networkDeviceController.zoneExportAddInitiators(exportURI, maskToInitiatorsMap, stepId);
    } catch (Exception ex) {
        _log.error("Exception adding initators: " + ex.getMessage(), ex);
        String opName = ResourceOperationTypeEnum.ADD_INITIATOR_WORKFLOW_STEP.getName();
        ServiceError serviceError = VPlexApiException.errors.zoneAddInitiatorStepFailed(opName, ex);
        WorkflowStepCompleter.stepFailed(stepId, serviceError);
    }
}
Also used : ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) HashMap(java.util.HashMap) ExportMask(com.emc.storageos.db.client.model.ExportMask) 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) ExportGroup(com.emc.storageos.db.client.model.ExportGroup) 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)

Example 23 with WorkflowException

use of com.emc.storageos.workflow.WorkflowException in project coprhd-controller by CoprHD.

the class VPlexDeviceController method migrateVirtualVolume.

/**
 * Creates and starts a VPlex data migration for the passed virtual volume
 * on the passed VPlex storage system. The passed target is a newly created
 * backend volume to which the data will be migrated. The source for the
 * data migration is the current backend volume for the virtual volume that
 * is in the same varray as the passed target. The method also creates
 * a migration job to monitor the progress of the migration. The workflow
 * step will complete when the migration completes, at which point the
 * migration is automatically committed.
 *
 * @param vplexURI
 *            The URI of the VPlex storage system.
 * @param virtualVolumeURI
 *            The URI of the virtual volume.
 * @param targetVolumeURI
 *            The URI of the migration target.
 * @param migrationURI
 *            The URI of the migration.
 * @param newNhURI
 *            The URI of the new varray for the virtual volume
 *            when a local virtual volume is being migrated to the other
 *            cluster, or null.
 * @param stepId
 *            The workflow step identifier.
 * @throws WorkflowException
 */
public void migrateVirtualVolume(URI vplexURI, URI virtualVolumeURI, URI targetVolumeURI, URI migrationURI, URI newNhURI, String stepId) throws WorkflowException {
    _log.info("Migration {} using target {}", migrationURI, targetVolumeURI);
    try {
        // Update step state to executing.
        WorkflowStepCompleter.stepExecuting(stepId);
        // Initialize the step data. The step data indicates if we
        // successfully started the migration and is used in
        // rollback.
        _workflowService.storeStepData(stepId, Boolean.FALSE);
        // Get the virtual volume.
        Volume virtualVolume = getDataObject(Volume.class, virtualVolumeURI, _dbClient);
        String virtualVolumeName = virtualVolume.getDeviceLabel();
        _log.info("Virtual volume name is {}", virtualVolumeName);
        // Setup the native volume info for the migration target.
        Volume migrationTarget = getDataObject(Volume.class, targetVolumeURI, _dbClient);
        StorageSystem targetStorageSystem = getDataObject(StorageSystem.class, migrationTarget.getStorageController(), _dbClient);
        _log.info("Storage system for migration target is {}", migrationTarget.getStorageController());
        List<String> itls = VPlexControllerUtils.getVolumeITLs(migrationTarget);
        VolumeInfo nativeVolumeInfo = new VolumeInfo(targetStorageSystem.getNativeGuid(), targetStorageSystem.getSystemType(), migrationTarget.getWWN().toUpperCase().replaceAll(":", ""), migrationTarget.getNativeId(), migrationTarget.getThinlyProvisioned().booleanValue(), itls);
        // Get the migration associated with the target.
        Migration migration = getDataObject(Migration.class, migrationURI, _dbClient);
        // Determine the unique name for the migration. We identifying
        // the migration source and target, using array serial number
        // and volume native id, in the migration name. This was fine
        // for VPlex extent migration, which has a max length of 63
        // for the migration name. However, for remote migrations,
        // which require VPlex device migration, the max length is much
        // more restrictive, like 20 characters. So, we switched over
        // timestamps.
        StringBuilder migrationNameBuilder = new StringBuilder(MIGRATION_NAME_PREFIX);
        DateFormat dateFormatter = new SimpleDateFormat(MIGRATION_NAME_DATE_FORMAT);
        migrationNameBuilder.append(dateFormatter.format(new Date()));
        String migrationName = migrationNameBuilder.toString();
        migration.setLabel(migrationName);
        _dbClient.updateObject(migration);
        _log.info("Migration name is {}", migrationName);
        // Get the VPlex API client.
        StorageSystem vplexSystem = getDataObject(StorageSystem.class, vplexURI, _dbClient);
        VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplexSystem, _dbClient);
        _log.info("Got VPlex API client for VPlex {}", vplexURI);
        // Get the configured migration speed
        String speed = customConfigHandler.getComputedCustomConfigValue(CustomConfigConstants.MIGRATION_SPEED, vplexSystem.getSystemType(), null);
        _log.info("Migration speed is {}", speed);
        String transferSize = migrationSpeedToTransferSizeMap.get(speed);
        // Make a call to the VPlex API client to migrate the virtual
        // volume. Note that we need to do a remote migration when a
        // local virtual volume is being migrated to the other VPlex
        // cluster. If the passed new varray is not null, then
        // this is the case.
        Boolean isRemoteMigration = newNhURI != null;
        // We support both device and extent migrations, however,
        // when we don't know anything about the backend volumes
        // we must use device migration.
        Boolean useDeviceMigration = migration.getSource() == null;
        List<VPlexMigrationInfo> migrationInfoList = client.migrateVirtualVolume(migrationName, virtualVolumeName, Arrays.asList(nativeVolumeInfo), isRemoteMigration, useDeviceMigration, true, true, transferSize);
        _log.info("Started VPlex migration");
        // We store step data indicating that the migration was successfully
        // create and started. We will use this to determine the behavior
        // on rollback. If we never got to the point that the migration
        // was created and started, then there is no rollback to attempt
        // on the VLPEX as the migrate API already tried to clean everything
        // up on the VLPEX.
        _workflowService.storeStepData(stepId, Boolean.TRUE);
        // Initialize the migration info in the database.
        VPlexMigrationInfo migrationInfo = migrationInfoList.get(0);
        migration.setMigrationStatus(VPlexMigrationInfo.MigrationStatus.READY.getStatusValue());
        migration.setPercentDone("0");
        migration.setStartTime(migrationInfo.getStartTime());
        _dbClient.updateObject(migration);
        _log.info("Update migration info");
        // Create a migration task completer and queue a job to monitor
        // the migration progress. The completer will be invoked by the
        // job when the migration completes.
        MigrationTaskCompleter migrationCompleter = new MigrationTaskCompleter(migrationURI, stepId);
        VPlexMigrationJob migrationJob = new VPlexMigrationJob(migrationCompleter);
        migrationJob.setTimeoutTimeMsec(MINUTE_TO_MILLISECONDS * Long.valueOf(ControllerUtils.getPropertyValueFromCoordinator(coordinator, CONTROLLER_VPLEX_MIGRATION_TIMEOUT_MINUTES)));
        ControllerServiceImpl.enqueueJob(new QueueJob(migrationJob));
        _log.info("Queued job to monitor migration progress.");
    } catch (VPlexApiException vae) {
        _log.error("Exception migrating VPlex virtual volume: " + vae.getMessage(), vae);
        WorkflowStepCompleter.stepFailed(stepId, vae);
    } catch (Exception ex) {
        _log.error("Exception migrating VPlex virtual volume: " + ex.getMessage(), ex);
        String opName = ResourceOperationTypeEnum.MIGRATE_VIRTUAL_VOLUME.getName();
        ServiceError serviceError = VPlexApiException.errors.migrateVirtualVolume(opName, ex);
        WorkflowStepCompleter.stepFailed(stepId, serviceError);
    }
}
Also used : ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) MigrationTaskCompleter(com.emc.storageos.vplexcontroller.completers.MigrationTaskCompleter) Migration(com.emc.storageos.db.client.model.Migration) VolumeInfo(com.emc.storageos.vplex.api.clientdata.VolumeInfo) VPlexVirtualVolumeInfo(com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo) Date(java.util.Date) 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) VPlexMigrationInfo(com.emc.storageos.vplex.api.VPlexMigrationInfo) VPlexMigrationJob(com.emc.storageos.vplexcontroller.job.VPlexMigrationJob) Volume(com.emc.storageos.db.client.model.Volume) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) SimpleDateFormat(java.text.SimpleDateFormat) DateFormat(java.text.DateFormat) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient) SimpleDateFormat(java.text.SimpleDateFormat) QueueJob(com.emc.storageos.volumecontroller.impl.job.QueueJob) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Example 24 with WorkflowException

use of com.emc.storageos.workflow.WorkflowException in project coprhd-controller by CoprHD.

the class VPlexDeviceController method storageViewRemoveInitiators.

/**
 * Workflow step to remove an initiator from a single Storage View as given by the ExportMask URI.
 * Note there is a dependence on ExportMask name equaling the Storage View name.
 * Note that arguments must match storageViewRemoveInitiatorsMethod above (except stepId).
 *
 * @param vplexURI
 *            -- URI of Vplex Storage System.
 * @param exportGroupURI
 *            -- URI of Export Group.
 * @param exportMaskURI
 *            -- URI of one ExportMask. Call only processes indicaated mask.
 * @param initiatorURIs
 *            -- URIs of Initiators to be removed.
 * @param targetURIs
 *            -- optional targets to be removed from the Storage View.
 *            If non null, a list of URIs for VPlex front-end ports that will be removed from Storage View.
 * @param taskCompleter
 *            -- the task completer, used to find the rollback context,
 *               which will be non-null in the case of rollback
 * @param rollbackContextKey
 *            context key for rollback processing
 * @param stepId
 *            -- Workflow step id.
 * @throws WorkflowException
 */
public void storageViewRemoveInitiators(URI vplexURI, URI exportGroupURI, URI exportMaskURI, List<URI> initiatorURIs, List<URI> targetURIs, TaskCompleter taskCompleter, String rollbackContextKey, String stepId) throws WorkflowException {
    ExportMaskRemoveInitiatorCompleter completer = null;
    try {
        WorkflowStepCompleter.stepExecuting(stepId);
        List<URI> initiatorIdsToProcess = new ArrayList<>(initiatorURIs);
        completer = new ExportMaskRemoveInitiatorCompleter(exportGroupURI, exportMaskURI, initiatorURIs, stepId);
        StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
        ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
        VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
        String vplexClusterName = VPlexUtil.getVplexClusterName(exportMask, vplexURI, client, _dbClient);
        Map<String, String> targetPortMap = VPlexControllerUtils.getTargetPortToPwwnMap(client, vplexClusterName);
        VPlexStorageViewInfo storageView = client.getStorageView(vplexClusterName, exportMask.getMaskName());
        _log.info("Refreshing ExportMask {}", exportMask.getMaskName());
        VPlexControllerUtils.refreshExportMask(_dbClient, storageView, exportMask, targetPortMap, _networkDeviceController);
        // get the context from the task completer, in case this is a rollback.
        if (taskCompleter != null && rollbackContextKey != null) {
            ExportOperationContext context = (ExportOperationContext) WorkflowService.getInstance().loadStepData(rollbackContextKey);
            if (context != null) {
                // a non-null context means this step is running as part of a rollback.
                List<URI> addedInitiators = new ArrayList<>();
                if (context.getOperations() != null) {
                    _log.info("Handling removeInitiators as a result of rollback");
                    ListIterator<ExportOperationContextOperation> li = context.getOperations().listIterator(context.getOperations().size());
                    while (li.hasPrevious()) {
                        ExportOperationContextOperation operation = (ExportOperationContextOperation) li.previous();
                        if (operation != null && VplexExportOperationContext.OPERATION_ADD_INITIATORS_TO_STORAGE_VIEW.equals(operation.getOperation())) {
                            addedInitiators = (List<URI>) operation.getArgs().get(0);
                            _log.info("Removing initiators {} as part of rollback", Joiner.on(',').join(addedInitiators));
                        }
                    }
                }
                // Update the initiators in the task completer such that we update the export mask/group correctly
                for (URI initiator : initiatorIdsToProcess) {
                    if (addedInitiators == null || !addedInitiators.contains(initiator)) {
                        completer.removeInitiator(initiator);
                    }
                }
                if (addedInitiators == null || addedInitiators.isEmpty()) {
                    _log.info("There was no context found for add initiator. So there is nothing to rollback.");
                    completer.ready(_dbClient);
                    return;
                }
                // Change the list of initiators to process to the list
                // that successfully were added during addInitiators.
                initiatorIdsToProcess.clear();
                initiatorIdsToProcess.addAll(addedInitiators);
            }
        }
        // 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(stepId));
        validator.removeInitiators(ctx).validate();
        // Invoke artificial failure to simulate invalid storageview name on vplex
        InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_060);
        // removing all storage ports but leaving the existing initiators and volumes.
        if (!exportMask.hasAnyExistingInitiators() && !exportMask.hasAnyExistingVolumes()) {
            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 remove 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()) {
                    // Remove the targets from the VPLEX
                    client.removeTargetsFromStorageView(exportMask.getMaskName(), targetPortInfos);
                }
            }
        }
        // Update the initiators in the ExportMask.
        List<PortInfo> initiatorPortInfo = new ArrayList<PortInfo>();
        for (URI initiatorURI : initiatorIdsToProcess) {
            Initiator initiator = getDataObject(Initiator.class, initiatorURI, _dbClient);
            // We don't want to remove existing initiator, unless this is a rollback step
            if (exportMask.hasExistingInitiator(initiator) && !WorkflowService.getInstance().isStepInRollbackState(stepId)) {
                continue;
            }
            PortInfo portInfo = new PortInfo(initiator.getInitiatorPort().toUpperCase().replaceAll(":", ""), initiator.getInitiatorNode().toUpperCase().replaceAll(":", ""), initiator.getLabel(), getVPlexInitiatorType(initiator));
            initiatorPortInfo.add(portInfo);
        }
        // Remove the initiators if there aren't any existing volumes, unless this is a rollback step or validation is disabled.
        if (!initiatorPortInfo.isEmpty() && (!exportMask.hasAnyExistingVolumes() || !validatorConfig.isValidationEnabled() || WorkflowService.getInstance().isStepInRollbackState(stepId))) {
            String lockName = null;
            boolean lockAcquired = false;
            try {
                ExportGroup exportGroup = _dbClient.queryObject(ExportGroup.class, exportGroupURI);
                String clusterId = ConnectivityUtil.getVplexClusterForVarray(exportGroup.getVirtualArray(), vplexURI, _dbClient);
                lockName = _vplexApiLockManager.getLockName(vplexURI, clusterId);
                lockAcquired = _vplexApiLockManager.acquireLock(lockName, LockTimeoutValue.get(LockType.VPLEX_API_LIB));
                if (!lockAcquired) {
                    throw VPlexApiException.exceptions.couldNotObtainConcurrencyLock(vplex.getLabel());
                }
                // Remove the targets from the VPLEX
                // Test mechanism to invoke a failure. No-op on production systems.
                InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_016);
                client.removeInitiatorsFromStorageView(exportMask.getMaskName(), vplexClusterName, initiatorPortInfo);
            } finally {
                if (lockAcquired) {
                    _vplexApiLockManager.releaseLock(lockName);
                }
            }
        }
        completer.ready(_dbClient);
    } catch (VPlexApiException vae) {
        _log.error("Exception removing initiator from Storage View: " + vae.getMessage(), vae);
        failStep(completer, stepId, vae);
    } catch (Exception ex) {
        _log.error("Exception removing initiator from Storage View: " + ex.getMessage(), ex);
        String opName = ResourceOperationTypeEnum.DELETE_STORAGE_VIEW_INITIATOR.getName();
        ServiceError serviceError = VPlexApiException.errors.storageViewRemoveInitiatorFailed(opName, ex);
        failStep(completer, stepId, serviceError);
    }
}
Also used : ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) VPlexStorageViewInfo(com.emc.storageos.vplex.api.VPlexStorageViewInfo) ExportMask(com.emc.storageos.db.client.model.ExportMask) ArrayList(java.util.ArrayList) StoragePort(com.emc.storageos.db.client.model.StoragePort) ExportMaskRemoveInitiatorCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportMaskRemoveInitiatorCompleter) 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) PortInfo(com.emc.storageos.vplex.api.clientdata.PortInfo) ExportMaskValidationContext(com.emc.storageos.volumecontroller.impl.validators.contexts.ExportMaskValidationContext) ExportGroup(com.emc.storageos.db.client.model.ExportGroup) Initiator(com.emc.storageos.db.client.model.Initiator) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient) ExportOperationContext(com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext) ExportOperationContextOperation(com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext.ExportOperationContextOperation) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Example 25 with WorkflowException

use of com.emc.storageos.workflow.WorkflowException in project coprhd-controller by CoprHD.

the class VPlexDeviceController method promoteMirror.

/**
 * This method creates the virtual volume from the detached mirror device.
 *
 * @param vplexURI
 *            The vplex storage system URI
 * @param vplexMirrorURI
 *            The URI of the vplex mirror that needs to be promoted to the virtual volume
 * @param promoteVolumeURI
 *            The URI of the volume will be used as a promoted vplex volume
 * @param stepId
 *            The worflow stepId
 *
 * @throws WorkflowException
 *             When an error occurs updating the workflow step
 *             state.
 */
public void promoteMirror(URI vplexURI, URI vplexMirrorURI, URI promoteVolumeURI, String stepId) throws WorkflowException {
    try {
        WorkflowStepCompleter.stepExecuting(stepId);
        VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplexURI, _dbClient);
        VplexMirror vplexMirror = getDataObject(VplexMirror.class, vplexMirrorURI, _dbClient);
        Volume sourceVplexVolume = getDataObject(Volume.class, vplexMirror.getSource().getURI(), _dbClient);
        Volume promoteVolume = _dbClient.queryObject(Volume.class, promoteVolumeURI);
        // Find virtual volume that should have been created when we did detach mirror.
        // Virtual volume is created with the same name as the device name.
        VPlexVirtualVolumeInfo vvInfo = client.findVirtualVolume(vplexMirror.getDeviceLabel(), null);
        // Get the backend volume for this promoted VPLEX volume.
        StringSet assocVolumes = vplexMirror.getAssociatedVolumes();
        // Get the ViPR label for the promoted VPLEX volume.
        String promotedLabel = String.format("%s-%s", sourceVplexVolume.getLabel(), vplexMirror.getLabel());
        // Rename the vplex volume created using device detach mirror. If custom naming is enabled
        // generate the custom name, else the name follows the default naming convention and must
        // be renamed to append the "_vol" suffix.
        String newVolumeName = null;
        try {
            if (CustomVolumeNamingUtils.isCustomVolumeNamingEnabled(customConfigHandler, DiscoveredDataObject.Type.vplex.name())) {
                String customConfigName = CustomConfigConstants.CUSTOM_VOLUME_NAME;
                Project project = _dbClient.queryObject(Project.class, promoteVolume.getProject().getURI());
                TenantOrg tenant = _dbClient.queryObject(TenantOrg.class, promoteVolume.getTenant().getURI());
                DataSource customNameDataSource = CustomVolumeNamingUtils.getCustomConfigDataSource(project, tenant, promotedLabel, vvInfo.getWwn(), null, dataSourceFactory, customConfigName, _dbClient);
                if (customNameDataSource != null) {
                    newVolumeName = CustomVolumeNamingUtils.getCustomName(customConfigHandler, customConfigName, customNameDataSource, DiscoveredDataObject.Type.vplex.name());
                }
                // Rename the vplex volume created using device detach mirror,
                vvInfo = CustomVolumeNamingUtils.renameVolumeOnVPlex(vvInfo, newVolumeName, client);
                promotedLabel = newVolumeName;
            } else {
                // Build the name for volume so as to rename the vplex volume that is created
                // with the same name as the device name to follow the name pattern _vol
                // as the suffix for the vplex volumes
                StringBuilder volumeNameBuilder = new StringBuilder();
                volumeNameBuilder.append(vplexMirror.getDeviceLabel());
                volumeNameBuilder.append(VPlexApiConstants.VIRTUAL_VOLUME_SUFFIX);
                newVolumeName = volumeNameBuilder.toString();
                // Rename the vplex volume created using device detach mirror,
                vvInfo = CustomVolumeNamingUtils.renameVolumeOnVPlex(vvInfo, newVolumeName, client);
            }
        } catch (Exception e) {
            _log.warn(String.format("Error renaming promoted VPLEX volume %s", promoteVolumeURI), e);
        }
        _log.info(String.format("Renamed promoted virtual volume: %s path: %s", vvInfo.getName(), vvInfo.getPath()));
        // Fill in the details for the promoted vplex volume
        promoteVolume.setLabel(promotedLabel);
        promoteVolume.setNativeId(vvInfo.getPath());
        promoteVolume.setNativeGuid(vvInfo.getPath());
        promoteVolume.setDeviceLabel(vvInfo.getName());
        promoteVolume.setThinlyProvisioned(vvInfo.isThinEnabled());
        promoteVolume.setWWN(vvInfo.getWwn());
        // For Vplex virtual volumes set allocated capacity to 0 (cop-18608)
        promoteVolume.setAllocatedCapacity(0L);
        promoteVolume.setCapacity(vplexMirror.getCapacity());
        promoteVolume.setProvisionedCapacity(vplexMirror.getProvisionedCapacity());
        promoteVolume.setVirtualPool(vplexMirror.getVirtualPool());
        promoteVolume.setVirtualArray(vplexMirror.getVirtualArray());
        promoteVolume.setStorageController(vplexMirror.getStorageController());
        promoteVolume.setSystemType(DiscoveredDataObject.Type.vplex.name());
        promoteVolume.setPool(NullColumnValueGetter.getNullURI());
        promoteVolume.setAssociatedVolumes(new StringSet(assocVolumes));
        promoteVolume.setThinlyProvisioned(vplexMirror.getThinlyProvisioned());
        promoteVolume.setThinVolumePreAllocationSize(vplexMirror.getThinPreAllocationSize());
        // VPLEX volumes created by VIPR have syncActive set to true hence setting same value for promoted vplex
        // volumes
        promoteVolume.setSyncActive(true);
        // Also, we update the name portion of the project and tenant URIs
        // to reflect the new name. This is necessary because the API
        // to search for volumes by project, extracts the name portion of the
        // project URI to get the volume name.
        NamedURI namedURI = promoteVolume.getProject();
        namedURI.setName(promotedLabel);
        promoteVolume.setProject(namedURI);
        namedURI = promoteVolume.getTenant();
        namedURI.setName(promotedLabel);
        promoteVolume.setTenant(namedURI);
        // Remove mirror from the source VPLEX volume
        sourceVplexVolume.getMirrors().remove(vplexMirror.getId().toString());
        _dbClient.updateObject(sourceVplexVolume);
        // Delete the mirror object
        _dbClient.removeObject(vplexMirror);
        // Persist changes for the newly promoted volume
        _dbClient.updateObject(promoteVolume);
        WorkflowStepCompleter.stepSucceded(stepId);
    } catch (VPlexApiException vae) {
        _log.error("Exception promoting mirror volume: " + vae.getMessage(), vae);
        WorkflowStepCompleter.stepFailed(stepId, vae);
    } catch (Exception ex) {
        _log.error("Exception promoting mirror volume: " + ex.getMessage(), ex);
        ServiceError serviceError = VPlexApiException.errors.promoteMirrorFailed(ex);
        WorkflowStepCompleter.stepFailed(stepId, serviceError);
    }
}
Also used : ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) NamedURI(com.emc.storageos.db.client.model.NamedURI) VPlexVirtualVolumeInfo(com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo) 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) DataSource(com.emc.storageos.customconfigcontroller.DataSource) Project(com.emc.storageos.db.client.model.Project) Volume(com.emc.storageos.db.client.model.Volume) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient) StringSet(com.emc.storageos.db.client.model.StringSet) TenantOrg(com.emc.storageos.db.client.model.TenantOrg) VplexMirror(com.emc.storageos.db.client.model.VplexMirror)

Aggregations

WorkflowException (com.emc.storageos.workflow.WorkflowException)38 ControllerException (com.emc.storageos.volumecontroller.ControllerException)36 DeviceControllerException (com.emc.storageos.exceptions.DeviceControllerException)34 InternalException (com.emc.storageos.svcs.errorhandling.resources.InternalException)34 VPlexApiException (com.emc.storageos.vplex.api.VPlexApiException)34 ServiceError (com.emc.storageos.svcs.errorhandling.model.ServiceError)31 InternalServerErrorException (com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException)31 VPlexApiClient (com.emc.storageos.vplex.api.VPlexApiClient)29 DatabaseException (com.emc.storageos.db.exceptions.DatabaseException)27 IOException (java.io.IOException)27 URISyntaxException (java.net.URISyntaxException)27 StorageSystem (com.emc.storageos.db.client.model.StorageSystem)26 Volume (com.emc.storageos.db.client.model.Volume)24 URI (java.net.URI)21 ArrayList (java.util.ArrayList)18 NamedURI (com.emc.storageos.db.client.model.NamedURI)16 VPlexVirtualVolumeInfo (com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo)10 ExportGroup (com.emc.storageos.db.client.model.ExportGroup)8 VplexMirror (com.emc.storageos.db.client.model.VplexMirror)8 ExportMask (com.emc.storageos.db.client.model.ExportMask)7