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 2016/12/28 21:19:21 UTC

ambari git commit: AMBARI-19308 Non-editable properties should be handled for add/delete host component. (ababiichuk)

Repository: ambari
Updated Branches:
  refs/heads/trunk 540f4ee9a -> 74d636392


AMBARI-19308 Non-editable properties should be handled for add/delete host component. (ababiichuk)


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

Branch: refs/heads/trunk
Commit: 74d636392d4b82f6322af5a62a6dfe680743aaf4
Parents: 540f4ee
Author: ababiichuk <ab...@hortonworks.com>
Authored: Wed Dec 28 20:52:23 2016 +0200
Committer: ababiichuk <ab...@hortonworks.com>
Committed: Wed Dec 28 23:26:31 2016 +0200

----------------------------------------------------------------------
 ambari-web/app/controllers/main/host/details.js | 297 +++++++++++--------
 ambari-web/app/messages.js                      |   3 +
 .../modal_popups/dependent_configs_list.hbs     | 138 ++++++---
 .../host/details/addDeleteComponentPopup.hbs    |   8 +-
 .../dependent_configs_list_popup.js             |   8 +-
 .../test/controllers/main/host/details_test.js  | 121 +++++++-
 6 files changed, 383 insertions(+), 192 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/74d63639/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 c38838f..cb4a2ad 100644
--- a/ambari-web/app/controllers/main/host/details.js
+++ b/ambari-web/app/controllers/main/host/details.js
@@ -151,33 +151,68 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
     }
   ],
 
