You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by sr...@apache.org on 2015/04/10 03:15:24 UTC

[1/3] ambari git commit: AMBARI-10419. Create theme for MapReduce service enhanced configs

Repository: ambari
Updated Branches:
  refs/heads/trunk aaac2b551 -> 73dca62d9


AMBARI-10419. Create theme for MapReduce service enhanced configs


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

Branch: refs/heads/trunk
Commit: 73dca62d949c649b54fda6a92d2a16de88a5ed29
Parents: afae344
Author: Srimanth Gunturi <sg...@hortonworks.com>
Authored: Thu Apr 9 12:11:27 2015 -0700
Committer: Srimanth Gunturi <sg...@hortonworks.com>
Committed: Thu Apr 9 18:14:03 2015 -0700

----------------------------------------------------------------------
 .../stacks/HDP/2.2/services/YARN/metainfo.xml   |   6 +
 .../2.2/services/YARN/themes-mapred/theme.json  | 118 +++++++++++++++++++
 2 files changed, 124 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/73dca62d/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/metainfo.xml
index d1a71f8..189defc 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/metainfo.xml
@@ -90,6 +90,12 @@
       </osSpecifics>
       <configuration-dir>configuration-mapred</configuration-dir>
       <themes-dir>themes-mapred</themes-dir>
