Browse Source

AMBARI-8545 Create stack advisor script to recommend configurations (dsen)

Dmytro Sen 10 years ago
parent
commit
45468b65af

+ 0 - 1
ambari-server/src/main/resources/scripts/stack_advisor.py

@@ -17,7 +17,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 See the License for the specific language governing permissions and
 limitations under the License.
 limitations under the License.
 '''
 '''
-import StringIO
 
 
 import json
 import json
 import os
 import os

+ 7 - 8
ambari-server/src/main/resources/stacks/BIGTOP/0.8/services/stack_advisor.py

@@ -18,7 +18,6 @@ limitations under the License.
 """
 """
 
 
 import re
 import re
-import sys
 from math import ceil
 from math import ceil
 
 
 from stack_advisor import DefaultStackAdvisor
 from stack_advisor import DefaultStackAdvisor
@@ -259,7 +258,7 @@ class BaseBIGTOP08StackAdvisor(DefaultStackAdvisor):
       return self.getWarnItem("Value is less than the recommended default of -Xmx" + defaultValueXmx)
       return self.getWarnItem("Value is less than the recommended default of -Xmx" + defaultValueXmx)
     return None
     return None
 
 
-  def validateMapReduce2Configurations(self, properties, recommendedDefaults, configurations):
+  def validateMapReduce2Configurations(self, properties, recommendedDefaults, configurations, services, hosts):
     validationItems = [ {"config-name": 'mapreduce.map.java.opts', "item": self.validateXmxValue(properties, recommendedDefaults, 'mapreduce.map.java.opts')},
     validationItems = [ {"config-name": 'mapreduce.map.java.opts', "item": self.validateXmxValue(properties, recommendedDefaults, 'mapreduce.map.java.opts')},
                         {"config-name": 'mapreduce.reduce.java.opts', "item": self.validateXmxValue(properties, recommendedDefaults, 'mapreduce.reduce.java.opts')},
                         {"config-name": 'mapreduce.reduce.java.opts', "item": self.validateXmxValue(properties, recommendedDefaults, 'mapreduce.reduce.java.opts')},
                         {"config-name": 'mapreduce.task.io.sort.mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'mapreduce.task.io.sort.mb')},
                         {"config-name": 'mapreduce.task.io.sort.mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'mapreduce.task.io.sort.mb')},
@@ -269,7 +268,7 @@ class BaseBIGTOP08StackAdvisor(DefaultStackAdvisor):
                         {"config-name": 'yarn.app.mapreduce.am.command-opts', "item": self.validateXmxValue(properties, recommendedDefaults, 'yarn.app.mapreduce.am.command-opts')} ]
                         {"config-name": 'yarn.app.mapreduce.am.command-opts', "item": self.validateXmxValue(properties, recommendedDefaults, 'yarn.app.mapreduce.am.command-opts')} ]
     return self.toConfigurationValidationProblems(validationItems, "mapred-site")
     return self.toConfigurationValidationProblems(validationItems, "mapred-site")
 
 
-  def validateYARNConfigurations(self, properties, recommendedDefaults, configurations):
+  def validateYARNConfigurations(self, properties, recommendedDefaults, configurations, services, hosts):
     validationItems = [ {"config-name": 'yarn.nodemanager.resource.memory-mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'yarn.nodemanager.resource.memory-mb')},
     validationItems = [ {"config-name": 'yarn.nodemanager.resource.memory-mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'yarn.nodemanager.resource.memory-mb')},
                         {"config-name": 'yarn.scheduler.minimum-allocation-mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'yarn.scheduler.minimum-allocation-mb')},
                         {"config-name": 'yarn.scheduler.minimum-allocation-mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'yarn.scheduler.minimum-allocation-mb')},
                         {"config-name": 'yarn.scheduler.maximum-allocation-mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'yarn.scheduler.maximum-allocation-mb')} ]
                         {"config-name": 'yarn.scheduler.maximum-allocation-mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'yarn.scheduler.maximum-allocation-mb')} ]
@@ -318,7 +317,7 @@ class BIGTOP08StackAdvisor(BaseBIGTOP08StackAdvisor):
     parentRecommendConfDict.update(childRecommendConfDict)
     parentRecommendConfDict.update(childRecommendConfDict)
     return parentRecommendConfDict
     return parentRecommendConfDict
 
 
-  def recommendOozieConfigurations(self, configurations, clusterData):
+  def recommendOozieConfigurations(self, configurations, clusterData, services, hosts):
     if "FALCON_SERVER" in clusterData["components"]:
     if "FALCON_SERVER" in clusterData["components"]:
       putMapredProperty = self.putProperty(configurations, "oozie-site")
       putMapredProperty = self.putProperty(configurations, "oozie-site")
       putMapredProperty("oozie.services.ext",
       putMapredProperty("oozie.services.ext",
@@ -326,7 +325,7 @@ class BIGTOP08StackAdvisor(BaseBIGTOP08StackAdvisor):
                         "org.apache.oozie.service.PartitionDependencyManagerService," +
                         "org.apache.oozie.service.PartitionDependencyManagerService," +
                         "org.apache.oozie.service.HCatAccessorService")
                         "org.apache.oozie.service.HCatAccessorService")
 
 
-  def recommendHiveConfigurations(self, configurations, clusterData):
+  def recommendHiveConfigurations(self, configurations, clusterData, services, hosts):
     containerSize = clusterData['mapMemory'] if clusterData['mapMemory'] > 2048 else int(clusterData['reduceMemory'])
     containerSize = clusterData['mapMemory'] if clusterData['mapMemory'] > 2048 else int(clusterData['reduceMemory'])
     containerSize = min(clusterData['containers'] * clusterData['ramPerContainer'], containerSize)
     containerSize = min(clusterData['containers'] * clusterData['ramPerContainer'], containerSize)
     putHiveProperty = self.putProperty(configurations, "hive-site")
     putHiveProperty = self.putProperty(configurations, "hive-site")
@@ -335,7 +334,7 @@ class BIGTOP08StackAdvisor(BaseBIGTOP08StackAdvisor):
                     + "m -Djava.net.preferIPv4Stack=true -XX:NewRatio=8 -XX:+UseNUMA -XX:+UseParallelGC")
                     + "m -Djava.net.preferIPv4Stack=true -XX:NewRatio=8 -XX:+UseNUMA -XX:+UseParallelGC")
     putHiveProperty('hive.tez.container.size', containerSize)
     putHiveProperty('hive.tez.container.size', containerSize)
 
 
-  def recommendTezConfigurations(self, configurations, clusterData):
+  def recommendTezConfigurations(self, configurations, clusterData, services, hosts):
     putTezProperty = self.putProperty(configurations, "tez-site")
     putTezProperty = self.putProperty(configurations, "tez-site")
     putTezProperty("tez.am.resource.memory.mb", int(clusterData['amMemory']))
     putTezProperty("tez.am.resource.memory.mb", int(clusterData['amMemory']))
     putTezProperty("tez.am.java.opts",
     putTezProperty("tez.am.java.opts",
@@ -366,13 +365,13 @@ class BIGTOP08StackAdvisor(BaseBIGTOP08StackAdvisor):
     parentValidators.update(childValidators)
     parentValidators.update(childValidators)
     return parentValidators
     return parentValidators
 
 
-  def validateHiveConfigurations(self, properties, recommendedDefaults, configurations):
+  def validateHiveConfigurations(self, properties, recommendedDefaults, configurations, services, hosts):
     validationItems = [ {"config-name": 'hive.tez.container.size', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'hive.tez.container.size')},
     validationItems = [ {"config-name": 'hive.tez.container.size', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'hive.tez.container.size')},
                         {"config-name": 'hive.tez.java.opts', "item": self.validateXmxValue(properties, recommendedDefaults, 'hive.tez.java.opts')},
                         {"config-name": 'hive.tez.java.opts', "item": self.validateXmxValue(properties, recommendedDefaults, 'hive.tez.java.opts')},
                         {"config-name": 'hive.auto.convert.join.noconditionaltask.size', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'hive.auto.convert.join.noconditionaltask.size')} ]
                         {"config-name": 'hive.auto.convert.join.noconditionaltask.size', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'hive.auto.convert.join.noconditionaltask.size')} ]
     return self.toConfigurationValidationProblems(validationItems, "hive-site")
     return self.toConfigurationValidationProblems(validationItems, "hive-site")
 
 
-  def validateTezConfigurations(self, properties, recommendedDefaults, configurations):
+  def validateTezConfigurations(self, properties, recommendedDefaults, configurations, services, hosts):
     validationItems = [ {"config-name": 'tez.am.resource.memory.mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'tez.am.resource.memory.mb')},
     validationItems = [ {"config-name": 'tez.am.resource.memory.mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'tez.am.resource.memory.mb')},
                         {"config-name": 'tez.am.java.opts', "item": self.validateXmxValue(properties, recommendedDefaults, 'tez.am.java.opts')} ]
                         {"config-name": 'tez.am.java.opts', "item": self.validateXmxValue(properties, recommendedDefaults, 'tez.am.java.opts')} ]
     return self.toConfigurationValidationProblems(validationItems, "tez-site")
     return self.toConfigurationValidationProblems(validationItems, "tez-site")

+ 53 - 16
ambari-server/src/main/resources/stacks/HDP/2.0.6/services/stack_advisor.py

@@ -18,7 +18,7 @@ limitations under the License.
 """
 """
 
 
 import re
 import re
-import sys
+import os
 from math import ceil
 from math import ceil
 
 
 from stack_advisor import DefaultStackAdvisor
 from stack_advisor import DefaultStackAdvisor
@@ -91,13 +91,13 @@ class HDP206StackAdvisor(DefaultStackAdvisor):
       config[configType]["properties"][key] = str(value)
       config[configType]["properties"][key] = str(value)
     return appendProperty
     return appendProperty
 
 
-  def recommendYARNConfigurations(self, configurations, clusterData):
+  def recommendYARNConfigurations(self, configurations, clusterData, services, hosts):
     putYarnProperty = self.putProperty(configurations, "yarn-site")
     putYarnProperty = self.putProperty(configurations, "yarn-site")
     putYarnProperty('yarn.nodemanager.resource.memory-mb', int(round(clusterData['containers'] * clusterData['ramPerContainer'])))
     putYarnProperty('yarn.nodemanager.resource.memory-mb', int(round(clusterData['containers'] * clusterData['ramPerContainer'])))
     putYarnProperty('yarn.scheduler.minimum-allocation-mb', int(clusterData['ramPerContainer']))
     putYarnProperty('yarn.scheduler.minimum-allocation-mb', int(clusterData['ramPerContainer']))
     putYarnProperty('yarn.scheduler.maximum-allocation-mb', int(round(clusterData['containers'] * clusterData['ramPerContainer'])))
     putYarnProperty('yarn.scheduler.maximum-allocation-mb', int(round(clusterData['containers'] * clusterData['ramPerContainer'])))
 
 
-  def recommendMapReduce2Configurations(self, configurations, clusterData):
+  def recommendMapReduce2Configurations(self, configurations, clusterData, services, hosts):
     putMapredProperty = self.putProperty(configurations, "mapred-site")
     putMapredProperty = self.putProperty(configurations, "mapred-site")
     putMapredProperty('yarn.app.mapreduce.am.resource.mb', int(clusterData['amMemory']))
     putMapredProperty('yarn.app.mapreduce.am.resource.mb', int(clusterData['amMemory']))
     putMapredProperty('yarn.app.mapreduce.am.command-opts', "-Xmx" + str(int(round(0.8 * clusterData['amMemory']))) + "m")
     putMapredProperty('yarn.app.mapreduce.am.command-opts', "-Xmx" + str(int(round(0.8 * clusterData['amMemory']))) + "m")
@@ -196,20 +196,19 @@ class HDP206StackAdvisor(DefaultStackAdvisor):
     for service in services["services"]:
     for service in services["services"]:
       serviceName = service["StackServices"]["service_name"]
       serviceName = service["StackServices"]["service_name"]
       validator = self.validateServiceConfigurations(serviceName)
       validator = self.validateServiceConfigurations(serviceName)
-      if validator is not None:
-        siteName = validator[0]
-        method = validator[1]
-        if siteName in recommendedDefaults:
-          siteProperties = getSiteProperties(configurations, siteName)
-          if siteProperties is not None:
-            resultItems = method(siteProperties, recommendedDefaults[siteName]["properties"], configurations)
-            items.extend(resultItems)
+      if validator is not  None:
+        for siteName, method in validator.items():
+          if siteName in recommendedDefaults:
+            siteProperties = getSiteProperties(configurations, siteName)
+            if siteProperties is not None:
+              resultItems = method(siteProperties, recommendedDefaults[siteName]["properties"], configurations, services, hosts)
+              items.extend(resultItems)
     return items
     return items
 
 
   def getServiceConfigurationValidators(self):
   def getServiceConfigurationValidators(self):
     return {
     return {
-      "MAPREDUCE2": ["mapred-site", self.validateMapReduce2Configurations],
-      "YARN": ["yarn-site", self.validateYARNConfigurations]
+      "MAPREDUCE2": {"mapred-site": self.validateMapReduce2Configurations},
+      "YARN": {"yarn-site": self.validateYARNConfigurations}
     }
     }
 
 
   def validateServiceConfigurations(self, serviceName):
   def validateServiceConfigurations(self, serviceName):
@@ -231,6 +230,21 @@ class HDP206StackAdvisor(DefaultStackAdvisor):
   def getErrorItem(self, message):
   def getErrorItem(self, message):
     return {"level": "ERROR", "message": message}
     return {"level": "ERROR", "message": message}
 
 
+  def validatorEnoughDiskSpace(self, properties, propertyName, hostInfo, reqiuredDiskSpace):
+    if not propertyName in properties:
+      return self.getErrorItem("Value should be set")
+    dir = properties[propertyName]
+    if not dir.startswith("hdfs://"):
+      dir = re.sub("^file://", "", dir, count=1)
+    mountPoints = {}
+    for mountPoint in hostInfo["disk_info"]:
+      mountPoints[mountPoint["mountpoint"]] = to_number(mountPoint["available"])
+    mountPoint = getMountPointForDir(dir, mountPoints.keys())
+
+    if mountPoints[mountPoint] < reqiuredDiskSpace:
+      return self.getWarnItem("Recommended disk space for partition {0} is {1}k".format(mountPoint, reqiuredDiskSpace))
+    return None
+
   def validatorLessThenDefaultValue(self, properties, recommendedDefaults, propertyName):
   def validatorLessThenDefaultValue(self, properties, recommendedDefaults, propertyName):
     if not propertyName in properties:
     if not propertyName in properties:
       return self.getErrorItem("Value should be set")
       return self.getErrorItem("Value should be set")
@@ -260,7 +274,7 @@ class HDP206StackAdvisor(DefaultStackAdvisor):
       return self.getWarnItem("Value is less than the recommended default of -Xmx" + defaultValueXmx)
       return self.getWarnItem("Value is less than the recommended default of -Xmx" + defaultValueXmx)
     return None
     return None
 
 
-  def validateMapReduce2Configurations(self, properties, recommendedDefaults, configurations):
+  def validateMapReduce2Configurations(self, properties, recommendedDefaults, configurations, services, hosts):
     validationItems = [ {"config-name": 'mapreduce.map.java.opts', "item": self.validateXmxValue(properties, recommendedDefaults, 'mapreduce.map.java.opts')},
     validationItems = [ {"config-name": 'mapreduce.map.java.opts', "item": self.validateXmxValue(properties, recommendedDefaults, 'mapreduce.map.java.opts')},
                         {"config-name": 'mapreduce.reduce.java.opts', "item": self.validateXmxValue(properties, recommendedDefaults, 'mapreduce.reduce.java.opts')},
                         {"config-name": 'mapreduce.reduce.java.opts', "item": self.validateXmxValue(properties, recommendedDefaults, 'mapreduce.reduce.java.opts')},
                         {"config-name": 'mapreduce.task.io.sort.mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'mapreduce.task.io.sort.mb')},
                         {"config-name": 'mapreduce.task.io.sort.mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'mapreduce.task.io.sort.mb')},
@@ -270,7 +284,7 @@ class HDP206StackAdvisor(DefaultStackAdvisor):
                         {"config-name": 'yarn.app.mapreduce.am.command-opts', "item": self.validateXmxValue(properties, recommendedDefaults, 'yarn.app.mapreduce.am.command-opts')} ]
                         {"config-name": 'yarn.app.mapreduce.am.command-opts', "item": self.validateXmxValue(properties, recommendedDefaults, 'yarn.app.mapreduce.am.command-opts')} ]
     return self.toConfigurationValidationProblems(validationItems, "mapred-site")
     return self.toConfigurationValidationProblems(validationItems, "mapred-site")
 
 
-  def validateYARNConfigurations(self, properties, recommendedDefaults, configurations):
+  def validateYARNConfigurations(self, properties, recommendedDefaults, configurations, services, hosts):
     validationItems = [ {"config-name": 'yarn.nodemanager.resource.memory-mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'yarn.nodemanager.resource.memory-mb')},
     validationItems = [ {"config-name": 'yarn.nodemanager.resource.memory-mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'yarn.nodemanager.resource.memory-mb')},
                         {"config-name": 'yarn.scheduler.minimum-allocation-mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'yarn.scheduler.minimum-allocation-mb')},
                         {"config-name": 'yarn.scheduler.minimum-allocation-mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'yarn.scheduler.minimum-allocation-mb')},
                         {"config-name": 'yarn.scheduler.maximum-allocation-mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'yarn.scheduler.maximum-allocation-mb')} ]
                         {"config-name": 'yarn.scheduler.maximum-allocation-mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'yarn.scheduler.maximum-allocation-mb')} ]
@@ -370,4 +384,27 @@ def isSecurePort(port):
   if port is not None:
   if port is not None:
     return port < 1024
     return port < 1024
   else:
   else:
-    return False
+    return False
+
+def getMountPointForDir(dir, mountPoints):
+  """
+  :param dir: Directory to check, even if it doesn't exist.
+  :return: Returns the closest mount point as a string for the directory.
+  if the "dir" variable is None, will return None.
+  If the directory does not exist, will return "/".
+  """
+  bestMountFound = None
+  if dir:
+    dir = dir.strip().lower()
+
+    # If the path is "/hadoop/hdfs/data", then possible matches for mounts could be
+    # "/", "/hadoop/hdfs", and "/hadoop/hdfs/data".
+    # So take the one with the greatest number of segments.
+    for mountPoint in mountPoints:
+      if dir.startswith(mountPoint):
+        if bestMountFound is None:
+          bestMountFound = mountPoint
+        elif bestMountFound.count(os.path.sep) < mountPoint.count(os.path.sep):
+          bestMountFound = mountPoint
+
+  return bestMountFound

+ 7 - 7
ambari-server/src/main/resources/stacks/HDP/2.1/services/stack_advisor.py

@@ -29,7 +29,7 @@ class HDP21StackAdvisor(HDP206StackAdvisor):
     parentRecommendConfDict.update(childRecommendConfDict)
     parentRecommendConfDict.update(childRecommendConfDict)
     return parentRecommendConfDict
     return parentRecommendConfDict
 
 
-  def recommendOozieConfigurations(self, configurations, clusterData):
+  def recommendOozieConfigurations(self, configurations, clusterData, services, hosts):
     if "FALCON_SERVER" in clusterData["components"]:
     if "FALCON_SERVER" in clusterData["components"]:
       putMapredProperty = self.putProperty(configurations, "oozie-site")
       putMapredProperty = self.putProperty(configurations, "oozie-site")
       putMapredProperty("oozie.services.ext",
       putMapredProperty("oozie.services.ext",
@@ -37,7 +37,7 @@ class HDP21StackAdvisor(HDP206StackAdvisor):
                         "org.apache.oozie.service.PartitionDependencyManagerService," +
                         "org.apache.oozie.service.PartitionDependencyManagerService," +
                         "org.apache.oozie.service.HCatAccessorService")
                         "org.apache.oozie.service.HCatAccessorService")
 
 
-  def recommendHiveConfigurations(self, configurations, clusterData):
+  def recommendHiveConfigurations(self, configurations, clusterData, services, hosts):
     containerSize = clusterData['mapMemory'] if clusterData['mapMemory'] > 2048 else int(clusterData['reduceMemory'])
     containerSize = clusterData['mapMemory'] if clusterData['mapMemory'] > 2048 else int(clusterData['reduceMemory'])
     containerSize = min(clusterData['containers'] * clusterData['ramPerContainer'], containerSize)
     containerSize = min(clusterData['containers'] * clusterData['ramPerContainer'], containerSize)
     putHiveProperty = self.putProperty(configurations, "hive-site")
     putHiveProperty = self.putProperty(configurations, "hive-site")
@@ -46,7 +46,7 @@ class HDP21StackAdvisor(HDP206StackAdvisor):
                     + "m -Djava.net.preferIPv4Stack=true -XX:NewRatio=8 -XX:+UseNUMA -XX:+UseParallelGC -XX:+PrintGCDetails -verbose:gc -XX:+PrintGCTimeStamps")
                     + "m -Djava.net.preferIPv4Stack=true -XX:NewRatio=8 -XX:+UseNUMA -XX:+UseParallelGC -XX:+PrintGCDetails -verbose:gc -XX:+PrintGCTimeStamps")
     putHiveProperty('hive.tez.container.size', containerSize)
     putHiveProperty('hive.tez.container.size', containerSize)
 
 
-  def recommendTezConfigurations(self, configurations, clusterData):
+  def recommendTezConfigurations(self, configurations, clusterData, services, hosts):
     putTezProperty = self.putProperty(configurations, "tez-site")
     putTezProperty = self.putProperty(configurations, "tez-site")
     putTezProperty("tez.am.resource.memory.mb", int(clusterData['amMemory']))
     putTezProperty("tez.am.resource.memory.mb", int(clusterData['amMemory']))
     putTezProperty("tez.am.java.opts",
     putTezProperty("tez.am.java.opts",
@@ -71,19 +71,19 @@ class HDP21StackAdvisor(HDP206StackAdvisor):
   def getServiceConfigurationValidators(self):
   def getServiceConfigurationValidators(self):
     parentValidators = super(HDP21StackAdvisor, self).getServiceConfigurationValidators()
     parentValidators = super(HDP21StackAdvisor, self).getServiceConfigurationValidators()
     childValidators = {
     childValidators = {
-      "HIVE": ["hive-site", self.validateHiveConfigurations],
-      "TEZ": ["tez-site", self.validateTezConfigurations]
+      "HIVE": {"hive-site": self.validateHiveConfigurations},
+      "TEZ": {"tez-site": self.validateTezConfigurations}
     }
     }
     parentValidators.update(childValidators)
     parentValidators.update(childValidators)
     return parentValidators
     return parentValidators
 
 
-  def validateHiveConfigurations(self, properties, recommendedDefaults, configurations):
+  def validateHiveConfigurations(self, properties, recommendedDefaults, configurations, services, hosts):
     validationItems = [ {"config-name": 'hive.tez.container.size', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'hive.tez.container.size')},
     validationItems = [ {"config-name": 'hive.tez.container.size', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'hive.tez.container.size')},
                         {"config-name": 'hive.tez.java.opts', "item": self.validateXmxValue(properties, recommendedDefaults, 'hive.tez.java.opts')},
                         {"config-name": 'hive.tez.java.opts', "item": self.validateXmxValue(properties, recommendedDefaults, 'hive.tez.java.opts')},
                         {"config-name": 'hive.auto.convert.join.noconditionaltask.size', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'hive.auto.convert.join.noconditionaltask.size')} ]
                         {"config-name": 'hive.auto.convert.join.noconditionaltask.size', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'hive.auto.convert.join.noconditionaltask.size')} ]
     return self.toConfigurationValidationProblems(validationItems, "hive-site")
     return self.toConfigurationValidationProblems(validationItems, "hive-site")
 
 
-  def validateTezConfigurations(self, properties, recommendedDefaults, configurations):
+  def validateTezConfigurations(self, properties, recommendedDefaults, configurations, services, hosts):
     validationItems = [ {"config-name": 'tez.am.resource.memory.mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'tez.am.resource.memory.mb')},
     validationItems = [ {"config-name": 'tez.am.resource.memory.mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'tez.am.resource.memory.mb')},
                         {"config-name": 'tez.am.java.opts', "item": self.validateXmxValue(properties, recommendedDefaults, 'tez.am.java.opts')} ]
                         {"config-name": 'tez.am.java.opts', "item": self.validateXmxValue(properties, recommendedDefaults, 'tez.am.java.opts')} ]
     return self.toConfigurationValidationProblems(validationItems, "tez-site")
     return self.toConfigurationValidationProblems(validationItems, "tez-site")

+ 128 - 11
ambari-server/src/main/resources/stacks/HDP/2.2/services/stack_advisor.py

@@ -25,21 +25,22 @@ class HDP22StackAdvisor(HDP21StackAdvisor):
       "HDFS": self.recommendHDFSConfigurations,
       "HDFS": self.recommendHDFSConfigurations,
       "MAPREDUCE2": self.recommendMapReduce2Configurations,
       "MAPREDUCE2": self.recommendMapReduce2Configurations,
       "TEZ": self.recommendTezConfigurations,
       "TEZ": self.recommendTezConfigurations,
+      "AMS": self.recommendAmsConfigurations,
       "YARN": self.recommendYARNConfigurations
       "YARN": self.recommendYARNConfigurations
     }
     }
     parentRecommendConfDict.update(childRecommendConfDict)
     parentRecommendConfDict.update(childRecommendConfDict)
     return parentRecommendConfDict
     return parentRecommendConfDict
 
 
-  def recommendYARNConfigurations(self, configurations, clusterData):
-    super(HDP22StackAdvisor, self).recommendYARNConfigurations(configurations, clusterData)
+  def recommendYARNConfigurations(self, configurations, clusterData, services, hosts):
+    super(HDP22StackAdvisor, self).recommendYARNConfigurations(configurations, clusterData, services, hosts)
     putYarnProperty = self.putProperty(configurations, "yarn-site")
     putYarnProperty = self.putProperty(configurations, "yarn-site")
     putYarnProperty('yarn.nodemanager.resource.cpu-vcores', clusterData['cpu'])
     putYarnProperty('yarn.nodemanager.resource.cpu-vcores', clusterData['cpu'])
 
 
-  def recommendHDFSConfigurations(self, configurations, clusterData):
+  def recommendHDFSConfigurations(self, configurations, clusterData, services, hosts):
     putHdfsPropery = self.putProperty(configurations, "hdfs-site")
     putHdfsPropery = self.putProperty(configurations, "hdfs-site")
     putHdfsPropery("dfs.datanode.max.transfer.threads", 16384 if clusterData["hBaseInstalled"] else 4096)
     putHdfsPropery("dfs.datanode.max.transfer.threads", 16384 if clusterData["hBaseInstalled"] else 4096)
 
 
-  def recommendTezConfigurations(self, configurations, clusterData):
+  def recommendTezConfigurations(self, configurations, clusterData, services, hosts):
     putTezProperty = self.putProperty(configurations, "tez-site")
     putTezProperty = self.putProperty(configurations, "tez-site")
     putTezProperty("tez.am.resource.memory.mb", int(clusterData['amMemory']) * 2 if int(clusterData['amMemory']) < 3072 else int(clusterData['amMemory']))
     putTezProperty("tez.am.resource.memory.mb", int(clusterData['amMemory']) * 2 if int(clusterData['amMemory']) < 3072 else int(clusterData['amMemory']))
     putTezProperty("tez.am.java.opts",
     putTezProperty("tez.am.java.opts",
@@ -52,17 +53,57 @@ class HDP22StackAdvisor(HDP21StackAdvisor):
     putTezProperty("tez.runtime.io.sort.mb", int(taskResourceMemory * 0.4) if int(taskResourceMemory * 0.4) <= 2147483644 else 2147483644)
     putTezProperty("tez.runtime.io.sort.mb", int(taskResourceMemory * 0.4) if int(taskResourceMemory * 0.4) <= 2147483644 else 2147483644)
     putTezProperty("tez.runtime.unordered.output.buffer.size-mb", int(taskResourceMemory * 0.075))
     putTezProperty("tez.runtime.unordered.output.buffer.size-mb", int(taskResourceMemory * 0.075))
 
 
+  def recommendAmsConfigurations(self, configurations, clusterData, services, hosts):
+    putAmsHbaseSiteProperty = self.putProperty(configurations, "ams-hbase-site")
+    putTimelineServiceProperty = self.putProperty(configurations, "ams-site")
+    putHbaseEnvProperty = self.putProperty(configurations, "ams-hbase-env")
+
+    amsCollectorHosts = self.getComponentHostNames(services, "AMS", "METRIC_COLLECTOR")
+
+    # TODO recommend configuration for multiple AMS collectors
+    if len(amsCollectorHosts) > 1:
+      pass
+    else:
+      totalHostsCount = len(hosts["items"])
+      # TODO Tune values according to performance testing results
+      if totalHostsCount > 400:
+        putAmsHbaseSiteProperty("hfile.block.cache.size", 0.3)
+        putAmsHbaseSiteProperty("hbase.regionserver.global.memstore.upperLimit", 0.5)
+        putAmsHbaseSiteProperty("hbase.regionserver.global.memstore.lowerLimit", 0.4)
+        putTimelineServiceProperty("timeline.metrics.host.aggregator.ttl", 86400)
+
+        putHbaseEnvProperty("hbase_master_heapsize", "8096m")
+        putHbaseEnvProperty("hbase_regionserver_heapsize", "8096m")
+      elif totalHostsCount > 100:
+        putAmsHbaseSiteProperty("hfile.block.cache.size", 0.3)
+        putAmsHbaseSiteProperty("hbase.regionserver.global.memstore.upperLimit", 0.5)
+        putAmsHbaseSiteProperty("hbase.regionserver.global.memstore.lowerLimit", 0.4)
+        putTimelineServiceProperty("timeline.metrics.host.aggregator.ttl", 86400)
+
+        putHbaseEnvProperty("hbase_master_heapsize", "2048m")
+        putHbaseEnvProperty("hbase_regionserver_heapsize", "2048m")
+      else:
+        putAmsHbaseSiteProperty("hfile.block.cache.size", 0.3)
+        putAmsHbaseSiteProperty("hbase.regionserver.global.memstore.upperLimit", 0.5)
+        putAmsHbaseSiteProperty("hbase.regionserver.global.memstore.lowerLimit", 0.4)
+        putTimelineServiceProperty("timeline.metrics.host.aggregator.ttl", 86400)
+
+        putHbaseEnvProperty("hbase_master_heapsize", "1024m")
+        putHbaseEnvProperty("hbase_regionserver_heapsize", "1024m")
+
   def getServiceConfigurationValidators(self):
   def getServiceConfigurationValidators(self):
     parentValidators = super(HDP22StackAdvisor, self).getServiceConfigurationValidators()
     parentValidators = super(HDP22StackAdvisor, self).getServiceConfigurationValidators()
     childValidators = {
     childValidators = {
-      "HDFS": ["hdfs-site", self.validateHDFSConfigurations],
-      "MAPREDUCE2": ["mapred-site", self.validateMapReduce2Configurations],
-      "TEZ": ["tez-site", self.validateTezConfigurations]
+      "HDFS": {"hdfs-site": self.validateHDFSConfigurations},
+      "MAPREDUCE2": {"mapred-site": self.validateMapReduce2Configurations},
+      "AMS": {"ams-hbase-site": self.validateAmsHbaseSiteConfigurations,
+              "ams-hbase-env": self.validateAmsHbaseEnvConfigurations},
+      "TEZ": {"tez-site": self.validateTezConfigurations}
     }
     }
     parentValidators.update(childValidators)
     parentValidators.update(childValidators)
     return parentValidators
     return parentValidators
 
 
-  def validateTezConfigurations(self, properties, recommendedDefaults, configurations):
+  def validateTezConfigurations(self, properties, recommendedDefaults, configurations, services, hosts):
     validationItems = [ {"config-name": 'tez.am.resource.memory.mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'tez.am.resource.memory.mb')},
     validationItems = [ {"config-name": 'tez.am.resource.memory.mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'tez.am.resource.memory.mb')},
                         {"config-name": 'tez.am.java.opts', "item": self.validateXmxValue(properties, recommendedDefaults, 'tez.am.java.opts')},
                         {"config-name": 'tez.am.java.opts', "item": self.validateXmxValue(properties, recommendedDefaults, 'tez.am.java.opts')},
                         {"config-name": 'tez.task.resource.memory.mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'tez.task.resource.memory.mb')},
                         {"config-name": 'tez.task.resource.memory.mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'tez.task.resource.memory.mb')},
@@ -70,7 +111,61 @@ class HDP22StackAdvisor(HDP21StackAdvisor):
                         {"config-name": 'tez.runtime.unordered.output.buffer.size-mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'tez.runtime.unordered.output.buffer.size-mb')},]
                         {"config-name": 'tez.runtime.unordered.output.buffer.size-mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'tez.runtime.unordered.output.buffer.size-mb')},]
     return self.toConfigurationValidationProblems(validationItems, "tez-site")
     return self.toConfigurationValidationProblems(validationItems, "tez-site")
 
 
-  def recommendMapReduce2Configurations(self, configurations, clusterData):
+  def validateAmsHbaseSiteConfigurations(self, properties, recommendedDefaults, configurations, services, hosts):
+
+    amsCollectorHosts = self.getComponentHostNames(services, "AMS", "METRIC_COLLECTOR")
+    recommendedDiskSpace = 10485760
+    # TODO validate configuration for multiple AMS collectors
+    if len(amsCollectorHosts) > 1:
+      pass
+    else:
+      totalHostsCount = len(hosts["items"])
+      if totalHostsCount > 400:
+        recommendedDiskSpace  = 104857600  # * 1k == 100 Gb
+      elif totalHostsCount > 100:
+        recommendedDiskSpace  = 52428800  # * 1k == 50 Gb
+      elif totalHostsCount > 10:
+        recommendedDiskSpace  = 20971520  # * 1k == 20 Gb
+
+
+    validationItems = []
+    for collectorHostName in amsCollectorHosts:
+      for host in hosts["items"]:
+        if host["Hosts"]["host_name"] == collectorHostName:
+          validationItems.extend([ {"config-name": 'hbase.rootdir', "item": self.validatorEnoughDiskSpace(properties, 'hbase.rootdir', host["Hosts"], recommendedDiskSpace)}])
+          break
+
+    return self.toConfigurationValidationProblems(validationItems, "ams-hbase-site")
+
+  def validateAmsHbaseEnvConfigurations(self, properties, recommendedDefaults, configurations, services, hosts):
+    regionServerItem = self.validatorLessThenDefaultValue(properties, recommendedDefaults, "hbase_regionserver_heapsize")
+    masterItem = self.validatorLessThenDefaultValue(properties, recommendedDefaults, "hbase_master_heapsize")
+
+    if regionServerItem is None and masterItem is None:
+      hbase_regionserver_heapsize = formatXmxSizeToBytes(properties["hbase_regionserver_heapsize"])
+      hbase_master_heapsize = formatXmxSizeToBytes(properties["hbase_master_heapsize"])
+
+      # TODO Add AMS Collector Xmx property to ams-env
+      # Collector + HBASE Master + HBASE RegionServer HeapSize
+      requiredMemory = 1073741824 + hbase_regionserver_heapsize + hbase_master_heapsize
+
+      amsCollectorHosts = self.getComponentHostNames(services, "AMS", "METRIC_COLLECTOR")
+      for collectorHostName in amsCollectorHosts:
+        for host in hosts["items"]:
+          if host["Hosts"]["host_name"] == collectorHostName:
+            if host["Hosts"]["total_mem"] * 1024 < requiredMemory:  # in bytes
+              message = "Not enough total RAM on the host {0}, " \
+                        "at least {1} MB required" \
+                        .format(collectorHostName, requiredMemory/1048576)  # MB
+              regionServerItem = self.getWarnItem(message)
+              masterItem = self.getWarnItem(message)
+              break
+
+    validationItems = [{"config-name": "hbase_regionserver_heapsize", "item": regionServerItem},
+                       {"config-name": "hbase_master_heapsize", "item": masterItem}]
+    return self.toConfigurationValidationProblems(validationItems, "ams-hbase-env")
+
+  def recommendMapReduce2Configurations(self, configurations, clusterData, services, hosts):
     putMapredProperty = self.putProperty(configurations, "mapred-site")
     putMapredProperty = self.putProperty(configurations, "mapred-site")
     putMapredProperty('yarn.app.mapreduce.am.resource.mb', int(clusterData['amMemory']))
     putMapredProperty('yarn.app.mapreduce.am.resource.mb', int(clusterData['amMemory']))
     putMapredProperty('yarn.app.mapreduce.am.command-opts', "-Xmx" + str(int(round(0.8 * clusterData['amMemory']))) + "m" + " -Dhdp.version=${hdp.version}")
     putMapredProperty('yarn.app.mapreduce.am.command-opts', "-Xmx" + str(int(round(0.8 * clusterData['amMemory']))) + "m" + " -Dhdp.version=${hdp.version}")
@@ -80,7 +175,7 @@ class HDP22StackAdvisor(HDP21StackAdvisor):
     putMapredProperty('mapreduce.reduce.java.opts', "-Xmx" + str(int(round(0.8 * clusterData['reduceMemory']))) + "m")
     putMapredProperty('mapreduce.reduce.java.opts', "-Xmx" + str(int(round(0.8 * clusterData['reduceMemory']))) + "m")
     putMapredProperty('mapreduce.task.io.sort.mb', min(int(round(0.4 * clusterData['mapMemory'])), 1024))
     putMapredProperty('mapreduce.task.io.sort.mb', min(int(round(0.4 * clusterData['mapMemory'])), 1024))
 
 
-  def validateMapReduce2Configurations(self, properties, recommendedDefaults, configurations):
+  def validateMapReduce2Configurations(self, properties, recommendedDefaults, configurations, services, hosts):
     validationItems = [ {"config-name": 'mapreduce.map.java.opts', "item": self.validateXmxValue(properties, recommendedDefaults, 'mapreduce.map.java.opts')},
     validationItems = [ {"config-name": 'mapreduce.map.java.opts', "item": self.validateXmxValue(properties, recommendedDefaults, 'mapreduce.map.java.opts')},
                         {"config-name": 'mapreduce.reduce.java.opts', "item": self.validateXmxValue(properties, recommendedDefaults, 'mapreduce.reduce.java.opts')},
                         {"config-name": 'mapreduce.reduce.java.opts', "item": self.validateXmxValue(properties, recommendedDefaults, 'mapreduce.reduce.java.opts')},
                         {"config-name": 'mapreduce.task.io.sort.mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'mapreduce.task.io.sort.mb')},
                         {"config-name": 'mapreduce.task.io.sort.mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'mapreduce.task.io.sort.mb')},
@@ -89,7 +184,7 @@ class HDP22StackAdvisor(HDP21StackAdvisor):
                         {"config-name": 'yarn.app.mapreduce.am.resource.mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'yarn.app.mapreduce.am.resource.mb')}]
                         {"config-name": 'yarn.app.mapreduce.am.resource.mb', "item": self.validatorLessThenDefaultValue(properties, recommendedDefaults, 'yarn.app.mapreduce.am.resource.mb')}]
     return self.toConfigurationValidationProblems(validationItems, "mapred-site")
     return self.toConfigurationValidationProblems(validationItems, "mapred-site")
 
 
-  def validateHDFSConfigurations(self, properties, recommendedDefaults, configurations):
+  def validateHDFSConfigurations(self, properties, recommendedDefaults, configurations, services, hosts):
     # We can not access property hadoop.security.authentication from the
     # We can not access property hadoop.security.authentication from the
     # other config (core-site). That's why we are using another heuristics here
     # other config (core-site). That's why we are using another heuristics here
     hdfs_site = properties
     hdfs_site = properties
@@ -195,5 +290,27 @@ class HDP22StackAdvisor(HDP21StackAdvisor):
                                       data_transfer_protection_value, VALID_TRANSFER_PROTECTION_VALUES))})
                                       data_transfer_protection_value, VALID_TRANSFER_PROTECTION_VALUES))})
     return self.toConfigurationValidationProblems(validationItems, "hdfs-site")
     return self.toConfigurationValidationProblems(validationItems, "hdfs-site")
 
 
+  def getMastersWithMultipleInstances(self):
+    result = super(HDP22StackAdvisor, self).getMastersWithMultipleInstances()
+    result.extend(['METRIC_COLLECTOR'])
+    return result
+
+  def getNotValuableComponents(self):
+    result = super(HDP22StackAdvisor, self).getNotValuableComponents()
+    result.extend(['METRIC_MONITOR'])
+    return result
+
+  def getNotPreferableOnServerComponents(self):
+    result = super(HDP22StackAdvisor, self).getNotPreferableOnServerComponents()
+    result.extend(['METRIC_COLLECTOR'])
+    return result
 
 
+  def getCardinalitiesDict(self):
+    result = super(HDP22StackAdvisor, self).getCardinalitiesDict()
+    result['METRIC_COLLECTOR'] = {"min": 1}
+    return result
 
 
+  def getComponentLayoutSchemes(self):
+    result = super(HDP22StackAdvisor, self).getComponentLayoutSchemes()
+    result['METRIC_COLLECTOR'] = {"else": 2}
+    return result

+ 9 - 2
ambari-server/src/main/resources/stacks/stack_advisor.py

@@ -17,7 +17,6 @@ See the License for the specific language governing permissions and
 limitations under the License.
 limitations under the License.
 """
 """
 
 
-import time
 import socket
 import socket
 
 
 class StackAdvisor(object):
 class StackAdvisor(object):
@@ -480,7 +479,7 @@ class DefaultStackAdvisor(StackAdvisor):
     for service in servicesList:
     for service in servicesList:
       calculation = self.getServiceConfigurationRecommender(service)
       calculation = self.getServiceConfigurationRecommender(service)
       if calculation is not None:
       if calculation is not None:
-        calculation(configurations, clusterSummary)
+        calculation(configurations, clusterSummary, services, hosts)
 
 
     return recommendations
     return recommendations
 
 
@@ -584,3 +583,11 @@ class DefaultStackAdvisor(StackAdvisor):
     host index where component should exist.
     host index where component should exist.
     """
     """
     return {}
     return {}
+
+  def getComponentHostNames(self, servicesDict, serviceName, componentName):
+    for service in servicesDict["services"]:
+      if service["StackServices"]["service_name"] == serviceName:
+        for component in service['components']:
+          if component["StackServiceComponents"]["component_name"] == componentName:
+            return component["StackServiceComponents"]["hostnames"]
+  pass

+ 2 - 2
ambari-server/src/test/python/stacks/2.0.6/common/test_stack_advisor.py

@@ -337,7 +337,7 @@ class TestHDP206StackAdvisor(TestCase):
       }
       }
     }
     }
 
 
-    self.stackAdvisor.recommendYARNConfigurations(configurations, clusterData)
+    self.stackAdvisor.recommendYARNConfigurations(configurations, clusterData, None, None)
     self.assertEquals(configurations, expected)
     self.assertEquals(configurations, expected)
 
 
   def test_recommendMapReduce2Configurations_mapMemoryLessThan2560(self):
   def test_recommendMapReduce2Configurations_mapMemoryLessThan2560(self):
@@ -361,7 +361,7 @@ class TestHDP206StackAdvisor(TestCase):
       }
       }
     }
     }
 
 
-    self.stackAdvisor.recommendMapReduce2Configurations(configurations, clusterData)
+    self.stackAdvisor.recommendMapReduce2Configurations(configurations, clusterData, None, None)
     self.assertEquals(configurations, expected)
     self.assertEquals(configurations, expected)
 
 
   def test_getConfigurationClusterSummary_noHostsWithoutHBase(self):
   def test_getConfigurationClusterSummary_noHostsWithoutHBase(self):

+ 5 - 5
ambari-server/src/test/python/stacks/2.1/common/test_stack_advisor.py

@@ -47,7 +47,7 @@ class TestHDP21StackAdvisor(TestCase):
     expected = {
     expected = {
     }
     }
 
 
-    self.stackAdvisor.recommendOozieConfigurations(configurations, clusterData)
+    self.stackAdvisor.recommendOozieConfigurations(configurations, clusterData, None, None)
     self.assertEquals(configurations, expected)
     self.assertEquals(configurations, expected)
 
 
   def test_recommendOozieConfigurations_withFalconServer(self):
   def test_recommendOozieConfigurations_withFalconServer(self):
@@ -65,7 +65,7 @@ class TestHDP21StackAdvisor(TestCase):
       }
       }
     }
     }
 
 
-    self.stackAdvisor.recommendOozieConfigurations(configurations, clusterData)
+    self.stackAdvisor.recommendOozieConfigurations(configurations, clusterData, None, None)
     self.assertEquals(configurations, expected)
     self.assertEquals(configurations, expected)
 
 
   def test_recommendHiveConfigurations_mapMemoryLessThan2048(self):
   def test_recommendHiveConfigurations_mapMemoryLessThan2048(self):
@@ -86,7 +86,7 @@ class TestHDP21StackAdvisor(TestCase):
       }
       }
     }
     }
 
 
-    self.stackAdvisor.recommendHiveConfigurations(configurations, clusterData)
+    self.stackAdvisor.recommendHiveConfigurations(configurations, clusterData, None, None)
     self.assertEquals(configurations, expected)
     self.assertEquals(configurations, expected)
 
 
   def test_recommendHiveConfigurations_mapMemoryMoreThan2048(self):
   def test_recommendHiveConfigurations_mapMemoryMoreThan2048(self):
@@ -107,7 +107,7 @@ class TestHDP21StackAdvisor(TestCase):
       }
       }
     }
     }
 
 