+  /**
+   * Determines whether adding/deleting host component requires configs changes
+   * @type {Boolean}
+   */
+  isReconfigureRequired: false,
+
+  /**
+   * 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'),
-    isReconfigure: false,
     commonMessage: '',
     manualKerberosWarning: App.get('router.mainAdminKerberosController.isManualKerberos') ?
       Em.I18n.t('hosts.host.manualKerberosWarning') : '',
-    propertiesToChange: [],
     lastComponent: false,
-    lastComponentError: '',
-    setPopupSize: function () {
-      this.set('parentView.hasPropertiesToChange', !!this.get('propertiesToChange.length'));
-    }.observes('propertiesToChange.length')
+    lastComponentError: ''
   }),
 
-  applyConfigsCustomization: function (configs) {
-    configs.propertiesToChange.forEach(function (property) {
+  clearConfigsChanges: function () {
+    var arrayNames = ['allPropertiesToChange', 'recommendedPropertiesToChange', 'requiredPropertiesToChange', 'groupedPropertiesToChange'];
+    arrayNames.forEach(function (arrayName) {
+      this.get(arrayName).clear();
+    }, this);
+    this.set('isReconfigureRequired', false);
+  },
+
+  applyConfigsCustomization: function () {
+    this.get('recommendedPropertiesToChange').forEach(function (property) {
       var value = property.saveRecommended ? property.recommendedValue : property.initialValue,
         filename = property.propertyFileName;
-      if (configs.groups.length) {
-        var group = configs.groups.find(function (item) {
+      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);
   },
 
   /**
@@ -427,7 +462,8 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
       if (componentsMapItem.deletePropertyName) {
         this.set(componentsMapItem.deletePropertyName, true);
       }
-      returnFunc = this.showDeleteComponentPopup(component, true, componentsMapItem.configsCallbackName);
+      this.set('isReconfigureRequired', true);
+      returnFunc = this.showDeleteComponentPopup(component, componentsMapItem.configsCallbackName);
     } else if (componentName === 'JOURNALNODE') {
       returnFunc = App.showConfirmationPopup(function () {
         App.router.transitionTo('main.services.manageJournalNode');
@@ -438,35 +474,31 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
     return returnFunc;
   },
 
-  showDeleteComponentPopup: function (component, isReconfigure, callbackName) {
+  showDeleteComponentPopup: function (component, callbackName) {
     var self = this,
       isLastComponent = (this.getTotalComponent(component) === 1),
       componentName = component.get('componentName'),
       componentDisplayName = component.get('displayName'),
       commonMessage = Em.I18n.t('hosts.host.deleteComponent.popup.msg1').format(componentDisplayName);
-    if (isReconfigure) {
-      var configs = {
-        groups: [],
-        propertiesToChange: []
-      };
+    if (this.get('isReconfigureRequired')) {
       this.set('isConfigsLoadingInProgress', true);
       this.isServiceMetricsLoaded(function () {
-        self.loadConfigs(callbackName, configs);
+        self.loadConfigs(callbackName);
       });
     }
     return App.ModalPopup.show({
       header: Em.I18n.t('popup.confirmation.commonHeader'),
       controller: self,
       hasPropertiesToChange: false,
-      classNameBindings: ['hasPropertiesToChange:common-modal-wrapper', 'hasPropertiesToChange:modal-full-width'],
+      classNameBindings: ['controller.hasPropertiesToChange:common-modal-wrapper', 'controller.hasPropertiesToChange:modal-full-width'],
       modalDialogClasses: function () {
-        return this.get('hasPropertiesToChange') ? ['modal-lg'] : [];
-      }.property('hasPropertiesToChange'),
+        return this.get('controller.hasPropertiesToChange') ? ['modal-lg'] : [];
+      }.property('controller.hasPropertiesToChange'),
       primary: Em.I18n.t('hosts.host.deleteComponent.popup.confirm'),
       bodyClass: self.get('addDeleteComponentPopupBody').extend({
-        isReconfigure: isReconfigure,
         commonMessage: commonMessage,
-        propertiesToChange: isReconfigure ? configs.propertiesToChange : [],
+        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);
@@ -475,19 +507,28 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
       }),
       isChecked: false,
       disablePrimary: function () {
-        return (isReconfigure && this.get('controller.isConfigsLoadingInProgress')) || !this.get('isChecked');
-      }.property('controller.isConfigsLoadingInProgress', 'isChecked'),
+        return (this.get('controller.isReconfigureRequired') && this.get('controller.isConfigsLoadingInProgress')) || !this.get('isChecked');
+      }.property('controller.isReconfigureRequired', 'controller.isConfigsLoadingInProgress', 'isChecked'),
       onPrimary: function () {
         this._super();
-        if (isReconfigure) {
-          self.applyConfigsCustomization(configs);
+        if (self.get('isReconfigureRequired')) {
+          self.applyConfigsCustomization();
         }
         self._doDeleteHostComponent(componentName, function () {
-          if (isReconfigure) {
-            self.saveConfigsBatch(configs.groups, componentName);
+          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();
       }
     });
   },
@@ -697,7 +738,8 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
           this.set(componentsMapItem.addPropertyName, false);
         };
       }
-      returnFunc = self.showAddComponentPopup(component, hostName, null, true, componentsMapItem.configsCallbackName, primary);
+      this.set('isReconfigureRequired', true);
+      returnFunc = self.showAddComponentPopup(component, hostName, null, componentsMapItem.configsCallbackName, primary);
     } else if (componentName === 'JOURNALNODE') {
       returnFunc = App.showConfirmationPopup(function () {
         App.router.transitionTo('main.services.manageJournalNode');
@@ -710,19 +752,15 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
     return returnFunc;
   },
 
-  showAddComponentPopup: function (component, hostName, primary, isReconfigure, callbackName, primaryOnReconfigure) {
+  showAddComponentPopup: function (component, hostName, primary, callbackName, primaryOnReconfigure) {
     var self = this,
       componentName = component.get('componentName'),
       componentDisplayName = component.get('displayName'),
       commonMessage = Em.I18n.t('hosts.host.addComponent.msg').format(componentDisplayName);
-    if (isReconfigure) {
-      var configs = {
-        groups: [],
-        propertiesToChange: []
-      };
+    if (this.get('isReconfigureRequired')) {
       this.set('isConfigsLoadingInProgress', true);
       this.isServiceMetricsLoaded(function () {
-        self.loadConfigs(callbackName, configs);
+        self.loadConfigs(callbackName);
       });
     }
     return App.ModalPopup.show({
@@ -731,28 +769,33 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
       hasPropertiesToChange: false,
       classNameBindings: ['hasPropertiesToChange:common-modal-wrapper', 'hasPropertiesToChange:modal-full-width'],
       modalDialogClasses: function () {
-        return this.get('hasPropertiesToChange') ? ['modal-lg'] : [];
-      }.property('hasPropertiesToChange'),
+        return this.get('controller.hasPropertiesToChange') ? ['modal-lg'] : [];
+      }.property('controller.hasPropertiesToChange'),
       primary: Em.I18n.t('hosts.host.addComponent.popup.confirm'),
       bodyClass: self.get('addDeleteComponentPopupBody').extend({
-        commonMessage: commonMessage,
-        isReconfigure: isReconfigure,
-        propertiesToChange: isReconfigure ? configs.propertiesToChange : []
+        commonMessage: commonMessage
       }),
-      disablePrimary: function () {
-        return isReconfigure && this.get('controller.isConfigsLoadingInProgress');
-      }.property('controller.isConfigsLoadingInProgress'),
+      disablePrimary: Em.computed.and('controller.isReconfigureRequired', 'controller.isConfigsLoadingInProgress'),
       onPrimary: function () {
         this._super();
-        if (isReconfigure) {
-          self.applyConfigsCustomization(configs);
-          self.saveConfigsBatch(configs.groups, componentName, hostName);
+        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();
       }
     });
   },
@@ -824,17 +867,14 @@ 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, opt, params) {
+  loadStormConfigs: function (data) {
     App.ajax.send({
       name: 'admin.get.all_configurations',
       sender: this,
       data: {
-        urlParams: '(type=storm-site&tag=' + data.Clusters.desired_configs['storm-site'].tag + ')',
-        configs: params.configs
+        urlParams: '(type=storm-site&tag=' + data.Clusters.desired_configs['storm-site'].tag + ')'
       },
       success: 'onLoadStormConfigs'
     });
@@ -843,10 +883,9 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
   /**
    * Update zk configs
    * @param {object} configs
-   * @param {object} configsForReview
    * @method updateZkConfigs
    */
