use of com.emc.storageos.blockorchestrationcontroller.VolumeDescriptor in project coprhd-controller by CoprHD.
the class VPlexDeviceController method getDescriptorsForAssociatedVolumes.
/**
* From the passed list of descriptors, finds the descriptors for the
* associated volumes of the VPLEX volume with the passed URI.
*
* @param vplexVolumeURI
* The URI of the VPLEX volume.
* @param descriptors
* The list of volume descriptors.
*
* @return A list containing the volume descriptors representing the
* associated volumes for the VPLEX volume.
*/
private List<VolumeDescriptor> getDescriptorsForAssociatedVolumes(URI vplexVolumeURI, List<VolumeDescriptor> descriptors) {
_log.info("Getting associated volume descriptors for VPLEX copy {}", vplexVolumeURI);
List<VolumeDescriptor> assocVolumeDescriptors = new ArrayList<VolumeDescriptor>();
Volume vplexVolume = getDataObject(Volume.class, vplexVolumeURI, _dbClient);
_log.info("Got VPLEX volume");
StringSet assocVolumeURIs = vplexVolume.getAssociatedVolumes();
if (null == assocVolumeURIs || assocVolumeURIs.isEmpty()) {
_log.error("VPLEX volume {} has no backend volumes.", vplexVolume.forDisplay());
throw InternalServerErrorException.internalServerErrors.noAssociatedVolumesForVPLEXVolume(vplexVolume.forDisplay());
}
Iterator<String> assocVolumeURIsIter = assocVolumeURIs.iterator();
while (assocVolumeURIsIter.hasNext()) {
URI assocVolumeURI = URI.create(assocVolumeURIsIter.next());
_log.info("Associated volume is {}", assocVolumeURI);
Iterator<VolumeDescriptor> descriptorIter = descriptors.iterator();
while (descriptorIter.hasNext()) {
VolumeDescriptor descriptor = descriptorIter.next();
URI volumeURI = descriptor.getVolumeURI();
_log.info("Descriptor volume is {}", volumeURI);
if (volumeURI.equals(assocVolumeURI)) {
_log.info("Found descriptor for associated volume");
assocVolumeDescriptors.add(descriptor);
break;
}
}
}
return assocVolumeDescriptors;
}
use of com.emc.storageos.blockorchestrationcontroller.VolumeDescriptor in project coprhd-controller by CoprHD.
the class VPlexDeviceController method importCopy.
/**
* Creates and starts the import workflow to import the volume to a VPLEX
* virtual volume.
*
* @param vplexSystemURI
* The URI of the VPLEX system.
* @param volumeDescriptors
* The list of volume descriptors.
* @param projectURI
* The URI of the VPLEX project.
* @param tenantURI
* The URI of the VPLEX tenant.
* @param stepId
* The workflow step id.
*
* @throws ControllerException
* When an error occurs configuring the import
* workflow.
*/
public void importCopy(URI vplexSystemURI, List<VolumeDescriptor> volumeDescriptors, URI projectURI, URI tenantURI, String stepId) throws ControllerException {
_log.info("Executing import step for full copy.");
List<VolumeDescriptor> importVolumeDescriptors = VolumeDescriptor.filterByType(volumeDescriptors, new VolumeDescriptor.Type[] { Type.VPLEX_IMPORT_VOLUME }, new VolumeDescriptor.Type[] {});
VolumeDescriptor importVolumeDescriptor = importVolumeDescriptors.get(0);
Volume importVolume = getDataObject(Volume.class, importVolumeDescriptor.getVolumeURI(), _dbClient);
// Update step state to executing.
WorkflowStepCompleter.stepExecuting(stepId);
// Reuse the import volume API to create a sub workflow to execute
// the import.
importVolume(vplexSystemURI, volumeDescriptors, projectURI, tenantURI, importVolume.getVirtualPool(), importVolume.getLabel(), null, Boolean.FALSE, stepId);
_log.info("Created and started sub workflow to import the copy");
}
use of com.emc.storageos.blockorchestrationcontroller.VolumeDescriptor in project coprhd-controller by CoprHD.
the class VPlexDeviceController method rollbackImportCopy.
/**
* If a failure occurs during an import of a full copy, make sure
* the volume is torn back down.
*
* @param vplexVolumeDescriptor
* The descriptor for the VPLEX copy volume
* @param assocVolumeDescrs
* The descriptors for its backend volumes.
* @param stepId
* The rollback step id.
*/
public void rollbackImportCopy(VolumeDescriptor vplexVolumeDescriptor, List<VolumeDescriptor> assocVolumeDescrs, String stepId) {
// Update step state to executing.
WorkflowStepCompleter.stepExecuting(stepId);
// Make sure the volume is torn down.
List<VolumeDescriptor> volumeDescriptors = new ArrayList<VolumeDescriptor>();
// only delete active ones
Volume vplexVol = _dbClient.queryObject(Volume.class, vplexVolumeDescriptor.getVolumeURI());
if (vplexVol != null && !vplexVol.getInactive()) {
volumeDescriptors.add(vplexVolumeDescriptor);
}
for (VolumeDescriptor volDes : assocVolumeDescrs) {
Volume vol = _dbClient.queryObject(Volume.class, volDes.getVolumeURI());
if (vol != null && !vol.getInactive()) {
volumeDescriptors.add(volDes);
}
}
_blockOrchestrationController.deleteVolumes(volumeDescriptors, stepId);
}
use of com.emc.storageos.blockorchestrationcontroller.VolumeDescriptor in project coprhd-controller by CoprHD.
the class VPlexDeviceController method migrateVolumes.
/**
* Deprecating this for now, should be using the migrateVolumes call with the WF passed in from
* the BlockOrchestrator.
*
* {@inheritDoc}
*/
@Override
public void migrateVolumes(URI vplexURI, URI virtualVolumeURI, List<URI> targetVolumeURIs, Map<URI, URI> migrationsMap, Map<URI, URI> poolVolumeMap, URI newCoSURI, URI newNhURI, String successMsg, String failMsg, OperationTypeEnum opType, String opId, String wfStepId) throws ControllerException {
List<URI> migrationURIs = new ArrayList<URI>(migrationsMap.values());
try {
_log.info("VPlex controller migrate volume {} on VPlex {}", virtualVolumeURI, vplexURI);
// Get the VPlex storage system
StorageSystem vplexSystem = getDataObject(StorageSystem.class, vplexURI, _dbClient);
_log.info("Got VPlex system");
// If a workflow step id is passed, then this is being called
// from a step in a "parent" workflow. In that case, this
// sub-workflow takes the name of the step.
String wfId = (wfStepId != null ? wfStepId : opId);
// Get a new workflow to execute the migrations.
Workflow workflow = _workflowService.getNewWorkflow(this, MIGRATE_VOLUMES_WF_NAME, false, wfId);
_log.info("Created new workflow with operation id {}", wfId);
// Create a step to validate the volume and prevent migration if the
// the ViPR DB does not properly reflect the actual backend volumes.
// A successful migration will delete the backend source volumes. If
// the ViPR DB does not correctly reflect the actual backend volume,
// we could delete a backend volume used by some other VPLEX volume.
String waitFor = createWorkflowStepToValidateVPlexVolume(workflow, vplexSystem, virtualVolumeURI, null);
// We first need to create steps in the workflow to create the new
// backend volume(s) to which the data for the virtual volume will
// be migrated.
List<VolumeDescriptor> descriptors = new ArrayList<VolumeDescriptor>();
Map<URI, StorageSystem> storageSystemMap = new HashMap<URI, StorageSystem>();
Map<URI, Volume> volumeMap = new HashMap<URI, Volume>();
Iterator<URI> storagePoolIter = poolVolumeMap.keySet().iterator();
while (storagePoolIter.hasNext()) {
URI storagePoolURI = storagePoolIter.next();
URI volumeURI = poolVolumeMap.get(storagePoolURI);
_log.info("Creating descriptor for volume{} in pool {}", volumeURI, storagePoolURI);
descriptors.add(createDescriptorForBlockVolumeCreation(storagePoolURI, volumeURI, storageSystemMap, volumeMap));
_log.info("Created descriptor for volume");
}
// Add steps in the block device controller to create the target
// volumes.
waitFor = _blockDeviceController.addStepsForCreateVolumes(workflow, waitFor, descriptors, wfId);
// Set the project and tenant. We prefer a project created for the Vplex system,
// but will fallback to the volume's project if there isn't a project for the VPlex.
Volume firstVolume = volumeMap.values().iterator().next();
Project vplexProject = VPlexUtil.lookupVplexProject(firstVolume, vplexSystem, _dbClient);
URI tenantURI = vplexProject.getTenantOrg().getURI();
_log.info("Project is {}, Tenant is {}", vplexProject.getId(), tenantURI);
// Now we need to do the necessary zoning and export steps to ensure
// the VPlex can see these new backend volumes.
createWorkflowStepsForBlockVolumeExport(workflow, vplexSystem, storageSystemMap, volumeMap, vplexProject.getId(), tenantURI, waitFor);
_log.info("Created workflow steps for volume export.");
// Now make a migration Step for each passed target to which data
// for the passed virtual volume will be migrated. The migrations
// will be done from this controller.
Iterator<URI> targetVolumeIter = targetVolumeURIs.iterator();
while (targetVolumeIter.hasNext()) {
URI targetVolumeURI = targetVolumeIter.next();
_log.info("Target volume is {}", targetVolumeURI);
URI migrationURI = migrationsMap.get(targetVolumeURI);
_log.info("Migration is {}", migrationURI);
String stepId = workflow.createStepId();
_log.info("Migration opId is {}", stepId);
Workflow.Method vplexExecuteMethod = new Workflow.Method(MIGRATE_VIRTUAL_VOLUME_METHOD_NAME, vplexURI, virtualVolumeURI, targetVolumeURI, migrationURI, newNhURI);
Workflow.Method vplexRollbackMethod = new Workflow.Method(RB_MIGRATE_VIRTUAL_VOLUME_METHOD_NAME, vplexURI, migrationURI, stepId);
_log.info("Creating workflow migration step");
workflow.createStep(MIGRATION_CREATE_STEP, String.format("VPlex %s migrating to target volume %s.", vplexSystem.getId().toString(), targetVolumeURI.toString()), EXPORT_STEP, vplexSystem.getId(), vplexSystem.getSystemType(), getClass(), vplexExecuteMethod, vplexRollbackMethod, stepId);
_log.info("Created workflow migration step");
}
// Once the migrations complete, we will commit the migrations.
// So, now we create the steps to commit the migrations.
String waitForStep = MIGRATION_CREATE_STEP;
List<URI> migrationSources = new ArrayList<URI>();
Iterator<URI> migrationsIter = migrationsMap.values().iterator();
while (migrationsIter.hasNext()) {
URI migrationURI = migrationsIter.next();
_log.info("Migration is {}", migrationURI);
Migration migration = getDataObject(Migration.class, migrationURI, _dbClient);
// The migration source volume may be null for ingested volumes
// for which we do not know anything about the backend volumes.
// If we don't know the source, we know we are migrating an
// ingested volume and we will not want to do any renaming
// after the commit as we do when migration ViPR create volumes,
// which adhere to a standard naming convention.
Boolean rename = Boolean.TRUE;
if (migration.getSource() != null) {
migrationSources.add(migration.getSource());
} else {
rename = Boolean.FALSE;
}
_log.info("Added migration source {}", migration.getSource());
String stepId = workflow.createStepId();
_log.info("Commit operation id is {}", stepId);
Workflow.Method vplexExecuteMethod = new Workflow.Method(COMMIT_MIGRATION_METHOD_NAME, vplexURI, virtualVolumeURI, migrationURI, rename, newCoSURI, newNhURI);
Workflow.Method vplexRollbackMethod = new Workflow.Method(RB_COMMIT_MIGRATION_METHOD_NAME, migrationURIs, newCoSURI, newNhURI, stepId);
_log.info("Creating workflow step to commit migration");
waitForStep = workflow.createStep(MIGRATION_COMMIT_STEP, String.format("VPlex %s committing volume migration", vplexSystem.getId().toString()), waitForStep, vplexSystem.getId(), vplexSystem.getSystemType(), getClass(), vplexExecuteMethod, vplexRollbackMethod, stepId);
_log.info("Created workflow step to commit migration");
}
// Create a step that creates a sub workflow to delete the old
// migration source volumes, which are no longer used by the
// virtual volume. We also update the virtual volume CoS. If
// we make it to this step, then all migrations were committed.
// We do this in a sub workflow because we don't won't to
// initiate rollback regardless of success or failure.
String stepId = workflow.createStepId();
Workflow.Method vplexExecuteMethod = new Workflow.Method(DELETE_MIGRATION_SOURCES_METHOD, vplexURI, virtualVolumeURI, newCoSURI, newNhURI, migrationSources);
workflow.createStep(DELETE_MIGRATION_SOURCES_STEP, String.format("Creating workflow to delete migration sources"), MIGRATION_COMMIT_STEP, vplexSystem.getId(), vplexSystem.getSystemType(), getClass(), vplexExecuteMethod, null, stepId);
_log.info("Created workflow step to create sub workflow for source deletion");
// Finish up and execute the plan. The Workflow will handle the
// TaskCompleter
List<URI> volumes = new ArrayList<URI>();
volumes.add(virtualVolumeURI);
volumes.addAll(targetVolumeURIs);
TaskCompleter completer = new MigrationWorkflowCompleter(volumes, migrationURIs, opId, wfStepId);
_log.info("Executing workflow plan");
workflow.executePlan(completer, successMsg);
_log.info("Workflow plan executed");
} catch (Exception e) {
_log.error(failMsg, e);
List<URI> volumes = new ArrayList<URI>();
volumes.add(virtualVolumeURI);
volumes.addAll(targetVolumeURIs);
TaskCompleter completer = new MigrationWorkflowCompleter(volumes, migrationURIs, opId, wfStepId);
ServiceError serviceError = VPlexApiException.errors.jobFailed(e);
serviceError.setMessage(failMsg);
failStep(completer, opId, serviceError);
}
}
use of com.emc.storageos.blockorchestrationcontroller.VolumeDescriptor in project coprhd-controller by CoprHD.
the class VPlexDeviceController method buildArrayMap.
/**
* Build a map of URI to cached StorageSystem for the underlying arrays.
*
* @param vplexSystem
* Only return Storage Systems connected this VPlex
* @param descriptors
* @param VolmeDescriptor.Type
* used to filter descriptors
* @return Map<arrayURI, StorageSystem>
*/
private Map<URI, StorageSystem> buildArrayMap(StorageSystem vplexSystem, List<VolumeDescriptor> descriptors, VolumeDescriptor.Type[] types) {
Map<URI, StorageSystem> arrayMap = new HashMap<URI, StorageSystem>();
// Get only the descriptors for the type if specified..
if (types != null) {
descriptors = VolumeDescriptor.filterByType(descriptors, types, new VolumeDescriptor.Type[] {});
}
for (VolumeDescriptor desc : descriptors) {
if (arrayMap.containsKey(desc.getDeviceURI()) == false) {
if (vplexSystem == null) {
StorageSystem array = getDataObject(StorageSystem.class, desc.getDeviceURI(), _dbClient);
arrayMap.put(desc.getDeviceURI(), array);
} else {
Set<URI> connectedSystems = ConnectivityUtil.getStorageSystemAssociationsByNetwork(_dbClient, vplexSystem.getId(), StoragePort.PortType.backend);
if (connectedSystems.contains(desc.getDeviceURI())) {
StorageSystem array = getDataObject(StorageSystem.class, desc.getDeviceURI(), _dbClient);
arrayMap.put(desc.getDeviceURI(), array);
}
}
}
}
return arrayMap;
}
Aggregations