/* * Copyright (c) 2012 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.smis; import static com.emc.storageos.volumecontroller.impl.smis.SmisConstants.CIM_PROTOCOL_CONTROLLER_FOR_UNIT; import static com.emc.storageos.volumecontroller.impl.smis.SmisConstants.CP_DEPENDENT; import static com.emc.storageos.volumecontroller.impl.smis.SmisConstants.CP_DEVICE_ID; import static com.emc.storageos.volumecontroller.impl.smis.SmisConstants.CP_DEVICE_NUMBER; import static com.emc.storageos.volumecontroller.impl.smis.SmisConstants.PS_DEVICE_NUMBER; import static com.emc.storageos.volumecontroller.impl.smis.SmisConstants.ANTECEDENT; import static com.emc.storageos.volumecontroller.impl.smis.SmisConstants.LUNMASKING; import java.net.URI; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Map; import javax.cim.CIMInstance; import javax.cim.CIMObjectPath; import javax.cim.CIMProperty; import javax.wbem.CloseableIterator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.cimadapter.connections.cim.CimConnection; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.model.BlockObject; import com.emc.storageos.db.client.model.ExportGroup; import com.emc.storageos.db.client.model.ExportMask; import com.emc.storageos.exceptions.DeviceControllerErrors; import com.emc.storageos.exceptions.DeviceControllerException; import com.emc.storageos.svcs.errorhandling.model.ServiceError; import com.emc.storageos.volumecontroller.TaskCompleter; import com.emc.storageos.volumecontroller.impl.VolumeURIHLU; public class ExportMaskOperationsHelper { private static Logger _log = LoggerFactory.getLogger(ExportMaskOperationsHelper.class); public static void populateDeviceNumberFromProtocolControllers(DbClient dbClient, CimConnection cimConnection, URI exportMaskURI, VolumeURIHLU[] volumeURIHLUs, CIMObjectPath[] protocolControllers, TaskCompleter taskCompleter) throws DeviceControllerException { setHLUFromProtocolControllers(dbClient, cimConnection, exportMaskURI, volumeURIHLUs, Arrays.asList(protocolControllers), taskCompleter); } public static boolean volumeURIHLUsHasNullHLU(VolumeURIHLU[] volumeURIHLUs) { boolean hasNullHLU = false; if (volumeURIHLUs != null && volumeURIHLUs.length > 0) { for (VolumeURIHLU vuh : volumeURIHLUs) { if (vuh.getHLU() == null || vuh.getHLU().equals(ExportGroup.LUN_UNASSIGNED_STR)) { hasNullHLU = true; break; } } } return hasNullHLU; } /** * During an export group operation e.g. creating one with initiators and volumes or when * adding volume(s) to an existing export group the user has the option of supplying HLUs * (Host Lun Unit) for the corresponding volumes. If the user does not supply HLUs, the * underlying array generates them. This helper function displays those array generated * HLUs during a GET/volume/exports operation. If the user has supplied the HLUs, this * function does nothing. * * @throws DeviceControllerException **/ public static void setHLUFromProtocolControllers(DbClient dbClient, CimConnection cimConnection, URI exportMaskURI, VolumeURIHLU[] volumeURIHLUs, Collection<CIMObjectPath> protocolControllers, TaskCompleter taskCompleter) throws DeviceControllerException { long startTime = System.currentTimeMillis(); boolean hasNullHLU = volumeURIHLUsHasNullHLU(volumeURIHLUs); if (!hasNullHLU || protocolControllers.isEmpty()) { return; } try { ExportMask mask = dbClient.queryObject(ExportMask.class, exportMaskURI); Map<String, URI> deviceIdToURI = new HashMap<String, URI>(); for (VolumeURIHLU vuh : volumeURIHLUs) { BlockObject volume = BlockObject.fetch(dbClient, vuh.getVolumeURI()); // We are only concerned with those BlockObjects associated // with the ExportMask that do not yet have an HLU set if (!mask.checkIfVolumeHLUSet(vuh.getVolumeURI())) { deviceIdToURI.put(volume.getNativeId(), volume.getId()); } } boolean requiresUpdate = false; CloseableIterator<CIMInstance> protocolControllerForUnitIter; for (CIMObjectPath protocolController : protocolControllers) { _log.info(String.format("setHLUFromProtocolControllers -- protocolController=%s", protocolController.toString())); protocolControllerForUnitIter = null; try { protocolControllerForUnitIter = cimConnection.getCimClient() .referenceInstances(protocolController, CIM_PROTOCOL_CONTROLLER_FOR_UNIT, null, false, PS_DEVICE_NUMBER); while (protocolControllerForUnitIter.hasNext()) { CIMInstance pcu = protocolControllerForUnitIter.next(); CIMObjectPath pcuPath = pcu.getObjectPath(); CIMProperty<CIMObjectPath> dependentVolumePropery = (CIMProperty<CIMObjectPath>) pcuPath.getKey(CP_DEPENDENT); CIMObjectPath dependentVolumePath = dependentVolumePropery.getValue(); String deviceId = dependentVolumePath.getKey(CP_DEVICE_ID).getValue().toString(); URI volumeURI = deviceIdToURI.get(deviceId); if (volumeURI != null) { String deviceNumber = CIMPropertyFactory.getPropertyValue(pcu, CP_DEVICE_NUMBER); _log.info(String.format("setHLUFromProtocolControllers -- volumeURI=%s --> %s", volumeURI.toString(), deviceNumber)); mask.addVolume(volumeURI, (int) Long.parseLong(deviceNumber, 16)); requiresUpdate = true; } } } finally { if (protocolControllerForUnitIter != null) { protocolControllerForUnitIter.close(); } } } if (requiresUpdate) { dbClient.persistObject(mask); } } catch (Exception e) { _log.error("Unexpected error: setHLUFromProtocolControllers failed.", e); ServiceError error = DeviceControllerErrors.smis.methodFailed("setHLUFromProtocolControllers", e.getMessage()); taskCompleter.error(dbClient, error); } finally { long totalTime = System.currentTimeMillis() - startTime; _log.info(String.format("setHLUFromProtocolControllers took %f seconds", (double) totalTime / (double) 1000)); } } /** * This method is invoked specifically on AddVolumeToMaskingView jobs, which in turn * gets HLU's for processed volumes alone. * * @param dbClient * @param cimConnection * @param exportMaskURI * @param volumeURIHLUs * @param volumePaths * @param taskCompleter * @throws DeviceControllerException */ public static void setHLUFromProtocolControllersOnAddVolume(DbClient dbClient, CimConnection cimConnection, URI exportMaskURI, VolumeURIHLU[] volumeURIHLUs, CIMObjectPath[] volumePaths, TaskCompleter taskCompleter) throws DeviceControllerException { long startTime = System.currentTimeMillis(); boolean hasNullHLU = volumeURIHLUsHasNullHLU(volumeURIHLUs); if (!hasNullHLU || volumePaths.length == 0) { return; } try { ExportMask mask = dbClient.queryObject(ExportMask.class, exportMaskURI); Map<String, URI> deviceIdToURI = new HashMap<String, URI>(); for (VolumeURIHLU vuh : volumeURIHLUs) { BlockObject volume = BlockObject.fetch(dbClient, vuh.getVolumeURI()); deviceIdToURI.put(volume.getNativeId(), volume.getId()); } boolean requiresUpdate = false; CloseableIterator<CIMInstance> protocolControllerForUnitIter; for (CIMObjectPath volumePath : volumePaths) { _log.info(String.format("setHLUFromProtocolControllers -- protocolController=%s", volumePath.toString())); protocolControllerForUnitIter = null; try { protocolControllerForUnitIter = cimConnection.getCimClient() .referenceInstances(volumePath, CIM_PROTOCOL_CONTROLLER_FOR_UNIT, null, false, PS_DEVICE_NUMBER); while (protocolControllerForUnitIter.hasNext()) { CIMInstance pcu = protocolControllerForUnitIter.next(); CIMObjectPath pcuPath = pcu.getObjectPath(); CIMObjectPath maskingViewPath = (CIMObjectPath) pcuPath.getKey(ANTECEDENT).getValue(); // Provider returns multiple references with same relationship , hence looking for class name if (!maskingViewPath.toString().contains(LUNMASKING)) { _log.info("Skipping CIMPath other than masking view path {}", pcuPath); continue; } String deviceId = volumePath.getKey(CP_DEVICE_ID).getValue().toString(); URI volumeURI = deviceIdToURI.get(deviceId); if (volumeURI != null) { String deviceNumber = CIMPropertyFactory.getPropertyValue(pcu, CP_DEVICE_NUMBER); _log.info(String.format("setHLUFromProtocolControllers -- volumeURI=%s --> %s", volumeURI.toString(), deviceNumber)); mask.addVolume(volumeURI, (int) Long.parseLong(deviceNumber, 16)); requiresUpdate = true; } } } finally { if (protocolControllerForUnitIter != null) { protocolControllerForUnitIter.close(); } } } if (requiresUpdate) { dbClient.updateObject(mask); } } catch (Exception e) { _log.error("Unexpected error: setHLUFromProtocolControllers failed.", e); ServiceError error = DeviceControllerErrors.smis.methodFailed( "setHLUFromProtocolControllers", e.getMessage()); taskCompleter.error(dbClient, error); } finally { long totalTime = System.currentTimeMillis() - startTime; _log.info(String.format("setHLUFromProtocolControllersDuringAddVolume took %f seconds", (double) totalTime / (double) 1000)); } } }