Repository: ambari Updated Branches: refs/heads/trunk fb763311e -> 9f87c98dc
AMBARI-10230 Support config-dependency changes when they cross services. (ababiichuk) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/9f87c98d Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/9f87c98d Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/9f87c98d Branch: refs/heads/trunk Commit: 9f87c98dcf352f2bae671556e74e06798ee0a5a6 Parents: fb76331 Author: aBabiichuk <ababiic...@cybervisiontech.com> Authored: Fri Mar 27 12:31:25 2015 +0200 Committer: aBabiichuk <ababiic...@cybervisiontech.com> Committed: Fri Mar 27 12:31:25 2015 +0200 ---------------------------------------------------------------------- .../controllers/main/service/info/configs.js | 338 +++++------ ambari-web/app/messages.js | 3 + .../mixins/common/configs/enhanced_configs.js | 586 ++++++++++++++++--- ambari-web/app/mixins/common/serverValidator.js | 77 --- .../modal_popups/dependent_configs_list.hbs | 8 +- .../common/modal_popups/select_groups_popup.hbs | 32 + ambari-web/app/views.js | 1 + .../dependent_configs_list_popup.js | 12 +- .../common/modal_popups/select_groups_popup.js | 77 +++ .../main/service/info/config_test.js | 43 -- .../common/configs/enhanced_configs_test.js | 19 +- 11 files changed, 764 insertions(+), 432 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/9f87c98d/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 b126798..19179a0 100644 --- a/ambari-web/app/controllers/main/service/info/configs.js +++ b/ambari-web/app/controllers/main/service/info/configs.js @@ -38,6 +38,10 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM requestInProgress: null, selectedServiceConfigTypes: [], selectedServiceSupportsFinal: [], + + /** + * config groups for current service + */ configGroups: [], allConfigs: [], uiConfigs: [], @@ -65,19 +69,6 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM }.property('selectedVersion', 'content.serviceName', 'dataIsLoaded'), /** - * array that contains config properties that were changed and - * belongs to not current service - * @returns {*|Array} - */ - unsavedDependentConfigs: function() { - return App.ConfigProperty.find().filter(function(cp) { - return cp.get('stackConfigProperty.serviceName') !== this.get('content.serviceName') - && this.get('dependentFileNames').contains(cp.get('fileName')) - && cp.get('isNotDefaultValue'); - }, this); - }, - - /** * @type {boolean} */ canEdit: function () { @@ -252,8 +243,6 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM */ isInit: true, - restartHosts: Em.A(), - /** * On load function */ @@ -261,10 +250,12 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM console.log("TRACE: Loading configure for service"); var self = this; if (App.get('supports.enhancedConfigs')) { - App.config.loadConfigTheme(this.get('content.serviceName')).then(function() { - self.loadDependentConfigs().done(function () { - App.themesMapper.generateAdvancedTabs([self.get('content.serviceName')]); - }); + App.config.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')); + } }); } this.clearStep(); @@ -333,73 +324,6 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM }, /** - * this method defines dependent file names for configs - * and load them to model - * @method loadDependentConfigs - */ - loadDependentConfigs: function() { - /** - * filter out configs for current service with - * <code>propertyDependedBy<code> - * @type {Array} - */ - var serviceStackProperties = App.StackConfigProperty.find().filter(function(stackProperty) { - return stackProperty.get('serviceName') === this.get('content.serviceName') && stackProperty.get('propertyDependedBy.length') > 0 - }, this); - - /** - * defines what fileNames should UI load - */ - serviceStackProperties.forEach(function(serviceStackProperty) { - this.calculateDependentFileNames(serviceStackProperty); - }, this); - - var serviceConfigsToLoad = this.getServiceNamesForConfigs(); - - /** - * load serviceConfigVersion - * by serviceName that has dependent properties - */ - if (serviceConfigsToLoad.length > 0) { - return App.config.loadConfigCurrentVersions(serviceConfigsToLoad); - } - }, - - /** - * get required fileNames that has dependencies - * @returns {string[]} - */ - getServiceNamesForConfigs: function() { - return App.StackService.find().filter(function(s) { - for (var i = 0; i < this.get('dependentFileNames.length'); i++) { - if (Object.keys(s.get('configTypes')).contains(App.config.getConfigTagFromFileName(this.get('dependentFileNames')[i]))) - return true; - } - return false; - }, this).mapProperty('serviceName').concat(this.get('content.serviceName')); - }, - - /** - * dependent file names for configs - */ - dependentFileNames: [], - - /** - * defines file names for configs - * @param {App.StackConfigProperty} stackProperty - */ - calculateDependentFileNames: function(stackProperty) { - if (stackProperty.get('propertyDependedBy.length') > 0) { - stackProperty.get('propertyDependedBy').forEach(function(dependent) { - if (!this.get('dependentFileNames').contains(dependent.type)) { - this.get('dependentFileNames').push(dependent.type); - } - this.calculateDependentFileNames(App.StackConfigProperty.find(dependent.name + "_" + dependent.type)); - }, this); - } - }, - - /** * get service config versions of current service */ loadServiceConfigVersions: function () { @@ -526,6 +450,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM /** * load config groups of service + * and dependent services */ loadServiceTagsAndGroups: function () { this.trackRequest(App.ajax.send({ @@ -533,7 +458,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM sender: this, data: { serviceName: this.get('content.serviceName'), - urlParams: "&config_groups/ConfigGroup/tag=" + this.get('content.serviceName') + urlParams: "&config_groups/ConfigGroup/tag.in(" + [this.get('content.serviceName')].concat(this.get('dependentServiceNames')).join(',')+ ')' }, success: 'loadServiceConfigsSuccess' })); @@ -543,20 +468,6 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM this.setConfigGroups(data, opt, params); }, - setConfigTags: function (data, opt, params) { - var serviceConfigsDef = this.get('serviceConfigs').findProperty('serviceName', this.get('content.serviceName')); - var siteToTagMap = {}; - var configTypesRendered = Object.keys(serviceConfigsDef.get('configTypesRendered')); - configTypesRendered.forEach(function (siteName) { - if (data.Clusters.desired_configs[siteName]) { - siteToTagMap[siteName] = data.Clusters.desired_configs[siteName].tag; - } else { - siteToTagMap[siteName] = 'version1'; - } - }, this); - this.loadedClusterSiteToTagMap = siteToTagMap; - }, - setConfigGroups: function (data, opt, params) { var serviceName = this.get('content.serviceName'); var displayName = this.get('content.displayName'); @@ -594,9 +505,50 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM selectedConfigGroup = newConfigGroup; } configGroups.push(newConfigGroup); + } else if (this.get('dependentServiceNames').contains(item.tag)) { + /** + * Load config groups for services that has dependent properties. + * If user change properties that have dependencies in not default config group + * user should pick to which config group Ambari should save these properties + * @type {App.ConfigGroup} + */ + var newDependentConfigGroup = App.ConfigGroup.create({ + id: item.id, + name: item.group_name, + description: item.description, + isDefault: false, + parentConfigGroup: null, + service: App.Service.find().findProperty('serviceName', item.tag), + hosts: item.hosts.mapProperty('host_name') + }); + if (!this.get('dependentConfigGroups').findProperty('name', item.group_name)) { + this.get('dependentConfigGroups').push(newDependentConfigGroup); + } } }, this); } + this.get('dependentServiceNames').forEach(function(serviceName) { + if (serviceName !== this.get('content.serviceName')) { + var service = App.Service.find().findProperty('serviceName', serviceName); + /** + * default groups for dependent services + * @type {App.ConfigGroup} + */ + var defaultConfigGroup = App.ConfigGroup.create({ + name: service.get('displayName') + " Default", + description: "Default cluster level " + serviceName + " configuration", + isDefault: true, + hosts: [], + parentConfigGroup: null, + service: service, + serviceName: serviceName, + configSiteTags: [] + }); + if (!this.get('dependentConfigGroups').findProperty('name', defaultConfigGroup.get('name'))) { + this.get('dependentConfigGroups').push(defaultConfigGroup); + } + } + }, this); this.set('configGroups', configGroups); var defaultConfigGroup = App.ConfigGroup.create({ name: displayName + " Default", @@ -1202,7 +1154,6 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM } return newSCP; }, - /** * tells controller in saving configs was started * for now just changes flag <code>saveInProgress<code> to true @@ -1237,27 +1188,11 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM showWarningPopupsBeforeSave: function() { var displayName = this.get('content.displayName'); if (this.isDirChanged()) { - App.showConfirmationPopup(this.showDependenciesAndSave.bind(this), + App.showConfirmationPopup(this.restartServicePopup.bind(this), Em.I18n.t('services.service.config.confirmDirectoryChange').format(displayName), this.completeSave.bind(this) ); } else { - this.showDependenciesAndSave(); - } - }, - - /** - * if there are some dependent configs in different services - * this popup will be shown with info about this configs - * @method showDependenciesAndSave - */ - showDependenciesAndSave: function() { - var dependentConfigs = this.unsavedDependentConfigs(); - if (dependentConfigs.length > 0) { - App.showDependentConfigsPopup(dependentConfigs, - this.restartServicePopup.bind(this), - this.completeSave.bind(this)); - } else { this.restartServicePopup(); } }, @@ -1303,51 +1238,39 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM configs = App.config.textareaIntoFileConfigs(configs, 'capacity-scheduler.xml'); } - if (App.get('supports.enhancedConfigs')) { - if (this.get('content.serviceName') === 'HIVE') { - this.setHiveHostName(configs); - } else if (this.get('content.serviceName') === 'OOZIE') { - this.setOozieHostName(configs); - } - - this.loadConfigsToModel(configs, self.get('selectedVersion')); + /** + * generates list of properties that was changed + * @type {Array} + */ + var modifiedConfigs = configs + // get only modified and created configs + .filter(function (config) { + return config.get('isNotDefaultValue') || config.get('isNotSaved'); + }) + // get file names and add file names that was modified, for example after property removing + .mapProperty('filename').concat(this.get('modifiedFileNames')).uniq() + // get configs by filename + .map(function (fileName) { + return configs.filterProperty('filename', fileName); + }); - this.saveEnhancedConfigs(); + if (!!modifiedConfigs.length) { + // concatenate results + modifiedConfigs = modifiedConfigs.reduce(function (current, prev) { + return current.concat(prev); + }); + } + // save modified original configs that have no group + this.saveSiteConfigs(modifiedConfigs.filter(function (config) { + return !config.get('group'); + })); - } else { - /** - * generates list of properties that was changed - * @type {Array} - */ - var modifiedConfigs = configs - // get only modified and created configs - .filter(function (config) { - return config.get('isNotDefaultValue') || config.get('isNotSaved'); - }) - // get file names and add file names that was modified, for example after property removing - .mapProperty('filename').concat(this.get('modifiedFileNames')).uniq() - // get configs by filename - .map(function (fileName) { - return configs.filterProperty('filename', fileName); - }); + /** + * First we put cluster configurations, which automatically creates /configurations + * resources. Next we update host level overrides. + */ + this.doPUTClusterConfigurations(); - if (!!modifiedConfigs.length) { - // concatenate results - modifiedConfigs = modifiedConfigs.reduce(function (current, prev) { - return current.concat(prev); - }); - } - // save modified original configs that have no group - this.saveSiteConfigs(modifiedConfigs.filter(function (config) { - return !config.get('group'); - })); - - /** - * First we put cluster configurations, which automatically creates /configurations - * resources. Next we update host level overrides. - */ - this.doPUTClusterConfigurations(); - } } else { var overridenConfigs = []; var groupHosts = []; @@ -1356,33 +1279,33 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM }); // find custom original properties that assigned to selected config group overridenConfigs = overridenConfigs.concat(configs.filterProperty('group') - .filter(function(config) { return config.get('group.name') == self.get('selectedConfigGroup.name'); })); - - if (App.get('supports.enhancedConfigs')) { - - this.loadConfigsToModel(overridenConfigs, this.get('selectedVersion')); - - this.saveEnhancedConfigsAndGroup(this.get('selectedConfigGroup')); + .filter(function (config) { + return config.get('group.name') == self.get('selectedConfigGroup.name'); + })); - } else { - this.formatConfigValues(overridenConfigs); - selectedConfigGroup.get('hosts').forEach(function (hostName) { - groupHosts.push({"host_name": hostName}); - }); + this.formatConfigValues(overridenConfigs); + selectedConfigGroup.get('hosts').forEach(function (hostName) { + groupHosts.push({"host_name": hostName}); + }); - this.putConfigGroupChanges({ - ConfigGroup: { - "id": selectedConfigGroup.get('id'), - "cluster_name": App.get('clusterName'), - "group_name": selectedConfigGroup.get('name'), - "tag": selectedConfigGroup.get('service.id'), - "description": selectedConfigGroup.get('description'), - "hosts": groupHosts, - "service_config_version_note": this.get('serviceConfigVersionNote'), - "desired_configs": this.buildGroupDesiredConfigs(overridenConfigs) - } - }, true); - } + /** + * if there are some changes in dependent configs + * need to save these config to in separate request + */ + this.saveDependentGroups(); + + this.putConfigGroupChanges({ + ConfigGroup: { + "id": selectedConfigGroup.get('id'), + "cluster_name": App.get('clusterName'), + "group_name": selectedConfigGroup.get('name'), + "tag": selectedConfigGroup.get('service.id'), + "description": selectedConfigGroup.get('description'), + "hosts": groupHosts, + "service_config_version_note": this.get('serviceConfigVersionNote'), + "desired_configs": this.buildGroupDesiredConfigs(overridenConfigs) + } + }, true); } }, @@ -1658,7 +1581,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM if (showPopup) { ajaxOptions.success = "putConfigGroupChangesSuccess"; } - App.ajax.send(ajaxOptions); + return App.ajax.send(ajaxOptions); }, putConfigGroupChangesSuccess: function () { @@ -2021,7 +1944,9 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM * adding config tags for dependentConfigs */ for (var i = 0; i < this.get('dependentFileNames.length'); i++) { - serviceConfigTags.pushObject({siteName: this.get('dependentFileNames')[i]}); + if (!serviceConfigTags.findProperty('siteName', this.get('dependentFileNames')[i])) { + serviceConfigTags.pushObject({siteName: this.get('dependentFileNames')[i]}); + } } this.setNewTagNames(serviceConfigTags); var siteNameToServerDataMap = {}; @@ -2035,7 +1960,29 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM }, this); configsToSave = this.filterChangedConfiguration(configsToSave); if (configsToSave.length > 0) { - this.doPUTClusterConfigurationSites(configsToSave); + var data = []; + data.pushObject(JSON.stringify({ + Clusters: { + desired_config: configsToSave + } + })); + if (App.get('supports.enhancedConfigs')) { + /** + * adding configs that were changed for dependent services + * if there are such configs + */ + this.get('dependentServiceNames').forEach(function(serviceName) { + var dependentConfigsToSave = this.getDependentConfigObject(serviceName); + if (dependentConfigsToSave.length > 0) { + data.pushObject(JSON.stringify({ + Clusters: { + desired_config: dependentConfigsToSave + } + })); + } + }, this); + } + this.doPUTClusterConfigurationSites(data); } else { this.onDoPUTClusterConfigurations(); } @@ -2183,15 +2130,15 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM /** * Saves configuration of set of sites. The provided data * contains the site name and tag to be used. - * @param {Object} sites + * @param {Object[]} services * @method doPUTClusterConfigurationSites */ - doPUTClusterConfigurationSites: function (sites) { + doPUTClusterConfigurationSites: function (services) { App.ajax.send({ - name: 'common.service.configurations', + name: 'common.across.services.configurations', sender: this, data: { - desired_config: sites + data: '[' + services.toString() + ']' }, success: 'doPUTClusterConfigurationSiteSuccessCallback', error: 'doPUTClusterConfigurationSiteErrorCallback' @@ -2640,9 +2587,10 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM * add new overridden property to config property object * @param {object} serviceConfigProperty - config property object * @param {App.ConfigGroup} group - config group for new property + * @param {String} value * @method addOverrideProperty */ - addOverrideProperty: function (serviceConfigProperty, group) { + addOverrideProperty: function (serviceConfigProperty, group, value) { var overrides = serviceConfigProperty.get('overrides'); if (!overrides) { overrides = []; @@ -2650,7 +2598,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM } // create new override with new value var newSCP = App.ServiceConfigProperty.create(serviceConfigProperty); - newSCP.set('value', ''); + newSCP.set('value', value || ''); newSCP.set('isOriginalSCP', false); // indicated this is overridden value, newSCP.set('parentSCP', serviceConfigProperty); newSCP.set('isEditable', true); http://git-wip-us.apache.org/repos/asf/ambari/blob/9f87c98d/ambari-web/app/messages.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js index 50d62f0..42a0aaa 100644 --- a/ambari-web/app/messages.js +++ b/ambari-web/app/messages.js @@ -255,6 +255,7 @@ Em.I18n.translations = { 'common.minutes': "Minutes", 'common.seconds': "Seconds", 'common.milliseconds': "Milliseconds", + 'common.configGroup': 'Config Group', 'models.alert_instance.tiggered.verbose': "Occured on {0} <br> Checked on {1}", 'models.alert_definition.triggered.verbose': "Occured on {0}", @@ -344,6 +345,8 @@ Em.I18n.translations = { 'popup.dependent.configs.table.currentValue': 'Current value', 'popup.dependent.configs.table.recommendedValue': 'Recommended value', + 'popup.dependent.configs.select.config.group': 'Please select to which config group would you like to save dependent properties', + 'login.header':'Sign in', 'login.username':'Username', 'login.loginButton':'Sign in', http://git-wip-us.apache.org/repos/asf/ambari/blob/9f87c98d/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 a661ddb..61c2a2e 100644 --- a/ambari-web/app/mixins/common/configs/enhanced_configs.js +++ b/ambari-web/app/mixins/common/configs/enhanced_configs.js @@ -17,127 +17,131 @@ */ var App = require('app'); +var blueprintUtils = require('utils/blueprint'); App.EnhancedConfigsMixin = Em.Mixin.create({ - modifiedFileNames: [], - /** - * merge step configs from model - * for default config group properties should be list - * of changed properties - * @param properties - * @param currentVersionNumber + * values for dependent configs + * @type {Object[]} + * ex: + * { + * saveRecommended: {boolean}, //by default is true (checkbox binding) + * fileName: {string}, //file name without '.xml' + * propertyName: {string}, + * configGroup: {string}, + * value: {string}, + * serviceName: {string}, + * recommendedValue: {string} + * } + * @private */ - loadConfigsToModel: function(properties, currentVersionNumber) { - var serviceName = this.get('content.serviceName'); - if (properties && properties.length) { - properties.forEach(function(p) { - var configFromModel = App.ConfigProperty.find(p.get('name') + '_' + App.config.getConfigTagFromFileName(p.get('filename')) + '_' + currentVersionNumber); - if (configFromModel && configFromModel.get('name')) { - configFromModel.setProperties({ - 'value': p.get('value'), - 'isFinal': p.get('isFinal'), - 'defaultValue': p.get('defaultValue'), - 'defaultIsFinal': p.get('defaultIsFinal'), - 'isRequiredByAgent': p.get('isRequiredByAgent'), - 'isNotSaved': p.get('isNotSaved') - }); - } else { - App.store.load(App.ConfigProperty, { - id: p.get('name') + '_' + App.config.getConfigTagFromFileName(p.get('filename')) + '_' + currentVersionNumber, - name: p.get('name'), - file_name: p.get('filename'), - value: p.get('value'), - is_final: p.get('isFinal'), - default_value: p.get('defaultValue'), - default_is_final: p.get('defaultIsFinal'), - is_required_by_agent: p.get('isRequiredByAgent'), - is_not_saved: p.get('isNotSaved'), - is_required: false, - config_version_id: serviceName + '_' + currentVersionNumber - }) - } - }); - } - }, + _dependentConfigValues: [], /** - * generates data and save configs for default group - * @method saveEnhancedConfigs + * dependent file names for configs + * @type {string[]} */ - saveEnhancedConfigs: function() { + dependentFileNames: [], - var fileNamesToSave = this.getFileNamesToSave(this.get('modifiedFileNames')); + /** + * dependent service names for configs + * @type {string[]} + */ + dependentServiceNames: [], - var configsToSave = this.getConfigsToSave(fileNamesToSave); + /** + * config groups for dependent services + * @type {App.ConfigGroup[]} + */ + dependentConfigGroups: [], - var desired_configs = this.generateDesiredConfigsJSON(configsToSave, fileNamesToSave, this.get('serviceConfigNote')); + /** + * contains config group name that need to be saved + * { + * serviceName: configGroupName + * } + * @type {Object} + */ + groupsToSave: {}, - this.doPUTClusterConfigurationSites(desired_configs); - }, + /***********************************METHODS THAT WORKS WITH MODEL ********************************************/ /** - * generates data and save configs for not default group - * @param selectedConfigGroup - * @method saveEnhancedConfigsAndGroup + * generates desired_config objects for default config group + * @returns {Object} + * @method getDependentConfigObject */ - saveEnhancedConfigsAndGroup: function(selectedConfigGroup) { - //TODO update for dependent configs - var serviceConfigVersion = App.ConfigVersion.find().findProperty('groupName', selectedConfigGroup.get('name')); + getDependentConfigObject: function(serviceName) { - var overridenConfigs = App.ConfigProperty.find().filter(function(cp) { - return cp.get('configVersion.groupId') === selectedConfigGroup.get('id') || cp.get('isNotDefaultValue'); - }); + var fileNamesToSave = this._getFileNamesToSave(serviceName); - var hostNames = serviceConfigVersion.get('hosts').map(function(hostName) { - return { - "host_name": hostName - } - }); + var configsToSave = this._getConfigsToSave(fileNamesToSave); - var fileNamesToSave = overridenConfigs.mapProperty('fileName').uniq(); - - this.putConfigGroupChanges({ - ConfigGroup: { - "id": selectedConfigGroup.get('id'), - "cluster_name": App.get('clusterName'), - "group_name": selectedConfigGroup.get('name'), - "tag": selectedConfigGroup.get('service.id'), - "description": selectedConfigGroup.get('description'), - "hosts": hostNames, - "service_config_version_note": this.get('serviceConfigNote'), - "desired_configs": this.generateDesiredConfigsJSON(overridenConfigs, fileNamesToSave, null, true) - } - }, true); + return this.generateDesiredConfigsJSON(configsToSave, fileNamesToSave, this.get('serviceConfigNote')); }, /** - * get file names that need to be saved - * @param {Array} modifiedFileNames - * @returns {Ember.Enumerable} + * generates data and save configs for not default groups only + * that uses configs from model App.ConfigProperty + * @param serviceName + * @param configGroup + * @method saveEnhancedConfigsAndGroup */ - getFileNamesToSave: function(modifiedFileNames) { - return App.ConfigProperty.find().filter(function(cp) { - return cp.get('isNotDefaultValue') || cp.get('isNotSaved'); - }, this).mapProperty('fileName').concat(modifiedFileNames).uniq(); + saveModelConfigsWithGroup: function(serviceName, configGroup) { + /** + * for now we are saving configs from model only for dependent services + * so excluding situation in current service is trying to be saved + * this is temporary solution + */ + if (this.get('content.serviceName') !== serviceName) { + + var configsToSave = App.ConfigProperty.find().filter(function(cp) { + return cp.get('configVersion.groupName') == configGroup.get('name') || cp.get('isNotSaved'); + }); + if (configsToSave.length > 0) { + var hostNames = configGroup.get('hosts').map(function(hostName) { + return { + "host_name": hostName + } + }); + + var fileNamesToSave = configsToSave.mapProperty('fileName').uniq(); + + this.putConfigGroupChanges({ + ConfigGroup: { + "id": configGroup.get('id'), + "cluster_name": App.get('clusterName'), + "group_name": configGroup.get('name'), + "tag": configGroup.get('service.id'), + "description": configGroup.get('description'), + "hosts": hostNames, + "service_config_version_note": this.get('serviceConfigNote'), + "desired_configs": this.generateDesiredConfigsJSON(configsToSave, fileNamesToSave, null, true) + } + }) + } + } }, /** - * get configs that need to be saved, for default group - * @param fileNamesToSave - * @returns {App.ConfigProperty[]} + * save configs from model to default config group + * @param serviceName */ - getConfigsToSave: function(fileNamesToSave) { - if (Em.isArray(fileNamesToSave) && fileNamesToSave.length) { - return App.ConfigProperty.find().filter(function(cp) { - return (fileNamesToSave.contains(cp.get('fileName')) && cp.get('isOriginalSCP')) || cp.get('isNotSaved'); - }); - } else { - return Em.A([]); + saveModelConfigs: function(serviceName) { + var desired_configs = this.getDependentConfigObject(serviceName); + if (desired_configs.length > 0) { + var data = [JSON.stringify({ + Clusters: { + desired_config: desired_configs + } + })]; + this.doPUTClusterConfigurationSites(data); } }, + /********************************METHODS THAT GENERATES JSON TO SAVE *****************************************/ + /** * generating common JSON object for desired configs * @param configsToSave @@ -250,13 +254,403 @@ App.EnhancedConfigsMixin = Em.Mixin.create({ } }, + /******************************METHODS THAT WORKS WITH DEPENDENT CONFIGS *************************************/ + + /** + * clear values for dependent configs + * @method clearDependentConfigs + * @private + */ + clearDependentConfigs: function() { + this.set('groupsToSave', {}); + this.set('_dependentConfigValues', []); + }, + + onConfigGroupChangeForEnhanced: function() { + this.clearDependentConfigs(); + }.observes('selectedConfigGroup'), + + + /** + * saves properties for dependent service to config group based on <code>groupsToSave<code> + */ + saveDependentGroups: function() { + if (App.get('supports.enhancedConfigs') && this.get('dependentServiceNames.length') && Object.keys(this.get('groupsToSave')).length > 0) { + + this.get('dependentServiceNames').forEach(function(serviceName) { + if (this.get('groupsToSave')[serviceName]) { + if (this.get('groupsToSave')[serviceName].contains('Default')) { + this.saveModelConfigs(serviceName); + } else { + this.saveModelConfigsWithGroup(serviceName, this.get('dependentConfigGroups').findProperty('name', this.get('groupsToSave')[serviceName])); + } + } + }, this); + + } + }, + + + /** + * runs <code>setDependentServicesAndFileNames<code> + * for stack properties for current service + * @method loadDependentConfigs + */ + setDependentServices: function(serviceName) { + App.StackConfigProperty.find().forEach(function(stackProperty) { + if (stackProperty.get('serviceName') === serviceName && stackProperty.get('propertyDependedBy.length') > 0) { + this._setDependentServicesAndFileNames(stackProperty); + } + }, this); + }, + /** - * overriden in controller + * get service for current config type + * @param {String} configType - config fileName without xml + * @return App.StackService */ - doPUTClusterConfigurationSites: Em.K, + getServiceByConfigType: function(configType) { + return App.StackService.find().find(function(s) { + return Object.keys(s.get('configTypes')).contains(configType); + }); + }, + + /** + * show popup to select config group for dependent services + * to which dependent configs will ve saved + * @method showSelectGroupsPopup + */ + showSelectGroupsPopup: function(callback) { + var servicesWithConfigGroups = []; + this.get('dependentServiceNames').forEach(function(serviceName) { + if (serviceName !== this.get('content.serviceName')) { + if (!this.get('groupsToSave')[serviceName]) { + var groups = this.get('dependentConfigGroups').filterProperty('service.serviceName', serviceName).mapProperty('name').uniq(); + servicesWithConfigGroups.push({ + serviceName: serviceName, + configGroupNames: groups + }) + } + } + }, this); + if (servicesWithConfigGroups.length > 0) { + App.showSelectGroupsPopup(servicesWithConfigGroups, this.get('groupsToSave'), callback); + } else { + callback(); + } + }, + + + /** + * sends request to get values for dependent configs + * @param changedConfigs + * @returns {$.ajax|null} + */ + getRecommendationsForDependencies: function(changedConfigs) { + if (Em.isArray(changedConfigs) && changedConfigs.length > 0) { + var recommendations = this.get('hostGroups'); + var configs = this._getConfigsByGroup(this.get('stepConfigs')); + recommendations.blueprint.configurations = blueprintUtils.buildConfigsJSON(this.get('services'), configs); + + var dataToSend = { + recommend: 'configurations', + hosts: this.get('hostNames'), + services: this.get('serviceNames'), + recommendations: recommendations + }; + /** TODO uncomment when be will be ready + if (App.get('supports.enhancedConfigs')) { + dataToSend.recommend = 'configuration-dependencies'; + dataToSend.changed_configurations = changedConfigs; + } + **/ + return App.ajax.send({ + name: 'config.recommendations', + sender: this, + data: { + stackVersionUrl: App.get('stackVersionURL'), + dataToSend: dataToSend + }, + success: 'dependenciesSuccess', + error: 'dependenciesError' + }); + } else { + return null; + } + }, /** - * overriden in controller + * shows popup with results for recommended value + * if case properties that was changes belongs to not default group + * user should pick to what config group from dependent service dependent properties will be saved + * @param data + * @method dependenciesSuccess */ - putConfigGroupChanges: Em.K + dependenciesSuccess: function (data) { + var self = this; + if (!this.get('selectedConfigGroup.isDefault')) { + self.showSelectGroupsPopup(function () { + self._saveRecommendedValues(data); + if (self.get('_dependentConfigValues.length') > 0) { + App.showDependentConfigsPopup(self.get('_dependentConfigValues'), function () { + self._saveDependentConfigs(); + }); + } + }); + } else { + self._saveRecommendedValues(data); + if (self.get('_dependentConfigValues.length') > 0) { + App.showDependentConfigsPopup(self.get('_dependentConfigValues'), function () { + self._saveDependentConfigs(); + }); + } + } + }, + + /** + * + * @param jqXHR + * @param ajaxOptions + * @param error + * @param opt + */ + dependenciesError: function(jqXHR, ajaxOptions, error, opt) { + App.ajax.defaultErrorHandler(jqXHR, opt.url, opt.method, jqXHR.status); + }, + + + /** + * defines file names for configs and set them to <code>dependentFileNames<code> and + * defines service names for configs and set them to <code>dependentServiceNames<code> + * @param {App.StackConfigProperty} stackProperty + * @private + */ + _setDependentServicesAndFileNames: function(stackProperty) { + if (stackProperty.get('propertyDependedBy.length') > 0) { + stackProperty.get('propertyDependedBy').forEach(function(dependent) { + var tag = App.config.getConfigTagFromFileName(dependent.type); + /** setting dependent fileNames (without '.xml') **/ + if (!this.get('dependentFileNames').contains(tag)) { + this.get('dependentFileNames').push(tag); + } + /** setting dependent serviceNames (without current serviceName) **/ + var dependentProperty = App.StackConfigProperty.find(dependent.name + "_" + tag); + if (dependentProperty) { + if (!this.get('dependentServiceNames').contains(dependentProperty.get('serviceName')) && dependentProperty.get('serviceName') !== this.get('content.serviceName')) { + this.get('dependentServiceNames').push(dependentProperty.get('serviceName')); + } + this._setDependentServicesAndFileNames(dependentProperty); + } + }, this); + } + }, + + /** + * get file names that need to be saved + * used for default config group + * @param {String} serviceName + * @returns {Ember.Enumerable} + * @private + */ + _getFileNamesToSave: function(serviceName) { + return App.ConfigProperty.find().filter(function(cp) { + return cp.get('isNotDefaultValue') && cp.get('stackConfigProperty.serviceName') === serviceName; + }, this).mapProperty('fileName').uniq(); + }, + + /** + * get configs that need to be saved, for default group + * @param fileNamesToSave + * @returns {App.ConfigProperty[]} + * @private + */ + _getConfigsToSave: function(fileNamesToSave) { + if (Em.isArray(fileNamesToSave) && fileNamesToSave.length) { + return App.ConfigProperty.find().filter(function(cp) { + return fileNamesToSave.contains(cp.get('fileName')) && cp.get('configVersion.isCurrent'); + }); + } else { + return Em.A([]); + } + }, + + /** + * save values that are stored in <code>_dependentConfigValues<code> + * for current service to step configs + * for dependent services to model + * @private + */ + _saveDependentConfigs: function() { + var self = this; + this.get('_dependentConfigValues').forEach(function(dependentConfig) { + if (Em.get(dependentConfig, 'saveRecommended')) { // if saveRecommended is false leave properties as is + if (Em.get(dependentConfig, 'serviceName') === self.get('content.serviceName')) { //for current service save dependent properties to step configs + self.get('stepConfigs').objectAt(0).get('configs').forEach(function(stepConfig) { + if (stepConfig.get('filename') === App.config.getOriginalFileName(Em.get(dependentConfig, 'fileName')) + && stepConfig.get('name') === Em.get(dependentConfig, 'propertyName')) { + if (self.get('selectedConfigGroup.isDefault')) { + stepConfig.set('value', Em.get(dependentConfig, 'recommendedValue')) + } else { + if (!stepConfig.get('overrides')) { + stepConfig.set('overrides', Em.A([])); + } + var overridenConfig = stepConfig.get('overrides').findProperty('isEditable'); + if (overridenConfig) { + overridenConfig.set('value', Em.get(dependentConfig, 'recommendedValue')); + } else { + self.addOverrideProperty(stepConfig, self.get('selectedConfigGroup'), Em.get(dependentConfig, 'recommendedValue')); + } + } + } + }) + } else { //for not current service save dependent properties to model + + App.ConfigProperty.find().forEach(function(cp) { + if (cp.get('name') === Em.get(dependentConfig, 'propertyName') + && cp.get('fileName') === App.config.getOriginalFileName(Em.get(dependentConfig, 'fileName'))) { + + if (self.get('selectedConfigGroup.isDefault') || Em.get(dependentConfig, 'configGroup').contains('Default')) { + if (cp.get('isOriginalSCP')) { + cp.set('value', Em.get(dependentConfig, 'recommendedValue')) + } + } else { + if (cp.get('configVersion.groupName') === self.get('groupsToSave')[dependentConfig.serviceName]) { + cp.set('value', Em.get(dependentConfig, 'recommendedValue')); + } else { + App.store.load(App.ConfigProperty, { + id: Em.get(dependentConfig, 'propertyName') + '_' + Em.get(dependentConfig, 'fileName') + '_', + name: Em.get(dependentConfig, 'propertyName'), + value: Em.get(dependentConfig, 'recommendedValue'), + file_name: App.config.getOriginalFileName(Em.get(dependentConfig, 'fileName')), + is_not_saved: true + }) + } + } + + } + }); + } + } + }); + }, + + /** + * get array of config objects for current service depends on config group + * for default group - it will be current stepConfigs + * for not default group - overriden property in case there is such property in group + * otherwise - property from default group + * @param stepConfigs + * @returns {App.ServiceConfigProperty[]} + * @private + */ + _getConfigsByGroup: function(stepConfigs) { + var configsToSend = []; + if (this.get('selectedConfigGroup.isDefault')) { + return stepConfigs; + } else { + stepConfigs.forEach(function(stepConfig) { + if (stepConfig.get('overrides')) { + var conf = stepConfig.get('overrides').findProperty('group.name', this.get('selectedConfigGroup.name')); + if (conf) { + configsToSend.pushObject(conf); + } else { + configsToSend.pushObject(stepConfig); + } + } else { + configsToSend.pushObject(stepConfig); + } + }, this) + } + return configsToSend; + }, + + /** + * saves values from response for dependent configs to <code>_dependentConfigValues<code> + * @param data + * @method saveRecommendedValues + * @private + */ + _saveRecommendedValues: function(data) { + Em.assert('invalid data', data && data.resources[0] && Em.get(data.resources[0], 'recommendations.blueprint.configurations')); + var configs = data.resources[0].recommendations.blueprint.configurations; + for (var key in configs) { + for (var propertyName in configs[key].properties) { + var service = this.getServiceByConfigType(key); + var value = this._getCurrentValue(service.get('serviceName'), key, propertyName, this.get('selectedConfigGroup')); + if (!Em.isNone(value)) { + var dependentProperty = this.get('_dependentConfigValues').findProperty('propertyName', propertyName); + if (dependentProperty) { + if (value != configs[key].properties[propertyName]) { + Em.set(dependentProperty, 'value', value); + Em.set(dependentProperty, 'recommendedValue', configs[key].properties[propertyName]); + } else { + this.get('_dependentConfigValues').removeObject(dependentProperty); + } + } else { + var configGroup = this.get('selectedConfigGroup.isDefault') ? + service.get('serviceName') + ' Default' : this.get('groupsToSave')[service.get('serviceName')] || this.get('selectedConfigGroup.name'); + if (value != configs[key].properties[propertyName]) { + this.get('_dependentConfigValues').pushObject({ + saveRecommended: true, + fileName: key, + propertyName: propertyName, + configGroup: configGroup, + value: value, + serviceName: service.get('serviceName'), + recommendedValue: configs[key].properties[propertyName] + }); + } + } + } + } + } + }, + + /** + * get current value for property by serviceName, tag and ConfigGroup + * @param serviceName + * @param tag + * @param propertyName + * @param configGroup + * @returns {null|Object} + * @private + */ + _getCurrentValue: function(serviceName, tag, propertyName, configGroup) { + if (serviceName == this.get('content.serviceName')) { + var stepConfig = this.get('stepConfigs').objectAt(0).get('configs').find(function(stepConfig) { + return (stepConfig.get('filename') === App.config.getOriginalFileName(tag) && stepConfig.get('name') === propertyName); + }); + if (stepConfig) { + if (configGroup.get('isDefault') || Em.isNone(stepConfig.get('overrides'))) { + return stepConfig.get('value'); + } else { + var overridenConfig = stepConfig.get('overrides').findProperty('isEditable'); + if (overridenConfig) { + return overridenConfig.get('value'); + } else { + return stepConfig.get('value'); + } + } + } + } else { + var currentDefaultProperties = App.ConfigProperty.find().filter(function(cp) { + return cp.get('configVersion.isCurrent') && cp.get('configVersion.isDefault'); + }); + if (!this.get('selectedConfigGroup.isDefault') && (!this.get('groupsToSave')[serviceName] || !this.get('groupsToSave')[serviceName].contains('Default'))) { + var currentProperties = App.ConfigProperty.find().filter(function(cp) { + return cp.get('configVersion.isCurrent') && cp.get('configVersion.groupName') === this.get('groupsToSave')[serviceName]; + }, this); + var modelConfig = currentProperties.findProperty('name', propertyName); + if (modelConfig) { + return modelConfig.get('value'); + } + } + + var modelDefaultConfig = currentDefaultProperties.findProperty('name', propertyName); + if (modelDefaultConfig) { + return modelDefaultConfig.get('value'); + } + } + return null; + } }); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/9f87c98d/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 4c89182..d6eeef3 100644 --- a/ambari-web/app/mixins/common/serverValidator.js +++ b/ambari-web/app/mixins/common/serverValidator.js @@ -135,83 +135,6 @@ App.ServerValidatorMixin = Em.Mixin.create({ }, /** - * - * @param changedConfigs - * @returns {$.ajax|null} - */ - getRecommendationsForDependencies: function(changedConfigs) { - if (Em.isArray(changedConfigs) && changedConfigs.length > 0) { - var recommendations = this.get('hostGroups'); - recommendations.blueprint.configurations = blueprintUtils.buildConfigsJSON(this.get('services'), this.get('stepConfigs')); - - var dataToSend = { - recommend: 'configurations', - hosts: this.get('hostNames'), - services: this.get('serviceNames'), - recommendations: recommendations - }; - /** TODO uncomment when be will be ready - if (App.get('supports.enhancedConfigs')) { - dataToSend.recommend = 'configuration-dependencies'; - dataToSend.changed_configurations = changedConfigs; - } - **/ - return App.ajax.send({ - name: 'config.recommendations', - sender: this, - data: { - stackVersionUrl: App.get('stackVersionURL'), - dataToSend: dataToSend - }, - success: 'dependenciesSuccess', - error: 'dependenciesError' - }); - } else { - return null; - } - }, - - /** - * - * @param data - */ - dependenciesSuccess: function(data) { - Em.assert('invalid data', data && data.resources[0] && Em.get(data.resources[0], 'recommendations.blueprint.configurations')); - var configs = data.resources[0].recommendations.blueprint.configurations; - - this.loadConfigsToModel(this.get('stepConfigs')[0].get('configs'), this.get('selectedVersion')); - - var currentProperties = App.ConfigProperty.find().filterProperty('configVersion.isCurrent').filterProperty('configVersion.groupId', -1); - for (var key in configs) { - for (var propertyName in configs[key].properties) { - var property = currentProperties.findProperty('name', propertyName) - if (property) { - property.set('recommendedValue', configs[key].properties[propertyName]); - } - } - } - - var configsToShow = currentProperties.filter(function(p) { - return p.get('recommendedValue') && p.get('recommendedValue') !== p.get('value'); - }); - - if (configsToShow.length > 0) { - App.showDependentConfigsPopup(configsToShow); - } - }, - - /** - * - * @param jqXHR - * @param ajaxOptions - * @param error - * @param opt - */ - dependenciesError: function(jqXHR, ajaxOptions, error, opt) { - App.ajax.defaultErrorHandler(jqXHR, opt.url, opt.method, jqXHR.status); - }, - - /** * @method loadRecommendationsSuccess * success callback after loading recommendations * (used only during install) http://git-wip-us.apache.org/repos/asf/ambari/blob/9f87c98d/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 926c5ea..3c02de9 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 @@ -25,8 +25,9 @@ <tr> <th>{{t popup.dependent.configs.table.saveProperty}}</th> <th>{{t common.property}}</th> - <th>{{t common.fileName}}</th> <th>{{t common.service}}</th> + <th>{{t common.configGroup}}</th> + <th>{{t common.fileName}}</th> <th>{{t popup.dependent.configs.table.currentValue}}</th> <th>{{t popup.dependent.configs.table.recommendedValue}}</th> </tr> @@ -35,9 +36,10 @@ {{#each config in view.parentView.configs}} <tr> <td>{{view Em.Checkbox checkedBinding="config.saveRecommended"}}</td> - <td>{{config.name}}</td> + <td>{{config.propertyName}}</td> + <td>{{config.serviceName}}</td> + <td>{{config.configGroup}}</td> <td>{{config.fileName}}</td> - <td>{{config.stackConfigProperty.serviceName}}</td> <td>{{config.value}}</td> <td>{{config.recommendedValue}}</td> </tr> http://git-wip-us.apache.org/repos/asf/ambari/blob/9f87c98d/ambari-web/app/templates/common/modal_popups/select_groups_popup.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/common/modal_popups/select_groups_popup.hbs b/ambari-web/app/templates/common/modal_popups/select_groups_popup.hbs new file mode 100644 index 0000000..09ee681 --- /dev/null +++ b/ambari-web/app/templates/common/modal_popups/select_groups_popup.hbs @@ -0,0 +1,32 @@ +{{! +* 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. +}} + +<div class="alert alert-warning"> + {{t popup.dependent.configs.select.config.group}} +</div> +<form class="form-horizontal"> +{{#each service in view.parentView.dependentServices}} + <div class="form-group"> + <label class="col-sm-2 control-label">{{service.serviceName}} </label> + <div class="col-sm-8"> + {{view App.selectConfigGroupForService contentBinding="service.configGroupNames" serviceNameBinding="service.serviceName" groupsToSaveBinding="groupsToSave"}} + </div> + </div> +{{/each}} +</form> + http://git-wip-us.apache.org/repos/asf/ambari/blob/9f87c98d/ambari-web/app/views.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views.js b/ambari-web/app/views.js index 8d099b1..b19b535 100644 --- a/ambari-web/app/views.js +++ b/ambari-web/app/views.js @@ -34,6 +34,7 @@ require('views/common/modal_popups/reload_popup'); require('views/common/modal_popups/cluster_check_popup'); require('views/common/modal_popups/invalid_KDC_popup'); require('views/common/modal_popups/dependent_configs_list_popup'); +require('views/common/modal_popups/select_groups_popup'); require('views/common/editable_list'); require('views/common/rolling_restart_view'); require('views/common/select_custom_date_view'); http://git-wip-us.apache.org/repos/asf/ambari/blob/9f87c98d/ambari-web/app/views/common/modal_popups/dependent_configs_list_popup.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/common/modal_popups/dependent_configs_list_popup.js b/ambari-web/app/views/common/modal_popups/dependent_configs_list_popup.js index 73ed1f6..4c221ba 100644 --- a/ambari-web/app/views/common/modal_popups/dependent_configs_list_popup.js +++ b/ambari-web/app/views/common/modal_popups/dependent_configs_list_popup.js @@ -32,7 +32,7 @@ App.showDependentConfigsPopup = function (configs, callback, secondaryCallback) primary: Em.I18n.t('common.save'), secondary: Em.I18n.t('common.cancel'), header: Em.I18n.t('popup.dependent.configs.header'), - classNames: ['full-width-modal'], + classNames: ['sixty-percent-width-modal','modal-full-width'], configs: configs, bodyClass: Em.View.extend({ templateName: require('templates/common/modal_popups/dependent_configs_list') @@ -42,21 +42,13 @@ App.showDependentConfigsPopup = function (configs, callback, secondaryCallback) }.property('controller.stepConfigs.@each'), onPrimary: function () { this.hide(); - configs.filterProperty('saveRecommended', true).forEach(function(c) { - c.set('value', c.get('recommendedValue')); - var stepConfig = this.get('stepConfigs').find(function(stepConf) { - return stepConf.get('name') === c.get('name') && stepConf.get('filename') === c.get('fileName'); - }); - if (stepConfig) { - stepConfig.set('value', c.get('recommendedValue')); - } - }, this); if (callback) { callback(); } }, onSecondary: function() { this.hide(); + configs.setEach('saveRecommended', false); if(secondaryCallback) { secondaryCallback(); } http://git-wip-us.apache.org/repos/asf/ambari/blob/9f87c98d/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 new file mode 100644 index 0000000..0448cdf --- /dev/null +++ b/ambari-web/app/views/common/modal_popups/select_groups_popup.js @@ -0,0 +1,77 @@ +/** + * 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'); + +/** + * Show confirmation popup + * @param {[Object]} servicesWithGroups + * @param {Object} groupsToSave + * @param {function} [callback=null] + * @param {function} [secondaryCallback=null] + * we use this parameter to defer saving configs before we make some decisions. + * @return {App.ModalPopup} + */ +App.showSelectGroupsPopup = function (servicesWithGroups, groupsToSave, callback, secondaryCallback) { + return App.ModalPopup.show({ + encodeBody: false, + primary: Em.I18n.t('common.save'), + secondary: Em.I18n.t('common.cancel'), + header: Em.I18n.t('popup.dependent.configs.header'), + dependentServices: servicesWithGroups, + groupsToSave: groupsToSave, + bodyClass: Em.View.extend({ + templateName: require('templates/common/modal_popups/select_groups_popup') + }), + + onPrimary: function () { + this._super(); + if (callback) { + callback(); + } + }, + + onSecondary: function() { + this._super(); + if(secondaryCallback) { + secondaryCallback(); + } + } + }); +}; + +App.selectConfigGroupForService = Ember.Select.extend({ + + /** + * set Default group by default + */ + didInsertElement: function() { + var defaultVersion = this.get('content').find(function(cg) { + return cg.contains('Default'); + }); + this.set('value', defaultVersion); + }, + + /** + * + */ + onChangeValue: function() { + var groupsToSave = this.get('groupsToSave'); + groupsToSave[this.get('serviceName')] = this.get('value'); + }.observes('value') +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/9f87c98d/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 9de9f39..9614e3a 100644 --- a/ambari-web/test/controllers/main/service/info/config_test.js +++ b/ambari-web/test/controllers/main/service/info/config_test.js @@ -1315,47 +1315,4 @@ describe("App.MainServiceInfoConfigsController", function () { }); }); - describe('#calculateDependentFileNames()', function() { - - beforeEach(function() { - mainServiceInfoConfigsController.set('dependentFileNames', []); - App.resetDsStoreTypeMap(App.StackConfigProperty); - App.StackConfigProperty.createRecord({id: 'name1_site1', propertyDependedBy: [{ - type: 'site2', - name: 'name2' - }]}); - App.StackConfigProperty.createRecord({id: 'name2_site2', propertyDependedBy: [{ - type: 'site3', - name: 'name3' - }, - { - type: 'site4', - name: 'name4' - }] - }); - App.StackConfigProperty.createRecord({id: 'name3_site3', propertyDependedBy: []}); - App.StackConfigProperty.createRecord({id: 'name4_site4', propertyDependedBy: []}); - }); - - it('adds all file names that need to be loaded to dependentFileNames', function() { - mainServiceInfoConfigsController.calculateDependentFileNames(App.StackConfigProperty.find('name1_site1')); - expect(mainServiceInfoConfigsController.get('dependentFileNames').toArray()).to.eql(["site2", "site3", "site4"]); - }); - }); - - describe('#getServiceNamesForConfigs()', function() { - it('returns serviceNames which configs need to be loaded', function() { - mainServiceInfoConfigsController.set('content', {}); - mainServiceInfoConfigsController.set('content.serviceName', 'currentService'); - mainServiceInfoConfigsController.set('dependentFileNames', ['site1', 'site2']); - App.resetDsStoreTypeMap(App.StackService); - App.StackService.createRecord({id: 'service1', serviceName: 'service1', configTypes: {'site1':'site1'}}); - App.StackService.createRecord({id: 'service2', serviceName: 'service2', configTypes: {'site1':'site1', 'site2': 'site2'}}); - App.StackService.createRecord({id: 'service3', serviceName: 'service3', configTypes: {'site3':'site3'}}); - expect(mainServiceInfoConfigsController.getServiceNamesForConfigs()).to.eql(['service1', 'service2', 'currentService']); - }); - - - }); - }); http://git-wip-us.apache.org/repos/asf/ambari/blob/9f87c98d/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 eacfea5..babbd3b 100644 --- a/ambari-web/test/mixins/common/configs/enhanced_configs_test.js +++ b/ambari-web/test/mixins/common/configs/enhanced_configs_test.js @@ -22,22 +22,25 @@ describe('App.EnhancedConfigsMixin', function() { var mixinObject = Em.Controller.extend(App.EnhancedConfigsMixin, {}); var instanceObject = mixinObject.create({}); - describe('#getFileNamesToSave()', function() { + var stackProperty + describe('#_getFileNamesToSave()', function() { beforeEach(function() { App.resetDsStoreTypeMap(App.ConfigProperty); + App.resetDsStoreTypeMap(App.StackConfigProperty); + stackProperty = App.ConfigProperty.createRecord({id: '1', serviceName: 'service1'}); }); it('returns file names that was changed', function() { - App.ConfigProperty.createRecord({id: 'p1_c1', value:'1', defaultValue: '2', fileName: 'file1'}); - App.ConfigProperty.createRecord({id: 'p2_c1', value:'1', defaultValue: '1', fileName: 'file2'}); - expect(instanceObject.getFileNamesToSave(['file3'])).to.eql(['file1','file3']) + App.ConfigProperty.createRecord({id: 'p1_c1', value:'1', defaultValue: '2', fileName: 'file1', stackConfigProperty: stackProperty}); + App.ConfigProperty.createRecord({id: 'p2_c1', value:'1', defaultValue: '1', fileName: 'file2', stackConfigProperty: stackProperty}); + expect(instanceObject._getFileNamesToSave('service1')).to.eql(['file1']) }); - it('returns file names that was changed by adding property', function() { - App.ConfigProperty.createRecord({id: 'p1_c1', value:'1', defaultValue: '1', fileName: 'file1', isNotSaved: false}); - App.ConfigProperty.createRecord({id: 'p2_c1', value:'1', defaultValue: '1', fileName: 'file2', isNotSaved: true}); - expect(instanceObject.getFileNamesToSave(['file3'])).to.eql(['file2','file3']) + it('returns file names that was changed for current service', function() { + App.ConfigProperty.createRecord({id: 'p1_c1', value:'7', defaultValue: '1', fileName: 'file1', stackConfigProperty: stackProperty}); + App.ConfigProperty.createRecord({id: 'p2_c1', value:'8', defaultValue: '1', fileName: 'file2'}); + expect(instanceObject._getFileNamesToSave('service1')).to.eql(['file1']) }); });