use of com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo in project coprhd-controller by CoprHD.
the class VplexDBCkr method checkVolumesOnVplex.
public void checkVolumesOnVplex(URI vplexSystemURI, boolean deleteInvalidVolumes) {
URIQueryResultList result = new URIQueryResultList();
List<URI> deletevirtualvolumeURIs = new ArrayList<URI>();
int nerrors = 0;
int invalidVolumeCount = 0;
dbClient.queryByConstraint(ContainmentConstraint.Factory.getStorageDeviceVolumeConstraint(vplexSystemURI), result);
Iterator<URI> iter = result.iterator();
VPlexApiClient client = getVPlexApiClient(vplexSystemURI);
// Get all the virtual volumes. We elect for shallow here as it's quicker-
// we will spend time below getting details.
writeLog("Retrieving all virtual volumes... this will take some time...");
Map<String, VPlexVirtualVolumeInfo> vvInfoMap = client.getVirtualVolumes(true);
List<VPlexStorageViewInfo> storageViews = client.getStorageViewsLite();
writeLog("... done");
try {
while (iter.hasNext()) {
Volume volume = dbClient.queryObject(Volume.class, iter.next());
if (volume == null || volume.getInactive()) {
continue;
}
writeLog(String.format("Checking volume %s (%s)", volume.getLabel(), volume.getDeviceLabel()));
if (volume.getAssociatedVolumes() == null || volume.getAssociatedVolumes().isEmpty()) {
writeLog(String.format("Volume %s (%s) has no associated volumes... skipping", volume.getLabel(), volume.getDeviceLabel()));
continue;
}
VPlexVirtualVolumeInfo vvInfo = vvInfoMap.get(volume.getDeviceLabel());
if (vvInfo == null) {
writeLog(String.format("ERROR: Volume %s (%s) had no VirtualVolumeInfo in VPlex", volume.getLabel(), volume.getDeviceLabel()));
deletevirtualvolumeURIs.add(volume.getId());
nerrors++;
invalidVolumeCount++;
continue;
}
if ((null != vvInfo.getWwn()) && (null != volume.getWWN())) {
if (vvInfo.getName().equals(volume.getDeviceLabel())) {
if (vvInfo.getWwn().toUpperCase().equals(volume.getWWN().toUpperCase())) {
writeLog(String.format("Virtual Volume %s wwn %s matches VPLEX", vvInfo.getName(), vvInfo.getWwn()));
} else {
writeLog(String.format("ERROR: Virtual Volume %s wwn %s in VPLEX mismatch with viprdb %s", vvInfo.getName(), vvInfo.getWwn(), volume.getWWN()));
deletevirtualvolumeURIs.add(volume.getId());
invalidVolumeCount++;
nerrors++;
}
}
}
StringSet wwns = new StringSet();
for (String cluster : vvInfo.getClusters()) {
Map<String, VPlexStorageVolumeInfo> svInfoMap = client.getStorageVolumeInfoForDevice(vvInfo.getSupportingDevice(), vvInfo.getLocality(), cluster, false);
for (String wwn : svInfoMap.keySet()) {
// writeLog("adding wwn " + wwn.toUpperCase());
wwns.add(wwn.toUpperCase());
VPlexStorageVolumeInfo svInfo = svInfoMap.get(wwn);
writeLog(String.format("StorageVolume wwn %s name %s cluster %s", wwn, svInfo.getName(), cluster));
}
}
// Now check associated volumes against the wwns.
for (String associatedVolume : volume.getAssociatedVolumes()) {
Volume assocVolume = dbClient.queryObject(Volume.class, URI.create(associatedVolume));
if (assocVolume == null) {
writeLog("Associated volunme not found in database... skipping: " + associatedVolume);
continue;
}
if (wwns.contains(assocVolume.getWWN().toUpperCase())) {
writeLog(String.format("Volume %s wwn %s matches VPLEX", assocVolume.getLabel(), assocVolume.getWWN()));
} else {
writeLog(String.format("ERROR: Volume %s wwn %s is not present in VPLEX", assocVolume.getLabel(), assocVolume.getWWN()));
nerrors++;
}
}
List<ExportMask> exportMaskListInDB = isVolumeExported(volume.getId());
if (null != exportMaskListInDB) {
for (ExportMask exportMaskInDB : exportMaskListInDB) {
boolean found = false;
boolean storageviewfound = false;
for (VPlexStorageViewInfo storageView : storageViews) {
if (storageView.getName().equals(exportMaskInDB.getMaskName())) {
storageviewfound = true;
for (String volumeNameStr : storageView.getVirtualVolumes()) {
String[] tokens = volumeNameStr.split(",");
String volumeName = tokens[1];
if (volumeName.equals(volume.getDeviceLabel())) {
found = true;
break;
}
}
if (!found) {
writeLog(String.format("ERROR: volume %s is in exportmask %s in viprdb but not in vplex storageview %s", volume.getDeviceLabel(), exportMaskInDB.getMaskName(), storageView.getName()));
nerrors++;
}
break;
}
}
if (!storageviewfound) {
writeLog(String.format("ERROR: volume %s is in exportmask %s in viprdb but storageview not found in vplex", volume.getDeviceLabel(), exportMaskInDB.getMaskName()));
nerrors++;
}
}
}
for (VPlexStorageViewInfo storageView : storageViews) {
writeLog(String.format("Checking Storageview %s", storageView.getName()));
for (String volumeNameStr : storageView.getVirtualVolumes()) {
String[] tokens = volumeNameStr.split(",");
String volumeName = tokens[1];
if (volumeName.equals(volume.getDeviceLabel())) {
boolean storageviewfound = false;
if (null != exportMaskListInDB) {
for (ExportMask exportMaskInDB : exportMaskListInDB) {
if (storageView.getName().equals(exportMaskInDB.getMaskName())) {
storageviewfound = true;
break;
}
}
}
if (!storageviewfound) {
writeLog(String.format("ERROR: volume %s is in vplex storageview %s but not in viprdb exportmask", volumeName, storageView.getName()));
nerrors++;
}
}
}
}
}
if (deleteInvalidVolumes) {
writeLog("deleting invalid volumes");
// deleting virtual volumes that no longer exist in vplex
List<VolumeDescriptor> volumeDescriptors = getDescriptorsForVolumesToBeDeleted(vplexSystemURI, deletevirtualvolumeURIs, VolumeDeleteTypeEnum.VIPR_ONLY.name());
cleanupForViPROnlyDelete(volumeDescriptors);
// Mark them inactive. Note that some of the volumes may be mirrors,
// which have a different database type.
List<VolumeDescriptor> descriptorsForMirrors = VolumeDescriptor.getDescriptors(volumeDescriptors, VolumeDescriptor.Type.BLOCK_MIRROR);
dbClient.markForDeletion(dbClient.queryObject(BlockMirror.class, VolumeDescriptor.getVolumeURIs(descriptorsForMirrors)));
List<VolumeDescriptor> descriptorsForVolumes = VolumeDescriptor.filterByType(volumeDescriptors, null, new VolumeDescriptor.Type[] { VolumeDescriptor.Type.BLOCK_MIRROR });
dbClient.markForDeletion(dbClient.queryObject(Volume.class, VolumeDescriptor.getVolumeURIs(descriptorsForVolumes)));
// Update the task status for each volume
for (URI volumeURI : deletevirtualvolumeURIs) {
Volume volume = dbClient.queryObject(Volume.class, volumeURI);
dbClient.updateObject(volume);
}
}
} catch (Exception e) {
writeLog(String.format("Exception: while verifying virtual volumes", e));
}
// List<URI> maskUrislist = new ArrayList<URI>();;
// maskUrislist.add(URI.create("urn:storageos:ExportMask:3742e612-cc93-422b-a1a5-43490e0fe8ea:vdc1"));
// for (URI mskUri : maskUrislist) {
// boolean found = false;
// ExportMask exportMaskUri = dbClient.queryObject(ExportMask.class, mskUri);
// if (exportMaskUri == null || exportMaskUri.getInactive()) {
// continue;
// }
// writeLog(String.format("exportMaskUri in ViPR DB is %s", exportMaskUri.getMaskName()));
// for (VPlexStorageViewInfo storageView : storageViews) {
// if (storageView.getName().equals(exportMaskUri.getMaskName())) {
// found = true;
// }
// }
// if(!found) {
// writeLog(String.format("ERROR: exportMask not found in vplex %s",exportMaskUri.getMaskName()));
// nerrors++;
// }
// }
writeLog("Total errors for this VPLEX: " + nerrors);
}
use of com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo 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);
}
}
use of com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo in project coprhd-controller by CoprHD.
the class VPlexDeviceController method migrationSupportedForVolume.
/**
* Determines if the controller can support migration for the passed VPLEX volume.
*
* @param volume
* A reference to a VPLEX volume.
* @param varrayURI
* A reference to a varray or null.
*
* @return true if migration is supported, false otherwise.
*/
public static boolean migrationSupportedForVolume(Volume volume, URI varrayURI, DbClient dbClient) {
boolean supported = true;
// Migration is supported for all volumes that were not ingested.
if (volume.isIngestedVolumeWithoutBackend(dbClient)) {
VirtualPool vpool = dbClient.queryObject(VirtualPool.class, volume.getVirtualPool());
// Migration is supported for all local volumes.
if (VirtualPool.HighAvailabilityType.vplex_distributed.name().equals(vpool.getHighAvailability())) {
StorageSystem vplexSystem = dbClient.queryObject(StorageSystem.class, volume.getStorageController());
try {
VPlexApiFactory apiFactory = VPlexApiFactory.getInstance();
VPlexApiClient client = getVPlexAPIClient(apiFactory, vplexSystem, dbClient);
VPlexVirtualVolumeInfo vvInfo = client.getVirtualVolumeStructure(volume.getDeviceLabel());
VPlexDistributedDeviceInfo ddInfo = (VPlexDistributedDeviceInfo) vvInfo.getSupportingDeviceInfo();
List<VPlexDeviceInfo> localDeviceInfoList = ddInfo.getLocalDeviceInfo();
for (VPlexDeviceInfo localDeviceInfo : localDeviceInfoList) {
_log.info("localDeviceInfo: {}, {}", localDeviceInfo.getName(), localDeviceInfo.getCluster());
// the passed varray.
if (varrayURI != null) {
_log.info("varrayURI:{}", varrayURI);
String varrayCluster = ConnectivityUtil.getVplexClusterForVarray(varrayURI, vplexSystem.getId(), dbClient);
_log.info("varrayCluster:{}", varrayCluster);
if (!localDeviceInfo.getCluster().contains(varrayCluster)) {
continue;
}
}
// For distributed volumes, the local device must be built
// on a single extent.
_log.info("Local device: {}", localDeviceInfo.getName());
_log.info("Extent count: {}", localDeviceInfo.getExtentInfo().size());
if (localDeviceInfo.getExtentInfo().size() != 1) {
supported = false;
break;
}
}
} catch (VPlexApiException vae) {
_log.error("Exception checking if migration supported for volume:", vae);
throw vae;
} catch (Exception ex) {
_log.error("Exception checking if migration supported for volume", ex);
throw VPlexApiException.exceptions.failedGettingMigrationSupportedForVolume(vplexSystem.getId().toString(), volume.getLabel());
}
}
}
return supported;
}
use of com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo 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);
}
}
use of com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo 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);
}
}
Aggregations