Revert "AMBARI-18713 use exclude list of mount device types on docker 
containers (dsen)"


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/90967bcd
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/90967bcd
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/90967bcd

Branch: refs/heads/branch-feature-AMBARI-18634
Commit: 90967bcd0df7a5ab089611ee5502bb90d0084a0a
Parents: fbf636d
Author: Dmytro Sen <d...@apache.org>
Authored: Wed Nov 23 18:47:20 2016 +0200
Committer: Dmytro Sen <d...@apache.org>
Committed: Wed Nov 23 18:47:20 2016 +0200

----------------------------------------------------------------------
 .../src/main/resources/scripts/stack_advisor.py |  11 +-
 .../HDP/2.0.6/configuration/cluster-env.xml     |  10 -
 .../stacks/HDP/2.0.6/services/stack_advisor.py  |  50 +-
 .../stacks/HDP/2.1/services/stack_advisor.py    |  20 +-
 .../stacks/HDP/2.2/services/stack_advisor.py    |   7 -
 .../src/main/resources/stacks/stack_advisor.py  | 200 +-------
 .../stacks/2.0.6/common/test_stack_advisor.py   |  34 +-
 .../stacks/2.1/common/test_stack_advisor.py     |   5 -
 .../stacks/2.2/common/test_stack_advisor.py     |  20 +-
 .../test/python/stacks/test_stack_adviser.py    | 239 ----------
 ambari-web/app/mixins.js                        |   1 +
 .../app/utils/configs/config_initializer.js     |  28 +-
 .../mount_points_based_initializer_mixin.js     | 340 ++++++++++++++
 ambari-web/test/utils/ajax/ajax_test.js         |   9 +-
 .../utils/configs/config_initializer_test.js    | 458 +++++++++++++++++++
 15 files changed, 855 insertions(+), 577 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/90967bcd/ambari-server/src/main/resources/scripts/stack_advisor.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/scripts/stack_advisor.py 
b/ambari-server/src/main/resources/scripts/stack_advisor.py
index abfab87..5926c39 100755
--- a/ambari-server/src/main/resources/scripts/stack_advisor.py
+++ b/ambari-server/src/main/resources/scripts/stack_advisor.py
@@ -70,11 +70,13 @@ def main(argv=None):
   if len(args) < 3:
     sys.stderr.write(USAGE)
     sys.exit(2)
+    pass
 
   action = args[0]
   if action not in ALL_ACTIONS:
     sys.stderr.write(USAGE)
     sys.exit(2)
+    pass
 
   hostsFile = args[1]
   servicesFile = args[2]
@@ -87,7 +89,6 @@ def main(argv=None):
   stackName = services["Versions"]["stack_name"]
   stackVersion = services["Versions"]["stack_version"]
   parentVersions = []
-
   if "stack_hierarchy" in services["Versions"]:
     parentVersions = services["Versions"]["stack_hierarchy"]["stack_versions"]
 
@@ -95,9 +96,8 @@ def main(argv=None):
 
   # Perform action
   actionDir = os.path.realpath(os.path.dirname(args[1]))
-
-  # filter
-  hosts = stackAdvisor.filterHostMounts(hosts, services)
+  result = {}
+  result_file = "non_valid_result_file.json"
 
   if action == RECOMMEND_COMPONENT_LAYOUT_ACTION:
     result = stackAdvisor.recommendComponentLayout(services, hosts)
@@ -111,11 +111,12 @@ def main(argv=None):
   elif action == RECOMMEND_CONFIGURATION_DEPENDENCIES:
     result = stackAdvisor.recommendConfigurationDependencies(services, hosts)
     result_file = os.path.join(actionDir, "configurations.json")
-  else:  # action == VALIDATE_CONFIGURATIONS
+  else: # action == VALIDATE_CONFIGURATIONS
     result = stackAdvisor.validateConfigurations(services, hosts)
     result_file = os.path.join(actionDir, "configurations-validation.json")
 
   dumpJson(result, result_file)
+  pass
 
 
 def instantiateStackAdvisor(stackName, stackVersion, parentVersions):

http://git-wip-us.apache.org/repos/asf/ambari/blob/90967bcd/ambari-server/src/main/resources/stacks/HDP/2.0.6/configuration/cluster-env.xml
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/resources/stacks/HDP/2.0.6/configuration/cluster-env.xml
 
b/ambari-server/src/main/resources/stacks/HDP/2.0.6/configuration/cluster-env.xml
index bf257a3..0d313cc 100644
--- 
a/ambari-server/src/main/resources/stacks/HDP/2.0.6/configuration/cluster-env.xml
+++ 
b/ambari-server/src/main/resources/stacks/HDP/2.0.6/configuration/cluster-env.xml
@@ -274,14 +274,4 @@ gpgcheck=0</value>
     <description>For properties handled by handle_mounted_dirs this will make 
Ambari </description>
     <on-ambari-upgrade add="true"/>
   </property>
-  <property>
-    <name>agent_mounts_ignore_list</name>
-    <value/>
-    <description>Comma separated list of the mounts which would be ignored by 
Ambari during property values suggestion by Stack Adviser</description>
-    <on-ambari-upgrade add="true"/>
-    <value-attributes>
-      <visible>true</visible>
-      <empty-value-valid>true</empty-value-valid>
-    </value-attributes>
-  </property>
 </configuration>

http://git-wip-us.apache.org/repos/asf/ambari/blob/90967bcd/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/stack_advisor.py
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/stack_advisor.py 
b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/stack_advisor.py
index 9b5ff68..83014b7 100644
--- 
a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/stack_advisor.py
+++ 
b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/stack_advisor.py
@@ -101,23 +101,9 @@ class HDP206StackAdvisor(DefaultStackAdvisor):
       "HBASE": self.recommendHbaseConfigurations,
       "STORM": self.recommendStormConfigurations,
       "AMBARI_METRICS": self.recommendAmsConfigurations,
-      "RANGER": self.recommendRangerConfigurations,
-      "ZOOKEEPER": self.recommendZookeeperConfigurations,
-      "OOZIE": self.recommendOozieConfigurations
+      "RANGER": self.recommendRangerConfigurations
     }
 
-  def recommendOozieConfigurations(self, configurations, clusterData, 
services, hosts):
-    oozie_mount_properties = [
-      ("oozie_data_dir", "OOZIE_SERVER", "/hadoop/oozie/data", "single"),
-    ]
-    self.updateMountProperties("oozie-env", oozie_mount_properties, 
configurations, services, hosts)
-
-  def recommendZookeeperConfigurations(self, configurations, clusterData, 
services, hosts):
-    zk_mount_properties = [
-      ("dataDir", "ZOOKEEPER_SERVER", "/hadoop/zookeeper", "single"),
-    ]
-    self.updateMountProperties("zoo.cfg", zk_mount_properties, configurations, 
services, hosts)
-
   def recommendYARNConfigurations(self, configurations, clusterData, services, 
hosts):
     putYarnProperty = self.putProperty(configurations, "yarn-site", services)
     putYarnPropertyAttribute = self.putPropertyAttribute(configurations, 
"yarn-site")
@@ -130,15 +116,6 @@ class HDP206StackAdvisor(DefaultStackAdvisor):
     putYarnProperty('yarn.scheduler.maximum-allocation-mb', 
int(configurations["yarn-site"]["properties"]["yarn.nodemanager.resource.memory-mb"]))
     putYarnEnvProperty('min_user_id', self.get_system_min_uid())
 
-    yarn_mount_properties = [
-      ("yarn.nodemanager.local-dirs", "NODEMANAGER", "/hadoop/yarn/local", 
"multi"),
-      ("yarn.nodemanager.log-dirs", "NODEMANAGER", "/hadoop/yarn/log", 
"multi"),
-      ("yarn.timeline-service.leveldb-timeline-store.path", 
"APP_TIMELINE_SERVER", "/hadoop/yarn/timeline", "single"),
-      ("yarn.timeline-service.leveldb-state-store.path", 
"APP_TIMELINE_SERVER", "/hadoop/yarn/timeline", "single")
-    ]
-
-    self.updateMountProperties("yarn-site", yarn_mount_properties, 
configurations, services, hosts)
-
     sc_queue_name = self.recommendYarnQueue(services, "yarn-env", 
"service_check.queue.name")
     if sc_queue_name is not None:
       putYarnEnvProperty("service_check.queue.name", sc_queue_name)
