AMBARI-14416. Refactor Host Details controller

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

Branch: refs/heads/branch-dev-patch-upgrade
Commit: 6c38d84b1152807c0b94f175e090d90ad0c74a28
Parents: 2c7ecd1
Author: Alex Antonenko <hiv...@gmail.com>
Authored: Fri Dec 18 18:59:19 2015 +0200
Committer: Alex Antonenko <hiv...@gmail.com>
Committed: Fri Dec 18 18:59:19 2015 +0200

----------------------------------------------------------------------
 ambari-web/app/controllers/main/host/details.js | 256 ++++---
 ambari-web/app/messages.js                      |   6 +-
 ambari-web/app/mixins.js                        |   1 +
 .../configs/add_component_config_initializer.js | 303 ++++++++
 .../app/utils/configs/config_initializer.js     | 622 +++------------
 .../utils/configs/config_initializer_class.js   |  97 ++-
 .../configs/control_flow_initializer_mixin.js   | 127 ++++
 .../configs/ha_config_initializer_class.js      | 167 +----
 .../configs/hosts_based_initializer_mixin.js    | 401 ++++++++++
 .../mount_points_based_initializer_mixin.js     | 326 ++++++++
 .../utils/configs/nn_ha_config_initializer.js   |  76 +-
 .../utils/configs/rm_ha_config_initializer.js   |  31 +-
 .../test/controllers/main/host/details_test.js  | 750 ++++++++++++++-----
 13 files changed, 2095 insertions(+), 1068 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/6c38d84b/ambari-web/app/controllers/main/host/details.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/host/details.js 
b/ambari-web/app/controllers/main/host/details.js
index ea1a168..8ec521e 100644
--- a/ambari-web/app/controllers/main/host/details.js
+++ b/ambari-web/app/controllers/main/host/details.js
@@ -20,6 +20,7 @@ var App = require('app');
 var batchUtils = require('utils/batch_scheduled_requests');
 var hostsManagement = require('utils/hosts');
 var stringUtils = require('utils/string_utils');
+require('utils/configs/add_component_config_initializer');
 
 App.MainHostDetailsController = 
