/*
* Copyright (c) 2013 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.systemservices.impl.client;
import com.emc.storageos.security.authentication.InternalApiSignatureKeyGenerator;
import com.emc.storageos.security.helpers.BaseServiceClient;
import com.emc.storageos.systemservices.exceptions.SysClientException;
import com.emc.storageos.systemservices.exceptions.SyssvcException;
import com.emc.storageos.services.util.Exec;
import com.sun.jersey.api.client.ClientHandlerException;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.helpers.MessageFormatter;
import javax.ws.rs.core.MediaType;
import java.net.InetAddress;
import java.net.URI;
import java.net.UnknownHostException;
/**
* Factory to create SysClient instance
*/
public class SysClientFactory {
private static final Logger _log = LoggerFactory.getLogger(SysClient.class);
public static final URI URI_GET_IMAGE = URI.create("/upgrade/internal/image");
public static final URI URI_WAKEUP_UPGRADE_MANAGER = URI.create("/upgrade/internal/wakeup?type=upgrade");
public static final URI URI_GET_DRIVER = URI.create("/storagedriver/internal/download");
public static final URI URI_WAKEUP_SECRETS_MANAGER = URI.create("/upgrade/internal/wakeup?type=secrets");
public static final URI URI_WAKEUP_PROPERTY_MANAGER = URI.create("/upgrade/internal/wakeup?type=property");
public static final URI URI_WAKEUP_VDC_MANAGER = URI.create("/upgrade/internal/wakeup?type=vdc");
public static final URI URI_GET_INTERNAL_NODE_HARDWARE = URI.create("/monitor/internal/node-hardware-info");
public static final URI URI_NODE_LOGS = URI.create("/logs/internal/node-logs");
public static final URI URI_LOG_LEVELS = URI.create("/logs/internal/log-level");
public static final URI URI_RESTART_SERVICE = URI.create("/control/internal/service/restart");
public static final URI URI_POWEROFF_NODE = URI.create("/control/internal/node/poweroff");
public static final URI URI_REBOOT_NODE = URI.create("/control/internal/node/reboot");
public static final URI URI_NODE_DBRESET = URI.create("/control/internal/node/db-reset");
public static final URI URI_SEND_POWEROFF_AGREEMENT = URI.create("/control/internal/node/poweroff-agreement");
public static final URI URI_NODE_BACKUPS_DOWNLOAD = URI.create("/backupset/internal/node-backups/download");
public static final URI URI_NODE_BACKUPS_PULL = URI.create("/backupset/internal/pull");
public static final URI URI_NODE_PULL_BACKUP_FILE = URI.create("/backupset/internal/pull-file");
public static final URI URI_GET_PROPERTIES = URI.create("/config/internal/properties");
public static final URI URI_GET_DB_OFFLINE_STATUS = URI.create("/control/internal/node/dbsvc-offline-status");
public static final URI URI_GET_DBREPAIR_STATUS = URI.create("/control/internal/node/dbrepair-status");
public static final String BASE_URL_FORMAT = "http://%1$s:%2$s";
public static final String URI_NODE_BACKUPS_RESTORE_TEMPLATE =
"/backupset/internal/restore?backupname=%s&isLocal=%s&password=%s&isgeofromscratch=%s";
// URI for retrieving managed capacity for provisioning in apisvc
public static final URI _URI_PROVISIONING_MANAGED_CAPACITY = URI.create
("/internal/system/managed-capacity");
// URI for retrieving managed capacity for unstructured, waiting from data service team
// for the new url
public static final URI _URI_UNSTRUCTURED_MANAGED_CAPACITY = URI.create
("/internal/object/managed-objCapacity");
/**
* Coordinator client
*/
private static volatile InternalApiSignatureKeyGenerator _keyGenerator;
private static int _timeout; // connection timeout
private static int _readTimeout; // read timeout
private static final String _IPCHECKTOOL_CMD = "/etc/storageos/ipchecktool";
private static final int _IPCHECKTOOL_IP_CONFLICT = 3;
private static final int _IPCHECKTOOL_NO_NODE = 4;
private static final long _IPCHECKTOOL_TIMEOUT = 60000; // 1 min
public static void setKeyGenerator(InternalApiSignatureKeyGenerator keyGenerator) {
_keyGenerator = keyGenerator;
}
public static synchronized void setTimeout(int timeout) {
_timeout = timeout;
_readTimeout = timeout;
}
public static synchronized void init() {
// nothing to do (remove this?)
}
public static synchronized SysClient getSysClient(URI endpoint, int readTimeout,
int connectionTimeout) {
_readTimeout = readTimeout;
_timeout = connectionTimeout;
return getSysClient(endpoint);
}
public static SysClient getSysClient(URI endpoint) {
return new SysClient(endpoint);
}
public static class SysClient extends BaseServiceClient {
private URI _endpoint;
private SysClient(URI endpoint) {
_endpoint = endpoint;
setServer(endpoint.toString());
setClientReadTimeout(_readTimeout);
setClientConnectTimeout(_timeout);
setKeyGenerator(_keyGenerator);
}
@Override
public String toString() {
return "endpoint=" + _endpoint + " timeout=" + _timeout + " readTimeout=" + _readTimeout;
}
@Override
public void setServer(String server) {
setServiceURI(_endpoint);
}
/**
* Call this method to perform GET action on any URI.
*
* @param getUri URI on which GET action is invoked.
* @param returnType Response return type
* @return response of the type passed.
* @throws SysClientException
*/
public <T> T get(URI getUri, Class<T> returnType,
String acceptType) throws SysClientException {
final WebResource webResource = createRequest(getUri);
if (acceptType == null) {
acceptType = MediaType.APPLICATION_JSON;
}
ClientResponse response;
try {
WebResource.Builder builder = addSignature(webResource).accept(acceptType);
response = builder.get(ClientResponse.class);
} catch (ClientHandlerException e) {
checkNodeStatus(getUri, "GET");
throw e;
}
final int status = response.getStatus();
if (isSuccess(status)) {
return response.getEntity(returnType);
}
else if (status == 204) {
_log.debug("get returns, status code: {}", status);
return null;
}
throw SyssvcException.syssvcExceptions.sysClientError(
MessageFormatter.arrayFormat("GET " +
"request on URI {} to node {} failed with status {}",
new Object[] { getUri, _endpoint.toString(),
status }).getMessage());
}
/**
* Call this method to perform POST action on any URI.
*
* @param postUri URI on which POST action is invoked.
* @param returnType Response return type
* @return response of the type passed.
* @throws SysClientException
*/
public <T> T post(URI postUri, Class<T> returnType,
Object requestBody) throws
SysClientException {
final WebResource webResource = createRequest(postUri);
ClientResponse response;
final WebResource.Builder resourceBuilder = addSignature(webResource);
_log.info("webResource=" + webResource);
try {
if (requestBody == null) {
_log.info("RequestBody is null");
response = resourceBuilder.post(ClientResponse.class);
} else {
_log.info("requestBody=" + requestBody);
response = resourceBuilder.post(ClientResponse.class, requestBody);
}
_log.info("response=" + response);
} catch (ClientHandlerException e) {
_log.info("ClientHandlerException: " + e);
checkNodeStatus(postUri, "POST");
throw e;
}
final int status = response.getStatus();
if (!isSuccess(status)) {
_log.info("response={}", response);
throw SyssvcException.syssvcExceptions.sysClientError(
MessageFormatter.arrayFormat("POST request on URI {} to node {} failed with status {}",
new Object[] { postUri, _endpoint.toString(), status }).getMessage());
}
return returnType != null ? response.getEntity(returnType) : null;
}
/**
* Call this method in case GET/POST fails to find the cause
*
* @param uri URI on which POST/GET action is invoked
* @param uriCmd POST or GET to be indicated in the message
* @throws SysClientException
*/
private void checkNodeStatus(URI uri, String uriCmd) throws SysClientException {
_log.info("Entering SysClientFactory.checkNodeStatus()");
String nodeIP;
try {
_log.info("Before InetAddress.getByName()");
nodeIP = InetAddress.getByName(_endpoint.getHost()).getHostAddress();
_log.info("after InetAddress.getByName()");
} catch (UnknownHostException e) {
_log.info(" request on URI {} to node {} failed to get node IP address {}",
new Object[] { uri, _endpoint.toString(), e.getMessage() });
throw SyssvcException.syssvcExceptions.sysClientError(
MessageFormatter.arrayFormat(uriCmd + " request on URI {} to node {} failed to get node IP address {}",
new Object[] { uri, _endpoint.toString(), e.getMessage() }).getMessage());
}
_log.info("out first try catch");
final String[] cmd = { _IPCHECKTOOL_CMD, "--ip", nodeIP };
_log.info("get cmd");
Exec.Result result = Exec.sudo(_IPCHECKTOOL_TIMEOUT, cmd);
_log.info("Exec.Result");
if (result.getExitValue() == _IPCHECKTOOL_IP_CONFLICT) {
_log.info(" request on URI {} to node {} failed due to IP conflict at {}",
new Object[] { uri, _endpoint.toString(), nodeIP });
throw SyssvcException.syssvcExceptions.sysClientError(
MessageFormatter.arrayFormat(uriCmd +
" request on URI {} to node {} failed due to IP conflict at {}",
new Object[] { uri, _endpoint.toString(),
nodeIP }).getMessage());
} else if (result.getExitValue() == _IPCHECKTOOL_NO_NODE) {
_log.info(" request on URI {} to node {} failed due to node with IP {} is down.",
new Object[] { uri, _endpoint.toString(),
nodeIP });
throw SyssvcException.syssvcExceptions.sysClientError(
MessageFormatter.arrayFormat(uriCmd +
" request on URI {} to node {} failed due to node with IP {} is down.",
new Object[] { uri, _endpoint.toString(),
nodeIP }).getMessage());
}
_log.info("out of Check status");
}
private boolean isSuccess(int status) {
return (status == 200 || status == 202);
}
}
}