-  updateZkConfigs: function (configs, configsForReview) {
+  updateZkConfigs: function (configs) {
     var portValue = configs['zoo.cfg'] && Em.get(configs['zoo.cfg'], 'clientPort');
     var zkPort = typeof portValue === 'undefined' ? '2181' : portValue;
     var infraSolrZnode = configs['infra-solr-env'] ? Em.get(configs['infra-solr-env'], 'infra_solr_znode') : '/ambari-solr';
@@ -854,6 +893,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);
@@ -886,19 +926,21 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
           };
         var configProperty = initializer.initialValue(propertyDef, hostComponentsTopology, dependencies);
         initializer.updateSiteObj(configs[fileName], configProperty);
-        if (configsForReview && currentValue !== propertyDef.value) {
+        if (this.get('isReconfigureRequired') && currentValue !== propertyDef.value) {
           var service = App.config.get('serviceByConfigTypeMap')[fileName];
-          configsForReview.propertiesToChange.pushObject({
+          propertiesToChange.pushObject({
             propertyFileName: fileName,
             propertyName: propertyName,
             serviceDisplayName: service && service.get('displayName'),
             initialValue: currentValue,
-            recommendedValue: propertyDef.value,
-            saveRecommended: true
+            recommendedValue: propertyDef.value
           });
         }
-      });
-    });
+      }, this);
+    }, this);
+    if (this.get('isReconfigureRequired')) {
+      this.setConfigsChangesForDisplay();
+    }
   },
 
   /**
@@ -923,35 +965,33 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
   /**
    * update and save Storm related configs to server
    * @param {object} data
-   * @param {object} opt
-   * @param {object} params
    * @method onLoadStormConfigs
    */
