/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.smis.job; import java.net.URI; import java.util.Calendar; import java.util.List; import java.util.Map; import javax.cim.CIMInstance; import javax.cim.CIMObjectPath; import javax.wbem.CloseableIterator; import javax.wbem.client.WBEMClient; import com.emc.storageos.db.client.constraint.ContainmentConstraint; import com.emc.storageos.db.client.model.BlockSnapshotSession; import com.emc.storageos.db.client.model.SynchronizationState; import com.emc.storageos.db.client.util.CustomQueryUtility; import com.emc.storageos.volumecontroller.impl.ControllerUtils; import com.emc.storageos.volumecontroller.impl.smis.SmisUtils; import com.emc.storageos.volumecontroller.impl.utils.ConsistencyGroupUtils; 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.model.BlockMirror; import com.emc.storageos.db.client.model.BlockObject; 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.db.client.model.Volume.ReplicationState; 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.smis.CIMConnectionFactory; import com.emc.storageos.volumecontroller.impl.smis.CIMPropertyFactory; import com.emc.storageos.volumecontroller.impl.smis.SmisCommandHelper; import com.emc.storageos.volumecontroller.impl.smis.SmisConstants; public class SmisCreateListReplicaJob extends SmisReplicaCreationJobs { private static final Logger _log = LoggerFactory.getLogger(SmisCreateListReplicaJob.class); private Map<String, URI> _srcNativeIdToReplicaUriMap; private Map<String, String> _tgtToSrcMap; private int _syncType; private Boolean _isSyncActive; public SmisCreateListReplicaJob(CIMObjectPath job, URI storgeSystemURI, Map<String, URI> srcNativeIdToReplicaUriMap, Map<String, String> tgtToSrcMap, int syncType, Boolean syncActive, TaskCompleter taskCompleter) { super(job, storgeSystemURI, taskCompleter, "CreateListReplica"); this._srcNativeIdToReplicaUriMap = srcNativeIdToReplicaUriMap; this._tgtToSrcMap = tgtToSrcMap; this._syncType = syncType; this._isSyncActive = syncActive; } public void updateStatus(JobContext jobContext) throws Exception { CloseableIterator<CIMInstance> syncVolumeIter = null; DbClient dbClient = jobContext.getDbClient(); JobStatus jobStatus = getJobStatus(); try { if (jobStatus == JobStatus.IN_PROGRESS) { return; } List<? extends BlockObject> replicas = BlockObject.fetch(dbClient, getTaskCompleter().getIds()); if (jobStatus == JobStatus.SUCCESS) { CIMConnectionFactory cimConnectionFactory = jobContext.getCimConnectionFactory(); WBEMClient client = getWBEMClient(dbClient, cimConnectionFactory); if (_syncType == SmisConstants.MIRROR_VALUE || _syncType == SmisConstants.CLONE_VALUE) { updatePools(client, dbClient, (List<? extends Volume>) replicas); } syncVolumeIter = client.associatorInstances(getCimJob(), null, SmisConstants.CIM_STORAGE_VOLUME, null, null, false, _volumeProps); StorageSystem storage = dbClient.queryObject(StorageSystem.class, getStorageSystemURI()); processListReplica(syncVolumeIter, client, dbClient, jobContext.getSmisCommandHelper(), storage, replicas, _syncType, _isSyncActive); } else if (jobStatus == JobStatus.FAILED || jobStatus == JobStatus.FATAL_ERROR) { _log.info("Failed to create list relica"); for (BlockObject replica : replicas) { replica.setInactive(true); } dbClient.persistObject(replicas); } } catch (Exception e) { setPostProcessingErrorStatus("Encountered an internal error during create list replica job status processing: " + e.getMessage()); _log.error("Caught an exception while trying to updateStatus for SmisCreateListReplicaJob", e); } finally { if (syncVolumeIter != null) { syncVolumeIter.close(); } super.updateStatus(jobContext); } } protected void processListReplica(CloseableIterator<CIMInstance> syncVolumeIter, WBEMClient client, DbClient dbClient, SmisCommandHelper helper, StorageSystem storage, List<? extends BlockObject> replicas, int syncType, boolean isSyncActive) throws Exception { // Get mapping of target Id to source Id Map<String, String> tgtIdToSrcIdMap = !_tgtToSrcMap.isEmpty() ? _tgtToSrcMap : getConsistencyGroupSyncPairs(dbClient, helper, storage, _srcNativeIdToReplicaUriMap.keySet(), syncType); Calendar now = Calendar.getInstance(); while (syncVolumeIter.hasNext()) { // Get the sync volume native device id CIMInstance syncVolume = syncVolumeIter.next(); CIMObjectPath syncVolumePath = syncVolume.getObjectPath(); String syncDeviceID = syncVolumePath.getKey(SmisConstants.CP_DEVICE_ID).getValue().toString(); String elementName = CIMPropertyFactory.getPropertyValue(syncVolume, SmisConstants.CP_ELEMENT_NAME); String wwn = CIMPropertyFactory.getPropertyValue(syncVolume, SmisConstants.CP_WWN_NAME); String alternateName = CIMPropertyFactory.getPropertyValue(syncVolume, SmisConstants.CP_NAME); // Get the associated volume for this sync volume String volumeDeviceID = tgtIdToSrcIdMap.get(syncDeviceID); // Lookup the replica ID based on the source volume native device ID URI replicaURI = _srcNativeIdToReplicaUriMap.get(volumeDeviceID); BlockObject replica = BlockObject.fetch(dbClient, replicaURI); // 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 (!URIUtil.isType(replicaURI, BlockSnapshot.class) || replica != null) { replica.setNativeId(syncDeviceID); replica.setDeviceLabel(elementName); replica.setCreationTime(now); replica.setWWN(wwn.toUpperCase()); replica.setAlternateName(alternateName); if (replica instanceof BlockSnapshot) { BlockSnapshot snapshot = (BlockSnapshot) replica; snapshot.setNativeGuid(NativeGUIDGenerator.generateNativeGuid(storage, snapshot)); snapshot.setIsSyncActive(isSyncActive); snapshot.setProvisionedCapacity(getProvisionedCapacityInformation(client, syncVolume)); snapshot.setAllocatedCapacity(getAllocatedCapacityInformation(client, syncVolume)); updateSnapshotSessionLinkedTargets(snapshot, dbClient); setSettingsInstance(storage, snapshot, dbClient); } else if (replica instanceof BlockMirror) { BlockMirror mirror = (BlockMirror) replica; mirror.setNativeGuid(NativeGUIDGenerator.generateNativeGuid(storage, mirror)); mirror.setSyncType(Integer.toString(syncType)); mirror.setSyncState(SynchronizationState.SYNCHRONIZED.name()); mirror.setProvisionedCapacity(getProvisionedCapacityInformation(client, syncVolume)); mirror.setAllocatedCapacity(getAllocatedCapacityInformation(client, syncVolume)); } else if (replica instanceof Volume) { Volume clone = (Volume) replica; clone.setNativeGuid(NativeGUIDGenerator.generateNativeGuid(dbClient, clone)); clone.setSyncActive(isSyncActive); if (isSyncActive) { clone.setReplicaState(ReplicationState.SYNCHRONIZED.name()); } else { clone.setReplicaState(ReplicationState.INACTIVE.name()); } clone.setProvisionedCapacity(getProvisionedCapacityInformation(client, syncVolume)); clone.setAllocatedCapacity(getAllocatedCapacityInformation(client, syncVolume)); } dbClient.persistObject(replica); } } } /** * If the snapshot is found to be part of a ReplicationGroup containing linked targets to * an existing BlockSnapshotSession, we must update it with the ID of this snapshot. * * @param snapshot BlockSnapshot being added * @param dbClient Database client */ private void updateSnapshotSessionLinkedTargets(BlockSnapshot snapshot, DbClient dbClient) { List<BlockSnapshot> snapshots = ControllerUtils.getSnapshotsPartOfReplicationGroup(snapshot, dbClient); if (snapshots == null || snapshots.isEmpty()) { return; } // Check if existing ReplicationGroup members are linked targets for a BlockSnapshotSession for (BlockSnapshot existing : snapshots) { List<BlockSnapshotSession> sessions = CustomQueryUtility.queryActiveResourcesByConstraint(dbClient, BlockSnapshotSession.class, ContainmentConstraint.Factory.getLinkedTargetSnapshotSessionConstraint(existing.getId())); if (!sessions.isEmpty()) { BlockSnapshotSession session = sessions.get(0); session.getLinkedTargets().add(snapshot.getId().toString()); dbClient.updateObject(session); break; } } } private void setSettingsInstance(StorageSystem storage, BlockSnapshot snapshot, DbClient dbClient) { if (!storage.checkIfVmax3()) { return; } String cgName = ConsistencyGroupUtils.getSourceConsistencyGroupName(snapshot, dbClient); String instance = SmisUtils.generateVmax3SettingsInstance(storage, cgName, snapshot.getReplicationGroupInstance()); snapshot.setSettingsInstance(instance); } }