Search in sources :

Example 1 with VolumeInfo

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

the class VplexVolumeValidator method validateVolume.

/**
 * Validates an individual volume.
 *
 * @param virtualVolume the Volume to validate
 * @param delete boolean indicating if this validation is part of a delete operation
 * @param remediate boolean indicating whether or not remediation should be attempted
 * @param checks variable list of ValCks
 */
public void validateVolume(Volume virtualVolume, boolean delete, boolean remediate, ValCk... checks) {
    List<ValCk> checkList = Arrays.asList(checks);
    String volumeId = String.format("%s (%s)(%s)", virtualVolume.getLabel(), virtualVolume.getNativeGuid(), virtualVolume.getId());
    log.info("Initiating Vplex Volume validation: " + volumeId);
    VPlexVirtualVolumeInfo vvinfo = null;
    try {
        vvinfo = client.findVirtualVolume(virtualVolume.getDeviceLabel(), virtualVolume.getNativeId());
    } catch (VPlexApiException ex) {
        log.info(ex.getMessage());
    }
    if (vvinfo == null) {
        try {
            // Didn't find the virtual volume. Look at the storage volume, and from that determine
            // the deviceName. Then lookup the Device or DistributedDevice and check to see if
            // the device has been reassigned to a different virtual volume.
            Volume storageVolume = VPlexUtil.getVPLEXBackendVolume(virtualVolume, true, getDbClient(), false);
            if (storageVolume != null) {
                StorageSystem system = getDbClient().queryObject(StorageSystem.class, storageVolume.getStorageController());
                // Look up the corresponding device name to our Storage Volume
                VolumeInfo volumeInfo = new VolumeInfo(system.getNativeGuid(), system.getSystemType(), storageVolume.getWWN().toUpperCase().replaceAll(":", ""), storageVolume.getNativeId(), storageVolume.getThinlyProvisioned().booleanValue(), VPlexControllerUtils.getVolumeITLs(storageVolume));
                String deviceName = client.getDeviceForStorageVolume(volumeInfo);
                log.info("device name is " + deviceName);
                if (deviceName == null) {
                    if (!delete) {
                        // We didn't find a device name for the storage volume. Error if not deleting.
                        getValidatorLogger().logDiff(volumeId, "Vplex device-name", system.getSerialNumber() + "-" + storageVolume.getNativeId(), ValidatorLogger.NO_MATCHING_ENTRY);
                        return;
                    }
                }
                if (null != deviceName && !deviceName.trim().matches(VPlexApiConstants.STORAGE_VOLUME_NOT_IN_USE)) {
                    String volumeType = VPlexApiConstants.LOCAL_VIRTUAL_VOLUME;
                    if (virtualVolume.getAssociatedVolumes() != null && virtualVolume.getAssociatedVolumes().size() > 1) {
                        volumeType = VPlexApiConstants.DISTRIBUTED_VIRTUAL_VOLUME;
                    }
                    VPlexResourceInfo resourceInfo = client.getDeviceStructure(deviceName, volumeType);
                    if (resourceInfo instanceof VPlexDeviceInfo) {
                        // local device
                        VPlexDeviceInfo localDeviceInfo = (VPlexDeviceInfo) resourceInfo;
                        String virtualVolumeName = localDeviceInfo.getVirtualVolume();
                        if (virtualVolumeName != null && !virtualVolumeName.equals(virtualVolume.getDeviceLabel())) {
                            getValidatorLogger().logDiff(volumeId, "virtual-volume name changed", virtualVolume.getDeviceLabel(), virtualVolumeName);
                        }
                    } else if (resourceInfo instanceof VPlexDistributedDeviceInfo) {
                        VPlexDistributedDeviceInfo distDeviceInfo = (VPlexDistributedDeviceInfo) resourceInfo;
                        String virtualVolumeName = distDeviceInfo.getVirtualVolume();
                        if (virtualVolumeName != null && !virtualVolumeName.equals(virtualVolume.getDeviceLabel())) {
                            getValidatorLogger().logDiff(volumeId, "virtual-volume name changed", virtualVolume.getDeviceLabel(), virtualVolumeName);
                        }
                    }
                }
            }
        } catch (VPlexApiException ex) {
            log.error("Unable to determine if VPLEX device reused: " + volumeId, ex);
            if (getValidatorConfig().isValidationEnabled()) {
                throw ex;
            }
        }
        if (!delete) {
            // If we didn't log an error above indicating that the volume was reused,
            // and we are not deleting, it is still an error.
            // If we are deleting we won't error if it's just not there.
            getValidatorLogger().logDiff(volumeId, "virtual-volume", virtualVolume.getDeviceLabel(), ValidatorLogger.NO_MATCHING_ENTRY);
        }
        log.info("Vplex Validation complete (no vvinfo found); " + volumeId);
        return;
    }
    if (checkList.contains(ValCk.ID)) {
        if (!virtualVolume.getDeviceLabel().equals(vvinfo.getName())) {
            getValidatorLogger().logDiff(volumeId, "native-id", virtualVolume.getNativeId(), vvinfo.getName());
        }
        if (!NullColumnValueGetter.isNullValue(virtualVolume.getWWN()) && vvinfo.getWwn() != null && !virtualVolume.getWWN().equalsIgnoreCase(vvinfo.getWwn())) {
            getValidatorLogger().logDiff(volumeId, "wwn", virtualVolume.getWWN(), vvinfo.getWwn());
        }
        if (virtualVolume.getAssociatedVolumes() != null && !virtualVolume.getAssociatedVolumes().isEmpty()) {
            String locality = virtualVolume.getAssociatedVolumes().size() > 1 ? VPlexApiConstants.DISTRIBUTED_VIRTUAL_VOLUME : VPlexApiConstants.LOCAL_VIRTUAL_VOLUME;
            if (!locality.equalsIgnoreCase(vvinfo.getLocality())) {
                getValidatorLogger().logDiff(volumeId, "locality", locality, vvinfo.getLocality());
            }
        }
    }
    if (checkList.contains(ValCk.VPLEX) && !virtualVolume.isIngestedVolumeWithoutBackend(getDbClient())) {
        try {
            String drillDownInfo = client.getDrillDownInfoForDevice(vvinfo.getSupportingDevice());
            VPlexDrillDownParser parser = new VPlexDrillDownParser(drillDownInfo);
            VPlexDrillDownParser.Node root = parser.parse();
            boolean distributed = (root.getType() == VPlexDrillDownParser.NodeType.DIST) ? true : false;
            if (distributed) {
                List<VPlexDrillDownParser.Node> svols = root.getNodesOfType(NodeType.SVOL);
                boolean hasMirror = svols.size() > 2;
                String clusterName = VPlexControllerUtils.getVPlexClusterName(getDbClient(), virtualVolume);
                for (VPlexDrillDownParser.Node child : root.getChildren()) {
                    if (child.getArg2().equals(clusterName)) {
                        validateStorageVolumes(virtualVolume, volumeId, root.getArg1(), true, child.getArg2(), hasMirror);
                    }
                }
            } else {
                List<VPlexDrillDownParser.Node> svols = root.getNodesOfType(NodeType.SVOL);
                boolean hasMirror = svols.size() > 1;
                validateStorageVolumes(virtualVolume, volumeId, root.getArg1(), false, root.getArg2(), hasMirror);
            }
        } catch (Exception ex) {
            getValidatorLogger().logDiff(volumeId, "exception trying to validate storage volumes", virtualVolume.getDeviceLabel(), "N/A");
        }
    }
    log.info("Vplex Validation complete; " + volumeId);
}
Also used : ValCk(com.emc.storageos.volumecontroller.impl.validators.ValCk) VPlexDistributedDeviceInfo(com.emc.storageos.vplex.api.VPlexDistributedDeviceInfo) VPlexVirtualVolumeInfo(com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo) VPlexStorageVolumeInfo(com.emc.storageos.vplex.api.VPlexStorageVolumeInfo) VolumeInfo(com.emc.storageos.vplex.api.clientdata.VolumeInfo) VPlexDrillDownParser(com.emc.storageos.util.VPlexDrillDownParser) VPlexVirtualVolumeInfo(com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) Volume(com.emc.storageos.db.client.model.Volume) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) VPlexDeviceInfo(com.emc.storageos.vplex.api.VPlexDeviceInfo) VPlexResourceInfo(com.emc.storageos.vplex.api.VPlexResourceInfo) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Example 2 with VolumeInfo

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

