/* * Copyright (c) 2014 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.vnxe.job; import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.Calendar; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.model.BlockConsistencyGroup; import com.emc.storageos.db.client.model.Volume; import com.emc.storageos.exceptions.DeviceControllerException; import com.emc.storageos.vnxe.VNXeApiClient; import com.emc.storageos.vnxe.models.ParametersOut; import com.emc.storageos.vnxe.models.VNXeBase; import com.emc.storageos.vnxe.models.VNXeCommandJob; import com.emc.storageos.vnxe.models.VNXeLun; import com.emc.storageos.volumecontroller.JobContext; import com.emc.storageos.volumecontroller.TaskCompleter; import com.emc.storageos.volumecontroller.impl.NativeGUIDGenerator; public class VNXeCreateVolumesJob extends VNXeJob { private static final long serialVersionUID = 485930354573814000L; private static final Logger _logger = LoggerFactory.getLogger(VNXeCreateFileSystemJob.class); private final URI storagePool; private final boolean isConsistencyGroup; public VNXeCreateVolumesJob(List<String> jobIds, URI storageSystemUri, TaskCompleter taskCompleter, URI storagePoolUri, boolean isConsistencyGroup) { super(jobIds, storageSystemUri, taskCompleter, "createVolumes"); this.storagePool = storagePoolUri; this.isConsistencyGroup = isConsistencyGroup; } /** * Called to update the job status when the volumes create job completes. * * @param jobContext The job context. */ @Override public void updateStatus(JobContext jobContext) throws Exception { DbClient dbClient = jobContext.getDbClient(); try { if (_status == JobStatus.IN_PROGRESS) { return; } String opId = getTaskCompleter().getOpId(); StringBuilder logMsgBuilder = new StringBuilder(String.format("Updating status of job %s to %s", opId, _status.name())); VNXeApiClient vnxeApiClient = getVNXeClient(jobContext); // VNXeCommandJob job = vnxeApiClient.getJob(getJobIds().get(0)); // If terminal state update storage pool capacity if (_status == JobStatus.SUCCESS || _status == JobStatus.FAILED) { List<URI> volUris = getTaskCompleter().getIds(); List<String> volsInPool = new ArrayList<String>(); for (URI voluri : volUris) { volsInPool.add(voluri.toString()); } VNXeJob.updateStoragePoolCapacity(dbClient, vnxeApiClient, storagePool, volsInPool); } Calendar now = Calendar.getInstance(); int volumeCount = 0; if (_status == JobStatus.SUCCESS) { if (!isConsistencyGroup) { for (String jobId : getJobIds()) { VNXeCommandJob vnxeJob = vnxeApiClient.getJob(jobId); ParametersOut output = vnxeJob.getParametersOut(); String nativeId = null; URI volumeId = getTaskCompleter().getId(volumeCount); if (output != null) { VNXeBase storageResource = output.getStorageResource(); if (storageResource != null) { nativeId = storageResource.getId(); } } processVolume(vnxeApiClient, nativeId, volumeId, dbClient, logMsgBuilder, now); volumeCount++; } } else { List<URI> volIds = getTaskCompleter().getIds(); processVolumesinConsistencyGroup(vnxeApiClient, volIds, dbClient, logMsgBuilder, now); } } else if (_status == JobStatus.FAILED) { List<URI> volIds = getTaskCompleter().getIds(); for (URI volId : volIds) { Volume volume = dbClient.queryObject(Volume.class, volId); volume.setInactive(true); dbClient.updateObject(volume); if (logMsgBuilder.length() != 0) { logMsgBuilder.append("\n"); } logMsgBuilder.append(String.format( "Task %s failed to create volume: %s", opId, volId)); } } _logger.info(logMsgBuilder.toString()); } catch (Exception e) { _logger.error("Caught an exception while trying to updateStatus for VNXeCreateVolumesJob", e); setErrorStatus("Encountered an internal error during volume create job status processing : " + e.getMessage()); } finally { super.updateStatus(jobContext); } } private void processVolume(VNXeApiClient apiClient, String nativeId, URI volumeId, DbClient dbClient, StringBuilder logMsgBuilder, Calendar creationTime) throws IOException, DeviceControllerException { Volume volume = dbClient.queryObject(Volume.class, volumeId); // If the volume is inactive, the job failed while the asynchronous work was running. // Honor that the job failed and do not commit the volume, which would make it active again. if (volume.getInactive()) { if (logMsgBuilder.length() != 0) { logMsgBuilder.append("\n"); } logMsgBuilder.append(String.format( "Create volume job failed and volume set to inactive. Volume was likely created successfully and will be left on the array for ingestion. NativeId: %s, URI: %s", nativeId, getTaskCompleter().getId())); return; } volume.setCreationTime(creationTime); VNXeLun vnxeLun = apiClient.getLun(nativeId); if (vnxeLun != null) { updateVolume(volume, vnxeLun, dbClient); if (logMsgBuilder.length() != 0) { logMsgBuilder.append("\n"); } logMsgBuilder.append(String.format( "Created volume successfully .. NativeId: %s, URI: %s", nativeId, volumeId.toString())); } else { _logger.error("Could not find the lun: {} in the array", nativeId); } } private void processVolumesinConsistencyGroup(VNXeApiClient apiClient, List<URI> volIds, DbClient dbClient, StringBuilder logMsgBuilder, Calendar creationTime) throws IOException { BlockConsistencyGroup group = null; for (URI volId : volIds) { Volume volume = dbClient.queryObject(Volume.class, volId); // If the volume is inactive, the job failed while the asynchronous work was running. // Honor that the job failed and do not commit the volume, which would make it active again. if (volume.getInactive()) { if (logMsgBuilder.length() != 0) { logMsgBuilder.append("\n"); } logMsgBuilder.append(String.format( "Create volume job failed and volume set to inactive. Volume was likely created successfully and will be left on the array for ingestion. NativeId: %s, URI: %s", volume.getNativeId(), getTaskCompleter().getId())); return; } volume.setCreationTime(creationTime); if (group == null) { group = dbClient.queryObject(BlockConsistencyGroup.class, volume.getConsistencyGroup()); } String cgId = null; if (apiClient.isUnityClient()) { String cgName = volume.getReplicationGroupInstance(); cgId = apiClient.getConsistencyGroupIdByName(cgName); } else { cgId = group.getCgNameOnStorageSystem(volume.getStorageController()); } VNXeLun vnxeLun = apiClient.getLunByLunGroup(cgId, volume.getNativeGuid()); if (vnxeLun != null) { updateVolume(volume, vnxeLun, dbClient); dbClient.updateObject(volume); if (logMsgBuilder.length() != 0) { logMsgBuilder.append("\n"); } logMsgBuilder.append(String.format( "Created volume successfully .. NativeId: %s, URI: %s", vnxeLun.getId(), volId.toString())); } else { _logger.error("Could not find the lun:{} in the array", volume.getNativeGuid()); } } } private void updateVolume(Volume volume, VNXeLun vnxeLun, DbClient dbClient) throws IOException { volume.setWWN(vnxeLun.getWwn()); volume.setInactive(false); volume.setProvisionedCapacity(vnxeLun.getSizeTotal()); volume.setAllocatedCapacity(vnxeLun.getSizeAllocated()); volume.setNativeId(vnxeLun.getId()); volume.setNativeGuid(NativeGUIDGenerator.generateNativeGuid(dbClient, volume)); volume.setDeviceLabel(vnxeLun.getName()); dbClient.updateObject(volume); } }