@@ -169,13 +146,6 @@ class HDP206StackAdvisor(DefaultStackAdvisor):
     putMapredProperty('mapreduce.map.java.opts', "-Xmx" + str(int(round(0.8 * 
clusterData['mapMemory']))) + "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))
-
-    mapred_mounts = [
-      ("mapred.local.dir", ["TASKTRACKER", "NODEMANAGER"], "/hadoop/mapred", 
"multi")
-    ]
-
-    self.updateMountProperties("mapred-site", mapred_mounts, configurations, 
services, hosts)
-
     mr_queue = self.recommendYarnQueue(services, "mapred-site", 
"mapreduce.job.queuename")
     if mr_queue is not None:
       putMapredProperty("mapreduce.job.queuename", mr_queue)
@@ -423,18 +393,12 @@ class HDP206StackAdvisor(DefaultStackAdvisor):
       if len(namenodes.split(',')) > 1:
         putHDFSSitePropertyAttributes("dfs.namenode.rpc-address", "delete", 
"true")
 
-    hdfs_mount_properties = [
-      ("dfs.datanode.data.dir", "DATANODE", "/hadoop/hdfs/data", "multi"),
-      ("dfs.name.dir", "NAMENODE", "/hadoop/hdfs/namenode", "multi"),
-      ("dfs.namenode.name.dir", "DATANODE", "/hadoop/hdfs/namenode", "multi"),
-      ("dfs.data.dir", "DATANODE", "/hadoop/hdfs/data", "multi"),
-      ("fs.checkpoint.dir", "SECONDARY_NAMENODE", 
"/hadoop/hdfs/namesecondary", "single"),
-      ("dfs.namenode.checkpoint.dir", "SECONDARY_NAMENODE", 
"/hadoop/hdfs/namesecondary", "single")
-    ]
-
-    self.updateMountProperties("hdfs-site", hdfs_mount_properties, 
configurations, services, hosts)
-
-    dataDirs = hdfsSiteProperties['dfs.datanode.data.dir'].split(",")
+    #Initialize default 'dfs.datanode.data.dir' if needed
+    if (not hdfsSiteProperties) or ('dfs.datanode.data.dir' not in 
hdfsSiteProperties):
+      dataDirs = '/hadoop/hdfs/data'
+      putHDFSSiteProperty('dfs.datanode.data.dir', dataDirs)
+    else:
+      dataDirs = hdfsSiteProperties['dfs.datanode.data.dir'].split(",")
 
     # dfs.datanode.du.reserved should be set to 10-15% of volume size
     # For each host selects maximum size of the volume. Then gets minimum for 
all hosts.

http://git-wip-us.apache.org/repos/asf/ambari/blob/90967bcd/ambari-server/src/main/resources/stacks/HDP/2.1/services/stack_advisor.py
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/resources/stacks/HDP/2.1/services/stack_advisor.py 
b/ambari-server/src/main/resources/stacks/HDP/2.1/services/stack_advisor.py
index 17225d0..9678dc1 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.1/services/stack_advisor.py
+++ b/ambari-server/src/main/resources/stacks/HDP/2.1/services/stack_advisor.py
@@ -24,30 +24,12 @@ class HDP21StackAdvisor(HDP206StackAdvisor):
     childRecommendConfDict = {
       "OOZIE": self.recommendOozieConfigurations,
       "HIVE": self.recommendHiveConfigurations,
-      "TEZ": self.recommendTezConfigurations,
-      "STORM": self.recommendStormConfigurations,
-      "FALCON": self.recommendFalconConfigurations
+      "TEZ": self.recommendTezConfigurations
     }
     parentRecommendConfDict.update(childRecommendConfDict)
     return parentRecommendConfDict
 
-  def recommendStormConfigurations(self, configurations, clusterData, 
services, hosts):
-    storm_mounts = [
-      ("storm.local.dir", ["NODEMANAGER", "NIMBUS"], "/hadoop/storm", "single")
-    ]
-
-    self.updateMountProperties("storm-site", storm_mounts, configurations, 
services, hosts)
-
-  def recommendFalconConfigurations(self, configurations, clusterData, 
services, hosts):
-    falcon_mounts = [
-      ("*.falcon.graph.storage.directory", "FALCON_SERVER", 
"/hadoop/falcon/data/lineage/graphdb", "single")
-    ]
-
-    self.updateMountProperties("falcon-startup.properties", falcon_mounts, 
configurations, services, hosts)
-
   def recommendOozieConfigurations(self, configurations, clusterData, 
services, hosts):
-    super(HDP21StackAdvisor, 
self).recommendOozieConfigurations(configurations, clusterData, services, hosts)
-
     oozieSiteProperties = getSiteProperties(services['configurations'], 
'oozie-site')
     oozieEnvProperties = getSiteProperties(services['configurations'], 
'oozie-env')
     putOozieProperty = self.putProperty(configurations, "oozie-site", services)

http://git-wip-us.apache.org/repos/asf/ambari/blob/90967bcd/ambari-server/src/main/resources/stacks/HDP/2.2/services/stack_advisor.py
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/resources/stacks/HDP/2.2/services/stack_advisor.py 
b/ambari-server/src/main/resources/stacks/HDP/2.2/services/stack_advisor.py
index feafc04..a8a75e5 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.2/services/stack_advisor.py
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/stack_advisor.py
@@ -44,17 +44,10 @@ class HDP22StackAdvisor(HDP21StackAdvisor):
       "RANGER": self.recommendRangerConfigurations,
       "LOGSEARCH" : self.recommendLogsearchConfigurations,
       "SPARK": self.recommendSparkConfigurations,
-      "KAFKA": self.recommendKafkaConfigurations,
     }
     parentRecommendConfDict.update(childRecommendConfDict)
     return parentRecommendConfDict
 
-  def recommendKafkaConfigurations(self, configurations, clusterData, 
services, hosts):
-    kafka_mounts = [
-      ("log.dirs", "KAFKA_BROKER", "/kafka-logs", "multi")
-    ]
-
-    self.updateMountProperties("kafka-broker", kafka_mounts, configurations, 
services, hosts)
 
   def recommendSparkConfigurations(self, configurations, clusterData, 
services, hosts):
     """

http://git-wip-us.apache.org/repos/asf/ambari/blob/90967bcd/ambari-server/src/main/resources/stacks/stack_advisor.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/stack_advisor.py 
b/ambari-server/src/main/resources/stacks/stack_advisor.py
index 66d1387..f6191f8 100644
--- a/ambari-server/src/main/resources/stacks/stack_advisor.py
+++ b/ambari-server/src/main/resources/stacks/stack_advisor.py
@@ -972,18 +972,6 @@ class DefaultStackAdvisor(StackAdvisor):
       return None
     return siteConfig.get("properties")
 
-  def getServicesSiteProperties(self, services, siteName):
-    if not services:
-      return None
-
-    configurations = services.get("configurations")
-    if not configurations:
-      return None
-    siteConfig = configurations.get(siteName)
-    if siteConfig is None:
-      return None
-    return siteConfig.get("properties")
-
   def putProperty(self, config, configType, services=None):
     userConfigs = {}
     changedConfigs = []
@@ -1052,27 +1040,14 @@ class DefaultStackAdvisor(StackAdvisor):
       config[configType]["property_attributes"][key][attribute] = 
attributeValue if isinstance(attributeValue, list) else str(attributeValue)
     return appendPropertyAttribute
 
+
+  """
+  Returns the hosts which are running the given component.
+  """
   def getHosts(self, componentsList, componentName):
-    """
-    Returns the hosts which are running the given component.
-    """
     hostNamesList = [component["hostnames"] for component in componentsList if 
component["component_name"] == componentName]
     return hostNamesList[0] if len(hostNamesList) > 0 else []
 
-  def getMountPoints(self, hosts):
-    """
-    Return list of mounts available on the hosts
-
-    :type hosts dict
-    """
-    mount_points = []
-
-    for item in hosts["items"]:
-      if "disk_info" in item["Hosts"]:
-        mount_points.append(item["Hosts"]["disk_info"])
-
-    return mount_points
-
   def isSecurityEnabled(self, services):
     """
     Determines if security is enabled by testing the value of 