the class VPlexDeviceController method createVirtualVolumes.

/**
 * Do the creation of a VPlex Virtual Volume. This is called as a Workflow Step.
 * NOTE: The parameters here must match createVirtualVolumesMethod above (except stepId).
 *
 * @param vplexURI
 *            -- URI of the VPlex StorageSystem
 * @param vplexVolumeURIs
 *            -- URI of the VPlex volumes to be created. They must contain
 *            associatedVolumes (URI of the underlying Storage Volumes).
 * @param computeResourceMap
 *            A Map of the compute resource for each volume.
 * @param stepId
 *            - The stepId used for completion.
 * @throws WorkflowException
 */
public void createVirtualVolumes(URI vplexURI, List<URI> vplexVolumeURIs, Map<URI, URI> computeResourceMap, String stepId) throws WorkflowException {
    List<List<VolumeInfo>> rollbackData = new ArrayList<List<VolumeInfo>>();
    List<URI> createdVplexVolumeURIs = new ArrayList<URI>();
    try {
        WorkflowStepCompleter.stepExecuting(stepId);
        // Get the API client.
        StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
        VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
        // Make a map of StorageSystem ids to Storage System
        Map<URI, StorageSystem> storageMap = new HashMap<URI, StorageSystem>();
        // Make a map of Virtual Volumes to Storage Volumes.
        Map<Volume, List<Volume>> volumeMap = new HashMap<Volume, List<Volume>>();
        // Make a string buffer for volume labels
        StringBuffer volumeLabels = new StringBuffer();
        // List of storage system Guids
        List<String> storageSystemGuids = new ArrayList<String>();
        Boolean isDistributedVolume = false;
        Map<String, Set<URI>> clusterVarrayMap = new HashMap<>();
        for (URI vplexVolumeURI : vplexVolumeURIs) {
            Volume vplexVolume = getDataObject(Volume.class, vplexVolumeURI, _dbClient);
            URI vplexVolumeVarrayURI = vplexVolume.getVirtualArray();
            String clusterId = ConnectivityUtil.getVplexClusterForVarray(vplexVolumeVarrayURI, vplexVolume.getStorageController(), _dbClient);
            if (clusterVarrayMap.containsKey(clusterId)) {
                clusterVarrayMap.get(clusterId).add(vplexVolumeVarrayURI);
            } else {
                Set<URI> varraysForCluster = new HashSet<>();
                varraysForCluster.add(vplexVolumeVarrayURI);
                clusterVarrayMap.put(clusterId, varraysForCluster);
            }
            volumeLabels.append(vplexVolume.getLabel()).append(" ");
            volumeMap.put(vplexVolume, new ArrayList<Volume>());
            // Find the underlying Storage Volumes
            StringSet associatedVolumes = vplexVolume.getAssociatedVolumes();
            if (associatedVolumes.size() > 1) {
                isDistributedVolume = true;
            }
            for (String associatedVolume : associatedVolumes) {
                Volume storageVolume = getDataObject(Volume.class, new URI(associatedVolume), _dbClient);
                URI storageSystemId = storageVolume.getStorageController();
                if (storageMap.containsKey(storageSystemId) == false) {
                    StorageSystem storage = _dbClient.queryObject(StorageSystem.class, storageSystemId);
                    storageMap.put(storageSystemId, storage);
                    if (!storageSystemGuids.contains(storage.getNativeGuid())) {
                        storageSystemGuids.add(storage.getNativeGuid());
                    }
                }
                volumeMap.get(vplexVolume).add(storageVolume);
            }
        }
        _log.info(String.format("Request to create: %s virtual volume(s) %s", volumeMap.size(), volumeLabels));
        long startTime = System.currentTimeMillis();
        // If a new backend system is connected to a VPLEX and the VPLEX does not
        // yet know about the system i.e., the system does not show up in the path
        // /clusters/cluster-x/storage-elements/storage-arrays, and a user attempts
        // to create a virtual volume, the request may fail because we cannot find
        // the storage system. When the backend volume on the new system is created
        // and exported to the VPLEX, the VPLEX will recognize new system. However,
        // this may not occur immediately. So, when we go to create the vplex volume
        // using that backend volume, we may not find that system and volume on the
        // first try. We saw this in development. As such there was a retry loop
        // added when finding the backend volumes in the discovery that is performed
        // in the method to create the virtual volume.
        // 
        // However changes for CTRL-12826 were merged on 7/31/2015 that circumvented
        // that retry code. Changes were made to do the array re-discover here prior
        // to virtual volume creation, rather than during virtual volume creation and
        // false was passed to the create virtual volume routine for the discovery
        // required flag. The newly added call does not do any kind of retry if the
        // system is not found and so a failure will occur in the scenario described
        // above. If a system is not found an exception is thrown. Now we will catch
        // that exception and re-enable discovery in the volume creation routine.
        // Essentially we revert to what was happening before the 12826 changes if there
        // is an issue discovering the systems on the initial try here.
        boolean discoveryRequired = false;
        try {
            client.rediscoverStorageSystems(storageSystemGuids);
        } catch (Exception e) {
            String warnMsg = String.format("Initial discovery of one or more of these backend systems %s failed: %s." + "Discovery is required during virtual volume creation", storageSystemGuids, e.getMessage());
            _log.warn(warnMsg);
            discoveryRequired = true;
        }
        // Now make a call to the VPlexAPIClient.createVirtualVolume for each vplex volume.
        StringBuilder buf = new StringBuilder();
        buf.append("Vplex: " + vplexURI + " created virtual volume(s): ");
        boolean thinEnabled = false;
        boolean searchAllClustersForStorageVolumes = ((clusterVarrayMap.keySet().size() > 1 || isDistributedVolume) ? true : false);
        List<VPlexVirtualVolumeInfo> virtualVolumeInfos = new ArrayList<VPlexVirtualVolumeInfo>();
        Map<String, Volume> vplexVolumeNameMap = new HashMap<String, Volume>();
        List<VPlexClusterInfo> clusterInfoList = null;
        for (Volume vplexVolume : volumeMap.keySet()) {
            URI vplexVolumeId = vplexVolume.getId();
            _log.info(String.format("Creating virtual volume: %s (%s)", vplexVolume.getLabel(), vplexVolumeId));
            URI vplexVolumeVarrayURI = vplexVolume.getVirtualArray();
            String clusterId = null;
            for (Entry<String, Set<URI>> clusterEntry : clusterVarrayMap.entrySet()) {
                if (clusterEntry.getValue().contains(vplexVolumeVarrayURI)) {
                    clusterId = clusterEntry.getKey();
                }
            }
            List<VolumeInfo> vinfos = new ArrayList<VolumeInfo>();
            for (Volume storageVolume : volumeMap.get(vplexVolume)) {
                StorageSystem storage = storageMap.get(storageVolume.getStorageController());
                List<String> itls = VPlexControllerUtils.getVolumeITLs(storageVolume);
                VolumeInfo info = new VolumeInfo(storage.getNativeGuid(), storage.getSystemType(), storageVolume.getWWN().toUpperCase().replaceAll(":", ""), storageVolume.getNativeId(), storageVolume.getThinlyProvisioned().booleanValue(), itls);
                if (storageVolume.getVirtualArray().equals(vplexVolumeVarrayURI)) {
                    // We always want the source backend volume identified first. It
                    // may not be first in the map as the map is derived from the
                    // VPLEX volume's associated volumes list which is an unordered
                    // StringSet.
                    vinfos.add(0, info);
                } else {
                    vinfos.add(info);
                }
                if (info.getIsThinProvisioned()) {
                    // if either or both legs of distributed is thin, try for thin-enabled
                    // (or if local and the single backend volume is thin, try as well)
                    thinEnabled = true;
                }
            }
            // Update rollback information.
            rollbackData.add(vinfos);
            _workflowService.storeStepData(stepId, rollbackData);
            InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_045);
            // Make a call to get cluster info
            if (null == clusterInfoList) {
                if (searchAllClustersForStorageVolumes) {
                    clusterInfoList = client.getClusterInfoDetails();
                } else {
                    clusterInfoList = new ArrayList<VPlexClusterInfo>();
                }
            }
            // Make the call to create a virtual volume. It is distributed if there are two (or more?)
            // physical volumes.
            boolean isDistributed = (vinfos.size() >= 2);
            thinEnabled = thinEnabled && verifyVplexSupportsThinProvisioning(vplex);
            VPlexVirtualVolumeInfo vvInfo = client.createVirtualVolume(vinfos, isDistributed, discoveryRequired, false, clusterId, clusterInfoList, false, thinEnabled, searchAllClustersForStorageVolumes);
            // Note: according to client.createVirtualVolume, this will never be the case.
            if (vvInfo == null) {
                VPlexApiException ex = VPlexApiException.exceptions.cantFindRequestedVolume(vplexVolume.getLabel());
                throw ex;
            }
            vplexVolumeNameMap.put(vvInfo.getName(), vplexVolume);
            virtualVolumeInfos.add(vvInfo);
        }
        InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_046);
        Map<String, VPlexVirtualVolumeInfo> foundVirtualVolumes = client.findVirtualVolumes(clusterInfoList, virtualVolumeInfos);
        if (!foundVirtualVolumes.isEmpty()) {
            for (Entry<String, Volume> entry : vplexVolumeNameMap.entrySet()) {
                Volume vplexVolume = entry.getValue();
                VPlexVirtualVolumeInfo vvInfo = foundVirtualVolumes.get(entry.getKey());
                try {
                    // Now we try and rename the volume to the customized name. Note that if custom naming
                    // is disabled the custom name will not be generated and will be null.
                    // Create the VPLEX volume name custom configuration datasource and generate the
                    // custom volume name based on whether the volume is a local or distributed volume.
                    String hostOrClusterName = null;
                    URI computeResourceURI = computeResourceMap.get(vplexVolume.getId());
                    if (computeResourceURI != null) {
                        DataObject hostOrCluster = null;
                        if (URIUtil.isType(computeResourceURI, Cluster.class)) {
                            hostOrCluster = getDataObject(Cluster.class, computeResourceURI, _dbClient);
                        } else if (URIUtil.isType(computeResourceURI, Host.class)) {
                            hostOrCluster = getDataObject(Host.class, computeResourceURI, _dbClient);
                        }
                        if ((hostOrCluster != null) && ((vplexVolume.getPersonality() == null) || (vplexVolume.checkPersonality(Volume.PersonalityTypes.SOURCE)))) {
                            hostOrClusterName = hostOrCluster.getLabel();
                        }
                    }
                    if (CustomVolumeNamingUtils.isCustomVolumeNamingEnabled(customConfigHandler, vplex.getSystemType())) {
                        String customConfigName = CustomVolumeNamingUtils.getCustomConfigName(hostOrClusterName != null);
                        Project project = getDataObject(Project.class, vplexVolume.getProject().getURI(), _dbClient);
                        TenantOrg tenant = getDataObject(TenantOrg.class, vplexVolume.getTenant().getURI(), _dbClient);
                        DataSource customNameDataSource = CustomVolumeNamingUtils.getCustomConfigDataSource(project, tenant, vplexVolume.getLabel(), vvInfo.getWwn(), hostOrClusterName, dataSourceFactory, customConfigName, _dbClient);
                        if (customNameDataSource != null) {
                            String customVolumeName = CustomVolumeNamingUtils.getCustomName(customConfigHandler, customConfigName, customNameDataSource, vplex.getSystemType());
                            vvInfo = CustomVolumeNamingUtils.renameVolumeOnVPlex(vvInfo, customVolumeName, client);
                            // Update the label to match the custom name.
                            vplexVolume.setLabel(vvInfo.getName());
                            // Also, we update the name portion of the project and tenant URIs
                            // to reflect the custom name. This is necessary because the API
                            // to search for volumes by project, extracts the name portion of the
                            // project URI to get the volume name.
                            NamedURI namedURI = vplexVolume.getProject();
                            namedURI.setName(vvInfo.getName());
                            vplexVolume.setProject(namedURI);
                            namedURI = vplexVolume.getTenant();
                            namedURI.setName(vvInfo.getName());
                            vplexVolume.setTenant(namedURI);
                        }
                    }
                } catch (Exception e) {
                    _log.warn(String.format("Error renaming newly created VPLEX volume %s:%s", vplexVolume.getId(), vplexVolume.getLabel()), e);
                }
                buf.append(vvInfo.getName() + " ");
                _log.info(String.format("Created virtual volume: %s path: %s size: %s", vvInfo.getName(), vvInfo.getPath(), vvInfo.getCapacityBytes()));
                vplexVolume.setNativeId(vvInfo.getPath());
                vplexVolume.setNativeGuid(vvInfo.getPath());
                vplexVolume.setDeviceLabel(vvInfo.getName());
                vplexVolume.setThinlyProvisioned(vvInfo.isThinEnabled());
                checkThinEnabledResult(vvInfo, thinEnabled, _workflowService.getWorkflowFromStepId(stepId).getOrchTaskId());
                vplexVolume.setWWN(vvInfo.getWwn());
                // For Vplex virtual volumes set allocated capacity to 0 (cop-18608)
                vplexVolume.setAllocatedCapacity(0L);
                vplexVolume.setProvisionedCapacity(vvInfo.getCapacityBytes());
                _dbClient.updateObject(vplexVolume);
                // Record VPLEX volume created event.
                createdVplexVolumeURIs.add(vplexVolume.getId());
                recordBourneVolumeEvent(vplexVolume.getId(), OperationTypeEnum.CREATE_BLOCK_VOLUME.getEvType(true), Operation.Status.ready, OperationTypeEnum.CREATE_BLOCK_VOLUME.getDescription());
            }
        }
        if (foundVirtualVolumes.size() != vplexVolumeNameMap.size()) {
            VPlexApiException ex = VPlexApiException.exceptions.cantFindAllRequestedVolume();
            throw ex;
        }
        long elapsed = System.currentTimeMillis() - startTime;
        _log.info(String.format("TIMER: %s virtual volume(s) %s create took %f seconds", volumeMap.size(), volumeLabels.toString(), (double) elapsed / (double) 1000));
        WorkflowStepCompleter.stepSucceded(stepId);
    } catch (VPlexApiException vae) {
        _log.error("Exception creating Vplex Virtual Volume: " + vae.getMessage(), vae);
        // not created.
        for (URI vplexVolumeURI : vplexVolumeURIs) {
            if (!createdVplexVolumeURIs.contains(vplexVolumeURI)) {
                recordBourneVolumeEvent(vplexVolumeURI, OperationTypeEnum.CREATE_BLOCK_VOLUME.getEvType(false), Operation.Status.error, OperationTypeEnum.CREATE_BLOCK_VOLUME.getDescription());
            }
        }
        WorkflowStepCompleter.stepFailed(stepId, vae);
    } catch (Exception ex) {
        _log.error("Exception creating Vplex Virtual Volume: " + ex.getMessage(), ex);
        // not created.
        for (URI vplexVolumeURI : vplexVolumeURIs) {
            if (!createdVplexVolumeURIs.contains(vplexVolumeURI)) {
                recordBourneVolumeEvent(vplexVolumeURI, OperationTypeEnum.CREATE_BLOCK_VOLUME.getEvType(false), Operation.Status.error, OperationTypeEnum.CREATE_BLOCK_VOLUME.getDescription());
            }
        }
        String opName = ResourceOperationTypeEnum.CREATE_VIRTUAL_VOLUME.getName();
        ServiceError serviceError = VPlexApiException.errors.createVirtualVolumesFailed(opName, ex);
        WorkflowStepCompleter.stepFailed(stepId, serviceError);
    }
}
Also used : Set(java.util.Set) HashSet(java.util.HashSet) StringSet(com.emc.storageos.db.client.model.StringSet) HashMap(java.util.HashMap) NamedURI(com.emc.storageos.db.client.model.NamedURI) ArrayList(java.util.ArrayList) VolumeInfo(com.emc.storageos.vplex.api.clientdata.VolumeInfo) VPlexVirtualVolumeInfo(com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo) NamedURI(com.emc.storageos.db.client.model.NamedURI) URI(java.net.URI) VPlexVirtualVolumeInfo(com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo) VPlexClusterInfo(com.emc.storageos.vplex.api.VPlexClusterInfo) StringSet(com.emc.storageos.db.client.model.StringSet) 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) HashSet(java.util.HashSet) ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) Cluster(com.emc.storageos.db.client.model.Cluster) Host(com.emc.storageos.db.client.model.Host) InternalException(com.emc.storageos.svcs.errorhandling.resources.InternalException) InternalServerErrorException(com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) ControllerException(com.emc.storageos.volumecontroller.ControllerException) IOException(java.io.IOException) URISyntaxException(java.net.URISyntaxException) WorkflowException(com.emc.storageos.workflow.WorkflowException) DatabaseException(com.emc.storageos.db.exceptions.DatabaseException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) DataSource(com.emc.storageos.customconfigcontroller.DataSource) Project(com.emc.storageos.db.client.model.Project) DiscoveredDataObject(com.emc.storageos.db.client.model.DiscoveredDataObject) DataObject(com.emc.storageos.db.client.model.DataObject) VPlexControllerUtils.getDataObject(com.emc.storageos.vplexcontroller.VPlexControllerUtils.getDataObject) Volume(com.emc.storageos.db.client.model.Volume) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient) TenantOrg(com.emc.storageos.db.client.model.TenantOrg)

