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 2014/08/19 21:10:11 UTC
git commit: AMBARI-6922 FE: Ambari installer and service config page
should validate configs by calling /validations. (ababiichuk)
Repository: ambari
Updated Branches:
refs/heads/trunk 4644a826b -> 818dc161f
AMBARI-6922 FE: Ambari installer and service config page should validate configs by calling /validations. (ababiichuk)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/818dc161
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/818dc161
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/818dc161
Branch: refs/heads/trunk
Commit: 818dc161fe41b7f9b92e67042b3840e4a8158737
Parents: 4644a82
Author: aBabiichuk <ab...@cybervisiontech.com>
Authored: Tue Aug 19 22:03:23 2014 +0300
Committer: aBabiichuk <ab...@cybervisiontech.com>
Committed: Tue Aug 19 22:10:08 2014 +0300
----------------------------------------------------------------------
ambari-web/app/controllers/installer.js | 32 ++-
.../controllers/main/service/info/configs.js | 20 +-
.../app/controllers/wizard/step5_controller.js | 18 +-
.../app/controllers/wizard/step6_controller.js | 13 +-
.../app/controllers/wizard/step7_controller.js | 56 +----
ambari-web/app/messages.js | 4 +
ambari-web/app/mixins.js | 1 +
ambari-web/app/mixins/common/serverValidator.js | 239 +++++++++++++++++++
ambari-web/app/models/service_config.js | 15 +-
ambari-web/app/models/stack_service.js | 3 +
ambari-web/app/routes/installer.js | 11 +-
ambari-web/app/utils/blueprint.js | 81 +++++++
ambari-web/app/utils/config.js | 20 +-
ambari-web/test/utils/blueprint_test.js | 137 +++++++++++
14 files changed, 560 insertions(+), 90 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/818dc161/ambari-web/app/controllers/installer.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/installer.js b/ambari-web/app/controllers/installer.js
index 03c5afb..8b1fa1f 100644
--- a/ambari-web/app/controllers/installer.js
+++ b/ambari-web/app/controllers/installer.js
@@ -38,6 +38,15 @@ App.InstallerController = App.WizardController.extend({
slaveGroupProperties: null,
stacks: null,
clients:[],
+ /**
+ * recommendations for host groups loaded from server
+ */
+ recommendations: null,
+ /**
+ * recommendationsHostGroups - current component assignment after 5 and 6 steps
+ * (uses for host groups validation and to load recommended configs)
+ */
+ recommendationsHostGroups: null,
controllerName: 'installerController'
}),
@@ -64,7 +73,10 @@ App.InstallerController = App.WizardController.extend({
'stacksVersions',
'currentStep',
'serviceInfo',
- 'hostInfo'
+ 'hostInfo',
+ 'recommendations',
+ 'recommendationsHostGroups',
+ 'recommendationsConfigs'
],
init: function () {
@@ -467,6 +479,18 @@ App.InstallerController = App.WizardController.extend({
this.set("content.masterComponentHosts", masterComponentHosts);
},
+ loadRecommendations: function() {
+ this.set("content.recommendations", this.getDBProperty('recommendations'));
+ },
+
+ loadCurrentHostGroups: function() {
+ this.set("content.recommendationsHostGroups", this.getDBProperty('recommendationsHostGroups'));
+ },
+
+ loadRecommendationsConfigs: function() {
+ App.router.set("wizardStep7Controller.recommendationsConfigs", this.getDBProperty('recommendationsConfigs'));
+ },
+
/**
* Load master component hosts data for using in required step controllers
*/
@@ -685,6 +709,7 @@ App.InstallerController = App.WizardController.extend({
callback: function () {
this.loadMasterComponentHosts();
this.loadConfirmedHosts();
+ this.loadRecommendations();
}
}
],
@@ -694,6 +719,7 @@ App.InstallerController = App.WizardController.extend({
callback: function () {
this.loadSlaveComponentHosts();
this.loadClients();
+ this.loadRecommendations();
}
}
],
@@ -703,6 +729,8 @@ App.InstallerController = App.WizardController.extend({
callback: function () {
this.loadServiceConfigGroups();
this.loadServiceConfigProperties();
+ this.loadCurrentHostGroups();
+ this.loadRecommendationsConfigs();
}
}
]
@@ -739,7 +767,7 @@ App.InstallerController = App.WizardController.extend({
* Clear loaded recommendations
*/
clearRecommendations: function() {
- this.set('recommendations', undefined)
+ this.set('content.recommendations', undefined)
}
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/818dc161/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 a856d1e..a1b3677 100644
--- a/ambari-web/app/controllers/main/service/info/configs.js
+++ b/ambari-web/app/controllers/main/service/info/configs.js
@@ -21,7 +21,7 @@ require('controllers/wizard/slave_component_groups_controller');
var batchUtils = require('utils/batch_scheduled_requests');
var lazyLoading = require('utils/lazy_loading');
-App.MainServiceInfoConfigsController = Em.Controller.extend({
+App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorMixin, {
name: 'mainServiceInfoConfigsController',
isHostsConfigsPage: false,
forceTransition: false,
@@ -1091,15 +1091,17 @@ App.MainServiceInfoConfigsController = Em.Controller.extend({
(serviceName !== 'HDFS' && this.get('content.isStopped') === true) ||
((serviceName === 'HDFS') && this.get('content.isStopped') === true && (!App.Service.find().someProperty('id', 'MAPREDUCE') || App.Service.find('MAPREDUCE').get('isStopped')))) {
- if (this.isDirChanged()) {
- App.showConfirmationPopup(function () {
+ this.serverSideValidation().done(function() {
+ if (self.isDirChanged()) {
+ App.showConfirmationPopup(function () {
+ self.saveConfigs();
+ }, Em.I18n.t('services.service.config.confirmDirectoryChange').format(displayName), function () {
+ self.set('isApplyingChanges', false)
+ });
+ } else {
self.saveConfigs();
- }, Em.I18n.t('services.service.config.confirmDirectoryChange').format(displayName), function () {
- self.set('isApplyingChanges', false)
- });
- } else {
- this.saveConfigs();
- }
+ }
+ });
} else {
status = 'started';
if (this.get('content.serviceName') !== 'HDFS' || (this.get('content.serviceName') === 'HDFS' && !App.Service.find().someProperty('id', 'MAPREDUCE'))) {
http://git-wip-us.apache.org/repos/asf/ambari/blob/818dc161/ambari-web/app/controllers/wizard/step5_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/wizard/step5_controller.js b/ambari-web/app/controllers/wizard/step5_controller.js
index b82fa1c..7df1b8b 100644
--- a/ambari-web/app/controllers/wizard/step5_controller.js
+++ b/ambari-web/app/controllers/wizard/step5_controller.js
@@ -212,11 +212,11 @@ App.WizardStep5Controller = Em.Controller.extend({
return false;
}
- if (App.supports.serverRecommendValidate) {
+ if (App.get('supports.serverRecommendValidate')) {
self.set('submitDisabled', true);
// reset previous recommendations
- App.router.set('installerController.recommendations', null);
+ this.set('content.recommendations', null);
if (self.get('servicesMasters').length === 0) {
return;
@@ -375,7 +375,7 @@ App.WizardStep5Controller = Em.Controller.extend({
console.log("WizardStep5Controller: Loading step5: Assign Masters");
this.clearStep();
this.renderHostInfo();
- if (App.supports.serverRecommendValidate ) {
+ if (App.get('supports.serverRecommendValidate')) {
this.loadComponentsRecommendationsFromServer(this.loadStepCallback);
} else {
this.loadComponentsRecommendationsLocally(this.loadStepCallback);
@@ -478,7 +478,7 @@ App.WizardStep5Controller = Em.Controller.extend({
loadComponentsRecommendationsFromServer: function(callback, includeMasters) {
var self = this;
- if (App.router.get('installerController.recommendations')) {
+ if (this.get('content.recommendations')) {
// Don't do AJAX call if recommendations has been already received
// But if user returns to previous step (selecting services), stored recommendations will be cleared in routers' next handler and AJAX call will be made again
callback(self.createComponentInstallationObjects(), self);
@@ -523,7 +523,7 @@ App.WizardStep5Controller = Em.Controller.extend({
/**
* Create components for displaying component-host comboboxes in UI assign dialog
- * expects installerController.recommendations will be filled with recommendations API call result
+ * expects content.recommendations will be filled with recommendations API call result
* @return {Object[]}
*/
createComponentInstallationObjects: function() {
@@ -538,7 +538,7 @@ App.WizardStep5Controller = Em.Controller.extend({
var masterHosts = self.get('content.masterComponentHosts'); //saved to local storage info
var selectedNotInstalledServices = self.get('content.services').filterProperty('isSelected').filterProperty('isInstalled', false).mapProperty('serviceName');
- var recommendations = App.router.get('installerController.recommendations');
+ var recommendations = this.get('content.recommendations');
var resultComponents = [];
var multipleComponentHasBeenAdded = {};
@@ -616,7 +616,7 @@ App.WizardStep5Controller = Em.Controller.extend({
* @method loadRecommendationsSuccessCallback
*/
loadRecommendationsSuccessCallback: function (data) {
- App.router.set('installerController.recommendations', data.resources[0].recommendations);
+ this.set('content.recommendations', data.resources[0].recommendations);
},
/**
@@ -1025,7 +1025,7 @@ App.WizardStep5Controller = Em.Controller.extend({
// load recommendations with partial request
self.loadComponentsRecommendationsFromServer(function() {
// For validation use latest received recommendations because ir contains current master layout and recommended slave/client layout
- self.validate(App.router.get('installerController.recommendations'), function() {
+ self.validate(self.get('content.recommendations'), function() {
if (callback) {
callback();
}
@@ -1047,7 +1047,7 @@ App.WizardStep5Controller = Em.Controller.extend({
}
};
- if (App.supports.serverRecommendValidate ) {
+ if (App.get('supports.serverRecommendValidate')) {
self.recommendAndValidate(function() {
goNextStepIfValid();
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/818dc161/ambari-web/app/controllers/wizard/step6_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/wizard/step6_controller.js b/ambari-web/app/controllers/wizard/step6_controller.js
index a74f020..78c1254 100644
--- a/ambari-web/app/controllers/wizard/step6_controller.js
+++ b/ambari-web/app/controllers/wizard/step6_controller.js
@@ -377,7 +377,7 @@ App.WizardStep6Controller = Em.Controller.extend({
var clientHeaders = headers.findProperty('name', 'CLIENT');
var slaveComponents = this.get('content.slaveComponentHosts');
if (!slaveComponents) { // we are at this page for the first time
- if (!App.supports.serverRecommendValidate) {
+ if (!App.get('supports.serverRecommendValidate')) {
hostsObj.forEach(function (host) {
var checkboxes = host.get('checkboxes');
checkboxes.setEach('checked', !host.hasMaster);
@@ -393,7 +393,7 @@ App.WizardStep6Controller = Em.Controller.extend({
lastHost.get('checkboxes').setEach('checked', true);
}
} else {
- var recommendations = App.router.get('installerController.recommendations');
+ var recommendations = this.get('content.recommendations');
// Get all host-component pairs from recommendations
var componentHostPairs = recommendations.blueprint.host_groups.map(function (group) {
return group.components.map(function (component) {
@@ -495,7 +495,7 @@ App.WizardStep6Controller = Em.Controller.extend({
callValidation: function (successCallback) {
var self = this;
- if (App.supports.serverRecommendValidate) {
+ if (App.get('supports.serverRecommendValidate')) {
self.callServerSideValidation(successCallback);
} else {
var res = self.callClientSideValidation();
@@ -540,7 +540,7 @@ App.WizardStep6Controller = Em.Controller.extend({
var invisibleComponents = invisibleMasters.concat(invisibleSlaves).concat(alreadyInstalledClients);
- var invisibleBlueprint = blueprintUtils.filterByComponents(App.router.get('installerController.recommendations'), invisibleComponents);
+ var invisibleBlueprint = blueprintUtils.filterByComponents(this.get('content.recommendations'), invisibleComponents);
masterBlueprint = blueprintUtils.mergeBlueprints(masterBlueprint, invisibleBlueprint);
} else if (this.get('isAddHostWizard')) {
masterBlueprint = self.getMasterSlaveBlueprintForAddHostWizard();
@@ -548,6 +548,9 @@ App.WizardStep6Controller = Em.Controller.extend({
slaveBlueprint = blueprintUtils.addComponentsToBlueprint(slaveBlueprint, invisibleSlaves);
}
+ var bluePrintsForValidation = blueprintUtils.mergeBlueprints(masterBlueprint, slaveBlueprint);
+ this.set('content.recommendationsHostGroups', bluePrintsForValidation);
+
App.ajax.send({
name: 'config.validations',
sender: self,
@@ -556,7 +559,7 @@ App.WizardStep6Controller = Em.Controller.extend({
hosts: hostNames,
services: services,
validate: 'host_groups',
- recommendations: blueprintUtils.mergeBlueprints(masterBlueprint, slaveBlueprint)
+ recommendations: bluePrintsForValidation
},
success: 'updateValidationsSuccessCallback'
}).
http://git-wip-us.apache.org/repos/asf/ambari/blob/818dc161/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 bb222b5..6bf145c 100644
--- a/ambari-web/app/controllers/wizard/step7_controller.js
+++ b/ambari-web/app/controllers/wizard/step7_controller.js
@@ -29,7 +29,7 @@ var stringUtils = require('utils/string_utils');
*
*/
-App.WizardStep7Controller = Em.Controller.extend({
+App.WizardStep7Controller = Em.Controller.extend(App.ServerValidatorMixin, {
name: 'wizardStep7Controller',
@@ -113,8 +113,6 @@ App.WizardStep7Controller = Em.Controller.extend({
serviceConfigsData: require('data/service_configs'),
- recommendedConfigs: null,
-
/**
* Are advanced configs loaded
* @type {bool}
@@ -600,7 +598,7 @@ App.WizardStep7Controller = Em.Controller.extend({
var s = App.StackService.find(component.get('serviceName')),
defaultGroupSelected = component.get('selectedConfigGroup.isDefault');
- if(!App.supports.serverRecommendValidate) {
+ if(!App.get('supports.serverRecommendValidate')) {
if (s && s.get('configsValidator')) {
var recommendedDefaults = this._getRecommendedDefaultsForComponent(component.get('serviceName'));
s.get('configsValidator').set('recommendedDefaults', recommendedDefaults);
@@ -723,8 +721,8 @@ App.WizardStep7Controller = Em.Controller.extend({
}
//STEP 6: Distribute configs by service and wrap each one in App.ServiceConfigProperty (configs -> serviceConfigs)
var self = this;
- if (App.supports.serverRecommendValidate) {
- this.loadDefaultConfigs(function() {
+ if (App.get('supports.serverRecommendValidate')) {
+ this.loadServerSideConfigsRecommendations().complete(function() {
self.setStepConfigs(configs, storedConfigs);
self.checkHostOverrideInstaller();
self.activateSpecialConfigs();
@@ -771,7 +769,7 @@ App.WizardStep7Controller = Em.Controller.extend({
masterComponentHosts: this.get('wizardController.content.masterComponentHosts'),
slaveComponentHosts: this.get('wizardController.content.slaveComponentHosts')
};
- var serviceConfigs = App.config.renderConfigs(configs, storedConfigs, this.get('allSelectedServiceNames'), this.get('installedServiceNames'), localDB, this.get('recommendedConfigs'));
+ var serviceConfigs = App.config.renderConfigs(configs, storedConfigs, this.get('allSelectedServiceNames'), this.get('installedServiceNames'), localDB, this.get('recommendationsConfigs'));
if (this.get('wizardController.name') === 'addServiceController') {
serviceConfigs.setEach('showConfig', true);
serviceConfigs.setEach('selected', false);
@@ -930,41 +928,6 @@ App.WizardStep7Controller = Em.Controller.extend({
}
},
- loadDefaultConfigs: function(callback) {
- var selectedServices = App.StackService.find().filterProperty('isSelected').mapProperty('serviceName');
- var installedServices = App.StackService.find().filterProperty('isInstalled').mapProperty('serviceName');
- var services = installedServices.concat(selectedServices).uniq();
- this.set('isDefaultsLoaded', false);
- var hostNames = Object.keys(this.get('content.hosts'));
- App.ajax.send({
- 'name': 'wizard.step7.loadrecommendations.configs',
- 'sender': this,
- 'data': {
- stackVersionUrl: App.get('stackVersionURL'),
- hosts: hostNames,
- services: services,
- recommendations: App.router.get('installerController.recommendations')
- },
- 'success': 'loadDefaultConfigsSuccess'
- })
- .retry({
- times: App.maxRetries,
- timeout: App.timeout
- })
- .then(function () {
- callback();
- }, function () {
- App.showReloadPopup();
- console.log('Load recommendations failed');
- });
- },
-
- loadDefaultConfigsSuccess: function(data) {
- if (!data) {
- console.warn('error while loading default config values');
- }
- this.set("recommendedConfigs", Em.get(data.resources[0] , "recommendations.blueprint.configurations"));
- },
/**
* Check if Oozie or Hive use existing database then need
* to restore missed properties
@@ -1360,12 +1323,15 @@ App.WizardStep7Controller = Em.Controller.extend({
* @method submit
*/
submit: function () {
+ if (this.get('isSubmitDisabled')) {
+ return;
+ }
var _this = this;
- if (!this.get('isSubmitDisabled')) {
- this.checkDatabaseConnectionTest().done(function () {
+ this.serverSideValidation().done(function () {
+ _this.checkDatabaseConnectionTest().done(function () {
_this.resolveHiveMysqlDatabase();
});
- }
+ });
}
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/818dc161/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index cd25878..989a657 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -648,6 +648,10 @@ Em.I18n.translations = {
'installer.step7.popup.mySQLWarning.confirmation.body': 'You will be brought back to the \"Assign Masters\" step and will lose all your current customizations. Are you sure?',
'installer.step7.popup.database.connection.header': 'Database Connectivity Warning',
'installer.step7.popup.database.connection.body': 'You have not run or passed the database connection test for: {0}. It is highly recommended that you pass the connection test before proceeding to prevent failures during deployment.',
+ 'installer.step7.popup.validation.failed.header': 'Validation failed.',
+ 'installer.step7.popup.validation.failed.body': 'Some services are not properly configured. You have to change the highlighted configs according to the recommended values.',
+ 'installer.step7.popup.validation.request.failed.body': 'Config validaition failed.',
+ 'installer.step7.popup.validation.warning.body': 'Some services are not properly configured. Recommended to change the highlighted configs. Are you sure you want to proceed witout changing configs?',
'installer.step7.oozie.database.new': 'New Derby Database',
'installer.step7.hive.database.new': 'New MySQL Database',
http://git-wip-us.apache.org/repos/asf/ambari/blob/818dc161/ambari-web/app/mixins.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins.js b/ambari-web/app/mixins.js
index 3384391..f087569 100644
--- a/ambari-web/app/mixins.js
+++ b/ambari-web/app/mixins.js
@@ -21,6 +21,7 @@
require('mixins/common/localStorage');
require('mixins/common/userPref');
+require('mixins/common/serverValidator');
require('mixins/models/service_mixin');
require('mixins/common/tableServerProvider');
require('mixins/common/table_server_mixin');
http://git-wip-us.apache.org/repos/asf/ambari/blob/818dc161/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
new file mode 100644
index 0000000..a4be042
--- /dev/null
+++ b/ambari-web/app/mixins/common/serverValidator.js
@@ -0,0 +1,239 @@
+/**
+ * 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 blueprintUtils = require('utils/blueprint');
+
+App.ServerValidatorMixin = Em.Mixin.create({
+
+ /**
+ * @type {bool} set true if at leasst one config has error
+ */
+ configValidationError: false,
+
+ /**
+ * @type {bool} set true if at leasst one config has warning
+ */
+ configValidationWarning: false,
+
+ /**
+ * @type {bool} set true if at leasst one config has warning
+ */
+ configValidationFailed: false,
+
+ /**
+ * recommendation configs loaded from server
+ * (used only during install)
+ * @type {Object}
+ */
+ recommendationsConfigs: null,
+
+ /**
+ * by default loads data from model otherwise must be overridden as computed property
+ * refer to \assets\data\stacks\HDP-2.1\recommendations_configs.json to learn structure
+ * (shouldn't contain configurations filed)
+ * @type {Object}
+ */
+ hostNames: function() {
+ return this.get('content.hosts')
+ ? Object.keys(this.get('content.hosts'))
+ : App.HostComponent.find().mapProperty('hostName').uniq();
+ }.property('content.hosts'),
+
+
+ /**
+ * by default loads data from model otherwise must be overridden as computed property
+ * @type {Array} - of strings (serviceNames)
+ */
+ serviceNames: function() {
+ return this.get('content.serviceName')
+ ? [this.get('content.serviceName')]
+ : App.StackService.find().filter(function(s){return s.get('isSelected') || s.get('isInstalled')}).mapProperty('serviceName');
+ }.property('content.serviceName'),
+
+ /**
+ * by default loads data from model otherwise must be overridden as computed property
+ * filter services that support server validation and concat with misc configs if Installer or current service
+ * @type {Array} - of objects (services)
+ */
+ services: function() {
+ return this.get('content.serviceName')
+ ? [App.StackService.find(this.get('content.serviceName'))]
+ : App.StackService.find().filter(function(s){
+ return s.get('allowServerValidator') && (s.get('isSelected') || s.get('isInsalled'))
+ }).concat(require("data/service_configs"));
+ }.property('content.serviceName'),
+
+ /**
+ * by default loads data from model otherwise must be overridden as computed property
+ * can be used for service|host configs pages
+ * @type {Array} of strings (hostNames)
+ */
+ hostGroups: function() {
+ return this.get('content.recommendationsHostGroups') || blueprintUtils.generateHostGroups(this.get('hostNames'), App.HostComponent.find());
+ }.property('content.recommendationsHostGroups', 'hostNames'),
+
+ /**
+ * controller that is child of this mixis has to contain stepConfigs
+ * @type {Array}
+ */
+ stepConfigs: null,
+
+ /**
+ * @method loadServerSideConfigsRecommendations
+ * laod recommendations from server
+ * (used only during install)
+ * @returns {*}
+ */
+ loadServerSideConfigsRecommendations: function() {
+ if (this.get('recommendationsConfigs') || !App.get('supports.serverRecommendValidate')) {
+ return $.Deferred().resolve();
+ }
+ return App.ajax.send({
+ 'name': 'wizard.step7.loadrecommendations.configs',
+ 'sender': this,
+ 'data': {
+ stackVersionUrl: App.get('stackVersionURL'),
+ hosts: this.get('hostNames'),
+ services: this.get('serviceNames'),
+ recommendations: this.get('hostGroups')
+ },
+ 'success': 'loadRecommendationsSuccess',
+ 'error': 'loadRecommendationsError'
+ });
+ },
+
+ /**
+ * @method loadRecommendationsSuccess
+ * success callback after loading recommendations
+ * (used only during install)
+ * @param data
+ */
+ loadRecommendationsSuccess: function(data) {
+ if (!data) {
+ console.warn('error while loading default config values');
+ }
+ this.set("recommendationsConfigs", Em.get(data.resources[0] , "recommendations.blueprint.configurations"));
+ },
+
+ loadRecommendationsError: function() {
+ console.error('Load recommendations failed');
+ },
+
+ /**
+ * @method serverSideValidation
+ * send request to validate configs
+ * @returns {*}
+ */
+ serverSideValidation: function() {
+ var self = this;
+ var deferred = $.Deferred();
+ if (!App.get('supports.serverRecommendValidate')) {
+ deferred.resolve();
+ return deferred;
+ }
+ var recommendations = this.get('hostGroups');
+ recommendations.blueprint.configurations = blueprintUtils.buildConfisJSON(this.get('services'), this.get('stepConfigs'));
+ App.ajax.send({
+ name: 'config.validations',
+ sender: this,
+ data: {
+ stackVersionUrl: App.get('stackVersionURL'),
+ hosts: this.get('hostNames'),
+ services: this.get('serviceNames'),
+ validate: 'configurations',
+ recommendations: recommendations
+ },
+ success: 'validationSuccess',
+ error: 'validationError'
+ }).complete(function() {
+ self.warnUser(deferred);
+ });
+ return deferred;
+ },
+
+
+ /**
+ * @method validationSuccess
+ * success callback after getting responce from server
+ * go through the step configs and set warn and error messages
+ * @param data
+ */
+ validationSuccess: function(data) {
+ var self = this;
+ self.set('configValidationError', false);
+ self.set('configValidationWarning', false);
+ self.set('configValidationFailed', false);
+ data.resources.forEach(function(r) {
+ r.items.forEach(function(item){
+ if (item.type == "configuration") {
+ self.get('stepConfigs').forEach(function(service) {
+ service.get('configs').forEach(function(property) {
+ if ((property.get('filename') == item['config-type'] + '.xml') && (property.get('name') == item['config-name'])) {
+ if (item.level == "ERROR") {
+ self.set('configValidationError', true);
+ property.set('errorMessage', item.message);
+ property.set('error', true);
+ } else if (item.level == "ERROR") {
+ self.set('configValidationWarning', true);
+ property.set('warnMessage', item.message);
+ property.set('warn', true);
+ }
+ }
+ });
+ })
+ }
+ });
+ });
+ },
+
+ validationError: function() {
+ this.set('configValidationFailed', true);
+ console.error('config validation failed');
+ },
+
+
+ /**
+ * warn user if some errors or warning were
+ * in seting up configs otherwise go to the nex operation
+ * @param deferred
+ * @returns {*}
+ */
+ warnUser: function(deferred) {
+ var self = this;
+ if (this.get('configValidationFailed')) {
+ this.set('isSubmitDisabled', false);
+ this.set("isApplyingChanges", false);
+ return App.showAlertPopup(Em.I18n.t('installer.step7.popup.validation.failed.header'), Em.I18n.t('installer.step7.popup.validation.request.failed.body'));
+ } else if (this.get('configValidationError')) {
+ this.set("isApplyingChanges", false);
+ this.set('isSubmitDisabled', true);
+ return App.showAlertPopup(Em.I18n.t('installer.step7.popup.validation.failed.header'), Em.I18n.t('installer.step7.popup.validation.failed.body'));
+ } else if (this.get('configValidationWarning')) {
+ this.set('isSubmitDisabled', true);
+ this.set("isApplyingChanges", false);
+ return App.showConfirmationPopup(function () {
+ self.set('isSubmitDisabled', false);
+ self.set("isApplyingChanges", true);
+ deferred.resolve();
+ }, Em.I18n.t('installer.step7.popup.validation.warning.body'));
+ } else {
+ deferred.resolve();
+ }
+ }
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/818dc161/ambari-web/app/models/service_config.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/service_config.js b/ambari-web/app/models/service_config.js
index 7ef67f3..2df2ad7 100644
--- a/ambari-web/app/models/service_config.js
+++ b/ambari-web/app/models/service_config.js
@@ -844,13 +844,14 @@ App.ServiceConfigProperty = Ember.Object.extend({
}
}
}
-
- var serviceValidator = this.get('serviceValidator');
- if (serviceValidator!=null) {
- var validationIssue = serviceValidator.validateConfig(this);
- if (validationIssue) {
- this.set('warnMessage', validationIssue);
- isWarn = true;
+ if (!App.get('supports.serverRecommendValidate')) {
+ var serviceValidator = this.get('serviceValidator');
+ if (serviceValidator!=null) {
+ var validationIssue = serviceValidator.validateConfig(this);
+ if (validationIssue) {
+ this.set('warnMessage', validationIssue);
+ isWarn = true;
+ }
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/818dc161/ambari-web/app/models/stack_service.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/stack_service.js b/ambari-web/app/models/stack_service.js
index c599c33..0b489f8 100644
--- a/ambari-web/app/models/stack_service.js
+++ b/ambari-web/app/models/stack_service.js
@@ -171,6 +171,9 @@ App.StackService = DS.Model.extend(App.ServiceModelMixin, {
return defaultConfigsHandler && defaultConfigsHandler.configsValidator;
}.property('serviceName'),
+ allowServerValidator: function() {
+ return ["YARN", "STORM", "MAPREDUCE2", "HIVE", "TEZ"].contains(this.get('serviceName'));
+ }.property('serviceName'),
/**
* configCategories are fetched from App.StackService.configCategories.
* Also configCategories that does not match any serviceComponent of a service and not included in the permissible default pattern are omitted
http://git-wip-us.apache.org/repos/asf/ambari/blob/818dc161/ambari-web/app/routes/installer.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/installer.js b/ambari-web/app/routes/installer.js
index 7abfe96..0a5e46e 100644
--- a/ambari-web/app/routes/installer.js
+++ b/ambari-web/app/routes/installer.js
@@ -250,6 +250,7 @@ module.exports = Em.Route.extend({
controller.saveClients(wizardStep4Controller);
controller.clearRecommendations(); // Force reload recommendation between steps 4 and 5
+ controller.setDBProperty('recommendations', undefined);
controller.setDBProperty('masterComponentHosts', undefined);
router.transitionTo('step5');
}
@@ -273,6 +274,7 @@ module.exports = Em.Route.extend({
var wizardStep5Controller = router.get('wizardStep5Controller');
controller.saveMasterComponentHosts(wizardStep5Controller);
controller.setDBProperty('slaveComponentHosts', undefined);
+ controller.setDBProperty('recommendations', wizardStep5Controller.get('content.recommendations'));
router.transitionTo('step6');
}
}),
@@ -302,6 +304,8 @@ module.exports = Em.Route.extend({
controller.setDBProperty('serviceConfigProperties', null);
controller.setDBProperty('advancedServiceConfig', null);
controller.setDBProperty('serviceConfigGroups', null);
+ controller.setDBProperty('recommendationsHostGroups', wizardStep6Controller.get('content.recommendationsHostGroups'));
+ controller.setDBProperty('recommendationsConfigs', null);
controller.loadAdvancedConfigs(wizardStep7Controller);
router.transitionTo('step7');
}
@@ -326,12 +330,13 @@ module.exports = Em.Route.extend({
},
back: Em.Router.transitionTo('step6'),
next: function (router) {
- var installerController = router.get('installerController');
+ var controller = router.get('installerController');
var wizardStep7Controller = router.get('wizardStep7Controller');
- installerController.saveServiceConfigProperties(wizardStep7Controller);
+ controller.saveServiceConfigProperties(wizardStep7Controller);
if (App.supports.hostOverridesInstaller) {
- installerController.saveServiceConfigGroups(wizardStep7Controller);
+ controller.saveServiceConfigGroups(wizardStep7Controller);
}
+ controller.setDBProperty('recommendationsConfigs', wizardStep7Controller.get('recommendationsConfigs'));
router.transitionTo('step8');
}
}),
http://git-wip-us.apache.org/repos/asf/ambari/blob/818dc161/ambari-web/app/utils/blueprint.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/blueprint.js b/ambari-web/app/utils/blueprint.js
index b56ceca..f8ec9c2 100644
--- a/ambari-web/app/utils/blueprint.js
+++ b/ambari-web/app/utils/blueprint.js
@@ -185,5 +185,86 @@ module.exports = {
});
return res;
+ },
+
+ /**
+ * @method buildConfisJSON - generet JSON according to blueprint format
+ * @param {Em.Array} stepConfigs - array of Ember Objects
+ * @param {Array} services
+ * @returns {Object}
+ * Example:
+ * {
+ * "yarn-env": {
+ * "properties": {
+ * "content": "some value",
+ * "yarn_heapsize": "1024",
+ * "resourcemanager_heapsize": "1024",
+ * }
+ * },
+ * "yarn-log4j": {
+ * "properties": {
+ * "content": "some other value"
+ * }
+ * }
+ * }
+ */
+ buildConfisJSON: function(services, stepConfigs) {
+ var configurations = {};
+ services.forEach(function(service) {
+ var config = stepConfigs.findProperty('serviceName', service.get('serviceName'));
+ if (config && service.get('configTypes')) {
+ Object.keys(service.get('configTypes')).forEach(function(type) {
+ configurations[type] = {
+ properties: {}
+ }
+ });
+ config.get('configs').forEach(function(property){
+ if (configurations[property.get('filename').replace('.xml','')]){
+ configurations[property.get('filename').replace('.xml','')]['properties'][property.get('name')] = property.get('value');
+ } else {
+ console.warn(property.get('name') + " from " + property.get('filename') + " can't be validate");
+ }
+ });
+ }
+ });
+ return configurations;
+ },
+
+ /**
+ * @method generateHostGroups
+ * @param {Array} hostNames - list of all hostNames
+ * @param {Array} hostComponents - list of all hostComponents
+ * @returns {{blueprint: {host_groups: Array}, blueprint_cluster_binding: {host_groups: Array}}}
+ */
+ generateHostGroups: function(hostNames, hostComponents) {
+ var recommendations = {
+ blueprint: {
+ host_groups: []
+ },
+ blueprint_cluster_binding: {
+ host_groups: []
+ }
+ };
+
+ for (var i = 1; i <= hostNames.length; i++) {
+ var host_group = {
+ name: "host-group-" + i,
+ components: []
+ };
+ var hcFiltered = hostComponents.filterProperty('hostName', hostNames[i-1]).mapProperty('componentName');
+ for (var j = 0; j < hcFiltered.length; j++) {
+ host_group.components.push({
+ name: hcFiltered[j]
+ });
+ }
+ recommendations.blueprint.host_groups.push(host_group);
+ recommendations.blueprint_cluster_binding.host_groups.push({
+ name: "host-group-" + i,
+ hosts: [{
+ fqdn: hostNames[i-1]
+ }]
+ });
+ }
+ return recommendations;
}
};
http://git-wip-us.apache.org/repos/asf/ambari/blob/818dc161/ambari-web/app/utils/config.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/config.js b/ambari-web/app/utils/config.js
index f576f38..62db148 100644
--- a/ambari-web/app/utils/config.js
+++ b/ambari-web/app/utils/config.js
@@ -690,8 +690,8 @@ App.config = Em.Object.create({
// Use calculated default values for some configs
var recommendedDefaults = {};
- if (App.supports.serverRecommendValidate) {
- if (!storedConfigs && service.get('configTypes')) {
+ if (App.get('supports.serverRecommendValidate')) {
+ if (!storedConfigs && service.get('configTypes') && service.get('allowServerValidator')) {
Object.keys(service.get('configTypes')).forEach(function (type) {
if (!recommended || !recommended[type]) {
return;
@@ -727,14 +727,14 @@ App.config = Em.Object.create({
}
});
}
- }
- if (service.get('configsValidator')) {
- service.get('configsValidator').set('recommendedDefaults', recommendedDefaults);
- var validators = service.get('configsValidator').get('configValidators');
- for (var validatorName in validators) {
- var c = configsByService.findProperty('name', validatorName);
- if (c) {
- c.set('serviceValidator', service.get('configsValidator'));
+ if (service.get('configsValidator')) {
+ service.get('configsValidator').set('recommendedDefaults', recommendedDefaults);
+ var validators = service.get('configsValidator').get('configValidators');
+ for (var validatorName in validators) {
+ var c = configsByService.findProperty('name', validatorName);
+ if (c) {
+ c.set('serviceValidator', service.get('configsValidator'));
+ }
}
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/818dc161/ambari-web/test/utils/blueprint_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/utils/blueprint_test.js b/ambari-web/test/utils/blueprint_test.js
index e527a09..1f8d803 100644
--- a/ambari-web/test/utils/blueprint_test.js
+++ b/ambari-web/test/utils/blueprint_test.js
@@ -276,4 +276,141 @@ describe('utils/blueprint', function() {
);
});
});
+
+ describe('#buildConfisJSON', function () {
+ var tests = [
+ {
+ "services": [
+ Em.Object.create({
+ serviceName: "YARN",
+ configTypes: {
+ "yarn-site": {},
+ "yarn-env": {}
+ },
+ allowServerValidator: true,
+ isInstalled: true
+ })
+ ],
+ "stepConfigs": [
+ Em.Object.create({
+ serviceName: "YARN",
+ configs: [
+ Em.Object.create({
+ name: "p1",
+ value: "v1",
+ filename: "yarn-site.xml"
+ }),
+ Em.Object.create({
+ name: "p2",
+ value: "v2",
+ filename: "yarn-site.xml"
+ }),
+ Em.Object.create({
+ name: "p3",
+ value: "v3",
+ filename: "yarn-env.xml"
+ })
+ ]
+ })
+ ],
+ "configurations": {
+ "yarn-site": {
+ "properties": {
+ "p1": "v1",
+ "p2": "v2"
+ }
+ },
+ "yarn-env": {
+ "properties": {
+ "p3": "v3"
+ }
+ }
+ }
+ }
+ ];
+ tests.forEach(function (test) {
+ it("generate configs for request (use in validation)", function () {
+ expect(blueprintUtils.buildConfisJSON(test.services, test.stepConfigs)).to.eql(test.configurations);
+ });
+ });
+ });
+
+ describe('#generateHostGroups', function () {
+ var tests = [
+ {
+ "hostNames": ["host1", "host2"],
+ "hostComponents": [
+ Em.Object.create({
+ componentName: "C1",
+ hostName: "host1"
+ }),
+ Em.Object.create({
+ componentName: "C2",
+ hostName: "host1"
+ }),
+ Em.Object.create({
+ componentName: "C1",
+ hostName: "host2"
+ }),
+ Em.Object.create({
+ componentName: "C3",
+ hostName: "host2"
+ })
+ ],
+ result: {
+ blueprint: {
+ host_groups: [
+ {
+ name: "host-group-1",
+ "components": [
+ {
+ "name": "C1"
+ },
+ {
+ "name": "C2"
+ }
+ ]
+ },
+ {
+ name: "host-group-2",
+ "components": [
+ {
+ "name": "C1"
+ },
+ {
+ "name": "C3"
+ }
+ ]
+ }
+ ]
+ },
+ blueprint_cluster_binding: {
+ host_groups: [
+ {
+ "name": "host-group-1",
+ "hosts": [
+ {
+ "fqdn": "host1"
+ }
+ ]
+ },
+ {
+ "name": "host-group-2",
+ "hosts": [
+ {
+ "fqdn": "host2"
+ }
+ ]
+ },
+ ]
+ }
+ }
+ }
+ ];
+ tests.forEach(function (test) {
+ it("generate host groups", function () {
+ expect(blueprintUtils.generateHostGroups(test.hostNames, test.hostComponents)).to.eql(test.result);
+ });
+ });
+ });
});
\ No newline at end of file