use of com.emc.storageos.blockorchestrationcontroller.VolumeDescriptor in project coprhd-controller by CoprHD.
the class VPlexBlockServiceApiImpl method changeVolumeVirtualPool.
/**
* {@inheritDoc}
*/
@Override
public TaskList changeVolumeVirtualPool(List<Volume> volumes, VirtualPool vpool, VirtualPoolChangeParam vpoolChangeParam, String taskId) throws InternalException {
TaskList taskList = new TaskList();
StringBuffer notSuppReasonBuff = new StringBuffer();
VirtualPool volumeVirtualPool = _dbClient.queryObject(VirtualPool.class, volumes.get(0).getVirtualPool());
if (VirtualPoolChangeAnalyzer.isSupportedPathParamsChange(volumes.get(0), volumeVirtualPool, vpool, _dbClient, notSuppReasonBuff) || VirtualPoolChangeAnalyzer.isSupportedAutoTieringPolicyAndLimitsChange(volumes.get(0), volumeVirtualPool, vpool, _dbClient, notSuppReasonBuff)) {
taskList = createTasksForVolumes(vpool, volumes, taskId);
checkCommonVpoolUpdates(volumes, vpool, taskId);
return taskList;
}
// Check if any of the volumes passed is a VPLEX volume
// in a VPLEX CG with corresponding local consistency
// group(s) for the backend volumes.
Volume changeVPoolVolume = isVPlexVolumeInCgWithLocalType(volumes);
if (changeVPoolVolume != null) {
s_logger.info("Change vpool request has volumes in VPLEX CG with backing local CGs");
// If any of the volumes is a CG and if this is a data
// migration of the volumes, then the volumes passed must
// contain all the volumes in that CG.
VirtualPool currentVPool = _dbClient.queryObject(VirtualPool.class, changeVPoolVolume.getVirtualPool());
VirtualPoolChangeOperationEnum vpoolChange = VirtualPoolChangeAnalyzer.getSupportedVPlexVolumeVirtualPoolChangeOperation(changeVPoolVolume, currentVPool, vpool, _dbClient, new StringBuffer());
if ((vpoolChange != null) && (vpoolChange == VirtualPoolChangeOperationEnum.VPLEX_DATA_MIGRATION)) {
s_logger.info("Vpool change is a data migration");
ControllerOperationValuesWrapper operationsWrapper = new ControllerOperationValuesWrapper();
operationsWrapper.put(ControllerOperationValuesWrapper.MIGRATION_SUSPEND_BEFORE_COMMIT, vpoolChangeParam.getMigrationSuspendBeforeCommit());
operationsWrapper.put(ControllerOperationValuesWrapper.MIGRATION_SUSPEND_BEFORE_DELETE_SOURCE, vpoolChangeParam.getMigrationSuspendBeforeDeleteSource());
List<Volume> volumesNotInRG = new ArrayList<Volume>();
taskList = migrateVolumesInReplicationGroup(volumes, vpool, volumesNotInRG, null, operationsWrapper);
// Migrate volumes not in Replication Group as single volumes
if (!volumesNotInRG.isEmpty()) {
// Get the migration descriptors
List<VolumeDescriptor> descriptors = new ArrayList<VolumeDescriptor>();
for (Volume volume : volumesNotInRG) {
StorageSystem vplexStorageSystem = _dbClient.queryObject(StorageSystem.class, volume.getStorageController());
descriptors.addAll(createChangeVirtualPoolDescriptors(vplexStorageSystem, volume, vpool, taskId, null, null, operationsWrapper, true));
}
// Create the tasks
taskList.getTaskList().addAll(createTasksForVolumes(vpool, volumesNotInRG, taskId).getTaskList());
// Now we get the Orchestration controller and use it to migrate all the volumes not in a RG.
orchestrateVPoolChanges(volumesNotInRG, descriptors, taskId);
}
return taskList;
}
}
// Otherwise proceed as we normally would performing
// individual vpool changes for each volume.
String nextTaskId = taskId;
for (Volume volume : volumes) {
taskList.getTaskList().addAll(changeVolumeVirtualPool(volume.getStorageController(), volume, vpool, vpoolChangeParam, nextTaskId).getTaskList());
// Create a unique task id.
nextTaskId = UUID.randomUUID().toString();
}
return taskList;
}
use of com.emc.storageos.blockorchestrationcontroller.VolumeDescriptor in project coprhd-controller by CoprHD.
the class VPlexBlockServiceApiImpl method createVolumeDescriptorsForVarrayChange.
/**
* Creates the volumes descriptors for a varray change for the passed
* list of VPLEX volumes.
*
* @param volumes The VPLEX volumes being moved
* @param newVarray The target virtual array
* @param taskId The task identifier
*
* @return A list of volume descriptors
*/
private List<VolumeDescriptor> createVolumeDescriptorsForVarrayChange(List<Volume> volumes, VirtualArray newVarray, String taskId) {
// The list of descriptors for the virtual array change.
List<VolumeDescriptor> descriptors = new ArrayList<VolumeDescriptor>();
// The VPLEX system.
StorageSystem vplexSystem = _dbClient.queryObject(StorageSystem.class, volumes.get(0).getStorageController());
// Create a descriptor for each vplex volume.
for (Volume vplexVolume : volumes) {
VolumeDescriptor descriptor = new VolumeDescriptor(VolumeDescriptor.Type.VPLEX_VIRT_VOLUME, vplexVolume.getStorageController(), vplexVolume.getId(), null, null);
Map<String, Object> descrParams = new HashMap<String, Object>();
descrParams.put(VolumeDescriptor.PARAM_VARRAY_CHANGE_NEW_VAARAY_ID, newVarray.getId());
descriptor.setParameters(descrParams);
descriptors.add(descriptor);
// We'll need to prepare a target volume and create a
// descriptor for each backend volume being migrated.
StringSet assocVolumes = vplexVolume.getAssociatedVolumes();
if (null == assocVolumes) {
s_logger.warn("VPLEX volume {} has no backend volumes. It was possibly ingested 'Virtual Volume Only'.", vplexVolume.forDisplay());
} else {
String assocVolumeId = assocVolumes.iterator().next();
URI assocVolumeURI = URI.create(assocVolumeId);
Volume assocVolume = _dbClient.queryObject(Volume.class, assocVolumeURI);
VirtualPool assocVolumeVPool = _dbClient.queryObject(VirtualPool.class, assocVolume.getVirtualPool());
descriptors.addAll(createBackendVolumeMigrationDescriptors(vplexSystem, vplexVolume, assocVolume, newVarray, assocVolumeVPool, getVolumeCapacity(assocVolume), taskId, null, false, null));
}
}
return descriptors;
}
use of com.emc.storageos.blockorchestrationcontroller.VolumeDescriptor in project coprhd-controller by CoprHD.
the class VPlexBlockServiceApiImpl method createChangeVirtualPoolDescriptors.
/**
* Change the VirtualPool for the passed virtual volume on the passed VPlex
* storage system.
*
* @param vplexSystem A reference to the VPlex storage system.
* @param volume A reference to the virtual volume.
* @param newVpool The desired VirtualPool.
* @param taskId The task identifier.
* @param operationsWrapper a wrapper of various controller options
* @param allowHighAvailabilityMigrations Flag to allow HA migration descriptors to be created
* @throws InternalException
*/
protected List<VolumeDescriptor> createChangeVirtualPoolDescriptors(StorageSystem vplexSystem, Volume volume, VirtualPool newVpool, String taskId, List<Recommendation> recommendations, VirtualPoolCapabilityValuesWrapper capabilities, ControllerOperationValuesWrapper operationsWrapper, boolean allowHighAvailabilityMigrations) throws InternalException {
// Get the varray and current vpool for the virtual volume.
URI volumeVarrayURI = volume.getVirtualArray();
VirtualArray volumeVarray = _dbClient.queryObject(VirtualArray.class, volumeVarrayURI);
URI volumeVpoolURI = volume.getVirtualPool();
VirtualPool currentVpool = _dbClient.queryObject(VirtualPool.class, volumeVpoolURI);
s_logger.info(String.format("Creating VPLEX change vpool descriptors for volume [%s](%s) " + "which belongs to: varray [%s](%s) - vpool [%s](%s)", volume.getLabel(), volume.getId(), volumeVarray.getLabel(), volumeVarray.getId(), currentVpool.getLabel(), currentVpool.getId()));
List<VolumeDescriptor> descriptors = new ArrayList<VolumeDescriptor>();
// Add the VPLEX Virtual Volume Descriptor for change vpool
VolumeDescriptor vplexVirtualVolumeDesc = new VolumeDescriptor(VolumeDescriptor.Type.VPLEX_VIRT_VOLUME, volume.getStorageController(), volume.getId(), volume.getPool(), null);
Map<String, Object> volumeParams = new HashMap<String, Object>();
volumeParams.put(VolumeDescriptor.PARAM_VPOOL_CHANGE_EXISTING_VOLUME_ID, volume.getId());
volumeParams.put(VolumeDescriptor.PARAM_VPOOL_CHANGE_NEW_VPOOL_ID, newVpool.getId());
volumeParams.put(VolumeDescriptor.PARAM_VPOOL_CHANGE_OLD_VPOOL_ID, volume.getVirtualPool());
if (operationsWrapper != null) {
if (operationsWrapper.getMigrationSuspendBeforeCommit() != null) {
volumeParams.put(VolumeDescriptor.PARAM_MIGRATION_SUSPEND_BEFORE_COMMIT, operationsWrapper.getMigrationSuspendBeforeCommit());
}
if (operationsWrapper.getMigrationSuspendBeforeDeleteSource() != null) {
volumeParams.put(VolumeDescriptor.PARAM_MIGRATION_SUSPEND_BEFORE_DELETE_SOURCE, operationsWrapper.getMigrationSuspendBeforeDeleteSource());
}
}
vplexVirtualVolumeDesc.setParameters(volumeParams);
descriptors.add(vplexVirtualVolumeDesc);
// nothing about the backend volumes.
if (VirtualPoolChangeAnalyzer.vpoolChangeRequiresMigration(currentVpool, newVpool)) {
Volume migSrcVolume = getAssociatedVolumeInVArray(volume, volumeVarrayURI);
descriptors.addAll(createBackendVolumeMigrationDescriptors(vplexSystem, volume, migSrcVolume, volumeVarray, newVpool, getVolumeCapacity(migSrcVolume != null ? migSrcVolume : volume), taskId, recommendations, false, capabilities));
}
if (allowHighAvailabilityMigrations) {
// Now determine if the backend volume in the HA varray
// needs to be migrated.
URI haVarrayURI = VirtualPoolChangeAnalyzer.getHaVarrayURI(currentVpool);
if (haVarrayURI != null) {
VirtualArray haVarray = _dbClient.queryObject(VirtualArray.class, haVarrayURI);
VirtualPool currentHaVpool = VirtualPoolChangeAnalyzer.getHaVpool(currentVpool, _dbClient);
VirtualPool newHaVpool = VirtualPoolChangeAnalyzer.getNewHaVpool(currentVpool, newVpool, _dbClient);
if (VirtualPoolChangeAnalyzer.vpoolChangeRequiresMigration(currentHaVpool, newHaVpool)) {
Volume migSrcVolume = getAssociatedVolumeInVArray(volume, haVarrayURI);
descriptors.addAll(createBackendVolumeMigrationDescriptors(vplexSystem, volume, migSrcVolume, haVarray, newHaVpool, getVolumeCapacity(migSrcVolume != null ? migSrcVolume : volume), taskId, recommendations, true, capabilities));
}
}
}
return descriptors;
}
use of com.emc.storageos.blockorchestrationcontroller.VolumeDescriptor in project coprhd-controller by CoprHD.
the class VPlexBlockServiceApiImpl method changeVirtualArrayForVolumes.
/**
* {@inheritDoc}
*/
@Override
public void changeVirtualArrayForVolumes(List<Volume> volumes, BlockConsistencyGroup cg, List<Volume> cgVolumes, VirtualArray newVirtualArray, String taskId) throws InternalException {
// if they remove the snapshots, they can perform the varray change.
for (Volume volume : volumes) {
List<BlockSnapshot> snapshots = getSnapshots(volume);
if (!snapshots.isEmpty()) {
for (BlockSnapshot snapshot : snapshots) {
if (!snapshot.getInactive()) {
throw APIException.badRequests.volumeForVarrayChangeHasSnaps(volume.getId().toString());
}
}
}
// If the volume has mirrors then varray change will not
// be allowed. User needs to explicitly delete mirrors first.
// This is applicable for both Local and Distributed volumes.
// For distributed volume getMirrors will get mirror if any
// on source or HA side.
StringSet mirrorURIs = volume.getMirrors();
if (mirrorURIs != null && !mirrorURIs.isEmpty()) {
List<VplexMirror> mirrors = _dbClient.queryObject(VplexMirror.class, StringSetUtil.stringSetToUriList(mirrorURIs));
if (mirrors != null && !mirrors.isEmpty()) {
throw APIException.badRequests.volumeForVarrayChangeHasMirrors(volume.getId().toString(), volume.getLabel());
}
}
}
// vpool change.
if ((cg != null) && (volumes.size() > _maxCgVolumesForMigration)) {
throw APIException.badRequests.cgContainsTooManyVolumesForVArrayChange(cg.getLabel(), volumes.size(), _maxCgVolumesForMigration);
}
// we don't allow the varray change.
if ((cg != null) && (cg.checkForType(Types.LOCAL)) && (cgVolumes.size() > 1)) {
verifyTargetSystemsForCGDataMigration(volumes, null, newVirtualArray.getId());
}
// Create the volume descriptors for the virtual array change.
List<VolumeDescriptor> descriptors = createVolumeDescriptorsForVarrayChange(volumes, newVirtualArray, taskId);
try {
// Orchestrate the virtual array change.
BlockOrchestrationController controller = getController(BlockOrchestrationController.class, BlockOrchestrationController.BLOCK_ORCHESTRATION_DEVICE);
controller.changeVirtualArray(descriptors, taskId);
s_logger.info("Successfully invoked block orchestrator.");
} catch (InternalException e) {
s_logger.error("Controller error", e);
for (VolumeDescriptor descriptor : descriptors) {
// migration targets and migrations.
if (VolumeDescriptor.Type.VPLEX_MIGRATE_VOLUME.equals(descriptor.getType())) {
_dbClient.error(Volume.class, descriptor.getVolumeURI(), taskId, e);
_dbClient.error(Migration.class, descriptor.getMigrationId(), taskId, e);
}
}
throw e;
}
}
use of com.emc.storageos.blockorchestrationcontroller.VolumeDescriptor in project coprhd-controller by CoprHD.
the class VPlexBlockServiceApiImpl method createVPlexVolumeDescriptors.
/**
* Create the necessary volume descriptors for Vplex volumes, including the backend
* volume descriptors and the virtual volume descriptors.
*
* @param param
* - the VolumeCreate parameters
* @param project
* -- user's project
* @param vArray
* -- virtual array volumes are created in
* @param vPool
* -- virtual pool (ROOT) used to create the volumes
* @param recommendations
* -- recommendations received from placement
* @param task
* -- a task identifier
* @param vPoolCapabilities
* - VirtualPoolCapabilitiesWrapper
* @param blockConsistencyGroupURI
* - the block consistency group URI
* @param taskList
* - OUTPUT list of tasks created
* @param allVolumes
* - OUTPUT - list of volumes created
* @param createTask
* -- boolean flag indicating to create tasks
* @return
*/
public List<VolumeDescriptor> createVPlexVolumeDescriptors(VolumeCreate param, Project project, final VirtualArray vArray, final VirtualPool vPool, List<Recommendation> recommendations, String task, VirtualPoolCapabilityValuesWrapper vPoolCapabilities, URI blockConsistencyGroupURI, TaskList taskList, List<URI> allVolumes, boolean createTask) {
s_logger.info("Request to create {} VPlex virtual volume(s)", vPoolCapabilities.getResourceCount());
// Determine if we're processing an SRDF copy so we can set appropriate name.
boolean srdfCopy = false;
if (recommendations.get(0).getRecommendation() != null && recommendations.get(0).getRecommendation() instanceof SRDFCopyRecommendation) {
srdfCopy = true;
}
// Sort the recommendations by VirtualArray. There can be up to two
// VirtualArrays, the requested VirtualArray and the HA VirtualArray
// either passed or determined by the placement when HA virtual volumes
// are being created. We also set the VPlex storage system, which
// should be the same for all recommendations.
URI vplexStorageSystemURI = null;
URI[] vplexSystemURIOut = new URI[1];
Map<String, List<VPlexRecommendation>> varrayRecommendationsMap = sortRecommendationsByVarray(recommendations, vplexSystemURIOut);
vplexStorageSystemURI = vplexSystemURIOut[0];
// for the srdf copies, since they are already pre-created.
if (!srdfCopy) {
validateVolumeLabels(param.getName(), project, vPoolCapabilities, varrayRecommendationsMap);
}
// Determine the project to be used for the VPlex's artifacts
StorageSystem vplexStorageSystem = _dbClient.queryObject(StorageSystem.class, vplexStorageSystemURI);
Project vplexProject = getVplexProject(vplexStorageSystem, _dbClient, _tenantsService);
// The volume size.
long size = SizeUtil.translateSize(param.getSize());
// The consistency group or null when not specified.
final BlockConsistencyGroup consistencyGroup = blockConsistencyGroupURI == null ? null : _dbClient.queryObject(BlockConsistencyGroup.class, blockConsistencyGroupURI);
// Find all volumes assigned to the group
boolean cgContainsVolumes = false;
if (consistencyGroup != null) {
final List<Volume> activeCGVolumes = getActiveCGVolumes(consistencyGroup);
cgContainsVolumes = (activeCGVolumes != null && !activeCGVolumes.isEmpty());
}
// If the consistency group is created but does not specify the LOCAL
// type, the CG must be a CG created prior to 2.2 or an ingested CG. In
// this case, we don't want a volume creation to result in backend CGs.
// The only exception is if the CG does not reference any volumes. In
// this case, if the LOCAL type isn't specified, we can create backend
// CGs.
BlockConsistencyGroup backendCG = null;
if (consistencyGroup != null && (!consistencyGroup.created() || !cgContainsVolumes || consistencyGroup.getTypes().contains(Types.LOCAL.toString()))) {
backendCG = consistencyGroup;
}
// Prepare Bourne volumes to represent the backend volumes for the
// recommendations in each VirtualArray.
int varrayCount = 0;
String volumeLabel = param.getName();
List<VolumeDescriptor> descriptors = new ArrayList<VolumeDescriptor>();
URI[][] varrayVolumeURIs = new URI[2][vPoolCapabilities.getResourceCount()];
Iterator<String> varrayIter = varrayRecommendationsMap.keySet().iterator();
while (varrayIter.hasNext()) {
String varrayId = varrayIter.next();
s_logger.info("Processing backend recommendations for Virtual Array {}", varrayId);
List<VPlexRecommendation> vplexRecommendations = varrayRecommendationsMap.get(varrayId);
List<VolumeDescriptor> varrayDescriptors = makeBackendVolumeDescriptors(vplexRecommendations, project, vplexProject, vPool, volumeLabel, varrayCount, size, backendCG, vPoolCapabilities, createTask, task);
descriptors.addAll(varrayDescriptors);
List<URI> varrayURIs = VolumeDescriptor.getVolumeURIs(varrayDescriptors);
allVolumes.addAll(varrayURIs);
for (int i = 0; i < varrayURIs.size(); i++) {
varrayVolumeURIs[varrayCount][i] = varrayURIs.get(i);
}
varrayCount++;
}
// Prepare Bourne volumes to represent the highly available virtual
// volumes and associate the virtual volumes with their associated
// backend volumes.
s_logger.info("Preparing virtual volumes");
List<URI> virtualVolumeURIs = new ArrayList<URI>();
URI nullPoolURI = NullColumnValueGetter.getNullURI();
vPoolCapabilities.put(VirtualPoolCapabilityValuesWrapper.AUTO_TIER__POLICY_NAME, null);
for (int i = 0; i < vPoolCapabilities.getResourceCount(); i++) {
// Compute the volume label based on the label of the underlying volume
String volumeLabelBuilt = null;
Volume associatedVolume = _dbClient.queryObject(Volume.class, varrayVolumeURIs[0][i]);
// Get the virtual volume backing replication group instance name, if available.
String backingReplicationGroupInstance = null;
if (associatedVolume != null) {
volumeLabelBuilt = generateLabelFromAssociatedVolume(volumeLabel, associatedVolume);
backingReplicationGroupInstance = NullColumnValueGetter.isNotNullValue(associatedVolume.getReplicationGroupInstance()) ? associatedVolume.getReplicationGroupInstance() : NullColumnValueGetter.getNullStr();
} else {
volumeLabelBuilt = AbstractBlockServiceApiImpl.generateDefaultVolumeLabel(volumeLabel, i, vPoolCapabilities.getResourceCount());
}
s_logger.info("Volume label is {}", volumeLabelBuilt);
Volume volume = StorageScheduler.getPrecreatedVolume(_dbClient, taskList, volumeLabelBuilt);
boolean volumePrecreated = false;
if (volume != null) {
volumePrecreated = true;
}
long thinVolumePreAllocationSize = 0;
if (null != vPool.getThinVolumePreAllocationPercentage()) {
thinVolumePreAllocationSize = VirtualPoolUtil.getThinVolumePreAllocationSize(vPool.getThinVolumePreAllocationPercentage(), size);
}
volume = prepareVolume(VolumeType.VPLEX_VIRTUAL_VOLUME, volume, size, thinVolumePreAllocationSize, project, vArray, vPool, vplexStorageSystemURI, nullPoolURI, volumeLabelBuilt, consistencyGroup, vPoolCapabilities);
StringSet associatedVolumes = new StringSet();
associatedVolumes.add(varrayVolumeURIs[0][i].toString());
s_logger.info("Associating volume {}", varrayVolumeURIs[0][i].toString());
// associated with the virtual volume.
if (varrayCount > 1) {
associatedVolumes.add(varrayVolumeURIs[1][i].toString());
s_logger.info("Associating volume {}", varrayVolumeURIs[1][i].toString());
}
volume.setAssociatedVolumes(associatedVolumes);
if (null != backingReplicationGroupInstance) {
s_logger.info("Setting virtual volume backingReplicationGroupInstance to {}", backingReplicationGroupInstance);
volume.setBackingReplicationGroupInstance(backingReplicationGroupInstance);
}
_dbClient.updateObject(volume);
URI volumeId = volume.getId();
s_logger.info("Prepared virtual volume {}", volumeId);
virtualVolumeURIs.add(volumeId);
allVolumes.add(volumeId);
if (createTask && !volumePrecreated) {
Operation op = _dbClient.createTaskOpStatus(Volume.class, volume.getId(), task, ResourceOperationTypeEnum.CREATE_BLOCK_VOLUME);
TaskResourceRep volumeTask = toTask(volume, task, op);
taskList.getTaskList().add(volumeTask);
}
VolumeDescriptor descriptor = new VolumeDescriptor(VolumeDescriptor.Type.VPLEX_VIRT_VOLUME, vplexStorageSystemURI, volumeId, null, consistencyGroup == null ? null : consistencyGroup.getId(), vPoolCapabilities, volume.getCapacity());
// Set the compute resource in the descriptor if the volume to be created will be exported
// to a host/cluster after it has been created so that the compute resource name can be
// included in the volume name if the custom volume naming is so configured. Do not set the
// compute resource if the descriptor is for an SRDF target as the target is not exported
// to the compute resource.
URI computeResourceURI = param.getComputeResource();
if ((computeResourceURI != null) && (!srdfCopy)) {
s_logger.info(String.format("Volume %s - will be exported to Host/Cluster: %s", volume.getLabel(), computeResourceURI.toString()));
descriptor.setComputeResource(computeResourceURI);
}
descriptors.add(descriptor);
}
return descriptors;
}
Aggregations