Search in sources :

Example 21 with VPlexApiClient

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

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

the class VPlexDeviceController method validateStorageProviderConnection.

/**
 * Validate a VPLEX Storage Provider connection.
 *
 * @param ipAddress
 *            the Storage Provider's IP address
 * @param portNumber
 *            the Storage Provider's IP port
 *
 * @return true if the Storage Provider connection is valid
 */
@Override
public boolean validateStorageProviderConnection(String ipAddress, Integer portNumber) {
    boolean connectionValid;
    try {
        // look up the provider by ip address and port
        StringBuffer providerId = new StringBuffer(ipAddress).append(HYPHEN_OPERATOR).append(portNumber);
        URIQueryResultList providerUriList = new URIQueryResultList();
        _dbClient.queryByConstraint(AlternateIdConstraint.Factory.getStorageProviderByProviderIDConstraint(providerId.toString()), providerUriList);
        if (providerUriList.iterator().hasNext()) {
            StorageProvider provider = _dbClient.queryObject(StorageProvider.class, providerUriList.iterator().next());
            VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, provider, _dbClient);
            if (client != null) {
                client.verifyConnectivity();
                // if we got this far without blowing up, then the connection is valid
                _log.info("VPLEX Storage Provider connection at {} is valid.", providerId);
                connectionValid = true;
            } else {
                _log.error("a VplexApiClient could not be created for provider {}.", provider.getLabel());
                connectionValid = false;
            }
        } else {
            _log.error("Could not find a VPLEX Storage Provider " + "with address-port {} in ViPR.", providerId);
            connectionValid = false;
        }
    } catch (Exception ex) {
        _log.error("Connection to VPLEX Storage Provider {} is invalid.", ipAddress, ex);
        connectionValid = false;
    }
    return connectionValid;
}
Also used : VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient) StorageProvider(com.emc.storageos.db.client.model.StorageProvider) URIQueryResultList(com.emc.storageos.db.client.constraint.URIQueryResultList) InternalException(com.emc.storageos.svcs.errorhandling.resources.InternalException) InternalServerErrorException(com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) ControllerException(com.emc.storageos.volumecontroller.ControllerException) IOException(java.io.IOException) URISyntaxException(java.net.URISyntaxException) WorkflowException(com.emc.storageos.workflow.WorkflowException) DatabaseException(com.emc.storageos.db.exceptions.DatabaseException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException)

Example 23 with VPlexApiClient

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

the class VPlexDeviceController method getVPlexAPIClient.

private static VPlexApiClient getVPlexAPIClient(VPlexApiFactory vplexApiFactory, StorageProvider vplexMnmgtSvr, DbClient dbClient) throws URISyntaxException {
    VPlexApiClient client = VPlexControllerUtils.getVPlexAPIClient(vplexApiFactory, vplexMnmgtSvr, dbClient);
    updateTimeoutValues();
    return client;
}
Also used : VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient)

Example 24 with VPlexApiClient

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

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

the class VPlexDeviceController method rollbackRestoreResync.

/**
 * Called if the restore/resync volume operation fails
 *
 * @param vplexURI
 *            The URI of the VPLEX system.
 * @param vplexVolumeURI
 *            The URI of the distributed VPLEX volume.
 * @param cgURI
 *            The URI of the volume's CG or null.
 * @param detachStepId
 *            The Id of the detach mirror step.
 * @param stepId
 *            The workflow step identifier.
 */
