diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java index 9c884258608..9625f101269 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java @@ -44,12 +44,14 @@ import java.text.MessageFormat; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Random; import java.util.Set; import java.util.TreeMap; @@ -64,6 +66,7 @@ import org.apache.ambari.server.agent.ExecutionCommand; import org.apache.ambari.server.agent.ExecutionCommand.KeyNames; import org.apache.ambari.server.api.services.AmbariMetaInfo; +import org.apache.ambari.server.api.services.ServiceKey; import org.apache.ambari.server.configuration.Configuration; import org.apache.ambari.server.controller.internal.RequestOperationLevel; import org.apache.ambari.server.controller.internal.RequestResourceFilter; @@ -102,6 +105,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; import com.google.gson.Gson; import com.google.inject.Inject; import com.google.inject.Singleton; @@ -568,68 +573,61 @@ private void findHostAndAddServiceCheckAction(final ActionExecutionContext actio final String serviceGroupName = resourceFilter.getServiceGroupName(); final String serviceName = resourceFilter.getServiceName(); Service service = cluster.getService(serviceGroupName, serviceName); - final String componentName = actionMetadata.getClient(service.getServiceType()); - String smokeTestRole = actionMetadata.getServiceCheckAction(service.getServiceType()); - if (null == smokeTestRole) { - smokeTestRole = actionExecutionContext.getActionName(); - } - Set candidateHosts; - final Map serviceHostComponents; + // If specified a specific host, run on it as long as it contains the component. + // Otherwise, throw the exception. + List candidateHostsList = resourceFilter.getHostNames(); - if (componentName != null) { - serviceHostComponents = cluster.getService(serviceGroupName, serviceName).getServiceComponent(componentName).getServiceComponentHosts(); + ServiceComponentHost selectedServiceComponentHost = calculateServiceComponentHostForServiceCheck(cluster, service, + candidateHostsList, actionExecutionContext.isMaintenanceModeHostExcluded()); - if (serviceHostComponents.isEmpty()) { - throw new AmbariException(MessageFormat.format("No hosts found for service: {0}, component: {1} in cluster: {2}", - serviceName, componentName, clusterName)); - } + long nowTimestamp = System.currentTimeMillis(); + Map actionParameters = actionExecutionContext.getParameters(); - // If specified a specific host, run on it as long as it contains the component. - // Otherwise, use candidates that contain the component. - List candidateHostsList = resourceFilter.getHostNames(); - if (candidateHostsList != null && !candidateHostsList.isEmpty()) { - candidateHosts = new HashSet<>(candidateHostsList); + String smokeTestRole = actionMetadata.getServiceCheckAction(service.getServiceType()); + if (null == smokeTestRole) { + smokeTestRole = actionExecutionContext.getActionName(); + } - // Get the intersection. - candidateHosts.retainAll(serviceHostComponents.keySet()); + addServiceCheckAction(stage, selectedServiceComponentHost.getHostName(), smokeTestRole, nowTimestamp, + selectedServiceComponentHost.getServiceGroupName(), + selectedServiceComponentHost.getServiceName(), + selectedServiceComponentHost.getServiceComponentName(), + actionParameters, actionExecutionContext.isRetryAllowed(), + actionExecutionContext.isFailureAutoSkipped(), + serviceName); + } - if (candidateHosts.isEmpty()) { - throw new AmbariException(MessageFormat.format("The resource filter for hosts does not contain components for " + - "service: {0}, component: {1} in cluster: {2}", serviceName, componentName, clusterName)); - } - } else { - candidateHosts = serviceHostComponents.keySet(); - } - } else { - // TODO: This code branch looks unreliable (taking random component, should prefer the clients) - Map serviceComponents = cluster.getService(serviceGroupName, serviceName).getServiceComponents(); + ServiceComponentHost calculateServiceComponentHostForServiceCheck(Cluster cluster, Service service) throws AmbariException { + return calculateServiceComponentHostForServiceCheck(cluster, service, null, true); + } - // Filter components without any HOST - Iterator serviceComponentNameIterator = serviceComponents.keySet().iterator(); - while (serviceComponentNameIterator.hasNext()){ - String componentToCheck = serviceComponentNameIterator.next(); - if (serviceComponents.get(componentToCheck).getServiceComponentHosts().isEmpty()){ - serviceComponentNameIterator.remove(); - } - } + /** + * Calculates the ServiceComponentHost for cluster service where the service check will be executed. + * Takes into account all the possible clients. + * Those include the given service clients and clients of dependent services if the client component name is specified in the metainfo.xml of the given service + * + * Filters out hosts that are : not listed in candidateHostsList (if non null or not empty) + * in maintenance mode (based on isMaintenanceModeHostExcluded) + * are unhealthy + * + * Based on the ServiceComponentHosts that left selects a ServiceComponentHost using following logic: + * If possible select a host that's not loaded with tasks. Random otherwise + * If possible select a component of the service that the service check runs for. Random otherwise + */ + ServiceComponentHost calculateServiceComponentHostForServiceCheck(Cluster cluster, Service service, + List candidateHostsList, boolean isMaintenanceModeHostExcluded) throws AmbariException { - if (serviceComponents.isEmpty()) { - throw new AmbariException(MessageFormat.format("Did not find any hosts with components for service: {0} in cluster: {1}", - serviceName, clusterName)); - } + //calculate the possible host-component map where the service check could be executed + Multimap hostComponentMultiMap = calculateHostsClientsMultimap(service, cluster, candidateHostsList); - // Pick a random service (should prefer clients). - ServiceComponent serviceComponent = serviceComponents.values().iterator().next(); - serviceHostComponents = serviceComponent.getServiceComponentHosts(); - candidateHosts = serviceHostComponents.keySet(); - } + Set candidateHosts = hostComponentMultiMap.keySet(); // check if all hostnames are valid. for(String candidateHostName: candidateHosts) { - ServiceComponentHost serviceComponentHost = serviceHostComponents.get(candidateHostName); + Collection serviceComponentHosts = hostComponentMultiMap.get(candidateHostName); - if (serviceComponentHost == null) { + if (serviceComponentHosts == null || serviceComponentHosts.isEmpty()) { throw new AmbariException("Provided hostname = " + candidateHostName + " is either not a valid cluster host or does not satisfy the filter condition."); } @@ -637,12 +635,11 @@ private void findHostAndAddServiceCheckAction(final ActionExecutionContext actio // Filter out hosts that are in maintenance mode - they should never be included in service checks Set hostsInMaintenanceMode = new HashSet<>(); - if (actionExecutionContext.isMaintenanceModeHostExcluded()) { + if (isMaintenanceModeHostExcluded) { Iterator iterator = candidateHosts.iterator(); while (iterator.hasNext()) { String candidateHostName = iterator.next(); - ServiceComponentHost serviceComponentHost = serviceHostComponents.get(candidateHostName); - Host host = serviceComponentHost.getHost(); + Host host = cluster.getHost(candidateHostName); if (host.getMaintenanceState(cluster.getClusterId()) == MaintenanceState.ON) { hostsInMaintenanceMode.add(candidateHostName); iterator.remove(); @@ -656,19 +653,141 @@ private void findHostAndAddServiceCheckAction(final ActionExecutionContext actio if (healthyHostNames.isEmpty()) { String message = MessageFormat.format( "While building a service check command for {0}, there were no healthy eligible hosts: unhealthy[{1}], maintenance[{2}]", - serviceName, StringUtils.join(candidateHosts, ','), + service.getName(), StringUtils.join(candidateHosts, ','), StringUtils.join(hostsInMaintenanceMode, ',')); throw new AmbariException(message); } + //Those 2 selections could be swapped depending on the preferred logic + //First : Select a host that's not loaded with tasks, if possible. Random otherwise + //Second : Select a component of the service that the service check runs for, if possible. Random otherwise String preferredHostName = selectRandomHostNameWithPreferenceOnAvailability(healthyHostNames); + return selectRandomSCHForServiceCheck(hostComponentMultiMap.get(preferredHostName), service); + } - long nowTimestamp = System.currentTimeMillis(); - Map actionParameters = actionExecutionContext.getParameters(); - addServiceCheckAction(stage, preferredHostName, smokeTestRole, nowTimestamp, serviceGroupName, serviceName, componentName, - actionParameters, actionExecutionContext.isRetryAllowed(), - actionExecutionContext.isFailureAutoSkipped()); + /** + * Finds the client component name using ActionMetadata and the given service metainfo.xml + * If the client component name is defined calculated the host - client components map using the service dependencies, + * otherwise just maps all service hosts to components + * + * If candidateHostsList is not null and not empty the map will be filtered using given hostnames. + */ + private Multimap calculateHostsClientsMultimap(Service service, Cluster cluster, List candidateHostsList) throws AmbariException { + + String clientComponentName; + CommandScriptDefinition commandScript = ambariMetaInfo.getService(service).getCommandScript(); + if (commandScript != null && commandScript.getClientComponentType() != null) { + clientComponentName = commandScript.getClientComponentType(); + } else { + clientComponentName = actionMetadata.getClient(service.getServiceType()); + } + + if (clientComponentName != null) { + //If the client component is defined, find the hosts were the service check could run + return calculateClientHostComponentMultiMapUsingDependencies(service, clientComponentName, cluster, candidateHostsList); + } else { + //else just add all service components as the potential candidates, filter those that are not installed on any host + Multimap hostComponentMultiMap = HashMultimap.create(); + // TODO: This code branch looks unreliable (taking random component, should prefer the clients) + Map serviceComponents = service.getServiceComponents(); + + // Filter components without any HOST + serviceComponents.keySet().removeIf(componentToCheck -> serviceComponents.get(componentToCheck).getServiceComponentHosts().isEmpty()); + + if (serviceComponents.isEmpty()) { + throw new AmbariException(MessageFormat.format("Did not find any hosts with components for service: {0} in cluster: {1}", + service.getName(), cluster.getClusterName())); + } + + ServiceComponent serviceComponent = serviceComponents.values().iterator().next(); + for (Map.Entry entry : serviceComponent.getServiceComponentHosts().entrySet()){ + //filter the hostnames that aren't on candidate list + if (candidateHostsList == null || candidateHostsList.isEmpty() || candidateHostsList.contains(entry.getKey())) { + hostComponentMultiMap.put(entry.getKey(), entry.getValue()); + } + } + + return hostComponentMultiMap; + } + } + + /** + * Calculates the Multimap that will contain all the hostNames mapped to client components. + * It will include the client components of the dependent services if the dependent service has such. + * + */ + private Multimap calculateClientHostComponentMultiMapUsingDependencies(Service service, String clientComponentName, + Cluster cluster, List candidateHosts) throws AmbariException { + + Multimap hostComponentMultiMap = HashMultimap.create(); + List clientServiceComponents = new ArrayList<>(); + + // Try to find the client in service itself + try { + clientServiceComponents.add(service.getServiceComponent(clientComponentName)); + } catch (AmbariException e) { + //ignore + } + + // Try to find the clients in dependent services + List dependentServiceKeys = service.getServiceDependencies(); + for (ServiceKey serviceKey : dependentServiceKeys) { + Service dependentService = cluster.getService(serviceKey.getServiceId()); + try { + clientServiceComponents.add(dependentService.getServiceComponent(clientComponentName)); + } catch (AmbariException e) { + // ignore + } + } + + if (clientServiceComponents.isEmpty()) { + throw new AmbariException("Couldn't find any client components " + clientComponentName + + " in the dependent services: " + dependentServiceKeys + + " and the service " + service + + " itself to execute service check on cluster " + cluster.getClusterName()); + } + + for (ServiceComponent clientServiceComponent : clientServiceComponents) { + for (Map.Entry entry : clientServiceComponent.getServiceComponentHosts().entrySet()){ + hostComponentMultiMap.put(entry.getKey(), entry.getValue()); + } + } + + if (hostComponentMultiMap.isEmpty()) { + throw new AmbariException(MessageFormat.format("No hosts with client component found for service: {0}, client component: {1} in cluster: {2}", + service.getName(), clientComponentName, cluster.getClusterName())); + } + + //filter hosts that are not in candidateHosts collection + if (candidateHosts != null && !candidateHosts.isEmpty()) { + Set hostsToRemove = new HashSet<>(hostComponentMultiMap.keySet()); + hostsToRemove.removeAll(candidateHosts); + hostsToRemove.forEach(host -> hostComponentMultiMap.removeAll(host)); + + if (hostComponentMultiMap.isEmpty()) { + throw new AmbariException(MessageFormat.format("The resource filter for hosts does not contain client components " + + "service: {0}, client component: {1} in cluster: {2}", service.getName(), clientComponentName, cluster.getClusterName())); + } + } + + return hostComponentMultiMap; + } + + /** + * + * Returns random ServiceComponentHost from the given collection that belongs to the given Service, if there is such. + * Otherwise returns random ServiceComponentHost from the given collection. + */ + private ServiceComponentHost selectRandomSCHForServiceCheck(Collection serviceComponentHosts, Service service) { + ServiceComponentHost candidateSCH = null; + for (ServiceComponentHost serviceComponentHost : serviceComponentHosts) { + if (Objects.equals(serviceComponentHost.getServiceId(), service.getServiceId())) { + return serviceComponentHost; + } + candidateSCH = serviceComponentHost; + } + return candidateSCH; } /** @@ -718,7 +837,7 @@ private String selectRandomHostNameWithPreferenceOnAvailability(List can */ public void addServiceCheckAction(Stage stage, String hostname, String smokeTestRole, long nowTimestamp, String serviceGroupName, String serviceName, String componentName, - Map actionParameters, boolean retryAllowed, boolean autoSkipFailure) + Map actionParameters, boolean retryAllowed, boolean autoSkipFailure, String initiatingServiceName) throws AmbariException { String clusterName = stage.getClusterName(); @@ -743,7 +862,7 @@ public void addServiceCheckAction(Stage stage, String hostname, String smokeTest HostRoleCommand hrc = stage.getHostRoleCommand(hostname, smokeTestRole); if (hrc != null) { - hrc.setCommandDetail(String.format("%s %s", RoleCommand.SERVICE_CHECK.toString(), serviceName)); + hrc.setCommandDetail(String.format("%s %s", RoleCommand.SERVICE_CHECK.toString(), initiatingServiceName)); } // [ type -> [ key, value ] ] Map> configurations = 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 7989fe77707..a595c851e8a 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 @@ -3163,31 +3163,31 @@ protected RequestStageContainer doStageCreation(RequestStageContainer requestSta } for (Service service : smokeTestServices) { // Creates smoke test commands - // find service component host - ServiceComponent component = getClientComponentForRunningAction(cluster, service); - String componentName = component != null ? component.getName() : null; - String clientHost = getClientHostForRunningAction(cluster, service, component); String smokeTestRole = actionMetadata.getServiceCheckAction(service.getServiceType()); + try { + // find service component host + ServiceComponentHost componentForServiceCheck = customCommandExecutionHelper. + calculateServiceComponentHostForServiceCheck(cluster, service); + + if (StringUtils.isBlank(stage.getHostParamsStage())) { + RepositoryVersionEntity repositoryVersion = componentForServiceCheck.getServiceComponent().getDesiredRepositoryVersion(); + stage.setHostParamsStage(StageUtils.getGson().toJson( + customCommandExecutionHelper.createDefaultHostParams(cluster, repositoryVersion.getStackId()))); + } - if (clientHost == null || smokeTestRole == null) { - LOG.info("Nothing to do for service check as could not find role or" - + " or host to run check on" - + ", clusterName=" + cluster.getClusterName() - + ", serviceGroupName=" + service.getServiceGroupName() - + ", serviceName=" + service.getName() - + ", clientHost=" + clientHost - + ", serviceCheckRole=" + smokeTestRole); - continue; - } - - if (StringUtils.isBlank(stage.getHostParamsStage())) { - RepositoryVersionEntity repositoryVersion = component.getDesiredRepositoryVersion(); - stage.setHostParamsStage(StageUtils.getGson().toJson( - customCommandExecutionHelper.createDefaultHostParams(cluster, repositoryVersion.getStackId()))); + customCommandExecutionHelper.addServiceCheckAction(stage, componentForServiceCheck.getHostName(), smokeTestRole, + nowTimestamp, componentForServiceCheck.getServiceGroupName(), componentForServiceCheck.getServiceName(), + componentForServiceCheck.getServiceComponentName(), null, false, false, service.getName()); + + } catch (AmbariException e) { + LOG.warn("Nothing to do for service check as could not find role or" + + " or host to run check on" + + ", clusterName=" + cluster.getClusterName() + + ", serviceGroupName=" + service.getServiceGroupName() + + ", serviceName=" + service.getName() + + ", serviceCheckRole=" + smokeTestRole + + "Actual reason : " + e.getMessage()); } - - customCommandExecutionHelper.addServiceCheckAction(stage, clientHost, smokeTestRole, - nowTimestamp, service.getServiceGroupName(), service.getName(), componentName, null, false, false); } RoleCommandOrder rco = getRoleCommandOrder(cluster); @@ -3988,79 +3988,6 @@ public void updateGroups(Set requests) throws AmbariException { // currently no group updates are supported } - protected String getClientHostForRunningAction(Cluster cluster, Service service, ServiceComponent serviceComponent) - throws AmbariException { - if (serviceComponent != null && !serviceComponent.getServiceComponentHosts().isEmpty()) { - Set candidateHosts = serviceComponent.getServiceComponentHosts().keySet(); - filterHostsForAction(candidateHosts, service, cluster, Resource.Type.Cluster); - return getHealthyHost(candidateHosts); - } - return null; - } - - protected ServiceComponent getClientComponentForRunningAction(Cluster cluster, - Service service) throws AmbariException { - /* - * We assume Cluster level here. That means that we never run service - * checks on clients/hosts that are in maintenance state. - * That also means that we can not run service check if the only host - * that has client component is in maintenance state - */ - - StackId stackId = service.getDesiredStackId(); - ComponentInfo compInfo = - ambariMetaInfo.getService(stackId.getStackName(), - stackId.getStackVersion(), service.getServiceType()).getClientComponent(); - if (compInfo != null) { - try { - ServiceComponent serviceComponent = - service.getServiceComponent(compInfo.getName()); - if (!serviceComponent.getServiceComponentHosts().isEmpty()) { - return serviceComponent; - } - } catch (ServiceComponentNotFoundException e) { - LOG.warn("Could not find required component to run action" - + ", clusterName=" + cluster.getClusterName() - + ", serviceName=" + service.getName() - + ", componentName=" + compInfo.getName()); - } - } - - // any component will do - Map components = service.getServiceComponents(); - if (!components.isEmpty()) { - for (ServiceComponent serviceComponent : components.values()) { - if (!serviceComponent.getServiceComponentHosts().isEmpty()) { - return serviceComponent; - } - } - } - return null; - } - - /** - * Utility method that filters out hosts from set based on their maintenance - * state status. - */ - protected void filterHostsForAction(Set candidateHosts, Service service, - final Cluster cluster, - final Resource.Type level) - throws AmbariException { - Set ignoredHosts = maintenanceStateHelper.filterHostsInMaintenanceState( - candidateHosts, new MaintenanceStateHelper.HostPredicate() { - @Override - public boolean shouldHostBeRemoved(final String hostname) - throws AmbariException { - Host host = clusters.getHost(hostname); - return !maintenanceStateHelper.isOperationAllowed( - host, cluster.getClusterId(), level); - } - } - ); - LOG.debug("Ignoring hosts when selecting available hosts for action due to maintenance state.Ignored hosts ={}, cluster={}, service={}", - ignoredHosts, cluster.getClusterName(), service.getName()); - } - /** * Filters hosts to only select healthy ones that are heartbeating. *

diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/CommandScriptDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/state/CommandScriptDefinition.java index 093b0caf8a1..6e938df7703 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/CommandScriptDefinition.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/CommandScriptDefinition.java @@ -44,6 +44,8 @@ public class CommandScriptDefinition { */ private int timeout = 0; + private String clientComponentType = null; + public String getScript() { return script; @@ -57,6 +59,10 @@ public int getTimeout() { return timeout; } + public String getClientComponentType() { + return clientComponentType; + } + public enum Type { PYTHON } @@ -77,7 +83,8 @@ public boolean equals(Object obj) { return new EqualsBuilder(). append(script, rhs.script). append(scriptType, rhs.scriptType). - append(timeout, rhs.timeout).isEquals(); + append(timeout, rhs.timeout). + append(clientComponentType, rhs.clientComponentType).isEquals(); } @Override @@ -85,6 +92,7 @@ public int hashCode() { return new HashCodeBuilder(17, 31). append(script). append(scriptType). - append(timeout).toHashCode(); + append(timeout). + append(clientComponentType).toHashCode(); } } diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelperTest.java index 2df4f10619c..c4d6f4d3dd0 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelperTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelperTest.java @@ -71,7 +71,6 @@ import org.apache.ambari.server.state.SecurityType; import org.apache.ambari.server.state.Service; import org.apache.ambari.server.state.ServiceComponent; -import org.apache.ambari.server.state.ServiceGroup; import org.apache.ambari.server.state.StackId; import org.apache.ambari.server.state.StackInfo; import org.apache.ambari.server.state.State; @@ -220,6 +219,8 @@ public void testRefreshQueueCustomCommand() throws Exception { EasyMock.replay(hostRoleCommand, actionManager, configHelper); + createServiceComponentHosts("c1", "CORE", "c1"); + ambariManagementController.createAction(actionRequest, requestProperties); Request request = requestCapture.getValue(); @@ -265,6 +266,8 @@ public void testHostsFilterHealthy() throws Exception { EasyMock.replay(hostRoleCommand, actionManager, configHelper); + createServiceComponentHosts("c1", "CORE", "c1"); + ambariManagementController.createAction(actionRequest, requestProperties); Request request = requestCapture.getValue(); @@ -301,6 +304,8 @@ public void testHostsFilterUnhealthyHost() throws Exception { EasyMock.replay(hostRoleCommand, actionManager, configHelper); + createServiceComponentHosts("c1", "CORE", "c1"); + ambariManagementController.createAction(actionRequest, requestProperties); Request request = requestCapture.getValue(); @@ -315,10 +320,6 @@ public void testHostsFilterUnhealthyHost() throws Exception { @Test public void testHostsFilterUnhealthyComponent() throws Exception { - // Set custom status to host - clusters.getCluster("c1").getService("GANGLIA").getServiceComponent( - "GANGLIA_MONITOR").getServiceComponentHost("c1-c6402").setState(State.UNKNOWN); - Map requestProperties = new HashMap() { { put("context", "Restart all components for GANGLIA"); @@ -339,6 +340,12 @@ public void testHostsFilterUnhealthyComponent() throws Exception { EasyMock.replay(hostRoleCommand, actionManager, configHelper); + createServiceComponentHosts("c1", "CORE", "c1"); + + // Set custom status to host + clusters.getCluster("c1").getService("GANGLIA").getServiceComponent( + "GANGLIA_MONITOR").getServiceComponentHost("c1-c6402").setState(State.UNKNOWN); + ambariManagementController.createAction(actionRequest, requestProperties); Request request = requestCapture.getValue(); @@ -446,14 +453,9 @@ public void testServiceCheckComponentWithEmptyHosts() throws Exception { } @Test - public void testServiceCheckWithOverriddenTimeout() throws Exception { + public void testServiceCheckWithOverriddenTimeoutAndHostFiltering() throws Exception { AmbariCustomCommandExecutionHelper ambariCustomCommandExecutionHelper = injector.getInstance(AmbariCustomCommandExecutionHelper.class); - Cluster c1 = clusters.getCluster("c1"); - Service s = c1.getService("ZOOKEEPER"); - ServiceComponent sc = s.getServiceComponent("ZOOKEEPER_CLIENT"); - Assert.assertTrue(sc.getServiceComponentHosts().keySet().size() > 1); - // There are multiple hosts with ZK Client. List requestResourceFilter = new ArrayList() {{ add(new RequestResourceFilter("CORE", "ZOOKEEPER", "ZOOKEEPER_CLIENT", Arrays.asList(new String[]{"c1-c6401"}))); @@ -475,6 +477,13 @@ public void testServiceCheckWithOverriddenTimeout() throws Exception { EasyMock.expect(execCmd.getLocalComponents()).andReturn(localComponents).anyTimes(); EasyMock.replay(configHelper, stage, execCmdWrapper, execCmd); + createServiceComponentHosts("c1", "CORE", "c1"); + + Cluster c1 = clusters.getCluster("c1"); + Service s = c1.getService("ZOOKEEPER"); + ServiceComponent sc = s.getServiceComponent("ZOOKEEPER_CLIENT"); + Assert.assertTrue(sc.getServiceComponentHosts().keySet().size() > 1); + ambariCustomCommandExecutionHelper.addExecutionCommandsToStage(actionExecutionContext, stage, new HashMap<>(), null); Map configMap = timeOutCapture.getValues().get(0); for (Map.Entry config : configMap.entrySet()) { @@ -500,14 +509,53 @@ public void testServiceCheckWithOverriddenTimeout() throws Exception { public void testServiceCheckPicksRandomHost() throws Exception { AmbariCustomCommandExecutionHelper ambariCustomCommandExecutionHelper = injector.getInstance(AmbariCustomCommandExecutionHelper.class); + // There are multiple hosts with ZK Client. + List requestResourceFilter = new ArrayList() {{ + add(new RequestResourceFilter("CORE", "ZOOKEEPER", "ZOOKEEPER_CLIENT", null)); + }}; + ActionExecutionContext actionExecutionContext = new ActionExecutionContext("c1", "SERVICE_CHECK", requestResourceFilter); + Stage stage = EasyMock.niceMock(Stage.class); + ExecutionCommandWrapper execCmdWrapper = EasyMock.niceMock(ExecutionCommandWrapper.class); + ExecutionCommand execCmd = EasyMock.niceMock(ExecutionCommand.class); + + EasyMock.expect(stage.getClusterName()).andReturn("c1"); + // + EasyMock.expect(stage.getExecutionCommandWrapper(EasyMock.eq("c1-c6401"), EasyMock.anyString())).andReturn(execCmdWrapper); + EasyMock.expect(stage.getExecutionCommandWrapper(EasyMock.eq("c1-c6402"), EasyMock.anyString())).andReturn(execCmdWrapper); + EasyMock.expect(execCmdWrapper.getExecutionCommand()).andReturn(execCmd); + EasyMock.expect(execCmd.getForceRefreshConfigTagsBeforeExecution()).andReturn(true); + + HashSet localComponents = new HashSet<>(); + EasyMock.expect(execCmd.getLocalComponents()).andReturn(localComponents).anyTimes(); + EasyMock.replay(configHelper, stage, execCmdWrapper, execCmd); + + createServiceComponentHosts("c1", "CORE", "c1"); + Cluster c1 = clusters.getCluster("c1"); Service s = c1.getService("ZOOKEEPER"); ServiceComponent sc = s.getServiceComponent("ZOOKEEPER_CLIENT"); Assert.assertTrue(sc.getServiceComponentHosts().keySet().size() > 1); - // There are multiple hosts with ZK Client. + ambariCustomCommandExecutionHelper.addExecutionCommandsToStage(actionExecutionContext, stage, new HashMap<>(), null); + } + + + + /** + * Perform a Service Check for HDFS on the HADOOP_CLIENTS/SOME_CLIENT_FOR_SERVICE_CHECK service component. + * The HADOOP_CLIENTS service is the service on which HDFS depends. + * The SOME_CLIENT_FOR_SERVICE_CHECK component is defined in HDFS's metainfo file. + * This should cause Ambari to execute service check on dependent service client component. + * + * Also assures that service check doesn't works without dependency defined + * @throws Exception + */ + @Test + public void testServiceCheckRunsOnDependentClientService() throws Exception { + AmbariCustomCommandExecutionHelper ambariCustomCommandExecutionHelper = injector.getInstance(AmbariCustomCommandExecutionHelper.class); + List requestResourceFilter = new ArrayList() {{ - add(new RequestResourceFilter("CORE", "ZOOKEEPER", "ZOOKEEPER_CLIENT", null)); + add(new RequestResourceFilter("CORE", "HDFS", null, null)); }}; ActionExecutionContext actionExecutionContext = new ActionExecutionContext("c1", "SERVICE_CHECK", requestResourceFilter); Stage stage = EasyMock.niceMock(Stage.class); @@ -516,8 +564,7 @@ public void testServiceCheckPicksRandomHost() throws Exception { EasyMock.expect(stage.getClusterName()).andReturn("c1"); // - EasyMock.expect(stage.getExecutionCommandWrapper(EasyMock.eq("c1-c6401"), EasyMock.anyString())).andReturn(execCmdWrapper); - EasyMock.expect(stage.getExecutionCommandWrapper(EasyMock.eq("c1-c6402"), EasyMock.anyString())).andReturn(execCmdWrapper); + EasyMock.expect(stage.getExecutionCommandWrapper(EasyMock.eq("c1-c6403"), EasyMock.anyString())).andReturn(execCmdWrapper); EasyMock.expect(execCmdWrapper.getExecutionCommand()).andReturn(execCmd); EasyMock.expect(execCmd.getForceRefreshConfigTagsBeforeExecution()).andReturn(true); @@ -525,6 +572,44 @@ public void testServiceCheckPicksRandomHost() throws Exception { EasyMock.expect(execCmd.getLocalComponents()).andReturn(localComponents).anyTimes(); EasyMock.replay(configHelper, stage, execCmdWrapper, execCmd); + createServiceComponentHosts("c1", "CORE", "c1"); + + //add host with client only + addHost("c1-c6403", "c1"); + + //create client service + OrmTestHelper ormTestHelper = injector.getInstance(OrmTestHelper.class); + RepositoryVersionEntity repositoryVersion = ormTestHelper.getOrCreateRepositoryVersion(new StackId("HDP-2.0.6"), "2.0.6-1234"); + createService("c1", "CORE", "HADOOP_CLIENTS", repositoryVersion); + createServiceComponent("c1", "CORE", "HADOOP_CLIENTS", "SOME_CLIENT_FOR_SERVICE_CHECK", State.INIT); + createServiceComponentHost("c1", "CORE", "HADOOP_CLIENTS", "SOME_CLIENT_FOR_SERVICE_CHECK", "c1-c6403", State.INIT); + + //make sure there are no HDFS_CLIENT components from HDFS service + Cluster c1 = clusters.getCluster("c1"); + Service s = c1.getService("HDFS"); + try { + ServiceComponent sc = s.getServiceComponent("HDFS_CLIENT"); + Assert.assertEquals(0, sc.getServiceComponentHosts().keySet().size()); + } catch (AmbariException e) { + //ignore + } + + //make sure the SOME_CLIENT_FOR_SERVICE_CHECK component exists on some hosts + Service clientService = c1.getService("HADOOP_CLIENTS"); + ServiceComponent clientServiceComponent = clientService.getServiceComponent("SOME_CLIENT_FOR_SERVICE_CHECK"); + Assert.assertEquals(1, clientServiceComponent.getServiceComponentHosts().keySet().size()); + + //Check if service check works without dependency defined + try { + ambariCustomCommandExecutionHelper.addExecutionCommandsToStage(actionExecutionContext, stage, new HashMap<>(), null); + Assert.fail("Previous method call should have thrown the exception"); + } catch (AmbariException e) { + Assert.assertTrue(e.getMessage().contains("Couldn't find any client components SOME_CLIENT_FOR_SERVICE_CHECK in the dependent services")); + } + + //add dependency from HDFS to HADOOP_CLIENTS + c1.addDependencyToService("CORE", "HDFS", clientService.getServiceId()); + ambariCustomCommandExecutionHelper.addExecutionCommandsToStage(actionExecutionContext, stage, new HashMap<>(), null); } @@ -557,6 +642,8 @@ public void testAvailableServicesMapContainsVersions() throws Exception { actionRequest.getResourceFilters().add(new RequestResourceFilter("CORE", "YARN", "RESOURCEMANAGER", Collections.singletonList("c1-c6401"))); EasyMock.replay(hostRoleCommand, actionManager, configHelper); + createServiceComponentHosts("c1", "CORE", "c1"); + ambariManagementController.createAction(actionRequest, requestProperties); Request request = requestCapture.getValue(); @@ -607,6 +694,8 @@ public void testAvailableServicesMapIsEmptyWhenRepositoriesNotResolved() throws EasyMock.replay(hostRoleCommand, actionManager, configHelper); + createServiceComponentHosts("c1", "CORE", "c1"); + ambariManagementController.createAction(actionRequest, requestProperties); Request request = requestCapture.getValue(); Stage stage = request.getStages().iterator().next(); @@ -690,12 +779,12 @@ private void createClusterFixture(String clusterName, StackId stackId, addHost(hostC6402, clusterName); Cluster cluster = clusters.getCluster(clusterName); - ServiceGroup serviceGroup = cluster.addServiceGroup("CORE"); Assert.assertNotNull(cluster); String serviceGroupName = "CORE"; ServiceGroupResourceProviderTest.createServiceGroup(ambariManagementController, clusterName, serviceGroupName); + createService(clusterName, serviceGroupName, "HDFS", repositoryVersion); createService(clusterName, serviceGroupName, "YARN", repositoryVersion); createService(clusterName, serviceGroupName, "GANGLIA", repositoryVersion); createService(clusterName, serviceGroupName, "ZOOKEEPER", repositoryVersion); @@ -709,7 +798,12 @@ private void createClusterFixture(String clusterName, StackId stackId, // this component should be not installed on any host createServiceComponent(clusterName, serviceGroupName, "FLUME", "FLUME_HANDLER", State.INIT); + } + + private void createServiceComponentHosts(String clusterName, String serviceGroupName, String hostPrefix) throws AmbariException, AuthorizationException { + String hostC6401 = hostPrefix + "-c6401"; + String hostC6402 = hostPrefix + "-c6402"; createServiceComponentHost(clusterName, serviceGroupName, "YARN", "RESOURCEMANAGER", hostC6401, null); createServiceComponentHost(clusterName, serviceGroupName, "YARN", "NODEMANAGER", hostC6401, null); createServiceComponentHost(clusterName, serviceGroupName, "GANGLIA", "GANGLIA_SERVER", hostC6401, State.INIT); diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java index bd0ee32ce1f..90498c41b16 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java @@ -41,7 +41,6 @@ import static org.easymock.EasyMock.verify; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -76,7 +75,6 @@ import org.apache.ambari.server.api.services.AmbariMetaInfo; import org.apache.ambari.server.configuration.Configuration; import org.apache.ambari.server.controller.internal.RequestStageContainer; -import org.apache.ambari.server.controller.spi.Resource; import org.apache.ambari.server.orm.InMemoryDefaultTestModule; import org.apache.ambari.server.orm.dao.RepositoryVersionDAO; import org.apache.ambari.server.orm.entities.LdapSyncSpecEntity; @@ -90,7 +88,6 @@ import org.apache.ambari.server.security.ldap.LdapBatchDto; import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.Clusters; -import org.apache.ambari.server.state.ComponentInfo; import org.apache.ambari.server.state.Config; import org.apache.ambari.server.state.ConfigHelper; import org.apache.ambari.server.state.DesiredConfig; @@ -274,181 +271,6 @@ public void testGetClusters() throws Exception { verify(injector, clusters, cluster, response, credentialStoreService); } - @Test - public void testGetClientHostForRunningAction_componentIsNull() throws Exception { - Injector injector = createNiceMock(Injector.class); - - Cluster cluster = createNiceMock(Cluster.class); - Service service = createNiceMock(Service.class); - ServiceComponent component = null; - - replay(cluster, service, injector); - - AmbariManagementControllerImpl controller = new AmbariManagementControllerImpl(null, clusters, injector); - String host = controller.getClientHostForRunningAction(cluster, service, component); - - assertNull(host); - verify(cluster, service, injector); - } - - @Test - public void testGetClientHostForRunningAction_componentMapIsEmpty() throws Exception { - Injector injector = createNiceMock(Injector.class); - - Cluster cluster = createNiceMock(Cluster.class); - Service service = createNiceMock(Service.class); - ServiceComponent component = createNiceMock(ServiceComponent.class); - Map hostMap = new HashMap<>(); - expect(component.getServiceComponentHosts()).andReturn(hostMap); - - replay(cluster, service, component, injector); - - AmbariManagementControllerImpl controller = new AmbariManagementControllerImpl(null, clusters, injector); - String host = controller.getClientHostForRunningAction(cluster, service, component); - - verify(cluster, service, component, injector); - assertNull(host); - } - - @Test - public void testGetClientHostForRunningAction_returnsHelathyHost() throws Exception { - Injector injector = createNiceMock(Injector.class); - ActionManager actionManager = createNiceMock(ActionManager.class); - - Cluster cluster = createNiceMock(Cluster.class); - Service service = createNiceMock(Service.class); - ServiceComponent component = createNiceMock(ServiceComponent.class); - Map hostMap = createNiceMock(Map.class); - Set hostsSet = createNiceMock(Set.class); - expect(hostMap.isEmpty()).andReturn(false); - expect(hostMap.keySet()).andReturn(hostsSet); - expect(component.getServiceComponentHosts()).andReturn(hostMap).times(2); - - replay(cluster, service, component, injector, actionManager, hostMap, hostsSet); - - AmbariManagementControllerImpl controller = createMockBuilder(AmbariManagementControllerImpl.class) - .addMockedMethod("filterHostsForAction") - .addMockedMethod("getHealthyHost") - .withConstructor(actionManager, clusters, injector) - .createMock(); - expect(controller.getHealthyHost(hostsSet)).andReturn("healthy_host"); - controller.filterHostsForAction(hostsSet, service, cluster, Resource.Type.Cluster); - expectLastCall().once(); - - replay(controller); - String host = controller.getClientHostForRunningAction(cluster, service, component); - - assertEquals("healthy_host", host); - verify(controller, cluster, service, component, injector, hostMap); - } - - @Test - public void testGetClientHostForRunningAction_clientComponent() throws Exception { - Injector injector = createNiceMock(Injector.class); - Cluster cluster = createNiceMock(Cluster.class); - Service service = createNiceMock(Service.class); - StackId stackId = createNiceMock(StackId.class); - ServiceComponent component = createNiceMock(ServiceComponent.class); - - expect(service.getServiceType()).andReturn("service"); - expect(service.getServiceComponent("component")).andReturn(component); - expect(service.getServiceComponents()).andReturn(Collections.singletonMap("component", component)).anyTimes(); - expect(service.getDesiredStackId()).andReturn(stackId); - expect(stackId.getStackName()).andReturn("stack"); - expect(stackId.getStackVersion()).andReturn("1.0"); - - ServiceInfo serviceInfo = createNiceMock(ServiceInfo.class); - ComponentInfo compInfo = createNiceMock(ComponentInfo.class); - expect(serviceInfo.getClientComponent()).andReturn(compInfo); - expect(compInfo.getName()).andReturn("component"); - expect(component.getServiceComponentHosts()).andReturn(Collections.singletonMap("host", null)).anyTimes(); - expect(ambariMetaInfo.getService("stack", "1.0", "service")).andReturn(serviceInfo); - - replay(injector, cluster, service, component, serviceInfo, compInfo, ambariMetaInfo, stackId); - - AmbariManagementControllerImpl controller = new AmbariManagementControllerImpl(null, clusters, injector); - setAmbariMetaInfo(ambariMetaInfo, controller); - ServiceComponent resultComponent = controller.getClientComponentForRunningAction(cluster, service); - - assertNotNull(resultComponent); - assertEquals(component, resultComponent); - verify(injector, cluster, service, component, serviceInfo, compInfo, ambariMetaInfo, stackId); - } - - @Test - public void testGetClientHostForRunningAction_clientComponentThrowsException() throws Exception { - Injector injector = createNiceMock(Injector.class); - Cluster cluster = createNiceMock(Cluster.class); - Service service = createNiceMock(Service.class); - StackId stackId = createNiceMock(StackId.class); - ServiceComponent component1 = createNiceMock(ServiceComponent.class); - ServiceComponent component2 = createNiceMock(ServiceComponent.class); - - expect(service.getServiceType()).andReturn("service"); - expect(service.getServiceComponent("component")).andThrow( - new ServiceComponentNotFoundException("cluster", "service", "service", "CORE", "component")); - expect(service.getDesiredStackId()).andReturn(stackId); - expect(stackId.getStackName()).andReturn("stack"); - expect(stackId.getStackVersion()).andReturn("1.0"); - Map componentsMap = new HashMap<>(); - componentsMap.put("component1", component1); - componentsMap.put("component2", component2); - expect(service.getServiceComponents()).andReturn(componentsMap); - expect(component1.getServiceComponentHosts()).andReturn(Collections.emptyMap()); - expect(component2.getServiceComponentHosts()).andReturn(Collections.singletonMap("host", null)).anyTimes(); - - ServiceInfo serviceInfo = createNiceMock(ServiceInfo.class); - ComponentInfo compInfo = createNiceMock(ComponentInfo.class); - expect(serviceInfo.getClientComponent()).andReturn(compInfo); - expect(compInfo.getName()).andReturn("component"); - expect(ambariMetaInfo.getService("stack", "1.0", "service")).andReturn(serviceInfo); - - replay(injector, cluster, service, component1, component2, serviceInfo, compInfo, ambariMetaInfo, stackId); - - AmbariManagementControllerImpl controller = new AmbariManagementControllerImpl(null, clusters, injector); - setAmbariMetaInfo(ambariMetaInfo, controller); - ServiceComponent resultComponent = controller.getClientComponentForRunningAction(cluster, service); - - assertNotNull(resultComponent); - assertEquals(component2, resultComponent); - verify(injector, cluster, service, component1, component2, serviceInfo, compInfo, ambariMetaInfo, stackId); - } - - @Test - public void testGetClientHostForRunningAction_noClientComponent() throws Exception { - Injector injector = createNiceMock(Injector.class); - Cluster cluster = createNiceMock(Cluster.class); - Service service = createNiceMock(Service.class); - StackId stackId = createNiceMock(StackId.class); - ServiceComponent component1 = createNiceMock(ServiceComponent.class); - ServiceComponent component2 = createNiceMock(ServiceComponent.class); - - expect(service.getServiceType()).andReturn("service"); - expect(service.getDesiredStackId()).andReturn(stackId); - expect(stackId.getStackName()).andReturn("stack"); - expect(stackId.getStackVersion()).andReturn("1.0"); - Map componentsMap = new HashMap<>(); - componentsMap.put("component1", component1); - componentsMap.put("component2", component2); - expect(service.getServiceComponents()).andReturn(componentsMap); - expect(component1.getServiceComponentHosts()).andReturn(Collections.emptyMap()); - expect(component2.getServiceComponentHosts()).andReturn(Collections.singletonMap("host", null)).anyTimes(); - - ServiceInfo serviceInfo = createNiceMock(ServiceInfo.class); - expect(serviceInfo.getClientComponent()).andReturn(null); - expect(ambariMetaInfo.getService("stack", "1.0", "service")).andReturn(serviceInfo); - - replay(injector, cluster, service, component1, component2, serviceInfo, ambariMetaInfo, stackId); - - AmbariManagementControllerImpl controller = new AmbariManagementControllerImpl(null, clusters, injector); - setAmbariMetaInfo(ambariMetaInfo, controller); - ServiceComponent resultComponent = controller.getClientComponentForRunningAction(cluster, service); - - assertNotNull(resultComponent); - assertEquals(component2, resultComponent); - verify(injector, cluster, service, component1, component2, serviceInfo, ambariMetaInfo, stackId); - } - /** * Ensure that ClusterNotFoundException is propagated in case where there is a single request. */ diff --git a/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerCommonServicesTest.java b/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerCommonServicesTest.java index ee15bb59820..d5626eb34a2 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerCommonServicesTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerCommonServicesTest.java @@ -217,6 +217,7 @@ public void testGetStack() { assertEquals(CommandScriptDefinition.Type.PYTHON, commandScript.getScriptType()); assertEquals(300, commandScript.getTimeout()); + assertEquals("SOME_CLIENT_FOR_SERVICE_CHECK", commandScript.getClientComponentType()); List configDependencies = pigService.getConfigDependencies(); assertEquals(1, configDependencies.size()); assertEquals("global", configDependencies.get(0)); diff --git a/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerTest.java index 5ba9b8033fc..c1cd5fefba1 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerTest.java @@ -247,6 +247,7 @@ public void testGetStack() { assertEquals("scripts/service_check.py", commandScript.getScript()); assertEquals(CommandScriptDefinition.Type.PYTHON, commandScript.getScriptType()); assertEquals(300, commandScript.getTimeout()); + assertEquals("SOME_CLIENT_FOR_SERVICE_CHECK", commandScript.getClientComponentType()); List configDependencies = pigService.getConfigDependencies(); assertEquals(1, configDependencies.size()); assertEquals("global", configDependencies.get(0)); diff --git a/ambari-server/src/test/resources/common-services/PIG/1.0/metainfo.xml b/ambari-server/src/test/resources/common-services/PIG/1.0/metainfo.xml index 74d310f0b19..f63e44299b9 100644 --- a/ambari-server/src/test/resources/common-services/PIG/1.0/metainfo.xml +++ b/ambari-server/src/test/resources/common-services/PIG/1.0/metainfo.xml @@ -55,6 +55,7 @@ PYTHON 300 + SOME_CLIENT_FOR_SERVICE_CHECK diff --git a/ambari-server/src/test/resources/stacks/HDP/0.1/services/PIG/metainfo.xml b/ambari-server/src/test/resources/stacks/HDP/0.1/services/PIG/metainfo.xml index 6ca5435dcec..a63b6e74677 100644 --- a/ambari-server/src/test/resources/stacks/HDP/0.1/services/PIG/metainfo.xml +++ b/ambari-server/src/test/resources/stacks/HDP/0.1/services/PIG/metainfo.xml @@ -50,6 +50,7 @@ PYTHON 300 + SOME_CLIENT_FOR_SERVICE_CHECK diff --git a/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/metainfo.xml b/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/metainfo.xml index 600f56e9e57..f677a792831 100644 --- a/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/metainfo.xml +++ b/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/metainfo.xml @@ -189,6 +189,7 @@ PYTHON 300 + SOME_CLIENT_FOR_SERVICE_CHECK diff --git a/ambari-server/src/test/resources/stacks/HDP/2.0.6/services/HADOOP_CLIENTS/metainfo.xml b/ambari-server/src/test/resources/stacks/HDP/2.0.6/services/HADOOP_CLIENTS/metainfo.xml new file mode 100644 index 00000000000..385b9ed1e32 --- /dev/null +++ b/ambari-server/src/test/resources/stacks/HDP/2.0.6/services/HADOOP_CLIENTS/metainfo.xml @@ -0,0 +1,41 @@ + + + + 2.0 + + + HADOOP_CLIENTS + Clients service for testing purposes + 0.1.2.0.6 + CLIENT + + + SOME_CLIENT_FOR_SERVICE_CHECK + CLIENT + 0+ + 0.95.2.2.0.6.0-hbase-master + + + + + PYTHON + 300 + + + +