use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexDeviceController method expandVirtualVolume.
/**
* Expands the virtual volume with the passed URI to it full expandable capacity.
*
* @param vplexSystemURI
* The URI of the VPlex system.
* @param vplexVolumeURI
* The URI of the VPlex volume to expand.
* @param newSize
* The new requested volume size.
* @param systemNativeGuids
* The URIs of the backend storage systems, or null
* @param stepId
* The workflow step identifier.
*
* @throws WorkflowException
* When an error occurs updating the work step state.
*/
public void expandVirtualVolume(URI vplexSystemURI, URI vplexVolumeURI, Long newSize, List<String> systemNativeGuids, String stepId) throws WorkflowException {
try {
// Update step state to executing.
WorkflowStepCompleter.stepExecuting(stepId);
// Get the virtual volume.
Volume vplexVolume = getDataObject(Volume.class, vplexVolumeURI, _dbClient);
String vplexVolumeName = vplexVolume.getDeviceLabel();
_log.info("Virtual volume name is {}", vplexVolumeName);
// Get the VPlex API client.
StorageSystem vplexSystem = getDataObject(StorageSystem.class, vplexSystemURI, _dbClient);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplexSystem, _dbClient);
_log.info("Got VPlex API client for VPlex system {}", vplexSystemURI);
// arrays to pick up the new expanded volume size.
if (systemNativeGuids != null) {
client.rediscoverStorageSystems(systemNativeGuids);
// Async code.
try {
Thread.sleep(60000);
} catch (Exception e) {
// ignore exceptions
_log.warn("thread sleep exception " + e.getLocalizedMessage());
}
}
// Make a call to the VPlex API client to expand the virtual
// volume.
int expansionStatusRetryCount = Integer.valueOf(ControllerUtils.getPropertyValueFromCoordinator(coordinator, VPlexApiConstants.EXPANSION_STATUS_RETRY_COUNT));
long expansionStatusSleepTime = Long.valueOf(ControllerUtils.getPropertyValueFromCoordinator(coordinator, VPlexApiConstants.EXPANSION_STATUS_SLEEP_TIME_MS));
VPlexVirtualVolumeInfo vplexVolumeInfo = client.expandVirtualVolume(vplexVolumeName, expansionStatusRetryCount, expansionStatusSleepTime);
_log.info("Completed VPlex volume expansion");
// Update the VPlex volume size in the database.
vplexVolume.setCapacity(newSize);
vplexVolume.setProvisionedCapacity(vplexVolumeInfo.getCapacityBytes());
// For Vplex virtual volumes set allocated capacity to 0 (cop-18608)
vplexVolume.setAllocatedCapacity(0L);
_dbClient.updateObject(vplexVolume);
_log.info("Updated volume size");
// Update step status to success.
WorkflowStepCompleter.stepSucceded(stepId);
} catch (VPlexApiException vae) {
_log.error("Exception expanding VPlex virtual volume: " + vae.getMessage(), vae);
WorkflowStepCompleter.stepFailed(stepId, vae);
} catch (Exception ex) {
_log.error("Exception expanding VPlex virtual volume: " + ex.getMessage(), ex);
String opName = ResourceOperationTypeEnum.EXPAND_VIRTUAL_VOLUME.getName();
ServiceError serviceError = VPlexApiException.errors.expandVirtualVolumeFailed(opName, ex);
WorkflowStepCompleter.stepFailed(stepId, serviceError);
}
}
use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexDeviceController method refreshConnectionStatusForAllVPlexManagementServers.
/**
* Refreshes the connection status for all VPLEX management servers.
*
* @return The list of those to which a connection was successful.
*/
public List<URI> refreshConnectionStatusForAllVPlexManagementServers() {
List<URI> activeMgmntServers = new ArrayList<URI>();
List<StorageProvider> vplexMnmgtServers = CustomQueryUtility.getActiveStorageProvidersByInterfaceType(_dbClient, StorageProvider.InterfaceType.vplex.name());
for (StorageProvider vplexMnmgtServer : vplexMnmgtServers) {
try {
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplexMnmgtServer, _dbClient);
client.verifyConnectivity();
activeMgmntServers.add(vplexMnmgtServer.getId());
vplexMnmgtServer.setConnectionStatus(StorageProvider.ConnectionStatus.CONNECTED.toString());
} catch (Exception e) {
_log.warn("Can't connect to VPLEX management server {}", vplexMnmgtServer.getIPAddress());
vplexMnmgtServer.setConnectionStatus(StorageProvider.ConnectionStatus.NOTCONNECTED.toString());
} finally {
_dbClient.updateObject(vplexMnmgtServer);
}
}
return activeMgmntServers;
}
use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexDeviceController method createVirtualVolumeFromImportStep.
/**
* Create a Virtual Volume from an Imported Volume.
* There are three cases here:
* 1. We want to create a non-distributed virtual volume. In this case,
* there is an existingVolume, but newVolume == null.
* 2. We want to create a distributed virtual volume from an existing volume,
* and then add a mirror to a new volume (in the other varray).
* In this case, both existingVolume and newVolume are non-null.
* 3. We had an existing Virtual volume, and we only want to upgrade it
* to a distributed Virtual Volume (existingVolumeURI == null).
*
* @param vplexURI
* @param vplexVolumeURI
* @param existingVolumeURI
* @param newVolumeURI
* @param vplexSystemProject
* @param vplexSystemTenant
* @param newCosURI
* @param newLabel
* @param stepId
* @throws WorkflowException
*/
public void createVirtualVolumeFromImportStep(URI vplexURI, URI vplexVolumeURI, URI existingVolumeURI, URI newVolumeURI, URI vplexSystemProject, URI vplexSystemTenant, URI newCosURI, String newLabel, String transferSize, String stepId) throws WorkflowException {
try {
WorkflowStepCompleter.stepExecuting(stepId);
// Get the API client.
StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
// Get the three volumes.
Volume vplexVolume = getDataObject(Volume.class, vplexVolumeURI, _dbClient);
Volume existingVolume = null;
Volume newVolume = null;
if (existingVolumeURI != null) {
existingVolume = getDataObject(Volume.class, existingVolumeURI, _dbClient);
}
if (newVolumeURI != null) {
newVolume = getDataObject(Volume.class, newVolumeURI, _dbClient);
}
VPlexVirtualVolumeInfo virtvinfo = null;
VolumeInfo vinfo = null;
// Make the call to create the (non-distributed) virtual volume.
if (existingVolume != null) {
StorageSystem array = getDataObject(StorageSystem.class, existingVolume.getStorageController(), _dbClient);
List<String> itls = VPlexControllerUtils.getVolumeITLs(existingVolume);
List<VolumeInfo> vinfos = new ArrayList<VolumeInfo>();
VirtualPool newVirtualPool = getDataObject(VirtualPool.class, newCosURI, _dbClient);
boolean thinEnabled = VirtualPool.ProvisioningType.Thin.toString().equalsIgnoreCase(newVirtualPool.getSupportedProvisioningType());
vinfo = new VolumeInfo(array.getNativeGuid(), array.getSystemType(), existingVolume.getWWN().toUpperCase().replaceAll(":", ""), existingVolume.getNativeId(), thinEnabled, itls);
vinfos.add(vinfo);
thinEnabled = thinEnabled && verifyVplexSupportsThinProvisioning(vplex);
virtvinfo = client.createVirtualVolume(vinfos, false, true, true, null, null, true, thinEnabled, true);
// Note: According to client.createVirtualVolume code, this will never be the case (null)
if (virtvinfo == null) {
String opName = ResourceOperationTypeEnum.CREATE_VVOLUME_FROM_IMPORT.getName();
ServiceError serviceError = VPlexApiException.errors.createVirtualVolumeFromImportStepFailed(opName);
WorkflowStepCompleter.stepFailed(stepId, serviceError);
return;
}
_log.info(String.format("Created virtual volume: %s path: %s thinEnabled: %b", virtvinfo.getName(), virtvinfo.getPath(), virtvinfo.isThinEnabled()));
checkThinEnabledResult(virtvinfo, thinEnabled, _workflowService.getWorkflowFromStepId(stepId).getOrchTaskId());
// not set.
if (newVolume != null) {
vplexVolume.setNativeId(virtvinfo.getPath());
vplexVolume.setNativeGuid(virtvinfo.getPath());
vplexVolume.setDeviceLabel(virtvinfo.getName());
vplexVolume.setThinlyProvisioned(virtvinfo.isThinEnabled());
_dbClient.updateObject(vplexVolume);
}
} else {
virtvinfo = client.findVirtualVolume(vplexVolume.getDeviceLabel(), vplexVolume.getNativeId());
}
// now create a mirror to the new volume.
if (newVolume != null) {
String clusterId = ConnectivityUtil.getVplexClusterForVarray(vplexVolume.getVirtualArray(), vplexVolume.getStorageController(), _dbClient);
StorageSystem array = getDataObject(StorageSystem.class, newVolume.getStorageController(), _dbClient);
List<String> itls = VPlexControllerUtils.getVolumeITLs(newVolume);
vinfo = new VolumeInfo(array.getNativeGuid(), array.getSystemType(), newVolume.getWWN().toUpperCase().replaceAll(":", ""), newVolume.getNativeId(), newVolume.getThinlyProvisioned().booleanValue(), itls);
// Add rollback data.
_workflowService.storeStepData(stepId, vinfo);
virtvinfo = client.upgradeVirtualVolumeToDistributed(virtvinfo, vinfo, true, clusterId, transferSize);
if (virtvinfo == null) {
String opName = ResourceOperationTypeEnum.UPGRADE_VPLEX_LOCAL_TO_DISTRIBUTED.getName();
ServiceError serviceError = VPlexApiException.errors.upgradeLocalToDistributedFailed(opName);
WorkflowStepCompleter.stepFailed(stepId, serviceError);
return;
}
}
// Update the virtual volume device label and native Id.
// Also make sure the WWN is set.
vplexVolume.setNativeId(virtvinfo.getPath());
vplexVolume.setNativeGuid(virtvinfo.getPath());
vplexVolume.setDeviceLabel(virtvinfo.getName());
vplexVolume.setThinlyProvisioned(virtvinfo.isThinEnabled());
vplexVolume.setWWN(virtvinfo.getWwn());
// If we are importing, we need to move the existing import volume to
// the system project/tenant, update its label, and set the new CoS.
Volume srcSideAssocVolume = null;
if (existingVolume != null) {
srcSideAssocVolume = existingVolume;
existingVolume.setProject(new NamedURI(vplexSystemProject, existingVolume.getLabel()));
existingVolume.setTenant(new NamedURI(vplexSystemTenant, existingVolume.getLabel()));
existingVolume.setLabel(newLabel);
existingVolume.setVirtualPool(newCosURI);
existingVolume.addInternalFlags(Flag.INTERNAL_OBJECT);
_dbClient.updateObject(existingVolume);
// If the VPLEX volume is being upgraded to distributed, it's provisioned
// should be set and does not change. However, when importing an existing
// volume to a VPLEX volume, we need to set the provisioned capacity
// of the VPLEX volume to the provisioned capacity of the existing volume.
vplexVolume.setProvisionedCapacity(existingVolume.getProvisionedCapacity());
// For Vplex virtual volumes set allocated capacity to 0 (cop-18608)
vplexVolume.setAllocatedCapacity(0L);
// For import associated with creating a VPLEX full copy, we need
// to add the copy to the list of copies for the source VPLEX volume.
// We only do this when the copy is successfully completed.
URI srcVplexVolumeURI = vplexVolume.getAssociatedSourceVolume();
if (!NullColumnValueGetter.isNullURI(srcVplexVolumeURI)) {
// Note that the associated source volume will be null if
// this is just a standard import of a non-VPLEX volume. It
// will be set in the case we use the import workflow to
// import a native copy to a VPLEX volume for the purpose
// of creating a full copy.
Volume srcVplexVolume = _dbClient.queryObject(Volume.class, srcVplexVolumeURI);
if (null != srcVplexVolume) {
StringSet srcVplexVolumeCopies = srcVplexVolume.getFullCopies();
if (srcVplexVolumeCopies == null) {
srcVplexVolumeCopies = new StringSet();
srcVplexVolume.setFullCopies(srcVplexVolumeCopies);
}
srcVplexVolumeCopies.add(vplexVolumeURI.toString());
_dbClient.updateObject(srcVplexVolume);
}
// Also, reflect the replica state in the vplex copy.
vplexVolume.setReplicaState(existingVolume.getReplicaState());
}
} else {
// and update the CoS.
for (String assocVolume : vplexVolume.getAssociatedVolumes()) {
try {
srcSideAssocVolume = _dbClient.queryObject(Volume.class, new URI(assocVolume));
srcSideAssocVolume.setVirtualPool(newCosURI);
_dbClient.updateObject(srcSideAssocVolume);
} catch (URISyntaxException ex) {
_log.error("Bad assocVolume URI: " + assocVolume, ex);
}
}
vplexVolume.getAssociatedVolumes().add(newVolumeURI.toString());
vplexVolume.setVirtualPool(newCosURI);
}
// created and we need to make sure it has the correct name.
try {
if ((CustomVolumeNamingUtils.isCustomVolumeNamingEnabled(customConfigHandler, vplex.getSystemType())) && (existingVolume != null)) {
// Create the VPLEX volume name custom configuration datasource and generate the
// custom volume name.
String customConfigName = CustomVolumeNamingUtils.getCustomConfigName(false);
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(), vplexVolume.getWWN(), null, dataSourceFactory, customConfigName, _dbClient);
if (customNameDataSource != null) {
String customVolumeName = CustomVolumeNamingUtils.getCustomName(customConfigHandler, customConfigName, customNameDataSource, vplex.getSystemType());
virtvinfo = CustomVolumeNamingUtils.renameVolumeOnVPlex(virtvinfo, customVolumeName, client);
vplexVolume.setNativeId(virtvinfo.getPath());
vplexVolume.setNativeGuid(virtvinfo.getPath());
vplexVolume.setDeviceLabel(virtvinfo.getName());
vplexVolume.setLabel(virtvinfo.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(virtvinfo.getName());
vplexVolume.setProject(namedURI);
namedURI = vplexVolume.getTenant();
namedURI.setName(virtvinfo.getName());
vplexVolume.setTenant(namedURI);
}
}
} catch (Exception e) {
_log.warn(String.format("Error attempting to rename VPLEX volume %s", vplexVolumeURI), e);
}
// Update the volume.
_dbClient.updateObject(vplexVolume);
// Complete the workflow step.
WorkflowStepCompleter.stepSucceded(stepId);
} catch (VPlexApiException vae) {
if (existingVolumeURI != null) {
_log.error("Exception importing non-VPLEX volume to VPLEX: " + vae.getMessage(), vae);
} else {
_log.error("Exception upgrading a local VPLEX volume to distributed: " + vae.getMessage(), vae);
}
WorkflowStepCompleter.stepFailed(stepId, vae);
} catch (Exception ex) {
ServiceError serviceError;
if (existingVolumeURI != null) {
_log.error("Exception importing non-VPLEX volume to VPLEX: " + ex.getMessage(), ex);
String opName = ResourceOperationTypeEnum.IMPORT_BLOCK_VOLUME.getName();
serviceError = VPlexApiException.errors.importVolumeFailedException(opName, ex);
} else {
_log.error("Exception upgrading a local VPLEX volume to distributed: " + ex.getMessage(), ex);
String opName = ResourceOperationTypeEnum.UPGRADE_VPLEX_LOCAL_TO_DISTRIBUTED.getName();
serviceError = VPlexApiException.errors.upgradeLocalToDistributedFailedException(opName, ex);
}
WorkflowStepCompleter.stepFailed(stepId, serviceError);
}
}
use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexDeviceController method rollbackPromoteMirror.
/**
* Here we try to delete the virtual volume thats created from the mirror and then try to
* reattach the mirror so as to leave the original state. This is only going to be best effort.
* Delete the volume objects that were created as promotees.
*
* @param promotees
* The URIs of the volumes that were supposed to be promoted from mirror.
* @param executeStepId
* step Id of the execute step
* @param stepId
* The stepId used for completion.
*
* @throws WorkflowException
* When an error occurs updating the workflow step
* state.
*/
public void rollbackPromoteMirror(URI vplexURI, URI mirrorURI, URI promoteeURI, String executeStepId, String stepId) throws WorkflowException {
try {
// Update step state to executing.
WorkflowStepCompleter.stepExecuting(stepId);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplexURI, _dbClient);
VplexMirror vplexMirror = _dbClient.queryObject(VplexMirror.class, mirrorURI);
// Get source volume for the mirror
Volume sourceVplexVolume = getDataObject(Volume.class, vplexMirror.getSource().getURI(), _dbClient);
String locality = null;
if (sourceVplexVolume.getAssociatedVolumes() != null && sourceVplexVolume.getAssociatedVolumes().size() > 1) {
locality = VPlexApiConstants.DISTRIBUTED_VIRTUAL_VOLUME;
} else {
locality = VPlexApiConstants.LOCAL_VIRTUAL_VOLUME;
}
// Delete the virtual volume that should have been created when we did detach mirror.
// Virtual volume is created with the same name as the device name.
// Delete the virtual volume only, donot tear down
client.destroyVirtualVolume(vplexMirror.getDeviceLabel());
// Attach the mirror device back to the source device
client.attachMirror(locality, sourceVplexVolume.getDeviceLabel(), vplexMirror.getDeviceLabel());
_log.info("Successfully re-attached mirror %s to the source volume %s during rollback. ", vplexMirror.getDeviceLabel(), sourceVplexVolume.getDeviceLabel());
} catch (Exception e) {
// If exception occurs that means mirror is already detached and we couldn't reattach
// So cleanup database objects related to a mirror.
VplexMirror vplexMirror = _dbClient.queryObject(VplexMirror.class, mirrorURI);
Volume sourceVplexVolume = getDataObject(Volume.class, vplexMirror.getSource().getURI(), _dbClient);
// Remove mirror from the source VPLEX volume
sourceVplexVolume.getMirrors().remove(vplexMirror.getId().toString());
_dbClient.updateObject(sourceVplexVolume);
_log.info("Removed mirror %s from source volume %s", mirrorURI, sourceVplexVolume.getId());
// Delete mirror and associated volume from database
if (null != vplexMirror.getAssociatedVolumes()) {
for (String assocVolumeId : vplexMirror.getAssociatedVolumes()) {
Volume volume = _dbClient.queryObject(Volume.class, URI.create(assocVolumeId));
_dbClient.removeObject(volume);
}
}
// Delete the mirror object
_dbClient.removeObject(vplexMirror);
_log.error("Error during rollback of promote mirror: {}", e.getMessage(), e);
} finally {
// Delete the volume that was supposed to be promoted volume
Volume volume = _dbClient.queryObject(Volume.class, promoteeURI);
_dbClient.removeObject(volume);
// Return success so rollback continues
WorkflowStepCompleter.stepSucceded(stepId);
}
}
use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexDeviceController method addStepsForAddInitiators.
/**
* Add workflow steps for adding Initiators to a specific varray for the given VPlex.
*
* @param workflow
* -- Workflow steps go into
* @param vplex
* -- Storage system
* @param exportGroup
* -- ExportGroup operation invoked on
* @param varrayURI
* -- Virtual Array URI that the Initiators are in
* @param hostInitiatorURIs
* -- URIs of the Initiators
* @param initiators
* -- list of Initiator objects
* @param hostURI
* -- The hostURI
* @param previousStepId
* -- wait on this step if non-null
* @param opId
* -- step id for our operation
* @return StepId of last step generated
*/
private String addStepsForAddInitiators(Workflow workflow, StorageSystem vplex, ExportGroup exportGroup, URI varrayURI, List<URI> hostInitiatorURIs, List<Initiator> initiators, URI hostURI, String previousStepId, String opId) throws Exception {
String lastStepId = null;
URI vplexURI = vplex.getId();
URI exportURI = exportGroup.getId();
String initListStr = Joiner.on(',').join(hostInitiatorURIs);
// Find the ExportMask for my host.
ExportMask exportMask = VPlexUtil.getExportMaskForHostInVarray(_dbClient, exportGroup, hostURI, vplexURI, varrayURI);
if (exportMask == null) {
_log.info("No export mask found for hostURI: " + hostURI + " varrayURI: " + varrayURI);
Map<URI, Integer> volumeMap = ExportUtils.getExportGroupVolumeMap(_dbClient, vplex, exportGroup);
// Partition the Volumes by varray.
Map<URI, Set<URI>> varrayToVolumes = VPlexUtil.mapBlockObjectsToVarrays(_dbClient, volumeMap.keySet(), vplexURI, exportGroup);
// Filter the volumes by our Varray.
Map<URI, Integer> varrayVolumeMap = ExportMaskUtils.filterVolumeMap(volumeMap, varrayToVolumes.get(varrayURI));
// Create the ExportMask if there are volumes in this varray.
if (!varrayVolumeMap.isEmpty()) {
lastStepId = assembleExportMasksWorkflow(vplexURI, exportURI, varrayURI, hostInitiatorURIs, varrayVolumeMap, true, workflow, previousStepId, opId);
}
} else {
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
String vplexClusterName = VPlexUtil.getVplexClusterName(exportMask, vplexURI, client, _dbClient);
VPlexStorageViewInfo storageView = client.getStorageView(vplexClusterName, exportMask.getMaskName());
_log.info("Refreshing ExportMask {}", exportMask.getMaskName());
VPlexControllerUtils.refreshExportMask(_dbClient, storageView, exportMask, VPlexControllerUtils.getTargetPortToPwwnMap(client, vplexClusterName), _networkDeviceController);
if (exportMask.getVolumes() == null) {
// This can occur in Brownfield scenarios where we have not added any volumes yet to the HA side,
// CTRL10760
_log.info(String.format("No volumes in ExportMask %s (%s), so not adding initiators", exportMask.getMaskName(), exportMask.getId()));
return lastStepId;
}
_log.info(String.format("Adding initiators %s for host %s mask %s (%s)", getInitiatorsWwnsString(initiators), hostURI.toString(), exportMask.getMaskName(), exportMask.getId()));
// Calculate the path parameters for the volumes in this ExportMask
Collection<URI> volumeURIs = new HashSet<URI>();
if (exportMask.getVolumes() != null && !exportMask.getVolumes().isEmpty()) {
volumeURIs = (Collections2.transform(exportMask.getVolumes().keySet(), CommonTransformerFunctions.FCTN_STRING_TO_URI));
} else if (exportGroup.getVolumes() != null && !exportGroup.getVolumes().isEmpty()) {
// Hit this condition
// in CTRL-9944
// (unknown why)
_log.info(String.format("No volumes in ExportMask %s, using ExportGroup %s for ExportPathParam", exportMask.getId(), exportGroup.getId()));
Map<URI, Integer> volumeMap = ExportUtils.getExportGroupVolumeMap(_dbClient, vplex, exportGroup);
// Partition the Volumes by varray. Then use only the volumes in the requested varray.
Map<URI, Set<URI>> varrayToVolumes = VPlexUtil.mapBlockObjectsToVarrays(_dbClient, volumeMap.keySet(), vplexURI, exportGroup);
volumeURIs = varrayToVolumes.get(varrayURI);
} else {
_log.info(String.format("No volumes at all- using default path parameters: %s", exportMask.getId()));
}
ExportPathParams pathParams = _blockScheduler.calculateExportPathParamForVolumes(volumeURIs, exportGroup.getNumPaths(), exportMask.getStorageDevice(), exportGroup.getId());
if (exportGroup.getType() != null) {
pathParams.setExportGroupType(exportGroup.getType());
}
// Assign additional StoragePorts if needed.
Map<URI, List<URI>> assignments = _blockScheduler.assignStoragePorts(vplex, exportGroup, initiators, exportMask.getZoningMap(), pathParams, volumeURIs, _networkDeviceController, varrayURI, opId);
List<URI> newTargetURIs = BlockStorageScheduler.getTargetURIsFromAssignments(assignments);
// Build a list of StoragePort targets to remove during rollback. Do not remove existing storage ports during rollback.
List<URI> rollbackTargetURIs = new ArrayList<URI>();
for (URI target : newTargetURIs) {
if (exportMask.getStoragePorts().contains(target.toString())) {
// Skip the target port if it exists in the ViPR ExportMask
continue;
}
rollbackTargetURIs.add(target);
}
exportMask.addZoningMap(BlockStorageScheduler.getZoneMapFromAssignments(assignments));
_dbClient.updateObject(exportMask);
_log.info(String.format("Adding targets %s for host %s", newTargetURIs.toString(), hostURI.toString()));
// Create a Step to add the SAN Zone
String zoningStepId = workflow.createStepId();
Workflow.Method zoningMethod = zoneAddInitiatorStepMethod(vplexURI, exportURI, hostInitiatorURIs, varrayURI);
Workflow.Method zoningRollbackMethod = zoneRollbackMethod(exportURI, zoningStepId);
zoningStepId = workflow.createStep(ZONING_STEP, String.format("Zone initiator %s to ExportGroup %s(%s)", initListStr, exportGroup.getLabel(), exportURI), previousStepId, vplexURI, vplex.getSystemType(), this.getClass(), zoningMethod, zoningRollbackMethod, zoningStepId);
// Create a Step to add the initiator to the Storage View
String message = String.format("initiators %s to StorageView %s", initListStr, exportGroup.getGeneratedName());
ExportMask sharedExportMask = VPlexUtil.getSharedExportMaskInDb(exportGroup, vplexURI, _dbClient, varrayURI, null, null);
boolean shared = false;
if (null != sharedExportMask && sharedExportMask.getId().equals(exportMask.getId())) {
shared = true;
}
String addInitStep = workflow.createStepId();
ExportMaskAddInitiatorCompleter addInitCompleter = new ExportMaskAddInitiatorCompleter(exportURI, exportMask.getId(), hostInitiatorURIs, newTargetURIs, addInitStep);
Workflow.Method addToViewMethod = storageViewAddInitiatorsMethod(vplexURI, exportURI, exportMask.getId(), hostInitiatorURIs, newTargetURIs, shared, addInitCompleter);
Workflow.Method addToViewRollbackMethod = storageViewAddInitiatorsRollbackMethod(vplexURI, exportURI, exportMask.getId(), hostInitiatorURIs, rollbackTargetURIs, addInitStep);
lastStepId = workflow.createStep("storageView", "Add " + message, zoningStepId, vplexURI, vplex.getSystemType(), this.getClass(), addToViewMethod, addToViewRollbackMethod, addInitStep);
}
return lastStepId;
}
Aggregations