-    self.stackAdvisor.recommendHiveConfigurations(configurations, clusterData)
+    self.stackAdvisor.recommendHiveConfigurations(configurations, clusterData, None, None)
     self.assertEquals(configurations, expected)
     self.assertEquals(configurations, expected)
 
 
   def test_createComponentLayoutRecommendations_mastersIn10nodes(self):
   def test_createComponentLayoutRecommendations_mastersIn10nodes(self):
@@ -157,5 +157,5 @@ class TestHDP21StackAdvisor(TestCase):
       }
       }
     }
     }
 
 
-    self.stackAdvisor.recommendHiveConfigurations(configurations, clusterData)
+    self.stackAdvisor.recommendHiveConfigurations(configurations, clusterData, None, None)
     self.assertEquals(configurations, expected)
     self.assertEquals(configurations, expected)

+ 68 - 20
ambari-server/src/test/python/stacks/2.2/common/test_stack_advisor.py

@@ -16,7 +16,6 @@ See the License for the specific language governing permissions and
 limitations under the License.
 limitations under the License.
 '''
 '''
 
 
-import json
 import os
 import os
 from unittest import TestCase
 from unittest import TestCase
 
 
@@ -62,7 +61,7 @@ class TestHDP22StackAdvisor(TestCase):
         }
         }
       }
       }
     }
     }
