Search in sources :

Example 16 with VPlexApiException

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

the class VPlexDeviceController method commitMigration.

/**
 * Invoked by the migration workflow to commit the migration after it has
 * been completed.
 *
 * @param vplexURI
 *            The URI of the VPlex storage system.
 * @param virtualVolumeURI
 *            The URI of the virtual volume.
 * @param migrationURI
 *            The URI of the data migration.
 * @param rename
 *            Indicates if the volume should be renamed after commit to
 *            conform to ViPR standard naming conventions.
 * @param newVpoolURI - the new virtual pool for the virtual volume (or null if not changing)
 * @param newVarrayURI - the new varray for the virtual volume (or null if not changing)
 * @param stepId
 *            The workflow step identifier.
 *
 * @throws WorkflowException
 */
public void commitMigration(URI vplexURI, URI virtualVolumeURI, URI migrationURI, Boolean rename, URI newVpoolURI, URI newVarrayURI, String stepId) throws WorkflowException {
    _log.info("Committing migration {}", migrationURI);
    Migration migration = null;
    VPlexApiClient client = null;
    try {
        // Update step state to executing.
        WorkflowStepCompleter.stepExecuting(stepId);
        // Get the migration.
        migration = getDataObject(Migration.class, migrationURI, _dbClient);
        // workflow, so check the status.
        if (!VPlexMigrationInfo.MigrationStatus.COMMITTED.getStatusValue().equals(migration.getMigrationStatus())) {
            // Get the VPlex API client.
            StorageSystem vplexSystem = getDataObject(StorageSystem.class, vplexURI, _dbClient);
            client = getVPlexAPIClient(_vplexApiFactory, vplexSystem, _dbClient);
            _log.info("Got VPlex API client for system {}", vplexURI);
            // Make a call to the VPlex API client to commit the migration.
            // Note that for ingested VPLEX volumes created outside ViPR, we
            // don't want to update the name.
            List<VPlexMigrationInfo> migrationInfoList = new ArrayList<VPlexMigrationInfo>();
            Volume virtualVolume = getDataObject(Volume.class, virtualVolumeURI, _dbClient);
            try {
                migrationInfoList = client.commitMigrations(virtualVolume.getDeviceLabel(), Arrays.asList(migration.getLabel()), true, true, rename.booleanValue());
                _log.info("Committed migration {}", migration.getLabel());
            } catch (VPlexApiException vae) {
                _log.error("Exception committing VPlex migration: " + vae.getMessage(), vae);
                boolean committed = false;
                // Check the migration status. Maybe it committed even though we had an error.
                VPlexMigrationInfo migrationInfo = client.getMigrationInfo(migration.getLabel());
                if (migrationInfo.getStatus().equalsIgnoreCase(VPlexMigrationInfo.MigrationStatus.COMMITTED.name())) {
                    _log.info("Migration {} has committed despite exception", migration.getLabel());
                    migrationInfoList.clear();
                    migrationInfoList.add(migrationInfo);
                    committed = true;
                } else {
                    _log.info("Migration {} status {}", migration.getLabel(), migrationInfo.getStatus());
                }
                if (!committed) {
                    // This was observed at customer site COP-21257
                    if (vae.getServiceCode() == ServiceCode.VPLEX_API_RESPONSE_TIMEOUT_ERROR) {
                        // We are going to throw an error, but we don't want to rollback completely
                        _workflowService.setWorkflowRollbackContOnError(stepId, false);
                    }
                    WorkflowStepCompleter.stepFailed(stepId, vae);
                    return;
                }
            }
            // Below this point migration is committed, no turning back.
            // Initialize the migration info in the database.
            migration.setMigrationStatus(VPlexMigrationInfo.MigrationStatus.COMMITTED.getStatusValue());
            _dbClient.updateObject(migration);
            _log.info("Update migration status to committed");
            // Update the virtual volume native id and associated
            // volumes. Note that we don't update CoS until all
            // commits are successful.
            VPlexVirtualVolumeInfo updatedVirtualVolumeInfo = migrationInfoList.get(0).getVirtualVolumeInfo();
            // update any properties that were changed after migration including deviceLabel, nativeGuid, and nativeId.
            // also, if the updated volume isn't thin-enabled, it is thin-capable, and the target vpool supports thin
            // provisioning, then a call should be made to the VPLEX to flip the thin-enabled flag on for this volume.
            URI targetVolumeUri = migration.getTarget();
            Volume targetVolume = getDataObject(Volume.class, targetVolumeUri, _dbClient);
            if (updatedVirtualVolumeInfo != null) {
                _log.info(String.format("New virtual volume is %s", updatedVirtualVolumeInfo.toString()));
                // if the new virtual volume is thin-capable, but thin-enabled is not true,
                // that means we need to ask the VPLEX to convert it to a thin-enabled volume.
                // this doesn't happen automatically for thick-to-thin data migrations.
                boolean isThinEnabled = updatedVirtualVolumeInfo.isThinEnabled();
                if (!isThinEnabled && VPlexApiConstants.TRUE.equalsIgnoreCase(updatedVirtualVolumeInfo.getThinCapable())) {
                    if (verifyVplexSupportsThinProvisioning(vplexSystem)) {
                        if (null != targetVolume) {
                            _log.info(String.format("migration target Volume is %s", targetVolume.forDisplay()));
                            VirtualPool targetVirtualPool = getDataObject(VirtualPool.class, targetVolume.getVirtualPool(), _dbClient);
                            if (null != targetVirtualPool) {
                                _log.info(String.format("migration target VirtualPool is %s", targetVirtualPool.forDisplay()));
                                boolean doEnableThin = VirtualPool.ProvisioningType.Thin.toString().equalsIgnoreCase(targetVirtualPool.getSupportedProvisioningType());
                                if (doEnableThin) {
                                    _log.info(String.format("the new VirtualPool is thin, requesting VPLEX to enable thin provisioning on %s", updatedVirtualVolumeInfo.getName()));
                                    isThinEnabled = client.setVirtualVolumeThinEnabled(updatedVirtualVolumeInfo);
                                }
                            }
                        }
                    }
                }
                virtualVolume.setDeviceLabel(updatedVirtualVolumeInfo.getName());
                virtualVolume.setNativeId(updatedVirtualVolumeInfo.getPath());
                virtualVolume.setNativeGuid(updatedVirtualVolumeInfo.getPath());
                virtualVolume.setThinlyProvisioned(isThinEnabled);
            }
            // Note that for ingested volumes, there will be no associated volumes
            // at first.
            StringSet assocVolumes = virtualVolume.getAssociatedVolumes();
            if ((assocVolumes != null) && (!assocVolumes.isEmpty())) {
                // For a distributed volume, there could be multiple
                // migrations. When the first completes, there will
                // be no associated volumes. However, when the second
                // completes, there will be associated volumes. However,
                // the migration source could be null.
                URI sourceVolumeUri = migration.getSource();
                if (sourceVolumeUri != null) {
                    assocVolumes.remove(sourceVolumeUri.toString());
                    // Retain any previous RP fields on the new target volume.
                    Volume sourceVolume = getDataObject(Volume.class, sourceVolumeUri, _dbClient);
                    if (sourceVolume != null) {
                        boolean targetUpdated = false;
                        if (NullColumnValueGetter.isNotNullValue(sourceVolume.getRpCopyName())) {
                            targetVolume.setRpCopyName(sourceVolume.getRpCopyName());
                            targetUpdated = true;
                        }
                        if (NullColumnValueGetter.isNotNullValue(sourceVolume.getInternalSiteName())) {
                            targetVolume.setInternalSiteName(sourceVolume.getInternalSiteName());
                            targetUpdated = true;
                        }
                        if (targetUpdated) {
                            _dbClient.updateObject(targetVolume);
                        }
                    }
                }
                assocVolumes.add(migration.getTarget().toString());
            } else {
                // NOTE: Now an ingested volume will have associated volumes.
                // It will no longer be considered an ingested volume.
                assocVolumes = new StringSet();
                assocVolumes.add(migration.getTarget().toString());
                virtualVolume.setAssociatedVolumes(assocVolumes);
            }
            updateMigratedVirtualVolumeVpoolAndVarray(virtualVolume, newVpoolURI, newVarrayURI);
            _dbClient.updateObject(virtualVolume);
            _log.info("Updated virtual volume.");
        } else {
            _log.info("The migration is already committed.");
            // Note that we don't set the device label and native id. If the
            // migration was committed outside of Bourne, the virtual volume
            // will still have the old name. If it was committed through
            // Bourne, these values would already have been update.
            // Regardless, we have to update the vpool, and we update the
            // associated volumes in case it was committed outside of
            // Bourne.
            associateVplexVolumeWithMigratedTarget(migration, virtualVolumeURI);
            _log.info("Updated virtual volume.");
        }
        // Update the workflow step status.
        StringBuilder successMsgBuilder = new StringBuilder();
        successMsgBuilder.append("VPlex System: ");
        successMsgBuilder.append(vplexURI);
        successMsgBuilder.append(" migration: ");
        successMsgBuilder.append(migrationURI);
        successMsgBuilder.append(" was committed");
        _log.info(successMsgBuilder.toString());
        WorkflowStepCompleter.stepSucceded(stepId);
        _log.info("Updated workflow step state to success");
    } catch (VPlexApiException vae) {
        _log.error("Exception committing VPlex migration: " + vae.getMessage(), vae);
        WorkflowStepCompleter.stepFailed(stepId, vae);
    } catch (Exception ex) {
        _log.error("Exception committing VPlex migration: " + ex.getMessage(), ex);
        String opName = ResourceOperationTypeEnum.COMMIT_VOLUME_MIGRATION.getName();
        ServiceError serviceError = VPlexApiException.errors.commitMigrationFailed(opName, ex);
        WorkflowStepCompleter.stepFailed(stepId, serviceError);
    }
}
Also used : ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) Migration(com.emc.storageos.db.client.model.Migration) ArrayList(java.util.ArrayList) VirtualPool(com.emc.storageos.db.client.model.VirtualPool) VPlexVirtualVolumeInfo(com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo) 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) VPlexMigrationInfo(com.emc.storageos.vplex.api.VPlexMigrationInfo) 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) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Example 17 with VPlexApiException

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