Em.Controller.extend(App.SupportClientConfigsDownload, App.InstallComponent, 
App.InstallNewVersion, {
 
@@ -761,11 +762,56 @@ App.MainHostDetailsController = 
Em.Controller.extend(App.SupportClientConfigsDow
    * @method updateZkConfigs
    */
   updateZkConfigs: function (configs) {
-    var zks = this.getZkServerHosts();
     var portValue = configs['zoo.cfg'] && Em.get(configs['zoo.cfg'], 
'clientPort');
-    var zkPort = typeof portValue === 'udefined' ? '2181' : portValue;
-    var zksWithPort = this.concatZkNames(zks, zkPort);
-    this.setZKConfigs(configs, zksWithPort, zks);
+    var zkPort = typeof portValue === 'undefined' ? '2181' : portValue;
+    var initializer = App.AddZooKeeperComponentsInitializer;
+    var hostComponentsTopology = {
+      masterComponentHosts: []
+    };
+    var masterComponents = this.bootstrapHostsMapping('ZOOKEEPER_SERVER');
+    if (this.get('fromDeleteHost') || this.get('fromDeleteZkServer')) {
+      this.set('fromDeleteHost', false);
+      this.set('fromDeleteZkServer', false);
+      var removedHost = masterComponents.findProperty('hostName', 
this.get('content.hostName'));
+      if (!Em.isNone(removedHost)) {
+        Em.set(removedHost, 'isInstalled', false);
+      }
+    }
+    var dependencies = {
+      zkClientPort: zkPort
+    };
+    hostComponentsTopology.masterComponentHosts = masterComponents;
+    Em.keys(configs).forEach(function(fileName) {
+      var properties = configs[fileName];
+      Em.keys(properties).forEach(function(propertyName) {
+        var propertyDef = {
+          fileName: fileName,
+          name: propertyName,
+          value: properties[propertyName]
+        };
+        var configProperty = initializer.initialValue(propertyDef, 
hostComponentsTopology, dependencies);
+        initializer.updateSiteObj(configs[fileName], configProperty);
+      });
+    });
+  },
+
+  /**
+   *
+   * @param {string} componentName
+   * @param {string[]} [hostNames]
+   * @returns {}
+   */
+  bootstrapHostsMapping: function(componentName, hostNames) {
+    if (Em.isNone(hostNames)) {
+      hostNames = App.HostComponent.find().filterProperty('componentName', 
componentName).mapProperty('hostName');
+    }
+    return hostNames.map(function(hostName) {
+      return {
+        component: componentName,
+        hostName: hostName,
+        isInstalled: true
+      };
+    });
   },
 
   /**
@@ -827,35 +873,49 @@ App.MainHostDetailsController = 
Em.Controller.extend(App.SupportClientConfigsDow
    * @method onLoadHiveConfigs
    */
   onLoadHiveConfigs: function (data) {
-    var
-      hiveMetastoreHost = this.get('hiveMetastoreHost'),
-      webhcatServerHost = this.get('webhcatServerHost'),
-      hiveMSHosts = this.getHiveHosts(),
-      hiveMasterHosts = 
hiveMSHosts.concat(App.HostComponent.find().filterProperty('componentName', 
'HIVE_SERVER').mapProperty('hostName')).uniq().sort().join(','),
-      configs = {},
-      attributes = {},
-      port = "",
-      hiveUser = "",
-      webhcatUser = "";
-
+    var hiveMetastoreHost = this.get('hiveMetastoreHost');
+    var webhcatServerHost = this.get('webhcatServerHost');
+    var port = "";
+    var configs = {};
+    var attributes = {};
+    var localDB = {
+      masterComponentHosts: this.getHiveHosts()
+    };
+    var dependencies = {
+      hiveMetastorePort: ""
+    };
+    var initializer = App.AddHiveComponentsInitializer;
     data.items.forEach(function (item) {
       configs[item.type] = item.properties;
       attributes[item.type] = item.properties_attributes || {};
     }, this);
 
+
     port = configs['hive-site']['hive.metastore.uris'].match(/:[0-9]{2,4}/);
     port = port ? port[0].slice(1) : "9083";
 
-    hiveUser = configs['hive-env']['hive_user'];
-    webhcatUser = configs['hive-env']['webhcat_user'];
+    dependencies.hiveMetastorePort = port;
+
+    initializer.setup({
+      hiveUser: configs['hive-env']['hive_user'],
+      webhcatUser: configs['hive-env']['webhcat_user']
+    });
+
+    ['hive-site', 'webhcat-site', 'hive-env', 
'core-site'].forEach(function(fileName) {
+      if (configs[fileName]) {
+        Em.keys(configs[fileName]).forEach(function(propertyName) {
+          var propertyDef = {
+            fileName: fileName,
+            name: propertyName,
+            value: configs[fileName][propertyName]
+          };
+          configs[fileName][propertyName] = 
Em.get(initializer.initialValue(propertyDef, localDB, dependencies), 'value');
+        });
+      }
+    });
+
+    initializer.cleanup();
 
-    for (var i = 0; i < hiveMSHosts.length; i++) {
-      hiveMSHosts[i] = "thrift://" + hiveMSHosts[i] + ":" + port;
-    }
-    configs['hive-site']['hive.metastore.uris'] = hiveMSHosts.join(',');
-    configs['webhcat-site']['templeton.hive.properties'] = 
configs['webhcat-site']['templeton.hive.properties'].replace(/thrift.+[0-9]{2,},/i,
 hiveMSHosts.join('\\,') + ",");
-    configs['core-site']['hadoop.proxyuser.' + hiveUser + '.hosts'] = 
hiveMasterHosts;
-    configs['core-site']['hadoop.proxyuser.' + webhcatUser + '.hosts'] = 
hiveMasterHosts;
     var groups = [
       {
         properties: {
@@ -953,32 +1013,47 @@ App.MainHostDetailsController = 
Em.Controller.extend(App.SupportClientConfigsDow
   deleteWebHCatServer: false,
 
   getHiveHosts: function () {
-    var
-      hiveHosts = App.HostComponent.find().filterProperty('componentName', 
'HIVE_METASTORE').mapProperty('hostName'),
-      webhcatHosts = App.HostComponent.find().filterProperty('componentName', 
'WEBHCAT_SERVER').mapProperty('hostName'),
-      hiveMetastoreHost = this.get('hiveMetastoreHost'),
-      webhcatServerHost = this.get('webhcatServerHost');
+    var self = this;
+    var removePerformed = this.get('fromDeleteHost') || 
this.get('deleteHiveMetaStore') || this.get('deleteHiveServer') || 
this.get('deleteWebHCatServer');
+    var hiveMasterComponents = ['WEBHCAT_SERVER', 'HIVE_METASTORE', 
'HIVE_SERVER'];
+    var masterComponentsMap = hiveMasterComponents.map(function(componentName) 
{
+      return self.bootstrapHostsMapping(componentName);
+    }).reduce(function(p,c) {
+      return p.concat(c);
+    });
 
-    hiveHosts = hiveHosts.concat(webhcatHosts).uniq();
+    if (removePerformed) {
+      self.setProperties({
+        deleteHiveMetaStore: false,
+        deleteHiveServer: false,
+        deleteWebHCatServer: false,
+        fromDeleteHost: false
+      });
+      masterComponentsMap = masterComponentsMap.map(function(masterComponent) {
+        masterComponent.isInstalled = masterComponent.hostName !== 
self.get('content.hostName');
+        return masterComponent;
+      });
+    }
 
-    if (!!hiveMetastoreHost) {
-      hiveHosts.push(hiveMetastoreHost);
+    if (!!this.get('hiveMetastoreHost')) {
+      masterComponentsMap.push({
+        component: 'HIVE_METASTORE',
+        hostName: this.get('hiveMetastoreHost'),
+        isInstalled: !removePerformed
+      });
       this.set('hiveMetastoreHost', '');
     }
 
-    if (!!webhcatServerHost) {
-      hiveHosts.push(webhcatServerHost);
-      this.set('webhcatServerHost' ,'');
+    if (!!this.get('webhcatServerHost')) {
+      masterComponentsMap.push({
+        component: 'WEBHCAT_SERVER',
+        hostName: this.get('webhcatServerHost'),
+        isInstalled: !removePerformed
+      });
+      this.set('webhcatServerHost', '');
     }
 
-    if (this.get('fromDeleteHost') || this.get('deleteHiveMetaStore') || 
this.get('deleteHiveServer') || this.get('deleteWebHCatServer')) {
-      this.set('deleteHiveMetaStore', false);
-      this.set('deleteHiveServer', false);
-      this.set('deleteWebHCatServer', false);
-      this.set('fromDeleteHost', false);
-      hiveHosts = hiveHosts.without(this.get('content.hostName'));
-    }
-    return hiveHosts.sort();
+    return masterComponentsMap;
   },
 
   /**
@@ -1218,6 +1293,9 @@ App.MainHostDetailsController = 
Em.Controller.extend(App.SupportClientConfigsDow
       urlParams.push('(type=yarn-site&tag=' + 
data.Clusters.desired_configs['yarn-site'].tag + ')');
       urlParams.push('(type=zoo.cfg&tag=' + 
data.Clusters.desired_configs['zoo.cfg'].tag + ')');
     }
+    if (services.someProperty('serviceName', 'ACCUMULO')) {
+      urlParams.push('(type=accumulo-site&tag=' + 
data.Clusters.desired_configs['accumulo-site'].tag + ')');
+    }
     return urlParams;
   },
 
@@ -1260,62 +1338,31 @@ App.MainHostDetailsController = 
Em.Controller.extend(App.SupportClientConfigsDow
         }
       );
     }
-    this.saveConfigsBatch(groups, 'ZOOKEEPER_SERVER');
-  },
-  /**
-   *
-   * Set new values for some configs (based on available ZooKeeper Servers)
-   * @param configs {object}
-   * @param zksWithPort {string}
-   * @param zks {array}
-   * @return {Boolean}
-   */
-  setZKConfigs: function (configs, zksWithPort, zks) {
-    if (typeof configs !== 'object' || !Array.isArray(zks)) return false;
-    if (App.get('isHaEnabled') && configs['core-site']) {
-      App.config.updateHostsListValue(configs['core-site'], 
'ha.zookeeper.quorum', zksWithPort);
-    }
-    if (configs['hbase-site']) {
-      App.config.updateHostsListValue(configs['hbase-site'], 
'hbase.zookeeper.quorum', zks.join(','));
-    }
-    if (configs['accumulo-site']) {
-      App.config.updateHostsListValue(configs['accumulo-site'], 
'instance.zookeeper.host', zksWithPort);
-    }
-    if (configs['webhcat-site']) {
-      App.config.updateHostsListValue(configs['webhcat-site'], 
'templeton.zookeeper.hosts', zksWithPort);
-    }
-    if (configs['hive-site']) {
-      App.config.updateHostsListValue(configs['hive-site'], 
'hive.cluster.delegation.token.store.zookeeper.connectString', zksWithPort);
-    }
-    if (configs['storm-site']) {
-      configs['storm-site']['storm.zookeeper.servers'] = 
JSON.stringify(zks).replace(/"/g, "'");
-    }
-    if (App.get('isRMHaEnabled') && configs['yarn-site']) {
-      App.config.updateHostsListValue(configs['yarn-site'], 
'yarn.resourcemanager.zk-address', zksWithPort);
+    if (App.Service.find().someProperty('serviceName', 'HBASE')) {
+      groups.push(
+        {
+          properties: {
+            'hbase-site': configs['hbase-site']
+          },
+          properties_attributes: {
+            'hbase-site': attributes['hbase-site']
+          }
+        }
+      );
     }
-    if (App.get('isHadoop22Stack')) {
-      if (configs['hive-site']) {
-        App.config.updateHostsListValue(configs['hive-site'], 
'hive.zookeeper.quorum', zksWithPort);
-      }
-      if (configs['yarn-site']) {
-        App.config.updateHostsListValue(configs['yarn-site'], 
'hadoop.registry.zk.quorum', zksWithPort);
-        App.config.updateHostsListValue(configs['yarn-site'], 
'yarn.resourcemanager.zk-address', zksWithPort);
-      }
+    if (App.Service.find().someProperty('serviceName', 'ACCUMULO')) {
+      groups.push(
+        {
+          properties: {
+            'accumulo-site': configs['accumulo-site']
+          },
+          properties_attributes: {
+            'accumulo-site': attributes['accumulo-site']
+          }
+        }
+      );
     }
-    return true;
-  },
-  /**
-   * concatenate URLs to ZOOKEEPER hosts with port "2181",
-   * as value of config divided by comma
-   * @param zks {array}
-   * @param port {string}
-   */
-  concatZkNames: function (zks, port) {
-    var zks_with_port = '';
-    zks.forEach(function (zk) {
-      zks_with_port += zk + ':' + port + ',';
-    });
-    return zks_with_port.slice(0, -1);
+    this.saveConfigsBatch(groups, 'ZOOKEEPER_SERVER');
   },
 
   /**
@@ -1331,21 +1378,6 @@ App.MainHostDetailsController = 
Em.Controller.extend(App.SupportClientConfigsDow
   fromDeleteZkServer: false,
 
   /**
-   * Get list of hostnames where ZK Server is installed
-   * @returns {string[]}
-   * @method getZkServerHosts
-   */
-  getZkServerHosts: function () {
-    var zks = App.HostComponent.find().filterProperty('componentName', 
'ZOOKEEPER_SERVER').mapProperty('hostName');
-    if (this.get('fromDeleteHost') || this.get('fromDeleteZkServer')) {
-      this.set('fromDeleteHost', false);
-      this.set('fromDeleteZkServer', false);
-      return zks.without(this.get('content.hostName'));
-    }
-    return zks;
-  },
-
-  /**
    * Send command to server to install selected host component
    * @param {Object} event
    * @method installComponent

http://git-wip-us.apache.org/repos/asf/ambari/blob/6c38d84b/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index bd71c2f..12402fd 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -2302,14 +2302,14 @@ Em.I18n.translations = {
   'host.host.componentFilter.slave':'Slave Components',
   'host.host.componentFilter.client':'Client Components',
   'hosts.host.deleteComponent.popup.msg1':'Are you sure you want to delete 
{0}?',
-  'hosts.host.deleteComponent.popup.deleteZooKeeperServer':'Deleting 
<i>ZooKeeper Server</i> may reconfigure such 
properties:<ul><li>ha.zookeeper.quorum</li><li>hbase.zookeeper.quorum</li><li>templeton.zookeeper.hosts</li><li>yarn.resourcemanager.zk-address</li><li>hive.zookeeper.quorum</li><li>hive.cluster.delegation.token.store.zookeeper.connectString</li></ul>',
+  'hosts.host.deleteComponent.popup.deleteZooKeeperServer':'Deleting 
<i>ZooKeeper Server</i> may reconfigure such 
properties:<ul><li>ha.zookeeper.quorum</li><li>hbase.zookeeper.quorum</li><li>templeton.zookeeper.hosts</li><li>yarn.resourcemanager.zk-address</li><li>hive.zookeeper.quorum</li><li>hive.cluster.delegation.token.store.zookeeper.connectString</li><li>storm.zookeeper.servers</li><li>instance.zookeeper.host</li></ul>',
   'hosts.host.deleteComponent.popup.deleteRangerKMSServer': 'Deleting 
<i>Ranger KMS Server</i> may reconfigure such 
properties:<ul><li>hadoop.security.key.provider.path</li><li>dfs.encryption.key.provider.uri</li>',
   'hosts.host.deleteComponent.popup.warning':'<b>WARNING!</b> Delete the last 
<i>{0}</i> component in the cluster?</br>Deleting the last component in the 
cluster could result in permanent loss of service data.',
   'hosts.host.deleteComponent.popup.confirm':'Confirm Delete',
   'hosts.host.installComponent.popup.confirm':'Confirm Install',
   'hosts.host.installComponent.msg':'Are you sure you want to install {0}?',
   'hosts.host.addComponent.msg':'Are you sure you want to add {0}?',
-  'hosts.host.addComponent.ZOOKEEPER_SERVER':'Adding ZooKeeper Server may 
reconfigure such 
properties:<ul><li>ha.zookeeper.quorum</li><li>hbase.zookeeper.quorum</li><li>templeton.zookeeper.hosts</li><li>yarn.resourcemanager.zk-address</li><li>hive.zookeeper.quorum</li><li>hive.cluster.delegation.token.store.zookeeper.connectString</li></ul>',
+  'hosts.host.addComponent.ZOOKEEPER_SERVER':'Adding ZooKeeper Server may 
reconfigure such 
properties:<ul><li>ha.zookeeper.quorum</li><li>hbase.zookeeper.quorum</li><li>templeton.zookeeper.hosts</li><li>yarn.resourcemanager.zk-address</li><li>hive.zookeeper.quorum</li><li>hive.cluster.delegation.token.store.zookeeper.connectString</li><li>storm.zookeeper.servers</li><li>instance.zookeeper.host</li></ul>',
   'hosts.host.addComponent.NIMBUS': 'Adding Nimbus will reconfigure 
<b>nimbus.seeds</b>, <b>topology.min.replication.count</b>, 
<b>topology.max.replication.wait.time.sec</b> properties if they are defined.',
   'hosts.host.addComponent.RANGER_KMS_SERVER': 'Adding Ranger KMS Server may 
reconfigure such 
properties:<ul><li>hadoop.security.key.provider.path</li><li>dfs.encryption.key.provider.uri</li>',
   'hosts.host.addComponent.deleteHostWithZooKeeper':'Deleting host with 
ZooKeeper Server may reconfigure such 
properties:<ul><li>ha.zookeeper.quorum</li><li>hbase.zookeeper.quorum</li><li>templeton.zookeeper.hosts</li><li>yarn.resourcemanager.zk-address</li><li>hive.zookeeper.quorum</li><li>hive.cluster.delegation.token.store.zookeeper.connectString</li></ul>',
@@ -2819,4 +2819,4 @@ Em.I18n.translations = {
   'utils.ajax.defaultErrorPopupBody.statusCode': '{0} status code',
 
   'wizard.inProgress': '{0} in Progress'
-};
\ No newline at end of file
+};

http://git-wip-us.apache.org/repos/asf/ambari/blob/6c38d84b/ambari-web/app/mixins.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins.js b/ambari-web/app/mixins.js
index 276e777..90fbaa2 100644
--- a/ambari-web/app/mixins.js
+++ b/ambari-web/app/mixins.js
@@ -56,3 +56,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/6c38d84b/ambari-web/app/utils/configs/add_component_config_initializer.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/configs/add_component_config_initializer.js 
b/ambari-web/app/utils/configs/add_component_config_initializer.js
new file mode 100644
index 0000000..6fc505c
--- /dev/null
+++ b/ambari-web/app/utils/configs/add_component_config_initializer.js
@@ -0,0 +1,303 @@
+/**
+ * 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');
+require('utils/configs/config_initializer_class');
+require('utils/configs/ha_config_initializer_class');
+require('utils/configs/hosts_based_initializer_mixin');
+require('utils/configs/control_flow_initializer_mixin');
+
+var _slice = Array.prototype.slice;
+
+/**
+ * Main class responsible for properties computation.
+ * This class contains all required info to manipulate properties regarding 
value updates
+ * during removing/adding components.
+ * To determine when component removed or added you just need to setup 
properly localDB object
+ * and set `isInstalled` flag to `true` where selected component(s) will be 
located after adding/removing.
+ * By default all initializer handlers filtering localDB by `isInstalled` 
`true`.
+ *
+ * @mixes App.ControlFlowInitializerMixin
+ * @mixes App.HostsBasedInitializerMixin
+ * @type {AddComponentConfigInitializer}
+ * @augments {HaConfigInitializerClass}
+ */
+App.AddComponentConfigInitializer = 
App.HaConfigInitializerClass.extend(App.HostsBasedInitializerMixin, 
App.ControlFlowInitializerMixin, {
+  /**
+   * All initializer properties definition.
+   * Object format is the same as for App.ConfigInitializerClass.initializers
+   * @see App.ConfigInitializerClass.initializers
+   *
+   * @return {object} property name - initializer map
+   */
+  __defaultInitializers: function() {
+    return {
+      'ha.zookeeper.quorum': 
this.getNameNodeHAOnlyHostsPortConfig('ZOOKEEPER_SERVER', '', '', ',', 
'zkClientPort', true),
+      'hbase.zookeeper.quorum': 
this.getHostsListComponentConfig('ZOOKEEPER_SERVER', true),
+      'instance.zookeeper.host': 
this.getHostsWithPortConfig('ZOOKEEPER_SERVER', '', '', ',', 'zkClientPort', 
true),
+      'templeton.zookeeper.hosts': 
this.getHostsWithPortConfig('ZOOKEEPER_SERVER', '', '', ',', 'zkClientPort', 
true),
+      'hive.cluster.delegation.token.store.zookeeper.connectString': 
this.getHostsWithPortConfig('ZOOKEEPER_SERVER', '', '', ',', 'zkClientPort', 
true),
+      'storm.zookeeper.servers': 
this.getHostsListComponentJSONStringifiedConfig('ZOOKEEPER_SERVER', true),
+      'hive.zookeeper.quorum': this.getHDPStackOnlyHostsPortConfig('2.2', 
'ZOOKEEPER_SERVER', '', '', ',', 'zkClientPort', true),
+      'hadoop.registry.zk.quorum': this.getHDPStackOnlyHostsPortConfig('2.2', 
'ZOOKEEPER_SERVER', '', '', ',', 'zkClientPort', true),
+      'nimbus.seeds': 
this.getHostsListComponentJSONStringifiedConfig('NIMBUS', true),
+      'hadoop.proxyuser.{{hiveUser}}.hosts': 
this.getComponentsHostsConfig(['HIVE_SERVER', 'WEBHCAT_SERVER', 
'HIVE_METASTORE'], false),
+      'hadoop.proxyuser.{{webhcatUser}}.hosts': 
this.getComponentsHostsConfig(['HIVE_SERVER', 'WEBHCAT_SERVER', 
'HIVE_METASTORE'], false, true),
+      'hadoop.proxyuser.{{hiveUser}}.hosts': 
this.getComponentsHostsConfig(['HIVE_SERVER', 'WEBHCAT_SERVER', 
'HIVE_METASTORE'], false, true),
+      'hive.metastore.uris': this.getHostsWithPortConfig(['WEBHCAT_SERVER', 
'HIVE_METASTORE'], 'thrift://', '', ',thrift://', 'hiveMetastorePort', true)
+    };
+  },
+
+  /**
+   * All unique initializer definition.
+   * Object format is the same as for 
App.ConfigInitializerClass.uniqueInitializers
+   * @see App.ConfigInitializerClass.uniqueInitializers
+   *
+   * @type {Object}
+   */
+  __defaultUniqueInitializers: {
+    'yarn.resourcemanager.zk-address': '_initYarnRMZkAdress',
+    'templeton.hive.properties': '_initTempletonHiveProperties'
+  },
+
+  /**
+   * Property names to initialize. This attribute should be overrided in class 
instance.
+   * `initializers` property will set up according this list from 
`__defaultUniqueInitializers` and
+   * `__defaultInitializers`
+   *
+   * @type {string[]}
+   */
+  initializeForProperties: null,
+
+  initializers: function() {
+    return {};
+  }.property(),
+
+  uniqueInitializers: {},
+
+  init: function() {
+    this._super();
+    this._bootstrapInitializers(this.get('initializeForProperties'));
+  },
+
+  initializerTypes: [
+    {
+      name: 'json_stringified_value',
+      method: '_initAsJSONStrigifiedValueConfig'
+    }
+  ],
+
+  /**
+   * @override
+   * @param {object} settings
+   */
+  setup: function (settings) {
+    this._updateInitializers(settings);
+  },
+
+  /**
+   * @override
+   */
+  cleanup: function () {
+    this._restoreInitializers();
+  },
+
+  getJSONStringifiedValueConfig: function() {
+    return {
+      type: 'json_stringified_value'
+    };
+  },
+
+  _initAsJSONStrigifiedValueConfig: function(configProperty, localDB, 
dependencies, initializer) {
+    var hostsValue = Em.get(configProperty, 
'value').split(Em.getWithDefault(initializer, 'modifier.delimiter', ','));
+    var propertyValue = JSON.stringify(hostsValue).replace(/"/g, "'");
+    Em.setProperties(configProperty, {
+      value: propertyValue,
+      recommendedValue: propertyValue
+    });
+    return configProperty;
+  },
+
+  /**
+   * Perform value update according to hosts. Mutate <code>siteConfigs</code>
+   *
+   * @param {object} siteConfigs
+   * @param {configProperty} configProperty
+   * @returns {boolean}
+   */
+  updateSiteObj: function(siteConfigs, configProperty) {
+    if (!siteConfigs || !configProperty) return false;
+    App.config.updateHostsListValue(siteConfigs, configProperty.name, 
configProperty.value);
+    return true;
+  },
+
+  /**
+   * @see App.ControlFlowInitializerMixin.getNameNodeHAControl
+   * @see App.HostsBasedInitializerMixin.getComponentsHostsConfig
+   */
+  getNameNodeHAOnlyHostsConfig: function(components, asArray) {
+    return [
+      this.getNameNodeHAControl(),
+      this.getComponentsHostsConfig.apply(this, _slice.call(arguments))
+    ];
+  },
+
+  /**
+   * @override
+   **/
+  getHostsWithPortConfig: function (component, prefix, suffix, delimiter, 
port, portFromDependencies) {
+    var ret = this._super.apply(this, _slice.call(arguments));
+    ret.componentExists = true;
+    return ret;
+  },
+
+  /**
+   * @see App.ControlFlowInitializerMixin.getNameNodeHAControl
+   * @see App.HostsBasedInitializerMixin.getHostsWithPortConfig
+   */
+  getNameNodeHAOnlyHostsPortConfig: function(component, prefix, suffix, 
delimiter, port, portFromDependencies) {
+    return [
+      this.getNameNodeHAControl(),
+      this.getHostsWithPortConfig.apply(this, _slice.call(arguments))
+    ];
+  },
+
+  /**
+   * @see App.ControlFlowInitializerMixin.getResourceManagerHAControl
+   * @see App.HostsBasedInitializerMixin.getHostsWithPortConfig
+   */
+  getResourceManagerHAOnlyHostsPortConfig: function(component, prefix, suffix, 
delimiter, port, portFromDependencies) {
+    return [
+      this.getResourceManagerHAControl(),
+      this.getHostsWithPortConfig.apply(this, _slice.call(arguments))
+    ];
+  },
+
+  /**
+   * @see App.HostsBasedInitializerMixin.getHostsListComponentConfig
+   * @see getJSONStringifiedValueConfig
+   */
+  getHostsListComponentJSONStringifiedConfig: function(component, 
componentExists, delimiter) {
+    return [
+      this.getHostsListComponentConfig.apply(this, _slice.call(arguments)),
+      this.getJSONStringifiedValueConfig()
+    ];
+  },
+
+  /**
+   * @see App.ControlFlowInitializerMixin.getHDPStackVersionControl
+   * @see App.HostsBasedInitializerMixin.getHostsWithPortConfig
+   */
+  getHDPStackOnlyHostsPortConfig: function(minStackVersion, component, prefix, 
suffix, delimiter, port, portFromDependencies) {
+    return [
+      this.getHDPStackVersionControl(minStackVersion),
+      this.getHostsWithPortConfig.apply(this, _slice.call(arguments, 1))
+    ];
+  },
+
+  _initYarnRMZkAdress: function(configProperty, localDB, dependencies) {
+    if (App.get('isRMHaEnabled') || App.get('isHadoop22Stack')) {
+      return this._initAsHostsWithPort(configProperty, localDB, dependencies, {
+        component: 'ZOOKEEPER_SERVER',
+        componentExists: true,
+        modifier: {
+          prefix: '',
+          suffix: '',
+          delimiter: ','
+        },
+        portKey: 'zkClientPort'
+      });
+    } else {
+      return configProperty;
+    }
+  },
+
+  _initTempletonHiveProperties: function(configProperty, localDB, dependecies, 
initializer) {
+    var hostNames = 
localDB.masterComponentHosts.filter(function(masterComponent) {
+      return ['WEBHCAT_SERVER', 
'HIVE_METASTORE'].contains(masterComponent.component) && 
masterComponent.isInstalled === true;
+    }).mapProperty('hostName').uniq().sort();
+    var hiveMSHosts = hostNames.map(function(hostName) {
+      return "thrift://" + hostName + ":" + dependecies.hiveMetastorePort;
+    }).join('\\,');
+    var value = configProperty.value.replace(/thrift.+[0-9]{2,},/i, 
hiveMSHosts + ",");
+    Em.setProperties(configProperty, {
+      value: value,
+      recommendedValue: value
+    });
+    return configProperty;
+  },
+
+  /**
+   * Set up `this.initializers` and `this.uniqueInitializers` properties 
according
+   * to property list names.
+   *
+   * @param  {string[]} properties list of property names
+   */
+  _bootstrapInitializers: function(properties) {
+    var initializers = {},
+     uniqueInitializers = {},
+     defaultInitializers = this.__defaultInitializers(),
+     defaultUniqueInitializers = this.get('__defaultUniqueInitializers');
+
+    if (Em.isNone(properties)) {
+      initializers = this.__defaultInitializers();
+      uniqueInitializer = this.get('__defaultUniqueInitializers');
+    } else {
+      properties.forEach(function(propertyName) {
+        if (defaultInitializers[propertyName]) {
+          initializers[propertyName] = defaultInitializers[propertyName];
+        } else if (defaultUniqueInitializers[propertyName]) {
+          uniqueInitializers[propertyName] = 
defaultUniqueInitializers[propertyName];
+        }
+      });
+    }
+    this._setForComputed('initializers', initializers);
+    this.set('uniqueInitializers', uniqueInitializers);
+  }
+});
+
+/**
+ * ZooKeeper service add/remove components initializer.
+ * @instance App.AddComponentConfigInitializer
+ */
+App.AddZooKeeperComponentsInitializer = 
App.AddComponentConfigInitializer.create({
+  initializeForProperties: [
+    'ha.zookeeper.quorum',
+    'hbase.zookeeper.quorum',
+    'instance.zookeeper.host',
+    'templeton.zookeeper.hosts',
+    'hive.cluster.delegation.token.store.zookeeper.connectString',
+    'yarn.resourcemanager.zk-address',
+    'hive.zookeeper.quorum',
+    'storm.zookeeper.servers',
+    'hadoop.registry.zk.quorum'
+  ]
+});
+
+/**
+ * Hive service add/remove components initializer.
+ * @instance App.AddComponentConfigInitializer
+ */
+App.AddHiveComponentsInitializer = App.AddComponentConfigInitializer.create({
+  initializeForProperties: [
+    'hive.metastore.uris',
+    'templeton.hive.properties',
+    'hadoop.proxyuser.{{webhcatUser}}.hosts',
+    'hadoop.proxyuser.{{hiveUser}}.hosts'
+  ]
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/6c38d84b/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 8c156bb..df520d2 100644
--- a/ambari-web/app/utils/configs/config_initializer.js
+++ b/ambari-web/app/utils/configs/config_initializer.js
@@ -17,57 +17,11 @@
  */
 
 var App = require('app');
-require('utils/configs/config_initializer_class');
 var stringUtils = require('utils/string_utils');
 
-/**
- * Regexp for host with port ('hostName:1234')
- *
- * @type {string}
- */
-var hostWithPort = "([\\w|\\.]*)(?=:)";
-
-/**
- * Regexp for host with port and protocol ('://hostName:1234')
- *
- * @type {string}
- */
-var hostWithPrefix = ":\/\/" + hostWithPort;
-
-/**
- * Regexp used to determine if mount point is windows-like
- *
- * @type {RegExp}
- */
-var winRegex = /^([a-z]):\\?$/;
-
-/**
- * Settings for <code>host_with_component</code>-initializer
- * Used for configs with value equal to hostName that has 
<code>component</code>
- * Value may be modified with if <code>withModifier</code> is true (it is by 
default)
- * <code>hostWithPort</code>-regexp will be used in this case
- *
- * @see _initAsHostWithComponent
- * @param {string} component
- * @param {boolean} [withModifier=true]
- * @return {object}
- */
-function getSimpleComponentConfig(component, withModifier) {
-  if (arguments.length === 1) {
-    withModifier = true;
-  }
-  var config = {
-    type: 'host_with_component',
-    component: component
-  };
-  if (withModifier) {
-    config.modifier = {
-      type: 'regexp',
-      regex: hostWithPort
-    }
-  }
-  return config;
-}
+require('utils/configs/config_initializer_class');
+require('utils/configs/mount_points_based_initializer_mixin');
+require('utils/configs/hosts_based_initializer_mixin');
 
 /**
  * Zookeeper-based configs don't have any customization settings
@@ -82,90 +36,6 @@ function getZKBasedConfig() {
 }
 
 /**
- * Almost the same to <code>getSimpleComponentConfig</code>, but with 
possibility to modify <code>replaceWith</code>-value
- * <code>prefix</code> is added before it
- * <code>suffix</code> is added after it
- * <code>hostWithPrefix</code>-regexp is used
- *
- * @see _initAsHostWithComponent
- * @param {string} component
- * @param {string} [prefix]
- * @param {string} [suffix]
- * @returns {object}
- */
-function getComponentConfigWithAffixes (component, prefix, suffix) {
-  prefix = prefix || '';
-  suffix = suffix || '';
-  return {
-    type: 'host_with_component',
-    component: component,
-    modifier: {
-      type: 'regexp',
-      regex: hostWithPrefix,
-      prefix: prefix,
-      suffix: suffix
-    }
-  };
-}
-
-/**
- * Settings for <code>hosts_with_components</code>-initializer
- * Used for configs with value equal to the hosts list
- * May set value as array (if <code>asArray</code> is true) or as 
comma-sepratated string (if <code>asArray</code> is false)
- *
- * @see _initAsHostsWithComponents
- * @param {string|string[]} components
- * @param {boolean} [asArray=false]
- * @returns {{type: string, components: string[], asArray: boolean}}
- */
-function getComponentsHostsConfig(components, asArray) {
-  if (1 === arguments.length) {
-    asArray = false;
-  }
-  return {
-    type: 'hosts_with_components',
-    components: Em.makeArray(components),
-    asArray: asArray
-  };
-}
-
-/**
- * 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}}
- */
-function getSingleMountPointConfig(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}}
- */
-function getMultipleMountPointsConfig(components, winReplacer) {
-  winReplacer = winReplacer || 'default';
-  return {
-    components: Em.makeArray(components),
-    winReplacer: winReplacer,
-    type: 'multiple_mountpoints'
-  }
-}
-
-/**
  * Initializer for configs
  * Used on the cluster install
  *
@@ -183,86 +53,88 @@ function getMultipleMountPointsConfig(components, 
winReplacer) {
  *
  * @instance ConfigInitializer
  */
-App.ConfigInitializer = App.ConfigInitializerClass.create({
-
-  initializers: {
-    'dfs.namenode.rpc-address': getSimpleComponentConfig('NAMENODE'),
-    'dfs.http.address': getSimpleComponentConfig('NAMENODE'),
-    'dfs.namenode.http-address': getSimpleComponentConfig('NAMENODE'),
-    'dfs.https.address': getSimpleComponentConfig('NAMENODE'),
-    'dfs.namenode.https-address': getSimpleComponentConfig('NAMENODE'),
-    'dfs.secondary.http.address': 
getSimpleComponentConfig('SECONDARY_NAMENODE'),
-    'dfs.namenode.secondary.http-address': 
getSimpleComponentConfig('SECONDARY_NAMENODE'),
-    'yarn.resourcemanager.hostname': 
getSimpleComponentConfig('RESOURCEMANAGER', false),
-    'yarn.resourcemanager.resource-tracker.address': 
getSimpleComponentConfig('RESOURCEMANAGER'),
-    'yarn.resourcemanager.webapp.https.address': 
getSimpleComponentConfig('RESOURCEMANAGER'),
-    'yarn.resourcemanager.webapp.address': 
getSimpleComponentConfig('RESOURCEMANAGER'),
-    'yarn.resourcemanager.scheduler.address': 
getSimpleComponentConfig('RESOURCEMANAGER'),
-    'yarn.resourcemanager.address': 
getSimpleComponentConfig('RESOURCEMANAGER'),
-    'yarn.resourcemanager.admin.address': 
getSimpleComponentConfig('RESOURCEMANAGER'),
-    'yarn.timeline-service.webapp.address': 
getSimpleComponentConfig('APP_TIMELINE_SERVER'),
-    'yarn.timeline-service.webapp.https.address': 
getSimpleComponentConfig('APP_TIMELINE_SERVER'),
-    'yarn.timeline-service.address': 
getSimpleComponentConfig('APP_TIMELINE_SERVER'),
-    'mapred.job.tracker': getSimpleComponentConfig('JOBTRACKER'),
-    'mapred.job.tracker.http.address': getSimpleComponentConfig('JOBTRACKER'),
-    'mapreduce.history.server.http.address': 
getSimpleComponentConfig('HISTORYSERVER'),
-    'hive_hostname': getSimpleComponentConfig('HIVE_SERVER', false),
-    'oozie_hostname': getSimpleComponentConfig('OOZIE_SERVER', false),
-    'oozie.base.url': getComponentConfigWithAffixes('OOZIE_SERVER', '://'),
-    'hawq_dfs_url': getSimpleComponentConfig('NAMENODE'),
-    'hawq_rm_yarn_address': getSimpleComponentConfig('RESOURCEMANAGER'),
-    'hawq_rm_yarn_scheduler_address': 
getSimpleComponentConfig('RESOURCEMANAGER'),
-    'fs.default.name': getComponentConfigWithAffixes('NAMENODE', '://'),
-    'fs.defaultFS': getComponentConfigWithAffixes('NAMENODE', '://'),
-    'hbase.rootdir': getComponentConfigWithAffixes('NAMENODE', '://'),
-    'instance.volumes': getComponentConfigWithAffixes('NAMENODE', '://'),
-    'yarn.log.server.url': getComponentConfigWithAffixes('HISTORYSERVER', 
'://'),
-    'mapreduce.jobhistory.webapp.address': 
getSimpleComponentConfig('HISTORYSERVER'),
-    'mapreduce.jobhistory.address': getSimpleComponentConfig('HISTORYSERVER'),
-    'kafka.ganglia.metrics.host': getSimpleComponentConfig('GANGLIA_SERVER', 
false),
-    'hive_master_hosts': getComponentsHostsConfig(['HIVE_METASTORE', 
'HIVE_SERVER']),
-    'hadoop_host': getSimpleComponentConfig('NAMENODE', false),
-    'nimbus.host': getSimpleComponentConfig('NIMBUS', false),
-    'nimbus.seeds': getComponentsHostsConfig('NIMBUS', true),
-    'storm.zookeeper.servers': getComponentsHostsConfig('ZOOKEEPER_SERVER', 
true),
-    'hawq_master_address_host': getSimpleComponentConfig('HAWQMASTER', false),
-    'hawq_standby_address_host': getSimpleComponentConfig('HAWQSTANDBY', 
false),
-
-    '*.broker.url': {
-      type: 'host_with_component',
-      component: 'FALCON_SERVER',
-      modifier: {
-        type: 'regexp',
-        regex: 'localhost'
-      }
-    },
-
-    'zookeeper.connect': getZKBasedConfig(),
-    'hive.zookeeper.quorum': getZKBasedConfig(),
-    'templeton.zookeeper.hosts': getZKBasedConfig(),
-    'hadoop.registry.zk.quorum': getZKBasedConfig(),
-    'hive.cluster.delegation.token.store.zookeeper.connectString': 
getZKBasedConfig(),
-    'instance.zookeeper.host': getZKBasedConfig(),
-
-    'dfs.name.dir': getMultipleMountPointsConfig('NAMENODE', 'file'),
-    'dfs.namenode.name.dir': getMultipleMountPointsConfig('NAMENODE', 'file'),
-    'dfs.data.dir': getMultipleMountPointsConfig('DATANODE', 'file'),
-    'dfs.datanode.data.dir': getMultipleMountPointsConfig('DATANODE', 'file'),
-    'yarn.nodemanager.local-dirs': getMultipleMountPointsConfig('NODEMANAGER'),
-    'yarn.nodemanager.log-dirs': getMultipleMountPointsConfig('NODEMANAGER'),
-    'mapred.local.dir': getMultipleMountPointsConfig(['TASKTRACKER', 
'NODEMANAGER']),
-    'log.dirs': getMultipleMountPointsConfig('KAFKA_BROKER'),
-
-    'fs.checkpoint.dir': getSingleMountPointConfig('SECONDARY_NAMENODE', 
'file'),
-    'dfs.namenode.checkpoint.dir': 
getSingleMountPointConfig('SECONDARY_NAMENODE', 'file'),
-    'yarn.timeline-service.leveldb-timeline-store.path': 
getSingleMountPointConfig('APP_TIMELINE_SERVER'),
-    'yarn.timeline-service.leveldb-state-store.path': 
getSingleMountPointConfig('APP_TIMELINE_SERVER'),
-    'dataDir': getSingleMountPointConfig('ZOOKEEPER_SERVER'),
-    'oozie_data_dir': getSingleMountPointConfig('OOZIE_SERVER'),
-    'storm.local.dir': getSingleMountPointConfig(['NODEMANAGER', 'NIMBUS']),
-    '*.falcon.graph.storage.directory': 
getSingleMountPointConfig('FALCON_SERVER'),
-    '*.falcon.graph.serialize.path': getSingleMountPointConfig('FALCON_SERVER')
-  },
+App.ConfigInitializer = 
App.ConfigInitializerClass.create(App.MountPointsBasedInitializerMixin, 
App.HostsBasedInitializerMixin, {
+
+  initializers: function() {
+    return {
+      'dfs.namenode.rpc-address': this.getSimpleComponentConfig('NAMENODE'),
+      'dfs.http.address': this.getSimpleComponentConfig('NAMENODE'),
+      'dfs.namenode.http-address': this.getSimpleComponentConfig('NAMENODE'),
+      'dfs.https.address': this.getSimpleComponentConfig('NAMENODE'),
+      'dfs.namenode.https-address': this.getSimpleComponentConfig('NAMENODE'),
+      'dfs.secondary.http.address': 
this.getSimpleComponentConfig('SECONDARY_NAMENODE'),
+      'dfs.namenode.secondary.http-address': 
this.getSimpleComponentConfig('SECONDARY_NAMENODE'),
+      'yarn.resourcemanager.hostname': 
this.getSimpleComponentConfig('RESOURCEMANAGER', false),
+      'yarn.resourcemanager.resource-tracker.address': 
this.getSimpleComponentConfig('RESOURCEMANAGER'),
+      'yarn.resourcemanager.webapp.https.address': 
this.getSimpleComponentConfig('RESOURCEMANAGER'),
+      'yarn.resourcemanager.webapp.address': 
this.getSimpleComponentConfig('RESOURCEMANAGER'),
+      'yarn.resourcemanager.scheduler.address': 
this.getSimpleComponentConfig('RESOURCEMANAGER'),
+      'yarn.resourcemanager.address': 
this.getSimpleComponentConfig('RESOURCEMANAGER'),
+      'yarn.resourcemanager.admin.address': 
this.getSimpleComponentConfig('RESOURCEMANAGER'),
+      'yarn.timeline-service.webapp.address': 
this.getSimpleComponentConfig('APP_TIMELINE_SERVER'),
+      'yarn.timeline-service.webapp.https.address': 
this.getSimpleComponentConfig('APP_TIMELINE_SERVER'),
+      'yarn.timeline-service.address': 
this.getSimpleComponentConfig('APP_TIMELINE_SERVER'),
+      'mapred.job.tracker': this.getSimpleComponentConfig('JOBTRACKER'),
+      'mapred.job.tracker.http.address': 
this.getSimpleComponentConfig('JOBTRACKER'),
+      'mapreduce.history.server.http.address': 
this.getSimpleComponentConfig('HISTORYSERVER'),
+      'hive_hostname': this.getSimpleComponentConfig('HIVE_SERVER', false),
+      'oozie_hostname': this.getSimpleComponentConfig('OOZIE_SERVER', false),
+      'oozie.base.url': this.getComponentConfigWithAffixes('OOZIE_SERVER', 
'://'),
+      'hawq_dfs_url': this.getSimpleComponentConfig('NAMENODE'),
+      'hawq_rm_yarn_address': this.getSimpleComponentConfig('RESOURCEMANAGER'),
+      'hawq_rm_yarn_scheduler_address': 
this.getSimpleComponentConfig('RESOURCEMANAGER'),
+      'fs.default.name': this.getComponentConfigWithAffixes('NAMENODE', '://'),
+      'fs.defaultFS': this.getComponentConfigWithAffixes('NAMENODE', '://'),
+      'hbase.rootdir': this.getComponentConfigWithAffixes('NAMENODE', '://'),
+      'instance.volumes': this.getComponentConfigWithAffixes('NAMENODE', 
'://'),
+      'yarn.log.server.url': 
this.getComponentConfigWithAffixes('HISTORYSERVER', '://'),
+      'mapreduce.jobhistory.webapp.address': 
this.getSimpleComponentConfig('HISTORYSERVER'),
+      'mapreduce.jobhistory.address': 
this.getSimpleComponentConfig('HISTORYSERVER'),
+      'kafka.ganglia.metrics.host': 
this.getSimpleComponentConfig('GANGLIA_SERVER', false),
+      'hive_master_hosts': this.getComponentsHostsConfig(['HIVE_METASTORE', 
'HIVE_SERVER']),
+      'hadoop_host': this.getSimpleComponentConfig('NAMENODE', false),
+      'nimbus.host': this.getSimpleComponentConfig('NIMBUS', false),
+      'nimbus.seeds': this.getComponentsHostsConfig('NIMBUS', true),
+      'storm.zookeeper.servers': 
this.getComponentsHostsConfig('ZOOKEEPER_SERVER', true),
+      'hawq_master_address_host': this.getSimpleComponentConfig('HAWQMASTER', 
false),
+      'hawq_standby_address_host': 
this.getSimpleComponentConfig('HAWQSTANDBY', false),
+
+      '*.broker.url': {
+        type: 'host_with_component',
+        component: 'FALCON_SERVER',
+        modifier: {
+          type: 'regexp',
+          regex: 'localhost'
+        }
+      },
+
+      'zookeeper.connect': getZKBasedConfig(),
+      'hive.zookeeper.quorum': getZKBasedConfig(),
+      'templeton.zookeeper.hosts': getZKBasedConfig(),
+      'hadoop.registry.zk.quorum': getZKBasedConfig(),
+      'hive.cluster.delegation.token.store.zookeeper.connectString': 
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(''),
 
   uniqueInitializers: {
     'hadoop.registry.rm.enabled': '_setYarnSliderDependency',
@@ -276,28 +148,12 @@ App.ConfigInitializer = 
App.ConfigInitializerClass.create({
   },
 
   initializerTypes: [
-    {name: 'host_with_component', method: '_initAsHostWithComponent'},
-    {name: 'hosts_with_components', method: '_initAsHostsWithComponents'},
     {name: 'zookeeper_based', method: '_initAsZookeeperServersList'},
     {name: 'single_mountpoint', method: '_initAsSingleMountPoint'},
     {name: 'multiple_mountpoints', method: '_initAsMultipleMountPoints'}
   ],
 
   /**
-   * 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'
-  },
-
-  /**
    * Some strange method that should define <code>ranger_admin_password</code>
    * TODO DELETE as soon as <code>ranger_admin_password</code> will be fetched 
from stack adviser!
    *
@@ -329,65 +185,6 @@ App.ConfigInitializer = App.ConfigInitializerClass.create({
   },
 
   /**
-   * Initializer for configs with value equal to hostName with needed component
-   * Value example: 'hostName'
-   *
-   * @param {configProperty} configProperty
-   * @param {topologyLocalDB} localDB
-   * @param {object} dependencies
-   * @param {object} initializer
-   * @returns {Object}
-   * @private
-   */
-  _initAsHostWithComponent: function (configProperty, localDB, dependencies, 
initializer) {
-    var component = localDB.masterComponentHosts.findProperty('component', 
initializer.component);
-    if (!component) {
-      return configProperty;
-    }
-    if (initializer.modifier) {
-      var replaceWith = Em.getWithDefault(initializer.modifier, 'prefix', '')
-        + component.hostName
-        + Em.getWithDefault(initializer.modifier, 'suffix', '');
-      this.setRecommendedValue(configProperty, initializer.modifier.regex, 
replaceWith);
-    }
-    else {
-      Em.setProperties(configProperty, {
-        recommendedValue: component.hostName,
-        value: component.hostName
-      })
-    }
-
-    return configProperty;
-  },
-
-  /**
-   * Initializer for configs with value equal to hostNames with needed 
components
-   * May be array or comma-separated list
-   * Depends on <code>initializer.asArray</code> (true - array, false - string)
-   * Value example: 'hostName1,hostName2,hostName3' or ['hostName1', 
'hostName2', 'hostName3']
-   *
-   * @param {configProperty} configProperty
-   * @param {topologyLocalDB} localDB
-   * @param {object} dependencies
-   * @param {object} initializer
-   * @return {Object}
-   * @private
-   */
-  _initAsHostsWithComponents: function (configProperty, localDB, dependencies, 
initializer) {
-    var hostNames = localDB.masterComponentHosts.filter(function 
(masterComponent) {
-      return initializer.components.contains(masterComponent.component);
-    }).mapProperty('hostName');
-    if (!initializer.asArray) {
-      hostNames = hostNames.uniq().join(',');
-    }
-    Em.setProperties(configProperty, {
-      value: hostNames,
-      recommendedValue: hostNames
-    });
-    return configProperty;
-  },
-
-  /**
    * Unique initializer for <code>hive_database</code>-config
    *
    * @param {configProperty} configProperty
@@ -508,7 +305,7 @@ App.ConfigInitializer = App.ConfigInitializerClass.create({
    */
   _initYarnRMzkAddress: function (configProperty, localDB, dependencies) {
     var value = localDB.masterComponentHosts.filterProperty('component', 
'ZOOKEEPER_SERVER').map(function (component) {
-      return component.hostName + ':' + dependencies.clientPort
+      return component.hostName + ':' + dependencies.clientPort;
     }).join(',');
     Em.setProperties(configProperty, {
       value: value,
@@ -577,252 +374,5 @@ App.ConfigInitializer = 
App.ConfigInitializerClass.create({
     Em.set(configProperty, 'value', value);
     Em.set(configProperty, 'initialValue', value);
     return configProperty;
-  },
-
-  /**
-   * 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);
-
-    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);
-    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>
-   * </ul>
-   *
-   * @param {{mountpoint: string, available: number}} mPoint
-   * @returns {boolean} true - valid, false - invalid
-   * @private
-   */
-  _filterMountPoint: function (mPoint) {
-    var isAvailable = mPoint.available !== 0;
-    if (!isAvailable) {
-      return false;
-    }
-
-    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'));
-    var notDev = !(['devtmpfs', 'tmpfs', 'vboxsf', 
'CDFS'].contains(mPoint.type));
-
-    return notHome && notDocker && notBoot && notDev;
-  },
-
-  /**
-   * 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
-   * @returns {string[]}
-   * @private
-   */
-  _getAllMountPoints: function (setOfHostNames, hostsInfo) {
-    var allMountPoints = [];
-    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(this._filterMountPoint).forEach(function 
(mPoint) {
-        if( !allMountPoints.findProperty("mountpoint", mPoint.mountpoint)) {
-          allMountPoints.push(mPoint);
-        }
-      }, this);
-    }
-
-    if (!allMountPoints.length) {
-      allMountPoints.push(mountPointAsRoot);
-    }
-    return allMountPoints;
   }
-
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/6c38d84b/ambari-web/app/utils/configs/config_initializer_class.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/configs/config_initializer_class.js 
b/ambari-web/app/utils/configs/config_initializer_class.js
index 3e96fca..0663bc3 100644
--- a/ambari-web/app/utils/configs/config_initializer_class.js
+++ b/ambari-web/app/utils/configs/config_initializer_class.js
@@ -19,6 +19,12 @@
 var App = require('app');
 
 /**
+ * @typedef {object} initializer
+ * @property {string} type initializer type name
+ * @property {boolean} [isChecker] determines control flow callback
+ */
+
+/**
  * @typedef {object} initializerType
  * @property {string} name key
  * @property {string} method function's name (prefer to start method-name with 
'_init' or '_initAs'). Each method here is called with arguments equal to 
<code>initialValue</code>-call args. Initializer-settings are added as last 
argument
@@ -32,6 +38,7 @@ var App = require('app');
  * @property {string} name config's name
  * @property {number|string} value current value
  * @property {string} filename file name where this config is
+ * @property {number|string} [recommendedValue] value which is recommended
  */
 
 /**
@@ -73,13 +80,19 @@ var App = require('app');
  */
 App.ConfigInitializerClass = Em.Object.extend({
 
+  _initializerFlowCode: {
+    next: 0,
+    skipNext: 1,
+    skipAll: 2
+  },
+
   concatenatedProperties: ['initializerTypes'],
 
   /**
    * Map with configurations for config initializers
    * It's used only for initializers which are common for some configs (if not 
- use <code>uniqueInitializers</code>-map)
    * Key {string} configProperty-name
-   * Value {object|object[]} settings for initializer
+   * Value {initializer|initializer[]} settings for initializer
    *
    * @type {object}
    */
@@ -121,15 +134,31 @@ App.ConfigInitializerClass = Em.Object.extend({
     var initializer = initializers[Em.get(configProperty, 'name')];
     if (initializer) {
       initializer = Em.makeArray(initializer);
-      initializer.forEach(function (init) {
+      var i = 0;
+      while(i < initializer.length) {
+        var init = initializer[i];
         var _args = [].slice.call(args);
         var type = initializerTypes.findProperty('name', init.type);
         // add initializer-settings
         _args.push(init);
         var methodName = type.method;
         Em.assert('method-initializer is not a function ' + methodName, 
'function' === Em.typeOf(self[methodName]));
-        configProperty = self[methodName].apply(self, _args);
-      });
+        if (init.isChecker) {
+          var result = self[methodName].apply(self, _args);
+          if (result === this.flowSkipNext()) {
+            i++; // skip next
+          }
+          else {
+            if (result === this.flowSkipAll()) {
+              break;
+            }
+          }
+        }
+        else {
+          configProperty = self[methodName].apply(self, _args);
+        }
+        i++;
+      }
     }
     return configProperty;
   },
@@ -148,7 +177,6 @@ App.ConfigInitializerClass = Em.Object.extend({
   initialValue: function (configProperty, localDB, dependencies) {
     var configName = Em.get(configProperty, 'name');
     var initializers = this.get('initializers');
-
     var initializer = initializers[configName];
     if (initializer) {
       return this._defaultInitializer(configProperty, localDB, dependencies);
@@ -239,13 +267,13 @@ App.ConfigInitializerClass = Em.Object.extend({
     var copyInitializers = Em.copy(originalInitializers, true);
     this.set('__copyInitializers', copyInitializers);
     var initializers = this._updateNames('initializers', settings);
-    this.set('initializers', initializers);
+    this._setForComputed('initializers', initializers);
 
     var originalUniqueInitializers = this.get('uniqueInitializers');
     var copyUniqueInitializers = Em.copy(originalUniqueInitializers, true);
     this.set('__copyUniqueInitializers', copyUniqueInitializers);
     var uniqueInitializers = this._updateNames('uniqueInitializers', settings);
-    this.set('uniqueInitializers', uniqueInitializers);
+    this._setForComputed('uniqueInitializers', uniqueInitializers);
   },
 
   /**
@@ -257,10 +285,10 @@ App.ConfigInitializerClass = Em.Object.extend({
     var copyInitializers = this.get('__copyInitializers');
     var copyUniqueInitializers = this.get('__copyUniqueInitializers');
     if ('object' === Em.typeOf(copyInitializers)) {
-      this.set('initializers', Em.copy(copyInitializers, true));
+      this._setForComputed('initializers', Em.copy(copyInitializers, true));
     }
     if ('object' === Em.typeOf(copyUniqueInitializers)) {
-      this.set('uniqueInitializers', Em.copy(copyUniqueInitializers, true));
+      this._setForComputed('uniqueInitializers', 
Em.copy(copyUniqueInitializers, true));
     }
   },
 
@@ -293,6 +321,55 @@ App.ConfigInitializerClass = Em.Object.extend({
       source[configName] = initializer;
     });
     return source;
-  }
+  },
+
+  flowNext: function() {
+    return this.get('_initializerFlowCode.next');
+  },
+
+  flowSkipNext: function() {
+    return this.get('_initializerFlowCode.skipNext');
+  },
+
+  flowSkipAll: function() {
+    return this.get('_initializerFlowCode.skipAll');
+  },
 
+  /**
+   * Set value for computed property using `reopen`. Currently used to update 
'initializers'
+   * and 'uniqueInitializers'.
+   * Used to set value for props like:
+   * <code>cp: function() { }.property()</code>
+   * <code>
+   * var obj = App.ConfigInitializerClass.create({
+   *   cp: function() {
+   *                   return {
+   *                   key: "value"
+   *                   }
+   *   }.property(),
+   *   setProp: function() {
+   *                   this.set('cp', {newKey: "new_value"}); // will not 
change `cp` value
+   *   },
+   *   updateProp: function() {
+   *                   this._setForComputed('cp', { newKey: "new_value"}); // 
will update
+   *   }
+   * });
+   *
+   * obj.get('cp'); // {key: "value"}
+   * obj.setProp();
+   * obj.get('cp'); // {key: "value"}
+   * obj.updateProp();
+   * obj.get('cp'); // {newKey: "new_value"}
+   * </code>
+   * @private
+   * @param  {string} key
+   * @param  {*} value
+   */
+  _setForComputed: function(key, value) {
+    var obj = {};
+    obj[key] = function() {
+      return value;
+    }.property();
+    this.reopen(obj);
+  }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/6c38d84b/ambari-web/app/utils/configs/control_flow_initializer_mixin.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/configs/control_flow_initializer_mixin.js 
b/ambari-web/app/utils/configs/control_flow_initializer_mixin.js
new file mode 100644
index 0000000..5247586
--- /dev/null
+++ b/ambari-web/app/utils/configs/control_flow_initializer_mixin.js
@@ -0,0 +1,127 @@
+/**
+ * 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');
+var stringUtils = require('utils/string_utils');
+
+/**
+ * Mixin with preconfigured initializers that helps to build conditional 
execution
+ * based on exit code from App.ConfigInitializerClass._initializerFlowCode.
+ * Each control flow initializer should has attribute <b>isChecker: true</b>
+ * Each handler should return exit code value based on 
App.ConfigInitializerClass._initializerFlowCode.
+ *
+ * There are few methods:
+ * @see App.ConfigInitializerClass.flowNext
+ * @see App.ConfigInitializerClass.flowSkipNext
+ * @see App.ConfigInitializerClass.flowSkipAll
+ *
+ * For details and examples @see App.AddComponentConfigInitializer
+ *
+ * @mixin App.ControlFlowInitializerMixin
+ */
+App.ControlFlowInitializerMixin = Em.Mixin.create({
+
+  initializerTypes: [
+    {
+      name: 'namenode_ha_enabled',
+      method: '_initNameNodeHACheck'
+    },
+    {
+      name: 'resourcemanager_ha_enabled',
+      method: '_initResourceManagerHACheck'
+    },
+    {
+      name: 'hdp_stack_version_checker',
+      method: '_initHDPStackVersionCheck'
+    }
+  ],
+
+  /**
+   * Control flow initializer based on minimal stack version.
+   *
+   * @param  {string} minStackVersionNumber
+   * @return {object}
+   */
+  getHDPStackVersionControl: function(minStackVersionNumber) {
+    return { type: 'hdp_stack_version_checker', isChecker: true, stackVersion: 
minStackVersionNumber };
+  },
+
+  /**
+   * getHDPStackVersionControl handler.
+   * When stack version satisfies passed minStackVersionNumber computation 
process will continue.
+   * If not all next computation will be skipped.
+   *
+   * @param  {configProperty} configProperty
+   * @param  {topologyLocalDB} localDB
+   * @param  {dependencies} dependencies
+   * @param  {initializer} initializer
+   * @return {number} _initializerFlowCode exit code
+   */
+  _initHDPStackVersionCheck: function(configProperty, localDB, dependencies, 
initializer) {
+    return (stringUtils.compareVersions(App.get('currentStackVersionNumber'), 
initializer.stackVersion) > -1) ?
+      this.flowNext() :
+      this.flowSkipAll();
+  },
+
+  /**
+   * Control flow initializer based on NameNode HA Status.
+   *
+   * @return {initializer}
+   */
+  getNameNodeHAControl: function() {
+    return { type: 'namenode_ha_enabled', isChecker: true };
+  },
+
+  /**
+   * getNameNodeHAControl handler.
+   * When NameNode HA enabled next computation will be performed, either next 
will be skipped.
+   *
+   * @param  {configProperty} configProperty
+   * @param  {topologyLocalDB} localDB
+   * @param  {dependencies} dependencies
+   * @param  {initializer} initializer
+   * @return {number} _initializerFlowCode exit code
+   */
+  _initNameNodeHACheck: function(configProperty, localDB, dependencies) {
+    return App.get('isHaEnabled') ? this.flowNext() : this.flowSkipNext();
+  },
+
+  /**
+   * Control flow initializer based on ResourceManager HA Status.
+   *
+   * @return {initializer}
+   */
+  getResourceManagerHAControl: function(trueBranch, falseBranch) {
+    return { type: 'resourcemanager_ha_enabled', isChecker: true };
+  },
+
+  /**
+   * getResourceManagerHAControl handler.
+   * When ResourceManager HA enabled next computation will be performed, 
either next will be skipped.
+   *
+   * @param  {configProperty} configProperty
+   * @param  {topologyLocalDB} localDB
+   * @param  {dependencies} dependencies
+   * @param  {initializer} initializer
+   * @return {number} _initializerFlowCode exit code
+   */
+  _initResourceManagerHACheck: function(configProperty, localDB, dependencies) 
{
+    return App.get('isRMHaEnabled') ? this.flowNext() : this.flowSkipNext();
+  }
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/6c38d84b/ambari-web/app/utils/configs/ha_config_initializer_class.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/configs/ha_config_initializer_class.js 
b/ambari-web/app/utils/configs/ha_config_initializer_class.js
index e7ade94..3477ef1 100644
--- a/ambari-web/app/utils/configs/ha_config_initializer_class.js
+++ b/ambari-web/app/utils/configs/ha_config_initializer_class.js
@@ -28,171 +28,6 @@ App.HaConfigInitializerClass = 
App.ConfigInitializerClass.extend({
   initializerTypes: [
     {name: 'host_with_port', method: '_initAsHostWithPort'},
     {name: 'hosts_with_port', method: '_initAsHostsWithPort'}
-  ],
-
-  /**
-   * Initializer for configs with value equal to the hostName where some 
component exists
-   * Value may be customized with prefix and suffix (see 
<code>initializer.modifier</code>)
-   * Port-value is calculated according to <code>initializer.portKey</code> or 
<code>initializer.port</code> values
-   * If calculated port-value is empty, it will be skipped (and ':' too)
-   * Value-examples: 'SOME_COOL_PREFIXhost1:port1SOME_COOL_SUFFIX', 
'host1:port2'
-   *
-   * @param {configProperty} configProperty
-   * @param {extendedTopologyLocalDB} localDB
-   * @param {nnHaConfigDependencies} dependencies
-   * @param {object} initializer
-   * @returns {object}
-   * @private
-   * @method _initAsHostWithPort
-   */
-  _initAsHostWithPort: function (configProperty, localDB, dependencies, 
initializer) {
-    var hostName = localDB.masterComponentHosts.filterProperty('component', 
initializer.component).findProperty('isInstalled', 
initializer.componentExists).hostName;
-    var port = this.__getPort(dependencies, initializer);
-    var value = initializer.modifier.prefix + hostName + (port ? ':' + port : 
'') + initializer.modifier.suffix;
-    Em.setProperties(configProperty, {
-      value: value,
-      recommendedValue: value
-    });
-    return configProperty;
-  },
-
-  /**
-   * Initializer for configs with value equal to the list of hosts where some 
component exists
-   * Value may be customized with prefix and suffix (see 
<code>initializer.modifier</code>)
-   * Delimiter between hostNames also may be customized in the 
<code>initializer.modifier</code>
-   * Port-value is calculated according to <code>initializer.portKey</code> or 
<code>initializer.port</code> values
-   * If calculated port-value is empty, it will be skipped (and ':' too)
-   * Value examples: 
'SOME_COOL_PREFIXhost1:port,host2:port,host2:portSOME_COOL_SUFFIX', 
'host1:port|||host2:port|||host2:port'
-   *
-   * @param {configProperty} configProperty
-   * @param {topologyLocalDB} localDB
-   * @param {nnHaConfigDependencies} dependencies
-   * @param {object} initializer
-   * @returns {object}
-   * @private
-   * @method _initAsHostsWithPort
-   */
-  _initAsHostsWithPort: function (configProperty, localDB, dependencies, 
initializer) {
-    var hostNames = localDB.masterComponentHosts.filterProperty('component', 
initializer.component).mapProperty('hostName');
-    var port = this.__getPort(dependencies, initializer);
-    var value = initializer.modifier.prefix + hostNames.map(function 
(hostName) {
-        return hostName + (port ? ':' + port : '');
-      }).join(initializer.modifier.delimiter) + initializer.modifier.suffix;
-    Em.setProperties(configProperty, {
-      value: value,
-      recommendedValue: value
-    });
-    return configProperty;
-  },
-
-  /**
-   * Returns port-value from <code>dependencies</code> accorfing to 
<code>initializer.portKey</code> or <code>initializer.port</code> values
-   *
-   * @param {nnHaConfigDependencies} dependencies
-   * @param {object} initializer
-   * @returns {string|number}
-   * @private
-   * @method __getPort
-   */
-  __getPort: function (dependencies, initializer) {
-    var portKey = initializer.portKey;
-    if (portKey) {
-      return  dependencies[portKey];
-    }
-    return initializer.port;
-  }
-
-});
-
-App.HaConfigInitializerClass.reopenClass({
-
-  /**
-   * Settings for <code>host_with_port</code>-initializer
-   * Used for configs with value equal to hostName where some component exists 
concatenated with port-value
-   * Port-value is calculated according to <code>port</code> and 
<code>portFromDependencies</code> values
-   * If <code>portFromDependencies</code> is <code>true</code>, 
<code>port</code>-value is used as key of the <code>dependencies</code> (where 
real port-value is)
-   * Otherwise - <code>port</code>-value used as is
-   * If calculated port-value is empty, it will be skipped (and ':' too)
-   * Value also may be customized with prefix and suffix
-   *
-   * @param {string} component needed component
-   * @param {boolean} componentExists component already exists or just going 
to be installed
-   * @param {string} prefix=''
-   * @param {string} suffix=''
-   * @param {string} port
-   * @param {boolean} [portFromDependencies=false]
-   * @returns {{type: string, component: string, componentExists: boolean, 
modifier: {prefix: (string), suffix: (string)}}}
-   * @method getHostWithPortConfig
-   * @static
-   */
-  getHostWithPortConfig: function (component, componentExists, prefix, suffix, 
port, portFromDependencies) {
-    if (arguments.length < 6) {
-      portFromDependencies = false;
-    }
-    prefix = prefix || '';
-    suffix = suffix || '';
-    var ret = {
-      type: 'host_with_port',
-      component: component,
-      componentExists: componentExists,
-      modifier: {
-        prefix: prefix,
-        suffix: suffix
-      }
-    };
-    if (portFromDependencies) {
-      ret.portKey = port;
-    }
-    else {
-      ret.port = port;
-    }
-    return ret;
-  },
-
-  /**
-   * Settings for <code>hosts_with_port</code>-initializer
-   * Used for configs with value equal to the list of hostNames with port
-   * Value also may be customized with prefix, suffix and delimiter between 
host:port elements
-   * Port-value is calculated according to <code>port</code> and 
<code>portFromDependencies</code> values
-   * If <code>portFromDependencies</code> is <code>true</code>, 
<code>port</code>-value is used as key of the <code>dependencies</code> (where 
real port-value is)
-   * Otherwise - <code>port</code>-value used as is
-   * If calculated port-value is empty, it will be skipped (and ':' too)
-   *
-   * @param {string} component hosts where this component exists are used as 
config-value
-   * @param {string} prefix='' substring added before hosts-list
-   * @param {string} suffix='' substring added after hosts-list
-   * @param {string} delimiter=',' delimiter between hosts in the value
-   * @param {string} port if <code>portFromDependencies</code> is 
<code>false</code> this value is used as port for hosts
-   * if <code>portFromDependencies</code> is <code>true</code> `port` is used 
as key in the <code>dependencies</code> to get real port-value
-   * @param {boolean} portFromDependencies=false true - use <code>port</code> 
as key for <code>dependencies</code> to get real port-value,
-   * false - use <code>port</code> as port-value
-   * @returns {{type: string, component: string, modifier: {prefix: (string), 
suffix: (string), delimiter: (string)}}}
-   * @method getHostsWithPortConfig
-   * @static
-   */
-  getHostsWithPortConfig: function (component, prefix, suffix, delimiter, 
port, portFromDependencies) {
-    if (arguments.length < 6) {
-      portFromDependencies = false;
-    }
-    prefix = prefix || '';
-    suffix = suffix || '';
-    delimiter = delimiter || ',';
-    var ret = {
-      type: 'hosts_with_port',
-      component: component,
-      modifier: {
-        prefix: prefix,
-        suffix: suffix,
-        delimiter: delimiter
-      }
-    };
-    if (portFromDependencies) {
-      ret.portKey = port;
-    }
-    else {
-      ret.port = port;
-    }
-    return ret;
-  }
+  ]
 
 });
\ No newline at end of file

Reply via email to