-    self.stackAdvisor.recommendTezConfigurations(configurations, clusterData)
+    self.stackAdvisor.recommendTezConfigurations(configurations, clusterData, None, None)
     self.assertEquals(configurations, expected)
     self.assertEquals(configurations, expected)
 
 
   def test_recommendTezConfigurations_amMemoryMoreThan3072(self):
   def test_recommendTezConfigurations_amMemoryMoreThan3072(self):
@@ -85,7 +84,7 @@ class TestHDP22StackAdvisor(TestCase):
         }
         }
       }
       }
     }
     }
-    self.stackAdvisor.recommendTezConfigurations(configurations, clusterData)
+    self.stackAdvisor.recommendTezConfigurations(configurations, clusterData, None, None)
     self.assertEquals(configurations, expected)
     self.assertEquals(configurations, expected)
 
 
   def test_recommendTezConfigurations_mapMemoryLessThan768(self):
   def test_recommendTezConfigurations_mapMemoryLessThan768(self):
@@ -108,7 +107,7 @@ class TestHDP22StackAdvisor(TestCase):
         }
         }
       }
       }
     }
     }
-    self.stackAdvisor.recommendTezConfigurations(configurations, clusterData)
+    self.stackAdvisor.recommendTezConfigurations(configurations, clusterData, None, None)
     self.assertEquals(configurations, expected)
     self.assertEquals(configurations, expected)
 
 
 
 