the class VPlexDeviceController method storageViewAddInitiators.

/**
 * Workflow Step to add initiator to Storage View.
 * Note arguments (except stepId) must match storageViewAddInitiatorsMethod above.
 *
 * @param vplexURI
 *            -- URI of VPlex StorageSystem
 * @param exportURI
 *            -- ExportGroup URI
 * @param maskURI
 *            -- ExportMask URI. Optional.
 *            If non-null, only the indicated ExportMask will be processed.
 *            Otherwise, all ExportMasks will be processed.
 * @param initiatorURIs
 *            -- List of initiator URIs to be added.
 * @param targetURIs
 *            -- optional list of additional targets URIs (VPLEX FE ports) to be added.
 *            If non null, the targets (VPlex front end ports) indicated by the targetURIs will be added
 *            to the Storage View.
 * @param completer the ExportMaskAddInitiatorCompleter
 * @param stepId
 *            -- Workflow step id.
 * @throws WorkflowException
 */
public void storageViewAddInitiators(URI vplexURI, URI exportURI, URI maskURI, List<URI> initiatorURIs, List<URI> targetURIs, boolean sharedExportMask, ExportMaskAddInitiatorCompleter completer, String stepId) throws DeviceControllerException {
    try {
        WorkflowStepCompleter.stepExecuting(stepId);
        ExportOperationContext context = new VplexExportOperationContext();
        // Prime the context object
        completer.updateWorkflowStepContext(context);
        StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
        ExportGroup exportGroup = getDataObject(ExportGroup.class, exportURI, _dbClient);
        VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
        List<ExportMask> exportMasks = ExportMaskUtils.getExportMasks(_dbClient, exportGroup, vplexURI);
        for (ExportMask exportMask : exportMasks) {
            // If a specific ExportMask is to be processed, ignore any others.
            if (maskURI != null && !exportMask.getId().equals(maskURI)) {
                continue;
            }
            _log.info("Refreshing ExportMask {}", exportMask.getMaskName());
            String vplexClusterName = VPlexUtil.getVplexClusterName(exportMask, vplexURI, client, _dbClient);
            VPlexStorageViewInfo storageView = client.getStorageView(vplexClusterName, exportMask.getMaskName());
            VPlexControllerUtils.refreshExportMask(_dbClient, storageView, exportMask, VPlexControllerUtils.getTargetPortToPwwnMap(client, vplexClusterName), _networkDeviceController);
            // Determine host of ExportMask
            Set<URI> exportMaskHosts = VPlexUtil.getExportMaskHosts(_dbClient, exportMask, sharedExportMask);
            List<Initiator> inits = _dbClient.queryObject(Initiator.class, initiatorURIs);
            if (sharedExportMask) {
                for (Initiator initUri : inits) {
                    URI hostUri = VPlexUtil.getInitiatorHost(initUri);
                    if (null != hostUri) {
                        exportMaskHosts.add(hostUri);
                    }
                }
            }
            // Invoke artificial failure to simulate invalid storageview name on vplex
            InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_060);
            // Add new targets if specified
            if (targetURIs != null && targetURIs.isEmpty() == false) {
                List<PortInfo> targetPortInfos = new ArrayList<PortInfo>();
                List<URI> targetsAddedToStorageView = new ArrayList<URI>();
                for (URI target : targetURIs) {
                    // Do not try to add a port twice.
                    if (exportMask.getStoragePorts().contains(target.toString())) {
                        continue;
                    }
                    // Log any ports not listed as a target in the Export Masks zoningMap
                    Set<String> zoningMapTargets = BlockStorageScheduler.getTargetIdsFromAssignments(exportMask.getZoningMap());
                    if (!zoningMapTargets.contains(target.toString())) {
                        _log.info(String.format("Target %s not in zoning map", target));
                    }
                    // Build the PortInfo structure for the port to be added
                    StoragePort port = getDataObject(StoragePort.class, target, _dbClient);
                    PortInfo pi = new PortInfo(port.getPortNetworkId().toUpperCase().replaceAll(":", ""), null, port.getPortName(), null);
                    targetPortInfos.add(pi);
                    targetsAddedToStorageView.add(target);
                }
                if (!targetPortInfos.isEmpty()) {
                    // Add the targets on the VPLEX
                    client.addTargetsToStorageView(exportMask.getMaskName(), targetPortInfos);
                    // Add the targets to the database.
                    for (URI target : targetsAddedToStorageView) {
                        exportMask.addTarget(target);
                    }
                }
            }
            List<PortInfo> initiatorPortInfos = new ArrayList<PortInfo>();
            List<String> initiatorPortWwns = new ArrayList<String>();
            Map<PortInfo, Initiator> portInfosToInitiatorMap = new HashMap<PortInfo, Initiator>();
            for (Initiator initiator : inits) {
                // Only add this initiator if it's for the same host as other initiators in mask
                if (!exportMaskHosts.contains(VPlexUtil.getInitiatorHost(initiator))) {
                    continue;
                }
                // Only add this initiator if it's not in the mask already after refresh
                if (exportMask.hasInitiator(initiator.getId().toString())) {
                    continue;
                }
                PortInfo portInfo = new PortInfo(initiator.getInitiatorPort().toUpperCase().replaceAll(":", ""), initiator.getInitiatorNode().toUpperCase().replaceAll(":", ""), initiator.getLabel(), getVPlexInitiatorType(initiator));
                initiatorPortInfos.add(portInfo);
                initiatorPortWwns.add(initiator.getInitiatorPort());
                portInfosToInitiatorMap.put(portInfo, initiator);
            }
            if (!initiatorPortInfos.isEmpty()) {
                String lockName = null;
                boolean lockAcquired = false;
                try {
                    StringSet portIds = exportMask.getStoragePorts();
                    StoragePort exportMaskPort = getDataObject(StoragePort.class, URI.create(portIds.iterator().next()), _dbClient);
                    String clusterId = ConnectivityUtil.getVplexClusterOfPort(exportMaskPort);
                    lockName = _vplexApiLockManager.getLockName(vplexURI, clusterId);
                    lockAcquired = _vplexApiLockManager.acquireLock(lockName, LockTimeoutValue.get(LockType.VPLEX_API_LIB));
                    if (!lockAcquired) {
                        throw VPlexApiException.exceptions.couldNotObtainConcurrencyLock(vplex.getLabel());
                    }
                    // Add the initiators to the VPLEX
                    client.addInitiatorsToStorageView(exportMask.getMaskName(), vplexClusterName, initiatorPortInfos);
                    ExportOperationContext.insertContextOperation(completer, VplexExportOperationContext.OPERATION_ADD_INITIATORS_TO_STORAGE_VIEW, initiatorURIs);
                } finally {
                    if (lockAcquired) {
                        _vplexApiLockManager.releaseLock(lockName);
                    }
                }
            }
        }
        InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_003);
        completer.ready(_dbClient);
    } catch (VPlexApiException vae) {
        _log.error("VPlexApiException adding initiator to Storage View: " + vae.getMessage(), vae);
        failStep(completer, stepId, vae);
    } catch (Exception ex) {
        _log.error("Exception adding initiator to Storage View: " + ex.getMessage(), ex);
        String opName = ResourceOperationTypeEnum.ADD_STORAGE_VIEW_INITIATOR.getName();
        ServiceError serviceError = VPlexApiException.errors.storageViewAddInitiatorFailed(opName, ex);
        failStep(completer, stepId, serviceError);
    }
}
Also used : VPlexStorageViewInfo(com.emc.storageos.vplex.api.VPlexStorageViewInfo) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) NamedURI(com.emc.storageos.db.client.model.NamedURI) URI(java.net.URI) PortInfo(com.emc.storageos.vplex.api.clientdata.PortInfo) Initiator(com.emc.storageos.db.client.model.Initiator) ExportOperationContext(com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext) StringSet(com.emc.storageos.db.client.model.StringSet) StorageSystem(com.emc.storageos.db.client.model.StorageSystem) ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) ExportMask(com.emc.storageos.db.client.model.ExportMask) StoragePort(com.emc.storageos.db.client.model.StoragePort) 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) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient)