+      <themes>
+        <theme>
+          <fileName>theme.json</fileName>
+          <default>true</default>
+        </theme>
+      </themes>
 
     </service>
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/73dca62d/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/themes-mapred/theme.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/themes-mapred/theme.json b/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/themes-mapred/theme.json
new file mode 100644
index 0000000..97d05dc
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/themes-mapred/theme.json
@@ -0,0 +1,118 @@
+{
+  "Theme": {
+    "name": "default",
+    "description": "Default theme for MAPREDUCE service",
+    "configuration": {
+      "layouts": [
+        {
+          "name": "default",
+          "tabs": [
+            {
+              "name": "settings",
+              "display-name": "Settings",
+              "layout": {
+                "tab-columns": "1",
+                "tab-rows": "1",
+                "sections": [
+                  {
+                    "name": "section-mr-scheduler",
+                    "display-name": "MR Scheduler Defaults",
+                    "row-index": "0",
+                    "column-index": "0",
+                    "row-span": "1",
+                    "column-span": "2",
+                    "section-columns": "2",
+                    "section-rows": "1",
+                    "subsections": [
+                      {
+                        "name": "subsection-mr-scheduler-col1",
+                        "row-index": "0",
+                        "column-index": "0",
+                        "row-span": "1",
+                        "column-span": "1"
+                      },
+                      {
+                        "name": "subsection-mr-scheduler-col2",
+                        "row-index": "0",
+                        "column-index": "1",
+                        "row-span": "1",
+                        "column-span": "1"
+                      }
+                    ]
+                  }
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    "placement": {
+      "configuration-layout": "default",
+      "configs": [
+        {
+          "config": "mapred-site/mapreduce.map.memory.mb",
+          "subsection-name": "subsection-mr-scheduler-col1"
+        },
+        {
+          "config": "mapred-site/mapreduce.reduce.memory.mb",
+          "subsection-name": "subsection-mr-scheduler-col1"
+        },
+        {
+          "config": "mapred-site/yarn.app.mapreduce.am.resource.mb",
+          "subsection-name": "subsection-mr-scheduler-col2"
+        },
+        {
+          "config": "mapred-site/mapreduce.task.io.sort.mb",
+          "subsection-name": "subsection-mr-scheduler-col2"
+        }
+      ]
+    },
+    "widgets":[
+      {
+        "config":"mapred-site/mapreduce.map.memory.mb",
+        "widget":{
+          "type":"slider",
+          "units":[
+            {
+              "unit-name":"GB"
+            }
+          ]
+        }
+      },
+      {
+        "config":"mapred-site/mapreduce.reduce.memory.mb",
+        "widget":{
+          "type":"slider",
+          "units":[
+            {
+              "unit-name":"GB"
+            }
+          ]
+        }
+      },
+      {
+        "config":"mapred-site/yarn.app.mapreduce.am.resource.mb",
+        "widget":{
+          "type":"slider",
+          "units":[
+            {
+              "unit-name":"GB"
+            }
+          ]
+        }
+      },
+      {
+        "config":"mapred-site/mapreduce.task.io.sort.mb",
+        "widget":{
+          "type":"slider",
+          "units":[
+            {
+              "unit-name":"MB"
+            }
+          ]
+        }
+      }
+    ]
+  }
+}


[3/3] ambari git commit: AMBARI-10377. Small refactor of save configs part on service page (ababiichuk via srimanth)

Posted by sr...@apache.org.
AMBARI-10377. Small refactor of save configs part on service page (ababiichuk via srimanth)


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

Branch: refs/heads/trunk
Commit: 2d30cd5736104cb6cf19b6fa88fbb9deb157c603
Parents: aaac2b5
Author: Srimanth Gunturi <sg...@hortonworks.com>
Authored: Thu Apr 9 10:58:44 2015 -0700
Committer: Srimanth Gunturi <sg...@hortonworks.com>
Committed: Thu Apr 9 18:14:03 2015 -0700

----------------------------------------------------------------------
 .../controllers/main/service/info/configs.js    |   34 +-
 .../app/controllers/wizard/step8_controller.js  |   33 +-
 .../app/mixins/common/configs/configs_saver.js  | 1552 +++++++++---------
 .../dependent_configs_list_popup.js             |    6 +-
 .../main/service/info/config_test.js            |  168 +-
 .../mixins/common/configs/configs_saver_test.js |   40 +
 6 files changed, 825 insertions(+), 1008 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/2d30cd57/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 4503846..fb54278 100644
--- a/ambari-web/app/controllers/main/service/info/configs.js
+++ b/ambari-web/app/controllers/main/service/info/configs.js
@@ -84,12 +84,6 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
   selectedVersion: null,
 
   /**
-   * file names of changed configs
-   * @type {string[]}
-   */
-  modifiedFileNames: [],
-
-  /**
    * note passed on configs save
    * @type {string}
    */
@@ -237,18 +231,6 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
   ],
 
   /**
-   * List of heapsize properties not to be parsed
-   * @type {string[]}
-   */
-  heapsizeException: ['hadoop_heapsize', 'yarn_heapsize', 'nodemanager_heapsize', 'resourcemanager_heapsize', 'apptimelineserver_heapsize', 'jobhistory_heapsize', 'nfsgateway_heapsize'],
-
-  /**
-   * Regular expression for heapsize properties detection
-   * @type {regexp}
-   */
-  heapsizeRegExp: /_heapsize|_newsize|_maxnewsize|_permsize|_maxpermsize$/,
-
-  /**
    * Dropdown menu items in filter combobox
    * @type {{attributeName: string, attributeValue: string, name: string, selected: boolean}[]}
    */
@@ -297,9 +279,9 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
       this.get('requestInProgress').abort();
       this.set('requestInProgress', null);
     }
+    this.clearSaveInfo();
     this.setProperties({
       saveInProgress: false,
-      modifiedFileNames: [],
       isInit: true,
       hash: null,
       forceTransition: false,
@@ -1009,16 +991,6 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
   },
 
   /**
-   * method to run saving configs
-   * @method saveStepConfigs
-   */
-  saveStepConfigs: function() {
-    if (!this.get("isSubmitDisabled")) {
-      this.startSave();
-      this.showWarningPopupsBeforeSave();
-    }
-  },
-  /**
    * Array of Objects
    * {
    *  hostProperty - hostName property name for current component
@@ -1029,7 +1001,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
    * }
    */
 
-  hostComponentsmapping: [
+  hostComponentsMapping: [
     {
       hostProperty: 'snamenode_host',
       componentName: 'SECONDARY_NAMENODE',
@@ -1149,7 +1121,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
       console.log("No NameNode Host available.  This is expected if you're using GLUSTERFS rather than HDFS.");
     }
 
-    var hostProperties = this.get('hostComponentsmapping').filter(function (h) {
+    var hostProperties = this.get('hostComponentsMapping').filter(function (h) {
       return h.serviceUseThis.contains(serviceName) || h.serviceName == serviceName;
     });
     hostProperties.forEach(function (h) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/2d30cd57/ambari-web/app/controllers/wizard/step8_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/wizard/step8_controller.js b/ambari-web/app/controllers/wizard/step8_controller.js
index 5560419..bdfa292 100644
--- a/ambari-web/app/controllers/wizard/step8_controller.js
+++ b/ambari-web/app/controllers/wizard/step8_controller.js
@@ -1619,7 +1619,7 @@ App.WizardStep8Controller = Em.Controller.extend(App.AddSecurityConfigs, App.wiz
       configGroup.properties.forEach(function (property) {
         groupConfigs.push(Em.Object.create(property));
       });
-      groupData.desired_configs = serviceConfigController.buildGroupDesiredConfigs.call(serviceConfigController, groupConfigs, timeTag);
+      groupData.desired_configs = this.buildGroupDesiredConfigs(groupConfigs, timeTag);
       // check for group from installed service
       if (configGroup.isForInstalledService === true) {
         // if group is a new one, create it
@@ -1645,6 +1645,37 @@ App.WizardStep8Controller = Em.Controller.extend(App.AddSecurityConfigs, App.wiz
   },
 
   /**
+   * construct desired_configs for config groups from overriden properties
+   * @param configs
+   * @param timeTag
+   * @return {Array}
+   * @private
+   * @method buildGroupDesiredConfigs
+   */
+  buildGroupDesiredConfigs: function (configs, timeTag) {
+    var sites = [];
+    var time = timeTag || (new Date).getTime();
+    var siteFileNames = configs.mapProperty('filename').uniq();
+    sites = siteFileNames.map(function (filename) {
+      return {
+        type: filename.replace('.xml', ''),
+        tag: 'version' + time,
+        properties: []
+      };
+    });
+
+    configs.forEach(function (config) {
+      var type = config.get('filename').replace('.xml', '');
+      var site = sites.findProperty('type', type);
+      site.properties.push(config);
+    });
+
+    return sites.map(function (site) {
+      return this.createSiteObj(site.type, site.tag, site.properties);
+    }, this);
+  },
+
+  /**
    * Create new config groups request
    * Queued request
    * @param {Object[]} sendData

http://git-wip-us.apache.org/repos/asf/ambari/blob/2d30cd57/ambari-web/app/mixins/common/configs/configs_saver.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/configs/configs_saver.js b/ambari-web/app/mixins/common/configs/configs_saver.js
index b32d816..a35689b 100644
--- a/ambari-web/app/mixins/common/configs/configs_saver.js
+++ b/ambari-web/app/mixins/common/configs/configs_saver.js
@@ -20,12 +20,116 @@ var App = require('app');
 var dataManipulationUtils = require('utils/data_manipulation');
 var lazyLoading = require('utils/lazy_loading');
 
+/**
+ * this mixin has method to save configs (used in MainServiceInfoConfigsController)
+ * all methods are divided into couple groups :
+ *  0. HELPERS - some helper methods
+ *  1. PRE SAVE CHECKS - warning popups and validations checks
+ *  2. PREPARE CONFIGS TO SAVE - filtering and formatting changed configs
+ *    2.1 PREPARE DATABASE CONFIGS - modify database properties
+ *    2.2 ADD DYNAMIC CONFIGS - !!!NEED INVESTIGATION
+ *  3. GENERATING JSON TO SAVE - generating json data
+ *  4. AJAX REQUESTS - ajax request
+ *  5. AFTER SAVE INFO - after save methods like to show popup with result
+ *  6. ADDITIONAL
+ */
 App.ConfigsSaverMixin = Em.Mixin.create({
 
   /**
    * @type {boolean}
    */
   saveConfigsFlag: true,
+
+  /**
+   * file names of changed configs
+   * @type {string[]}
+   */
+  modifiedFileNames: [],
+
+  /**
+   * List of heapsize properties not to be parsed
+   * @type {string[]}
+   */
+  heapsizeException: ['hadoop_heapsize', 'yarn_heapsize', 'nodemanager_heapsize', 'resourcemanager_heapsize', 'apptimelineserver_heapsize', 'jobhistory_heapsize'],
+
+  /**
+   * Regular expression for heapsize properties detection
+   * @type {regexp}
+   */
+  heapsizeRegExp: /_heapsize|_newsize|_maxnewsize|_permsize|_maxpermsize$/,
+
+  /**
+   * clear info to default
+   * @method clearSaveInfo
+   */
+  clearSaveInfo: function() {
+    this.set('modifiedFileNames', []);
+  },
+
+  /**
+   * method to run saving configs
+   * @method saveStepConfigs
+   */
+  saveStepConfigs: function() {
+    if (!this.get("isSubmitDisabled")) {
+      this.startSave();
+      this.showWarningPopupsBeforeSave();
+    }
+  },
+
+  /**
+   * Save changed configs and config groups
+   * @method saveConfigs
+   */
+  saveConfigs: function () {
+    var selectedConfigGroup = this.get('selectedConfigGroup');
+    if (selectedConfigGroup.get('isDefault')) {
+
+      var data = [];
+      this.get('stepConfigs').forEach(function(stepConfig) {
+
+        var serviceConfig = this.getServiceConfigToSave(stepConfig.get('serviceName'), stepConfig.get('configs'));
+
+        if (serviceConfig)  {
+          data.push(serviceConfig);
+        }
+
+      }, this);
+
+      if (Em.isArray(data) && data.length) {
+        this.putChangedConfigurations(data, true);
+      } else {
+        this.onDoPUTClusterConfigurations();
+      }
+    } else {
+
+      this.get('stepConfigs').forEach(function(stepConfig) {
+        var serviceName = stepConfig.get('serviceName');
+        var configs = stepConfig.get('configs');
+        var configGroup = this.getGroupForService(serviceName);
+
+        if (configGroup.get('isDefault')) {
+
+          var configsToSave = this.getServiceConfigToSave(serviceName, configs);
+
+          if (configsToSave) {
+            this.putChangedConfigurations([configsToSave], false);
+          }
+
+        } else {
+
+          var overridenConfigs = this.getConfigsForGroup(configs, configGroup.get('name'));
+
+          if (Em.isArray(overridenConfigs) && overridenConfigs.length) {
+            this.saveGroup(overridenConfigs, configGroup, this.get('content.serviceName') === serviceName);
+          }
+        }
+      }, this);
+    }
+  },
+
+  /*********************************** 0. HELPERS ********************************************/
+
   /**
    * tells controller in saving configs was started
    * for now just changes flag <code>saveInProgress<code> to true
@@ -46,10 +150,19 @@ App.ConfigsSaverMixin = Em.Mixin.create({
     this.set("saveInProgress", false);
   },
 
+  /**
+   * Are some unsaved changes available
+   * @returns {boolean}
+   * @method hasUnsavedChanges
+   */
+  hasUnsavedChanges: function () {
+    return this.get('hash') != this.getHash();
+  },
+
+  /*********************************** 1. PRE SAVE CHECKS ************************************/
 
   /**
    * show some warning popups before user save configs
-   * @method showWarningPopupsBeforeSave
    * @private
    * @method showWarningPopupsBeforeSave
    */
@@ -67,7 +180,7 @@ App.ConfigsSaverMixin = Em.Mixin.create({
     } else {
       self.showChangedDependentConfigs(null, function() {
         self.restartServicePopup();
-      });
+      }, this.completeSave.bind(this));
     }
   },
 
@@ -103,9 +216,12 @@ App.ConfigsSaverMixin = Em.Mixin.create({
     return dirChanged;
   },
 
+  /*********************************** 2. GENERATING DATA TO SAVE ****************************/
+
   /**
    * get config properties for that fileNames that was changed
    * @param stepConfigs
+   * @private
    * @returns {Array}
    */
   getModifiedConfigs: function(stepConfigs) {
@@ -131,506 +247,188 @@ App.ConfigsSaverMixin = Em.Mixin.create({
   },
 
   /**
-   * Save changed configs and config groups
-   * @method saveConfigs
+   * get configs that belongs to config group
+   * @param stepConfigs
+   * @private
+   * @param configGroupName
    */
-  saveConfigs: function () {
-    var selectedConfigGroup = this.get('selectedConfigGroup');
-    var configs = this.get('stepConfigs').findProperty('serviceName', this.get('content.serviceName')).get('configs');
-
-    if (selectedConfigGroup.get('isDefault')) {
-      if (this.get('content.serviceName') === 'YARN') {
-        configs = App.config.textareaIntoFileConfigs(configs, 'capacity-scheduler.xml');
-      }
-
-      /**
-       * generates list of properties that was changed
-       * @type {Array}
-       */
-      var modifiedConfigs = this.getModifiedConfigs(configs);
+  getConfigsForGroup: function(stepConfigs, configGroupName) {
+    var overridenConfigs = [];
 
-      // save modified original configs that have no group
-      this.saveSiteConfigs(modifiedConfigs.filter(function (config) {
-        return !config.get('group');
+    stepConfigs.filterProperty('isOverridden', true).forEach(function (config) {
+      overridenConfigs = overridenConfigs.concat(config.get('overrides'));
+    });
+    // find custom original properties that assigned to selected config group
+    return overridenConfigs.concat(stepConfigs.filterProperty('group')
+      .filter(function (config) {
+        return config.get('group.name') == configGroupName;
       }));
+  },
 
-      /**
-       * First we put cluster configurations, which automatically creates /configurations
-       * resources. Next we update host level overrides.
-       */
-      this.doPUTClusterConfigurations();
-
-    } else {
-
-      var overridenConfigs = this.getConfigsForGroup(configs, selectedConfigGroup.get('name'));
+  /**
+   *
+   * @param serviceName
+   * @param configs
+   * @private
+   * @returns {*}
+   */
+  getServiceConfigToSave: function(serviceName, configs) {
 
-      /**
-       * if there are some changes in dependent configs
-       * need to save these config to in separate request
-       */
-      this.get('dependentServiceNames').forEach(function(serviceName) {
-        var serviceConfig = this.get('stepConfigs').findProperty('serviceName', serviceName);
-        if (serviceConfig && this.get('changedProperties').findProperty('serviceName', serviceName) && this.get('groupsToSave')[serviceName]) {
-          var stepConfigs = serviceConfig.get('configs');
+    if (serviceName === 'YARN') {
+      configs = App.config.textareaIntoFileConfigs(configs, 'capacity-scheduler.xml');
+    }
+    /**
+     * generates list of properties that was changed
+     * @type {Array}
+     */
+    var modifiedConfigs = this.getModifiedConfigs(configs);
 
-          if (this.get('groupsToSave')[serviceName].contains('Default')) {
-            var data = [];
+    // save modified original configs that have no group
+    modifiedConfigs = this.saveSiteConfigs(modifiedConfigs.filter(function (config) {
+      return !config.get('group');
+    }));
 
-            var modifiedConfigs = this.getModifiedConfigs(stepConfigs);
+    if (!Em.isArray(modifiedConfigs) || modifiedConfigs.length == 0) return null;
 
-            var fileNamesToSave = modifiedConfigs.mapProperty('filename').uniq();
+    var fileNamesToSave = modifiedConfigs.mapProperty('filename').concat(this.get('modifiedFileNames')).uniq();
 
-            var dependentConfigsToSave = this.generateDesiredConfigsJSON(modifiedConfigs, fileNamesToSave, this.get('serviceConfigNote'));
+    var configsToSave = this.generateDesiredConfigsJSON(modifiedConfigs, fileNamesToSave, this.get('serviceConfigNote'));
 
-            if (dependentConfigsToSave.length > 0) {
-              data.pushObject(JSON.stringify({
-                Clusters: {
-                  desired_config: dependentConfigsToSave
-                }
-              }));
-            }
-            this.doPUTClusterConfigurationSites(data, false);
-          } else {
-            var overridenConfigs = this.getConfigsForGroup(stepConfigs, selectedConfigGroup.get('name'));
-            var group = this.get('dependentConfigGroups').findProperty('name', this.get('groupsToSave')[serviceName]);
-            this.saveGroup(overridenConfigs, group, false);
-          }
+    if (configsToSave.length > 0) {
+      return JSON.stringify({
+        Clusters: {
+          desired_config: configsToSave
         }
-      }, this);
-
-      this.saveGroup(overridenConfigs, selectedConfigGroup, true);
+      });
+    } else {
+      return null;
     }
   },
 
   /**
-   * get configs that belongs to config group
-   * @param stepConfigs
-   * @param configGroupName
+   * save site configs
+   * @param configs
+   * @private
+   * @method saveSiteConfigs
    */
-  getConfigsForGroup: function(stepConfigs, configGroupName) {
-    var overridenConfigs = [];
-
-    stepConfigs.filterProperty('isOverridden', true).forEach(function (config) {
-      overridenConfigs = overridenConfigs.concat(config.get('overrides'));
-    });
-    // find custom original properties that assigned to selected config group
-    overridenConfigs = overridenConfigs.concat(stepConfigs.filterProperty('group')
-      .filter(function (config) {
-        return config.get('group.name') == configGroupName;
-      }));
-
-    this.formatConfigValues(overridenConfigs);
-    return overridenConfigs;
+  saveSiteConfigs: function (configs) {
+    //storedConfigs contains custom configs as well
+    configs = this.setHiveHostName(configs);
+    configs = this.setOozieHostName(configs);
+    this.formatConfigValues(configs);
+    var mappedConfigs = App.config.excludeUnsupportedConfigs(this.get('configMapping').all(), App.Service.find().mapProperty('serviceName'));
+    var allUiConfigs = this.loadUiSideConfigs(mappedConfigs);
+    return configs.concat(allUiConfigs);
   },
 
   /**
-   * save config group
-   * @param overridenConfigs
-   * @param selectedConfigGroup
-   * @param showPopup
+   * Represent boolean value as string (true => 'true', false => 'false') and trim other values
+   * @param serviceConfigProperties
+   * @private
+   * @method formatConfigValues
    */
-  saveGroup: function(overridenConfigs, selectedConfigGroup, showPopup) {
-    var groupHosts = [];
-    var fileNamesToSave = overridenConfigs.mapProperty('filename');
-    selectedConfigGroup.get('hosts').forEach(function (hostName) {
-      groupHosts.push({"host_name": hostName});
+  formatConfigValues: function (serviceConfigProperties) {
+    serviceConfigProperties.forEach(function (_config) {
+      if (typeof _config.get('value') === "boolean") _config.set('value', _config.value.toString());
+      _config.set('value', App.config.trimProperty(_config, true));
     });
-    this.putConfigGroupChanges({
-      ConfigGroup: {
-        "id": selectedConfigGroup.get('id'),
-        "cluster_name": App.get('clusterName'),
-        "group_name": selectedConfigGroup.get('name'),
-        "tag": selectedConfigGroup.get('service.id'),
-        "description": selectedConfigGroup.get('description'),
-        "hosts": groupHosts,
-        "service_config_version_note": this.get('serviceConfigVersionNote'),
-        "desired_configs": this.generateDesiredConfigsJSON(overridenConfigs, fileNamesToSave, null, true)
-      }
-    }, showPopup);
   },
+
+  /*********************************** 2.1 PREPARE DATABASE CONFIGS ****************************/
+
   /**
-   * On save configs handler. Open save configs popup with appropriate message
+   * set hive hostnames in configs
+   * @param configs
    * @private
-   * @method onDoPUTClusterConfigurations
+   * @method setHiveHostName
    */
-  onDoPUTClusterConfigurations: function () {
-    var header, message, messageClass, value, status = 'unknown', urlParams = '',
-      result = {
-        flag: this.get('saveConfigsFlag'),
-        message: null,
-        value: null
-      },
-      extendedModel = App.Service.extendedModel[this.get('content.serviceName')],
-      currentService = extendedModel ? App[extendedModel].find(this.get('content.serviceName')) : App.Service.find(this.get('content.serviceName'));
-
-    if (!result.flag) {
-      result.message = Em.I18n.t('services.service.config.failSaveConfig');
-    }
+  setHiveHostName: function (configs) {
+    var dbHostPropertyName = null, configsToRemove = [];
+    if (configs.someProperty('name', 'hive_database')) {
+      var hiveDb = configs.findProperty('name', 'hive_database');
 
-    App.router.get('clusterController').updateClusterData();
-    App.router.get('updateController').updateComponentConfig(function () {
-    });
-    var flag = result.flag;
-    if (result.flag === true) {
-      header = Em.I18n.t('services.service.config.saved');
-      message = Em.I18n.t('services.service.config.saved.message');
-      messageClass = 'alert alert-success';
-      // warn the user if any of the components are in UNKNOWN state
-      urlParams += ',ServiceComponentInfo/installed_count,ServiceComponentInfo/total_count';
-      if (this.get('content.serviceName') === 'HDFS') {
-        urlParams += '&ServiceComponentInfo/service_name.in(HDFS)'
+      switch(hiveDb.value) {
+        case 'New MySQL Database':
+        case 'New PostgreSQL Database':
+          dbHostPropertyName = configs.someProperty('name', 'hive_ambari_host') ? 'hive_ambari_host' : dbHostPropertyName;
+          configsToRemove = ['hive_existing_mysql_host', 'hive_existing_mysql_database', 'hive_existing_oracle_host', 'hive_existing_oracle_database', 'hive_existing_postgresql_host', 'hive_existing_postgresql_database', 'hive_existing_mssql_server_database', 'hive_existing_mssql_server_host', 'hive_existing_mssql_server_2_database', 'hive_existing_mssql_server_2_host'];
+          break;
+        case 'Existing MySQL Database':
+          dbHostPropertyName = configs.someProperty('name', 'hive_existing_mysql_host') ? 'hive_existing_mysql_host' : dbHostPropertyName;
+          configsToRemove = ['hive_ambari_database', 'hive_existing_oracle_host', 'hive_existing_oracle_database', 'hive_existing_postgresql_host', 'hive_existing_postgresql_database', 'hive_existing_mssql_server_database', 'hive_existing_mssql_server_host', 'hive_existing_mssql_server_2_database', 'hive_existing_mssql_server_2_host'];
+          break;
+        case 'Existing PostgreSQL Database':
+          dbHostPropertyName = configs.someProperty('name', 'hive_existing_postgresql_host') ? 'hive_existing_postgresql_host' : dbHostPropertyName;
+          configsToRemove = ['hive_ambari_database', 'hive_existing_mysql_host', 'hive_existing_mysql_database', 'hive_existing_oracle_host', 'hive_existing_oracle_database', 'hive_existing_mssql_server_database', 'hive_existing_mssql_server_host', 'hive_existing_mssql_server_2_database', 'hive_existing_mssql_server_2_host'];
+          break;
+        case 'Existing Oracle Database':
+          dbHostPropertyName = configs.someProperty('name', 'hive_existing_oracle_host') ? 'hive_existing_oracle_host' : dbHostPropertyName;
+          configsToRemove = ['hive_ambari_database', 'hive_existing_mysql_host', 'hive_existing_mysql_database', 'hive_existing_postgresql_host', 'hive_existing_postgresql_database', 'hive_existing_mssql_server_database', 'hive_existing_mssql_server_host', 'hive_existing_mssql_server_2_database', 'hive_existing_mssql_server_2_host'];
+          break;
+        case 'Existing MSSQL Server database with SQL authentication':
+          dbHostPropertyName = configs.someProperty('name', 'hive_existing_mssql_server_host') ? 'hive_existing_mssql_server_host' : dbHostPropertyName;
+          configsToRemove = ['hive_ambari_database', 'hive_existing_mysql_host', 'hive_existing_mysql_database', 'hive_existing_postgresql_host', 'hive_existing_postgresql_database', 'hive_existing_oracle_host', 'hive_existing_oracle_database', 'hive_existing_mssql_server_2_database', 'hive_existing_mssql_server_2_host'];
+          break;
+        case 'Existing MSSQL Server database with integrated authentication':
+          dbHostPropertyName = configs.someProperty('name', 'hive_existing_mssql_server_2_host') ? 'hive_existing_mssql_server_2_host' : dbHostPropertyName;
+          configsToRemove = ['hive_ambari_database', 'hive_existing_mysql_host', 'hive_existing_mysql_database', 'hive_existing_postgresql_host', 'hive_existing_postgresql_database', 'hive_existing_oracle_host', 'hive_existing_oracle_database', 'hive_existing_mssql_server_database', 'hive_existing_mssql_server_host'];
+          break;
       }
-    } else {
-      header = Em.I18n.t('common.failure');
-      message = result.message;
-      messageClass = 'alert alert-error';
-      value = result.value;
+      configs = dataManipulationUtils.rejectPropertyValues(configs, 'name', configsToRemove);
     }
-    if(currentService){
-      App.QuickViewLinks.proto().set('content', currentService);
-      App.QuickViewLinks.proto().loadTags();
+    if (dbHostPropertyName) {
+      var hiveHostNameProperty = App.ServiceConfigProperty.create(App.config.get('preDefinedSiteProperties').findProperty('name', 'hive_hostname'));
+      hiveHostNameProperty.set('value', configs.findProperty('name', dbHostPropertyName).get('value'));
+      configs.pushObject(hiveHostNameProperty);
     }
-    this.showSaveConfigsPopup(header, flag, message, messageClass, value, status, urlParams);
+    return configs;
   },
 
   /**
-   * Show save configs popup
-   * @return {App.ModalPopup}
+   * set oozie hostnames in configs
+   * @param configs
    * @private
-   * @method showSaveConfigsPopup
+   * @method setOozieHostName
    */
-  showSaveConfigsPopup: function (header, flag, message, messageClass, value, status, urlParams) {
-    var self = this;
-    if (flag) {
-      this.set('forceTransition', flag);
-      self.loadStep();
-    }
-    return App.ModalPopup.show({
-      header: header,
-      primary: Em.I18n.t('ok'),
-      secondary: null,
-      onPrimary: function () {
-        this.hide();
-        if (!flag) {
-          self.completeSave();
-        }
-      },
-      onClose: function () {
-        this.hide();
-        self.completeSave();
-      },
-      disablePrimary: true,
-      bodyClass: Ember.View.extend({
-        flag: flag,
-        message: function () {
-          return this.get('isLoaded') ? message : Em.I18n.t('services.service.config.saving.message');
-        }.property('isLoaded'),
-        messageClass: function () {
-          return this.get('isLoaded') ? messageClass : 'alert alert-info';
-        }.property('isLoaded'),
-        setDisablePrimary: function () {
-          this.get('parentView').set('disablePrimary', !this.get('isLoaded'));
-        }.observes('isLoaded'),
-        runningHosts: [],
-        runningComponentCount: 0,
-        unknownHosts: [],
-        unknownComponentCount: 0,
-        siteProperties: value,
-        isLoaded: false,
-        componentsFilterSuccessCallback: function (response) {
-          var count = 0,
-            view = this,
-            lazyLoadHosts = function (dest) {
-              lazyLoading.run({
-                initSize: 20,
-                chunkSize: 50,
-                delay: 50,
-                destination: dest,
-                source: hosts,
-                context: view
-              });
-            },
-            /**
-             * Map components for their hosts
-             * Return format:
-             * <code>
-             *   {
-             *    host1: [component1, component2, ...],
-             *    host2: [component3, component4, ...]
-             *   }
-             * </code>
-             * @return {object}
-             */
-              setComponents = function (item, components) {
-              item.host_components.forEach(function (c) {
-                var name = c.HostRoles.host_name;
-                if (!components[name]) {
-                  components[name] = [];
-                }
-                components[name].push(App.format.role(item.ServiceComponentInfo.component_name));
-              });
-              return components;
-            },
-            /**
-             * Map result of <code>setComponents</code> to array
-             * @return {{name: string, components: string}[]}
-             */
-              setHosts = function (components) {
-              var hosts = [];
-              Em.keys(components).forEach(function (key) {
-                hosts.push({
-                  name: key,
-                  components: components[key].join(', ')
-                });
-              });
-              return hosts;
-            },
-            components = {},
-            hosts = [];
-          switch (status) {
-            case 'unknown':
-              response.items.filter(function (item) {
-                return (item.ServiceComponentInfo.total_count > item.ServiceComponentInfo.started_count + item.ServiceComponentInfo.installed_count);
-              }).forEach(function (item) {
-                var total = item.ServiceComponentInfo.total_count,
-                  started = item.ServiceComponentInfo.started_count,
-                  installed = item.ServiceComponentInfo.installed_count,
-                  unknown = total - started + installed;
-                components = setComponents(item, components);
-                count += unknown;
-              });
-              hosts = setHosts(components);
-              this.set('unknownComponentCount', count);
-              lazyLoadHosts(this.get('unknownHosts'));
-              break;
-            case 'started':
-              response.items.filterProperty('ServiceComponentInfo.started_count').forEach(function (item) {
-                var started = item.ServiceComponentInfo.started_count;
-                components = setComponents(item, components);
-                count += started;
-                hosts = setHosts(components);
-              });
-              this.set('runningComponentCount', count);
-              lazyLoadHosts(this.get('runningHosts'));
-              break;
-          }
-        },
-        componentsFilterErrorCallback: function () {
-          this.set('isLoaded', true);
-        },
-        didInsertElement: function () {
-          return App.ajax.send({
-            name: 'components.filter_by_status',
-            sender: this,
-            data: {
-              clusterName: App.get('clusterName'),
-              urlParams: urlParams
-            },
-            success: 'componentsFilterSuccessCallback',
-            error: 'componentsFilterErrorCallback'
-          });
-        },
-        getDisplayMessage: function () {
-          var displayMsg = [];
-          var siteProperties = this.get('siteProperties');
-          if (siteProperties) {
-            siteProperties.forEach(function (_siteProperty) {
-              var displayProperty = _siteProperty.siteProperty;
-              var displayNames = _siteProperty.displayNames;
-
-              if (displayNames && displayNames.length) {
-                if (displayNames.length === 1) {
-                  displayMsg.push(displayProperty + Em.I18n.t('as') + displayNames[0]);
-                } else {
-                  var name;
-                  displayNames.forEach(function (_name, index) {
-                    if (index === 0) {
-                      name = _name;
-                    } else if (index === siteProperties.length - 1) {
-                      name = name + Em.I18n.t('and') + _name;
-                    } else {
-                      name = name + ', ' + _name;
-                    }
-                  }, this);
-                  displayMsg.push(displayProperty + Em.I18n.t('as') + name);
-
-                }
-              } else {
-                displayMsg.push(displayProperty);
-              }
-            }, this);
-          }
-          return displayMsg;
-
-        }.property('siteProperties'),
-
-        runningHostsMessage: function () {
-          return Em.I18n.t('services.service.config.stopService.runningHostComponents').format(this.get('runningComponentCount'), this.get('runningHosts.length'));
-        }.property('runningComponentCount', 'runningHosts.length'),
-
-        unknownHostsMessage: function () {
-          return Em.I18n.t('services.service.config.stopService.unknownHostComponents').format(this.get('unknownComponentCount'), this.get('unknownHosts.length'));
-        }.property('unknownComponentCount', 'unknownHosts.length'),
-
-        templateName: require('templates/main/service/info/configs_save_popup')
-      })
-    })
-  },
-
-  /**
-   * construct desired_configs for config groups from overriden properties
-   * @param configs
-   * @param timeTag
-   * @return {Array}
-   * @private
-   * @method buildGroupDesiredConfigs
-   */
-  buildGroupDesiredConfigs: function (configs, timeTag) {
-    var sites = [];
-    var time = timeTag || (new Date).getTime();
-    var siteFileNames = configs.mapProperty('filename').uniq();
-    sites = siteFileNames.map(function (filename) {
-      return {
-        type: filename.replace('.xml', ''),
-        tag: 'version' + time,
-        properties: []
-      };
-    });
-
-    configs.forEach(function (config) {
-      var type = config.get('filename').replace('.xml', '');
-      var site = sites.findProperty('type', type);
-      site.properties.push(config);
-    });
-
-    return sites.map(function (site) {
-      return this.createSiteObj(site.type, site.tag, site.properties);
-    }, this);
-  },
-  /**
-   * persist properties of config groups to server
-   * show result popup if <code>showPopup</code> is true
-   * @param data {Object}
-   * @param showPopup {Boolean}
-   * @method putConfigGroupChanges
-   */
-  putConfigGroupChanges: function (data, showPopup) {
-    var ajaxOptions = {
-      name: 'config_groups.update_config_group',
-      sender: this,
-      data: {
-        id: data.ConfigGroup.id,
-        configGroup: data
-      }
-    };
-    if (showPopup) {
-      ajaxOptions.success = "putConfigGroupChangesSuccess";
-    }
-    return App.ajax.send(ajaxOptions);
-  },
-
-  /**
-   * @private
-   * @method putConfigGroupChangesSuccess
-   */
-  putConfigGroupChangesSuccess: function () {
-    this.set('saveConfigsFlag', true);
-    this.onDoPUTClusterConfigurations();
-  },
-
-  /**
-   * set hive hostnames in configs
-   * @param configs
-   * @private
-   * @method setHiveHostName
-   */
-  setHiveHostName: function (configs) {
+  setOozieHostName: function (configs) {
     var dbHostPropertyName = null, configsToRemove = [];
-    if (configs.someProperty('name', 'hive_database')) {
-      var hiveDb = configs.findProperty('name', 'hive_database');
-
-      switch(hiveDb.value) {
+    if (configs.someProperty('name', 'oozie_database')) {
+      var oozieDb = configs.findProperty('name', 'oozie_database');
+      switch (oozieDb.value) {
+        case 'New Derby Database':
+          configsToRemove = ['oozie_ambari_database', 'oozie_existing_mysql_host', 'oozie_existing_mysql_database', 'oozie_existing_oracle_host', 'oozie_existing_oracle_database', 'oozie_existing_postgresql_host', 'oozie_existing_postgresql_database', 'oozie_existing_mssql_server_database', 'oozie_existing_mssql_server_host', 'oozie_existing_mssql_server_2_database', 'oozie_existing_mssql_server_2_host'];
+          break;
         case 'New MySQL Database':
-        case 'New PostgreSQL Database':
-          dbHostPropertyName = configs.someProperty('name', 'hive_ambari_host') ? 'hive_ambari_host' : dbHostPropertyName;
-          configsToRemove = ['hive_existing_mysql_host', 'hive_existing_mysql_database', 'hive_existing_oracle_host', 'hive_existing_oracle_database', 'hive_existing_postgresql_host', 'hive_existing_postgresql_database', 'hive_existing_mssql_server_database', 'hive_existing_mssql_server_host', 'hive_existing_mssql_server_2_database', 'hive_existing_mssql_server_2_host'];
+          var ambariHost = configs.findProperty('name', 'oozie_ambari_host');
+          if (ambariHost) {
+            ambariHost.name = 'oozie_hostname';
+          }
+          configsToRemove = ['oozie_existing_mysql_host', 'oozie_existing_mysql_database', 'oozie_existing_oracle_host', 'oozie_existing_oracle_database', 'oozie_derby_database', 'oozie_existing_postgresql_host', 'oozie_existing_postgresql_database', 'oozie_existing_mssql_server_database', 'oozie_existing_mssql_server_host', 'oozie_existing_mssql_server_2_database', 'oozie_existing_mssql_server_2_host'];
           break;
         case 'Existing MySQL Database':
-          dbHostPropertyName = configs.someProperty('name', 'hive_existing_mysql_host') ? 'hive_existing_mysql_host' : dbHostPropertyName;
-          configsToRemove = ['hive_ambari_database', 'hive_existing_oracle_host', 'hive_existing_oracle_database', 'hive_existing_postgresql_host', 'hive_existing_postgresql_database', 'hive_existing_mssql_server_database', 'hive_existing_mssql_server_host', 'hive_existing_mssql_server_2_database', 'hive_existing_mssql_server_2_host'];
+          dbHostPropertyName = configs.someProperty('name', 'oozie_existing_mysql_host') ? 'oozie_existing_mysql_host' : dbHostPropertyName;
+          configsToRemove = ['oozie_ambari_database', 'oozie_existing_oracle_host', 'oozie_existing_oracle_database', 'oozie_derby_database', 'oozie_existing_postgresql_host', 'oozie_existing_postgresql_database', 'oozie_existing_mssql_server_database', 'oozie_existing_mssql_server_host', 'oozie_existing_mssql_server_2_database', 'oozie_existing_mssql_server_2_host'];
           break;
         case 'Existing PostgreSQL Database':
-          dbHostPropertyName = configs.someProperty('name', 'hive_existing_postgresql_host') ? 'hive_existing_postgresql_host' : dbHostPropertyName;
-          configsToRemove = ['hive_ambari_database', 'hive_existing_mysql_host', 'hive_existing_mysql_database', 'hive_existing_oracle_host', 'hive_existing_oracle_database', 'hive_existing_mssql_server_database', 'hive_existing_mssql_server_host', 'hive_existing_mssql_server_2_database', 'hive_existing_mssql_server_2_host'];
+          dbHostPropertyName = configs.someProperty('name', 'oozie_existing_postgresql_host') ? 'oozie_existing_postgresql_host' : dbHostPropertyName;
+          configsToRemove = ['oozie_ambari_database', 'oozie_existing_mysql_host', 'oozie_existing_mysql_database', 'oozie_existing_oracle_host', 'oozie_existing_oracle_database', 'oozie_existing_mssql_server_database', 'oozie_existing_mssql_server_host', 'oozie_existing_mssql_server_2_database', 'oozie_existing_mssql_server_2_host'];
           break;
         case 'Existing Oracle Database':
-          dbHostPropertyName = configs.someProperty('name', 'hive_existing_oracle_host') ? 'hive_existing_oracle_host' : dbHostPropertyName;
-          configsToRemove = ['hive_ambari_database', 'hive_existing_mysql_host', 'hive_existing_mysql_database', 'hive_existing_postgresql_host', 'hive_existing_postgresql_database', 'hive_existing_mssql_server_database', 'hive_existing_mssql_server_host', 'hive_existing_mssql_server_2_database', 'hive_existing_mssql_server_2_host'];
+          dbHostPropertyName = configs.someProperty('name', 'oozie_existing_oracle_host') ? 'oozie_existing_oracle_host' : dbHostPropertyName;
+          configsToRemove = ['oozie_ambari_database', 'oozie_existing_mysql_host', 'oozie_existing_mysql_database', 'oozie_derby_database', 'oozie_existing_mssql_server_database', 'oozie_existing_mssql_server_host', 'oozie_existing_mssql_server_2_database', 'oozie_existing_mssql_server_2_host'];
           break;
         case 'Existing MSSQL Server database with SQL authentication':
-          dbHostPropertyName = configs.someProperty('name', 'hive_existing_mssql_server_host') ? 'hive_existing_mssql_server_host' : dbHostPropertyName;
-          configsToRemove = ['hive_ambari_database', 'hive_existing_mysql_host', 'hive_existing_mysql_database', 'hive_existing_postgresql_host', 'hive_existing_postgresql_database', 'hive_existing_oracle_host', 'hive_existing_oracle_database', 'hive_existing_mssql_server_2_database', 'hive_existing_mssql_server_2_host'];
+          dbHostPropertyName = configs.someProperty('name', 'oozie_existing_mssql_server_host') ? 'oozie_existing_mssql_server_host' : dbHostPropertyName;
+          configsToRemove = ['oozie_ambari_database', 'oozie_existing_oracle_host', 'oozie_existing_oracle_database', 'oozie_derby_database', 'oozie_existing_postgresql_host', 'oozie_existing_postgresql_database', 'oozie_existing_mysql_host', 'oozie_existing_mysql_database', 'oozie_existing_mssql_server_2_database', 'oozie_existing_mssql_server_2_host'];
           break;
         case 'Existing MSSQL Server database with integrated authentication':
-          dbHostPropertyName = configs.someProperty('name', 'hive_existing_mssql_server_2_host') ? 'hive_existing_mssql_server_2_host' : dbHostPropertyName;
-          configsToRemove = ['hive_ambari_database', 'hive_existing_mysql_host', 'hive_existing_mysql_database', 'hive_existing_postgresql_host', 'hive_existing_postgresql_database', 'hive_existing_oracle_host', 'hive_existing_oracle_database', 'hive_existing_mssql_server_database', 'hive_existing_mssql_server_host'];
+          dbHostPropertyName = configs.someProperty('name', 'oozie_existing_mssql_server_2_host') ? 'oozie_existing_mssql_server_2_host' : dbHostPropertyName;
+          configsToRemove = ['oozie_ambari_database', 'oozie_existing_oracle_host', 'oozie_existing_oracle_database', 'oozie_derby_database', 'oozie_existing_postgresql_host', 'oozie_existing_postgresql_database', 'oozie_existing_mysql_host', 'oozie_existing_mysql_database', 'oozie_existing_mssql_server_database', 'oozie_existing_mssql_server_host'];
           break;
       }
       configs = dataManipulationUtils.rejectPropertyValues(configs, 'name', configsToRemove);
     }
-    if (dbHostPropertyName) {
-      var hiveHostNameProperty = App.ServiceConfigProperty.create(App.config.get('preDefinedSiteProperties').findProperty('name', 'hive_hostname'));
-      hiveHostNameProperty.set('value', configs.findProperty('name', dbHostPropertyName).get('value'));
-      configs.pushObject(hiveHostNameProperty);
-    }
-    return configs;
-  },
-
-  /**
-   * set oozie hostnames in configs
-   * @param configs
-   * @private
-   * @method setOozieHostName
-   */
-  setOozieHostName: function (configs) {
-    var dbHostPropertyName = null, configsToRemove = [];
-    if (configs.someProperty('name', 'oozie_database')) {
-      var oozieDb = configs.findProperty('name', 'oozie_database');
-      switch (oozieDb.value) {
-        case 'New Derby Database':
-          configsToRemove = ['oozie_ambari_database', 'oozie_existing_mysql_host', 'oozie_existing_mysql_database', 'oozie_existing_oracle_host', 'oozie_existing_oracle_database', 'oozie_existing_postgresql_host', 'oozie_existing_postgresql_database', 'oozie_existing_mssql_server_database', 'oozie_existing_mssql_server_host', 'oozie_existing_mssql_server_2_database', 'oozie_existing_mssql_server_2_host'];
-          break;
-        case 'New MySQL Database':
-          var ambariHost = configs.findProperty('name', 'oozie_ambari_host');
-          if (ambariHost) {
-            ambariHost.name = 'oozie_hostname';
-          }
-          configsToRemove = ['oozie_existing_mysql_host', 'oozie_existing_mysql_database', 'oozie_existing_oracle_host', 'oozie_existing_oracle_database', 'oozie_derby_database', 'oozie_existing_postgresql_host', 'oozie_existing_postgresql_database', 'oozie_existing_mssql_server_database', 'oozie_existing_mssql_server_host', 'oozie_existing_mssql_server_2_database', 'oozie_existing_mssql_server_2_host'];
-          break;
-        case 'Existing MySQL Database':
-          dbHostPropertyName = configs.someProperty('name', 'oozie_existing_mysql_host') ? 'oozie_existing_mysql_host' : dbHostPropertyName;
-          configsToRemove = ['oozie_ambari_database', 'oozie_existing_oracle_host', 'oozie_existing_oracle_database', 'oozie_derby_database', 'oozie_existing_postgresql_host', 'oozie_existing_postgresql_database', 'oozie_existing_mssql_server_database', 'oozie_existing_mssql_server_host', 'oozie_existing_mssql_server_2_database', 'oozie_existing_mssql_server_2_host'];
-          break;
-        case 'Existing PostgreSQL Database':
-          dbHostPropertyName = configs.someProperty('name', 'oozie_existing_postgresql_host') ? 'oozie_existing_postgresql_host' : dbHostPropertyName;
-          configsToRemove = ['oozie_ambari_database', 'oozie_existing_mysql_host', 'oozie_existing_mysql_database', 'oozie_existing_oracle_host', 'oozie_existing_oracle_database', 'oozie_existing_mssql_server_database', 'oozie_existing_mssql_server_host', 'oozie_existing_mssql_server_2_database', 'oozie_existing_mssql_server_2_host'];
-          break;
-        case 'Existing Oracle Database':
-          dbHostPropertyName = configs.someProperty('name', 'oozie_existing_oracle_host') ? 'oozie_existing_oracle_host' : dbHostPropertyName;
-          configsToRemove = ['oozie_ambari_database', 'oozie_existing_mysql_host', 'oozie_existing_mysql_database', 'oozie_derby_database', 'oozie_existing_mssql_server_database', 'oozie_existing_mssql_server_host', 'oozie_existing_mssql_server_2_database', 'oozie_existing_mssql_server_2_host'];
-          break;
-        case 'Existing MSSQL Server database with SQL authentication':
-          dbHostPropertyName = configs.someProperty('name', 'oozie_existing_mssql_server_host') ? 'oozie_existing_mssql_server_host' : dbHostPropertyName;
-          configsToRemove = ['oozie_ambari_database', 'oozie_existing_oracle_host', 'oozie_existing_oracle_database', 'oozie_derby_database', 'oozie_existing_postgresql_host', 'oozie_existing_postgresql_database', 'oozie_existing_mysql_host', 'oozie_existing_mysql_database', 'oozie_existing_mssql_server_2_database', 'oozie_existing_mssql_server_2_host'];
-          break;
-        case 'Existing MSSQL Server database with integrated authentication':
-          dbHostPropertyName = configs.someProperty('name', 'oozie_existing_mssql_server_2_host') ? 'oozie_existing_mssql_server_2_host' : dbHostPropertyName;
-          configsToRemove = ['oozie_ambari_database', 'oozie_existing_oracle_host', 'oozie_existing_oracle_database', 'oozie_derby_database', 'oozie_existing_postgresql_host', 'oozie_existing_postgresql_database', 'oozie_existing_mysql_host', 'oozie_existing_mysql_database', 'oozie_existing_mssql_server_database', 'oozie_existing_mssql_server_host'];
-          break;
-      }
-      configs = dataManipulationUtils.rejectPropertyValues(configs, 'name', configsToRemove);
-    }
-
+
     if (dbHostPropertyName) {
       var oozieHostNameProperty = App.ServiceConfigProperty.create(App.config.get('preDefinedSiteProperties').findProperty('name', 'oozie_hostname'));
       oozieHostNameProperty.set('value', configs.findProperty('name', dbHostPropertyName).get('value'));
@@ -639,35 +437,7 @@ App.ConfigsSaverMixin = Em.Mixin.create({
     return configs;
   },
 
-  /**
-   * save site configs
-   * @param configs
-   * @private
-   * @method saveSiteConfigs
-   */
-  saveSiteConfigs: function (configs) {
-    //storedConfigs contains custom configs as well
-    configs = this.setHiveHostName(configs);
-    configs = this.setOozieHostName(configs);
-    this.formatConfigValues(configs);
-    var mappedConfigs = App.config.excludeUnsupportedConfigs(this.get('configMapping').all(), App.Service.find().mapProperty('serviceName'));
-    var allUiConfigs = this.loadUiSideConfigs(mappedConfigs);
-    this.set('uiConfigs', configs.concat(allUiConfigs));
-  },
-
-  /**
-   * Reprecent boolean value as string (true => 'true', false => 'false') and trim other values
-   * @param serviceConfigProperties
-   * @private
-   * @method formatConfigValues
-   */
-  formatConfigValues: function (serviceConfigProperties) {
-    serviceConfigProperties.forEach(function (_config) {
-      if (typeof _config.get('value') === "boolean") _config.set('value', _config.value.toString());
-      _config.set('value', App.config.trimProperty(_config, true));
-    });
-  },
-
+  /*********************************** 2.2 ADD DYNAMIC CONFIGS ********************************/
   /**
    * return configs from the UI side
    * @param configMapping array with configs
@@ -780,100 +550,506 @@ App.ConfigsSaverMixin = Em.Mixin.create({
     return valueWithOverrides;
   },
 
+  /*********************************** 3. GENERATING JSON TO SAVE *****************************/
+
   /**
-   * Saves cluster level configurations for all necessary sites
-   * PUT calls are made to /api/v1/clusters/clusterName for each site
-   * @private
-   * @method doPUTClusterConfigurations
+   * generating common JSON object for desired configs
+   * @param configsToSave
+   * @param fileNamesToSave
+   * @param serviceConfigNote
+   * @param {boolean} [isNotDefaultGroup=false]
+   * @returns {Array}
    */
-  doPUTClusterConfigurations: function () {
-    this.set('saveConfigsFlag', true);
-    var serviceConfigTags = this.get('serviceConfigTags');
-    /**
-     * adding config tags for dependentConfigs
-     */
-    for (var i = 0; i < this.get('dependentFileNames.length'); i++) {
-      if (!serviceConfigTags.findProperty('siteName', this.get('dependentFileNames')[i])) {
-        serviceConfigTags.pushObject({siteName: this.get('dependentFileNames')[i]});
-      }
+  generateDesiredConfigsJSON: function(configsToSave, fileNamesToSave, serviceConfigNote, isNotDefaultGroup) {
+    var desired_config = [];
+    if (Em.isArray(configsToSave) && Em.isArray(fileNamesToSave) && fileNamesToSave.length && configsToSave.length) {
+      serviceConfigNote = serviceConfigNote || "";
+      var tagVersion = "version" + (new Date).getTime();
+
+      fileNamesToSave.forEach(function(fName) {
+        if (this.allowSaveSite(fName)) {
+          var properties = configsToSave.filterProperty('filename', fName);
+          var type = App.config.getConfigTagFromFileName(fName);
+          desired_config.push(this.createDesiredConfig(type, tagVersion, properties, serviceConfigNote, isNotDefaultGroup));
+        }
+      }, this);
+    }
+    return desired_config;
+  },
+
+  /**
+   * for some file names we have a restriction
+   * and can't save them, in this this method will return false
+   * @param fName
+   * @returns {boolean}
+   */
+  allowSaveSite: function(fName) {
+    switch (fName) {
+      case 'mapred-queue-acls.xml':
+        return false;
+      case 'core-site.xml':
+        return ['HDFS', 'GLUSTERFS'].contains(this.get('content.serviceName'));
+      default :
+        return true;
+    }
+  },
+
+  /**
+   * generating common JSON object for desired config
+   * @param {string} type - file name without '.xml'
+   * @param {string} tagVersion - version + timestamp
+   * @param {App.ConfigProperty[]} properties - array of properties from model
+   * @param {string} serviceConfigNote
+   * @param {boolean} [isNotDefaultGroup=false]
+   * @returns {{type: string, tag: string, properties: {}, properties_attributes: {}|undefined, service_config_version_note: string|undefined}}
+   */
+  createDesiredConfig: function(type, tagVersion, properties, serviceConfigNote, isNotDefaultGroup) {
+    Em.assert('type and tagVersion should be defined', type && tagVersion);
+    var desired_config = {
+      "type": type,
+      "tag": tagVersion,
+      "properties": {}
+    };
+    if (!isNotDefaultGroup) {
+      desired_config.service_config_version_note = serviceConfigNote || "";
+    }
+    var attributes = { final: {} };
+    if (Em.isArray(properties)) {
+      properties.forEach(function(property) {
+
+        if (property.get('isRequiredByAgent')) {
+          desired_config.properties[property.get('name')] = this.formatValueBeforeSave(property);
+          /**
+           * add is final value
+           */
+          if (property.get('isFinal')) {
+            attributes.final[property.get('name')] = "true";
+          }
+        }
+      }, this);
+    }
+
+    if (Object.keys(attributes.final).length) {
+      desired_config.properties_attributes = attributes;
+    }
+    return desired_config;
+  },
+
+  /**
+   * format value before save performs some changing of values
+   * according to the rules that includes heapsizeException trimming and some custom rules
+   * @param {App.ConfigProperty} property
+   * @returns {string}
+   */
+  formatValueBeforeSave: function(property) {
+    var name = property.get('name');
+    var value = property.get('value');
+    //TODO check for core-site
+    if (this.get('heapsizeRegExp').test(name) && !this.get('heapsizeException').contains(name) && !(value).endsWith("m")) {
+      return value += "m";
+    }
+    if (typeof property.get('value') === "boolean") {
+      return property.get('value').toString();
+    }
+    switch (name) {
+      case 'storm.zookeeper.servers':
+        if (Object.prototype.toString.call(value) === '[object Array]' ) {
+          return JSON.stringify(value).replace(/"/g, "'");
+        } else {
+          return value;
+        }
+        break;
+      default:
+        return App.config.trimProperty(property, true);
     }
-    this.setNewTagNames(serviceConfigTags);
-    var siteNameToServerDataMap = {};
-    var configsToSave = [];
-    serviceConfigTags.forEach(function (_serviceTags) {
-      var configs = this.createConfigObject(_serviceTags.siteName, _serviceTags.newTagName);
-      if (configs) {
-        configsToSave.push(configs);
-        siteNameToServerDataMap[_serviceTags.siteName] = configs;
+  },
+
+  /*********************************** 4. AJAX REQUESTS **************************************/
+
+  /**
+   * save config group
+   * @param overridenConfigs
+   * @param selectedConfigGroup
+   * @param showPopup
+   */
+  saveGroup: function(overridenConfigs, selectedConfigGroup, showPopup) {
+    var groupHosts = [];
+    var fileNamesToSave = overridenConfigs.mapProperty('filename');
+    selectedConfigGroup.get('hosts').forEach(function (hostName) {
+      groupHosts.push({"host_name": hostName});
+    });
+    this.putConfigGroupChanges({
+      ConfigGroup: {
+        "id": selectedConfigGroup.get('id'),
+        "cluster_name": App.get('clusterName'),
+        "group_name": selectedConfigGroup.get('name'),
+        "tag": selectedConfigGroup.get('service.id'),
+        "description": selectedConfigGroup.get('description'),
+        "hosts": groupHosts,
+        "service_config_version_note": this.get('serviceConfigVersionNote'),
+        "desired_configs": this.generateDesiredConfigsJSON(overridenConfigs, fileNamesToSave, null, true)
       }
-    }, this);
-    configsToSave = this.filterChangedConfiguration(configsToSave);
-    if (configsToSave.length > 0) {
-      var data = [];
-      data.pushObject(JSON.stringify({
-        Clusters: {
-          desired_config: configsToSave
+    }, showPopup);
+  },
+
+  /**
+   * persist properties of config groups to server
+   * show result popup if <code>showPopup</code> is true
+   * @param data {Object}
+   * @param showPopup {Boolean}
+   * @method putConfigGroupChanges
+   */
+  putConfigGroupChanges: function (data, showPopup) {
+    var ajaxOptions = {
+      name: 'config_groups.update_config_group',
+      sender: this,
+      data: {
+        id: data.ConfigGroup.id,
+        configGroup: data
+      }
+    };
+    if (showPopup) {
+      ajaxOptions.success = "putConfigGroupChangesSuccess";
+    }
+    return App.ajax.send(ajaxOptions);
+  },
+
+  /**
+   * Saves configuration of set of sites. The provided data
+   * contains the site name and tag to be used.
+   * @param {Object[]} services
+   * @param {boolean} showPopup
+   * @return {$.ajax}
+   * @method putChangedConfigurations
+   */
+  putChangedConfigurations: function (services, showPopup) {
+    var ajaxData = {
+      name: 'common.across.services.configurations',
+      sender: this,
+      data: {
+        data: '[' + services.toString() + ']'
+      },
+      error: 'doPUTClusterConfigurationSiteErrorCallback'
+    };
+    if (showPopup) {
+      ajaxData.success = 'doPUTClusterConfigurationSiteSuccessCallback'
+    }
+    return App.ajax.send(ajaxData);
+  },
+
+  /*********************************** 5. AFTER SAVE INFO ************************************/
+
+  /**
+   * @private
+   * @method putConfigGroupChangesSuccess
+   */
+  putConfigGroupChangesSuccess: function () {
+    this.set('saveConfigsFlag', true);
+    this.onDoPUTClusterConfigurations();
+  },
+
+  /**
+   * @private
+   * @method doPUTClusterConfigurationSiteSuccessCallback
+   */
+  doPUTClusterConfigurationSiteSuccessCallback: function () {
+    this.onDoPUTClusterConfigurations();
+  },
+
+  /**
+   * @private
+   * @method doPUTClusterConfigurationSiteErrorCallback
+   */
+  doPUTClusterConfigurationSiteErrorCallback: function () {
+    this.set('saveConfigsFlag', false);
+    this.doPUTClusterConfigurationSiteSuccessCallback();
+  },
+
+  /**
+   * On save configs handler. Open save configs popup with appropriate message
+   * @private
+   * @method onDoPUTClusterConfigurations
+   */
+  onDoPUTClusterConfigurations: function () {
+    var header, message, messageClass, value, status = 'unknown', urlParams = '',
+      result = {
+        flag: this.get('saveConfigsFlag'),
+        message: null,
+        value: null
+      },
+      extendedModel = App.Service.extendedModel[this.get('content.serviceName')],
+      currentService = extendedModel ? App[extendedModel].find(this.get('content.serviceName')) : App.Service.find(this.get('content.serviceName'));
+
+    if (!result.flag) {
+      result.message = Em.I18n.t('services.service.config.failSaveConfig');
+    }
+
+    App.router.get('clusterController').updateClusterData();
+    App.router.get('updateController').updateComponentConfig(function () {
+    });
+    var flag = result.flag;
+    if (result.flag === true) {
+      header = Em.I18n.t('services.service.config.saved');
+      message = Em.I18n.t('services.service.config.saved.message');
+      messageClass = 'alert alert-success';
+      // warn the user if any of the components are in UNKNOWN state
+      urlParams += ',ServiceComponentInfo/installed_count,ServiceComponentInfo/total_count';
+      if (this.get('content.serviceName') === 'HDFS') {
+        urlParams += '&ServiceComponentInfo/service_name.in(HDFS)'
+      }
+    } else {
+      header = Em.I18n.t('common.failure');
+      message = result.message;
+      messageClass = 'alert alert-error';
+      value = result.value;
+    }
+    if(currentService){
+      App.QuickViewLinks.proto().set('content', currentService);
+      App.QuickViewLinks.proto().loadTags();
+    }
+    this.showSaveConfigsPopup(header, flag, message, messageClass, value, status, urlParams);
+  },
+
+  /**
+   * Show save configs popup
+   * @return {App.ModalPopup}
+   * @private
+   * @method showSaveConfigsPopup
+   */
+  showSaveConfigsPopup: function (header, flag, message, messageClass, value, status, urlParams) {
+    var self = this;
+    if (flag) {
+      this.set('forceTransition', flag);
+      self.loadStep();
+    }
+    return App.ModalPopup.show({
+      header: header,
+      primary: Em.I18n.t('ok'),
+      secondary: null,
+      onPrimary: function () {
+        this.hide();
+        if (!flag) {
+          self.completeSave();
+        }
+      },
+      onClose: function () {
+        this.hide();
+        self.completeSave();
+      },
+      disablePrimary: true,
+      bodyClass: Ember.View.extend({
+        flag: flag,
+        message: function () {
+          return this.get('isLoaded') ? message : Em.I18n.t('services.service.config.saving.message');
+        }.property('isLoaded'),
+        messageClass: function () {
+          return this.get('isLoaded') ? messageClass : 'alert alert-info';
+        }.property('isLoaded'),
+        setDisablePrimary: function () {
+          this.get('parentView').set('disablePrimary', !this.get('isLoaded'));
+        }.observes('isLoaded'),
+        runningHosts: [],
+        runningComponentCount: 0,
+        unknownHosts: [],
+        unknownComponentCount: 0,
+        siteProperties: value,
+        isLoaded: false,
+        componentsFilterSuccessCallback: function (response) {
+          var count = 0,
+            view = this,
+            lazyLoadHosts = function (dest) {
+              lazyLoading.run({
+                initSize: 20,
+                chunkSize: 50,
+                delay: 50,
+                destination: dest,
+                source: hosts,
+                context: view
+              });
+            },
+            /**
+             * Map components for their hosts
+             * Return format:
+             * <code>
+             *   {
+             *    host1: [component1, component2, ...],
+             *    host2: [component3, component4, ...]
+             *   }
+             * </code>
+             * @return {object}
+             */
+              setComponents = function (item, components) {
+              item.host_components.forEach(function (c) {
+                var name = c.HostRoles.host_name;
+                if (!components[name]) {
+                  components[name] = [];
+                }
+                components[name].push(App.format.role(item.ServiceComponentInfo.component_name));
+              });
+              return components;
+            },
+            /**
+             * Map result of <code>setComponents</code> to array
+             * @return {{name: string, components: string}[]}
+             */
+              setHosts = function (components) {
+              var hosts = [];
+              Em.keys(components).forEach(function (key) {
+                hosts.push({
+                  name: key,
+                  components: components[key].join(', ')
+                });
+              });
+              return hosts;
+            },
+            components = {},
+            hosts = [];
+          switch (status) {
+            case 'unknown':
+              response.items.filter(function (item) {
+                return (item.ServiceComponentInfo.total_count > item.ServiceComponentInfo.started_count + item.ServiceComponentInfo.installed_count);
+              }).forEach(function (item) {
+                var total = item.ServiceComponentInfo.total_count,
+                  started = item.ServiceComponentInfo.started_count,
+                  installed = item.ServiceComponentInfo.installed_count,
+                  unknown = total - started + installed;
+                components = setComponents(item, components);
+                count += unknown;
+              });
+              hosts = setHosts(components);
+              this.set('unknownComponentCount', count);
+              lazyLoadHosts(this.get('unknownHosts'));
+              break;
+            case 'started':
+              response.items.filterProperty('ServiceComponentInfo.started_count').forEach(function (item) {
+                var started = item.ServiceComponentInfo.started_count;
+                components = setComponents(item, components);
+                count += started;
+                hosts = setHosts(components);
+              });
+              this.set('runningComponentCount', count);
+              lazyLoadHosts(this.get('runningHosts'));
+              break;
+          }
+        },
+        componentsFilterErrorCallback: function () {
+          this.set('isLoaded', true);
+        },
+        didInsertElement: function () {
+          return App.ajax.send({
+            name: 'components.filter_by_status',
+            sender: this,
+            data: {
+              clusterName: App.get('clusterName'),
+              urlParams: urlParams
+            },
+            success: 'componentsFilterSuccessCallback',
+            error: 'componentsFilterErrorCallback'
+          });
+        },
+        getDisplayMessage: function () {
+          var displayMsg = [];
+          var siteProperties = this.get('siteProperties');
+          if (siteProperties) {
+            siteProperties.forEach(function (_siteProperty) {
+              var displayProperty = _siteProperty.siteProperty;
+              var displayNames = _siteProperty.displayNames;
+
+              if (displayNames && displayNames.length) {
+                if (displayNames.length === 1) {
+                  displayMsg.push(displayProperty + Em.I18n.t('as') + displayNames[0]);
+                } else {
+                  var name;
+                  displayNames.forEach(function (_name, index) {
+                    if (index === 0) {
+                      name = _name;
+                    } else if (index === siteProperties.length - 1) {
+                      name = name + Em.I18n.t('and') + _name;
+                    } else {
+                      name = name + ', ' + _name;
+                    }
+                  }, this);
+                  displayMsg.push(displayProperty + Em.I18n.t('as') + name);
+
+                }
+              } else {
+                displayMsg.push(displayProperty);
+              }
+            }, this);
+          }
+          return displayMsg;
+
+        }.property('siteProperties'),
+
+        runningHostsMessage: function () {
+          return Em.I18n.t('services.service.config.stopService.runningHostComponents').format(this.get('runningComponentCount'), this.get('runningHosts.length'));
+        }.property('runningComponentCount', 'runningHosts.length'),
+
+        unknownHostsMessage: function () {
+          return Em.I18n.t('services.service.config.stopService.unknownHostComponents').format(this.get('unknownComponentCount'), this.get('unknownHosts.length'));
+        }.property('unknownComponentCount', 'unknownHosts.length'),
+
+        templateName: require('templates/main/service/info/configs_save_popup')
+      })
+    })
+  },
+
+  /*********************************** 6. ADDITIONAL *******************************************/
+
+  /**
+   * If some configs are changed and user navigates away or select another config-group, show this popup with propose to save changes
+   * @param {String} path
+   * @param {object} callback - callback with action to change configs view(change group or version)
+   * @return {App.ModalPopup}
+   * @method showSavePopup
+   */
+  showSavePopup: function (path, callback) {
+    var self = this;
+    return App.ModalPopup.show({
+      header: Em.I18n.t('common.warning'),
+      bodyClass: Em.View.extend({
+        templateName: require('templates/common/configs/save_configuration'),
+        showSaveWarning: true,
+        notesArea: Em.TextArea.extend({
+          classNames: ['full-width'],
+          placeholder: Em.I18n.t('dashboard.configHistory.info-bar.save.popup.placeholder'),
+          onChangeValue: function() {
+            this.get('parentView.parentView').set('serviceConfigNote', this.get('value'));
+          }.observes('value')
+        })
+      }),
+      footerClass: Ember.View.extend({
+        templateName: require('templates/main/service/info/save_popup_footer')
+      }),
+      primary: Em.I18n.t('common.save'),
+      secondary: Em.I18n.t('common.cancel'),
+      onSave: function () {
+        self.set('serviceConfigVersionNote', this.get('serviceConfigNote'));
+        self.saveStepConfigs();
+        this.hide();
+      },
+      onDiscard: function () {
+        self.set('preSelectedConfigVersion', null);
+        if (path) {
+          self.set('forceTransition', true);
+          App.router.route(path);
+        } else if (callback) {
+          // Prevent multiple popups
+          self.set('hash', self.getHash());
+          callback();
         }
-      }));
-      if (App.get('supports.enhancedConfigs')) {
-        /**
-         * adding configs that were changed for dependent services
-         * if there are such configs
-         */
-        this.get('dependentServiceNames').forEach(function(serviceName) {
-
-          var serviceConfigs = this.get('stepConfigs').findProperty('serviceName', serviceName).get('configs');
-
-          var modifiedConfigs = this.getModifiedConfigs(serviceConfigs);
-
-          var fileNamesToSave = modifiedConfigs.mapProperty('filename').uniq();
-
-          var dependentConfigsToSave = this.generateDesiredConfigsJSON(modifiedConfigs, fileNamesToSave, this.get('serviceConfigNote'));
-          if (dependentConfigsToSave.length > 0) {
-            data.pushObject(JSON.stringify({
-              Clusters: {
-                desired_config: dependentConfigsToSave
-              }
-            }));
-          }
-        }, this);
+        this.hide();
+      },
+      onCancel: function () {
+        this.hide();
       }
-      this.doPUTClusterConfigurationSites(data, true);
-    } else {
-      this.onDoPUTClusterConfigurations();
-    }
+    });
   },
 
   /**
-   * create different config object depending on siteName
-   * @param {String} siteName
-   * @param {String} tagName
-   * @returns {Object|null}
-   * @private
-   * @method createConfigObject
+   * TODO the methods below are not used as the logic was changed
+   * check and delete if this methods is not required
    */
-  createConfigObject: function (siteName, tagName) {
-    console.log("TRACE: Inside " + siteName);
-    var configObject = {};
-    switch (siteName) {
-      case 'core-site':
-        if (this.get('content.serviceName') === 'HDFS' || this.get('content.serviceName') === 'GLUSTERFS') {
-          configObject = this.createCoreSiteObj(tagName);
-        } else {
-          return null;
-        }
-        break;
-      default:
-        var filename = App.config.getOriginalFileName(siteName);
-        if (filename === 'mapred-queue-acls.xml') {
-          return null;
-        }
-        configObject = this.createSiteObj(siteName, tagName, this.get('uiConfigs').filterProperty('filename', filename));
-        break;
-    }
-    configObject.service_config_version_note = this.get('serviceConfigVersionNote');
-    return configObject;
-  },
 
   /**
    * filter out unchanged configurations
@@ -988,59 +1164,6 @@ App.ConfigsSaverMixin = Em.Mixin.create({
   },
 
   /**
-   * Saves configuration of set of sites. The provided data
-   * contains the site name and tag to be used.
-   * @param {Object[]} services
-   * @param {boolean} showPopup
-   * @return {$.ajax}
-   * @method doPUTClusterConfigurationSites
-   */
-  doPUTClusterConfigurationSites: function (services, showPopup) {
-    var ajaxData = {
-      name: 'common.across.services.configurations',
-      sender: this,
-      data: {
-        data: '[' + services.toString() + ']'
-      },
-      error: 'doPUTClusterConfigurationSiteErrorCallback'
-    };
-    if (showPopup) {
-      ajaxData.success = 'doPUTClusterConfigurationSiteSuccessCallback'
-    }
-    return App.ajax.send(ajaxData);
-  },
-
-  /**
-   * @private
-   * @method doPUTClusterConfigurationSiteSuccessCallback
-   */
-  doPUTClusterConfigurationSiteSuccessCallback: function () {
-    this.onDoPUTClusterConfigurations();
-  },
-
-  /**
-   * @private
-   * @method doPUTClusterConfigurationSiteErrorCallback
-   */
-  doPUTClusterConfigurationSiteErrorCallback: function () {
-    this.set('saveConfigsFlag', false);
-    this.doPUTClusterConfigurationSiteSuccessCallback();
-  },
-
-  /**
-   * add newTagName property to each config in serviceConfigs
-   * @param serviceConfigs
-   * @private
-   * @method setNewTagNames
-   */
-  setNewTagNames: function (serviceConfigs) {
-    var time = (new Date).getTime();
-    serviceConfigs.forEach(function (_serviceConfigs) {
-      _serviceConfigs.newTagName = 'version' + time;
-    }, this);
-  },
-
-  /**
    * Save "final" attribute for properties
    * @param {Array} properties - array of properties
    * @returns {Object|null}
@@ -1065,27 +1188,6 @@ App.ConfigsSaverMixin = Em.Mixin.create({
   },
 
   /**
-   * create core site object
-   * @param tagName
-   * @return {{type: string, tag: string, properties: object}}
-   * @method createCoreSiteObj
-   */
-  createCoreSiteObj: function (tagName) {
-    var coreSiteObj = this.get('uiConfigs').filterProperty('filename', 'core-site.xml');
-    var coreSiteProperties = {};
-    coreSiteObj.forEach(function (_coreSiteObj) {
-      coreSiteProperties[_coreSiteObj.name] = _coreSiteObj.value;
-      //this.recordHostOverride(_coreSiteObj, 'core-site', tagName, this);
-    }, this);
-    var result = {"type": "core-site", "tag": tagName, "properties": coreSiteProperties};
-    var attributes = this.getConfigAttributes(coreSiteObj);
-    if (attributes) {
-      result['properties_attributes'] = attributes;
-    }
-    return result;
-  },
-
-  /**
    * create site object
    * @param {string} siteName
    * @param {string} tagName
@@ -1147,177 +1249,5 @@ App.ConfigsSaverMixin = Em.Mixin.create({
       default:
         return value;
     }
-  },
-
-  /**
-   * Are some unsaved changes available
-   * @returns {boolean}
-   * @method hasUnsavedChanges
-   */
-  hasUnsavedChanges: function () {
-    return this.get('hash') != this.getHash();
-  },
-
-  /**
-   * If some configs are changed and user navigates away or select another config-group, show this popup with propose to save changes
-   * @param {String} path
-   * @param {object} callback - callback with action to change configs view(change group or version)
-   * @return {App.ModalPopup}
-   * @method showSavePopup
-   */
-  showSavePopup: function (path, callback) {
-    var self = this;
-    return App.ModalPopup.show({
-      header: Em.I18n.t('common.warning'),
-      bodyClass: Em.View.extend({
-        templateName: require('templates/common/configs/save_configuration'),
-        showSaveWarning: true,
-        notesArea: Em.TextArea.extend({
-          classNames: ['full-width'],
-          placeholder: Em.I18n.t('dashboard.configHistory.info-bar.save.popup.placeholder'),
-          onChangeValue: function() {
-            this.get('parentView.parentView').set('serviceConfigNote', this.get('value'));
-          }.observes('value')
-        })
-      }),
-      footerClass: Ember.View.extend({
-        templateName: require('templates/main/service/info/save_popup_footer')
-      }),
-      primary: Em.I18n.t('common.save'),
-      secondary: Em.I18n.t('common.cancel'),
-      onSave: function () {
-        self.set('serviceConfigVersionNote', this.get('serviceConfigNote'));
-        self.saveStepConfigs();
-        this.hide();
-      },
-      onDiscard: function () {
-        self.set('preSelectedConfigVersion', null);
-        if (path) {
-          self.set('forceTransition', true);
-          App.router.route(path);
-        } else if (callback) {
-          // Prevent multiple popups
-          self.set('hash', self.getHash());
-          callback();
-        }
-        this.hide();
-      },
-      onCancel: function () {
-        this.hide();
-      }
-    });
-  },
-  /********************************METHODS THAT GENERATES JSON TO SAVE *****************************************/
-
-  /**
-   * generating common JSON object for desired configs
-   * @param configsToSave
-   * @param fileNamesToSave
-   * @param serviceConfigNote
-   * @param {boolean} [isNotDefaultGroup=false]
-   * @returns {Array}
-   */
-  generateDesiredConfigsJSON: function(configsToSave, fileNamesToSave, serviceConfigNote, isNotDefaultGroup) {
-    var desired_config = [];
-    if (Em.isArray(configsToSave) && Em.isArray(fileNamesToSave) && fileNamesToSave.length && configsToSave.length) {
-      serviceConfigNote = serviceConfigNote || "";
-      var tagVersion = "version" + (new Date).getTime();
-
-      fileNamesToSave.forEach(function(fName) {
-        if (this.allowSaveSite(fName)) {
-          var properties = configsToSave.filterProperty('filename', fName);
-          var type = App.config.getConfigTagFromFileName(fName);
-          desired_config.push(this.createDesiredConfig(type, tagVersion, properties, serviceConfigNote, isNotDefaultGroup));
-        }
-      }, this);
-    }
-    return desired_config;
-  },
-
-  /**
-   * for some file names we have a restriction
-   * and can't save them, in this this method will return false
-   * @param fName
-   * @returns {boolean}
-   */
-  allowSaveSite: function(fName) {
-    switch (fName) {
-      case 'mapred-queue-acls.xml':
-        return false;
-      case 'core-site.xml':
-        return ['HDFS', 'GLUSTERFS'].contains(this.get('content.serviceName'));
-      default :
-        return true;
-    }
-  },
-
-  /**
-   * generating common JSON object for desired config
-   * @param {string} type - file name without '.xml'
-   * @param {string} tagVersion - version + timestamp
-   * @param {App.ConfigProperty[]} properties - array of properties from model
-   * @param {string} serviceConfigNote
-   * @param {boolean} [isNotDefaultGroup=false]
-   * @returns {{type: string, tag: string, properties: {}, properties_attributes: {}|undefined, service_config_version_note: string|undefined}}
-   */
-  createDesiredConfig: function(type, tagVersion, properties, serviceConfigNote, isNotDefaultGroup) {
-    Em.assert('type and tagVersion should be defined', type && tagVersion);
-    var desired_config = {
-      "type": type,
-      "tag": tagVersion,
-      "properties": {}
-    };
-    if (!isNotDefaultGroup) {
-      desired_config.service_config_version_note = serviceConfigNote || "";
-    }
-    var attributes = { final: {} };
-    if (Em.isArray(properties)) {
-      properties.forEach(function(property) {
-
-        if (property.get('isRequiredByAgent')) {
-          desired_config.properties[property.get('name')] = this.formatValueBeforeSave(property);
-          /**
-           * add is final value
-           */
-          if (property.get('isFinal')) {
-            attributes.final[property.get('name')] = "true";
-          }
-        }
-      }, this);
-    }
-
-    if (Object.keys(attributes.final).length) {
-      desired_config.properties_attributes = attributes;
-    }
-    return desired_config;
-  },
-
-  /**
-   * format value before save performs some changing of values
-   * according to the rules that includes heapsizeException trimming and some custom rules
-   * @param {App.ConfigProperty} property
-   * @returns {string}
-   */
-  formatValueBeforeSave: function(property) {
-    var name = property.get('name');
-    var value = property.get('value');
-    //TODO check for core-site
-    if (this.get('heapsizeRegExp').test(name) && !this.get('heapsizeException').contains(name) && !(value).endsWith("m")) {
-      return value += "m";
-    }
-    if (typeof property.get('value') === "boolean") {
-      return property.get('value').toString();
-    }
-    switch (name) {
-      case 'storm.zookeeper.servers':
-        if (Object.prototype.toString.call(value) === '[object Array]' ) {
-          return JSON.stringify(value).replace(/"/g, "'");
-        } else {
-          return value;
-        }
-        break;
-      default:
-        return App.config.trimProperty(property, true);
-    }
   }
 });
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/2d30cd57/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 4de93d5..c412762 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,10 +22,11 @@ var App = require('app');
  * Show confirmation popup
  * @param {[Object]} configs
  * @param {function} [callback=null]
+ * @param {function} [secondary=null]
  * we use this parameter to defer saving configs before we make some decisions.
  * @return {App.ModalPopup}
  */
-App.showDependentConfigsPopup = function (configs, callback) {
+App.showDependentConfigsPopup = function (configs, callback, secondary) {
   return App.ModalPopup.show({
     encodeBody: false,
     header: Em.I18n.t('popup.dependent.configs.header'),
@@ -51,6 +52,9 @@ App.showDependentConfigsPopup = function (configs, callback) {
       configs.forEach(function(c) {
         Em.set(c, 'saveRecommended', Em.get(c, 'saveRecommendedDefault'));
       });
+      if (secondary) {
+        secondary();
+      }
     }
   });
 };

http://git-wip-us.apache.org/repos/asf/ambari/blob/2d30cd57/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 36750e9..eabcb0f 100644
--- a/ambari-web/test/controllers/main/service/info/config_test.js
+++ b/ambari-web/test/controllers/main/service/info/config_test.js
@@ -377,120 +377,7 @@ describe("App.MainServiceInfoConfigsController", function () {
     });
   });
 
-  describe("#setServerConfigValue", function () {
-
-    it("parsing storm.zookeeper.servers property in non standart method", function () {
-      expect(mainServiceInfoConfigsController.setServerConfigValue("storm.zookeeper.servers", ["a", "b"])).to.equal('[\'a\',\'b\']');
-    });
-    it("parsing default properties", function () {
-      expect(mainServiceInfoConfigsController.setServerConfigValue("any.other.property", "value")).to.equal("value");
-    });
-  });
-
-  describe("#createSiteObj", function () {
-
-    var tests = [
-      {
-        siteName: "hdfs-site",
-        tagName: "version1",
-        siteObj: Em.A([
-          {
-            name: "property1",
-            value: "value1"
-          },
-          {
-            name: "property2",
-            value: "value2&lt;"
-          },
-          {
-            name: "property_heapsize",
-            value: "value3"
-          },
-          {
-            name: "property_permsize",
-            value: "value4m"
-          }
-        ]),
-        result: {
-          "type": "hdfs-site",
-          "tag": "version1",
-          "properties": {
-            "property1": "value1",
-            "property2": "value2&lt;",
-            "property_heapsize": "value3m",
-            "property_permsize": "value4m"
-          }
-        },
-        m: "default"
-      },
-      {
-        siteName: "falcon-startup.properties",
-        tagName: "version1",
-        siteObj: Em.A([
-          {
-            name: "property1",
-            value: "value1"
-          },
-          {
-            name: "property2",
-            value: "value2&lt;"
-          }
-        ]),
-        result: {
-          "type": "falcon-startup.properties",
-          "tag": "version1",
-          "properties": {
-            "property1": "value1",
-            "property2": "value2&lt;"
-          }
-        },
-        m: "for falcon-startup.properties"
-
-      }
-    ];
-    tests.forEach(function (t) {
-      it("create site object " + t.m, function () {
-        expect(mainServiceInfoConfigsController.createSiteObj(t.siteName, t.tagName, t.siteObj)).to.deep.eql(t.result)
-      });
-    });
-  });
-
-  describe("#createCoreSiteObj", function () {
-
-    var tests = [
-      {
-        tagName: "version1",
-        uiConfigs: Em.A([
-          Em.Object.create({
-            name: "property1",
-            value: "value1",
-            filename: "core-site.xml"
-          }),
-          Em.Object.create({
-            name: "property2",
-            value: "value2&lt;",
-            filename: "core-site.xml"
-          })
-        ]),
-        result: {
-          "type": "core-site",
-          "tag": "version1",
-          "properties": {
-            "property1": "value1",
-            "property2": "value2&lt;"
-          }
-        }
-      }
-    ];
-    tests.forEach(function (t) {
-      it("create core object", function () {
-        mainServiceInfoConfigsController.set("uiConfigs", t.uiConfigs);
-        expect(mainServiceInfoConfigsController.createCoreSiteObj(t.tagName)).to.deep.eql(t.result);
-      });
-    });
-  });
-
-  describe("#doPUTClusterConfigurationSites", function () {
+  describe("#putChangedConfigurations", function () {
       var sc = [
       Em.Object.create({
         configs: [
@@ -551,17 +438,17 @@ describe("App.MainServiceInfoConfigsController", function () {
     });
     it("ajax request to put cluster cfg", function () {
       mainServiceInfoConfigsController.set('stepConfigs', sc);
-      expect(mainServiceInfoConfigsController.doPUTClusterConfigurationSites([]));
+      expect(mainServiceInfoConfigsController.putChangedConfigurations([]));
       expect(App.ajax.send.calledOnce).to.be.true;
     });
     it('values should be parsed', function () {
       mainServiceInfoConfigsController.set('stepConfigs', sc);
-      mainServiceInfoConfigsController.doPUTClusterConfigurationSites([]);
+      mainServiceInfoConfigsController.putChangedConfigurations([]);
       expect(mainServiceInfoConfigsController.get('stepConfigs')[0].get('configs').mapProperty('value').uniq()).to.eql(['1024m']);
     });
     it('values should not be parsed', function () {
       mainServiceInfoConfigsController.set('stepConfigs', scExc);
-      mainServiceInfoConfigsController.doPUTClusterConfigurationSites([]);
+      mainServiceInfoConfigsController.putChangedConfigurations([]);
       expect(mainServiceInfoConfigsController.get('stepConfigs')[0].get('configs').mapProperty('value').uniq()).to.eql(['1024m']);
     });
   });
@@ -866,53 +753,6 @@ describe("App.MainServiceInfoConfigsController", function () {
 
   });
 
-  describe("#createConfigObject", function() {
-    var tests = [
-      {
-        siteName: "core-site",
-        serviceName: "HDFS",
-        method: "createCoreSiteObj"
-      },
-      {
-        siteName: "core-site",
-        serviceName: "ANY",
-        method: false
-      },
-      {
-        siteName: "any",
-        method: "createSiteObj"
-      },
-      {
-        siteName: "mapred-queue-acls",
-        method: false
-      }
-    ];
-
-    beforeEach(function() {
-      sinon.stub(mainServiceInfoConfigsController, "createCoreSiteObj", Em.K);
-      sinon.stub(mainServiceInfoConfigsController, "createSiteObj", Em.K);
-      mainServiceInfoConfigsController.set("content", {});
-    });
-
-    afterEach(function() {
-      mainServiceInfoConfigsController.createCoreSiteObj.restore();
-      mainServiceInfoConfigsController.createSiteObj.restore();
-    });
-
-    tests.forEach(function(t) {
-      it("create object for " + t.siteName + " run method " + t.method, function() {
-        mainServiceInfoConfigsController.set("content.serviceName", t.serviceName);
-        mainServiceInfoConfigsController.createConfigObject(t.siteName, "versrion1");
-        if (t.method) {
-          expect(mainServiceInfoConfigsController[t.method].calledOnce).to.equal(true);
-        } else {
-          expect(mainServiceInfoConfigsController["createCoreSiteObj"].calledOnce).to.equal(false);
-          expect(mainServiceInfoConfigsController["createSiteObj"].calledOnce).to.equal(false);
-        }
-      });
-    });
-  });
-
   describe("#putConfigGroupChanges", function() {
 
     var t = {

http://git-wip-us.apache.org/repos/asf/ambari/blob/2d30cd57/ambari-web/test/mixins/common/configs/configs_saver_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/mixins/common/configs/configs_saver_test.js b/ambari-web/test/mixins/common/configs/configs_saver_test.js
index abd5f58..d8b3cb3 100644
--- a/ambari-web/test/mixins/common/configs/configs_saver_test.js
+++ b/ambari-web/test/mixins/common/configs/configs_saver_test.js
@@ -147,5 +147,45 @@ describe('App.ConfigsSaverMixin', function() {
       expect(instanceObject.createDesiredConfig).to.be.calledOnce
     })
   });
+
+  describe('#getModifiedConfigs', function () {
+    var configs = [
+      Em.Object.create({
+        name: 'p1',
+        filename: 'f1',
+        isNotDefaultValue: true,
+        value: 'v1'
+      }),
+      Em.Object.create({
+        name: 'p2',
+        filename: 'f1',
+        isNotDefaultValue: false,
+        value: 'v2'
+      }),
+      Em.Object.create({
+        name: 'p3',
+        filename: 'f2',
+        isNotSaved: true,
+        value: 'v4'
+      }),
+      Em.Object.create({
+        name: 'p4',
+        filename: 'f3',
+        isNotDefaultValue: false,
+        isNotSaved: false,
+        value: 'v4'
+      })
+    ];
+    it('filter out changed configs', function () {
+      expect(instanceObject.getModifiedConfigs(configs).mapProperty('name')).to.eql(['p1','p2','p3']);
+      expect(instanceObject.getModifiedConfigs(configs).mapProperty('filename').uniq()).to.eql(['f1','f2']);
+    });
+
+    it('filter out changed configs and modifiedFileNames', function () {
+      instanceObject.set('modifiedFileNames', ['f3']);
+      expect(instanceObject.getModifiedConfigs(configs).mapProperty('name')).to.eql(['p1','p2','p3','p4']);
+      expect(instanceObject.getModifiedConfigs(configs).mapProperty('filename').uniq()).to.eql(['f1','f2','f3']);
+    });
+  });
 });
 


[2/3] ambari git commit: AMBARI-10396. Dependent configs dialog should allow selection of config-groups (ababiichuk via srimanth)

Posted by sr...@apache.org.
AMBARI-10396. Dependent configs dialog should allow selection of config-groups (ababiichuk via srimanth)


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

Branch: refs/heads/trunk
Commit: afae3449b92244f43b553bc55ad04b0fdab0709c
Parents: 2d30cd5
Author: Srimanth Gunturi <sg...@hortonworks.com>
Authored: Thu Apr 9 11:01:27 2015 -0700
Committer: Srimanth Gunturi <sg...@hortonworks.com>
Committed: Thu Apr 9 18:14:03 2015 -0700

----------------------------------------------------------------------
 ambari-web/app/messages.js                      |  7 +--
 .../mixins/common/configs/enhanced_configs.js   | 57 +++++++++-----------
 ambari-web/app/styles/application.less          | 12 +++++
 .../modal_popups/dependent_configs_list.hbs     | 17 +++---
 .../common/modal_popups/select_groups_popup.hbs |  9 +---
 .../dependent_configs_list_popup.js             | 26 +++++----
 .../common/modal_popups/select_groups_popup.js  | 55 ++++++-------------
 7 files changed, 85 insertions(+), 98 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/afae3449/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index 73691db..e605056 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -340,12 +340,13 @@ Em.I18n.translations = {
   'popup.invalid.KDC.admin.principal': 'Admin principal',
   'popup.invalid.KDC.admin.password': 'Admin password',
 
-  'popup.dependent.configs.header': 'Dependent Properties',
-  'popup.dependent.configs.title': 'Properties that was changed has dependent properties. It\'s recommended to update these properties!',
+  'popup.dependent.configs.header': 'Dependent Configurations',
+  'popup.dependent.configs.title': 'Configurations depending on changes made are show below. It is recommended to update these values',
   'popup.dependent.configs.table.saveProperty': 'Save property',
   'popup.dependent.configs.table.currentValue': 'Current value',
-  'popup.dependent.configs.table.recommendedValue': 'Recommended value',
+  'popup.dependent.configs.table.recommendedValue': 'Recommended',
 
+  'popup.dependent.configs.select.config.group.header': 'Select Config Group',
   'popup.dependent.configs.select.config.group': 'Please select to which config group would you like to save dependent properties',
 
   'popup.dependent.configs.dependencies.info': 'There are {0} configs was changed in {1} services.',

http://git-wip-us.apache.org/repos/asf/ambari/blob/afae3449/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 c14867b..1781d5d 100644
--- a/ambari-web/app/mixins/common/configs/enhanced_configs.js
+++ b/ambari-web/app/mixins/common/configs/enhanced_configs.js
@@ -57,6 +57,8 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
    *   configGroup: {string},
    *   value: {string},
    *   serviceName: {string},
+   *   allowChangeGroup: {boolean}, //used to disable group link for current service
+   *   serviceDisplayName: {string},
    *   recommendedValue: {string}
    * }
    * @private
@@ -91,7 +93,7 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
   /**
    * contains config group name that need to be saved
    * {
-   *    serviceName: configGroupName
+   *    serviceName: {String} configGroupName
    * }
    * @type {Object}
    */
@@ -111,6 +113,10 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
 
   onConfigGroupChangeForEnhanced: function() {
     this.clearDependentConfigs();
+    this.get('dependentServiceNames').forEach(function(serviceName) {
+      var defaultGroup = this.get('dependentConfigGroups').filterProperty('service.serviceName', serviceName).findProperty('isDefault');
+      this.get('groupsToSave')[serviceName] = defaultGroup.get('name');
+    }, this);
   }.observes('selectedConfigGroup'),
 
 
@@ -132,23 +138,14 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
    * to which dependent configs will ve saved
    * @method showSelectGroupsPopup
    */
-  showSelectGroupsPopup: function(callback) {
-    var servicesWithConfigGroups = [];
-    this.get('dependentServiceNames').forEach(function(serviceName) {
-      if (serviceName !== this.get('content.serviceName')) {
-        if (!this.get('groupsToSave')[serviceName]) {
-          var groups = this.get('dependentConfigGroups').filterProperty('service.serviceName', serviceName).mapProperty('name').uniq();
-          servicesWithConfigGroups.push({
-            serviceName: serviceName,
-            configGroupNames: groups
-          })
-        }
+  showSelectGroupPopup: function(event) {
+    var serviceName = event.context;
+    if (serviceName !== this.get('content.serviceName')) {
+      var groups = this.get('dependentConfigGroups').filterProperty('service.serviceName', serviceName).mapProperty('name').uniq();
+      if (groups.length) {
+        var configs = this.get('_dependentConfigValues').filterProperty('serviceName', serviceName);
+        App.showSelectGroupsPopup(serviceName, groups, this.get('groupsToSave'), configs);
       }
-    }, this);
-    if (servicesWithConfigGroups.length > 0) {
-      App.showSelectGroupsPopup(servicesWithConfigGroups, this.get('groupsToSave'), callback);
-    } else {
-      callback();
     }
   },
 
@@ -223,16 +220,8 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
    * @method dependenciesSuccess
    */
   dependenciesSuccess: function (data, opt, params) {
-    var self = this;
-    if (!this.get('selectedConfigGroup.isDefault')) {
-      self.showSelectGroupsPopup(function () {
-        self._saveRecommendedValues(data, params.initial);
-        self._updateDependentConfigs(self.get('selectedConfigGroup.isDefault'));
-      });
-    } else {
-      self._saveRecommendedValues(data, params.initial);
-      self._updateDependentConfigs(self.get('selectedConfigGroup.isDefault'));
-    }
+    this._saveRecommendedValues(data, params.initial);
+    this._updateDependentConfigs();
   },
 
   /**
@@ -241,9 +230,9 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
    */
   showChangedDependentConfigs: function(event, callback, secondary) {
     var self = this;
-    if (self.get('_dependentConfigValues.length') > 0) {
+    if (this.get('_dependentConfigValues.length') > 0) {
       App.showDependentConfigsPopup(this.get('_dependentConfigValues'), function() {
-        self._updateDependentConfigs(self.get('selectedConfigGroup.isDefault'));
+        self._updateDependentConfigs();
         if (callback) {
           callback();
         }
@@ -297,10 +286,9 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
   /**
    * save values that are stored in <code>_dependentConfigValues<code>
    * to step configs
-   * @param isDefaultConfigGroup
    * @private
    */
-  _updateDependentConfigs: function(isDefaultConfigGroup) {
+  _updateDependentConfigs: function() {
     var self = this;
     var dependentConfigs = this.get('_dependentConfigValues');
     this.get('stepConfigs').forEach(function(serviceConfigs) {
@@ -309,9 +297,12 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
         var dependentConfig = dependentConfigs.filterProperty('propertyName', cp.get('name')).findProperty('fileName', App.config.getConfigTagFromFileName(cp.get('filename')));
         if (dependentConfig) {
           var valueToSave = dependentConfig.saveRecommended ? dependentConfig.recommendedValue : dependentConfig.value;
-          if (isDefaultConfigGroup || selectedGroup.get('isDefault')) {
+          if (selectedGroup.get('isDefault')) {
             cp.set('value', valueToSave);
           } else {
+            if (serviceConfigs.get('serviceName') !== self.get('content.serviceName')) {
+              cp.set('value', cp.get('defaultValue'));
+            }
             var overridenConfig = cp.get('overrides') && cp.get('overrides').findProperty('group.name', selectedGroup.get('name'));
             if (overridenConfig) {
               overridenConfig.set('value', valueToSave);
@@ -430,6 +421,8 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
                   configGroup: group ? group.get('name') : service.get('displayName') + " Default",
                   value: value,
                   serviceName: serviceName,
+                  allowChangeGroup: serviceName != this.get('content.serviceName') && !this.get('selectedConfigGroup.isDefault'),
+                  serviceDisplayName: service.get('displayName'),
                   recommendedValue: configs[key].properties[propertyName]
                 });
               }

http://git-wip-us.apache.org/repos/asf/ambari/blob/afae3449/ambari-web/app/styles/application.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/application.less b/ambari-web/app/styles/application.less
index e5b8a9b..2af791a 100644
--- a/ambari-web/app/styles/application.less
+++ b/ambari-web/app/styles/application.less
@@ -5580,6 +5580,18 @@ input[type="checkbox"].align-checkbox {
   }
 }
 
+#config-dependencies {
+  max-height: 500px;
+  overflow-y: auto;
+  td {
+    min-width: 120px;
+  }
+  td.check-box-col {
+    min-width: 5px;
+    width: 5px;
+  }
+}
+
 .path-link {
   white-space: nowrap;
   cursor: pointer;

http://git-wip-us.apache.org/repos/asf/ambari/blob/afae3449/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 3c02de9..c42d50d 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
@@ -19,11 +19,11 @@
 <div class="alert alert-warning">
   {{t popup.dependent.configs.title}}
 </div>
-<div id="config-validation-warnings" class="limited-height-2">
-  <table class="table no-borders">
+<div id="config-dependencies" class="limited-height-2">
+  <table class="table table-striped">
     <thead>
     <tr>
-      <th>{{t popup.dependent.configs.table.saveProperty}}</th>
+      <th class="check-box-col">{{view view.ToggleAll}}</th>
       <th>{{t common.property}}</th>
       <th>{{t common.service}}</th>
       <th>{{t common.configGroup}}</th>
@@ -35,10 +35,15 @@
     <tbody>
     {{#each config in view.parentView.configs}}
       <tr>
-        <td>{{view Em.Checkbox checkedBinding="config.saveRecommended"}}</td>
+        <td class="check-box-col">{{view Em.Checkbox checkedBinding="config.saveRecommended"}}</td>
         <td>{{config.propertyName}}</td>
-        <td>{{config.serviceName}}</td>
-        <td>{{config.configGroup}}</td>
+        <td>{{config.serviceDisplayName}}</td>
+        <td>
+          <span {{bindAttr class="config.allowChangeGroup::not-active-link"}} ><a href="javascript:void(null);" class="black"
+            {{action showSelectGroupPopup config.serviceName target="App.router.mainServiceInfoConfigsController"}}>
+            {{config.configGroup}}
+          </a></span>
+        </td>
         <td>{{config.fileName}}</td>
         <td>{{config.value}}</td>
         <td>{{config.recommendedValue}}</td>

http://git-wip-us.apache.org/repos/asf/ambari/blob/afae3449/ambari-web/app/templates/common/modal_popups/select_groups_popup.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/modal_popups/select_groups_popup.hbs b/ambari-web/app/templates/common/modal_popups/select_groups_popup.hbs
index 09ee681..00a24ef 100644
--- a/ambari-web/app/templates/common/modal_popups/select_groups_popup.hbs
+++ b/ambari-web/app/templates/common/modal_popups/select_groups_popup.hbs
@@ -16,17 +16,12 @@
 * limitations under the License.
 }}
 
-<div class="alert alert-warning">
-  {{t popup.dependent.configs.select.config.group}}
-</div>
 <form class="form-horizontal">
-{{#each service in view.parentView.dependentServices}}
   <div class="form-group">
-    <label class="col-sm-2 control-label">{{service.serviceName}}&nbsp;</label>
+    <label class="col-sm-2 control-label"><strong>{{view.parentView.serviceName}}&nbsp;</strong>&nbsp;</label>
     <div class="col-sm-8">
-      {{view App.selectConfigGroupForService contentBinding="service.configGroupNames" serviceNameBinding="service.serviceName" groupsToSaveBinding="groupsToSave"}}
+      {{view Ember.Select contentBinding="view.parentView.groups" valueBinding="view.parentView.selectedGroup"}}
     </div>
   </div>
-{{/each}}
 </form>
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/afae3449/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 c412762..90729e6 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
@@ -21,35 +21,41 @@ var App = require('app');
 /**
  * Show confirmation popup
  * @param {[Object]} configs
- * @param {function} [callback=null]
+ * @param {function} [primary=null]
  * @param {function} [secondary=null]
  * we use this parameter to defer saving configs before we make some decisions.
  * @return {App.ModalPopup}
  */
-App.showDependentConfigsPopup = function (configs, callback, secondary) {
+App.showDependentConfigsPopup = function (configs, primary, secondary) {
   return App.ModalPopup.show({
     encodeBody: false,
     header: Em.I18n.t('popup.dependent.configs.header'),
     classNames: ['sixty-percent-width-modal','modal-full-width'],
     configs: configs,
     bodyClass: Em.View.extend({
-      templateName: require('templates/common/modal_popups/dependent_configs_list')
+      templateName: require('templates/common/modal_popups/dependent_configs_list'),
+
+      ToggleAll: Em.Checkbox.extend({
+        didInsertElement: function () {
+          this.set('checked', !this.get('parentView.parentView.configs').someProperty('saveRecommended', false));
+        },
+        click: function () {
+          this.get('parentView.parentView.configs').setEach('saveRecommended', this.get('checked'));
+        }
+      })
     }),
-    stepConfigs: function() {
-      return App.get('router.mainServiceInfoConfigsController.stepConfigs').objectAt(0).get('configs');
-    }.property('controller.stepConfigs.@each'),
     onPrimary: function () {
       this._super();
-      configs.forEach(function(c) {
+      this.get('configs').forEach(function (c) {
         Em.set(c, 'saveRecommendedDefault', Em.get(c, 'saveRecommended'));
       });
-      if (callback) {
-        callback();
+      if (primary) {
+        primary();
       }
     },
     onSecondary: function() {
       this._super();
-      configs.forEach(function(c) {
+      this.get('configs').forEach(function(c) {
         Em.set(c, 'saveRecommended', Em.get(c, 'saveRecommendedDefault'));
       });
       if (secondary) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/afae3449/ambari-web/app/views/common/modal_popups/select_groups_popup.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/modal_popups/select_groups_popup.js b/ambari-web/app/views/common/modal_popups/select_groups_popup.js
index 0448cdf..3774708 100644
--- a/ambari-web/app/views/common/modal_popups/select_groups_popup.js
+++ b/ambari-web/app/views/common/modal_popups/select_groups_popup.js
@@ -20,58 +20,33 @@ var App = require('app');
 
 /**
  * Show confirmation popup
- * @param {[Object]} servicesWithGroups
+ * * @param {String} serviceName
+ * @param {String[]} groups
  * @param {Object} groupsToSave
- * @param {function} [callback=null]
- * @param {function} [secondaryCallback=null]
- * we use this parameter to defer saving configs before we make some decisions.
+ * @param {Object[]} configs
  * @return {App.ModalPopup}
  */
-App.showSelectGroupsPopup = function (servicesWithGroups, groupsToSave, callback, secondaryCallback) {
+App.showSelectGroupsPopup = function (serviceName, groups, groupsToSave, configs) {
   return App.ModalPopup.show({
     encodeBody: false,
     primary: Em.I18n.t('common.save'),
     secondary: Em.I18n.t('common.cancel'),
-    header: Em.I18n.t('popup.dependent.configs.header'),
-    dependentServices: servicesWithGroups,
+    header: Em.I18n.t('popup.dependent.configs.select.config.group.header'),
+    groups: groups,
+    serviceName: serviceName,
     groupsToSave: groupsToSave,
+    selectedGroup: '',
+    didInsertElement: function() {
+      this._super();
+      this.set('selectedGroup', this.get('groupsToSave')[this.get('serviceName')]);
+    },
     bodyClass: Em.View.extend({
       templateName: require('templates/common/modal_popups/select_groups_popup')
     }),
-
     onPrimary: function () {
       this._super();
-      if (callback) {
-        callback();
-      }
-    },
-
-    onSecondary: function() {
-      this._super();
-      if(secondaryCallback) {
-        secondaryCallback();
-      }
+      this.get('groupsToSave')[this.get('serviceName')] = this.get('selectedGroup');
+      configs.setEach('configGroup', this.get('groupsToSave')[this.get('serviceName')]);
     }
   });
-};
-
-App.selectConfigGroupForService = Ember.Select.extend({
-
-  /**
-   * set Default group by default
-   */
-  didInsertElement: function() {
-    var defaultVersion = this.get('content').find(function(cg) {
-      return cg.contains('Default');
-    });
-    this.set('value', defaultVersion);
-  },
-
-  /**
-   *
-   */
-  onChangeValue: function() {
-    var groupsToSave = this.get('groupsToSave');
-    groupsToSave[this.get('serviceName')] = this.get('value');
-  }.observes('value')
-});
+};
\ No newline at end of file