/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.ambari.funtest.server; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.stream.JsonReader; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.ResponseHandler; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpDelete; import org.apache.http.RequestLine; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import org.apache.http.entity.StringEntity; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.codec.binary.Base64; import java.io.IOException; import java.io.StringReader; import java.util.Map; import java.lang.StringBuilder; import org.apache.commons.lang.StringUtils; /** * REST API Client that performs various operations on the Ambari Server * using Http. */ public class AmbariHttpWebRequest extends WebRequest { private static final Log LOG = LogFactory.getLog(AmbariHttpWebRequest.class); private static String SERVER_URL_FORMAT = "http://%s:%d"; private static String SERVER_SSL_URL_FORMAT = "https://%s:%d"; private String content; private String serverName; private int serverApiPort; private int serverAgentPort; private WebResponse response; private String curlApi; /** * Constructor to set the REST API URL, Server API port, Server Agent API port, user id and password. * * @param params */ public AmbariHttpWebRequest(ConnectionParams params) { setServerName(params.getServerName()); setServerApiPort(params.getServerApiPort()); setServerAgentPort(params.getServerAgentPort()); setUserName(params.getUserName()); setPassword(params.getPassword()); addHeader("X-Requested-By", "ambari"); if (getUserName() != null) { addHeader("Authorization", getBasicAuthentication()); } } /** * Sends the request to the Ambari server and returns the response. * * @return - Response from the Ambari server. * @throws IOException */ @Override public WebResponse getResponse() throws IOException { if (response == null) { LOG.info(getCurlApi()); response = executeRequest(); } return response; } /** * Gets the full URI * * @return - Full path to the URI */ @Override public String getUrl() { return getServerApiUrl() + getApiPath(); } /** * Gets the JSON content (request data). * * @return - JSON content. */ @Override public String getContent() { if (content == null) { content = getRequestData(); } return content; } /** * Gets the content encoding. * * @return - Content encoding. */ @Override public String getContentEncoding() { return "UTF-8"; } /** * Gets the content type, like application/json, application/text, etc. * * @return - Content type. */ @Override public String getContentType() { return "application/json"; } /** * Gets the curl command line call for this request. Useful for * debugging. * * @return - Curl command line call. */ public String getCurlApi() { if (curlApi == null) { StringBuilder sb = new StringBuilder(); sb.append("curl"); if (getUserName() != null) { sb.append(String.format(" -u %s", getUserName())); if (getPassword() != null) { sb.append(String.format(":%s", getPassword())); } } sb.append(String.format(" -H \"%s\"", "X-Requested-By: ambari")); sb.append(String.format(" -X %s", getHttpMethod())); if (getHttpMethod().equals("PUT") || getHttpMethod().equals("POST")) { if (getContent() != null) { sb.append(String.format(" -d '%s'", getContent())); } } sb.append(String.format(" %s", getUrl())); curlApi = sb.toString(); } return curlApi; } /** * Sets the REST API URL for the Ambari Server * * @param serverName - REST API URL */ public void setServerName(String serverName) { this.serverName = serverName; } /** * Gets the REST API URL for the Ambari Server * * @return - REST API URL */ public String getServerName() { return this.serverName; } /** * Gets the port number for the REST API used by the web clients. * * @return - Server API port number. */ public int getServerApiPort() { return this.serverApiPort; } /** * Sets the port number for the REST API used by the web clients. * * @param serverApiPort - Server API port. */ public void setServerApiPort(int serverApiPort) { this.serverApiPort = serverApiPort; } /** * Gets the port number for the REST API used by the agent. * * @return - Agent API port number. */ public int getServerAgentPort() { return this.serverAgentPort; } /** * Sets the port number for the REST API used by the agent. * * @param serverAgentPort - Agent API port number. */ public void setServerAgentPort(int serverAgentPort) { this.serverAgentPort = serverAgentPort; } /** * Gets the REST API path fragment. * * @return - REST API path. */ protected String getApiPath() { return ""; } /** * Gets the request data used in POST and PUT requests. * * @return - Request data. */ protected String getRequestData() { return ""; } /** * Gets the basic authentication string to be used for the Authorization header. * * @return - Base-64 encoded authentication string. */ protected String getBasicAuthentication() { String authString = getUserName() + ":" + getPassword(); byte[] authEncBytes = Base64.encodeBase64(authString.getBytes()); String authStringEnc = new String(authEncBytes); return "Basic " + authStringEnc; } /** * Gets URL for the Ambari Server (without the API path) * * @return - Ambari server URL. */ protected String getServerApiUrl() { return String.format(SERVER_URL_FORMAT, getServerName(), getServerApiPort()); } /** * Gets URL for the Agent Server (without the API path) * * @return - Agent server URL. */ protected String getServerAgentUrl() { return String.format(SERVER_URL_FORMAT, getServerName(), getServerAgentPort()); } /** * Helper method to create simple Json objects. * * @param name - Name * @param value - Value * @return - A JsonObject {name: value} */ protected static JsonObject createJsonObject(String name, String value) { JsonObject jsonObject = new JsonObject(); jsonObject.addProperty(name, value); return jsonObject; } /** * Helper method to create simple Json objects. * * @param name - Name * @param jsonElement - Json object. * @return - A JsonObject {name: jsonElement } */ protected static JsonObject createJsonObject(String name, JsonElement jsonElement) { JsonObject jsonObject = new JsonObject(); jsonObject.add(name, jsonElement); return jsonObject; } /** * Executes the current request by using HttpClient methods and returns the response. * * @return - Response from the Ambari server/Agent server. * @throws IOException */ private WebResponse executeRequest() throws IOException { final WebResponse response = new WebResponse(); CloseableHttpClient httpClient = HttpClients.createDefault(); try { HttpRequestBase requestBase = null; String httpMethod = getHttpMethod(); if (httpMethod.equals("GET")) { requestBase = new HttpGet(getRequestUrl()); } else if (httpMethod.equals("POST")) { HttpPost httpPost = new HttpPost(getRequestUrl()); if (StringUtils.isNotEmpty(getContent())) { httpPost.setHeader("Content-Type", getContentType()); httpPost.setEntity(new StringEntity(getContent(), getContentEncoding())); } requestBase = httpPost; } else if (httpMethod.equals("PUT")) { HttpPut httpPut = new HttpPut(getRequestUrl()); if (StringUtils.isNotEmpty(getContent())) { httpPut.setHeader("Content-Type", getContentType()); httpPut.setEntity(new StringEntity(getContent(), getContentEncoding())); } requestBase = httpPut; } else if (httpMethod.equals("DELETE")) { requestBase = new HttpDelete(getRequestUrl()); } else { new RuntimeException(String.format("Unsupported HTTP method: %s", httpMethod)); } Map<String, String> headers = getHeaders(); for (Map.Entry<String, String> header : headers.entrySet()) { requestBase.addHeader(header.getKey(), header.getValue()); } RequestLine requestLine = requestBase.getRequestLine(); LOG.debug(requestLine); ResponseHandler<String> responseHandler = new ResponseHandler<String>() { @Override public String handleResponse(final HttpResponse httpResponse) throws ClientProtocolException, IOException { int statusCode = httpResponse.getStatusLine().getStatusCode(); response.setStatusCode(statusCode); HttpEntity entity = httpResponse.getEntity(); return entity != null ? EntityUtils.toString(entity) : null; } }; String responseBody = httpClient.execute(requestBase, responseHandler); response.setContent(responseBody); } finally { httpClient.close(); } return response; } private String getRequestUrl() { StringBuilder requestUrl = new StringBuilder(getUrl()); if (StringUtils.isNotEmpty(getQueryString())) { requestUrl.append("?"); requestUrl.append(getQueryString()); } return requestUrl.toString(); } }