Example 18 with VPlexApiException

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

the class VPlexDeviceController method storageViewAddVolumes.

/**
 * Method for adding volumes to a single ExportMask.
 *
 * @param vplexURI
 * @param exportGroupURI
 * @param exportMaskURI
 * @param volumeMap
 * @param opId
 * @throws ControllerException
 */
public void storageViewAddVolumes(URI vplexURI, URI exportGroupURI, URI exportMaskURI, Map<URI, Integer> volumeMap, String opId) throws ControllerException {
    String volListStr = "";
    ExportMaskAddVolumeCompleter completer = null;
    try {
        WorkflowStepCompleter.stepExecuting(opId);
        completer = new ExportMaskAddVolumeCompleter(exportGroupURI, exportMaskURI, volumeMap, opId);
        ExportOperationContext context = new VplexExportOperationContext();
        // Prime the context object
        completer.updateWorkflowStepContext(context);
        volListStr = Joiner.on(',').join(volumeMap.keySet());
        StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
        ExportMask exportMask = getDataObject(ExportMask.class, exportMaskURI, _dbClient);
        InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_001);
        VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
        // Need to massage the map to fit the API
        List<BlockObject> volumes = new ArrayList<BlockObject>();
        Map<String, Integer> deviceLabelToHLU = new HashMap<String, Integer>();
        boolean duplicateHLU = false;
        List<URI> volumesToAdd = new ArrayList<URI>();
        String vplexClusterName = VPlexUtil.getVplexClusterName(exportMask, vplexURI, client, _dbClient);
        VPlexStorageViewInfo storageView = client.getStorageView(vplexClusterName, exportMask.getMaskName());
        VPlexControllerUtils.refreshExportMask(_dbClient, storageView, exportMask, VPlexControllerUtils.getTargetPortToPwwnMap(client, vplexClusterName), _networkDeviceController);
        exportMask = getDataObject(ExportMask.class, exportMaskURI, _dbClient);
        for (Map.Entry<URI, Integer> entry : volumeMap.entrySet()) {
            if (exportMask.hasVolume(entry.getKey())) {
                _log.info(String.format("Volume %s is already in Exportmask %s %s hence skipping adding volume again. This must be shared exportmask. ", entry.getKey(), exportMask.getMaskName(), exportMask.getId()));
                continue;
            }
            Integer requestedHLU = entry.getValue();
            // If user have provided specific HLU for volume, then check if its already in use
            if (requestedHLU.intValue() != VPlexApiConstants.LUN_UNASSIGNED && exportMask.anyVolumeHasHLU(requestedHLU.toString())) {
                String message = String.format("Failed to add Volumes %s to ExportMask %s", volListStr, exportMaskURI);
                _log.error(message);
                String opName = ResourceOperationTypeEnum.ADD_EXPORT_VOLUME.getName();
                ServiceError serviceError = VPlexApiException.errors.exportHasExistingVolumeWithRequestedHLU(entry.getKey().toString(), requestedHLU.toString(), opName);
                failStep(completer, opId, serviceError);
                duplicateHLU = true;
                break;
            }
            BlockObject vol = Volume.fetchExportMaskBlockObject(_dbClient, entry.getKey());
            volumes.add(vol);
            deviceLabelToHLU.put(vol.getDeviceLabel(), requestedHLU);
            volumesToAdd.add(entry.getKey());
        }
        // If duplicate HLU are found then return, completer is set to error above
        if (duplicateHLU) {
            return;
        }
        // If deviceLabelToHLU map is empty then volumes already exists in the storage view hence return.
        if (deviceLabelToHLU.isEmpty()) {
            completer.ready(_dbClient);
            return;
        }
        VPlexStorageViewInfo svInfo = client.addVirtualVolumesToStorageView(exportMask.getMaskName(), vplexClusterName, deviceLabelToHLU);
        ExportOperationContext.insertContextOperation(completer, VplexExportOperationContext.OPERATION_ADD_VOLUMES_TO_STORAGE_VIEW, volumesToAdd);
        // When VPLEX volumes are exported to a storage view, they get a WWN,
        // so set the WWN from the returned storage view information.
        Map<URI, Integer> updatedVolumeMap = new HashMap<URI, Integer>();
        for (BlockObject volume : volumes) {
            String deviceLabel = volume.getDeviceLabel();
            String wwn = svInfo.getWWNForStorageViewVolume(volume.getDeviceLabel());
            volume.setWWN(wwn);
            _dbClient.updateObject(volume);
            updatedVolumeMap.put(volume.getId(), svInfo.getHLUForStorageViewVolume(deviceLabel));
            // user.
            if (exportMask.hasExistingVolume(wwn)) {
                _log.info("wwn {} has been added to the storage view {} by the user, but it " + "was already in existing volumes, removing from existing volumes.", wwn, exportMask.forDisplay());
                exportMask.removeFromExistingVolumes(wwn);
            }
            exportMask.addToUserCreatedVolumes(volume);
        }
        // We also need to update the volume/lun id map in the export mask
        // to those assigned by the VPLEX.
        _log.info("Updating volume/lun map in export mask {}", exportMask.getId());
        exportMask.addVolumes(updatedVolumeMap);
        _dbClient.updateObject(exportMask);
        InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_002);
        completer.ready(_dbClient);
    } catch (VPlexApiException vae) {
        String message = String.format("Failed to add Volumes %s to ExportMask %s", volListStr, exportMaskURI);
        _log.error(message, vae);
        failStep(completer, opId, vae);
    } catch (Exception ex) {
        String message = String.format("Failed to add Volumes %s to ExportMask %s", volListStr, exportMaskURI);
        _log.error(message, ex);
        String opName = ResourceOperationTypeEnum.ADD_EXPORT_VOLUME.getName();
        ServiceError serviceError = VPlexApiException.errors.exportGroupAddVolumesFailed(volListStr, exportGroupURI.toString(), opName, ex);
        failStep(completer, opId, serviceError);
    }
}
Also used : ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) VPlexStorageViewInfo(com.emc.storageos.vplex.api.VPlexStorageViewInfo) HashMap(java.util.HashMap) ExportMask(com.emc.storageos.db.client.model.ExportMask) ArrayList(java.util.ArrayList) 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) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient) ExportOperationContext(com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext) ExportMaskAddVolumeCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportMaskAddVolumeCompleter) Map(java.util.Map) OpStatusMap(com.emc.storageos.db.client.model.OpStatusMap) HashMap(java.util.HashMap) StringMap(com.emc.storageos.db.client.model.StringMap) BlockObject(com.emc.storageos.db.client.model.BlockObject) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Example 19 with VPlexApiException

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