Example 3 with VolumeInfo

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

the class VPlexDeviceController method createVirtualVolumeFromImportStep.

/**
 * Create a Virtual Volume from an Imported Volume.
 * There are three cases here:
 * 1. We want to create a non-distributed virtual volume. In this case,
 * there is an existingVolume, but newVolume == null.
 * 2. We want to create a distributed virtual volume from an existing volume,
 * and then add a mirror to a new volume (in the other varray).
 * In this case, both existingVolume and newVolume are non-null.
 * 3. We had an existing Virtual volume, and we only want to upgrade it
 * to a distributed Virtual Volume (existingVolumeURI == null).
 *
 * @param vplexURI
 * @param vplexVolumeURI
 * @param existingVolumeURI
 * @param newVolumeURI
 * @param vplexSystemProject
 * @param vplexSystemTenant
 * @param newCosURI
 * @param newLabel
 * @param stepId
 * @throws WorkflowException
 */
public void createVirtualVolumeFromImportStep(URI vplexURI, URI vplexVolumeURI, URI existingVolumeURI, URI newVolumeURI, URI vplexSystemProject, URI vplexSystemTenant, URI newCosURI, String newLabel, String transferSize, String stepId) throws WorkflowException {
    try {
        WorkflowStepCompleter.stepExecuting(stepId);
        // Get the API client.
        StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
        VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
        // Get the three volumes.
        Volume vplexVolume = getDataObject(Volume.class, vplexVolumeURI, _dbClient);
        Volume existingVolume = null;
        Volume newVolume = null;
        if (existingVolumeURI != null) {
            existingVolume = getDataObject(Volume.class, existingVolumeURI, _dbClient);
        }
        if (newVolumeURI != null) {
            newVolume = getDataObject(Volume.class, newVolumeURI, _dbClient);
        }
        VPlexVirtualVolumeInfo virtvinfo = null;
        VolumeInfo vinfo = null;
        // Make the call to create the (non-distributed) virtual volume.
        if (existingVolume != null) {
            StorageSystem array = getDataObject(StorageSystem.class, existingVolume.getStorageController(), _dbClient);
            List<String> itls = VPlexControllerUtils.getVolumeITLs(existingVolume);
            List<VolumeInfo> vinfos = new ArrayList<VolumeInfo>();
            VirtualPool newVirtualPool = getDataObject(VirtualPool.class, newCosURI, _dbClient);
            boolean thinEnabled = VirtualPool.ProvisioningType.Thin.toString().equalsIgnoreCase(newVirtualPool.getSupportedProvisioningType());
            vinfo = new VolumeInfo(array.getNativeGuid(), array.getSystemType(), existingVolume.getWWN().toUpperCase().replaceAll(":", ""), existingVolume.getNativeId(), thinEnabled, itls);
            vinfos.add(vinfo);
            thinEnabled = thinEnabled && verifyVplexSupportsThinProvisioning(vplex);
            virtvinfo = client.createVirtualVolume(vinfos, false, true, true, null, null, true, thinEnabled, true);
            // Note: According to client.createVirtualVolume code, this will never be the case (null)
            if (virtvinfo == null) {
                String opName = ResourceOperationTypeEnum.CREATE_VVOLUME_FROM_IMPORT.getName();
                ServiceError serviceError = VPlexApiException.errors.createVirtualVolumeFromImportStepFailed(opName);
                WorkflowStepCompleter.stepFailed(stepId, serviceError);
                return;
            }
            _log.info(String.format("Created virtual volume: %s path: %s thinEnabled: %b", virtvinfo.getName(), virtvinfo.getPath(), virtvinfo.isThinEnabled()));
            checkThinEnabledResult(virtvinfo, thinEnabled, _workflowService.getWorkflowFromStepId(stepId).getOrchTaskId());
            // not set.
            if (newVolume != null) {
                vplexVolume.setNativeId(virtvinfo.getPath());
                vplexVolume.setNativeGuid(virtvinfo.getPath());
                vplexVolume.setDeviceLabel(virtvinfo.getName());
                vplexVolume.setThinlyProvisioned(virtvinfo.isThinEnabled());
                _dbClient.updateObject(vplexVolume);
            }
        } else {
            virtvinfo = client.findVirtualVolume(vplexVolume.getDeviceLabel(), vplexVolume.getNativeId());
        }
        // now create a mirror to the new volume.
        if (newVolume != null) {
            String clusterId = ConnectivityUtil.getVplexClusterForVarray(vplexVolume.getVirtualArray(), vplexVolume.getStorageController(), _dbClient);
            StorageSystem array = getDataObject(StorageSystem.class, newVolume.getStorageController(), _dbClient);
            List<String> itls = VPlexControllerUtils.getVolumeITLs(newVolume);
            vinfo = new VolumeInfo(array.getNativeGuid(), array.getSystemType(), newVolume.getWWN().toUpperCase().replaceAll(":", ""), newVolume.getNativeId(), newVolume.getThinlyProvisioned().booleanValue(), itls);
            // Add rollback data.
            _workflowService.storeStepData(stepId, vinfo);
            virtvinfo = client.upgradeVirtualVolumeToDistributed(virtvinfo, vinfo, true, clusterId, transferSize);
            if (virtvinfo == null) {
                String opName = ResourceOperationTypeEnum.UPGRADE_VPLEX_LOCAL_TO_DISTRIBUTED.getName();
                ServiceError serviceError = VPlexApiException.errors.upgradeLocalToDistributedFailed(opName);
                WorkflowStepCompleter.stepFailed(stepId, serviceError);
                return;
            }
        }
        // Update the virtual volume device label and native Id.
        // Also make sure the WWN is set.
        vplexVolume.setNativeId(virtvinfo.getPath());
        vplexVolume.setNativeGuid(virtvinfo.getPath());
        vplexVolume.setDeviceLabel(virtvinfo.getName());
        vplexVolume.setThinlyProvisioned(virtvinfo.isThinEnabled());
        vplexVolume.setWWN(virtvinfo.getWwn());
        // If we are importing, we need to move the existing import volume to
        // the system project/tenant, update its label, and set the new CoS.
        Volume srcSideAssocVolume = null;
        if (existingVolume != null) {
            srcSideAssocVolume = existingVolume;
            existingVolume.setProject(new NamedURI(vplexSystemProject, existingVolume.getLabel()));
            existingVolume.setTenant(new NamedURI(vplexSystemTenant, existingVolume.getLabel()));
            existingVolume.setLabel(newLabel);
            existingVolume.setVirtualPool(newCosURI);
            existingVolume.addInternalFlags(Flag.INTERNAL_OBJECT);
            _dbClient.updateObject(existingVolume);
            // If the VPLEX volume is being upgraded to distributed, it's provisioned
            // should be set and does not change. However, when importing an existing
            // volume to a VPLEX volume, we need to set the provisioned capacity
            // of the VPLEX volume to the provisioned capacity of the existing volume.
            vplexVolume.setProvisionedCapacity(existingVolume.getProvisionedCapacity());
            // For Vplex virtual volumes set allocated capacity to 0 (cop-18608)
            vplexVolume.setAllocatedCapacity(0L);
            // For import associated with creating a VPLEX full copy, we need
            // to add the copy to the list of copies for the source VPLEX volume.
            // We only do this when the copy is successfully completed.
            URI srcVplexVolumeURI = vplexVolume.getAssociatedSourceVolume();
            if (!NullColumnValueGetter.isNullURI(srcVplexVolumeURI)) {
                // Note that the associated source volume will be null if
                // this is just a standard import of a non-VPLEX volume. It
                // will be set in the case we use the import workflow to
                // import a native copy to a VPLEX volume for the purpose
                // of creating a full copy.
                Volume srcVplexVolume = _dbClient.queryObject(Volume.class, srcVplexVolumeURI);
                if (null != srcVplexVolume) {
                    StringSet srcVplexVolumeCopies = srcVplexVolume.getFullCopies();
                    if (srcVplexVolumeCopies == null) {
                        srcVplexVolumeCopies = new StringSet();
                        srcVplexVolume.setFullCopies(srcVplexVolumeCopies);
                    }
                    srcVplexVolumeCopies.add(vplexVolumeURI.toString());
                    _dbClient.updateObject(srcVplexVolume);
                }
                // Also, reflect the replica state in the vplex copy.
                vplexVolume.setReplicaState(existingVolume.getReplicaState());
            }
        } else {
            // and update the CoS.
            for (String assocVolume : vplexVolume.getAssociatedVolumes()) {
                try {
                    srcSideAssocVolume = _dbClient.queryObject(Volume.class, new URI(assocVolume));
                    srcSideAssocVolume.setVirtualPool(newCosURI);
                    _dbClient.updateObject(srcSideAssocVolume);
                } catch (URISyntaxException ex) {
                    _log.error("Bad assocVolume URI: " + assocVolume, ex);
                }
            }
            vplexVolume.getAssociatedVolumes().add(newVolumeURI.toString());
            vplexVolume.setVirtualPool(newCosURI);
        }
        // created and we need to make sure it has the correct name.
        try {
            if ((CustomVolumeNamingUtils.isCustomVolumeNamingEnabled(customConfigHandler, vplex.getSystemType())) && (existingVolume != null)) {
                // Create the VPLEX volume name custom configuration datasource and generate the
                // custom volume name.
                String customConfigName = CustomVolumeNamingUtils.getCustomConfigName(false);
                Project project = getDataObject(Project.class, vplexVolume.getProject().getURI(), _dbClient);
                TenantOrg tenant = getDataObject(TenantOrg.class, vplexVolume.getTenant().getURI(), _dbClient);
                DataSource customNameDataSource = CustomVolumeNamingUtils.getCustomConfigDataSource(project, tenant, vplexVolume.getLabel(), vplexVolume.getWWN(), null, dataSourceFactory, customConfigName, _dbClient);
                if (customNameDataSource != null) {
                    String customVolumeName = CustomVolumeNamingUtils.getCustomName(customConfigHandler, customConfigName, customNameDataSource, vplex.getSystemType());
                    virtvinfo = CustomVolumeNamingUtils.renameVolumeOnVPlex(virtvinfo, customVolumeName, client);
                    vplexVolume.setNativeId(virtvinfo.getPath());
                    vplexVolume.setNativeGuid(virtvinfo.getPath());
                    vplexVolume.setDeviceLabel(virtvinfo.getName());
                    vplexVolume.setLabel(virtvinfo.getName());
                    // Also, we update the name portion of the project and tenant URIs
                    // to reflect the custom name. This is necessary because the API
                    // to search for volumes by project, extracts the name portion of the
                    // project URI to get the volume name.
                    NamedURI namedURI = vplexVolume.getProject();
                    namedURI.setName(virtvinfo.getName());
                    vplexVolume.setProject(namedURI);
                    namedURI = vplexVolume.getTenant();
                    namedURI.setName(virtvinfo.getName());
                    vplexVolume.setTenant(namedURI);
                }
            }
        } catch (Exception e) {
            _log.warn(String.format("Error attempting to rename VPLEX volume %s", vplexVolumeURI), e);
        }
        // Update the volume.
        _dbClient.updateObject(vplexVolume);
        // Complete the workflow step.
        WorkflowStepCompleter.stepSucceded(stepId);
    } catch (VPlexApiException vae) {
        if (existingVolumeURI != null) {
            _log.error("Exception importing non-VPLEX volume to VPLEX: " + vae.getMessage(), vae);
        } else {
            _log.error("Exception upgrading a local VPLEX volume to distributed: " + vae.getMessage(), vae);
        }
        WorkflowStepCompleter.stepFailed(stepId, vae);
    } catch (Exception ex) {
        ServiceError serviceError;
        if (existingVolumeURI != null) {
            _log.error("Exception importing non-VPLEX volume to VPLEX: " + ex.getMessage(), ex);
            String opName = ResourceOperationTypeEnum.IMPORT_BLOCK_VOLUME.getName();
            serviceError = VPlexApiException.errors.importVolumeFailedException(opName, ex);
        } else {
            _log.error("Exception upgrading a local VPLEX volume to distributed: " + ex.getMessage(), ex);
            String opName = ResourceOperationTypeEnum.UPGRADE_VPLEX_LOCAL_TO_DISTRIBUTED.getName();
            serviceError = VPlexApiException.errors.upgradeLocalToDistributedFailedException(opName, ex);
        }
        WorkflowStepCompleter.stepFailed(stepId, serviceError);
    }
}
Also used : ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) NamedURI(com.emc.storageos.db.client.model.NamedURI) ArrayList(java.util.ArrayList) VolumeInfo(com.emc.storageos.vplex.api.clientdata.VolumeInfo) VPlexVirtualVolumeInfo(com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo) VirtualPool(com.emc.storageos.db.client.model.VirtualPool) URISyntaxException(java.net.URISyntaxException) VPlexVirtualVolumeInfo(com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo) NamedURI(com.emc.storageos.db.client.model.NamedURI) URI(java.net.URI) InternalException(com.emc.storageos.svcs.errorhandling.resources.InternalException) InternalServerErrorException(com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) ControllerException(com.emc.storageos.volumecontroller.ControllerException) IOException(java.io.IOException) URISyntaxException(java.net.URISyntaxException) WorkflowException(com.emc.storageos.workflow.WorkflowException) DatabaseException(com.emc.storageos.db.exceptions.DatabaseException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) DataSource(com.emc.storageos.customconfigcontroller.DataSource) Project(com.emc.storageos.db.client.model.Project) Volume(com.emc.storageos.db.client.model.Volume) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient) StringSet(com.emc.storageos.db.client.model.StringSet) TenantOrg(com.emc.storageos.db.client.model.TenantOrg) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Example 4 with VolumeInfo

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