@@ -140,7 +139,7 @@ class TestHDP22StackAdvisor(TestCase):
       }
       }
     }
     }
     expected = []  # No warnings
     expected = []  # No warnings
-    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations)
+    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations, None, None)
     self.assertEquals(validation_problems, expected)
     self.assertEquals(validation_problems, expected)
 
 
     # TEST CASE: Unsecured cluster, unsecure ports
     # TEST CASE: Unsecured cluster, unsecure ports
@@ -157,7 +156,7 @@ class TestHDP22StackAdvisor(TestCase):
       }
       }
     }
     }
     expected = []  # No warnings
     expected = []  # No warnings
-    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations)
+    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations, None, None)
     self.assertEquals(validation_problems, expected)
     self.assertEquals(validation_problems, expected)
 
 
     # TEST CASE: Secure cluster, invalid dfs.http.policy value
     # TEST CASE: Secure cluster, invalid dfs.http.policy value
@@ -179,7 +178,7 @@ class TestHDP22StackAdvisor(TestCase):
                  'level': 'WARN',
                  'level': 'WARN',
                  'message': "Invalid property value: WRONG_VALUE. Valid values are ['HTTP_ONLY', 'HTTPS_ONLY', 'HTTP_AND_HTTPS']",
                  'message': "Invalid property value: WRONG_VALUE. Valid values are ['HTTP_ONLY', 'HTTPS_ONLY', 'HTTP_AND_HTTPS']",
                  'type': 'configuration'}]
                  'type': 'configuration'}]
