/* * Copyright (c) 2013 EMC Corporation * All Rights Reserved */ package com.emc.storageos.hds.api; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.http.HttpStatus; import org.milyn.payload.JavaResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.hds.HDSConstants; import com.emc.storageos.hds.HDSException; import com.emc.storageos.hds.model.Add; import com.emc.storageos.hds.model.ArrayGroup; import com.emc.storageos.hds.model.Delete; import com.emc.storageos.hds.model.EchoCommand; import com.emc.storageos.hds.model.Error; import com.emc.storageos.hds.model.Get; import com.emc.storageos.hds.model.LDEV; import com.emc.storageos.hds.model.LogicalUnit; import com.emc.storageos.hds.model.Modify; import com.emc.storageos.hds.model.ObjectLabel; import com.emc.storageos.hds.model.Pool; import com.emc.storageos.hds.model.StorageArray; import com.emc.storageos.hds.util.SmooksUtil; import com.emc.storageos.hds.xmlgen.InputXMLGenerationClient; import com.sun.jersey.api.client.ClientResponse; /** * This volume manager is responsible creating volumes/delete volumes. * */ public class HDSApiVolumeManager { /** * Logger instance to log messages. */ private static final Logger log = LoggerFactory.getLogger(HDSApiVolumeManager.class); private HDSApiClient hdsApiClient; public HDSApiVolumeManager(HDSApiClient hdsApiClient) { this.hdsApiClient = hdsApiClient; } /** * Creates the Thick volume with the passed information. * * @TODO we should add support for multi volume creation by constructing the xml with new attributes. rest will work fine. * @param systemId : represents SystemObjectID. * @param arrayGroupId : represents StoragePoolObjectID. * @param luCapacityInBytes: Logical Unit Capacity in bytes. * @param noOfLus : No. of LU's to created * @param volumeName : Logical Unit name. * @return : asyncMessageId * @throws Exception */ public String createThickVolumes(String systemId, String arrayGroupId, Long luCapacityInBytes, int noOfLus, String volumeName, String formatType, String model, Integer devNum) throws Exception { Long luCapacityInKB = luCapacityInBytes / 1024; InputStream responseStream = null; String asyncTaskMessageId = null; try { Map<String, Object> attributeMap = new HashMap<String, Object>(); StorageArray storageArray = new StorageArray(systemId); Pool arrayGroup = new Pool(arrayGroupId); Add addOp = new Add(HDSConstants.LOGICALUNIT, noOfLus, formatType); addOp.setBulk(Boolean.TRUE); LogicalUnit logicalUnit = new LogicalUnit(null, String.valueOf(luCapacityInKB), volumeName, null, devNum); attributeMap.put(HDSConstants.STORAGEARRAY, storageArray); attributeMap.put(HDSConstants.ARRAY_GROUP, arrayGroup); attributeMap.put(HDSConstants.ADD, addOp); attributeMap.put(HDSConstants.MODEL, model); attributeMap.put(HDSConstants.LOGICALUNIT, logicalUnit); String createVolumeInputXML = InputXMLGenerationClient.getInputXMLString( HDSConstants.CREATE_THICK_VOLUMES_OP, attributeMap, HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE, HDSConstants.HITACHI_SMOOKS_CONFIG_FILE); log.info("Query to create thick volume: {}", createVolumeInputXML); URI endpointURI = hdsApiClient.getBaseURI(); ClientResponse response = hdsApiClient.post(endpointURI, createVolumeInputXML); if (HttpStatus.SC_OK == response.getStatus()) { responseStream = response.getEntityInputStream(); JavaResult result = SmooksUtil.getParsedXMLJavaResult(responseStream, HDSConstants.SMOOKS_CONFIG_FILE); EchoCommand command = result.getBean(EchoCommand.class); if (HDSConstants.PROCESSING_STR.equalsIgnoreCase(command.getStatus())) { asyncTaskMessageId = command.getMessageID(); } else if (HDSConstants.FAILED_STR.equalsIgnoreCase(command.getStatus())) { Error error = result.getBean(Error.class); log.error("Volume creation failed status messageID: {}", command.getMessageID()); log.error("Volume creation failed with error code: {} with message: {}", error.getCode(), error.getDescription()); throw HDSException.exceptions.notAbleToCreateVolume( error.getCode(), error.getDescription()); } } else { log.error("LogicalUnit creation failed with invalid response code {}", response.getStatus()); throw HDSException.exceptions .invalidResponseFromHDS(String .format("LogicalUnit creation failed due to invalid response %1$s from server for system %2$s", response.getStatus(), systemId)); } } finally { if (null != responseStream) { try { responseStream.close(); } catch (IOException e) { log.warn("Exception occurred while close volume creation response stream"); } } } return asyncTaskMessageId; } /** * Creates the Thin volume with the passed information. * * @param systemId : represents SystemObjectID. * @param arrayGroupId : represents StoragePoolObjectID. * @param luCapacityInBytes: Logical Unit Capacity in bytes. * @param noOfLus : No. of LU's to created * @param volumeName : Logical Unit name. * @param formatType : formatType. * @param model : model. * @return : asyncMessageId * @throws Exception */ public String createThinVolumes(String systemId, String arrayGroupId, Long luCapacityInBytes, int noOfLus, String volumeName, String formatType, String model) throws Exception { Long luCapacityInKB = luCapacityInBytes / 1024; InputStream responseStream = null; String asyncTaskMessageId = null; try { Map<String, Object> attributeMap = new HashMap<String, Object>(); StorageArray storageArray = new StorageArray(systemId); Pool arrayGroup = new Pool(null); Add addOp = new Add(HDSConstants.VIRTUALVOLUME, noOfLus, null); LogicalUnit logicalUnit = new LogicalUnit(arrayGroupId, String.valueOf(luCapacityInKB), volumeName, HDSConstants.EMULATION_OPENV, null); attributeMap.put(HDSConstants.STORAGEARRAY, storageArray); attributeMap.put(HDSConstants.ARRAY_GROUP, arrayGroup); attributeMap.put(HDSConstants.ADD, addOp); attributeMap.put(HDSConstants.LOGICALUNIT, logicalUnit); attributeMap.put(HDSConstants.MODEL, model); String createVolumeInputXML = InputXMLGenerationClient.getInputXMLString( HDSConstants.CREATE_THIN_VOLUMES_OP, attributeMap, HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE, HDSConstants.HITACHI_SMOOKS_CONFIG_FILE); log.info("Query to create thin Volume: {}", createVolumeInputXML); URI endpointURI = hdsApiClient.getBaseURI(); ClientResponse response = hdsApiClient.post(endpointURI, createVolumeInputXML); if (HttpStatus.SC_OK == response.getStatus()) { responseStream = response.getEntityInputStream(); JavaResult result = SmooksUtil.getParsedXMLJavaResult(responseStream, HDSConstants.SMOOKS_CONFIG_FILE); EchoCommand command = result.getBean(EchoCommand.class); if (HDSConstants.PROCESSING_STR.equalsIgnoreCase(command.getStatus())) { asyncTaskMessageId = command.getMessageID(); } else if (HDSConstants.FAILED_STR.equalsIgnoreCase(command.getStatus())) { Error error = result.getBean(Error.class); log.error("Thin Volume creation failed status messageID: {}", command.getMessageID()); log.error("Thin Volume creation failed with error code: {} with message: {}", error.getCode(), error.getDescription()); throw HDSException.exceptions.notAbleToCreateVolume( error.getCode(), error.getDescription()); } } else { log.error("Thin Volume creation failed with invalid response code {}", response.getStatus()); throw HDSException.exceptions .invalidResponseFromHDS(String .format("Thin Volume creation failed due to invalid response %1$s from server for system %2$s", response.getStatus(), systemId)); } } finally { if (null != responseStream) { try { responseStream.close(); } catch (IOException e) { log.warn("Exception occurred while close thin volume creation response stream"); } } } return asyncTaskMessageId; } /** * Modify the Virtual Volumes with the passed information. * * @param systemId : represents SystemObjectID. * @param newLUCapacityInBytes: new VirtualVolume Capacity in bytes. * @return : asyncMessageId * @throws Exception */ public String modifyVirtualVolume(String systemId, String luObjectId, Long newLUCapacityInBytes, String model) throws Exception { Long luCapacityInKB = newLUCapacityInBytes / 1024; InputStream responseStream = null; String asyncTaskMessageId = null; try { Map<String, Object> attributeMap = new HashMap<String, Object>(); StorageArray storageArray = new StorageArray(systemId); Modify modifyOp = new Modify(HDSConstants.VIRTUALVOLUME, false); LogicalUnit logicalUnit = new LogicalUnit(luObjectId, String.valueOf(luCapacityInKB)); attributeMap.put(HDSConstants.STORAGEARRAY, storageArray); attributeMap.put(HDSConstants.MODEL, model); attributeMap.put(HDSConstants.MODIFY, modifyOp); attributeMap.put(HDSConstants.LOGICALUNIT, logicalUnit); String modifyVolumeInputXML = InputXMLGenerationClient.getInputXMLString( HDSConstants.MODIFY_THIN_VOLUME_OP, attributeMap, HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE, HDSConstants.HITACHI_SMOOKS_CONFIG_FILE); log.info("Query to modify Thin Volume: {}", modifyVolumeInputXML); URI endpointURI = hdsApiClient.getBaseURI(); ClientResponse response = hdsApiClient.post(endpointURI, modifyVolumeInputXML); if (HttpStatus.SC_OK == response.getStatus()) { responseStream = response.getEntityInputStream(); JavaResult result = SmooksUtil.getParsedXMLJavaResult(responseStream, HDSConstants.SMOOKS_CONFIG_FILE); EchoCommand command = result.getBean(EchoCommand.class); if (HDSConstants.PROCESSING_STR.equalsIgnoreCase(command.getStatus())) { asyncTaskMessageId = command.getMessageID(); } else if (HDSConstants.FAILED_STR.equalsIgnoreCase(command.getStatus())) { Error error = result.getBean(Error.class); log.error("Thin Volume modification failed status messageID: {}", command.getMessageID()); log.error("Thin Volume modification failed with error code: {} with message: {}", error.getCode(), error.getDescription()); throw HDSException.exceptions.notAbleToCreateVolume( error.getCode(), error.getDescription()); } } else { log.error("Thin Volume modification failed with invalid response code {}", response.getStatus()); throw HDSException.exceptions .invalidResponseFromHDS(String .format("Thin Volume modification failed due to invalid response %1$s from server for system %2$s", response.getStatus(), systemId)); } } finally { if (null != responseStream) { try { responseStream.close(); } catch (IOException e) { log.warn("Exception occurred while closing Thin volume modification response stream"); } } } return asyncTaskMessageId; } /** * Formats the LogicalUnit. * * @param systemObjectId * @param luObjectId * @return */ public String formatLogicalUnit(String systemObjectId, String luObjectId) { InputStream responseStream = null; String asyncTaskMessageId = null; try { Map<String, Object> attributeMap = new HashMap<String, Object>(); StorageArray storageArray = new StorageArray(systemObjectId); Modify modifyOp = new Modify(HDSConstants.LU_FORMAT_TARGET, true); LogicalUnit logicalUnit = new LogicalUnit(luObjectId, null); attributeMap.put(HDSConstants.STORAGEARRAY, storageArray); attributeMap.put(HDSConstants.MODIFY, modifyOp); attributeMap.put(HDSConstants.LOGICALUNIT, logicalUnit); String fromatVolumeInputXML = InputXMLGenerationClient.getInputXMLString( HDSConstants.FORMAT_VOLUME_OP, attributeMap, HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE, HDSConstants.HITACHI_SMOOKS_CONFIG_FILE); log.info("Query to format LogicalUnit: {}", fromatVolumeInputXML); URI endpointURI = hdsApiClient.getBaseURI(); ClientResponse response = hdsApiClient.post(endpointURI, fromatVolumeInputXML); if (HttpStatus.SC_OK == response.getStatus()) { responseStream = response.getEntityInputStream(); JavaResult result = SmooksUtil.getParsedXMLJavaResult(responseStream, HDSConstants.SMOOKS_CONFIG_FILE); EchoCommand command = result.getBean(EchoCommand.class); if (HDSConstants.PROCESSING_STR.equalsIgnoreCase(command.getStatus())) { asyncTaskMessageId = command.getMessageID(); } else if (HDSConstants.FAILED_STR.equalsIgnoreCase(command.getStatus())) { Error error = result.getBean(Error.class); log.error("Query to format LogicalUnit: failed status messageID: {}", command.getMessageID()); log.error("LogicalUnit formatting failed with error code: {} with message: {}", error.getCode(), error.getDescription()); throw HDSException.exceptions.notAbleToCreateVolume(error.getCode(), error.getDescription()); } } else { log.error("LogicalUnit format failed with invalid response code {}", response.getStatus()); throw HDSException.exceptions .invalidResponseFromHDS(String .format("LogicalUnit format failed due to invalid response %1$s from server for system %2$s", response.getStatus(), systemObjectId)); } } finally { if (null != responseStream) { try { responseStream.close(); } catch (IOException e) { log.warn("Exception occurred while closing Formatting LogicalUnit response stream"); } } } return asyncTaskMessageId; } public String deleteThickLogicalUnits(String systemObjectID, Set<String> logicalUnitIdList, String model) throws Exception { InputStream responseStream = null; String asyncTaskMessageId = null; try { // If the LogicalUnits are LUSE, we should release them. releaseLUSEVolumesIfPresent(systemObjectID, logicalUnitIdList); Map<String, Object> attributeMap = new HashMap<String, Object>(); StorageArray storageArray = new StorageArray(systemObjectID); Delete deleteOp = new Delete(HDSConstants.LOGICALUNIT); List<LogicalUnit> luList = new ArrayList<LogicalUnit>(); for (String logicalUnitId : logicalUnitIdList) { LogicalUnit logicalUnit = new LogicalUnit(logicalUnitId, null); luList.add(logicalUnit); } attributeMap.put(HDSConstants.STORAGEARRAY, storageArray); attributeMap.put(HDSConstants.DELETE, deleteOp); attributeMap.put(HDSConstants.MODEL, model); attributeMap.put(HDSConstants.LOGICALUNIT_LIST, luList); String deleteVolumesInputXML = InputXMLGenerationClient.getInputXMLString( HDSConstants.DELETE_VOLUMES_OP, attributeMap, HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE, HDSConstants.HITACHI_SMOOKS_CONFIG_FILE); log.debug("volume delete payload :{}", deleteVolumesInputXML); URI endpointURI = hdsApiClient.getBaseURI(); ClientResponse response = hdsApiClient.post(endpointURI, deleteVolumesInputXML); if (HttpStatus.SC_OK == response.getStatus()) { responseStream = response.getEntityInputStream(); JavaResult result = SmooksUtil.getParsedXMLJavaResult(responseStream, HDSConstants.SMOOKS_CONFIG_FILE); EchoCommand command = result.getBean(EchoCommand.class); if (HDSConstants.PROCESSING_STR.equalsIgnoreCase(command.getStatus())) { asyncTaskMessageId = command.getMessageID(); } else if (HDSConstants.FAILED_STR.equalsIgnoreCase(command.getStatus())) { Error error = result.getBean(Error.class); log.info("command failed error code: {}", error.getCode()); log.info("Command failed: messageID: {} {}", command.getMessageID(), error.getDescription()); throw HDSException.exceptions.notAbleToDeleteVolume(error.getCode(), error.getDescription()); } } else { log.error("LogicalUnit deletion failed with invalid response code {}", response.getStatus()); throw HDSException.exceptions .invalidResponseFromHDS(String .format("LogicalUnit creation failed due to invalid response %1$s from server for system %2$s", response.getStatus(), systemObjectID)); } } finally { if (null != responseStream) { try { responseStream.close(); } catch (IOException e) { log.error(e.getMessage(), e); } } } return asyncTaskMessageId; } public String deleteThinLogicalUnits(String systemObjectID, Set<String> logicalUnitIdList, String model) throws Exception { InputStream responseStream = null; String asyncTaskMessageId = null; try { Map<String, Object> attributeMap = new HashMap<String, Object>(); StorageArray storageArray = new StorageArray(systemObjectID); Delete deleteOp = new Delete(HDSConstants.VIRTUALVOLUME, true); List<LogicalUnit> luList = new ArrayList<LogicalUnit>(); for (String logicalUnitId : logicalUnitIdList) { LogicalUnit logicalUnit = new LogicalUnit(logicalUnitId, null); luList.add(logicalUnit); } attributeMap.put(HDSConstants.STORAGEARRAY, storageArray); attributeMap.put(HDSConstants.DELETE, deleteOp); attributeMap.put(HDSConstants.MODEL, model); attributeMap.put(HDSConstants.LOGICALUNIT_LIST, luList); String deleteVolumesInputXML = InputXMLGenerationClient.getInputXMLString( HDSConstants.DELETE_VOLUMES_OP, attributeMap, HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE, HDSConstants.HITACHI_SMOOKS_CONFIG_FILE); log.info("volume delete payload :{}", deleteVolumesInputXML); URI endpointURI = hdsApiClient.getBaseURI(); ClientResponse response = hdsApiClient.post(endpointURI, deleteVolumesInputXML); if (HttpStatus.SC_OK == response.getStatus()) { responseStream = response.getEntityInputStream(); JavaResult result = SmooksUtil.getParsedXMLJavaResult(responseStream, HDSConstants.SMOOKS_CONFIG_FILE); EchoCommand command = result.getBean(EchoCommand.class); if (HDSConstants.PROCESSING_STR.equalsIgnoreCase(command.getStatus())) { asyncTaskMessageId = command.getMessageID(); } else if (HDSConstants.FAILED_STR.equalsIgnoreCase(command.getStatus())) { Error error = result.getBean(Error.class); log.info("command failed error code: {}", error.getCode()); log.info("Command failed: messageID: {} {}", command.getMessageID(), error.getDescription()); throw HDSException.exceptions.notAbleToDeleteVolume(error.getCode(), error.getDescription()); } } else { log.error("LogicalUnit deletion failed with invalid response code {}", response.getStatus()); throw HDSException.exceptions .invalidResponseFromHDS(String .format("LogicalUnit creation failed due to invalid response %1$s from server for system %2$s", response.getStatus(), systemObjectID)); } } finally { if (null != responseStream) { try { responseStream.close(); } catch (IOException e) { log.error(e.getMessage(), e); } } } return asyncTaskMessageId; } /** * When we delete a logicalunit we should first check whether it is LUSE volume or not. * If it is LUSE volume, then we should release LUSE and delete all volumes. * * @param systemObjectID * @param logicalUnitIdList */ private void releaseLUSEVolumesIfPresent(String systemObjectID, Set<String> logicalUnitIdList) { if (null != logicalUnitIdList && !logicalUnitIdList.isEmpty()) { for (String logicalUnitObjectId : logicalUnitIdList) { // Query the Device Manager to get logicalUnit details. try { LogicalUnit logicalUnit = getLogicalUnitInfo(systemObjectID, logicalUnitObjectId); if (null == logicalUnit || logicalUnit.getComposite() == 0) { continue; } if (logicalUnit.getComposite() == 1) { // Releasing LUSE don't delete underlying LDEV. // Should we delete them? releaseLUSE(systemObjectID, logicalUnitObjectId); } } catch (Exception e) { log.error(e.getMessage(), e); } } } } /** * Return the storagepool information. * * @param systemObjectId * @param poolObjectId * @return * @throws Exception */ public Pool getStoragePoolInfo(String systemObjectId, String poolObjectId) throws Exception { InputStream responseStream = null; Pool storagePool = null; String poolMethodType = null; Map<String, Object> attributeMap = new HashMap<String, Object>(); StorageArray storageArray = new StorageArray(systemObjectId); attributeMap.put(HDSConstants.STORAGEARRAY, storageArray); Get getOp = new Get(HDSConstants.STORAGEARRAY); attributeMap.put(HDSConstants.GET, getOp); Pool pool = new Pool(poolObjectId); if (poolObjectId.contains(HDSConstants.ARRAYGROUP)) { attributeMap.put(HDSConstants.ARRAY_GROUP, pool); poolMethodType = HDSConstants.GET_ARRAYGROUP_INFO_OP; } else if (poolObjectId.contains(HDSConstants.JOURNALPOOL)) { attributeMap.put(HDSConstants.JOURNAL_POOL, pool); poolMethodType = HDSConstants.GET_JOURNAL_POOL_INFO_OP; } String getStoragePoolInputXML = InputXMLGenerationClient.getInputXMLString( poolMethodType, attributeMap, HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE, HDSConstants.HITACHI_SMOOKS_CONFIG_FILE); URI endpointURI = hdsApiClient.getBaseURI(); log.info("Storagepool info query payload :{}", getStoragePoolInputXML); ClientResponse response = hdsApiClient.post(endpointURI, getStoragePoolInputXML); if (HttpStatus.SC_OK == response.getStatus()) { responseStream = response.getEntityInputStream(); JavaResult result = SmooksUtil.getParsedXMLJavaResult(responseStream, HDSConstants.SMOOKS_CONFIG_FILE); verifyErrorPayload(result); storagePool = result.getBean(Pool.class); } else { log.error("Get StoragePool info failed with invalid response code {}", response.getStatus()); throw HDSException.exceptions .invalidResponseFromHDS(String .format("Not able to query StoragePool info due to invalid response %1$s from server for system %2$s", response.getStatus(), systemObjectId)); } return storagePool; } /** * Utility method to check if there are any errors or not. * * @param javaResult * @throws Exception */ private void verifyErrorPayload(JavaResult javaResult) throws Exception { EchoCommand command = javaResult.getBean(EchoCommand.class); if (null == command || null == command.getStatus() || HDSConstants.FAILED_STR.equalsIgnoreCase(command.getStatus())) { Error error = javaResult.getBean(Error.class); if (command != null) { log.info("Error response received for messageID", command.getMessageID()); } log.info("command failed with error code: {} with message {}", error.getCode(), error.getDescription()); throw HDSException.exceptions.errorResponseReceived( error.getCode(), error.getDescription()); } } /** * Return the LogicalUnit info for the given logicalUnitObjectId. * * @param systemObjectId * @param logicalUnitObjectId * @return * @throws Exception */ public LogicalUnit getLogicalUnitInfo(String systemObjectId, String logicalUnitObjectId) throws Exception { InputStream responseStream = null; LogicalUnit logicalUnit = null; Map<String, Object> attributeMap = new HashMap<String, Object>(); StorageArray storageArray = new StorageArray(systemObjectId); Get getOp = new Get(HDSConstants.STORAGEARRAY); attributeMap.put(HDSConstants.STORAGEARRAY, storageArray); attributeMap.put(HDSConstants.GET, getOp); LogicalUnit lu = new LogicalUnit(logicalUnitObjectId, null); attributeMap.put(HDSConstants.LOGICALUNIT, lu); String getLogicalUnitsInputXML = InputXMLGenerationClient.getInputXMLString( HDSConstants.GET_LOGICALUNITS_OP, attributeMap, HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE, HDSConstants.HITACHI_SMOOKS_CONFIG_FILE); URI endpointURI = hdsApiClient.getBaseURI(); log.info("Volume info query payload :{}", getLogicalUnitsInputXML); ClientResponse response = hdsApiClient.post(endpointURI, getLogicalUnitsInputXML); if (HttpStatus.SC_OK == response.getStatus()) { responseStream = response.getEntityInputStream(); JavaResult result = SmooksUtil.getParsedXMLJavaResult(responseStream, HDSConstants.SMOOKS_CONFIG_FILE); verifyErrorPayload(result); logicalUnit = (LogicalUnit) result.getBean(HDSConstants.LOGICALUNIT_BEAN_NAME); } else { log.error("Get LogicalUnit info failed with invalid response code {}", response.getStatus()); throw HDSException.exceptions .invalidResponseFromHDS(String .format("Not able to query LogicalUnit info due to invalid response %1$s from server for system %2$s", response.getStatus(), systemObjectId)); } return logicalUnit; } /** * Form a single meta volume by concatenating multiple volumes. * * @param systemObjectId * @param ldevIds * @return * @throws Exception */ public LogicalUnit addLUSE(String systemObjectId, String metaHead, List<String> ldevIds) throws Exception { String addLUSEQuery = constructAddLUSEQuery(systemObjectId, metaHead, ldevIds); URI endpointURI = hdsApiClient.getBaseURI(); InputStream responseStream = null; LogicalUnit logicalUnit = null; try { log.info("Add LUSE Query payload :{}", addLUSEQuery); ClientResponse response = hdsApiClient.post(endpointURI, addLUSEQuery); if (HttpStatus.SC_OK == response.getStatus()) { responseStream = response.getEntityInputStream(); JavaResult result = SmooksUtil.getParsedXMLJavaResult(responseStream, HDSConstants.SMOOKS_CONFIG_FILE); verifyErrorPayload(result); logicalUnit = (LogicalUnit) result.getBean(HDSConstants.LOGICALUNIT_BEAN_NAME); } else { log.error("AddLUSE failed with invalid response code {}", response.getStatus()); throw HDSException.exceptions .invalidResponseFromHDS(String .format("Not able to Add LUSE due to invalid response %1$s from server for system %2$s", response.getStatus(), systemObjectId)); } } finally { if (null != responseStream) { try { responseStream.close(); } catch (IOException e) { log.warn("IOException occurred while closing the response stream"); } } } return logicalUnit; } /** * This client method is responsible to release all the volumes in LUSE volume. * * @param systemObjectId * @param logicalUnitId * @return * @throws Exception */ public LogicalUnit releaseLUSE(String systemObjectId, String logicalUnitId) throws Exception { Map<String, Object> attributeMap = new HashMap<String, Object>(); StorageArray storageArray = new StorageArray(systemObjectId); attributeMap.put(HDSConstants.STORAGEARRAY, storageArray); Add addOp = new Add(HDSConstants.LUSE_TARGET); attributeMap.put(HDSConstants.GET, addOp); attributeMap.put(HDSConstants.LOGICALUNIT, logicalUnitId); String releaseLUSEVolumeInputXML = InputXMLGenerationClient.getInputXMLString( HDSConstants.RELEASE_LUSE_VOLUME_OP, attributeMap, HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE, HDSConstants.HITACHI_SMOOKS_CONFIG_FILE); URI endpointURI = hdsApiClient.getBaseURI(); InputStream responseStream = null; LogicalUnit logicalUnit = null; try { log.info("release LUSE Query payload :{}", releaseLUSEVolumeInputXML); ClientResponse response = hdsApiClient.post(endpointURI, releaseLUSEVolumeInputXML); if (HttpStatus.SC_OK == response.getStatus()) { responseStream = response.getEntityInputStream(); JavaResult result = SmooksUtil.getParsedXMLJavaResult(responseStream, HDSConstants.SMOOKS_CONFIG_FILE); verifyErrorPayload(result); logicalUnit = (LogicalUnit) result.getBean(HDSConstants.LOGICALUNIT_BEAN_NAME); } else { log.error("deleteLUSE failed with invalid response code {}", response.getStatus()); throw HDSException.exceptions .invalidResponseFromHDS(String .format("Not able to delete LUSE due to invalid response %1$s from server for system %2$s", response.getStatus(), systemObjectId)); } } finally { if (null != responseStream) { try { responseStream.close(); } catch (IOException e) { log.warn("IOException occurred while closing the response stream"); } } } return logicalUnit; } private String constructAddLUSEQuery(String systemId, String metaHead, List<String> ldevIds) { Map<String, Object> attributeMap = new HashMap<String, Object>(); List<LDEV> ldevsList = new LinkedList<LDEV>(); StorageArray storageArray = new StorageArray(systemId); attributeMap.put(HDSConstants.STORAGEARRAY, storageArray); Add addOp = new Add(HDSConstants.LUSE_TARGET, true); attributeMap.put(HDSConstants.ADD, addOp); if (null != ldevIds && !ldevIds.isEmpty()) { LDEV metaHeadLDEV = new LDEV(metaHead); ldevsList.add(metaHeadLDEV); for (String ldevId : ldevIds) { LDEV metaMemberLDEV = new LDEV(ldevId); ldevsList.add(metaMemberLDEV); } } attributeMap.put("LDEV_List", ldevsList); String addLUSEVolumeInputXML = InputXMLGenerationClient.getInputXMLString( HDSConstants.ADD_LUSE_VOLUME_OP, attributeMap, HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE, HDSConstants.HITACHI_SMOOKS_CONFIG_FILE); return addLUSEVolumeInputXML; } /** * Returns all LogicalUnits of a given system. * * @param systemObjectId * @return */ public List<LogicalUnit> getAllLogicalUnits(String systemObjectId) throws Exception { InputStream responseStream = null; List<LogicalUnit> luList = null; Map<String, Object> attributeMap = new HashMap<String, Object>(); StorageArray storageArray = new StorageArray(systemObjectId); attributeMap.put(HDSConstants.STORAGEARRAY, storageArray); Get getOp = new Get(HDSConstants.STORAGEARRAY); attributeMap.put(HDSConstants.GET, getOp); LogicalUnit lu = new LogicalUnit(); attributeMap.put(HDSConstants.LOGICALUNIT, lu); String getLogicalUnitsInputXML = InputXMLGenerationClient.getInputXMLString( HDSConstants.GET_LOGICALUNITS_OP, attributeMap, HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE, HDSConstants.HITACHI_SMOOKS_CONFIG_FILE); URI endpointURI = hdsApiClient.getBaseURI(); log.info("Get all LogicalUnits query payload :{}", getLogicalUnitsInputXML); ClientResponse response = hdsApiClient.post(endpointURI, getLogicalUnitsInputXML); if (HttpStatus.SC_OK == response.getStatus()) { responseStream = response.getEntityInputStream(); JavaResult result = SmooksUtil.getParsedXMLJavaResult(responseStream, HDSConstants.SMOOKS_CONFIG_FILE); verifyErrorPayload(result); luList = (List<LogicalUnit>) result.getBean(HDSConstants.LOGICALUNIT_LIST_BEAN_NAME); } else { log.error("Get all LogicalUnits failed with invalid response code {}", response.getStatus()); throw HDSException.exceptions .invalidResponseFromHDS(String .format("Not able to query all LogicalUnits due to invalid response %1$s from server for system %2$s", response.getStatus(), systemObjectId)); } return luList; } /** * Adds the label to an Object in DeviceManager. * Currently this is supported for labeling LDEV. * So, targetID must be a LDEV ID of a LU. * * @param targetID * @param label * @return * @throws Exception */ public ObjectLabel addLabelToObject(String targetID, String label) throws Exception { InputStream responseStream = null; ObjectLabel objectLabel = null; Map<String, Object> attributeMap = new HashMap<String, Object>(); Add addOp = new Add(HDSConstants.OBJECTLABEL); addOp.setOverwrite(Boolean.TRUE); attributeMap.put(HDSConstants.ADD, addOp); ObjectLabel objectLabelReq = new ObjectLabel(targetID, label); attributeMap.put(HDSConstants.OBJECTLABEL, objectLabelReq); String addLabelToObject = InputXMLGenerationClient.getInputXMLString( HDSConstants.ADD_LABEL_TO_OBJECT_OP, attributeMap, HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE, HDSConstants.HITACHI_SMOOKS_CONFIG_FILE); URI endpointURI = hdsApiClient.getBaseURI(); log.info("Add Label to Object payload :{}", addLabelToObject); ClientResponse response = hdsApiClient.post(endpointURI, addLabelToObject); if (HttpStatus.SC_OK == response.getStatus()) { responseStream = response.getEntityInputStream(); JavaResult result = SmooksUtil.getParsedXMLJavaResult(responseStream, HDSConstants.SMOOKS_CONFIG_FILE); verifyErrorPayload(result); objectLabel = result.getBean(ObjectLabel.class); } else { log.error("Add label to Object failed with invalid response code {}", response.getStatus()); throw HDSException.exceptions .invalidResponseFromHDS(String .format("Not able to Add Label to object due to invalid response %1$s from server", response.getStatus())); } return objectLabel; } public String modifyThinVolumeTieringPolicy(String systemObjectID, String luObjectID, String ldevObjectID, String tieringPolicyName, String model) { InputStream responseStream = null; String asyncTaskMessageId = null; Map<String, Object> attributeMap = new HashMap<String, Object>(); Modify modifyOp = new Modify(HDSConstants.VIRTUALVOLUME); StorageArray array = new StorageArray(systemObjectID); LogicalUnit logicalUnit = new LogicalUnit(); logicalUnit.setObjectID(luObjectID); LDEV ldev = new LDEV(ldevObjectID); ldev.setTierLevel(Integer.parseInt(tieringPolicyName)); attributeMap.put(HDSConstants.STORAGEARRAY, array); attributeMap.put(HDSConstants.MODIFY, modifyOp); attributeMap.put(HDSConstants.MODEL, model); attributeMap.put(HDSConstants.LOGICALUNIT, logicalUnit); attributeMap.put(HDSConstants.LDEV, ldev); String modifyThinVolumeTieringPolicyPayload = InputXMLGenerationClient.getInputXMLString( HDSConstants.MODIFY_THIN_VOLUME_OP, attributeMap, HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE, HDSConstants.HITACHI_SMOOKS_CONFIG_FILE); URI endpointURI = hdsApiClient.getBaseURI(); log.info("Modify Volume TieringPolicy payload:{}", modifyThinVolumeTieringPolicyPayload); ClientResponse response = hdsApiClient.post(endpointURI, modifyThinVolumeTieringPolicyPayload); if (HttpStatus.SC_OK == response.getStatus()) { responseStream = response.getEntityInputStream(); JavaResult result = SmooksUtil.getParsedXMLJavaResult(responseStream, HDSConstants.SMOOKS_CONFIG_FILE); EchoCommand command = result.getBean(EchoCommand.class); if (HDSConstants.PROCESSING_STR.equalsIgnoreCase(command.getStatus())) { asyncTaskMessageId = command.getMessageID(); } else if (HDSConstants.FAILED_STR.equalsIgnoreCase(command.getStatus())) { Error error = result.getBean(Error.class); log.error("Modify Volume TieringPolicy failed status messageID: {}", command.getMessageID()); log.error("Modify Volume TieringPolicy failed with error code: {} with message: {}", error.getCode(), error.getDescription()); throw HDSException.exceptions.notAbleToCreateVolume( error.getCode(), error.getDescription()); } } else { log.error("Modify Volume TieringPolicy failed with invalid response code {}", response.getStatus()); throw HDSException.exceptions .invalidResponseFromHDS(String .format("Modify Volume TieringPolicy failed due to invalid response %1$s from server for system %2$s", response.getStatus(), systemObjectID)); } return asyncTaskMessageId; } public String createSnapshotVolume(String systemObjectId, Long luCapacityInBytes, String model) throws Exception { Long luCapacityInKB = luCapacityInBytes / 1024; InputStream responseStream = null; String asyncTaskMessageId = null; try { log.info("Creating snapshot with {}KB size on Storage System {}", luCapacityInKB, systemObjectId); Map<String, Object> attributeMap = new HashMap<String, Object>(); Add addOp = new Add(HDSConstants.VIRTUALVOLUME); StorageArray storageArray = new StorageArray(systemObjectId); ArrayGroup arrayGroup = new ArrayGroup(); arrayGroup.setType("2"); LogicalUnit logicalUnit = new LogicalUnit(); logicalUnit.setCapacityInKB(String.valueOf(luCapacityInKB)); logicalUnit.setEmulation(HDSConstants.EMULATION_OPENV); attributeMap.put(HDSConstants.STORAGEARRAY, storageArray); attributeMap.put(HDSConstants.MODEL, model); attributeMap.put(HDSConstants.ARRAY_GROUP, arrayGroup); attributeMap.put(HDSConstants.ADD, addOp); attributeMap.put(HDSConstants.LOGICALUNIT, logicalUnit); String createSnapshotInputXML = InputXMLGenerationClient.getInputXMLString( HDSConstants.CREATE_SNAPSHOT_VOLUME_OP, attributeMap, HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE, HDSConstants.HITACHI_SMOOKS_CONFIG_FILE); log.info("Query to create snapshot Volume: {}", createSnapshotInputXML); URI endpointURI = hdsApiClient.getBaseURI(); ClientResponse response = hdsApiClient.post(endpointURI, createSnapshotInputXML); if (HttpStatus.SC_OK == response.getStatus()) { responseStream = response.getEntityInputStream(); JavaResult result = SmooksUtil.getParsedXMLJavaResult(responseStream, HDSConstants.SMOOKS_CONFIG_FILE); EchoCommand command = result.getBean(EchoCommand.class); if (HDSConstants.PROCESSING_STR.equalsIgnoreCase(command.getStatus())) { asyncTaskMessageId = command.getMessageID(); } else if (HDSConstants.FAILED_STR.equalsIgnoreCase(command.getStatus())) { Error error = result.getBean(Error.class); log.error("Thin snapshot creation failed status messageID: {}", command.getMessageID()); log.error("Thin snapshot creation failed with error code: {} with message: {}", error.getCode(), error.getDescription()); throw HDSException.exceptions.notAbleToCreateSnapshot( error.getCode(), error.getDescription()); } } else { log.error("Thin snapshot creation failed with invalid response code {}", response.getStatus()); throw HDSException.exceptions .invalidResponseFromHDS(String .format("Thin snapshot creation failed due to invalid response %1$s from server for system %2$s", response.getStatus(), systemObjectId)); } log.info("Snapshot creation initiated on Storage System {}", systemObjectId); } finally { if (null != responseStream) { try { responseStream.close(); } catch (IOException e) { log.warn("Exception occurred while closing snapshot creation response stream"); } } } return asyncTaskMessageId; } public String deleteSnapshotVolume(String storageSystemObjId, String logicalUnitObjId, String model) throws Exception { String asyncTaskMessageId = null; InputStream responseStream = null; try { if (null != storageSystemObjId && null != logicalUnitObjId) { log.info("Deleting snapshot with id {} from Storage System {}", logicalUnitObjId, storageSystemObjId); Map<String, Object> attributeMap = new HashMap<String, Object>(); Delete deleteOp = new Delete(HDSConstants.VIRTUALVOLUME); StorageArray storageArray = new StorageArray(storageSystemObjId); LogicalUnit logicalUnit = new LogicalUnit(); logicalUnit.setObjectID(logicalUnitObjId); attributeMap.put(HDSConstants.DELETE, deleteOp); attributeMap.put(HDSConstants.MODEL, model); attributeMap.put(HDSConstants.STORAGEARRAY, storageArray); attributeMap.put(HDSConstants.LOGICALUNIT, logicalUnit); String createSnapshotInputXML = InputXMLGenerationClient.getInputXMLString( HDSConstants.DELETE_SNAPSHOT_VOLUME_OP, attributeMap, HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE, HDSConstants.HITACHI_SMOOKS_CONFIG_FILE); log.info("Query to delete snapshot Volume: {}", createSnapshotInputXML); URI endpointURI = hdsApiClient.getBaseURI(); ClientResponse response = hdsApiClient.post(endpointURI, createSnapshotInputXML); if (HttpStatus.SC_OK == response.getStatus()) { responseStream = response.getEntityInputStream(); JavaResult result = SmooksUtil.getParsedXMLJavaResult(responseStream, HDSConstants.SMOOKS_CONFIG_FILE); EchoCommand command = result.getBean(EchoCommand.class); if (HDSConstants.PROCESSING_STR.equalsIgnoreCase(command.getStatus())) { asyncTaskMessageId = command.getMessageID(); } else if (HDSConstants.FAILED_STR.equalsIgnoreCase(command.getStatus())) { Error error = result.getBean(Error.class); log.error("Snapshot volume deletion failed status messageID: {}", command.getMessageID()); log.error("Snapshot volume failed with error code: {} with message: {}", error.getCode(), error.getDescription()); throw HDSException.exceptions.notAbleToDeleteSnapshot( error.getCode(), error.getDescription()); } } else { log.error("Snapshot deletion failed with invalid response code {}", response.getStatus()); throw HDSException.exceptions .invalidResponseFromHDS(String .format("Snapshot deletion failed due to invalid response %1$s from server for system %2$s", response.getStatus(), storageSystemObjId)); } log.info("Snapshot with id {} deleted from Storage System {}", logicalUnitObjId, storageSystemObjId); } } finally { if (null != responseStream) { try { responseStream.close(); } catch (IOException e) { log.warn("Exception occurred while closing snapshot deletion response stream"); } } } return asyncTaskMessageId; } }