-  onLoadStormConfigs: function (data, opt, params) {
+  onLoadStormConfigs: function (data) {
     var nimbusHost = this.get('nimbusHost'),
       stormNimbusHosts = this.getStormNimbusHosts(),
       configs = {},
-      attributes = {};
+      attributes = {},
+      propertiesToChange = this.get('allPropertiesToChange');
 
     data.items.forEach(function (item) {
       configs[item.type] = item.properties;
       attributes[item.type] = item.properties_attributes || {};
     }, this);
 
-    this.updateZkConfigs(configs, params.configs);
+    this.updateZkConfigs(configs);
 
     var nimbusSeedsInit = configs['storm-site']['nimbus.seeds'],
       nimbusSeedsRecommended = JSON.stringify(stormNimbusHosts).replace(/"/g, "'");
     configs['storm-site']['nimbus.seeds'] = nimbusSeedsRecommended;
-    if (params.configs && nimbusSeedsInit !== nimbusSeedsRecommended) {
+    if (this.get('isReconfigureRequired') && nimbusSeedsInit !== nimbusSeedsRecommended) {
       var service = App.config.get('serviceByConfigTypeMap')['storm-site'];
-      params.configs.propertiesToChange.pushObject({
+      propertiesToChange.pushObject({
         propertyFileName: 'storm-site',
         propertyName: 'nimbus.seeds',
         serviceDisplayName: service && service.get('displayName'),
         initialValue: nimbusSeedsInit,
-        recommendedValue: nimbusSeedsRecommended,
-        saveRecommended: true
+        recommendedValue: nimbusSeedsRecommended
       });
     }
     var groups = [
@@ -964,8 +1004,9 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
         }
       }
     ];
-    if (params.configs) {
-      params.configs.groups.pushObjects(groups);
+    if (this.get('isReconfigureRequired')) {
+      this.get('groupedPropertiesToChange').pushObjects(groups);
+      this.setConfigsChangesForDisplay();
     } else {
       this.saveConfigsBatch(groups, 'NIMBUS', nimbusHost);
     }
@@ -974,11 +1015,9 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
   /**
    * Success callback for load configs request
    * @param {object} data
-   * @param {object} opt
-   * @param {object} params
    * @method loadWebHCatConfigs
    */
-  loadWebHCatConfigs: function (data, opt, params) {
+  loadWebHCatConfigs: function (data) {
     return App.ajax.send({
       name: 'admin.get.all_configurations',
       sender: this,
@@ -989,8 +1028,7 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
           '(type=webhcat-site&tag=' + data.Clusters.desired_configs['webhcat-site'].tag + ')',
           '(type=hive-env&tag=' + data.Clusters.desired_configs['hive-env'].tag + ')',
           '(type=core-site&tag=' + data.Clusters.desired_configs['core-site'].tag + ')'
-        ].join('|'),
-        configs: params.configs
+        ].join('|')
       },
       success: 'onLoadHiveConfigs'
     });
@@ -1003,7 +1041,7 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
    * @param {object} params
    * @method loadHiveConfigs
    */
-  loadHiveConfigs: function (data, opt, params) {
+  loadHiveConfigs: function (data) {
     return App.ajax.send({
       name: 'admin.get.all_configurations',
       sender: this,
@@ -1013,8 +1051,7 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
           '(type=webhcat-site&tag=' + data.Clusters.desired_configs['webhcat-site'].tag + ')',
           '(type=hive-env&tag=' + data.Clusters.desired_configs['hive-env'].tag + ')',
           '(type=core-site&tag=' + data.Clusters.desired_configs['core-site'].tag + ')'
-        ].join('|'),
-        configs: params.configs
+        ].join('|')
       },
       success: 'onLoadHiveConfigs'
     });
@@ -1045,7 +1082,7 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
       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";
@@ -1070,20 +1107,19 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
               value: currentValue
             };
           configs[fileName][propertyName] = Em.get(initializer.initialValue(propertyDef, localDB, dependencies), 'value');
-          if (params.configs && propertyDef.value !== currentValue) {
+          if (this.get('isReconfigureRequired') && propertyDef.value !== currentValue) {
             var service = App.config.get('serviceByConfigTypeMap')[fileName];
-            params.configs.propertiesToChange.pushObject({
+            propertiesToChange.pushObject({
               propertyFileName: fileName,
               propertyName: propertyName,
               serviceDisplayName: service && service.get('displayName'),
               initialValue: currentValue,
-              recommendedValue: propertyDef.value,
-              saveRecommended: true
+              recommendedValue: propertyDef.value
             });
           }
-        });
+        }, this);
       }
-    });
+    }, this);
 
     initializer.cleanup();
 
@@ -1109,8 +1145,9 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
         }
       }
     ];