public void rollbackRestoreResync(URI vplexURI, URI vplexVolumeURI, URI cgURI, String detachStepId, String stepId) {
    _log.info("Executing rollback of restore/resync volume {} on VPLEX {}", new Object[] { vplexVolumeURI, vplexURI });
    String mirrorDeviceName = "";
    try {
        // Update workflow step.
        WorkflowStepCompleter.stepExecuting(stepId);
        // Get the rollback data so we know what to do.
        @SuppressWarnings("unchecked") Map<String, String> rollbackData = (Map<String, String>) _workflowService.loadStepData(detachStepId);
        String successWarningMessage = null;
        if (rollbackData != null) {
            boolean reattachMirror = Boolean.parseBoolean(rollbackData.get(REATTACH_MIRROR));
            boolean addVolumeBackToCG = Boolean.parseBoolean(rollbackData.get(ADD_BACK_TO_CG));
            String restoreDeviceName = rollbackData.get(RESTORE_DEVICE_NAME);
            if ((restoreDeviceName != null) || reattachMirror || addVolumeBackToCG) {
                // Get the API client.
                StorageSystem vplexSystem = getDataObject(StorageSystem.class, vplexURI, _dbClient);
                VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplexSystem, _dbClient);
                _log.info("Got VPLEX API client");
                // Get the VPLEX volume.
                Volume vplexVolume = getDataObject(Volume.class, vplexVolumeURI, _dbClient);
                String vplexVolumeName = vplexVolume.getDeviceLabel();
                _log.info("Got VPLEX volume");
                // the remote mirror, do this first.
                if (reattachMirror) {
                    // Attach the mirror.
                    mirrorDeviceName = rollbackData.get(DETACHED_DEVICE);
                    client.reattachMirrorToDistributedVolume(vplexVolumeName, mirrorDeviceName);
                    _log.info("Reattached the mirror");
                }
                // and needs to be restored, do so after reattaching the device.
                if (restoreDeviceName != null) {
                    String modifiedName = null;
                    try {
                        modifiedName = restoreDeviceName.substring(0, VPlexApiConstants.MAX_DEVICE_NAME_LENGTH_FOR_ATTACH_MIRROR);
                        client.renameDistributedDevice(modifiedName, restoreDeviceName);
                    } catch (Exception e) {
                        // We don't fail the rollback workflow step in this case, but instead just log a message
                        // indicating this error. The distribute device for the volume will just have
                        // the modified name.
                        successWarningMessage = String.format("Failed renaming the distributed device %s back " + " to its orginal name %s after reattaching remote mirror", modifiedName, restoreDeviceName);
                        _log.warn(successWarningMessage);
                    }
                }
                // reattached.
                if (addVolumeBackToCG) {
                    ConsistencyGroupManager consistencyGroupManager = getConsistencyGroupManager(vplexVolume);
                    consistencyGroupManager.addVolumeToCg(cgURI, vplexVolume, client, false);
                    _log.info("Added volume back to consistency group.");
                }
            }
        }
        // Update workflow step state to success.
        if (successWarningMessage != null) {
            WorkflowStepCompleter.stepSucceeded(stepId, successWarningMessage);
        } else {
            WorkflowStepCompleter.stepSucceded(stepId);
        }
        _log.info("Updated workflow step state to success");
    } catch (VPlexApiException vae) {
        _log.error("Exception in restore/resync volume rollback for VPLEX distributed volume" + vae.getMessage(), vae);
        WorkflowStepCompleter.stepFailed(stepId, vae);
    } catch (Exception e) {
        _log.error("Exception in restore/resync volume rollback for VPLEX distributed volume " + e.getMessage(), e);
        WorkflowStepCompleter.stepFailed(stepId, VPlexApiException.exceptions.failedAttachingVPlexVolumeMirror(mirrorDeviceName, vplexVolumeURI.toString(), e));
    }
}
Also used : Volume(com.emc.storageos.db.client.model.Volume) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient) Map(java.util.Map) OpStatusMap(com.emc.storageos.db.client.model.OpStatusMap) HashMap(java.util.HashMap) StringMap(com.emc.storageos.db.client.model.StringMap) InternalException(com.emc.storageos.svcs.errorhandling.resources.InternalException) InternalServerErrorException(com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) ControllerException(com.emc.storageos.volumecontroller.ControllerException) IOException(java.io.IOException) URISyntaxException(java.net.URISyntaxException) WorkflowException(com.emc.storageos.workflow.WorkflowException) DatabaseException(com.emc.storageos.db.exceptions.DatabaseException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Aggregations

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