-    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations)
+    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations, None, None)
     self.assertEquals(validation_problems, expected)
     self.assertEquals(validation_problems, expected)
 
 
     # TEST CASE: Secure cluster, dfs.http.policy=HTTPS_ONLY, https address not defined
     # TEST CASE: Secure cluster, dfs.http.policy=HTTPS_ONLY, https address not defined
@@ -196,7 +195,7 @@ class TestHDP22StackAdvisor(TestCase):
       }
       }
     }
     }
     expected = [ ]
     expected = [ ]
-    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations)
+    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations, None, None)
     self.assertEquals(validation_problems, expected)
     self.assertEquals(validation_problems, expected)
 
 
     # TEST CASE: Secure cluster, dfs.http.policy=HTTPS_ONLY, https address defined and secure
     # TEST CASE: Secure cluster, dfs.http.policy=HTTPS_ONLY, https address defined and secure
@@ -214,7 +213,7 @@ class TestHDP22StackAdvisor(TestCase):
       }
       }
     }
     }
     expected = []
     expected = []
-    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations)
+    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations, None, None)
     self.assertEquals(validation_problems, expected)
     self.assertEquals(validation_problems, expected)
 
 
     # TEST CASE: Secure cluster, dfs.http.policy=HTTPS_ONLY, https address defined and non secure
     # TEST CASE: Secure cluster, dfs.http.policy=HTTPS_ONLY, https address defined and non secure
