use of com.emc.storageos.db.client.model.ExportGroup in project coprhd-controller by CoprHD.
the class ExportChangePortGroupCompleter method complete.
@Override
protected void complete(DbClient dbClient, Operation.Status status, ServiceCoded coded) throws DeviceControllerException {
try {
String eventMessage = null;
log.info("Change port group completer:" + status.name());
ExportGroup exportGroup = dbClient.queryObject(ExportGroup.class, getId());
Operation operation = new Operation();
switch(status) {
case error:
operation.error(coded);
eventMessage = String.format(EXPORT_CHANGE_PORT_GROUP_FAILED_MSG, exportGroup.getLabel());
break;
case ready:
operation.ready();
updateVolumeExportPathParam(dbClient);
eventMessage = String.format(EXPORT_CHANGE_PORT_GROUP_MSG, exportGroup.getLabel());
break;
case suspended_no_error:
operation.suspendedNoError();
eventMessage = String.format(EXPORT_CHANGE_PORT_GROUP_SUSPENDED_MSG, exportGroup.getLabel());
break;
case suspended_error:
operation.suspendedError(coded);
eventMessage = String.format(EXPORT_CHANGE_PORT_GROUP_SUSPENDED_MSG, exportGroup.getLabel());
break;
default:
break;
}
exportGroup.getOpStatus().updateTaskStatus(getOpId(), operation);
dbClient.updateObject(exportGroup);
log.info(String.format("Done Export change port group - Id: %s, OpId: %s, status: %s", getId().toString(), getOpId(), status.name()));
recordBlockExportOperation(dbClient, OperationTypeEnum.EXPORT_CHANGE_PORT_GROUP, status, eventMessage, exportGroup);
} catch (Exception e) {
log.error(String.format("Failed updating status for Export change port group - Id: %s, OpId: %s", getId().toString(), getOpId()), e);
} finally {
super.complete(dbClient, status, coded);
}
}
use of com.emc.storageos.db.client.model.ExportGroup in project coprhd-controller by CoprHD.
the class SmisStorageDevice method rollbackChangePortGroupRemovePaths.
/**
* Check if the masking view is still exist. If not, then set the step error so that it won't continue to roll back
* If exists, set the step ready, then it would continue the roll back.
*/
@Override
public void rollbackChangePortGroupRemovePaths(StorageSystem storage, URI exportGroupURI, URI oldMaskURI, TaskCompleter completer) {
try {
ExportMask exportMask = _dbClient.queryObject(ExportMask.class, oldMaskURI);
if (exportMask != null) {
String maskName = exportMask.getMaskName();
CIMObjectPath maskingViewPath = _cimPath.getMaskingViewPath(storage, maskName);
if (_helper.checkExists(storage, maskingViewPath, false, false) != null) {
// The masking view still exist, then continue the roll back
completer.ready(_dbClient);
return;
}
}
// if export mask is null, or masking view does not exist, then it has been deleted. mark the completer error so that it won't continue to roll back
if (exportMask != null && !exportMask.getInactive()) {
_dbClient.markForDeletion(exportMask);
}
List<ExportGroup> exportGroups = ExportMaskUtils.getExportGroups(_dbClient, oldMaskURI);
if (exportGroups != null) {
// Remove the mask references in the export group
for (ExportGroup exportGroup : exportGroups) {
// Remove this mask from the export group
exportGroup.removeExportMask(exportMask.getId().toString());
}
// Update all of the export groups in the DB
_dbClient.updateObject(exportGroups);
}
String msg = String.format("The export mask %s has been deleted, stop roll back.", oldMaskURI.toString());
_log.info(msg);
completer.error(_dbClient, DeviceControllerException.errors.jobFailedOpMsg("Rollback change port group delete export mask", msg));
} catch (Exception e) {
completer.error(_dbClient, DeviceControllerException.errors.jobFailed(e));
}
}
use of com.emc.storageos.db.client.model.ExportGroup in project coprhd-controller by CoprHD.
the class ExportMaskUtils method getExportGroups.
/**
* Find all export groups that are referencing the export mask URI
*
* @param dbClient db client
* @param exportMask export mask URi
* @return list of export groups referring to the export mask URI
*/
public static List<ExportGroup> getExportGroups(DbClient dbClient, URI exportMaskURI) {
URIQueryResultList exportGroupURIs = new URIQueryResultList();
dbClient.queryByConstraint(ContainmentConstraint.Factory.getExportMaskExportGroupConstraint(exportMaskURI), exportGroupURIs);
List<ExportGroup> exportGroups = new ArrayList<ExportGroup>();
for (URI egURI : exportGroupURIs) {
ExportGroup exportGroup = dbClient.queryObject(ExportGroup.class, egURI);
if (exportGroup == null || exportGroup.getInactive() == true) {
continue;
}
exportGroups.add(exportGroup);
}
return exportGroups;
}
use of com.emc.storageos.db.client.model.ExportGroup in project coprhd-controller by CoprHD.
the class VPlexDeviceController method assembleExportMasksWorkflow.
/**
* Method to assemble the find or create VPLEX storage views (export masks) workflow for the given
* ExportGroup, Initiators, and the block object Map.
*
* @param vplexURI
* the URI of the VPLEX StorageSystem object
* @param export
* the ExportGroup in question
* @param varrayUri
* -- NOTE! The varrayURI may NOT be the same as the exportGroup varray!.
* @param initiators
* if initiators is null, the method will use all initiators from the ExportGroup
* @param blockObjectMap
* the key (URI) of this map can reference either the volume itself or a snapshot.
* @param zoningStepNeeded - Determines whether zone step is needed
* @param workflow
* the controller workflow
* @param waitFor
* -- If non-null, will wait on previous workflow step
* @param opId
* the workflow step id
* @return the last Workflow Step id
* @throws Exception
*/
private String assembleExportMasksWorkflow(URI vplexURI, URI export, URI varrayUri, List<URI> initiators, Map<URI, Integer> blockObjectMap, boolean zoningStepNeeded, Workflow workflow, String waitFor, String opId) throws Exception {
long startAssembly = new Date().getTime();
VPlexControllerUtils.cleanStaleExportMasks(_dbClient, vplexURI);
_log.info("TIMER: clean stale export masks took {} ms", new Date().getTime() - startAssembly);
StorageSystem vplexSystem = getDataObject(StorageSystem.class, vplexURI, _dbClient);
ExportGroup exportGroup = getDataObject(ExportGroup.class, export, _dbClient);
// filter volume map just for this VPLEX's virtual volumes
_log.info("object map before filtering for this VPLEX: " + blockObjectMap);
Map<URI, Integer> filteredBlockObjectMap = new HashMap<URI, Integer>();
for (URI boURI : blockObjectMap.keySet()) {
BlockObject bo = Volume.fetchExportMaskBlockObject(_dbClient, boURI);
if (bo.getStorageController().equals(vplexURI)) {
filteredBlockObjectMap.put(bo.getId(), blockObjectMap.get(boURI));
}
}
blockObjectMap = filteredBlockObjectMap;
_log.info("object map after filtering for this VPLEX: " + blockObjectMap);
// validate volume to lun map to make sure there aren't any duplicate LUN entries
ExportUtils.validateExportGroupVolumeMap(exportGroup.getLabel(), blockObjectMap);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplexSystem, _dbClient);
// we will need lists of new export masks to create and existing export masks to simply update
List<ExportMask> exportMasksToCreateOnDevice = new ArrayList<ExportMask>();
List<ExportMask> exportMasksToUpdateOnDevice = new ArrayList<ExportMask>();
// In case we are just updating the existing export masks we will need this map
// to add initiators which are not already there.
Map<URI, List<Initiator>> exportMasksToUpdateOnDeviceWithInitiators = new HashMap<URI, List<Initiator>>();
// In case we are just updating the existing export masks we will need this map
// to add storage ports which are not already there.
Map<URI, List<URI>> exportMasksToUpdateOnDeviceWithStoragePorts = new HashMap<URI, List<URI>>();
// try to collect initiators, if none supplied by caller
if (initiators == null) {
initiators = new ArrayList<URI>();
if (exportGroup.hasInitiators()) {
for (String initiator : exportGroup.getInitiators()) {
initiators.add(URI.create(initiator));
}
}
}
// sort initiators in a host to initiator map
Map<URI, List<Initiator>> hostInitiatorMap = VPlexUtil.makeHostInitiatorsMap(initiators, _dbClient);
// This Set will be used to track shared export mask in database.
Set<ExportMask> sharedExportMasks = new HashSet<ExportMask>();
// look at each host
String lockName = null;
boolean lockAcquired = false;
String vplexClusterId = ConnectivityUtil.getVplexClusterForVarray(varrayUri, vplexURI, _dbClient);
String vplexClusterName = VPlexUtil.getVplexClusterName(varrayUri, vplexURI, client, _dbClient);
try {
lockName = _vplexApiLockManager.getLockName(vplexURI, vplexClusterId);
lockAcquired = _vplexApiLockManager.acquireLock(lockName, LockTimeoutValue.get(LockType.VPLEX_API_LIB));
if (!lockAcquired) {
throw VPlexApiException.exceptions.couldNotObtainConcurrencyLock(vplexSystem.getLabel());
}
Map<String, String> targetPortToPwwnMap = VPlexControllerUtils.getTargetPortToPwwnMap(client, vplexClusterName);
Boolean[] doInitiatorRefresh = new Boolean[] { new Boolean(true) };
/**
* COP-28674: During Vblock boot volume export, if existing storage views are found then check for existing volumes
* If found throw exception. This condition is valid only for boot volume vblock export.
*/
if (exportGroup.forHost() && ExportMaskUtils.isVblockHost(initiators, _dbClient) && ExportMaskUtils.isBootVolume(_dbClient, blockObjectMap)) {
_log.info("VBlock boot volume Export: Validating the Vplex Cluster {} to find existing storage views", vplexClusterName);
List<Initiator> initiatorList = _dbClient.queryObject(Initiator.class, initiators);
List<String> initiatorNames = getInitiatorNames(vplexSystem.getSerialNumber(), vplexClusterName, client, initiatorList.iterator(), doInitiatorRefresh);
List<VPlexStorageViewInfo> storageViewInfos = client.getStorageViewsContainingInitiators(vplexClusterName, initiatorNames);
List<String> maskNames = new ArrayList<String>();
if (!CollectionUtils.isEmpty(storageViewInfos)) {
for (VPlexStorageViewInfo storageView : storageViewInfos) {
if (!CollectionUtils.isEmpty(storageView.getVirtualVolumes())) {
maskNames.add(storageView.getName());
} else {
_log.info("Found Storage View {} for cluster {} with empty volumes", storageView.getName(), vplexClusterName);
}
}
} else {
_log.info("No Storage views found for cluster {}", vplexClusterName);
}
if (!CollectionUtils.isEmpty(maskNames)) {
Set<URI> computeResourceSet = hostInitiatorMap.keySet();
throw VPlexApiException.exceptions.existingMaskFoundDuringBootVolumeExport(Joiner.on(", ").join(maskNames), Joiner.on(", ").join(computeResourceSet), vplexClusterName);
} else {
_log.info("VBlock Boot volume Export : Validation passed");
}
}
for (URI hostUri : hostInitiatorMap.keySet()) {
_log.info("assembling export masks workflow, now looking at host URI: " + hostUri);
List<Initiator> inits = hostInitiatorMap.get(hostUri);
_log.info("this host contains these initiators: " + inits);
boolean foundMatchingStorageView = false;
boolean allPortsFromMaskMatchForVarray = true;
_log.info("attempting to locate an existing ExportMask for this host's initiators on VPLEX Cluster " + vplexClusterId);
Map<URI, ExportMask> vplexExportMasks = new HashMap<URI, ExportMask>();
allPortsFromMaskMatchForVarray = filterExportMasks(vplexExportMasks, inits, varrayUri, vplexSystem, vplexClusterId);
ExportMask sharedVplexExportMask = null;
switch(vplexExportMasks.size()) {
case FOUND_NO_VIPR_EXPORT_MASKS:
// Didn't find any single existing ExportMask for this Host/Initiators.
// Check if there is a shared ExportMask in CoprHD with by checking the existing initiators list.
sharedVplexExportMask = VPlexUtil.getExportMasksWithExistingInitiators(vplexURI, _dbClient, inits, varrayUri, vplexClusterId);
// on the VPLEX and set it up as a new ExportMask.
if (null != sharedVplexExportMask) {
sharedExportMasks.add(sharedVplexExportMask);
// If sharedVplexExportMask is found then that export mask will be used to add any missing
// initiators or storage ports as needed, and volumes requested, if not already present.
setupExistingExportMaskWithNewHost(blockObjectMap, vplexSystem, exportGroup, varrayUri, exportMasksToUpdateOnDevice, exportMasksToUpdateOnDeviceWithInitiators, exportMasksToUpdateOnDeviceWithStoragePorts, inits, sharedVplexExportMask, opId);
VPlexStorageViewInfo storageView = client.getStorageView(vplexClusterName, sharedVplexExportMask.getMaskName());
_log.info("Refreshing ExportMask {}", sharedVplexExportMask.getMaskName());
VPlexControllerUtils.refreshExportMask(_dbClient, storageView, sharedVplexExportMask, targetPortToPwwnMap, _networkDeviceController);
foundMatchingStorageView = true;
break;
} else {
_log.info("could not find an existing matching ExportMask in ViPR, " + "so ViPR will see if there is one already on the VPLEX system");
// ViPR will attempt to find a suitable existing storage view
// on the VPLEX and set it up as a new ExportMask.
long start = new Date().getTime();
foundMatchingStorageView = checkForExistingStorageViews(client, targetPortToPwwnMap, vplexSystem, vplexClusterName, inits, exportGroup, varrayUri, blockObjectMap, exportMasksToUpdateOnDevice, exportMasksToUpdateOnDeviceWithInitiators, exportMasksToUpdateOnDeviceWithStoragePorts, doInitiatorRefresh, opId);
long elapsed = new Date().getTime() - start;
_log.info("TIMER: finding an existing storage view took {} ms and returned {}", elapsed, foundMatchingStorageView);
break;
}
case FOUND_ONE_VIPR_EXPORT_MASK:
// get the single value in the map
ExportMask viprExportMask = vplexExportMasks.values().iterator().next();
_log.info("a valid ExportMask matching these initiators exists already in ViPR " + "for this VPLEX device, so ViPR will re-use it: " + viprExportMask.getMaskName());
VPlexStorageViewInfo storageView = client.getStorageView(vplexClusterName, viprExportMask.getMaskName());
_log.info("Refreshing ExportMask {}", viprExportMask.getMaskName());
VPlexControllerUtils.refreshExportMask(_dbClient, storageView, viprExportMask, targetPortToPwwnMap, _networkDeviceController);
reuseExistingExportMask(blockObjectMap, vplexSystem, exportGroup, varrayUri, exportMasksToUpdateOnDevice, exportMasksToUpdateOnDeviceWithStoragePorts, inits, allPortsFromMaskMatchForVarray, viprExportMask, opId);
foundMatchingStorageView = true;
break;
default:
String message = "Invalid Configuration: more than one VPLEX ExportMask " + "in this cluster exists in ViPR for these initiators " + inits;
_log.error(message);
throw new Exception(message);
}
// or set up a brand new ExportMask (to create a storage view on the VPLEX) for the Host.
if (!foundMatchingStorageView) {
if (null == sharedVplexExportMask) {
// If we reached here, it means there isn't an existing storage view on the VPLEX with the host,
// and no other shared ExportMask was found in the database by looking at existingInitiators.
// So, ViPR will try to find if there is shared export mask already for the ExportGroup in the database.
sharedVplexExportMask = VPlexUtil.getSharedExportMaskInDb(exportGroup, vplexURI, _dbClient, varrayUri, vplexClusterId, hostInitiatorMap);
}
if (null != sharedVplexExportMask) {
// If a sharedExportMask was found, then the new host will be added to that ExportMask
_log.info(String.format("Shared export mask %s %s found for the export group %s %s which will be reused for initiators %s .", sharedVplexExportMask.getMaskName(), sharedVplexExportMask.getId(), exportGroup.getLabel(), exportGroup.getId(), inits.toString()));
sharedExportMasks.add(sharedVplexExportMask);
VPlexStorageViewInfo storageView = client.getStorageView(vplexClusterName, sharedVplexExportMask.getMaskName());
_log.info("Refreshing ExportMask {}", sharedVplexExportMask.getMaskName());
VPlexControllerUtils.refreshExportMask(_dbClient, storageView, sharedVplexExportMask, targetPortToPwwnMap, _networkDeviceController);
setupExistingExportMaskWithNewHost(blockObjectMap, vplexSystem, exportGroup, varrayUri, exportMasksToUpdateOnDevice, exportMasksToUpdateOnDeviceWithInitiators, exportMasksToUpdateOnDeviceWithStoragePorts, inits, sharedVplexExportMask, opId);
} else {
// Otherwise, create a brand new ExportMask, which will enable the storage view to
// be created on the VPLEX device as part of this workflow
_log.info("did not find a matching existing storage view anywhere, so ViPR " + "will initialize a new one and push it to the VPLEX device");
setupNewExportMask(blockObjectMap, vplexSystem, exportGroup, varrayUri, exportMasksToCreateOnDevice, inits, vplexClusterId, opId);
}
}
}
} finally {
if (lockAcquired) {
_vplexApiLockManager.releaseLock(lockName);
}
}
_log.info("updating zoning if necessary for both new and updated export masks");
String zoningStepId = waitFor;
if (zoningStepNeeded) {
_log.info("Adding step to update zones if required.");
zoningStepId = addStepsForZoningUpdate(export, initiators, blockObjectMap, workflow, waitFor, exportMasksToCreateOnDevice, exportMasksToUpdateOnDevice);
} else {
// If exportMasksToCreateOnDevice list as not empty, new export must be created and zoned on switch .
if (!exportMasksToCreateOnDevice.isEmpty()) {
_log.info("Adding zone step to newly created exportMask");
zoningStepId = addStepsForZoningUpdate(export, initiators, blockObjectMap, workflow, waitFor, exportMasksToCreateOnDevice, new ArrayList<ExportMask>());
}
// create the FCZoneReference for new volumes by referencing existing FCZoneReference on same ExportGroup
if (!exportMasksToUpdateOnDevice.isEmpty()) {
_log.info("Update ExportGroup: {} will use existing zone and new FCZoneReference will get added", export);
zoningStepId = addStepsForFCZoneRefCreate(export, blockObjectMap, workflow, zoningStepId, exportMasksToUpdateOnDevice);
}
}
_log.info("set up initiator pre-registration step");
String storageViewStepId = addStepsForInitiatorRegistration(initiators, vplexSystem, vplexClusterName, workflow, zoningStepId);
_log.info("processing the export masks to be created");
for (ExportMask exportMask : exportMasksToCreateOnDevice) {
storageViewStepId = addStepsForExportMaskCreate(blockObjectMap, workflow, vplexSystem, exportGroup, storageViewStepId, exportMask);
}
_log.info("processing the export masks to be updated");
for (ExportMask exportMask : exportMasksToUpdateOnDevice) {
boolean shared = false;
if (sharedExportMasks.contains(exportMask)) {
shared = true;
}
storageViewStepId = addStepsForExportMaskUpdate(export, blockObjectMap, workflow, vplexSystem, exportMasksToUpdateOnDeviceWithInitiators, exportMasksToUpdateOnDeviceWithStoragePorts, storageViewStepId, exportMask, shared);
}
long elapsed = new Date().getTime() - startAssembly;
_log.info("TIMER: export mask assembly took {} ms", elapsed);
return storageViewStepId;
}
use of com.emc.storageos.db.client.model.ExportGroup 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);
}
}
Aggregations