/* * Copyright (c) 2012 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.smis.job; import java.net.URI; import java.util.Calendar; import java.util.HashMap; import java.util.List; import java.util.Map; 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.model.BlockSnapshot; import com.emc.storageos.db.client.model.StorageSystem; import com.emc.storageos.db.client.model.Volume; import com.emc.storageos.volumecontroller.JobContext; import com.emc.storageos.volumecontroller.TaskCompleter; import com.emc.storageos.volumecontroller.impl.NativeGUIDGenerator; import com.emc.storageos.volumecontroller.impl.block.taskcompleter.BlockSnapshotCreateCompleter; 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; public class SmisBlockCreateCGSnapshotJob extends SmisSnapShotJob { private static final Logger _log = LoggerFactory.getLogger(SmisBlockCreateCGSnapshotJob.class); private final Boolean _wantSyncActive; private final String _sourceGroupId; public SmisBlockCreateCGSnapshotJob(CIMObjectPath cimJob, URI storageSystem, boolean wantSyncActive, String sourceGroupId, TaskCompleter taskCompleter) { super(cimJob, storageSystem, taskCompleter, "CreateBlockCGSnapshot"); _wantSyncActive = wantSyncActive; _sourceGroupId = sourceGroupId; } @Override public void updateStatus(JobContext jobContext) throws Exception { CloseableIterator<CIMObjectPath> syncVolumeIter = null; DbClient dbClient = jobContext.getDbClient(); JobStatus jobStatus = getJobStatus(); try { if (jobStatus == JobStatus.IN_PROGRESS) { return; } BlockSnapshotCreateCompleter completer = (BlockSnapshotCreateCompleter) getTaskCompleter(); List<BlockSnapshot> snapshots = dbClient.queryObject(BlockSnapshot.class, completer.getSnapshotURIs()); StorageSystem storage = dbClient.queryObject(StorageSystem.class, getStorageSystemURI()); if (jobStatus == JobStatus.SUCCESS) { // 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 that were created by the // Job and try to match them up with the appropriate BlockSnapshot CIMConnectionFactory cimConnectionFactory = jobContext.getCimConnectionFactory(); WBEMClient client = getWBEMClient(dbClient, cimConnectionFactory); CIMObjectPath replicationGroupPath = client.associatorNames(getCimJob(), null, SmisConstants.SE_REPLICATION_GROUP, null, null).next(); String replicationGroupInstance = (String) replicationGroupPath.getKey(SmisConstants.CP_INSTANCE_ID).getValue(); replicationGroupInstance = SmisUtils.getTargetGroupName(replicationGroupInstance, storage.getUsingSmis80()); String relationshipName = getRelationShipName(client, replicationGroupPath, replicationGroupInstance); syncVolumeIter = client.associatorNames(replicationGroupPath, null, SmisConstants.CIM_STORAGE_VOLUME, null, null); Calendar now = Calendar.getInstance(); while (syncVolumeIter.hasNext()) { // Get the sync volume native device id CIMObjectPath syncVolumePath = syncVolumeIter.next(); CIMInstance syncVolume = client.getInstance(syncVolumePath, false, false, null); String syncDeviceID = syncVolumePath.getKey(SmisConstants.CP_DEVICE_ID).getValue().toString(); String elementName = CIMPropertyFactory.getPropertyValue(syncVolume, SmisConstants.CP_ELEMENT_NAME); // Get the associated volume for this sync volume CIMObjectPath volumePath = null; CloseableIterator<CIMObjectPath> volumeIter = client.associatorNames(syncVolumePath, null, SmisConstants.CIM_STORAGE_VOLUME, null, null); volumePath = volumeIter.next(); volumeIter.close(); String volumeDeviceID = volumePath.getKey(SmisConstants.CP_DEVICE_ID).getValue().toString(); String wwn = CIMPropertyFactory.getPropertyValue(syncVolume, SmisConstants.CP_WWN_NAME); String alternativeName = CIMPropertyFactory.getPropertyValue(syncVolume, SmisConstants.CP_NAME); // Lookup the associated snapshot based on the volume native device id BlockSnapshot snapshot = volumeToSnapMap.get(volumeDeviceID); // In the case snapping an RP+VPlex target volume, we will only be creating a single // BlockSnapshot corresponding to the requested target. The corresponding backing // array consistency group will still be snapped so if we have multiple target volumes, // we need to perform this null check to avoid a NPE. if (snapshot != null) { snapshot.setNativeId(syncDeviceID); snapshot.setNativeGuid(NativeGUIDGenerator.generateNativeGuid(storage, snapshot)); snapshot.setReplicationGroupInstance(replicationGroupInstance); snapshot.setDeviceLabel(elementName); snapshot.setInactive(false); snapshot.setIsSyncActive(_wantSyncActive); snapshot.setCreationTime(now); snapshot.setWWN(wwn.toUpperCase()); snapshot.setAlternateName(alternativeName); commonSnapshotUpdate(snapshot, syncVolume, client, storage, _sourceGroupId, relationshipName, true, dbClient); _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, replicationGroupInstance, volumePath.toString())); dbClient.updateObject(snapshot); } } } else if (jobStatus == JobStatus.FAILED || jobStatus == JobStatus.FATAL_ERROR) { _log.info("Failed to create snapshot"); for (BlockSnapshot snapshot : snapshots) { snapshot.setInactive(true); } dbClient.updateObject(snapshots); } } catch (Exception e) { setPostProcessingErrorStatus("Encountered an internal error during create CG snapshot job status processing: " + e.getMessage()); _log.error("Caught an exception while trying to updateStatus for SmisBlockCreateCGSnapshotJob", e); } finally { if (syncVolumeIter != null) { syncVolumeIter.close(); } super.updateStatus(jobContext); } } private String getRelationShipName(WBEMClient client, CIMObjectPath replicationGroupPath, String replicationGroupID) { CloseableIterator<CIMInstance> iterator = null; try { _log.info("replicationGroupID : {}", replicationGroupID); iterator = client.referenceInstances(replicationGroupPath, SmisConstants.SE_GROUP_SYNCHRONIZED_RG_RG, null, false, null); while (iterator.hasNext()) { CIMInstance groupSynchronized = iterator.next(); CIMProperty syncElement = groupSynchronized.getProperty(SmisConstants.CP_SYNCED_ELEMENT); _log.info("syncElement : {}", syncElement.getValue().toString()); if (syncElement.toString().contains(replicationGroupID)) { String relationshipName = (String) groupSynchronized .getProperty(SmisConstants.RELATIONSHIP_NAME).getValue(); _log.info("Relationship name : {}", relationshipName); return relationshipName; } } } catch (Exception e) { _log.error("Caught an exception while trying to get the relationship name for Group Synchronized"); } finally { if (iterator != null) { iterator.close(); } } return null; } }