@@ -232,7 +231,7 @@ class TestHDP22StackAdvisor(TestCase):
       }
       }
     }
     }
     expected = []
     expected = []
-    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations)
+    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations, None, None)
     self.assertEquals(validation_problems, expected)
     self.assertEquals(validation_problems, expected)
 
 
     # TEST CASE: Secure cluster, dfs.http.policy=HTTPS_ONLY, non secure dfs port, https property not defined
     # TEST CASE: Secure cluster, dfs.http.policy=HTTPS_ONLY, non secure dfs port, https property not defined
@@ -276,7 +275,7 @@ class TestHDP22StackAdvisor(TestCase):
                             "order to be able to use HTTPS.",
                             "order to be able to use HTTPS.",
                  'type': 'configuration'}
                  'type': 'configuration'}
     ]
     ]
-    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations)
+    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations, None, None)
     self.assertEquals(validation_problems, expected)
     self.assertEquals(validation_problems, expected)
 
 
 
 
@@ -321,7 +320,7 @@ class TestHDP22StackAdvisor(TestCase):
                             "able to use HTTPS.",
                             "able to use HTTPS.",
                  'type': 'configuration'}
                  'type': 'configuration'}
     ]
     ]
-    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations)
+    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations, None, None)
     self.assertEquals(validation_problems, expected)
     self.assertEquals(validation_problems, expected)
 
 
     # TEST CASE: Secure cluster, dfs.http.policy=HTTPS_ONLY, valid non-root configuration
     # TEST CASE: Secure cluster, dfs.http.policy=HTTPS_ONLY, valid non-root configuration
