/*
* 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.List;
import java.util.Map;
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.Delete;
import com.emc.storageos.hds.model.EchoCommand;
import com.emc.storageos.hds.model.Error;
import com.emc.storageos.hds.model.FreeLun;
import com.emc.storageos.hds.model.Get;
import com.emc.storageos.hds.model.HDSHost;
import com.emc.storageos.hds.model.HostStorageDomain;
import com.emc.storageos.hds.model.ISCSIName;
import com.emc.storageos.hds.model.Path;
import com.emc.storageos.hds.model.StorageArray;
import com.emc.storageos.hds.model.WorldWideName;
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 HDSApiExportManager {
/**
* Logger instance to log messages.
*/
private static final Logger log = LoggerFactory.getLogger(HDSApiExportManager.class);
private static final int MAX_RETRIES = 10;
private HDSApiClient hdsApiClient;
public HDSApiExportManager(HDSApiClient hdsApiClient) {
this.hdsApiClient = hdsApiClient;
}
/**
* Register the given host with HiCommand Device Manager.
*
* @param hostName
* @param ipAddress
* @param portWWN
* @return
* @throws Exception
*/
public HDSHost registerHost(HDSHost hdshost, List<String> portWWNList,
String initiatorType) throws Exception {
String addHostQueryWithParams = null;
InputStream responseStream = null;
HDSHost registeredhost = null;
try {
if (initiatorType.equalsIgnoreCase(HDSConstants.FC)) {
addHostQueryWithParams = constructAddFCInitiatorHostQuery(hdshost, portWWNList);
} else if (initiatorType.equalsIgnoreCase(HDSConstants.ISCSI)) {
addHostQueryWithParams = constructAddiSCSIInitiatorHostQuery(hdshost, portWWNList);
}
log.info("Query to Add host: {}", addHostQueryWithParams);
URI endpointURI = hdsApiClient.getBaseURI();
ClientResponse response = hdsApiClient.post(endpointURI,
addHostQueryWithParams);
if (HttpStatus.SC_OK == response.getStatus()) {
responseStream = response.getEntityInputStream();
JavaResult javaResult = SmooksUtil.getParsedXMLJavaResult(responseStream,
HDSConstants.HOST_INFO_SMOOKS_CONFIG_FILE);
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 (error.getCode() == HDSConstants.HOST_ALREADY_EXISTS) {
log.info("The host {} already exists on DeviceManager", hdshost.getName());
return registeredhost;
}
else if (error.getCode() == HDSConstants.HOST_PORT_WWN_ALREADY_EXISTS) {
log.info("The WWN is already in use by another host");
return registeredhost;
} else {
log.error("Error response received for messageID", command.getMessageID());
log.error("command failed with error code: {} with message {}",
error.getCode(), error.getDescription());
throw HDSException.exceptions.notAbleToAddHostToDeviceManager(
hdshost.getName());
}
}
registeredhost = javaResult.getBean(HDSHost.class);
if (null == registeredhost) {
throw HDSException.exceptions.notAbleToAddHostToDeviceManager(String
.format("Not able to add host:%1$s to Device manager",
hdshost.getName()));
}
} else {
throw HDSException.exceptions
.invalidResponseFromHDS(String
.format("Add Host to Device Manager failed due to invalid response %1$s from server",
response.getStatus()));
}
} finally {
if (null != responseStream) {
try {
responseStream.close();
} catch (IOException e) {
log.warn("IOException occurred while closing the response stream");
}
}
}
return registeredhost;
}
/**
* Gets host registered with HiCommand Device Manager.
*
* @return
* @throws Exception
*/
@SuppressWarnings("unchecked")
public List<HDSHost> getHostsRegisteredWithDM() throws Exception {
InputStream responseStream = null;
List<HDSHost> hostList = null;
try {
Map<String, Object> attributeMap = new HashMap<String, Object>();
Get getOp = new Get("Host");
attributeMap.put("Get", getOp);
String getHostQuery = InputXMLGenerationClient
.getInputXMLString("getHostsInfo", attributeMap,
HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE,
HDSConstants.HITACHI_SMOOKS_CONFIG_FILE);
log.info("Query to Add host: {}", getHostQuery);
URI endpointURI = hdsApiClient.getBaseURI();
ClientResponse response = hdsApiClient.post(endpointURI,
getHostQuery);
if (HttpStatus.SC_OK == response.getStatus()) {
responseStream = response.getEntityInputStream();
JavaResult javaResult = SmooksUtil.getParsedXMLJavaResult(responseStream,
HDSConstants.HOST_INFO_SMOOKS_CONFIG_FILE);
verifyErrorPayload(javaResult);
hostList = (List<HDSHost>) javaResult
.getBean(HDSConstants.HOST_LIST_BEAN_NAME);
if (null == hostList || hostList.isEmpty()) {
throw HDSException.exceptions.notAbleToGetHostInfoForHSD();
}
} else {
throw HDSException.exceptions
.invalidResponseFromHDS(String
.format("Not able to Get registered hosts from Device Manager failed due to invalid response %1$s from server",
response.getStatus()));
}
} finally {
if (null != responseStream) {
try {
responseStream.close();
} catch (IOException e) {
log.warn("IOException occurred while closing the response stream");
}
}
}
return hostList;
}
/**
* Constructs the addHostQuery.
*
* @param hostName
* @param ipAddress
* @param portWWNList
* @return
*/
private String constructAddFCInitiatorHostQuery(HDSHost hdshost, List<String> portWWNList) {
Map<String, Object> attributeMap = new HashMap<String, Object>();
List<WorldWideName> wwnList = new ArrayList<WorldWideName>();
Add addOp = new Add(HDSConstants.HOST);
attributeMap.put(HDSConstants.HOST, hdshost);
attributeMap.put(HDSConstants.ADD, addOp);
if (null != portWWNList && !portWWNList.isEmpty()) {
for (String portWWN : portWWNList) {
WorldWideName wwn = new WorldWideName(portWWN);
wwnList.add(wwn);
}
hdshost.setWwnList(wwnList);
}
attributeMap.put(HDSConstants.WWN_LIST, wwnList);
String addHostWithWorldWideNamesQuery = InputXMLGenerationClient
.getInputXMLString(HDSConstants.ADD_HOST_WITH_WWN_OP, attributeMap,
HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE,
HDSConstants.HITACHI_SMOOKS_CONFIG_FILE);
return addHostWithWorldWideNamesQuery;
}
/**
* Constructs the addHostQuery.
*
* @param hostName
* @param ipAddress
* @param portWWNList
* @return
*/
private String constructAddiSCSIInitiatorHostQuery(HDSHost hdshost, List<String> portWWNList) {
Map<String, Object> attributeMap = new HashMap<String, Object>();
List<ISCSIName> wwnList = new ArrayList<ISCSIName>();
Add addOp = new Add(HDSConstants.HOST);
attributeMap.put(HDSConstants.HOST, hdshost);
attributeMap.put(HDSConstants.ADD, addOp);
if (null != portWWNList && !portWWNList.isEmpty()) {
for (String portWWN : portWWNList) {
ISCSIName wwn = new ISCSIName(portWWN, null);
wwnList.add(wwn);
}
}
attributeMap.put(HDSConstants.ISCSINAME_LIST, wwnList);
String addHostWithISCSINamesQuery = InputXMLGenerationClient
.getInputXMLString(HDSConstants.ADD_HOST_WITH_ISCSINAMES_OP, attributeMap,
HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE,
HDSConstants.HITACHI_SMOOKS_CONFIG_FILE);
return addHostWithISCSINamesQuery;
}
/**
* Add WWN to the HostStorageDomain means enable LUN security by adding WWN.
*
* @param systemId
* @param hsdId
* @param wwnList
* @param model
* @return
* @throws Exception
*/
public HostStorageDomain addWWNToHostStorageDomain(String systemId, String hsdId,
List<String> wwnList, String model) throws Exception {
InputStream responseStream = null;
HostStorageDomain hsd = null;
try {
String addWWNToHSDQuery = constructWWNQuery(systemId, hsdId, wwnList, model);
log.info("Query to add FC initiators to HostStorageDomain: {}", addWWNToHSDQuery);
URI endpointURI = hdsApiClient.getBaseURI();
ClientResponse response = hdsApiClient.post(endpointURI, addWWNToHSDQuery);
if (HttpStatus.SC_OK == response.getStatus()) {
responseStream = response.getEntityInputStream();
JavaResult javaResult = SmooksUtil.getParsedXMLJavaResult(responseStream,
HDSConstants.SMOOKS_CONFIG_FILE);
verifyErrorPayload(javaResult);
hsd = javaResult.getBean(HostStorageDomain.class);
if (null == hsd) {
throw HDSException.exceptions
.notAbleToAddInitiatorToHostStorageDomain("FC",
hsdId, systemId);
}
} else {
throw HDSException.exceptions
.invalidResponseFromHDS(String
.format("Add initiator to HostStorageDomain failed due to invalid response %1$s from server",
response.getStatus()));
}
} finally {
if (null != responseStream) {
try {
responseStream.close();
} catch (IOException e) {
log.warn("IOException occurred while closing the response stream");
}
}
}
return hsd;
}
/**
* Remove given WWN's from HostStorageDomain means disable LUN security by removing these WWN's.
*
* @param systemId
* @param hsdId
* @param wwnList
* @param model
* @return
* @throws Exception
*/
public void deleteWWNsFromHostStorageDomain(String systemId, String hsdId,
List<String> wwnList, String model) throws Exception {
InputStream responseStream = null;
try {
String removeWWNFromHSDQuery = constructDeleteWWNQuery(systemId, hsdId, wwnList, model);
log.info("Query to delete FC initiators to HostStorageDomain: {}", removeWWNFromHSDQuery);
URI endpointURI = hdsApiClient.getBaseURI();
ClientResponse response = hdsApiClient.post(endpointURI, removeWWNFromHSDQuery);
if (HttpStatus.SC_OK == response.getStatus()) {
responseStream = response.getEntityInputStream();
JavaResult javaResult = SmooksUtil.getParsedXMLJavaResult(responseStream,
HDSConstants.SMOOKS_CONFIG_FILE);
verifyErrorPayload(javaResult);
log.info("Remove fc initiators: {} from HSD: {}", wwnList, hsdId);
} else {
throw HDSException.exceptions
.invalidResponseFromHDS(String
.format("Deleting initiator from HostStorageDomain failed due to response %1$s from server",
response.getStatus()));
}
} finally {
if (null != responseStream) {
try {
responseStream.close();
} catch (IOException e) {
log.warn("IOException occurred while closing the response stream");
}
}
}
}
/**
* Add WWN to the HostStorageDomain means enable LUN security by adding WWN.
*
* @param systemId
* @param hsdId
* @param scsiNameList
* @param model
* @return
* @throws Exception
*/
public HostStorageDomain addISCSIInitatorsToHostStorageDomain(String systemId, String hsdId,
List<String> scsiNameList, String model) throws Exception {
InputStream responseStream = null;
HostStorageDomain hsd = null;
try {
String addISCSINamesToHSDQuery = constructISCSIQuery(systemId, hsdId, scsiNameList, model);
log.info("Query to add SCSI Initiators to HostStorageDomain: {}", addISCSINamesToHSDQuery);
URI endpointURI = hdsApiClient.getBaseURI();
ClientResponse response = hdsApiClient.post(endpointURI, addISCSINamesToHSDQuery);
if (HttpStatus.SC_OK == response.getStatus()) {
responseStream = response.getEntityInputStream();
JavaResult javaResult = SmooksUtil.getParsedXMLJavaResult(responseStream,
HDSConstants.SMOOKS_CONFIG_FILE);
verifyErrorPayload(javaResult);
hsd = javaResult.getBean(HostStorageDomain.class);
if (null == hsd) {
throw HDSException.exceptions
.notAbleToAddInitiatorToHostStorageDomain("iSCSI",
hsdId, systemId);
}
} else {
throw HDSException.exceptions
.invalidResponseFromHDS(String
.format("Add iSCSI initiator to HostStorageDomain failed due to invalid response %1$s from server",
response.getStatus()));
}
} finally {
if (null != responseStream) {
try {
responseStream.close();
} catch (IOException e) {
log.warn("IOException occurred while closing the response stream");
}
}
}
return hsd;
}
/**
* Remove ISCSIName from the HostStorageDomain means disable LUN security by to the given iSCSIName.
*
* @param systemId
* @param hsdId
* @param scsiNameList
* @param model
* @return
* @throws Exception
*/
public void deleteISCSIsFromHostStorageDomain(String systemId, String hsdId,
List<String> scsiNameList, String model) throws Exception {
InputStream responseStream = null;
try {
String addISCSINamesToHSDQuery = constructRemoveISCSIQuery(systemId, hsdId, scsiNameList, model);
log.info("Query to remove SCSI Initiators from HostStorageDomain: {}", addISCSINamesToHSDQuery);
URI endpointURI = hdsApiClient.getBaseURI();
ClientResponse response = hdsApiClient.post(endpointURI, addISCSINamesToHSDQuery);
if (HttpStatus.SC_OK == response.getStatus()) {
responseStream = response.getEntityInputStream();
JavaResult javaResult = SmooksUtil.getParsedXMLJavaResult(responseStream,
HDSConstants.SMOOKS_CONFIG_FILE);
verifyErrorPayload(javaResult);
log.info("Remove iscsi initiators: {} from HSD: {}", scsiNameList, hsdId);
} else {
throw HDSException.exceptions
.invalidResponseFromHDS(String
.format("Remove iSCSI initiator From HostStorageDomain failed due to invalid response %1$s from server",
response.getStatus()));
}
} finally {
if (null != responseStream) {
try {
responseStream.close();
} catch (IOException e) {
log.warn("IOException occurred while closing the response stream");
}
}
}
}
/**
* 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);
log.info("Error response received from Hitachi server for messageID", command.getMessageID());
log.info("Hitachi command failed with error code:{} with message:{} for request:{}",
new Object[] { error.getCode().toString(), error.getDescription(), error.getSource() });
throw HDSException.exceptions.errorResponseReceived(
error.getCode(), error.getDescription());
}
}
/**
* Return the existing HSD's configured on the storage array.
*
* @param systemId
* @param type
* @return
* @throws Exception
*/
public List<HostStorageDomain> getHostStorageDomains(String systemId)
throws Exception {
InputStream responseStream = null;
StorageArray storageArray = null;
List<HostStorageDomain> hsdList = null;
try {
Map<String, Object> attributeMap = new HashMap<String, Object>();
StorageArray array = new StorageArray(systemId);
attributeMap.put(HDSConstants.STORAGEARRAY, array);
Get getOp = new Get(HDSConstants.STORAGEARRAY);
attributeMap.put(HDSConstants.GET, getOp);
HostStorageDomain hsd = new HostStorageDomain();
attributeMap.put(HDSConstants.HOST_STORAGE_DOMAIN, hsd);
String getAllHSDQuery = InputXMLGenerationClient.getInputXMLString(
HDSConstants.GET_HSD_INFO_OP, attributeMap,
HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE,
HDSConstants.HITACHI_SMOOKS_CONFIG_FILE);
log.info("Query to get HostStorageDomain: {}", getAllHSDQuery);
URI endpointURI = hdsApiClient.getBaseURI();
ClientResponse response = hdsApiClient.post(endpointURI, getAllHSDQuery);
if (HttpStatus.SC_OK == response.getStatus()) {
responseStream = response.getEntityInputStream();
JavaResult javaResult = SmooksUtil.getParsedXMLJavaResult(responseStream,
HDSConstants.SMOOKS_CONFIG_FILE);
verifyErrorPayload(javaResult);
storageArray = javaResult.getBean(StorageArray.class);
if (null != storageArray) {
hsdList = storageArray.getHsdList();
}
} else {
throw HDSException.exceptions
.invalidResponseFromHDS(String
.format("Not able to query HostStorageDomain's due to invalid response %1$s from server",
response.getStatus()));
}
} finally {
if (null != responseStream) {
try {
responseStream.close();
} catch (IOException e) {
log.warn("IOException occurred while closing the response stream");
}
}
}
return hsdList;
}
/**
* Return the existing HSD's configured on the storage array.
*
* @param systemId
* @param type
* @return
* @throws Exception
*/
public HostStorageDomain getHostStorageDomain(String systemId, String hsdId)
throws Exception {
InputStream responseStream = null;
HostStorageDomain hsd = null;
try {
Map<String, Object> attributeMap = new HashMap<String, Object>();
StorageArray array = new StorageArray(systemId);
attributeMap.put(HDSConstants.STORAGEARRAY, array);
Get getOp = new Get(HDSConstants.STORAGEARRAY);
attributeMap.put(HDSConstants.GET, getOp);
HostStorageDomain inputHsd = new HostStorageDomain(hsdId);
attributeMap.put(HDSConstants.HOST_STORAGE_DOMAIN, inputHsd);
String getHSDQuery = InputXMLGenerationClient.getInputXMLString(
HDSConstants.GET_HSD_INFO_OP, attributeMap,
HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE,
HDSConstants.HITACHI_SMOOKS_CONFIG_FILE);
log.info("Query to get HostStorageDomain: {}", getHSDQuery);
URI endpointURI = hdsApiClient.getBaseURI();
ClientResponse response = hdsApiClient.post(endpointURI, getHSDQuery);
if (HttpStatus.SC_OK == response.getStatus()) {
responseStream = response.getEntityInputStream();
JavaResult javaResult = SmooksUtil.getParsedXMLJavaResult(responseStream,
HDSConstants.SMOOKS_CONFIG_FILE);
verifyErrorPayload(javaResult);
hsd = javaResult.getBean(HostStorageDomain.class);
} else {
throw HDSException.exceptions
.invalidResponseFromHDS(String
.format("Not able to query HostStorageDomain due to invalid response %1$s from server",
response.getStatus()));
}
} finally {
if (null != responseStream) {
try {
responseStream.close();
} catch (IOException e) {
log.warn("IOException occurred while closing the response stream");
}
}
}
return hsd;
}
/**
* Construct the WWN Query by adding multiple WWNs.
* This query should be used to add FC initiators to the FC HSD.
*
* @param systemId
* @param hsdId
* @param wwnList
* @return
*/
private String constructWWNQuery(String systemId, String hsdId, List<String> wwnList, String model) {
Map<String, Object> attributeMap = new HashMap<String, Object>();
StorageArray array = new StorageArray(systemId);
Add addOp = new Add(HDSConstants.ADD_WWN_TO_HSD_TARGET);
attributeMap.put(HDSConstants.STORAGEARRAY, array);
attributeMap.put(HDSConstants.ADD, addOp);
attributeMap.put(HDSConstants.MODEL, model);
HostStorageDomain hsd = new HostStorageDomain(hsdId);
attributeMap.put(HDSConstants.HOST_STORAGE_DOMAIN, hsd);
List<WorldWideName> wwnObjList = new ArrayList<WorldWideName>();
if (null != wwnList && !wwnList.isEmpty()) {
for (String initiatorWWN : wwnList) {
WorldWideName wwn = new WorldWideName(initiatorWWN);
wwnObjList.add(wwn);
}
}
attributeMap.put(HDSConstants.WWN_LIST, wwnObjList);
String addWWNQuery = InputXMLGenerationClient.getInputXMLString(
HDSConstants.ADD_WWN_TO_HSD_OP, attributeMap,
HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE,
HDSConstants.HITACHI_SMOOKS_CONFIG_FILE);
return addWWNQuery;
}
/**
* Construct the WWN Query by adding multiple WWNs.
* This query should be used to add FC initiators to the FC HSD.
*
* @param systemId
* @param hsdId
* @param wwnList
* @return
*/
private String constructDeleteWWNQuery(String systemId, String hsdId, List<String> wwnList, String model) {
Map<String, Object> attributeMap = new HashMap<String, Object>();
StorageArray array = new StorageArray(systemId);
Delete deleteOp = new Delete(HDSConstants.ADD_WWN_TO_HSD_TARGET);
attributeMap.put(HDSConstants.STORAGEARRAY, array);
attributeMap.put(HDSConstants.DELETE, deleteOp);
attributeMap.put(HDSConstants.MODEL, model);
HostStorageDomain hsd = new HostStorageDomain(hsdId);
attributeMap.put(HDSConstants.HOST_STORAGE_DOMAIN, hsd);
List<WorldWideName> wwnObjList = new ArrayList<WorldWideName>();
if (null != wwnList && !wwnList.isEmpty()) {
for (String initiatorWWN : wwnList) {
WorldWideName wwn = new WorldWideName(initiatorWWN);
wwnObjList.add(wwn);
}
}
attributeMap.put(HDSConstants.WWN_LIST, wwnObjList);
String deleteWWNFromHSDQuery = InputXMLGenerationClient.getInputXMLString(
HDSConstants.DELETE_WWN_FROM_HSD_OP, attributeMap,
HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE,
HDSConstants.HITACHI_SMOOKS_CONFIG_FILE);
return deleteWWNFromHSDQuery;
}
/**
* Construct the iSCSINames Query by adding multiple WWNs.
* This query should be used to add the iSCSI initiators to the iSCSI HSD.
*
* @param systemId
* @param hsdId
* @param wwnList
* @return
*/
private String constructISCSIQuery(String systemId, String hsdId, List<String> scsiNameList, String model) {
Map<String, Object> attributeMap = new HashMap<String, Object>();
StorageArray array = new StorageArray(systemId);
Add addOp = new Add(HDSConstants.ISCSI_NAME_FOR_HSD_TARGET);
attributeMap.put(HDSConstants.STORAGEARRAY, array);
attributeMap.put(HDSConstants.ADD, addOp);
attributeMap.put(HDSConstants.MODEL, model);
HostStorageDomain hsd = new HostStorageDomain(hsdId);
attributeMap.put(HDSConstants.HOST_STORAGE_DOMAIN, hsd);
List<ISCSIName> iSCSIObjList = new ArrayList<ISCSIName>();
if (null != scsiNameList && !scsiNameList.isEmpty()) {
for (String iScsiName : scsiNameList) {
ISCSIName iSCSIName = new ISCSIName(iScsiName, null);
iSCSIObjList.add(iSCSIName);
}
}
attributeMap.put(HDSConstants.ISCSINAME_LIST, iSCSIObjList);
String addISCSINamesToHSDQuery = InputXMLGenerationClient.getInputXMLString(
HDSConstants.ADD_ISCSI_NAME_TO_HSD_OP, attributeMap,
HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE,
HDSConstants.HITACHI_SMOOKS_CONFIG_FILE);
return addISCSINamesToHSDQuery;
}
/**
* Construct the iSCSINames Query by adding multiple WWNs.
* This query should be used to add the iSCSI initiators to the iSCSI HSD.
*
* @param systemId
* @param hsdId
* @param wwnList
* @return
*/
private String constructRemoveISCSIQuery(String systemId, String hsdId, List<String> scsiNameList, String model) {
Map<String, Object> attributeMap = new HashMap<String, Object>();
StorageArray array = new StorageArray(systemId);
Delete deleteOp = new Delete(HDSConstants.ISCSI_NAME_FOR_HSD_TARGET);
attributeMap.put(HDSConstants.STORAGEARRAY, array);
attributeMap.put(HDSConstants.DELETE, deleteOp);
attributeMap.put(HDSConstants.MODEL, model);
HostStorageDomain hsd = new HostStorageDomain(hsdId);
attributeMap.put(HDSConstants.HOST_STORAGE_DOMAIN, hsd);
List<ISCSIName> iSCSIObjList = new ArrayList<ISCSIName>();
if (null != scsiNameList && !scsiNameList.isEmpty()) {
for (String iScsiName : scsiNameList) {
ISCSIName iSCSIName = new ISCSIName(iScsiName, null);
iSCSIObjList.add(iSCSIName);
}
}
attributeMap.put(HDSConstants.ISCSINAME_LIST, iSCSIObjList);
String removeISCSINamesToHSDQuery = InputXMLGenerationClient.getInputXMLString(
HDSConstants.REMOVE_ISCSI_NAME_FROM_HSD_OP, attributeMap,
HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE,
HDSConstants.HITACHI_SMOOKS_CONFIG_FILE);
return removeISCSINamesToHSDQuery;
}
/**
* Add new HostStorageDomain.
*
* @param systemId
* @param targetPortID
* @param hsdNickName
* @param hostMode.
* @param hostModeOption
* @param model
* @return
* @throws Exception
*/
public HostStorageDomain addHostStorageDomain(String systemId, String targetPortID,
String domainType, String hsdName, String hsdNickName, String hostMode,
String hostModeOption, String model) throws Exception {
InputStream responseStream = null;
HostStorageDomain hsd = null;
try {
Map<String, Object> attributeMap = new HashMap<String, Object>();
StorageArray array = new StorageArray(systemId);
Add addOp = new Add(HDSConstants.HOST_STORAGE_DOMAIN);
attributeMap.put(HDSConstants.STORAGEARRAY, array);
attributeMap.put(HDSConstants.ADD, addOp);
attributeMap.put(HDSConstants.MODEL, model);
HostStorageDomain inputHsd = new HostStorageDomain(targetPortID, hsdName, domainType, hsdNickName);
inputHsd.setHostMode(hostMode);
inputHsd.setHostModeOption(hostModeOption);
attributeMap.put(HDSConstants.HOST_STORAGE_DOMAIN, inputHsd);
String addHSDToSystemQuery = InputXMLGenerationClient.getInputXMLString(
HDSConstants.ADD_HSD_TO_SYSTEM_OP, attributeMap,
HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE,
HDSConstants.HITACHI_SMOOKS_CONFIG_FILE);
log.info("Query to create HostStorageDomain: {}", addHSDToSystemQuery);
URI endpointURI = hdsApiClient.getBaseURI();
ClientResponse response = hdsApiClient.post(endpointURI, addHSDToSystemQuery);
if (HttpStatus.SC_OK == response.getStatus()) {
responseStream = response.getEntityInputStream();
JavaResult javaResult = SmooksUtil.getParsedXMLJavaResult(responseStream,
HDSConstants.SMOOKS_CONFIG_FILE);
verifyErrorPayload(javaResult);
hsd = javaResult.getBean(HostStorageDomain.class);
if (null == hsd) {
throw HDSException.exceptions.notAbleToAddHSD(systemId);
}
} else {
throw HDSException.exceptions
.invalidResponseFromHDS(String
.format("Not able to add HostStorageDomain due to invalid response %1$s from server",
response.getStatus()));
}
} finally {
if (null != responseStream) {
try {
responseStream.close();
} catch (IOException e) {
log.warn("IOException occurred while closing the response stream");
}
}
}
return hsd;
}
/**
* API call to addLun to the storage array.
* Once the client makes the call, the luns should be visible to the host.
*
* @param systemId
* @param targetPortId
* @param domainId
* @param deviceLunList
* @param model
* @throws Exception
*/
public List<Path> addLUN(String systemId, String targetPortId, String domainId,
Map<String, String> deviceLunList, String model) throws Exception {
InputStream responseStream = null;
List<Path> pathList = new ArrayList<Path>();
try {
String addLUNQuery = constructAddLUNQuery(systemId, targetPortId, domainId,
deviceLunList, pathList, model);
log.info("Query to addLUN Query: {}", addLUNQuery);
URI endpointURI = hdsApiClient.getBaseURI();
ClientResponse response = hdsApiClient.post(endpointURI, addLUNQuery);
if (HttpStatus.SC_OK == response.getStatus()) {
responseStream = response.getEntityInputStream();
JavaResult javaResult = SmooksUtil.getParsedXMLJavaResult(responseStream,
HDSConstants.SMOOKS_CONFIG_FILE);
verifyErrorPayload(javaResult);
pathList = (List<Path>) javaResult.getBean(HDSConstants.PATHLIST_RESPONSE_BEANID);
if (pathList.isEmpty()) {
throw HDSException.exceptions.notAbleToAddVolumeToHSD(
domainId, systemId);
}
} else {
throw HDSException.exceptions
.invalidResponseFromHDS(String
.format("Not able to add Volume to HostStorageDomain due to invalid response %1$s from server",
response.getStatus()));
}
} finally {
if (null != responseStream) {
try {
responseStream.close();
} catch (IOException e) {
log.warn("IOException occurred while closing the response stream");
}
}
}
return pathList;
}
/**
* Constructs the addLun query using multiple path elements. Each path
* element defines the path from volume to initiators.
*
* @param systemId
* @param targetPortId
* @param domainId
* @param deviceLunList
* @param pathList
* @param model
* @return
* @throws Exception
*/
private String constructAddLUNQuery(String systemId, String targetPortId,
String domainId, Map<String, String> deviceLunList, List<Path> pathList, String model) throws Exception {
Map<String, Object> attributeMap = new HashMap<String, Object>();
StorageArray array = new StorageArray(systemId);
Add addOp = new Add(HDSConstants.LUN_TARGET);
attributeMap.put(HDSConstants.STORAGEARRAY, array);
attributeMap.put(HDSConstants.ADD, addOp);
attributeMap.put(HDSConstants.MODEL, model);
if (null != deviceLunList && !deviceLunList.isEmpty()) {
for (String device : deviceLunList.keySet()) {
String lun = deviceLunList.get(device);
Path path = new Path(targetPortId, domainId, null, lun, device);
pathList.add(path);
log.info("Device :{} lun:{}", device, lun);
}
}
attributeMap.put(HDSConstants.PATH_LIST, pathList);
String addLunInputXML = InputXMLGenerationClient.getInputXMLString(
HDSConstants.ADD_PATH_TO_HSD_OP, attributeMap,
HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE,
HDSConstants.HITACHI_SMOOKS_CONFIG_FILE);
return addLunInputXML;
}
/**
* Return the Free Lun's available for a Given HSD in a System.
*
* @throws Exception
*
*/
public List<FreeLun> getFreeLUNInfo(String systemId, String hsdId) throws Exception {
InputStream responseStream = null;
HostStorageDomain hostStorageDomain = null;
List<FreeLun> freeLunList = null;
try {
Map<String, Object> attributeMap = new HashMap<String, Object>();
StorageArray array = new StorageArray(systemId);
Get getOp = new Get(HDSConstants.STORAGEARRAY);
attributeMap.put(HDSConstants.STORAGEARRAY, array);
HostStorageDomain hsd = new HostStorageDomain(hsdId);
FreeLun freeLun = new FreeLun();
attributeMap.put(HDSConstants.GET, getOp);
attributeMap.put(HDSConstants.HOST_STORAGE_DOMAIN, hsd);
attributeMap.put(HDSConstants.FREELUN, freeLun);
String getFreeLunQueryInputXML = InputXMLGenerationClient.getInputXMLString(
HDSConstants.GET_FREE_LUN_INFO_OP, attributeMap,
HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE,
HDSConstants.HITACHI_SMOOKS_CONFIG_FILE);
log.info("Query to get FreeLUN's of a HostStorageDomain: {}", getFreeLunQueryInputXML);
URI endpointURI = hdsApiClient.getBaseURI();
ClientResponse response = hdsApiClient.post(endpointURI,
getFreeLunQueryInputXML);
if (HttpStatus.SC_OK == response.getStatus()) {
responseStream = response.getEntityInputStream();
JavaResult javaResult = SmooksUtil.getParsedXMLJavaResult(responseStream,
HDSConstants.SMOOKS_CONFIG_FILE);
verifyErrorPayload(javaResult);
hostStorageDomain = javaResult.getBean(HostStorageDomain.class);
if (null != hostStorageDomain && null != hostStorageDomain.getFreeLunList()) {
freeLunList = hostStorageDomain.getFreeLunList();
} else {
throw HDSException.exceptions
.notAbleToGetFreeLunInfoForHSD(hsdId, systemId);
}
} else {
throw HDSException.exceptions
.invalidResponseFromHDS(String
.format("Not able to get FreeLun info for HostStorageDomain due to invalid response %1$s from server",
response.getStatus()));
}
} finally {
if (null != responseStream) {
try {
responseStream.close();
} catch (IOException e) {
log.warn("IOException occurred while closing the response stream");
}
}
}
return freeLunList;
}
/**
* Delete the Host Storage Domain for a given storage array.
*
* @param systemObjectId
* @param hsdObjectId
* @param model
* @throws Exception
*/
public void deleteHostStorageDomain(String systemObjectId, String hsdObjectId, String model) throws Exception {
InputStream responseStream = null;
try {
Map<String, Object> attributeMap = new HashMap<String, Object>();
StorageArray array = new StorageArray(systemObjectId);
Delete deleteOp = new Delete(HDSConstants.HOST_STORAGE_DOMAIN);
attributeMap.put(HDSConstants.STORAGEARRAY, array);
attributeMap.put(HDSConstants.DELETE, deleteOp);
attributeMap.put(HDSConstants.MODEL, model);
HostStorageDomain inputHsd = new HostStorageDomain(hsdObjectId);
attributeMap.put(HDSConstants.HOST_STORAGE_DOMAIN, inputHsd);
String deleteHSDFromSystemQuery = InputXMLGenerationClient.getInputXMLString(
HDSConstants.DELETE_HSD_FROM_SYSTEM_OP, attributeMap,
HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE,
HDSConstants.HITACHI_SMOOKS_CONFIG_FILE);
log.info("Query to delete HostStorageDomain: {}", deleteHSDFromSystemQuery);
URI endpointURI = hdsApiClient.getBaseURI();
ClientResponse response = hdsApiClient.post(endpointURI,
deleteHSDFromSystemQuery);
if (HttpStatus.SC_OK == response.getStatus()) {
responseStream = response.getEntityInputStream();
JavaResult javaResult = SmooksUtil.getParsedXMLJavaResult(responseStream,
HDSConstants.SMOOKS_CONFIG_FILE);
verifyErrorPayload(javaResult);
log.info("Deleted HSD {} from system {}", hsdObjectId, systemObjectId);
} else {
throw HDSException.exceptions
.invalidResponseFromHDS(String
.format("Not able to delete HostStorageDomain due to invalid response %1$s from server",
response.getStatus()));
}
} finally {
if (null != responseStream) {
try {
responseStream.close();
} catch (IOException e) {
log.warn("IOException occurred while closing the response stream");
}
}
}
}
/**
* Delete the LUN Path from HSD of a given storage array.
*
* @param systemObjectId
* @param pathObjectIdList
* @param model
*
* @throws Exception
*/
public void deleteLunPathsFromSystem(String systemObjectId, List<String> pathObjectIdList, String model) throws Exception {
InputStream responseStream = null;
try {
boolean operationSucceeds = false;
int retryCount = 0;
StringBuilder errorDescriptionBuilder = new StringBuilder();
while (!operationSucceeds && retryCount < MAX_RETRIES) {
retryCount++;
String deleteLUNsQuery = constructDeleteLunPathsQuery(systemObjectId,
pathObjectIdList, model);
log.info("Batch query to deleteLUNs Query: {}", deleteLUNsQuery);
URI endpointURI = hdsApiClient.getBaseURI();
ClientResponse response = hdsApiClient.post(endpointURI,
deleteLUNsQuery);
if (HttpStatus.SC_OK == response.getStatus()) {
responseStream = response.getEntityInputStream();
JavaResult javaResult = SmooksUtil.getParsedXMLJavaResult(
responseStream, HDSConstants.SMOOKS_CONFIG_FILE);
try {
verifyErrorPayload(javaResult);
operationSucceeds = true; // If no exception then operation succeeds
} catch (HDSException hdsException) {
Error error = javaResult.getBean(Error.class);
if (error != null && (error.getDescription().contains("2010")
|| error.getDescription().contains("5132") || error.getDescription().contains("7473"))) {
log.error("Error response recieved from HiCommandManger: {}", error.getDescription());
log.info("Exception from HICommand Manager recieved during delete operation, retrying operation {} time",
retryCount);
errorDescriptionBuilder.append("error ").append(retryCount).append(" : ").append(error.getDescription())
.append("-#####-");
Thread.sleep(60000); // Wait for a minute before retry
continue; // Retry the operation again if retry count not exceeded
} else {
throw HDSException.exceptions
.invalidResponseFromHDS(String
.format("Not able to delete LunPaths due to invalid response %1$s from server",
response.getStatus()));
}
}
log.info("Deleted {} LUN paths from system:{}",
pathObjectIdList.size(), systemObjectId);
} else {
throw HDSException.exceptions
.invalidResponseFromHDS(String
.format("Not able to delete Volume from HostGroups due to invalid response %1$s from server",
response.getStatus()));
}
}
if (!operationSucceeds) {// Delete operation failed ever after repeated retries
throw HDSException.exceptions
.invalidResponseFromHDS(String
.format("Not able to delete LunPaths due to repeated errors from HiCommand server, errors description are as %s",
errorDescriptionBuilder.toString()));
}
} finally {
if (null != responseStream) {
try {
responseStream.close();
} catch (IOException e) {
log.warn("IOException occurred while closing the response stream");
}
}
}
}
/**
* Construct the WWN Query by adding multiple WWNs.
* This query should be used to add FC initiators to the FC HSD.
*
* @param systemId
* @param hsdId
* @param lunPathObjectIdList
* @return
*/
private String constructDeleteLunPathsQuery(String systemId, List<String> lunPathObjectIdList, String model) {
Map<String, Object> attributeMap = new HashMap<String, Object>();
List<Path> pathList = new ArrayList<Path>();
StorageArray array = new StorageArray(systemId);
Delete deleteOp = new Delete(HDSConstants.LUN_TARGET);
attributeMap.put(HDSConstants.STORAGEARRAY, array);
attributeMap.put(HDSConstants.MODEL, model);
attributeMap.put(HDSConstants.DELETE, deleteOp);
if (null != lunPathObjectIdList && !lunPathObjectIdList.isEmpty()) {
for (String pathObjectId : lunPathObjectIdList) {
Path path = new Path(pathObjectId);
pathList.add(path);
}
}
attributeMap.put(HDSConstants.PATH_LIST, pathList);
String deleteLunInputXML = InputXMLGenerationClient.getInputXMLString(
HDSConstants.DELETE_PATH_FROM_HSD_OP, attributeMap,
HDSConstants.HITACHI_INPUT_XML_CONTEXT_FILE,
HDSConstants.HITACHI_SMOOKS_CONFIG_FILE);
return deleteLunInputXML;
}
}