the class VPlexDeviceController method exportGroupCreate.

/*
     * (non-Javadoc)
     *
     * @see com.emc.storageos.volumecontroller.impl.vplex.VplexController#exportGroupCreate(java.net.URI, java.net.URI,
     * java.util.Map,
     * java.util.List, java.lang.String)
     */
@Override
public void exportGroupCreate(URI vplex, URI export, List<URI> initiators, Map<URI, Integer> volumeMap, String opId) throws ControllerException {
    ExportCreateCompleter completer = null;
    try {
        WorkflowStepCompleter.stepExecuting(opId);
        completer = new ExportCreateCompleter(export, volumeMap, opId);
        ExportGroup exportGroup = _dbClient.queryObject(ExportGroup.class, export);
        StorageSystem vplexSystem = _dbClient.queryObject(StorageSystem.class, vplex);
        _log.info(String.format("VPLEX exportGroupCreate %s vplex %s", exportGroup.getLabel(), vplexSystem.getNativeGuid()));
        URI srcVarray = exportGroup.getVirtualArray();
        boolean isRecoverPointExport = ExportUtils.checkIfInitiatorsForRP(_dbClient, exportGroup.getInitiators());
        initiators = VPlexUtil.filterInitiatorsForVplex(_dbClient, initiators);
        if (initiators == null || initiators.isEmpty()) {
            _log.info("ExportGroup created with no initiators connected to VPLEX supplied, no need to orchestrate VPLEX further.");
            completer.ready(_dbClient);
            return;
        }
        // Determine whether this export will be done across both VPLEX clusters, or just one.
        // If both, we will set up some data structures to handle both exports.
        // Distributed volumes can be exported to both clusters.
        // Local volumes may be from either the src or HA varray, and will be exported
        // the the appropriate hosts.
        // Hosts may have connectivity to one varray (local or HA), or both.
        // Only one HA varray is allowed (technically one Varray not matching the ExportGroup).
        // It is persisted in the exportGroup.altVirtualArray map with the Vplex System ID as key.
        // Get a mapping of Virtual Array to the Volumes visible in each Virtual Array.
        Map<URI, Set<URI>> varrayToVolumes = VPlexUtil.mapBlockObjectsToVarrays(_dbClient, volumeMap.keySet(), vplex, exportGroup);
        // Extract the src volumes into their own set.
        Set<URI> srcVolumes = varrayToVolumes.get(srcVarray);
        // Remove the srcVolumes from the varraysToVolumesMap
        varrayToVolumes.remove(srcVarray);
        URI haVarray = null;
        // And we're not exporting to recover point Initiators
        if (!varrayToVolumes.isEmpty() && !isRecoverPointExport) {
            // Make sure there is only one "HA" varray and return the HA virtual array.
            haVarray = VPlexUtil.pickHAVarray(varrayToVolumes);
        }
        // Partition the initiators by Varray.
        // Some initiators may be connected to both virtual arrays, others connected to
        // only one of the virtual arrays or the other.
        List<URI> varrayURIs = new ArrayList<URI>();
        varrayURIs.add(srcVarray);
        if (haVarray != null) {
            varrayURIs.add(haVarray);
        }
        Map<URI, List<URI>> varrayToInitiators = VPlexUtil.partitionInitiatorsByVarray(_dbClient, initiators, varrayURIs, vplexSystem);
        if (varrayToInitiators.isEmpty()) {
            throw VPlexApiException.exceptions.exportCreateNoinitiatorsHaveCorrectConnectivity(initiators.toString(), varrayURIs.toString());
        }
        // Validate that the export can be successful:
        // If both src and ha volumes are present, all hosts must be connected.
        // Otherwise, at least one host must be connected.
        URI source = (srcVolumes == null || srcVolumes.isEmpty()) ? null : srcVarray;
        VPlexUtil.validateVPlexClusterExport(_dbClient, source, haVarray, initiators, varrayToInitiators);
        Workflow workflow = _workflowService.getNewWorkflow(this, "exportGroupCreate", true, opId);
        // HA side initiators, and volumes accessible from the HA side.
        if (haVarray != null && varrayToInitiators.get(haVarray) != null) {
            exportGroup.putAltVirtualArray(vplex.toString(), haVarray.toString());
            _dbClient.updateObject(exportGroup);
        }
        findAndUpdateFreeHLUsForClusterExport(vplexSystem, exportGroup, initiators, volumeMap);
        // Do the source side export if there are src side volumes and initiators.
        if (srcVolumes != null && varrayToInitiators.get(srcVarray) != null) {
            assembleExportMasksWorkflow(vplex, export, srcVarray, varrayToInitiators.get(srcVarray), ExportMaskUtils.filterVolumeMap(volumeMap, srcVolumes), true, workflow, null, opId);
        }
        // HA side initiators, and volumes accessible from the HA side.
        if (haVarray != null && varrayToInitiators.get(haVarray) != null) {
            assembleExportMasksWorkflow(vplex, export, haVarray, varrayToInitiators.get(haVarray), ExportMaskUtils.filterVolumeMap(volumeMap, varrayToVolumes.get(haVarray)), true, workflow, null, opId);
        }
        // Initiate the workflow.
        StringBuilder buf = new StringBuilder();
        buf.append(String.format("VPLEX create ExportGroup %s for initiators %s completed successfully", export, initiators.toString()));
        workflow.executePlan(completer, buf.toString());
        _log.info("VPLEX exportGroupCreate workflow scheduled");
    } catch (VPlexApiException vae) {
        _log.error("Exception creating Export Group: " + vae.getMessage(), vae);
        failStep(completer, opId, vae);
    } catch (Exception ex) {
        _log.error("Exception creating Export Group: " + ex.getMessage(), ex);
        String opName = ResourceOperationTypeEnum.CREATE_EXPORT_GROUP.getName();
        ServiceError serviceError = VPlexApiException.errors.exportGroupCreateFailed(opName, ex);
        failStep(completer, opId, serviceError);
    }
}
Also used : ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) Set(java.util.Set) HashSet(java.util.HashSet) StringSet(com.emc.storageos.db.client.model.StringSet) ArrayList(java.util.ArrayList) Workflow(com.emc.storageos.workflow.Workflow) 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) ExportCreateCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportCreateCompleter) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) 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)