@@ -340,7 +339,7 @@ class TestHDP22StackAdvisor(TestCase):
       }
       }
     }
     }
     expected = []
     expected = []
-    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations)
+    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations, None, None)
     self.assertEquals(validation_problems, expected)
     self.assertEquals(validation_problems, expected)
 
 
     # TEST CASE: Secure cluster, dfs.http.policy=HTTP_ONLY, insecure port
     # TEST CASE: Secure cluster, dfs.http.policy=HTTP_ONLY, insecure port
@@ -376,7 +375,7 @@ class TestHDP22StackAdvisor(TestCase):
                             "['dfs.datanode.address', 'dfs.datanode.http.address'] use secure ports.",
                             "['dfs.datanode.address', 'dfs.datanode.http.address'] use secure ports.",
                  'type': 'configuration'}
                  'type': 'configuration'}
                 ]
                 ]
-    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations)
+    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations, None, None)
     self.assertEquals(validation_problems, expected)
     self.assertEquals(validation_problems, expected)
 
 
     # TEST CASE: Secure cluster, dfs.http.policy=HTTP_ONLY, valid configuration
     # TEST CASE: Secure cluster, dfs.http.policy=HTTP_ONLY, valid configuration
@@ -394,7 +393,7 @@ class TestHDP22StackAdvisor(TestCase):
       }
       }
     }
     }
     expected = []
     expected = []
