This is an automated email from the ASF dual-hosted git repository.

rlevas pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ambari.git


The following commit(s) were added to refs/heads/trunk by this push:
     new d27b445  [AMBARI-24052] Add Kerberos-related configuration 
recommendations to the stack advisor
d27b445 is described below

commit d27b4454544e98227219e1b7fc0a6c91d905f005
Author: Robert Levas <[email protected]>
AuthorDate: Fri Jun 8 06:49:36 2018 -0400

    [AMBARI-24052] Add Kerberos-related configuration recommendations to the 
stack advisor
    
    * [AMBARI-24052] Add Kerberos-related configuration recommendations to the 
stack advisor
    
    * [AMBARI-24052] Add Kerberos-related configuration recommendations to the 
stack advisor
---
 .../services/stackadvisor/StackAdvisorHelper.java  |   9 +-
 .../services/stackadvisor/StackAdvisorRequest.java |   1 +
 .../ConfigurationRecommendationCommand.java        |  23 ++--
 ...leSignOnConfigurationRecommendationCommand.java | 121 ---------------------
 .../commands/StackAdvisorCommandType.java          |   2 +
 .../server/controller/KerberosHelperImpl.java      |   2 +-
 .../src/main/resources/scripts/stack_advisor.py    |   6 +
 .../stacks/HDP/2.6/services/stack_advisor.py       |   4 +
 .../src/main/resources/stacks/service_advisor.py   |   8 ++
 .../src/main/resources/stacks/stack_advisor.py     | 116 +++++++++++++++++---
 .../stackadvisor/StackAdvisorHelperTest.java       |  47 +++++++-
 .../stackadvisor/StackAdvisorRequestTypeTest.java  |  25 +++--
 .../ConfigurationRecommendationCommandTest.java    |   2 +-
 .../serviceadvisor/ServiceAdvisorCommandType.java  |   2 +
 14 files changed, 205 insertions(+), 163 deletions(-)

diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelper.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelper.java
index c09e08c..f6770bfa 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelper.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelper.java
@@ -29,8 +29,8 @@ import 
org.apache.ambari.server.api.services.stackadvisor.commands.ComponentLayo
 import 
org.apache.ambari.server.api.services.stackadvisor.commands.ConfigurationDependenciesRecommendationCommand;
 import 
org.apache.ambari.server.api.services.stackadvisor.commands.ConfigurationRecommendationCommand;
 import 
org.apache.ambari.server.api.services.stackadvisor.commands.ConfigurationValidationCommand;
-import 
org.apache.ambari.server.api.services.stackadvisor.commands.SingleSignOnConfigurationRecommendationCommand;
 import 
org.apache.ambari.server.api.services.stackadvisor.commands.StackAdvisorCommand;
+import 
org.apache.ambari.server.api.services.stackadvisor.commands.StackAdvisorCommandType;
 import 
org.apache.ambari.server.api.services.stackadvisor.recommendations.RecommendationResponse;
 import 
org.apache.ambari.server.api.services.stackadvisor.validations.ValidationResponse;
 import org.apache.ambari.server.configuration.Configuration;
