Search in sources :

Example 11 with VPlexStorageViewInfo

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

the class VPlexDeviceController method exportGroupRemoveVolumes.

/*
     * (non-Javadoc)
     *
     * @see com.emc.storageos.volumecontroller.impl.vplex.VplexController#exportRemoveVolume(java.net.URI, java.net.URI,
     * java.net.URI,
     * java.lang.String)
     */
@Override
public void exportGroupRemoveVolumes(URI vplexURI, URI exportURI, List<URI> volumeURIs, String opId) throws ControllerException {
    String volListStr = "";
    ExportRemoveVolumeCompleter completer = null;
    boolean hasSteps = false;
    try {
        _log.info("entering export group remove volumes");
        WorkflowStepCompleter.stepExecuting(opId);
        completer = new ExportRemoveVolumeCompleter(exportURI, volumeURIs, opId);
        volListStr = Joiner.on(',').join(volumeURIs);
        validator.volumeURIs(volumeURIs, false, false, ValCk.ID);
        Workflow workflow = _workflowService.getNewWorkflow(this, EXPORT_GROUP_REMOVE_VOLUMES, false, opId);
        StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
        ExportGroup exportGroup = getDataObject(ExportGroup.class, exportURI, _dbClient);
        List<ExportMask> exportMasks = ExportMaskUtils.getExportMasks(_dbClient, exportGroup, vplex.getId());
        StringBuffer errorMessages = new StringBuffer();
        boolean isValidationNeeded = validatorConfig.isValidationEnabled();
        _log.info("Orchestration level validation needed : {}", isValidationNeeded);
        VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
        // For safety, run remove volumes serially
        String previousStep = null;
        for (ExportMask exportMask : exportMasks) {
            if (exportMask.getInactive()) {
                _log.info(String.format("ExportMask %s (%s) is inactive, skipping", exportMask.getMaskName(), exportMask.getId()));
                continue;
            }
            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);
            List<URI> volumeURIList = new ArrayList<URI>();
            List<URI> remainingVolumesInMask = new ArrayList<URI>();
            if (exportMask.getVolumes() != null && !exportMask.getVolumes().isEmpty()) {
                // note that this is the assumed behavior even for the
                // situation in which this export mask is in use by other
                // export groups... see CTRL-3941
                // assemble a list of other ExportGroups that reference this ExportMask
                List<ExportGroup> otherExportGroups = ExportUtils.getOtherExportGroups(exportGroup, exportMask, _dbClient);
                if (otherExportGroups != null && !otherExportGroups.isEmpty()) {
                    // Gets the list of volume URIs that are not other Export Groups
                    volumeURIList = getVolumeListDiff(exportGroup, exportMask, otherExportGroups, volumeURIs);
                } else {
                    volumeURIList = volumeURIs;
                }
                Map<URI, BlockObject> blockObjectMap = VPlexUtil.translateRPSnapshots(_dbClient, volumeURIList);
                volumeURIList.clear();
                volumeURIList.addAll(blockObjectMap.keySet());
                volumeURIList = ExportMaskUtils.filterVolumesByExportMask(volumeURIList, exportMask);
                for (String volumeURI : exportMask.getVolumes().keySet()) {
                    remainingVolumesInMask.add(URI.create(volumeURI));
                }
                remainingVolumesInMask.removeAll(volumeURIList);
            }
            _log.info(String.format("exportGroupRemove: mask %s volumes to process: %s", exportMask.getMaskName(), volumeURIList.toString()));
            // Fetch exportMask again as exportMask zoning Map might have changed in zoneExportRemoveVolumes
            exportMask = _dbClient.queryObject(ExportMask.class, exportMask.getId());
            boolean existingVolumes = exportMask.hasAnyExistingVolumes();
            // The useradded - existing initiators enhancement made in refreshExportMask
            // guarantees that all the discovered initiators are added to userAdded,
            // irrespective of whether it's already registered on the array manually.
            boolean existingInitiators = exportMask.hasAnyExistingInitiators();
            boolean canMaskBeDeleted = remainingVolumesInMask.isEmpty() && !existingInitiators && !existingVolumes;
            if (!canMaskBeDeleted) {
                _log.info("this mask is not empty, so just updating: " + exportMask.getMaskName());
                completer.addExportMaskToRemovedVolumeMapping(exportMask.getId(), volumeURIList);
                Workflow.Method storageViewRemoveVolume = storageViewRemoveVolumesMethod(vplex.getId(), exportGroup.getId(), exportMask.getId(), volumeURIList, opId, completer, null);
                previousStep = workflow.createStep("removeVolumes", String.format("Removing volumes from export on storage array %s (%s) for export mask %s (%s)", vplex.getNativeGuid(), vplex.getId().toString(), exportMask.getMaskName(), exportMask.getId()), previousStep, vplex.getId(), vplex.getSystemType(), this.getClass(), storageViewRemoveVolume, rollbackMethodNullMethod(), null);
                // Add zoning step for removing volumes
                List<NetworkZoningParam> zoningParam = NetworkZoningParam.convertExportMasksToNetworkZoningParam(exportGroup.getId(), Collections.singletonList(exportMask.getId()), _dbClient);
                Workflow.Method zoneRemoveVolumesMethod = _networkDeviceController.zoneExportRemoveVolumesMethod(zoningParam, volumeURIList);
                previousStep = workflow.createStep(null, "Zone remove volumes mask: " + exportMask.getMaskName(), previousStep, nullURI, "network-system", _networkDeviceController.getClass(), zoneRemoveVolumesMethod, _networkDeviceController.zoneNullRollbackMethod(), null);
                hasSteps = true;
            /**
             * TODO
             * ExportremoveVolumeCompleter should be enhanced to remove export mask from export group if last volume removed.
             * We already take care of this.
             */
            } else {
                _log.info("this mask is empty of ViPR-managed volumes, and there are no existing volumes or initiators, so deleting: " + exportMask.getMaskName());
                List<NetworkZoningParam> zoningParams = NetworkZoningParam.convertExportMasksToNetworkZoningParam(exportURI, Collections.singletonList(exportMask.getId()), _dbClient);
                hasSteps = true;
                String exportMaskDeleteStep = workflow.createStepId();
                Workflow.Method deleteStorageView = deleteStorageViewMethod(vplexURI, exportURI, exportMask.getId(), false);
                previousStep = workflow.createStep(DELETE_STORAGE_VIEW, String.format("Deleting storage view: %s (%s)", exportMask.getMaskName(), exportMask.getId()), previousStep, vplexURI, vplex.getSystemType(), this.getClass(), deleteStorageView, null, exportMaskDeleteStep);
                // Unzone step (likely just a FCZoneReference removal since this is remove volume only)
                previousStep = workflow.createStep(ZONING_STEP, "Zoning subtask for export-group: " + exportURI, previousStep, NullColumnValueGetter.getNullURI(), "network-system", _networkDeviceController.getClass(), _networkDeviceController.zoneExportRemoveVolumesMethod(zoningParams, volumeURIs), null, workflow.createStepId());
            }
        }
        if (hasSteps) {
            String message = errorMessages.toString();
            if (isValidationNeeded && !message.isEmpty()) {
                _log.error("Error Message {}", errorMessages);
                List<Volume> volumes = _dbClient.queryObject(Volume.class, volumeURIs);
                String volumesForDisplay = Joiner.on(", ").join(Collections2.transform(volumes, CommonTransformerFunctions.fctnDataObjectToForDisplay()));
                throw DeviceControllerException.exceptions.removeVolumesValidationError(volumesForDisplay, vplex.forDisplay(), message);
            }
            workflow.executePlan(completer, String.format("Sucessfully removed volumes or deleted Storage View: %s (%s)", exportGroup.getLabel(), exportGroup.getId()));
        } else {
            completer.ready(_dbClient);
        }
    } catch (VPlexApiException vae) {
        String message = String.format("Failed to remove Volume %s from ExportGroup %s", volListStr, exportURI);
        _log.error(message, vae);
        failStep(completer, opId, vae);
    } catch (Exception ex) {
        String message = String.format("Failed to remove Volume %s from ExportGroup %s", volListStr, exportURI);
        _log.error(message, ex);
        String opName = ResourceOperationTypeEnum.DELETE_EXPORT_VOLUME.getName();
        ServiceError serviceError = VPlexApiException.errors.exportGroupRemoveVolumesFailed(volListStr, exportURI.toString(), opName, ex);
        failStep(completer, opId, serviceError);
    }
}
Also used : VPlexStorageViewInfo(com.emc.storageos.vplex.api.VPlexStorageViewInfo) ArrayList(java.util.ArrayList) NamedURI(com.emc.storageos.db.client.model.NamedURI) URI(java.net.URI) BlockObject(com.emc.storageos.db.client.model.BlockObject) 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) NetworkZoningParam(com.emc.storageos.networkcontroller.impl.NetworkZoningParam) ExportRemoveVolumeCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportRemoveVolumeCompleter) ExportGroup(com.emc.storageos.db.client.model.ExportGroup) Volume(com.emc.storageos.db.client.model.Volume) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient)