-    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations)
+    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations, None, None)
     self.assertEquals(validation_problems, expected)
     self.assertEquals(validation_problems, expected)
 
 
     # TEST CASE: Secure cluster, absent dfs.http.policy (typical situation)
     # TEST CASE: Secure cluster, absent dfs.http.policy (typical situation)
@@ -411,7 +410,7 @@ class TestHDP22StackAdvisor(TestCase):
       }
       }
     }
     }
     expected = []
     expected = []
-    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations)
+    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations, None, None)
     self.assertEquals(validation_problems, expected)
     self.assertEquals(validation_problems, expected)
 
 
     # TEST CASE: Secure cluster, dfs.http.policy=HTTP_ONLY, misusage of dfs.data.transfer.protection warning
     # TEST CASE: Secure cluster, dfs.http.policy=HTTP_ONLY, misusage of dfs.data.transfer.protection warning
@@ -435,7 +434,7 @@ class TestHDP22StackAdvisor(TestCase):
                  'message': "dfs.data.transfer.protection property can not be used when dfs.http.policy is "
                  'message': "dfs.data.transfer.protection property can not be used when dfs.http.policy is "
                             "set to any value other then HTTPS_ONLY. Tip: When dfs.http.policy property is not defined, it defaults to HTTP_ONLY",
                             "set to any value other then HTTPS_ONLY. Tip: When dfs.http.policy property is not defined, it defaults to HTTP_ONLY",
                  'type': 'configuration'}]
                  'type': 'configuration'}]
-    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations)
+    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations, None, None)
     self.assertEquals(validation_problems, expected)
     self.assertEquals(validation_problems, expected)
 
 
     # TEST CASE: Secure cluster, dfs.http.policy=HTTPS_ONLY, wrong dfs.data.transfer.protection value
     # TEST CASE: Secure cluster, dfs.http.policy=HTTPS_ONLY, wrong dfs.data.transfer.protection value
@@ -458,7 +457,7 @@ class TestHDP22StackAdvisor(TestCase):
                  'level': 'WARN',
                  'level': 'WARN',
                  'message': "Invalid property value: WRONG_VALUE. Valid values are ['authentication', 'integrity', 'privacy'].",
                  'message': "Invalid property value: WRONG_VALUE. Valid values are ['authentication', 'integrity', 'privacy'].",
                  'type': 'configuration'}]
                  'type': 'configuration'}]
-    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations)
+    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations, None, None)
     self.assertEquals(validation_problems, expected)
     self.assertEquals(validation_problems, expected)
 
 
     # TEST CASE: Hadoop wire encryption enabled
     # TEST CASE: Hadoop wire encryption enabled
@@ -477,7 +476,7 @@ class TestHDP22StackAdvisor(TestCase):
       }
       }
     }
     }
     expected = []  # No warnings
     expected = []  # No warnings
-    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations)
+    validation_problems = self.stackAdvisor.validateHDFSConfigurations(properties, recommendedDefaults, configurations, None, None)
     self.assertEquals(validation_problems, expected)
     self.assertEquals(validation_problems, expected)
 
 
   def test_recommendYARNConfigurations(self):
   def test_recommendYARNConfigurations(self):
@@ -498,5 +497,54 @@ class TestHDP22StackAdvisor(TestCase):
       }
       }
     }
     }
 
 
-    self.stackAdvisor.recommendYARNConfigurations(configurations, clusterData)
+    self.stackAdvisor.recommendYARNConfigurations(configurations, clusterData, None, None)
+    self.assertEquals(configurations, expected)
+
+  def test_recommendAmsConfigurations(self):
+    configurations = {}
+    clusterData = {}
+
+    services = {
+      "services":  [ {
+        "StackServices": {
+          "service_name": "AMS"
+        },"components": [{
+          "StackServiceComponents": {
+            "component_name": "METRIC_COLLECTOR",
+            "hostnames": ["host1"]
+          }
+
+        }]
+      }]
+    }
+    hosts = {
+      "items": [{
+        "Hosts": {
+          "host_name": "host1",
+
+        }
+      }]
+    }
+
+    expected = {
+      "ams-hbase-env": {
+        "properties": {
+          "hbase_master_heapsize": "1024m",
+          "hbase_regionserver_heapsize": "1024m",
+        }
+      },
+      "ams-hbase-site": {
+        "properties": {
+          "hbase.regionserver.global.memstore.lowerLimit": "0.4",
+          "hbase.regionserver.global.memstore.upperLimit": "0.5",
+          "hfile.block.cache.size": "0.3"
+        }
+      },
+      "ams-site": {
+        "properties": {
+          "timeline.metrics.host.aggregator.ttl": "86400"
+        }
+      }
+    }
+    self.stackAdvisor.recommendAmsConfigurations(configurations, clusterData, services, hosts)
     self.assertEquals(configurations, expected)
     self.assertEquals(configurations, expected)