/*
* Copyright (c) 2008-2013 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.impl.smis.job;
import java.net.URI;
import java.util.List;
import javax.cim.CIMInstance;
import javax.cim.CIMObjectPath;
import javax.cim.CIMProperty;
import javax.wbem.CloseableIterator;
import javax.wbem.client.WBEMClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.URIUtil;
import com.emc.storageos.db.client.constraint.ContainmentConstraint;
import com.emc.storageos.db.client.model.BlockObject;
import com.emc.storageos.db.client.model.BlockSnapshot;
import com.emc.storageos.db.client.model.BlockSnapshotSession;
import com.emc.storageos.db.client.model.StorageSystem;
import com.emc.storageos.db.client.model.StringSet;
import com.emc.storageos.db.client.util.CustomQueryUtility;
import com.emc.storageos.db.client.util.NullColumnValueGetter;
import com.emc.storageos.volumecontroller.TaskCompleter;
import com.emc.storageos.volumecontroller.impl.smis.SmisConstants;
import com.emc.storageos.volumecontroller.impl.smis.SmisUtils;
public class SmisSnapShotJob extends SmisJob {
private static final Logger _log = LoggerFactory.getLogger(SmisSnapShotJob.class);
public SmisSnapShotJob(CIMObjectPath cimJob, URI storageSystem,
TaskCompleter taskCompleter, String jobName) {
super(cimJob, storageSystem, taskCompleter, jobName);
}
/**
* This method updates provisioned capacity and allocated capacity for snapshots.
* It also set settingsInstance for VMAX V3 snapshot.
*
* @param snapShot A reference to the snapshot to be updated.
* @param syncVolume A reference to the CIM instance representing the snapshot target volume.
* @param client A reference to a WBEM client.
* @param storage A reference to the storage system.
* @param sourceElementId String of source volume (or source group) ID
* @param elementName String used as ElementName when creating ReplicationSettingData during single snapshot creation,
* or RelationshipName used in CreateGroupReplica for group snapshot. Note elementName should be target device's DeviceID
* or target group ID.
* @param createSession true if a BlockSnapshotSession should be created to represent the settings instance.
* @param dbClient A reference to a database client.
*/
protected void commonSnapshotUpdate(
BlockSnapshot snapShot, CIMInstance syncVolume, WBEMClient client, StorageSystem storage, String sourceElementId,
String elementName, boolean createSession, DbClient dbClient) {
try {
CIMProperty consumableBlocks = syncVolume
.getProperty(SmisConstants.CP_CONSUMABLE_BLOCKS);
CIMProperty blockSize = syncVolume.getProperty(SmisConstants.CP_BLOCK_SIZE);
// calculate provisionedCapacity = consumableBlocks * block size
Long provisionedCapacity = Long.valueOf(consumableBlocks.getValue()
.toString()) * Long.valueOf(blockSize.getValue().toString());
snapShot.setProvisionedCapacity(provisionedCapacity);
// set Allocated Capacity
CloseableIterator<CIMInstance> iterator = null;
iterator = client.referenceInstances(syncVolume.getObjectPath(),
SmisConstants.CIM_ALLOCATED_FROM_STORAGEPOOL, null, false,
SmisConstants.PS_SPACE_CONSUMED);
if (iterator.hasNext()) {
CIMInstance allocatedFromStoragePoolPath = iterator.next();
CIMProperty spaceConsumed = allocatedFromStoragePoolPath
.getProperty(SmisConstants.CP_SPACE_CONSUMED);
if (null != spaceConsumed) {
snapShot.setAllocatedCapacity(Long.valueOf(spaceConsumed.getValue()
.toString()));
}
}
// set settingsInstance for VMAX V3 only
setSettingsInstance(storage, snapShot, sourceElementId, elementName, createSession, dbClient);
} catch (Exception e) {
// Don't want to fail the snapshot creation, if capacity retrieval fails, as auto discovery cycle
// will take care of updating capacity informations later.
_log.error(
"Caught an exception while trying to update Capacity and SettingsInstance for Snapshots",
e);
}
}
/**
* Set settings instance for VMAX V3 only. If the flag so indicates, this function
* will also create a snapshot session to represent this settings instance, which is
* the CIM instance ID for a synchronization aspect. The session needs to be created
* for legacy code that created VMAX3 BlockSnapshots w/o representing the snapshot session.
*
* @param storage storage A reference to the storage system.
* @param snapshot BlockSnapshot to be updated
* @param sourceElementId String of source volume (or source group) ID
* @param elementName String used as ElementName when creating ReplicationSettingData during single snapshot creation,
* or RelationshipName used in CreateGroupReplica for group snapshot. Note elementName should be target device's DeviceID
* or target group ID.
* @param createSession true if a BlockSnapshotSession should be created to represent the settings instance.
* @param dbClient A reference to a database client.
*
*/
private void setSettingsInstance(StorageSystem storage, BlockSnapshot snapshot, String sourceElementId, String elementName,
boolean createSession, DbClient dbClient) {
if ((storage.checkIfVmax3()) && (createSession)) {
setSettingsInstance(storage, snapshot, sourceElementId, elementName);
// If the flag so indicates create a BlockSnapshotSession instance to represent this
// settings instance.
BlockSnapshotSession snapSession = getSnapshotSession(snapshot, dbClient);
if (snapSession.getId() == null) {
snapSession.setId(URIUtil.createId(BlockSnapshotSession.class));
snapSession.setLabel(snapshot.getLabel());
snapSession.setSessionLabel(SmisUtils.getSessionLabelFromSettingsInstance(snapshot));
snapSession.setSessionInstance(snapshot.getSettingsInstance());
snapSession.setProject(snapshot.getProject());
snapSession.setStorageController(storage.getId());
setParentOrConsistencyGroupAssociation(snapSession, snapshot, dbClient);
}
addSnapshotAsLinkedTarget(snapSession, snapshot);
createOrUpdateSession(snapSession, dbClient);
}
}
private BlockSnapshotSession getSnapshotSession(BlockSnapshot snapshot, DbClient dbClient) {
BlockSnapshotSession result = null;
if (snapshot.hasConsistencyGroup()) {
List<BlockSnapshotSession> groupSnapSessions = CustomQueryUtility.queryActiveResourcesByConstraint(dbClient,
BlockSnapshotSession.class,
ContainmentConstraint.Factory.getBlockSnapshotSessionByConsistencyGroup(snapshot.getConsistencyGroup()));
if (!groupSnapSessions.isEmpty()) {
for (BlockSnapshotSession groupSnapSession : groupSnapSessions) {
// When creating a group snapshot with multiple targets, we might
// have already created the BlockSnapshotSession instance to represent
// the group session. So, if we find a snapshot session for the
// group that has the same session instance paths as the passed snapshot,
// then we just return that session as we already created it when another
// snapshot in the group was processed.
String sessionInstance = groupSnapSession.getSessionInstance();
if ((NullColumnValueGetter.isNotNullValue(sessionInstance)) &&
(sessionInstance.equals(snapshot.getSettingsInstance()))) {
result = groupSnapSession;
break;
}
}
}
}
if (result == null) {
result = new BlockSnapshotSession();
}
return result;
}
private void setParentOrConsistencyGroupAssociation(BlockSnapshotSession session, BlockSnapshot snapshot, DbClient dbClient) {
if (snapshot.hasConsistencyGroup() && NullColumnValueGetter.isNotNullValue(snapshot.getReplicationGroupInstance())) {
session.setConsistencyGroup(snapshot.getConsistencyGroup());
BlockObject parent = BlockObject.fetch(dbClient, snapshot.getParent().getURI());
if (parent != null) {
session.setReplicationGroupInstance(parent.getReplicationGroupInstance());
session.setSessionSetName(parent.getReplicationGroupInstance());
}
} else {
session.setParent(snapshot.getParent());
}
}
private void addSnapshotAsLinkedTarget(BlockSnapshotSession session, BlockSnapshot snapshot) {
if (session.getLinkedTargets() == null) {
session.setLinkedTargets(new StringSet());
}
session.getLinkedTargets().add(snapshot.getId().toString());
}
private void createOrUpdateSession(BlockSnapshotSession session, DbClient dbClient) {
if (session.getCreationTime() == null) {
dbClient.createObject(session);
} else {
dbClient.updateObject(session);
}
}
private void setSettingsInstance(StorageSystem storage,
BlockSnapshot snapshot, String sourceElementId, String elementName) {
String instance = SmisUtils.generateVmax3SettingsInstance(storage, sourceElementId, elementName);
snapshot.setSettingsInstance(instance);
}
}