Example 12 with VPlexStorageViewInfo

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

the class VPlexDeviceController method assembleExportMasksWorkflow.

/**
 * Method to assemble the find or create VPLEX storage views (export masks) workflow for the given
 * ExportGroup, Initiators, and the block object Map.
 *
 * @param vplexURI
 *            the URI of the VPLEX StorageSystem object
 * @param export
 *            the ExportGroup in question
 * @param varrayUri
 *            -- NOTE! The varrayURI may NOT be the same as the exportGroup varray!.
 * @param initiators
 *            if initiators is null, the method will use all initiators from the ExportGroup
 * @param blockObjectMap
 *            the key (URI) of this map can reference either the volume itself or a snapshot.
 * @param zoningStepNeeded - Determines whether zone step is needed
 * @param workflow
 *            the controller workflow
 * @param waitFor
 *            -- If non-null, will wait on previous workflow step
 * @param opId
 *            the workflow step id
 * @return the last Workflow Step id
 * @throws Exception
 */
private String assembleExportMasksWorkflow(URI vplexURI, URI export, URI varrayUri, List<URI> initiators, Map<URI, Integer> blockObjectMap, boolean zoningStepNeeded, Workflow workflow, String waitFor, String opId) throws Exception {
    long startAssembly = new Date().getTime();
    VPlexControllerUtils.cleanStaleExportMasks(_dbClient, vplexURI);
    _log.info("TIMER: clean stale export masks took {} ms", new Date().getTime() - startAssembly);
    StorageSystem vplexSystem = getDataObject(StorageSystem.class, vplexURI, _dbClient);
    ExportGroup exportGroup = getDataObject(ExportGroup.class, export, _dbClient);
    // filter volume map just for this VPLEX's virtual volumes
    _log.info("object map before filtering for this VPLEX: " + blockObjectMap);
    Map<URI, Integer> filteredBlockObjectMap = new HashMap<URI, Integer>();
    for (URI boURI : blockObjectMap.keySet()) {
        BlockObject bo = Volume.fetchExportMaskBlockObject(_dbClient, boURI);
        if (bo.getStorageController().equals(vplexURI)) {
            filteredBlockObjectMap.put(bo.getId(), blockObjectMap.get(boURI));
        }
    }
    blockObjectMap = filteredBlockObjectMap;
    _log.info("object map after filtering for this VPLEX: " + blockObjectMap);
    // validate volume to lun map to make sure there aren't any duplicate LUN entries
    ExportUtils.validateExportGroupVolumeMap(exportGroup.getLabel(), blockObjectMap);
    VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplexSystem, _dbClient);
    // we will need lists of new export masks to create and existing export masks to simply update
    List<ExportMask> exportMasksToCreateOnDevice = new ArrayList<ExportMask>();
    List<ExportMask> exportMasksToUpdateOnDevice = new ArrayList<ExportMask>();
    // In case we are just updating the existing export masks we will need this map
    // to add initiators which are not already there.
    Map<URI, List<Initiator>> exportMasksToUpdateOnDeviceWithInitiators = new HashMap<URI, List<Initiator>>();
    // In case we are just updating the existing export masks we will need this map
    // to add storage ports which are not already there.
    Map<URI, List<URI>> exportMasksToUpdateOnDeviceWithStoragePorts = new HashMap<URI, List<URI>>();
    // try to collect initiators, if none supplied by caller
    if (initiators == null) {
        initiators = new ArrayList<URI>();
        if (exportGroup.hasInitiators()) {
            for (String initiator : exportGroup.getInitiators()) {
                initiators.add(URI.create(initiator));
            }
        }
    }
    // sort initiators in a host to initiator map
    Map<URI, List<Initiator>> hostInitiatorMap = VPlexUtil.makeHostInitiatorsMap(initiators, _dbClient);
    // This Set will be used to track shared export mask in database.
    Set<ExportMask> sharedExportMasks = new HashSet<ExportMask>();
    // look at each host
    String lockName = null;
    boolean lockAcquired = false;
    String vplexClusterId = ConnectivityUtil.getVplexClusterForVarray(varrayUri, vplexURI, _dbClient);
    String vplexClusterName = VPlexUtil.getVplexClusterName(varrayUri, vplexURI, client, _dbClient);
    try {
        lockName = _vplexApiLockManager.getLockName(vplexURI, vplexClusterId);
        lockAcquired = _vplexApiLockManager.acquireLock(lockName, LockTimeoutValue.get(LockType.VPLEX_API_LIB));
        if (!lockAcquired) {
            throw VPlexApiException.exceptions.couldNotObtainConcurrencyLock(vplexSystem.getLabel());
        }
        Map<String, String> targetPortToPwwnMap = VPlexControllerUtils.getTargetPortToPwwnMap(client, vplexClusterName);
        Boolean[] doInitiatorRefresh = new Boolean[] { new Boolean(true) };
        /**
         * COP-28674: During Vblock boot volume export, if existing storage views are found then check for existing volumes
         * If found throw exception. This condition is valid only for boot volume vblock export.
         */
        if (exportGroup.forHost() && ExportMaskUtils.isVblockHost(initiators, _dbClient) && ExportMaskUtils.isBootVolume(_dbClient, blockObjectMap)) {
            _log.info("VBlock boot volume Export: Validating the Vplex Cluster {} to find existing storage views", vplexClusterName);
            List<Initiator> initiatorList = _dbClient.queryObject(Initiator.class, initiators);
            List<String> initiatorNames = getInitiatorNames(vplexSystem.getSerialNumber(), vplexClusterName, client, initiatorList.iterator(), doInitiatorRefresh);
            List<VPlexStorageViewInfo> storageViewInfos = client.getStorageViewsContainingInitiators(vplexClusterName, initiatorNames);
            List<String> maskNames = new ArrayList<String>();
            if (!CollectionUtils.isEmpty(storageViewInfos)) {
                for (VPlexStorageViewInfo storageView : storageViewInfos) {
                    if (!CollectionUtils.isEmpty(storageView.getVirtualVolumes())) {
                        maskNames.add(storageView.getName());
                    } else {
                        _log.info("Found Storage View {} for cluster {} with empty volumes", storageView.getName(), vplexClusterName);
                    }
                }
            } else {
                _log.info("No Storage views found for cluster {}", vplexClusterName);
            }
            if (!CollectionUtils.isEmpty(maskNames)) {
                Set<URI> computeResourceSet = hostInitiatorMap.keySet();
                throw VPlexApiException.exceptions.existingMaskFoundDuringBootVolumeExport(Joiner.on(", ").join(maskNames), Joiner.on(", ").join(computeResourceSet), vplexClusterName);
            } else {
                _log.info("VBlock Boot volume Export : Validation passed");
            }
        }
        for (URI hostUri : hostInitiatorMap.keySet()) {
            _log.info("assembling export masks workflow, now looking at host URI: " + hostUri);
            List<Initiator> inits = hostInitiatorMap.get(hostUri);
            _log.info("this host contains these initiators: " + inits);
            boolean foundMatchingStorageView = false;
            boolean allPortsFromMaskMatchForVarray = true;
            _log.info("attempting to locate an existing ExportMask for this host's initiators on VPLEX Cluster " + vplexClusterId);
            Map<URI, ExportMask> vplexExportMasks = new HashMap<URI, ExportMask>();
            allPortsFromMaskMatchForVarray = filterExportMasks(vplexExportMasks, inits, varrayUri, vplexSystem, vplexClusterId);
            ExportMask sharedVplexExportMask = null;
            switch(vplexExportMasks.size()) {
                case FOUND_NO_VIPR_EXPORT_MASKS:
                    // Didn't find any single existing ExportMask for this Host/Initiators.
                    // Check if there is a shared ExportMask in CoprHD with by checking the existing initiators list.
                    sharedVplexExportMask = VPlexUtil.getExportMasksWithExistingInitiators(vplexURI, _dbClient, inits, varrayUri, vplexClusterId);
                    // on the VPLEX and set it up as a new ExportMask.
                    if (null != sharedVplexExportMask) {
                        sharedExportMasks.add(sharedVplexExportMask);
                        // If sharedVplexExportMask is found then that export mask will be used to add any missing
                        // initiators or storage ports as needed, and volumes requested, if not already present.
                        setupExistingExportMaskWithNewHost(blockObjectMap, vplexSystem, exportGroup, varrayUri, exportMasksToUpdateOnDevice, exportMasksToUpdateOnDeviceWithInitiators, exportMasksToUpdateOnDeviceWithStoragePorts, inits, sharedVplexExportMask, opId);
                        VPlexStorageViewInfo storageView = client.getStorageView(vplexClusterName, sharedVplexExportMask.getMaskName());
                        _log.info("Refreshing ExportMask {}", sharedVplexExportMask.getMaskName());
                        VPlexControllerUtils.refreshExportMask(_dbClient, storageView, sharedVplexExportMask, targetPortToPwwnMap, _networkDeviceController);
                        foundMatchingStorageView = true;
                        break;
                    } else {
                        _log.info("could not find an existing matching ExportMask in ViPR, " + "so ViPR will see if there is one already on the VPLEX system");
                        // ViPR will attempt to find a suitable existing storage view
                        // on the VPLEX and set it up as a new ExportMask.
                        long start = new Date().getTime();
                        foundMatchingStorageView = checkForExistingStorageViews(client, targetPortToPwwnMap, vplexSystem, vplexClusterName, inits, exportGroup, varrayUri, blockObjectMap, exportMasksToUpdateOnDevice, exportMasksToUpdateOnDeviceWithInitiators, exportMasksToUpdateOnDeviceWithStoragePorts, doInitiatorRefresh, opId);
                        long elapsed = new Date().getTime() - start;
                        _log.info("TIMER: finding an existing storage view took {} ms and returned {}", elapsed, foundMatchingStorageView);
                        break;
                    }
                case FOUND_ONE_VIPR_EXPORT_MASK:
                    // get the single value in the map
                    ExportMask viprExportMask = vplexExportMasks.values().iterator().next();
                    _log.info("a valid ExportMask matching these initiators exists already in ViPR " + "for this VPLEX device, so ViPR will re-use it: " + viprExportMask.getMaskName());
                    VPlexStorageViewInfo storageView = client.getStorageView(vplexClusterName, viprExportMask.getMaskName());
                    _log.info("Refreshing ExportMask {}", viprExportMask.getMaskName());
                    VPlexControllerUtils.refreshExportMask(_dbClient, storageView, viprExportMask, targetPortToPwwnMap, _networkDeviceController);
                    reuseExistingExportMask(blockObjectMap, vplexSystem, exportGroup, varrayUri, exportMasksToUpdateOnDevice, exportMasksToUpdateOnDeviceWithStoragePorts, inits, allPortsFromMaskMatchForVarray, viprExportMask, opId);
                    foundMatchingStorageView = true;
                    break;
                default:
                    String message = "Invalid Configuration: more than one VPLEX ExportMask " + "in this cluster exists in ViPR for these initiators " + inits;
                    _log.error(message);
                    throw new Exception(message);
            }
            // or set up a brand new ExportMask (to create a storage view on the VPLEX) for the Host.
            if (!foundMatchingStorageView) {
                if (null == sharedVplexExportMask) {
                    // If we reached here, it means there isn't an existing storage view on the VPLEX with the host,
                    // and no other shared ExportMask was found in the database by looking at existingInitiators.
                    // So, ViPR will try to find if there is shared export mask already for the ExportGroup in the database.
                    sharedVplexExportMask = VPlexUtil.getSharedExportMaskInDb(exportGroup, vplexURI, _dbClient, varrayUri, vplexClusterId, hostInitiatorMap);
                }
                if (null != sharedVplexExportMask) {
                    // If a sharedExportMask was found, then the new host will be added to that ExportMask
                    _log.info(String.format("Shared export mask %s %s found for the export group %s %s which will be reused for initiators %s .", sharedVplexExportMask.getMaskName(), sharedVplexExportMask.getId(), exportGroup.getLabel(), exportGroup.getId(), inits.toString()));
                    sharedExportMasks.add(sharedVplexExportMask);
                    VPlexStorageViewInfo storageView = client.getStorageView(vplexClusterName, sharedVplexExportMask.getMaskName());
                    _log.info("Refreshing ExportMask {}", sharedVplexExportMask.getMaskName());
                    VPlexControllerUtils.refreshExportMask(_dbClient, storageView, sharedVplexExportMask, targetPortToPwwnMap, _networkDeviceController);
                    setupExistingExportMaskWithNewHost(blockObjectMap, vplexSystem, exportGroup, varrayUri, exportMasksToUpdateOnDevice, exportMasksToUpdateOnDeviceWithInitiators, exportMasksToUpdateOnDeviceWithStoragePorts, inits, sharedVplexExportMask, opId);
                } else {
                    // Otherwise, create a brand new ExportMask, which will enable the storage view to
                    // be created on the VPLEX device as part of this workflow
                    _log.info("did not find a matching existing storage view anywhere, so ViPR " + "will initialize a new one and push it to the VPLEX device");
                    setupNewExportMask(blockObjectMap, vplexSystem, exportGroup, varrayUri, exportMasksToCreateOnDevice, inits, vplexClusterId, opId);
                }
            }
        }
    } finally {
        if (lockAcquired) {
            _vplexApiLockManager.releaseLock(lockName);
        }
    }
    _log.info("updating zoning if necessary for both new and updated export masks");
    String zoningStepId = waitFor;
    if (zoningStepNeeded) {
        _log.info("Adding step to update zones if required.");
        zoningStepId = addStepsForZoningUpdate(export, initiators, blockObjectMap, workflow, waitFor, exportMasksToCreateOnDevice, exportMasksToUpdateOnDevice);
    }
    _log.info("set up initiator pre-registration step");
    String storageViewStepId = addStepsForInitiatorRegistration(initiators, vplexSystem, vplexClusterName, workflow, zoningStepId);
    _log.info("processing the export masks to be created");
    for (ExportMask exportMask : exportMasksToCreateOnDevice) {
        storageViewStepId = addStepsForExportMaskCreate(blockObjectMap, workflow, vplexSystem, exportGroup, storageViewStepId, exportMask);
    }
    _log.info("processing the export masks to be updated");
    for (ExportMask exportMask : exportMasksToUpdateOnDevice) {
        boolean shared = false;
        if (sharedExportMasks.contains(exportMask)) {
            shared = true;
        }
        storageViewStepId = addStepsForExportMaskUpdate(export, blockObjectMap, workflow, vplexSystem, exportMasksToUpdateOnDeviceWithInitiators, exportMasksToUpdateOnDeviceWithStoragePorts, storageViewStepId, exportMask, shared);
    }
    long elapsed = new Date().getTime() - startAssembly;
    _log.info("TIMER: export mask assembly took {} ms", elapsed);
    return storageViewStepId;
}
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) 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) BlockObject(com.emc.storageos.db.client.model.BlockObject) StorageSystem(com.emc.storageos.db.client.model.StorageSystem) HashSet(java.util.HashSet) ExportMask(com.emc.storageos.db.client.model.ExportMask) 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) ExportGroup(com.emc.storageos.db.client.model.ExportGroup) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient)