Example 20 with VPlexApiException

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

the class VPlexDeviceController method deleteStorageView.

/**
 * A Workflow Step to delete a VPlex Storage View.
 *
 * @param vplexURI vplex
 * @param exportMaskURI export mask
 * @param isRollbackStep is this being run as a rollback step?
 * @param stepId step ID
 * @throws WorkflowException
 */
public void deleteStorageView(URI vplexURI, URI exportGroupURI, URI exportMaskURI, boolean isRollbackStep, String stepId) throws WorkflowException {
    ExportMaskDeleteCompleter completer = null;
    try {
        WorkflowStepCompleter.stepExecuting(stepId);
        completer = new ExportMaskDeleteCompleter(exportGroupURI, exportMaskURI, stepId);
        completer.setRollingBack(isRollbackStep);
        StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
        Boolean[] viewFound = new Boolean[] { new Boolean(false) };
        ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
        VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
        if (exportMask != null) {
            String vplexClusterName = VPlexUtil.getVplexClusterName(exportMask, vplexURI, client, _dbClient);
            VPlexStorageViewInfo storageView = client.getStorageView(vplexClusterName, exportMask.getMaskName());
            if (storageView != null) {
                // we can ignore this in the case of a missing storage view on the VPLEX, it has already been
                // deleted
                _log.info("Refreshing ExportMask {}", exportMask.getMaskName());
                VPlexControllerUtils.refreshExportMask(_dbClient, storageView, exportMask, VPlexControllerUtils.getTargetPortToPwwnMap(client, vplexClusterName), _networkDeviceController);
            }
            if (exportMask.hasAnyExistingVolumes() || exportMask.hasAnyExistingInitiators()) {
                _log.warn("ExportMask {} still has non-ViPR-created existing volumes or initiators, " + "so ViPR will not remove it from the VPLEX device", exportMask.getMaskName());
            }
            if (exportMask.getInactive()) {
                _log.warn("ExportMask {} is already inactive, so there's " + "no need to delete it off the VPLEX", exportMask.getMaskName());
            } else {
                List<URI> volumeURIs = new ArrayList<URI>();
                if (exportMask.getUserAddedVolumes() != null && !exportMask.getUserAddedVolumes().isEmpty()) {
                    volumeURIs = StringSetUtil.stringSetToUriList(exportMask.getUserAddedVolumes().values());
                }
                List<Initiator> initiators = new ArrayList<>();
                if (exportMask.getUserAddedInitiators() != null && !exportMask.getUserAddedInitiators().isEmpty()) {
                    List<URI> initiatorURIs = StringSetUtil.stringSetToUriList(exportMask.getUserAddedInitiators().values());
                    initiators.addAll(_dbClient.queryObject(Initiator.class, initiatorURIs));
                }
                ExportMaskValidationContext ctx = new ExportMaskValidationContext();
                ctx.setStorage(vplex);
                ctx.setExportMask(exportMask);
                ctx.setBlockObjects(volumeURIs, _dbClient);
                ctx.setInitiators(initiators);
                ctx.setAllowExceptions(!WorkflowService.getInstance().isStepInRollbackState(stepId));
                validator.exportMaskDelete(ctx).validate();
                InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_084);
                // note: there's a chance if the existing storage view originally had only
                // storage ports configured in it, then it would be deleted by this
                _log.info("removing this export mask from VPLEX: " + exportMask.getMaskName());
                client.deleteStorageView(exportMask.getMaskName(), vplexClusterName, viewFound);
                if (viewFound[0]) {
                    _log.info("as expected, storage view was found for deletion on the VPLEX.");
                } else {
                    _log.info("storage view was not found on the VPLEX during deletion, " + "but no errors were encountered.");
                }
            }
            _log.info("Marking export mask for deletion from Vipr: " + exportMask.getMaskName());
            _dbClient.markForDeletion(exportMask);
            _log.info("updating ExportGroups containing this ExportMask");
            List<ExportGroup> exportGroups = ExportMaskUtils.getExportGroups(_dbClient, exportMask);
            for (ExportGroup exportGroup : exportGroups) {
                _log.info("Removing mask from ExportGroup " + exportGroup.getGeneratedName());
                exportGroup.removeExportMask(exportMaskURI);
                _dbClient.updateObject(exportGroup);
            }
        } else {
            _log.info("ExportMask to delete could not be found in database: " + exportMaskURI);
        }
        completer.ready(_dbClient);
    } catch (VPlexApiException vae) {
        _log.error("Exception deleting ExportMask: " + exportMaskURI, vae);
        failStep(completer, stepId, vae);
    } catch (DeviceControllerException ex) {
        _log.error("Exception deleting ExportMask: " + exportMaskURI, ex);
        failStep(completer, stepId, ex);
    } catch (Exception ex) {
        _log.error("Exception deleting ExportMask: " + exportMaskURI, ex);
        ServiceError svcError = VPlexApiException.errors.deleteStorageViewFailed(ex);
        failStep(completer, stepId, svcError);
    }
}
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) 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) ExportMaskDeleteCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportMaskDeleteCompleter) 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) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Aggregations

