Search in sources :

Example 26 with VPlexApiClient

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

the class VPlexDeviceController method expandVirtualVolume.

/**
 * Expands the virtual volume with the passed URI to it full expandable capacity.
 *
 * @param vplexSystemURI
 *            The URI of the VPlex system.
 * @param vplexVolumeURI
 *            The URI of the VPlex volume to expand.
 * @param newSize
 *            The new requested volume size.
 * @param systemNativeGuids
 *            The URIs of the backend storage systems, or null
 * @param stepId
 *            The workflow step identifier.
 *
 * @throws WorkflowException
 *             When an error occurs updating the work step state.
 */
public void expandVirtualVolume(URI vplexSystemURI, URI vplexVolumeURI, Long newSize, List<String> systemNativeGuids, String stepId) throws WorkflowException {
    try {
        // Update step state to executing.
        WorkflowStepCompleter.stepExecuting(stepId);
        // Get the virtual volume.
        Volume vplexVolume = getDataObject(Volume.class, vplexVolumeURI, _dbClient);
        String vplexVolumeName = vplexVolume.getDeviceLabel();
        _log.info("Virtual volume name is {}", vplexVolumeName);
        // Get the VPlex API client.
        StorageSystem vplexSystem = getDataObject(StorageSystem.class, vplexSystemURI, _dbClient);
        VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplexSystem, _dbClient);
        _log.info("Got VPlex API client for VPlex system {}", vplexSystemURI);
        // arrays to pick up the new expanded volume size.
        if (systemNativeGuids != null) {
            client.rediscoverStorageSystems(systemNativeGuids);
            // Async code.
            try {
                Thread.sleep(60000);
            } catch (Exception e) {
                // ignore exceptions
                _log.warn("thread sleep exception " + e.getLocalizedMessage());
            }
        }
        // Make a call to the VPlex API client to expand the virtual
        // volume.
        int expansionStatusRetryCount = Integer.valueOf(ControllerUtils.getPropertyValueFromCoordinator(coordinator, VPlexApiConstants.EXPANSION_STATUS_RETRY_COUNT));
        long expansionStatusSleepTime = Long.valueOf(ControllerUtils.getPropertyValueFromCoordinator(coordinator, VPlexApiConstants.EXPANSION_STATUS_SLEEP_TIME_MS));
        VPlexVirtualVolumeInfo vplexVolumeInfo = client.expandVirtualVolume(vplexVolumeName, expansionStatusRetryCount, expansionStatusSleepTime);
        _log.info("Completed VPlex volume expansion");
        // Update the VPlex volume size in the database.
        vplexVolume.setCapacity(newSize);
        vplexVolume.setProvisionedCapacity(vplexVolumeInfo.getCapacityBytes());
        // For Vplex virtual volumes set allocated capacity to 0 (cop-18608)
        vplexVolume.setAllocatedCapacity(0L);
        _dbClient.updateObject(vplexVolume);
        _log.info("Updated volume size");
        // Update step status to success.
        WorkflowStepCompleter.stepSucceded(stepId);
    } catch (VPlexApiException vae) {
        _log.error("Exception expanding VPlex virtual volume: " + vae.getMessage(), vae);
        WorkflowStepCompleter.stepFailed(stepId, vae);
    } catch (Exception ex) {
        _log.error("Exception expanding VPlex virtual volume: " + ex.getMessage(), ex);
        String opName = ResourceOperationTypeEnum.EXPAND_VIRTUAL_VOLUME.getName();
        ServiceError serviceError = VPlexApiException.errors.expandVirtualVolumeFailed(opName, ex);
        WorkflowStepCompleter.stepFailed(stepId, serviceError);
    }
}
Also used : ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) Volume(com.emc.storageos.db.client.model.Volume) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient) 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) AlternateIdConstraint(com.emc.storageos.db.client.constraint.AlternateIdConstraint) ContainmentConstraint(com.emc.storageos.db.client.constraint.ContainmentConstraint) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Example 27 with VPlexApiClient

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

the class VPlexDeviceController method refreshConnectionStatusForAllVPlexManagementServers.

/**
 * Refreshes the connection status for all VPLEX management servers.
 *
 * @return The list of those to which a connection was successful.
 */
public List<URI> refreshConnectionStatusForAllVPlexManagementServers() {
    List<URI> activeMgmntServers = new ArrayList<URI>();
    List<StorageProvider> vplexMnmgtServers = CustomQueryUtility.getActiveStorageProvidersByInterfaceType(_dbClient, StorageProvider.InterfaceType.vplex.name());
    for (StorageProvider vplexMnmgtServer : vplexMnmgtServers) {
        try {
            VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplexMnmgtServer, _dbClient);
            client.verifyConnectivity();
            activeMgmntServers.add(vplexMnmgtServer.getId());
            vplexMnmgtServer.setConnectionStatus(StorageProvider.ConnectionStatus.CONNECTED.toString());
        } catch (Exception e) {
            _log.warn("Can't connect to VPLEX management server {}", vplexMnmgtServer.getIPAddress());
            vplexMnmgtServer.setConnectionStatus(StorageProvider.ConnectionStatus.NOTCONNECTED.toString());
        } finally {
            _dbClient.updateObject(vplexMnmgtServer);
        }
    }
    return activeMgmntServers;
}
Also used : VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient) ArrayList(java.util.ArrayList) StorageProvider(com.emc.storageos.db.client.model.StorageProvider) 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)