cluster-env/security enabled.
@@ -1109,170 +1084,3 @@ class DefaultStackAdvisor(StackAdvisor):
 
   def getServiceNames(self, services):
     return [service["StackServices"]["service_name"] for service in 
services["services"]]
-
-  def filterHostMounts(self, hosts, services):
-    """
-    Filter mounts on the host using agent_mounts_ignore_list, by excluding and 
record with mount-point
-     mentioned in agent_mounts_ignore_list.
-
-    This function updates hosts dictionary
-
-    Example:
-
-      agent_mounts_ignore_list : "/run/secrets"
-
-      Hosts record :
-
-       "disk_info" : [
-          {
-              ...
-            "mountpoint" : "/"
-          },
-          {
-              ...
-            "mountpoint" : "/run/secrets"
-          }
-        ]
-
-      Result would be :
-
-        "disk_info" : [
-          {
-              ...
-            "mountpoint" : "/"
-          }
-        ]
-
-    :type hosts dict
-    :type services dict
-    """
-    if not services:
-      return hosts
-
-    cluster_env = self.getServicesSiteProperties(services, "cluster-env")
-    ignore_list = []
-
-    if not cluster_env or "items" not in hosts:
-      return hosts
-
-    if "agent_mounts_ignore_list" in cluster_env and 
cluster_env["agent_mounts_ignore_list"].strip():
-      ignore_list = [x.strip() for x in 
cluster_env["agent_mounts_ignore_list"].strip().split(",")]
-
-    for host in hosts["items"]:
-      if "Hosts" not in host and "disk_info" not in host["Hosts"]:
-        continue
-
-      host = host["Hosts"]
-      host["disk_info"] = [disk for disk in host["disk_info"] if 
disk["mountpoint"] not in ignore_list]
-
-    return hosts
-
-  def __getSameHostMounts(self, hosts):
-    """
-    Return list of the mounts which are same and present on all hosts
-
-    :type hosts dict
-    :rtype list
-    """
-    if not hosts:
-      return None
-
-    hostMounts = self.getMountPoints(hosts)
-    mounts = []
-    for m in hostMounts:
-      host_mounts = set([item["mountpoint"] for item in m])
-      mounts = host_mounts if not mounts else mounts & host_mounts
-
-    return sorted(mounts)
-
-  def getMountPathVariations(self, initial_value, component_name, services, 
hosts):
-    """
-    Recommends best fitted mount by prefixing path with it.
-
-    :return return list of paths with properly selected paths. If no 
recommendation possible,
-     would be returned empty list
-
-    :type initial_value str
-    :type component_name str
-    :type services dict
-    :type hosts dict
-    :rtype list
-    """
-    available_mounts = []
-
-    if not initial_value:
-      return available_mounts
-
-    mounts = self.__getSameHostMounts(hosts)
-    sep = "/"
-
-    if not mounts:
-      return available_mounts
-
-    for mount in mounts:
-      new_mount = initial_value if mount == "/" else os.path.join(mount + sep, 
initial_value.lstrip(sep))
-      if new_mount not in available_mounts:
-        available_mounts.append(new_mount)
-
-    # no list transformations after filling the list, because this will cause 
item order change
-    return available_mounts
-
-  def getMountPathVariation(self, initial_value, component_name, services, 
hosts):
-    """
-    Recommends best fitted mount by prefixing path with it.
-
-    :return return list of paths with properly selected paths. If no 
recommendation possible,
-     would be returned empty list
-
-    :type initial_value str
-        :type component_name str
-    :type services dict
-    :type hosts dict
-    :rtype str
-    """
-    try:
-      return [self.getMountPathVariations(initial_value, component_name, 
services, hosts)[0]]
-    except IndexError:
-      return []
-
-  def updateMountProperties(self, siteConfig, propertyDefinitions, 
configurations,  services, hosts):
-    """
-    Update properties according to recommendations for available mount-points
-
-    propertyDefinitions is an array of set : property name, component name, 
initial value, recommendation type
-
-     Where,
-
-       property name - name of the property
-       component name, name of the component to which belongs this property
-       initial value - initial path
-       recommendation type - could be "multi" or "single". This describes 
recommendation strategy, to use only one disk
-        or use all available space on the host
-
-    :type propertyDefinitions list
-    :type siteConfig str
-    :type configurations dict
-    :type services dict
-    :type hosts dict
-    """
-
-    props = self.getServicesSiteProperties(services, siteConfig)
-    put_f = self.putProperty(configurations, siteConfig, services)
-
-    for prop_item in propertyDefinitions:
-      name, component, default_value, rc_type = prop_item
-      recommendation = None
-
-      if props is None or name not in props:
-        if rc_type == "multi":
-          recommendation = self.getMountPathVariations(default_value, 
component, services, hosts)
-        else:
-          recommendation = self.getMountPathVariation(default_value, 
component, services, hosts)
-      elif props and name in props and props[name] == default_value:
-        if rc_type == "multi":
-          recommendation = self.getMountPathVariations(default_value, 
component, services, hosts)
-        else:
-          recommendation = self.getMountPathVariation(default_value, 
component, services, hosts)
-
-      if recommendation:
-        put_f(name, ",".join(recommendation))

http://git-wip-us.apache.org/repos/asf/ambari/blob/90967bcd/ambari-server/src/test/python/stacks/2.0.6/common/test_stack_advisor.py
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/python/stacks/2.0.6/common/test_stack_advisor.py 
b/ambari-server/src/test/python/stacks/2.0.6/common/test_stack_advisor.py
index 00ee563..9595b9e 100644
--- a/ambari-server/src/test/python/stacks/2.0.6/common/test_stack_advisor.py
+++ b/ambari-server/src/test/python/stacks/2.0.6/common/test_stack_advisor.py
@@ -1195,13 +1195,8 @@ class TestHDP206StackAdvisor(TestCase):
                   {'properties':
                      {'falcon_user': 'falcon'}},
                 'hdfs-site':
