/* * Copyright (c) 2008-2016 EMC Corporation * All Rights Reserved */ package com.emc.storageos.xiv.api; import java.net.URI; import java.text.MessageFormat; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.codehaus.jettison.json.JSONArray; import org.codehaus.jettison.json.JSONException; import org.codehaus.jettison.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.db.client.model.ExportGroup; import com.emc.storageos.services.restutil.StandardRestClient; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.api.client.WebResource; import com.sun.jersey.api.client.WebResource.Builder; import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter; import com.sun.jersey.api.client.filter.LoggingFilter; /** * Performs all the operations on XIV - Hyperscale Manager using its REST APIs */ public class XIVRestClient extends StandardRestClient { private static Logger _log = LoggerFactory.getLogger(XIVRestClient.class); private static final int RETRY_NUMBER = 5; private static final int DELAY_NUMBER = 60000; private static final String ERROR_CODE = "httpStatusCode"; private static final String SEPARATOR = ":"; private static final String NAME = "name"; private static final String VOLUME = "volume"; private static final String LUN = "lun"; private static final String STATUS_EXECUTION_PASS = "0"; private static final String STATUS = "status"; private static final String RESPONSE = "response"; private static final String COUNTS = "counts"; private static final String DATACOUNT = "data_count"; private static final String TOTALCOUNT = "total_count"; private static final String DATA = "data"; private static final String HOST = "host"; private static final String PORT = "port"; private static final String HOSTPORT = "host_port"; private static final String VOLMAP = "vol_map"; private static final String CLUSTER = "cluster"; private static final String WWN = "wwn"; private static final String MESSAGE = "message"; private static final String SERVER = "server"; private static final String FAILED_SYSTEMS = "failed_systems"; private static String INSTANCE_URL = "/:{1}"; private static String SEARCH_URL = "?{1}={2}"; private static String SYSTEMS_URL = "/xiv/v2/systems"; private static String CLUSTER_URL = "/xiv/v2/:{0}/clusters"; private static String HOST_URL = "/xiv/v2/:{0}/hosts"; private static String HOST_PORT_URL = "/xiv/v2/:{0}/host_ports"; private static String VOLUME_URL = "/xiv/v2/:{0}/volumes"; private static String SNAPSHOT_URL = "/xiv/v2/:{0}/snapshots"; private static String EXPORT_VOLUME_URL = "/xiv/v2/:{0}/vol_maps"; private static String EXPORT_VOLUME_INSTANCE_URL = EXPORT_VOLUME_URL + "/:{1}:{2}:{3}"; private static String CLUSTER_INSTANCE_URL = CLUSTER_URL + INSTANCE_URL; private static String HOST_INSTANCE_URL = HOST_URL + INSTANCE_URL; private static String HOST_PORT_INSTANCE_URL = HOST_PORT_URL + "/:{1}:{2}:{3}"; private static String VOLUME_INSTANCE_URL = VOLUME_URL + INSTANCE_URL; private static String SNAPSHOT_INSTANCE_URL = SNAPSHOT_URL + INSTANCE_URL; private static String DELETE_BODY = "{\"request\":[{\"action\":\"delete\"}]}"; private static String CLUSTER_CREATE_BODY = "'{'\"request\":['{'\"action\":\"create\",\"params\":'{'\"name\":\"{0}\"'}}']'}'"; private static String HOST_CREATE_BODY = "'{'\"request\":['{'\"action\":\"create\",\"params\":'{'\"name\":\"{0}\"'}}']'}'"; private static String HOST_CREATE_ON_CLUSTER_BODY = "'{'\"request\":['{'\"action\":\"create\",\"params\":'{'\"name\":\"{0}\",\"cluster\":\"{1}\"'}}']'}'"; private static String HOST_PORT_CREATE_BODY = "'{'\"request\":['{'\"action\":\"create\",\"params\":'{'\"port\":\"{1}\",\"host\":\"{0}\",\"type\":\"{2}\"'}}']'}'"; private static String EXPORT_VOLUME_TO_CLUSTER_BODY = "'{'\"request\":['{'\"action\":\"create\",\"params\":'{'\"volume\":\"{1}\",\"host_cluster_name\":\"{0}\",\"map_type\":\"cluster\",\"lun\":\"{2}\"}}]}"; private static String EXPORT_VOLUME_TO_HOST_BODY = "'{'\"request\":['{'\"action\":\"create\",\"params\":'{'\"volume\":\"{1}\",\"host_cluster_name\":\"{0}\",\"map_type\":\"host\",\"lun\":\"{2}\"}}]}"; /** * Host Status on XIV */ public enum HOST_STATUS { CLUSTER_HOST, STANDALONE_HOST, HOST_NOT_PRESENT } /* * Hyperscale Manger REST response validator. * Used to find the Error state retured after REST operation. */ class ResponseValidator { boolean failed; String responseStatus; String responseMessage; JSONArray failedSystems; ResponseValidator() { failed = false; } ResponseValidator(JSONObject response) throws Exception { validate(response); } void validate(JSONObject response) throws Exception { if (null != response) { try { if (null != response) { JSONObject status = response.optJSONObject(STATUS); if (null != status) { JSONObject server = status.optJSONObject(SERVER); if (null != server) { responseStatus = server.optString(STATUS); responseMessage = server.optString(MESSAGE); if (!STATUS_EXECUTION_PASS.equals(responseStatus)) { failed = true; } } if (!failed) { failedSystems = status.optJSONArray(FAILED_SYSTEMS); if (null != failedSystems && failedSystems.length() > 0) { failed = true; } } } JSONObject responseObj = response.optJSONObject(RESPONSE); if (!failed && null != responseObj) { JSONObject counts = responseObj.optJSONObject(COUNTS); if (null != counts) { String datacount = counts.optString(DATACOUNT); String totalcount = counts.optString(TOTALCOUNT); if (STATUS_EXECUTION_PASS.equals(datacount) || STATUS_EXECUTION_PASS.equals(totalcount)) { failed = true; } } } } } catch (Exception e) { failed = true; throw XIVRestException.exceptions.jsonParserFailure(response.toString()); } } } boolean isFailed() { return failed; } @Override public String toString() { StringBuffer message = new StringBuffer(); if (null != responseMessage && null != responseStatus) { message.append("Status : ").append(responseStatus); message.append("Message : ").append(responseMessage); message.append("\n"); } if (null != failedSystems) { try { for (int i = 0; i < failedSystems.length(); i++) { JSONObject failedSystem = failedSystems.getJSONObject(i); message.append(failedSystem.getString(NAME)).append(SEPARATOR).append(failedSystem.getString(MESSAGE)); message.append("\n"); } } catch (JSONException e) { _log.error("Error occured parsing failure response message : {}", failedSystems.toString(), e); } } return message.toString(); } } /** * Constructor of XIVRESTOperations * * @param endpoint Base URI of Hyperscale Manager * @param client REST Client instance */ /** * * @param baseURI Base URI of Hyperscale Manager * @param username user name of XIV * @param password password of XIV * @param client REST Client instance */ public XIVRestClient(URI baseURI, String username, String password, Client client) { _client = client; _base = baseURI; _username = username; _password = password; _client.addFilter(new HTTPBasicAuthFilter(username, password)); } /** * Sets User Name * * @param username User Name of XIV */ public void setUsername(String username) { _username = username; } /** * Sets password * * @param password Password of XIV */ public void setPassword(String password) { _password = password; } /* * (non-Javadoc) * * @see com.emc.storageos.services.restutil.StandardRestClient#setResourceHeaders(com.sun.jersey.api.client.WebResource) */ @Override protected Builder setResourceHeaders(WebResource resource) { return resource.getRequestBuilder(); } /* * (non-Javadoc) * * @see com.emc.storageos.services.restutil.StandardRestClient#authenticate() */ @Override protected void authenticate() { _client.addFilter(new HTTPBasicAuthFilter(_username, _password)); if (_log.isDebugEnabled()) { _client.addFilter(new LoggingFilter(System.out)); } } /* * (non-Javadoc) * * @see com.emc.storageos.services.restutil.StandardRestClient#checkResponse(java.net.URI, com.sun.jersey.api.client.ClientResponse) */ @Override protected int checkResponse(URI uri, ClientResponse response) { ClientResponse.Status status = response.getClientResponseStatus(); return status.getStatusCode(); } /** * Check if the instance specified in URI is available on XIV system. If not available wait for a minute and then retry. * Retry at-least RETRY_NUMBER times before declaring the instance was not available on Array * * @param uri Instance URI * @throws Exception If error occurs during execution. Throws Resource not found exception after RETRY_NUMBER tries. */ private void checkAvailability(final String uri) throws Exception { boolean availabe = findAvailability(getInstance(uri)); int counter = 1; while(!availabe && counter < RETRY_NUMBER) { try { _log.warn("Resource {} not found on Array. Waiting for a minute to check availability. Count : {}", uri, counter); Thread.sleep(DELAY_NUMBER); } catch(InterruptedException ex) { Thread.currentThread().interrupt(); } availabe = findAvailability(getInstance(uri)); counter++; } //Check availability after RETRY_NUMBER if(!availabe){ throw XIVRestException.exceptions.resourceNotFound(uri); } } /** * Find if the instance specified in URI is available on XIV system * * @param uri Instance URI * @return true if present else false * @throws Exception If error occurs during execution */ private boolean findAvailability(final String uri) throws Exception { return findAvailability(getInstance(uri)); } /** * Find if the instance specified using JSONObject is available on XIV system * * @param instance Instance represented as JSONObject * @return true if present else false * @throws Exception If error occurs during execution */ private boolean findAvailability(final JSONObject instance) throws Exception { ResponseValidator status = new ResponseValidator(instance); return !status.isFailed(); } /** * Gets Instance as JSONObject from the URI specified * * @param uri Instance URI * @return Instance JSONObject * @throws Exception Exception If error occurs during execution */ private JSONObject getInstance(final String uri) throws Exception { JSONObject instance = null; ClientResponse response = null; try { response = get(_base.resolve(uri)); instance = response.getEntity(JSONObject.class); } catch (Exception e) { throw XIVRestException.exceptions.xivRestRequestFailure(uri, e.getMessage()); } return instance; } /** * Executes POST request. Can be used to Create/Delete/Update instance on XIV using the URI * * @param xivSystem XIV System name on which the instance needs to be created * @param uri URI representing the Instance base path * @param jsonBody Create body in JSON format * @return ResponseValidator of the create operation * @throws Exception Exception Exception If error occurs during execution */ private ResponseValidator executePOSTRequest(final String xivSystem, final String uri, final String jsonBody) throws Exception { ResponseValidator failureStatus = new ResponseValidator(); ClientResponse response = null; try { response = post(_base.resolve(uri), jsonBody); JSONObject arrayClusters = response.getEntity(JSONObject.class); failureStatus.validate(arrayClusters); } catch (Exception e) { throw XIVRestException.exceptions.xivRestRequestFailure(uri.toString(), e.getMessage()); } return failureStatus; } /** * Creates Cluster on XIV system * * @param xivSystem XIV system * @param clusterName Cluster name * @return True if already present. Else False * @throws Exception Throws Exception If error occurs during execution */ public boolean createCluster(final String xivSystem, final String clusterName) throws Exception { boolean isAvailable = findAvailability(MessageFormat.format(CLUSTER_INSTANCE_URL, xivSystem, clusterName)); if (isAvailable) { _log.info("Cluster {} already exist on XIV {}. Skipping creation!", clusterName, xivSystem); } else { final String body = MessageFormat.format(CLUSTER_CREATE_BODY, clusterName); ResponseValidator failureStatus = executePOSTRequest(xivSystem, MessageFormat.format(CLUSTER_URL, xivSystem), body); if (failureStatus.isFailed()) { throw XIVRestException.exceptions.clusterCreationFailure(xivSystem, clusterName, failureStatus.toString()); } } return isAvailable; } /** * Deletes cluster if its is present only if the underlying structure is deleted * * @param xivSystem XIV system that hosts the cluster * @param clusterName Cluster name * @return True if deleted. Else false. * @throws Exception Throws Exception If error occurs during execution */ public boolean deleteCluster(final String xivSystem, final String clusterName) throws Exception { final String instanceURL = MessageFormat.format(CLUSTER_INSTANCE_URL, xivSystem, clusterName); boolean deleteSuccessful = false; if (findAvailability(instanceURL)) { // Validate if there are any Hosts associated with the cluster. boolean isHostsAvailable = findAvailability(MessageFormat.format(HOST_URL + SEARCH_URL, xivSystem, CLUSTER, clusterName)); if (!isHostsAvailable) { // Now go ahead and delete Cluster. ResponseValidator failureStatus = executePOSTRequest(xivSystem, instanceURL, DELETE_BODY); deleteSuccessful = true; if (failureStatus.isFailed()) { throw XIVRestException.exceptions.clusterDeleteFailure(xivSystem, clusterName, failureStatus.toString()); } } else { _log.warn("There are some more Hosts associated with the Cluster {}. Skipping deletion.", clusterName); } } else { throw XIVRestException.exceptions.instanceUnavailableForDelete(xivSystem, CLUSTER, clusterName); } return deleteSuccessful; } /** * Creates Host on XIV system. Maps it to a Cluster * * @param xivSystem xivSystem XIV system * @param clusterName clusterName Cluster name * @param hostName Host Name * @return True if already present. Else False * @throws Exception Exception Exception Exception If error occurs during execution */ public boolean createHost(final String xivSystem, final String clusterName, final String hostName) throws Exception { boolean isAvailable = findAvailability(MessageFormat.format(HOST_INSTANCE_URL, xivSystem, hostName)); if (isAvailable) { _log.info("Host {} already exist on XIV {}. Skipping creation!", hostName, xivSystem); } else { String body = null; if (null != clusterName) { body = MessageFormat.format(HOST_CREATE_ON_CLUSTER_BODY, hostName, clusterName); } else { body = MessageFormat.format(HOST_CREATE_BODY, hostName); } ResponseValidator failureStatus = executePOSTRequest(xivSystem, MessageFormat.format(HOST_URL, xivSystem), body); if (failureStatus.isFailed()) { throw XIVRestException.exceptions.hostCreationFailure(xivSystem, hostName, failureStatus.toString()); } } return isAvailable; } /** * Deletes Host on the XIV if underlying instances are deleted * * @param xivSystem XIV system * @param hostName Host name to be deleted * @param forceDelete True would delete Host even if Volumes are mapped to Cluster * @return True if deleted. Else false. * @throws Exception Throws Exception If error occurs during execution */ public boolean deleteHost(final String xivSystem, final String hostName, final boolean forceDelete) throws Exception { final String instanceURL = MessageFormat.format(HOST_INSTANCE_URL, xivSystem, hostName); boolean deleteSuccessful = false; if (findAvailability(instanceURL)) { // Validate if there are any volumes mapped before deleting. boolean isVolumeExportAvailable = findAvailability( MessageFormat.format(EXPORT_VOLUME_URL + SEARCH_URL, xivSystem, HOST, hostName)); if (forceDelete || !isVolumeExportAvailable) { // Validate if there are any Initiators associated with Host before deleting. boolean isInitiatorAvailable = findAvailability( MessageFormat.format(HOST_PORT_URL + SEARCH_URL, xivSystem, HOST, hostName)); if (!isInitiatorAvailable) { // Now go ahead and delete Host. ResponseValidator failureStatus = executePOSTRequest(xivSystem, instanceURL, DELETE_BODY); deleteSuccessful = true; if (failureStatus.isFailed()) { throw XIVRestException.exceptions.hostDeleteFailure(xivSystem, hostName, failureStatus.toString()); } } else { _log.warn("There are Initiators available on Host {}. Skipping deletion.", hostName); } } else { _log.warn("There are some more Volume exported to Host {}. Skipping deletion.", hostName); } } else { throw XIVRestException.exceptions.instanceUnavailableForDelete(xivSystem, HOST, hostName); } return deleteSuccessful; } /** * Creates Host Port (Initiator) * * @param xivSystem XIV system * @param hostName Host Name * @param hostPort Host Port name * @param hostPortType Host Port type * @return True if already present. Else False * @throws Exception Exception Exception Exception If error occurs during execution */ public boolean createHostPort(final String xivSystem, final String hostName, final String hostPort, final String hostPortType) throws Exception { boolean isAvailable = findAvailability(MessageFormat.format(HOST_PORT_INSTANCE_URL, xivSystem, hostPortType, hostName, hostPort)); if (isAvailable) { _log.info("HostPort {} already exist on XIV {}. Skipping creation!", hostPort, xivSystem); } else { final String body = MessageFormat.format(HOST_PORT_CREATE_BODY, hostName, hostPort, hostPortType); ResponseValidator failureStatus = executePOSTRequest(xivSystem, MessageFormat.format(HOST_PORT_URL, xivSystem), body); if (failureStatus.isFailed()) { throw XIVRestException.exceptions.hostPortCreationFailure(xivSystem, hostName, hostPort, failureStatus.toString()); } } return isAvailable; } /** * Deletes Host Port on the Host if all the underlying instances are deleted. * * @param xivSystem XIV System * @param hostName Host name where the port exists * @param hostPort Host port name * @param hostPortType Host port type * @param forceDelete Force delete a Host Port * @return True if it is deleted. Else false. * @throws Exception Throws Exception If error occurs during execution */ public boolean deleteHostPort(final String xivSystem, final String hostName, final String hostPort, final String hostPortType, final Boolean forceDelete) throws Exception { final String instanceURL = MessageFormat.format(HOST_PORT_INSTANCE_URL, xivSystem, hostPortType, hostName, hostPort); boolean deleteSuccessful = false; if (findAvailability(instanceURL)) { // Validate if there are any volumes mapped before deleting. if (forceDelete || !findAvailability(MessageFormat.format(EXPORT_VOLUME_URL + SEARCH_URL, xivSystem, HOST, hostName))) { // Now go ahead and delete HostPort. ResponseValidator failureStatus = executePOSTRequest(xivSystem, instanceURL, DELETE_BODY); deleteSuccessful = true; if (failureStatus.isFailed()) { throw XIVRestException.exceptions.hostPortDeleteFailure(xivSystem, hostName, hostPort, failureStatus.toString()); } } else { _log.warn("There are some more Volume exported to Host {}. Skipping Host Port deletion.", hostName); } } else { throw XIVRestException.exceptions.instanceUnavailableForDelete(xivSystem, HOSTPORT, hostName + SEPARATOR + hostPort); } return deleteSuccessful; } /** * Exports a volume to a Cluster * * @param xivSystem XIV System * @param exportType Cluster or Host * @param exportName Cluster name/Host name to where volume is exported * @param volumeName Name of the volume to be exported * @param lunID LUN number to be assigned * @param isSnapshot * @return True if Volume is already exported to a specific Cluster. Else false. * @throws Exception Exception Exception Exception If error occurs during execution */ public boolean exportVolume(final String xivSystem, final String exportType, final String exportName, final String volumeName, final String lunID, final boolean isSnapshot) throws Exception { final String instanceURL = isSnapshot ? SNAPSHOT_INSTANCE_URL : VOLUME_INSTANCE_URL; //Check if Volume/snapshot is present on Array before proceeding. checkAvailability(MessageFormat.format(instanceURL, xivSystem, volumeName)); boolean isAvailable = findAvailability( MessageFormat.format(EXPORT_VOLUME_INSTANCE_URL, xivSystem, exportType.toLowerCase(), exportName, volumeName)); if (isAvailable) { _log.info("Volume {} already already exported to {} {} on XIV {}. Skipping Export!", volumeName, exportType, exportName, xivSystem); } else { String body = null; if (ExportGroup.ExportGroupType.Cluster.name().equals(exportType)) { body = MessageFormat.format(EXPORT_VOLUME_TO_CLUSTER_BODY, exportName, volumeName, lunID); } else { body = MessageFormat.format(EXPORT_VOLUME_TO_HOST_BODY, exportName, volumeName, lunID); } ResponseValidator failureStatus = executePOSTRequest(xivSystem, MessageFormat.format(EXPORT_VOLUME_URL, xivSystem), body); if (failureStatus.isFailed()) { throw XIVRestException.exceptions.volumeExportToClusterFailure(xivSystem, exportName, volumeName, failureStatus.toString()); } } return isAvailable; } /** * Un exports the volume masked to Host/Cluster * * @param xivSystem XIV system * @param exportType Export type [Cluster/Host] * @param exportName Export name * @param volumeName Volume name * @return True if unexport is successful. Else false. * @throws Exception Throws Exception If error occurs during execution */ public boolean unExportVolume(final String xivSystem, final String exportType, final String exportName, final String volumeName) throws Exception { final String instanceURL = MessageFormat.format(EXPORT_VOLUME_INSTANCE_URL, xivSystem, exportType.toLowerCase(), exportName, volumeName); boolean deleteSuccessful = false; if (findAvailability(instanceURL)) { ResponseValidator failureStatus = executePOSTRequest(xivSystem, instanceURL, DELETE_BODY); deleteSuccessful = true; if (failureStatus.isFailed()) { throw XIVRestException.exceptions.volumeExportToClusterFailure(xivSystem, exportName, volumeName, failureStatus.toString()); } } else { _log.info("Volume not available to do unexport on XIV {} : {}", exportType + SEPARATOR + exportName + SEPARATOR + volumeName, xivSystem); } return deleteSuccessful; } /** * Gets status of Host on XIV system * * @param xivSystem XIV system * @param hostName Host name to be verified * @return HOST_STATUS * @throws Exception Exception Exception Exception If error occurs during execution */ public HOST_STATUS getHostStatus(final String xivSystem, final String hostName) throws Exception { final String hostURI = MessageFormat.format(HOST_INSTANCE_URL, xivSystem, hostName); HOST_STATUS hostStatus = HOST_STATUS.HOST_NOT_PRESENT; JSONObject hostInstance = getInstance(hostURI); if (findAvailability(hostInstance)) { hostStatus = HOST_STATUS.STANDALONE_HOST; JSONObject response = hostInstance.getJSONObject(RESPONSE); JSONObject data = response.getJSONObject(DATA); JSONObject host = data.getJSONObject(HOST); final String hostCluster = host.getString(CLUSTER); if (null != hostCluster && !hostCluster.isEmpty()) { hostStatus = HOST_STATUS.CLUSTER_HOST; } } return hostStatus; } /** * Gets Host port for a Host on XIV * * @param xivSystem XIV system * @param hostName Host name * @return Collection of Host Port names * @throws Exception Throws Exception If error occurs during execution */ public Set<String> getHostPorts(final String xivSystem, final String hostName) throws Exception { String hostPortSearchURL = MessageFormat.format(HOST_PORT_URL + SEARCH_URL, xivSystem, HOST, hostName); JSONObject hostPortsInstance = getInstance(hostPortSearchURL); Set<String> discHostPorts = new HashSet<String>(); if (findAvailability(hostPortsInstance)) { JSONObject response = hostPortsInstance.getJSONObject(RESPONSE); JSONObject data = response.getJSONObject(DATA); JSONArray hostPorts = data.getJSONArray(HOSTPORT); int portsize = hostPorts.length(); for (int i = 0; i < portsize; i++) { JSONObject hostPort = hostPorts.getJSONObject(i); discHostPorts.add(hostPort.getString(NAME)); } } return discHostPorts; } /** * Get Host name for the port from Array * @param xivSystem StorageSystem name * @param portName Port name * @return Host Name * @throws Exception If error occurs during execution */ public String getHostNameFromPort(final String xivSystem, final String portName) throws Exception { final String portURI = MessageFormat.format(HOST_PORT_URL + SEARCH_URL, xivSystem, PORT, portName); JSONObject portInstance = getInstance(portURI); String hostName = null; if (findAvailability(portInstance)) { JSONObject response = portInstance.getJSONObject(RESPONSE); JSONObject data = response.getJSONObject(DATA); JSONArray hostPorts = data.getJSONArray(HOSTPORT); int portsize = hostPorts.length(); for (int i = 0; i < portsize; i++) { JSONObject hostPort = hostPorts.getJSONObject(i); hostName = hostPort.getString(HOST); } } return hostName; } /** * Gets Volumes mapped on the XIV * * @param xivSystem XIV system * @param clusterName Cluster name * @param hostName Host name * @return Map of Volume and LUN id * @throws Exception Throws Exception If error occurs during execution */ public Map<String, Integer> getVolumesMappedToHost(final String xivSystem, final String clusterName, final String hostName) throws Exception { Map<String, Integer> discVolsMappedToCluster = new HashMap<String, Integer>(); Map<String, Integer> discVolsMappedToHost = new HashMap<String, Integer>(); Map<String, Integer> discVolWWNMappedToHost = new HashMap<String, Integer>(); if (null != clusterName && !clusterName.isEmpty()) { String clusterVolsSearchURL = MessageFormat.format(EXPORT_VOLUME_URL + SEARCH_URL, xivSystem, CLUSTER, clusterName); JSONObject volsMappedToClusterInstance = getInstance(clusterVolsSearchURL); if (findAvailability(volsMappedToClusterInstance)) { JSONObject cluResponse = volsMappedToClusterInstance.getJSONObject(RESPONSE); JSONObject cluData = cluResponse.getJSONObject(DATA); JSONArray mappedVolumes = cluData.getJSONArray(VOLMAP); int mappedVolumessize = mappedVolumes.length(); for (int i = 0; i < mappedVolumessize; i++) { JSONObject mappedVolume = mappedVolumes.getJSONObject(i); discVolsMappedToHost.put(mappedVolume.getString(VOLUME), new Integer(mappedVolume.getString(LUN))); } } } else if (null != hostName && !hostName.isEmpty()) { final String hostURL = MessageFormat.format(HOST_INSTANCE_URL, xivSystem, hostName); JSONObject hostInstance = getInstance(hostURL); if (findAvailability(hostInstance)) { JSONObject response = hostInstance.getJSONObject(RESPONSE); JSONObject data = response.getJSONObject(DATA); JSONObject host = data.getJSONObject(HOST); final String hostCluster = host.getString(CLUSTER); if (null != hostCluster && !hostCluster.isEmpty()) { String clusterVolsSearchURL = MessageFormat.format(EXPORT_VOLUME_URL + SEARCH_URL, xivSystem, CLUSTER, hostCluster); JSONObject volsMappedToClusterInstance = getInstance(clusterVolsSearchURL); if (findAvailability(volsMappedToClusterInstance)) { JSONObject cluResponse = volsMappedToClusterInstance.getJSONObject(RESPONSE); JSONObject cluData = cluResponse.getJSONObject(DATA); JSONArray mappedVolumes = cluData.getJSONArray(VOLMAP); int mappedVolumessize = mappedVolumes.length(); for (int i = 0; i < mappedVolumessize; i++) { JSONObject mappedVolume = mappedVolumes.getJSONObject(i); discVolsMappedToCluster.put(mappedVolume.getString(VOLUME), new Integer(mappedVolume.getString(LUN))); } } } } String hostPortSearchURL = MessageFormat.format(EXPORT_VOLUME_URL + SEARCH_URL, xivSystem, HOST, hostName); JSONObject volsMappedToHostInstance = getInstance(hostPortSearchURL); if (findAvailability(volsMappedToHostInstance)) { JSONObject response = volsMappedToHostInstance.getJSONObject(RESPONSE); JSONObject data = response.getJSONObject(DATA); JSONArray mappedVolumes = data.getJSONArray(VOLMAP); int mappedVolumessize = mappedVolumes.length(); for (int i = 0; i < mappedVolumessize; i++) { JSONObject mappedVolume = mappedVolumes.getJSONObject(i); discVolsMappedToHost.put(mappedVolume.getString(VOLUME), new Integer(mappedVolume.getString(LUN))); } } // Remove the Cluster Volumes as it belongs to Cluster Mask. if (!discVolsMappedToHost.isEmpty() && !discVolsMappedToCluster.isEmpty()) { for (String key : discVolsMappedToCluster.keySet()) { discVolsMappedToHost.remove(key); } } } if (!discVolsMappedToHost.isEmpty()) { Set<Entry<String, Integer>> discVolsMappedToHostSet = discVolsMappedToHost.entrySet(); for (Entry<String, Integer> volMapping : discVolsMappedToHostSet) { String volName = volMapping.getKey(); String volInstanceURL = MessageFormat.format(VOLUME_INSTANCE_URL, xivSystem, volName); JSONObject volInstance = getInstance(volInstanceURL); JSONObject response = volInstance.getJSONObject(RESPONSE); JSONObject data = response.getJSONObject(DATA); JSONObject volumeData = data.getJSONObject(VOLUME); discVolWWNMappedToHost.put(volumeData.getString(WWN), volMapping.getValue()); } } return discVolWWNMappedToHost; } /** * Returns Port details for a port name specified if exist on Array * * @param xivSystem XIV Storage System name * @param portName Port name for which the details to be found * @return Container (HOST) name. * @throws Exception If error occurs during execution. */ public String getHostPortContainer(final String xivSystem, final String portName) throws Exception { String containerName = null; String hostPortSearchURL = MessageFormat.format(HOST_PORT_URL + SEARCH_URL, xivSystem, PORT, portName); JSONObject hostPortInstances = getInstance(hostPortSearchURL); if (findAvailability(hostPortInstances)) { JSONObject response = hostPortInstances.optJSONObject(RESPONSE); if (null != response) { JSONObject data = response.optJSONObject(DATA); if (null != data) { JSONArray portResult = data.optJSONArray(HOSTPORT); if (null != portResult) { for (int i = 0; i < portResult.length(); i++) { JSONObject resultObj = portResult.getJSONObject(i); final String hostName = resultObj.getString("host"); if (null != hostName && !hostName.isEmpty()) { containerName = hostName; } } } } } } return containerName; } /** * Returns Host details for a name specified if exist on Array * * @param xivSystem XIV Storage System name * @param hostName Host name for which the details to be found * @return Container (CLUSTER) name. * @throws Exception If error occurs during execution. */ public String getHostContainer(final String xivSystem, final String hostName) throws Exception { String containerName = null; final String hostURI = MessageFormat.format(HOST_INSTANCE_URL, xivSystem, hostName); JSONObject hostInstance = getInstance(hostURI); if (findAvailability(hostInstance)) { JSONObject response = hostInstance.getJSONObject(RESPONSE); JSONObject data = response.getJSONObject(DATA); JSONObject host = data.getJSONObject(HOST); final String hostCluster = host.getString(CLUSTER); if (null != hostCluster && !hostCluster.isEmpty()) { containerName = hostCluster; } } return containerName; } public boolean getSystemsAvailability() throws Exception { return findAvailability(SYSTEMS_URL); } }