Example 13 with VPlexStorageViewInfo

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

the class VPlexDeviceController method addStepsForAddInitiators.

/**
 * Add workflow steps for adding Initiators to a specific varray for the given VPlex.
 *
 * @param workflow
 *            -- Workflow steps go into
 * @param vplex
 *            -- Storage system
 * @param exportGroup
 *            -- ExportGroup operation invoked on
 * @param varrayURI
 *            -- Virtual Array URI that the Initiators are in
 * @param hostInitiatorURIs
 *            -- URIs of the Initiators
 * @param initiators
 *            -- list of Initiator objects
 * @param hostURI
 *            -- The hostURI
 * @param previousStepId
 *            -- wait on this step if non-null
 * @param opId
 *            -- step id for our operation
 * @return StepId of last step generated
 */
private String addStepsForAddInitiators(Workflow workflow, StorageSystem vplex, ExportGroup exportGroup, URI varrayURI, List<URI> hostInitiatorURIs, List<Initiator> initiators, URI hostURI, String previousStepId, String opId) throws Exception {
    String lastStepId = null;
    URI vplexURI = vplex.getId();
    URI exportURI = exportGroup.getId();
    String initListStr = Joiner.on(',').join(hostInitiatorURIs);
    // Find the ExportMask for my host.
    ExportMask exportMask = VPlexUtil.getExportMaskForHostInVarray(_dbClient, exportGroup, hostURI, vplexURI, varrayURI);
    if (exportMask == null) {
        _log.info("No export mask found for hostURI: " + hostURI + " varrayURI: " + varrayURI);
        Map<URI, Integer> volumeMap = ExportUtils.getExportGroupVolumeMap(_dbClient, vplex, exportGroup);
        // Partition the Volumes by varray.
        Map<URI, Set<URI>> varrayToVolumes = VPlexUtil.mapBlockObjectsToVarrays(_dbClient, volumeMap.keySet(), vplexURI, exportGroup);
        // Filter the volumes by our Varray.
        Map<URI, Integer> varrayVolumeMap = ExportMaskUtils.filterVolumeMap(volumeMap, varrayToVolumes.get(varrayURI));
        // Create the ExportMask if there are volumes in this varray.
        if (!varrayVolumeMap.isEmpty()) {
            lastStepId = assembleExportMasksWorkflow(vplexURI, exportURI, varrayURI, hostInitiatorURIs, varrayVolumeMap, true, workflow, previousStepId, opId);
        }
    } else {
        VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
        String vplexClusterName = VPlexUtil.getVplexClusterName(exportMask, vplexURI, client, _dbClient);
        VPlexStorageViewInfo storageView = client.getStorageView(vplexClusterName, exportMask.getMaskName());
        _log.info("Refreshing ExportMask {}", exportMask.getMaskName());
        VPlexControllerUtils.refreshExportMask(_dbClient, storageView, exportMask, VPlexControllerUtils.getTargetPortToPwwnMap(client, vplexClusterName), _networkDeviceController);
        if (exportMask.getVolumes() == null) {
            // This can occur in Brownfield scenarios where we have not added any volumes yet to the HA side,
            // CTRL10760
            _log.info(String.format("No volumes in ExportMask %s (%s), so not adding initiators", exportMask.getMaskName(), exportMask.getId()));
            return lastStepId;
        }
        _log.info(String.format("Adding initiators %s for host %s mask %s (%s)", getInitiatorsWwnsString(initiators), hostURI.toString(), exportMask.getMaskName(), exportMask.getId()));
        // Calculate the path parameters for the volumes in this ExportMask
        Collection<URI> volumeURIs = new HashSet<URI>();
        if (exportMask.getVolumes() != null && !exportMask.getVolumes().isEmpty()) {
            volumeURIs = (Collections2.transform(exportMask.getVolumes().keySet(), CommonTransformerFunctions.FCTN_STRING_TO_URI));
        } else if (exportGroup.getVolumes() != null && !exportGroup.getVolumes().isEmpty()) {
            // Hit this condition
            // in CTRL-9944
            // (unknown why)
            _log.info(String.format("No volumes in ExportMask %s, using ExportGroup %s for ExportPathParam", exportMask.getId(), exportGroup.getId()));
            Map<URI, Integer> volumeMap = ExportUtils.getExportGroupVolumeMap(_dbClient, vplex, exportGroup);
            // Partition the Volumes by varray. Then use only the volumes in the requested varray.
            Map<URI, Set<URI>> varrayToVolumes = VPlexUtil.mapBlockObjectsToVarrays(_dbClient, volumeMap.keySet(), vplexURI, exportGroup);
            volumeURIs = varrayToVolumes.get(varrayURI);
        } else {
            _log.info(String.format("No volumes at all- using default path parameters: %s", exportMask.getId()));
        }
        ExportPathParams pathParams = _blockScheduler.calculateExportPathParamForVolumes(volumeURIs, exportGroup.getNumPaths(), exportMask.getStorageDevice(), exportGroup.getId());
        if (exportGroup.getType() != null) {
            pathParams.setExportGroupType(exportGroup.getType());
        }
        // Assign additional StoragePorts if needed.
        Map<URI, List<URI>> assignments = _blockScheduler.assignStoragePorts(vplex, exportGroup, initiators, exportMask.getZoningMap(), pathParams, volumeURIs, _networkDeviceController, varrayURI, opId);
        List<URI> newTargetURIs = BlockStorageScheduler.getTargetURIsFromAssignments(assignments);
        // Build a list of StoragePort targets to remove during rollback. Do not remove existing storage ports during rollback.
        List<URI> rollbackTargetURIs = new ArrayList<URI>();
        for (URI target : newTargetURIs) {
            if (exportMask.getStoragePorts().contains(target.toString())) {
                // Skip the target port if it exists in the ViPR ExportMask
                continue;
            }
            rollbackTargetURIs.add(target);
        }
        exportMask.addZoningMap(BlockStorageScheduler.getZoneMapFromAssignments(assignments));
        _dbClient.updateObject(exportMask);
        _log.info(String.format("Adding targets %s for host %s", newTargetURIs.toString(), hostURI.toString()));
        // Create a Step to add the SAN Zone
        String zoningStepId = workflow.createStepId();
        Workflow.Method zoningMethod = zoneAddInitiatorStepMethod(vplexURI, exportURI, hostInitiatorURIs, varrayURI);
        Workflow.Method zoningRollbackMethod = zoneRollbackMethod(exportURI, zoningStepId);
        zoningStepId = workflow.createStep(ZONING_STEP, String.format("Zone initiator %s to ExportGroup %s(%s)", initListStr, exportGroup.getLabel(), exportURI), previousStepId, vplexURI, vplex.getSystemType(), this.getClass(), zoningMethod, zoningRollbackMethod, zoningStepId);
        // Create a Step to add the initiator to the Storage View
        String message = String.format("initiators %s to StorageView %s", initListStr, exportGroup.getGeneratedName());
        ExportMask sharedExportMask = VPlexUtil.getSharedExportMaskInDb(exportGroup, vplexURI, _dbClient, varrayURI, null, null);
        boolean shared = false;
        if (null != sharedExportMask && sharedExportMask.getId().equals(exportMask.getId())) {
            shared = true;
        }
        String addInitStep = workflow.createStepId();
        ExportMaskAddInitiatorCompleter addInitCompleter = new ExportMaskAddInitiatorCompleter(exportURI, exportMask.getId(), hostInitiatorURIs, newTargetURIs, addInitStep);
        Workflow.Method addToViewMethod = storageViewAddInitiatorsMethod(vplexURI, exportURI, exportMask.getId(), hostInitiatorURIs, newTargetURIs, shared, addInitCompleter);
        Workflow.Method addToViewRollbackMethod = storageViewAddInitiatorsRollbackMethod(vplexURI, exportURI, exportMask.getId(), hostInitiatorURIs, rollbackTargetURIs, addInitStep);
        lastStepId = workflow.createStep("storageView", "Add " + message, zoningStepId, vplexURI, vplex.getSystemType(), this.getClass(), addToViewMethod, addToViewRollbackMethod, addInitStep);
    }
    return lastStepId;
}
Also used : VPlexStorageViewInfo(com.emc.storageos.vplex.api.VPlexStorageViewInfo) Set(java.util.Set) HashSet(java.util.HashSet) StringSet(com.emc.storageos.db.client.model.StringSet) ExportMask(com.emc.storageos.db.client.model.ExportMask) 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) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient) ApplicationAddVolumeList(com.emc.storageos.volumecontroller.ApplicationAddVolumeList) ArrayList(java.util.ArrayList) URIQueryResultList(com.emc.storageos.db.client.constraint.URIQueryResultList) List(java.util.List) Map(java.util.Map) OpStatusMap(com.emc.storageos.db.client.model.OpStatusMap) HashMap(java.util.HashMap) StringMap(com.emc.storageos.db.client.model.StringMap) HashSet(java.util.HashSet) ExportPathParams(com.emc.storageos.db.client.model.ExportPathParams)

