You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ab...@apache.org on 2017/02/23 13:15:30 UTC

[1/4] ambari git commit: AMBARI-20143 Merge changes in branch-feature-preview-configs to branch-2.5. (ababiichuk)

Repository: ambari
Updated Branches:
  refs/heads/branch-2.5 ac19fd107 -> 304bd0605


http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/test/controllers/main/service/reassign/step4_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/service/reassign/step4_controller_test.js b/ambari-web/test/controllers/main/service/reassign/step4_controller_test.js
index 362153a..612efd0 100644
--- a/ambari-web/test/controllers/main/service/reassign/step4_controller_test.js
+++ b/ambari-web/test/controllers/main/service/reassign/step4_controller_test.js
@@ -19,6 +19,7 @@
 var App = require('app');
 
 require('controllers/main/service/reassign/step4_controller');
+require('controllers/main/service/reassign_controller');
 var testHelpers = require('test/helpers');
 
 describe('App.ReassignMasterWizardStep4Controller', function () {
@@ -30,71 +31,6 @@ describe('App.ReassignMasterWizardStep4Controller', function () {
     })
   });
 
-  describe('#setAdditionalConfigs()', function () {
-
-    beforeEach(function () {
-      sinon.stub(App, 'get').withArgs('isHaEnabled').returns(true);
-    });
-
-    afterEach(function () {
-      App.get.restore();
-    });
-
-    it('Component is absent', function () {
-      controller.set('additionalConfigsMap', []);
-      var configs = {};
-
-      expect(controller.setAdditionalConfigs(configs, 'COMP1', '')).to.be.false;
-      expect(configs).to.eql({});
-    });
-
-    it('configs for Hadoop 2 is present', function () {
-      controller.set('additionalConfigsMap', [
-        {
-          componentName: 'COMP1',
-          configs: {
-            'test-site': {
-              'property1': '<replace-value>:1111'
-            }
-          },
-          configs_Hadoop2: {
-            'test-site': {
-              'property2': '<replace-value>:2222'
-            }
-          }
-        }
-      ]);
-      var configs = {
-        'test-site': {}
-      };
-
-      expect(controller.setAdditionalConfigs(configs, 'COMP1', 'host1')).to.be.true;
-      expect(configs).to.eql({
-        'test-site': {
-          'property2': 'host1:2222'
-        }
-      });
-    });
-
-    it('ignore some configs for NameNode after HA', function () {
-      controller.set('additionalConfigsMap', [
-        {
-          componentName: 'NAMENODE',
-          configs: {
-            'test-site': {
-              'fs.defaultFS': '<replace-value>:1111',
-              'dfs.namenode.rpc-address': '<replace-value>:1111'
-            }
-          }
-        }
-      ]);
-      var configs = {'test-site': {}};
-
-      expect(controller.setAdditionalConfigs(configs, 'NAMENODE', 'host1')).to.be.true;
-      expect(configs).to.eql({'test-site': {}});
-    });
-  });
-
   describe('#getHostComponentsNames()', function () {
     it('No host-components', function () {
       controller.set('hostComponents', []);
@@ -113,7 +49,11 @@ describe('App.ReassignMasterWizardStep4Controller', function () {
   describe('#testDBConnection', function() {
     beforeEach(function() {
       controller.set('requiredProperties', Em.A([]));
-      controller.set('content.serviceProperties', Em.Object.create({'javax.jdo.option.ConnectionDriverName': 'mysql'}));
+      controller.set('content.configs', Em.Object.create({
+        'hive-site': {
+          'javax.jdo.option.ConnectionDriverName': 'mysql'
+        }
+      }));
       controller.set('content.reassign.component_name', 'HIVE_SERVER');
       sinon.stub(controller, 'getConnectionProperty', Em.K);
       sinon.stub(App.router, 'get', Em.K);
@@ -200,7 +140,7 @@ describe('App.ReassignMasterWizardStep4Controller', function () {
       controller.set('content.hasManualSteps', false);
 
       controller.removeUnneededTasks();
-      expect(controller.get('tasks').mapProperty('id')).to.eql([1,3,4,5,6,9,12,13]);
+      expect(controller.get('tasks').mapProperty('id')).to.eql([1, 3, 4, 6, 9, 12, 13]);
     });
 
     it('reassign component is not NameNode and HA disabled', function () {
@@ -210,7 +150,7 @@ describe('App.ReassignMasterWizardStep4Controller', function () {
       isHaEnabled = false;
 
       controller.removeUnneededTasks();
-      expect(controller.get('tasks').mapProperty('id')).to.eql([1, 3, 4, 5, 6]);
+      expect(controller.get('tasks').mapProperty('id')).to.eql([1, 3, 4, 6]);
     });
 
     it('reassign component is not NameNode and HA enabled', function () {
@@ -220,7 +160,7 @@ describe('App.ReassignMasterWizardStep4Controller', function () {
       isHaEnabled = true;
 
       controller.removeUnneededTasks();
-      expect(controller.get('tasks').mapProperty('id')).to.eql([1, 3, 4, 5, 6]);
+      expect(controller.get('tasks').mapProperty('id')).to.eql([1, 3, 4, 6]);
     });
 
     it('reassign component is NameNode and HA disabled', function () {
@@ -230,7 +170,7 @@ describe('App.ReassignMasterWizardStep4Controller', function () {
       isHaEnabled = false;
 
       controller.removeUnneededTasks();
-      expect(controller.get('tasks').mapProperty('id')).to.eql([1, 3, 4, 5, 6]);
+      expect(controller.get('tasks').mapProperty('id')).to.eql([1, 3, 4, 6]);
     });
 
     it('reassign component is NameNode and HA enabled', function () {
@@ -240,7 +180,19 @@ describe('App.ReassignMasterWizardStep4Controller', function () {
       isHaEnabled = true;
 
       controller.removeUnneededTasks();
-      expect(controller.get('tasks').mapProperty('id')).to.eql([1, 3, 4, 5, 6, 7, 8]);
+      expect(controller.get('tasks').mapProperty('id')).to.eql([1, 3, 4, 6, 7, 8]);
+    });
+
+    it('component with reconfiguration', function () {
+      controller.set('tasks', commands);
+      controller.set('content.hasManualSteps', false);
+      controller.set('content.reassign.component_name', 'COMP1');
+      controller.set('wizardController', {
+        isComponentWithReconfiguration: true
+      });
+
+      controller.removeUnneededTasks();
+      expect(controller.get('tasks').mapProperty('id')).to.eql([1, 3, 4, 5, 6, 9, 13]);
     });
 
     it('reassign component is HiveServer and db type is mysql', function () {
@@ -287,17 +239,6 @@ describe('App.ReassignMasterWizardStep4Controller', function () {
       expect(controller.get('tasks').mapProperty('id')).to.eql([1,2,3,4,5,6,7,8,9,10,11,12]);
     });
 
-    it('reassign component is Metrics Collector', function () {
-      controller.set('content.hasManualSteps', false);
-      controller.set('content.databaseType', 'mysql');
-      controller.set('content.reassign.component_name', 'METRICS_COLLECTOR');
-      isHaEnabled = false;
-
-      controller.set('tasks', commandsForDB);
-      controller.removeUnneededTasks();
-      expect(controller.get('tasks').mapProperty('id')).to.eql([1,2,5,6,8,10,12]);
-    });
-
     it('reassign component is Mysql Server', function () {
       controller.set('content.hasManualSteps', false);
       controller.set('content.databaseType', 'mysql');
@@ -312,6 +253,7 @@ describe('App.ReassignMasterWizardStep4Controller', function () {
 
   describe("#stopRequiredServices()", function() {
     before(function () {
+      controller.set('wizardController', App.get('router.reassignMasterController'));
       sinon.stub(controller, 'stopServices', Em.K);
     });
     after(function () {
@@ -524,199 +466,23 @@ describe('App.ReassignMasterWizardStep4Controller', function () {
   describe('#reconfigure()', function () {
 
     beforeEach(function () {
-      sinon.stub(controller, 'loadConfigsTags', Em.K);
+      sinon.stub(controller, 'saveClusterStatus', Em.K);
+      sinon.stub(controller, 'saveConfigsToServer', Em.K);
     });
 
     afterEach(function () {
-      controller.loadConfigsTags.restore();
+      controller.saveClusterStatus.restore();
+      controller.saveConfigsToServer.restore();
     });
 
-    it('loadConfigsTags is called once', function () {
+    it('saveClusterStatus is called once', function () {
       controller.reconfigure();
-      expect(controller.loadConfigsTags.calledOnce).to.be.true;
-    });
-  });
-
-  describe('#loadConfigsTags()', function () {
-    it('request is sent', function () {
-      controller.loadConfigsTags();
-      var args = testHelpers.findAjaxRequest('name', 'config.tags');
-      expect(args).exists;
-    });
-  });
-
-  describe('#getConfigUrlParams()', function () {
-    var testCases = [
-      {
-        componentName: 'NAMENODE',
-        result: [
-          "(type=hdfs-site&tag=1)",
-          "(type=core-site&tag=2)"
-        ]
-      },
-      {
-        componentName: 'SECONDARY_NAMENODE',
-        result: [
-          "(type=hdfs-site&tag=1)",
-          "(type=core-site&tag=2)"
-        ]
-      },
-      {
-        componentName: 'JOBTRACKER',
-        result: [
-          "(type=mapred-site&tag=4)"
-        ]
-      },
-      {
-        componentName: 'RESOURCEMANAGER',
-        result: [
-          "(type=yarn-site&tag=5)"
-        ]
-      },
-      {
-        componentName: 'APP_TIMELINE_SERVER',
-        result: [
-          "(type=yarn-site&tag=5)",
-          "(type=yarn-env&tag=8)"
-        ]
-      },
-      {
-        componentName: 'OOZIE_SERVER',
-        result: [
-          "(type=oozie-site&tag=6)",
-          "(type=core-site&tag=2)",
-          "(type=oozie-env&tag=2)"
-        ]
-      },
-      {
-        componentName: 'WEBHCAT_SERVER',
-        result: [
-          "(type=hive-env&tag=11)",
-          "(type=webhcat-site&tag=7)",
-          "(type=core-site&tag=2)"
-        ]
-      },
-      {
-        componentName: 'HIVE_SERVER',
-        result: [
-          '(type=hive-site&tag=10)',
-          '(type=webhcat-site&tag=7)',
-          '(type=hive-env&tag=11)',
-          '(type=core-site&tag=2)'
-        ]
-      },
-      {
-        componentName: 'HIVE_METASTORE',
-        result: [
-          '(type=hive-site&tag=10)',
-          '(type=webhcat-site&tag=7)',
-          '(type=hive-env&tag=11)',
-          '(type=core-site&tag=2)'
-        ]
-      },
-      {
-        componentName: 'MYSQL_SERVER',
-        result: [
-          '(type=hive-site&tag=10)'
-        ]
-      },
-      {
-        componentName: 'HISTORYSERVER',
-        result: [
-          '(type=mapred-site&tag=4)'
-        ]
-      }
-    ];
-
-    var data = {
-      Clusters: {
-        desired_configs: {
-          'hdfs-site': {tag: 1},
-          'core-site': {tag: 2},
-          'hbase-site': {tag: 3},
-          'mapred-site': {tag: 4},
-          'yarn-site': {tag: 5},
-          'oozie-site': {tag: 6},
-          'oozie-env': {tag: 2},
-          'webhcat-site': {tag: 7},
-          'yarn-env': {tag: 8},
-          'accumulo-site': {tag: 9},
-          'hive-site': {tag: 10},
-          'hive-env': {tag: 11}
-        }
-      }
-    };
-
-    var services = [];
-
-    beforeEach(function () {
-      sinon.stub(App.Service, 'find', function () {
-        return services;
-      });
-    });
-    afterEach(function () {
-      App.Service.find.restore();
-    });
-
-    testCases.forEach(function (test) {
-      it('get config of ' + test.componentName, function () {
-        expect(controller.getConfigUrlParams(test.componentName, data)).to.eql(test.result);
-      });
-    });
-    it('get config of NAMENODE when HBASE installed', function () {
-      services = [
-        {
-          serviceName: 'HBASE'
-        }
-      ];
-      expect(controller.getConfigUrlParams('NAMENODE', data)).to.eql([
-        "(type=hdfs-site&tag=1)",
-        "(type=core-site&tag=2)",
-        "(type=hbase-site&tag=3)"
-      ]);
-    });
-
-    it('get config of NAMENODE when ACCUMULO installed', function () {
-      services = [
-        {
-          serviceName: 'ACCUMULO'
-        }
-      ];
-      expect(controller.getConfigUrlParams('NAMENODE', data)).to.eql([
-        "(type=hdfs-site&tag=1)",
-        "(type=core-site&tag=2)",
-        "(type=accumulo-site&tag=9)"
-      ]);
-    });
-
-  });
-
-  describe('#onLoadConfigsTags()', function () {
-    var dummyData = {
-      Clusters: {
-        desired_configs : {}
-      }
-    };
-
-    beforeEach(function () {
-      sinon.stub(controller, 'getConfigUrlParams', function () {
-        return [];
-      });
-      controller.set('content.reassign.component_name', 'COMP1');
-      controller.onLoadConfigsTags(dummyData);
-      this.args = testHelpers.findAjaxRequest('name', 'reassign.load_configs');
+      expect(controller.saveClusterStatus.calledOnce).to.be.true;
     });
 
-    afterEach(function () {
-      controller.getConfigUrlParams.restore();
-    });
-
-    it('request is sent', function () {
-      expect(this.args).exists;
-    });
-
-    it('getConfigUrlParams is called with correct data', function () {
-      expect(controller.getConfigUrlParams.calledWith('COMP1', dummyData)).to.be.true;
+    it('saveConfigsToServer is called once', function () {
+      controller.reconfigure();
+      expect(controller.saveConfigsToServer.calledOnce).to.be.true;
     });
   });
 
@@ -789,66 +555,6 @@ describe('App.ReassignMasterWizardStep4Controller', function () {
     });
   });
 
-  describe('#setSecureConfigs()', function () {
-
-    beforeEach(function () {
-      this.stub = sinon.stub(App, 'get');
-    });
-
-    afterEach(function () {
-      Em.tryInvoke(App.get, 'restore');
-    });
-
-    it('undefined component and security disabled', function () {
-      var secureConfigs = [];
-      this.stub.withArgs('isKerberosEnabled').returns(false);
-      controller.set('secureConfigsMap', []);
-      expect(controller.setSecureConfigs(secureConfigs, {}, 'COMP1')).to.be.false;
-      expect(secureConfigs).to.eql([]);
-    });
-
-    it('component exist and security disabled', function () {
-      var secureConfigs = [];
-      this.stub.withArgs('isKerberosEnabled').returns(false);
-      controller.set('secureConfigsMap', [{
-        componentName: 'COMP1'
-      }]);
-      expect(controller.setSecureConfigs(secureConfigs, {}, 'COMP1')).to.be.false;
-      expect(secureConfigs).to.eql([]);
-    });
-
-    it('undefined component and security enabled', function () {
-      var secureConfigs = [];
-      this.stub.withArgs('isKerberosEnabled').returns(true);
-      controller.set('secureConfigsMap', []);
-      expect(controller.setSecureConfigs(secureConfigs, {}, 'COMP1')).to.be.false;
-      expect(secureConfigs).to.eql([]);
-    });
-    it('component exist and security enabled', function () {
-      var secureConfigs = [];
-      this.stub.withArgs('isKerberosEnabled').returns(true);
-      var configs = {'s1': {
-        'k1': 'kValue',
-        'p1': 'pValue'
-      }};
-      controller.set('secureConfigsMap', [{
-        componentName: 'COMP1',
-        configs: [{
-          site: 's1',
-          keytab: 'k1',
-          principal: 'p1'
-        }]
-      }]);
-      expect(controller.setSecureConfigs(secureConfigs, configs, 'COMP1')).to.be.true;
-      expect(secureConfigs).to.eql([
-        {
-          "keytab": "kValue",
-          "principal": "pValue"
-        }
-      ]);
-    });
-  });
-
   describe('#getComponentDir()', function () {
     var configs = {
       'hdfs-site': {
@@ -1333,292 +1039,6 @@ describe('App.ReassignMasterWizardStep4Controller', function () {
     });
   });
 
-  describe("#setDynamicConfigs HIVE", function() {
-    beforeEach(function () {
-      controller.set('content.masterComponentHosts', [
-        {component: 'HIVE_METASTORE', hostName: 'host1'},
-        {component: 'HIVE_METASTORE', hostName: 'host3'},
-        {component: 'HIVE_SERVER', hostName: 'host4'}
-      ]);
-      controller.set('content.reassignHosts.source', 'host1');
-      controller.set('content.reassignHosts.target', 'host2');
-    });
-    it("reassign component is HIVE_METASTORE", function() {
-      var configs = {
-        'hive-env': {
-          'hive_user': 'hive_user'
-        },
-        'hive-site': {
-          'hive.metastore.uris': ''
-        },
-        'webhcat-site': {
-          'templeton.hive.properties': 'thrift'
-        },
-        'core-site': {
-          'hadoop.proxyuser.hive_user.hosts': ''
-        }
-      };
-      App.MoveHmConfigInitializer.setup(controller._getHiveInitializerSettings(configs));
-      configs = controller.setDynamicConfigs(configs, App.MoveHmConfigInitializer);
-      expect(configs['hive-site']['hive.metastore.uris']).to.equal('thrift://host3:9083,thrift://host2:9083');
-      expect(configs['webhcat-site']['templeton.hive.properties']).to.equal('thrift');
-      expect(configs['core-site']['hadoop.proxyuser.hive_user.hosts']).to.equal('host2,host3,host4');
-    });
-
-    it("reassign component is HIVE_SERVER", function() {
-      controller.get('content.masterComponentHosts').pushObject({component: 'HIVE_SERVER', hostName: 'host1'});
-      var configs = {
-        'hive-env': {
-          'hive_user': 'hive_user'
-        },
-        'hive-site': {
-          'hive.metastore.uris': ''
-        },
-        'webhcat-site': {
-          'templeton.hive.properties': 'thrift'
-        },
-        'core-site': {
-          'hadoop.proxyuser.hive_user.hosts': ''
-        }
-      };
-      App.MoveHsConfigInitializer.setup(controller._getHiveInitializerSettings(configs));
-      configs = controller.setDynamicConfigs(configs, App.MoveHsConfigInitializer);
-      expect(configs['core-site']['hadoop.proxyuser.hive_user.hosts']).to.equal('host1,host2,host3,host4');
-    });
-
-    it("reassign component is WEBHCAT_SERVER", function() {
-      controller.get('content.masterComponentHosts').pushObject({component: 'WEBHCAT_SERVER', hostName: 'host1'});
-      var configs = {
-        'hive-env': {
-          'webhcat_user': 'webhcat_user'
-        },
-        'hive-site': {
-          'hive.metastore.uris': ''
-        },
-        'webhcat-site': {
-          'templeton.hive.properties': 'thrift'
-        },
-        'core-site': {
-          'hadoop.proxyuser.webhcat_user.hosts': ''
-        }
-      };
-      App.MoveWsConfigInitializer.setup(controller._getWsInitializerSettings(configs));
-      configs = controller.setDynamicConfigs(configs, App.MoveWsConfigInitializer);
-      expect(configs['core-site']['hadoop.proxyuser.webhcat_user.hosts']).to.equal('host2');
-    });
-  });
-
-  describe('#setDynamicConfigs RESOURCEMANAGER', function () {
-    beforeEach(function () {
-      sinon.stub(App, 'get').withArgs('isRMHaEnabled').returns(true);
-    });
-    afterEach(function () {
-      App.get.restore();
-      App.MoveRmConfigInitializer.cleanup();
-    });
-
-    it('HA enabled and resource manager 1', function () {
-      controller.set('content.reassignHosts.source', 'host1');
-      controller.set('content.reassignHosts.target', 'host3');
-      var configs = {
-        'yarn-site': {
-          'yarn.resourcemanager.hostname.rm1': 'host1',
-          'yarn.resourcemanager.webapp.address.rm1': 'host1:8088',
-          'yarn.resourcemanager.webapp.https.address.rm1': 'host1:8443',
-          'yarn.resourcemanager.hostname.rm2': 'host2',
-          'yarn.resourcemanager.webapp.address.rm2': 'host2:8088',
-          'yarn.resourcemanager.webapp.https.address.rm2': 'host2:8443'
-        }
-      };
-      var additionalDependencies = controller._getRmAdditionalDependencies(configs);
-      App.MoveRmConfigInitializer.setup(controller._getRmInitializerSettings(configs));
-      configs = controller.setDynamicConfigs(configs, App.MoveRmConfigInitializer, additionalDependencies);
-      expect(configs['yarn-site']).to.eql({
-        'yarn.resourcemanager.hostname.rm1': 'host3',
-        'yarn.resourcemanager.webapp.address.rm1': 'host3:8088',
-        'yarn.resourcemanager.webapp.https.address.rm1': 'host3:8443',
-        'yarn.resourcemanager.hostname.rm2': 'host2',
-        'yarn.resourcemanager.webapp.address.rm2': 'host2:8088',
-        'yarn.resourcemanager.webapp.https.address.rm2': 'host2:8443'
-      });
-    });
-
-    it('HA enabled and resource manager 2', function () {
-      controller.set('content.reassignHosts.source', 'host2');
-      controller.set('content.reassignHosts.target', 'host3');
-      var configs = {
-        'yarn-site': {
-          'yarn.resourcemanager.hostname.rm1': 'host1',
-          'yarn.resourcemanager.webapp.address.rm1': 'host1:8088',
-          'yarn.resourcemanager.webapp.https.address.rm1': 'host1:8443',
-          'yarn.resourcemanager.hostname.rm2': 'host2',
-          'yarn.resourcemanager.webapp.address.rm2': 'host2:8088',
-          'yarn.resourcemanager.webapp.https.address.rm2': 'host2:8443'
-        }
-      };
-      var additionalDependencies = controller._getRmAdditionalDependencies(configs);
-      App.MoveRmConfigInitializer.setup(controller._getRmInitializerSettings(configs));
-      configs = controller.setDynamicConfigs(configs, App.MoveRmConfigInitializer, additionalDependencies);
-
-      expect(configs['yarn-site']).to.eql({
-        'yarn.resourcemanager.hostname.rm1': 'host1',
-        'yarn.resourcemanager.webapp.address.rm1': 'host1:8088',
-        'yarn.resourcemanager.webapp.https.address.rm1': 'host1:8443',
-        'yarn.resourcemanager.hostname.rm2': 'host3',
-        'yarn.resourcemanager.webapp.address.rm2': 'host3:8088',
-        'yarn.resourcemanager.webapp.https.address.rm2': 'host3:8443'
-      });
-    });
-  });
-
-  describe('#setDynamicConfigs NAMENODE', function () {
-    var isHaEnabled = false;
-
-    beforeEach(function () {
-      sinon.stub(App, 'get', function () {
-        return isHaEnabled;
-      });
-      sinon.stub(App.Service, 'find', function () {
-        return [
-          {serviceName: 'HDFS'},
-          {serviceName: 'ACCUMULO'},
-          {serviceName: 'HBASE'},
-          {serviceName: 'HAWQ'}
-        ];
-      });
-      controller.set('content.reassignHosts.source', 'host1');
-    });
-
-    afterEach(function () {
-      App.get.restore();
-      App.Service.find.restore();
-      App.MoveNameNodeConfigInitializer.cleanup();
-    });
-
-    it('HA isn\'t enabled and HBASE, HAWQ and ACCUMULO service', function () {
-      isHaEnabled = false;
-      var configs = {
-        'hbase-site': {
-          'hbase.rootdir': 'hdfs://localhost:8020/apps/hbase/data'
-        },
-        'accumulo-site': {
-          'instance.volumes': 'hdfs://localhost:8020/apps/accumulo/data',
-          'instance.volumes.replacements': ''
-        },
-        'hawq-site': {
-          'hawq_dfs_url': 'localhost:8020/hawq/data'
-        }
-      };
-
-      controller.set('content.reassignHosts.target', 'host2');
-
-      App.MoveNameNodeConfigInitializer.setup(controller._getNnInitializerSettings(configs));
-      configs = controller.setDynamicConfigs(configs, App.MoveNameNodeConfigInitializer);
-
-      expect(configs['hbase-site']['hbase.rootdir']).to.equal('hdfs://host2:8020/apps/hbase/data');
-      expect(configs['accumulo-site']['instance.volumes']).to.equal('hdfs://host2:8020/apps/accumulo/data');
-      expect(configs['accumulo-site']['instance.volumes.replacements']).to.equal('hdfs://host1:8020/apps/accumulo/data hdfs://host2:8020/apps/accumulo/data');
-      expect(configs['hawq-site'].hawq_dfs_url).to.equal('host2:8020/hawq/data');
-    });
-
-    it('HA enabled and namenode 1', function () {
-      isHaEnabled = true;
-      var configs = {
-        'hdfs-site': {
-          'dfs.nameservices': 's',
-          'dfs.namenode.http-address.s.nn1': 'host1:50070',
-          'dfs.namenode.https-address.s.nn1': 'host1:50470',
-          'dfs.namenode.rpc-address.s.nn1': 'host1:8020'
-        },
-        'hdfs-client': {
-          'dfs.namenode.rpc-address.s.nn1': '',
-          'dfs.namenode.http-address.s.nn1': 'host1:50070'
-        }
-      };
-
-      controller.set('content.reassignHosts.target', 'host2');
-      App.MoveNameNodeConfigInitializer.setup(controller._getNnInitializerSettings(configs));
-      configs = controller.setDynamicConfigs(configs, App.MoveNameNodeConfigInitializer);
-      expect(configs['hdfs-site']).to.eql({
-        "dfs.nameservices": "s",
-        "dfs.namenode.http-address.s.nn1": "host2:50070",
-        "dfs.namenode.https-address.s.nn1": "host2:50470",
-        "dfs.namenode.rpc-address.s.nn1": "host2:8020"
-      });
-      expect(configs['hdfs-client']).to.eql({
-        "dfs.namenode.http-address.s.nn1": "host2:50070",
-        "dfs.namenode.rpc-address.s.nn1": "host2:8020"
-      });
-    });
-
-    it('HA enabled and namenode 2', function () {
-      isHaEnabled = true;
-      var configs = {
-        'hdfs-site': {
-          'dfs.nameservices': 's',
-          "dfs.namenode.http-address.s.nn1": "host1:50070",
-          'dfs.namenode.http-address.s.nn2': 'host2:50070',
-          'dfs.namenode.https-address.s.nn2': 'host2:50470',
-          'dfs.namenode.rpc-address.s.nn2': 'host2:8020'
-        },
-        'hdfs-client': {
-          'dfs.namenode.rpc-address.s.nn2': '',
-          'dfs.namenode.http-address.s.nn2': 'host2:50070'
-        }
-      };
-      controller.set('content.reassignHosts.source', 'host2');
-      controller.set('content.reassignHosts.target', 'host3');
-
-      App.MoveNameNodeConfigInitializer.setup(controller._getNnInitializerSettings(configs));
-      configs = controller.setDynamicConfigs(configs, App.MoveNameNodeConfigInitializer);
-
-      expect(configs['hdfs-site']).to.eql({
-        "dfs.nameservices": "s",
-        "dfs.namenode.http-address.s.nn1": "host1:50070",
-        "dfs.namenode.http-address.s.nn2": "host3:50070",
-        "dfs.namenode.https-address.s.nn2": "host3:50470",
-        "dfs.namenode.rpc-address.s.nn2": "host3:8020"
-      });
-      expect(configs['hdfs-client']).to.eql({
-        "dfs.namenode.http-address.s.nn2": "host3:50070",
-        "dfs.namenode.rpc-address.s.nn2": "host3:8020"
-      });
-    });
-
-  });
-
-  describe('#setDynamicConfigs OOZIE_SERVER', function () {
-
-    it('should upodate hadoop.proxyuser.${oozie_user}.hosts', function () {
-
-      var configs = {
-        'oozie-env': {
-          'oozie_user': 'cool_dude'
-        },
-        'core-site': {
-          'hadoop.proxyuser.cool_dude.hosts': ''
-        }
-      };
-
-      controller.set('content.masterComponentHosts', [
-        {component: 'OOZIE_SERVER', hostName: 'host2'},
-        {component: 'OOZIE_SERVER', hostName: 'host3'},
-        {component: 'OOZIE_SERVER', hostName: 'host1'}
-      ]);
-
-      controller.set('content.reassignHosts.source', 'host1');
-      controller.set('content.reassignHosts.target', 'host4');
-
-      App.MoveOSConfigInitializer.setup(controller._getOsInitializerSettings(configs));
-      configs = controller.setDynamicConfigs(configs, App.MoveOSConfigInitializer);
-      App.MoveOSConfigInitializer.cleanup();
-
-      expect(configs['core-site']['hadoop.proxyuser.cool_dude.hosts']).to.equal('host2,host3,host4');
-
-    });
-
-  });
-
   describe.skip("#prepareDBCheckAction()", function() {
     beforeEach(function () {
       sinon.stub(App.router, 'get').returns({

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/test/controllers/wizard/step7_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/wizard/step7_test.js b/ambari-web/test/controllers/wizard/step7_test.js
index cd6b21c..5677a8d 100644
--- a/ambari-web/test/controllers/wizard/step7_test.js
+++ b/ambari-web/test/controllers/wizard/step7_test.js
@@ -2059,4 +2059,22 @@ describe('App.InstallerStep7Controller', function () {
 
   });
 
+  describe('#setButtonClickFinish', function () {
+
+    beforeEach(function () {
+      installerStep7Controller.set('submitButtonClicked', true);
+      App.set('router.nextBtnClickInProgress', true);
+      installerStep7Controller.setButtonClickFinish();
+    });
+
+    it('submitButtonClicked should be false', function () {
+      expect(installerStep7Controller.get('submitButtonClicked')).to.be.false;
+    });
+
+    it('nextBtnClickInProgress should be false', function () {
+      expect(App.get('router.nextBtnClickInProgress')).to.be.false;
+    });
+
+  });
+
 });


[4/4] ambari git commit: AMBARI-20143 Merge changes in branch-feature-preview-configs to branch-2.5. (ababiichuk)

Posted by ab...@apache.org.
AMBARI-20143 Merge changes in branch-feature-preview-configs to branch-2.5. (ababiichuk)


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

Branch: refs/heads/branch-2.5
Commit: 304bd060536ad1f5b153657862e91a8b96411167
Parents: ac19fd1
Author: ababiichuk <ab...@hortonworks.com>
Authored: Thu Feb 23 15:15:20 2017 +0200
Committer: ababiichuk <ab...@hortonworks.com>
Committed: Thu Feb 23 15:26:14 2017 +0200

----------------------------------------------------------------------
 ambari-web/app/assets/test/tests.js             |   1 +
 .../rangerAdmin/step3_controller.js             |  54 +-
 .../rangerAdmin/step4_controller.js             |  68 +-
 .../rangerAdmin/wizard_controller.js            |  43 +
 ambari-web/app/controllers/main/host/details.js | 859 +++++++++++-------
 .../controllers/main/service/info/configs.js    |   8 +-
 ambari-web/app/controllers/main/service/item.js | 118 ++-
 .../main/service/reassign/step1_controller.js   |  78 +-
 .../main/service/reassign/step3_controller.js   | 672 +++++++++++++++
 .../main/service/reassign/step4_controller.js   | 634 +-------------
 .../main/service/reassign_controller.js         |  55 +-
 .../app/controllers/wizard/step7_controller.js  |  24 +-
 ambari-web/app/messages.js                      |  33 +-
 .../mixins/common/configs/enhanced_configs.js   |   5 +
 .../app/mixins/common/track_request_mixin.js    |   6 +-
 .../app/mixins/main/service/groups_mapping.js   |   2 +-
 .../app/routes/ra_high_availability_routes.js   |   6 +-
 ambari-web/app/routes/reassign_master_routes.js |  25 +-
 ambari-web/app/styles/application.less          |  68 +-
 .../modal_popups/dependent_configs_table.hbs    |  20 +-
 .../highAvailability/journalNode/step2.hbs      |   4 +
 .../highAvailability/rangerAdmin/step3.hbs      |   7 +
 .../main/host/details/addComponentPopup.hbs     |  19 -
 .../host/details/addDeleteComponentPopup.hbs    |  48 ++
 .../main/host/details/deleteComponentPopup.hbs  |  43 -
 .../templates/main/service/add_host_popup.hbs   |  28 -
 .../info/delete_service_warning_popup.hbs       |  26 +
 .../templates/main/service/reassign/step3.hbs   |  36 +-
 .../highAvailability/rangerAdmin/step3_view.js  |   6 +-
 ambari-web/app/views/main/host/summary.js       |   4 -
 .../views/main/service/reassign/step3_view.js   |   4 +-
 .../views/main/service/reassign/step5_view.js   |   4 +-
 .../rangerAdmin/step3_controller_test.js        | 104 +++
 .../test/controllers/main/host/details_test.js  | 862 ++++++++++---------
 .../main/service/info/config_test.js            |  15 +-
 .../test/controllers/main/service/item_test.js  |  17 +-
 .../service/reassign/step1_controller_test.js   |  17 +-
 .../service/reassign/step3_controller_test.js   | 634 ++++++++++++++
 .../service/reassign/step4_controller_test.js   | 646 +-------------
 .../test/controllers/wizard/step7_test.js       |  18 +
 40 files changed, 3062 insertions(+), 2259 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/assets/test/tests.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/test/tests.js b/ambari-web/app/assets/test/tests.js
index 7440819..aae27ea 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -82,6 +82,7 @@ var files = [
   'test/controllers/main/admin/highAvailability/hawq/addStandby/step3_controller_test',
   'test/controllers/main/admin/highAvailability/hawq/removeStandby/step2_controller_test',
   'test/controllers/main/admin/highAvailability/hawq/activateStandby/step2_controller_test',
+  'test/controllers/main/admin/highAvailability/rangerAdmin/step3_controller_test',
   'test/controllers/main/dashboard/config_history_controller_test',
   'test/controllers/main/charts/heatmap_test',
   'test/controllers/main/charts/heatmap_metrics/heatmap_metric_test',

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/controllers/main/admin/highAvailability/rangerAdmin/step3_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/admin/highAvailability/rangerAdmin/step3_controller.js b/ambari-web/app/controllers/main/admin/highAvailability/rangerAdmin/step3_controller.js
index 475cc52..7e46810 100644
--- a/ambari-web/app/controllers/main/admin/highAvailability/rangerAdmin/step3_controller.js
+++ b/ambari-web/app/controllers/main/admin/highAvailability/rangerAdmin/step3_controller.js
@@ -19,6 +19,58 @@
 var App = require('app');
 
 App.RAHighAvailabilityWizardStep3Controller = Em.Controller.extend({
-  name: "rAHighAvailabilityWizardStep3Controller"
+  name: 'rAHighAvailabilityWizardStep3Controller',
+
+  isLoaded: false,
+
+  versionLoaded: true,
+
+  hideDependenciesInfoBar: true,
+
+  stepConfigs: [
+    App.ServiceConfig.create({
+      serviceName: 'MISC',
+      showConfig: true
+    })
+  ],
+
+  loadStep: function () {
+    var self = this;
+    App.get('router.mainController.isLoading').call(App.get('router.clusterController'), 'isConfigsPropertiesLoaded').done(function () {
+      var stepConfig = self.get('stepConfigs.firstObject'),
+        configs = [],
+        configCategories = [],
+        installedServices = App.Service.find().mapProperty('serviceName');
+      self.get('wizardController.configs').forEach(function (config) {
+        var service = App.config.get('serviceByConfigTypeMap')[config.siteName];
+        if (service) {
+          var serviceName = service.get('serviceName'),
+            serviceDisplayName = service.get('displayName');
+          if (installedServices.contains(serviceName)) {
+            var property = App.configsCollection.getConfigByName(config.propertyName, config.siteName) || {};
+            if (!configCategories.someProperty('name'), serviceName) {
+              configCategories.push(App.ServiceConfigCategory.create({
+                name: serviceName,
+                displayName: serviceDisplayName
+              }));
+            }
+            configs.push(App.ServiceConfigProperty.create(property, {
+              category: serviceName,
+              value: self.get('content.loadBalancerURL'),
+              isEditable: false
+            }));
+          }
+        }
+      });
+      stepConfig.setProperties({
+        configs: configs,
+        configCategories: configCategories
+      });
+      self.setProperties({
+        isLoaded: true,
+        selectedService: stepConfig
+      });
+    });
+  }
 });
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/controllers/main/admin/highAvailability/rangerAdmin/step4_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/admin/highAvailability/rangerAdmin/step4_controller.js b/ambari-web/app/controllers/main/admin/highAvailability/rangerAdmin/step4_controller.js
index b241707..df96b1f 100644
--- a/ambari-web/app/controllers/main/admin/highAvailability/rangerAdmin/step4_controller.js
+++ b/ambari-web/app/controllers/main/admin/highAvailability/rangerAdmin/step4_controller.js
@@ -52,18 +52,7 @@ App.RAHighAvailabilityWizardStep4Controller = App.HighAvailabilityProgressPageCo
 
   onLoadConfigsTags: function (data) {
     var urlParams = [];
-    urlParams.push('(type=admin-properties&tag=' + data.Clusters.desired_configs['admin-properties'].tag + ')');
-    var siteNamesToFetch = [
-      'ranger-hdfs-security',
-      'ranger-yarn-security',
-      'ranger-hbase-security',
-      'ranger-hive-security',
-      'ranger-knox-security',
-      'ranger-kafka-security',
-      'ranger-kms-security',
-      'ranger-storm-security',
-      'ranger-atlas-security'
-    ];
+    var siteNamesToFetch = this.get('wizardController.configs').mapProperty('siteName');
     siteNamesToFetch.map(function(siteName) {
       if(siteName in data.Clusters.desired_configs) {
         urlParams.push('(type=' + siteName + '&tag=' + data.Clusters.desired_configs[siteName].tag + ')');
@@ -83,63 +72,18 @@ App.RAHighAvailabilityWizardStep4Controller = App.HighAvailabilityProgressPageCo
 
   onLoadConfigs: function (data) {
     var configs = [];
-    var self = this;
-    data.items.findProperty('type', 'admin-properties').properties['policymgr_external_url'] = this.get('content.loadBalancerURL');
-    configs.push({
-      Clusters: {
-        desired_config: this.reconfigureSites(['admin-properties'], data, Em.I18n.t('admin.highAvailability.step4.save.configuration.note').format(App.format.role('RANGER_ADMIN', false)))
-      }
-    });
 
-    var configsToChange = [
-      {
-        siteName: 'ranger-hdfs-security',
-        property: 'ranger.plugin.hdfs.policy.rest.url'
-      },
-      {
-        siteName: 'ranger-yarn-security',
-        property: 'ranger.plugin.yarn.policy.rest.url'
-      },
-      {
-        siteName: 'ranger-hbase-security',
-        property: 'ranger.plugin.hbase.policy.rest.url'
-      },
-      {
-        siteName: 'ranger-hive-security',
-        property: 'ranger.plugin.hive.policy.rest.url'
-      },
-      {
-        siteName: 'ranger-knox-security',
-        property: 'ranger.plugin.knox.policy.rest.url'
-      },
-      {
-        siteName: 'ranger-kafka-security',
-        property: 'ranger.plugin.kafka.policy.rest.url'
-      },
-      {
-        siteName: 'ranger-kms-security',
-        property: 'ranger.plugin.kms.policy.rest.url'
-      },
-      {
-        siteName: 'ranger-storm-security',
-        property: 'ranger.plugin.storm.policy.rest.url'
-      },
-      {
-        siteName: 'ranger-atlas-security',
-        property: 'ranger.plugin.atlas.policy.rest.url'
-      }
-    ];
-    configsToChange.map(function(item) {
+    this.get('wizardController.configs').map(function(item) {
       var config = data.items.findProperty('type', item.siteName);
-      if(config) {
-        config.properties[item.property] = self.get('content.loadBalancerURL');
+      if (config) {
+        config.properties[item.propertyName] = this.get('content.loadBalancerURL');
         configs.push({
           Clusters: {
-            desired_config: self.reconfigureSites([item.siteName], data, Em.I18n.t('admin.highAvailability.step4.save.configuration.note').format(App.format.role('RANGER_ADMIN', false)))
+            desired_config: this.reconfigureSites([item.siteName], data, Em.I18n.t('admin.highAvailability.step4.save.configuration.note').format(App.format.role('RANGER_ADMIN', false)))
           }
         });
       }
-    });
+    }, this);
 
     App.ajax.send({
       name: 'common.service.multiConfigurations',

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/controllers/main/admin/highAvailability/rangerAdmin/wizard_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/admin/highAvailability/rangerAdmin/wizard_controller.js b/ambari-web/app/controllers/main/admin/highAvailability/rangerAdmin/wizard_controller.js
index 2bc6e37..3f4bf33 100644
--- a/ambari-web/app/controllers/main/admin/highAvailability/rangerAdmin/wizard_controller.js
+++ b/ambari-web/app/controllers/main/admin/highAvailability/rangerAdmin/wizard_controller.js
@@ -41,6 +41,49 @@ App.RAHighAvailabilityWizardController = App.WizardController.extend({
     masterComponentHosts: null
   }),
 
+  configs: [
+    {
+      siteName: 'admin-properties',
+      propertyName: 'policymgr_external_url'
+    },
+    {
+      siteName: 'ranger-hdfs-security',
+      propertyName: 'ranger.plugin.hdfs.policy.rest.url'
+    },
+    {
+      siteName: 'ranger-yarn-security',
+      propertyName: 'ranger.plugin.yarn.policy.rest.url'
+    },
+    {
+      siteName: 'ranger-hbase-security',
+      propertyName: 'ranger.plugin.hbase.policy.rest.url'
+    },
+    {
+      siteName: 'ranger-hive-security',
+      propertyName: 'ranger.plugin.hive.policy.rest.url'
+    },
+    {
+      siteName: 'ranger-knox-security',
+      propertyName: 'ranger.plugin.knox.policy.rest.url'
+    },
+    {
+      siteName: 'ranger-kafka-security',
+      propertyName: 'ranger.plugin.kafka.policy.rest.url'
+    },
+    {
+      siteName: 'ranger-kms-security',
+      propertyName: 'ranger.plugin.kms.policy.rest.url'
+    },
+    {
+      siteName: 'ranger-storm-security',
+      propertyName: 'ranger.plugin.storm.policy.rest.url'
+    },
+    {
+      siteName: 'ranger-atlas-security',
+      propertyName: 'ranger.plugin.atlas.policy.rest.url'
+    }
+  ],
+
   init: function () {
     this._super();
     this.clearStep();

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/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 f040db5..c3b02b7 100644
--- a/ambari-web/app/controllers/main/host/details.js
+++ b/ambari-web/app/controllers/main/host/details.js
@@ -22,7 +22,7 @@ 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, {
+App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDownload, App.InstallComponent, App.InstallNewVersion, App.TrackRequestMixin, {
 
   name: 'mainHostDetailsController',
 
@@ -39,12 +39,18 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
   isFromHosts: false,
 
   /**
-   * Are we adding hive server2 component
+   * Determines whether we are adding Hive Server2 component
    * @type {bool}
    */
   addHiveServer: false,
 
   /**
+   * Determines whether we are adding ZooKeeper Server component
+   * @type {bool}
+   */
+  addZooKeeperServer: false,
+
+  /**
    * path to page visited before
    * @type {string}
    */
@@ -67,6 +73,45 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
    */
   isOozieServerAddable: true,
 
+  isConfigsLoadingInProgress: false,
+
+  addDeleteComponentsMap: {
+    'ZOOKEEPER_SERVER': {
+      addPropertyName: 'addZooKeeperServer',
+      deletePropertyName: 'fromDeleteZkServer'
+    },
+    'HIVE_METASTORE': {
+      deletePropertyName: 'deleteHiveMetaStore',
+      hostPropertyName: 'hiveMetastoreHost',
+      configTagsCallbackName: 'loadHiveConfigs',
+      configsCallbackName: 'onLoadHiveConfigs'
+    },
+    'WEBHCAT_SERVER': {
+      deletePropertyName: 'deleteWebHCatServer',
+      hostPropertyName: 'webhcatServerHost',
+      configTagsCallbackName: 'loadWebHCatConfigs',
+      configsCallbackName: 'onLoadHiveConfigs'
+    },
+    'HIVE_SERVER': {
+      addPropertyName: 'addHiveServer',
+      deletePropertyName: 'deleteHiveServer',
+      configTagsCallbackName: 'loadHiveConfigs',
+      configsCallbackName: 'onLoadHiveConfigs'
+    },
+    'NIMBUS': {
+      deletePropertyName: 'deleteNimbusHost',
+      hostPropertyName: 'nimbusHost',
+      configTagsCallbackName: 'loadStormConfigs',
+      configsCallbackName: 'onLoadStormConfigs'
+    },
+    'RANGER_KMS_SERVER': {
+      deletePropertyName: 'deleteRangerKMSServer',
+      hostPropertyName: 'rangerKMSServerHost',
+      configTagsCallbackName: 'loadRangerConfigs',
+      configsCallbackName: 'onLoadRangerConfigs'
+    }
+  },
+
   zooKeeperRelatedServices: [
     {
       serviceName: 'HIVE',
@@ -106,6 +151,99 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
   ],
 
   /**
+   * Determines whether adding/deleting host component requires configs changes
+   * @type {Boolean}
+   */
+  isReconfigureRequired: false,
+
+  /**
+   * Contains component-related config properties loaded from server
+   * @type {Object|null}
+   */
+  configs: null,
+
+  /**
+   * Array of all properties affected by adding/deleting host component
+   * @type {Array}
+   */
+  allPropertiesToChange: [],
+
+  /**
+   * Array of editable properties affected by adding/deleting host component
+   * @type {Array}
+   */
+  recommendedPropertiesToChange: [],
+
+  /**
+   * Array of non-editable properties affected by adding/deleting host component
+   * @type {Array}
+   */
+  requiredPropertiesToChange: [],
+
+  /**
+   * Properties affected by adding/deleting host component, grouped by service, formatted for PUT call
+   * @type {Array}
+   */
+  groupedPropertiesToChange: [],
+
+  hasPropertiesToChange: Em.computed.or('recommendedPropertiesToChange.length', 'requiredPropertiesToChange.length'),
+
+  addDeleteComponentPopupBody: Em.View.extend({
+    templateName: require('templates/main/host/details/addDeleteComponentPopup'),
+    commonMessage: '',
+    manualKerberosWarning: App.get('router.mainAdminKerberosController.isManualKerberos') ?
+      Em.I18n.t('hosts.host.manualKerberosWarning') : '',
+    lastComponent: false,
+    lastComponentError: '',
+    hasHostsSelect: false,
+    selectedHost: null,
+    anyHostsWithoutComponent: true
+  }),
+
+  saveLoadedConfigs: function (data) {
+    var configs = {
+      items: []
+    };
+    data.items.forEach(function (item) {
+      var configTypeObject = Em.getProperties(item, ['type', 'properties_attributes']),
+        properties = {};
+      Em.keys(item.properties).forEach(function (propertyName) {
+        properties[propertyName] = item.properties[propertyName];
+      });
+      configTypeObject.properties = properties;
+      configs.items.push(configTypeObject);
+    });
+    this.set('configs', configs);
+  },
+
+  clearConfigsChanges: function (shouldKeepLoadedConfigs) {
+    var arrayNames = ['allPropertiesToChange', 'recommendedPropertiesToChange', 'requiredPropertiesToChange', 'groupedPropertiesToChange'];
+    this.abortRequests();
+    arrayNames.forEach(function (arrayName) {
+      this.get(arrayName).clear();
+    }, this);
+    this.set('isReconfigureRequired', false);
+    if (!shouldKeepLoadedConfigs) {
+      this.set('configs', null);
+    }
+  },
+
+  applyConfigsCustomization: function () {
+    this.get('recommendedPropertiesToChange').forEach(function (property) {
+      var value = property.saveRecommended ? property.recommendedValue : property.initialValue,
+        filename = property.propertyFileName;
+      if (this.get('groupedPropertiesToChange.length')) {
+        var group = this.get('groupedPropertiesToChange').find(function (item) {
+          return item.properties.hasOwnProperty(filename);
+        });
+        if (group) {
+          group.properties[filename][property.propertyName] = value;
+        }
+      }
+    }, this);
+  },
+
+  /**
    * Open dashboard page
    * @method routeHome
    */
@@ -343,51 +481,81 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
     if ($(event.target).closest('li').hasClass('disabled')) {
       return;
     }
-    var self = this;
     var component = event.context;
     var componentName = component.get('componentName');
     var displayName = component.get('displayName');
-    var isLastComponent = (this.getTotalComponent(component) === 1);
+    var returnFunc;
+    var componentsMapItem = this.get('addDeleteComponentsMap')[componentName];
+    if (componentsMapItem) {
+      if (componentsMapItem.deletePropertyName) {
+        this.set(componentsMapItem.deletePropertyName, true);
+      }
+      this.clearConfigsChanges();
+      this.set('isReconfigureRequired', true);
+      returnFunc = this.showDeleteComponentPopup(component);
+    } else if (componentName === 'JOURNALNODE') {
+      returnFunc = App.showConfirmationPopup(function () {
+        App.router.transitionTo('main.services.manageJournalNode');
+      }, Em.I18n.t('hosts.host.deleteComponent.popup.deleteJournalNodeMsg'));
+    } else {
+      returnFunc = this.showDeleteComponentPopup(component);
+    }
+    return returnFunc;
+  },
+
+  showDeleteComponentPopup: function (component) {
+    var self = this,
+      isLastComponent = (this.getTotalComponent(component) === 1),
+      componentName = component.get('componentName'),
+      componentDisplayName = component.get('displayName'),
+      componentsMapItem = this.get('addDeleteComponentsMap')[componentName],
+      commonMessage = Em.I18n.t('hosts.host.deleteComponent.popup.msg1').format(componentDisplayName),
+      configTagsCallbackName,
+      configsCallbackName;
+    if (componentsMapItem) {
+      configTagsCallbackName = componentsMapItem.configTagsCallbackName;
+      configsCallbackName = componentsMapItem.configsCallbackName;
+    }
+    this.loadComponentRelatedConfigs(configTagsCallbackName, configsCallbackName);
     return App.ModalPopup.show({
       header: Em.I18n.t('popup.confirmation.commonHeader'),
-      primary: componentName == 'JOURNALNODE'? Em.I18n.t('ok') : Em.I18n.t('hosts.host.deleteComponent.popup.confirm'),
-      bodyClass: Em.View.extend({
-        templateName: require('templates/main/host/details/deleteComponentPopup')
+      controller: self,
+      classNameBindings: ['controller.hasPropertiesToChange:sixty-percent-width-modal', 'controller.hasPropertiesToChange:modal-full-width'],
+      primary: Em.I18n.t('hosts.host.deleteComponent.popup.confirm'),
+      bodyClass: self.get('addDeleteComponentPopupBody').extend({
+        commonMessage: commonMessage,
+        recommendedPropertiesToChange: self.get('recommendedPropertiesToChange'),
+        requiredPropertiesToChange: self.get('requiredPropertiesToChange'),
+        lastComponentError: Em.I18n.t('hosts.host.deleteComponent.popup.warning').format(componentDisplayName),
+        lastComponent: function () {
+          this.set('parentView.isChecked', !isLastComponent);
+          return isLastComponent;
+        }.property()
       }),
-      isHiveMetastore: componentName == 'HIVE_METASTORE',
-      isWebHCatServer: componentName == 'WEBHCAT_SERVER',
-      isNimbus: componentName == 'NIMBUS',
-      isRangerKMSServer: componentName == 'RANGER_KMS_SERVER',
-      isZkServer: componentName == 'ZOOKEEPER_SERVER',
-      isJournalNode: componentName == 'JOURNALNODE',
-
-      deleteHiveMetastoreMsg: Em.I18n.t('hosts.host.deleteComponent.popup.deleteHiveMetastore'),
-      deleteWebHCatServerMsg: Em.I18n.t('hosts.host.deleteComponent.popup.deleteWebHCatServer'),
-      deleteNimbusMsg: Em.I18n.t('hosts.host.deleteComponent.popup.deleteNimbus'),
-      deleteRangerKMSServereMsg: Em.I18n.t('hosts.host.deleteComponent.popup.deleteRangerKMSServer'),
-      lastComponentError: Em.I18n.t('hosts.host.deleteComponent.popup.warning').format(displayName),
-      deleteComponentMsg: Em.I18n.t('hosts.host.deleteComponent.popup.msg1').format(displayName),
-      deleteZkServerMsg: Em.I18n.t('hosts.host.deleteComponent.popup.deleteZooKeeperServer'),
-      deleteJournalNodeMsg: Em.I18n.t('hosts.host.deleteComponent.popup.deleteJournalNodeMsg'),
-
       isChecked: false,
-      disablePrimary: Em.computed.not('isChecked'),
-      lastComponent: function () {
-        this.set('isChecked', !isLastComponent);
-        return isLastComponent;
-      }.property(),
-
+      disablePrimary: function () {
+        return (this.get('controller.isReconfigureRequired') && this.get('controller.isConfigsLoadingInProgress')) || !this.get('isChecked');
+      }.property('controller.isReconfigureRequired', 'controller.isConfigsLoadingInProgress', 'isChecked'),
       onPrimary: function () {
-        var popup = this;
-        if (componentName == 'JOURNALNODE') {
-          popup.hide();
-          App.router.transitionTo('main.services.manageJournalNode');
-        } else {
-          self._doDeleteHostComponent(component, function () {
-            self.set('redrawComponents', true);
-            popup.hide();
-          });
+        this._super();
+        if (self.get('isReconfigureRequired')) {
+          self.applyConfigsCustomization();
         }
+        self._doDeleteHostComponent(componentName, function () {
+          if (self.get('isReconfigureRequired')) {
+            self.saveConfigsBatch(self.get('groupedPropertiesToChange'), componentName);
+            self.clearConfigsChanges();
+          }
+          self.set('redrawComponents', true);
+        });
+      },
+      onSecondary: function () {
+        this._super();
+        self.clearConfigsChanges();
+      },
+      onClose: function () {
+        this._super();
+        self.clearConfigsChanges();
       }
     });
   },
@@ -425,13 +593,13 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
    *          when components failed to get deleted.
    * @method _doDeleteHostComponent
    */
-  _doDeleteHostComponent: function (component, callback) {
+  _doDeleteHostComponent: function (componentName, callback) {
     callback = callback || Em.K;
     App.ajax.send({
-      name: (Em.isNone(component)) ? 'common.delete.host' : 'common.delete.host_component',
+      name: (Em.isNone(componentName)) ? 'common.delete.host' : 'common.delete.host_component',
       sender: this,
       data: {
-        componentName: (component) ? component.get('componentName') : '',
+        componentName: componentName || '',
         hostName: this.get('content.hostName')
       },
       success: '_doDeleteHostComponentSuccessCallback',
@@ -450,31 +618,8 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
    * @method _doDeleteHostComponentSuccessCallback
    */
   _doDeleteHostComponentSuccessCallback: function (response, request, data) {
-    var self = this;
     this.set('_deletedHostComponentResult', null);
     this.removeHostComponentModel(data.componentName, data.hostName);
-    if (data.componentName == 'ZOOKEEPER_SERVER') {
-      this.set('fromDeleteZkServer', true);
-      this.updateStormConfigs();
-      self.isServiceMetricsLoaded(function () {
-        self.loadConfigs();
-      });
-    } else if (data.componentName == 'HIVE_METASTORE') {
-      this.set('deleteHiveMetaStore', true);
-      this.loadConfigs('loadHiveConfigs');
-    } else if (data.componentName == 'WEBHCAT_SERVER') {
-      this.set('deleteWebHCatServer', true);
-      this.loadConfigs('loadWebHCatConfigs');
-    } else if (data.componentName == 'HIVE_SERVER') {
-      this.set('deleteHiveServer', true);
-      this.loadConfigs('loadHiveConfigs');
-    } else if (data.componentName == 'NIMBUS') {
-      this.set('deleteNimbusHost', true);
-      this.loadConfigs('loadStormConfigs');
-    } else if (data.componentName == 'RANGER_KMS_SERVER') {
-      this.set('deleteRangerKMSServer', true);
-      this.loadConfigs('loadRangerConfigs');
-    }
   },
 
   /**
@@ -591,14 +736,16 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
       returnFunc,
       self = this,
       component = event.context,
-      hostName = event.selectedHost || this.get('content.hostName'),
+      hostName = this.get('content.hostName'),
       componentName = component.get('componentName'),
-      missedComponents = event.selectedHost ? [] : this.checkComponentDependencies(componentName, {
+      hasHostsSelect = event.hasOwnProperty('selectedHost'),
+      missedComponents = hasHostsSelect ? [] : this.checkComponentDependencies(componentName, {
         scope: 'host',
         installedComponents: this.get('content.hostComponents').mapProperty('componentName')
       }),
       isManualKerberos = App.get('router.mainAdminKerberosController.isManualKerberos'),
-      manualKerberosWarning = isManualKerberos ? Em.I18n.t('hosts.host.manualKerberosWarning') : '';
+      manualKerberosWarning = isManualKerberos ? Em.I18n.t('hosts.host.manualKerberosWarning') : '',
+      componentsMapItem = this.get('addDeleteComponentsMap')[componentName];
 
     if (!!missedComponents.length) {
       var popupMessage = Em.I18n.t('host.host.addComponent.popup.dependedComponents.body').format(component.get('displayName'),
@@ -608,106 +755,139 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
       return App.showAlertPopup(Em.I18n.t('host.host.addComponent.popup.dependedComponents.header'), popupMessage);
     }
 
-    switch (componentName) {
-      case 'ZOOKEEPER_SERVER':
-        returnFunc = App.showConfirmationPopup(function () {
-          self.installHostComponentCall(self.get('content.hostName'), component)
-        }, Em.I18n.t('hosts.host.addComponent.' + componentName) + manualKerberosWarning);
-        break;
-      case 'HIVE_METASTORE':
-        returnFunc = App.showConfirmationPopup(function () {
-          self.set('hiveMetastoreHost', hostName);
-          self.loadConfigs("loadHiveConfigs");
-        }, Em.I18n.t('hosts.host.addComponent.' + componentName) + manualKerberosWarning);
-        break;
-      case 'WEBHCAT_SERVER':
-        returnFunc = App.showConfirmationPopup(function () {
-          self.set('webhcatServerHost', hostName);
-          self.loadConfigs("loadWebHCatConfigs");
-        }, Em.I18n.t('hosts.host.addComponent.' + componentName) + manualKerberosWarning);
-        break;
-      case 'NIMBUS':
-        returnFunc = App.showConfirmationPopup(function () {
-          self.set('nimbusHost', hostName);
-          self.loadConfigs("loadStormConfigs");
-        }, Em.I18n.t('hosts.host.addComponent.' + componentName) + manualKerberosWarning);
-        break;
-      case 'RANGER_KMS_SERVER':
-        returnFunc = App.showConfirmationPopup(function () {
-          self.set('rangerKMSServerHost', hostName);
-          self.loadConfigs("loadRangerConfigs");
-        }, Em.I18n.t('hosts.host.addComponent.' + componentName) + manualKerberosWarning);
-        break;
-      case 'JOURNALNODE':
-        returnFunc = App.showConfirmationPopup(function () {
-          App.router.transitionTo('main.services.manageJournalNode');
-        }, Em.I18n.t('hosts.host.addComponent.' + componentName) + manualKerberosWarning);
-        break;
-      default:
-        returnFunc = this.addClientComponent(component, isManualKerberos);
+    if (componentsMapItem) {
+      var primary;
+      if (componentsMapItem.hostPropertyName) {
+        this.set(componentsMapItem.hostPropertyName, hostName);
+      }
+      if (componentsMapItem.addPropertyName) {
+        this.set(componentsMapItem.addPropertyName, true);
+        primary = function () {
+          this.set(componentsMapItem.addPropertyName, false);
+        };
+      }
+      this.clearConfigsChanges();
+      this.set('isReconfigureRequired', true);
+      returnFunc = self.showAddComponentPopup(component, hostName, null, primary, hasHostsSelect);
+    } else if (componentName === 'JOURNALNODE') {
+      returnFunc = App.showConfirmationPopup(function () {
+        App.router.transitionTo('main.services.manageJournalNode');
+      }, Em.I18n.t('hosts.host.addComponent.' + componentName) + manualKerberosWarning);
+    } else {
+      returnFunc = this.showAddComponentPopup(component, hostName, function () {
+        if (hasHostsSelect) {
+          hostName = self.get('content.hostName');
+        }
+        self.installHostComponentCall(hostName, component);
+      }, null, hasHostsSelect);
     }
     return returnFunc;
   },
 
-  /**
-   * Send command to server to install client on selected host
-   * @param {App.HostComponent} component
-   * @param {boolean} isManualKerberos
-   * @returns {*}
-   */
-  addClientComponent: function (component, isManualKerberos) {
+  showAddComponentPopup: function (component, hostName, primary, primaryOnReconfigure, hasHostsSelect) {
     var self = this,
-      displayName = this.formatClientsMessage(component);
-
-    return this.showAddComponentPopup(displayName, isManualKerberos, function () {
-      self.installHostComponentCall(self.get('content.hostName'), component);
-    });
-  },
-
-  /**
-   *
-   * @param {string} displayName
-   * @param {boolean} isManualKerberos
-   * @param {Function} primary
-   * @returns {*}
-   */
-  showAddComponentPopup: function (displayName, isManualKerberos, primary) {
-    isManualKerberos = isManualKerberos || false;
-
+      componentName = component.get('componentName'),
+      componentDisplayName = component.get('displayName'),
+      componentsMapItem = this.get('addDeleteComponentsMap')[componentName],
+      commonMessage = Em.I18n.t('hosts.host.addComponent.msg').format(componentDisplayName),
+      configTagsCallbackName,
+      configsCallbackName;
+    if (componentsMapItem) {
+      configTagsCallbackName = componentsMapItem.configTagsCallbackName || 'loadConfigsSuccessCallback';
+      configsCallbackName = componentsMapItem.configsCallbackName || 'saveZkConfigs';
+    }
+    if (hasHostsSelect) {
+      if (this.get('isReconfigureRequired')) {
+        this.set('isConfigsLoadingInProgress', true);
+      }
+    } else {
+      this.loadComponentRelatedConfigs(configTagsCallbackName, configsCallbackName);
+    }
     return App.ModalPopup.show({
-      primary: Em.I18n.t('hosts.host.addComponent.popup.confirm'),
       header: Em.I18n.t('popup.confirmation.commonHeader'),
-
-      addComponentMsg: Em.I18n.t('hosts.host.addComponent.msg').format(displayName),
-
-      manualKerberosWarning: isManualKerberos ? Em.I18n.t('hosts.host.manualKerberosWarning') : '',
-
-      bodyClass: Em.View.extend({
-        templateName: require('templates/main/host/details/addComponentPopup')
+      controller: self,
+      classNameBindings: ['controller.hasPropertiesToChange:sixty-percent-width-modal', 'controller.hasPropertiesToChange:modal-full-width'],
+      primary: Em.I18n.t('hosts.host.addComponent.popup.confirm'),
+      bodyClass: self.get('addDeleteComponentPopupBody').extend({
+        commonMessage: commonMessage,
+        hasHostsSelect: hasHostsSelect,
+        addComponentMsg: Em.I18n.t('hosts.host.addComponent.msg').format(componentDisplayName),
+        selectHostMsg: Em.I18n.t('services.summary.selectHostForComponent').format(componentDisplayName),
+        thereIsNoHostsMsg: Em.I18n.t('services.summary.allHostsAlreadyRunComponent').format(componentDisplayName),
+        hostsWithoutComponent: function () {
+          if (this.get('hasHostsSelect')) {
+            var hostsWithComponent = App.HostComponent.find().filterProperty('componentName', componentName).mapProperty('hostName'),
+              result = App.get('allHostNames');
+            hostsWithComponent.forEach(function (host) {
+              result = result.without(host);
+            });
+            return result;
+          } else {
+            return [];
+          }
+        }.property('hasHostsSelect'),
+        anyHostsWithoutComponent: Em.computed.or('!hasHostsSelect', 'hostsWithoutComponent.length'),
+        selectedHostObserver: function () {
+          hostName = this.get('selectedHost');
+          self.clearConfigsChanges(true);
+          if (!self.get('content')) {
+            self.set('content', {});
+          }
+          self.setProperties({
+            'isReconfigureRequired': !!componentsMapItem,
+            'content.hostName': hostName
+          });
+          if (componentsMapItem) {
+            var configs = self.get('configs'),
+              params = configs && configs.params || {};
+            if (componentsMapItem.hostPropertyName) {
+              self.set(componentsMapItem.hostPropertyName, hostName);
+            }
+            if (componentsMapItem.addPropertyName) {
+              self.set(componentsMapItem.addPropertyName, true);
+            }
+            if (configs) {
+              this.set('isConfigsLoadingInProgress', true);
+              self[configsCallbackName](configs, null, params);
+            } else {
+              self.loadComponentRelatedConfigs(configTagsCallbackName, configsCallbackName);
+            }
+          }
+        }.observes('selectedHost')
       }),
-
+      disablePrimary: Em.computed.and('controller.isReconfigureRequired', 'controller.isConfigsLoadingInProgress'),
       onPrimary: function () {
-        this.hide();
-        primary();
+        this._super();
+        if (self.get('isReconfigureRequired')) {
+          self.applyConfigsCustomization();
+          self.saveConfigsBatch(self.get('groupedPropertiesToChange'), componentName, hostName);
+          if (primaryOnReconfigure) {
+            primaryOnReconfigure.call(self);
+          }
+          self.clearConfigsChanges();
+        } else if (primary) {
+          primary();
+        }
+      },
+      onSecondary: function () {
+        this._super();
+        self.clearConfigsChanges();
+      },
+      onClose: function () {
+        this._super();
+        self.clearConfigsChanges();
       }
     });
   },
 
-  /**
-   * format message for operation of adding clients
-   * @param client
-   */
-  formatClientsMessage: function (client) {
-    var displayName = Em.isNone(client.get('displayName')) ? '' : client.get('displayName');
-    var subComponentNames = client.get('subComponentNames');
-    if (subComponentNames && subComponentNames.length > 0) {
-      var dns = [];
-      subComponentNames.forEach(function (scn) {
-        dns.push(App.format.role(scn, false));
+  loadComponentRelatedConfigs: function (configTagsCallbackName, configsCallbackName) {
+    var self = this;
+    if (this.get('isReconfigureRequired')) {
+      this.set('isConfigsLoadingInProgress', true);
+      this.isServiceMetricsLoaded(function () {
+        self.loadConfigs(configTagsCallbackName, configsCallbackName);
       });
-      displayName += " (" + dns.join(", ") + ")";
     }
-    return displayName;
   },
 
   /**
@@ -727,17 +907,7 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
       this.mimicWorkStatusChange(params.component, App.HostComponentStatus.installing, App.HostComponentStatus.stopped);
     }
 
-    this.showBackgroundOperationsPopup(function () {
-      if (params.componentName === 'ZOOKEEPER_SERVER' || params.componentName === 'HIVE_SERVER') {
-        self.set(params.componentName === 'ZOOKEEPER_SERVER' ? 'zkRequestId' : 'hiveRequestId', data.Requests.id);
-        self.addObserver(
-          'App.router.backgroundOperationsController.serviceTimestamp',
-          self,
-          (params.componentName === 'ZOOKEEPER_SERVER' ? self.checkZkConfigs : self.checkHiveDone)
-        );
-        params.componentName === 'ZOOKEEPER_SERVER' ? self.checkZkConfigs() : self.checkHiveDone();
-      }
-    });
+    this.showBackgroundOperationsPopup();
     return true;
   },
 
@@ -753,22 +923,6 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
   },
 
   /**
-   * Call load tags
-   * @method checkHiveDone
-   */
-  checkHiveDone: function () {
-    var bg = App.router.get('backgroundOperationsController.services').findProperty('id', this.get('hiveRequestId'));
-    if (bg && !bg.get('isRunning')) {
-      var self = this;
-      this.removeObserver('App.router.backgroundOperationsController.serviceTimestamp', this, this.checkHiveDone);
-      setTimeout(function () {
-        self.set('addHiveServer', true);
-        self.loadConfigs("loadHiveConfigs");
-      }, App.get('componentsUpdateInterval'));
-    }
-  },
-
-  /**
    * Success callback for load configs request
    * @param {object} data
    * @method loadOozieConfigs
@@ -788,7 +942,7 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
   /**
    * get Oozie database config and set databaseType
    * @param {object} data
-   * @method onLoadHiveConfigs
+   * @method onLoadOozieConfigs
    */
   onLoadOozieConfigs: function (data) {
     var configs = {};
@@ -803,17 +957,20 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
   /**
    * Success callback for Storm load configs request
    * @param {object} data
+   * @param {object} opt
+   * @param {object} params
    * @method loadStormConfigs
    */
-  loadStormConfigs: function (data) {
-    App.ajax.send({
+  loadStormConfigs: function (data, opt, params) {
+    var request = App.ajax.send({
       name: 'admin.get.all_configurations',
       sender: this,
       data: {
         urlParams: '(type=storm-site&tag=' + data.Clusters.desired_configs['storm-site'].tag + ')'
       },
-      success: 'onLoadStormConfigs'
+      success: params.callback
     });
+    this.trackRequest(request);
   },
 
   /**
@@ -829,6 +986,7 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
     var hostComponentsTopology = {
       masterComponentHosts: []
     };
+    var propertiesToChange = this.get('allPropertiesToChange');
     var masterComponents = this.bootstrapHostsMapping('ZOOKEEPER_SERVER');
     if (this.get('fromDeleteHost') || this.get('fromDeleteZkServer')) {
       this.set('fromDeleteHost', false);
@@ -837,6 +995,13 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
       if (!Em.isNone(removedHost)) {
         Em.set(removedHost, 'isInstalled', false);
       }
+    } else if (this.get('addZooKeeperServer')) {
+      this.set('addZooKeeperServer', false);
+      masterComponents.push({
+        component: 'ZOOKEEPER_SERVER',
+        hostName: this.get('content.hostName'),
+        isInstalled: true
+      });
     }
     var dependencies = {
       zkClientPort: zkPort,
@@ -846,15 +1011,26 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
     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);
+        var currentValue = properties[propertyName],
+          propertyDef = {
+            fileName: fileName,
+            name: propertyName,
+            value: currentValue
+          },
+          configProperty = initializer.initialValue(propertyDef, hostComponentsTopology, dependencies);
         initializer.updateSiteObj(configs[fileName], configProperty);
-      });
-    });
+        if (this.get('isReconfigureRequired') && currentValue !== configs[fileName][propertyName]) {
+          var service = App.config.get('serviceByConfigTypeMap')[fileName];
+          propertiesToChange.pushObject({
+            propertyFileName: fileName,
+            propertyName: propertyName,
+            serviceDisplayName: service && service.get('displayName'),
+            initialValue: currentValue,
+            recommendedValue: propertyDef.value
+          });
+        }
+      }, this);
+    }, this);
   },
 
   /**
@@ -885,8 +1061,10 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
     var nimbusHost = this.get('nimbusHost'),
       stormNimbusHosts = this.getStormNimbusHosts(),
       configs = {},
-      attributes = {};
+      attributes = {},
+      propertiesToChange = this.get('allPropertiesToChange');
 
+    this.saveLoadedConfigs(data);
     data.items.forEach(function (item) {
       configs[item.type] = item.properties;
       attributes[item.type] = item.properties_attributes || {};
@@ -894,7 +1072,19 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
 
     this.updateZkConfigs(configs);
 
-    configs['storm-site']['nimbus.seeds'] = JSON.stringify(stormNimbusHosts).replace(/"/g, "'");
+    var nimbusSeedsInit = configs['storm-site']['nimbus.seeds'],
+      nimbusSeedsRecommended = JSON.stringify(stormNimbusHosts).replace(/"/g, "'");
+    configs['storm-site']['nimbus.seeds'] = nimbusSeedsRecommended;
+    if (this.get('isReconfigureRequired') && nimbusSeedsInit !== nimbusSeedsRecommended) {
+      var service = App.config.get('serviceByConfigTypeMap')['storm-site'];
+      propertiesToChange.pushObject({
+        propertyFileName: 'storm-site',
+        propertyName: 'nimbus.seeds',
+        serviceDisplayName: service && service.get('displayName'),
+        initialValue: nimbusSeedsInit,
+        recommendedValue: nimbusSeedsRecommended
+      });
+    }
     var groups = [
       {
         properties: {
@@ -905,16 +1095,22 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
         }
       }
     ];
-    this.saveConfigsBatch(groups, 'NIMBUS', nimbusHost);
+    if (this.get('isReconfigureRequired')) {
+      this.setConfigsChanges(groups);
+    } else {
+      this.saveConfigsBatch(groups, 'NIMBUS', nimbusHost);
+    }
   },
 
   /**
    * Success callback for load configs request
    * @param {object} data
-   * @method loadHiveConfigs
+   * @param {object} opt
+   * @param {object} params
+   * @method loadWebHCatConfigs
    */
-  loadWebHCatConfigs: function (data) {
-    return App.ajax.send({
+  loadWebHCatConfigs: function (data, opt, params) {
+    var request = App.ajax.send({
       name: 'admin.get.all_configurations',
       sender: this,
       data: {
@@ -926,17 +1122,21 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
           '(type=core-site&tag=' + data.Clusters.desired_configs['core-site'].tag + ')'
         ].join('|')
       },
-      success: 'onLoadHiveConfigs'
+      success: params.callback
     });
+    this.trackRequest(request);
+    return request;
   },
 
   /**
    * Success callback for load configs request
    * @param {object} data
+   * @param {object} opt
+   * @param {object} params
    * @method loadHiveConfigs
    */
-  loadHiveConfigs: function (data) {
-    return App.ajax.send({
+  loadHiveConfigs: function (data, opt, params) {
+    var request = App.ajax.send({
       name: 'admin.get.all_configurations',
       sender: this,
       data: {
@@ -947,8 +1147,10 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
           '(type=core-site&tag=' + data.Clusters.desired_configs['core-site'].tag + ')'
         ].join('|')
       },
-      success: 'onLoadHiveConfigs'
+      success: params.callback
     });
+    this.trackRequest(request);
+    return request;
   },
 
   /**
@@ -972,11 +1174,15 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
       hiveMetastorePort: ""
     };
     var initializer = params.webHCat ? App.AddWebHCatComponentsInitializer : App.AddHiveComponentsInitializer;
+    this.saveLoadedConfigs(data);
+    this.set('configs.params', {
+      webHCat: params.webHCat
+    });
     data.items.forEach(function (item) {
       configs[item.type] = item.properties;
       attributes[item.type] = item.properties_attributes || {};
     }, this);
-
+    var propertiesToChange = this.get('allPropertiesToChange');
 
     port = configs['hive-site']['hive.metastore.uris'].match(/:[0-9]{2,4}/);
     port = port ? port[0].slice(1) : "9083";
@@ -994,16 +1200,27 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
     ['hive-site', 'webhcat-site', 'hive-env', 'core-site'].forEach(function(fileName) {
       if (configs[fileName]) {
         Em.keys(configs[fileName]).forEach(function(propertyName) {
-          var propertyDef = {
+          var currentValue = configs[fileName][propertyName],
+            propertyDef = {
               fileName: fileName,
               name: propertyName,
-              value: configs[fileName][propertyName]
+              value: currentValue
             },
             configProperty = initializer.initialValue(propertyDef, localDB, dependencies);
           initializer.updateSiteObj(configs[fileName], configProperty);
-        });
+          if (this.get('isReconfigureRequired') && currentValue !== configs[fileName][propertyName]) {
+            var service = App.config.get('serviceByConfigTypeMap')[fileName];
+            propertiesToChange.pushObject({
+              propertyFileName: fileName,
+              propertyName: propertyName,
+              serviceDisplayName: service && service.get('displayName'),
+              initialValue: currentValue,
+              recommendedValue: propertyDef.value
+            });
+          }
+        }, this);
       }
-    });
+    }, this);
 
     initializer.cleanup();
 
@@ -1029,12 +1246,16 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
         }
       }
     ];
-    var params = [groups];
-    var componentName = this.get('addHiveServer') ? 'HIVE_SERVER' : (hiveMetastoreHost ? 'HIVE_METASTORE' : 'WEBHCAT_SERVER');
-    var host = webhcatServerHost || hiveMetastoreHost;
-    params.pushObjects([componentName, host]);
-    this.saveConfigsBatch.apply(this, params);
-    this.set('addHiveServer', false);
+    if (this.get('isReconfigureRequired')) {
+      this.setConfigsChanges(groups);
+    } else {
+      var args = [groups];
+      var componentName = this.get('addHiveServer') ? 'HIVE_SERVER' : (hiveMetastoreHost ? 'HIVE_METASTORE' : 'WEBHCAT_SERVER');
+      var host = webhcatServerHost || hiveMetastoreHost;
+      args.pushObjects([componentName, host]);
+      this.saveConfigsBatch.apply(this, args);
+      this.set('addHiveServer', false);
+    }
   },
 
   /**
@@ -1044,36 +1265,48 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
    * @param host
    */
   saveConfigsBatch: function (groups, componentName, host) {
-    groups.forEach(function (group) {
-      var desiredConfigs = [],
-        tag = 'version' + (new Date).getTime(),
-        properties = group.properties;
-
-      for (var site in properties) {
-        if (!properties.hasOwnProperty(site) || Em.isNone(properties[site])) continue;
-        desiredConfigs.push({
-          "type": site,
-          "tag": tag,
-          "properties": properties[site],
-          "properties_attributes": group.properties_attributes[site],
-          "service_config_version_note": Em.I18n.t('hosts.host.configs.save.note').format(App.format.role(componentName, false))
-        });
-      }
-      if (desiredConfigs.length > 0) {
-        App.ajax.send({
-          name: 'common.service.configurations',
-          sender: this,
-          data: {
-            desired_config: desiredConfigs,
+    if (groups.length) {
+      groups.forEach(function (group) {
+        var desiredConfigs = [],
+          tag = 'version' + (new Date).getTime(),
+          properties = group.properties;
+
+        for (var site in properties) {
+          if (!properties.hasOwnProperty(site) || Em.isNone(properties[site])) continue;
+          desiredConfigs.push({
+            "type": site,
+            "tag": tag,
+            "properties": properties[site],
+            "properties_attributes": group.properties_attributes[site],
+            "service_config_version_note": Em.I18n.t('hosts.host.configs.save.note').format(App.format.role(componentName, false))
+          });
+        }
+        if (desiredConfigs.length > 0) {
+          App.ajax.send({
+            name: 'common.service.configurations',
+            sender: this,
+            data: {
+              desired_config: desiredConfigs,
+              componentName: componentName,
+              host: host
+            },
+            success: 'installHostComponent'
+          });
+        } else {
+          this.installHostComponent(null, null, {
             componentName: componentName,
             host: host
-          },
-          success: 'installHostComponent'
-        });
-      }
-      //clear hive metastore host not to send second request to install component
-      host = null;
-    }, this);
+          });
+        }
+        //clear hive metastore host not to send second request to install component
+        host = null;
+      }, this);
+    } else {
+      this.installHostComponent(null, null, {
+        componentName: componentName,
+        host: host
+      });
+    }
   },
 
   /**
@@ -1150,23 +1383,26 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
   /**
    * Success callback for load configs request
    * @param {object} data
-   * @method loadHiveConfigs
+   * @param {object} opt
+   * @param {object} params
+   * @method loadRangerConfigs
    */
-  loadRangerConfigs: function (data) {
-    App.ajax.send({
+  loadRangerConfigs: function (data, opt, params) {
+    var request = App.ajax.send({
       name: 'admin.get.all_configurations',
       sender: this,
       data: {
         urlParams: '(type=core-site&tag=' + data.Clusters.desired_configs['core-site'].tag + ')|(type=hdfs-site&tag=' + data.Clusters.desired_configs['hdfs-site'].tag + ')|(type=kms-env&tag=' + data.Clusters.desired_configs['kms-env'].tag + ')'
       },
-      success: 'onLoadRangerConfigs'
+      success: params.callback
     });
+    this.trackRequest(request);
   },
 
   /**
    * update and save Hive hive.metastore.uris config to server
    * @param {object} data
-   * @method onLoadHiveConfigs
+   * @method onLoadRangerConfigs
    */
   onLoadRangerConfigs: function (data) {
     var properties = [
@@ -1196,20 +1432,37 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
             'hdfs-site': hdfsSiteConfigs.properties_attributes
           }
         }
-      ];
+      ],
+      propertiesToChange = this.get('allPropertiesToChange');
+
+    this.saveLoadedConfigs(data);
 
     properties.forEach(function (property) {
       var typeConfigs = data.items.findProperty('type', property.type).properties,
-          currentValue = typeConfigs[property.name],
-          pattern = new RegExp('^kms:\\/\\/http@(.+):' + rkmsPort + '\\/kms$'),
-          patternMatch = currentValue && currentValue.match(pattern),
-          currentHostsList = patternMatch && patternMatch[1].split(';').sort().join(';');
+        currentValue = typeConfigs[property.name],
+        pattern = new RegExp('^kms:\\/\\/http@(.+):' + rkmsPort + '\\/kms$'),
+        patternMatch = currentValue && currentValue.match(pattern),
+        currentHostsList = patternMatch && patternMatch[1].split(';').sort().join(';');
       if (currentHostsList !== rkmsHosts) {
         typeConfigs[property.name] = newValue;
+        if (this.get('isReconfigureRequired')) {
+          var service = App.config.get('serviceByConfigTypeMap')[property.type];
+          propertiesToChange.pushObject({
+            propertyFileName: property.type,
+            propertyName: property.name,
+            serviceDisplayName: service && service.get('displayName'),
+            initialValue: currentValue,
+            recommendedValue: newValue,
+            saveRecommended: true
+          });
+        }
       }
-    });
-
-    this.saveConfigsBatch(groups, 'RANGER_KMS_SERVER', hostToInstall);
+    }, this);
+    if (this.get('isReconfigureRequired')) {
+      this.setConfigsChanges(groups);
+    } else {
+      this.saveConfigsBatch(groups, 'RANGER_KMS_SERVER', hostToInstall);
+    }
   },
 
   /**
@@ -1307,47 +1560,22 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
   },
 
   /**
-   * Update storm config
-   * @method updateStormConfigs
-   */
-  updateStormConfigs: function () {
-    if (App.Service.find('STORM').get('isLoaded') && App.get('isHadoop23Stack')) {
-      this.loadConfigs("loadStormConfigs");
-    }
-  },
-
-  /**
-   * Load tags
-   * @method checkZkConfigs
-   */
-  checkZkConfigs: function () {
-    var bg = App.router.get('backgroundOperationsController.services').findProperty('id', this.get('zkRequestId'));
-    if (bg && !bg.get('isRunning')) {
-      var self = this;
-      this.removeObserver('App.router.backgroundOperationsController.serviceTimestamp', this, this.checkZkConfigs);
-      setTimeout(function () {
-        self.updateStormConfigs();
-        var callback =   function () {
-          self.loadConfigs();
-        };
-        self.isServiceMetricsLoaded(callback);
-      }, App.get('componentsUpdateInterval'));
-    }
-  },
-
-  /**
    * Load configs
    * This function when used without a callback should be always used from successcallback function of the promise `App.router.get('mainController').isLoading.call(App.router.get('clusterController'), 'isServiceContentFullyLoaded').done(promise)`
    * This is required to make sure that service metrics API determining the HA state of components is loaded
    * @method loadConfigs
    */
-  loadConfigs: function (callback) {
-    App.ajax.send({
+  loadConfigs: function (configTagsCallback, configsCallback) {
+    var request = App.ajax.send({
       name: 'config.tags',
       sender: this,
-      success: callback ? callback : 'loadConfigsSuccessCallback',
+      data: {
+        callback: configsCallback || 'saveZkConfigs'
+      },
+      success: configTagsCallback || 'loadConfigsSuccessCallback',
       error: 'onLoadConfigsErrorCallback'
     });
+    this.trackRequest(request);
   },
 
   /**
@@ -1361,21 +1589,25 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
   /**
    * Success callback for load configs request
    * @param {object} data
-   * @method adConfigsSuccessCallback
+   * @param {object} opt
+   * @param {object} params
+   * @method loadConfigsSuccessCallback
    */
-  loadConfigsSuccessCallback: function (data) {
+  loadConfigsSuccessCallback: function (data, opt, params) {
     var urlParams = this.constructConfigUrlParams(data);
     if (urlParams.length > 0) {
-      App.ajax.send({
+      var request = App.ajax.send({
         name: 'reassign.load_configs',
         sender: this,
         data: {
           urlParams: urlParams.join('|')
         },
-        success: 'saveZkConfigs'
+        success: params.callback || 'saveZkConfigs'
       });
+      this.trackRequest(request);
       return true;
     }
+    this.set('isConfigsLoadingInProgress', false);
     return false;
   },
 
@@ -1410,6 +1642,7 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
   saveZkConfigs: function (data) {
     var configs = {};
     var attributes = {};
+    this.saveLoadedConfigs(data);
     data.items.forEach(function (item) {
       configs[item.type] = item.properties;
       attributes[item.type] = item.properties_attributes || {};
@@ -1431,7 +1664,11 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
         groups.push(group);
       }
     });
-    this.saveConfigsBatch(groups, 'ZOOKEEPER_SERVER');
+    if (this.get('isReconfigureRequired')) {
+      this.setConfigsChanges(groups);
+    } else {
+      this.saveConfigsBatch(groups, 'ZOOKEEPER_SERVER');
+    }
   },
 
   /**
@@ -2258,7 +2495,7 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
       allComponents.forEach(function (component, index) {
         var length = allComponents.get('length');
         if (!deleteError) {
-          this._doDeleteHostComponent(component, function () {
+          this._doDeleteHostComponent(component.get('componentName'), function () {
             deleteError = self.get('_deletedHostComponentResult');
             if (index == length - 1) {
               dfd.resolve();
@@ -2290,7 +2527,6 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
     });
   },
   deleteHostSuccessCallback: function (data, rq, requestBody) {
-    var self = this;
     App.router.get('updateController').updateHost(function () {
       App.router.transitionTo('hosts.index');
     });
@@ -2301,7 +2537,7 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
   deleteHostErrorCallback: function (xhr, textStatus, errorThrown, opt) {
     xhr.responseText = "{\"message\": \"" + xhr.statusText + "\"}";
     var self = this;
-    var callback =   function () {
+    var callback = function () {
       self.loadConfigs();
     };
     self.isServiceMetricsLoaded(callback);
@@ -2433,9 +2669,11 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
             }
           };
           if (clientsToAdd.length) {
-            var message = stringUtils.getFormattedStringFromArray(clientsToAdd.mapProperty('displayName'));
-            var isManualKerberos = App.get('router.mainAdminKerberosController.isManualKerberos');
-            self.showAddComponentPopup(message, isManualKerberos, function () {
+            var message = stringUtils.getFormattedStringFromArray(clientsToAdd.mapProperty('displayName')),
+              componentObject = Em.Object.create({
+                displayName: message
+              });
+            self.showAddComponentPopup(componentObject, self.get('content.hostName'), function () {
               sendInstallCommand();
               clientsToAdd.forEach(function (component) {
                 self.installHostComponentCall(self.get('content.hostName'), component);
@@ -2535,5 +2773,34 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
    */
   isServiceMetricsLoaded: function(callback) {
     App.router.get('mainController').isLoading.call(App.router.get('clusterController'), 'isServiceContentFullyLoaded').done(callback);
+  },
+
+  setConfigsChangesForDisplay: function () {
+    if (App.get('router.clusterController.isConfigsPropertiesLoaded')) {
+      this.get('allPropertiesToChange').forEach(function (property) {
+        var stackProperty = App.configsCollection.getConfigByName(property.propertyName, property.propertyFileName);
+        if (stackProperty && (!stackProperty.isEditable || !stackProperty.isReconfigurable)) {
+          this.get('requiredPropertiesToChange').pushObject(property);
+        } else {
+          Em.set(property, 'saveRecommended', true);
+          this.get('recommendedPropertiesToChange').pushObject(property);
+        }
+      }, this);
+      this.set('isConfigsLoadingInProgress', false);
+      this.removeObserver('App.router.clusterController.isConfigsPropertiesLoaded', this, 'setConfigsChangesForDisplay');
+    }
+  },
+
+  setConfigsChanges: function (groups) {
+    this.get('groupedPropertiesToChange').pushObjects(groups);
+    if (this.get('allPropertiesToChange.length')) {
+      if (App.get('router.clusterController.isConfigsPropertiesLoaded')) {
+        this.setConfigsChangesForDisplay();
+      } else {
+        this.addObserver('App.router.clusterController.isConfigsPropertiesLoaded', this, 'setConfigsChangesForDisplay');
+      }
+    } else {
+      this.set('isConfigsLoadingInProgress', false);
+    }
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/controllers/main/service/info/configs.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/info/configs.js b/ambari-web/app/controllers/main/service/info/configs.js
index 32062e8..786c6f9 100644
--- a/ambari-web/app/controllers/main/service/info/configs.js
+++ b/ambari-web/app/controllers/main/service/info/configs.js
@@ -21,7 +21,7 @@ var batchUtils = require('utils/batch_scheduled_requests');
 
 App.MainServiceInfoConfigsController = Em.Controller.extend(App.AddSecurityConfigs, App.ConfigsLoader,
   App.ServerValidatorMixin, App.EnhancedConfigsMixin, App.ThemesMappingMixin, App.ConfigsSaverMixin,
-  App.ConfigsComparator, App.ComponentActionsByConfigs, App.TrackRequestMixin, {
+  App.ConfigsComparator, App.ComponentActionsByConfigs, {
 
   name: 'mainServiceInfoConfigsController',
 
@@ -239,8 +239,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.AddSecurityConfi
     App.set('componentToBeDeleted', {});
     this.clearLoadInfo();
     this.clearSaveInfo();
-    this.clearRecommendationsInfo();
-    this.clearAllRecommendations();
+    this.clearRecommendations();
     this.setProperties({
       saveInProgress: false,
       isInit: true,
@@ -679,8 +678,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.AddSecurityConfi
    */
   doCancel: function () {
     this.set('preSelectedConfigVersion', null);
-    this.clearAllRecommendations();
-    this.clearRecommendationsInfo();
+    this.clearRecommendations();
     this.loadSelectedVersion(this.get('selectedVersion'), this.get('selectedConfigGroup'));
   },
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/controllers/main/service/item.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/item.js b/ambari-web/app/controllers/main/service/item.js
index 11df45a..7d67322 100644
--- a/ambari-web/app/controllers/main/service/item.js
+++ b/ambari-web/app/controllers/main/service/item.js
@@ -21,7 +21,7 @@ var batchUtils = require('utils/batch_scheduled_requests');
 var blueprintUtils = require('utils/blueprint');
 var stringUtils = require('utils/string_utils');
 
-App.MainServiceItemController = Em.Controller.extend(App.SupportClientConfigsDownload, App.InstallComponent, App.ConfigsSaverMixin, App.EnhancedConfigsMixin, {
+App.MainServiceItemController = Em.Controller.extend(App.SupportClientConfigsDownload, App.InstallComponent, App.ConfigsSaverMixin, App.EnhancedConfigsMixin, App.GroupsMappingMixin, {
   name: 'mainServiceItemController',
 
   /**
@@ -86,6 +86,8 @@ App.MainServiceItemController = Em.Controller.extend(App.SupportClientConfigsDow
 
   deleteServiceProgressPopup: null,
 
+  isRecommendationInProgress: false,
+
   isClientsOnlyService: function() {
     return App.get('services.clientOnly').contains(this.get('content.serviceName'));
   }.property('content.serviceName'),
@@ -939,63 +941,15 @@ App.MainServiceItemController = Em.Controller.extend(App.SupportClientConfigsDow
    * @param componentName
    */
   addComponent: function (componentName) {
-    var self = this;
     var component = App.StackServiceComponent.find().findProperty('componentName', componentName);
-    var componentDisplayName = component.get('displayName');
 
     App.get('router.mainAdminKerberosController').getKDCSessionState(function () {
-      return App.ModalPopup.show({
-        primary: Em.computed.ifThenElse('anyHostsWithoutComponent', Em.I18n.t('hosts.host.addComponent.popup.confirm'), undefined),
-
-        header: Em.I18n.t('popup.confirmation.commonHeader'),
-
-        addComponentMsg: Em.I18n.t('hosts.host.addComponent.msg').format(componentDisplayName),
-
-        selectHostMsg: Em.computed.i18nFormat('services.summary.selectHostForComponent', 'componentDisplayName'),
-
-        thereIsNoHostsMsg: Em.computed.i18nFormat('services.summary.allHostsAlreadyRunComponent', 'componentDisplayName'),
-
-        hostsWithoutComponent: function () {
-          var hostsWithComponent = App.HostComponent.find().filterProperty('componentName', componentName).mapProperty('hostName');
-          var result = App.get('allHostNames');
-
-          hostsWithComponent.forEach(function (host) {
-            result = result.without(host);
-          });
-
-          return result;
-        }.property(),
-
-        anyHostsWithoutComponent: Em.computed.gt('hostsWithoutComponent.length', 0),
-
-        selectedHost: null,
-
-        componentName: componentName,
-
-        componentDisplayName: componentDisplayName,
-
-        bodyClass: Em.View.extend({
-          templateName: require('templates/main/service/add_host_popup')
-        }),
-
-        onPrimary: function () {
-          var selectedHost = this.get('selectedHost');
-
-          // Install
-          if (['HIVE_METASTORE', 'RANGER_KMS_SERVER', 'NIMBUS'].contains(component.get('componentName')) && !!selectedHost) {
-            App.router.get('mainHostDetailsController').addComponentWithCheck(
-                {
-                  context: component,
-                  selectedHost: selectedHost
-                }
-            );
-          } else {
-            self.installHostComponentCall(selectedHost, component);
-          }
-
-          this.hide();
+      App.router.get('mainHostDetailsController').addComponentWithCheck(
+        {
+          context: component,
+          selectedHost: null
         }
-      });
+      );
     });
   },
 
@@ -1337,17 +1291,48 @@ App.MainServiceItemController = Em.Controller.extend(App.SupportClientConfigsDow
   showLastWarning: function (serviceName, interDependentServices, dependentServicesToDeleteFmt) {
     var self = this,
       displayName = App.format.role(serviceName, true),
-      popupHeader = Em.I18n.t('services.service.delete.popup.header');
-
-    return App.showConfirmationPopup(
-      function() {self.confirmDeleteService(serviceName, interDependentServices, dependentServicesToDeleteFmt)},
-      Em.I18n.t('services.service.delete.popup.warning').format(displayName) +
-      (interDependentServices.length ? Em.I18n.t('services.service.delete.popup.warning.dependent').format(dependentServicesToDeleteFmt) : ''),
-      null,
-      popupHeader,
-      Em.I18n.t('common.delete'),
-      true
-    );
+      popupHeader = Em.I18n.t('services.service.delete.popup.header'),
+      popupPrimary = Em.I18n.t('common.delete'),
+      warningMessage = Em.I18n.t('services.service.delete.popup.warning').format(displayName) +
+        (interDependentServices.length ? Em.I18n.t('services.service.delete.popup.warning.dependent').format(dependentServicesToDeleteFmt) : ''),
+      callback = this.loadConfigRecommendations.bind(this, null, function () {
+        var serviceNames = self.get('changedProperties').mapProperty('serviceName').uniq();
+        self.loadConfigGroups(serviceNames).done(function () {
+          self.set('isRecommendationInProgress', false);
+        })
+      });
+    this.clearRecommendations();
+    this.setProperties({
+      isRecommendationInProgress: true,
+      selectedConfigGroup: Em.Object.create({
+        isDefault: true
+      })
+    });
+    App.get('router.mainController.isLoading').call(this, 'isServiceConfigsLoaded').done(callback);
+    return App.ModalPopup.show({
+      controller: self,
+      header: popupHeader,
+      primary: popupPrimary,
+      primaryClass: 'btn-danger',
+      disablePrimary: Em.computed.alias('controller.isRecommendationInProgress'),
+      classNameBindings: ['controller.changedProperties.length:sixty-percent-width-modal', 'controller.changedProperties.length:modal-full-width'],
+      bodyClass: Em.View.extend({
+        templateName: require('templates/main/service/info/delete_service_warning_popup'),
+        warningMessage: new Em.Handlebars.SafeString(warningMessage)
+      }),
+      onPrimary: function () {
+        self.confirmDeleteService(serviceName, interDependentServices, dependentServicesToDeleteFmt);
+        this._super();
+      },
+      onSecondary: function () {
+        self.clearRecommendations();
+        this._super();
+      },
+      onClose: function () {
+        self.clearRecommendations();
+        this._super();
+      }
+    });
   },
 
   /**
@@ -1589,8 +1574,7 @@ App.MainServiceItemController = Em.Controller.extend(App.SupportClientConfigsDow
     if (params.servicesToDeleteNext) {
       this.deleteServiceCall(params.servicesToDeleteNext);
     } else {
-      var callback = this.loadConfigRecommendations.bind(this, null, this.saveConfigs.bind(this));
-      App.get('router.mainController.isLoading').call(this, 'isServiceConfigsLoaded').done(callback);
+      this.saveConfigs();
     }
   },
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/controllers/main/service/reassign/step1_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/reassign/step1_controller.js b/ambari-web/app/controllers/main/service/reassign/step1_controller.js
index 9f30bb7..c631e85 100644
--- a/ambari-web/app/controllers/main/service/reassign/step1_controller.js
+++ b/ambari-web/app/controllers/main/service/reassign/step1_controller.js
@@ -26,9 +26,18 @@ App.ReassignMasterWizardStep1Controller = Em.Controller.extend({
    * @type {object}
    */
   dbPropertyMap: {
-    'HIVE_SERVER': 'javax.jdo.option.ConnectionDriverName',
-    'HIVE_METASTORE': 'javax.jdo.option.ConnectionDriverName',
-    'OOZIE_SERVER': 'oozie.service.JPAService.jdbc.driver'
+    'HIVE_SERVER': {
+      type: 'hive-site',
+      name: 'javax.jdo.option.ConnectionDriverName'
+    },
+    'HIVE_METASTORE': {
+      type: 'hive-site',
+      name: 'javax.jdo.option.ConnectionDriverName'
+    },
+    'OOZIE_SERVER': {
+      type: 'oozie-site',
+      name: 'oozie.service.JPAService.jdbc.driver'
+    }
   },
 
   loadConfigsTags: function () {
@@ -79,55 +88,78 @@ App.ReassignMasterWizardStep1Controller = Em.Controller.extend({
   },
 
   onLoadConfigs: function (data) {
-    var databaseProperty = null,
-        databaseType = null,
-        properties = {},
-        isRemoteDB = null;
+    var databaseProperty,
+      databaseType = null,
+      databaseTypeMatch,
+      properties = {},
+      configs = {},
+      dbPropertyMapItem = Em.getWithDefault(this.get('dbPropertyMap'), this.get('content.reassign.component_name'), null),
+      serviceDbProp = this.get('content.reassign.service_id').toLowerCase() + '_database';
 
     data.items.forEach(function(item) {
-      $.extend(properties, item.properties);
+      configs[item.type] = item.properties;
     });
 
-    this.set('content.serviceProperties', properties);
+    this.get('content').setProperties({
+      serviceProperties: properties,
+      configs: configs
+    });
 
-    databaseProperty = properties[ Em.getWithDefault(this.get('dbPropertyMap'), this.get('content.reassign.component_name'), null) ];
-    databaseType = databaseProperty.match(/MySQL|PostgreS|Oracle|Derby|MSSQL|Anywhere/gi)[0];
+    if (dbPropertyMapItem) {
+      databaseProperty = Em.getWithDefault(configs, dbPropertyMapItem.type, {})[dbPropertyMapItem.name];
+      databaseTypeMatch = databaseProperty && databaseProperty.match(/MySQL|PostgreS|Oracle|Derby|MSSQL|Anywhere/gi);
+      if (databaseTypeMatch) {
+        databaseType = databaseTypeMatch[0];
+      }
+    }
     this.set('databaseType', databaseType);
 
     if (this.get('content.reassign.component_name') == 'OOZIE_SERVER' && databaseType !== 'derby') {
       App.router.reassignMasterController.set('content.hasManualSteps', false);
     }
 
-    var serviceDbProp = this.get('content.reassign.service_id').toLowerCase() + "_database";
-    properties['is_remote_db'] = /Existing/ig.test( properties[serviceDbProp] );
+    properties['is_remote_db'] = /Existing/ig.test(properties[serviceDbProp]);
 
     properties['database_hostname'] = this.getDatabaseHost();
 
     this.saveDatabaseType(databaseType);
     this.saveServiceProperties(properties);
+    this.saveConfigs(configs);
   },
 
   saveDatabaseType: function(type) {
-    if(type) {
+    if (type) {
       App.router.get(this.get('content.controllerName')).saveDatabaseType(type);
     }
   },
 
   saveServiceProperties: function(properties) {
-    if(properties) {
+    if (properties) {
       App.router.get(this.get('content.controllerName')).saveServiceProperties(properties);
     }
   },
 
+  saveConfigs: function(configs) {
+    if (configs) {
+      App.router.get(this.get('content.controllerName')).saveConfigs(configs);
+    }
+  },
+
   getDatabaseHost: function() {
-    var db_type = this.get('databaseType');
-    var connectionURLPRops = {
-      'HIVE': 'javax.jdo.option.ConnectionURL',
-      'OOZIE': 'oozie.service.JPAService.jdbc.url'
-    };
-
-    var service = this.get('content.reassign.service_id');
-    var connectionURL = this.get('content.serviceProperties')[connectionURLPRops[service]];
+    var db_type = this.get('databaseType'),
+      connectionURLProps = {
+        'HIVE': {
+          type: 'hive-site',
+          name: 'javax.jdo.option.ConnectionURL'
+        },
+        'OOZIE': {
+          type: 'oozie-site',
+          name: 'oozie.service.JPAService.jdbc.url'
+        }
+      },
+      service = this.get('content.reassign.service_id'),
+      connectionURLPropsItem = connectionURLProps[service],
+      connectionURL = Em.getWithDefault(this.get('content.configs'), connectionURLPropsItem.type, {})[connectionURLPropsItem.name];
 
     connectionURL = connectionURL.replace("jdbc:" + db_type + "://", "");
     connectionURL = connectionURL.replace("/hive?createDatabaseIfNotExist=true", "");


[2/4] ambari git commit: AMBARI-20143 Merge changes in branch-feature-preview-configs to branch-2.5. (ababiichuk)

Posted by ab...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/templates/main/service/reassign/step3.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/service/reassign/step3.hbs b/ambari-web/app/templates/main/service/reassign/step3.hbs
index 1ffe989..1b9c8ff 100644
--- a/ambari-web/app/templates/main/service/reassign/step3.hbs
+++ b/ambari-web/app/templates/main/service/reassign/step3.hbs
@@ -27,17 +27,37 @@
   </div>
 {{/if}}
 <div id="step8-content" class="well pre-scrollable">
-  <div id="printReview">
-    <a class="btn btn-info pull-right" {{action printReview target="view"}}>{{t common.print}}</a> <br/>
-  </div>
   <div id="step8-info">
-    <p><b>{{t services.reassign.step3.component}}</b> {{controller.content.reassign.display_name}}</p>
-
-    <p><b>{{t services.reassign.step3.sourceHost}}</b> {{view.sourceHost}}</p>
-
-    <p><b>{{t services.reassign.step3.targetHost}}</b> {{view.targetHost}}</p>
+    <table id="reassign-review-table">
+      <tr>
+        <td><b>{{t services.reassign.step3.component}}</b></td>
+        <td colspan="2">{{controller.content.reassign.display_name}}</td>
+      </tr>
+      <tr>
+        <td><b>{{t services.reassign.step3.sourceHost}}</b></td>
+        <td>{{view.sourceHost}}</td>
+        <td><span class="to-be-disabled-red"><i class="icon-minus"></i>&nbsp;{{t admin.highAvailability.wizard.step3.toBeDeleted}}</span></td>
+      </tr>
+      <tr>
+        <td><b>{{t services.reassign.step3.targetHost}}</b></td>
+        <td>{{view.targetHost}}</td>
+        <td><span class="to-be-installed-green"><i class="icon-plus"></i>&nbsp;{{t admin.highAvailability.wizard.step3.toBeInstalled}}</span></td>
+      </tr>
+    </table>
   </div>
 </div>
+{{#if wizardController.isComponentWithReconfiguration}}
+  {{#if isLoaded}}
+    {{#if stepConfigs.length}}
+      <div id="serviceConfig">
+        {{t services.reassign.step3.configs}}
+        {{view App.ServiceConfigView}}
+      </div>
+    {{/if}}
+  {{else}}
+    {{view App.SpinnerView}}
+  {{/if}}
+{{/if}}
 <div class="btn-area">
   <a class="btn pull-left" {{action back href="true"}}>&larr; {{t common.back}}</a>
   <a class="btn btn-success pull-right"

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/views/main/admin/highAvailability/rangerAdmin/step3_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/admin/highAvailability/rangerAdmin/step3_view.js b/ambari-web/app/views/main/admin/highAvailability/rangerAdmin/step3_view.js
index 8aa0125..1c55608 100644
--- a/ambari-web/app/views/main/admin/highAvailability/rangerAdmin/step3_view.js
+++ b/ambari-web/app/views/main/admin/highAvailability/rangerAdmin/step3_view.js
@@ -21,6 +21,10 @@ var App = require('app');
 
 App.RAHighAvailabilityWizardStep3View = Em.View.extend({
 
-  templateName: require('templates/main/admin/highAvailability/rangerAdmin/step3')
+  templateName: require('templates/main/admin/highAvailability/rangerAdmin/step3'),
+
+  didInsertElement: function () {
+    this.get('controller').loadStep();
+  }
 
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/views/main/host/summary.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/host/summary.js b/ambari-web/app/views/main/host/summary.js
index 80c4890..89332de 100644
--- a/ambari-web/app/views/main/host/summary.js
+++ b/ambari-web/app/views/main/host/summary.js
@@ -215,11 +215,7 @@ App.MainHostSummaryView = Em.View.extend(App.TimeRangeMixin, {
    */
   addableComponentObject: Em.Object.extend({
     componentName: '',
-    subComponentNames: null,
     displayName: function () {
-      if (this.get('componentName') === 'CLIENTS') {
-        return this.t('common.clients');
-      }
       return App.format.role(this.get('componentName'), false);
     }.property('componentName')
   }),

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/views/main/service/reassign/step3_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/service/reassign/step3_view.js b/ambari-web/app/views/main/service/reassign/step3_view.js
index 003fcb6..b6a379e 100644
--- a/ambari-web/app/views/main/service/reassign/step3_view.js
+++ b/ambari-web/app/views/main/service/reassign/step3_view.js
@@ -27,8 +27,8 @@ App.ReassignMasterWizardStep3View = Em.View.extend({
 
   targetHost: Em.computed.alias('controller.content.reassignHosts.target'),
 
-  printReview: function () {
-    $("#step8-info").jqprint();
+  didInsertElement: function () {
+    this.get('controller').loadStep();
   },
 
   jdbcSetupMessage: function() {

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/views/main/service/reassign/step5_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/service/reassign/step5_view.js b/ambari-web/app/views/main/service/reassign/step5_view.js
index c5fc3c8..e10dc14 100644
--- a/ambari-web/app/views/main/service/reassign/step5_view.js
+++ b/ambari-web/app/views/main/service/reassign/step5_view.js
@@ -42,8 +42,8 @@ App.ReassignMasterWizardStep5View = Em.View.extend({
     }
 
     if (this.get('controller.content.reassign.component_name') === 'APP_TIMELINE_SERVER') {
-      user = this.get('controller.content.serviceProperties.yarn-env.yarn_user');
-      path = this.get('controller.content.serviceProperties.yarn-site')['yarn.timeline-service.leveldb-timeline-store.path'];
+      user = this.get('controller.content.configs.yarn-env.yarn_user');
+      path = this.get('controller.content.configs.yarn-site')['yarn.timeline-service.leveldb-timeline-store.path'];
     }
 
     return Em.I18n.t('services.reassign.step5.body.' + this.get('controller.content.reassign.component_name').toLowerCase() + ha).

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/test/controllers/main/admin/highAvailability/rangerAdmin/step3_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/admin/highAvailability/rangerAdmin/step3_controller_test.js b/ambari-web/test/controllers/main/admin/highAvailability/rangerAdmin/step3_controller_test.js
new file mode 100644
index 0000000..4dc3539
--- /dev/null
+++ b/ambari-web/test/controllers/main/admin/highAvailability/rangerAdmin/step3_controller_test.js
@@ -0,0 +1,104 @@
+/**
+ * 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('controllers/main/admin/highAvailability/rangerAdmin/step3_controller');
+require('controllers/main/admin/highAvailability/rangerAdmin/wizard_controller');
+require('controllers/main');
+
+describe('App.RAHighAvailabilityWizardStep3Controller', function () {
+
+  var controller;
+
+  beforeEach(function () {
+    controller = App.RAHighAvailabilityWizardStep3Controller.create();
+  });
+
+  describe('#loadStep', function () {
+
+    var dfd,
+      testCases = [
+        {
+          path: 'isLoaded',
+          result: true
+        },
+        {
+          path: 'selectedService.configs.length',
+          result: 1,
+          massage: 'configs length'
+        },
+        {
+          path: 'selectedService.configs.firstObject.name',
+          result: 'policymgr_external_url',
+          message: 'property name'
+        },
+        {
+          path: 'selectedService.configs.firstObject.category',
+          result: 'RANGER',
+          message: 'config category'
+        },
+        {
+          path: 'selectedService.configs.firstObject.value',
+          result: 'http://localhost:1111',
+          message: 'property value'
+        }
+      ],
+      service = Em.Object.create({
+        serviceName: 'RANGER',
+        displayName: 'Ranger'
+      });
+
+    beforeEach(function () {
+      dfd = $.Deferred();
+      sinon.stub(App.get('router.mainController'), 'isLoading').returns(dfd);
+      sinon.stub(App.Service, 'find').returns([service]);
+      sinon.stub(App.config, 'get').withArgs('serviceByConfigTypeMap').returns({
+        'admin-properties': service
+      });
+      sinon.stub(App.configsCollection, 'getConfigByName').returns({
+        name: 'policymgr_external_url'
+      });
+      controller.setProperties({
+        wizardController: App.get('router.rAHighAvailabilityWizardController'),
+        content: {
+          loadBalancerURL: 'http://localhost:1111'
+        }
+      });
+      controller.loadStep();
+      dfd.resolve();
+    });
+
+    afterEach(function () {
+      App.get('router.mainController.isLoading').restore();
+      App.Service.find.restore();
+      App.config.get.restore();
+      App.configsCollection.getConfigByName.restore();
+    });
+
+    testCases.forEach(function (testCase) {
+
+      it(testCase.message || testCase.path, function () {
+        expect(controller.get(testCase.path)).to.equal(testCase.result);
+      });
+
+    });
+
+  });
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/test/controllers/main/host/details_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/host/details_test.js b/ambari-web/test/controllers/main/host/details_test.js
index 9efece0..57c81dd 100644
--- a/ambari-web/test/controllers/main/host/details_test.js
+++ b/ambari-web/test/controllers/main/host/details_test.js
@@ -500,125 +500,72 @@ describe('App.MainHostDetailsController', function () {
   });
 
   describe('#addComponent()', function () {
+    var cases = [
+      {
+        componentName: 'ZOOKEEPER_SERVER',
+        showAddComponentPopupCallCount: 1,
+        showConfirmationPopupCallCount: 0
+      },
+      {
+        componentName: 'RESOURCEMANAGER',
+        showAddComponentPopupCallCount: 1,
+        showConfirmationPopupCallCount: 0
+      },
+      {
+        componentName: 'JOURNALNODE',
+        showAddComponentPopupCallCount: 0,
+        showConfirmationPopupCallCount: 1
+      },
+      {
+        componentName: 'HIVE_CLIENT',
+        showAddComponentPopupCallCount: 1,
+        showConfirmationPopupCallCount: 0
+      }
+    ];
     beforeEach(function () {
-      sinon.spy(App, "showConfirmationPopup");
-      sinon.stub(controller, "addClientComponent", Em.K);
-      sinon.stub(controller, "installHostComponentCall", Em.K);
       sinon.stub(controller, "checkComponentDependencies", Em.K);
+      sinon.stub(controller, "showAddComponentPopup", Em.K);
+      sinon.stub(controller, "clearConfigsChanges", Em.K);
+      sinon.stub(App, "showConfirmationPopup", Em.K);
       controller.set('content', {
         hostComponents: [Em.Object.create({
           componentName: "HDFS_CLIENT"
         })]
       });
-      controller.reopen({
-        securityEnabled: false
-      });
     });
 
     afterEach(function () {
-      App.showConfirmationPopup.restore();
-      controller.addClientComponent.restore();
-      controller.installHostComponentCall.restore();
       controller.checkComponentDependencies.restore();
+      controller.showAddComponentPopup.restore();
+      controller.clearConfigsChanges.restore();
+      App.showConfirmationPopup.restore();
     });
 
-    it('add ZOOKEEPER_SERVER', function () {
-      var event = {
-        context: Em.Object.create({
-          componentName: 'ZOOKEEPER_SERVER'
-        })
-      };
-      controller.addComponent(event);
-      expect(App.showConfirmationPopup.calledOnce).to.be.true;
-    });
-    it('add WEBHCAT_SERVER', function () {
-      var event = {
-        context: Em.Object.create({
-          componentName: 'WEBHCAT_SERVER'
-        })
-      };
-      controller.addComponent(event);
-      expect(App.showConfirmationPopup.calledOnce).to.be.true;
-    });
-    it('add slave component', function () {
-      var event = {
-        context: Em.Object.create({
-          componentName: 'HIVE_CLIENT'
-        })
-      };
-      controller.set('securityEnabled', false);
-      controller.addComponent(event);
-      expect(controller.addClientComponent.calledWith(Em.Object.create({
-        componentName: 'HIVE_CLIENT'
-      }))).to.be.true;
-    });
-  });
+    cases.forEach(function (testCase) {
 
-  describe('#formatClientsMessage()', function () {
-    var testCases = [
-      {
-        title: 'subComponentNames is null',
-        client: Em.Object.create({
-          subComponentNames: null,
-          displayName: 'CLIENTS'
-        }),
-        result: 'CLIENTS'
-      },
-      {
-        title: 'subComponentNames is empty',
-        client: Em.Object.create({
-          subComponentNames: [],
-          displayName: 'CLIENTS'
-        }),
-        result: 'CLIENTS'
-      },
-      {
-        title: 'displayName is null',
-        client: Em.Object.create({
-          subComponentNames: ['DATANODE'],
-          displayName: null
-        }),
-        result: ' (DataNode)'
-      },
-      {
-        title: 'displayName is CLIENTS',
-        client: Em.Object.create({
-          subComponentNames: ['DATANODE'],
-          displayName: 'CLIENTS'
-        }),
-        result: 'CLIENTS (DataNode)'
-      }
-    ];
-    testCases.forEach(function (test) {
-      it(test.title, function () {
-        expect(controller.formatClientsMessage(test.client)).to.equal(test.result);
-      });
-    });
-  });
+      describe('add ' + testCase.componentName, function () {
 
-  describe('#addClientComponent()', function () {
+        beforeEach(function () {
+          var event = {
+            context: Em.Object.create({
+              componentName: testCase.componentName
+            })
+          };
+          controller.addComponent(event);
+        });
 
-    var component = Em.Object.create({
-      componentName: ' Comp1'
-    });
+        it('controller.showAddComponentPopup', function () {
+          expect(controller.showAddComponentPopup.callCount).to.equal(testCase.showAddComponentPopupCallCount);
+        });
 
-    beforeEach(function () {
-      sinon.spy(controller, 'showAddComponentPopup');
-      sinon.stub(controller, 'installHostComponentCall', Em.K);
-    });
+        it('App.showConfirmationPopup', function () {
+          expect(App.showConfirmationPopup.callCount).to.equal(testCase.showConfirmationPopupCallCount);
+        });
 
-    afterEach(function () {
-      controller.showAddComponentPopup.restore();
-      controller.installHostComponentCall.restore();
-    });
+      });
 
-    it('any CLIENT component', function () {
-      controller.set('content.hostName', 'host1');
-      var popup = controller.addClientComponent(component);
-      expect(controller.showAddComponentPopup.calledOnce).to.be.true;
-      popup.onPrimary();
-      expect(controller.installHostComponentCall.calledWith('host1', component)).to.be.true;
     });
+
   });
 
   describe("#loadOozieConfigs()", function() {
@@ -647,7 +594,7 @@ describe('App.MainHostDetailsController', function () {
             tag: 'tag'
           }
         }
-      }});
+      }}, null, {});
       var args = testHelpers.findAjaxRequest('name', 'admin.get.all_configurations');
       expect(args[0]).exists;
       expect(args[0].sender).to.be.eql(controller);
@@ -672,6 +619,7 @@ describe('App.MainHostDetailsController', function () {
       sinon.stub(controller, 'getStormNimbusHosts').returns("host1");
       sinon.stub(controller, 'updateZkConfigs', Em.K);
       sinon.stub(controller, 'saveConfigsBatch', Em.K);
+      sinon.stub(controller, 'saveLoadedConfigs', Em.K);
       controller.set('nimbusHost', 'host2');
       controller.onLoadStormConfigs(data);
     });
@@ -679,6 +627,7 @@ describe('App.MainHostDetailsController', function () {
       controller.getStormNimbusHosts.restore();
       controller.updateZkConfigs.restore();
       controller.saveConfigsBatch.restore();
+      controller.saveLoadedConfigs.restore();
     });
     it("updateZkConfigs called with valid arguments", function() {
       expect(controller.updateZkConfigs.calledWith({'storm-site': {
@@ -718,7 +667,7 @@ describe('App.MainHostDetailsController', function () {
             tag: 'tag'
           }
         }
-      }});
+      }}, null, {});
       var args = testHelpers.findAjaxRequest('name', 'admin.get.all_configurations');
       expect(args[0]).exists;
       expect(args[0].sender).to.be.eql(controller);
@@ -742,7 +691,7 @@ describe('App.MainHostDetailsController', function () {
             tag: 'tag'
           }
         }
-      }});
+      }}, null, {});
       var args = testHelpers.findAjaxRequest('name', 'admin.get.all_configurations');
       expect(args[0]).exists;
       expect(args[0].sender).to.be.eql(controller);
@@ -812,10 +761,8 @@ describe('App.MainHostDetailsController', function () {
 
   describe('#showAddComponentPopup()', function () {
 
-    var message = 'Comp1';
-
     beforeEach(function () {
-      sinon.spy(App.ModalPopup, 'show');
+      sinon.stub(App.ModalPopup, 'show');
     });
 
     afterEach(function () {
@@ -823,9 +770,8 @@ describe('App.MainHostDetailsController', function () {
     });
 
     it('should display add component confirmation', function () {
-      var popup = controller.showAddComponentPopup(message, false, Em.K);
+      controller.showAddComponentPopup(Em.Object.create());
       expect(App.ModalPopup.show.calledOnce).to.be.true;
-      expect(popup.get('addComponentMsg')).to.eql(Em.I18n.t('hosts.host.addComponent.msg').format(message));
     });
   });
 
@@ -1008,7 +954,7 @@ describe('App.MainHostDetailsController', function () {
     });
 
     it('url params is empty', function () {
-      expect(controller.loadConfigsSuccessCallback()).to.be.false;
+      expect(controller.loadConfigsSuccessCallback(null, null, {})).to.be.false;
       var args = testHelpers.findAjaxRequest('name', 'reassign.load_configs');
       expect(args).not.exists;
     });
@@ -1017,6 +963,12 @@ describe('App.MainHostDetailsController', function () {
       var args = testHelpers.findAjaxRequest('name', 'reassign.load_configs');
       expect(args).exists;
     });
+    it('isConfigsLoadingInProgress is false', function () {
+      mockUrlParams = [];
+      controller.set('isConfigsLoadingInProgress', true);
+      controller.loadConfigsSuccessCallback(null, null, {});
+      expect(controller.get('isConfigsLoadingInProgress')).to.be.false;
+    });
   });
 
   describe('#saveZkConfigs()', function () {
@@ -1074,6 +1026,7 @@ describe('App.MainHostDetailsController', function () {
     beforeEach(function () {
       sinon.stub(controller, 'saveConfigsBatch', Em.K);
       sinon.stub(controller, 'updateZkConfigs', Em.K);
+      sinon.stub(controller, 'saveLoadedConfigs', Em.K);
       sinon.stub(App.Service, 'find', function() {
         return [
           Em.Object.create({ serviceName: 'HIVE' }),
@@ -1090,77 +1043,78 @@ describe('App.MainHostDetailsController', function () {
       App.Service.find.restore();
       controller.updateZkConfigs.restore();
       controller.saveConfigsBatch.restore();
+      controller.saveLoadedConfigs.restore();
     });
 
-      it('configs for YARN', function () {
-        var expected = {
-          properties: {
-            'yarn-site': {
-              p: 'ys'
-            }
-          },
-          properties_attributes: {
-            'yarn-site': {
-              p: 'pa_ys'
-            }
+    it('configs for YARN', function () {
+      var expected = {
+        properties: {
+          'yarn-site': {
+            p: 'ys'
           }
-        };
-        expect(this.groups[1]).to.be.eql(expected);
-      });
+        },
+        properties_attributes: {
+          'yarn-site': {
+            p: 'pa_ys'
+          }
+        }
+      };
+      expect(this.groups[1]).to.be.eql(expected);
+    });
 
-      it('configs for HIVE', function () {
-        var expected = {
-          "properties": {
-            "hive-site": {
-              "hs": "hs"
-            },
-            "webhcat-site": {
-              "ws": "ws"
-            }
+    it('configs for HIVE', function () {
+      var expected = {
+        "properties": {
+          "hive-site": {
+            "hs": "hs"
           },
-          "properties_attributes": {
-            "hive-site": {
-              "hs": "pa_hs"
-            },
-            "webhcat-site": {
-              "ws": "pa_ws"
-            }
+          "webhcat-site": {
+            "ws": "ws"
           }
-        };
-        expect(this.groups[0]).to.be.eql(expected);
-      });
-
-      it('configs for HBASE', function () {
-        var expected = {
-          "properties": {
-            "hbase-site": {
-              "hbs": "hbs"
-            }
+        },
+        "properties_attributes": {
+          "hive-site": {
+            "hs": "pa_hs"
           },
-          "properties_attributes": {
-            "hbase-site": {
-              "hbs": "pa_hbs"
-            }
+          "webhcat-site": {
+            "ws": "pa_ws"
           }
-        };
-        expect(this.groups[2]).to.be.eql(expected);
-      });
+        }
+      };
+      expect(this.groups[0]).to.be.eql(expected);
+    });
 
-      it('configs for ACCUMULO', function () {
-        var expected = {
-          "properties": {
-            "accumulo-site": {
-              "as": "as"
-            }
-          },
-          "properties_attributes": {
-            "accumulo-site": {
-              "as": "pa_as"
-            }
+    it('configs for HBASE', function () {
+      var expected = {
+        "properties": {
+          "hbase-site": {
+            "hbs": "hbs"
           }
-        };
-        expect(this.groups[3]).to.be.eql(expected);
-      });
+        },
+        "properties_attributes": {
+          "hbase-site": {
+            "hbs": "pa_hbs"
+          }
+        }
+      };
+      expect(this.groups[2]).to.be.eql(expected);
+    });
+
+    it('configs for ACCUMULO', function () {
+      var expected = {
+        "properties": {
+          "accumulo-site": {
+            "as": "as"
+          }
+        },
+        "properties_attributes": {
+          "accumulo-site": {
+            "as": "pa_as"
+          }
+        }
+      };
+      expect(this.groups[3]).to.be.eql(expected);
+    });
 
   });
 
@@ -1928,9 +1882,9 @@ describe('App.MainHostDetailsController', function () {
       expect(App.showConfirmationPopup.calledOnce).to.be.true;
       popup.onPrimary();
       expect(controller.sendComponentCommand.calledWith(
-          controller.get('serviceNonClientActiveComponents'),
-          Em.I18n.t('hosts.host.maintainance.startAllComponents.context'),
-          App.HostComponentStatus.started)
+        controller.get('serviceNonClientActiveComponents'),
+        Em.I18n.t('hosts.host.maintainance.startAllComponents.context'),
+        App.HostComponentStatus.started)
       ).to.be.true;
     });
   });
@@ -1966,9 +1920,9 @@ describe('App.MainHostDetailsController', function () {
       expect(App.showConfirmationPopup.calledOnce).to.be.true;
       popup.onPrimary();
       expect(controller.sendComponentCommand.calledWith(
-          controller.get('serviceNonClientActiveComponents'),
-          Em.I18n.t('hosts.host.maintainance.stopAllComponents.context'),
-          App.HostComponentStatus.stopped)
+        controller.get('serviceNonClientActiveComponents'),
+        Em.I18n.t('hosts.host.maintainance.stopAllComponents.context'),
+        App.HostComponentStatus.stopped)
       ).to.be.true;
     });
     it('serviceNonClientActiveComponents is correct, NAMENODE started', function () {
@@ -2556,8 +2510,8 @@ describe('App.MainHostDetailsController', function () {
   describe('#_doDeleteHostComponent()', function () {
     it('single component', function () {
       controller.set('content.hostName', 'host1');
-      var component = Em.Object.create({componentName: 'COMP'});
-      controller._doDeleteHostComponent(component);
+      var componentName = 'COMP';
+      controller._doDeleteHostComponent(componentName);
       var args = testHelpers.findAjaxRequest('name', 'common.delete.host_component');
       expect(args[0]).exists;
       expect(args[0].data).to.be.eql({
@@ -2578,73 +2532,28 @@ describe('App.MainHostDetailsController', function () {
   });
 
   describe('#_doDeleteHostComponentSuccessCallback()', function () {
+    var data = {
+      componentName: 'COMPONENT',
+      hostName: 'h1'
+    };
+
     beforeEach(function () {
       sinon.stub(controller, 'removeHostComponentModel', Em.K);
-      sinon.stub(controller, 'isServiceMetricsLoaded', function (callback) {
-        callback();
-      });
-      sinon.stub(controller, 'loadConfigs', Em.K);
+      controller.set('_deletedHostComponentResult', {});
+      controller._doDeleteHostComponentSuccessCallback({}, {}, data);
     });
 
     afterEach(function () {
       controller.removeHostComponentModel.restore();
-      controller.isServiceMetricsLoaded.restore();
-      controller.loadConfigs.restore();
     });
 
-    it('ZOOKEEPER_SERVER component', function () {
-      var data = {
-        componentName: 'ZOOKEEPER_SERVER'
-      };
-      controller._doDeleteHostComponentSuccessCallback({}, {}, data);
-      expect(controller.get('_deletedHostComponentResult')).to.be.null;
-      expect(controller.get('fromDeleteZkServer')).to.be.true;
-      expect(controller.loadConfigs.calledOnce).to.be.true;
-    });
-    it('Not ZOOKEEPER_SERVER component', function () {
-      var data = {
-        componentName: 'COMP'
-      };
-      controller.set('fromDeleteZkServer', false);
-      controller._doDeleteHostComponentSuccessCallback({}, {}, data);
+    it('should reset `_deletedHostComponentResult`', function () {
       expect(controller.get('_deletedHostComponentResult')).to.be.null;
-      expect(controller.get('fromDeleteZkServer')).to.be.false;
     });
+
     it('should call `removeHostComponentModel` with correct params', function () {
-      var data = {
-        componentName: 'COMPONENT',
-        hostName: 'h1'
-      };
-      controller._doDeleteHostComponentSuccessCallback({}, {}, data);
       expect(controller.removeHostComponentModel.calledWith('COMPONENT', 'h1')).to.be.true;
     });
-    it('HIVE_METASTORE component', function () {
-      var data = {
-        componentName: 'HIVE_METASTORE'
-      };
-      controller._doDeleteHostComponentSuccessCallback({}, {}, data);
-      expect(controller.get('_deletedHostComponentResult')).to.be.null;
-      expect(controller.get('deleteHiveMetaStore')).to.be.true;
-      expect(controller.loadConfigs.calledWith('loadHiveConfigs')).to.be.true;
-    });
-    it('NIMBUS component', function () {
-      var data = {
-        componentName: 'NIMBUS'
-      };
-      controller._doDeleteHostComponentSuccessCallback({}, {}, data);
-      expect(controller.get('_deletedHostComponentResult')).to.be.null;
-      expect(controller.get('deleteNimbusHost')).to.be.true;
-      expect(controller.loadConfigs.calledWith('loadStormConfigs')).to.be.true;
-    });
-    it('RANGER_KMS_SERVER component', function () {
-      var data = {
-        componentName: 'RANGER_KMS_SERVER'
-      };
-      controller._doDeleteHostComponentSuccessCallback({}, {}, data);
-      expect(controller.get('_deletedHostComponentResult')).to.be.null;
-      expect(controller.get('deleteRangerKMSServer')).to.be.true;
-      expect(controller.loadConfigs.calledWith('loadRangerConfigs')).to.be.true;
-    });
   });
 
   describe('#upgradeComponentSuccessCallback()', function () {
@@ -2679,62 +2588,6 @@ describe('App.MainHostDetailsController', function () {
     });
   });
 
-  describe('#checkZkConfigs()', function () {
-    beforeEach(function () {
-      sinon.stub(controller, 'removeObserver');
-      sinon.stub(controller, 'loadConfigs');
-      sinon.stub(controller, 'isServiceMetricsLoaded', Em.clb);
-      this.stub = sinon.stub(App.router, 'get');
-    });
-    afterEach(function () {
-      controller.loadConfigs.restore();
-      controller.removeObserver.restore();
-      controller.isServiceMetricsLoaded.restore();
-      this.stub.restore();
-    });
-
-    it('No operations of ZOOKEEPER_SERVER', function () {
-      this.stub.withArgs('backgroundOperationsController.services').returns([]);
-      controller.checkZkConfigs();
-      expect(controller.removeObserver.called).to.be.false;
-      expect(controller.loadConfigs.called).to.be.false;
-    });
-
-    it('Operation of ZOOKEEPER_SERVER running', function () {
-      this.stub.withArgs('backgroundOperationsController.services').returns([Em.Object.create({
-        id: 1,
-        isRunning: true
-      })]);
-      controller.set('zkRequestId', 1);
-      controller.checkZkConfigs();
-      expect(controller.removeObserver.called).to.be.false;
-      expect(controller.loadConfigs.called).to.be.false;
-    });
-
-    describe('Operation of ZOOKEEPER_SERVER finished', function () {
-
-      beforeEach(function () {
-        this.stub.withArgs('backgroundOperationsController.services').returns([Em.Object.create({
-          id: 1
-        })]);
-        this.clock = sinon.useFakeTimers();
-        controller.set('zkRequestId', 1);
-        controller.checkZkConfigs();
-      });
-
-      afterEach(function () {
-        this.clock.restore();
-      });
-
-      it('loadConfigs is called after `componentsUpdateInterval`', function () {
-        expect(controller.removeObserver.calledWith('App.router.backgroundOperationsController.serviceTimestamp', controller, controller.checkZkConfigs)).to.be.true;
-        this.clock.tick(App.get('componentsUpdateInterval'));
-        expect(controller.loadConfigs.calledOnce).to.be.true;
-      });
-
-    });
-  });
-
   describe('#_doDeleteHostComponentErrorCallback()', function () {
     it('call showBackgroundOperationsPopup', function () {
       controller._doDeleteHostComponentErrorCallback({}, 'textStatus', {}, {url: 'url'});
@@ -2883,86 +2736,86 @@ describe('App.MainHostDetailsController', function () {
   describe('#installClients()', function () {
 
     var cases = [
-        {
-          context: [
-            Em.Object.create({
-              componentName: 'c0',
-              workStatus: 'INSTALLED'
-            }),
-            Em.Object.create({
-              componentName: 'c1',
-              workStatus: 'INIT'
-            }),
-            Em.Object.create({
-              componentName: 'c2',
-              workStatus: 'INSTALL_FAILED'
-            })
-          ],
-          dependencies: {
-            c0: [],
-            c1: [],
-            c2: []
-          },
-          getSecurityTypeCalled: null, //should have same value as getKDCSessionStateCalled, always
-          getKDCSessionStateCalled: true,
-          sendComponentCommandCalled: true,
-          showAlertPopupCalled: false,
-          title: 'No clients to add, some clients to install'
+      {
+        context: [
+          Em.Object.create({
+            componentName: 'c0',
+            workStatus: 'INSTALLED'
+          }),
+          Em.Object.create({
+            componentName: 'c1',
+            workStatus: 'INIT'
+          }),
+          Em.Object.create({
+            componentName: 'c2',
+            workStatus: 'INSTALL_FAILED'
+          })
+        ],
+        dependencies: {
+          c0: [],
+          c1: [],
+          c2: []
         },
-        {
-          context: [
-            Em.Object.create({
-              componentName: 'c3',
-              displayName: 'c3'
-            })
-          ],
-          dependencies: {
-            c3: []
-          },
-          getSecurityTypeCalled: null, //should have same value as getKDCSessionStateCalled, always
-          getKDCSessionStateCalled: true,
-          sendComponentCommandCalled: false,
-          showAlertPopupCalled: false,
-          title: 'No clients to install, some clients to add'
+        getSecurityTypeCalled: null, //should have same value as getKDCSessionStateCalled, always
+        getKDCSessionStateCalled: true,
+        sendComponentCommandCalled: true,
+        showAlertPopupCalled: false,
+        title: 'No clients to add, some clients to install'
+      },
+      {
+        context: [
+          Em.Object.create({
+            componentName: 'c3',
+            displayName: 'c3'
+          })
+        ],
+        dependencies: {
+          c3: []
         },
-        {
-          context: [
-            Em.Object.create({
-              componentName: 'c4',
-              displayName: 'c4'
-            })
-          ],
-          dependencies: {
-            c4: ['c5']
-          },
-          getSecurityTypeCalled: null, //should have same value as getKDCSessionStateCalled, always
-          getKDCSessionStateCalled: false,
-          sendComponentCommandCalled: false,
-          showAlertPopupCalled: true,
-          title: 'Clients to add have unresolved dependencies'
+        getSecurityTypeCalled: null, //should have same value as getKDCSessionStateCalled, always
+        getKDCSessionStateCalled: true,
+        sendComponentCommandCalled: false,
+        showAlertPopupCalled: false,
+        title: 'No clients to install, some clients to add'
+      },
+      {
+        context: [
+          Em.Object.create({
+            componentName: 'c4',
+            displayName: 'c4'
+          })
+        ],
+        dependencies: {
+          c4: ['c5']
         },
-        {
-          context: [
-            Em.Object.create({
-              componentName: 'c5',
-              displayName: 'c5'
-            }),
-            Em.Object.create({
-              componentName: 'c6',
-              displayName: 'c6'
-            })
-          ],
-          dependencies: {
-            c5: ['c6'],
-            c6: ['c5']
-          },
-          getSecurityTypeCalled: null, //should have same value as getKDCSessionStateCalled, always
-          getKDCSessionStateCalled: true,
-          sendComponentCommandCalled: false,
-          showAlertPopupCalled: false,
-          title: 'Clients to add have mutual dependencies'
-        }
-      ];
+        getSecurityTypeCalled: null, //should have same value as getKDCSessionStateCalled, always
+        getKDCSessionStateCalled: false,
+        sendComponentCommandCalled: false,
+        showAlertPopupCalled: true,
+        title: 'Clients to add have unresolved dependencies'
+      },
+      {
+        context: [
+          Em.Object.create({
+            componentName: 'c5',
+            displayName: 'c5'
+          }),
+          Em.Object.create({
+            componentName: 'c6',
+            displayName: 'c6'
+          })
+        ],
+        dependencies: {
+          c5: ['c6'],
+          c6: ['c5']
+        },
+        getSecurityTypeCalled: null, //should have same value as getKDCSessionStateCalled, always
+        getKDCSessionStateCalled: true,
+        sendComponentCommandCalled: false,
+        showAlertPopupCalled: false,
+        title: 'Clients to add have mutual dependencies'
+      }
+    ];
 
     beforeEach(function () {
       sinon.stub(controller, 'sendComponentCommand', Em.K);
@@ -3096,9 +2949,7 @@ describe('App.MainHostDetailsController', function () {
       });
 
       it('_doDeleteHostComponent is called with correct arguments', function () {
-        expect(controller._doDeleteHostComponent.calledWith(Em.Object.create({
-          componentName: 'COMP1'
-        }))).to.be.true;
+        expect(controller._doDeleteHostComponent.calledWith('COMP1')).to.be.true;
       });
       it('fromDeleteHost is true', function () {
         expect(controller.get('fromDeleteHost')).to.be.true;
@@ -3429,11 +3280,13 @@ describe('App.MainHostDetailsController', function () {
     ];
 
     beforeEach(function () {
-      sinon.spy(controller, 'saveConfigsBatch')
+      sinon.spy(controller, 'saveConfigsBatch');
+      sinon.stub(controller, 'saveLoadedConfigs', Em.K);
     });
 
     afterEach(function () {
       controller.saveConfigsBatch.restore();
+      controller.saveLoadedConfigs.restore();
     });
 
     cases.forEach(function (item) {
@@ -3510,43 +3363,6 @@ describe('App.MainHostDetailsController', function () {
     });
   });
 
-  describe("#updateStormConfigs()", function () {
-    beforeEach(function () {
-      this.serviceMock = sinon.stub(App.Service, 'find');
-      sinon.stub(controller, 'loadConfigs');
-      this.mock = sinon.stub(App, 'get')
-    });
-    afterEach(function () {
-      this.serviceMock.restore();
-      this.mock.restore();
-      controller.loadConfigs.restore();
-    });
-    it("storm not installed, hadoop stack is 2.2", function () {
-      this.serviceMock.returns(Em.Object.create({
-        isLoaded: false
-      }));
-      this.mock.returns(false);
-      controller.updateStormConfigs();
-      expect(controller.loadConfigs.called).to.be.false;
-    });
-    it("storm installed, hadoop stack is 2.2", function () {
-      this.serviceMock.returns(Em.Object.create({
-        isLoaded: true
-      }));
-      this.mock.returns(false);
-      controller.updateStormConfigs();
-      expect(controller.loadConfigs.called).to.be.false;
-    });
-    it("storm installed, hadoop stack is 2.3", function () {
-      this.serviceMock.returns(Em.Object.create({
-        isLoaded: true
-      }));
-      this.mock.returns(true);
-      controller.updateStormConfigs();
-      expect(controller.loadConfigs.calledWith('loadStormConfigs')).to.be.true;
-    });
-  });
-
   describe("#parseNnCheckPointTime", function () {
     var tests = [
       {
@@ -3714,10 +3530,13 @@ describe('App.MainHostDetailsController', function () {
 
     beforeEach(function() {
       sinon.stub(controller, 'saveConfigsBatch', Em.K);
+      sinon.stub(controller, 'saveLoadedConfigs', Em.K);
+      controller.set('configs', {});
     });
 
     afterEach(function() {
       controller.saveConfigsBatch.restore();
+      controller.saveLoadedConfigs.restore();
     });
 
     var makeHostComponentModel = function(componentName, hostNames) {
@@ -4054,4 +3873,237 @@ describe('App.MainHostDetailsController', function () {
       });
     });
   });
+
+  describe('#setConfigsChangesForDisplay', function () {
+
+    var propertiesToChange = [
+        {
+          propertyName: 'n0',
+          propertyFileName: 'f0'
+        },
+        {
+          propertyName: 'n1',
+          propertyFileName: 'f1'
+        },
+        {
+          propertyName: 'n2',
+          propertyFileName: 'f2'
+        },
+        {
+          propertyName: 'n3',
+          propertyFileName: 'f3'
+        }
+      ],
+      result = {
+        recommendedPropertiesToChange: [
+          {
+            propertyName: 'n0',
+            propertyFileName: 'f0',
+            saveRecommended: true
+          },
+          {
+            propertyName: 'n3',
+            propertyFileName: 'f3',
+            saveRecommended: true
+          }
+        ],
+        requiredPropertiesToChange: [
+          {
+            propertyName: 'n1',
+            propertyFileName: 'f1'
+          },
+          {
+            propertyName: 'n2',
+            propertyFileName: 'f2'
+          }
+        ]
+      };
+
+    beforeEach(function () {
+      controller.setProperties({
+        allPropertiesToChange: propertiesToChange,
+        recommendedPropertiesToChange: [],
+        requiredPropertiesToChange: []
+      });
+      sinon.stub(App.configsCollection, 'getConfigByName', function (propertyName) {
+        var map = {
+          n0: {
+            isEditable: true,
+            isReconfigurable: true
+          },
+          n1: {
+            isEditable: true,
+            isReconfigurable: false
+          },
+          n2: {
+            isEditable: false,
+            isReconfigurable: false
+          }
+        };
+        return map[propertyName];
+      });
+      sinon.stub(App, 'get').withArgs('router.clusterController.isConfigsPropertiesLoaded').returns(true);
+      controller.set('isConfigsLoadingInProgress', true);
+      controller.setConfigsChangesForDisplay();
+    });
+
+    afterEach(function () {
+      App.configsCollection.getConfigByName.restore();
+      App.get.restore();
+    });
+
+    it('editable changes', function () {
+      expect(controller.get('recommendedPropertiesToChange').toArray()).to.eql(result.recommendedPropertiesToChange);
+    });
+
+    it('non-editable changes', function () {
+      expect(controller.get('requiredPropertiesToChange').toArray()).to.eql(result.requiredPropertiesToChange);
+    });
+
+    it('isConfigsLoadingInProgress', function () {
+      expect(controller.get('isConfigsLoadingInProgress')).to.be.false;
+    });
+
+  });
+
+  describe('#clearConfigsChanges', function () {
+
+    beforeEach(function () {
+      sinon.stub(controller, 'abortRequests', Em.K);
+      controller.setProperties({
+        allPropertiesToChange: [{}],
+        recommendedPropertiesToChange: [{}],
+        requiredPropertiesToChange: [{}],
+        groupedPropertiesToChange: [{}],
+        isReconfigureRequired: true,
+        configs: {}
+      });
+    });
+
+    afterEach(function () {
+      controller.abortRequests.restore();
+    });
+
+    describe('default case', function () {
+
+      beforeEach(function () {
+        controller.clearConfigsChanges();
+      });
+
+      it('allPropertiesToChange', function () {
+        expect(controller.get('allPropertiesToChange')).to.have.length(0);
+      });
+
+      it('recommendedPropertiesToChange', function () {
+        expect(controller.get('recommendedPropertiesToChange')).to.have.length(0);
+      });
+
+      it('groupedPropertiesToChange', function () {
+        expect(controller.get('groupedPropertiesToChange')).to.have.length(0);
+      });
+
+      it('isReconfigureRequired', function () {
+        expect(controller.get('isReconfigureRequired')).to.be.false;
+      });
+
+      it('configs', function () {
+        expect(controller.get('configs')).to.be.null;
+      });
+
+    });
+
+    describe('no loaded configs cleanup', function () {
+
+      beforeEach(function () {
+        controller.clearConfigsChanges(true);
+      });
+
+      it('configs shouldn\'t be cleared', function () {
+        expect(controller.get('configs')).to.not.be.null;
+      });
+
+    });
+
+  });
+
+  describe('#saveLoadedConfigs', function () {
+
+    var data = {
+      items: [
+        {
+          type: 't0',
+          properties: {
+            p0: 'v0',
+            p1: 'v1'
+          },
+          properties_attributes: {}
+        },
+        {
+          type: 't1',
+          properties: {
+            p2: 'v2',
+            p3: 'v3'
+          },
+          properties_attributes: {}
+        }
+      ]
+    };
+
+    it('should store data in configs object', function () {
+      controller.set('configs', null);
+      controller.saveLoadedConfigs(data);
+      expect(controller.get('configs')).to.eql(data);
+    });
+
+  });
+
+  describe('#loadComponentRelatedConfigs', function () {
+
+    var testCases = [
+      {
+        isReconfigureRequired: true,
+        loadConfigsCallCount: 1,
+        isConfigsLoadingInProgress: true,
+        message: 'reconfigure required'
+      },
+      {
+        isReconfigureRequired: false,
+        loadConfigsCallCount: 0,
+        isConfigsLoadingInProgress: false,
+        message: 'no reconfigure required'
+      }
+    ];
+
+    testCases.forEach(function (test) {
+
+      describe(test.message, function () {
+
+        beforeEach(function () {
+          sinon.stub(controller, 'isServiceMetricsLoaded', Em.clb);
+          sinon.stub(controller, 'loadConfigs', Em.K);
+          controller.setProperties({
+            isReconfigureRequired: test.isReconfigureRequired,
+            isConfigsLoadingInProgress: false
+          });
+          controller.loadComponentRelatedConfigs();
+        });
+
+        afterEach(function () {
+          controller.isServiceMetricsLoaded.restore();
+          controller.loadConfigs.restore();
+        });
+
+        it('loadConfigs', function () {
+          expect(controller.loadConfigs.callCount).to.equal(test.loadConfigsCallCount);
+        });
+
+        it('isConfigsLoadingInProgress', function () {
+          expect(controller.get('isConfigsLoadingInProgress')).to.equal(test.isConfigsLoadingInProgress);
+        });
+
+      });
+
+    });
+
+  });
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/test/controllers/main/service/info/config_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/service/info/config_test.js b/ambari-web/test/controllers/main/service/info/config_test.js
index 09772ff..874a104 100644
--- a/ambari-web/test/controllers/main/service/info/config_test.js
+++ b/ambari-web/test/controllers/main/service/info/config_test.js
@@ -535,20 +535,23 @@ describe("App.MainServiceInfoConfigsController", function () {
     beforeEach(function () {
       sinon.stub(Em.run, 'once', Em.K);
       sinon.stub(mainServiceInfoConfigsController, 'loadSelectedVersion');
-      sinon.stub(mainServiceInfoConfigsController, 'clearRecommendationsInfo');
+      sinon.spy(mainServiceInfoConfigsController, 'clearRecommendations');
+      mainServiceInfoConfigsController.set('groupsToSave', { HDFS: 'my cool group'});
+      mainServiceInfoConfigsController.set('recommendations', Em.A([{name: 'prop_1'}]));
+      mainServiceInfoConfigsController.doCancel();
     });
     afterEach(function () {
       Em.run.once.restore();
       mainServiceInfoConfigsController.loadSelectedVersion.restore();
-      mainServiceInfoConfigsController.clearRecommendationsInfo.restore();
+      mainServiceInfoConfigsController.clearRecommendations.restore();
+    });
+
+    it("should launch recommendations cleanup", function() {
+      expect(mainServiceInfoConfigsController.clearRecommendations.calledOnce).to.be.true;
     });
 
     it("should clear dependent configs", function() {
-      mainServiceInfoConfigsController.set('groupsToSave', { HDFS: 'my cool group'});
-      mainServiceInfoConfigsController.set('recommendations', Em.A([{name: 'prop_1'}]));
-      mainServiceInfoConfigsController.doCancel();
       expect(App.isEmptyObject(mainServiceInfoConfigsController.get('recommendations'))).to.be.true;
-      expect(mainServiceInfoConfigsController.clearRecommendationsInfo.calledOnce).to.be.true;
     });
   });
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/test/controllers/main/service/item_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/service/item_test.js b/ambari-web/test/controllers/main/service/item_test.js
index 1b21b78..969305d 100644
--- a/ambari-web/test/controllers/main/service/item_test.js
+++ b/ambari-web/test/controllers/main/service/item_test.js
@@ -1416,6 +1416,7 @@ describe('App.MainServiceItemController', function () {
       sinon.stub(App.ModalPopup, 'show');
       sinon.stub(App.format, 'role', function(name) {return name});
       sinon.stub(mainServiceItemController, 'kerberosDeleteWarning');
+      sinon.stub(mainServiceItemController, 'showLastWarning');
 
       mainServiceItemController.reopen({
         interDependentServices: []
@@ -1475,7 +1476,7 @@ describe('App.MainServiceItemController', function () {
       this.allowUninstallServices.returns(true);
       this.mockService.returns([Em.Object.create({workStatus: App.Service.statesMap.stopped}), Em.Object.create({workStatus: App.Service.statesMap.stopped})]);
       mainServiceItemController.deleteService('S1');
-      expect(App.showConfirmationPopup.calledOnce).to.be.true;
+      expect(mainServiceItemController.showLastWarning.calledOnce).to.be.true;
     });
 
     it("service has not dependent services, and install failed", function() {
@@ -1483,7 +1484,7 @@ describe('App.MainServiceItemController', function () {
       this.allowUninstallServices.returns(true);
       this.mockService.returns([Em.Object.create({workStatus: App.Service.statesMap.install_failed}), Em.Object.create({workStatus: App.Service.statesMap.install_failed})]);
       mainServiceItemController.deleteService('S1');
-      expect(App.showConfirmationPopup.calledOnce).to.be.true;
+      expect(mainServiceItemController.showLastWarning.calledOnce).to.be.true;
     });
 
     it("service has not dependent services, and not stopped", function() {
@@ -1707,29 +1708,27 @@ describe('App.MainServiceItemController', function () {
 
     beforeEach(function() {
       mainServiceItemController = App.MainServiceItemController.create({});
-      sinon.stub(mainServiceItemController, 'loadConfigRecommendations', Em.K);
+      sinon.stub(mainServiceItemController, 'saveConfigs', Em.K);
       sinon.stub(mainServiceItemController, 'deleteServiceCall', Em.K);
-      sinon.stub(App.get('router.mainController'), 'isLoading').returns($.Deferred().resolve().promise());
       mainServiceItemController.reopen({
         interDependentServices: []
       })
     });
     afterEach(function() {
-      mainServiceItemController.loadConfigRecommendations.restore();
+      mainServiceItemController.saveConfigs.restore();
       mainServiceItemController.deleteServiceCall.restore();
-      App.get('router.mainController').isLoading.restore();
     });
 
-    it("loadConfigRecommendations should be called", function() {
+    it("saveConfigs should be called", function() {
       mainServiceItemController.deleteServiceCallSuccessCallback([], null, {});
       expect(mainServiceItemController.deleteServiceCall.called).to.be.false;
-      expect(mainServiceItemController.loadConfigRecommendations.calledOnce).to.be.true;
+      expect(mainServiceItemController.saveConfigs.calledOnce).to.be.true;
     });
 
     it("deleteServiceCall should be called", function() {
       mainServiceItemController.deleteServiceCallSuccessCallback([], null, {servicesToDeleteNext: true});
       expect(mainServiceItemController.deleteServiceCall.calledOnce).to.be.true;
-      expect(mainServiceItemController.loadConfigRecommendations.called).to.be.false;
+      expect(mainServiceItemController.saveConfigs.called).to.be.false;
     });
   });
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/test/controllers/main/service/reassign/step1_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/service/reassign/step1_controller_test.js b/ambari-web/test/controllers/main/service/reassign/step1_controller_test.js
index a43d91f..7dbf24a 100644
--- a/ambari-web/test/controllers/main/service/reassign/step1_controller_test.js
+++ b/ambari-web/test/controllers/main/service/reassign/step1_controller_test.js
@@ -33,7 +33,7 @@ describe('App.ReassignMasterWizardStep1Controller', function () {
   });
   controller.set('_super', Em.K);
 
-  describe('#loadConfigTags', function() {
+  describe('#loadConfigsTags', function() {
     beforeEach(function() {
       this.stub = sinon.stub(App.router, 'get');
     });
@@ -42,7 +42,7 @@ describe('App.ReassignMasterWizardStep1Controller', function () {
       this.stub.restore();
     });
 
-    it('tests loadConfigTags', function() {
+    it('tests loadConfigsTags', function() {
       controller.loadConfigsTags();
       var args = testHelpers.findAjaxRequest('name', 'config.tags');
       expect(args).exists;
@@ -77,8 +77,11 @@ describe('App.ReassignMasterWizardStep1Controller', function () {
     });
 
     it('tests getDatabaseHost', function() {
-      controller.set('content.serviceProperties', {
-        'javax.jdo.option.ConnectionURL': "jdbc:mysql://c6401/hive?createDatabaseIfNotExist=true"
+      controller.set('content.configs', {
+        'hive-site': {
+          'javax.jdo.option.ConnectionURL': 'jdbc:mysql://c6401/hive?createDatabaseIfNotExist=true'
+
+        }
       });
 
       controller.set('content.reassign.service_id', 'HIVE');
@@ -108,7 +111,8 @@ describe('App.ReassignMasterWizardStep1Controller', function () {
       sinon.stub(controller, 'getDatabaseHost', Em.K);
       sinon.stub(controller, 'saveDatabaseType', Em.K);
       sinon.stub(controller, 'saveServiceProperties', Em.K);
-    
+      sinon.stub(controller, 'saveConfigs', Em.K);
+
       reassignCtrl = App.router.reassignMasterController;
       reassignCtrl.set('content.hasManualSteps', true);
     });
@@ -117,12 +121,14 @@ describe('App.ReassignMasterWizardStep1Controller', function () {
       controller.getDatabaseHost.restore();
       controller.saveDatabaseType.restore();
       controller.saveServiceProperties.restore();
+      controller.saveConfigs.restore();
     });
   
     it('should not set hasManualSteps to false for oozie with derby db', function() {
       var data = {
         items: [
           {
+            type: 'oozie-site',
             properties: {
               'oozie.service.JPAService.jdbc.driver': 'jdbc:derby:${oozie.data.dir}/${oozie.db.schema.name}-db;create=true'
             }
@@ -141,6 +147,7 @@ describe('App.ReassignMasterWizardStep1Controller', function () {
       var data = {
         items: [
           {
+            type: 'oozie-site',
             properties: {
               'oozie.service.JPAService.jdbc.driver': 'mysql'
             }

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/test/controllers/main/service/reassign/step3_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/service/reassign/step3_controller_test.js b/ambari-web/test/controllers/main/service/reassign/step3_controller_test.js
index e433f47..203d162 100644
--- a/ambari-web/test/controllers/main/service/reassign/step3_controller_test.js
+++ b/ambari-web/test/controllers/main/service/reassign/step3_controller_test.js
@@ -18,6 +18,8 @@
 
 var App = require('app');
 require('controllers/main/service/reassign/step3_controller');
+require('controllers/main/service/reassign_controller');
+var testHelpers = require('test/helpers');
 var controller;
 
 describe('App.ReassignMasterWizardStep3Controller', function () {
@@ -50,4 +52,636 @@ describe('App.ReassignMasterWizardStep3Controller', function () {
       expect(App.router.send.calledWith("next")).to.be.true;
     });
   });
+
+  describe('#setAdditionalConfigs()', function () {
+
+    beforeEach(function () {
+      sinon.stub(App, 'get').withArgs('isHaEnabled').returns(true);
+    });
+
+    afterEach(function () {
+      App.get.restore();
+    });
+
+    it('Component is absent', function () {
+      controller.set('additionalConfigsMap', []);
+      var configs = {};
+
+      expect(controller.setAdditionalConfigs(configs, 'COMP1', '')).to.be.false;
+      expect(configs).to.eql({});
+    });
+
+    it('configs for Hadoop 2 is present', function () {
+      controller.set('additionalConfigsMap', [
+        {
+          componentName: 'COMP1',
+          configs: {
+            'test-site': {
+              'property1': '<replace-value>:1111'
+            }
+          },
+          configs_Hadoop2: {
+            'test-site': {
+              'property2': '<replace-value>:2222'
+            }
+          }
+        }
+      ]);
+      var configs = {
+        'test-site': {}
+      };
+
+      expect(controller.setAdditionalConfigs(configs, 'COMP1', 'host1')).to.be.true;
+      expect(configs).to.eql({
+        'test-site': {
+          'property2': 'host1:2222'
+        }
+      });
+    });
+
+    it('ignore some configs for NameNode after HA', function () {
+      controller.set('additionalConfigsMap', [
+        {
+          componentName: 'NAMENODE',
+          configs: {
+            'test-site': {
+              'fs.defaultFS': '<replace-value>:1111',
+              'dfs.namenode.rpc-address': '<replace-value>:1111'
+            }
+          }
+        }
+      ]);
+      var configs = {'test-site': {}};
+
+      expect(controller.setAdditionalConfigs(configs, 'NAMENODE', 'host1')).to.be.true;
+      expect(configs).to.eql({'test-site': {}});
+    });
+  });
+
+  describe('#getConfigUrlParams()', function () {
+    var testCases = [
+      {
+        componentName: 'NAMENODE',
+        result: [
+          "(type=hdfs-site&tag=1)",
+          "(type=core-site&tag=2)"
+        ]
+      },
+      {
+        componentName: 'SECONDARY_NAMENODE',
+        result: [
+          "(type=hdfs-site&tag=1)",
+          "(type=core-site&tag=2)"
+        ]
+      },
+      {
+        componentName: 'JOBTRACKER',
+        result: [
+          "(type=mapred-site&tag=4)"
+        ]
+      },
+      {
+        componentName: 'RESOURCEMANAGER',
+        result: [
+          "(type=yarn-site&tag=5)"
+        ]
+      },
+      {
+        componentName: 'APP_TIMELINE_SERVER',
+        result: [
+          "(type=yarn-site&tag=5)",
+          "(type=yarn-env&tag=8)"
+        ]
+      },
+      {
+        componentName: 'OOZIE_SERVER',
+        result: [
+          "(type=oozie-site&tag=6)",
+          "(type=core-site&tag=2)",
+          "(type=oozie-env&tag=2)"
+        ]
+      },
+      {
+        componentName: 'WEBHCAT_SERVER',
+        result: [
+          "(type=hive-env&tag=11)",
+          "(type=webhcat-site&tag=7)",
+          "(type=core-site&tag=2)"
+        ]
+      },
+      {
+        componentName: 'HIVE_SERVER',
+        result: [
+          '(type=hive-site&tag=10)',
+          '(type=webhcat-site&tag=7)',
+          '(type=hive-env&tag=11)',
+          '(type=core-site&tag=2)'
+        ]
+      },
+      {
+        componentName: 'HIVE_METASTORE',
+        result: [
+          '(type=hive-site&tag=10)',
+          '(type=webhcat-site&tag=7)',
+          '(type=hive-env&tag=11)',
+          '(type=core-site&tag=2)'
+        ]
+      },
+      {
+        componentName: 'MYSQL_SERVER',
+        result: [
+          '(type=hive-site&tag=10)'
+        ]
+      },
+      {
+        componentName: 'HISTORYSERVER',
+        result: [
+          '(type=mapred-site&tag=4)'
+        ]
+      }
+    ];
+
+    var data = {
+      Clusters: {
+        desired_configs: {
+          'hdfs-site': {tag: 1},
+          'core-site': {tag: 2},
+          'hbase-site': {tag: 3},
+          'mapred-site': {tag: 4},
+          'yarn-site': {tag: 5},
+          'oozie-site': {tag: 6},
+          'oozie-env': {tag: 2},
+          'webhcat-site': {tag: 7},
+          'yarn-env': {tag: 8},
+          'accumulo-site': {tag: 9},
+          'hive-site': {tag: 10},
+          'hive-env': {tag: 11}
+        }
+      }
+    };
+
+    var services = [];
+
+    beforeEach(function () {
+      controller.set('wizardController', App.get('router.reassignMasterController'));
+      sinon.stub(App.Service, 'find', function () {
+        return services;
+      });
+    });
+    afterEach(function () {
+      App.Service.find.restore();
+    });
+
+    testCases.forEach(function (test) {
+      it('get config of ' + test.componentName, function () {
+        expect(controller.getConfigUrlParams(test.componentName, data)).to.eql(test.result);
+      });
+    });
+    it('get config of NAMENODE when HBASE installed', function () {
+      services = [
+        {
+          serviceName: 'HBASE'
+        }
+      ];
+      expect(controller.getConfigUrlParams('NAMENODE', data)).to.eql([
+        "(type=hdfs-site&tag=1)",
+        "(type=core-site&tag=2)",
+        "(type=hbase-site&tag=3)"
+      ]);
+    });
+
+    it('get config of NAMENODE when ACCUMULO installed', function () {
+      services = [
+        {
+          serviceName: 'ACCUMULO'
+        }
+      ];
+      expect(controller.getConfigUrlParams('NAMENODE', data)).to.eql([
+        "(type=hdfs-site&tag=1)",
+        "(type=core-site&tag=2)",
+        "(type=accumulo-site&tag=9)"
+      ]);
+    });
+
+  });
+
+  describe('#onLoadConfigsTags()', function () {
+    var dummyData = {
+      Clusters: {
+        desired_configs : {}
+      }
+    };
+
+    beforeEach(function () {
+      sinon.stub(controller, 'getConfigUrlParams', function () {
+        return [];
+      });
+      controller.set('content', {
+        reassign: {
+          component_name: 'COMP1'
+        }
+      });
+      controller.onLoadConfigsTags(dummyData);
+      this.args = testHelpers.findAjaxRequest('name', 'reassign.load_configs');
+    });
+
+    afterEach(function () {
+      controller.getConfigUrlParams.restore();
+    });
+
+    it('request is sent', function () {
+      expect(this.args).exists;
+    });
+
+    it('getConfigUrlParams is called with correct data', function () {
+      expect(controller.getConfigUrlParams.calledWith('COMP1', dummyData)).to.be.true;
+    });
+  });
+
+  describe('#setSecureConfigs()', function () {
+
+    beforeEach(function () {
+      this.stub = sinon.stub(App, 'get');
+    });
+
+    afterEach(function () {
+      Em.tryInvoke(App.get, 'restore');
+    });
+
+    it('undefined component and security disabled', function () {
+      var secureConfigs = [];
+      this.stub.withArgs('isKerberosEnabled').returns(false);
+      controller.set('secureConfigsMap', []);
+      expect(controller.setSecureConfigs(secureConfigs, {}, 'COMP1')).to.be.false;
+      expect(secureConfigs).to.eql([]);
+    });
+
+    it('component exist and security disabled', function () {
+      var secureConfigs = [];
+      this.stub.withArgs('isKerberosEnabled').returns(false);
+      controller.set('secureConfigsMap', [{
+        componentName: 'COMP1'
+      }]);
+      expect(controller.setSecureConfigs(secureConfigs, {}, 'COMP1')).to.be.false;
+      expect(secureConfigs).to.eql([]);
+    });
+
+    it('undefined component and security enabled', function () {
+      var secureConfigs = [];
+      this.stub.withArgs('isKerberosEnabled').returns(true);
+      controller.set('secureConfigsMap', []);
+      expect(controller.setSecureConfigs(secureConfigs, {}, 'COMP1')).to.be.false;
+      expect(secureConfigs).to.eql([]);
+    });
+    it('component exist and security enabled', function () {
+      var secureConfigs = [];
+      this.stub.withArgs('isKerberosEnabled').returns(true);
+      var configs = {'s1': {
+        'k1': 'kValue',
+        'p1': 'pValue'
+      }};
+      controller.set('secureConfigsMap', [{
+        componentName: 'COMP1',
+        configs: [{
+          site: 's1',
+          keytab: 'k1',
+          principal: 'p1'
+        }]
+      }]);
+      expect(controller.setSecureConfigs(secureConfigs, configs, 'COMP1')).to.be.true;
+      expect(secureConfigs).to.eql([
+        {
+          "keytab": "kValue",
+          "principal": "pValue"
+        }
+      ]);
+    });
+  });
+
+  describe('#setDynamicCinfigs()', function () {
+
+    describe('HIVE', function() {
+      beforeEach(function () {
+        controller.set('content', Em.Object.create({
+          masterComponentHosts: [
+            {
+              component: 'HIVE_METASTORE',
+              hostName: 'host1'
+            },
+            {
+              component: 'HIVE_METASTORE',
+              hostName: 'host3'
+            },
+            {
+              component: 'HIVE_SERVER',
+              hostName: 'host4'
+            }
+          ],
+          reassignHosts: {
+            source: 'host1',
+            target: 'host2'
+          }
+        }));
+      });
+      it("reassign component is HIVE_METASTORE", function() {
+        var configs = {
+          'hive-env': {
+            'hive_user': 'hive_user'
+          },
+          'hive-site': {
+            'hive.metastore.uris': ''
+          },
+          'webhcat-site': {
+            'templeton.hive.properties': 'thrift'
+          },
+          'core-site': {
+            'hadoop.proxyuser.hive_user.hosts': ''
+          }
+        };
+        App.MoveHmConfigInitializer.setup(controller._getHiveInitializerSettings(configs));
+        configs = controller.setDynamicConfigs(configs, App.MoveHmConfigInitializer);
+        expect(configs['hive-site']['hive.metastore.uris']).to.equal('thrift://host3:9083,thrift://host2:9083');
+        expect(configs['webhcat-site']['templeton.hive.properties']).to.equal('thrift');
+        expect(configs['core-site']['hadoop.proxyuser.hive_user.hosts']).to.equal('host2,host3,host4');
+      });
+
+      it("reassign component is HIVE_SERVER", function() {
+        controller.get('content.masterComponentHosts').pushObject({component: 'HIVE_SERVER', hostName: 'host1'});
+        var configs = {
+          'hive-env': {
+            'hive_user': 'hive_user'
+          },
+          'hive-site': {
+            'hive.metastore.uris': ''
+          },
+          'webhcat-site': {
+            'templeton.hive.properties': 'thrift'
+          },
+          'core-site': {
+            'hadoop.proxyuser.hive_user.hosts': ''
+          }
+        };
+        App.MoveHsConfigInitializer.setup(controller._getHiveInitializerSettings(configs));
+        configs = controller.setDynamicConfigs(configs, App.MoveHsConfigInitializer);
+        expect(configs['core-site']['hadoop.proxyuser.hive_user.hosts']).to.equal('host1,host2,host3,host4');
+      });
+
+      it("reassign component is WEBHCAT_SERVER", function() {
+        controller.get('content.masterComponentHosts').pushObject({component: 'WEBHCAT_SERVER', hostName: 'host1'});
+        var configs = {
+          'hive-env': {
+            'webhcat_user': 'webhcat_user'
+          },
+          'hive-site': {
+            'hive.metastore.uris': ''
+          },
+          'webhcat-site': {
+            'templeton.hive.properties': 'thrift'
+          },
+          'core-site': {
+            'hadoop.proxyuser.webhcat_user.hosts': ''
+          }
+        };
+        App.MoveWsConfigInitializer.setup(controller._getWsInitializerSettings(configs));
+        configs = controller.setDynamicConfigs(configs, App.MoveWsConfigInitializer);
+        expect(configs['core-site']['hadoop.proxyuser.webhcat_user.hosts']).to.equal('host2');
+      });
+    });
+
+    describe('RESOURCEMANAGER', function () {
+      beforeEach(function () {
+        sinon.stub(App, 'get').withArgs('isRMHaEnabled').returns(true);
+      });
+      afterEach(function () {
+        App.get.restore();
+        App.MoveRmConfigInitializer.cleanup();
+      });
+
+      it('HA enabled and resource manager 1', function () {
+        controller.set('content', Em.Object.create({
+          reassignHosts: {
+            source: 'host1',
+            target: 'host3'
+          }
+        }));
+        var configs = {
+          'yarn-site': {
+            'yarn.resourcemanager.hostname.rm1': 'host1',
+            'yarn.resourcemanager.webapp.address.rm1': 'host1:8088',
+            'yarn.resourcemanager.webapp.https.address.rm1': 'host1:8443',
+            'yarn.resourcemanager.hostname.rm2': 'host2',
+            'yarn.resourcemanager.webapp.address.rm2': 'host2:8088',
+            'yarn.resourcemanager.webapp.https.address.rm2': 'host2:8443'
+          }
+        };
+        var additionalDependencies = controller._getRmAdditionalDependencies(configs);
+        App.MoveRmConfigInitializer.setup(controller._getRmInitializerSettings(configs));
+        configs = controller.setDynamicConfigs(configs, App.MoveRmConfigInitializer, additionalDependencies);
+        expect(configs['yarn-site']).to.eql({
+          'yarn.resourcemanager.hostname.rm1': 'host3',
+          'yarn.resourcemanager.webapp.address.rm1': 'host3:8088',
+          'yarn.resourcemanager.webapp.https.address.rm1': 'host3:8443',
+          'yarn.resourcemanager.hostname.rm2': 'host2',
+          'yarn.resourcemanager.webapp.address.rm2': 'host2:8088',
+          'yarn.resourcemanager.webapp.https.address.rm2': 'host2:8443'
+        });
+      });
+
+      it('HA enabled and resource manager 2', function () {
+        controller.set('content', Em.Object.create({
+          reassignHosts: {
+            source: 'host2',
+            target: 'host3'
+          }
+        }));
+        var configs = {
+          'yarn-site': {
+            'yarn.resourcemanager.hostname.rm1': 'host1',
+            'yarn.resourcemanager.webapp.address.rm1': 'host1:8088',
+            'yarn.resourcemanager.webapp.https.address.rm1': 'host1:8443',
+            'yarn.resourcemanager.hostname.rm2': 'host2',
+            'yarn.resourcemanager.webapp.address.rm2': 'host2:8088',
+            'yarn.resourcemanager.webapp.https.address.rm2': 'host2:8443'
+          }
+        };
+        var additionalDependencies = controller._getRmAdditionalDependencies(configs);
+        App.MoveRmConfigInitializer.setup(controller._getRmInitializerSettings(configs));
+        configs = controller.setDynamicConfigs(configs, App.MoveRmConfigInitializer, additionalDependencies);
+
+        expect(configs['yarn-site']).to.eql({
+          'yarn.resourcemanager.hostname.rm1': 'host1',
+          'yarn.resourcemanager.webapp.address.rm1': 'host1:8088',
+          'yarn.resourcemanager.webapp.https.address.rm1': 'host1:8443',
+          'yarn.resourcemanager.hostname.rm2': 'host3',
+          'yarn.resourcemanager.webapp.address.rm2': 'host3:8088',
+          'yarn.resourcemanager.webapp.https.address.rm2': 'host3:8443'
+        });
+      });
+    });
+
+    describe('NAMENODE', function () {
+      var isHaEnabled = false;
+
+      beforeEach(function () {
+        sinon.stub(App, 'get', function () {
+          return isHaEnabled;
+        });
+        sinon.stub(App.Service, 'find', function () {
+          return [
+            {serviceName: 'HDFS'},
+            {serviceName: 'ACCUMULO'},
+            {serviceName: 'HBASE'},
+            {serviceName: 'HAWQ'}
+          ];
+        });
+        controller.set('content', Em.Object.create({
+          reassignHosts: {
+            source: 'host1'
+          }
+        }));
+      });
+
+      afterEach(function () {
+        App.get.restore();
+        App.Service.find.restore();
+        App.MoveNameNodeConfigInitializer.cleanup();
+      });
+
+      it('HA isn\'t enabled and HBASE, HAWQ and ACCUMULO service', function () {
+        isHaEnabled = false;
+        var configs = {
+          'hbase-site': {
+            'hbase.rootdir': 'hdfs://localhost:8020/apps/hbase/data'
+          },
+          'accumulo-site': {
+            'instance.volumes': 'hdfs://localhost:8020/apps/accumulo/data',
+            'instance.volumes.replacements': ''
+          },
+          'hawq-site': {
+            'hawq_dfs_url': 'localhost:8020/hawq/data'
+          }
+        };
+
+        controller.set('content.reassignHosts.target', 'host2');
+
+        App.MoveNameNodeConfigInitializer.setup(controller._getNnInitializerSettings(configs));
+        configs = controller.setDynamicConfigs(configs, App.MoveNameNodeConfigInitializer);
+
+        expect(configs['hbase-site']['hbase.rootdir']).to.equal('hdfs://host2:8020/apps/hbase/data');
+        expect(configs['accumulo-site']['instance.volumes']).to.equal('hdfs://host2:8020/apps/accumulo/data');
+        expect(configs['accumulo-site']['instance.volumes.replacements']).to.equal('hdfs://host1:8020/apps/accumulo/data hdfs://host2:8020/apps/accumulo/data');
+        expect(configs['hawq-site'].hawq_dfs_url).to.equal('host2:8020/hawq/data');
+      });
+
+      it('HA enabled and namenode 1', function () {
+        isHaEnabled = true;
+        var configs = {
+          'hdfs-site': {
+            'dfs.nameservices': 's',
+            'dfs.namenode.http-address.s.nn1': 'host1:50070',
+            'dfs.namenode.https-address.s.nn1': 'host1:50470',
+            'dfs.namenode.rpc-address.s.nn1': 'host1:8020'
+          },
+          'hdfs-client': {
+            'dfs.namenode.rpc-address.s.nn1': '',
+            'dfs.namenode.http-address.s.nn1': 'host1:50070'
+          }
+        };
+
+        controller.set('content.reassignHosts.target', 'host2');
+        App.MoveNameNodeConfigInitializer.setup(controller._getNnInitializerSettings(configs));
+        configs = controller.setDynamicConfigs(configs, App.MoveNameNodeConfigInitializer);
+        expect(configs['hdfs-site']).to.eql({
+          "dfs.nameservices": "s",
+          "dfs.namenode.http-address.s.nn1": "host2:50070",
+          "dfs.namenode.https-address.s.nn1": "host2:50470",
+          "dfs.namenode.rpc-address.s.nn1": "host2:8020"
+        });
+        expect(configs['hdfs-client']).to.eql({
+          "dfs.namenode.http-address.s.nn1": "host2:50070",
+          "dfs.namenode.rpc-address.s.nn1": "host2:8020"
+        });
+      });
+
+      it('HA enabled and namenode 2', function () {
+        isHaEnabled = true;
+        var configs = {
+          'hdfs-site': {
+            'dfs.nameservices': 's',
+            "dfs.namenode.http-address.s.nn1": "host1:50070",
+            'dfs.namenode.http-address.s.nn2': 'host2:50070',
+            'dfs.namenode.https-address.s.nn2': 'host2:50470',
+            'dfs.namenode.rpc-address.s.nn2': 'host2:8020'
+          },
+          'hdfs-client': {
+            'dfs.namenode.rpc-address.s.nn2': '',
+            'dfs.namenode.http-address.s.nn2': 'host2:50070'
+          }
+        };
+        controller.set('content.reassignHosts.source', 'host2');
+        controller.set('content.reassignHosts.target', 'host3');
+
+        App.MoveNameNodeConfigInitializer.setup(controller._getNnInitializerSettings(configs));
+        configs = controller.setDynamicConfigs(configs, App.MoveNameNodeConfigInitializer);
+
+        expect(configs['hdfs-site']).to.eql({
+          "dfs.nameservices": "s",
+          "dfs.namenode.http-address.s.nn1": "host1:50070",
+          "dfs.namenode.http-address.s.nn2": "host3:50070",
+          "dfs.namenode.https-address.s.nn2": "host3:50470",
+          "dfs.namenode.rpc-address.s.nn2": "host3:8020"
+        });
+        expect(configs['hdfs-client']).to.eql({
+          "dfs.namenode.http-address.s.nn2": "host3:50070",
+          "dfs.namenode.rpc-address.s.nn2": "host3:8020"
+        });
+      });
+
+    });
+
+    describe('OOZIE_SERVER', function () {
+
+      it('should upodate hadoop.proxyuser.${oozie_user}.hosts', function () {
+
+        var configs = {
+          'oozie-env': {
+            'oozie_user': 'cool_dude'
+          },
+          'core-site': {
+            'hadoop.proxyuser.cool_dude.hosts': ''
+          }
+        };
+
+        controller.set('content', Em.Object.create({
+          masterComponentHosts: [
+            {
+              component: 'OOZIE_SERVER',
+              hostName: 'host2'
+            },
+            {
+              component: 'OOZIE_SERVER',
+              hostName: 'host3'
+            },
+            {
+              component: 'OOZIE_SERVER',
+              hostName: 'host1'
+            }
+          ],
+          reassignHosts: {
+            source: 'host1',
+            target: 'host4'
+          }
+        }));
+
+        App.MoveOSConfigInitializer.setup(controller._getOsInitializerSettings(configs));
+        configs = controller.setDynamicConfigs(configs, App.MoveOSConfigInitializer);
+        App.MoveOSConfigInitializer.cleanup();
+
+        expect(configs['core-site']['hadoop.proxyuser.cool_dude.hosts']).to.equal('host2,host3,host4');
+
+      });
+
+    });
+
+  });
 });


[3/4] ambari git commit: AMBARI-20143 Merge changes in branch-feature-preview-configs to branch-2.5. (ababiichuk)

Posted by ab...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/controllers/main/service/reassign/step3_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/reassign/step3_controller.js b/ambari-web/app/controllers/main/service/reassign/step3_controller.js
index d717dea..d4edb1e 100644
--- a/ambari-web/app/controllers/main/service/reassign/step3_controller.js
+++ b/ambari-web/app/controllers/main/service/reassign/step3_controller.js
@@ -21,6 +21,678 @@ var App = require('app');
 App.ReassignMasterWizardStep3Controller = Em.Controller.extend({
   name: 'reassignMasterWizardStep3Controller',
 
+  componentSpecificTypesMap: {
+    'NAMENODE': [
+      {
+        serviceName: 'HBASE',
+        configTypes: ['hbase-site']
+      },
+      {
+        serviceName: 'ACCUMULO',
+        configTypes: ['accumulo-site']
+      },
+      {
+        serviceName: 'HAWQ',
+        configTypes: ['hawq-site', 'hdfs-client']
+      }
+    ],
+    'RESOURCEMANAGER': [
+      {
+        serviceName: 'HAWQ',
+        configTypes: ['hawq-site', 'yarn-client']
+      }
+    ]
+  },
+
+  /**
+   * additional configs with template values
+   * Part of value to substitute has following format: "<replace-value>"
+   */
+  additionalConfigsMap: [
+    {
+      componentName: 'RESOURCEMANAGER',
+      configs: {
+        'yarn-site': {
+          'yarn.resourcemanager.address': '<replace-value>:8050',
+          'yarn.resourcemanager.admin.address': '<replace-value>:8141',
+          'yarn.resourcemanager.resource-tracker.address': '<replace-value>:8025',
+          'yarn.resourcemanager.scheduler.address': '<replace-value>:8030',
+          'yarn.resourcemanager.webapp.address': '<replace-value>:8088',
+          'yarn.resourcemanager.hostname': '<replace-value>'
+        }
+      }
+    },
+    {
+      componentName: 'JOBTRACKER',
+      configs: {
+        'mapred-site': {
+          'mapred.job.tracker.http.address': '<replace-value>:50030',
+          'mapred.job.tracker': '<replace-value>:50300'
+        }
+      }
+    },
+    {
+      componentName: 'SECONDARY_NAMENODE',
+      configs: {
+        'hdfs-site': {
+          'dfs.secondary.http.address': '<replace-value>:50090'
+        }
+      },
+      configs_Hadoop2: {
+        'hdfs-site': {
+          'dfs.namenode.secondary.http-address': '<replace-value>:50090'
+        }
+      }
+    },
+    {
+      componentName: 'NAMENODE',
+      configs: {
+        'hdfs-site': {
+          'dfs.http.address': '<replace-value>:50070',
+          'dfs.https.address': '<replace-value>:50470'
+        },
+        'core-site': {
+          'fs.default.name': 'hdfs://<replace-value>:8020'
+        }
+      },
+      configs_Hadoop2: {
+        'hdfs-site': {
+          'dfs.namenode.rpc-address': '<replace-value>:8020',
+          'dfs.namenode.http-address': '<replace-value>:50070',
+          'dfs.namenode.https-address': '<replace-value>:50470'
+        },
+        'core-site': {
+          'fs.defaultFS': 'hdfs://<replace-value>:8020'
+        }
+      }
+    },
+    {
+      componentName: 'APP_TIMELINE_SERVER',
+      configs: {
+        'yarn-site': {
+          'yarn.timeline-service.webapp.address': '<replace-value>:8188',
+          'yarn.timeline-service.webapp.https.address': '<replace-value>:8190',
+          'yarn.timeline-service.address': '<replace-value>:10200'
+        }
+      }
+    },
+    {
+      componentName: 'OOZIE_SERVER',
+      configs: {
+        'oozie-site': {
+          'oozie.base.url': 'http://<replace-value>:11000/oozie'
+        },
+        'core-site': {
+          'hadoop.proxyuser.oozie.hosts': '<replace-value>'
+        }
+      }
+    },
+    {
+      componentName: 'HIVE_METASTORE',
+      configs: {
+        'hive-site': {}
+      }
+    },
+    {
+      componentName: 'MYSQL_SERVER',
+      configs: {
+        'hive-site': {
+          'javax.jdo.option.ConnectionURL': 'jdbc:mysql://<replace-value>/hive?createDatabaseIfNotExist=true'
+        }
+      }
+    },
+    {
+      componentName: 'HISTORYSERVER',
+      configs: {
+        'mapred-site': {
+          'mapreduce.jobhistory.webapp.address': '<replace-value>:19888',
+          'mapreduce.jobhistory.address': '<replace-value>:10020'
+        }
+      }
+    }
+  ],
+
+  secureConfigsMap: [
+    {
+      componentName: 'NAMENODE',
+      configs: [
+        {
+          site: 'hdfs-site',
+          keytab: 'dfs.namenode.keytab.file',
+          principal: 'dfs.namenode.kerberos.principal'
+        },
+        {
+          site: 'hdfs-site',
+          keytab: 'dfs.web.authentication.kerberos.keytab',
+          principal: 'dfs.web.authentication.kerberos.principal'
+        }
+      ]
+    },
+    {
+      componentName: 'SECONDARY_NAMENODE',
+      configs: [
+        {
+          site: 'hdfs-site',
+          keytab: 'dfs.secondary.namenode.keytab.file',
+          principal: 'dfs.secondary.namenode.kerberos.principal'
+        },
+        {
+          site: 'hdfs-site',
+          keytab: 'dfs.web.authentication.kerberos.keytab',
+          principal: 'dfs.web.authentication.kerberos.principal'
+        }
+      ]
+    },
+    {
+      componentName: 'RESOURCEMANAGER',
+      configs: [
+        {
+          site: 'yarn-site',
+          keytab: 'yarn.resourcemanager.keytab',
+          principal: 'yarn.resourcemanager.principal'
+        },
+        {
+          site: 'yarn-site',
+          keytab: 'yarn.resourcemanager.webapp.spnego-keytab-file',
+          principal: 'yarn.resourcemanager.webapp.spnego-principal'
+        }
+      ]
+    },
+    {
+      componentName: 'OOZIE_SERVER',
+      configs: [
+        {
+          site: 'oozie-site',
+          keytab: 'oozie.authentication.kerberos.keytab',
+          principal: 'oozie.authentication.kerberos.principal'
+        },
+        {
+          site: 'oozie-site',
+          keytab: 'oozie.service.HadoopAccessorService.keytab.file',
+          principal: 'oozie.service.HadoopAccessorService.kerberos.principal'
+        }
+      ]
+    },
+    {
+      componentName: 'WEBHCAT_SERVER',
+      configs: [
+        {
+          site: 'webhcat-site',
+          keytab: 'templeton.kerberos.keytab',
+          principal: 'templeton.kerberos.principal'
+        }
+      ]
+    },
+    {
+      componentName: 'HIVE_SERVER',
+      configs: [
+        {
+          site: 'hive-site',
+          keytab: 'hive.server2.authentication.kerberos.keytab',
+          principal: 'hive.server2.authentication.kerberos.principal'
+        },
+        {
+          site: 'hive-site',
+          keytab: 'hive.server2.authentication.spnego.keytab',
+          principal: 'hive.server2.authentication.spnego.principal'
+        }
+      ]
+    },
+    {
+      componentName: 'HIVE_METASTORE',
+      configs: [
+        {
+          site: 'hive-site',
+          keytab: 'hive.metastore.kerberos.keytab.file',
+          principal: 'hive.metastore.kerberos.principal'
+        }
+      ]
+    }
+
+  ],
+
+  isLoaded: false,
+
+  versionLoaded: true,
+
+  hideDependenciesInfoBar: true,
+
+  configs: null,
+
+  configsAttributes: null,
+
+  secureConfigs: [],
+
+  stepConfigs: [],
+
+  propertiesToChange: {},
+
+  isSubmitDisabled: Em.computed.and('wizardController.isComponentWithReconfiguration', '!isLoaded'),
+
+  loadStep: function () {
+    if (this.get('wizardController.isComponentWithReconfiguration')) {
+      this.set('isLoaded', false);
+      App.ajax.send({
+        name: 'config.tags',
+        sender: this,
+        success: 'onLoadConfigsTags'
+      });
+    }
+  },
+
+  clearStep: function () {
+    this.setProperties({
+      configs: null,
+      configsAttributes: null,
+      secureConfigs: [],
+      propertiesToChange: {}
+    });
+  },
+
+  onLoadConfigsTags: function (data) {
+    var urlParams = this.getConfigUrlParams(this.get('content.reassign.component_name'), data);
+
+    App.ajax.send({
+      name: 'reassign.load_configs',
+      sender: this,
+      data: {
+        urlParams: urlParams.join('|')
+      },
+      success: 'onLoadConfigs'
+    });
+  },
+
+  getConfigUrlParams: function (componentName, data) {
+    var urlParams = [];
+
+    this.get('wizardController.serviceToConfigSiteMap')[componentName].forEach(function(site){
+      urlParams.push('(type=' + site + '&tag=' + data.Clusters.desired_configs[site].tag + ')');
+    });
+
+    // specific cases for certain components
+    var specificTypes = this.get('componentSpecificTypesMap')[componentName];
+    if (specificTypes) {
+      var services = App.Service.find();
+      specificTypes.forEach(function (service) {
+        if (services.someProperty('serviceName', service.serviceName)) {
+          service.configTypes.forEach(function (site) {
+            urlParams.push('(type=' + site + '&tag=' + data.Clusters.desired_configs[site].tag + ')');
+          });
+        }
+      });
+    }
+
+    return urlParams;
+  },
+
+  renderServiceConfigs: function (configs) {
+    var self = this,
+      configCategories = [],
+      displayedConfigs = [],
+      serviceConfig = App.ServiceConfig.create({
+        serviceName: 'MISC',
+        configCategories: configCategories,
+        showConfig: true,
+        configs: displayedConfigs
+      });
+    App.get('router.mainController.isLoading').call(App.get('router.clusterController'), 'isConfigsPropertiesLoaded').done(function () {
+      Em.keys(self.get('propertiesToChange')).forEach(function (type) {
+        var service = App.config.get('serviceByConfigTypeMap')[type];
+        if (service) {
+          var serviceName = service.get('serviceName');
+          if (!configCategories.someProperty('name', serviceName)) {
+            configCategories.push(App.ServiceConfigCategory.create({
+              name: serviceName,
+              displayName: service.get('displayName')
+            }));
+          }
+          this.get('propertiesToChange')[type].forEach(function (property) {
+            var propertyName = property.name,
+              stackProperty = App.configsCollection.getConfigByName(propertyName, type) || {},
+              displayedProperty = App.ServiceConfigProperty.create({
+                name: propertyName,
+                displayName: propertyName,
+                fileName: type
+              }, stackProperty, {
+                value: configs[type][propertyName],
+                category: serviceName,
+                isEditable: Boolean(stackProperty.isEditable !== false && !property.isSecure)
+              });
+            displayedConfigs.push(displayedProperty);
+          });
+        }
+      }, self);
+      self.setProperties({
+        stepConfigs: [serviceConfig],
+        selectedService: serviceConfig,
+        isLoaded: true
+      });
+    });
+  },
+
+  onLoadConfigs: function (data) {
+    // Find hawq-site.xml location
+    var hawqSiteIndex = -1;
+    for(var i = 0; i < data.items.length; i++){
+      if(data.items[i].type == 'hawq-site'){
+        hawqSiteIndex = i;
+        break;
+      }
+    }
+
+    // if certain services are deployed, include related site files to additionalConfigsMap and relatedServicesMap.
+    if(hawqSiteIndex >= 0){ // if HAWQ is deployed
+      var hawqSiteProperties = {
+        'hawq_rm_yarn_address': '<replace-value>:8050',
+        'hawq_rm_yarn_scheduler_address': '<replace-value>:8030'
+      }
+
+      var rmComponent = this.get('additionalConfigsMap').findProperty('componentName', "RESOURCEMANAGER");
+      rmComponent.configs["hawq-site"] = hawqSiteProperties;
+
+      if(data.items[hawqSiteIndex].properties["hawq_global_rm_type"].toLowerCase() === "yarn"){
+        this.get('wizardController.relatedServicesMap')['RESOURCEMANAGER'].append('HAWQ');
+      }
+
+    }
+
+    var componentName = this.get('content.reassign.component_name');
+    var targetHostName = this.get('content.reassignHosts.target');
+    var configs = {};
+    var attributes = {};
+    var secureConfigs = [];
+
+    data.items.forEach(function (item) {
+      configs[item.type] = item.properties;
+      if (item.properties_attributes) {
+        attributes[item.type] = item.properties_attributes;
+      }
+    });
+
+    this.set('configsAttributes', attributes);
+
+    this.setAdditionalConfigs(configs, componentName, targetHostName);
+    this.setSecureConfigs(secureConfigs, configs, componentName);
+
+    this.set('secureConfigs', secureConfigs);
+
+    switch (componentName) {
+      case 'NAMENODE':
+        App.MoveNameNodeConfigInitializer.setup(this._getNnInitializerSettings(configs));
+        configs = this.setDynamicConfigs(configs, App.MoveNameNodeConfigInitializer);
+        App.MoveNameNodeConfigInitializer.cleanup();
+        break;
+      case 'RESOURCEMANAGER':
+        App.MoveRmConfigInitializer.setup(this._getRmInitializerSettings(configs));
+        var additionalDependencies = this._getRmAdditionalDependencies(configs);
+        configs = this.setDynamicConfigs(configs, App.MoveRmConfigInitializer, additionalDependencies);
+        App.MoveRmConfigInitializer.cleanup();
+        break;
+      case 'HIVE_METASTORE':
+        App.MoveHmConfigInitializer.setup(this._getHiveInitializerSettings(configs));
+        configs = this.setDynamicConfigs(configs, App.MoveHmConfigInitializer);
+        App.MoveHmConfigInitializer.cleanup();
+        break;
+      case 'HIVE_SERVER':
+        App.MoveHsConfigInitializer.setup(this._getHiveInitializerSettings(configs));
+        configs = this.setDynamicConfigs(configs, App.MoveHsConfigInitializer);
+        App.MoveHsConfigInitializer.cleanup();
+        break;
+      case 'WEBHCAT_SERVER':
+        App.MoveWsConfigInitializer.setup(this._getWsInitializerSettings(configs));
+        configs = this.setDynamicConfigs(configs, App.MoveWsConfigInitializer);
+        App.MoveWsConfigInitializer.cleanup();
+        break;
+      case 'OOZIE_SERVER':
+        App.MoveOSConfigInitializer.setup(this._getOsInitializerSettings(configs));
+        configs = this.setDynamicConfigs(configs, App.MoveOSConfigInitializer);
+        App.MoveOSConfigInitializer.cleanup();
+    }
+
+    this.renderServiceConfigs(configs);
+    this.set('configs', configs);
+  },
+
+  /**
+   * set additional configs
+   * configs_Hadoop2 - configs which belongs to Hadoop 2 stack only
+   * @param configs
+   * @param componentName
+   * @param replaceValue
+   * @return {Boolean}
+   */
+  setAdditionalConfigs: function (configs, componentName, replaceValue) {
+    var component = this.get('additionalConfigsMap').findProperty('componentName', componentName);
+
+    if (Em.isNone(component)) return false;
+    var additionalConfigs = (component.configs_Hadoop2) ? component.configs_Hadoop2 : component.configs;
+
+    for (var site in additionalConfigs) {
+      if (additionalConfigs.hasOwnProperty(site)) {
+        for (var property in additionalConfigs[site]) {
+          if (additionalConfigs[site].hasOwnProperty(property)) {
+            if (App.get('isHaEnabled') && componentName === 'NAMENODE' && (property === 'fs.defaultFS' || property === 'dfs.namenode.rpc-address')) continue;
+
+            configs[site][property] = additionalConfigs[site][property].replace('<replace-value>', replaceValue);
+            if (!this.get('propertiesToChange').hasOwnProperty(site)) {
+              this.get('propertiesToChange')[site] = [];
+            }
+            this.get('propertiesToChange')[site].push({
+              name: property
+            });
+          }
+        }
+      }
+    }
+    return true;
+  },
+
+  /**
+   * set secure configs for component
+   * @param secureConfigs
+   * @param configs
+   * @param componentName
+   * @return {Boolean}
+   */
+  setSecureConfigs: function (secureConfigs, configs, componentName) {
+    var securityEnabled = App.get('isKerberosEnabled');
+    var component = this.get('secureConfigsMap').findProperty('componentName', componentName);
+    if (Em.isNone(component) || !securityEnabled) return false;
+
+    component.configs.forEach(function (config) {
+      secureConfigs.push({
+        keytab: configs[config.site][config.keytab],
+        principal: configs[config.site][config.principal]
+      });
+      if (!this.get('propertiesToChange').hasOwnProperty(config.site)) {
+        this.get('propertiesToChange')[config.site] = [];
+      }
+      this.get('propertiesToChange')[config.site].push(
+        {
+          name: config.keytab,
+          isSecure: true
+        },
+        {
+          name: config.principal,
+          isSecure: true
+        }
+      );
+    }, this);
+    return true;
+  },
+
+  /**
+   * Get additional dependencies-data for App.MoveNameNodeConfigInitializer
+   *
+   * @param {object} configs
+   * @returns {object}
+   * @private
+   * @method _getNnInitializerSettings
+   */
+  _getNnInitializerSettings: function (configs) {
+    var ret = {};
+    if (App.get('isHaEnabled')) {
+      ret.namespaceId = configs['hdfs-site']['dfs.nameservices'];
+      ret.suffix = (configs['hdfs-site']['dfs.namenode.http-address.' + ret.namespaceId + '.nn1'].indexOf(this.get('content.reassignHosts.source')) != -1) ? 'nn1' : 'nn2';
+    }
+    return ret;
+  },
+
+  /**
+   * Settings used to the App.MoveRmConfigInitializer setup
+   *
+   * @param {object} configs
+   * @returns {{suffix: string}}
+   * @private
+   * @method _getRmInitializerSettings
+   */
+  _getRmInitializerSettings: function (configs) {
+    return {
+      suffix: configs['yarn-site']['yarn.resourcemanager.hostname.rm1'] === this.get('content.reassignHosts.source') ? 'rm1': 'rm2'
+    };
+  },
+
+  /**
+   * Get additional dependencies-data for App.MoveRmConfigInitializer
+   *
+   * @param {object} configs
+   * @returns {object}
+   * @private
+   * @method _getRmAdditionalDependencies
+   */
+  _getRmAdditionalDependencies: function (configs) {
+    var ret = {};
+    var rm1 = configs['yarn-site']['yarn.resourcemanager.hostname.rm1'];
+    if (rm1) {
+      ret.rm1 = rm1;
+    }
+    var rm2 = configs['yarn-site']['yarn.resourcemanager.hostname.rm2'];
+    if (rm2) {
+      ret.rm2 = rm2;
+    }
+    return ret;
+  },
+
+  /**
+   * Settings used to the App.MoveHsConfigInitializer and App.MoveHmConfigInitializer setup
+   *
+   * @param {object} configs
+   * @returns {{hiveUser: string}}
+   * @private
+   * @method _getHiveInitializerSettings
+   */
+  _getHiveInitializerSettings: function (configs) {
+    return {
+      hiveUser: configs['hive-env']['hive_user']
+    };
+  },
+
+  /**
+   * Settings used to the App.MoveWsConfigInitializer setup
+   *
+   * @param {object} configs
+   * @returns {{webhcatUser: string}}
+   * @private
+   * @method _getWsInitializerSettings
+   */
+  _getWsInitializerSettings: function (configs) {
+    return {
+      webhcatUser: configs['hive-env']['webhcat_user']
+    };
+  },
+
+  /**
+   * Settings used to the App.MoveOSConfigInitializer setup
+   *
+   * @param {object} configs
+   * @returns {object}
+   * @private
+   * @method _getOsInitializerSettings
+   */
+  _getOsInitializerSettings: function (configs) {
+    var ret = {};
+    var cfg = configs['oozie-env']['oozie_user'];
+    if (cfg) {
+      ret.oozieUser = cfg;
+    }
+    return ret;
+  },
+
+  /**
+   * Set config values according to the new cluster topology
+   *
+   * @param {object} configs
+   * @param {MoveComponentConfigInitializerClass} initializer
+   * @param {object} [additionalDependencies={}]
+   * @returns {object}
+   * @method setDynamicConfigs
+   */
+  setDynamicConfigs: function (configs, initializer, additionalDependencies) {
+    additionalDependencies = additionalDependencies || {};
+    var topologyDB = this._prepareTopologyDB(),
+      dependencies = this._prepareDependencies(additionalDependencies),
+      initializerObjects = initializer.get('initializers'),
+      uniqueInitializerObjects = initializer.get('uniqueInitializers');
+    Em.keys(configs).forEach(function (site) {
+      Em.keys(configs[site]).forEach(function (config) {
+        // temporary object for initializer
+        var cfg = {
+          name: config,
+          filename: site,
+          value: configs[site][config]
+        };
+        configs[site][config] = initializer.initialValue(cfg, topologyDB, dependencies).value;
+        if (initializerObjects[config] || uniqueInitializerObjects[config]) {
+          if (!this.get('propertiesToChange').hasOwnProperty(site)) {
+            this.get('propertiesToChange')[site] = [];
+          }
+          this.get('propertiesToChange')[site].push({
+            name: config
+          });
+        }
+      }, this);
+    }, this);
+    return configs;
+  },
+
+  /**
+   *
+   * @returns {extendedTopologyLocalDB}
+   * @private
+   * @method _prepareTopologyDB
+   */
+  _prepareTopologyDB: function () {
+    var ret = this.get('content').getProperties(['masterComponentHosts', 'slaveComponentHosts', 'hosts']);
+    ret.installedServices = App.Service.find().mapProperty('serviceName');
+    return ret;
+  },
+
+  /**
+   * Create dependencies for Config Initializers
+   *
+   * @param {object} additionalDependencies  some additional information that should be added
+   * @returns {reassignComponentDependencies}
+   * @private
+   * @method _prepareDependencies
+   */
+  _prepareDependencies: function (additionalDependencies) {
+    additionalDependencies = additionalDependencies || {};
+    var ret = {};
+    ret.sourceHostName = this.get('content.reassignHosts.source');
+    ret.targetHostName = this.get('content.reassignHosts.target');
+    return Em.merge(ret, additionalDependencies);
+  },
+
+  updateServiceConfigs: function () {
+    var configs = this.get('configs');
+    if (configs) {
+      this.get('selectedService.configs').forEach(function (property) {
+        var type = App.config.getConfigTagFromFileName(property.fileName);
+        configs[type][property.name] = property.value;
+      }, this);
+    }
+  },
+
   submit: function() {
     App.get('router.mainAdminKerberosController').getKDCSessionState(function() {
       App.router.send("next");

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/controllers/main/service/reassign/step4_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/reassign/step4_controller.js b/ambari-web/app/controllers/main/service/reassign/step4_controller.js
index e14cb2a..f87d05b 100644
--- a/ambari-web/app/controllers/main/service/reassign/step4_controller.js
+++ b/ambari-web/app/controllers/main/service/reassign/step4_controller.js
@@ -72,267 +72,19 @@ App.ReassignMasterWizardStep4Controller = App.HighAvailabilityProgressPageContro
 
   dependentHostComponents: [],
 
-  /**
-   * List of components, that do not need reconfiguration for moving to another host
-   * Reconfigure command will be skipped
-   */
-  componentsWithoutReconfiguration: ['METRICS_COLLECTOR'],
-
-  /**
-   * Map with lists of related services.
-   * Used to define list of services to stop/start.
-   */
-  relatedServicesMap: {
-    'JOBTRACKER': ['PIG', 'OOZIE'],
-    'RESOURCEMANAGER': ['YARN', 'MAPREDUCE2', 'TEZ', 'PIG', 'OOZIE', 'SLIDER', 'SPARK'],
-    'APP_TIMELINE_SERVER': ['YARN', 'MAPREDUCE2', 'TEZ', 'OOZIE', 'SLIDER', 'SPARK'],
-    'HIVE_SERVER': ['HIVE', 'FALCON', 'ATLAS', 'OOZIE'],
-    'HIVE_METASTORE': ['HIVE', 'PIG', 'FALCON', 'ATLAS', 'OOZIE'],
-    'WEBHCAT_SERVER': ['HIVE'],
-    'OOZIE_SERVER': ['OOZIE', 'FALCON', 'KNOX'],
-    'MYSQL_SERVER': ['HIVE', 'OOZIE', 'RANGER', 'RANGER_KMS'],
-    'METRICS_COLLECTOR': ['AMBARI_METRICS']
-  },
-
   dbPropertyMap: {
-    'HIVE_SERVER': 'javax.jdo.option.ConnectionDriverName',
-    'HIVE_METASTORE': 'javax.jdo.option.ConnectionDriverName',
-    'OOZIE_SERVER': 'oozie.service.JPAService.jdbc.url'
-  },
-
-  /**
-   * additional configs with template values
-   * Part of value to substitute has following format: "<replace-value>"
-   */
-  additionalConfigsMap: [
-    {
-      componentName: 'RESOURCEMANAGER',
-      configs: {
-        'yarn-site': {
-          'yarn.resourcemanager.address': '<replace-value>:8050',
-          'yarn.resourcemanager.admin.address': '<replace-value>:8141',
-          'yarn.resourcemanager.resource-tracker.address': '<replace-value>:8025',
-          'yarn.resourcemanager.scheduler.address': '<replace-value>:8030',
-          'yarn.resourcemanager.webapp.address': '<replace-value>:8088',
-          'yarn.resourcemanager.hostname': '<replace-value>'
-        }
-      }
-    },
-    {
-      componentName: 'JOBTRACKER',
-      configs: {
-        'mapred-site': {
-          'mapred.job.tracker.http.address': '<replace-value>:50030',
-          'mapred.job.tracker': '<replace-value>:50300'
-        }
-      }
-    },
-    {
-      componentName: 'SECONDARY_NAMENODE',
-      configs: {
-        'hdfs-site': {
-          'dfs.secondary.http.address': '<replace-value>:50090'
-        }
-      },
-      configs_Hadoop2: {
-        'hdfs-site': {
-          'dfs.namenode.secondary.http-address': '<replace-value>:50090'
-        }
-      }
-    },
-    {
-      componentName: 'NAMENODE',
-      configs: {
-        'hdfs-site': {
-          'dfs.http.address': '<replace-value>:50070',
-          'dfs.https.address': '<replace-value>:50470'
-        },
-        'core-site': {
-          'fs.default.name': 'hdfs://<replace-value>:8020'
-        }
-      },
-      configs_Hadoop2: {
-        'hdfs-site': {
-          'dfs.namenode.rpc-address': '<replace-value>:8020',
-          'dfs.namenode.http-address': '<replace-value>:50070',
-          'dfs.namenode.https-address': '<replace-value>:50470'
-        },
-        'core-site': {
-          'fs.defaultFS': 'hdfs://<replace-value>:8020'
-        }
-      }
-    },
-    {
-      componentName: 'APP_TIMELINE_SERVER',
-      configs: {
-        'yarn-site': {
-          'yarn.timeline-service.webapp.address': '<replace-value>:8188',
-          'yarn.timeline-service.webapp.https.address': '<replace-value>:8190',
-          'yarn.timeline-service.address': '<replace-value>:10200'
-        }
-      }
-    },
-    {
-      componentName: 'OOZIE_SERVER',
-        configs: {
-          'oozie-site': {
-            'oozie.base.url': 'http://<replace-value>:11000/oozie'
-          },
-          'core-site': {
-            'hadoop.proxyuser.oozie.hosts': '<replace-value>'
-          }
-        }
-    },
-    {
-      componentName: 'HIVE_METASTORE',
-      configs: {
-        'hive-site': {}
-      }
-    },
-    {
-      componentName: 'MYSQL_SERVER',
-      configs: {
-        'hive-site': {
-          'javax.jdo.option.ConnectionURL': 'jdbc:mysql://<replace-value>/hive?createDatabaseIfNotExist=true'
-        }
-      }
-    },
-    {
-      componentName: 'HISTORYSERVER',
-      configs: {
-        'mapred-site': {
-          'mapreduce.jobhistory.webapp.address': '<replace-value>:19888',
-          'mapreduce.jobhistory.address': '<replace-value>:10020'
-        }
-      }
-    }
-  ],
-
-  secureConfigsMap: [
-    {
-      componentName: 'NAMENODE',
-      configs: [
-        {
-          site: 'hdfs-site',
-          keytab: 'dfs.namenode.keytab.file',
-          principal: 'dfs.namenode.kerberos.principal'
-        },
-        {
-          site: 'hdfs-site',
-          keytab: 'dfs.web.authentication.kerberos.keytab',
-          principal: 'dfs.web.authentication.kerberos.principal'
-        }
-      ]
-    },
-    {
-      componentName: 'SECONDARY_NAMENODE',
-      configs: [
-        {
-          site: 'hdfs-site',
-          keytab: 'dfs.secondary.namenode.keytab.file',
-          principal: 'dfs.secondary.namenode.kerberos.principal'
-        },
-        {
-          site: 'hdfs-site',
-          keytab: 'dfs.web.authentication.kerberos.keytab',
-          principal: 'dfs.web.authentication.kerberos.principal'
-        }
-      ]
+    'HIVE_SERVER': {
+      type: 'hive-site',
+      name: 'javax.jdo.option.ConnectionDriverName'
     },
-    {
-      componentName: 'RESOURCEMANAGER',
-      configs: [
-        {
-          site: 'yarn-site',
-          keytab: 'yarn.resourcemanager.keytab',
-          principal: 'yarn.resourcemanager.principal'
-        },
-        {
-          site: 'yarn-site',
-          keytab: 'yarn.resourcemanager.webapp.spnego-keytab-file',
-          principal: 'yarn.resourcemanager.webapp.spnego-principal'
-        }
-      ]
-    },
-    {
-      componentName: 'OOZIE_SERVER',
-      configs: [
-        {
-          site: 'oozie-site',
-          keytab: 'oozie.authentication.kerberos.keytab',
-          principal: 'oozie.authentication.kerberos.principal'
-        },
-        {
-          site: 'oozie-site',
-          keytab: 'oozie.service.HadoopAccessorService.keytab.file',
-          principal: 'oozie.service.HadoopAccessorService.kerberos.principal'
-        }
-      ]
-    },
-    {
-      componentName: 'WEBHCAT_SERVER',
-      configs: [
-        {
-          site: 'webhcat-site',
-          keytab: 'templeton.kerberos.keytab',
-          principal: 'templeton.kerberos.principal'
-        }
-      ]
+    'HIVE_METASTORE': {
+      type: 'hive-site',
+      name: 'javax.jdo.option.ConnectionDriverName'
     },
-    {
-      componentName: 'HIVE_SERVER',
-      configs: [
-        {
-          site: 'hive-site',
-          keytab: 'hive.server2.authentication.kerberos.keytab',
-          principal: 'hive.server2.authentication.kerberos.principal'
-        },
-        {
-          site: 'hive-site',
-          keytab: 'hive.server2.authentication.spnego.keytab',
-          principal: 'hive.server2.authentication.spnego.principal'
-        }
-      ]
-    },
-    {
-      componentName: 'HIVE_METASTORE',
-      configs: [
-        {
-          site: 'hive-site',
-          keytab: 'hive.metastore.kerberos.keytab.file',
-          principal: 'hive.metastore.kerberos.principal'
-        }
-      ]
-    }
-
-  ],
-
-  /**
-   * set additional configs
-   * configs_Hadoop2 - configs which belongs to Hadoop 2 stack only
-   * @param configs
-   * @param componentName
-   * @param replaceValue
-   * @return {Boolean}
-   */
-  setAdditionalConfigs: function (configs, componentName, replaceValue) {
-    var component = this.get('additionalConfigsMap').findProperty('componentName', componentName);
-
-    if (Em.isNone(component)) return false;
-    var additionalConfigs = (component.configs_Hadoop2) ? component.configs_Hadoop2 : component.configs;
-
-    for (var site in additionalConfigs) {
-      if (additionalConfigs.hasOwnProperty(site)) {
-        for (var property in additionalConfigs[site]) {
-          if (additionalConfigs[site].hasOwnProperty(property)) {
-            if (App.get('isHaEnabled') && componentName === 'NAMENODE' && (property === 'fs.defaultFS' || property === 'dfs.namenode.rpc-address')) continue;
-
-            configs[site][property] = additionalConfigs[site][property].replace('<replace-value>', replaceValue);
-          }
-        }
-      }
+    'OOZIE_SERVER': {
+      type: 'oozie-site',
+      name: 'oozie.service.JPAService.jdbc.url'
     }
-    return true;
   },
 
   /**
@@ -418,7 +170,7 @@ App.ReassignMasterWizardStep4Controller = App.HighAvailabilityProgressPageContro
       this.removeTasks(['startZooKeeperServers', 'startNameNode']);
     }
 
-    if (this.get('componentsWithoutReconfiguration').contains(componentName)) {
+    if (!this.get('wizardController.isComponentWithReconfiguration')) {
       this.removeTasks(['reconfigure']);
     }
 
@@ -478,7 +230,7 @@ App.ReassignMasterWizardStep4Controller = App.HighAvailabilityProgressPageContro
    * make server call to stop services
    */
   stopRequiredServices: function () {
-    this.stopServices(this.get('relatedServicesMap')[this.get('content.reassign.component_name')], true);
+    this.stopServices(this.get('wizardController.relatedServicesMap')[this.get('content.reassign.component_name')], true);
   },
 
   createHostComponents: function () {
@@ -523,313 +275,12 @@ App.ReassignMasterWizardStep4Controller = App.HighAvailabilityProgressPageContro
   },
 
   reconfigure: function () {
-    this.loadConfigsTags();
-  },
-
-  loadConfigsTags: function () {
-    App.ajax.send({
-      name: 'config.tags',
-      sender: this,
-      success: 'onLoadConfigsTags',
-      error: 'onTaskError'
-    });
-  },
-
-  serviceToConfigSiteMap: {
-    'NAMENODE': ['hdfs-site', 'core-site'],
-    'SECONDARY_NAMENODE': ['hdfs-site', 'core-site'],
-    'JOBTRACKER': ['mapred-site'],
-    'RESOURCEMANAGER': ['yarn-site'],
-    'WEBHCAT_SERVER': ['hive-env', 'webhcat-site', 'core-site'],
-    'APP_TIMELINE_SERVER': ['yarn-site', 'yarn-env'],
-    'OOZIE_SERVER': ['oozie-site', 'core-site', 'oozie-env'],
-    'HIVE_SERVER': ['hive-site', 'webhcat-site', 'hive-env', 'core-site'],
-    'HIVE_METASTORE': ['hive-site', 'webhcat-site', 'hive-env', 'core-site'],
-    'MYSQL_SERVER': ['hive-site'],
-    'HISTORYSERVER': ['mapred-site']
-  },
-
-  /**
-   * construct URL parameters for config call
-   * @param componentName
-   * @param data
-   * @return {Array}
-   */
-  getConfigUrlParams: function (componentName, data) {
-    var urlParams = [];
-
-    this.get('serviceToConfigSiteMap')[componentName].forEach(function(site){
-      urlParams.push('(type=' + site + '&tag=' + data.Clusters.desired_configs[site].tag + ')');
-    });
-
-    // specific cases for NameNode component
-    if (componentName === 'NAMENODE') {
-        if (App.Service.find().someProperty('serviceName', 'HBASE')) {
-          urlParams.push('(type=hbase-site&tag=' + data.Clusters.desired_configs['hbase-site'].tag + ')');
-        }
-        if (App.Service.find().someProperty('serviceName', 'ACCUMULO')) {
-          urlParams.push('(type=accumulo-site&tag=' + data.Clusters.desired_configs['accumulo-site'].tag + ')');
-        }
-        if (App.Service.find().someProperty('serviceName', 'HAWQ')) {
-          urlParams.push('(type=hawq-site&tag=' + data.Clusters.desired_configs['hawq-site'].tag + ')');
-          urlParams.push('(type=hdfs-client&tag=' + data.Clusters.desired_configs['hdfs-client'].tag + ')');
-        }
-    }
-
-    if (componentName === 'RESOURCEMANAGER') {
-        if (App.Service.find().someProperty('serviceName', 'HAWQ')) {
-          urlParams.push('(type=hawq-site&tag=' + data.Clusters.desired_configs['hawq-site'].tag + ')');
-          urlParams.push('(type=yarn-client&tag=' + data.Clusters.desired_configs['yarn-client'].tag + ')');
-        }
-    }
-
-    return urlParams;
-  },
-
-  onLoadConfigsTags: function (data) {
-    var urlParams = this.getConfigUrlParams(this.get('content.reassign.component_name'), data);
-
-    App.ajax.send({
-      name: 'reassign.load_configs',
-      sender: this,
-      data: {
-        urlParams: urlParams.join('|')
-      },
-      success: 'onLoadConfigs',
-      error: 'onTaskError'
-    });
-  },
-
-  /**
-   *
-   * @returns {extendedTopologyLocalDB}
-   * @private
-   * @method _prepareTopologyDB
-   */
-  _prepareTopologyDB: function () {
-    var ret = this.get('content').getProperties(['masterComponentHosts', 'slaveComponentHosts', 'hosts']);
-    ret.installedServices = App.Service.find().mapProperty('serviceName');
-    return ret;
-  },
-
-  /**
-   * Create dependencies for Config Initializers
-   *
-   * @param {object} additionalDependencies  some additional information that should be added
-   * @returns {reassignComponentDependencies}
-   * @private
-   * @method _prepareDependencies
-   */
-  _prepareDependencies: function (additionalDependencies) {
-    additionalDependencies = additionalDependencies || {};
-    var ret = {};
-    ret.sourceHostName = this.get('content.reassignHosts.source');
-    ret.targetHostName = this.get('content.reassignHosts.target');
-    return Em.merge(ret, additionalDependencies);
-  },
-
-  /**
-   * Get additional dependencies-data for App.MoveRmConfigInitializer
-   *
-   * @param {object} configs
-   * @returns {object}
-   * @private
-   * @method _getRmAdditionalDependencies
-   */
-  _getRmAdditionalDependencies: function (configs) {
-    var ret = {};
-    var rm1 = configs['yarn-site']['yarn.resourcemanager.hostname.rm1'];
-    if (rm1) {
-      ret.rm1 = rm1;
-    }
-    var rm2 = configs['yarn-site']['yarn.resourcemanager.hostname.rm2'];
-    if (rm2) {
-      ret.rm2 = rm2;
-    }
-    return ret;
-  },
-
-  /**
-   * Settings used to the App.MoveOSConfigInitializer setup
-   *
-   * @param {object} configs
-   * @returns {object}
-   * @private
-   * @method _getOsInitializerSettings
-   */
-  _getOsInitializerSettings: function (configs) {
-    var ret = {};
-    var cfg = configs['oozie-env']['oozie_user'];
-    if (cfg) {
-      ret.oozieUser = cfg;
-    }
-    return ret;
-  },
-
-  /**
-   * Get additional dependencies-data for App.MoveNameNodeConfigInitializer
-   *
-   * @param {object} configs
-   * @returns {object}
-   * @private
-   * @method _getNnInitializerSettings
-   */
-  _getNnInitializerSettings: function (configs) {
-    var ret = {};
-    if (App.get('isHaEnabled')) {
-      ret.namespaceId = configs['hdfs-site']['dfs.nameservices'];
-      ret.suffix = (configs['hdfs-site']['dfs.namenode.http-address.' + ret.namespaceId + '.nn1'].indexOf(this.get('content.reassignHosts.source')) != -1) ? 'nn1' : 'nn2';
-    }
-    return ret;
-  },
-
-  /**
-   * Settings used to the App.MoveHsConfigInitializer and App.MoveHmConfigInitializer setup
-   *
-   * @param {object} configs
-   * @returns {{hiveUser: string}}
-   * @private
-   * @method _getHiveInitializerSettings
-   */
-  _getHiveInitializerSettings: function (configs) {
-    return {
-      hiveUser: configs['hive-env']['hive_user']
-    };
-  },
-
-  /**
-   * Settings used to the App.MoveWsConfigInitializer setup
-   *
-   * @param {object} configs
-   * @returns {{webhcatUser: string}}
-   * @private
-   * @method _getWsInitializerSettings
-   */
-  _getWsInitializerSettings: function (configs) {
-    return {
-      webhcatUser: configs['hive-env']['webhcat_user']
-    };
-  },
-
-  /**
-   * Settings used to the App.MoveRmConfigInitializer setup
-   *
-   * @param {object} configs
-   * @returns {{suffix: string}}
-   * @private
-   * @method _getRmInitializerSettings
-   */
-  _getRmInitializerSettings: function (configs) {
-    return {
-      suffix: configs['yarn-site']['yarn.resourcemanager.hostname.rm1'] === this.get('content.reassignHosts.source') ? 'rm1': 'rm2'
-    };
-  },
-
-  onLoadConfigs: function (data) {
-    // Find hawq-site.xml location
-    var hawqSiteIndex = -1;
-    for(var i = 0; i < data.items.length; i++){
-      if(data.items[i].type == 'hawq-site'){
-        hawqSiteIndex = i;
-        break;
-      }
-    }
-
-    // if certain services are deployed, include related site files to additionalConfigsMap and relatedServicesMap.
-    if(hawqSiteIndex >= 0){ // if HAWQ is deployed
-      var hawqSiteProperties = {
-        'hawq_rm_yarn_address': '<replace-value>:8050',
-        'hawq_rm_yarn_scheduler_address': '<replace-value>:8030'
-      }
-
-      var rmComponent = this.get('additionalConfigsMap').findProperty('componentName', "RESOURCEMANAGER");
-      rmComponent.configs["hawq-site"] = hawqSiteProperties;
-
-      if(data.items[hawqSiteIndex].properties["hawq_global_rm_type"].toLowerCase() === "yarn"){
-        this.get('relatedServicesMap')['RESOURCEMANAGER'].append('HAWQ');
-      }
-
-    }
-
-    var componentName = this.get('content.reassign.component_name');
-    var targetHostName = this.get('content.reassignHosts.target');
-    var configs = {};
-    var attributes = {};
-    var secureConfigs = [];
-
-    data.items.forEach(function (item) {
-      configs[item.type] = item.properties;
-      if (item.properties_attributes) {
-        attributes[item.type] = item.properties_attributes;
-      }
-    }, this);
-
-    this.setAdditionalConfigs(configs, componentName, targetHostName);
-    this.setSecureConfigs(secureConfigs, configs, componentName);
-
-    switch (componentName) {
-      case 'NAMENODE':
-        App.MoveNameNodeConfigInitializer.setup(this._getNnInitializerSettings(configs));
-        configs = this.setDynamicConfigs(configs, App.MoveNameNodeConfigInitializer);
-        App.MoveNameNodeConfigInitializer.cleanup();
-        break;
-      case 'RESOURCEMANAGER':
-        App.MoveRmConfigInitializer.setup(this._getRmInitializerSettings(configs));
-        var additionalDependencies = this._getRmAdditionalDependencies(configs);
-        configs = this.setDynamicConfigs(configs, App.MoveRmConfigInitializer, additionalDependencies);
-        App.MoveRmConfigInitializer.cleanup();
-        break;
-      case 'HIVE_METASTORE':
-        App.MoveHmConfigInitializer.setup(this._getHiveInitializerSettings(configs));
-        configs = this.setDynamicConfigs(configs, App.MoveHmConfigInitializer);
-        App.MoveHmConfigInitializer.cleanup();
-        break;
-      case 'HIVE_SERVER':
-        App.MoveHsConfigInitializer.setup(this._getHiveInitializerSettings(configs));
-        configs = this.setDynamicConfigs(configs, App.MoveHsConfigInitializer);
-        App.MoveHsConfigInitializer.cleanup();
-        break;
-      case 'WEBHCAT_SERVER':
-        App.MoveWsConfigInitializer.setup(this._getWsInitializerSettings(configs));
-        configs = this.setDynamicConfigs(configs, App.MoveWsConfigInitializer);
-        App.MoveWsConfigInitializer.cleanup();
-        break;
-      case 'OOZIE_SERVER':
-        App.MoveOSConfigInitializer.setup(this._getOsInitializerSettings(configs));
-        configs = this.setDynamicConfigs(configs, App.MoveOSConfigInitializer);
-        App.MoveOSConfigInitializer.cleanup();
-    }
-
+    var configs = this.get('content.configs'),
+      attributes = this.get('content.configsAttributes'),
+      secureConfigs = this.get('content.secureConfigs'),
+      componentName = this.get('content.reassign.component_name');
     this.saveClusterStatus(secureConfigs, this.getComponentDir(configs, componentName));
     this.saveConfigsToServer(configs, attributes);
-    this.saveServiceProperties(configs);
-  },
-
-  /**
-   * Set config values according to the new cluster topology
-   *
-   * @param {object} configs
-   * @param {MoveComponentConfigInitializerClass} initializer
-   * @param {object} [additionalDependencies={}]
-   * @returns {object}
-   * @method setDynamicConfigs
-   */
-  setDynamicConfigs: function (configs, initializer, additionalDependencies) {
-    additionalDependencies = additionalDependencies || {};
-    var topologyDB = this._prepareTopologyDB();
-    var dependencies = this._prepareDependencies(additionalDependencies);
-    Em.keys(configs).forEach(function (site) {
-      Em.keys(configs[site]).forEach(function (config) {
-        // temporary object for initializer
-        var cfg = {
-          name: config,
-          filename: site,
-          value: configs[site][config]
-        };
-        configs[site][config] = initializer.initialValue(cfg, topologyDB, dependencies).value;
-      });
-    });
-    return configs;
   },
 
   /**
@@ -912,27 +363,6 @@ App.ReassignMasterWizardStep4Controller = App.HighAvailabilityProgressPageContro
   },
 
   /**
-   * set secure configs for component
-   * @param secureConfigs
-   * @param configs
-   * @param componentName
-   * @return {Boolean}
-   */
-  setSecureConfigs: function (secureConfigs, configs, componentName) {
-    var securityEnabled = App.get('isKerberosEnabled');
-    var component = this.get('secureConfigsMap').findProperty('componentName', componentName);
-    if (Em.isNone(component) || !securityEnabled) return false;
-
-    component.configs.forEach(function (config) {
-      secureConfigs.push({
-        keytab: configs[config.site][config.keytab],
-        principal: configs[config.site][config.principal]
-      });
-    });
-    return true;
-  },
-
-  /**
    * derive component directory from configurations
    * @param configs
    * @param componentName
@@ -994,7 +424,7 @@ App.ReassignMasterWizardStep4Controller = App.HighAvailabilityProgressPageContro
    * make server call to start services
    */
   startRequiredServices: function () {
-    var relatedServices = this.get('relatedServicesMap')[this.get('content.reassign.component_name')];
+    var relatedServices = this.get('wizardController.relatedServicesMap')[this.get('content.reassign.component_name')];
     if (relatedServices) {
       this.startServices(false, relatedServices, true);
     } else {
@@ -1178,10 +608,11 @@ App.ReassignMasterWizardStep4Controller = App.HighAvailabilityProgressPageContro
   }.property('propertiesPattern'),
 
   getConnectionProperty: function(regexp) {
-    var propertyName = this.get('requiredProperties').filter(function(item) {
+    var configType = this.get('requiredProperties.type'),
+      propertyName = this.get('requiredProperties.names').filter(function(item) {
       return regexp.test(item);
     })[0];
-    return this.get('content.serviceProperties')[propertyName];
+    return Em.getWithDefault(this.get('content.configs'), configType, {})[propertyName];
   },
 
   /**
@@ -1202,18 +633,35 @@ App.ReassignMasterWizardStep4Controller = App.HighAvailabilityProgressPageContro
   /** @property {object} requiredProperties - properties that necessary for database connection **/
   requiredProperties: function() {
     var propertiesMap = {
-      OOZIE: ['oozie.db.schema.name','oozie.service.JPAService.jdbc.username','oozie.service.JPAService.jdbc.password','oozie.service.JPAService.jdbc.driver','oozie.service.JPAService.jdbc.url'],
-      HIVE: ['ambari.hive.db.schema.name','javax.jdo.option.ConnectionUserName','javax.jdo.option.ConnectionPassword','javax.jdo.option.ConnectionDriverName','javax.jdo.option.ConnectionURL']
+      OOZIE: {
+        type: 'oozie-site',
+        names: ['oozie.db.schema.name', 'oozie.service.JPAService.jdbc.username', 'oozie.service.JPAService.jdbc.password', 'oozie.service.JPAService.jdbc.driver', 'oozie.service.JPAService.jdbc.url']
+      },
+      HIVE: {
+        type: 'hive-site',
+        names: ['ambari.hive.db.schema.name', 'javax.jdo.option.ConnectionUserName', 'javax.jdo.option.ConnectionPassword', 'javax.jdo.option.ConnectionDriverName', 'javax.jdo.option.ConnectionURL']
+      }
     };
 
     return propertiesMap[this.get('content.reassign.service_id')];
   }.property(),
 
   dbType: function() {
-    var databaseTypes = /MySQL|PostgreS|Oracle|Derby|MSSQL|Anywhere/gi;
-    var databaseProp = this.get('content.serviceProperties')[Em.getWithDefault(this.get('dbPropertyMap'), this.get('content.reassign.component_name'), null)];
+    var databaseTypes = /MySQL|PostgreS|Oracle|Derby|MSSQL|Anywhere/gi,
+      dbPropertyMapItem = Em.getWithDefault(this.get('dbPropertyMap'), this.get('content.reassign.component_name'), null),
+      databasePropMatch,
+      databaseProp,
+      result;
+
+    if (dbPropertyMapItem) {
+      databaseProp = Em.getWithDefault(this.get('content.configs'), dbPropertyMapItem.type, {})[dbPropertyMapItem.name];
+      databasePropMatch = databaseProp && databaseProp.match(databaseTypes);
+      if (databasePropMatch) {
+        result = databasePropMatch[0];
+      }
+    }
 
-    return databaseProp.match(databaseTypes)[0];
+    return result;
   }.property(),
 
   prepareDBCheckAction: function() {

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/controllers/main/service/reassign_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/reassign_controller.js b/ambari-web/app/controllers/main/service/reassign_controller.js
index 07d6e2c..5b3e951 100644
--- a/ambari-web/app/controllers/main/service/reassign_controller.js
+++ b/ambari-web/app/controllers/main/service/reassign_controller.js
@@ -65,7 +65,9 @@ App.ReassignMasterController = App.WizardController.extend({
     hasCheckDBStep: false,
     componentsWithCheckDBStep: ['HIVE_METASTORE', 'HIVE_SERVER', 'OOZIE_SERVER'],
     componentsWithoutSecurityConfigs: ['MYSQL_SERVER'],
-    reassignComponentsInMM: []
+    reassignComponentsInMM: [],
+    configs: null,
+    configsAttributes: null
   }),
 
   /**
@@ -131,6 +133,8 @@ App.ReassignMasterController = App.WizardController.extend({
           this.loadTasksRequestIds();
           this.loadRequestIds();
           this.loadReassignComponentsInMM();
+          this.loadConfigs();
+          this.loadSecureConfigs();
         }
       }
     ],
@@ -138,13 +142,46 @@ App.ReassignMasterController = App.WizardController.extend({
       {
         type: 'sync',
         callback: function () {
-          this.loadSecureConfigs();
           this.loadComponentDir();
         }
       }
     ]
   },
 
+  serviceToConfigSiteMap: {
+    'NAMENODE': ['hdfs-site', 'core-site'],
+    'SECONDARY_NAMENODE': ['hdfs-site', 'core-site'],
+    'JOBTRACKER': ['mapred-site'],
+    'RESOURCEMANAGER': ['yarn-site'],
+    'WEBHCAT_SERVER': ['hive-env', 'webhcat-site', 'core-site'],
+    'APP_TIMELINE_SERVER': ['yarn-site', 'yarn-env'],
+    'OOZIE_SERVER': ['oozie-site', 'core-site', 'oozie-env'],
+    'HIVE_SERVER': ['hive-site', 'webhcat-site', 'hive-env', 'core-site'],
+    'HIVE_METASTORE': ['hive-site', 'webhcat-site', 'hive-env', 'core-site'],
+    'MYSQL_SERVER': ['hive-site'],
+    'HISTORYSERVER': ['mapred-site']
+  },
+
+  /**
+   * Map with lists of related services.
+   * Used to define list of services to stop/start.
+   */
+  relatedServicesMap: {
+    'JOBTRACKER': ['PIG', 'OOZIE'],
+    'RESOURCEMANAGER': ['YARN', 'MAPREDUCE2', 'TEZ', 'PIG', 'OOZIE', 'SLIDER', 'SPARK'],
+    'APP_TIMELINE_SERVER': ['YARN', 'MAPREDUCE2', 'TEZ', 'OOZIE', 'SLIDER', 'SPARK'],
+    'HIVE_SERVER': ['HIVE', 'FALCON', 'ATLAS', 'OOZIE'],
+    'HIVE_METASTORE': ['HIVE', 'PIG', 'FALCON', 'ATLAS', 'OOZIE'],
+    'WEBHCAT_SERVER': ['HIVE'],
+    'OOZIE_SERVER': ['OOZIE', 'FALCON', 'KNOX'],
+    'MYSQL_SERVER': ['HIVE', 'OOZIE', 'RANGER', 'RANGER_KMS'],
+    'METRICS_COLLECTOR': ['AMBARI_METRICS']
+  },
+
+  isComponentWithReconfiguration: function () {
+    return this.get('serviceToConfigSiteMap').hasOwnProperty(this.get('content.reassign.component_name'));
+  }.property('content.reassign.component_name'),
+
   addManualSteps: function () {
     var hasManualSteps = this.get('content.componentsWithManualCommands').contains(this.get('content.reassign.component_name'));
     this.set('content.hasManualSteps', hasManualSteps);
@@ -285,6 +322,20 @@ App.ReassignMasterController = App.WizardController.extend({
     this.set('content.serviceProperties', serviceProperties);
   },
 
+  saveConfigs: function (configs, attributes) {
+    var configsObject = {
+      configs: configs,
+      configsAttributes: attributes
+    };
+    this.setDBProperties(configsObject);
+    this.get('content').setProperties(configsObject);
+  },
+
+  loadConfigs: function () {
+    var configsObject = this.getDBProperties(['configs', 'configsAttributes']);
+    this.get('content').setProperties(configsObject);
+  },
+
   saveDatabaseType: function (type) {
     this.setDBProperty('databaseType', type);
     this.set('content.databaseType', type);

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/controllers/wizard/step7_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/wizard/step7_controller.js b/ambari-web/app/controllers/wizard/step7_controller.js
index 66ea208..90cd804 100644
--- a/ambari-web/app/controllers/wizard/step7_controller.js
+++ b/ambari-web/app/controllers/wizard/step7_controller.js
@@ -42,7 +42,7 @@ var App = require('app');
  * @property {?object[]} slaveComponentHosts
  */
 
-App.WizardStep7Controller = Em.Controller.extend(App.ServerValidatorMixin, App.EnhancedConfigsMixin, App.ToggleIsRequiredMixin, App.GroupsMappingMixin, App.TrackRequestMixin, {
+App.WizardStep7Controller = Em.Controller.extend(App.ServerValidatorMixin, App.EnhancedConfigsMixin, App.ToggleIsRequiredMixin, App.GroupsMappingMixin, {
 
   name: 'wizardStep7Controller',
 
@@ -1511,8 +1511,7 @@ App.WizardStep7Controller = Em.Controller.extend(App.ServerValidatorMixin, App.E
       },
       onSecondary: function () {
         this._super();
-        self.set('submitButtonClicked', false);
-        App.set('router.nextBtnClickInProgress', false);
+        self.setButtonClickFinish();
         deferred.reject();
       }
     });
@@ -1535,8 +1534,7 @@ App.WizardStep7Controller = Em.Controller.extend(App.ServerValidatorMixin, App.E
             }
           },
           onSecondary: function() {
-            App.set('router.nextBtnClickInProgress', false);
-            self.set('submitButtonClicked', false);
+            self.setButtonClickFinish();
             this.hide();
           },
           onClose: function() {
@@ -1570,6 +1568,14 @@ App.WizardStep7Controller = Em.Controller.extend(App.ServerValidatorMixin, App.E
       return false;
     }
     App.set('router.nextBtnClickInProgress', true);
+    if (this.get('wizardController.name') === 'addServiceController' && this.get('hasChangedDependencies')) {
+      return this.showChangedDependentConfigs({}, this.proceedWithChecks.bind(this), this.setButtonClickFinish.bind(this));
+    } else {
+      return this.proceedWithChecks();
+    }
+  },
+
+  proceedWithChecks: function () {
     if (this.get('supportsPreInstallChecks')) {
       var preInstallChecksController = App.router.get('preInstallChecksController');
       if (preInstallChecksController.get('preInstallChecksWhereRun')) {
@@ -1580,6 +1586,11 @@ App.WizardStep7Controller = Em.Controller.extend(App.ServerValidatorMixin, App.E
     return this.postSubmit();
   },
 
+  setButtonClickFinish: function () {
+    this.set('submitButtonClicked', false);
+    App.set('router.nextBtnClickInProgress', false);
+  },
+
   postSubmit: function () {
     var self = this;
     this.set('submitButtonClicked', true);
@@ -1588,8 +1599,7 @@ App.WizardStep7Controller = Em.Controller.extend(App.ServerValidatorMixin, App.E
     })
       .fail(function (value) {
         if ("invalid_configs" === value) {
-          self.set('submitButtonClicked', false);
-          App.set('router.nextBtnClickInProgress', false);
+          self.setButtonClickFinish();
         } else {
           // Failed due to validation mechanism failure.
           // Should proceed with other checks

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index 33195e0..134990e 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -1295,7 +1295,8 @@ Em.I18n.translations = {
   'admin.manageJournalNode.wizard.step8.header': 'Start All Services',
 
   'admin.manageJournalNode.wizard.step1.body': 'Add, or Remove JournalNodes',
-  'admin.manageJournalNode.wizard.step3.confirm.config.body': '<b>Configuration Change Review.</b></br>' +
+  'admin.manageJournalNode.wizard.step3.confirm.hosts.body': '<b>Confirm your host selections.</b>',
+  'admin.manageJournalNode.wizard.step3.confirm.config.body': '<p><b>Review Configuration Changes.</b></p>' +
   'As part of this process, configuration changes are required. Please review the changes below, and note that they are for <b>review only</b>.  Future steps in this wizard will update this configuration, and restart <b>all</b> services automatically.',
 
   'admin.manageJournalNode.wizard.step4.task0.title' : 'Stop Standby NameNode',
@@ -1579,8 +1580,9 @@ Em.I18n.translations = {
   'admin.ra_highAvailability.wizard.step3.alert_message': '<b>Confirm your host selections.</b>',
   'admin.ra_highAvailability.wizard.step3.currentRA': 'Current Ranger Admin',
   'admin.ra_highAvailability.wizard.step3.additionalRA': 'Additional Ranger Admin',
-  'admin.rm_highAvailability.wizard.step3.configs_changes': '<b>Review Configuration Changes.</b></br>' +
-  '<i>policymgr_external_url</i> in admin-properties.xml will be changed by the Wizard to enable Ranger Admin HA',
+  'admin.rm_highAvailability.wizard.step3.configs_changes': '<p><b>Review Configuration Changes.</b></p>' +
+    'The following lists the configuration changes that will be made by the Wizard to enable Ranger Admin HA. ' +
+    'This information is for <b> review only </b> and is not editable.',
   'admin.ra_highAvailability.wizard.step4.header': 'Install, Start and Test',
   'admin.ra_highAvailability.wizard.step4.task0.title': 'Stop All Services',
   'admin.ra_highAvailability.wizard.step4.task1.title': 'Install Additional Ranger Admin',
@@ -2260,10 +2262,12 @@ Em.I18n.translations = {
   'services.reassign.step2.body':'Assign {0} to new host.',
   'services.reassign.step2.body.namenodeHA':'Move {0} to new host. You can move only one master component at a time.',
   'services.reassign.step3.header':'Review',
-  'services.reassign.step3.body':'Please review the changes you made',
+  'services.reassign.step3.body':'<b>Confirm your host selections.</b>',
   'services.reassign.step3.targetHost':'Target Host:',
   'services.reassign.step3.sourceHost':'Source Host:',
   'services.reassign.step3.component':'Component name:',
+  'services.reassign.step3.configs':'<div class="alert alert-info">' +
+    '<p><b>Review Configuration Changes.</b></p>The Wizard will make the following configuration changes.</div>',
   'services.reassign.step4.header':'Configure Component',
 
   'services.reassign.step4.tasks.stopRequiredServices.title':'Stop Required Services',
@@ -2632,17 +2636,12 @@ 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>zookeeper.connect</li><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.deleteJournalNodeMsg': 'You are about to open <i>Manage Journal Node Wizard</i>. Are you sure?',
   '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>zookeeper.connect</li><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>',
   'host.host.addComponent.popup.dependedComponents.body': '{0} requires {1} to be installed along with it on the same host. Please add them first and then try adding {0}',
   'host.host.addComponent.popup.dependedComponents.header': 'Component dependencies',
@@ -2650,7 +2649,7 @@ Em.I18n.translations = {
   'hosts.host.zooKeeper.configs.save.note': 'This configuration is created by ambari while installing/deleting zookeeper component on a host',
   'hosts.host.addComponent.securityNote':'You are running your cluster in secure mode. You must set up the keytab for {0} on {1} before you proceed. Otherwise, the component will not be able to start properly.',
   'hosts.host.addComponent.popup.confirm':'Confirm Add',
-  'hosts.host.manualKerberosWarning': '<br/><strong>Because Kerberos has been manually installed on the cluster, you will have to create/distribute principals and keytabs when this operation is finished.</strong>',
+  'hosts.host.manualKerberosWarning': '<strong>Because Kerberos has been manually installed on the cluster, you will have to create/distribute principals and keytabs when this operation is finished.</strong>',
   'hosts.host.deleteComponent.popup.deleteNimbus':'Deleting <i>Storm Nimbus</i> 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.storm.configs.save.note': 'This configuration is created by ambari while installing/deleting storm component on a host',
   'hosts.host.datanode.decommission':'Decommission DataNode',
@@ -2668,8 +2667,6 @@ Em.I18n.translations = {
   'hosts.host.hbase_regionserver.decommission.warning':'Last RegionServer can\'t be decommissioned',
   'hosts.host.decommissioned':'Decommissioned',
   'hosts.host.decommissioning':'Decommissioning',
-  'hosts.host.addComponent.HIVE_METASTORE':'Adding <i>Hive Metastore</i> will reconfigure such properties:<ul><li>hive.metastore.uris</li><li>templeton.hive.properties</li></ul>',
-  'hosts.host.addComponent.WEBHCAT_SERVER':'You are about to add <i>WebHCat Server</i>. Are you sure?',
   'hosts.host.addComponent.JOURNALNODE': 'You are about to open <i>Manage Journal Node Wizard</i>. Are you sure?',
   'hosts.host.deleteComponent.popup.deleteHiveMetastore':'Deleting <i>Hive Metastore</i> will reconfigure such properties:<ul><li>hive.metastore.uris</li><li>templeton.hive.properties</li></ul>',
   'hosts.host.deleteComponent.popup.deleteWebHCatServer':'You are about to delete <i>WebHCat Server</i>. Are you sure?',
@@ -3259,8 +3256,8 @@ Em.I18n.translations = {
   'admin.removeHawqStandby.wizard.step2.header': 'Review',
   'admin.removeHawqStandby.wizard.step2.hawqStandby': '<b>Current HAWQ Standby:</b>',
   'admin.removeHawqStandby.wizard.step2.confirm.config.body':'<div class="alert alert-info">' +
-      '<b>Review Configuration Changes.</b></br></br>After removing the HAWQ Standby Master, the Wizard removes the ' +
-      'hawq_standby_address_host property from hawq-site.xml. As a best practice, you should configure a new HAWQ Standby Master host after the Wizard completes.</div>',
+    '<p><b>Review Configuration Changes.</b></p>After removing the HAWQ Standby Master, the Wizard removes the ' +
+    'hawq_standby_address_host property from hawq-site.xml. As a best practice, you should configure a new HAWQ Standby Master host after the Wizard completes.</div>',
   'admin.removeHawqStandby.wizard.step2.confirm.host.body':'<b>Review HAWQ Standby Master role changes.</b>',
   'admin.removeHawqStandby.wizard.step2.confirmPopup.body': 'Do you wish to continue with removing HAWQ Standby Master? Please confirm, before proceeding as you will not be able to rollback from Ambari.',
   'admin.removeHawqStandby.wizard.step3.header': 'Finalize Setup',
@@ -3294,10 +3291,10 @@ Em.I18n.translations = {
   'admin.activateHawqStandby.wizard.step2.toBeActivated': 'TO BE ACTIVATED AS NEW HAWQ MASTER',
   'admin.activateHawqStandby.step4.save.configuration.note': 'This configuration is created by Activate HAWQ Standby wizard',
   'admin.activateHawqStandby.wizard.step2.confirm.config.body': '<div class="alert alert-info">' +
-      '<b>Review Configuration Changes.</b><br/><br/>The Wizard will make the following configuration changes. '+
-      'This information is for review only, and cannot be edited.<br/><br/><b>After activating the HAWQ Standby ' +
-      'Master, the wizard removes the hawq_standby_address_host property from hawq-site.xml.</b> ' +
-      'As a best practice, you should configure a new HAWQ Standby Master host after the wizard completes.</div>',
+    '<p><b>Review Configuration Changes.</b></p>The Wizard will make the following configuration changes. '+
+    'This information is for review only, and cannot be edited.<br/><br/><b>After activating the HAWQ Standby ' +
+    'Master, the wizard removes the hawq_standby_address_host property from hawq-site.xml.</b> ' +
+    'As a best practice, you should configure a new HAWQ Standby Master host after the wizard completes.</div>',
   'admin.activateHawqStandby.wizard.step2.confirm.host.body':'<b>Review HAWQ Master & Standby Master role changes.</b>',
   'admin.activateHawqStandby.wizard.step2.confirmPopup.body': 'Do you wish to continue with activating HAWQ Standy Master? ' +
       'Please confirm, before proceeding as you will not be able to rollback from Ambari.',

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/mixins/common/configs/enhanced_configs.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/configs/enhanced_configs.js b/ambari-web/app/mixins/common/configs/enhanced_configs.js
index f7cc4cf..3e653ae 100644
--- a/ambari-web/app/mixins/common/configs/enhanced_configs.js
+++ b/ambari-web/app/mixins/common/configs/enhanced_configs.js
@@ -158,6 +158,11 @@ App.EnhancedConfigsMixin = Em.Mixin.create(App.ConfigWithOverrideRecommendationP
     this.set('recommendationsConfigs', null);
   },
 
+  clearRecommendations: function () {
+    this.clearRecommendationsInfo();
+    this.clearAllRecommendations();
+  },
+
   /**
    * sends request to get values for dependent configs
    * @param {{type: string, name: string}[]} changedConfigs - list of changed configs to track recommendations

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/mixins/common/track_request_mixin.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/track_request_mixin.js b/ambari-web/app/mixins/common/track_request_mixin.js
index c665253..dd97b97 100644
--- a/ambari-web/app/mixins/common/track_request_mixin.js
+++ b/ambari-web/app/mixins/common/track_request_mixin.js
@@ -38,14 +38,14 @@ App.TrackRequestMixin = Em.Mixin.create({
     this.get('requestsInProgress').pushObject({
       request: request,
       id: requestId,
-      status: request.state(),
-      completed: ['resolved', 'rejected'].contains(request.state())
+      status: Em.tryInvoke(request, 'state'),
+      completed: ['resolved', 'rejected'].contains(Em.tryInvoke(request, 'state'))
     });
     request.always(function() {
       var requestInProgress = self.get('requestsInProgress').findProperty('id', requestId) || {};
       Em.setProperties(requestInProgress, {
         completed: true,
-        status: request.state()
+        status: Em.tryInvoke(request, 'state')
       });
     });
   },

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/mixins/main/service/groups_mapping.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/main/service/groups_mapping.js b/ambari-web/app/mixins/main/service/groups_mapping.js
index 40cd0cb..6c166c8 100644
--- a/ambari-web/app/mixins/main/service/groups_mapping.js
+++ b/ambari-web/app/mixins/main/service/groups_mapping.js
@@ -23,7 +23,7 @@ var App = require('app');
  *
  * @type {Em.Mixin}
  */
-App.GroupsMappingMixin = Em.Mixin.create({
+App.GroupsMappingMixin = Em.Mixin.create(App.TrackRequestMixin, {
 
   /**
    * Load config groups

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/routes/ra_high_availability_routes.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/ra_high_availability_routes.js b/ambari-web/app/routes/ra_high_availability_routes.js
index 9995937..13ddd8f 100644
--- a/ambari-web/app/routes/ra_high_availability_routes.js
+++ b/ambari-web/app/routes/ra_high_availability_routes.js
@@ -129,12 +129,14 @@ module.exports = App.WizardRoute.extend({
       controller.dataLoading().done(function () {
         controller.setCurrentStep('3');
         controller.loadAllPriorSteps().done(function () {
+          var stepController = router.get('rAHighAvailabilityWizardStep3Controller');
+          stepController.set('wizardController', controller);
           controller.connectOutlet('rAHighAvailabilityWizardStep3', controller.get('content'));
         });
       });
     },
     next: function (router) {
-      router.transitionTo('step4');
+      router.transitionTo('step4');iiii
     },
     back: function (router) {
       router.transitionTo('step2');
@@ -149,6 +151,8 @@ module.exports = App.WizardRoute.extend({
         controller.setCurrentStep('4');
         controller.setLowerStepsDisable(4);
         controller.loadAllPriorSteps().done(function () {
+          var stepController = router.get('rAHighAvailabilityWizardStep4Controller');
+          stepController.set('wizardController', controller);
           controller.connectOutlet('rAHighAvailabilityWizardStep4', controller.get('content'));
         });
       });

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/routes/reassign_master_routes.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/reassign_master_routes.js b/ambari-web/app/routes/reassign_master_routes.js
index 35bd96f..d5cbadb 100644
--- a/ambari-web/app/routes/reassign_master_routes.js
+++ b/ambari-web/app/routes/reassign_master_routes.js
@@ -169,16 +169,22 @@ module.exports = App.WizardRoute.extend({
   step3: Em.Route.extend({
     route: '/step3',
     connectOutlets: function (router) {
-      var controller = router.get('reassignMasterController');
+      var controller = router.get('reassignMasterController'),
+        stepController = router.get('reassignMasterWizardStep3Controller');
       controller.setCurrentStep('3');
       controller.dataLoading().done(function () {
         controller.loadAllPriorSteps();
+        stepController.set('wizardController', controller);
         controller.connectOutlet('reassignMasterWizardStep3', controller.get('content'));
       })
     },
     back: Em.Router.transitionTo('step2'),
     next: function (router) {
-      var controller = router.get('reassignMasterController');
+      var controller = router.get('reassignMasterController'),
+        stepController = router.get('reassignMasterWizardStep3Controller'),
+        configs = stepController.get('configs'),
+        attributes = stepController.get('configsAttributes'),
+        secureConfigs = stepController.get('secureConfigs');
       App.db.setReassignTasksStatuses(undefined);
       App.db.setReassignTasksRequestIds(undefined);
       App.clusterStatus.setClusterStatus({
@@ -188,9 +194,16 @@ module.exports = App.WizardRoute.extend({
         localdb: App.db.data
       });
       controller.saveReassignComponentsInMM(controller.getReassignComponentsInMM());
+      stepController.updateServiceConfigs();
+      controller.saveConfigs(configs, attributes);
+      controller.saveSecureConfigs(secureConfigs);
       router.transitionTo('step4');
     },
 
+    exit: function (router) {
+      router.get('reassignMasterWizardStep3Controller').clearStep();
+    },
+
     unroutePath: function () {
       return false;
     }
@@ -199,11 +212,13 @@ module.exports = App.WizardRoute.extend({
   step4: Em.Route.extend({
     route: '/step4',
     connectOutlets: function (router) {
-      var controller = router.get('reassignMasterController');
+      var controller = router.get('reassignMasterController'),
+        stepController = router.get('reassignMasterWizardStep4Controller');
       controller.setCurrentStep('4');
       controller.setLowerStepsDisable(4);
       router.get('mainController').isLoading.call(router.get('clusterController'), 'isServiceContentFullyLoaded').done(function () {
         controller.loadAllPriorSteps();
+        stepController.set('wizardController', controller);
         controller.connectOutlet('reassignMasterWizardStep4', controller.get('content'));
       });
     },
@@ -303,11 +318,13 @@ module.exports = App.WizardRoute.extend({
   step7: Em.Route.extend({
     route: '/step7',
     connectOutlets: function (router) {
-      var controller = router.get('reassignMasterController');
+      var controller = router.get('reassignMasterController'),
+        stepController = router.get('reassignMasterWizardStep7Controller');
       controller.setCurrentStep('7');
       controller.setLowerStepsDisable(7);
       controller.dataLoading().done(function () {
         controller.loadAllPriorSteps();
+        stepController.set('wizardController', controller);
         controller.connectOutlet('reassignMasterWizardStep7', controller.get('content'));
       });
     },

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/styles/application.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/application.less b/ambari-web/app/styles/application.less
index f7cab50..c100408 100644
--- a/ambari-web/app/styles/application.less
+++ b/ambari-web/app/styles/application.less
@@ -1087,7 +1087,7 @@ h1 {
     margin-top: 8px;
   }
 
-  #ha-step3-review-table, #manage-journal-node-step2-review-table {
+  #ha-step3-review-table, #manage-journal-node-step2-review-table, #reassign-review-table {
     td {
       text-align: left;
       vertical-align: top;
@@ -5990,28 +5990,52 @@ input[type="radio"].align-checkbox, input[type="checkbox"].align-checkbox {
   td {
     min-width: 120px;
     word-break: break-all;
+    &.check-box-col {
+      min-width: 5px;
+      width: 5px;
+    }
+    &.config-dependency-name {
+      min-width: @config-dependency-t-name-width;
+    }
+    &.config-dependency-service {
+      min-width: @config-dependency-t-service-width;
+      max-width: @config-dependency-t-service-width;
+    }
+    &.config-dependency-group {
+      max-width: @config-dependency-t-group-width;
+    }
+    &.config-dependency-filename {
+      max-width: @config-dependency-t-filename-width;
+    }
+    &.config-dependency-value,
+    &.config-dependency-recommended-value {
+      width: @config-dependency-t-value-width;
+      min-width: @config-dependency-t-value-width;
+    }
+    .diff {
+      td {
+        color: #fff;
+        &.empty {
+          width: 50%;
+        }
+        &.delete {
+          background-color: @health-status-red !important;
+        }
+        &.insert {
+          background-color: @health-status-green !important;
+        }
+        &.replace {
+          background-color: @health-status-orange !important;
+        }
+      }
+    }
   }
-  td.check-box-col {
-    min-width: 5px;
-    width: 5px;
-  }
-  td.config-dependency-name {
-    min-width: @config-dependency-t-name-width;
-  }
-  td.config-dependency-service {
-    min-width: @config-dependency-t-service-width;
-    max-width: @config-dependency-t-service-width;
-  }
-  td.config-dependency-group {
-    max-width: @config-dependency-t-group-width;
-  }
-  td.config-dependency-filename {
-    max-width: @config-dependency-t-filename-width;
-  }
-  td.config-dependency-value,
-  td.config-dependency-recommended-value {
-    width: @config-dependency-t-value-width;
-    min-width: @config-dependency-t-value-width;
+  .config-dependencies-headings-wrapper {
+    width: 100%;
+    .config-dependencies-heading {
+      float: left;
+      width: 50%;
+    }
   }
 }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/templates/common/modal_popups/dependent_configs_table.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/modal_popups/dependent_configs_table.hbs b/ambari-web/app/templates/common/modal_popups/dependent_configs_table.hbs
index b6fff84..be811e3 100644
--- a/ambari-web/app/templates/common/modal_popups/dependent_configs_table.hbs
+++ b/ambari-web/app/templates/common/modal_popups/dependent_configs_table.hbs
@@ -29,15 +29,17 @@
       <th>{{t common.configGroup}}</th>
       <th>{{t common.fileName}}</th>
       <th>
-        <div class="span6">
-          {{t popup.dependent.configs.table.currentValue}}
-        </div>
-        <div class="span6">
-          {{#if view.isEditable}}
-            {{t popup.dependent.configs.table.recommendedValue}}
-          {{else}}
-            {{t popup.dependent.configs.table.newValue}}
-          {{/if}}
+        <div class="config-dependencies-headings-wrapper">
+          <div class="config-dependencies-heading">
+            {{t popup.dependent.configs.table.currentValue}}
+          </div>
+          <div class="config-dependencies-heading">
+            {{#if view.isEditable}}
+              {{t popup.dependent.configs.table.recommendedValue}}
+            {{else}}
+              {{t popup.dependent.configs.table.newValue}}
+            {{/if}}
+          </div>
         </div>
       </th>
     </tr>

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/templates/main/admin/highAvailability/journalNode/step2.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/admin/highAvailability/journalNode/step2.hbs b/ambari-web/app/templates/main/admin/highAvailability/journalNode/step2.hbs
index 456e9ed..731e4f5 100644
--- a/ambari-web/app/templates/main/admin/highAvailability/journalNode/step2.hbs
+++ b/ambari-web/app/templates/main/admin/highAvailability/journalNode/step2.hbs
@@ -19,6 +19,10 @@
 
 <h2>{{t admin.manageJournalNode.wizard.step2.header}}</h2>
 
+<div class="alert alert-info">
+  {{t admin.manageJournalNode.wizard.step3.confirm.hosts.body}}
+</div>
+
 <div id="manage-journal-node-step2-content" class="well pre-scrollable">
     <div id="step8-info">
         <table id="manage-journal-node-step2-review-table">

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/templates/main/admin/highAvailability/rangerAdmin/step3.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/admin/highAvailability/rangerAdmin/step3.hbs b/ambari-web/app/templates/main/admin/highAvailability/rangerAdmin/step3.hbs
index 32ea830..68fca6b 100644
--- a/ambari-web/app/templates/main/admin/highAvailability/rangerAdmin/step3.hbs
+++ b/ambari-web/app/templates/main/admin/highAvailability/rangerAdmin/step3.hbs
@@ -46,6 +46,13 @@
 <div class="alert alert-info">
   {{{t admin.rm_highAvailability.wizard.step3.configs_changes}}}
 </div>
+{{#if isLoaded}}
+  <div id="serviceConfig">
+    {{view App.ServiceConfigView}}
+  </div>
+{{else}}
+  {{view App.SpinnerView}}
+{{/if}}
 <div class="btn-area">
   <a class="btn" {{action back}}>&larr; {{t common.back}}</a>
   <a class="btn btn-success pull-right" {{action next}}>{{t common.next}} &rarr;</a>

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/templates/main/host/details/addComponentPopup.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/host/details/addComponentPopup.hbs b/ambari-web/app/templates/main/host/details/addComponentPopup.hbs
deleted file mode 100644
index ff69b9e..0000000
--- a/ambari-web/app/templates/main/host/details/addComponentPopup.hbs
+++ /dev/null
@@ -1,19 +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.
-}}
-
-{{addComponentMsg}}<br />{{{manualKerberosWarning}}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/templates/main/host/details/addDeleteComponentPopup.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/host/details/addDeleteComponentPopup.hbs b/ambari-web/app/templates/main/host/details/addDeleteComponentPopup.hbs
new file mode 100644
index 0000000..d1e7aa6
--- /dev/null
+++ b/ambari-web/app/templates/main/host/details/addDeleteComponentPopup.hbs
@@ -0,0 +1,48 @@
+{{!
+* 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.
+}}
+
+{{#if view.lastComponent}}
+  <div class="alert-error row-fluid">
+    <div class='tinyspan tinyoffset'>{{view Ember.Checkbox checkedBinding="view.parentView.isChecked"}}</div>
+    <div class="span10">{{{view.lastComponentError}}}</div>
+  </div>
+{{/if}}
+{{#if view.anyHostsWithoutComponent}}
+  {{#if view.hasHostsSelect}}
+    <div>{{view.selectHostMsg}}</div>
+    <div>
+      {{view Ember.Select contentBinding="view.hostsWithoutComponent" selectionBinding="view.selectedHost"}}
+    </div>
+  {{/if}}
+  {{#if controller.isReconfigureRequired}}
+    {{#if controller.isConfigsLoadingInProgress}}
+      {{view App.SpinnerView}}
+    {{else}}
+      {{view.commonMessage}}
+      {{#if controller.hasPropertiesToChange}}
+        {{view App.DependentConfigsListView isAfterRecommendation=false recommendationsBinding="controller.recommendedPropertiesToChange" requiredChangesBinding="controller.requiredPropertiesToChange"}}
+      {{/if}}
+      {{{view.manualKerberosWarning}}}
+    {{/if}}
+  {{else}}
+    <div>{{view.commonMessage}}</div>
+    <div>{{{view.manualKerberosWarning}}}</div>
+  {{/if}}
+{{else}}
+  {{view.thereIsNoHostsMsg}}
+{{/if}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/templates/main/host/details/deleteComponentPopup.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/host/details/deleteComponentPopup.hbs b/ambari-web/app/templates/main/host/details/deleteComponentPopup.hbs
deleted file mode 100644
index 10b24fd..0000000
--- a/ambari-web/app/templates/main/host/details/deleteComponentPopup.hbs
+++ /dev/null
@@ -1,43 +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.
-}}
-
-<p>{{{deleteComponentMsg}}}</p>
-{{#if lastComponent}}
-  <div class="alert-error row-fluid">
-    <div class='tinyspan tinyoffset'>{{view Ember.Checkbox checkedBinding="isChecked"}}</div>
-    <div class='span10'>{{{lastComponentError}}}</div>
-  </div>
-{{/if}}
-{{#if isZkServer}}
-  <div class='alert'>{{{deleteZkServerMsg}}}</div>
-{{/if}}
-{{#if isHiveMetastore}}
-  <div class='alert'>{{{deleteHiveMetastoreMsg}}}</div>
-{{/if}}
-{{#if isWebHCatServer}}
-  <div class='alert'>{{{deleteWebHCatServerMsg}}}</div>
-{{/if}}
-{{#if isNimbus}}
-  <div class='alert'>{{{deleteNimbusMsg}}}</div>
-{{/if}}
-{{#if isRangerKMSServer}}
-  <div class='alert'>{{{deleteRangerKMSServereMsg}}}</div>
-{{/if}}
-{{#if isJournalNode}}
-    <div class='alert'>{{{deleteJournalNodeMsg}}}</div>
-{{/if}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/templates/main/service/add_host_popup.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/service/add_host_popup.hbs b/ambari-web/app/templates/main/service/add_host_popup.hbs
deleted file mode 100644
index 7431080..0000000
--- a/ambari-web/app/templates/main/service/add_host_popup.hbs
+++ /dev/null
@@ -1,28 +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.
-}}
-
-{{#if anyHostsWithoutComponent}}
-  {{selectHostMsg}}<br />
-  <div>
-    {{view Ember.Select contentBinding="hostsWithoutComponent" selectionBinding="selectedHost"}}
-  </div>
-
-  {{addComponentMsg}}<br /><br />
-{{else}}
-  {{thereIsNoHostsMsg}}
-{{/if}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/304bd060/ambari-web/app/templates/main/service/info/delete_service_warning_popup.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/service/info/delete_service_warning_popup.hbs b/ambari-web/app/templates/main/service/info/delete_service_warning_popup.hbs
new file mode 100644
index 0000000..92f2097
--- /dev/null
+++ b/ambari-web/app/templates/main/service/info/delete_service_warning_popup.hbs
@@ -0,0 +1,26 @@
+{{!
+* 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.
+}}
+
+{{view.warningMessage}}
+{{#if controller.isRecommendationInProgress}}
+  {{view App.SpinnerView}}
+{{else}}
+  {{#if controller.changedProperties.length}}
+    {{view App.DependentConfigsListView recommendationsBinding="controller.changedProperties"}}
+  {{/if}}
+{{/if}}
\ No newline at end of file