-                  {'properties':
-                     {'dfs.data.dir': '/hadoop/hdfs/data',
-                      'dfs.datanode.data.dir': '/hadoop/hdfs/data',
-                      'fs.checkpoint.dir': '/hadoop/hdfs/namesecondary',
-                      'dfs.namenode.name.dir': '/hadoop/hdfs/namenode',
-                      'dfs.name.dir': '/hadoop/hdfs/namenode',
-                      'dfs.namenode.checkpoint.dir': 
'/hadoop/hdfs/namesecondary',
+                  {'properties': 
+                     {'dfs.datanode.data.dir': '/hadoop/hdfs/data',
                       'dfs.datanode.du.reserved': '10240000000'}},
                 'hive-env':
                   {'properties':
@@ -1334,12 +1329,7 @@ class TestHDP206StackAdvisor(TestCase):
                      {'falcon_user': 'falcon'}},
                 'hdfs-site':
                   {'properties':
-                     {'dfs.data.dir': '/hadoop/hdfs/data',
-                      'dfs.datanode.data.dir': '/hadoop/hdfs/data',
-                      'fs.checkpoint.dir': '/hadoop/hdfs/namesecondary',
-                      'dfs.namenode.name.dir': '/hadoop/hdfs/namenode',
-                      'dfs.name.dir': '/hadoop/hdfs/namenode',
-                      'dfs.namenode.checkpoint.dir': 
'/hadoop/hdfs/namesecondary',
+                     {'dfs.datanode.data.dir': '/hadoop/hdfs/data',
                       'dfs.datanode.du.reserved': '10240000000'}},
                 'hive-env':
                   {'properties':
@@ -1473,13 +1463,8 @@ class TestHDP206StackAdvisor(TestCase):
                      {'hive_user': 'hive',
                       'webhcat_user': 'webhcat'}},
                 'hdfs-site':
-                  {'properties':
-                     {'dfs.data.dir': '/hadoop/hdfs/data',
-                      'dfs.datanode.data.dir': '/hadoop/hdfs/data',
-                      'fs.checkpoint.dir': '/hadoop/hdfs/namesecondary',
-                      'dfs.namenode.name.dir': '/hadoop/hdfs/namenode',
-                      'dfs.name.dir': '/hadoop/hdfs/namenode',
-                      'dfs.namenode.checkpoint.dir': 
'/hadoop/hdfs/namesecondary',
+                  {'properties': 
+                     {'dfs.datanode.data.dir': '/hadoop/hdfs/data',
                       'dfs.datanode.du.reserved': '10240000000'}},
                 'hadoop-env':
                   {'properties':
@@ -1499,15 +1484,10 @@ class TestHDP206StackAdvisor(TestCase):
 
     expected["hdfs-site"] = {
       'properties': {
+        'dfs.datanode.data.dir': '/hadoop/hdfs/data',
         'dfs.datanode.du.reserved': '10240000000',
         'dfs.internal.nameservices': 'mycluster',
-        'dfs.ha.namenodes.mycluster': 'nn1,nn2',
-        'dfs.data.dir': '/hadoop/hdfs/data',
-        'dfs.datanode.data.dir': '/hadoop/hdfs/data',
-        'fs.checkpoint.dir': '/hadoop/hdfs/namesecondary',
-        'dfs.namenode.name.dir': '/hadoop/hdfs/namenode',
-        'dfs.name.dir': '/hadoop/hdfs/namenode',
-        'dfs.namenode.checkpoint.dir': '/hadoop/hdfs/namesecondary',
+        'dfs.ha.namenodes.mycluster': 'nn1,nn2'
       },
       'property_attributes': {
         'dfs.namenode.rpc-address': {

http://git-wip-us.apache.org/repos/asf/ambari/blob/90967bcd/ambari-server/src/test/python/stacks/2.1/common/test_stack_advisor.py
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/python/stacks/2.1/common/test_stack_advisor.py 
b/ambari-server/src/test/python/stacks/2.1/common/test_stack_advisor.py
index a9b36b1..7835262 100644
--- a/ambari-server/src/test/python/stacks/2.1/common/test_stack_advisor.py
+++ b/ambari-server/src/test/python/stacks/2.1/common/test_stack_advisor.py
@@ -486,12 +486,7 @@ class TestHDP21StackAdvisor(TestCase):
       },
       "hdfs-site": {
         "properties": {
-          'dfs.data.dir': '/hadoop/hdfs/data',
           'dfs.datanode.data.dir': '/hadoop/hdfs/data',
-          'fs.checkpoint.dir': '/hadoop/hdfs/namesecondary',
-          'dfs.namenode.name.dir': '/hadoop/hdfs/namenode',
-          'dfs.name.dir': '/hadoop/hdfs/namenode',
-          'dfs.namenode.checkpoint.dir': '/hadoop/hdfs/namesecondary',
           'dfs.datanode.du.reserved': '10240000000'
         }
       }

http://git-wip-us.apache.org/repos/asf/ambari/blob/90967bcd/ambari-server/src/test/python/stacks/2.2/common/test_stack_advisor.py
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/python/stacks/2.2/common/test_stack_advisor.py 
b/ambari-server/src/test/python/stacks/2.2/common/test_stack_advisor.py
index 53c92ae..3cd05d3 100644
--- a/ambari-server/src/test/python/stacks/2.2/common/test_stack_advisor.py
+++ b/ambari-server/src/test/python/stacks/2.2/common/test_stack_advisor.py
@@ -3068,12 +3068,7 @@ class TestHDP22StackAdvisor(TestCase):
           'dfs.namenode.safemode.threshold-pct': '1.000',
           'dfs.datanode.failed.volumes.tolerated': '1',
           'dfs.namenode.handler.count': '25',
-          'dfs.datanode.data.dir': '/path/1,/path/2,/path/3,/path/4',
-          'dfs.data.dir': '/hadoop/hdfs/data',
-          'fs.checkpoint.dir': '/hadoop/hdfs/namesecondary',
-          'dfs.namenode.name.dir': '/hadoop/hdfs/namenode',
-          'dfs.name.dir': '/hadoop/hdfs/namenode',
-          'dfs.namenode.checkpoint.dir': '/hadoop/hdfs/namesecondary'
+          'dfs.datanode.data.dir': '/path/1,/path/2,/path/3,/path/4'
         },
         'property_attributes': {
           'dfs.datanode.failed.volumes.tolerated': {'maximum': '4'},
@@ -3748,11 +3743,7 @@ class TestHDP22StackAdvisor(TestCase):
           "yarn.nodemanager.linux-container-executor.cgroups.hierarchy": 
"/yarn",
           "yarn.scheduler.maximum-allocation-mb": "39424",
           "yarn.nodemanager.linux-container-executor.resources-handler.class": 
"org.apache.hadoop.yarn.server.nodemanager.util.CgroupsLCEResourcesHandler",
-          "hadoop.registry.rm.enabled": "false",
-          "yarn.timeline-service.leveldb-state-store.path": 
"/hadoop/yarn/timeline",
-          "yarn.timeline-service.leveldb-timeline-store.path": 
"/hadoop/yarn/timeline",
-          "yarn.nodemanager.local-dirs": 
"/hadoop/yarn/local,/dev/shm/hadoop/yarn/local,/vagrant/hadoop/yarn/local",
-          "yarn.nodemanager.log-dirs": 
"/hadoop/yarn/log,/dev/shm/hadoop/yarn/log,/vagrant/hadoop/yarn/log"
+          "hadoop.registry.rm.enabled": "false"
         },
         "property_attributes": {
           "yarn.scheduler.minimum-allocation-vcores": {
@@ -3798,6 +3789,7 @@ class TestHDP22StackAdvisor(TestCase):
           "yarn.nodemanager.linux-container-executor.group": "hadoop",
           "yarn.nodemanager.container-executor.class": 
"org.apache.hadoop.yarn.server.nodemanager.DefaultContainerExecutor",
           "yarn.nodemanager.linux-container-executor.cgroups.mount-path": 
"/cgroup",
+          "yarn.nodemanager.linux-container-executor.group": "hadoop",
           "yarn.nodemanager.linux-container-executor.cgroups.mount": "true",
           "yarn.nodemanager.resource.memory-mb": "39424",
           "yarn.scheduler.minimum-allocation-mb": "3584",
@@ -3807,11 +3799,7 @@ class TestHDP22StackAdvisor(TestCase):
           "yarn.nodemanager.linux-container-executor.cgroups.hierarchy": 
"/yarn",
           "yarn.scheduler.maximum-allocation-mb": "39424",
           "yarn.nodemanager.linux-container-executor.resources-handler.class": 
"org.apache.hadoop.yarn.server.nodemanager.util.CgroupsLCEResourcesHandler",
-          "hadoop.registry.rm.enabled": "false",
-          "yarn.timeline-service.leveldb-state-store.path": 
"/hadoop/yarn/timeline",
-          "yarn.timeline-service.leveldb-timeline-store.path": 
"/hadoop/yarn/timeline",
-          "yarn.nodemanager.local-dirs": 
"/hadoop/yarn/local,/dev/shm/hadoop/yarn/local,/vagrant/hadoop/yarn/local",
-          "yarn.nodemanager.log-dirs": 
"/hadoop/yarn/log,/dev/shm/hadoop/yarn/log,/vagrant/hadoop/yarn/log"
+          "hadoop.registry.rm.enabled": "false"
         },
         "property_attributes": {
           "yarn.nodemanager.linux-container-executor.cgroups.mount": {

http://git-wip-us.apache.org/repos/asf/ambari/blob/90967bcd/ambari-server/src/test/python/stacks/test_stack_adviser.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/python/stacks/test_stack_adviser.py 
b/ambari-server/src/test/python/stacks/test_stack_adviser.py
deleted file mode 100644
index 2c171f1..0000000
--- a/ambari-server/src/test/python/stacks/test_stack_adviser.py
+++ /dev/null
@@ -1,239 +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.
-"""
-
-import os
-from unittest import TestCase
-
-
-class TestBasicAdvisor(TestCase):
-  def setUp(self):
-    import imp
-    self.maxDiff = None
-    self.testDirectory = os.path.dirname(os.path.abspath(__file__))
-    stackAdvisorPath = os.path.abspath(os.path.join(self.testDirectory, 
'../../../main/resources/stacks/stack_advisor.py'))
-
-    default_sa_classname = 'DefaultStackAdvisor'
-
-    with open(stackAdvisorPath, 'rb') as fp:
-      stack_advisor_impl = imp.load_module('stack_advisor', fp, 
stackAdvisorPath, ('.py', 'rb', imp.PY_SOURCE))
-
-    clazz = getattr(stack_advisor_impl, default_sa_classname)
-    self.stackAdvisor = clazz()
-
-  def test_filterHostMounts(self):
-
-    filtered_mount = "/data"
-
-    hosts = {
-      "items": [
-        {
-          "Hosts": {
-            "cpu_count": 4,
-            "total_mem": 50331648,
-            "disk_info": [
-              {"mountpoint": "/"},
-              {"mountpoint": "/dev/shm"},
-              {"mountpoint": "/vagrant"},
-              {"mountpoint": "/dev/shm"},
-              {"mountpoint": "/vagrant"},
-              {"mountpoint": filtered_mount},
-            ],
-            "public_host_name": "c6401.ambari.apache.org",
-            "host_name": "c6401.ambari.apache.org"
-          },
-        },
-        {
-          "Hosts": {
-            "cpu_count": 4,
-            "total_mem": 50331648,
-            "disk_info": [
-              {"mountpoint": "/"},
-              {"mountpoint": "/dev/shm1"},
-              {"mountpoint": "/vagrant1"},
-              {"mountpoint": filtered_mount}
-            ],
-            "public_host_name": "c6402.ambari.apache.org",
-            "host_name": "c6402.ambari.apache.org"
-          },
-        }
-      ]
-    }
-
-    services = {
-      "Versions": {
-        "parent_stack_version": "2.5",
-        "stack_name": "HDP",
-        "stack_version": "2.6",
-        "stack_hierarchy": {
-          "stack_name": "HDP",
-          "stack_versions": ["2.5", "2.4", "2.3", "2.2", "2.1", "2.0.6"]
-        }
-      },
-      "services": [
-      ],
-      "configurations": {
-        "cluster-env": {
-          "properties": {
-            "agent_mounts_ignore_list": filtered_mount
-          }
-        }
-      }
-    }
-
-    filtered_hosts = self.stackAdvisor.filterHostMounts(hosts, services)
-
-    for host in filtered_hosts["items"]:
-      self.assertEquals(False, filtered_mount in host["Hosts"]["disk_info"])
-
-  def test_getMountPathVariations(self):
-
-    filtered_mount = "/data"
-
-    hosts = {
-      "items": [
-        {
-          "Hosts": {
-            "cpu_count": 4,
-            "total_mem": 50331648,
-            "disk_info": [
-              {"mountpoint": "/"},
-              {"mountpoint": "/dev/shm"},
-              {"mountpoint": "/vagrant"},
-              {"mountpoint": "/dev/shm"},
-              {"mountpoint": "/vagrant"},
-              {"mountpoint": filtered_mount},
-            ],
-            "public_host_name": "c6401.ambari.apache.org",
-            "host_name": "c6401.ambari.apache.org"
-          },
-        },
-        {
-          "Hosts": {
-            "cpu_count": 4,
-            "total_mem": 50331648,
-            "disk_info": [
-              {"mountpoint": "/"},
-              {"mountpoint": "/dev/shm1"},
-              {"mountpoint": "/vagrant1"},
-              {"mountpoint": filtered_mount}
-            ],
-            "public_host_name": "c6402.ambari.apache.org",
-            "host_name": "c6402.ambari.apache.org"
-          },
-        }
-      ]
-    }
-
-    services = {
-      "Versions": {
-        "parent_stack_version": "2.5",
-        "stack_name": "HDP",
-        "stack_version": "2.6",
-        "stack_hierarchy": {
-          "stack_name": "HDP",
-          "stack_versions": ["2.5", "2.4", "2.3", "2.2", "2.1", "2.0.6"]
-        }
-      },
-      "services": [
-      ],
-      "configurations": {
-        "cluster-env": {
-          "properties": {
-            "agent_mounts_ignore_list": filtered_mount
-          }
-        }
-      }
-    }
-
-    hosts = self.stackAdvisor.filterHostMounts(hosts, services)
-    avail_mounts = self.stackAdvisor.getMountPathVariations("/test/folder", 
"DATANODE", services, hosts)
-
-    self.assertEquals(True, avail_mounts is not None)
-    self.assertEquals(1, len(avail_mounts))
-    self.assertEquals("/test/folder", avail_mounts[0])
-
-  def test_updateMountProperties(self):
-    hosts = {
-      "items": [
-        {
-          "Hosts": {
-            "cpu_count": 4,
-            "total_mem": 50331648,
-            "disk_info": [
-              {"mountpoint": "/"},
-              {"mountpoint": "/dev/shm"},
-              {"mountpoint": "/vagrant"},
-              {"mountpoint": "/dev/shm"},
-              {"mountpoint": "/vagrant"},
-              {"mountpoint": "/data"},
-            ],
-            "public_host_name": "c6401.ambari.apache.org",
-            "host_name": "c6401.ambari.apache.org"
-          },
-        },
-        {
-          "Hosts": {
-            "cpu_count": 4,
-            "total_mem": 50331648,
-            "disk_info": [
-              {"mountpoint": "/"},
-              {"mountpoint": "/me"},
-              {"mountpoint": "/dev/shm1"},
-              {"mountpoint": "/vagrant1"},
-              {"mountpoint": "/data"}
-            ],
-            "public_host_name": "c6402.ambari.apache.org",
-            "host_name": "c6402.ambari.apache.org"
-          },
-        }
-      ]
-    }
-
-    services = {
-      "Versions": {
-        "parent_stack_version": "2.5",
-        "stack_name": "HDP",
-        "stack_version": "2.6",
-        "stack_hierarchy": {
-          "stack_name": "HDP",
-          "stack_versions": ["2.5", "2.4", "2.3", "2.2", "2.1", "2.0.6"]
-        }
-      },
-      "services": [
-      ],
-      "configurations": {
-        "cluster-env": {
-          "properties": {
-            "agent_mounts_ignore_list": ""
-          }
-        },
-        "some-site": {
-          "path_prop": "/test"
-        }
-      }
-    }
-
-    pathProperties = [
-      ("path_prop", "DATANODE", "/test", "multi"),
-    ]
-
-    configurations = {}
-
-    self.stackAdvisor.updateMountProperties("some-site", pathProperties, 
configurations, services, hosts)
-
-    self.assertEquals("/test,/data/test", 
configurations["some-site"]["properties"]["path_prop"])

http://git-wip-us.apache.org/repos/asf/ambari/blob/90967bcd/ambari-web/app/mixins.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins.js b/ambari-web/app/mixins.js
index 7b4d6b4..594ed74 100644
--- a/ambari-web/app/mixins.js
+++ b/ambari-web/app/mixins.js
@@ -69,3 +69,4 @@ require('mixins/common/widgets/widget_mixin');
 require('mixins/common/widgets/widget_section');
 require('mixins/unit_convert/base_unit_convert_mixin');
 require('mixins/unit_convert/convert_unit_widget_view_mixin');
+require('utils/configs/mount_points_based_initializer_mixin');

http://git-wip-us.apache.org/repos/asf/ambari/blob/90967bcd/ambari-web/app/utils/configs/config_initializer.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/configs/config_initializer.js 
b/ambari-web/app/utils/configs/config_initializer.js
index de9ca7e..cb5b41f 100644
--- a/ambari-web/app/utils/configs/config_initializer.js
+++ b/ambari-web/app/utils/configs/config_initializer.js
@@ -20,6 +20,7 @@ var App = require('app');
 var stringUtils = require('utils/string_utils');
 
 require('utils/configs/config_initializer_class');
+require('utils/configs/mount_points_based_initializer_mixin');
 require('utils/configs/hosts_based_initializer_mixin');
 
 /**
@@ -52,7 +53,7 @@ function getZKBasedConfig() {
  *
  * @instance ConfigInitializer
  */
-App.ConfigInitializer = 
App.ConfigInitializerClass.create(App.HostsBasedInitializerMixin, {
+App.ConfigInitializer = 
App.ConfigInitializerClass.create(App.MountPointsBasedInitializerMixin, 
App.HostsBasedInitializerMixin, {
 
   initializers: function() {
     return {
@@ -110,7 +111,26 @@ App.ConfigInitializer = 
App.ConfigInitializerClass.create(App.HostsBasedInitiali
       'templeton.zookeeper.hosts': getZKBasedConfig(),
       'hadoop.registry.zk.quorum': getZKBasedConfig(),
       'hive.cluster.delegation.token.store.zookeeper.connectString': 
getZKBasedConfig(),
-      'instance.zookeeper.host': getZKBasedConfig()
+      'instance.zookeeper.host': getZKBasedConfig(),
+
+      'dfs.name.dir': this.getMultipleMountPointsConfig('NAMENODE', 'file'),
+      'dfs.namenode.name.dir': this.getMultipleMountPointsConfig('NAMENODE', 
'file'),
+      'dfs.data.dir': this.getMultipleMountPointsConfig('DATANODE', 'file'),
+      'dfs.datanode.data.dir': this.getMultipleMountPointsConfig('DATANODE', 
'file'),
+      'yarn.nodemanager.local-dirs': 
this.getMultipleMountPointsConfig('NODEMANAGER'),
+      'yarn.nodemanager.log-dirs': 
this.getMultipleMountPointsConfig('NODEMANAGER'),
+      'mapred.local.dir': this.getMultipleMountPointsConfig(['TASKTRACKER', 
'NODEMANAGER']),
+      'log.dirs': this.getMultipleMountPointsConfig('KAFKA_BROKER'),
+
+      'fs.checkpoint.dir': 
this.getSingleMountPointConfig('SECONDARY_NAMENODE', 'file'),
+      'dfs.namenode.checkpoint.dir': 
this.getSingleMountPointConfig('SECONDARY_NAMENODE', 'file'),
+      'yarn.timeline-service.leveldb-timeline-store.path': 
this.getSingleMountPointConfig('APP_TIMELINE_SERVER'),
+      'yarn.timeline-service.leveldb-state-store.path': 
this.getSingleMountPointConfig('APP_TIMELINE_SERVER'),
+      'dataDir': this.getSingleMountPointConfig('ZOOKEEPER_SERVER'),
+      'oozie_data_dir': this.getSingleMountPointConfig('OOZIE_SERVER'),
+      'storm.local.dir': this.getSingleMountPointConfig(['NODEMANAGER', 
'NIMBUS']),
+      '*.falcon.graph.storage.directory': 
this.getSingleMountPointConfig('FALCON_SERVER'),
+      '*.falcon.graph.serialize.path': 
this.getSingleMountPointConfig('FALCON_SERVER')
     }
   }.property(''),
 
@@ -126,7 +146,9 @@ App.ConfigInitializer = 
App.ConfigInitializerClass.create(App.HostsBasedInitiali
   },
 
   initializerTypes: [
-    {name: 'zookeeper_based', method: '_initAsZookeeperServersList'}
+    {name: 'zookeeper_based', method: '_initAsZookeeperServersList'},
+    {name: 'single_mountpoint', method: '_initAsSingleMountPoint'},
+    {name: 'multiple_mountpoints', method: '_initAsMultipleMountPoints'}
   ],
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/90967bcd/ambari-web/app/utils/configs/mount_points_based_initializer_mixin.js
----------------------------------------------------------------------
diff --git 
a/ambari-web/app/utils/configs/mount_points_based_initializer_mixin.js 
b/ambari-web/app/utils/configs/mount_points_based_initializer_mixin.js
new file mode 100644
index 0000000..59a3985
--- /dev/null
+++ b/ambari-web/app/utils/configs/mount_points_based_initializer_mixin.js
@@ -0,0 +1,340 @@
+/**
+ * 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.
+ */
+
+var App = require('app');
+
+/**
+ * Regexp used to determine if mount point is windows-like
+ *
+ * @type {RegExp}
+ */
+var winRegex = /^([a-z]):\\?$/;
+
+App.MountPointsBasedInitializerMixin = Em.Mixin.create({
+
+  /**
+   * Map for methods used as value-modifiers for configProperties with values 
as mount point(s)
+   * Used if mount point is win-like (@see winRegex)
+   * Key: id
+   * Value: method-name
+   *
+   * @type {{default: string, file: string, slashes: string}}
+   */
+  winReplacersMap: {
+    default: '_defaultWinReplace',
+    file: '_winReplaceWithFile',
+    slashes: '_defaultWinReplaceWithAdditionalSlashes'
+  },
+
+  /**
+   * Initializer for configs with value as one of the possible mount points
+   * Only hosts that contains on the components from 
<code>initializer.components</code> are processed
+   * Hosts with Windows needs additional processing (@see winReplacersMap)
+   * Value example: '/', '/some/cool/dir'
+   *
+   * @param {configProperty} configProperty
+   * @param {topologyLocalDB} localDB
+   * @param {object} dependencies
+   * @param {object} initializer
+   * @return {Object}
+   */
+  _initAsSingleMountPoint: function (configProperty, localDB, dependencies, 
initializer) {
+    var hostsInfo = this._updateHostInfo(localDB.hosts);
+    var setOfHostNames = this._getSetOfHostNames(localDB, initializer);
+    var winReplacersMap = this.get('winReplacersMap');
+    // In Add Host Wizard, if we did not select this slave component for any 
host, then we don't process any further.
+    if (!setOfHostNames.length) {
+      return configProperty;
+    }
+    var allMountPoints = this._getAllMountPoints(setOfHostNames, hostsInfo, 
localDB);
+
+    var mPoint = allMountPoints[0].mountpoint;
+    if (mPoint === "/") {
+      mPoint = Em.get(configProperty, 'recommendedValue');
+    }
+    else {
+      var mp = mPoint.toLowerCase();
+      if (winRegex.test(mp)) {
+        var methodName = winReplacersMap[initializer.winReplacer];
+        mPoint = this[methodName].call(this, configProperty, mp);
+      }
+      else {
+        mPoint = mPoint + Em.get(configProperty, 'recommendedValue');
+      }
+    }
+    Em.setProperties(configProperty, {
+      value: mPoint,
+      recommendedValue: mPoint
+    });
+
+    return configProperty;
+  },
+
+  /**
+   * Initializer for configs with value as all of the possible mount points
+   * Only hosts that contains on the components from 
<code>initializer.components</code> are processed
+   * Hosts with Windows needs additional processing (@see winReplacersMap)
+   * Value example: '/\n/some/cool/dir' (`\n` - is divider)
+   *
+   * @param {Object} configProperty
+   * @param {topologyLocalDB} localDB
+   * @param {object} dependencies
+   * @param {object} initializer
+   * @return {Object}
+   */
+  _initAsMultipleMountPoints: function (configProperty, localDB, dependencies, 
initializer) {
+    var hostsInfo = this._updateHostInfo(localDB.hosts);
+    var self = this;
+    var setOfHostNames = this._getSetOfHostNames(localDB, initializer);
+    var winReplacersMap = this.get('winReplacersMap');
+    // In Add Host Wizard, if we did not select this slave component for any 
host, then we don't process any further.
+    if (!setOfHostNames.length) {
+      return configProperty;
+    }
+
+    var allMountPoints = this._getAllMountPoints(setOfHostNames, hostsInfo, 
localDB);
+    var mPoint = '';
+
+    allMountPoints.forEach(function (eachDrive) {
+      if (eachDrive.mountpoint === '/') {
+        mPoint += Em.get(configProperty, 'recommendedValue') + "\n";
+      }
+      else {
+        var mp = eachDrive.mountpoint.toLowerCase();
+        if (winRegex.test(mp)) {
+          var methodName = winReplacersMap[initializer.winReplacer];
+          mPoint += self[methodName].call(this, configProperty, mp);
+        }
+        else {
+          mPoint += eachDrive.mountpoint + Em.get(configProperty, 
'recommendedValue') + "\n";
+        }
+      }
+    }, this);
+
+    Em.setProperties(configProperty, {
+      value: mPoint,
+      recommendedValue: mPoint
+    });
+
+    return configProperty;
+  },
+
+  /**
+   * Replace drive-based windows-path with 'file:///'
+   *
+   * @param {configProperty} configProperty
+   * @param {string} mountPoint
+   * @returns {string}
+   * @private
+   */
+  _winReplaceWithFile: function (configProperty, mountPoint) {
+    var winDriveUrl = mountPoint.toLowerCase().replace(winRegex, 
'file:///$1:');
+    return winDriveUrl + Em.get(configProperty, 'recommendedValue') + '\n';
+  },
+
+  /**
+   * Replace drive-based windows-path
+   *
+   * @param {configProperty} configProperty
+   * @param {string} mountPoint
+   * @returns {string}
+   * @private
+   */
+  _defaultWinReplace: function (configProperty, mountPoint) {
+    var winDrive = mountPoint.toLowerCase().replace(winRegex, '$1:');
+    var winDir = Em.get(configProperty, 'recommendedValue').replace(/\//g, 
'\\');
+    return winDrive + winDir + '\n';
+  },
+
+  /**
+   * Same to <code>_defaultWinReplace</code>, but with extra-slash in the end
+   *
+   * @param {configProperty} configProperty
+   * @param {string} mountPoint
+   * @returns {string}
+   * @private
+   */
+  _defaultWinReplaceWithAdditionalSlashes: function (configProperty, 
mountPoint) {
+    var winDrive = mountPoint.toLowerCase().replace(winRegex, '$1:');
+    var winDir = Em.get(configProperty, 'recommendedValue').replace(/\//g, 
'\\\\');
+    return winDrive + winDir + '\n';
+  },
+
+  /**
+   * Update information from localDB using <code>App.Host</code>-model
+   *
+   * @param {object} hostsInfo
+   * @returns {object}
+   * @private
+   */
+  _updateHostInfo: function (hostsInfo) {
+    App.Host.find().forEach(function (item) {
+      if (!hostsInfo[item.get('id')]) {
+        hostsInfo[item.get('id')] = {
+          name: item.get('id'),
+          cpu: item.get('cpu'),
+          memory: item.get('memory'),
+          disk_info: item.get('diskInfo'),
+          bootStatus: "REGISTERED",
+          isInstalled: true
+        };
+      }
+    });
+    return hostsInfo;
+  },
+
+  /**
+   * Determines if mount point is valid
+   * Criterias:
+   * <ul>
+   *   <li>Should has available space</li>
+   *   <li>Should not be home-dir</li>
+   *   <li>Should not be docker-dir</li>
+   *   <li>Should not be boot-dir</li>
+   *   <li>Should not be dev-dir</li>
+   *   <li>Valid mount point started from /usr/hdp/ should be /usr/hdp/current
+   *       or /usr/hdp/<STACK_VERSION_NUMBER> e.g. /usr/hdp/2.5.0.0
+   *   </li>
+   * </ul>
+   *
+   * @param {{mountpoint: string, available: number}} mPoint
+   * @returns {function} true - valid, false - invalid
+   * @private
+   */
+  _filterMountPoint: function (localDB) {
+    var stackVersionNumber = [Em.getWithDefault(localDB.selectedStack || {}, 
'repository_version', null)].compact();
+    return function(mPoint) {
+      var isAvailable = mPoint.available !== 0;
+      if (!isAvailable) {
+        return false;
+      }
+
+      var stackRoot = '/usr/hdp';
+      var notHome = !['/', '/home'].contains(mPoint.mountpoint);
+      var notDocker = !['/etc/resolv.conf', '/etc/hostname', 
'/etc/hosts'].contains(mPoint.mountpoint);
+      var notBoot = mPoint.mountpoint && 
!(mPoint.mountpoint.startsWith('/boot')
+                                           || 
mPoint.mountpoint.startsWith('/mnt')
+                                           || 
mPoint.mountpoint.startsWith('/tmp'));
+      var notDev = !(['devtmpfs', 'tmpfs', 'vboxsf', 
'CDFS'].contains(mPoint.type));
+      var validStackRootMount = !(mPoint.mountpoint.startsWith(stackRoot) && 
!['current'].concat(stackVersionNumber).filter(function(i) {
+        return mPoint.mountpoint === stackRoot + '/' + i;
+      }).length);
+
+      return notHome && notDocker && notBoot && notDev && validStackRootMount;
+    };
+  },
+
+  /**
+   * Get list of hostNames from localDB which contains needed components
+   *
+   * @param {topologyLocalDB} localDB
+   * @param {object} initializer
+   * @returns {string[]}
+   * @private
+   */
+  _getSetOfHostNames: function (localDB, initializer) {
+    var masterComponentHostsInDB = Em.getWithDefault(localDB, 
'masterComponentHosts', []);
+    var slaveComponentHostsInDB = Em.getWithDefault(localDB, 
'slaveComponentHosts', []);
+    var hosts = masterComponentHostsInDB.filter(function (master) {
+      return initializer.components.contains(master.component);
+    }).mapProperty('hostName');
+
+    var sHosts = slaveComponentHostsInDB.find(function (slave) {
+      return initializer.components.contains(slave.componentName);
+    });
+    if (sHosts) {
+      hosts = hosts.concat(sHosts.hosts.mapProperty('hostName'));
+    }
+    return hosts;
+  },
+
+  /**
+   * Get list of all unique valid mount points for hosts
+   *
+   * @param {string[]} setOfHostNames
+   * @param {object} hostsInfo
+   * @param {topologyLocalDB} localDB
+   * @returns {string[]}
+   * @private
+   */
+  _getAllMountPoints: function (setOfHostNames, hostsInfo, localDB) {
+    var allMountPoints = [],
+        mountPointFilter = this._filterMountPoint(localDB);
+    for (var i = 0; i < setOfHostNames.length; i++) {
+      var hostname = setOfHostNames[i];
+      var mountPointsPerHost = hostsInfo[hostname].disk_info;
+      var mountPointAsRoot = mountPointsPerHost.findProperty('mountpoint', 
'/');
+
+      // If Server does not send any host details information then atleast one 
mountpoint should be presumed as root
+      // This happens in a single container Linux Docker environment.
+      if (!mountPointAsRoot) {
+        mountPointAsRoot = {
+          mountpoint: '/'
+        };
+      }
+
+      mountPointsPerHost.filter(mountPointFilter).forEach(function (mPoint) {
+        if( !allMountPoints.findProperty("mountpoint", mPoint.mountpoint)) {
+          allMountPoints.push(mPoint);
+        }
+      }, this);
+    }
+
+    if (!allMountPoints.length) {
+      allMountPoints.push(mountPointAsRoot);
+    }
+    return allMountPoints;
+  },
+
+  /**
+   * Settings for <code>single_mountpoint</code>-initializer
+   * Used for configs with value as one of the possible mount points
+   *
+   * @see _initAsSingleMountPoint
+   * @param {string|string[]} components
+   * @param {string} winReplacer
+   * @returns {{components: string[], winReplacer: string, type: string}}
+   */
+  getSingleMountPointConfig: function (components, winReplacer) {
+    winReplacer = winReplacer || 'default';
+    return {
+      components: Em.makeArray(components),
+      winReplacer: winReplacer,
+      type: 'single_mountpoint'
+    };
+  },
+
+  /**
+   * Settings for <code>multiple_mountpoints</code>-initializer
+   * Used for configs with value as all of the possible mount points
+   *
+   * @see _initAsMultipleMountPoints
+   * @param {string|string[]} components
+   * @param {string} winReplacer
+   * @returns {{components: string[], winReplacer: string, type: string}}
+   */
+  getMultipleMountPointsConfig: function (components, winReplacer) {
+    winReplacer = winReplacer || 'default';
+    return {
+      components: Em.makeArray(components),
+      winReplacer: winReplacer,
+      type: 'multiple_mountpoints'
+    };
+  }
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/90967bcd/ambari-web/test/utils/ajax/ajax_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/utils/ajax/ajax_test.js 
b/ambari-web/test/utils/ajax/ajax_test.js
index 3556e1e..d252c3d 100644
--- a/ambari-web/test/utils/ajax/ajax_test.js
+++ b/ambari-web/test/utils/ajax/ajax_test.js
@@ -29,16 +29,11 @@ describe('App.ajax', function() {
 
   beforeEach(function() {
     App.ajax.send.restore();
-    sinon.stub(App.logger, 'setTimer');
     sinon.spy(App.ajax, 'send'); // no sense to test stubbed function, so 
going to spy on it
     App.set('apiPrefix', '/api/v1');
     App.set('clusterName', 'tdk');
   });
 
-  afterEach(function() {
-    App.logger.setTimer.restore();
-  });
-
   describe('#send', function() {
     it('Without sender', function() {
       expect(App.ajax.send({})).to.equal(null);
@@ -173,7 +168,7 @@ describe('App.ajax', function() {
       });
     });
   });
-
+  
   describe('#abortRequests', function () {
 
     var xhr = {
@@ -203,6 +198,6 @@ describe('App.ajax', function() {
     it('should clear requests array', function () {
       expect(requests).to.have.length(0);
     });
-
+    
   });
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/90967bcd/ambari-web/test/utils/configs/config_initializer_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/utils/configs/config_initializer_test.js 
b/ambari-web/test/utils/configs/config_initializer_test.js
index ceed065..19ba03d 100644
--- a/ambari-web/test/utils/configs/config_initializer_test.js
+++ b/ambari-web/test/utils/configs/config_initializer_test.js
@@ -905,6 +905,312 @@ describe('App.ConfigInitializer', function () {
 
   });
 
+  describe('config with mount points', function () {
+
+    var localDB = {
+        masterComponentHosts: [
+          {
+            component: 'NAMENODE',
+            hostName: 'h0'
+          },
+          {
+            component: 'SECONDARY_NAMENODE',
+            hostName: 'h4'
+          },
+          {
+            component: 'APP_TIMELINE_SERVER',
+            hostName: 'h0'
+          },
+          {
+            component: 'ZOOKEEPER_SERVER',
+            hostName: 'h0'
+          },
+          {
+            component: 'ZOOKEEPER_SERVER',
+            hostName: 'h1'
+          },
+          {
+            component: 'OOZIE_SERVER',
+            hostName: 'h0'
+          },
+          {
+            component: 'OOZIE_SERVER',
+            hostName: 'h1'
+          },
+          {
+            component: 'NIMBUS',
+            hostName: 'h2'
+          },
+          {
+            component: 'FALCON_SERVER',
+            hostName: 'h3'
+          },
+          {
+            component: 'KAFKA_BROKER',
+            hostName: 'h0'
+          },
+          {
+            component: 'KAFKA_BROKER',
+            hostName: 'h1'
+          }
+        ],
+        slaveComponentHosts: [
+          {
+            componentName: 'DATANODE',
+            hosts: [
+              {
+                hostName: 'h0'
+              },
+              {
+                hostName: 'h1'
+              }
+            ]
+          },
+          {
+            componentName: 'TASKTRACKER',
+            hosts: [
+              {
+                hostName: 'h0'
+              },
+              {
+                hostName: 'h1'
+              }
+            ]
+          },
+          {
+            componentName: 'NODEMANAGER',
+            hosts: [
+              {
+                hostName: 'h0'
+              },
+              {
+                hostName: 'h1'
+              },
+              {
+                hostName: 'h4'
+              }
+            ]
+          },
+          {
+            componentName: 'HBASE_REGIONSERVER',
+            hosts: [
+              {
+                hostName: 'h0'
+              },
+              {
+                hostName: 'h1'
+              }
+            ]
+          },
+          {
+            componentName: 'SUPERVISOR',
+            hosts: [
+              {
+                hostName: 'h0'
+              },
+              {
+                hostName: 'h1'
+              }
+            ]
+          }
+        ],
+        hosts: {
+          h0: {
+            disk_info: [
+              {
+                mountpoint: '/'
+              },
+              {
+                mountpoint: '/home'
+              },
+              {
+                mountpoint: '/boot'
+              },
+              {
+                mountpoint: '/boot/efi'
+              },
+              {
+                mountpoint: '/mnt'
+              },
+              {
+                mountpoint: '/mnt/efi'
+              },
+              {
+                mountpoint: '/media/disk0',
+                available: '100000000'
+              },
+              {
+                mountpoint: '/mount0',
+                available: '100000000'
+              }
+            ]
+          },
+          h4: {
+            disk_info: [
+              {
+                mountpoint: 'c:',
+                available: '100000000'
+              }
+            ]
+          }
+        }
+      },
+      cases = [
+        {
+          name: 'dfs.namenode.name.dir',
+          isOnlyFirstOneNeeded: false,
+          value: '/media/disk0/default\n/mount0/default\n'
+        },
+        {
+          name: 'dfs.name.dir',
+          isOnlyFirstOneNeeded: false,
+          value: '/media/disk0/default\n/mount0/default\n'
+        },
+        {
+          name: 'fs.checkpoint.dir',
+          isOnlyFirstOneNeeded: true,
+          value: 'file:///c:/default\n'
+        },
+        {
+          name: 'dfs.namenode.checkpoint.dir',
+          isOnlyFirstOneNeeded: true,
+          value: 'file:///c:/default\n'
+        },
+        {
+          name: 'dfs.data.dir',
+          isOnlyFirstOneNeeded: false,
+          value: 
'/media/disk0/default\n/mount0/default\n/media/disk1/default\n/mount1/default\n'
+        },
+        {
+          name: 'dfs.datanode.data.dir',
+          isOnlyFirstOneNeeded: false,
+          value: 
'/media/disk0/default\n/mount0/default\n/media/disk1/default\n/mount1/default\n'
+        },
+        {
+          name: 'mapred.local.dir',
+          isOnlyFirstOneNeeded: false,
+          value: 
'/media/disk0/default\n/mount0/default\n/media/disk1/default\n/mount1/default\n'
+        },
+        {
+          name: 'yarn.nodemanager.log-dirs',
+          isOnlyFirstOneNeeded: false,
+          value: 
'/media/disk0/default\n/mount0/default\n/media/disk1/default\n/mount1/default\nc:\\default\n'
+        },
+        {
+          name: 'yarn.nodemanager.local-dirs',
+          isOnlyFirstOneNeeded: false,
+          value: 
'/media/disk0/default\n/mount0/default\n/media/disk1/default\n/mount1/default\nc:\\default\n'
+        },
+        {
+          name: 'yarn.timeline-service.leveldb-timeline-store.path',
+          isOnlyFirstOneNeeded: true,
+          value: '/media/disk0/default'
+        },
+        {
+          name: 'yarn.timeline-service.leveldb-state-store.path',
+          isOnlyFirstOneNeeded: true,
+          value: '/media/disk0/default'
+        },
+        {
+          name: 'dataDir',
+          isOnlyFirstOneNeeded: true,
+          value: '/media/disk0/default'
+        },
+        {
+          name: 'oozie_data_dir',
+          isOnlyFirstOneNeeded: true,
+          value: '/media/disk0/default'
+        },
+        {
+          name: 'storm.local.dir',
+          isOnlyFirstOneNeeded: true,
+          value: '/media/disk0/default'
+        },
+        {
+          name: '*.falcon.graph.storage.directory',
+          isOnlyFirstOneNeeded: true,
+          value: '/default'
+        },
+        {
+          name: '*.falcon.graph.serialize.path',
+          isOnlyFirstOneNeeded: true,
+          value: '/default'
+        },
+        {
+          name: 'log.dirs',
+          isOnlyFirstOneNeeded: false,
+          value: 
'/media/disk0/default\n/mount0/default\n/media/disk1/default\n/mount1/default\n'
+        }
+      ];
+
+    beforeEach(function () {
+      sinon.stub(App.Host, 'find').returns([
+        Em.Object.create({
+          id: 'h1',
+          diskInfo: [
+            {
+              mountpoint: '/media/disk1',
+              type: 'devtmpfs'
+            },
+            {
+              mountpoint: '/media/disk1',
+              type: 'tmpfs'
+            },
+            {
+              mountpoint: '/media/disk1',
+              type: 'vboxsf'
+            },
+            {
+              mountpoint: '/media/disk1',
+              type: 'CDFS'
+            },
+            {
+              mountpoint: '/media/disk1',
+              available: '0'
+            },
+            {
+              mountpoint: '/media/disk1',
+              available: '100000000'
+            },
+            {
+              mountpoint: '/mount1',
+              available: '100000000'
+            }
+          ]
+        }),
+        Em.Object.create({
+          id: 'h2',
+          diskInfo: [
+            {
+              mountpoint: '/'
+            }
+          ]
+        }),
+        Em.Object.create({
+          id: 'h3',
+          diskInfo: []
+        })
+      ]);
+    });
+
+    afterEach(function () {
+      App.Host.find.restore();
+    });
+
+    cases.forEach(function (item) {
+      it(item.name, function () {
+        serviceConfigProperty.setProperties({
+          name: item.name,
+          recommendedValue: '/default'
+        });
+        App.ConfigInitializer.initialValue(serviceConfigProperty, localDB, {});
+        expect(serviceConfigProperty.get('value')).to.equal(item.value);
+        
expect(serviceConfigProperty.get('recommendedValue')).to.equal(item.value);
+      });
+    });
+
+  });
+
   describe('initializerTypes', function () {
     var types = App.ConfigInitializer.get('initializerTypes');
     Em.keys(types).forEach(function(type) {
@@ -950,4 +1256,156 @@ describe('App.ConfigInitializer', function () {
     });
 
   });
+
+  describe('#_filterMountPoint', function() {
+    [
+      {
+        mPoint: {
+          mountpoint: '/'
+        },
+        localDB: {},
+        e: false
+      },
+      {
+        mPoint: {
+          mountpoint: '/home'
+        },
+        localDB: {},
+        e: false
+      },
+      {
+        mPoint: {
+          mountpoint: '/etc/resolv.conf'
+        },
+        localDB: {},
+        e: false
+      },
+      {
+        mPoint: {
+          mountpoint: '/etc/hostname'
+        },
+        localDB: {},
+        e: false
+      },
+      {
+        mPoint: {
+          mountpoint: '/etc/hosts'
+        },
+        localDB: {},
+        e: false
+      },
+      {
+        mPoint: {
+          mountpoint: '/boot'
+        },
+        localDB: {},
+        e: false
+      },
+      {
+        mPoint: {
+          mountpoint: '/mnt'
+        },
+        localDB: {},
+        e: false
+      },
+      {
+        mPoint: {
+          mountpoint: '/tmp'
+        },
+        localDB: {},
+        e: false
+      },
+      {
+        mPoint: {
+          mountpoint: '/some-dir',
+          type: 'devtmpfs'
+        },
+        localDB: {},
+        e: false
+      },
+      {
+        mPoint: {
+          mountpoint: '/some-dir',
+          type: 'tmpfs'
+        },
+        localDB: {},
+        e: false
+      },
+      {
+        mPoint: {
+          mountpoint: '/some-dir',
+          type: 'vboxsf'
+        },
+        localDB: {},
+        e: false
+      },
+      {
+        mPoint: {
+          mountpoint: '/some-dir',
+          type: 'CDFS'
+        },
+        localDB: {},
+        e: false
+      },
+      {
+        mPoint: {
+          mountpoint: '/usr/hdp'
+        },
+        localDB: {},
+        e: false
+      },
+      {
+        mPoint: {
+          mountpoint: '/usr/hdp/1'
+        },
+        localDB: {},
+        e: false
+      },
+      {
+        mPoint: {
+          mountpoint: '/usr/hdp/current'
+        },
+        localDB: {},
+        e: true
+      },
+      {
+        mPoint: {
+          mountpoint: '/usr/hdp/2.5'
+        },
+        localDB: {
+          selectedStack: {
+            repository_version: '2.5'
+          }
+        },
+        e: true
+      },
+      {
+        mPoint: {
+          mountpoint: '/usr/hdp/2.5.0'
+        },
+        localDB: {
+          selectedStack: {
+            repository_version: '2.5'
+          }
+        },
+        e: false
+      },
+      {
+        mPoint: {
+          mountpoint: '/normal/directory'
+        },
+        localDB: {
+          selectedStack: {
+            repository_version: '2.5'
+          }
+        },
+        e: true
+      }
+    ].forEach(function(test) {
+      it('mount point "{0}" should be {1}'.format(test.mPoint.mountpoint, 
test.e ? 'valid' : 'invalid'), function() {
+        var fFn = App.ConfigInitializer._filterMountPoint(test.localDB);
+        expect(fFn(test.mPoint)).to.be.equal(test.e);
+      });
+    });
+  });
 });

Reply via email to