use of com.emc.storageos.volumecontroller.Recommendation in project coprhd-controller by CoprHD.
the class SRDFBlockServiceApiImpl method prepareRecommendedVolumes.
/**
* Prepare Recommended Volumes for SRDF scenarios only.
*
* This method is responsible for acting the same as the unprotected "prepareRecommendedVolumes"
* call, however it needs to create multiple volumes per single volume requests in order to
* generate SRDF protection.
*
* Those most typical scenario is, that for any one volume requested in an SRDF configuration,
* we create: 1. One Source Volume 3. One Target Volume on target varrays
*
* @param param
* volume create request
* @param task
* task from request or generated
* @param taskList
* task list
* @param project
* project from request
* @param varray
* varray from request
* @param vpool
* vpool from request
* @param volumeCount
* volume count from the request
* @param recommendations
* list of resulting recommendations from placement
* @param consistencyGroup
* consistency group ID
* @return list of volume URIs created
*/
private List<URI> prepareRecommendedVolumes(final String task, final TaskList taskList, final Project project, final VirtualArray varray, final VirtualPool vpool, final Integer volumeCount, final List<Recommendation> recommendations, final BlockConsistencyGroup consistencyGroup, final String volumeLabel, final String size) {
List<URI> volumeURIs = new ArrayList<URI>();
try {
// Create an entire Protection object for each recommendation result.
Iterator<Recommendation> recommendationsIter = recommendations.iterator();
while (recommendationsIter.hasNext()) {
SRDFRecommendation recommendation = (SRDFRecommendation) recommendationsIter.next();
// until we (later) fix creating volumes while in SWAPPED state.
for (SRDFRecommendation.Target target : recommendation.getVirtualArrayTargetMap().values()) {
if (target != null && SRDFScheduler.rdfGroupHasSwappedVolumes(_dbClient, project.getId(), target.getSourceRAGroup())) {
RemoteDirectorGroup rdg = _dbClient.queryObject(RemoteDirectorGroup.class, target.getSourceRAGroup());
throw BadRequestException.badRequests.cannotAddVolumesToSwappedReplicationGroup(rdg.getLabel());
}
}
StorageSystem storageSystem = _dbClient.queryObject(StorageSystem.class, recommendation.getSourceStorageSystem());
// operation for each volume to be created.
for (int i = 0; i < volumeCount; i++) {
// get generated volume name
String newVolumeLabel = generateDefaultVolumeLabel(volumeLabel, i, volumeCount);
// Grab the existing volume and task object from the incoming task list
Volume srcVolume = StorageScheduler.getPrecreatedVolume(_dbClient, taskList, newVolumeLabel);
boolean volumePrecreated = false;
if (srcVolume != null) {
volumePrecreated = true;
}
// number of targets.
if (recommendation.getVpoolChangeVolume() == null) {
srcVolume = prepareVolume(srcVolume, project, varray, vpool, size, recommendation, newVolumeLabel, consistencyGroup, task, false, Volume.PersonalityTypes.SOURCE, null, null, null);
volumeURIs.add(srcVolume.getId());
if (!volumePrecreated) {
taskList.getTaskList().add(toTask(srcVolume, task));
}
} else {
srcVolume = _dbClient.queryObject(Volume.class, recommendation.getVpoolChangeVolume());
Operation op = _dbClient.createTaskOpStatus(Volume.class, srcVolume.getId(), task, ResourceOperationTypeEnum.CREATE_BLOCK_VOLUME);
// Fill in additional information that prepare would've filled in that's specific to SRDF.
// Best to only fill in information here that isn't harmful if a rollback occurred,
// and the protection never got set up.
volumeURIs.add(srcVolume.getId());
taskList.getTaskList().add(toTask(srcVolume, task, op));
}
// Remove "-source" designation in the label if found
if (newVolumeLabel.contains("-source")) {
newVolumeLabel = newVolumeLabel.replaceAll("-source", "");
}
Map<URI, VpoolRemoteCopyProtectionSettings> settingMap = VirtualPool.getRemoteProtectionSettings(vpool, _dbClient);
for (VirtualArray protectionVirtualArray : SRDFScheduler.getTargetVirtualArraysForVirtualPool(project, vpool, _dbClient, _permissionsHelper)) {
VpoolRemoteCopyProtectionSettings settings = settingMap.get(protectionVirtualArray.getId());
// COP-16363 Create target BCG in controllersvc
// Prepare and populate CG request for the SRDF targets
volumeURIs.addAll(prepareTargetVolumes(project, vpool, recommendation, new StringBuilder(newVolumeLabel), protectionVirtualArray, settings, srcVolume, task, taskList, size));
}
}
}
} catch (InternalException e) {
_log.error("Rolling back the created CGs if any.");
throw e;
} catch (BadRequestException e) {
_log.info("Bad request exception: " + e.getMessage());
throw e;
} catch (Exception e) {
_log.error("Rolling back the created CGs if any.");
throw APIException.badRequests.srdfInternalError(e);
}
return volumeURIs;
}
use of com.emc.storageos.volumecontroller.Recommendation in project coprhd-controller by CoprHD.
the class SRDFBlockServiceApiImpl method upgradeToTargetVolume.
/**
* Upgrade a local block volume to a protected SRDF volume
*
* @param volume
* -- VPlex volume (existing).
* @param vpool
* -- Requested vpool.
* @param taskId
* @throws InternalException
*/
private void upgradeToTargetVolume(final Volume volume, final VirtualPool vpool, final VirtualPoolChangeParam cosChangeParam, final String taskId) throws InternalException {
VirtualPoolCapabilityValuesWrapper capabilities = new VirtualPoolCapabilityValuesWrapper();
capabilities.put(VirtualPoolCapabilityValuesWrapper.BLOCK_CONSISTENCY_GROUP, volume.getConsistencyGroup());
List<Recommendation> recommendations = getRecommendationsForVirtualPoolChangeRequest(volume, vpool, cosChangeParam);
if (recommendations.isEmpty()) {
throw APIException.badRequests.noStorageFoundForVolume();
}
// Call out to the respective block service implementation to prepare and create the
// volumes based on the recommendations.
Project project = _dbClient.queryObject(Project.class, volume.getProject());
VirtualArray varray = _dbClient.queryObject(VirtualArray.class, volume.getVirtualArray());
// Generate a VolumeCreate object that contains the information that createVolumes likes to
// consume.
VolumeCreate param = new VolumeCreate(volume.getLabel(), String.valueOf(volume.getCapacity()), 1, vpool.getId(), volume.getVirtualArray(), volume.getProject().getURI());
capabilities.put(VirtualPoolCapabilityValuesWrapper.RESOURCE_COUNT, new Integer(1));
if (volume.getIsComposite()) {
// add meta volume properties to the capabilities instance
capabilities.put(VirtualPoolCapabilityValuesWrapper.IS_META_VOLUME, volume.getIsComposite());
capabilities.put(VirtualPoolCapabilityValuesWrapper.META_VOLUME_TYPE, volume.getCompositionType());
capabilities.put(VirtualPoolCapabilityValuesWrapper.META_VOLUME_MEMBER_COUNT, volume.getMetaMemberCount());
capabilities.put(VirtualPoolCapabilityValuesWrapper.META_VOLUME_MEMBER_SIZE, volume.getMetaMemberSize());
_log.debug(String.format("Capabilities : isMeta: %s, Meta Type: %s, Member size: %s, Count: %s", capabilities.getIsMetaVolume(), capabilities.getMetaVolumeType(), capabilities.getMetaVolumeMemberSize(), capabilities.getMetaVolumeMemberCount()));
}
Map<VpoolUse, List<Recommendation>> recommendationMap = new HashMap<VpoolUse, List<Recommendation>>();
recommendationMap.put(VpoolUse.ROOT, recommendations);
createVolumes(param, project, varray, vpool, recommendationMap, null, taskId, capabilities);
}
use of com.emc.storageos.volumecontroller.Recommendation in project coprhd-controller by CoprHD.
the class MigrationService method migrateVolume.
/**
* Performs a non-disruptive migration for the passed VPLEX virtual volume.
* The backend volume of the VPLEX volume that is migrated is the backend
* volume on the passed source storage system. The volume is migrated to the
* passed target storage system, which must be connected to the same VPLEX
* cluster as the source storage system.
*
* @prereq none
*
* @param migrateParam A reference to the migration parameters.
* @deprecated Use the Change Virtual Pool API instead
* @brief Perform a non-disruptive migration for a VPLEX volume.
* @return A TaskResourceRep for the volume being migrated.
* @throws InternalException
*/
@Deprecated
@POST
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_ADMIN })
public TaskResourceRep migrateVolume(MigrationParam migrateParam) throws InternalException {
// Create a unique task id.
String taskId = UUID.randomUUID().toString();
s_logger.info("Migrate volume {} from storage system {} to storage system {}", new Object[] { migrateParam.getVolume(), migrateParam.getSrcStorageSystem(), migrateParam.getTgtStorageSystem() });
// Verify the requested volume supports migration.
Volume vplexVolume = verifyRequestedVolumeSupportsMigration(migrateParam.getVolume());
s_logger.debug("Verfified requested volume");
// Make sure that we don't have some pending
// operation against the volume
checkForPendingTasks(Arrays.asList(vplexVolume.getTenant().getURI()), Arrays.asList(vplexVolume));
// Determine the backend volume of the requested VPlex volume that
// is to be migrated. It is the volume on the passed source storage
// system.
Volume migrationSrc = getMigrationSource(vplexVolume, migrateParam.getSrcStorageSystem());
s_logger.debug("Migration source is {}", migrationSrc.getId());
// The project for the migration target will be the same as that
// of the source.
Project migrationTgtProject = _permissionsHelper.getObjectById(migrationSrc.getProject().getURI(), Project.class);
s_logger.debug("Migration target project is {}", migrationTgtProject.getId());
// The VirtualArray for the migration target will be the same as
// that of the source.
VirtualArray migrationTargetVarray = _permissionsHelper.getObjectById(migrationSrc.getVirtualArray(), VirtualArray.class);
s_logger.debug("Migration target VirtualArray is {}", migrationTargetVarray.getId());
// Verify the requested target storage system exists and
// is a system to which the migration source volume can
// be migrated.
verifyTargetStorageSystemForMigration(migrateParam.getVolume(), vplexVolume.getStorageController(), migrateParam.getSrcStorageSystem(), migrateParam.getTgtStorageSystem());
s_logger.debug("Verified target storage system {}", migrateParam.getTgtStorageSystem());
// Get the VirtualPool for the migration target.
VirtualPool migrationTgtCos = getVirtualPoolForMigrationTarget(migrateParam.getVirtualPool(), vplexVolume, migrationSrc);
s_logger.debug("Migration target VirtualPool is {}", migrationTgtCos.getId());
// Get the VPlex storage system for the virtual volume.
URI vplexSystemURI = vplexVolume.getStorageController();
Set<URI> requestedVPlexSystems = new HashSet<URI>();
requestedVPlexSystems.add(vplexSystemURI);
// Get a placement recommendation on the requested target storage
// system connected to the VPlex storage system of the VPlex volume.
VPlexScheduler vplexScheduler = _vplexBlockServiceApi.getBlockScheduler();
VirtualPoolCapabilityValuesWrapper cosWrapper = new VirtualPoolCapabilityValuesWrapper();
cosWrapper.put(VirtualPoolCapabilityValuesWrapper.SIZE, migrationSrc.getCapacity());
cosWrapper.put(VirtualPoolCapabilityValuesWrapper.RESOURCE_COUNT, new Integer(1));
List<Recommendation> recommendations = vplexScheduler.scheduleStorage(migrationTargetVarray, requestedVPlexSystems, migrateParam.getTgtStorageSystem(), migrationTgtCos, false, null, null, cosWrapper, migrationTgtProject, VpoolUse.ROOT, new HashMap<VpoolUse, List<Recommendation>>());
if (recommendations.isEmpty()) {
throw APIException.badRequests.noStorageFoundForVolumeMigration(migrationTgtCos.getLabel(), migrationTargetVarray.getLabel(), vplexVolume.getId());
}
s_logger.debug("Got recommendation for migration target");
// There should be a single recommendation.
Recommendation recommendation = recommendations.get(0);
URI recommendedSystem = recommendation.getSourceStorageSystem();
URI recommendedPool = recommendation.getSourceStoragePool();
s_logger.debug("Recommendation storage system is {}", recommendedSystem);
s_logger.debug("Recommendation storage pool is {}", recommendedPool);
// Prepare the migration target.
List<URI> migrationTgts = new ArrayList<URI>();
Map<URI, URI> poolTgtMap = new HashMap<URI, URI>();
Long size = _vplexBlockServiceApi.getVolumeCapacity(migrationSrc);
Volume migrationTgt = VPlexBlockServiceApiImpl.prepareVolumeForRequest(size, migrationTgtProject, migrationTargetVarray, migrationTgtCos, recommendedSystem, recommendedPool, migrationSrc.getLabel(), ResourceOperationTypeEnum.CREATE_BLOCK_VOLUME, taskId, _dbClient);
URI migrationTgtURI = migrationTgt.getId();
migrationTgts.add(migrationTgtURI);
poolTgtMap.put(recommendedPool, migrationTgtURI);
s_logger.debug("Prepared migration target volume {}", migrationTgtURI);
// Prepare the migration.
Map<URI, URI> migrationsMap = new HashMap<URI, URI>();
Migration migration = _vplexBlockServiceApi.prepareMigration(migrateParam.getVolume(), migrationSrc.getId(), migrationTgt.getId(), taskId);
migrationsMap.put(migrationTgtURI, migration.getId());
s_logger.debug("Prepared migration {}", migration.getId());
// Create a task for the virtual volume being migrated and set the
// initial task state to pending.
Operation op = _dbClient.createTaskOpStatus(Volume.class, vplexVolume.getId(), taskId, ResourceOperationTypeEnum.MIGRATE_BLOCK_VOLUME);
TaskResourceRep task = toTask(vplexVolume, taskId, op);
s_logger.debug("Created task for volume {}", migrateParam.getVolume());
try {
VPlexController controller = _vplexBlockServiceApi.getController();
String successMsg = String.format("Migration succeeded for volume %s", migrateParam.getVolume());
String failMsg = String.format("Migration failed for volume %s", migrateParam.getVolume());
controller.migrateVolumes(vplexSystemURI, migrateParam.getVolume(), migrationTgts, migrationsMap, poolTgtMap, (migrateParam.getVirtualPool() != null ? migrateParam.getVirtualPool() : null), null, successMsg, failMsg, null, taskId, null);
s_logger.debug("Got VPlex controller and created migration workflow");
} catch (InternalException e) {
s_logger.error("Controller Error", e);
String errMsg = String.format("Controller Error: %s", e.getMessage());
task.setState(Operation.Status.error.name());
task.setMessage(errMsg);
Operation opStatus = new Operation(Operation.Status.error.name(), errMsg);
_dbClient.updateTaskOpStatus(Volume.class, task.getResource().getId(), taskId, opStatus);
migrationTgt.setInactive(true);
_dbClient.persistObject(migrationTgt);
migration.setInactive(true);
_dbClient.persistObject(migration);
throw e;
}
return task;
}
use of com.emc.storageos.volumecontroller.Recommendation in project coprhd-controller by CoprHD.
the class VolumeService method newVolume.
protected TaskList newVolume(VolumeCreate volumeCreate, Project project, BlockServiceApi api, VirtualPoolCapabilityValuesWrapper capabilities, VirtualArray varray, String task, VirtualPool vpool, VolumeCreateRequestGen param, int volumeCount, long requestedSize, String name) {
List recommendations = _placementManager.getRecommendationsForVolumeCreateRequest(varray, project, vpool, capabilities);
Map<VpoolUse, List<Recommendation>> recommendationsMap = new HashMap<VpoolUse, List<Recommendation>>();
recommendationsMap.put(VpoolUse.ROOT, recommendations);
if (recommendations.isEmpty()) {
throw APIException.badRequests.noMatchingStoragePoolsForVpoolAndVarray(vpool.getLabel(), varray.getLabel());
}
String volname = null;
if (param.volume.name != null)
volname = param.volume.name;
else
volname = param.volume.display_name;
auditOp(OperationTypeEnum.CREATE_BLOCK_VOLUME, true, AuditLogManager.AUDITOP_BEGIN, volname, volumeCount, varray.getId().toString(), project.getId().toString());
_log.debug("Block Service API call for : Create New Volume ");
TaskList passedTaskist = createTaskList(requestedSize, project, varray, vpool, name, task, volumeCount);
return api.createVolumes(volumeCreate, project, varray, vpool, recommendationsMap, passedTaskist, task, capabilities);
}
use of com.emc.storageos.volumecontroller.Recommendation in project coprhd-controller by CoprHD.
the class VPlexBlockFullCopyApiImpl method prepareFullCopyHAVolumes.
/**
* Places and prepares the HA volumes when copying a distributed VPLEX
* volume.
*
* @param name The base name for the volume.
* @param copyCount The number of copies to be made.
* @param size The size for the HA volume.
* @param vplexSystem A reference to the VPLEX storage system.
* @param vplexSystemProject A reference to the VPLEX system project.
* @param srcVarray The virtual array for the VPLEX volume being copied.
* @param srcHAVolume The HA volume of the VPLEX volume being copied.
* @param taskId The task identifier.
* @param volumeDescriptors The list of descriptors.
*
* @return A list of the prepared HA volumes for the VPLEX volume copy.
*/
private List<Volume> prepareFullCopyHAVolumes(String name, int copyCount, Long size, StorageSystem vplexSystem, Project vplexSystemProject, VirtualArray srcVarray, Volume srcHAVolume, String taskId, List<VolumeDescriptor> volumeDescriptors) {
List<Volume> copyHAVolumes = new ArrayList<>();
// Get the storage placement recommendations for the volumes.
// Placement must occur on the same VPLEX system
Set<URI> vplexSystemURIS = new HashSet<>();
vplexSystemURIS.add(vplexSystem.getId());
VirtualArray haVarray = _dbClient.queryObject(VirtualArray.class, srcHAVolume.getVirtualArray());
VirtualPool haVpool = _dbClient.queryObject(VirtualPool.class, srcHAVolume.getVirtualPool());
VirtualPoolCapabilityValuesWrapper haCapabilities = new VirtualPoolCapabilityValuesWrapper();
haCapabilities.put(VirtualPoolCapabilityValuesWrapper.SIZE, size);
haCapabilities.put(VirtualPoolCapabilityValuesWrapper.RESOURCE_COUNT, copyCount);
VirtualPool vpool = BlockFullCopyUtils.queryFullCopySourceVPool(srcHAVolume, _dbClient);
if (VirtualPool.ProvisioningType.Thin.toString().equalsIgnoreCase(vpool.getSupportedProvisioningType())) {
haCapabilities.put(VirtualPoolCapabilityValuesWrapper.THIN_PROVISIONING, Boolean.TRUE);
// To guarantee that storage pool for a copy has enough physical
// space to contain current allocated capacity of thin source volume
haCapabilities.put(VirtualPoolCapabilityValuesWrapper.THIN_VOLUME_PRE_ALLOCATE_SIZE, BlockFullCopyUtils.getAllocatedCapacityForFullCopySource(srcHAVolume, _dbClient));
}
List<Recommendation> recommendations = ((VPlexScheduler) _scheduler).scheduleStorageForImport(srcVarray, vplexSystemURIS, haVarray, haVpool, haCapabilities);
if (recommendations.isEmpty()) {
throw APIException.badRequests.noStorageForHaVolumesForVplexVolumeCopies();
}
// Prepare the HA volumes for the VPLEX volume copy.
int copyIndex = 1;
for (Recommendation recommendation : recommendations) {
VPlexRecommendation haRecommendation = (VPlexRecommendation) recommendation;
for (int i = 0; i < haRecommendation.getResourceCount(); i++) {
// Determine the name for the HA volume copy.
StringBuilder nameBuilder = new StringBuilder(name);
nameBuilder.append("-1");
if (copyCount > 1) {
nameBuilder.append("-");
nameBuilder.append(copyIndex++);
}
// Prepare the volume.
Volume volume = VPlexBlockServiceApiImpl.prepareVolumeForRequest(size, vplexSystemProject, haVarray, haVpool, haRecommendation.getSourceStorageSystem(), haRecommendation.getSourceStoragePool(), nameBuilder.toString(), null, taskId, _dbClient);
volume.addInternalFlags(Flag.INTERNAL_OBJECT);
_dbClient.persistObject(volume);
copyHAVolumes.add(volume);
// Create the volume descriptor and add it to the passed list.
VolumeDescriptor volumeDescriptor = new VolumeDescriptor(VolumeDescriptor.Type.BLOCK_DATA, volume.getStorageController(), volume.getId(), volume.getPool(), haCapabilities);
volumeDescriptors.add(volumeDescriptor);
}
}
return copyHAVolumes;
}
Aggregations