@@ -144,10 +144,13 @@ public class StackAdvisorHelper {
       command = new ComponentLayoutRecommendationCommand(recommendationsDir, 
recommendationsArtifactsLifetime, serviceAdvisorType,
           requestId, saRunner, metaInfo, ambariServerConfigurationHandler);
     } else if (requestType == StackAdvisorRequestType.CONFIGURATIONS) {
-      command = new ConfigurationRecommendationCommand(recommendationsDir, 
recommendationsArtifactsLifetime, serviceAdvisorType,
+      command = new 
ConfigurationRecommendationCommand(StackAdvisorCommandType.RECOMMEND_CONFIGURATIONS,
 recommendationsDir, recommendationsArtifactsLifetime, serviceAdvisorType,
           requestId, saRunner, metaInfo, ambariServerConfigurationHandler);
     } else if (requestType == StackAdvisorRequestType.SSO_CONFIGURATIONS) {
-      command = new 
SingleSignOnConfigurationRecommendationCommand(recommendationsDir, 
recommendationsArtifactsLifetime, serviceAdvisorType,
+      command = new 
ConfigurationRecommendationCommand(StackAdvisorCommandType.RECOMMEND_CONFIGURATIONS_FOR_SSO,
 recommendationsDir, recommendationsArtifactsLifetime, serviceAdvisorType,
+          requestId, saRunner, metaInfo, ambariServerConfigurationHandler);
+    } else if (requestType == StackAdvisorRequestType.KERBEROS_CONFIGURATIONS) 
{
+      command = new 
ConfigurationRecommendationCommand(StackAdvisorCommandType.RECOMMEND_CONFIGURATIONS_FOR_KERBEROS,
 recommendationsDir, recommendationsArtifactsLifetime, serviceAdvisorType,
           requestId, saRunner, metaInfo, ambariServerConfigurationHandler);
     } else if (requestType == 
StackAdvisorRequestType.CONFIGURATION_DEPENDENCIES) {
       command = new 
ConfigurationDependenciesRecommendationCommand(recommendationsDir, 
recommendationsArtifactsLifetime, serviceAdvisorType,
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequest.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequest.java
index f170c7b..83a9367 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequest.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequest.java
@@ -229,6 +229,7 @@ public class StackAdvisorRequest {
     HOST_GROUPS("host_groups"),
     CONFIGURATIONS("configurations"),
     SSO_CONFIGURATIONS("sso-configurations"),
+    KERBEROS_CONFIGURATIONS("kerberos-configurations"),
     CONFIGURATION_DEPENDENCIES("configuration-dependencies");
 
     private String type;
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationRecommendationCommand.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationRecommendationCommand.java
index 0de5382..56cf957 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationRecommendationCommand.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationRecommendationCommand.java
@@ -34,15 +34,24 @@ import 
org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRunner;
 import 
org.apache.ambari.server.api.services.stackadvisor.recommendations.RecommendationResponse;
 import 
org.apache.ambari.server.controller.internal.AmbariServerConfigurationHandler;
 import org.apache.ambari.server.state.ServiceInfo;
+import org.apache.commons.collections.CollectionUtils;
 
 /**
  * {@link 
org.apache.ambari.server.api.services.stackadvisor.commands.StackAdvisorCommand}
 implementation for
  * configuration recommendation.
+ * <p>
+ * One of the following recommandataion types is indicated:
+ * <ul>
+ * <li>RECOMMEND_CONFIGURATIONS</li>
+ * <li>RECOMMEND_CONFIGURATIONS_FOR_SSO</li>
+ * <li>RECOMMEND_CONFIGURATIONS_FOR_KERBEROS</li>
+ * </ul>
  */
-public class ConfigurationRecommendationCommand extends
-    StackAdvisorCommand<RecommendationResponse> {
+public class ConfigurationRecommendationCommand extends 
StackAdvisorCommand<RecommendationResponse> {
 
-  public ConfigurationRecommendationCommand(File recommendationsDir,
+  private final StackAdvisorCommandType commandType;
+
+  public ConfigurationRecommendationCommand(StackAdvisorCommandType 
commandType, File recommendationsDir,
                                             String 
recommendationsArtifactsLifetime,
                                             ServiceInfo.ServiceAdvisorType 
serviceAdvisorType,
                                             int requestId,
@@ -50,17 +59,17 @@ public class ConfigurationRecommendationCommand extends
                                             AmbariMetaInfo metaInfo,
                                             AmbariServerConfigurationHandler 
ambariServerConfigurationHandler) {
     super(recommendationsDir, recommendationsArtifactsLifetime, 
serviceAdvisorType, requestId, saRunner, metaInfo, 
ambariServerConfigurationHandler);
+    this.commandType = commandType;
   }
 
   @Override
-  protected StackAdvisorCommandType getCommandType() {
-    return StackAdvisorCommandType.RECOMMEND_CONFIGURATIONS;
+  public StackAdvisorCommandType getCommandType() {
+    return commandType;
   }
 
   @Override
   protected void validate(StackAdvisorRequest request) throws 
StackAdvisorException {
-    if (request.getHosts() == null || request.getHosts().isEmpty() || 
request.getServices() == null
-        || request.getServices().isEmpty()) {
+    if (CollectionUtils.isEmpty(request.getHosts()) || 
CollectionUtils.isEmpty(request.getServices())) {
       throw new StackAdvisorException("Hosts and services must not be empty");
     }
   }
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/SingleSignOnConfigurationRecommendationCommand.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/SingleSignOnConfigurationRecommendationCommand.java
deleted file mode 100644
index 3df5003..0000000
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/SingleSignOnConfigurationRecommendationCommand.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * 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.api.services.stackadvisor.commands;
-
-import static 
org.apache.ambari.server.api.services.stackadvisor.recommendations.RecommendationResponse.BindingHostGroup;
-import static 
org.apache.ambari.server.api.services.stackadvisor.recommendations.RecommendationResponse.HostGroup;
-
-import java.io.File;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.ambari.server.api.services.AmbariMetaInfo;
-import 
org.apache.ambari.server.api.services.stackadvisor.StackAdvisorException;
-import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest;
-import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRunner;
-import 
org.apache.ambari.server.api.services.stackadvisor.recommendations.RecommendationResponse;
-import 
org.apache.ambari.server.controller.internal.AmbariServerConfigurationHandler;
-import org.apache.ambari.server.state.ServiceInfo;
-
-/**
- * {@link SingleSignOnConfigurationRecommendationCommand} implementation for
- * single sign-on configuration recommendation.
- */
-public class SingleSignOnConfigurationRecommendationCommand extends
-    StackAdvisorCommand<RecommendationResponse> {
-
-  public SingleSignOnConfigurationRecommendationCommand(File 
recommendationsDir,
-                                                        String 
recommendationsArtifactsLifetime,
-                                                        
ServiceInfo.ServiceAdvisorType serviceAdvisorType,
-                                                        int requestId,
-                                                        StackAdvisorRunner 
saRunner,
-                                                        AmbariMetaInfo 
metaInfo, AmbariServerConfigurationHandler ambariServerConfigurationHandler) {
-    super(recommendationsDir, recommendationsArtifactsLifetime, 
serviceAdvisorType, requestId, saRunner, metaInfo, 
ambariServerConfigurationHandler);
-  }
-
-  @Override
-  protected StackAdvisorCommandType getCommandType() {
-    return StackAdvisorCommandType.RECOMMEND_CONFIGURATIONS_FOR_SSO;
-  }
-
-  @Override
-  protected void validate(StackAdvisorRequest request) throws 
StackAdvisorException {
-    if (request.getHosts() == null || request.getHosts().isEmpty() || 
request.getServices() == null
-        || request.getServices().isEmpty()) {
-      throw new StackAdvisorException("Hosts and services must not be empty");
-    }
-  }
-
-  @Override
-  protected RecommendationResponse updateResponse(StackAdvisorRequest request, 
RecommendationResponse response) {
-    
response.getRecommendations().getBlueprint().setHostGroups(processHostGroups(request));
-    
response.getRecommendations().getBlueprintClusterBinding().setHostGroups(processHostGroupBindings(request));
-    return response;
-  }
-
-  protected Set<HostGroup> processHostGroups(StackAdvisorRequest request) {
-    Set<HostGroup> resultSet = new HashSet<>();
-    for (Map.Entry<String, Set<String>> componentHost : 
request.getHostComponents().entrySet()) {
-      String hostGroupName = componentHost.getKey();
-      Set<String> components = componentHost.getValue();
-      if (hostGroupName != null && components != null) {
-        HostGroup hostGroup = new HostGroup();
-        Set<Map<String, String>> componentsSet = new HashSet<>();
-        for (String component : components) {
-          Map<String, String> componentMap = new HashMap<>();
-          componentMap.put("name", component);
-          componentsSet.add(componentMap);
-        }
-        hostGroup.setComponents(componentsSet);
-        hostGroup.setName(hostGroupName);
-        resultSet.add(hostGroup);
-      }
-    }
-    return resultSet;
-  }
-
-  private Set<BindingHostGroup> processHostGroupBindings(StackAdvisorRequest 
request) {
-    Set<BindingHostGroup> resultSet = new HashSet<>();
-    for (Map.Entry<String, Set<String>> hostBinding : 
request.getHostGroupBindings().entrySet()) {
-      String hostGroupName = hostBinding.getKey();
-      Set<String> hosts = hostBinding.getValue();
-      if (hostGroupName != null && hosts != null) {
-        BindingHostGroup bindingHostGroup = new BindingHostGroup();
-        Set<Map<String, String>> hostsSet = new HashSet<>();
-        for (String host : hosts) {
-          Map<String, String> hostMap = new HashMap<>();
-          hostMap.put("name", host);
-          hostsSet.add(hostMap);
-        }
-        bindingHostGroup.setHosts(hostsSet);
-        bindingHostGroup.setName(hostGroupName);
-        resultSet.add(bindingHostGroup);
-      }
-    }
-    return resultSet;
-  }
-
-  @Override
-  protected String getResultFileName() {
-    return "configurations.json";
-  }
-
-}
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommandType.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommandType.java
index 5e3589d..57924ee 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommandType.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommandType.java
@@ -31,6 +31,8 @@ public enum StackAdvisorCommandType {
 
   RECOMMEND_CONFIGURATIONS_FOR_SSO("recommend-configurations-for-sso"),
 
+  
RECOMMEND_CONFIGURATIONS_FOR_KERBEROS("recommend-configurations-for-kerberos"),
+
   RECOMMEND_CONFIGURATION_DEPENDENCIES("recommend-configuration-dependencies"),
 
   VALIDATE_CONFIGURATIONS("validate-configurations");
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java
index 0fc8165..77f2d39 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java
@@ -757,7 +757,7 @@ public class KerberosHelperImpl implements KerberosHelper {
           .forHosts(hostNames)
           .withComponentHostsMap(cluster.getServiceComponentHostMap(null, 
services))
           .withConfigurations(requestConfigurations)
-          .ofType(StackAdvisorRequest.StackAdvisorRequestType.CONFIGURATIONS)
+          
.ofType(StackAdvisorRequest.StackAdvisorRequestType.KERBEROS_CONFIGURATIONS)
           .build();
 
         try {
diff --git a/ambari-server/src/main/resources/scripts/stack_advisor.py 
b/ambari-server/src/main/resources/scripts/stack_advisor.py
index f292cca..b39a6e8 100755
--- a/ambari-server/src/main/resources/scripts/stack_advisor.py
+++ b/ambari-server/src/main/resources/scripts/stack_advisor.py
@@ -27,6 +27,7 @@ RECOMMEND_COMPONENT_LAYOUT_ACTION = 
'recommend-component-layout'
 VALIDATE_COMPONENT_LAYOUT_ACTION = 'validate-component-layout'
 RECOMMEND_CONFIGURATIONS = 'recommend-configurations'
 RECOMMEND_CONFIGURATIONS_FOR_SSO = 'recommend-configurations-for-sso'
+RECOMMEND_CONFIGURATIONS_FOR_KERBEROS = 'recommend-configurations-for-kerberos'
 RECOMMEND_CONFIGURATION_DEPENDENCIES = 'recommend-configuration-dependencies'
 VALIDATE_CONFIGURATIONS = 'validate-configurations'
 
@@ -34,6 +35,7 @@ ALL_ACTIONS = [RECOMMEND_COMPONENT_LAYOUT_ACTION,
                VALIDATE_COMPONENT_LAYOUT_ACTION,
                RECOMMEND_CONFIGURATIONS,
                RECOMMEND_CONFIGURATIONS_FOR_SSO,
+               RECOMMEND_CONFIGURATIONS_FOR_KERBEROS,
                RECOMMEND_CONFIGURATION_DEPENDENCIES,
                VALIDATE_CONFIGURATIONS]
 USAGE = "Usage: <action> <hosts_file> <services_file>\nPossible actions are: 
{0}\n".format( str(ALL_ACTIONS) )
@@ -123,6 +125,10 @@ def main(argv=None):
     services[ADVISOR_CONTEXT] = {CALL_TYPE : 'recommendConfigurationsForSSO'}
     result = stackAdvisor.recommendConfigurationsForSSO(services, hosts)
     result_file = os.path.join(actionDir, "configurations.json")
+  elif action == RECOMMEND_CONFIGURATIONS_FOR_KERBEROS:
+    services[ADVISOR_CONTEXT] = {CALL_TYPE : 
'recommendConfigurationsForKerberos'}
+    result = stackAdvisor.recommendConfigurationsForKerberos(services, hosts)
+    result_file = os.path.join(actionDir, "configurations.json")
   elif action == RECOMMEND_CONFIGURATION_DEPENDENCIES:
     services[ADVISOR_CONTEXT] = {CALL_TYPE : 
'recommendConfigurationDependencies'}
     result = stackAdvisor.recommendConfigurationDependencies(services, hosts)
diff --git 
a/ambari-server/src/main/resources/stacks/HDP/2.6/services/stack_advisor.py 
b/ambari-server/src/main/resources/stacks/HDP/2.6/services/stack_advisor.py
index f0c4bdc..b3acd5e 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.6/services/stack_advisor.py
+++ b/ambari-server/src/main/resources/stacks/HDP/2.6/services/stack_advisor.py
@@ -54,6 +54,10 @@ class HDP26StackAdvisor(HDP25StackAdvisor):
         "RANGER": self.recommendRangerConfigurationsForSSO
       }
 
+  def getServiceConfigurationRecommenderForKerberosDict(self):
+    # For backwards compatibility, return the dict use for general stack 
advisor calls.
+    return self.getServiceConfigurationRecommenderDict()
+
   def recommendSPARK2Configurations(self, configurations, clusterData, 
services, hosts):
     """
     :type configurations dict
diff --git a/ambari-server/src/main/resources/stacks/service_advisor.py 
b/ambari-server/src/main/resources/stacks/service_advisor.py
index 893863c..a960979 100644
--- a/ambari-server/src/main/resources/stacks/service_advisor.py
+++ b/ambari-server/src/main/resources/stacks/service_advisor.py
@@ -99,6 +99,14 @@ class ServiceAdvisor(DefaultStackAdvisor):
     """
     pass
 
+  def getServiceConfigurationRecommendationsForKerberos(self, configurations, 
clusterSummary, services, hosts):
+    """
+    Any Kerberos-related configuration recommendations for the service should 
be defined in this function.
+
+    Redirect to getServiceConfigurationRecommendations for backward 
compatibility
+    """
+    return self.getServiceConfigurationRecommendations(configurations, 
clusterSummary, services, hosts)
+
   def getServiceComponentLayoutValidations(self, services, hosts):
     """
     Returns an array of Validation objects about issues with the hostnames to 
which components are assigned.
diff --git a/ambari-server/src/main/resources/stacks/stack_advisor.py 
b/ambari-server/src/main/resources/stacks/stack_advisor.py
index 5fb4a83..4e4f4e5 100644
--- a/ambari-server/src/main/resources/stacks/stack_advisor.py
+++ b/ambari-server/src/main/resources/stacks/stack_advisor.py
@@ -341,6 +341,26 @@ class StackAdvisor(object):
     """
     pass
 
+  def recommendConfigurationsForKerberos(self, services, hosts):
+    """
+    Returns recommendation of Kerberos-related service configurations based on 
host-specific layout
+    of components.
+
+    This function takes as input all details about services being installed, 
and hosts
+    they are being installed into, to recommend host-specific configurations.
+
+    For backwards compatibility, this function redirects to 
recommendConfigurations. Implementations
+    should override this function to recommend Kerberos-specific property 
changes.
+
+    :type services: dict
+    :param services: Dictionary containing all information about services and 
component layout selected by the user.
+    :type hosts: dict
+    :param hosts: Dictionary containing all information about hosts in this 
cluster
+    :rtype: dict
+    :return: Layout recommendation of service components on cluster hosts in 
Ambari Blueprints friendly format.
+    """
+    return self.recommendConfigurations(services, hosts)
+
   def validateConfigurations(self, services, hosts):
     """"
     Returns array of Validation issues with configurations provided by user
@@ -1124,15 +1144,12 @@ class DefaultStackAdvisor(StackAdvisor):
 
   def calculateYarnAllocationSizes(self, configurations, services, hosts):
     # initialize data
-    servicesList = [service["StackServices"]["service_name"] for service in 
services["services"]]
-    components = [component["StackServiceComponents"]["component_name"]
-                  for service in services["services"]
-                  for component in service["components"]]
+    servicesList, componentsList = 
self.get_service_and_component_lists(services["services"])
     putYarnProperty = self.putProperty(configurations, "yarn-site", services)
     putYarnPropertyAttribute = self.putPropertyAttribute(configurations, 
"yarn-site")
 
     # calculate memory properties and get cluster data dictionary with whole 
information
-    clusterSummary = self.getConfigurationClusterSummary(servicesList, hosts, 
components, services)
+    clusterSummary = self.getConfigurationClusterSummary(servicesList, hosts, 
componentsList, services)
 
     # executing code from stack advisor HDP 206
     nodemanagerMinRam = 1048576 # 1TB in mb
@@ -1580,12 +1597,9 @@ class DefaultStackAdvisor(StackAdvisor):
     stackName = services["Versions"]["stack_name"]
     stackVersion = services["Versions"]["stack_version"]
     hostsList = [host["Hosts"]["host_name"] for host in hosts["items"]]
-    servicesList = [service["StackServices"]["service_name"] for service in 
services["services"]]
-    components = [component["StackServiceComponents"]["component_name"]
-                  for service in services["services"]
-                  for component in service["components"]]
+    servicesList, componentsList = 
self.get_service_and_component_lists(services["services"])
 
-    clusterSummary = self.getConfigurationClusterSummary(servicesList, hosts, 
components, services)
+    clusterSummary = self.getConfigurationClusterSummary(servicesList, hosts, 
componentsList, services)
 
     recommendations = {
       "Versions": {"stack_name": stackName, "stack_version": stackVersion},
@@ -1604,7 +1618,7 @@ class DefaultStackAdvisor(StackAdvisor):
 
     # If recommendation for config groups
     if "config-groups" in services:
-      self.recommendConfigGroupsConfigurations(recommendations, services, 
components, hosts,
+      self.recommendConfigGroupsConfigurations(recommendations, services, 
componentsList, hosts,
                                  servicesList)
     else:
       configurations = 
recommendations["recommendations"]["blueprint"]["configurations"]
@@ -1632,12 +1646,9 @@ class DefaultStackAdvisor(StackAdvisor):
     stackName = services["Versions"]["stack_name"]
     stackVersion = services["Versions"]["stack_version"]
     hostsList = [host["Hosts"]["host_name"] for host in hosts["items"]]
-    servicesList = [service["StackServices"]["service_name"] for service in 
services["services"]]
-    components = [component["StackServiceComponents"]["component_name"]
-                  for service in services["services"]
-                  for component in service["components"]]
+    servicesList, componentsList = 
self.get_service_and_component_lists(services["services"])
 
-    clusterSummary = self.getConfigurationClusterSummary(servicesList, hosts, 
components, services)
+    clusterSummary = self.getConfigurationClusterSummary(servicesList, hosts, 
componentsList, services)
 
     recommendations = {
       "Versions": {"stack_name": stackName, "stack_version": stackVersion},
@@ -1656,7 +1667,7 @@ class DefaultStackAdvisor(StackAdvisor):
 
     # If recommendation for config groups
     if "config-groups" in services:
-      self.recommendConfigGroupsConfigurations(recommendations, services, 
components, hosts,
+      self.recommendConfigGroupsConfigurations(recommendations, services, 
componentsList, hosts,
                                  servicesList)
     else:
       configurations = 
recommendations["recommendations"]["blueprint"]["configurations"]
@@ -1679,6 +1690,60 @@ class DefaultStackAdvisor(StackAdvisor):
 
     return recommendations
 
+  def recommendConfigurationsForKerberos(self, services, hosts):
+    self.services = services
+
+    stackName = services["Versions"]["stack_name"]
+    stackVersion = services["Versions"]["stack_version"]
+    hostsList = [host["Hosts"]["host_name"] for host in hosts["items"]]
+    servicesList, componentsList = 
self.get_service_and_component_lists(services["services"])
+
+    clusterSummary = self.getConfigurationClusterSummary(servicesList, hosts, 
componentsList, services)
+
+
+    recommendations = {
+      "Versions": {
+        "stack_name": stackName,
+        "stack_version": stackVersion
+      },
+      "hosts": hostsList,
+      "services": servicesList,
+      "recommendations": {
+        "blueprint": {
+          "configurations": {},
+          "host_groups": []
+        },
+        "blueprint_cluster_binding": {
+          "host_groups": []
+        }
+      }
+    }
+
+    # If recommendation for config groups
+    if "config-groups" in services:
+      self.recommendConfigGroupsConfigurations(recommendations, services, 
componentsList, hosts,
+                                 servicesList)
+    else:
+      configurations = 
recommendations["recommendations"]["blueprint"]["configurations"]
+
+      # there can be dependencies between service recommendations which 
require special ordering
+      # for now, make sure custom services (that have service advisors) run 
after standard ones
+      serviceAdvisors = []
+      recommenderDict = 
self.getServiceConfigurationRecommenderForKerberosDict()
+      for service in services["services"]:
+        serviceName = service["StackServices"]["service_name"]
+        calculation = recommenderDict.get(serviceName, None)
+        if calculation is not None:
+          calculation(configurations, clusterSummary, services, hosts)
+        else:
+          serviceAdvisor = self.getServiceAdvisor(serviceName)
+          if serviceAdvisor is not None:
+            serviceAdvisors.append(serviceAdvisor)
+      for serviceAdvisor in serviceAdvisors:
+        
serviceAdvisor.getServiceConfigurationRecommendationsForKerberos(configurations,
 clusterSummary, services, hosts)
+
+    return recommendations
+
   def getServiceConfigurationRecommender(self, service):
     return self.getServiceConfigurationRecommenderDict().get(service, None)
 
@@ -1688,6 +1753,9 @@ class DefaultStackAdvisor(StackAdvisor):
   def getServiceConfigurationRecommenderForSSODict(self):
     return {}
 
+  def getServiceConfigurationRecommenderForKerberosDict(self):
+    return {}
+
   # Recommendation helper methods
   def isComponentHostsPopulated(self, component):
     hostnames = self.getComponentAttribute(component, "hostnames")
@@ -3171,3 +3239,17 @@ class DefaultStackAdvisor(StackAdvisor):
       return int(re.sub("\D", "", s))
     except ValueError:
       return None
+
+  def get_service_and_component_lists(self, services):
+    serviceList = []
+    componentList = []
+
+    if services:
+      for service in services:
+        serviceList.append(service["StackServices"]["service_name"])
+
+        if service["components"]:
+          for component in service["components"]:
+            
componentList.append(component["StackServiceComponents"]["component_name"])
+
+    return serviceList, componentList
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelperTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelperTest.java
index c4282a2..2b3e6bb 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelperTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelperTest.java
@@ -20,6 +20,7 @@ package org.apache.ambari.server.api.services.stackadvisor;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
@@ -33,8 +34,10 @@ import 
org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest.St
 import 
org.apache.ambari.server.api.services.stackadvisor.commands.ComponentLayoutRecommendationCommand;
 import 
org.apache.ambari.server.api.services.stackadvisor.commands.ComponentLayoutValidationCommand;
 import 
org.apache.ambari.server.api.services.stackadvisor.commands.ConfigurationDependenciesRecommendationCommand;
+import 
org.apache.ambari.server.api.services.stackadvisor.commands.ConfigurationRecommendationCommand;
 import 
org.apache.ambari.server.api.services.stackadvisor.commands.ConfigurationValidationCommand;
 import 
org.apache.ambari.server.api.services.stackadvisor.commands.StackAdvisorCommand;
+import 
org.apache.ambari.server.api.services.stackadvisor.commands.StackAdvisorCommandType;
 import 
org.apache.ambari.server.api.services.stackadvisor.recommendations.RecommendationResponse;
 import 
org.apache.ambari.server.api.services.stackadvisor.validations.ValidationResponse;
 import org.apache.ambari.server.configuration.Configuration;
@@ -94,7 +97,7 @@ public class StackAdvisorHelperTest {
     doReturn(command).when(helper).createValidationCommand("ZOOKEEPER", 
request);
     helper.validate(request);
 
-    assertTrue(false);
+    fail();
   }
 
   @Test
@@ -144,7 +147,7 @@ public class StackAdvisorHelperTest {
     doReturn(command).when(helper).createRecommendationCommand("ZOOKEEPER", 
request);
     helper.recommend(request);
 
-    assertTrue(false);
+    fail("Expected StackAdvisorException to be thrown");
   }
 
   @Test
@@ -169,6 +172,21 @@ public class StackAdvisorHelperTest {
   }
 
   @Test
+  public void 
testCreateRecommendationCommand_returnsConfigurationRecommendationCommand() 
throws IOException, StackAdvisorException {
+    
testCreateConfigurationRecommendationCommand(StackAdvisorRequestType.CONFIGURATIONS,
 StackAdvisorCommandType.RECOMMEND_CONFIGURATIONS);
+  }
+
+  @Test
+  public void 
testCreateRecommendationCommand_returnsSingleSignOnConfigurationRecommendationCommand()
 throws IOException, StackAdvisorException {
+    
testCreateConfigurationRecommendationCommand(StackAdvisorRequestType.SSO_CONFIGURATIONS,
 StackAdvisorCommandType.RECOMMEND_CONFIGURATIONS_FOR_SSO);
+  }
+
+  @Test
+  public void 
testCreateRecommendationCommand_returnsKerberosConfigurationRecommendationCommand()
 throws IOException, StackAdvisorException {
+    
testCreateConfigurationRecommendationCommand(StackAdvisorRequestType.KERBEROS_CONFIGURATIONS,
 StackAdvisorCommandType.RECOMMEND_CONFIGURATIONS_FOR_KERBEROS);
+  }
+
+  @Test
   public void 
testCreateValidationCommand_returnsComponentLayoutValidationCommand()
       throws IOException, StackAdvisorException {
     Configuration configuration = mock(Configuration.class);
@@ -210,7 +228,7 @@ public class StackAdvisorHelperTest {
 
   @Test
   public void 
testCreateRecommendationDependencyCommand_returnsConfigurationDependencyRecommendationCommand()
-    throws IOException, StackAdvisorException {
+      throws IOException, StackAdvisorException {
     Configuration configuration = mock(Configuration.class);
     
when(configuration.getRecommendationsArtifactsRolloverMax()).thenReturn(100);
     StackAdvisorRunner saRunner = mock(StackAdvisorRunner.class);
@@ -218,7 +236,7 @@ public class StackAdvisorHelperTest {
     ServiceInfo service = mock(ServiceInfo.class);
     when(metaInfo.getService(Mockito.anyString(), Mockito.anyString(), 
Mockito.anyString())).thenReturn(service);
     
when(service.getServiceAdvisorType()).thenReturn(ServiceInfo.ServiceAdvisorType.PYTHON);
-    StackAdvisorHelper helper = new StackAdvisorHelper(configuration, 
saRunner, metaInfo,null);
+    StackAdvisorHelper helper = new StackAdvisorHelper(configuration, 
saRunner, metaInfo, null);
     StackAdvisorRequestType requestType = 
StackAdvisorRequestType.CONFIGURATION_DEPENDENCIES;
     StackAdvisorRequest request = 
StackAdvisorRequestBuilder.forStack("stackName", "stackVersion")
         .ofType(requestType).build();
@@ -228,6 +246,27 @@ public class StackAdvisorHelperTest {
     assertEquals(ConfigurationDependenciesRecommendationCommand.class, 
command.getClass());
   }
 
+  private void 
testCreateConfigurationRecommendationCommand(StackAdvisorRequestType 
requestType, StackAdvisorCommandType expectedCommandType)
+      throws IOException, StackAdvisorException {
+    Configuration configuration = mock(Configuration.class);
+    
when(configuration.getRecommendationsArtifactsRolloverMax()).thenReturn(100);
+    StackAdvisorRunner saRunner = mock(StackAdvisorRunner.class);
+    AmbariMetaInfo metaInfo = mock(AmbariMetaInfo.class);
+    ServiceInfo service = mock(ServiceInfo.class);
+    when(metaInfo.getService(Mockito.anyString(), Mockito.anyString(), 
Mockito.anyString())).thenReturn(service);
+    
when(service.getServiceAdvisorType()).thenReturn(ServiceInfo.ServiceAdvisorType.PYTHON);
+    StackAdvisorHelper helper = new StackAdvisorHelper(configuration, 
saRunner, metaInfo, null);
+
+    StackAdvisorRequest request = 
StackAdvisorRequestBuilder.forStack("stackName", "stackVersion")
+        .ofType(requestType).build();
+
+    StackAdvisorCommand<RecommendationResponse> command = 
helper.createRecommendationCommand("ZOOKEEPER", request);
+
+    assertTrue(command instanceof ConfigurationRecommendationCommand);
+    assertEquals(expectedCommandType, ((ConfigurationRecommendationCommand) 
command).getCommandType());
+
+  }
+
   private static StackAdvisorHelper stackAdvisorHelperSpy(Configuration 
configuration, StackAdvisorRunner saRunner, AmbariMetaInfo metaInfo) throws 
IOException {
     return spy(new StackAdvisorHelper(configuration, saRunner, metaInfo, 
null));
   }
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequestTypeTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequestTypeTest.java
index dde8780..cc0dac2 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequestTypeTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequestTypeTest.java
@@ -19,7 +19,7 @@
 package org.apache.ambari.server.api.services.stackadvisor;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import 
org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest.StackAdvisorRequestType;
 import org.junit.Test;
@@ -31,18 +31,22 @@ public class StackAdvisorRequestTypeTest {
 
   @Test
   public void testFromString_returnsHostGroupType() throws 
StackAdvisorException {
-    String text = "host_groups";
-    StackAdvisorRequestType type = StackAdvisorRequestType.fromString(text);
-
-    assertEquals(type, StackAdvisorRequestType.HOST_GROUPS);
+    testFromString("host_groups", StackAdvisorRequestType.HOST_GROUPS);
   }
 
   @Test
   public void testFromString_returnsConfigurationsType() throws 
StackAdvisorException {
-    String text = "configurations";
-    StackAdvisorRequestType type = StackAdvisorRequestType.fromString(text);
+    testFromString("configurations", StackAdvisorRequestType.CONFIGURATIONS);
+  }
 
-    assertEquals(type, StackAdvisorRequestType.CONFIGURATIONS);
+  @Test
+  public void testFromString_returnsSingleSignOnConfigurationsType() throws 
StackAdvisorException {
+    testFromString("sso-configurations", 
StackAdvisorRequestType.SSO_CONFIGURATIONS);
+  }
+
+  @Test
+  public void testFromString_returnsKerberosConfigurationsType() throws 
StackAdvisorException {
+    testFromString("kerberos-configurations", 
StackAdvisorRequestType.KERBEROS_CONFIGURATIONS);
   }
 
   @Test(expected = StackAdvisorException.class)
@@ -50,7 +54,10 @@ public class StackAdvisorRequestTypeTest {
     String text = "unknown_type";
     StackAdvisorRequestType.fromString(text);
 
-    assertTrue(false);
+    fail("Expected StackAdvisorException");
   }
 
+  private void testFromString(String text, StackAdvisorRequestType 
expectedType) throws StackAdvisorException {
+    assertEquals(expectedType, StackAdvisorRequestType.fromString(text));
+  }
 }
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationRecommendationCommandTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationRecommendationCommandTest.java
index b42f45d..c983af2 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationRecommendationCommandTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationRecommendationCommandTest.java
@@ -44,7 +44,7 @@ public class ConfigurationRecommendationCommandTest {
     StackAdvisorRunner saRunner = mock(StackAdvisorRunner.class);
     File file = mock(File.class);
     AmbariMetaInfo metaInfo = mock(AmbariMetaInfo.class);
-    ConfigurationRecommendationCommand command = new 
ConfigurationRecommendationCommand(file, "1w", 
ServiceInfo.ServiceAdvisorType.PYTHON, 1, saRunner, metaInfo, null);
+    ConfigurationRecommendationCommand command = new 
ConfigurationRecommendationCommand(StackAdvisorCommandType.RECOMMEND_CONFIGURATIONS,
 file, "1w", ServiceInfo.ServiceAdvisorType.PYTHON, 1, saRunner, metaInfo, 
null);
 
     StackAdvisorRequest request = mock(StackAdvisorRequest.class);
     Map<String, Set<String>> componentHostGroupMap = new HashMap<>();
diff --git 
a/ambari-serviceadvisor/src/main/java/org/apache/ambari/serviceadvisor/ServiceAdvisorCommandType.java
 
b/ambari-serviceadvisor/src/main/java/org/apache/ambari/serviceadvisor/ServiceAdvisorCommandType.java
index 0b302ce..cb9f46e 100644
--- 
a/ambari-serviceadvisor/src/main/java/org/apache/ambari/serviceadvisor/ServiceAdvisorCommandType.java
+++ 
b/ambari-serviceadvisor/src/main/java/org/apache/ambari/serviceadvisor/ServiceAdvisorCommandType.java
@@ -31,6 +31,8 @@ public enum ServiceAdvisorCommandType {
 
   RECOMMEND_CONFIGURATIONS_FOR_SSO("recommend-configurations-for-sso"),
 
+  
RECOMMEND_CONFIGURATIONS_FOR_KERBEROS("recommend-configurations-for-kerberos"),
+
   RECOMMEND_CONFIGURATION_DEPENDENCIES("recommend-configuration-dependencies"),
 
   VALIDATE_CONFIGURATIONS("validate-configurations");

-- 
To stop receiving notification emails like this one, please contact
[email protected].

Reply via email to