You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ab...@apache.org on 2015/12/28 13:17:43 UTC
ambari git commit: AMBARI-14501 Improve config recommendations flow
2. (ababiichuk)
Repository: ambari
Updated Branches:
refs/heads/trunk ff3643cdf -> 73a850eb0
AMBARI-14501 Improve config recommendations flow 2. (ababiichuk)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/73a850eb
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/73a850eb
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/73a850eb
Branch: refs/heads/trunk
Commit: 73a850eb0bb781d3f6650b176d375aca9b5021f2
Parents: ff3643c
Author: ababiichuk <ab...@hortonworks.com>
Authored: Mon Dec 28 13:01:20 2015 +0200
Committer: ababiichuk <ab...@hortonworks.com>
Committed: Mon Dec 28 14:17:03 2015 +0200
----------------------------------------------------------------------
.../controllers/main/service/info/configs.js | 16 +-
.../app/controllers/wizard/step7_controller.js | 86 +++-
ambari-web/app/mixins.js | 3 +
.../configs/config_recommendation_parser.js | 248 ++++++++++
.../common/configs/config_recommendations.js | 201 ++++++++
...onfig_with_override_recommendation_parser.js | 113 +++++
.../app/mixins/common/configs/configs_saver.js | 2 +-
.../mixins/common/configs/enhanced_configs.js | 464 ++-----------------
ambari-web/app/mixins/common/serverValidator.js | 2 +-
.../models/configs/objects/service_config.js | 4 +
.../configs/objects/service_config_property.js | 14 +
ambari-web/app/routes/add_service_routes.js | 2 +-
.../modal_popups/dependent_configs_list.hbs | 4 +-
ambari-web/app/utils/config.js | 26 +-
ambari-web/app/views/common/controls_view.js | 4 +-
.../common/modal_popups/select_groups_popup.js | 2 +-
.../main/service/info/config_test.js | 4 +-
.../common/configs/enhanced_configs_test.js | 10 +-
.../configs/widgets/config_widget_view_test.js | 14 +-
19 files changed, 770 insertions(+), 449 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/73a850eb/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 1eef9a1..85b4f60 100644
--- a/ambari-web/app/controllers/main/service/info/configs.js
+++ b/ambari-web/app/controllers/main/service/info/configs.js
@@ -264,7 +264,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ConfigsLoader, A
this.get('requestsInProgress').clear();
this.clearLoadInfo();
this.clearSaveInfo();
- this.clearDependentConfigs();
+ this.clearAllRecommendations();
this.setProperties({
saveInProgress: false,
isInit: true,
@@ -536,6 +536,18 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ConfigsLoader, A
},
/**
+ * Allow update property if recommendations
+ * is based on changing property
+ *
+ * @param parentProperties
+ * @returns {boolean}
+ * @override
+ */
+ allowUpdateProperty: function(parentProperties) {
+ return !!(parentProperties && parentProperties.length);
+ },
+
+ /**
* trigger App.config.createOverride
* @param {Object[]} stepConfig
* @private
@@ -576,7 +588,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ConfigsLoader, A
*/
doCancel: function () {
this.set('preSelectedConfigVersion', null);
- this.clearDependentConfigs();
+ this.clearAllRecommendations();
this.loadSelectedVersion(this.get('selectedVersion'), this.get('selectedConfigGroup'));
},
http://git-wip-us.apache.org/repos/asf/ambari/blob/73a850eb/ambari-web/app/controllers/wizard/step7_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/wizard/step7_controller.js b/ambari-web/app/controllers/wizard/step7_controller.js
index 2726236..823d663 100644
--- a/ambari-web/app/controllers/wizard/step7_controller.js
+++ b/ambari-web/app/controllers/wizard/step7_controller.js
@@ -706,18 +706,11 @@ App.WizardStep7Controller = Em.Controller.extend(App.ServerValidatorMixin, App.E
if (rangerService && !rangerService.get('isInstalled') && !rangerService.get('isSelected')) {
App.config.removeRangerConfigs(self.get('stepConfigs'));
}
- this.loadServerSideConfigsRecommendations().always(function() {
- if (self.get('wizardController.name') == 'addServiceController') {
- // for Add Service just remove or add dependent properties and ignore config values changes
- // for installed services only
- self.clearDependenciesForInstalledServices(self.get('installedServiceNames'), self.get('stepConfigs'));
- }
- self.completeConfigLoading();
- });
+ this.loadServerSideConfigsRecommendations().always(this.completeConfigLoading.bind(this));
},
completeConfigLoading: function() {
- this.clearDependentConfigsByService(App.StackService.find().filterProperty('isSelected').mapProperty('serviceName'));
+ this.clearRecommendationsByServiceName(App.StackService.find().filterProperty('isSelected').mapProperty('serviceName'));
console.timeEnd('wizard loadStep: ');
this.set('isRecommendedLoaded', true);
if (this.get('content.skipConfigStep')) {
@@ -727,6 +720,17 @@ App.WizardStep7Controller = Em.Controller.extend(App.ServerValidatorMixin, App.E
},
/**
+ * Update initialValues only while loading recommendations first time
+ *
+ * @param serviceName
+ * @returns {boolean}
+ * @override
+ */
+ updateInitialOnRecommendations: function(serviceName) {
+ return this._super(serviceName) && !this.get('isRecommendedLoaded');
+ },
+
+ /**
* Mark descriptor properties in configuration object.
*
* @param {Object[]} configs - config properties to change
@@ -1224,6 +1228,70 @@ App.WizardStep7Controller = Em.Controller.extend(App.ServerValidatorMixin, App.E
},
/**
+ * @param serviceName
+ * @returns {boolean}
+ * @override
+ */
+ useInitialValue: function(serviceName) {
+ return !App.Service.find(serviceName).get('serviceName', serviceName);
+ },
+
+ /**
+ *
+ * @param parentProperties
+ * @param name
+ * @param fileName
+ * @returns {*}
+ * @override
+ */
+ allowUpdateProperty: function(parentProperties, name, fileName) {
+ if (['installerController'].contains(this.get('wizardController.name')) || !!(parentProperties && parentProperties.length)) {
+ return true;
+ } else if (['addServiceController'].contains(this.get('wizardController.name'))) {
+ var stackProperty = App.configsCollection.getConfigByName(name, fileName);
+ if (!stackProperty || !this.get('installedServices')[stackProperty.serviceName]) {
+ return true;
+ } else if (stackProperty.propertyDependsOn.length) {
+ return stackProperty.propertyDependsOn.filter(function (p) {
+ var service = App.config.getServiceByConfigType(p.type);
+ return service && !this.get('installedServices')[service.get('serviceName')];
+ }, this).length;
+ } else {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ /**
+ * remove config based on recommendations
+ * @param config
+ * @param configsCollection
+ * @param parentProperties
+ * @protected
+ * @override
+ */
+ _removeConfigByRecommendation: function (config, configsCollection, parentProperties) {
+ this._super(config, configsCollection, parentProperties);
+ /**
+ * need to update wizard info when removing configs for installed services;
+ */
+ var installedServices = this.get('installedServices'), wizardController = this.get('wizardController'),
+ fileNamesToUpdate = wizardController ? wizardController.getDBProperty('fileNamesToUpdate') || [] : [],
+ fileName = Em.get(config, 'filename'), serviceName = Em.get(config, 'serviceName');
+ var modifiedFileNames = this.get('modifiedFileNames');
+ if (modifiedFileNames && !modifiedFileNames.contains(fileName)) {
+ modifiedFileNames.push(fileName);
+ } else if (wizardController && installedServices[serviceName]) {
+ if (!fileNamesToUpdate.contains(fileName)) {
+ fileNamesToUpdate.push(fileName);
+ }
+ }
+ if (wizardController) {
+ wizardController.setDBProperty('fileNamesToUpdate', fileNamesToUpdate.uniq());
+ }
+ },
+ /**
* @method manageConfigurationGroup
*/
manageConfigurationGroup: function () {
http://git-wip-us.apache.org/repos/asf/ambari/blob/73a850eb/ambari-web/app/mixins.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins.js b/ambari-web/app/mixins.js
index 90fbaa2..38d112d 100644
--- a/ambari-web/app/mixins.js
+++ b/ambari-web/app/mixins.js
@@ -45,6 +45,9 @@ require('mixins/wizard/selectHost');
require('mixins/wizard/addSecurityConfigs');
require('mixins/wizard/wizard_menu_view');
require('mixins/wizard/assign_master_components');
+require('mixins/common/configs/config_recommendations');
+require('mixins/common/configs/config_recommendation_parser');
+require('mixins/common/configs/config_with_override_recommendation_parser');
require('mixins/common/configs/enhanced_configs');
require('mixins/common/configs/configs_saver');
require('mixins/common/configs/configs_loader');
http://git-wip-us.apache.org/repos/asf/ambari/blob/73a850eb/ambari-web/app/mixins/common/configs/config_recommendation_parser.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/configs/config_recommendation_parser.js b/ambari-web/app/mixins/common/configs/config_recommendation_parser.js
new file mode 100644
index 0000000..4da42dd
--- /dev/null
+++ b/ambari-web/app/mixins/common/configs/config_recommendation_parser.js
@@ -0,0 +1,248 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var App = require('app');
+var validator = require('utils/validator');
+
+App.ConfigRecommendationParser = Em.Mixin.create(App.ConfigRecommendations, {
+
+ stepConfigs: [],
+
+ /**
+ * Method that goes through all configs
+ * and apply recommendations using callbacks
+ *
+ * @param recommendationObject
+ * @param configs
+ * @param parentProperties
+ * @param configGroup
+ * @param updateCallback
+ * @param removeCallback
+ * @param updateBoundariesCallback
+ */
+ parseRecommendations: function(recommendationObject, configs, parentProperties, configGroup,
+ updateCallback, removeCallback, updateBoundariesCallback) {
+ var propertiesToDelete = [];
+ configs.forEach(function (config) {
+ var name = Em.get(config, 'name'), fileName = Em.get(config, 'filename'),
+ site = App.config.getConfigTagFromFileName(fileName);
+ if (recommendationObject[site]) {
+ var properties = recommendationObject[site].properties,
+ property_attributes = recommendationObject[site].property_attributes;
+ if (properties) {
+ var recommendedValue = App.config.formatValue(properties[name]);
+ if (!Em.isNone(recommendedValue)) {
+ /** update config **/
+ updateCallback(config, recommendedValue, parentProperties, configGroup);
+
+ delete recommendationObject[site].properties[name];
+ }
+ }
+ if (property_attributes) {
+ var propertyAttributes = property_attributes[name];
+ var stackProperty = App.configsCollection.getConfigByName(name, fileName);
+ for (var attr in propertyAttributes) {
+ if (attr == 'delete' && this.allowUpdateProperty(parentProperties, name, fileName)) {
+ propertiesToDelete.push(config);
+ } else if (stackProperty) {
+ /** update config boundaries **/
+ updateBoundariesCallback(stackProperty, attr, propertyAttributes[attr], configGroup);
+ }
+ }
+ }
+ }
+ }, this);
+
+ if (propertiesToDelete.length) {
+ propertiesToDelete.forEach(function (property) {
+ /** remove config **/
+ removeCallback(property, configs, parentProperties, configGroup);
+
+ }, this);
+ }
+ },
+
+ /**
+ * Method that goes through all configs
+ * and apply recommendations to configs when it's needed
+ *
+ * @param {Object} recommendationObject
+ * @param {Object[]} configs
+ * @param {Object[]} parentProperties
+ */
+ updateConfigsByRecommendations: function (recommendationObject, configs, parentProperties) {
+ this.parseRecommendations(recommendationObject, configs, parentProperties, null,
+ this._updateConfigByRecommendation.bind(this), this._removeConfigByRecommendation.bind(this), this._updateBoundaries.bind(this));
+ },
+
+ /**
+ * This method goes through all config recommendations
+ * and trying to add new properties
+ *
+ * @param {Object} recommendationObject
+ * @param {Object[]} parentProperties
+ */
+ addByRecommendations: function (recommendationObject, parentProperties) {
+ for (var site in recommendationObject) {
+ if (Object.keys(recommendationObject[site].properties).length) {
+ var stepConfig = App.config.getStepConfigForProperty(this.get('stepConfigs'), site), configs = [];
+ if (stepConfig) {
+ for (var propertyName in recommendationObject[site].properties) {
+ if (this.allowUpdateProperty(parentProperties, propertyName, site)) {
+ this._addConfigByRecommendation(configs, propertyName, site, recommendationObject[site].properties[propertyName], parentProperties);
+ }
+ }
+ var mergedConfigs = configs.concat(stepConfig.get('configs'));
+ stepConfig.set('configs', mergedConfigs);
+ }
+ }
+ }
+ },
+
+ /**
+ * Update config based on recommendations
+ *
+ * @param config
+ * @param recommendedValue
+ * @param parentProperties
+ * @protected
+ */
+ _updateConfigByRecommendation: function (config, recommendedValue, parentProperties) {
+ Em.assert('config should be defined', config);
+ Em.set(config, 'recommendedValue', recommendedValue);
+ if (this.allowUpdateProperty(parentProperties, Em.get(config, 'name'), Em.get(config, 'filename'))) {
+ Em.set(config, 'value', recommendedValue);
+ this.applyRecommendation(Em.get(config, 'name'), Em.get(config, 'filename'), Em.get(config, 'group.name'), recommendedValue, this._getInitialValue(config), parentProperties);
+ }
+ if (this.updateInitialOnRecommendations(Em.get(config, 'serviceName'))) {
+ Em.set(config, 'initialValue', recommendedValue);
+ }
+ },
+
+ /**
+ * Add config based on recommendations
+ *
+ * @param configs
+ * @param name
+ * @param fileName
+ * @param recommendedValue
+ * @param parentProperties
+ * @protected
+ */
+ _addConfigByRecommendation: function (configs, name, fileName, recommendedValue, parentProperties) {
+ fileName = App.config.getOriginalFileName(fileName);
+ var stackConfig = App.configsCollection.getConfigByName(name, fileName),
+ service = App.config.get('serviceByConfigTypeMap')[App.config.getConfigTagFromFileName(fileName)];
+ if (service) {
+ var serviceName = stackConfig ? stackConfig.serviceName : service && service.get('serviceName'),
+ popupProperty = this.getRecommendation(name, fileName),
+ initialValue = popupProperty ? popupProperty.value : null;
+
+ var coreObject = {
+ "value": recommendedValue,
+ "recommendedValue": recommendedValue,
+ "initialValue": this.updateInitialOnRecommendations(serviceName) ? recommendedValue : initialValue,
+ "savedValue": !this.useInitialValue(serviceName) && !Em.isNone(initialValue) ? initialValue : null
+ };
+ var addedProperty = stackConfig || App.config.createDefaultConfig(name, serviceName, fileName, false);
+ Em.setProperties(addedProperty, coreObject);
+ var addedPropertyObject = App.ServiceConfigProperty.create(addedProperty);
+ configs.pushObject(addedPropertyObject);
+ addedPropertyObject.validate();
+
+ this.applyRecommendation(name, fileName, "Default",
+ recommendedValue, null, parentProperties);
+ }
+ },
+
+ /**
+ * Remove config based on recommendations
+ *
+ * @param config
+ * @param configsCollection
+ * @param parentProperties
+ * @protected
+ */
+ _removeConfigByRecommendation: function (config, configsCollection, parentProperties) {
+ Em.assert('config and configsCollection should be defined', config && configsCollection);
+ configsCollection.removeObject(config);
+
+ this.applyRecommendation(Em.get(config, 'name'), Em.get(config, 'filename'), Em.get(config, 'group.name'),
+ null, this._getInitialValue(config), parentProperties);
+ },
+
+ /**
+ * Update config valueAttributes by recommendations
+ *
+ * @param {Object} stackProperty
+ * @param {string} attr
+ * @param {Number|String|Boolean} value
+ * @protected
+ */
+ _updateBoundaries: function(stackProperty, attr, value) {
+ Em.set(stackProperty.valueAttributes, attr, value);
+ },
+
+ /**
+ * Get default config value
+ * <code>savedValue<code> for installed services
+ * <code>initialValue<code> for new services
+ *
+ * @param configProperty
+ * @returns {*}
+ * @protected
+ */
+ _getInitialValue: function (configProperty) {
+ if (!configProperty) return null;
+ return this.useInitialValue(Em.get(configProperty, 'serviceName')) ?
+ Em.get(configProperty, 'initialValue') : Em.get(configProperty, 'savedValue');
+ },
+
+ /**
+ * Update initial only when <code>initialValue<code> is used
+ *
+ * @param {string} serviceName
+ * @returns {boolean}
+ */
+ updateInitialOnRecommendations: function(serviceName) {
+ return this.useInitialValue(serviceName);
+ },
+
+ /**
+ * Defines if initialValue of config can be used on current controller
+ * if not savedValue is used instead
+ *
+ * @param {String} serviceName
+ * @return {boolean}
+ */
+ useInitialValue: function (serviceName) {
+ return false;
+ },
+
+ /**
+ * Defines if recommendation allowed to be applied
+ *
+ * @param parentProperties
+ * @param name
+ * @param fileName
+ * @returns {boolean}
+ */
+ allowUpdateProperty: function (parentProperties, name, fileName) {
+ return true;
+ }
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/73a850eb/ambari-web/app/mixins/common/configs/config_recommendations.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/configs/config_recommendations.js b/ambari-web/app/mixins/common/configs/config_recommendations.js
new file mode 100644
index 0000000..583e86d
--- /dev/null
+++ b/ambari-web/app/mixins/common/configs/config_recommendations.js
@@ -0,0 +1,201 @@
+/**
+ * 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');
+
+/**
+ * @typedef {object} recommendation
+ * @property {boolean} saveRecommended - by default is true (checkbox binding)
+ * @property {boolean} saveRecommendedDefault - used for cancel operation to restore previous state (saved checkbox value)
+ * @property {boolean} isDeleted - true if property was deleted
+ * @property {boolean} notDefined - true if property was added
+ * @property {string} propertyName
+ * @property {string} propertyFileName - file name without '.xml'
+ * @property {string} configGroup - name of config group, by default "Default"
+ * @property {string} serviceName
+ * @property {string} serviceDisplayName
+ * @property {string} initialValue
+ * @property {string} recommendedValue
+ * @property {boolean} allowChangeGroup - flag that allows to change config group for config from dependent not default group
+ * @property {string[]} parentConfigs - list of properties based on which current recommendation was performed
+ */
+
+App.ConfigRecommendations = Em.Mixin.create({
+
+ /**
+ * List of recommendations that was applied to configs
+ *
+ * @type {recommendation[]}
+ */
+ recommendations: [],
+
+ /**
+ * Update recommendation property if exists
+ * otherwise add new
+ *
+ * @param {string} name
+ * @param {string} fileName
+ * @param {string} configGroupName
+ * @param {string} recommendedValue
+ * @param {string} initialValue
+ * @param {Object[]}parentProperties
+ * @returns {recommendation}
+ */
+ applyRecommendation: function(name, fileName, configGroupName, recommendedValue, initialValue, parentProperties) {
+ var parentPropertiesNames = parentProperties ? parentProperties.map(function(p) {
+ return App.config.configId(p.name, p.type);
+ }) : [];
+ var updated = this.updateRecommendation(name, fileName, configGroupName, recommendedValue, parentPropertiesNames);
+ if (!updated)
+ var added = this.addRecommendation(name, fileName, configGroupName, recommendedValue, initialValue, parentPropertiesNames);
+ return updated || added;
+ },
+
+ /**
+ * Add new recommendation
+ *
+ * @param {string} name
+ * @param {string} fileName
+ * @param {string} configGroupName
+ * @param {string} recommendedValue
+ * @param {string} initialValue
+ * @param {string[]} parentPropertiesNames
+ * @returns {recommendation}
+ */
+ addRecommendation: function(name, fileName, configGroupName, recommendedValue, initialValue, parentPropertiesNames) {
+ Em.assert('name and fileName should be defined', name && fileName);
+ var site = App.config.getConfigTagFromFileName(fileName);
+ var service = App.config.get('serviceByConfigTypeMap')[site];
+ var recommendation = {
+ saveRecommended: true,
+ saveRecommendedDefault: true,
+ propertyFileName: site,
+ propertyName: name,
+
+ isDeleted: Em.isNone(recommendedValue),
+ notDefined: Em.isNone(initialValue),
+
+ configGroup: configGroupName || "Default",
+ initialValue: initialValue,
+ parentConfigs: parentPropertiesNames || [],
+ serviceName: service.get('serviceName'),
+ allowChangeGroup: false,//TODO groupName!= "Default" && (service.get('serviceName') != this.get('selectedService.serviceName'))
+ //TODO&& (App.ServiceConfigGroup.find().filterProperty('serviceName', service.get('serviceName')).length > 1), //TODO
+ serviceDisplayName: service.get('displayName'),
+ recommendedValue: recommendedValue
+ };
+ this.get('recommendations').pushObject(recommendation);
+ return recommendation;
+ },
+
+ /**
+ * Remove recommendation
+ * based on unique identifiers
+ *
+ * @param {string} name
+ * @param {string} fileName
+ * @param {string} configGroupName
+ */
+ removeRecommendation: function(name, fileName, configGroupName) {
+ this.removeRecommendationObject(this.getRecommendation(name, fileName, configGroupName));
+ },
+
+ /**
+ * Remove recommended Object
+ *
+ * @param {recommendation} recommendation
+ */
+ removeRecommendationObject: function(recommendation) {
+ if (recommendation)
+ this.get('recommendations').removeObject(recommendation);
+ },
+
+ /**
+ * Update recommended object
+ *
+ * @param name
+ * @param fileName
+ * @param configGroupName
+ * @param recommendedValue
+ * @param parentPropertiesNames
+ * @returns {*|recommendation|null}
+ */
+ updateRecommendation: function(name, fileName, configGroupName, recommendedValue, parentPropertiesNames) {
+ var recommendation = this.getRecommendation(name, fileName, configGroupName);
+ if (recommendation) {
+ Em.set(recommendation, 'recommendedValue', recommendedValue);
+ if (parentPropertiesNames && parentPropertiesNames.length) {
+ var mergedProperties = parentPropertiesNames.concat(Em.get(recommendation, 'parentPropertiesNames'));
+ Em.set(recommendation, 'parentPropertiesNames', mergedProperties);
+ }
+ }
+ return recommendation;
+ },
+
+ /**
+ * Get single recommendation
+ *
+ * @param name
+ * @param fileName
+ * @param configGroupName
+ * @returns {recommendation|null}
+ */
+ getRecommendation: function(name, fileName, configGroupName) {
+ Em.assert('name and fileName should be defined', name && fileName);
+ return this.get('recommendations').find(function (dcv) {
+ return dcv.propertyName === name
+ && dcv.propertyFileName === App.config.getConfigTagFromFileName(fileName)
+ && dcv.configGroup === (configGroupName || "Default");
+ });
+ },
+
+ /**
+ * Clear recommendations that are
+ * same as initial value
+ *
+ * @method cleanUpRecommendations
+ */
+ cleanUpRecommendations: function() {
+ var cleanDependentList = this.get('recommendations').filter(function(d) {
+ return !((Em.isNone(d.initialValue) && Em.isNone(d.recommendedValue)) || d.initialValue == d.recommendedValue);
+ }, this);
+ this.set('recommendations', cleanDependentList);
+ },
+
+ /**
+ * Remove all recommendations
+ *
+ * @method clearAllRecommendations
+ */
+ clearAllRecommendations: function() {
+ this.set('recommendations', []);
+ },
+
+ /**
+ * Clear values for dependent configs for given services
+ *
+ * @method clearRecommendationsByServiceName
+ */
+ clearRecommendationsByServiceName: function(serviceNames) {
+ var filteredRecommendations = this.get('recommendations').reject(function(c) {
+ return serviceNames.contains(c.serviceName);
+ }, this);
+ this.set('recommendations', filteredRecommendations);
+ }
+
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/73a850eb/ambari-web/app/mixins/common/configs/config_with_override_recommendation_parser.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/configs/config_with_override_recommendation_parser.js b/ambari-web/app/mixins/common/configs/config_with_override_recommendation_parser.js
new file mode 100644
index 0000000..5339637
--- /dev/null
+++ b/ambari-web/app/mixins/common/configs/config_with_override_recommendation_parser.js
@@ -0,0 +1,113 @@
+/**
+ * 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');
+
+App.ConfigWithOverrideRecommendationParser = Em.Mixin.create(App.ConfigRecommendationParser, {
+
+ /**
+ * Method that goes through all configs
+ * and apply recommendations to overrides when it's needed
+ *
+ * @param {Object} recommendationObject
+ * @param {Object[]} configs
+ * @param {Object[]} parentProperties
+ * @param {App.ServiceConfigGroup} configGroup
+ */
+ updateOverridesByRecommendations: function (recommendationObject, configs, parentProperties, configGroup) {
+ Em.assert('Config groups should be defined and not default', configGroup && configGroup.get('name') && !configGroup.get('isDefault'));
+ this.parseRecommendations(recommendationObject, configs, parentProperties, configGroup,
+ this._updateOverride.bind(this), this._removeOverride.bind(this), this._updateOverrideBoundaries.bind(this));
+ },
+
+ /**
+ * Update override by recommendations
+ * includes add/update actions
+ *
+ * @param config
+ * @param recommendedValue
+ * @param parentProperties
+ * @param configGroup
+ * @protected
+ */
+ _updateOverride: function(config, recommendedValue, parentProperties, configGroup) {
+ debugger;
+ var updateValue = this.allowUpdateProperty(parentProperties, Em.get(config, 'name'), Em.get(config, 'filename'));
+ var override = config.getOverride(configGroup.get('name'));
+ if (override) {
+ this._updateConfigByRecommendation(override, recommendedValue, parentProperties);
+ } else if (updateValue) {
+ this._addConfigOverrideRecommendation(config, recommendedValue, parentProperties, configGroup);
+ }
+ },
+
+ /**
+ * Remove override by recommendations
+ *
+ * @param property
+ * @param configs
+ * @param parentProperties
+ * @param configGroup
+ * @protected
+ */
+ _removeOverride: function(property, configs, parentProperties, configGroup) {
+ this._removeConfigByRecommendation(property.getOverride(configGroup.get('name')), property.get('overrides') || [], parentProperties);
+ },
+
+ /**
+ * Add override by recommendations
+ *
+ * @param config
+ * @param recommendedValue
+ * @param configGroup
+ * @param parentProperties
+ * @protected
+ */
+ _addConfigOverrideRecommendation: function (config, recommendedValue, parentProperties, configGroup) {
+ var popupProperty = this.getRecommendation(Em.get(config, 'name'), Em.get(config, 'filename'), configGroup.get('name')),
+ initialValue = popupProperty ? popupProperty.value : null;
+ var coreObject = {
+ "value": recommendedValue,
+ "recommendedValue": recommendedValue,
+ "initialValue": initialValue,
+ "savedValue": !this.useInitialValue(Em.get(config, 'serviceName')) && !Em.isNone(initialValue) ? initialValue : null,
+ "isEditable": true
+ };
+ var override = App.config.createOverride(config, coreObject, configGroup);
+ configGroup.get('properties').pushObject(override);
+
+ this.applyRecommendation(Em.get(config, 'name'), Em.get(config, 'filename'), configGroup.get('name'),
+ recommendedValue, this._getInitialValue(override), parentProperties);
+ },
+
+ /**
+ * Update override valueAttributes by recommendations
+ *
+ * @param {Object} stackProperty
+ * @param {string} attr
+ * @param {Number|String|Boolean} value
+ * @param {App.ServiceConfigGroup} configGroup
+ * @protected
+ */
+ _updateOverrideBoundaries: function(stackProperty, attr, value, configGroup) {
+ if (!stackProperty.valueAttributes[configGroup.get('name')]) {
+ stackProperty.valueAttributes[configGroup.get('name')] = {};
+ }
+ Em.set(stackProperty.valueAttributes[configGroup.get('name')], attr, value);
+ }
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/73a850eb/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 09cfd6f..383e4d0 100644
--- a/ambari-web/app/mixins/common/configs/configs_saver.js
+++ b/ambari-web/app/mixins/common/configs/configs_saver.js
@@ -620,7 +620,7 @@ App.ConfigsSaverMixin = Em.Mixin.create({
App.QuickViewLinks.proto().loadTags();
}
this.showSaveConfigsPopup(header, flag, message, messageClass, value, status, urlParams);
- this.clearDependentConfigs();
+ this.clearAllRecommendations();
},
/**
http://git-wip-us.apache.org/repos/asf/ambari/blob/73a850eb/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 7efcf55..0d3f20a 100644
--- a/ambari-web/app/mixins/common/configs/enhanced_configs.js
+++ b/ambari-web/app/mixins/common/configs/enhanced_configs.js
@@ -18,9 +18,8 @@
var App = require('app');
var blueprintUtils = require('utils/blueprint');
-var validator = require('utils/validator');
-App.EnhancedConfigsMixin = Em.Mixin.create({
+App.EnhancedConfigsMixin = Em.Mixin.create(App.ConfigWithOverrideRecommendationParser, {
/**
* this value is used for observing
@@ -49,17 +48,6 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
*/
isControllerSupportsEnhancedConfigs: Em.computed.existsIn('name', ['wizardStep7Controller','mainServiceInfoConfigsController']),
- /**
- * defines if initialValue of config can be used on current controller
- * if not savedValue is used instead
- * @param {String} serviceName
- * @return {boolean}
- * @method useInitialValue
- */
- useInitialValue: function(serviceName) {
- return ['wizardStep7Controller'].contains(this.get('name')) && !App.Service.find().findProperty('serviceName', serviceName);
- },
-
dependenciesGroupMessage: Em.I18n.t('popup.dependent.configs.dependencies.for.groups'),
/**
* message fro alert box for dependent configs
@@ -75,39 +63,15 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
}.property('changedProperties.length'),
/**
- * values for dependent configs
- * @type {Object[]}
- * ex:
- * {
- * saveRecommended: {boolean}, //by default is true (checkbox binding)
- * saveRecommendedDefault: {boolean}, used for cancel operation to restore previous state
- * toDelete: {boolean} [true], // defines if property should be deleted
- * toAdd: {boolean} [false], // defines if property should be added
- * isDeleted: {boolean} [true], // defines if property was deleted, but was present in initial configs
- * fileName: {string}, //file name without '.xml'
- * propertyName: {string},
- * parentConfigs: {string[]} // name of the parent configs
- * configGroup: {string},
- * value: {string},
- * serviceName: {string},
- * allowChangeGroup: {boolean}, //used to disable group link for current service
- * serviceDisplayName: {string},
- * recommendedValue: {string}
- * }
- * @private
- */
- _dependentConfigValues: Em.A([]),
-
- /**
* dependent properties that was changed by Ambari
* @type {Object[]}
*/
changedProperties: function() {
- return this.get('_dependentConfigValues').filter(function(dp) {
+ return this.get('recommendations').filter(function(dp) {
return (this.get('selectedConfigGroup.isDefault') && Em.get(dp, 'configGroup').contains('Default'))
|| [this.get('selectedConfigGroup.name'), this.get('selectedConfigGroup.dependentConfigGroups') && this.get('selectedConfigGroup.dependentConfigGroups')[Em.get(dp, 'serviceName')]].contains(Em.get(dp, 'configGroup'));
}, this);
- }.property('_dependentConfigValues.@each.saveRecommended', 'selectedConfigGroup'),
+ }.property('recommendations.@each.saveRecommended', 'recommendations.@each.recommendedValue', 'selectedConfigGroup'),
/**
* defines if change dependent group message should be shown
@@ -143,67 +107,6 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
/******************************METHODS THAT WORKS WITH DEPENDENT CONFIGS *************************************/
/**
- * clear values for dependent configs
- * @method clearDependentConfigs
- * @private
- */
- clearDependentConfigs: function() {
- this.setProperties({
- _dependentConfigValues: []
- });
- },
-
- /**
- * clear values for dependent configs for given services
- * @method clearDependentConfigs
- * @private
- */
- clearDependentConfigsByService: function(serviceNames) {
- var cleanDependencies = this.get('_dependentConfigValues').reject(function(c) {
- return serviceNames.contains(c.serviceName);
- }, this);
- this.get('stepConfigs').filter(function(s) {
- return serviceNames.contains(s.get('serviceName'));
- }).forEach(function(s) {
- s.get('configs').setEach('isNotSaved', false);
- });
- this.set('_dependentConfigValues', cleanDependencies);
- },
-
- /**
- * Remove configs from <code>_dependentConfigValues</code> which depends between installed services only.
- *
- * @param {String[]} installedServices
- * @param {App.ServiceConfig[]} stepConfigs
- */
- clearDependenciesForInstalledServices: function(installedServices, stepConfigs) {
- var allConfigs = stepConfigs.mapProperty('configs').filterProperty('length').reduce(function(p, c) {
- return p && p.concat(c);
- });
- var cleanDependencies = this.get('_dependentConfigValues').reject(function(item) {
- if (Em.get(item, 'propertyName').contains('hadoop.proxyuser')) return false;
- if (installedServices.contains(Em.get(item, 'serviceName'))) {
- var stackProperty = App.configsCollection.getConfigByName(item.propertyName, item.fileName);
- var parentConfigs = stackProperty && stackProperty.propertyDependsOn;
- if (!parentConfigs || !parentConfigs.length) {
- return true;
- }
- // check that all parent properties from installed service
- return !parentConfigs.reject(function(parentConfig) {
- var property = allConfigs.filterProperty('filename', App.config.getOriginalFileName(parentConfig.type))
- .findProperty('name', parentConfig.name);
- if (!property) {
- return false;
- }
- return installedServices.contains(Em.get(property, 'serviceName'));
- }).length;
- }
- return false;
- });
- this.set('_dependentConfigValues', cleanDependencies);
- },
-
- /**
* get config group object for current service
* @param serviceName
* @returns {App.ConfigGroup|null}
@@ -236,9 +139,7 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
* @method removeCurrentFromDependentList
*/
removeCurrentFromDependentList: function (config, saveRecommended) {
- var current = this.get('_dependentConfigValues').find(function(dependentConfig) {
- return Em.get(dependentConfig, 'propertyName') == config.get('name') && Em.get(dependentConfig, 'fileName') == App.config.getConfigTagFromFileName(config.get('filename'));
- });
+ var current = this.getRecommendation(config.get('name'), config.get('filename'), config.get('group.name'));
if (current) {
Em.setProperties(current, {
'saveRecommended': !!saveRecommended,
@@ -265,7 +166,8 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
hosts: this.get('hostNames'),
services: this.get('serviceNames')
};
- var clearConfigsOnAddService = this.isConfigHasInitialState();
+
+ var clearConfigsOnAddService = configGroup.get('isDefault') && this.isConfigHasInitialState();
if (clearConfigsOnAddService) {
recommendations.blueprint.configurations = this.get('initialConfigValues');
} else {
@@ -287,7 +189,6 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
stackVersionUrl: App.get('stackVersionURL'),
dataToSend: dataToSend,
notDefaultGroup: configGroup && !configGroup.get('isDefault'),
- initial: initial,
clearConfigsOnAddService: clearConfigsOnAddService
},
success: 'dependenciesSuccess',
@@ -313,7 +214,7 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
return !this.get('stepConfigs').filter(function(stepConfig) {
return stepConfig.get('changedConfigProperties').filter(function(c) {
return !this.get('changedProperties').map(function(changed) {
- return App.config.configId(changed.propertyName, changed.fileName);
+ return App.config.configId(changed.propertyName, changed.propertyFileName);
}).contains(App.config.configId(c.get('name'), c.get('filename')));
}, this).length;
}, this).length;
@@ -326,18 +227,16 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
clearConfigValues: function() {
this.get('stepConfigs').forEach(function(stepConfig) {
stepConfig.get('changedConfigProperties').forEach(function(c) {
- var recommendedProperty = this.get('_dependentConfigValues').find(function(d) {
- return App.config.configId(d.propertyName, d.fileName) == App.config.configId(c.get('name'), c.get('filename'));
- });
+ var recommendedProperty = this.getRecommendation(c.get('name'), c.get('filename'), c.get('group.name'));
if (recommendedProperty) {
- var initialValue = recommendedProperty.value;
+ var initialValue = recommendedProperty.initialValue;
if (Em.isNone(initialValue)) {
stepConfig.get('configs').removeObject(c);
} else {
+ c.set('initialValue', initialValue);
c.set('value', initialValue);
- c.set('recommendedValue', initialValue);
}
- this.get('_dependentConfigValues').removeObject(recommendedProperty);
+ this.removeRecommendationObject(recommendedProperty);
}
}, this)
}, this);
@@ -379,13 +278,11 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
* @method dependenciesSuccess
*/
dependenciesSuccess: function (data, opt, params) {
- this._saveRecommendedValues(data, params.initial, params.dataToSend.changed_configurations, params.notDefaultGroup);
+ this._saveRecommendedValues(data, params.dataToSend.changed_configurations, params.notDefaultGroup);
this.set("recommendationsConfigs", Em.get(data.resources[0] , "recommendations.blueprint.configurations"));
if (params.clearConfigsOnAddService) {
- if (this.get('wizardController.name') == 'addServiceController') {
- this.clearDependenciesForInstalledServices(this.get('installedServiceNames'), this.get('stepConfigs'));
- }
this.clearConfigValues();
+ this.clearAllRecommendations();
}
this.set('recommendationTimeStamp', (new Date).getTime());
},
@@ -395,7 +292,7 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
* @method showChangedDependentConfigs
*/
showChangedDependentConfigs: function(event, callback, secondary) {
- if (this.get('_dependentConfigValues.length') > 0) {
+ if (this.get('recommendations.length') > 0) {
App.showDependentConfigsPopup(this.get('changedProperties'), this.onSaveRecommendedPopup.bind(this), secondary);
} else {
if (callback) {
@@ -413,23 +310,32 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
*/
undoRedoRecommended: function(propertiesToUpdate, redo) {
propertiesToUpdate.forEach(function(p) {
- var initial = redo ? Em.get(p, 'value') : Em.get(p, 'recommendedValue');
- var recommended = redo ? Em.get(p, 'recommendedValue') : Em.get(p, 'value');
+ var initial = redo ? Em.get(p, 'initialValue') : Em.get(p, 'recommendedValue');
+ var recommended = redo ? Em.get(p, 'recommendedValue') : Em.get(p, 'initialValue');
var stepConfig = this.get('stepConfigs').findProperty('serviceName', Em.get(p, 'serviceName'));
var config = stepConfig.get('configs').find(function(scp) {
- return scp.get('name') == Em.get(p, 'propertyName') && scp.get('filename') == Em.get(p, 'fileName');
+ return scp.get('name') == Em.get(p, 'propertyName') && scp.get('filename') == App.config.getOriginalFileName(Em.get(p, 'propertyFileName'));
});
var selectedGroup = App.ServiceConfigGroup.find().filterProperty('serviceName', Em.get(p, 'serviceName')).findProperty('name', Em.get(p, 'configGroup'));
- if (Em.isNone(recommended)) {
- if (selectedGroup.get('isDefault')) {
+ if (selectedGroup.get('isDefault')) {
+ if (Em.isNone(recommended)) {
stepConfig.get('configs').removeObject(config);
+ } else if (Em.isNone(initial)) {
+ this._addConfigByRecommendation(stepConfig.get('configs'), Em.get(p, 'propertyName'), Em.get(p, 'propertyFileName'), recommended);
} else {
- config.get('overrides').removeObject(this._getOverride(config, selectedGroup));
+ Em.set(config, 'value', recommended);
}
- } else if (Em.isNone(initial)) {
- this._addConfigByRecommendation(stepConfig, selectedGroup, Em.get(p, 'propertyName'), Em.get(p, 'fileName'), Em.get(p, 'serviceName'), recommended, initial, config);
} else {
- Em.set(config, 'value', recommended);
+ if (Em.isNone(recommended)) {
+ config.get('overrides').removeObject(config.getOverride(selectedGroup.get('name')));
+ } else if (Em.isNone(initial)) {
+ this._addConfigOverrideRecommendation(config, recommended, null, selectedGroup);
+ } else {
+ var override = config.getOverride(selectedGroup.get('name'));
+ if (override) {
+ override.set('value', recommended);
+ }
+ }
}
}, this);
},
@@ -451,7 +357,7 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
}, this);
App.showSelectGroupsPopup(this.get('selectedService.serviceName'),
this.get('selectedService.configGroups').findProperty('name', this.get('selectedConfigGroup.name')),
- dependentServices, this.get('_dependentConfigValues'))
+ dependentServices, this.get('recommendations'))
},
/**
@@ -467,72 +373,33 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
},
/**
- * saves values from response for dependent config properties to <code>_dependentConfigValues<code>
+ * saves values from response for dependent config properties to <code>recommendations<code>
* @param data
- * @param [updateOnlyBoundaries=false]
* @param [changedConfigs=null]
* @param notDefaultGroup
- * @param updateInitial
* @method saveRecommendedValues
* @private
*/
- _saveRecommendedValues: function(data, updateOnlyBoundaries, changedConfigs, notDefaultGroup, updateInitial) {
+ _saveRecommendedValues: function(data, changedConfigs, notDefaultGroup) {
Em.assert('invalid data - `data.resources[0].recommendations.blueprint.configurations` not defined ', data && data.resources[0] && Em.get(data.resources[0], 'recommendations.blueprint.configurations'));
var configObject = data.resources[0].recommendations.blueprint.configurations;
if (!notDefaultGroup) {
- this.parseConfigsByTag(configObject, changedConfigs, updateInitial, updateOnlyBoundaries);
- } else if (data.resources[0].recommendations['config-groups']){
+ this.get('stepConfigs').forEach(function(stepConfig) {
+ this.updateConfigsByRecommendations(configObject, stepConfig.get('configs'), changedConfigs);
+ }, this);
+ this.addByRecommendations(configObject, changedConfigs);
+ } else if (data.resources[0].recommendations['config-groups']) {
var configFroGroup = data.resources[0].recommendations['config-groups'][0];
- this.parseConfigsByTag(configFroGroup.configurations, changedConfigs, updateInitial, updateOnlyBoundaries);
- this.parseConfigsByTag(configFroGroup.dependent_configurations, changedConfigs, updateInitial, updateOnlyBoundaries);
- }
- this._cleanUpPopupProperties();
- },
-
- /**
- * saves values from response for dependent configs to <code>_dependentConfigValues<code>
- * @param configObject - JSON response from `recommendations` endpoint
- * @param {App.ServiceConfigProperty[]} parentConfigs - config properties for which recommendations were received
- * @param updateInitial
- * @param updateOnlyBoundaries
- * @method saveRecommendedValues
- * @private
- */
- parseConfigsByTag: function(configObject, parentConfigs, updateInitial, updateOnlyBoundaries) {
- var parentPropertiesNames = parentConfigs ? parentConfigs.map(function(p) { return App.config.configId(Em.get(p, 'name'), Em.get(p, 'type'))}) : [];
- /** get all configs by config group **/
- for (var key in configObject) {
-
- /** defines main info for file name (service name, config group, config that belongs to filename) **/
- var service = App.config.get('serviceByConfigTypeMap')[key];
- var serviceName = service.get('serviceName');
- var stepConfig = this.get('stepConfigs').findProperty('serviceName', serviceName);
- if (stepConfig) {
- var configProperties = stepConfig ? stepConfig.get('configs').filterProperty('filename', App.config.getOriginalFileName(key)) : [];
-
- var group = this.getGroupForService(serviceName);
-
- for (var propertyName in configObject[key].properties) {
-
- var cp = configProperties.findProperty('name', propertyName);
-
- var configPropertyObject = (!group || group.get('isDefault')) ? cp : this._getOverride(cp, group);
-
- var recommendedValue = this.getFormattedValue(configObject[key].properties[propertyName]);
- var popupProperty = this.getPopupProperty(propertyName, key, Em.get(group || {}, 'name'));
- var initialValue = this._getInitialValue(configObject, popupProperty, serviceName, recommendedValue, updateInitial);
- if (configPropertyObject) {
- this._updateConfigByRecommendation(configPropertyObject, recommendedValue, updateInitial, updateOnlyBoundaries);
- } else if (!updateOnlyBoundaries) {
- this._addConfigByRecommendation(stepConfig, group, propertyName, key, serviceName, recommendedValue, initialValue, cp);
- }
- if (!updateOnlyBoundaries) {
- this._updatePopup(popupProperty, propertyName, key, recommendedValue, Em.get(configPropertyObject || {}, 'initialValue'), service, Em.get(group || {},'name') || "Default", parentPropertiesNames);
- }
+ this.get('stepConfigs').forEach(function(stepConfig) {
+ var configGroup = this.getGroupForService(stepConfig.get('serviceName'));
+ if (configGroup) {
+ this.updateOverridesByRecommendations(configFroGroup.configurations, stepConfig.get('configs'), changedConfigs, configGroup);
+ this.updateOverridesByRecommendations(configFroGroup.dependent_configurations, stepConfig.get('configs'), changedConfigs, configGroup);
+ this.toggleProperty('forceUpdateBoundaries');
}
- }
+ }, this);
}
- this.parseConfigAttributes(configObject, parentPropertiesNames, updateOnlyBoundaries);
+ this.cleanUpRecommendations();
},
installedServices: function () {
@@ -542,241 +409,6 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
}.property(),
/**
- * Save property attributes received from recommendations. These attributes are minimum, maximum,
- * increment_step. Attributes are stored in <code>App.StackConfigProperty</code> model.
- *
- * @param {Object[]} configs
- * @param parentPropertiesNames
- * @param updateOnlyBoundaries
- * @private
- */
- parseConfigAttributes: function(configs, parentPropertiesNames, updateOnlyBoundaries) {
- var self = this;
- Em.keys(configs).forEach(function (siteName) {
- var fileName = App.config.getOriginalFileName(siteName),
- service = App.config.get('serviceByConfigTypeMap')[siteName];
- var serviceName = service && service.get('serviceName'),
- stepConfig = self.get('stepConfigs').findProperty('serviceName', serviceName);
- if (stepConfig) {
- var group = self.getGroupForService(serviceName),
- configProperties = stepConfig ? stepConfig.get('configs').filterProperty('filename', App.config.getOriginalFileName(siteName)) : [],
- properties = configs[siteName].property_attributes || {};
- Em.keys(properties).forEach(function (propertyName) {
- var cp = configProperties.findProperty('name', propertyName);
- var stackProperty = App.configsCollection.getConfigByName(propertyName, siteName);
- var configObject = (!group || group.get('isDefault')) ? cp : self._getOverride(cp, group);
- var configsCollection = !group || group.get('isDefault') ? stepConfig.get('configs') : Em.getWithDefault(cp, 'overrides', []);
- var dependentProperty = self.getPopupProperty(propertyName, fileName, Em.get(group || {},'name'));
- var attributes = properties[propertyName] || {};
- Em.keys(attributes).forEach(function (attributeName) {
- if (attributeName == 'delete' && configObject) {
- if (!updateOnlyBoundaries) {
- self._removeConfigByRecommendation(configObject, configsCollection);
- self._updatePopup(dependentProperty, propertyName, siteName, null, Em.get(configObject, 'initialValue'), service, Em.get(group || {},'name') || "Default", parentPropertiesNames);
- }
- } else if (stackProperty) {
- var selectedConfigGroup = group && !group.get('isDefault') ? group.get('name') : null;
- if (selectedConfigGroup) {
- if (!stackProperty.valueAttributes[selectedConfigGroup]) {
- /** create not default group object for updating such values as min/max **/
- Em.set(stackProperty.valueAttributes, selectedConfigGroup, {});
- }
- if (stackProperty.valueAttributes[selectedConfigGroup][attributeName] != attributes[attributeName]) {
- Em.set(stackProperty.valueAttributes[selectedConfigGroup], attributeName, attributes[attributeName]);
- self.toggleProperty('forceUpdateBoundaries');
- }
- } else {
- Em.set(stackProperty.valueAttributes, attributeName, attributes[attributeName]);
- }
- }
- });
- });
- }
- });
- },
-
- /**
- * update config based on recommendations
- * @param config
- * @param recommendedValue
- * @param updateInitial
- * @param updateOnlyBoundaries
- * @private
- */
- _updateConfigByRecommendation: function(config, recommendedValue, updateInitial, updateOnlyBoundaries) {
- Em.assert('config should be defined', config);
- Em.set(config, 'recommendedValue', recommendedValue);
- if (!updateOnlyBoundaries) Em.set(config, 'value', recommendedValue);
- if (updateInitial && Em.isNone(Em.get(config, 'savedValue'))) Em.set(config, 'initialValue', recommendedValue);
- },
-
- /**
- * remove config based on recommendations
- * @param config
- * @param configsCollection
- * @private
- */
- _removeConfigByRecommendation: function(config, configsCollection) {
- Em.assert('config and configsCollection should be defined', config && configsCollection);
- configsCollection.removeObject(config);
- /**
- * need to update wizard info when removing configs for installed services;
- */
- var installedServices = this.get('installedServices'), wizardController = this.get('wizardController'),
- fileNamesToUpdate = wizardController ? wizardController.getDBProperty('fileNamesToUpdate') || [] : [],
- fileName = Em.get(config, 'filename'), serviceName = Em.get(config, 'serviceName');
- var modifiedFileNames = this.get('modifiedFileNames');
- if (modifiedFileNames && !modifiedFileNames.contains(fileName)) {
- modifiedFileNames.push(fileName);
- } else if (wizardController && installedServices[serviceName]) {
- if (!fileNamesToUpdate.contains(fileName)) {
- fileNamesToUpdate.push(fileName);
- }
- }
- if (wizardController) {
- wizardController.setDBProperty('fileNamesToUpdate', fileNamesToUpdate.uniq());
- }
- },
-
- /**
- * add config based on recommendations
- * @param stepConfigs
- * @param selectedGroup
- * @param name
- * @param fileName
- * @param serviceName
- * @param recommendedValue
- * @param initialValue
- * @param cp
- * @private
- */
- _addConfigByRecommendation: function(stepConfigs, selectedGroup, name, fileName, serviceName, recommendedValue, initialValue, cp) {
- fileName = App.config.getOriginalFileName(fileName);
- var coreObject = {
- "value": recommendedValue,
- "recommendedValue": recommendedValue,
- "initialValue": initialValue,
- "savedValue": !this.useInitialValue(serviceName) && !Em.isNone(initialValue) ? initialValue : null,
- "isEditable": true
- };
- if (!selectedGroup || selectedGroup.get('isDefault')) {
- var addedProperty = App.configsCollection.getConfigByName(name, fileName) || App.config.createDefaultConfig(name, serviceName, fileName, false, coreObject);
- var addedPropertyObject = App.ServiceConfigProperty.create(addedProperty);
- stepConfigs.get('configs').pushObject(addedPropertyObject);
- addedPropertyObject.validate();
- } else {
- if (cp) {
- var newOverride = App.config.createOverride(cp, coreObject, selectedGroup);
- selectedGroup.get('properties').pushObject(newOverride);
- } else {
- stepConfigs.get('configs').push(App.config.createCustomGroupConfig(name, fileName, recommendedValue, selectedGroup, true, true));
- }
- }
- },
-
- /**
- * @param configProperty
- * @param popupProperty
- * @param serviceName
- * @param recommendedValue
- * @param updateInitial
- * @returns {*}
- * @private
- */
- _getInitialValue: function(configProperty, popupProperty, serviceName, recommendedValue, updateInitial) {
- if (!this.useInitialValue(serviceName)) {
- return configProperty ? Em.get(configProperty, 'savedValue') : null;
- } else if (updateInitial) {
- return recommendedValue;
- } else {
- return popupProperty ? popupProperty.value : configProperty ? Em.get(configProperty, 'initialValue') : null;
- }
- },
-
- /**
- * format value for float values
- * @param value
- * @returns {*}
- */
- getFormattedValue: function(value) {
- return validator.isValidFloat(value) ? parseFloat(value).toString() : value;
- },
-
- /**
- * just get config override
- * @param cp
- * @param selectedGroup
- * @returns {*|Object}
- * @private
- */
- _getOverride: function(cp, selectedGroup) {
- return Em.get(cp, 'overrides.length') && Em.get(cp, 'overrides').findProperty('group.name', Em.get(selectedGroup, 'name'));
- },
-
- /**
- * get property form popup
- * @param name
- * @param fileName
- * @param groupName
- * @returns {Object}
- */
- getPopupProperty: function(name, fileName, groupName) {
- return this.get('_dependentConfigValues').find(function (dcv) {
- return dcv.propertyName === name && dcv.fileName === App.config.getOriginalFileName(fileName) && dcv.configGroup === (groupName || "Default");
- });
- },
-
- /**
- * add or update proeprty in popup
- * @param popupProperty
- * @param name
- * @param fileName
- * @param recommendedValue
- * @param initialValue
- * @param service
- * @param groupName
- * @param parentPropertiesNames
- * @private
- */
- _updatePopup: function(popupProperty, name, fileName, recommendedValue, initialValue, service, groupName, parentPropertiesNames) {
- if (popupProperty) {
- Em.set(popupProperty, 'recommendedValue', recommendedValue);
- Em.set(popupProperty, 'isDeleted', Em.isNone(recommendedValue));
- } else {
- var popupPropertyObject = {
- saveRecommended: true,
- saveRecommendedDefault: true,
- fileName: App.config.getOriginalFileName(fileName),
- propertyName: name,
-
- isDeleted: Em.isNone(recommendedValue),
- notDefined: Em.isNone(initialValue),
-
- configGroup: groupName,
- value: initialValue,
- parentConfigs: parentPropertiesNames,
- serviceName: service.get('serviceName'),
- allowChangeGroup: groupName!= "Default" && (service.get('serviceName') != this.get('selectedService.serviceName'))
- && (App.ServiceConfigGroup.find().filterProperty('serviceName', service.get('serviceName')).length > 1),
- serviceDisplayName: service.get('displayName'),
- recommendedValue: recommendedValue
- };
- this.get('_dependentConfigValues').pushObject(popupPropertyObject);
- }
- },
-
- /**
- * clean properties that have same current and recommended values
- * @private
- */
- _cleanUpPopupProperties: function() {
- var cleanDependentList = this.get('_dependentConfigValues').filter(function(d) {
- return !((Em.isNone(d.value) && Em.isNone(d.recommendedValue)) || d.value == d.recommendedValue);
- }, this);
- this.set('_dependentConfigValues', cleanDependentList);
- },
-
- /**
* Helper method to get property from the <code>stepConfigs</code>
*
* @param {String} name - config property name
http://git-wip-us.apache.org/repos/asf/ambari/blob/73a850eb/ambari-web/app/mixins/common/serverValidator.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/serverValidator.js b/ambari-web/app/mixins/common/serverValidator.js
index 7938729..40dd054 100644
--- a/ambari-web/app/mixins/common/serverValidator.js
+++ b/ambari-web/app/mixins/common/serverValidator.js
@@ -174,7 +174,7 @@ App.ServerValidatorMixin = Em.Mixin.create({
* @param data
*/
loadRecommendationsSuccess: function(data) {
- this._saveRecommendedValues(data, false, null, false, true);
+ this._saveRecommendedValues(data, null, false);
this.set("recommendationsConfigs", Em.get(data.resources[0] , "recommendations.blueprint.configurations"));
this.set('recommendationTimeStamp', (new Date).getTime());
},
http://git-wip-us.apache.org/repos/asf/ambari/blob/73a850eb/ambari-web/app/models/configs/objects/service_config.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/configs/objects/service_config.js b/ambari-web/app/models/configs/objects/service_config.js
index 2bc151b..56b8aa4 100644
--- a/ambari-web/app/models/configs/objects/service_config.js
+++ b/ambari-web/app/models/configs/objects/service_config.js
@@ -59,6 +59,10 @@ App.ServiceConfig = Ember.Object.extend({
}, this);
}.observes('configsWithErrors'),
+ configTypes: function() {
+ return App.StackService.find(this.get('serviceName')).get('configTypeList') || [];
+ }.property('serviceName'),
+
observeForeignKeys: function() {
//TODO refactor or move this logic to other place
var configs = this.get('configs');
http://git-wip-us.apache.org/repos/asf/ambari/blob/73a850eb/ambari-web/app/models/configs/objects/service_config_property.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/configs/objects/service_config_property.js b/ambari-web/app/models/configs/objects/service_config_property.js
index 3a4ca3d..4b48a98 100644
--- a/ambari-web/app/models/configs/objects/service_config_property.js
+++ b/ambari-web/app/models/configs/objects/service_config_property.js
@@ -506,6 +506,20 @@ App.ServiceConfigProperty = Em.Object.extend({
}.property('displayType', 'name', 'App.isHadoop22Stack'),
/**
+ * Get override for selected group
+ *
+ * @param {String} groupName
+ * @returns {App.ServiceConfigProperty|null}
+ */
+ getOverride: function(groupName) {
+ Em.assert('Group name should be defined string', (typeof groupName === 'string') && groupName);
+ if (this.get('overrides.length')) {
+ return this.get('overrides').findProperty('group.name', groupName);
+ }
+ return null;
+ },
+
+ /**
* Update description for `password`-config
* Add extra-message about their comparison
*
http://git-wip-us.apache.org/repos/asf/ambari/blob/73a850eb/ambari-web/app/routes/add_service_routes.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/add_service_routes.js b/ambari-web/app/routes/add_service_routes.js
index 35b06ab..30bdcbc 100644
--- a/ambari-web/app/routes/add_service_routes.js
+++ b/ambari-web/app/routes/add_service_routes.js
@@ -199,7 +199,7 @@ module.exports = App.WizardRoute.extend({
recommendationsConfigs: null
});
router.get('wizardStep7Controller').set('recommendationsConfigs', null);
- router.get('wizardStep7Controller').clearDependentConfigs();
+ router.get('wizardStep7Controller').clearAllRecommendations();
router.transitionTo('step4');
});
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/73a850eb/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 ca62592..cef7be2 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
@@ -44,12 +44,12 @@
{{config.configGroup}}
</a></span>
</td>
- <td class="config-dependency-filename">{{config.fileName}}</td>
+ <td class="config-dependency-filename">{{config.propertyFileName}}</td>
<td class="config-dependency-value">
{{#if config.notDefined}}
<i>{{t popup.dependent.configs.table.not.defined}}</i>
{{else}}
- {{config.value}}
+ {{config.initialValue}}
{{/if}}
</td>
<td class="config-dependency-recommended-value">
http://git-wip-us.apache.org/repos/asf/ambari/blob/73a850eb/ambari-web/app/utils/config.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/config.js b/ambari-web/app/utils/config.js
index f4c8034..a533994 100644
--- a/ambari-web/app/utils/config.js
+++ b/ambari-web/app/utils/config.js
@@ -19,6 +19,7 @@
var App = require('app');
require('utils/configs_collection');
var stringUtils = require('utils/string_utils');
+var validator = require('utils/validator');
var configTagFromFileNameMap = {};
@@ -212,7 +213,7 @@ App.config = Em.Object.create({
*/
getServiceByConfigType: function(configType) {
return App.StackService.find().find(function(s) {
- return Object.keys(s.get('configTypes')).contains(configType);
+ return s.get('configTypeList').contains(configType);
});
},
@@ -495,6 +496,29 @@ App.config = Em.Object.create({
},
/**
+ * Format float value
+ *
+ * @param {*} value
+ * @returns {string|*}
+ */
+ formatValue: function(value) {
+ return validator.isValidFloat(value) ? parseFloat(value).toString() : value;
+ },
+
+ /**
+ * Get step config by file name
+ *
+ * @param stepConfigs
+ * @param fileName
+ * @returns {Object|null}
+ */
+ getStepConfigForProperty: function (stepConfigs, fileName) {
+ return stepConfigs.find(function (s) {
+ return s.get('configTypes').contains(App.config.getConfigTagFromFileName(fileName));
+ });
+ },
+
+ /**
*
* @param configs
* @returns {Object[]}
http://git-wip-us.apache.org/repos/asf/ambari/blob/73a850eb/ambari-web/app/views/common/controls_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/controls_view.js b/ambari-web/app/views/common/controls_view.js
index a88be76..367a7ee 100644
--- a/ambari-web/app/views/common/controls_view.js
+++ b/ambari-web/app/views/common/controls_view.js
@@ -113,9 +113,9 @@ App.SupportsDependentConfigs = Ember.Mixin.create({
*/
restoreDependentConfigs: function(parentConfig) {
var controller = this.get('controller');
- var dependentConfigs = controller.get('_dependentConfigValues');
+ var dependentConfigs = controller.get('recommendations');
try {
- controller.set('_dependentConfigValues', dependentConfigs.reject(function(item) {
+ controller.set('recommendations', dependentConfigs.reject(function(item) {
if (item.parentConfigs.contains(parentConfig.get('name'))) {
if (item.parentConfigs.length > 1) {
item.parentConfigs.removeObject(parentConfig.get('name'));
http://git-wip-us.apache.org/repos/asf/ambari/blob/73a850eb/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 264d7b1..33c72a2 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
@@ -64,7 +64,7 @@ App.showSelectGroupsPopup = function (selectedServiceName, selectedConfigGroup,
var currentGroupName = this.get('selectedGroups')[serviceName] || "";
var configGroup = this.get('dependentStepConfigs').findProperty('serviceName', serviceName).get('configGroups').findProperty('name', selectedGroupName);
if (selectedGroupName != currentGroupName) {
- /** changing config group for _dependentConfigValues **/
+ /** changing config group for recommendations **/
configs.filterProperty('serviceName', serviceName).filterProperty('configGroup', selectedGroupName).forEach(function (c) {
if (configs.filterProperty('serviceName', serviceName).filterProperty('configGroup', currentGroupName)) {
configs.removeObject(c);
http://git-wip-us.apache.org/repos/asf/ambari/blob/73a850eb/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 b6abb8e..ba8f1d3 100644
--- a/ambari-web/test/controllers/main/service/info/config_test.js
+++ b/ambari-web/test/controllers/main/service/info/config_test.js
@@ -376,9 +376,9 @@ describe("App.MainServiceInfoConfigsController", function () {
it("should clear dependent configs", function() {
mainServiceInfoConfigsController.set('groupsToSave', { HDFS: 'my cool group'});
- mainServiceInfoConfigsController.set('_dependentConfigValues', Em.A([{name: 'prop_1'}]));
+ mainServiceInfoConfigsController.set('recommendations', Em.A([{name: 'prop_1'}]));
mainServiceInfoConfigsController.doCancel();
- expect(App.isEmptyObject(mainServiceInfoConfigsController.get('_dependentConfigValues'))).to.be.true;
+ expect(App.isEmptyObject(mainServiceInfoConfigsController.get('recommendations'))).to.be.true;
});
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/73a850eb/ambari-web/test/mixins/common/configs/enhanced_configs_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/mixins/common/configs/enhanced_configs_test.js b/ambari-web/test/mixins/common/configs/enhanced_configs_test.js
index 1b7115c..3ec4b07 100644
--- a/ambari-web/test/mixins/common/configs/enhanced_configs_test.js
+++ b/ambari-web/test/mixins/common/configs/enhanced_configs_test.js
@@ -24,19 +24,21 @@ describe('App.EnhancedConfigsMixin', function() {
var instanceObject = mixinObject.create({});
describe('#removeCurrentFromDependentList()', function() {
it('update some fields', function() {
- instanceObject.get('_dependentConfigValues').pushObject({
+ instanceObject.get('recommendations').pushObject({
saveRecommended: true,
saveRecommendedDefault: true,
+ configGroup: "Default",
propertyName: 'p1',
- fileName: 'f1',
+ propertyFileName: 'f1',
value: 'v1'
});
instanceObject.removeCurrentFromDependentList(Em.Object.create({name: 'p1', filename: 'f1.xml', value: 'v2'}));
- expect(instanceObject.get('_dependentConfigValues')[0]).to.eql({
+ expect(instanceObject.get('recommendations')[0]).to.eql({
saveRecommended: false,
saveRecommendedDefault: false,
+ configGroup: "Default",
propertyName: 'p1',
- fileName: 'f1',
+ propertyFileName: 'f1',
value: 'v1'
});
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/73a850eb/ambari-web/test/views/common/configs/widgets/config_widget_view_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/common/configs/widgets/config_widget_view_test.js b/ambari-web/test/views/common/configs/widgets/config_widget_view_test.js
index e7f979b..ed43a1b 100644
--- a/ambari-web/test/views/common/configs/widgets/config_widget_view_test.js
+++ b/ambari-web/test/views/common/configs/widgets/config_widget_view_test.js
@@ -209,22 +209,22 @@ describe('App.ConfigWidgetView', function () {
tests.forEach(function(test) {
it(test.m, function() {
- view.set('controller._dependentConfigValues', test.dependentConfigs);
+ view.set('controller.recommendations', test.dependentConfigs);
view.restoreDependentConfigs(view.get('config'));
- expect(view.get('controller._dependentConfigValues').mapProperty('name')).to.be.eql(test.e);
+ expect(view.get('controller.recommendations').mapProperty('name')).to.be.eql(test.e);
});
});
it('when dependent configs has multiple parents appropriate parent config should be removed', function() {
- view.set('controller._dependentConfigValues', [
+ view.set('controller.recommendations', [
{name: 'dependent1', parentConfigs: ['config1', 'config2']},
{name: 'dependent2', parentConfigs: ['config2', 'config1']},
{name: 'dependent3', parentConfigs: ['config1']}
]);
view.restoreDependentConfigs(view.get('config'));
- expect(view.get('controller._dependentConfigValues').findProperty('name', 'dependent1').parentConfigs.toArray()).to.be.eql(["config2"]);
- expect(view.get('controller._dependentConfigValues').findProperty('name', 'dependent2').parentConfigs.toArray()).to.be.eql(["config2"]);
- expect(view.get('controller._dependentConfigValues.length')).to.be.eql(2);
+ expect(view.get('controller.recommendations').findProperty('name', 'dependent1').parentConfigs.toArray()).to.be.eql(["config2"]);
+ expect(view.get('controller.recommendations').findProperty('name', 'dependent2').parentConfigs.toArray()).to.be.eql(["config2"]);
+ expect(view.get('controller.recommendations.length')).to.be.eql(2);
});
it('dependent config value should be set with inital or saved when it has one parent', function() {
@@ -237,7 +237,7 @@ describe('App.ConfigWidgetView', function () {
])
})
]);
- view.set('controller._dependentConfigValues', [
+ view.set('controller.recommendations', [
{propertyName: 'dependent1', parentConfigs: ['config1', 'config2'], fileName: 'some-file' },
{propertyName: 'dependent2', parentConfigs: ['config2', 'config1'], fileName: 'some-file'},
{propertyName: 'dependent3', parentConfigs: ['config1'], fileName: 'some-file' }