Browse Source

AMBARI-10312. Split utils/configs to separated mixins (onechiporenko)

Oleg Nechiporenko 10 years ago
parent
commit
16e96dda71

+ 3 - 3
ambari-web/app/controllers/main/service/info/configs.js

@@ -22,7 +22,7 @@ var batchUtils = require('utils/batch_scheduled_requests');
 var dataManipulationUtils = require('utils/data_manipulation');
 var lazyLoading = require('utils/lazy_loading');
 
-App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorMixin, App.EnhancedConfigsMixin, App.ConfigOverridable, App.PreloadRequestsChainMixin, {
+App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorMixin, App.EnhancedConfigsMixin, App.ConfigOverridable, App.PreloadRequestsChainMixin, App.ThemesMappingMixin, App.VersionsMappingMixin, {
 
   name: 'mainServiceInfoConfigsController',
 
@@ -325,11 +325,11 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
     var self = this;
     this.clearStep();
     if (App.get('supports.enhancedConfigs')) {
-      App.config.loadConfigTheme(this.get('content.serviceName')).always(function() {
+      this.loadConfigTheme(this.get('content.serviceName')).always(function() {
         self.setDependentServices(self.get('content.serviceName'));
         App.themesMapper.generateAdvancedTabs([self.get('content.serviceName')]);
         if (self.get('dependentServiceNames.length') > 0) {
-          App.config.loadConfigCurrentVersions(self.get('dependentServiceNames'));
+          self.loadConfigCurrentVersions(self.get('dependentServiceNames'));
         }
       });
     }

+ 2 - 2
ambari-web/app/controllers/wizard.js

@@ -20,7 +20,7 @@
 var App = require('app');
 require('models/host');
 
-App.WizardController = Em.Controller.extend(App.LocalStorage, {
+App.WizardController = Em.Controller.extend(App.LocalStorage, App.ThemesMappingMixin, {
 
   isStepDisabled: null,
 
@@ -1170,7 +1170,7 @@ App.WizardController = Em.Controller.extend(App.LocalStorage, {
       }).mapProperty('serviceName');
       // Load stack configs before loading themes
       App.config.loadConfigsFromStack(serviceNames).done(function() {
-        App.config.loadConfigThemeForServices(serviceNames).always(function() {
+        self.loadConfigThemeForServices(serviceNames).always(function() {
           self.set('stackConfigsLoaded', true);
           App.themesMapper.generateAdvancedTabs(serviceNames);
           dfd.resolve();

+ 24 - 1
ambari-web/app/controllers/wizard/step7_controller.js

@@ -633,7 +633,7 @@ App.WizardStep7Controller = Em.Controller.extend(App.ServerValidatorMixin, {
       self.set('isRecommendedLoaded', true);
       // format descriptor configs
       if (self.get('securityEnabled') && self.get('wizardController.name') == 'addServiceController') {
-        App.config.addKerberosDescriptorConfigs(configs, self.get('wizardController.kerberosDescriptorConfigs') || []);
+        self.addKerberosDescriptorConfigs(configs, self.get('wizardController.kerberosDescriptorConfigs') || []);
       }
       self.setStepConfigs(configs, storedConfigs);
       self.checkHostOverrideInstaller();
@@ -644,6 +644,29 @@ App.WizardStep7Controller = Em.Controller.extend(App.ServerValidatorMixin, {
       }
     });
   },
+
+  /**
+   * Mark descriptor properties in configuration object.
+   *
+   * @param {Object[]} configs - config properties to change
+   * @param {App.ServiceConfigProperty[]} descriptor - parsed kerberos descriptor
+   * @method addKerberosDescriptorConfigs
+   */
+  addKerberosDescriptorConfigs: function (configs, descriptor) {
+    descriptor.forEach(function (item) {
+      var property = configs.findProperty('name', item.get('name'));
+      if (property) {
+        Em.setProperties(property, {
+          isSecureConfig: true,
+          displayName: Em.get(item, 'name'),
+          isUserProperty: false,
+          isOverridable: false,
+          category: 'Advanced ' + Em.get(item, 'filename')
+        });
+      }
+    });
+  },
+
   /**
    * Load config groups
    * and (if some services are already installed) load config groups for installed services

+ 3 - 1
ambari-web/app/mixins.js

@@ -27,7 +27,9 @@ require('mixins/common/serverValidator');
 require('mixins/common/table_server_view_mixin');
 require('mixins/common/table_server_mixin');
 require('mixins/main/host/details/host_components/decommissionable');
-//require('mixins/main/service/themes_support');
+require('mixins/main/service/groups_mapping');
+require('mixins/main/service/themes_mapping');
+require('mixins/main/service/versions_mapping');
 require('mixins/main/service/configs/config_overridable');
 require('mixins/main/service/configs/preload_requests_chain');
 require('mixins/main/service/configs/widget_popover_support');

+ 64 - 0
ambari-web/app/mixins/main/service/groups_mapping.js

@@ -0,0 +1,64 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var App = require('app');
+
+/**
+ * Provide methods for config-groups loading from server and saving them into models
+ *
+ * @type {Em.Mixin}
+ */
+App.GroupsMappingMixin = Em.Mixin.create({
+
+  /**
+   * Load config groups
+   * @param {String[]} serviceNames
+   * @returns {$.Deferred()}
+   * @method loadConfigGroups
+   */
+  loadConfigGroups: function (serviceNames) {
+    var dfd = $.Deferred();
+    if (!serviceNames || serviceNames.length === 0) {
+      dfd.resolve();
+    } else {
+      App.ajax.send({
+        name: 'configs.config_groups.load.services',
+        sender: this,
+        data: {
+          serviceList: serviceNames.join(','),
+          dfd: dfd
+        },
+        success: 'saveConfigGroupsToModel'
+      });
+    }
+    return dfd.promise();
+  },
+
+  /**
+   * Runs <code>configGroupsMapper<code>
+   * @param {object} data
+   * @param {object} opt
+   * @param {object} params
+   * @method saveConfigGroupsToModel
+   */
+  saveConfigGroupsToModel: function (data, opt, params) {
+    App.configGroupsMapper.map(data, params.serviceList.split(','));
+    params.dfd.resolve();
+  }
+
+});

+ 106 - 0
ambari-web/app/mixins/main/service/themes_mapping.js

@@ -0,0 +1,106 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var App = require('app');
+
+/**
+ * Provide methods for config-themes loading from server and saving them into models
+ *
+ * @type {Em.Mixin}
+ */
+App.ThemesMappingMixin = Em.Mixin.create({
+
+  /**
+   * Load config themes from server and save them into models
+   * @param {string} serviceName
+   * @returns {$.ajax}
+   * @method loadConfigTheme
+   */
+  loadConfigTheme: function(serviceName) {
+    return App.ajax.send({
+      name: 'configs.theme',
+      sender: this,
+      data: {
+        serviceName: serviceName,
+        stackVersionUrl: App.get('stackVersionURL')
+      },
+      success: '_saveThemeToModel'
+    });
+  },
+
+  /**
+   * Success-callback for <code>loadConfigTheme</code>
+   * runs <code>themeMapper<code>
+   * @param {object} data
+   * @private
+   * @method saveThemeToModel
+   */
+  _saveThemeToModel: function(data) {
+    App.themesMapper.map(data);
+  },
+
+  /**
+   * Load themes for specified services by one API call
+   *
+   * @method loadConfigThemeForServices
+   * @param {String|String[]} serviceNames
+   * @returns {$.ajax}
+   */
+  loadConfigThemeForServices: function (serviceNames) {
+    return App.ajax.send({
+      name: 'configs.theme.services',
+      sender: this,
+      data: {
+        serviceNames: Em.makeArray(serviceNames).join(','),
+        stackVersionUrl: App.get('stackVersionURL')
+      },
+      success: '_loadConfigThemeForServicesSuccess',
+      error: '_loadConfigThemeForServicesError'
+    });
+  },
+
+  /**
+   * Success-callback for <code>loadConfigThemeForServices</code>
+   * @param {object} data
+   * @private
+   * @method _loadConfigThemeForServicesSuccess
+   */
+  _loadConfigThemeForServicesSuccess: function(data) {
+    if (!data.items.length) return;
+    App.themesMapper.map({
+      items: data.items.mapProperty('themes').reduce(function(p,c) {
+        return p.concat(c);
+      })
+    });
+  },
+
+  /**
+   * Error-callback for <code>loadConfigThemeForServices</code>
+   * @param {object} request
+   * @param {object} ajaxOptions
+   * @param {string} error
+   * @param {object} opt
+   * @param {object} params
+   * @private
+   * @method _loadConfigThemeForServicesError
+   */
+  _loadConfigThemeForServicesError: function(request, ajaxOptions, error, opt, params) {
+    console.log('ERROR: failed to load theme configs for', params.serviceNames);
+  }
+
+});

+ 107 - 0
ambari-web/app/mixins/main/service/versions_mapping.js

@@ -0,0 +1,107 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var App = require('app');
+
+/**
+ * Provide methods for config-versions loading from server and saving them into models
+ *
+ * @type {Em.Mixin}
+ */
+App.VersionsMappingMixin = Em.Mixin.create({
+
+  /**
+   * load config groups
+   * @param {string} [serviceName=null]
+   * @param {number} [configGroupId=null]
+   * @param {number} [configVersion=null]
+   * @param {boolean} [isForCompare=false]
+   * @returns {$.ajax}
+   * @method loadConfigVersions
+   */
+  loadConfigVersions: function (serviceName, configGroupId, configVersion, isForCompare) {
+    var info = this._generateAjaxDataForVersions(serviceName, configGroupId, configVersion, isForCompare);
+    return App.ajax.send($.extend({sender: this, success: 'saveConfigVersionsToModel'}, info));
+  },
+
+  /**
+   * Generate ajax info
+   * @param {string} [serviceName=null]
+   * @param {number} [configGroupId=null]
+   * @param {number} [configVersion=null]
+   * @param {boolean} [isForCompare=false]
+   * @returns {{name: string, data: {}}}
+   * @private
+   * @method generateAjaxDataForVersions
+   */
+  _generateAjaxDataForVersions: function (serviceName, configGroupId, configVersion, isForCompare) {
+    var result = {
+      name: 'configs.config_versions.load.all.min',
+      data: {}
+    };
+    if (serviceName) {
+      result.data.serviceName = serviceName;
+      if (configVersion) {
+        result.name = 'configs.config_versions.load';
+        result.data.configVersion = configVersion;
+        result.data.isForCompare = isForCompare;
+      }
+      else {
+        if (configGroupId) {
+          result.name = 'configs.config_versions.load.group';
+          result.data.configGroupId = configGroupId;
+        }
+        else {
+          result.name = 'configs.config_versions.load.service.min';
+        }
+      }
+    }
+    return result;
+  },
+
+  /**
+   *
+   * @param {string[]} serviceNames
+   * @returns {$.ajax}
+   * @method loadConfigCurrentVersions
+   */
+  loadConfigCurrentVersions: function (serviceNames) {
+    Em.assert('`serviceNames` should not be empty array', Em.isArray(serviceNames) && serviceNames.length > 0);
+    return App.ajax.send({
+      name: 'configs.config_versions.load.current_versions',
+      sender: this,
+      data: {
+        serviceNames: serviceNames.join(",")
+      },
+      success: '_saveConfigVersionsToModel'
+    });
+  },
+
+  /**
+   * Runs <code>configGroupsMapper<code>
+   * @param {object} data
+   * @param {object} opt
+   * @param {object} params
+   * @method _saveConfigVersionsToModel
+   * @private
+   */
+  _saveConfigVersionsToModel: function (data, opt, params) {
+    App.configVersionsMapper.map(data, params.isForCompare);
+  }
+
+});

+ 87 - 241
ambari-web/app/utils/config.js

@@ -19,18 +19,18 @@
 var App = require('app');
 var stringUtils = require('utils/string_utils');
 
-var configGroupsByTag = [];
-
 App.config = Em.Object.create({
 
   CONFIG_GROUP_NAME_MAX_LENGTH: 18,
 
   /**
    * filename exceptions used to support substandard sitenames which don't have "xml" extension
+   * @type {string[]}
    */
   filenameExceptions: [],
 
   preDefinedServiceConfigs: [],
+
   /**
    *
    * Returns file name version that stored on server.
@@ -231,6 +231,7 @@ App.config = Em.Object.create({
     }
     return category;
   },
+
   /**
    * additional handling for special properties such as
    * checkbox and digital which values with 'm' at the end
@@ -242,6 +243,7 @@ App.config = Em.Object.create({
       config.defaultValue = config.value;
     }
   },
+
   /**
    * calculate config properties:
    * category, filename, isUserProperty, description
@@ -281,6 +283,7 @@ App.config = Em.Object.create({
       return (yarnRegex.test(_config.name));
     }
   }.property(),
+
   /**
    * return:
    *   configs,
@@ -570,7 +573,6 @@ App.config = Em.Object.create({
     configData.supportsFinal = !!(advanced && advanced.supportsFinal);
   },
 
-
   /**
    * look over advanced configs and add missing configs to serviceConfigs
    * filter fetched configs by service if passed
@@ -648,6 +650,7 @@ App.config = Em.Object.create({
    * @param allSelectedServiceNames
    * @param installedServiceNames
    * @param localDB
+   * @param recommended
    * @return {Array}
    */
   renderConfigs: function (configs, storedConfigs, allSelectedServiceNames, installedServiceNames, localDB, recommended) {
@@ -718,6 +721,7 @@ App.config = Em.Object.create({
     }, this);
     return renderedServiceConfigs;
   },
+
   /**
    Takes care of the "dynamic defaults" for the GLUSTERFS configs.  Sets
    some of the config defaults to previously user-entered data.
@@ -738,24 +742,6 @@ App.config = Em.Object.create({
     }
   },
 
-  /**
-   * Mark descriptor properties in configuration object.
-   *
-   * @param {Object[]} configs - config properties to change
-   * @param {App.ServiceConfigProperty[]} descriptor - parsed kerberos descriptor
-   */
-  addKerberosDescriptorConfigs: function (configs, descriptor) {
-    descriptor.forEach(function (item) {
-      var property = configs.findProperty('name', item.get('name'));
-      if (property) {
-        Em.set(property, 'isSecureConfig', true);
-        Em.set(property, 'displayName', Em.get(item, 'name'));
-        Em.set(property, 'isUserProperty', false);
-        Em.set(property, 'isOverridable', false);
-        Em.set(property, 'category', 'Advanced ' + Em.get(item, 'filename'));
-      }
-    });
-  },
   /**
    * create new child configs from overrides, attach them to parent config
    * override - value of config, related to particular host(s)
@@ -781,25 +767,28 @@ App.config = Em.Object.create({
       configProperty.set('overrides', overrides);
     }
   },
+
   /**
    * create new ServiceConfig object by service name
-   * @param serviceName
+   * @param {string} serviceName
+   * @return {App.ServiceConfig}
+   * @method createServiceConfig
    */
   createServiceConfig: function (serviceName) {
     var preDefinedServiceConfig = App.config.get('preDefinedServiceConfigs').findProperty('serviceName', serviceName);
-    var serviceConfig = App.ServiceConfig.create({
+    return App.ServiceConfig.create({
       serviceName: preDefinedServiceConfig.get('serviceName'),
       displayName: preDefinedServiceConfig.get('displayName'),
       configCategories: preDefinedServiceConfig.get('configCategories'),
       configs: [],
       configGroups: []
     });
-    return serviceConfig;
   },
+
   /**
    * GETs all cluster level sites in one call.
    *
-   * @return {object}
+   * @return {$.ajax}
    */
   loadConfigsByTags: function (tags) {
     var urlParams = [];
@@ -820,7 +809,7 @@ App.config = Em.Object.create({
    * Fetch cluster configs from server
    *
    * @param callback
-   * @return {object|null}
+   * @return {$.ajax}
    */
   loadClusterConfig: function (callback) {
     return App.ajax.send({
@@ -888,7 +877,7 @@ App.config = Em.Object.create({
    * @param {String[]} serviceNames
    * @param {Object} opt
    * @param {Function} callback
-   * @returns {jqXHR}
+   * @returns {$.ajax}
    */
   loadAdvancedConfigPartial: function (serviceNames, opt, callback) {
     var data = {
@@ -1082,6 +1071,7 @@ App.config = Em.Object.create({
       callback.call(sender, serviceConfigs);
     }
   },
+
   loadServiceConfigGroupOverridesSuccess: function (data, opt, params) {
     data.items.forEach(function (config) {
       App.config.loadedConfigurationsCache[config.type + "_" + config.tag] = config.properties;
@@ -1104,6 +1094,7 @@ App.config = Em.Object.create({
     }, this);
     params.callback.call(params.sender, params.serviceConfigs);
   },
+
   /**
    * Create config with non default config group. Some custom config properties
    * can be created and assigned to non-default config group.
@@ -1135,6 +1126,7 @@ App.config = Em.Object.create({
     group.set('switchGroupTextFull', Em.I18n.t('services.service.config_groups.switchGroupTextFull').format(group.get('name')));
     return App.ServiceConfigProperty.create(propertyObject);
   },
+
   /**
    * format value of override of config
    * @param serviceConfig
@@ -1151,6 +1143,27 @@ App.config = Em.Object.create({
 
   /**
    * Set all site property that are derived from other site-properties
+   * Replace <foreignKey[0]>, <foreignKey[1]>, ... (in the name and value) to values from configs with names in foreignKey-array
+   * Replace <templateName[0]>, <templateName[1]>, ... (in the value) to values from configs with names in templateName-array
+   * Example:
+   * <code>
+   *  config: {
+   *    name: "name.<foreignKey[0]>.name",
+   *    foreignKey: ["name1"],
+   *    templateName: ["name2"],
+   *    value: "<foreignKey[0]><templateName[0]>"
+   *  }
+   * </code>
+   * "<foreignKey[0]>" in the name will be replaced with value from config with name "name1" (this config will be found
+   * in the mappedConfigs or allConfigs). New name will be set to the '_name'-property. If config with name "name1" won't
+   * be found, updated config will be marked as skipped (<code>noMatchSoSkipThisConfig</code>-property is set to true)
+   * "<templateName[0]>" in the value will be replace with value from config with name "name2" (it also will be found
+   * in the mappedConfigs or allConfigs).
+   *
+   * @param {object[]} mappedConfigs
+   * @param {object[]} allConfigs
+   * @param {object} config
+   * @method setConfigValue
    */
   setConfigValue: function (mappedConfigs, allConfigs, config) {
     var globalValue;
@@ -1160,54 +1173,66 @@ App.config = Em.Object.create({
     var fkValue = config.value.match(/<(foreignKey.*?)>/g);
     var fkName = config.name.match(/<(foreignKey.*?)>/g);
     var templateValue = config.value.match(/<(templateName.*?)>/g);
+
     if (fkValue) {
       fkValue.forEach(function (_fkValue) {
+
         var index = parseInt(_fkValue.match(/\[([\d]*)(?=\])/)[1]);
-        if (mappedConfigs.someProperty('name', config.foreignKey[index])) {
-          globalValue = mappedConfigs.findProperty('name', config.foreignKey[index]).value;
-          config.value = config.value.replace(_fkValue, globalValue);
-        } else if (allConfigs.someProperty('name', config.foreignKey[index])) {
-          if (allConfigs.findProperty('name', config.foreignKey[index]).value === '') {
-            globalValue = allConfigs.findProperty('name', config.foreignKey[index]).defaultValue;
-          } else {
-            globalValue = allConfigs.findProperty('name', config.foreignKey[index]).value;
+        var cfk = config.foreignKey[index];
+        var cFromMapped = mappedConfigs.findProperty('name', cfk);
+        if (Em.isNone(cFromMapped)) {
+          var cFromAll = allConfigs.findProperty('name', cfk);
+          if (!Em.isNone(cFromAll)) {
+            globalValue = Em.get(cFromAll, 'value') === '' ? Em.get(cFromAll, 'defaultValue') : Em.get(cFromAll, 'value');
+            config.value = config.value.replace(_fkValue, globalValue);
           }
+        }
+        else {
+          globalValue = Em.get(cFromMapped, 'value');
           config.value = config.value.replace(_fkValue, globalValue);
         }
-      }, this);
+      });
     }
 
     // config._name - formatted name from original config name
     if (fkName) {
       fkName.forEach(function (_fkName) {
+
         var index = parseInt(_fkName.match(/\[([\d]*)(?=\])/)[1]);
-        if (mappedConfigs.someProperty('name', config.foreignKey[index])) {
-          globalValue = mappedConfigs.findProperty('name', config.foreignKey[index]).value;
-          config._name = config.name.replace(_fkName, globalValue);
-        } else if (allConfigs.someProperty('name', config.foreignKey[index])) {
-          if (allConfigs.findProperty('name', config.foreignKey[index]).value === '') {
-            globalValue = allConfigs.findProperty('name', config.foreignKey[index]).defaultValue;
-          } else {
-            globalValue = allConfigs.findProperty('name', config.foreignKey[index]).value;
+        var cfk = config.foreignKey[index];
+        var cFromMapped = mappedConfigs.findProperty('name', cfk);
+
+        if (Em.isNone(cFromMapped)) {
+          var cFromAll = allConfigs.findProperty('name', cfk);
+          if (Em.isNone(cFromAll)) {
+            config.noMatchSoSkipThisConfig = true;
           }
+          else {
+            globalValue = Em.get(cFromAll, 'value') === '' ? Em.get(cFromAll, 'defaultValue') : Em.get(cFromAll, 'value');
+            config._name = config.name.replace(_fkName, globalValue);
+          }
+        }
+        else {
+          globalValue = Em.get(cFromMapped, 'value');
           config._name = config.name.replace(_fkName, globalValue);
-        } else {
-          config.noMatchSoSkipThisConfig = true;
         }
-      }, this);
+      });
     }
 
     //For properties in the configMapping file having foreignKey and templateName properties.
     if (templateValue) {
       templateValue.forEach(function (_value) {
         var index = parseInt(_value.match(/\[([\d]*)(?=\])/)[1]);
-        if (allConfigs.someProperty('name', config.templateName[index])) {
-          var globalValue = allConfigs.findProperty('name', config.templateName[index]).value;
-          config.value = config.value.replace(_value, globalValue);
-        } else {
+        var cfk = config.templateName[index];
+        var cFromAll = allConfigs.findProperty('name', cfk);
+        if (Em.isNone(cFromAll)) {
           config.value = null;
         }
-      }, this);
+        else {
+          var globalValue = Em.get(cFromAll, 'value');
+          config.value = config.value.replace(_value, globalValue);
+        }
+      });
     }
   },
 
@@ -1412,6 +1437,10 @@ App.config = Em.Object.create({
    * exclude configs that depends on services which are uninstalled
    * if config doesn't have serviceName or dependent service is installed then
    * config not excluded
+   * @param {object[]} configs
+   * @param {string[]} installedServices
+   * @return {object[]}
+   * @method excludeUnsupportedConfigs
    */
   excludeUnsupportedConfigs: function (configs, installedServices) {
     return configs.filter(function (config) {
@@ -1419,28 +1448,6 @@ App.config = Em.Object.create({
     });
   },
 
-
-
-  /**
-   * Gets all the configuration-groups for the given service.
-   *
-   * @param serviceId
-   *          (string) ID of the service. Ex: HDFS
-   */
-  getConfigGroupsForService: function (serviceId) {
-
-  },
-
-  /**
-   * Gets all the configuration-groups for a host.
-   *
-   * @param hostName
-   *          (string) host name used to register
-   */
-  getConfigGroupsForHost: function (hostName) {
-
-  },
-
   /**
    * Generate minimal config property object used in *_properties.js files.
    * Example:
@@ -1460,9 +1467,10 @@ App.config = Em.Object.create({
    *    .......
    *   ]
    * </code>
-   * @param {Array} names
+   * @param {string[]} names
    * @param {Object} properties - additional properties which will merge with base object definition
-   * @returns {*}
+   * @returns {object[]}
+   * @method generateConfigPropertiesByName
    */
   generateConfigPropertiesByName: function (names, properties) {
     return names.map(function (item) {
@@ -1515,174 +1523,12 @@ App.config = Em.Object.create({
   },
 
   /**
-   * runs <code>stackConfigPropertiesMapper<code>
-   * @param data
+   * Runs <code>stackConfigPropertiesMapper<code>
+   * @param {object} data
+   * @method saveConfigsToModel
    */
   saveConfigsToModel: function (data) {
     App.stackConfigPropertiesMapper.map(data);
-  },
-
-  /**
-   * load config groups
-   * @param {String[]} serviceNames
-   * @returns {$.Deferred()}
-   * @method loadConfigGroups
-   */
-  loadConfigGroups: function (serviceNames) {
-    var dfd = $.Deferred();
-    if (!serviceNames || serviceNames.length === 0) {
-      dfd.resolve();
-    } else {
-      App.ajax.send({
-        name: 'configs.config_groups.load.services',
-        sender: this,
-        data: {
-          serviceList: serviceNames.join(','),
-          dfd: dfd
-        },
-        success: 'saveConfigGroupsToModel'
-      });
-    }
-    return dfd.promise();
-  },
-
-  /**
-   * runs <code>configGroupsMapper<code>
-   * @param data
-   * @param opt
-   * @param params
-   */
-  saveConfigGroupsToModel: function (data, opt, params) {
-    App.configGroupsMapper.map(data, params.serviceList.split(','));
-    params.dfd.resolve();
-  },
-
-  /**
-   * load config groups
-   * @param {string} [serviceName=null]
-   * @param {number} [configGroupId=null]
-   * @param {number} [configVersion=null]
-   * @param {boolean} [isForCompare=false]
-   * @returns {$.ajax}
-   * @method loadConfigGroups
-   */
-  loadConfigVersions: function (serviceName, configGroupId, configVersion, isForCompare) {
-    var info = this.generateAjaxDataForVersions(serviceName, configGroupId, configVersion, isForCompare);
-    return App.ajax.send($.extend({sender: this, success: 'saveConfigVersionsToModel'}, info));
-  },
-
-  /**
-   *
-   * @param serviceNames
-   * @returns {$.ajax}
-   */
-  loadConfigCurrentVersions: function (serviceNames) {
-    Em.assert('serviceNames should be not empty array', Em.isArray(serviceNames) && serviceNames.length > 0);
-    return App.ajax.send({
-      name: 'configs.config_versions.load.current_versions',
-      sender: this,
-      data: {
-        serviceNames: serviceNames.join(",")
-      },
-      success: 'saveConfigVersionsToModel'
-    });
-  },
-  /**
-   * generate ajax info
-   * @param {string} [serviceName=null]
-   * @param {number} [configGroupId=null]
-   * @param {number} [configVersion=null]
-   * @param {boolean} [isForCompare=false]
-   * @returns {{name: string, data: {}}}
-   */
-  generateAjaxDataForVersions: function (serviceName, configGroupId, configVersion, isForCompare) {
-    var result = {
-      name: 'configs.config_versions.load.all.min',
-      data: {}
-    };
-    if (serviceName) {
-      result.data.serviceName = serviceName;
-      if (configVersion) {
-        result.name = 'configs.config_versions.load';
-        result.data.configVersion = configVersion;
-        result.data.isForCompare = isForCompare;
-      } else if (configGroupId) {
-        result.name = 'configs.config_versions.load.group';
-        result.data.configGroupId = configGroupId;
-      } else {
-        result.name = 'configs.config_versions.load.service.min';
-      }
-    }
-    return result;
-  },
-
-  /**
-   * runs <code>configGroupsMapper<code>
-   * @param data
-   * @param opt
-   * @param params
-   */
-  saveConfigVersionsToModel: function (data, opt, params) {
-    App.configVersionsMapper.map(data, params.isForCompare);
-  },
-
-  /**
-   * load config themes
-   * @param {string} serviceName
-   * @returns {$.ajax}
-   */
-  loadConfigTheme: function(serviceName) {
-    return App.ajax.send({
-      name: 'configs.theme',
-      sender: this,
-      data: {
-        serviceName: serviceName,
-        stackVersionUrl: App.get('stackVersionURL')
-      },
-      success: 'saveThemeToModel'
-    });
-  },
-
-  /**
-   * runs <code>themeMapper<code>
-   * @param data
-   */
-  saveThemeToModel: function(data) {
-    App.themesMapper.map(data);
-  },
-
-  /**
-   * Load themes for specified services by one API call.
-   *
-   * @method loadConfigThemeForServices
-   * @param {String|String[]} serviceNames
-   * @returns {$.Deferred}
-   */
-  loadConfigThemeForServices: function (serviceNames) {
-    var data = {
-      serviceNames: Em.isArray(serviceNames) ? serviceNames.join(',') : serviceNames,
-      stackVersionUrl: App.get('stackVersionURL')
-    };
-    return App.ajax.send({
-      name: 'configs.theme.services',
-      sender: this,
-      data: data,
-      success: 'loadConfigThemeForServicesSuccess',
-      error: 'loadConfigThemeForServicesError'
-    });
-  },
-
-  loadConfigThemeForServicesSuccess: function(data) {
-    if (!data.items.length) return;
-    App.themesMapper.map({
-      items: data.items.mapProperty('themes').reduce(function(p,c) {
-        return p.concat(c);
-      })
-    });
-  },
-
-  loadConfigThemeForServicesError: function(request, ajaxOptions, error, opt, params) {
-    console.log('ERROR: failed to load theme configs for', params.serviceNames);
   }
 
 });

+ 3 - 2
ambari-web/test/controllers/main/service/info/config_test.js

@@ -23,17 +23,18 @@ var mainServiceInfoConfigsController = null;
 describe("App.MainServiceInfoConfigsController", function () {
 
   beforeEach(function () {
-    sinon.stub(App.config, 'loadConfigTheme').returns($.Deferred().resolve().promise());
     sinon.stub(App.themesMapper, 'generateAdvancedTabs').returns(Em.K);
     mainServiceInfoConfigsController = App.MainServiceInfoConfigsController.create({
       loadDependentConfigs: function () {
         return {done: Em.K}
+      },
+      loadConfigTheme: function () {
+        return $.Deferred().resolve().promise();
       }
     });
   });
 
   afterEach(function() {
-    App.config.loadConfigTheme.restore();
     App.themesMapper.generateAdvancedTabs.restore();
   });
 

+ 33 - 0
ambari-web/test/controllers/wizard/step7_test.js

@@ -1548,4 +1548,37 @@ describe('App.InstallerStep7Controller', function () {
     });
   });
 
+  describe('#addKerberosDescriptorConfigs', function() {
+    var configs = [
+      { name: 'prop1', displayName: 'Prop1' },
+      { name: 'prop2', displayName: 'Prop2' },
+      { name: 'prop3', displayName: 'Prop3' }
+    ];
+    var descriptor = [
+      Em.Object.create({ name: 'prop4', filename: 'file-1'}),
+      Em.Object.create({ name: 'prop1', filename: 'file-1'})
+    ];
+    var propertiesAttrTests = [
+      {
+        attr: 'isUserProperty', val: false,
+        m: 'descriptor properties should not be marked as custom'
+      },
+      {
+        attr: 'category', val: 'Advanced file-1',
+        m: 'descriptor properties should be added to Advanced category'
+      },
+      {
+        attr: 'isOverridable', val: false,
+        m: 'descriptor properties should not be overriden'
+      }
+    ];
+
+    propertiesAttrTests.forEach(function(test) {
+      it(test.m, function() {
+        installerStep7Controller.addKerberosDescriptorConfigs(configs, descriptor);
+        expect(configs.findProperty('name', 'prop1')[test.attr]).to.be.eql(test.val);
+      });
+    });
+  });
+
 });

+ 143 - 100
ambari-web/test/utils/config_test.js

@@ -34,7 +34,7 @@ describe('App.config', function () {
 
   var loadAllServicesConfigs = function(context, serviceNames) {
     context.configGroups = modelSetup.setupConfigGroupsObject();
-  }
+  };
 
   var loadServiceModelsData = function(serviceNames) {
     serviceNames.forEach(function(serviceName) {
@@ -467,72 +467,6 @@ describe('App.config', function () {
 
   });
 
-  describe('#generateConfigPropertiesByName', function() {
-    var tests = [
-      {
-        names: ['property_1', 'property_2'],
-        properties: undefined,
-        e: {
-          keys: ['name', 'displayName', 'isVisible', 'isReconfigurable']
-        },
-        m: 'Should generate base property object without additional fields'
-      },
-      {
-        names: ['property_1', 'property_2'],
-        properties: { category: 'SomeCat', serviceName: 'SERVICE_NAME' },
-        e: {
-          keys: ['name', 'displayName', 'isVisible', 'isReconfigurable', 'category', 'serviceName']
-        },
-        m: 'Should generate base property object without additional fields'
-      }
-    ];
-
-    tests.forEach(function(test) {
-      it(test.m, function() {
-        expect(App.config.generateConfigPropertiesByName(test.names, test.properties).length).to.eql(test.names.length);
-        expect(App.config.generateConfigPropertiesByName(test.names, test.properties).map(function(property) {
-          return Em.keys(property);
-        }).reduce(function(p, c) {
-          return p.concat(c);
-        }).uniq()).to.eql(test.e.keys);
-      });
-    });
-
-  });
-
-  describe('#generateConfigPropertiesByName', function() {
-    var tests = [
-      {
-        names: ['property_1', 'property_2'],
-        properties: undefined,
-        e: {
-          keys: ['name', 'displayName', 'isVisible', 'isReconfigurable']
-        },
-        m: 'Should generate base property object without additional fields'
-      },
-      {
-        names: ['property_1', 'property_2'],
-        properties: { category: 'SomeCat', serviceName: 'SERVICE_NAME' },
-        e: {
-          keys: ['name', 'displayName', 'isVisible', 'isReconfigurable', 'category', 'serviceName']
-        },
-        m: 'Should generate base property object without additional fields'
-      }
-    ];
-
-    tests.forEach(function(test) {
-      it(test.m, function() {
-        expect(App.config.generateConfigPropertiesByName(test.names, test.properties).length).to.eql(test.names.length);
-        expect(App.config.generateConfigPropertiesByName(test.names, test.properties).map(function(property) {
-          return Em.keys(property);
-        }).reduce(function(p, c) {
-          return p.concat(c);
-        }).uniq()).to.eql(test.e.keys);
-      });
-    });
-
-  });
-
   describe('#setPreDefinedServiceConfigs', function() {
     beforeEach(function() {
       sinon.stub(App.StackService, 'find', function() {
@@ -800,39 +734,6 @@ describe('App.config', function () {
 
   });
 
-  describe('#addKerberosDescriptorConfigs', function() {
-    var configs = [
-      { name: 'prop1', displayName: 'Prop1' },
-      { name: 'prop2', displayName: 'Prop2' },
-      { name: 'prop3', displayName: 'Prop3' },
-    ];
-    var descriptor = [
-      Em.Object.create({ name: 'prop4', filename: 'file-1'}),
-      Em.Object.create({ name: 'prop1', filename: 'file-1'}),
-    ];
-    App.config.addKerberosDescriptorConfigs(configs, descriptor);
-    var propertiesAttrTests = [
-      {
-        attr: 'isUserProperty', val: false,
-        m: 'descriptor properties should not be marked as custom'
-      },
-      {
-        attr: 'category', val: 'Advanced file-1',
-        m: 'descriptor properties should be added to Advanced category'
-      },
-      {
-        attr: 'isOverridable', val: false,
-        m: 'descriptor properties should not be overriden'
-      },
-    ];
-
-    propertiesAttrTests.forEach(function(test) {
-      it(test.m, function() {
-        expect(configs.findProperty('name', 'prop1')[test.attr]).to.be.eql(test.val);
-      });
-    });
-  });
-
   describe('#advancedConfigIdentityData', function () {
 
     var configs = [
@@ -1186,4 +1087,146 @@ describe('App.config', function () {
 
   });
 
+  describe('#setConfigValue', function () {
+
+    Em.A([
+        {
+          mappedConfigs: [
+            {
+              name: 'falcon_user',
+              value: 'fu'
+            }
+          ],
+          allConfigs: [],
+          m: 'in mapped, value used',
+          e: {
+            _name: 'hadoop.proxyuser.fu.groups',
+            value: 'fu',
+            noMatchSoSkipThisConfig: false
+          }
+        },
+        {
+          mappedConfigs: [],
+          allConfigs: [
+            {
+              name: 'falcon_user',
+              value: 'fu'
+            }
+          ],
+          m: 'in all, value used',
+          e: {
+            _name: 'hadoop.proxyuser.fu.groups',
+            value: 'fu',
+            noMatchSoSkipThisConfig: false
+          }
+        },
+        {
+          mappedConfigs: [],
+          allConfigs: [
+            {
+              name: 'falcon_user',
+              value: '',
+              defaultValue: 'fu'
+            }
+          ],
+          m: 'in all, default value used',
+          e: {
+            _name: 'hadoop.proxyuser.fu.groups',
+            value: 'fu',
+            noMatchSoSkipThisConfig: false
+          }
+        },
+        {
+          mappedConfigs: [],
+          allConfigs: [],
+          m: 'not found',
+          e: {
+            _name: 'hadoop.proxyuser.<foreignKey[0]>.groups',
+            value: '<foreignKey[0]>',
+            noMatchSoSkipThisConfig: true
+          }
+        }
+      ]).forEach(function (test) {
+        it(test.m, function () {
+          var config = {
+            name: "hadoop.proxyuser.<foreignKey[0]>.groups",
+            templateName: ["proxyuser_group"],
+            foreignKey: ["falcon_user"],
+            noMatchSoSkipThisConfig: false,
+            value: "<foreignKey[0]>"
+          };
+          App.config.setConfigValue(test.mappedConfigs, test.allConfigs, config);
+          expect(config.value).to.equal(test.e.value);
+          if(test.e.noMatchSoSkipThisConfig) {
+            expect(Em.isNone(config._name)).to.be.true;
+          }
+          else {
+            expect(config._name).to.equal(test.e._name);
+          }
+          expect(config.noMatchSoSkipThisConfig).to.equal(test.e.noMatchSoSkipThisConfig);
+        });
+
+        Em.A([
+          {
+            mappedConfigs: [],
+            allConfigs: [
+              {
+                name: 'falcon_user',
+                value: 'fu'
+              },
+              {
+                name: 'proxyuser_group',
+                value: 'pg'
+              }
+            ],
+            m: 'in all, template in all',
+            e: {
+              _name: 'hadoop.proxyuser.fu.groups',
+              value: 'fupg'
+            }
+          },
+            {
+              mappedConfigs: [
+                {
+                  name: 'falcon_user',
+                  value: 'fu'
+                },
+                {
+                  name: 'proxyuser_group',
+                  value: 'pg'
+                }
+              ],
+              allConfigs: [],
+              m: 'in mapped, template in mapped',
+              e: {
+                _name: 'hadoop.proxyuser.fu.groups',
+                value: 'fupg'
+              }
+            },
+            {
+              mappedConfigs: [],
+              allConfigs: [],
+              m: 'not found (template not found too)',
+              e: {
+                _name: 'hadoop.proxyuser.<foreignKey[0]>.groups',
+                value: null
+              }
+            }
+        ]).forEach(function (test) {
+            it(test.m, function () {
+              var config = {
+                name: "hadoop.proxyuser.<foreignKey[0]>.groups",
+                templateName: ["proxyuser_group"],
+                foreignKey: ["falcon_user"],
+                noMatchSoSkipThisConfig: false,
+                value: "<foreignKey[0]><templateName[0]>"
+              };
+              App.config.setConfigValue(test.mappedConfigs, test.allConfigs, config);
+            });
+          });
+
+    });
+
+  });
+
 });