use of com.emc.storageos.volumecontroller.impl.smis.SmisException in project coprhd-controller by CoprHD.
the class VmaxSnapshotOperations method createGroupSnapshots.
/**
* Should implement create of a snapshot from a source volume that is part of a
* consistency group.
*
* Implementation note: In this method we will kick of the asynchronous creation
* of the target devices required for the CG snaps. Upon the successful
* device creation, the post operations will take place, which will include the
* creation of the target group and the group snapshot operation.
*
* @param storage [required] - StorageSystem object representing the array
* @param snapshotList [required] - BlockSnapshot URI list representing the previously created
* snap for the volume
* @param createInactive whether the snapshot needs to to be created with sync_active=true/false
* @param readOnly - Indicates if the snapshot should be read only.
* @param taskCompleter - TaskCompleter object used for the updating operation status.
* @throws DeviceControllerException
*/
@Override
public void createGroupSnapshots(StorageSystem storage, List<URI> snapshotList, Boolean createInactive, Boolean readOnly, TaskCompleter taskCompleter) throws DeviceControllerException {
_log.info("START createGroupSnapshots");
// Target group CIM Path
CIMObjectPath targetGroupPath = null;
// List of target device ids
List<String> targetDeviceIds = null;
// The source consistency group name
String sourceGroupName = null;
try {
final BlockSnapshot first = _dbClient.queryObject(BlockSnapshot.class, snapshotList.get(0));
sourceGroupName = ConsistencyGroupUtils.getSourceConsistencyGroupName(first, _dbClient);
Volume snapVolume = _dbClient.queryObject(Volume.class, first.getParent());
boolean thinProvisioning = snapVolume.getThinlyProvisioned() != null && snapVolume.getThinlyProvisioned();
TenantOrg tenant = _dbClient.queryObject(TenantOrg.class, snapVolume.getTenant().getURI());
String tenantName = tenant.getLabel();
final String snapLabelToUse = _nameGenerator.generate(tenantName, first.getLabel(), snapshotList.get(0).toString(), '-', storage.getUsingSmis80() ? SmisConstants.MAX_SMI80_SNAPSHOT_NAME_LENGTH : SmisConstants.MAX_SNAPSHOT_NAME_LENGTH);
// CTRL-5640: ReplicationGroup may not be accessible after provider fail-over.
ReplicationUtils.checkReplicationGroupAccessibleOrFail(storage, first, _dbClient, _helper, _cimPath);
final Map<String, List<Volume>> volumesBySizeMap = new HashMap<String, List<Volume>>();
// Group volumes by pool and size
for (URI uri : snapshotList) {
final BlockSnapshot snapshot = _dbClient.queryObject(BlockSnapshot.class, uri);
final Volume volume = _dbClient.queryObject(Volume.class, snapshot.getParent().getURI());
final String key = volume.getPool() + "-" + volume.getCapacity();
final List<Volume> currentVolumes = volumesBySizeMap.containsKey(key) ? volumesBySizeMap.get(key) : new ArrayList<Volume>();
currentVolumes.add(volume);
volumesBySizeMap.put(key, currentVolumes);
}
// For VMAX3, we need the target group to tag the setting instance
if (storage.checkIfVmax3() || !storage.getUsingSmis80()) {
targetDeviceIds = new ArrayList<String>();
for (Entry<String, List<Volume>> entry : volumesBySizeMap.entrySet()) {
final List<Volume> volumes = entry.getValue();
final Volume volume = volumes.get(0);
final URI poolId = volume.getPool();
CIMObjectPath volumeGroupPath = _helper.getVolumeGroupPath(storage, storage, volume, null);
// Create target devices based on the array model
final List<String> newDeviceIds = kickOffTargetDevicesCreation(storage, volumeGroupPath, sourceGroupName, snapLabelToUse, createInactive, thinProvisioning, volumes.size(), poolId, volume.getCapacity(), taskCompleter);
targetDeviceIds.addAll(newDeviceIds);
}
// Create target device group
targetGroupPath = ReplicationUtils.createTargetDeviceGroup(storage, sourceGroupName, targetDeviceIds, taskCompleter, _dbClient, _helper, _cimPath, SYNC_TYPE.SNAPSHOT);
}
// Create CG snapshot
CIMObjectPath job = VmaxGroupOperationsUtils.internalCreateGroupReplica(storage, sourceGroupName, snapLabelToUse, targetGroupPath, createInactive, thinProvisioning, taskCompleter, SYNC_TYPE.SNAPSHOT, _dbClient, _helper, _cimPath);
if (job != null) {
ControllerServiceImpl.enqueueJob(new QueueJob(new SmisBlockCreateCGSnapshotJob(job, storage.getId(), !createInactive, sourceGroupName, taskCompleter)));
}
} catch (Exception e) {
final String errMsg = format("An exception occurred when trying to create snapshots for consistency group {0} on storage system {1}", sourceGroupName, storage.getId());
_log.error(errMsg, e);
ServiceError error = DeviceControllerErrors.smis.methodFailed("createGroupSnapshots", e.getMessage());
taskCompleter.error(_dbClient, error);
// Roll back changes
rollbackCreateSnapshot(storage, targetGroupPath, targetDeviceIds, taskCompleter);
throw new SmisException(errMsg, e);
}
}
use of com.emc.storageos.volumecontroller.impl.smis.SmisException in project coprhd-controller by CoprHD.
the class XIVCloneOperations method createSingleClone.
@SuppressWarnings("rawtypes")
@Override
public void createSingleClone(StorageSystem storageSystem, URI sourceVolume, URI cloneVolume, Boolean createInactive, TaskCompleter taskCompleter) {
_log.info("START createSingleClone operation");
SmisException serviceCode = null;
CIMArgument[] outArgs = new CIMArgument[5];
try {
BlockObject sourceObj = BlockObject.fetch(_dbClient, sourceVolume);
URI tenantUri = null;
if (sourceObj instanceof BlockSnapshot) {
// In case of snapshot, get the tenant from its parent volume
NamedURI parentVolUri = ((BlockSnapshot) sourceObj).getParent();
Volume parentVolume = _dbClient.queryObject(Volume.class, parentVolUri);
tenantUri = parentVolume.getTenant().getURI();
} else {
tenantUri = ((Volume) sourceObj).getTenant().getURI();
}
Volume cloneObj = _dbClient.queryObject(Volume.class, cloneVolume);
StoragePool targetPool = _dbClient.queryObject(StoragePool.class, cloneObj.getPool());
TenantOrg tenantOrg = _dbClient.queryObject(TenantOrg.class, tenantUri);
String cloneLabel = _nameGenerator.generate(tenantOrg.getLabel(), cloneObj.getLabel(), cloneObj.getId().toString(), '-', SmisConstants.MAX_VOLUME_NAME_LENGTH);
CIMObjectPath sourceVolumePath = _cimPath.getBlockObjectPath(storageSystem, sourceObj);
CIMArgument[] inArgs = _helper.getCloneInputArguments(cloneLabel, sourceVolumePath, storageSystem, targetPool, createInactive);
_helper.callReplicationSvc(storageSystem, SmisConstants.CREATE_ELEMENT_REPLICA, inArgs, outArgs);
} catch (Exception e) {
String errorMsg = String.format(CREATE_ERROR_MSG_FORMAT, sourceVolume, cloneVolume);
_log.error(errorMsg, e);
serviceCode = DeviceControllerExceptions.smis.createFullCopyFailure(errorMsg, e);
} finally {
try {
// update clone and pool
// clone will be set to inactive if no return from provider
_smisStorageDevicePostProcessor.processCloneCreation(storageSystem, cloneVolume, outArgs, (CloneCreateCompleter) taskCompleter);
} catch (Exception e) {
String errorMsg = "Exception on creating clone of " + sourceVolume;
_log.error(errorMsg, e);
// set serviceCode only if no previous exception
if (serviceCode == null) {
serviceCode = DeviceControllerExceptions.smis.createFullCopyFailure(errorMsg, e);
}
}
if (serviceCode != null) {
taskCompleter.error(_dbClient, serviceCode);
throw serviceCode;
}
}
}
use of com.emc.storageos.volumecontroller.impl.smis.SmisException in project coprhd-controller by CoprHD.
the class VmaxSnapshotOperations method createTargetDevices.
/**
* Method will invoke the SMI-S operation to create 'count' number of VDEVs of the
* specified capacity.
*
* If any errors, taskCompleter will be updated.
*
* Note; This method will kick off of an asynchronous job. The SmisCreateVmaxCGTargetVolumesJob
* encapsulates this. When the task completes successfully, it will continue the
* work of completing the snapshot operation.
*
* @param storage - StorageSystem where VDEVs will be created
* @param poolPath - CIMObject representing the pool to allocate targets from
* @param storageSetting - Setting that allows for VDEV creation
* @param label - Name to appl to each VDEV
* @param createInactive - whether the snapshot needs to to be created with sync_active=true/false
* @param count - Number of VDEVs
* @param capacity - Size of each VDEV
* @param taskCompleter - Completer object used for task status update
* @throws DeviceControllerException
*
* @return - List of native Ids
*/
private List<String> createTargetDevices(StorageSystem storage, CIMObjectPath poolPath, CIMObjectPath volumeGroupPath, CIMInstance storageSetting, String sourceGroupName, String label, Boolean createInactive, int count, long capacity, TaskCompleter taskCompleter) throws DeviceControllerException {
_log.info(format("Creating target devices: Storage System: {0}, Consistency Group: {1}, Pool: {2}, Count: {3}", storage.getId(), sourceGroupName, poolPath, count));
try {
CIMObjectPath configSvcPath = _cimPath.getConfigSvcPath(storage);
CIMArgument[] inArgs = null;
if (storage.checkIfVmax3()) {
inArgs = _helper.getCreateVolumesBasedOnVolumeGroupInputArguments(storage, poolPath, volumeGroupPath, label, count, capacity);
} else {
inArgs = _helper.getCreateVolumesBasedOnSettingInputArguments(storage, poolPath, storageSetting, label, count, capacity);
}
CIMArgument[] outArgs = new CIMArgument[5];
SmisCreateVmaxCGTargetVolumesJob job = new SmisCreateVmaxCGTargetVolumesJob(null, storage.getId(), sourceGroupName, label, createInactive, taskCompleter);
_helper.invokeMethodSynchronously(storage, configSvcPath, _helper.createVolumesMethodName(storage), inArgs, outArgs, job);
return job.getTargetDeviceIds();
} catch (Exception e) {
final String errMsg = format("An error occurred when creating target devices on storage system {0}", storage.getId());
_log.error(errMsg, e);
taskCompleter.error(_dbClient, SmisException.errors.methodFailed(_helper.createVolumesMethodName(storage), e.getMessage()));
throw new SmisException(errMsg, e);
}
}
use of com.emc.storageos.volumecontroller.impl.smis.SmisException in project coprhd-controller by CoprHD.
the class VmaxExportOperations method removeVolumes.
@Override
public void removeVolumes(StorageSystem storage, URI exportMaskURI, List<URI> volumeURIList, List<Initiator> initiatorList, TaskCompleter taskCompleter) throws DeviceControllerException {
_log.info("{} removeVolumes START...", storage.getSerialNumber());
try {
_log.info("removeVolumes: Export mask id: {}", exportMaskURI);
_log.info("removeVolumes: volumes: {}", Joiner.on(',').join(volumeURIList));
if (initiatorList != null) {
_log.info("removeVolumes: impacted initiators: {}", Joiner.on(",").join(initiatorList));
}
List<? extends BlockObject> blockObjects = BlockObject.fetchAll(_dbClient, volumeURIList);
ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
boolean isRollback = WorkflowService.getInstance().isStepInRollbackState(taskCompleter.getOpId());
ExportMaskValidationContext ctx = new ExportMaskValidationContext();
ctx.setStorage(storage);
ctx.setExportMask(exportMask);
ctx.setBlockObjects(blockObjects);
ctx.setInitiators(initiatorList);
// Allow exceptions to be thrown when not rolling back
ctx.setAllowExceptions(!isRollback);
validator.removeVolumes(ctx).validate();
boolean isVmax3 = storage.checkIfVmax3();
WBEMClient client = _helper.getConnection(storage).getCimClient();
if (isRollback) {
// Get the context from the task completer for this rollback step. The stepId in this case
// will correspond to the rollback step and not the primary execution step. We don't know
// the rollback stepId until execution time, therefore there will be no step data in the
// database corresponding to this stepId. The underlying call to loadStepData will take care
// of finding the founding step (execution) step for this rollback stepId, from which the
// step data can be found.
ExportOperationContext context = (ExportOperationContext) WorkflowService.getInstance().loadStepData(taskCompleter.getOpId());
exportMaskRollback(storage, context, taskCompleter);
taskCompleter.ready(_dbClient);
return;
} else {
String maskingViewName = _helper.getExportMaskName(exportMaskURI);
// Always get the Storage Group from masking View, rather than depending on the name to find out SG.
String parentGroupName = _helper.getStorageGroupForGivenMaskingView(maskingViewName, storage);
// Storage Group does not exist, no operation on array side
if (null == parentGroupName) {
taskCompleter.ready(_dbClient);
return;
}
Map<String, List<URI>> volumesByGroup = _helper.groupVolumesBasedOnExistingGroups(storage, parentGroupName, volumeURIList);
_log.info("Group Volumes by Storage Group size : {}", volumesByGroup.size());
if (volumesByGroup.size() == 0) {
_log.info("Could not find any groups to which the volumes to remove belong.");
taskCompleter.ready(_dbClient);
return;
}
/**
* For each child Group bucket, remove the volumes from those bucket
*/
for (Entry<String, List<URI>> volumeByGroupEntry : volumesByGroup.entrySet()) {
String childGroupName = volumeByGroupEntry.getKey();
volumeURIList = volumeByGroupEntry.getValue();
_log.info("Processing Group {} with volumes {}", childGroupName, Joiner.on("\t").join(volumeURIList));
/**
* Empty child Storage Groups cannot be associated with Fast Policy.
* hence, verify if storage group size is > 1, if not, then remove the
* child group from Fast Policy, and then proceed with removing the volume from group
*/
if (volumesByGroup.get(childGroupName) != null && volumesByGroup.get(childGroupName).size() == volumeURIList.size() && !_helper.isStorageGroupSizeGreaterThanGivenVolumes(childGroupName, storage, volumeURIList.size())) {
_log.info("Storage Group has no more than {} volumes", volumeURIList.size());
URI blockURI = volumeURIList.get(0);
BlockObject blockObj = BlockObject.fetch(_dbClient, blockURI);
CIMObjectPath maskingGroupPath = _cimPath.getMaskingGroupPath(storage, childGroupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup);
String policyName = ControllerUtils.getAutoTieringPolicyName(blockObj.getId(), _dbClient);
if (!isVmax3 && !Constants.NONE.equalsIgnoreCase(policyName)) {
_log.info("Storage Group contains only 1 volume, hence this group will be disassociated from fast, as fast cannot be applied to empty group {}", childGroupName);
_helper.removeVolumeGroupFromPolicyAndLimitsAssociation(client, storage, maskingGroupPath);
}
}
Set<String> volumeDeviceIds = new HashSet<String>();
// Flag to indicate whether or not we need to use the EMCForce flag on this operation.
// We currently use this flag when dealing with RP Volumes as they are tagged for RP and the
// operation on these volumes would fail otherwise.
boolean forceFlag = false;
for (URI volURI : volumeURIList) {
BlockObject bo = Volume.fetchExportMaskBlockObject(_dbClient, volURI);
volumeDeviceIds.add(bo.getNativeId());
// The force flag only needs to be set once
if (!forceFlag) {
forceFlag = ExportUtils.useEMCForceFlag(_dbClient, volURI);
}
}
List<CIMObjectPath> volumePaths = new ArrayList<CIMObjectPath>();
// Determine if the volumes are associated with any phantom storage groups.
// If so, we need to remove volumes from those storage groups and potentially remove them.
removeVolumesFromPhantomStorageGroup(storage, client, exportMaskURI, volumeURIList, childGroupName, forceFlag);
// Create a relatively empty completer associated with the export mask. We don't have the export
// group
// at this level, so there's nothing decent to attach the completer to anyway.
String task = UUID.randomUUID().toString();
ExportMaskVolumeToStorageGroupCompleter completer = new ExportMaskVolumeToStorageGroupCompleter(null, exportMaskURI, task);
List<URI> volumesInSG = _helper.findVolumesInStorageGroup(storage, childGroupName, volumeURIList);
if (volumesInSG != null && !volumesInSG.isEmpty()) {
CIMArgument[] inArgs = _helper.getRemoveVolumesFromMaskingGroupInputArguments(storage, childGroupName, volumesInSG, forceFlag);
CIMArgument[] outArgs = new CIMArgument[5];
// If any of the volumes being removed are tied to RecoverPoint, we need to be aware that there
// might be some lag in terminating the remote copy session between VMAX and RP. So we need to
// catch a specific exception in this case and wait/retry.
boolean containsRPVolume = false;
// RecoverPoint related.
for (URI boUri : volumesInSG) {
if (URIUtil.isType(boUri, Volume.class)) {
Volume volume = _dbClient.queryObject(Volume.class, boUri);
if (volume != null && (volume.checkForRp() || RPHelper.isAssociatedToAnyRpVplexTypes(volume, _dbClient))) {
// Determined that the volume is RP related
containsRPVolume = true;
break;
}
}
}
// Initialize the retry/attempt variables
int attempt = 0;
int retries = 1;
if (containsRPVolume) {
// If we are dealing with an RP volume, we need to set the retry count appropriately
retries = MAX_RP_RETRIES;
}
while (attempt++ <= retries) {
try {
_helper.invokeMethodSynchronously(storage, _cimPath.getControllerConfigSvcPath(storage), "RemoveMembers", inArgs, outArgs, new SmisMaskingViewRemoveVolumeJob(null, storage.getId(), volumePaths, parentGroupName, childGroupName, _cimPath, completer));
// If the invoke succeeds without exception, break out of the retry loop.
break;
} catch (SmisException se) {
if (attempt != retries && containsRPVolume && se.getMessage().contains(COPY_SESSION_ERROR)) {
// There is some delay in terminating the remote copy session between VMAX and
// RecoverPoint
// so we need to wait and retry.
_log.warn(String.format("Encountered exception during attempt %s/%s to remove volumes %s from export group. Waiting %s milliseconds before trying again. Error: %s", attempt, MAX_RP_RETRIES, volumesInSG.toString(), RP_WAIT_FOR_RETRY, se.getMessage()));
try {
Thread.sleep(RP_WAIT_FOR_RETRY);
} catch (InterruptedException e1) {
Thread.currentThread().interrupt();
}
} else {
// This is not RP related so just re-throw the exception instead of retrying.
throw se;
}
}
}
if (isVmax3) {
// we need to add volumes to parking storage group
URI blockObjectURI = volumeURIList.get(0);
String policyName = _helper.getVMAX3FastSettingForVolume(blockObjectURI, null);
addVolumesToParkingStorageGroup(storage, policyName, volumeDeviceIds);
}
} else {
completer.ready(_dbClient);
}
}
taskCompleter.ready(_dbClient);
}
} catch (Exception e) {
_log.error(String.format("removeVolumes failed - maskName: %s", exportMaskURI.toString()), e);
ServiceError serviceError = null;
if (null != e.getMessage() && e.getMessage().contains("FAST association cannot have an empty storage group")) {
serviceError = DeviceControllerException.errors.concurrentRemoveFromSGCausesEmptySG(e);
} else {
serviceError = DeviceControllerException.errors.jobFailed(e);
}
taskCompleter.error(_dbClient, serviceError);
}
_log.info("{} removeVolumes END...", storage.getSerialNumber());
}
use of com.emc.storageos.volumecontroller.impl.smis.SmisException in project coprhd-controller by CoprHD.
the class VmaxGroupOperationsUtils method internalCreateGroupReplica.
public static CIMObjectPath internalCreateGroupReplica(StorageSystem storage, String groupName, String replicaLabel, CIMObjectPath targetGroupPath, boolean createInactive, boolean thinProvisioning, TaskCompleter taskCompleter, SYNC_TYPE syncType, DbClient dbClient, SmisCommandHelper helper, CIMObjectPathFactory cimPath) throws DeviceControllerException {
CIMObjectPath job = null;
try {
CIMObjectPath cgPath = cimPath.getReplicationGroupPath(storage, groupName);
CIMObjectPath replicationSvc = cimPath.getControllerReplicationSvcPath(storage);
CIMInstance replicaSettingData = null;
CIMObjectPath targetPoolPath = null;
if (syncType == SYNC_TYPE.CLONE && storage.checkIfVmax3() && ControllerUtils.isVmaxUsing81SMIS(storage, dbClient)) {
/**
* VMAX3 using SMI 8.1 provider needs to send DesiredCopyMethodology=32770
* to create TimeFinder differential clone.
*/
replicaSettingData = ReplicationUtils.getReplicationSettingForSMIS81TFGroupClones(storage, helper, cimPath, createInactive);
} else if (storage.checkIfVmax3() && syncType != SYNC_TYPE.MIRROR) {
String instanceId = targetGroupPath.getKey(SmisConstants.CP_INSTANCE_ID).getValue().toString();
replicaLabel = SmisUtils.getTargetGroupName(instanceId, storage.getUsingSmis80());
// Unlike single volume snapshot where snapSettingName is used in SMI-S as StorageSynchronized.EMCRelationshipName,
// for group snapshot, GroupSynchronized.RelationshipName is set via RelationshipName input argument of CreateGroupReplica
// method.
// Using replicaLabel in the call below is not necessary, just for convenience.
// But it has to be used in the getCreateGroupReplicaInputArgumentsForVMAX below.
replicaSettingData = helper.getReplicationSettingData(storage, replicaLabel, true);
} else if (syncType == SYNC_TYPE.CLONE) {
replicaSettingData = ReplicationUtils.getReplicationSettingForGroupClones(storage, helper, cimPath, createInactive);
} else if (syncType == SYNC_TYPE.MIRROR) {
replicaSettingData = ReplicationUtils.getReplicationSettingForGroupMirrors(storage, helper, cimPath);
} else {
replicaSettingData = ReplicationUtils.getReplicationSettingForGroupSnapshots(storage, helper, cimPath, thinProvisioning);
targetPoolPath = ReplicationUtils.getTargetPoolForVPSnapCreation(storage, groupName, null, thinProvisioning, dbClient, helper, cimPath);
}
CIMArgument[] inArgs = helper.getCreateGroupReplicaInputArgumentsForVMAX(storage, cgPath, createInactive, replicaLabel, targetGroupPath, targetPoolPath, replicaSettingData, syncType);
CIMArgument[] outArgs = new CIMArgument[5];
helper.invokeMethod(storage, replicationSvc, CREATE_GROUP_REPLICA, inArgs, outArgs);
job = cimPath.getCimObjectPathFromOutputArgs(outArgs, JOB);
} catch (Exception e) {
_log.info("Problem making SMI-S call: ", e);
// setInactive(((BlockSnapshotCreateCompleter)taskCompleter).getSnapshotURIs(), true);
taskCompleter.error(dbClient, SmisException.errors.methodFailed(CREATE_GROUP_REPLICA, e.getMessage()));
throw new SmisException("Error when creating group replica", e);
}
return job;
}
Aggregations