use of com.emc.storageos.blockorchestrationcontroller.VolumeDescriptor 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.blockorchestrationcontroller.VolumeDescriptor in project coprhd-controller by CoprHD.
the class VplexDBCkr method getDescriptorsForVolumesToBeDeleted.
public List<VolumeDescriptor> getDescriptorsForVolumesToBeDeleted(URI systemURI, List<URI> volumeURIs, String deletionType) {
List<VolumeDescriptor> volumeDescriptors = new ArrayList<VolumeDescriptor>();
for (URI volumeURI : volumeURIs) {
Volume volume = dbClient.queryObject(Volume.class, volumeURI);
VolumeDescriptor descriptor = new VolumeDescriptor(VolumeDescriptor.Type.VPLEX_VIRT_VOLUME, systemURI, volumeURI, null, null);
volumeDescriptors.add(descriptor);
// Add a descriptor for each of the associated volumes.
if (!volume.isIngestedVolumeWithoutBackend(dbClient) && (null != volume.getAssociatedVolumes())) {
for (String assocVolId : volume.getAssociatedVolumes()) {
Volume assocVolume = dbClient.queryObject(Volume.class, URI.create(assocVolId));
if (null != assocVolume && !assocVolume.getInactive() && assocVolume.getNativeId() != null) {
VolumeDescriptor assocDesc = new VolumeDescriptor(VolumeDescriptor.Type.BLOCK_DATA, assocVolume.getStorageController(), assocVolume.getId(), null, null);
volumeDescriptors.add(assocDesc);
}
}
// If there were any Vplex Mirrors, add a descriptors for them.
addDescriptorsForVplexMirrors(volumeDescriptors, volume);
}
}
return volumeDescriptors;
}
use of com.emc.storageos.blockorchestrationcontroller.VolumeDescriptor in project coprhd-controller by CoprHD.
the class VPlexDeviceController method addStepsForChangeVirtualArray.
@Override
public String addStepsForChangeVirtualArray(Workflow workflow, String waitFor, List<VolumeDescriptor> volumes, String taskId) throws InternalException {
try {
URI cgURI = null;
URI currentVarrayURI = null;
URI tgtVarrayURI = null;
URI vplexURI = null;
StorageSystem vplexSystem = null;
List<URI> vplexVolumeURIs = new ArrayList<URI>();
VPlexConsistencyGroupManager cgMgr = null;
// Get all the Virtual Volumes and the new varray URI.
List<VolumeDescriptor> vplexVolumeDescriptors = VolumeDescriptor.filterByType(volumes, new VolumeDescriptor.Type[] { VolumeDescriptor.Type.VPLEX_VIRT_VOLUME }, new VolumeDescriptor.Type[] {});
for (VolumeDescriptor vplexVolumeDescriptor : vplexVolumeDescriptors) {
// Add the URI for the VPLEX volume.
URI vplexVolumeURI = vplexVolumeDescriptor.getVolumeURI();
_log.info("Add steps to change virtual array for volume {}", vplexVolumeURI);
vplexVolumeURIs.add(vplexVolumeURI);
// Set the target virtual array if not already set.
if (tgtVarrayURI == null) {
if ((vplexVolumeDescriptor.getParameters() != null) && (!vplexVolumeDescriptor.getParameters().isEmpty())) {
tgtVarrayURI = (URI) vplexVolumeDescriptor.getParameters().get(VolumeDescriptor.PARAM_VARRAY_CHANGE_NEW_VAARAY_ID);
_log.info("Target virtual array for varray change is {}", tgtVarrayURI);
}
}
// migrated when multiple volumes are passed.
if (vplexURI == null) {
Volume vplexVolume = getDataObject(Volume.class, vplexVolumeURI, _dbClient);
vplexURI = vplexVolume.getStorageController();
vplexSystem = getDataObject(StorageSystem.class, vplexURI, _dbClient);
currentVarrayURI = vplexVolume.getVirtualArray();
cgURI = vplexVolume.getConsistencyGroup();
cgMgr = (VPlexConsistencyGroupManager) getConsistencyGroupManager(vplexVolume);
}
}
// We need to determine if the varray change will migrate the
// volumes to the other cluster of the VPLEX. If so and the
// volumes are in a consistency group, then the volumes must
// first be removed from the consistency group.
String lastStep = waitFor;
boolean volumesRemovedFromCG = false;
if (!NullColumnValueGetter.isNullURI(cgURI)) {
_log.info("Varray change volumes are in CG {}", cgURI);
String currentClusterId = ConnectivityUtil.getVplexClusterForVarray(currentVarrayURI, vplexURI, _dbClient);
String newClusterId = ConnectivityUtil.getVplexClusterForVarray(tgtVarrayURI, vplexURI, _dbClient);
if (!newClusterId.equals(currentClusterId)) {
_log.info("Varray change migrates volumes to cluster {}", newClusterId);
// The volumes are in a consistency group and the
// volumes will change cluster, so the volumes
// must be removed from the CG first.
lastStep = cgMgr.addStepForRemoveVolumesFromCG(workflow, waitFor, vplexSystem, vplexVolumeURIs, cgURI);
volumesRemovedFromCG = true;
}
}
// Create steps to migrate the backend volumes.
String migrateStep = null;
List<URI> localSystemsToRemoveCG = new ArrayList<URI>();
List<VolumeDescriptor> vplexMigrateVolumes = VolumeDescriptor.filterByType(volumes, new VolumeDescriptor.Type[] { VolumeDescriptor.Type.VPLEX_MIGRATE_VOLUME }, new VolumeDescriptor.Type[] {});
for (URI vplexVolumeURI : vplexVolumeURIs) {
_log.info("Adding migration steps for vplex volume {}", vplexVolumeURI);
// A list of the volumes to which the data on the current
// backend volumes will be migrated.
List<URI> newVolumes = new ArrayList<URI>();
// A Map containing a migration for each new backend
// volume
Map<URI, URI> migrationMap = new HashMap<URI, URI>();
// A map that specifies the storage pool in which
// each new volume should be created.
Map<URI, URI> poolVolumeMap = new HashMap<URI, URI>();
for (VolumeDescriptor desc : vplexMigrateVolumes) {
// Skip migration targets that are not for the VPLEX
// volume being processed.
Migration migration = getDataObject(Migration.class, desc.getMigrationId(), _dbClient);
if (!migration.getVolume().equals(vplexVolumeURI)) {
continue;
}
_log.info("Found migration {} for VPLEX volume", migration.getId());
// Set data required to add the migration steps.
newVolumes.add(desc.getVolumeURI());
migrationMap.put(desc.getVolumeURI(), desc.getMigrationId());
poolVolumeMap.put(desc.getVolumeURI(), desc.getPoolURI());
// If the migration is to a different storage system
// we may need to remove the backend CG on the source
// system after the migration completes.
URI migSrcURI = migration.getSource();
Volume migSrc = getDataObject(Volume.class, migSrcURI, _dbClient);
URI migTgtURI = migration.getTarget();
Volume migTgt = getDataObject(Volume.class, migTgtURI, _dbClient);
if ((!migTgt.getStorageController().equals(migSrc.getStorageController())) && (!localSystemsToRemoveCG.contains(migSrc.getStorageController()))) {
_log.info("Will remove CG on local system {} if volume is in a CG.", migSrc.getStorageController());
localSystemsToRemoveCG.add(migSrc.getStorageController());
}
}
// Note that the migrate step here is a step group associated
// with deleting the migration sources after the migrations
// have completed and committed. This means that anything
// that waits on this, will occur after the migrations have
// completed, been committed, and the migration sources deleted.
migrateStep = addStepsForMigrateVolumes(workflow, vplexURI, vplexVolumeURI, newVolumes, migrationMap, poolVolumeMap, null, tgtVarrayURI, false, false, taskId, lastStep);
_log.info("Added migration steps for vplex volume {}", vplexVolumeURI);
}
// Update last step
if (migrateStep != null) {
lastStep = migrateStep;
}
// If the volumes are in a CG, we add the final CG steps.
if (!NullColumnValueGetter.isNullURI(cgURI)) {
BlockConsistencyGroup cg = getDataObject(BlockConsistencyGroup.class, cgURI, _dbClient);
if (volumesRemovedFromCG) {
// If the volumes were removed from the consistency group, the
// varray change was across clusters. First add a step to delete
// the CG on the old cluster and then add steps to create the
// CG on the other cluster and add the volumes. The remove step
// must be executed first otherwise, when we go to create the CG
// on the other cluster, the create CG code will see that the CG
// already exists on the VPLEX system and it will not create it.
String removeStepId = workflow.createStepId();
StringSet systemCGs = cg.getSystemConsistencyGroups().get(vplexURI.toString());
String clusterCGName = systemCGs.iterator().next();
String clusterName = BlockConsistencyGroupUtils.fetchClusterName(clusterCGName);
String cgName = BlockConsistencyGroupUtils.fetchCgName(clusterCGName);
cgMgr.addStepForRemoveVPlexCG(workflow, removeStepId, lastStep, vplexSystem, cgURI, cgName, clusterName, Boolean.FALSE, null);
lastStep = cgMgr.addStepsForCreateConsistencyGroup(workflow, removeStepId, vplexSystem, vplexVolumeURIs, true);
_log.info("Added steps to remove the CG from the source cluster and add to target cluster.");
}
if (cg.checkForType(Types.LOCAL)) {
_log.info("CG {} has local type", cgURI);
// If the backend volumes are being migrated to a new storage system,
// then we need to add a step to delete the local CG.
boolean localCGDeleted = false;
List<URI> localSystemURIs = BlockConsistencyGroupUtils.getLocalSystems(cg, _dbClient);
for (URI localSystemURI : localSystemURIs) {
_log.info("CG exists on local system {}", localSystemURI);
if (localSystemsToRemoveCG.contains(localSystemURI)) {
localCGDeleted = true;
_log.info("Adding step to remove CG on local system{}", localSystemURI);
StorageSystem localSystem = getDataObject(StorageSystem.class, localSystemURI, _dbClient);
Workflow.Method deleteCGMethod = new Workflow.Method("deleteConsistencyGroup", localSystemURI, cgURI, Boolean.FALSE);
workflow.createStep("deleteLocalCG", String.format("Delete consistency group from storage system: %s", localSystemURI), lastStep, localSystemURI, localSystem.getSystemType(), BlockDeviceController.class, deleteCGMethod, null, null);
}
}
if (localCGDeleted) {
lastStep = "deleteLocalCG";
}
}
}
// Return the last step
return lastStep;
} catch (Exception ex) {
throw VPlexApiException.exceptions.addStepsForChangeVirtualPoolFailed(ex);
}
}
use of com.emc.storageos.blockorchestrationcontroller.VolumeDescriptor in project coprhd-controller by CoprHD.
the class VPlexDeviceController method createStepsForFullCopyImport.
/**
* Creates a step in the passed workflow to import each copy of the passed
* primary backend volume to a VPLEX virtual volume.
*
* @param workflow
* A reference to the workflow.
* @param vplexURI
* The URI of the VPLEX storage system.
* @param sourceBlockObject
* The primary backend volume/snapshot that was copied.
* @param vplexVolumeDescriptors
* The volume descriptors representing the
* copies of the VPLEX volume.
* @param assocVolumeDescriptors
* The volume descriptors representing the
* primary copies and, for copies of distributed VPLEX volumes, the
* newly created HA volumes. These volumes will comprise the backend
* volumes of the VPLEX volume copies.
* @param waitFor
* The step in to workflow for which these steps should wait
* to successfully complete before executing.
*
* @return The step for which any subsequent steps in the workflow should
* wait.
*/
private String createStepsForFullCopyImport(Workflow workflow, URI vplexURI, List<VolumeDescriptor> vplexVolumeDescriptors, List<VolumeDescriptor> assocVolumeDescriptors, String waitFor) {
StorageSystem vplexSystem = getDataObject(StorageSystem.class, vplexURI, _dbClient);
_log.info("Got VPLEX {}", vplexURI);
URI projectURI = null;
URI tenantURI = null;
Operation op = new Operation();
op.setResourceType(ResourceOperationTypeEnum.CREATE_BLOCK_VOLUME);
for (VolumeDescriptor vplexVolumeDescriptor : vplexVolumeDescriptors) {
_log.info("Creating step for VPLEX volume copy {}", vplexVolumeDescriptor.getVolumeURI());
List<VolumeDescriptor> descriptorsForImport = new ArrayList<VolumeDescriptor>();
descriptorsForImport.add(vplexVolumeDescriptor);
URI vplexVolumeURI = vplexVolumeDescriptor.getVolumeURI();
List<VolumeDescriptor> assocDescriptors = getDescriptorsForAssociatedVolumes(vplexVolumeURI, assocVolumeDescriptors);
descriptorsForImport.addAll(assocDescriptors);
// get the project and tenant from the vplex volume
if (projectURI == null) {
Volume vplexVol = _dbClient.queryObject(Volume.class, vplexVolumeURI);
if (vplexVol != null && !vplexVol.getInactive()) {
projectURI = vplexVol.getProject().getURI();
tenantURI = vplexVol.getTenant().getURI();
}
}
_log.info("Added descriptors for the copy's associated volumes");
String stepId = workflow.createStepId();
Workflow.Method executeMethod = createImportCopyMethod(vplexURI, descriptorsForImport, projectURI, tenantURI);
Workflow.Method rollbackMethod = rollbackImportCopyMethod(vplexVolumeDescriptor, assocDescriptors);
workflow.createStep(IMPORT_COPY_STEP, String.format("Importing copied volume to create VPLEX volume %s", vplexVolumeDescriptor.getVolumeURI()), waitFor, vplexURI, vplexSystem.getSystemType(), this.getClass(), executeMethod, rollbackMethod, stepId);
_log.info("Added import workflow step to create VPLEX volume copy");
// be updated when the step is executed and completed.
for (VolumeDescriptor assocDescriptor : assocDescriptors) {
if (assocDescriptor.getType().equals(VolumeDescriptor.Type.BLOCK_DATA)) {
op = _dbClient.createTaskOpStatus(Volume.class, assocDescriptor.getVolumeURI(), stepId, op);
}
}
}
return IMPORT_COPY_STEP;
}
use of com.emc.storageos.blockorchestrationcontroller.VolumeDescriptor in project coprhd-controller by CoprHD.
the class VPlexDeviceController method addStepsForPostDeleteVolumes.
/**
* Add step to Workflow for post - delete clean of Virtual Volumes (i.e. marking them inactive).
*
* @param workflow
* -- Workflow
* @param waitFor
* -- String waitFor of previous step, we wait on this to complete
* @param volumes
* -- List of VolumeDescriptors
* @param taskId
* -- String overall task id.
* @param completer
* -- VolumeWorkflowCompleter
* @return -- Returns waitFor of next step
*/
@Override
public String addStepsForPostDeleteVolumes(Workflow workflow, String waitFor, List<VolumeDescriptor> volumes, String taskId, VolumeWorkflowCompleter completer) {
// Filter to get only the VPlex volumes.
List<VolumeDescriptor> vplexVolumes = VolumeDescriptor.filterByType(volumes, new VolumeDescriptor.Type[] { VolumeDescriptor.Type.VPLEX_VIRT_VOLUME }, new VolumeDescriptor.Type[] {});
// Check to see if there are any volumes flagged to not be fully deleted.
// Any flagged volumes will be removed from the list of volumes to delete.
List<VolumeDescriptor> descriptorsToRemove = VolumeDescriptor.getDoNotDeleteDescriptors(vplexVolumes);
vplexVolumes.removeAll(descriptorsToRemove);
String returnWaitFor = waitFor;
// If there are no VPlex volumes, just return
if (vplexVolumes.isEmpty()) {
return returnWaitFor;
}
// Segregate by device and loop over each VPLEX system.
// Sort the volumes by its system, and consistency group
Map<URI, Set<URI>> cgVolsMap = new HashMap<URI, Set<URI>>();
// Keep a separate map for determining if we should delete the VPLEX CG as part of the delete operation.
Map<URI, Set<URI>> cgVolsWithBackingVolsMap = new HashMap<URI, Set<URI>>();
Map<URI, List<VolumeDescriptor>> vplexMap = VolumeDescriptor.getDeviceMap(vplexVolumes);
for (URI vplexURI : vplexMap.keySet()) {
List<URI> vplexVolumeURIs = VolumeDescriptor.getVolumeURIs(vplexMap.get(vplexURI));
List<URI> forgetVolumeURIs = new ArrayList<URI>();
for (URI vplexVolumeURI : vplexVolumeURIs) {
Volume vplexVolume = getDataObject(Volume.class, vplexVolumeURI, _dbClient);
boolean inCG = false;
if (!NullColumnValueGetter.isNullURI(vplexVolume.getConsistencyGroup())) {
inCG = true;
}
if (null == vplexVolume.getAssociatedVolumes()) {
_log.warn("VPLEX volume {} has no backend volumes. It was possibly ingested 'Virtual Volume Only'.", vplexVolume.forDisplay());
} else {
for (String forgetVolumeId : vplexVolume.getAssociatedVolumes()) {
forgetVolumeURIs.add(URI.create(forgetVolumeId));
}
}
if (inCG) {
Set<URI> cgVols = cgVolsMap.get(vplexVolume.getConsistencyGroup());
if (cgVols == null) {
cgVolsMap.put(vplexVolume.getConsistencyGroup(), new HashSet<>());
cgVolsWithBackingVolsMap.put(vplexVolume.getConsistencyGroup(), new HashSet<>());
}
cgVolsMap.get(vplexVolume.getConsistencyGroup()).add(vplexVolumeURI);
cgVolsWithBackingVolsMap.get(vplexVolume.getConsistencyGroup()).add(vplexVolumeURI);
cgVolsWithBackingVolsMap.get(vplexVolume.getConsistencyGroup()).addAll(forgetVolumeURIs);
}
// Adding the VPLEX mirror backend volume to forgetVolumeURIs
if (vplexVolume.getMirrors() != null && !(vplexVolume.getMirrors().isEmpty())) {
for (String mirrorId : vplexVolume.getMirrors()) {
VplexMirror vplexMirror = _dbClient.queryObject(VplexMirror.class, URI.create(mirrorId));
if (null != vplexMirror && !vplexMirror.getInactive() && null != vplexMirror.getAssociatedVolumes()) {
for (String forgetVolumeId : vplexMirror.getAssociatedVolumes()) {
forgetVolumeURIs.add(URI.create(forgetVolumeId));
}
}
}
}
}
// Add a step to forget the backend volumes for the deleted
// VPLEX volumes on this VPLEX system.
addStepToForgetVolumes(workflow, vplexURI, forgetVolumeURIs, returnWaitFor);
}
// Get the VPlex Volume URIs and any VPLEX system URI. It does not matter which
// system as it the step simply marks ViPR volumes in the database inactive.
List<URI> allVplexVolumeURIs = VolumeDescriptor.getVolumeURIs(vplexVolumes);
URI vplexURI = vplexVolumes.get(0).getDeviceURI();
// Add a step to the Workflow to mark the Virtual Volumes inactive.
// Rollback does the same thing.
returnWaitFor = workflow.createStep(null, "Mark virtual volumes inactive", VOLUME_FORGET_STEP, vplexURI, DiscoveredDataObject.Type.vplex.name(), this.getClass(), markVolumesInactiveMethod(allVplexVolumeURIs), markVolumesInactiveMethod(allVplexVolumeURIs), null);
if (cgVolsMap.isEmpty()) {
return returnWaitFor;
}
Volume vol = getDataObject(Volume.class, allVplexVolumeURIs.get(0), _dbClient);
ConsistencyGroupManager consistencyGroupManager = getConsistencyGroupManager(vol);
// Generate step(s) to delete the VPLEX consistency groups
for (URI cgURI : cgVolsMap.keySet()) {
// Skip volumes that are part of a VPlex SRDF target CG, as it will
// be deleted earlier
List<URI> volURIs = new ArrayList<URI>(cgVolsMap.get(cgURI));
volURIs = VPlexSrdfUtil.filterOutVplexSrdfTargets(_dbClient, volURIs);
if (volURIs.isEmpty()) {
_log.info(String.format("CG %s has all VPLEX SRDF targets, skipping as CG should already be deleted", cgURI));
continue;
}
// find member volumes in the group
volURIs = new ArrayList<URI>(cgVolsWithBackingVolsMap.get(cgURI));
Volume firstVol = _dbClient.queryObject(Volume.class, volURIs.get(0));
URI storage = firstVol.getStorageController();
// delete CG from array
if (VPlexUtil.cgHasNoOtherVPlexVolumes(_dbClient, cgURI, volURIs)) {
_log.info(String.format("Adding step to delete the consistency group %s", cgURI));
returnWaitFor = consistencyGroupManager.addStepsForDeleteConsistencyGroup(workflow, returnWaitFor, storage, cgURI, false);
} else {
_log.info(String.format("Skipping add step to delete the consistency group %s. Consistency group " + "contains other VPLEX volumes that have not been accounted for.", cgURI));
}
}
return returnWaitFor;
}
Aggregations