Example 14 with VPlexStorageViewInfo

use of com.emc.storageos.vplex.api.VPlexStorageViewInfo 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 15 with VPlexStorageViewInfo

use of com.emc.storageos.vplex.api.VPlexStorageViewInfo 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

VPlexStorageViewInfo (com.emc.storageos.vplex.api.VPlexStorageViewInfo)21 URI (java.net.URI)18 VPlexApiClient (com.emc.storageos.vplex.api.VPlexApiClient)16 ExportMask (com.emc.storageos.db.client.model.ExportMask)15 ArrayList (java.util.ArrayList)15 NamedURI (com.emc.storageos.db.client.model.NamedURI)14 URISyntaxException (java.net.URISyntaxException)14 StorageSystem (com.emc.storageos.db.client.model.StorageSystem)12 DatabaseException (com.emc.storageos.db.exceptions.DatabaseException)12 VPlexApiException (com.emc.storageos.vplex.api.VPlexApiException)12 IOException (java.io.IOException)12 DeviceControllerException (com.emc.storageos.exceptions.DeviceControllerException)11 Initiator (com.emc.storageos.db.client.model.Initiator)10 InternalException (com.emc.storageos.svcs.errorhandling.resources.InternalException)10 InternalServerErrorException (com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException)10 ControllerException (com.emc.storageos.volumecontroller.ControllerException)10 WorkflowException (com.emc.storageos.workflow.WorkflowException)10 ExportGroup (com.emc.storageos.db.client.model.ExportGroup)9 ServiceError (com.emc.storageos.svcs.errorhandling.model.ServiceError)9 HashMap (java.util.HashMap)9