VPlexApiException (com.emc.storageos.vplex.api.VPlexApiException)59 StorageSystem (com.emc.storageos.db.client.model.StorageSystem)53 ServiceError (com.emc.storageos.svcs.errorhandling.model.ServiceError)43 InternalException (com.emc.storageos.svcs.errorhandling.resources.InternalException)43 ControllerException (com.emc.storageos.volumecontroller.ControllerException)43 WorkflowException (com.emc.storageos.workflow.WorkflowException)43 DeviceControllerException (com.emc.storageos.exceptions.DeviceControllerException)41 InternalServerErrorException (com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException)41 VPlexApiClient (com.emc.storageos.vplex.api.VPlexApiClient)40 URI (java.net.URI)39 ArrayList (java.util.ArrayList)39 DatabaseException (com.emc.storageos.db.exceptions.DatabaseException)34 IOException (java.io.IOException)34 URISyntaxException (java.net.URISyntaxException)34 ExportMask (com.emc.storageos.db.client.model.ExportMask)26 Volume (com.emc.storageos.db.client.model.Volume)25 NamedURI (com.emc.storageos.db.client.model.NamedURI)21 Initiator (com.emc.storageos.db.client.model.Initiator)20 BlockStorageDevice (com.emc.storageos.volumecontroller.BlockStorageDevice)14 VPlexVirtualVolumeInfo (com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo)12