use of com.emc.storageos.vplexcontroller.VPlexController in project coprhd-controller by CoprHD.
the class VPlexBlockServiceApiImpl method upgradeToDistributed.
/**
* Upgrade a local VPLEX volume to a distributed VPLEX volume.
*
* @param vplexURI -- VPLEX System URI
* @param vplexVolume -- VPlex volume (existing).
* @param vpool -- Requested vpool.
* @param taskId
* @throws InternalException
*/
private void upgradeToDistributed(URI vplexURI, Volume vplexVolume, VirtualPool vpool, String transferSpeed, String taskId) throws InternalException {
try {
VirtualArray neighborhood = _dbClient.queryObject(VirtualArray.class, vplexVolume.getVirtualArray());
Set<URI> vplexes = new HashSet<URI>();
vplexes.add(vplexURI);
if (null == vplexVolume.getAssociatedVolumes() || vplexVolume.getAssociatedVolumes().isEmpty()) {
s_logger.error("VPLEX volume {} has no backend volumes.", vplexVolume.forDisplay());
throw InternalServerErrorException.internalServerErrors.noAssociatedVolumesForVPLEXVolume(vplexVolume.forDisplay());
}
Iterator<String> assocIter = vplexVolume.getAssociatedVolumes().iterator();
URI existingVolumeURI = new URI(assocIter.next());
Volume existingVolume = _dbClient.queryObject(Volume.class, existingVolumeURI);
if (existingVolume == null || existingVolume.getInactive() == true) {
throw new ServiceCodeException(ServiceCode.UNFORSEEN_ERROR, "Existing volume inactive", new Object[] {});
}
VirtualPoolCapabilityValuesWrapper cosCapabilities = new VirtualPoolCapabilityValuesWrapper();
cosCapabilities.put(VirtualPoolCapabilityValuesWrapper.SIZE, getVolumeCapacity(existingVolume));
cosCapabilities.put(VirtualPoolCapabilityValuesWrapper.RESOURCE_COUNT, new Integer(1));
cosCapabilities.put(VirtualPoolCapabilityValuesWrapper.THIN_PROVISIONING, existingVolume.getThinlyProvisioned());
// Get a recommendation.
// Then create the volume.
List<VolumeDescriptor> descriptors = new ArrayList<VolumeDescriptor>();
Volume createVolume = null;
// Determine if the user requested a specific HA VirtualArray and an associated HA VirtualPool.
VirtualArray requestedHaVarray = null;
VirtualPool requestedHaVirtualPool = vpool;
if (vpool.getHaVarrayVpoolMap() != null && !vpool.getHaVarrayVpoolMap().isEmpty()) {
for (String haNH : vpool.getHaVarrayVpoolMap().keySet()) {
if (haNH.equals(NullColumnValueGetter.getNullURI().toString())) {
continue;
}
requestedHaVarray = _dbClient.queryObject(VirtualArray.class, new URI(haNH));
String haVirtualPool = vpool.getHaVarrayVpoolMap().get(haNH);
if (haVirtualPool.equals(NullColumnValueGetter.getNullURI().toString())) {
continue;
}
requestedHaVirtualPool = _dbClient.queryObject(VirtualPool.class, new URI(haVirtualPool));
break;
}
}
// Get the recommendations and pick one.
List<Recommendation> recommendations = getBlockScheduler().scheduleStorageForImport(neighborhood, vplexes, requestedHaVarray, requestedHaVirtualPool, cosCapabilities);
if (recommendations.isEmpty()) {
throw APIException.badRequests.noStorageFoundForVolumeMigration(requestedHaVirtualPool.getLabel(), requestedHaVarray.getLabel(), existingVolume.getId());
}
Recommendation recommendation = recommendations.get(0);
VPlexRecommendation vplexRecommendation = (VPlexRecommendation) recommendation;
if (false == vplexURI.equals(vplexRecommendation.getVPlexStorageSystem())) {
APIException.badRequests.vplexPlacementError(vplexVolume.getId());
}
StorageSystem vplexSystem = _dbClient.queryObject(StorageSystem.class, vplexURI);
Project vplexProject = getVplexProject(vplexSystem, _dbClient, _tenantsService);
// Prepare the created volume.
VirtualArray haVirtualArray = _dbClient.queryObject(VirtualArray.class, vplexRecommendation.getVirtualArray());
createVolume = prepareVolumeForRequest(getVolumeCapacity(existingVolume), vplexProject, haVirtualArray, requestedHaVirtualPool, vplexRecommendation.getSourceStorageSystem(), vplexRecommendation.getSourceStoragePool(), vplexVolume.getLabel() + "-1", ResourceOperationTypeEnum.CREATE_BLOCK_VOLUME, taskId, _dbClient);
createVolume.addInternalFlags(Flag.INTERNAL_OBJECT);
_dbClient.updateObject(createVolume);
VolumeDescriptor desc = new VolumeDescriptor(VolumeDescriptor.Type.BLOCK_DATA, createVolume.getStorageController(), createVolume.getId(), createVolume.getPool(), cosCapabilities);
descriptors.add(desc);
// Add a descriptor for the VPlex Virtual Volume.
desc = new VolumeDescriptor(VolumeDescriptor.Type.VPLEX_VIRT_VOLUME, vplexVolume.getStorageController(), vplexVolume.getId(), vplexVolume.getPool(), cosCapabilities);
descriptors.add(desc);
// Now send the command to the controller.
try {
s_logger.info("Calling VPlex controller.");
VPlexController controller = getController();
controller.importVolume(vplexURI, descriptors, null, null, vpool.getId(), null, transferSpeed, Boolean.TRUE, taskId);
// controller.importVolume(vplexURI, vpool.getId(),
// null, null, /* no need to pass System Project/Tenant */
// null, /* no import volume */
// createVolume.getId(), vplexVolume.getId(), taskId);
} catch (InternalException ex) {
s_logger.error("ControllerException on upgradeToDistributed", ex);
String errMsg = String.format("ControllerException: %s", ex.getMessage());
Operation statusUpdate = new Operation(Operation.Status.error.name(), errMsg);
_dbClient.updateTaskOpStatus(Volume.class, vplexVolume.getId(), taskId, statusUpdate);
throw ex;
}
} catch (URISyntaxException ex) {
s_logger.debug("URISyntaxException", ex);
}
}
use of com.emc.storageos.vplexcontroller.VPlexController in project coprhd-controller by CoprHD.
the class VPlexBlockServiceApiImpl method startNativeContinuousCopies.
/**
* {@inheritDoc}
*/
@Override
public TaskList startNativeContinuousCopies(StorageSystem vplexStorageSystem, Volume vplexVolume, VirtualPool sourceVirtualPool, VirtualPoolCapabilityValuesWrapper capabilities, NativeContinuousCopyCreate param, String taskId) throws ControllerException {
// using the target volume of a block snapshot.
if (VPlexUtil.isVolumeBuiltOnBlockSnapshot(_dbClient, vplexVolume)) {
throw APIException.badRequests.mirrorNotAllowedVolumeIsExposedSnapshot(vplexVolume.getId().toString());
}
validateNotAConsistencyGroupVolume(vplexVolume, sourceVirtualPool);
TaskList taskList = new TaskList();
// Currently, For Vplex Local Volume this will create a single mirror and add it
// to the vplex volume. For Vplex Distributed Volume this will create single mirror
// on source and/or HA side and add it to the vplex volume. Two steps: first place
// the mirror and then prepare the mirror.
URI vplexStorageSystemURI = vplexVolume.getStorageController();
// For VPLEX Local volume there will be only one associated volume entry in this set.
StringSet associatedVolumeIds = vplexVolume.getAssociatedVolumes();
if (associatedVolumeIds == null) {
throw InternalServerErrorException.internalServerErrors.noAssociatedVolumesForVPLEXVolume(vplexVolume.forDisplay());
}
VirtualPool sourceMirrorVPool = null;
// Set source mirror vpool
if (!isNullOrEmpty(sourceVirtualPool.getMirrorVirtualPool()) && !NullColumnValueGetter.isNullURI(URI.create(sourceVirtualPool.getMirrorVirtualPool()))) {
sourceMirrorVPool = _dbClient.queryObject(VirtualPool.class, URI.create(sourceVirtualPool.getMirrorVirtualPool()));
}
// Check if volume is distributed and if HA Mirror Vpool is also set
VirtualPool haMirrorVPool = VPlexUtil.getHAMirrorVpool(sourceVirtualPool, associatedVolumeIds, _dbClient);
// Map of backend volume and the mirror pool to target backend volume for the mirror
Map<Volume, VirtualPool> backendVolumeToMirrorVpoolMap = new HashMap<Volume, VirtualPool>();
if (associatedVolumeIds.size() > 1) {
// If associatedVolumeIds size is greater than 1 then its a VPLEX Distributed Volume
updateBackendVolumeToMirrorVpoolMap(vplexVolume, associatedVolumeIds, sourceVirtualPool, sourceMirrorVPool, haMirrorVPool, backendVolumeToMirrorVpoolMap);
} else {
// If we are here that means we need to create mirror for the VPLEX local volume
for (String associatedVolumeId : associatedVolumeIds) {
Volume associatedVolume = _dbClient.queryObject(Volume.class, URI.create(associatedVolumeId));
if (associatedVolume != null) {
backendVolumeToMirrorVpoolMap.put(associatedVolume, sourceMirrorVPool);
}
}
}
// Project is not passed in continuous copies call.
// Implicit assumption to use same project as the source volume.
Project project = _permissionsHelper.getObjectById(vplexVolume.getProject(), Project.class);
Map<Volume, List<Recommendation>> backendvolumeToMirrorRecommendationMap = new HashMap<Volume, List<Recommendation>>();
Map<Volume, VirtualArray> backendvolumeToMirrorVarrayMap = new HashMap<Volume, VirtualArray>();
for (Volume backendVolume : backendVolumeToMirrorVpoolMap.keySet()) {
URI backendVolumeVarrayURI = backendVolume.getVirtualArray();
// Get the VPLEX cluster value from the varray
String cluster = ConnectivityUtil.getVplexClusterForVarray(backendVolumeVarrayURI, vplexStorageSystemURI, _dbClient);
if (cluster.equals(ConnectivityUtil.CLUSTER_UNKNOWN)) {
throw InternalServerErrorException.internalServerErrors.noVplexClusterInfoForVarray(backendVolumeVarrayURI.toString(), vplexStorageSystemURI.toString());
}
VirtualPool backendVolumeVpool = _dbClient.queryObject(VirtualPool.class, backendVolume.getVirtualPool());
VirtualPool mirrorVpool = backendVolumeToMirrorVpoolMap.get(backendVolume);
// Get recommendations for the mirror placement
List<Recommendation> volumeRecommendations = null;
VirtualArray varray = null;
if (mirrorVpool != null) {
// If mirror vpool is provided try to get recommendations using the provided mirror vpool
// Check if any of the varray for mirror vpool is same as that of the source volume varray.
// If yes then get recommendations using that varray.
StringSet mirrorVPoolVarrays = mirrorVpool.getVirtualArrays();
boolean foundMatch = false;
for (String mirrorVPoolVarrayId : mirrorVPoolVarrays) {
if (mirrorVPoolVarrayId.equals(backendVolumeVarrayURI.toString())) {
varray = _dbClient.queryObject(VirtualArray.class, backendVolumeVarrayURI);
volumeRecommendations = _scheduler.getRecommendationsForMirrors(varray, project, backendVolumeVpool, mirrorVpool, capabilities, vplexStorageSystemURI, backendVolume.getStorageController(), cluster);
foundMatch = true;
break;
}
}
if (!foundMatch) {
s_logger.info("Mirror Vpool varray is different than the source vpool varray");
// with the source volume VPLEX system.
for (String mirrorVPoolVarrayId : mirrorVPoolVarrays) {
if (VPlexUtil.checkIfVarrayContainsSpecifiedVplexSystem(mirrorVPoolVarrayId, cluster, vplexStorageSystemURI, _dbClient)) {
varray = _dbClient.queryObject(VirtualArray.class, URI.create(mirrorVPoolVarrayId));
volumeRecommendations = _scheduler.getRecommendationsForMirrors(varray, project, backendVolumeVpool, mirrorVpool, capabilities, vplexStorageSystemURI, backendVolume.getStorageController(), cluster);
if (!volumeRecommendations.isEmpty()) {
foundMatch = true;
break;
} else {
s_logger.info("Tried to get recommemdations using varray {} {}. ", varray.getId(), varray.getLabel());
}
}
}
}
} else {
if (sourceVirtualPool.getHighAvailability().equals(VirtualPool.HighAvailabilityType.vplex_local.name())) {
s_logger.info("Mirror vpool is not specified, use the source volume virtual pool and virtual array");
// In case of Vplex local if mirror pool is not provided then we can use source vpool as mirror vpool.
sourceMirrorVPool = backendVolumeVpool;
mirrorVpool = backendVolumeVpool;
backendVolumeToMirrorVpoolMap.put(backendVolume, sourceMirrorVPool);
// Separate Mirror vpool is not provided so use the source volume vpool and varray for
// getting recommendations.Here sourceVirtualPool and mirrorVPool will be same.
varray = _dbClient.queryObject(VirtualArray.class, backendVolumeVarrayURI);
volumeRecommendations = _scheduler.getRecommendationsForMirrors(varray, project, backendVolumeVpool, mirrorVpool, capabilities, vplexStorageSystemURI, backendVolume.getStorageController(), cluster);
}
}
if (mirrorVpool == null) {
throw APIException.badRequests.noMirrorVpoolForVplexVolume(vplexVolume.getLabel());
}
if (varray == null) {
throw APIException.badRequests.noVarrayForMirrorVpoolWithExpectedVplex(mirrorVpool.getLabel(), vplexStorageSystem.getLabel(), cluster);
}
if (volumeRecommendations == null || volumeRecommendations.isEmpty()) {
if (volumeRecommendations.isEmpty()) {
StorageSystem storageSystem = _dbClient.queryObject(StorageSystem.class, backendVolume.getStorageController());
throw APIException.badRequests.noMatchingStoragePoolsForContinuousCopiesVpoolForVplex(varray.getLabel(), sourceMirrorVPool.getLabel(), storageSystem.getLabel());
}
}
// Add mirror recommendations for the backend volume to the map
backendvolumeToMirrorRecommendationMap.put(backendVolume, volumeRecommendations);
backendvolumeToMirrorVarrayMap.put(backendVolume, varray);
}
// Prepare mirror.
int varrayCount = 0;
int volumeCounter = 1;
// volumeCount will be always 1 for now
int volumeCount = capabilities.getResourceCount();
String volumeLabel = param.getName();
List<URI> allVolumes = new ArrayList<URI>();
List<URI> allMirrors = new ArrayList<URI>();
List<VolumeDescriptor> descriptors = new ArrayList<VolumeDescriptor>();
// Currently only one local mirror is supported for the VPLEX local virtual volume
List<VplexMirror> preparedMirrors = new ArrayList<VplexMirror>();
for (Volume backendVolume : backendvolumeToMirrorRecommendationMap.keySet()) {
List<Recommendation> volumeRecommendations = backendvolumeToMirrorRecommendationMap.get(backendVolume);
VirtualArray varray = backendvolumeToMirrorVarrayMap.get(backendVolume);
VirtualPool mirrorVpool = backendVolumeToMirrorVpoolMap.get(backendVolume);
long thinVolumePreAllocationSize = 0;
if (null != mirrorVpool.getThinVolumePreAllocationPercentage()) {
thinVolumePreAllocationSize = VirtualPoolUtil.getThinVolumePreAllocationSize(mirrorVpool.getThinVolumePreAllocationPercentage(), vplexVolume.getCapacity());
}
for (Recommendation volumeRecommendation : volumeRecommendations) {
VPlexRecommendation vplexRecommendation = (VPlexRecommendation) volumeRecommendation;
StringBuilder mirrorLabelBuilder = new StringBuilder(volumeLabel);
if (backendVolume.getVirtualArray().equals(vplexVolume.getVirtualArray())) {
varrayCount = 0;
} else {
varrayCount = 1;
}
mirrorLabelBuilder.append('-').append(varrayCount);
if (volumeCount > 1) {
mirrorLabelBuilder.append('-').append(volumeCounter++);
}
// Create mirror object
VplexMirror createdMirror = initializeMirror(vplexVolume, mirrorVpool, varray, mirrorLabelBuilder.toString(), thinVolumePreAllocationSize, _dbClient);
preparedMirrors.add(createdMirror);
Operation op = _dbClient.createTaskOpStatus(VplexMirror.class, createdMirror.getId(), taskId, ResourceOperationTypeEnum.ATTACH_VPLEX_LOCAL_MIRROR);
s_logger.info("Prepared mirror {}", createdMirror.getId());
allMirrors.add(createdMirror.getId());
// Add descriptor for the mirror.
VolumeDescriptor descriptor = new VolumeDescriptor(VolumeDescriptor.Type.VPLEX_LOCAL_MIRROR, vplexStorageSystemURI, createdMirror.getId(), null, capabilities);
descriptors.add(descriptor);
// Create backend volume object and add it to the VplexMirror created above.
Volume volume = prepareVolume(createdMirror, backendVolume, mirrorVpool, varray, vplexRecommendation.getSourceStorageSystem(), vplexRecommendation.getSourceStoragePool(), mirrorLabelBuilder.toString(), thinVolumePreAllocationSize, capabilities, _dbClient);
op = new Operation();
op.setResourceType(ResourceOperationTypeEnum.CREATE_BLOCK_VOLUME);
_dbClient.createTaskOpStatus(Volume.class, volume.getId(), taskId, op);
URI volumeId = volume.getId();
allVolumes.add(volumeId);
s_logger.info("Prepared volume {}", volumeId);
// Add descriptor for the backend volume
descriptor = new VolumeDescriptor(VolumeDescriptor.Type.BLOCK_DATA, vplexRecommendation.getSourceStorageSystem(), volumeId, vplexRecommendation.getSourceStoragePool(), capabilities);
descriptors.add(descriptor);
}
}
Collection<URI> mirrorTargetIds = Collections2.transform(preparedMirrors, FCTN_VPLEX_MIRROR_TO_URI);
String mirrorTargetCommaDelimList = Joiner.on(',').join(mirrorTargetIds);
Operation op = _dbClient.createTaskOpStatus(Volume.class, vplexVolume.getId(), taskId, ResourceOperationTypeEnum.ATTACH_VPLEX_LOCAL_MIRROR, mirrorTargetCommaDelimList);
taskList.getTaskList().add(toTask(vplexVolume, preparedMirrors, taskId, op));
try {
VPlexController controller = getController();
controller.attachContinuousCopies(vplexStorageSystem.getId(), descriptors, vplexVolume.getId(), taskId);
} catch (InternalException e) {
if (s_logger.isErrorEnabled()) {
s_logger.error("Controller error", e);
}
String errMsg = String.format("Controller error: %s", e.getMessage());
for (URI volumeURI : allVolumes) {
_dbClient.error(Volume.class, volumeURI, taskId, e);
}
for (URI mirrorURI : allMirrors) {
_dbClient.error(VplexMirror.class, mirrorURI, taskId, e);
}
for (TaskResourceRep volumeTask : taskList.getTaskList()) {
volumeTask.setState(Operation.Status.error.name());
volumeTask.setMessage(errMsg);
}
throw e;
}
return taskList;
}
use of com.emc.storageos.vplexcontroller.VPlexController in project coprhd-controller by CoprHD.
the class VPlexBlockServiceApiImpl method resynchronizeSnapshot.
/**
* {@inheritDoc}
*/
@Override
public void resynchronizeSnapshot(BlockSnapshot snapshot, Volume parentVolume, String taskId) {
VPlexController controller = getController();
Volume vplexVolume = Volume.fetchVplexVolume(_dbClient, parentVolume);
StorageSystem vplexSystem = _dbClient.queryObject(StorageSystem.class, vplexVolume.getStorageController());
controller.resyncSnapshot(vplexSystem.getId(), snapshot.getId(), taskId);
}
use of com.emc.storageos.vplexcontroller.VPlexController in project coprhd-controller by CoprHD.
the class VPlexBlockServiceApiImpl method deactivateMirror.
/**
* {@inheritDoc}
*/
@Override
public TaskList deactivateMirror(StorageSystem vplexStorageSystem, URI mirrorURI, String taskId, String deleteType) {
TaskList taskList = new TaskList();
try {
VplexMirror mirror = _dbClient.queryObject(VplexMirror.class, mirrorURI);
Volume sourceVolume = _dbClient.queryObject(Volume.class, mirror.getSource().getURI());
Operation op = _dbClient.createTaskOpStatus(Volume.class, sourceVolume.getId(), taskId, ResourceOperationTypeEnum.DEACTIVATE_VOLUME_MIRROR, mirror.getId().toString());
taskList.getTaskList().add(toTask(sourceVolume, Arrays.asList(mirror), taskId, op));
if (VolumeDeleteTypeEnum.VIPR_ONLY.name().equals(deleteType)) {
s_logger.info("Perform ViPR-only delete for VPLEX mirrors %s", mirrorURI);
// Perform any database cleanup that is required.
cleanupForViPROnlyMirrorDelete(Arrays.asList(mirrorURI));
// Mark them inactive.
_dbClient.markForDeletion(_dbClient.queryObject(VplexMirror.class, mirrorURI));
// We must get the volume from the DB again, to properly update the status.
sourceVolume = _dbClient.queryObject(Volume.class, mirror.getSource().getURI());
op = sourceVolume.getOpStatus().get(taskId);
op.ready("VPLEX continuous copy succesfully deleted from ViPR");
sourceVolume.getOpStatus().updateTaskStatus(taskId, op);
_dbClient.updateObject(sourceVolume);
} else {
List<VolumeDescriptor> descriptors = new ArrayList<VolumeDescriptor>();
// Add a descriptor for each of the associated volumes.There will be only one associated volume
if (mirror.getAssociatedVolumes() != null) {
for (String assocVolId : mirror.getAssociatedVolumes()) {
Volume assocVolume = _dbClient.queryObject(Volume.class, URI.create(assocVolId));
if (assocVolume != null && !assocVolume.getInactive() && assocVolume.getNativeId() != null) {
// In order to add descriptor for the the backend volumes that needs to be
// deleted we are checking for volume nativeId as well, because its possible
// that we were not able to create backend volume due to SMIS communication
// and rollback didn't clean up VplexMirror and its associated volumes in
// database. So in such a case nativeId will be null and we just want to skip
// sending this volume to SMIS, else it fails with null reference when user
// attempts to cleanup this failed mirror.
VolumeDescriptor assocDesc = new VolumeDescriptor(VolumeDescriptor.Type.BLOCK_DATA, assocVolume.getStorageController(), assocVolume.getId(), null, null);
descriptors.add(assocDesc);
}
}
}
VPlexController controller = getController();
controller.deactivateMirror(vplexStorageSystem.getId(), mirror.getId(), descriptors, taskId);
}
} catch (ControllerException e) {
String errorMsg = format("Failed to deactivate continuous copy %s: %s", mirrorURI.toString(), e.getMessage());
s_logger.error(errorMsg, e);
for (TaskResourceRep taskResourceRep : taskList.getTaskList()) {
taskResourceRep.setState(Operation.Status.error.name());
taskResourceRep.setMessage(errorMsg);
_dbClient.error(Volume.class, taskResourceRep.getResource().getId(), taskId, e);
}
} catch (Exception e) {
String errorMsg = format("Failed to deactivate continuous copy %s: %s", mirrorURI.toString(), e.getMessage());
s_logger.error(errorMsg, e);
ServiceCoded sc = APIException.internalServerErrors.genericApisvcError(errorMsg, e);
for (TaskResourceRep taskResourceRep : taskList.getTaskList()) {
taskResourceRep.setState(Operation.Status.error.name());
taskResourceRep.setMessage(sc.getMessage());
_dbClient.error(Volume.class, taskResourceRep.getResource().getId(), taskId, sc);
}
}
return taskList;
}
use of com.emc.storageos.vplexcontroller.VPlexController 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;
}
Aggregations