/*
* Copyright 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.HashMap;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.model.BlockMirror;
import com.emc.storageos.db.client.model.StorageSystem;
import com.emc.storageos.db.client.model.Volume;
import com.emc.storageos.exceptions.DeviceControllerException;
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.BlockMirrorCreateCompleter;
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;
import com.emc.storageos.volumecontroller.impl.smis.SmisUtils;
public class SmisBlockCreateCGMirrorJob extends SmisBlockMirrorJob {
private static final long serialVersionUID = 1L;
private static final Logger _log = LoggerFactory.getLogger(SmisBlockCreateCGMirrorJob.class);
public SmisBlockCreateCGMirrorJob(CIMObjectPath job, URI storgeSystemURI, TaskCompleter taskCompleter) {
super(job, storgeSystemURI, taskCompleter, "CreateGroupMirrors");
}
public void updateStatus(JobContext jobContext) throws Exception {
CloseableIterator<CIMInstance> syncVolumeIter = null;
CloseableIterator<CIMObjectPath> repGroupPathIter = null;
DbClient dbClient = jobContext.getDbClient();
BlockMirrorCreateCompleter completer = (BlockMirrorCreateCompleter) getTaskCompleter();;
JobStatus jobStatus = getJobStatus();
try {
if (jobStatus == JobStatus.IN_PROGRESS) {
return;
}
CIMConnectionFactory cimConnectionFactory = jobContext.getCimConnectionFactory();
WBEMClient client = getWBEMClient(dbClient, cimConnectionFactory);
List<BlockMirror> mirrors = dbClient.queryObject(BlockMirror.class, completer.getIds());
if (jobStatus == JobStatus.SUCCESS || jobStatus == JobStatus.FAILED || jobStatus == JobStatus.FATAL_ERROR) {
updatePools(client, dbClient, mirrors);
}
if (jobStatus == JobStatus.SUCCESS) {
_log.info("Group mirror creation success");
repGroupPathIter = client.associatorNames(getCimJob(), null, SmisConstants.SE_REPLICATION_GROUP, null, null);
CIMObjectPath repGroupPath = repGroupPathIter.next();
StorageSystem storage = dbClient.queryObject(StorageSystem.class, getStorageSystemURI());
String repGroupID = (String) repGroupPath.getKey(SmisConstants.CP_INSTANCE_ID).getValue();
repGroupID = SmisUtils.getTargetGroupName(repGroupID, storage.getUsingSmis80());
CIMInstance syncInst = getSynchronizedInstance(client, repGroupPath);
String syncType = CIMPropertyFactory.getPropertyValue(syncInst, SmisConstants.CP_SYNC_TYPE);
syncVolumeIter = client.associatorInstances(repGroupPath, null, SmisConstants.CIM_STORAGE_VOLUME, null, null, false, _volumeProps);
processCGMirrors(syncVolumeIter, client, dbClient, jobContext.getSmisCommandHelper(), storage, mirrors, repGroupID, syncInst.getObjectPath().toString(), syncType);
} else if (isJobInTerminalFailedState()) {
_log.info("Failed to create group mirrors");
completer.error(dbClient, DeviceControllerException.exceptions.attachVolumeMirrorFailed(getMessage()));
for (BlockMirror mirror : mirrors) {
mirror.setInactive(true);
}
dbClient.persistObject(mirrors);
}
} catch (Exception e) {
setPostProcessingErrorStatus("Encountered an internal error during block create CG mirror job status processing: " +
e.getMessage());
_log.error("Caught an exception while trying to updateStatus for SmisBlockCreateCGMirrorJob", e);
} finally {
if (syncVolumeIter != null) {
syncVolumeIter.close();
}
if (repGroupPathIter != null) {
repGroupPathIter.close();
}
super.updateStatus(jobContext);
}
}
/**
* Iterate through all created sync volumes, match up with ViPR created mirrors, and update them in ViPR.
*
* @param syncVolumeIter
* @param client
* @param dbClient
* @param helper
* @param storage
* @param mirrors
* @param repGroupID
* @param syncInst
* @param syncType
* @throws Exception
*/
private void processCGMirrors(CloseableIterator<CIMInstance> syncVolumeIter, WBEMClient client, DbClient dbClient, SmisCommandHelper helper, StorageSystem storage,
List<BlockMirror> mirrors, String repGroupID, String syncInst, String syncType) throws Exception {
// Create mapping of volume.nativeDeviceId to BlockMirror object
Map<String, BlockMirror> volIdToMirrorMap = new HashMap<String, BlockMirror>();
for (BlockMirror mirror : mirrors) {
Volume volume = dbClient.queryObject(Volume.class, mirror.getSource());
volIdToMirrorMap.put(volume.getNativeId(), mirror);
}
// Get mapping of target Id to source Id
Map<String, String> tgtToSrcMap = getConsistencyGroupSyncPairs(dbClient, helper, storage, volIdToMirrorMap.keySet(), SmisConstants.MIRROR_VALUE);
Calendar now = Calendar.getInstance();
while (syncVolumeIter.hasNext()) {
// Get the target mirror volume native device id
CIMInstance syncVolume = syncVolumeIter.next();
CIMObjectPath syncVolumePath = syncVolume.getObjectPath();
String syncDeviceID = syncVolumePath.getKeyValue(SmisConstants.CP_DEVICE_ID).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 = tgtToSrcMap.get(syncDeviceID);
// Lookup mirror associated with the source volume based on the source volume's native id
BlockMirror mirror = volIdToMirrorMap.get(volumeDeviceID);
mirror.setReplicationGroupInstance(repGroupID);
mirror.setProvisionedCapacity(getProvisionedCapacityInformation(client, syncVolume));
mirror.setAllocatedCapacity(getAllocatedCapacityInformation(client, syncVolume));
mirror.setWWN(wwn);
mirror.setAlternateName(alternateName);
mirror.setNativeId(syncDeviceID);
mirror.setNativeGuid(NativeGUIDGenerator.generateNativeGuid(storage, mirror));
mirror.setDeviceLabel(elementName);
mirror.setInactive(false);
mirror.setCreationTime(now);
mirror.setSynchronizedInstance(syncInst);
mirror.setSyncType(syncType);
dbClient.persistObject(mirror);
_log.info(String.format("For target mirror volume %1$s, going to set BlockMirror %2$s nativeId to %3$s (%4$s). Associated volume is %5$s",
syncVolumePath.toString(), mirror.getId().toString(), syncDeviceID, elementName, volumeDeviceID));
}
}
}