/* * Copyright (c) 2008-2014 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.smis.ibm; import java.util.ArrayList; import java.util.List; import java.util.Set; import javax.cim.CIMObjectPath; import javax.wbem.WBEMException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.db.client.model.StorageSystem; import com.emc.storageos.exceptions.DeviceControllerErrors; import com.emc.storageos.svcs.errorhandling.model.ServiceError; import com.emc.storageos.volumecontroller.JobContext; import com.emc.storageos.volumecontroller.impl.JobPollResult; import com.emc.storageos.volumecontroller.impl.smis.job.SmisSynchSubTaskJob; import com.google.common.base.Joiner; import com.google.common.collect.Sets; /** * This is to workaround a timing issue of IBM replication service when creating * group snapshots. * * Upon returning from CreateGroupReplica method, TargetGroup is set to a * reference of IBMTSDS_SnapshotGroup, however, members of the snapshot group is * not available immediately somehow (the * IBMTSDS_GroupSynchronized.PercentSynced is 100 anyway). */ public class IBMSmisSynchSubTaskJob extends SmisSynchSubTaskJob { private static final long serialVersionUID = -2525684785231515418L; private static Logger _logger = LoggerFactory .getLogger(IBMSmisSynchSubTaskJob.class); private StorageSystem storageSystem; private String sgName = null; private int expectedObjCount = 0; private Set<String> removedCGMembers; private JobName jobName; private List<CIMObjectPath> sgMemberPaths = new ArrayList<CIMObjectPath>(); private Set<String> cgMembers; public static enum JobName { GetNewSGMembers, GetRemovedCGMembers } public IBMSmisSynchSubTaskJob(CIMObjectPath cimJob, StorageSystem storageSystem, JobName jobName, String sgName, int expectedObjCount, Set<String> members) { super(cimJob, storageSystem.getId(), jobName.name()); this.storageSystem = storageSystem; this.sgName = sgName; this.expectedObjCount = expectedObjCount; this.removedCGMembers = members; this.jobName = jobName; } @Override public JobPollResult poll(JobContext jobContext, long trackingPeriodInMillis) { switch (jobName) { case GetNewSGMembers: return pollNewSGMembers(jobContext, trackingPeriodInMillis); case GetRemovedCGMembers: return pollRemovedCGMembers(jobContext, trackingPeriodInMillis); default: return null; } } private JobPollResult pollNewSGMembers(JobContext jobContext, long trackingPeriodInMillis) { String instanceId = sgName; try { _pollResult.setJobName(getJobName()); _pollResult.setJobId(instanceId); _pollResult.setJobPercentComplete(0); _status = JobStatus.IN_PROGRESS; setErrorTrackingStartTime(0L); sgMemberPaths = jobContext.getXIVSmisCommandHelper().getSGMembers(storageSystem, sgName); if (sgMemberPaths.size() >= expectedObjCount) { _pollResult.setJobPercentComplete(100); _status = JobStatus.SUCCESS; _logger.info("IBMSmisSynchSubTaskJob: {} succeeded", instanceId); } // if resultObjPaths is not empty, we don't know it is full or partial result // we keep trying, until time out } catch (WBEMException e) { if (e.getID() == WBEMException.CIM_ERR_NOT_FOUND) { _status = JobStatus.FAILED; _errorDescription = e.getMessage(); _logger.error(String.format( "SMI-S object not found. Name: %s, ID: %s, Desc: %s", getJobName(), instanceId, _errorDescription), e); } else { processTransientError(instanceId, trackingPeriodInMillis, e.getMessage(), e); } } catch (Exception e) { processTransientError(instanceId, trackingPeriodInMillis, e.getMessage(), e); } finally { try { _logger.info("SmisJob: Post processing job: id {}", instanceId); // reset from previous possible transient error in post processing status. _postProcessingStatus = JobStatus.SUCCESS; updateStatus(jobContext); if (_postProcessingStatus == JobStatus.ERROR) { processPostProcessingError(instanceId, trackingPeriodInMillis, _errorDescription, null); } } catch (Exception e) { setFatalErrorStatus(e.getMessage()); _logger.error("Problem while trying to update status", e); } finally { if (isJobInTerminalFailedState()) { // Have to process job completion since updateStatus may not did this. ServiceError error = DeviceControllerErrors.smis.jobFailed(_errorDescription); getTaskCompleter().error(jobContext.getDbClient(), error); } } } _pollResult.setJobStatus(_status); _pollResult.setJobPostProcessingStatus(_postProcessingStatus); _pollResult.setErrorDescription(_errorDescription); return _pollResult; } private JobPollResult pollRemovedCGMembers(JobContext jobContext, long trackingPeriodInMillis) { String instanceId = null; try { CIMObjectPath objPath = getCimJob(); instanceId = objPath.getKey(IBMSmisConstants.CP_INSTANCE_ID) .toString(); _pollResult.setJobName(getJobName()); _pollResult.setJobId(instanceId); _pollResult.setJobPercentComplete(0); _status = JobStatus.IN_PROGRESS; setErrorTrackingStartTime(0L); cgMembers = jobContext.getXIVSmisCommandHelper().getCGMembers(storageSystem, objPath); if (cgMembers == null || cgMembers.isEmpty()) { _pollResult.setJobPercentComplete(100); _status = JobStatus.SUCCESS; _logger.info("IBMSmisSynchSubTaskJob: {} succeeded", instanceId); } else { Set<String> remainingMembers = Sets.intersection(removedCGMembers, cgMembers); if (remainingMembers.isEmpty()) { _pollResult.setJobPercentComplete(100); _status = JobStatus.SUCCESS; _logger.info("IBMSmisSynchSubTaskJob: {} succeeded", instanceId); } else { // all or some volumes are not delete _logger.debug("Members: " + Joiner.on(',').join(remainingMembers) + " are still in CG"); } } } catch (WBEMException e) { if (e.getID() == WBEMException.CIM_ERR_NOT_FOUND) { _status = JobStatus.FAILED; _errorDescription = e.getMessage(); _logger.error(String.format( "SMI-S object not found. Name: %s, ID: %s, Desc: %s", getJobName(), instanceId, _errorDescription), e); } else { processTransientError(instanceId, trackingPeriodInMillis, e.getMessage(), e); } } catch (Exception e) { processTransientError(instanceId, trackingPeriodInMillis, e.getMessage(), e); } finally { try { _logger.info("SmisJob: Post processing job: id {}", instanceId); // reset from previous possible transient error in post processing status. _postProcessingStatus = JobStatus.SUCCESS; updateStatus(jobContext); if (_postProcessingStatus == JobStatus.ERROR) { processPostProcessingError(instanceId, trackingPeriodInMillis, _errorDescription, null); } } catch (Exception e) { setFatalErrorStatus(e.getMessage()); _logger.error("Problem while trying to update status", e); } finally { if (isJobInTerminalFailedState()) { // Have to process job completion since updateStatus may not did this. ServiceError error = DeviceControllerErrors.smis.jobFailed(_errorDescription); getTaskCompleter().error(jobContext.getDbClient(), error); } } } _pollResult.setJobStatus(_status); _pollResult.setJobPostProcessingStatus(_postProcessingStatus); _pollResult.setErrorDescription(_errorDescription); return _pollResult; } public List<CIMObjectPath> getSGMemberPaths() { return sgMemberPaths; } public Set<String> getCGMembers() { return cgMembers; } }