the class VPlexDeviceController method rollbackUpgradeVirtualVolumeLocalToDistributed.

/**
 * Rollback upgrade of VPLEX local to VPLEX distributed volume.
 *
 * @param vplexURI
 *            Reference to VPLEX system
 * @param virtualVolumeName
 *            Virtual volume name which was supposed to be upgraded
 * @param virtualVolumePath
 *            Virtual volume path which was supposed to be upgraded
 * @param executeStepId
 *            step Id of the execute step; used to retrieve rollback data
 * @param stepId
 *            The rollback step id
 * @throws WorkflowException
 *             When an error occurs updating the workflow step state
 */
public void rollbackUpgradeVirtualVolumeLocalToDistributed(URI vplexURI, String virtualVolumeName, String virtualVolumePath, String executeStepId, String stepId) throws WorkflowException {
    try {
        VolumeInfo mirrorInfo = (VolumeInfo) _workflowService.loadStepData(executeStepId);
        if (mirrorInfo != null) {
            WorkflowStepCompleter.stepExecuting(stepId);
            // Get the API client.
            StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
            VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
            // Get the cluster id for this storage volume.
            String clusterId = client.getClaimedStorageVolumeClusterName(mirrorInfo);
            try {
                // Try to detach mirror that might have been added.
                client.detachMirrorFromDistributedVolume(virtualVolumeName, clusterId);
                // Find virtual volume and its supporting device
                VPlexVirtualVolumeInfo virtualVolumeInfo = client.findVirtualVolume(virtualVolumeName, virtualVolumePath);
                String sourceDeviceName = virtualVolumeInfo.getSupportingDevice();
                // Once mirror is detached we need to do device collapse so that its not seen as distributed device.
                client.deviceCollapse(sourceDeviceName, VPlexApiConstants.DISTRIBUTED_DEVICE);
                // Once device collapse is successful we need to set visibility of device to local because volume will be seen from
                // other cluster still as visibility of device changes to global once mirror is attached.
                client.setDeviceVisibility(sourceDeviceName);
            } catch (Exception e) {
                _log.error("Exception restoring virtual volume " + virtualVolumeName + " to its original state." + e);
                _log.info(String.format("Couldn't detach mirror corresponding to the backend volume %s from the VPLEX volume %s on VPLEX cluster %s during rollback. " + "Its possible mirror was never attached, so just move on to delete backend volume artifacts from the VPLEX", mirrorInfo.getVolumeName(), virtualVolumeName, clusterId));
            }
            // Its possible that mirror was never attached so we will try to delete the device even if we fail to
            // detach a mirror.
            // If mirror device is still attached this will anyway fail, so its safe to make this call.
            client.deleteLocalDevice(mirrorInfo);
        }
        WorkflowStepCompleter.stepSucceded(stepId);
    } catch (VPlexApiException vae) {
        _log.error("Exception rollback VPlex Virtual Volume upgrade from local to distributed : " + vae.getLocalizedMessage(), vae);
        WorkflowStepCompleter.stepFailed(stepId, vae);
    } catch (Exception ex) {
        _log.error("Exception rollback VPlex Virtual Volume upgrade from local to distributed : " + ex.getLocalizedMessage(), ex);
        ServiceError serviceError = VPlexApiException.errors.createVirtualVolumesRollbackFailed(stepId, ex);
        WorkflowStepCompleter.stepFailed(stepId, serviceError);
    }
}
Also used : ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient) VolumeInfo(com.emc.storageos.vplex.api.clientdata.VolumeInfo) VPlexVirtualVolumeInfo(com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo) VPlexVirtualVolumeInfo(com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo) InternalException(com.emc.storageos.svcs.errorhandling.resources.InternalException) InternalServerErrorException(com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) ControllerException(com.emc.storageos.volumecontroller.ControllerException) IOException(java.io.IOException) URISyntaxException(java.net.URISyntaxException) WorkflowException(com.emc.storageos.workflow.WorkflowException) DatabaseException(com.emc.storageos.db.exceptions.DatabaseException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Example 5 with VolumeInfo

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

the class VPlexDeviceController method createMirrors.

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

Aggregations

VolumeInfo (com.emc.storageos.vplex.api.clientdata.VolumeInfo)25 ArrayList (java.util.ArrayList)18 StorageSystem (com.emc.storageos.db.client.model.StorageSystem)11 VPlexVirtualVolumeInfo (com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo)11 VPlexApiException (com.emc.storageos.vplex.api.VPlexApiException)10 DatabaseException (com.emc.storageos.db.exceptions.DatabaseException)9 DeviceControllerException (com.emc.storageos.exceptions.DeviceControllerException)9 InternalException (com.emc.storageos.svcs.errorhandling.resources.InternalException)9 InternalServerErrorException (com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException)9 ControllerException (com.emc.storageos.volumecontroller.ControllerException)9 VPlexApiClient (com.emc.storageos.vplex.api.VPlexApiClient)9 WorkflowException (com.emc.storageos.workflow.WorkflowException)9 IOException (java.io.IOException)9 URISyntaxException (java.net.URISyntaxException)9 Volume (com.emc.storageos.db.client.model.Volume)8 URI (java.net.URI)8 NamedURI (com.emc.storageos.db.client.model.NamedURI)6 ServiceError (com.emc.storageos.svcs.errorhandling.model.ServiceError)6 HashMap (java.util.HashMap)6 URIQueryResultList (com.emc.storageos.db.client.constraint.URIQueryResultList)4