Repository: ambari Updated Branches: refs/heads/trunk 92b11fc48 -> 22cd004c4
AMBARI-15976. Add Log Level Counts to LogSearch Integration. (rnettleton) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/22cd004c Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/22cd004c Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/22cd004c Branch: refs/heads/trunk Commit: 22cd004c416205cd8dc60e09a68a29e235d063d5 Parents: 92b11fc Author: Bob Nettleton <[email protected]> Authored: Tue Apr 19 13:17:22 2016 -0400 Committer: Bob Nettleton <[email protected]> Committed: Tue Apr 19 13:18:36 2016 -0400 ---------------------------------------------------------------------- .../server/api/services/LoggingService.java | 72 +------ .../controller/AmbariManagementController.java | 9 + .../AmbariManagementControllerImpl.java | 5 + .../internal/LoggingResourceProvider.java | 9 +- .../logging/HostComponentLoggingInfo.java | 12 ++ .../logging/LogLevelQueryResponse.java | 99 ++++++++++ .../controller/logging/LogLineResult.java | 5 + .../logging/LoggingRequestHelper.java | 2 + .../LoggingRequestHelperFactoryImpl.java | 20 +- .../logging/LoggingRequestHelperImpl.java | 190 ++++++++++++++----- .../logging/LoggingSearchPropertyProvider.java | 10 +- .../controller/logging/NameValuePair.java | 55 ++++++ .../logging/LogLevelQueryResponseTest.java | 105 ++++++++++ .../LoggingRequestHelperFactoryImplTest.java | 103 +++++++++- .../LoggingSearchPropertyProviderTest.java | 86 ++++++++- 15 files changed, 660 insertions(+), 122 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/22cd004c/ambari-server/src/main/java/org/apache/ambari/server/api/services/LoggingService.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/LoggingService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/LoggingService.java index 08ec06e..c93f7bd 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/LoggingService.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/LoggingService.java @@ -18,7 +18,6 @@ package org.apache.ambari.server.api.services; -import org.apache.ambari.server.api.resources.ResourceInstance; import org.apache.ambari.server.api.services.serializers.ResultSerializer; import org.apache.ambari.server.controller.AmbariManagementController; import org.apache.ambari.server.controller.AmbariServer; @@ -29,7 +28,6 @@ import org.apache.ambari.server.controller.logging.LoggingRequestHelperFactory; import org.apache.ambari.server.controller.logging.LoggingRequestHelperFactoryImpl; import org.apache.ambari.server.controller.spi.Resource; import org.apache.ambari.server.utils.RetryHelper; -import org.apache.log4j.Logger; import javax.ws.rs.GET; import javax.ws.rs.Path; @@ -40,7 +38,6 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -54,14 +51,6 @@ import java.util.Map; */ public class LoggingService extends BaseService { - private static final Logger LOG = Logger.getLogger(LoggingService.class); - - public static final String LOGSEARCH_SITE_CONFIG_TYPE_NAME = "logsearch-site"; - - public static final String LOGSEARCH_SERVICE_NAME = "LOGSEARCH"; - - public static final String LOGSEARCH_SERVER_COMPONENT_NAME = "LOGSEARCH_SERVER"; - private final ControllerFactory controllerFactory; private final LoggingRequestHelperFactory helperFactory; @@ -80,40 +69,13 @@ public class LoggingService extends BaseService { } @GET - @Produces("text/plain") - public Response getLogSearchResource(String body, @Context HttpHeaders headers, @Context UriInfo uri) { - return handleRequest(headers, body, uri, Request.Type.GET, createLoggingResource()); - } - - @GET @Path("searchEngine") @Produces("text/plain") public Response getSearchEngine(String body, @Context HttpHeaders headers, @Context UriInfo uri) { //TODO, fix this cast after testing,RWN - return handleDirectRequest(headers, body, uri, Request.Type.GET, (MediaType)null); - } - - @GET - @Path("levelCount") - @Produces("text/plain") - public Response getLevelCountForCluster(String body, @Context HttpHeaders headers, @Context UriInfo ui) { - throw new IllegalStateException("not implemented yet"); - } - - @GET - @Path("graphing") - @Produces("text/plain") - public Response getGraphData(String body, @Context HttpHeaders headers, @Context UriInfo ui) { - throw new IllegalStateException("not implemented yet"); + return handleDirectRequest(uri, MediaType.TEXT_PLAIN_TYPE); } - - private ResourceInstance createLoggingResource() { - return createResource(Resource.Type.LoggingQuery, - Collections.singletonMap(Resource.Type.LoggingQuery, "logging")); - } - - /** * Handling method for REST services that don't require the QueryParameter and * partial-response syntax support provided by the Ambari REST framework. @@ -121,14 +83,12 @@ public class LoggingService extends BaseService { * In the case of the LoggingService, the query parameters passed to the search engine must * be preserved, since they are passed to the LogSearch REST API. * - * @param headers - * @param body - * @param uriInfo - * @param requestType - * @param mediaType - * @return + * @param uriInfo URI information for this request + * @param mediaType media type for this request + * + * @return a Response for the request associated with this UriInfo */ - protected Response handleDirectRequest(HttpHeaders headers, String body, UriInfo uriInfo, Request.Type requestType, MediaType mediaType) { + protected Response handleDirectRequest(UriInfo uriInfo, MediaType mediaType) { MultivaluedMap<String, String> queryParameters = uriInfo.getQueryParameters(); @@ -209,24 +169,4 @@ public class LoggingService extends BaseService { return AmbariServer.getController(); } } - - private static class LogSearchConnectionInfo { - - private final String hostName; - private final String portNumber; - - public LogSearchConnectionInfo(String hostName, String portNumber) { - this.hostName = hostName; - this.portNumber = portNumber; - } - - public String getHostName() { - return this.hostName; - } - - public String getPortNumber() { - return this.portNumber; - } - - } } http://git-wip-us.apache.org/repos/asf/ambari/blob/22cd004c/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java index a448a1f..d6b9d0e 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java @@ -33,6 +33,7 @@ import org.apache.ambari.server.controller.metrics.timeline.cache.TimelineMetric import org.apache.ambari.server.metadata.RoleCommandOrder; import org.apache.ambari.server.scheduler.ExecutionScheduleManager; import org.apache.ambari.server.security.authorization.AuthorizationException; +import org.apache.ambari.server.security.encryption.CredentialStoreService; import org.apache.ambari.server.security.ldap.LdapBatchDto; import org.apache.ambari.server.security.ldap.LdapSyncDto; import org.apache.ambari.server.stageplanner.RoleGraphFactory; @@ -800,5 +801,13 @@ public interface AmbariManagementController { * @return */ KerberosHelper getKerberosHelper(); + + /** + * Returns the CredentialStoreService implementation associated with this + * controller + * @return CredentialStoreService + */ + CredentialStoreService getCredentialStoreService(); + } http://git-wip-us.apache.org/repos/asf/ambari/blob/22cd004c/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java index 58bab59..6219205 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java @@ -4700,6 +4700,11 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle return kerberosHelper; } + @Override + public CredentialStoreService getCredentialStoreService() { + return credentialStoreService; + } + /** * Queries the CredentialStoreService to gather properties about it. * <p/> http://git-wip-us.apache.org/repos/asf/ambari/blob/22cd004c/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/LoggingResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/LoggingResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/LoggingResourceProvider.java index f2e07bd..d479f89 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/LoggingResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/LoggingResourceProvider.java @@ -20,7 +20,11 @@ package org.apache.ambari.server.controller.internal; import org.apache.ambari.server.controller.AmbariManagementController; +import org.apache.ambari.server.controller.AmbariServer; import org.apache.ambari.server.controller.logging.LogQueryResponse; +import org.apache.ambari.server.controller.logging.LoggingRequestHelper; +import org.apache.ambari.server.controller.logging.LoggingRequestHelperFactory; +import org.apache.ambari.server.controller.logging.LoggingRequestHelperFactoryImpl; import org.apache.ambari.server.controller.logging.LoggingRequestHelperImpl; import org.apache.ambari.server.controller.spi.NoSuchParentResourceException; import org.apache.ambari.server.controller.spi.NoSuchResourceException; @@ -86,8 +90,9 @@ public class LoggingResourceProvider extends AbstractControllerResourceProvider Resource resource = new ResourceImpl(Resource.Type.LoggingQuery); setResourceProperty(resource, LOGGING_SEARCH_SERVICE_PROPERTY_ID, "logging", getRequestPropertyIds(request, predicate)); - LoggingRequestHelperImpl requestHelper = - new LoggingRequestHelperImpl(); + // TODO, fix this during refactoring + LoggingRequestHelper requestHelper = + new LoggingRequestHelperFactoryImpl().getHelper(AmbariServer.getController(), ""); Map<String, String> queryParameters = new HashMap<String, String>(); http://git-wip-us.apache.org/repos/asf/ambari/blob/22cd004c/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/HostComponentLoggingInfo.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/HostComponentLoggingInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/HostComponentLoggingInfo.java index 516c322..3ef5213 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/HostComponentLoggingInfo.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/HostComponentLoggingInfo.java @@ -29,6 +29,8 @@ public class HostComponentLoggingInfo { private List<LogFileDefinitionInfo> listOfLogFileDefinitions; + private List<NameValuePair> listOfLogLevels; + public HostComponentLoggingInfo() { } @@ -52,4 +54,14 @@ public class HostComponentLoggingInfo { public void setListOfLogFileDefinitions(List<LogFileDefinitionInfo> listOfLogFileDefinitions) { this.listOfLogFileDefinitions = listOfLogFileDefinitions; } + + @JsonProperty("log_level_counts") + public List<NameValuePair> getListOfLogLevels() { + return listOfLogLevels; + } + + @JsonProperty("log_level_counts") + public void setListOfLogLevels(List<NameValuePair> listOfLogLevels) { + this.listOfLogLevels = listOfLogLevels; + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/22cd004c/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LogLevelQueryResponse.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LogLevelQueryResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LogLevelQueryResponse.java new file mode 100644 index 0000000..1280877 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LogLevelQueryResponse.java @@ -0,0 +1,99 @@ +/** + * 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.server.controller.logging; + +import org.codehaus.jackson.annotate.JsonProperty; + +import java.util.List; + +public class LogLevelQueryResponse { + + private String startIndex; + + private String pageSize; + + private String totalCount; + + private String resultSize; + + private String queryTimeMS; + + private List<NameValuePair> nameValueList; + + + @JsonProperty("startIndex") + public String getStartIndex() { + return startIndex; + } + + @JsonProperty("startIndex") + public void setStartIndex(String startIndex) { + this.startIndex = startIndex; + } + + @JsonProperty("pageSize") + public String getPageSize() { + return pageSize; + } + + @JsonProperty("pageSize") + public void setPageSize(String pageSize) { + this.pageSize = pageSize; + } + + @JsonProperty("totalCount") + public String getTotalCount() { + return totalCount; + } + + @JsonProperty("totalCount") + public void setTotalCount(String totalCount) { + this.totalCount = totalCount; + } + + @JsonProperty("resultSize") + public String getResultSize() { + return resultSize; + } + + @JsonProperty("resultSize") + public void setResultSize(String resultSize) { + this.resultSize = resultSize; + } + + @JsonProperty("queryTimeMS") + public String getQueryTimeMS() { + return queryTimeMS; + } + + @JsonProperty("queryTimeMS") + public void setQueryTimeMS(String queryTimeMS) { + this.queryTimeMS = queryTimeMS; + } + + + @JsonProperty("vNameValues") + public List<NameValuePair> getNameValueList() { + return nameValueList; + } + + @JsonProperty("vNameValues") + public void setNameValueList(List<NameValuePair> nameValueList) { + this.nameValueList = nameValueList; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/22cd004c/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LogLineResult.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LogLineResult.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LogLineResult.java index b6ab6bd..c71df51 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LogLineResult.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LogLineResult.java @@ -18,6 +18,7 @@ package org.apache.ambari.server.controller.logging; +import org.codehaus.jackson.annotate.JsonIgnoreProperties; import org.codehaus.jackson.annotate.JsonProperty; import java.util.HashMap; @@ -27,6 +28,10 @@ import java.util.Map; * This class represents a single entry from a LogSearch query. * */ +// annotate this class, so that Jackson will +// ignore any extra properties in the response that +// the integration code does not need at this time +@JsonIgnoreProperties(ignoreUnknown = true) public class LogLineResult { private final Map<String, String> mapOfLogLineProperties = http://git-wip-us.apache.org/repos/asf/ambari/blob/22cd004c/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelper.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelper.java index c1fe1d2..eb45c9e 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelper.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelper.java @@ -26,4 +26,6 @@ public interface LoggingRequestHelper { public Set<String> sendGetLogFileNamesRequest(String componentName, String hostName); + public LogLevelQueryResponse sendLogLevelQueryRequest(String componentName, String hostName); + } http://git-wip-us.apache.org/repos/asf/ambari/blob/22cd004c/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperFactoryImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperFactoryImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperFactoryImpl.java index 69d4f3c..970a92e 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperFactoryImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperFactoryImpl.java @@ -23,6 +23,7 @@ import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.Clusters; import org.apache.ambari.server.state.Config; import org.apache.ambari.server.state.ServiceComponentHost; +import org.apache.ambari.server.state.State; import org.apache.log4j.Logger; import java.util.List; @@ -48,14 +49,24 @@ public class LoggingRequestHelperFactoryImpl implements LoggingRequestHelperFact try { Cluster cluster = clusters.getCluster(clusterName); if (cluster != null) { + + boolean isLogSearchEnabled = + cluster.getServices().containsKey(LOGSEARCH_SERVICE_NAME); + + if (!isLogSearchEnabled) { + // log search not enabled, just return null, since no helper impl is necessary + return null; + } + Config logSearchSiteConfig = cluster.getDesiredConfigByType(LOGSEARCH_SITE_CONFIG_TYPE_NAME); List<ServiceComponentHost> listOfMatchingHosts = cluster.getServiceComponentHosts(LOGSEARCH_SERVICE_NAME, LOGSEARCH_SERVER_COMPONENT_NAME); + if (listOfMatchingHosts.size() == 0) { - LOG.info("No matching LOGSEARCH_SERVER instances found, this may indicate a deployment problem. Please verify that LogSearch is deployed and running."); + LOG.warn("No matching LOGSEARCH_SERVER instances found, this may indicate a deployment problem. Please verify that LogSearch is deployed and running."); return null; } @@ -66,11 +77,16 @@ public class LoggingRequestHelperFactoryImpl implements LoggingRequestHelperFact ServiceComponentHost serviceComponentHost = listOfMatchingHosts.get(0); + if (serviceComponentHost.getState() != State.STARTED) { + // if the LOGSEARCH_SERVER is not started, don't attempt to connect + return null; + } + final String logSearchHostName = serviceComponentHost.getHostName(); final String logSearchPortNumber = logSearchSiteConfig.getProperties().get(LOGSEARCH_UI_PORT_PROPERTY_NAME); - return new LoggingRequestHelperImpl(logSearchHostName, logSearchPortNumber); + return new LoggingRequestHelperImpl(logSearchHostName, logSearchPortNumber, ambariManagementController.getCredentialStoreService(), clusterName); } } catch (AmbariException ambariException) { LOG.error("Error occurred while trying to obtain the cluster, cluster name = " + clusterName, ambariException); http://git-wip-us.apache.org/repos/asf/ambari/blob/22cd004c/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperImpl.java index 2c3d941..624977e 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperImpl.java @@ -19,6 +19,10 @@ package org.apache.ambari.server.controller.logging; +import org.apache.ambari.server.AmbariException; +import org.apache.ambari.server.security.credential.Credential; +import org.apache.ambari.server.security.credential.PrincipalKeyCredential; +import org.apache.ambari.server.security.encryption.CredentialStoreService; import org.apache.commons.codec.binary.Base64; import org.apache.http.client.utils.URIBuilder; import org.apache.log4j.Logger; @@ -34,7 +38,6 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.StringReader; import java.net.HttpURLConnection; -import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.util.Collections; @@ -48,75 +51,78 @@ import java.util.Set; */ public class LoggingRequestHelperImpl implements LoggingRequestHelper { - private Logger LOG = Logger.getLogger(LoggingRequestHelperImpl.class); + private static Logger LOG = Logger.getLogger(LoggingRequestHelperImpl.class); - //TODO, hardcoded localhost for LogSearch service for dev purposes, will switch to config after POC finished + public static String LOGSEARCH_QUERY_PATH = "/service/dashboard/solr/logs_search"; - - private static String DEFAULT_HOSTNAME = "localhost"; - - private static String DEFAULT_PORT = "61888"; - - private static String LOGSEARCH_QUERY_PATH = "/service/dashboard/solr/logs_search"; + public static String LOGSEARCH_GET_LOG_LEVELS_PATH = "/service/dashboard/getLogLevelCounts"; private static String DEFAULT_LOGSEARCH_USER = "admin"; private static String DEFAULT_LOGSEARCH_PWD = "admin"; + public static final String LOGSEARCH_ADMIN_CREDENTIAL_NAME = "logsearch.admin.credential"; + private final String hostName; private final String portNumber; + private final CredentialStoreService credentialStoreService; - public LoggingRequestHelperImpl() { - this(DEFAULT_HOSTNAME, DEFAULT_PORT); - } + private final String clusterName; - public LoggingRequestHelperImpl(String hostName, String portNumber) { + public LoggingRequestHelperImpl(String hostName, String portNumber, CredentialStoreService credentialStoreService, String clusterName) { this.hostName = hostName; this.portNumber = portNumber; + this.credentialStoreService = credentialStoreService; + this.clusterName = clusterName; } public LogQueryResponse sendQueryRequest(Map<String, String> queryParameters) { try { // use the Apache builder to create the correct URI - URI logSearchURI = createLogSearchQueryURI(queryParameters); - LOG.info("Attempting to connect to LogSearch server at " + logSearchURI); + URI logSearchURI = createLogSearchQueryURI("http", queryParameters); + LOG.debug("Attempting to connect to LogSearch server at " + logSearchURI); HttpURLConnection httpURLConnection = (HttpURLConnection)logSearchURI.toURL().openConnection(); httpURLConnection.setRequestMethod("GET"); - setupBasicAuthentication(httpURLConnection); + + setupCredentials(httpURLConnection); + StringBuffer buffer = readQueryResponseFromServer(httpURLConnection); // setup a reader for the JSON response StringReader stringReader = new StringReader(buffer.toString()); - // setup the Jackson mapper/reader to read in the data structure - ObjectMapper mapper = createJSONObjectMapper(); - ObjectReader logQueryResponseReader = - mapper.reader(LogQueryResponse.class); - - LogQueryResponse queryResult = - logQueryResponseReader.readValue(stringReader); - - LOG.debug("DEBUG: response from LogSearch was: " + buffer); + createObjectReader(LogQueryResponse.class); - return queryResult; + return logQueryResponseReader.readValue(stringReader); - } catch (MalformedURLException e) { - // TODO, need better error handling here - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. - } catch (IOException e) { - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. - } catch (URISyntaxException e) { - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } catch (Exception e) { + LOG.error("Error occurred while trying to connect to the LogSearch service...", e); } return null; } + private void setupCredentials(HttpURLConnection httpURLConnection) { + PrincipalKeyCredential principalKeyCredential = + getLogSearchCredentials(); + + // determine the credential to use for connecting to LogSearch + if (principalKeyCredential != null) { + // setup credential stored in credential service + LOG.debug("Credential found in CredentialStore, will be used to connect to LogSearch"); + setupBasicAuthentication(httpURLConnection, createEncodedCredentials(principalKeyCredential)); + } else { + // fall back to hard-coded credential for now + LOG.debug("No credential found in CredentialStore, defaulting to fall-back credential for now"); + setupBasicAuthentication(httpURLConnection, createDefaultEncodedCredentials()); + } + } + public Set<String> sendGetLogFileNamesRequest(String componentName, String hostName) { Map<String, String> queryParameters = new HashMap<String, String>(); @@ -135,7 +141,7 @@ public class LoggingRequestHelperImpl implements LoggingRequestHelper { LogLineResult lineOne = response.getListOfResults().get(0); // this assumes that each component has only one associated log file, // which may not always hold true - LOG.info("For componentName = " + componentName + ", log file name is = " + lineOne.getLogFilePath()); + LOG.debug("For componentName = " + componentName + ", log file name is = " + lineOne.getLogFilePath()); return Collections.singleton(lineOne.getLogFilePath()); } @@ -143,12 +149,74 @@ public class LoggingRequestHelperImpl implements LoggingRequestHelper { return Collections.emptySet(); } - private URI createLogSearchQueryURI(Map<String, String> queryParameters) throws URISyntaxException { + @Override + public LogLevelQueryResponse sendLogLevelQueryRequest(String componentName, String hostName) { + try { + // use the Apache builder to create the correct URI + URI logLevelQueryURI = createLogLevelQueryURI("http", componentName, hostName); + LOG.debug("Attempting to connect to LogSearch server at " + logLevelQueryURI); + + HttpURLConnection httpURLConnection = (HttpURLConnection) logLevelQueryURI.toURL().openConnection(); + httpURLConnection.setRequestMethod("GET"); + + setupCredentials(httpURLConnection); + + StringBuffer buffer = readQueryResponseFromServer(httpURLConnection); + + // setup a reader for the JSON response + StringReader stringReader = + new StringReader(buffer.toString()); + + ObjectReader logQueryResponseReader = createObjectReader(LogLevelQueryResponse.class); + + return logQueryResponseReader.readValue(stringReader); + + } catch (Exception e) { + LOG.error("Error occurred while trying to connect to the LogSearch service...", e); + } + + return null; + } + + private static ObjectReader createObjectReader(Class type) { + // setup the Jackson mapper/reader to read in the data structure + ObjectMapper mapper = createJSONObjectMapper(); + + return mapper.reader(type); + } + + + + + private URI createLogSearchQueryURI(String scheme, Map<String, String> queryParameters) throws URISyntaxException { + URIBuilder uriBuilder = createBasicURI(scheme); + uriBuilder.setPath(LOGSEARCH_QUERY_PATH); + + // add any query strings specified + for (String key : queryParameters.keySet()) { + uriBuilder.addParameter(key, queryParameters.get(key)); + } + + return uriBuilder.build(); + } + + private URIBuilder createBasicURI(String scheme) { URIBuilder uriBuilder = new URIBuilder(); - uriBuilder.setScheme("http"); + uriBuilder.setScheme(scheme); uriBuilder.setHost(hostName); uriBuilder.setPort(Integer.valueOf(portNumber)); - uriBuilder.setPath(LOGSEARCH_QUERY_PATH); + return uriBuilder; + } + + private URI createLogLevelQueryURI(String scheme, String componentName, String hostName) throws URISyntaxException { + URIBuilder uriBuilder = createBasicURI(scheme); + uriBuilder.setPath(LOGSEARCH_GET_LOG_LEVELS_PATH); + + Map<String, String> queryParameters = new HashMap<String, String>(); + // set the query parameters to limit this level count + // request to the specific component on the specified host + queryParameters.put("host", hostName); + queryParameters.put("components_name",componentName); // add any query strings specified for (String key : queryParameters.keySet()) { @@ -158,7 +226,9 @@ public class LoggingRequestHelperImpl implements LoggingRequestHelper { return uriBuilder.build(); } - protected ObjectMapper createJSONObjectMapper() { + + + protected static ObjectMapper createJSONObjectMapper() { ObjectMapper mapper = new ObjectMapper(); AnnotationIntrospector introspector = @@ -174,7 +244,7 @@ public class LoggingRequestHelperImpl implements LoggingRequestHelper { // read in the response from LogSearch resultStream = httpURLConnection.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(resultStream)); - LOG.info("Response code from LogSearch Service is = " + httpURLConnection.getResponseCode()); + LOG.debug("Response code from LogSearch Service is = " + httpURLConnection.getResponseCode()); String line = reader.readLine(); StringBuffer buffer = new StringBuffer(); @@ -182,6 +252,9 @@ public class LoggingRequestHelperImpl implements LoggingRequestHelper { buffer.append(line); line = reader.readLine(); } + + LOG.debug("Sucessfully retrieved response from server, response = " + buffer); + return buffer; } finally { // make sure to close the stream after request is completed @@ -191,12 +264,43 @@ public class LoggingRequestHelperImpl implements LoggingRequestHelper { } } - private static void setupBasicAuthentication(HttpURLConnection httpURLConnection) { - //TODO, using hard-coded Base64 auth for now, need to revisit this - String encodedCredentials = - Base64.encodeBase64String((DEFAULT_LOGSEARCH_USER + ":" + DEFAULT_LOGSEARCH_PWD).getBytes()); + private PrincipalKeyCredential getLogSearchCredentials() { + try { + Credential credential = + credentialStoreService.getCredential(clusterName, LOGSEARCH_ADMIN_CREDENTIAL_NAME); + if ((credential != null) && (credential instanceof PrincipalKeyCredential)) { + return (PrincipalKeyCredential)credential; + } + + if (credential == null) { + LOG.debug("LogSearch credentials could not be obtained from store."); + } else { + LOG.error("LogSearch credentials were not of the correct type, this is likely an error in configuration, credential type is = " + credential.getClass().getName()); + } + } catch (AmbariException ambariException) { + LOG.error("Error encountered while trying to obtain LogSearch admin credentials.", ambariException); + } + + + return null; + } + + private static void setupBasicAuthentication(HttpURLConnection httpURLConnection, String encodedCredentials) { httpURLConnection.setRequestProperty("Authorization", "Basic " + encodedCredentials); } + // might need to remove this once the credential integration is in place + private static String createDefaultEncodedCredentials() { + return createEncodedCredentials(DEFAULT_LOGSEARCH_USER, DEFAULT_LOGSEARCH_PWD); + } + + private static String createEncodedCredentials(PrincipalKeyCredential principalKeyCredential) { + return createEncodedCredentials(principalKeyCredential.getPrincipal(), new String(principalKeyCredential.getKey())); + } + + private static String createEncodedCredentials(String userName, String password) { + return Base64.encodeBase64String((userName + ":" + password).getBytes()); + } + } http://git-wip-us.apache.org/repos/asf/ambari/blob/22cd004c/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingSearchPropertyProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingSearchPropertyProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingSearchPropertyProvider.java index 2d2ef18..e2da4c8 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingSearchPropertyProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingSearchPropertyProvider.java @@ -99,6 +99,9 @@ public class LoggingSearchPropertyProvider implements PropertyProvider { Set<String> logFileNames = requestHelper.sendGetLogFileNamesRequest(mappedComponentNameForLogSearch, hostName); + LogLevelQueryResponse levelQueryResponse = + requestHelper.sendLogLevelQueryRequest(mappedComponentNameForLogSearch, hostName); + if ((logFileNames != null) && (!logFileNames.isEmpty())) { loggingInfo.setComponentName(mappedComponentNameForLogSearch); List<LogFileDefinitionInfo> listOfFileDefinitions = @@ -114,7 +117,12 @@ public class LoggingSearchPropertyProvider implements PropertyProvider { loggingInfo.setListOfLogFileDefinitions(listOfFileDefinitions); - LOG.info("Adding logging info for component name = " + componentName + " on host name = " + hostName); + // add the log levels for this host component to the logging structure + if (levelQueryResponse != null) { + loggingInfo.setListOfLogLevels(levelQueryResponse.getNameValueList()); + } + + LOG.debug("Adding logging info for component name = " + componentName + " on host name = " + hostName); // add the logging metadata for this host component resource.setProperty("logging", loggingInfo); } else { http://git-wip-us.apache.org/repos/asf/ambari/blob/22cd004c/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/NameValuePair.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/NameValuePair.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/NameValuePair.java new file mode 100644 index 0000000..115145e --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/NameValuePair.java @@ -0,0 +1,55 @@ +/** + * 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.server.controller.logging; + +import org.codehaus.jackson.annotate.JsonProperty; + +public class NameValuePair { + + private String name; + + private String value; + + public NameValuePair() { + } + + public NameValuePair(String name, String value) { + this.name = name; + this.value = value; + } + + @JsonProperty("name") + public String getName() { + return name; + } + + @JsonProperty("name") + public void setName(String name) { + this.name = name; + } + + @JsonProperty("value") + public String getValue() { + return value; + } + + @JsonProperty("value") + public void setValue(String value) { + this.value = value; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/22cd004c/ambari-server/src/test/java/org/apache/ambari/server/controller/logging/LogLevelQueryResponseTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/logging/LogLevelQueryResponseTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/logging/LogLevelQueryResponseTest.java new file mode 100644 index 0000000..0035150 --- /dev/null +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/logging/LogLevelQueryResponseTest.java @@ -0,0 +1,105 @@ +/** + * 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.server.controller.logging; + +import org.codehaus.jackson.map.AnnotationIntrospector; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.ObjectReader; +import org.codehaus.jackson.map.annotate.JsonSerialize; +import org.codehaus.jackson.map.introspect.JacksonAnnotationIntrospector; +import org.junit.Assert; +import org.junit.Test; + +import java.io.StringReader; +import java.util.List; + +import static org.junit.Assert.assertEquals; + + +public class LogLevelQueryResponseTest { + + private static final String TEST_JSON_INPUT_LOG_LEVEL_QUERY = + "{\"pageSize\":\"0\",\"queryTimeMS\":\"1459970731998\",\"resultSize\":\"6\",\"startIndex\":\"0\",\"totalCount\":\"0\"," + + "\"vNameValues\":[{\"name\":\"FATAL\",\"value\":\"0\"},{\"name\":\"ERROR\",\"value\":\"0\"}," + + "{\"name\":\"WARN\",\"value\":\"41\"},{\"name\":\"INFO\",\"value\":\"186\"},{\"name\":\"DEBUG\",\"value\":\"0\"}," + + "{\"name\":\"TRACE\",\"value\":\"0\"}]}"; + + + @Test + public void testBasicParsing() throws Exception { + // setup a reader for the test JSON data + StringReader stringReader = + new StringReader(TEST_JSON_INPUT_LOG_LEVEL_QUERY); + + // setup the Jackson mapper/reader to read in the data structure + ObjectMapper mapper = + new ObjectMapper(); + AnnotationIntrospector introspector = + new JacksonAnnotationIntrospector(); + mapper.setAnnotationIntrospector(introspector); + mapper.getSerializationConfig().setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL); + + + ObjectReader logLevelQueryResponseReader = + mapper.reader(LogLevelQueryResponse.class); + + LogLevelQueryResponse result = + logLevelQueryResponseReader.readValue(stringReader); + + // expected values taken from JSON input string declared above + assertEquals("startIndex not parsed properly", + "0", result.getStartIndex()); + assertEquals("pageSize not parsed properly", + "0", result.getPageSize()); + assertEquals("totalCount not parsed properly", + "0", result.getTotalCount()); + assertEquals("resultSize not parsed properly", + "6", result.getResultSize()); + assertEquals("queryTimeMS not parsed properly", + "1459970731998", result.getQueryTimeMS()); + + assertEquals("Incorrect number of log level count items parsed", + 6, result.getNameValueList().size()); + + List<NameValuePair> resultList = + result.getNameValueList(); + assertNameValuePair("FATAL", "0", resultList.get(0)); + assertNameValuePair("ERROR", "0", resultList.get(1)); + assertNameValuePair("WARN", "41", resultList.get(2)); + assertNameValuePair("INFO", "186", resultList.get(3)); + assertNameValuePair("DEBUG", "0", resultList.get(4)); + assertNameValuePair("TRACE", "0", resultList.get(5)); + + } + + /** + * Convenience method for asserting on the values of NameValuePair instances + * + * @param expectedName the expected name + * @param expectedValue the expected value + * @param nameValuePair the NameValuePair instance to test + */ + static void assertNameValuePair(String expectedName, String expectedValue, NameValuePair nameValuePair) { + assertEquals("Unexpected name found in this pair", + expectedName, nameValuePair.getName()); + assertEquals("Unexpected value found in this pair", + expectedValue, nameValuePair.getValue()); + } + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/22cd004c/ambari-server/src/test/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperFactoryImplTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperFactoryImplTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperFactoryImplTest.java index 08f945d..af84e92 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperFactoryImplTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperFactoryImplTest.java @@ -19,21 +19,24 @@ package org.apache.ambari.server.controller.logging; import org.apache.ambari.server.controller.AmbariManagementController; +import org.apache.ambari.server.security.encryption.CredentialStoreService; import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.Clusters; import org.apache.ambari.server.state.Config; +import org.apache.ambari.server.state.Service; import org.apache.ambari.server.state.ServiceComponentHost; +import org.apache.ambari.server.state.State; import org.easymock.EasyMockSupport; -import org.junit.Assert; import org.junit.Test; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import java.util.Set; -import static org.junit.Assert.*; -import static org.easymock.EasyMock.*; +import static org.easymock.EasyMock.expect; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; public class LoggingRequestHelperFactoryImplTest { @@ -60,16 +63,23 @@ public class LoggingRequestHelperFactoryImplTest { ServiceComponentHost serviceComponentHostMock = mockSupport.createMock(ServiceComponentHost.class); + CredentialStoreService credentialStoreServiceMock = + mockSupport.createMock(CredentialStoreService.class); + Map<String, String> testProperties = new HashMap<String, String>(); testProperties.put("logsearch.ui.port", expectedPortNumber); expect(controllerMock.getClusters()).andReturn(clustersMock).atLeastOnce(); + expect(controllerMock.getCredentialStoreService()).andReturn(credentialStoreServiceMock).atLeastOnce(); expect(clustersMock.getCluster(expectedClusterName)).andReturn(clusterMock).atLeastOnce(); expect(clusterMock.getDesiredConfigByType("logsearch-site")).andReturn(logSearchSiteConfig).atLeastOnce(); expect(clusterMock.getServiceComponentHosts("LOGSEARCH", "LOGSEARCH_SERVER")).andReturn(Collections.singletonList(serviceComponentHostMock)).atLeastOnce(); + expect(clusterMock.getServices()).andReturn(Collections.singletonMap("LOGSEARCH", (Service) null)).atLeastOnce(); expect(logSearchSiteConfig.getProperties()).andReturn(testProperties).atLeastOnce(); expect(serviceComponentHostMock.getHostName()).andReturn(expectedHostName).atLeastOnce(); + expect(serviceComponentHostMock.getState()).andReturn(State.STARTED).atLeastOnce(); + mockSupport.replayAll(); @@ -89,8 +99,9 @@ public class LoggingRequestHelperFactoryImplTest { } @Test - public void testHelperCreationWithNoLogSearchServersAvailable() throws Exception { + public void testHelperCreationLogSearchServerNotStarted() throws Exception { final String expectedClusterName = "testclusterone"; + final String expectedHostName = "c6410.ambari.apache.org"; final String expectedPortNumber = "61889"; EasyMockSupport mockSupport = new EasyMockSupport(); @@ -107,6 +118,9 @@ public class LoggingRequestHelperFactoryImplTest { Config logSearchSiteConfig = mockSupport.createMock(Config.class); + ServiceComponentHost serviceComponentHostMock = + mockSupport.createMock(ServiceComponentHost.class); + Map<String, String> testProperties = new HashMap<String, String>(); testProperties.put("logsearch.ui.port", expectedPortNumber); @@ -114,7 +128,85 @@ public class LoggingRequestHelperFactoryImplTest { expect(controllerMock.getClusters()).andReturn(clustersMock).atLeastOnce(); expect(clustersMock.getCluster(expectedClusterName)).andReturn(clusterMock).atLeastOnce(); expect(clusterMock.getDesiredConfigByType("logsearch-site")).andReturn(logSearchSiteConfig).atLeastOnce(); + expect(clusterMock.getServiceComponentHosts("LOGSEARCH", "LOGSEARCH_SERVER")).andReturn(Collections.singletonList(serviceComponentHostMock)).atLeastOnce(); + expect(clusterMock.getServices()).andReturn(Collections.singletonMap("LOGSEARCH", (Service) null)).atLeastOnce(); + + // set the LOGSEARCH_SERVER's state to INSTALLED, to simulate the case where + // the server is installed, but not started + expect(serviceComponentHostMock.getState()).andReturn(State.INSTALLED).atLeastOnce(); + + + mockSupport.replayAll(); + + LoggingRequestHelperFactory helperFactory = + new LoggingRequestHelperFactoryImpl(); + + LoggingRequestHelper helper = + helperFactory.getHelper(controllerMock, expectedClusterName); + + assertNull("LoggingRequestHelper object returned by the factory should have been null", + helper); + + mockSupport.verifyAll(); + } + + @Test + public void testHelperCreationWithNoLogSearchServersAvailable() throws Exception { + final String expectedClusterName = "testclusterone"; + + EasyMockSupport mockSupport = new EasyMockSupport(); + + AmbariManagementController controllerMock = + mockSupport.createMock(AmbariManagementController.class); + + Clusters clustersMock = + mockSupport.createMock(Clusters.class); + + Cluster clusterMock = + mockSupport.createMock(Cluster.class); + + Config logSearchSiteConfig = + mockSupport.createMock(Config.class); + + expect(controllerMock.getClusters()).andReturn(clustersMock).atLeastOnce(); + expect(clustersMock.getCluster(expectedClusterName)).andReturn(clusterMock).atLeastOnce(); + expect(clusterMock.getDesiredConfigByType("logsearch-site")).andReturn(logSearchSiteConfig).atLeastOnce(); expect(clusterMock.getServiceComponentHosts("LOGSEARCH", "LOGSEARCH_SERVER")).andReturn(Collections.<ServiceComponentHost>emptyList()).atLeastOnce(); + expect(clusterMock.getServices()).andReturn(Collections.singletonMap("LOGSEARCH", (Service)null)).atLeastOnce(); + + mockSupport.replayAll(); + + LoggingRequestHelperFactory helperFactory = + new LoggingRequestHelperFactoryImpl(); + + LoggingRequestHelper helper = + helperFactory.getHelper(controllerMock, expectedClusterName); + + assertNull("LoggingRequestHelper object returned by the factory should have been null", + helper); + + mockSupport.verifyAll(); + } + + @Test + public void testHelperCreationWithNoLogSearchServiceDeployed() throws Exception { + final String expectedClusterName = "testclusterone"; + + EasyMockSupport mockSupport = new EasyMockSupport(); + + AmbariManagementController controllerMock = + mockSupport.createMock(AmbariManagementController.class); + + Clusters clustersMock = + mockSupport.createMock(Clusters.class); + + Cluster clusterMock = + mockSupport.createMock(Cluster.class); + + expect(controllerMock.getClusters()).andReturn(clustersMock).atLeastOnce(); + expect(clustersMock.getCluster(expectedClusterName)).andReturn(clusterMock).atLeastOnce(); + // do not include LOGSEARCH in this map, to simulate the case when LogSearch is not deployed + expect(clusterMock.getServices()).andReturn(Collections.singletonMap("HDFS", (Service)null)).atLeastOnce(); mockSupport.replayAll(); @@ -130,4 +222,5 @@ public class LoggingRequestHelperFactoryImplTest { mockSupport.verifyAll(); } + } http://git-wip-us.apache.org/repos/asf/ambari/blob/22cd004c/ambari-server/src/test/java/org/apache/ambari/server/controller/logging/LoggingSearchPropertyProviderTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/logging/LoggingSearchPropertyProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/logging/LoggingSearchPropertyProviderTest.java index b360a49..0d61984 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/logging/LoggingSearchPropertyProviderTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/logging/LoggingSearchPropertyProviderTest.java @@ -34,13 +34,44 @@ import org.easymock.EasyMockSupport; import org.junit.Test; import java.util.Collections; +import java.util.LinkedList; +import java.util.List; import java.util.Set; -import static org.junit.Assert.*; -import static org.easymock.EasyMock.*; +import static org.easymock.EasyMock.capture; +import static org.easymock.EasyMock.eq; +import static org.easymock.EasyMock.expect; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; + +/** + * This test case verifies the basic behavior of the + * LoggingSearchPropertyProvider. + * + * Specifically, it verifies that this PropertyProvider + * implementation uses the output from LogSearch queries + * to attach the correct logging-related output to the + * HostComponent resources in Ambari. + * + */ public class LoggingSearchPropertyProviderTest { + /** + * Verifies the following: + * + * 1. That this PropertyProvider implementation uses + * the expected interfaces to make queries to the LogSearch + * service. + * 2. That the PropertyProvider queries the current HostComponent + * resource in order to obtain the correct information to send to + * LogSearch. + * 3. That the output of the LogSearch query is properly set on the + * HostComponent resource in the expected structure. + * + * @throws Exception + */ @Test public void testBasicCall() throws Exception { final String expectedLogFilePath = @@ -76,7 +107,22 @@ public class LoggingSearchPropertyProviderTest { LoggingRequestHelper helperMock = mockSupport.createMock(LoggingRequestHelper.class); + LogLevelQueryResponse levelQueryResponse = + new LogLevelQueryResponse(); + + levelQueryResponse.setTotalCount("3"); + // setup test data for log levels + List<NameValuePair> testListOfLogLevels = + new LinkedList<NameValuePair>(); + testListOfLogLevels.add(new NameValuePair("ERROR", "150")); + testListOfLogLevels.add(new NameValuePair("WARN", "500")); + testListOfLogLevels.add(new NameValuePair("INFO", "2200")); + + levelQueryResponse.setNameValueList(testListOfLogLevels); + + expect(helperMock.sendGetLogFileNamesRequest(expectedLogSearchComponentName, "c6401.ambari.apache.org")).andReturn(Collections.singleton(expectedLogFilePath)); + expect(helperMock.sendLogLevelQueryRequest(expectedLogSearchComponentName,"c6401.ambari.apache.org")).andReturn(levelQueryResponse).atLeastOnce(); Request requestMock = mockSupport.createMock(Request.class); @@ -135,6 +181,9 @@ public class LoggingSearchPropertyProviderTest { Set<Resource> returnedResources = propertyProvider.populateResources(Collections.singleton(resourceMock), requestMock, predicateMock); + // verify that the property provider attached + // the expected logging structure to the associated resource + assertEquals("Returned resource set was of an incorrect size", 1, returnedResources.size()); @@ -163,10 +212,42 @@ public class LoggingSearchPropertyProviderTest { expectedAmbariURL + expectedSearchEnginePath + expectedTailFileQueryString, definitionInfo.getLogFileTailURL()); + // verify that the log level count information + // was properly added to the HostComponent resource + assertNotNull("LogLevel counts should not be null", + returnedLogInfo.getListOfLogLevels()); + assertEquals("LogLevel counts were of an incorrect size", + 3, returnedLogInfo.getListOfLogLevels().size()); + + List<NameValuePair> returnedLevelList = + returnedLogInfo.getListOfLogLevels(); + + assertEquals("NameValue name for log level was incorrect", + "ERROR", returnedLevelList.get(0).getName()); + assertEquals("NameValue name for log level was incorrect", + "150", returnedLevelList.get(0).getValue()); + + assertEquals("NameValue name for log level was incorrect", + "WARN", returnedLevelList.get(1).getName()); + assertEquals("NameValue name for log level was incorrect", + "500", returnedLevelList.get(1).getValue()); + + assertEquals("NameValue name for log level was incorrect", + "INFO", returnedLevelList.get(2).getName()); + assertEquals("NameValue name for log level was incorrect", + "2200", returnedLevelList.get(2).getValue()); + mockSupport.verifyAll(); } + /** + * Verifies that this property provider implementation will + * properly handle the case of LogSearch not being deployed in + * the cluster or available. + * + * @throws Exception + */ @Test public void testCheckWhenLogSearchNotAvailable() throws Exception { @@ -239,7 +320,6 @@ public class LoggingSearchPropertyProviderTest { PropertyProvider propertyProvider = new LoggingSearchPropertyProvider(helperFactoryMock, factoryMock); - // execute the populate resources method, verify that no exceptions occur, due to // the LogSearch helper not being available Set<Resource> returnedResources =
