/* * Copyright (c) 2008-2014 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.smis.ibm.xiv; import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.Calendar; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.cim.CIMArgument; import javax.cim.CIMInstance; import javax.cim.CIMObjectPath; import javax.cim.CIMProperty; import javax.cim.UnsignedInteger32; import javax.wbem.CloseableIterator; import javax.wbem.WBEMException; import javax.wbem.client.WBEMClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.cimadapter.connections.cim.CimConnection; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.model.BlockSnapshot; import com.emc.storageos.db.client.model.StoragePool; import com.emc.storageos.db.client.model.StorageSystem; import com.emc.storageos.db.client.model.StringMap; import com.emc.storageos.db.client.model.Volume; import com.emc.storageos.db.client.util.NullColumnValueGetter; import com.emc.storageos.db.exceptions.DatabaseException; import com.emc.storageos.exceptions.DeviceControllerErrors; import com.emc.storageos.svcs.errorhandling.model.ServiceError; import com.emc.storageos.volumecontroller.impl.ControllerUtils; import com.emc.storageos.volumecontroller.impl.NativeGUIDGenerator; import com.emc.storageos.volumecontroller.impl.block.taskcompleter.BlockSnapshotCreateCompleter; import com.emc.storageos.volumecontroller.impl.block.taskcompleter.CloneCreateCompleter; import com.emc.storageos.volumecontroller.impl.block.taskcompleter.MultiVolumeTaskCompleter; import com.emc.storageos.volumecontroller.impl.block.taskcompleter.VolumeTaskCompleter; import com.emc.storageos.volumecontroller.impl.smis.CIMConnectionFactory; import com.emc.storageos.volumecontroller.impl.smis.CIMPropertyFactory; import com.emc.storageos.volumecontroller.impl.smis.SmisConstants; import com.emc.storageos.volumecontroller.impl.smis.SmisUtils; import com.emc.storageos.volumecontroller.impl.smis.ibm.IBMCIMObjectPathFactory; import com.emc.storageos.volumecontroller.impl.smis.ibm.IBMSmisConstants; /* * Handle SMI-S result. */ public class XIVSmisStorageDevicePostProcessor { private static final Logger _log = LoggerFactory .getLogger(XIVSmisStorageDevicePostProcessor.class); private XIVSmisCommandHelper _helper; private IBMCIMObjectPathFactory _cimPath; private CIMConnectionFactory _cimConnection = null; private DbClient _dbClient = null; public void setCimObjectPathFactory( IBMCIMObjectPathFactory cimObjectPathFactory) { _cimPath = cimObjectPathFactory; } public void setSmisCommandHelper(XIVSmisCommandHelper smisCommandHelper) { _helper = smisCommandHelper; } public void setCimConnectionFactory(CIMConnectionFactory connectionFactory) { _cimConnection = connectionFactory; } public void setDbClient(DbClient dbClient) { _dbClient = dbClient; } /* * (non-Javadoc) Update DB with volume creation output from SMI-S. * * @see * com.emc.storageos.volumecontroller.impl.smis.job.SmisAbstractCreateVolumeJob * #updateStatus */ public Set<URI> processVolumeCreation(StorageSystem storageSystem, URI storagePoolURI, List<Volume> volumes, CIMArgument[] outArgs) throws Exception { Set<URI> volumeURIs = new HashSet<URI>(volumes.size()); StringBuilder logMsgBuilder = new StringBuilder( String.format("Processing volume creation")); CimConnection connection = _cimConnection.getConnection(storageSystem); WBEMClient client = connection.getCimClient(); Calendar now = Calendar.getInstance(); StoragePool storagePool = _dbClient.queryObject(StoragePool.class, storagePoolURI); updateStoragePoolCapacity(client, storagePool); StringMap reservationMap = storagePool.getReservedCapacityMap(); for (Volume volume : volumes) { reservationMap.remove(volume.getId().toString()); } _dbClient.persistObject(storagePool); CIMObjectPath[] elements = (CIMObjectPath[]) _cimPath .getFromOutputArgs(outArgs, IBMSmisConstants.CP_THE_ELEMENTS); UnsignedInteger32[] returnCoedes = (UnsignedInteger32[]) _cimPath .getFromOutputArgs(outArgs, IBMSmisConstants.CP_RETURN_CODES); List<Volume> volumesToSave = new ArrayList<Volume>(elements.length); if (elements != null && returnCoedes != null) { for (int i = 0; i < elements.length; i++) { URI volumeId = volumes.get(i).getId(); Volume volume = _dbClient.queryObject(Volume.class, volumeId); volumesToSave.add(volume); volumeURIs.add(volumeId); boolean isSuccess = false; CIMObjectPath volumePath = elements[i]; if (volumePath != null) { CIMProperty<String> deviceID = (CIMProperty<String>) volumePath .getKey(IBMSmisConstants.CP_DEVICE_ID); if (deviceID != null) { String nativeID = deviceID.getValue(); if ((nativeID != null) && (nativeID.length() != 0)) { isSuccess = true; volume.setPool(storagePoolURI); processVolume(volumePath, nativeID, volume, client, logMsgBuilder, now); } } } if (!isSuccess) { logMsgBuilder.append("\n"); logMsgBuilder.append(String.format( "Failed to create volume: %s with return code: %s", volumeId, returnCoedes[i].toString())); volume.setInactive(true); } } } if (!volumesToSave.isEmpty()) { _dbClient.persistObject(volumesToSave); } _log.info(logMsgBuilder.toString()); return volumeURIs; } /* * (non-Javadoc) Update storage pool capacity. * * totalCapacity - Current total storage capacity held by the pool. * freeCapacity - Total free capacity available for allocating volumes from * the pool. subscribedCapacity - In case of ThinPools, this would indicate * how much real storage is being used by the allocated devices in the pool. * * Note - EMC_VirtualProvisioningPool.EMCSubscribedCapacity - The amount of * storage capacity subscribed by all elements in the storage pool. * * IBMTSDS_VirtualPool.VirtualSpaceConsumed - The consumed amount of raw * storage (in bytes) from the ConsumedVirtualSpace of this StoragePool. * IBMTSDS_VirtualPool.VirtualSpaceReserved - The total amount of raw * storage (in bytes) reserved for Virtual Space on this StoragePool, * corresponding to value of the property 'hard_size_MiB' of XCLI command * pool_list. IBMTSDS_VirtualPool.TotalManagedSpace - The total amount of * virtual capacity (in bytes) managed by this StoragePool, corresponding to * value of property 'soft_size_MiB' of XCLI command pool_list. * IBMTSDS_VirtualPool.RemainingManagedSpace - The remaining amount of * virtual capacity (in bytes) from the TotalManagedSpace of this * StoragePool, corresponding to value of property 'soft_size_MiB.pool_list * - used_by_volumes_MiB - used_by_snapshots_MiB' of XCLI command pool_list. * This represents the amount of space not allocated to any volumes and * snapshots. */ private void updateStoragePoolCapacity(WBEMClient client, StoragePool storagePool) { try { _log.info(String .format("Old storage pool capacity data for pool %s - free capacity: %s; subscribed capacity: %s", storagePool.getNativeId(), storagePool .calculateFreeCapacityWithoutReservations(), storagePool.getSubscribedCapacity())); CIMObjectPath poolPath = _cimPath.getStoragePoolPath(storagePool); CIMInstance poolInstance = client.getInstance(poolPath, true, false, IBMSmisConstants.PS_POOL_CAPACITIES); // get capacity properties and update storage pool Long freePoolCapacity = SmisUtils.getFreeCapacity(poolInstance); storagePool.setFreeCapacity(freePoolCapacity); String subscribedCapacity = SmisUtils.getCIMPropertyValue( poolInstance, IBMSmisConstants.CP_VIRTUAL_SPACE_CONSUMED); if (null != subscribedCapacity) { storagePool.setSubscribedCapacity(ControllerUtils .convertBytesToKBytes(subscribedCapacity)); } _log.info(String .format("New storage pool capacity data for pool %s - free capacity: %s; subscribed capacity: %s", storagePool.getNativeId(), storagePool.getFreeCapacity(), storagePool.getSubscribedCapacity())); _dbClient.persistObject(storagePool); } catch (Exception ex) { _log.error( String.format( "Failed to update capacity of storage pool after volume provisioning operation. Storage pool %s .", storagePool.getNativeId()), ex); } } /* * (non-Javadoc) Processes a newly created volume. * * @param volumePath The CIM object path for the volume. * * @param nativeID The native volume identifier. * * @param volumeId The Bourne volume id. * * @param client The CIM client. * * @param logMsgBuilder Holds a log message. * * @param creationTime Holds the date-time for the volume creation * * @throws java.io.IOException When an error occurs querying the database. * * @throws DatabaseException */ private void processVolume(CIMObjectPath volumePath, String nativeID, Volume volume, WBEMClient client, StringBuilder logMsgBuilder, Calendar creationTime) throws DatabaseException { CIMInstance volumeInstance = null; try { volume.setCreationTime(creationTime); volume.setNativeId(nativeID); volume.setNativeGuid(NativeGUIDGenerator.generateNativeGuid( _dbClient, volume)); volumeInstance = client.getInstance(volumePath, true, false, null); if (volumeInstance != null) { String wwn = CIMPropertyFactory.getPropertyValue( volumeInstance, IBMSmisConstants.CP_NAME); volume.setAlternateName(wwn); volume.setWWN(wwn.toUpperCase()); String elementName = CIMPropertyFactory.getPropertyValue( volumeInstance, IBMSmisConstants.CP_ELEMENT_NAME); // should have already been set outside controller, just to make // sure there is no mismatch volume.setLabel(elementName); volume.setDeviceLabel(elementName); volume.setProvisionedCapacity(getProvisionedCapacityInformation(volumeInstance)); volume.setAllocatedCapacity(getAllocatedCapacityInformation( client, volumeInstance)); volume.setInactive(false); } else { volume.setInactive(true); } } catch (IOException e) { _log.error( "Caught an exception while trying to update volume attributes", e); } catch (WBEMException e) { _log.error( "Caught an exception while trying to update volume attributes", e); } if (logMsgBuilder.length() != 0) { logMsgBuilder.append("\n"); } logMsgBuilder.append(String.format( "Created volume successfully .. NativeId: %s", nativeID)); } /* * (non-Javadoc) Get provisioned capacity. * * @see SmisReplicaCreationJobs#getProvisionedCapacityInformation */ private long getProvisionedCapacityInformation(CIMInstance volumeInstance) { Long provisionedCapacity = 0L; try { if (volumeInstance != null) { CIMProperty consumableBlocks = volumeInstance .getProperty(IBMSmisConstants.CP_CONSUMABLE_BLOCKS); CIMProperty blockSize = volumeInstance .getProperty(IBMSmisConstants.CP_BLOCK_SIZE); // calculate provisionedCapacity = consumableBlocks * block size provisionedCapacity = Long.valueOf(consumableBlocks.getValue() .toString()) * Long.valueOf(blockSize.getValue().toString()); } } catch (Exception e) { _log.error("Updating ProvisionedCapacity failed for Volume {}", volumeInstance.getObjectPath(), e); } return provisionedCapacity; } /* * (non-Javadoc) Get allocated capacity. * * @see SmisReplicaCreationJobs#getAllocatedCapacityInformation */ protected long getAllocatedCapacityInformation(WBEMClient client, CIMInstance volumeInstance) { Long allocatedCapacity = 0L; CloseableIterator<CIMInstance> iterator = null; // TODO - use VirtualSpaceConsumed from SEVolume try { if (volumeInstance != null) { iterator = client.referenceInstances( volumeInstance.getObjectPath(), IBMSmisConstants.CIM_ALLOCATED_FROM_STORAGEPOOL, null, false, IBMSmisConstants.PS_SPACE_CONSUMED); if (iterator.hasNext()) { CIMInstance allocatedFromStoragePoolPath = iterator.next(); CIMProperty spaceConsumed = allocatedFromStoragePoolPath .getProperty(IBMSmisConstants.CP_SPACE_CONSUMED); allocatedCapacity = Long.valueOf(spaceConsumed.getValue() .toString()); } } } catch (Exception e) { _log.error("Updating Allocated Capacity failed for Volume {}", volumeInstance.getObjectPath(), e); } finally { if (iterator != null) { iterator.close(); } } return allocatedCapacity; } /** * Update DB with SMI-S output. */ public void processVolumeExpansion(StorageSystem storageSystem, URI storagePoolURI, URI volumeId, CIMArgument[] outArgs) throws Exception { StringBuilder logMsgBuilder = new StringBuilder( String.format("Processing volume expansion - ")); CimConnection connection = _cimConnection.getConnection(storageSystem); WBEMClient client = connection.getCimClient(); StoragePool storagePool = _dbClient.queryObject(StoragePool.class, storagePoolURI); StringMap reservationMap = storagePool.getReservedCapacityMap(); reservationMap.remove(volumeId.toString()); updateStoragePoolCapacity(client, storagePool); _dbClient.persistObject(storagePool); Volume volume = _dbClient.queryObject(Volume.class, volumeId); CIMObjectPath volumePath = (CIMObjectPath) _cimPath.getFromOutputArgs( outArgs, IBMSmisConstants.CP_THE_ELEMENT); boolean isSuccess = false; if (volumePath != null) { CIMInstance volumeInstance = client.getInstance(volumePath, true, false, null); if (volumeInstance != null) { isSuccess = true; volume.setProvisionedCapacity(getProvisionedCapacityInformation(volumeInstance)); volume.setAllocatedCapacity(getAllocatedCapacityInformation( client, volumeInstance)); _dbClient.persistObject(volume); logMsgBuilder .append(String .format("%n Capacity: %s, Provisioned capacity: %s, Allocated Capacity: %s", volume.getCapacity(), volume.getProvisionedCapacity(), volume.getAllocatedCapacity())); } } if (!isSuccess) { UnsignedInteger32 returnCoede = (UnsignedInteger32) _cimPath .getFromOutputArgs(outArgs, IBMSmisConstants.CP_RETURN_CODE); logMsgBuilder.append("\n"); logMsgBuilder.append(String.format( "Failed to expand volume: %s with return code: %s", volume.getId(), returnCoede.toString())); } _log.info(logMsgBuilder.toString()); } /** * Update DB with SMI-S output, also set task completer status. */ public List<Volume> processVolumeDeletion(StorageSystem storageSystem, List<Volume> volumes, CIMArgument[] outArgs, MultiVolumeTaskCompleter multiVolumeTaskCompleter) throws Exception { CimConnection connection = _cimConnection.getConnection(storageSystem); WBEMClient client = connection.getCimClient(); List<Volume> volumesToProcess = new ArrayList<Volume>(); for (Volume vol : volumes) { Volume volume = _dbClient.queryObject(Volume.class, vol.getId()); volumesToProcess.add(volume); StoragePool storagePool = _dbClient.queryObject(StoragePool.class, volume.getPool()); updateStoragePoolCapacity(client, storagePool); } StringBuilder logMsgBuilder = new StringBuilder(); UnsignedInteger32[] returnCoedes = (UnsignedInteger32[]) _cimPath .getFromOutputArgs(outArgs, IBMSmisConstants.CP_RETURN_CODES); List<Volume> volumesToSave = new ArrayList<Volume>(returnCoedes.length); for (int i = 0; i < returnCoedes.length; i++) { Volume volume = volumesToProcess.get(i); VolumeTaskCompleter deleteTaskCompleter = multiVolumeTaskCompleter .skipTaskCompleter(volume.getId()); if (returnCoedes[i].longValue() == 0L) { volume.setInactive(true); volume.setConsistencyGroup(NullColumnValueGetter.getNullURI()); _dbClient.updateAndReindexObject(volume); deleteTaskCompleter.ready(_dbClient); if (logMsgBuilder.length() != 0) { logMsgBuilder.append("\n"); } logMsgBuilder.append(String.format( "Successfully deleted volume %s", volume.getId())); } else { // cannot delete volume String errorMessage = String .format("Failed to delete volume: %s , nativeId: %s with return code: %s", volume.getId(), volume.getNativeId(), returnCoedes[i].toString()); ServiceError error = DeviceControllerErrors.smis.methodFailed( "doDeleteVolume", errorMessage); deleteTaskCompleter.error(_dbClient, error); if (logMsgBuilder.length() != 0) { logMsgBuilder.append("\n"); } logMsgBuilder.append(errorMessage); } } if (logMsgBuilder.length() > 0) { _log.info(logMsgBuilder.toString()); } return volumesToSave; } @SuppressWarnings("rawtypes") public void processSnapshotCreation(StorageSystem storageSystem, URI snapshotURI, boolean wantSyncActive, CIMArgument[] outArgs, BlockSnapshotCreateCompleter taskCompleter) throws Exception { StringBuilder logMsgBuilder = new StringBuilder( String.format("Processing snapshot creation - ")); CimConnection connection = _cimConnection.getConnection(storageSystem); WBEMClient client = connection.getCimClient(); BlockSnapshot snapshot = _dbClient.queryObject(BlockSnapshot.class, snapshotURI); CIMObjectPath syncVolumePath = (CIMObjectPath) _cimPath .getFromOutputArgs(outArgs, IBMSmisConstants.CP_TARGET_ELEMENT); if (syncVolumePath != null) { // Get the sync volume native device id CIMInstance syncVolume = client.getInstance(syncVolumePath, false, false, null); String syncDeviceID = syncVolumePath .getKey(IBMSmisConstants.CP_DEVICE_ID).getValue() .toString(); String elementName = CIMPropertyFactory.getPropertyValue( syncVolume, IBMSmisConstants.CP_ELEMENT_NAME); String wwn = CIMPropertyFactory.getPropertyValue(syncVolume, IBMSmisConstants.CP_NAME); snapshot.setNativeId(syncDeviceID); snapshot.setNativeGuid(NativeGUIDGenerator.generateNativeGuid( storageSystem, snapshot)); snapshot.setLabel(elementName); snapshot.setDeviceLabel(elementName); snapshot.setInactive(false); snapshot.setIsSyncActive(wantSyncActive); snapshot.setCreationTime(Calendar.getInstance()); snapshot.setWWN(wwn.toUpperCase()); snapshot.setAlternateName(wwn); snapshot.setProvisionedCapacity(getProvisionedCapacityInformation(syncVolume)); snapshot.setAllocatedCapacity(getAllocatedCapacityInformation( client, syncVolume)); logMsgBuilder .append(String .format("For sync volume path %1$s, going to set blocksnapshot %2$s nativeId to %3$s.", syncVolumePath.toString(), snapshot.getId() .toString(), syncDeviceID)); taskCompleter.ready(_dbClient); } else { snapshot.setInactive(true); ServiceError error = DeviceControllerErrors.smis .unableToFindSynchPath(""); logMsgBuilder.append("Failed due to no target element path"); taskCompleter.error(_dbClient, error); } _dbClient.persistObject(snapshot); _log.info(logMsgBuilder.toString()); } @SuppressWarnings("rawtypes") public void processCloneCreation(StorageSystem storageSystem, URI volumeURI, CIMArgument[] outArgs, CloneCreateCompleter taskCompleter) throws Exception { StringBuilder logMsgBuilder = new StringBuilder( String.format("Processing clone creation - ")); CimConnection connection = _cimConnection.getConnection(storageSystem); WBEMClient client = connection.getCimClient(); Volume cloneVolume = _dbClient.queryObject(Volume.class, volumeURI); URI poolURI = cloneVolume.getPool(); StoragePool pool = _dbClient.queryObject(StoragePool.class, poolURI); updateStoragePoolCapacity(client, pool); StringMap reservationMap = pool.getReservedCapacityMap(); // remove from reservation map reservationMap.remove(cloneVolume.getId().toString()); _dbClient.persistObject(pool); CIMObjectPath cloneVolumePath = (CIMObjectPath) _cimPath .getFromOutputArgs(outArgs, IBMSmisConstants.CP_TARGET_ELEMENT); if (cloneVolumePath != null) { // Get the sync volume native device id CIMInstance syncVolume = client.getInstance(cloneVolumePath, false, false, null); String deviceID = cloneVolumePath .getKey(IBMSmisConstants.CP_DEVICE_ID).getValue() .toString(); String elementName = CIMPropertyFactory.getPropertyValue( syncVolume, IBMSmisConstants.CP_ELEMENT_NAME); String wwn = CIMPropertyFactory.getPropertyValue(syncVolume, IBMSmisConstants.CP_NAME); cloneVolume.setNativeId(deviceID); cloneVolume.setNativeGuid(NativeGUIDGenerator.generateNativeGuid( _dbClient, cloneVolume)); cloneVolume.setLabel(elementName); cloneVolume.setDeviceLabel(elementName); cloneVolume.setInactive(false); cloneVolume.setCreationTime(Calendar.getInstance()); cloneVolume.setWWN(wwn.toUpperCase()); cloneVolume.setAlternateName(wwn); cloneVolume .setProvisionedCapacity(getProvisionedCapacityInformation(syncVolume)); cloneVolume.setAllocatedCapacity(getAllocatedCapacityInformation( client, syncVolume)); logMsgBuilder .append(String .format("For sync volume path %1$s, going to set blocksnapshot %2$s nativeId to %3$s.", cloneVolumePath.toString(), cloneVolume .getId().toString(), deviceID)); _dbClient.persistObject(cloneVolume); taskCompleter.ready(_dbClient); } else { cloneVolume.setInactive(true); _dbClient.persistObject(cloneVolume); ServiceError error = DeviceControllerErrors.smis .unableToFindSynchPath(volumeURI.toString()); logMsgBuilder.append(error.getMessage()); _log.error(logMsgBuilder.toString()); throw new Exception(error.getMessage()); } _log.info(logMsgBuilder.toString()); } @SuppressWarnings("rawtypes") public void processCGSnapshotCreation(StorageSystem storageSystem, List<URI> snapshotURIs, boolean wantSyncActive, String snapshotGroupName, BlockSnapshotCreateCompleter taskCompleter) throws Exception { _log.info("Processing CG snapshot creation"); CloseableIterator<CIMObjectPath> volumeIter = null; CimConnection connection = _cimConnection.getConnection(storageSystem); WBEMClient client = connection.getCimClient(); try { List<BlockSnapshot> snapshots = _dbClient.queryObject( BlockSnapshot.class, taskCompleter.getSnapshotURIs()); // Create mapping of volume.nativeDeviceId to BlockSnapshot object Map<String, BlockSnapshot> volumeToSnapMap = new HashMap<String, BlockSnapshot>(); for (BlockSnapshot snapshot : snapshots) { Volume volume = _dbClient.queryObject(Volume.class, snapshot.getParent()); volumeToSnapMap.put(volume.getNativeId(), snapshot); } // Iterate through the snapshot elements and try to match them up // with the appropriate BlockSnapshot // Note, NULL_IBM_CIM_OBJECT_PATH is used here. The snapshot group object will be looked up by snapshot group name List<CIMObjectPath> objectPaths = _helper.getSGMembers(storageSystem, SmisConstants.NULL_IBM_CIM_OBJECT_PATH, snapshotGroupName, snapshotURIs.size()); List<BlockSnapshot> objectsToSave = new ArrayList<BlockSnapshot>( snapshotURIs.size()); Calendar now = Calendar.getInstance(); for (CIMObjectPath syncVolumePath : objectPaths) { CIMInstance syncVolume = client.getInstance(syncVolumePath, false, false, null); String syncDeviceID = syncVolumePath .getKey(IBMSmisConstants.CP_DEVICE_ID).getValue() .toString(); String elementName = CIMPropertyFactory.getPropertyValue( syncVolume, IBMSmisConstants.CP_ELEMENT_NAME); // Get the associated volume for this sync volume CIMObjectPath volumePath = null; volumeIter = client.associatorNames(syncVolumePath, null, IBMSmisConstants.CIM_STORAGE_VOLUME, null, null); volumePath = volumeIter.next(); if (_log.isDebugEnabled()) { _log.debug("volumePath - " + volumePath); } volumeIter.close(); String volumeDeviceID = volumePath .getKey(IBMSmisConstants.CP_DEVICE_ID).getValue() .toString(); String wwn = CIMPropertyFactory.getPropertyValue(syncVolume, IBMSmisConstants.CP_NAME); String alternativeName = wwn; // Lookup the associated snapshot based on the volume native // device id BlockSnapshot snapshot = volumeToSnapMap.get(volumeDeviceID); if (snapshot != null) { snapshot.setNativeId(syncDeviceID); snapshot.setNativeGuid(NativeGUIDGenerator .generateNativeGuid(storageSystem, snapshot)); snapshot.setReplicationGroupInstance(snapshotGroupName); snapshot.setLabel(elementName); snapshot.setDeviceLabel(elementName); snapshot.setInactive(false); snapshot.setIsSyncActive(wantSyncActive); snapshot.setCreationTime(now); snapshot.setWWN(wwn.toUpperCase()); snapshot.setAlternateName(alternativeName); snapshot.setProvisionedCapacity(getProvisionedCapacityInformation(syncVolume)); snapshot.setAllocatedCapacity(getAllocatedCapacityInformation( client, syncVolume)); _log.info(String .format("For sync volume path %1$s, going to set blocksnapshot %2$s nativeId to %3$s (%4$s). " + "Replication Group instance is %5$s. Associated volume is %6$s", syncVolumePath.toString(), snapshot.getId() .toString(), syncDeviceID, elementName, snapshotGroupName, volumePath.toString())); objectsToSave.add(snapshot); } } if (!objectsToSave.isEmpty()) { _dbClient.persistObject(objectsToSave); taskCompleter.ready(_dbClient); } else { _log.info("Failed to create snapshot"); for (BlockSnapshot snapshot : snapshots) { snapshot.setInactive(true); } _dbClient.persistObject(snapshots); ServiceError error = DeviceControllerErrors.smis .noBlockSnapshotsFound(); taskCompleter.error(_dbClient, error); } } catch (Exception e) { _log.error( "Caught an exception while trying to process CG snapshotCreation", e); throw e; } finally { if (volumeIter != null) { volumeIter.close(); } } } }