Example 28 with VPlexApiClient

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

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

the class VPlexDeviceController method rollbackPromoteMirror.

/**
 * Here we try to delete the virtual volume thats created from the mirror and then try to
 * reattach the mirror so as to leave the original state. This is only going to be best effort.
 * Delete the volume objects that were created as promotees.
 *
 * @param promotees
 *            The URIs of the volumes that were supposed to be promoted from mirror.
 * @param executeStepId
 *            step Id of the execute step
 * @param stepId
 *            The stepId used for completion.
 *
 * @throws WorkflowException
 *             When an error occurs updating the workflow step
 *             state.
 */
public void rollbackPromoteMirror(URI vplexURI, URI mirrorURI, URI promoteeURI, String executeStepId, String stepId) throws WorkflowException {
    try {
        // Update step state to executing.
        WorkflowStepCompleter.stepExecuting(stepId);
        VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplexURI, _dbClient);
        VplexMirror vplexMirror = _dbClient.queryObject(VplexMirror.class, mirrorURI);
        // Get source volume for the mirror
        Volume sourceVplexVolume = getDataObject(Volume.class, vplexMirror.getSource().getURI(), _dbClient);
        String locality = null;
        if (sourceVplexVolume.getAssociatedVolumes() != null && sourceVplexVolume.getAssociatedVolumes().size() > 1) {
            locality = VPlexApiConstants.DISTRIBUTED_VIRTUAL_VOLUME;
        } else {
            locality = VPlexApiConstants.LOCAL_VIRTUAL_VOLUME;
        }
        // Delete the virtual volume that should have been created when we did detach mirror.
        // Virtual volume is created with the same name as the device name.
        // Delete the virtual volume only, donot tear down
        client.destroyVirtualVolume(vplexMirror.getDeviceLabel());
        // Attach the mirror device back to the source device
        client.attachMirror(locality, sourceVplexVolume.getDeviceLabel(), vplexMirror.getDeviceLabel());
        _log.info("Successfully re-attached mirror %s to the source volume %s during rollback. ", vplexMirror.getDeviceLabel(), sourceVplexVolume.getDeviceLabel());
    } catch (Exception e) {
        // If exception occurs that means mirror is already detached and we couldn't reattach
        // So cleanup database objects related to a mirror.
        VplexMirror vplexMirror = _dbClient.queryObject(VplexMirror.class, mirrorURI);
        Volume sourceVplexVolume = getDataObject(Volume.class, vplexMirror.getSource().getURI(), _dbClient);
        // Remove mirror from the source VPLEX volume
        sourceVplexVolume.getMirrors().remove(vplexMirror.getId().toString());
        _dbClient.updateObject(sourceVplexVolume);
        _log.info("Removed mirror %s from source volume %s", mirrorURI, sourceVplexVolume.getId());
        // Delete mirror and associated volume from database
        if (null != vplexMirror.getAssociatedVolumes()) {
            for (String assocVolumeId : vplexMirror.getAssociatedVolumes()) {
                Volume volume = _dbClient.queryObject(Volume.class, URI.create(assocVolumeId));
                _dbClient.removeObject(volume);
            }
        }
        // Delete the mirror object
        _dbClient.removeObject(vplexMirror);
        _log.error("Error during rollback of promote mirror: {}", e.getMessage(), e);
    } finally {
        // Delete the volume that was supposed to be promoted volume
        Volume volume = _dbClient.queryObject(Volume.class, promoteeURI);
        _dbClient.removeObject(volume);
        // Return success so rollback continues
        WorkflowStepCompleter.stepSucceded(stepId);
    }
}
Also used : Volume(com.emc.storageos.db.client.model.Volume) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient) VplexMirror(com.emc.storageos.db.client.model.VplexMirror) InternalException(com.emc.storageos.svcs.errorhandling.resources.InternalException) InternalServerErrorException(com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) ControllerException(com.emc.storageos.volumecontroller.ControllerException) IOException(java.io.IOException) URISyntaxException(java.net.URISyntaxException) WorkflowException(com.emc.storageos.workflow.WorkflowException) DatabaseException(com.emc.storageos.db.exceptions.DatabaseException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException)

Example 30 with VPlexApiClient

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

the class VPlexDeviceController method addStepsForAddInitiators.

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

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