use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexDeviceController method storageViewAddVolumes.
/**
* Method for adding volumes to a single ExportMask.
*
* @param vplexURI
* @param exportGroupURI
* @param exportMaskURI
* @param volumeMap
* @param opId
* @throws ControllerException
*/
public void storageViewAddVolumes(URI vplexURI, URI exportGroupURI, URI exportMaskURI, Map<URI, Integer> volumeMap, String opId) throws ControllerException {
String volListStr = "";
ExportMaskAddVolumeCompleter completer = null;
try {
WorkflowStepCompleter.stepExecuting(opId);
completer = new ExportMaskAddVolumeCompleter(exportGroupURI, exportMaskURI, volumeMap, opId);
ExportOperationContext context = new VplexExportOperationContext();
// Prime the context object
completer.updateWorkflowStepContext(context);
volListStr = Joiner.on(',').join(volumeMap.keySet());
StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
ExportMask exportMask = getDataObject(ExportMask.class, exportMaskURI, _dbClient);
InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_001);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
// Need to massage the map to fit the API
List<BlockObject> volumes = new ArrayList<BlockObject>();
Map<String, Integer> deviceLabelToHLU = new HashMap<String, Integer>();
boolean duplicateHLU = false;
List<URI> volumesToAdd = new ArrayList<URI>();
String vplexClusterName = VPlexUtil.getVplexClusterName(exportMask, vplexURI, client, _dbClient);
VPlexStorageViewInfo storageView = client.getStorageView(vplexClusterName, exportMask.getMaskName());
VPlexControllerUtils.refreshExportMask(_dbClient, storageView, exportMask, VPlexControllerUtils.getTargetPortToPwwnMap(client, vplexClusterName), _networkDeviceController);
exportMask = getDataObject(ExportMask.class, exportMaskURI, _dbClient);
for (Map.Entry<URI, Integer> entry : volumeMap.entrySet()) {
if (exportMask.hasVolume(entry.getKey())) {
_log.info(String.format("Volume %s is already in Exportmask %s %s hence skipping adding volume again. This must be shared exportmask. ", entry.getKey(), exportMask.getMaskName(), exportMask.getId()));
continue;
}
Integer requestedHLU = entry.getValue();
// If user have provided specific HLU for volume, then check if its already in use
if (requestedHLU.intValue() != VPlexApiConstants.LUN_UNASSIGNED && exportMask.anyVolumeHasHLU(requestedHLU.toString())) {
String message = String.format("Failed to add Volumes %s to ExportMask %s", volListStr, exportMaskURI);
_log.error(message);
String opName = ResourceOperationTypeEnum.ADD_EXPORT_VOLUME.getName();
ServiceError serviceError = VPlexApiException.errors.exportHasExistingVolumeWithRequestedHLU(entry.getKey().toString(), requestedHLU.toString(), opName);
failStep(completer, opId, serviceError);
duplicateHLU = true;
break;
}
BlockObject vol = Volume.fetchExportMaskBlockObject(_dbClient, entry.getKey());
volumes.add(vol);
deviceLabelToHLU.put(vol.getDeviceLabel(), requestedHLU);
volumesToAdd.add(entry.getKey());
}
// If duplicate HLU are found then return, completer is set to error above
if (duplicateHLU) {
return;
}
// If deviceLabelToHLU map is empty then volumes already exists in the storage view hence return.
if (deviceLabelToHLU.isEmpty()) {
completer.ready(_dbClient);
return;
}
VPlexStorageViewInfo svInfo = client.addVirtualVolumesToStorageView(exportMask.getMaskName(), vplexClusterName, deviceLabelToHLU);
ExportOperationContext.insertContextOperation(completer, VplexExportOperationContext.OPERATION_ADD_VOLUMES_TO_STORAGE_VIEW, volumesToAdd);
// When VPLEX volumes are exported to a storage view, they get a WWN,
// so set the WWN from the returned storage view information.
Map<URI, Integer> updatedVolumeMap = new HashMap<URI, Integer>();
for (BlockObject volume : volumes) {
String deviceLabel = volume.getDeviceLabel();
String wwn = svInfo.getWWNForStorageViewVolume(volume.getDeviceLabel());
volume.setWWN(wwn);
_dbClient.updateObject(volume);
updatedVolumeMap.put(volume.getId(), svInfo.getHLUForStorageViewVolume(deviceLabel));
// user.
if (exportMask.hasExistingVolume(wwn)) {
_log.info("wwn {} has been added to the storage view {} by the user, but it " + "was already in existing volumes, removing from existing volumes.", wwn, exportMask.forDisplay());
exportMask.removeFromExistingVolumes(wwn);
}
exportMask.addToUserCreatedVolumes(volume);
}
// We also need to update the volume/lun id map in the export mask
// to those assigned by the VPLEX.
_log.info("Updating volume/lun map in export mask {}", exportMask.getId());
exportMask.addVolumes(updatedVolumeMap);
_dbClient.updateObject(exportMask);
InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_002);
completer.ready(_dbClient);
} catch (VPlexApiException vae) {
String message = String.format("Failed to add Volumes %s to ExportMask %s", volListStr, exportMaskURI);
_log.error(message, vae);
failStep(completer, opId, vae);
} catch (Exception ex) {
String message = String.format("Failed to add Volumes %s to ExportMask %s", volListStr, exportMaskURI);
_log.error(message, ex);
String opName = ResourceOperationTypeEnum.ADD_EXPORT_VOLUME.getName();
ServiceError serviceError = VPlexApiException.errors.exportGroupAddVolumesFailed(volListStr, exportGroupURI.toString(), opName, ex);
failStep(completer, opId, serviceError);
}
}
use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexDeviceController method deleteStorageView.
/**
* A Workflow Step to delete a VPlex Storage View.
*
* @param vplexURI vplex
* @param exportMaskURI export mask
* @param isRollbackStep is this being run as a rollback step?
* @param stepId step ID
* @throws WorkflowException
*/
public void deleteStorageView(URI vplexURI, URI exportGroupURI, URI exportMaskURI, boolean isRollbackStep, String stepId) throws WorkflowException {
ExportMaskDeleteCompleter completer = null;
try {
WorkflowStepCompleter.stepExecuting(stepId);
completer = new ExportMaskDeleteCompleter(exportGroupURI, exportMaskURI, stepId);
completer.setRollingBack(isRollbackStep);
StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
Boolean[] viewFound = new Boolean[] { new Boolean(false) };
ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
if (exportMask != null) {
String vplexClusterName = VPlexUtil.getVplexClusterName(exportMask, vplexURI, client, _dbClient);
VPlexStorageViewInfo storageView = client.getStorageView(vplexClusterName, exportMask.getMaskName());
if (storageView != null) {
// we can ignore this in the case of a missing storage view on the VPLEX, it has already been
// deleted
_log.info("Refreshing ExportMask {}", exportMask.getMaskName());
VPlexControllerUtils.refreshExportMask(_dbClient, storageView, exportMask, VPlexControllerUtils.getTargetPortToPwwnMap(client, vplexClusterName), _networkDeviceController);
}
if (exportMask.hasAnyExistingVolumes() || exportMask.hasAnyExistingInitiators()) {
_log.warn("ExportMask {} still has non-ViPR-created existing volumes or initiators, " + "so ViPR will not remove it from the VPLEX device", exportMask.getMaskName());
}
if (exportMask.getInactive()) {
_log.warn("ExportMask {} is already inactive, so there's " + "no need to delete it off the VPLEX", exportMask.getMaskName());
} else {
List<URI> volumeURIs = new ArrayList<URI>();
if (exportMask.getUserAddedVolumes() != null && !exportMask.getUserAddedVolumes().isEmpty()) {
volumeURIs = StringSetUtil.stringSetToUriList(exportMask.getUserAddedVolumes().values());
}
List<Initiator> initiators = new ArrayList<>();
if (exportMask.getUserAddedInitiators() != null && !exportMask.getUserAddedInitiators().isEmpty()) {
List<URI> initiatorURIs = StringSetUtil.stringSetToUriList(exportMask.getUserAddedInitiators().values());
initiators.addAll(_dbClient.queryObject(Initiator.class, initiatorURIs));
}
ExportMaskValidationContext ctx = new ExportMaskValidationContext();
ctx.setStorage(vplex);
ctx.setExportMask(exportMask);
ctx.setBlockObjects(volumeURIs, _dbClient);
ctx.setInitiators(initiators);
ctx.setAllowExceptions(!WorkflowService.getInstance().isStepInRollbackState(stepId));
validator.exportMaskDelete(ctx).validate();
InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_084);
// note: there's a chance if the existing storage view originally had only
// storage ports configured in it, then it would be deleted by this
_log.info("removing this export mask from VPLEX: " + exportMask.getMaskName());
client.deleteStorageView(exportMask.getMaskName(), vplexClusterName, viewFound);
if (viewFound[0]) {
_log.info("as expected, storage view was found for deletion on the VPLEX.");
} else {
_log.info("storage view was not found on the VPLEX during deletion, " + "but no errors were encountered.");
}
}
_log.info("Marking export mask for deletion from Vipr: " + exportMask.getMaskName());
_dbClient.markForDeletion(exportMask);
_log.info("updating ExportGroups containing this ExportMask");
List<ExportGroup> exportGroups = ExportMaskUtils.getExportGroups(_dbClient, exportMask);
for (ExportGroup exportGroup : exportGroups) {
_log.info("Removing mask from ExportGroup " + exportGroup.getGeneratedName());
exportGroup.removeExportMask(exportMaskURI);
_dbClient.updateObject(exportGroup);
}
} else {
_log.info("ExportMask to delete could not be found in database: " + exportMaskURI);
}
completer.ready(_dbClient);
} catch (VPlexApiException vae) {
_log.error("Exception deleting ExportMask: " + exportMaskURI, vae);
failStep(completer, stepId, vae);
} catch (DeviceControllerException ex) {
_log.error("Exception deleting ExportMask: " + exportMaskURI, ex);
failStep(completer, stepId, ex);
} catch (Exception ex) {
_log.error("Exception deleting ExportMask: " + exportMaskURI, ex);
ServiceError svcError = VPlexApiException.errors.deleteStorageViewFailed(ex);
failStep(completer, stepId, svcError);
}
}
use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexDeviceController method createStorageView.
/**
* A Workflow Step to create a Storage View on the VPlex.
*
* @param vplexURI
* @param exportURI
* @param blockObjectMap
* - A list of Volume/Snapshot URIs to LUN ids.
* @param initiators
* @param stepId
* @throws ControllerException
*/
public void createStorageView(URI vplexURI, URI exportURI, URI exportMaskURI, Map<URI, Integer> blockObjectMap, List<URI> initiators, List<URI> targets, ExportMaskCreateCompleter completer, String stepId) throws ControllerException {
String lockName = null;
boolean lockAcquired = false;
try {
WorkflowStepCompleter.stepExecuting(stepId);
StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
ExportMask exportMask = getDataObject(ExportMask.class, exportMaskURI, _dbClient);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
// Setup the call to the VPlex API.
List<PortInfo> targetPortInfos = new ArrayList<PortInfo>();
for (URI target : targets) {
StoragePort port = getDataObject(StoragePort.class, target, _dbClient);
PortInfo pi = new PortInfo(port.getPortNetworkId().toUpperCase().replaceAll(":", ""), null, port.getPortName(), null);
targetPortInfos.add(pi);
if (lockName == null) {
String clusterId = ConnectivityUtil.getVplexClusterOfPort(port);
lockName = _vplexApiLockManager.getLockName(vplexURI, clusterId);
}
}
List<PortInfo> initiatorPortInfos = new ArrayList<PortInfo>();
for (URI init : initiators) {
Initiator initiator = getDataObject(Initiator.class, init, _dbClient);
PortInfo pi = new PortInfo(initiator.getInitiatorPort().toUpperCase().replaceAll(":", ""), initiator.getInitiatorNode().toUpperCase().replaceAll(":", ""), initiator.getLabel(), getVPlexInitiatorType(initiator));
initiatorPortInfos.add(pi);
}
List<BlockObject> blockObjects = new ArrayList<BlockObject>();
Map<String, Integer> boMap = new HashMap<String, Integer>();
for (URI vol : blockObjectMap.keySet()) {
Integer lun = blockObjectMap.get(vol);
if (lun == null) {
lun = ExportGroup.LUN_UNASSIGNED;
}
BlockObject bo = Volume.fetchExportMaskBlockObject(_dbClient, vol);
blockObjects.add(bo);
boMap.put(bo.getDeviceLabel(), lun);
}
lockAcquired = _vplexApiLockManager.acquireLock(lockName, LockTimeoutValue.get(LockType.VPLEX_API_LIB));
if (!lockAcquired) {
throw VPlexApiException.exceptions.couldNotObtainConcurrencyLock(vplex.getLabel());
}
VPlexStorageViewInfo svInfo = client.createStorageView(exportMask.getMaskName(), targetPortInfos, initiatorPortInfos, boMap);
// When VPLEX volumes or snapshots are exported to a storage view, they get a WWN,
// so set the WWN from the returned storage view information.
Map<URI, Integer> updatedBlockObjectMap = new HashMap<URI, Integer>();
for (BlockObject bo : blockObjects) {
String deviceLabel = bo.getDeviceLabel();
bo.setWWN(svInfo.getWWNForStorageViewVolume(deviceLabel));
_dbClient.updateObject(bo);
updatedBlockObjectMap.put(bo.getId(), svInfo.getHLUForStorageViewVolume(deviceLabel));
}
// We also need to update the volume/lun id map in the export mask
// to those assigned by the VPLEX.
_log.info("Updating volume/lun map in export mask {}", exportMask.getId());
_log.info("updatedBlockObjectMap: " + updatedBlockObjectMap.toString());
exportMask.addVolumes(updatedBlockObjectMap);
// Update user created volumes
exportMask.addToUserCreatedVolumes(blockObjects);
// update native id (this is the context path to the storage view on the vplex)
// e.g.: /clusters/cluster-1/exports/storage-views/V1_myserver_288
// this column being set to non-null can be used to indicate a storage view that
// has been successfully created on the VPLEX device
exportMask.setNativeId(svInfo.getPath());
_dbClient.updateObject(exportMask);
completer.ready(_dbClient);
} catch (VPlexApiException vae) {
_log.error("Exception creating VPlex Storage View: " + vae.getMessage(), vae);
if ((null != vae.getMessage()) && vae.getMessage().toUpperCase().contains(VPlexApiConstants.DUPLICATE_STORAGE_VIEW_ERROR_FRAGMENT.toUpperCase())) {
_log.error("storage view creation failure is due to duplicate storage view name");
ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
if (null != exportMask) {
_log.error("marking ExportMask inactive so that rollback will " + "not delete the existing storage view on the VPLEX");
_dbClient.removeObject(exportMask);
}
}
failStep(completer, stepId, vae);
} catch (Exception ex) {
_log.error("Exception creating VPlex Storage View: " + ex.getMessage(), ex);
String opName = ResourceOperationTypeEnum.CREATE_STORAGE_VIEW.getName();
ServiceError serviceError = VPlexApiException.errors.createStorageViewFailed(opName, ex);
failStep(completer, stepId, serviceError);
} finally {
if (lockAcquired) {
_vplexApiLockManager.releaseLock(lockName);
}
}
}
use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexDeviceController method createVirtualVolumes.
/**
* Do the creation of a VPlex Virtual Volume. This is called as a Workflow Step.
* NOTE: The parameters here must match createVirtualVolumesMethod above (except stepId).
*
* @param vplexURI
* -- URI of the VPlex StorageSystem
* @param vplexVolumeURIs
* -- URI of the VPlex volumes to be created. They must contain
* associatedVolumes (URI of the underlying Storage Volumes).
* @param computeResourceMap
* A Map of the compute resource for each volume.
* @param stepId
* - The stepId used for completion.
* @throws WorkflowException
*/
public void createVirtualVolumes(URI vplexURI, List<URI> vplexVolumeURIs, Map<URI, URI> computeResourceMap, String stepId) throws WorkflowException {
List<List<VolumeInfo>> rollbackData = new ArrayList<List<VolumeInfo>>();
List<URI> createdVplexVolumeURIs = new ArrayList<URI>();
try {
WorkflowStepCompleter.stepExecuting(stepId);
// Get the API client.
StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
// Make a map of StorageSystem ids to Storage System
Map<URI, StorageSystem> storageMap = new HashMap<URI, StorageSystem>();
// Make a map of Virtual Volumes to Storage Volumes.
Map<Volume, List<Volume>> volumeMap = new HashMap<Volume, List<Volume>>();
// Make a string buffer for volume labels
StringBuffer volumeLabels = new StringBuffer();
// List of storage system Guids
List<String> storageSystemGuids = new ArrayList<String>();
Boolean isDistributedVolume = false;
Map<String, Set<URI>> clusterVarrayMap = new HashMap<>();
for (URI vplexVolumeURI : vplexVolumeURIs) {
Volume vplexVolume = getDataObject(Volume.class, vplexVolumeURI, _dbClient);
URI vplexVolumeVarrayURI = vplexVolume.getVirtualArray();
String clusterId = ConnectivityUtil.getVplexClusterForVarray(vplexVolumeVarrayURI, vplexVolume.getStorageController(), _dbClient);
if (clusterVarrayMap.containsKey(clusterId)) {
clusterVarrayMap.get(clusterId).add(vplexVolumeVarrayURI);
} else {
Set<URI> varraysForCluster = new HashSet<>();
varraysForCluster.add(vplexVolumeVarrayURI);
clusterVarrayMap.put(clusterId, varraysForCluster);
}
volumeLabels.append(vplexVolume.getLabel()).append(" ");
volumeMap.put(vplexVolume, new ArrayList<Volume>());
// Find the underlying Storage Volumes
StringSet associatedVolumes = vplexVolume.getAssociatedVolumes();
if (associatedVolumes.size() > 1) {
isDistributedVolume = true;
}
for (String associatedVolume : associatedVolumes) {
Volume storageVolume = getDataObject(Volume.class, new URI(associatedVolume), _dbClient);
URI storageSystemId = storageVolume.getStorageController();
if (storageMap.containsKey(storageSystemId) == false) {
StorageSystem storage = _dbClient.queryObject(StorageSystem.class, storageSystemId);
storageMap.put(storageSystemId, storage);
if (!storageSystemGuids.contains(storage.getNativeGuid())) {
storageSystemGuids.add(storage.getNativeGuid());
}
}
volumeMap.get(vplexVolume).add(storageVolume);
}
}
_log.info(String.format("Request to create: %s virtual volume(s) %s", volumeMap.size(), volumeLabels));
long startTime = System.currentTimeMillis();
// If a new backend system is connected to a VPLEX and the VPLEX does not
// yet know about the system i.e., the system does not show up in the path
// /clusters/cluster-x/storage-elements/storage-arrays, and a user attempts
// to create a virtual volume, the request may fail because we cannot find
// the storage system. When the backend volume on the new system is created
// and exported to the VPLEX, the VPLEX will recognize new system. However,
// this may not occur immediately. So, when we go to create the vplex volume
// using that backend volume, we may not find that system and volume on the
// first try. We saw this in development. As such there was a retry loop
// added when finding the backend volumes in the discovery that is performed
// in the method to create the virtual volume.
//
// However changes for CTRL-12826 were merged on 7/31/2015 that circumvented
// that retry code. Changes were made to do the array re-discover here prior
// to virtual volume creation, rather than during virtual volume creation and
// false was passed to the create virtual volume routine for the discovery
// required flag. The newly added call does not do any kind of retry if the
// system is not found and so a failure will occur in the scenario described
// above. If a system is not found an exception is thrown. Now we will catch
// that exception and re-enable discovery in the volume creation routine.
// Essentially we revert to what was happening before the 12826 changes if there
// is an issue discovering the systems on the initial try here.
boolean discoveryRequired = false;
try {
client.rediscoverStorageSystems(storageSystemGuids);
} catch (Exception e) {
String warnMsg = String.format("Initial discovery of one or more of these backend systems %s failed: %s." + "Discovery is required during virtual volume creation", storageSystemGuids, e.getMessage());
_log.warn(warnMsg);
discoveryRequired = true;
}
// Now make a call to the VPlexAPIClient.createVirtualVolume for each vplex volume.
StringBuilder buf = new StringBuilder();
buf.append("Vplex: " + vplexURI + " created virtual volume(s): ");
boolean thinEnabled = false;
boolean searchAllClustersForStorageVolumes = ((clusterVarrayMap.keySet().size() > 1 || isDistributedVolume) ? true : false);
List<VPlexVirtualVolumeInfo> virtualVolumeInfos = new ArrayList<VPlexVirtualVolumeInfo>();
Map<String, Volume> vplexVolumeNameMap = new HashMap<String, Volume>();
List<VPlexClusterInfo> clusterInfoList = null;
for (Volume vplexVolume : volumeMap.keySet()) {
URI vplexVolumeId = vplexVolume.getId();
_log.info(String.format("Creating virtual volume: %s (%s)", vplexVolume.getLabel(), vplexVolumeId));
URI vplexVolumeVarrayURI = vplexVolume.getVirtualArray();
String clusterId = null;
for (Entry<String, Set<URI>> clusterEntry : clusterVarrayMap.entrySet()) {
if (clusterEntry.getValue().contains(vplexVolumeVarrayURI)) {
clusterId = clusterEntry.getKey();
}
}
List<VolumeInfo> vinfos = new ArrayList<VolumeInfo>();
for (Volume storageVolume : volumeMap.get(vplexVolume)) {
StorageSystem storage = storageMap.get(storageVolume.getStorageController());
List<String> itls = VPlexControllerUtils.getVolumeITLs(storageVolume);
VolumeInfo info = new VolumeInfo(storage.getNativeGuid(), storage.getSystemType(), storageVolume.getWWN().toUpperCase().replaceAll(":", ""), storageVolume.getNativeId(), storageVolume.getThinlyProvisioned().booleanValue(), itls);
if (storageVolume.getVirtualArray().equals(vplexVolumeVarrayURI)) {
// We always want the source backend volume identified first. It
// may not be first in the map as the map is derived from the
// VPLEX volume's associated volumes list which is an unordered
// StringSet.
vinfos.add(0, info);
} else {
vinfos.add(info);
}
if (info.getIsThinProvisioned()) {
// if either or both legs of distributed is thin, try for thin-enabled
// (or if local and the single backend volume is thin, try as well)
thinEnabled = true;
}
}
// Update rollback information.
rollbackData.add(vinfos);
_workflowService.storeStepData(stepId, rollbackData);
InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_045);
// Make a call to get cluster info
if (null == clusterInfoList) {
if (searchAllClustersForStorageVolumes) {
clusterInfoList = client.getClusterInfoDetails();
} else {
clusterInfoList = new ArrayList<VPlexClusterInfo>();
}
}
// Make the call to create a virtual volume. It is distributed if there are two (or more?)
// physical volumes.
boolean isDistributed = (vinfos.size() >= 2);
thinEnabled = thinEnabled && verifyVplexSupportsThinProvisioning(vplex);
VPlexVirtualVolumeInfo vvInfo = client.createVirtualVolume(vinfos, isDistributed, discoveryRequired, false, clusterId, clusterInfoList, false, thinEnabled, searchAllClustersForStorageVolumes);
// Note: according to client.createVirtualVolume, this will never be the case.
if (vvInfo == null) {
VPlexApiException ex = VPlexApiException.exceptions.cantFindRequestedVolume(vplexVolume.getLabel());
throw ex;
}
vplexVolumeNameMap.put(vvInfo.getName(), vplexVolume);
virtualVolumeInfos.add(vvInfo);
}
InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_046);
Map<String, VPlexVirtualVolumeInfo> foundVirtualVolumes = client.findVirtualVolumes(clusterInfoList, virtualVolumeInfos);
if (!foundVirtualVolumes.isEmpty()) {
for (Entry<String, Volume> entry : vplexVolumeNameMap.entrySet()) {
Volume vplexVolume = entry.getValue();
VPlexVirtualVolumeInfo vvInfo = foundVirtualVolumes.get(entry.getKey());
try {
// Now we try and rename the volume to the customized name. Note that if custom naming
// is disabled the custom name will not be generated and will be null.
// Create the VPLEX volume name custom configuration datasource and generate the
// custom volume name based on whether the volume is a local or distributed volume.
String hostOrClusterName = null;
URI computeResourceURI = computeResourceMap.get(vplexVolume.getId());
if (computeResourceURI != null) {
DataObject hostOrCluster = null;
if (URIUtil.isType(computeResourceURI, Cluster.class)) {
hostOrCluster = getDataObject(Cluster.class, computeResourceURI, _dbClient);
} else if (URIUtil.isType(computeResourceURI, Host.class)) {
hostOrCluster = getDataObject(Host.class, computeResourceURI, _dbClient);
}
if ((hostOrCluster != null) && ((vplexVolume.getPersonality() == null) || (vplexVolume.checkPersonality(Volume.PersonalityTypes.SOURCE)))) {
hostOrClusterName = hostOrCluster.getLabel();
}
}
if (CustomVolumeNamingUtils.isCustomVolumeNamingEnabled(customConfigHandler, vplex.getSystemType())) {
String customConfigName = CustomVolumeNamingUtils.getCustomConfigName(hostOrClusterName != null);
Project project = getDataObject(Project.class, vplexVolume.getProject().getURI(), _dbClient);
TenantOrg tenant = getDataObject(TenantOrg.class, vplexVolume.getTenant().getURI(), _dbClient);
DataSource customNameDataSource = CustomVolumeNamingUtils.getCustomConfigDataSource(project, tenant, vplexVolume.getLabel(), vvInfo.getWwn(), hostOrClusterName, dataSourceFactory, customConfigName, _dbClient);
if (customNameDataSource != null) {
String customVolumeName = CustomVolumeNamingUtils.getCustomName(customConfigHandler, customConfigName, customNameDataSource, vplex.getSystemType());
vvInfo = CustomVolumeNamingUtils.renameVolumeOnVPlex(vvInfo, customVolumeName, client);
// Update the label to match the custom name.
vplexVolume.setLabel(vvInfo.getName());
// Also, we update the name portion of the project and tenant URIs
// to reflect the custom name. This is necessary because the API
// to search for volumes by project, extracts the name portion of the
// project URI to get the volume name.
NamedURI namedURI = vplexVolume.getProject();
namedURI.setName(vvInfo.getName());
vplexVolume.setProject(namedURI);
namedURI = vplexVolume.getTenant();
namedURI.setName(vvInfo.getName());
vplexVolume.setTenant(namedURI);
}
}
} catch (Exception e) {
_log.warn(String.format("Error renaming newly created VPLEX volume %s:%s", vplexVolume.getId(), vplexVolume.getLabel()), e);
}
buf.append(vvInfo.getName() + " ");
_log.info(String.format("Created virtual volume: %s path: %s size: %s", vvInfo.getName(), vvInfo.getPath(), vvInfo.getCapacityBytes()));
vplexVolume.setNativeId(vvInfo.getPath());
vplexVolume.setNativeGuid(vvInfo.getPath());
vplexVolume.setDeviceLabel(vvInfo.getName());
vplexVolume.setThinlyProvisioned(vvInfo.isThinEnabled());
checkThinEnabledResult(vvInfo, thinEnabled, _workflowService.getWorkflowFromStepId(stepId).getOrchTaskId());
vplexVolume.setWWN(vvInfo.getWwn());
// For Vplex virtual volumes set allocated capacity to 0 (cop-18608)
vplexVolume.setAllocatedCapacity(0L);
vplexVolume.setProvisionedCapacity(vvInfo.getCapacityBytes());
_dbClient.updateObject(vplexVolume);
// Record VPLEX volume created event.
createdVplexVolumeURIs.add(vplexVolume.getId());
recordBourneVolumeEvent(vplexVolume.getId(), OperationTypeEnum.CREATE_BLOCK_VOLUME.getEvType(true), Operation.Status.ready, OperationTypeEnum.CREATE_BLOCK_VOLUME.getDescription());
}
}
if (foundVirtualVolumes.size() != vplexVolumeNameMap.size()) {
VPlexApiException ex = VPlexApiException.exceptions.cantFindAllRequestedVolume();
throw ex;
}
long elapsed = System.currentTimeMillis() - startTime;
_log.info(String.format("TIMER: %s virtual volume(s) %s create took %f seconds", volumeMap.size(), volumeLabels.toString(), (double) elapsed / (double) 1000));
WorkflowStepCompleter.stepSucceded(stepId);
} catch (VPlexApiException vae) {
_log.error("Exception creating Vplex Virtual Volume: " + vae.getMessage(), vae);
// not created.
for (URI vplexVolumeURI : vplexVolumeURIs) {
if (!createdVplexVolumeURIs.contains(vplexVolumeURI)) {
recordBourneVolumeEvent(vplexVolumeURI, OperationTypeEnum.CREATE_BLOCK_VOLUME.getEvType(false), Operation.Status.error, OperationTypeEnum.CREATE_BLOCK_VOLUME.getDescription());
}
}
WorkflowStepCompleter.stepFailed(stepId, vae);
} catch (Exception ex) {
_log.error("Exception creating Vplex Virtual Volume: " + ex.getMessage(), ex);
// not created.
for (URI vplexVolumeURI : vplexVolumeURIs) {
if (!createdVplexVolumeURIs.contains(vplexVolumeURI)) {
recordBourneVolumeEvent(vplexVolumeURI, OperationTypeEnum.CREATE_BLOCK_VOLUME.getEvType(false), Operation.Status.error, OperationTypeEnum.CREATE_BLOCK_VOLUME.getDescription());
}
}
String opName = ResourceOperationTypeEnum.CREATE_VIRTUAL_VOLUME.getName();
ServiceError serviceError = VPlexApiException.errors.createVirtualVolumesFailed(opName, ex);
WorkflowStepCompleter.stepFailed(stepId, serviceError);
}
}
use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexDeviceController method migrationSupportedForVolume.
/**
* Determines if the controller can support migration for the passed VPLEX volume.
*
* @param volume
* A reference to a VPLEX volume.
* @param varrayURI
* A reference to a varray or null.
*
* @return true if migration is supported, false otherwise.
*/
public static boolean migrationSupportedForVolume(Volume volume, URI varrayURI, DbClient dbClient) {
boolean supported = true;
// Migration is supported for all volumes that were not ingested.
if (volume.isIngestedVolumeWithoutBackend(dbClient)) {
VirtualPool vpool = dbClient.queryObject(VirtualPool.class, volume.getVirtualPool());
// Migration is supported for all local volumes.
if (VirtualPool.HighAvailabilityType.vplex_distributed.name().equals(vpool.getHighAvailability())) {
StorageSystem vplexSystem = dbClient.queryObject(StorageSystem.class, volume.getStorageController());
try {
VPlexApiFactory apiFactory = VPlexApiFactory.getInstance();
VPlexApiClient client = getVPlexAPIClient(apiFactory, vplexSystem, dbClient);
VPlexVirtualVolumeInfo vvInfo = client.getVirtualVolumeStructure(volume.getDeviceLabel());
VPlexDistributedDeviceInfo ddInfo = (VPlexDistributedDeviceInfo) vvInfo.getSupportingDeviceInfo();
List<VPlexDeviceInfo> localDeviceInfoList = ddInfo.getLocalDeviceInfo();
for (VPlexDeviceInfo localDeviceInfo : localDeviceInfoList) {
_log.info("localDeviceInfo: {}, {}", localDeviceInfo.getName(), localDeviceInfo.getCluster());
// the passed varray.
if (varrayURI != null) {
_log.info("varrayURI:{}", varrayURI);
String varrayCluster = ConnectivityUtil.getVplexClusterForVarray(varrayURI, vplexSystem.getId(), dbClient);
_log.info("varrayCluster:{}", varrayCluster);
if (!localDeviceInfo.getCluster().contains(varrayCluster)) {
continue;
}
}
// For distributed volumes, the local device must be built
// on a single extent.
_log.info("Local device: {}", localDeviceInfo.getName());
_log.info("Extent count: {}", localDeviceInfo.getExtentInfo().size());
if (localDeviceInfo.getExtentInfo().size() != 1) {
supported = false;
break;
}
}
} catch (VPlexApiException vae) {
_log.error("Exception checking if migration supported for volume:", vae);
throw vae;
} catch (Exception ex) {
_log.error("Exception checking if migration supported for volume", ex);
throw VPlexApiException.exceptions.failedGettingMigrationSupportedForVolume(vplexSystem.getId().toString(), volume.getLabel());
}
}
}
return supported;
}
Aggregations