-    if (params.configs) {
-      params.configs.groups.pushObjects(groups);
+    if (this.get('isReconfigureRequired')) {
+      this.get('groupedPropertiesToChange').pushObjects(groups);
+      this.setConfigsChangesForDisplay();
     } else {
       var args = [groups];
       var componentName = this.get('addHiveServer') ? 'HIVE_SERVER' : (hiveMetastoreHost ? 'HIVE_METASTORE' : 'WEBHCAT_SERVER');
@@ -1234,17 +1271,14 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
   /**
    * Success callback for load configs request
    * @param {object} data
-   * @param {object} opt
-   * @param {object} params
    * @method loadRangerConfigs
    */
-  loadRangerConfigs: function (data, opt, params) {
+  loadRangerConfigs: function (data) {
     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 + ')',
-        configs: params.configs
+        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'
     });
@@ -1253,11 +1287,9 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
   /**
    * update and save Hive hive.metastore.uris config to server
    * @param {object} data
-   * @param {object} opt
-   * @param {object} params
    * @method onLoadRangerConfigs
    */
-  onLoadRangerConfigs: function (data, opt, params) {
+  onLoadRangerConfigs: function (data) {
     var properties = [
       {
         type: 'core-site',
@@ -1286,13 +1318,14 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
         }
       }
     ];
+    var propertiesToChange = this.get('allPropertiesToChange');
 
     properties.forEach(function (property) {
       var typeConfigs = data.items.findProperty('type', property.type).properties,
         currentValue = typeConfigs[property.name];
-      if (params.configs && currentValue !== newValue) {
+      if (this.get('isReconfigureRequired') && currentValue !== newValue) {
         var service = App.config.get('serviceByConfigTypeMap')[property.type];
-        params.configs.propertiesToChange.pushObject({
+        propertiesToChange.pushObject({
           propertyFileName: property.type,
           propertyName: property.name,
           serviceDisplayName: service && service.get('displayName'),
@@ -1302,9 +1335,10 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
         });
       }
       typeConfigs[property.name] = newValue;
-    });
-    if (params.configs) {
-      params.configs.groups.pushObjects(groups);
+    }, this);
+    if (this.get('isReconfigureRequired')) {
+      this.get('groupedPropertiesToChange').pushObjects(groups);
+      this.setConfigsChangesForDisplay();
     } else {
       this.saveConfigsBatch(groups, 'RANGER_KMS_SERVER', hostToInstall);
     }
@@ -1410,20 +1444,12 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
    * This is required to make sure that service metrics API determining the HA state of components is loaded
    * @method loadConfigs
    */
-  loadConfigs: function (callback, configs) {
-    var self = this;
-    this.set('isConfigsLoadingInProgress', true);
+  loadConfigs: function (callback) {
     App.ajax.send({
       name: 'config.tags',
       sender: this,
       success: callback ? callback : 'loadConfigsSuccessCallback',
-      error: 'onLoadConfigsErrorCallback',
-      callback: function () {
-        self.set('isConfigsLoadingInProgress', false);
-      },
-      data: {
-        configs: configs
-      }
+      error: 'onLoadConfigsErrorCallback'
     });
   },
 
@@ -1438,19 +1464,16 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
   /**
    * Success callback for load configs request
    * @param {object} data
-   * @param {object} opt
-   * @param {object} params
    * @method loadConfigsSuccessCallback
    */
-  loadConfigsSuccessCallback: function (data, opt, params) {
+  loadConfigsSuccessCallback: function (data) {
     var urlParams = this.constructConfigUrlParams(data);
     if (urlParams.length > 0) {
       App.ajax.send({
         name: 'reassign.load_configs',
         sender: this,
         data: {
-          urlParams: urlParams.join('|'),
-          configs: params.configs
+          urlParams: urlParams.join('|')
         },
         success: 'saveZkConfigs'
       });
@@ -1483,11 +1506,9 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
   /**
    * save new ZooKeeper configs to server
    * @param {object} data
-   * @param {object} opt
-   * @param {object} params
    * @method saveZkConfigs
    */
-  saveZkConfigs: function (data, opt, params) {
+  saveZkConfigs: function (data) {
     var configs = {};
     var attributes = {};
     data.items.forEach(function (item) {
@@ -1495,7 +1516,7 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
       attributes[item.type] = item.properties_attributes || {};
     }, this);
 
-    this.updateZkConfigs(configs, params.configs);
+    this.updateZkConfigs(configs);
     var groups = [];
     var installedServiceNames = App.Service.find().mapProperty('serviceName');
     this.get('zooKeeperRelatedServices').forEach(function (service) {
@@ -1511,8 +1532,8 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
         groups.push(group);
       }
     });
-    if (params.configs) {
-      params.configs.groups.pushObjects(groups);
+    if (this.get('isReconfigureRequired')) {
+      this.get('groupedPropertiesToChange').pushObjects(groups);
     } else {
       this.saveConfigsBatch(groups, 'ZOOKEEPER_SERVER');
     }
@@ -2726,5 +2747,33 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
    */
   isServiceMetricsLoaded: function(callback) {
     App.router.get('mainController').isLoading.call(App.router.get('clusterController'), 'isServiceContentFullyLoaded').done(callback);
+  },
+
+  setConfigsChangesForDisplayObserver: 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, 'setConfigsChangesForDisplayObserver');
+    }
+  },
+
+  setConfigsChangesForDisplay: function () {
+    if (this.get('allPropertiesToChange.length')) {
+      if (App.get('router.clusterController.isConfigsPropertiesLoaded')) {
+        this.setConfigsChangesForDisplayObserver();
+      } else {
+        this.addObserver('App.router.clusterController.isConfigsPropertiesLoaded', this, 'setConfigsChangesForDisplayObserver');
+      }
+    } else {
+      this.set('isConfigsLoadingInProgress', false);
+    }
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/74d63639/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index c941411..6296d55 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -465,10 +465,13 @@ Em.I18n.translations = {
   'popup.dependent.configs.header': 'Dependent Configurations',
   'popup.dependent.configs.title.recommendation': 'Based on your configuration changes, Ambari is recommending the following dependent configuration changes.',
   'popup.dependent.configs.title.values': 'Ambari will update all checked configuration changes to the <b>Recommended Value</b>. Uncheck any configuration to retain the <b>Current Value</b>.',
+  'popup.dependent.configs.table.recommended': 'Recommended Changes',
+  'popup.dependent.configs.table.required': 'Required Changes',
   'popup.dependent.configs.table.saveProperty': 'Save property',
   'popup.dependent.configs.table.initValue': 'Initial value',
   'popup.dependent.configs.table.currentValue': 'Current Value',
   'popup.dependent.configs.table.recommendedValue': 'Recommended Value',
+  'popup.dependent.configs.table.newValue': 'New Value',
   'popup.dependent.configs.table.not.defined': 'Not Defined',
 
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/74d63639/ambari-web/app/templates/common/modal_popups/dependent_configs_list.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/modal_popups/dependent_configs_list.hbs b/ambari-web/app/templates/common/modal_popups/dependent_configs_list.hbs
index a1f53ef..af84306 100644
--- a/ambari-web/app/templates/common/modal_popups/dependent_configs_list.hbs
+++ b/ambari-web/app/templates/common/modal_popups/dependent_configs_list.hbs
@@ -16,51 +16,97 @@
 * limitations under the License.
 }}
 
-<div class="alert alert-warning">
-  {{#if view.isAfterRecommendation}}
-    <div>{{t popup.dependent.configs.title.recommendation}}</div>
-  {{/if}}
-  <div>{{t popup.dependent.configs.title.values}}</div>
-</div>
+{{#if view.recommendations.length}}
+  <div class="alert alert-warning">
+    {{#if view.isAfterRecommendation}}
+      <div>{{t popup.dependent.configs.title.recommendation}}</div>
+    {{/if}}
+    <div>{{t popup.dependent.configs.title.values}}</div>
+  </div>
+{{/if}}
 <span id="config-dependencies" class="limited-height-2">
-  <table class="table table-hover">
-    <thead>
-    <tr>
-      <th>{{t common.property}}</th>
-      <th>{{t common.service}}</th>
-      <th>{{t common.configGroup}}</th>
-      <th>{{t common.fileName}}</th>
-      <th class="row-fluid">
-          <div class="col-md-6">
-            {{t popup.dependent.configs.table.currentValue}}
-          </div>
-          <div class="col-md-6">
-            {{t popup.dependent.configs.table.recommendedValue}}
-          </div>
-      </th>
-      <th class="check-box-col">{{view view.toggleAll}}<label {{bindAttr for="view.toggleAllId"}}></label></th>
-    </tr>
-    </thead>
-    <tbody>
-    {{#each recommendation in view.recommendations}}
-      <tr {{bindAttr class="recommendation.saveRecommended:active"}}>
-        <td class="config-dependency-name">{{recommendation.propertyName}}</td>
-        <td class="config-dependency-service">{{recommendation.serviceDisplayName}}</td>
-        <td class="config-dependency-group">
-          <span {{bindAttr class="recommendation.allowChangeGroup::not-active-link"}} ><a href="javascript:void(null);" class="black"
-            {{action showSelectGroupPopup recommendation.serviceName target="App.router.mainServiceInfoConfigsController"}}>
-            {{recommendation.configGroup}}
-          </a></span>
-        </td>
-        <td class="config-dependency-filename">{{recommendation.propertyFileName}}</td>
-        <td>
-          <div>
-            {{view App.ConfigDiffView configBinding="recommendation"}}
-          </div>
-        </td>
-        <td class="check-box-col">{{view App.CheckboxView checkedBinding="recommendation.saveRecommended"}}</td>
-      </tr>
-    {{/each}}
-    </tbody>
-  </table>
+  {{#if view.recommendations.length}}
+    <h4>{{t popup.dependent.configs.table.recommended}}</h4>
+    <table class="table table-hover">
+      <thead>
+        <tr>
+          <th>{{t common.property}}</th>
+          <th>{{t common.service}}</th>
+          <th>{{t common.configGroup}}</th>
+          <th>{{t common.fileName}}</th>
+          <th class="row-fluid">
+            <div class="col-md-6">
+              {{t popup.dependent.configs.table.currentValue}}
+            </div>
+            <div class="col-md-6">
+              {{t popup.dependent.configs.table.recommendedValue}}
+            </div>
+          </th>
+          <th class="check-box-col">{{view view.toggleAll}}<label {{bindAttr for="view.toggleAllId"}}></label></th>
+        </tr>
+      </thead>
+      <tbody>
+        {{#each recommendation in view.recommendations}}
+          <tr {{bindAttr class="recommendation.saveRecommended:active"}}>
+            <td class="config-dependency-name">{{recommendation.propertyName}}</td>
+            <td class="config-dependency-service">{{recommendation.serviceDisplayName}}</td>
+            <td class="config-dependency-group">
+              <span {{bindAttr class="recommendation.allowChangeGroup::not-active-link"}} ><a href="javascript:void(null);" class="black"
+                {{action showSelectGroupPopup recommendation.serviceName target="App.router.mainServiceInfoConfigsController"}}>
+                {{recommendation.configGroup}}
+              </a></span>
+            </td>
+            <td class="config-dependency-filename">{{recommendation.propertyFileName}}</td>
+            <td>
+              <div>
+                {{view App.ConfigDiffView configBinding="recommendation"}}
+              </div>
+            </td>
+            <td class="check-box-col">{{view App.CheckboxView checkedBinding="recommendation.saveRecommended"}}</td>
+          </tr>
+        {{/each}}
+      </tbody>
+    </table>
+  {{/if}}
+  {{#if view.requiredChanges.length}}
+    <h4>{{t popup.dependent.configs.table.required}}</h4>
+    <table class="table table-hover">
+      <thead>
+        <tr>
+          <th>{{t common.property}}</th>
+          <th>{{t common.service}}</th>
+          <th>{{t common.configGroup}}</th>
+          <th>{{t common.fileName}}</th>
+          <th class="row-fluid">
+            <div class="col-md-6">
+              {{t popup.dependent.configs.table.currentValue}}
+            </div>
+            <div class="col-md-6">
+              {{t popup.dependent.configs.table.newValue}}
+            </div>
+          </th>
+        </tr>
+      </thead>
+      <tbody>
+        {{#each recommendation in view.requiredChanges}}
+          <tr>
+            <td class="config-dependency-name">{{recommendation.propertyName}}</td>
+            <td class="config-dependency-service">{{recommendation.serviceDisplayName}}</td>
+            <td class="config-dependency-group">
+              <span {{bindAttr class="recommendation.allowChangeGroup::not-active-link"}} ><a href="javascript:void(null);" class="black"
+                {{action showSelectGroupPopup recommendation.serviceName target="App.router.mainServiceInfoConfigsController"}}>
+                {{recommendation.configGroup}}
+              </a></span>
+            </td>
+            <td class="config-dependency-filename">{{recommendation.propertyFileName}}</td>
+            <td>
+              <div>
+                {{view App.ConfigDiffView configBinding="recommendation"}}
+              </div>
+            </td>
+          </tr>
+        {{/each}}
+      </tbody>
+    </table>
+  {{/if}}
 </span>

http://git-wip-us.apache.org/repos/asf/ambari/blob/74d63639/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
index 295acc8..ed8445e 100644
--- a/ambari-web/app/templates/main/host/details/addDeleteComponentPopup.hbs
+++ b/ambari-web/app/templates/main/host/details/addDeleteComponentPopup.hbs
@@ -24,17 +24,17 @@
     </div>
   </div>
 {{/if}}
-{{#if view.isReconfigure}}
+{{#if controller.isReconfigureRequired}}
   {{#if controller.isConfigsLoadingInProgress}}
     {{view App.SpinnerView}}
   {{else}}
     {{view.commonMessage}}
-    {{#if view.propertiesToChange.length}}
-      {{view App.DependentConfigsListView isAfterRecommendation=false recommendationsBinding="view.propertiesToChange"}}
+    {{#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}}
\ No newline at end of file
+{{/if}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/74d63639/ambari-web/app/views/common/modal_popups/dependent_configs_list_popup.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/modal_popups/dependent_configs_list_popup.js b/ambari-web/app/views/common/modal_popups/dependent_configs_list_popup.js
index 1aa46eb..e8e6df5 100644
--- a/ambari-web/app/views/common/modal_popups/dependent_configs_list_popup.js
+++ b/ambari-web/app/views/common/modal_popups/dependent_configs_list_popup.js
@@ -22,6 +22,8 @@ App.DependentConfigsListView = Em.View.extend({
   templateName: require('templates/common/modal_popups/dependent_configs_list'),
   isAfterRecommendation: true,
   recommendations: [],
+  requiredChanges: [],
+  toggleAllId: '',
   toggleAll: App.CheckboxView.extend({
     didInsertElement: function () {
       this.set('parentView.toggleAllId', this.get('elementId'));
@@ -32,13 +34,13 @@ App.DependentConfigsListView = Em.View.extend({
     },
     updateCheckboxObserver: function () {
       Em.run.once(this, 'updateCheckbox');
-    }.observes('parentView.parentView.recommendations.@each.saveRecommended'),
+    }.observes('parentView.recommendations.@each.saveRecommended'),
 
     updateCheckbox: function() {
-      this.set('checked', !(this.get('parentView.parentView.recommendations') || []).someProperty('saveRecommended', false));
+      this.set('checked', !(this.get('parentView.recommendations') || []).someProperty('saveRecommended', false));
     },
     updateSaveRecommended: function() {
-      this.get('parentView.parentView.recommendations').setEach('saveRecommended', this.get('checked'));
+      this.get('parentView.recommendations').setEach('saveRecommended', this.get('checked'));
     }
   })
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/74d63639/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 024e994..859320e 100644
--- a/ambari-web/test/controllers/main/host/details_test.js
+++ b/ambari-web/test/controllers/main/host/details_test.js
@@ -592,15 +592,12 @@ describe('App.MainHostDetailsController', function () {
             tag: 'tag'
           }
         }
-      }}, null, {
-        configs: {}
-      });
+      }});
       var args = testHelpers.findAjaxRequest('name', 'admin.get.all_configurations');
       expect(args[0]).exists;
       expect(args[0].sender).to.be.eql(controller);
       expect(args[0].data).to.be.eql({
-        urlParams: '(type=storm-site&tag=tag)',
-        configs: {}
+        urlParams: '(type=storm-site&tag=tag)'
       });
     });
   });
@@ -666,15 +663,12 @@ describe('App.MainHostDetailsController', function () {
             tag: 'tag'
           }
         }
-      }}, null, {
-        configs: {}
-      });
+      }});
       var args = testHelpers.findAjaxRequest('name', 'admin.get.all_configurations');
       expect(args[0]).exists;
       expect(args[0].sender).to.be.eql(controller);
       expect(args[0].data).to.be.eql({
-        urlParams: '(type=hive-site&tag=tag)|(type=webhcat-site&tag=tag)|(type=hive-env&tag=tag)|(type=core-site&tag=tag)',
-        configs: {}
+        urlParams: '(type=hive-site&tag=tag)|(type=webhcat-site&tag=tag)|(type=hive-env&tag=tag)|(type=core-site&tag=tag)'
       });
     });
   });
@@ -693,15 +687,12 @@ describe('App.MainHostDetailsController', function () {
             tag: 'tag'
           }
         }
-      }}, null, {
-        configs: {}
-      });
+      }});
       var args = testHelpers.findAjaxRequest('name', 'admin.get.all_configurations');
       expect(args[0]).exists;
       expect(args[0].sender).to.be.eql(controller);
       expect(args[0].data).to.be.eql({
-        urlParams: '(type=core-site&tag=tag)|(type=hdfs-site&tag=tag)|(type=kms-env&tag=tag)',
-        configs: {}
+        urlParams: '(type=core-site&tag=tag)|(type=hdfs-site&tag=tag)|(type=kms-env&tag=tag)'
       });
     });
   });
@@ -3834,4 +3825,104 @@ describe('App.MainHostDetailsController', function () {
       });
     });
   });
+
+  describe('#setConfigsChangesForDisplayObserver', function () {
+
+    var configsObject,
+      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 stackProperty;
+        switch (propertyName) {
+          case 'n0':
+            stackProperty = {
+              isEditable: true,
+              isReconfigurable: true
+            };
+            break;
+          case 'n1':
+            stackProperty = {
+              isEditable: true,
+              isReconfigurable: false
+            };
+            break;
+          case 'n2':
+            stackProperty = {
+              isEditable: false,
+              isReconfigurable: false
+            };
+            break;
+        }
+        return stackProperty;
+      });
+      sinon.stub(App, 'get').withArgs('router.clusterController.isConfigsPropertiesLoaded').returns(true);
+      controller.set('isConfigsLoadingInProgress', true);
+      controller.setConfigsChangesForDisplayObserver();
+    });
+
+    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;
+    });
+
+  });
 });