| /** |
| * 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, |
| |
| /** |
| * @type {object[]} contains additional message about validation errors |
| */ |
| configValidationGlobalMessage: [], |
| |
| /** |
| * 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.get('allHostNames'); |
| }.property('content.hosts', 'App.allHostNames'), |
| |
| allHostNames: [], |
| /** |
| * 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')] : this.get('allSelectedServiceNames'); |
| }.property('content.serviceName', 'allSelectedServiceNames.@each'), |
| |
| /** |
| * 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'))] |
| : this.get('content.services').filter(function(s){ |
| return (s.get('isSelected') || s.get('isInstalled')); |
| }).concat(require("data/service_configs")); |
| }.property('content.serviceName', 'content.services', 'content.services.@each.isSelected', 'content.services.@each.isInstalled', 'content.stacks.@each.isSelected'), |
| |
| /** |
| * 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')) { |
| 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(jqXHR, ajaxOptions, error, opt) { |
| App.ajax.defaultErrorHandler(jqXHR, opt.url, opt.method, jqXHR.status); |
| console.error('Load recommendations failed'); |
| }, |
| |
| serverSideValidation: function () { |
| var deferred = $.Deferred(); |
| this.set('configValidationFailed', false); |
| this.set('configValidationGlobalMessage', []); |
| if (this.get('configValidationFailed')) { |
| this.warnUser(deferred); |
| } else { |
| this.runServerSideValidation(deferred); |
| } |
| return deferred; |
| }, |
| |
| /** |
| * @method serverSideValidation |
| * send request to validate configs |
| * @returns {*} |
| */ |
| runServerSideValidation: function(deferred) { |
| var self = this; |
| var recommendations = this.get('hostGroups'); |
| recommendations.blueprint.configurations = blueprintUtils.buildConfisJSON(this.get('services'), this.get('stepConfigs')); |
| |
| var serviceNames = this.get('serviceNames'); |
| if (!self.get('isInstaller')) { |
| // When editing a service we validate only that service's configs. |
| // However, we should pass the IDs of services installed, or else, |
| // default value calculations will alter. |
| serviceNames = App.Service.find().mapProperty('serviceName'); |
| } |
| |
| return App.ajax.send({ |
| name: 'config.validations', |
| sender: this, |
| data: { |
| stackVersionUrl: App.get('stackVersionURL'), |
| hosts: this.get('hostNames'), |
| services: serviceNames, |
| validate: 'configurations', |
| recommendations: recommendations |
| }, |
| success: 'validationSuccess', |
| error: 'validationError' |
| }).complete(function() { |
| self.warnUser(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; |
| var checkedProperties = []; |
| var globalWarning = []; |
| self.set('configValidationError', false); |
| self.set('configValidationWarning', 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 == "WARN") { |
| self.set('configValidationWarning', true); |
| property.set('warnMessage', item.message); |
| property.set('warn', true); |
| } |
| // store property data to detect WARN or ERROR messages for missed property |
| if (["ERROR", "WARN"].contains(item.level)) checkedProperties.push(item['config-type'] + '/' + item['config-name']); |
| } |
| }); |
| }); |
| // check if error or warn message detected for property that absent in step configs |
| if (["ERROR", "WARN"].contains(item.level) && !checkedProperties.contains(item['config-type'] + '/' + item['config-name'])) { |
| var message = { |
| propertyName: item['config-name'], |
| filename: item['config-type'], |
| warnMessage: item.message, |
| serviceName: App.StackService.find().filter(function(service) { |
| return !!service.get('configTypes')[item['config-type']]; |
| })[0].get('displayName') |
| }; |
| self.set(item.level == 'WARN' ? 'configValidationWarning' : 'configValidationError', true); |
| globalWarning.push(message); |
| } |
| } |
| }); |
| }); |
| self.set('configValidationGlobalMessage', globalWarning); |
| }, |
| |
| validationError: function (jqXHR, ajaxOptions, error, opt) { |
| this.set('configValidationFailed', true); |
| App.ajax.defaultErrorHandler(jqXHR, opt.url, opt.method, jqXHR.status); |
| 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')) { |
| deferred.reject(); |
| 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('configValidationWarning') || this.get('configValidationError')) { |
| // Motivation: for server-side validation warnings and EVEN errors allow user to continue wizard |
| return App.ModalPopup.show({ |
| header: Em. I18n.t('installer.step7.popup.validation.warning.header'), |
| classNames: ['sixty-percent-width-modal','modal-full-width'], |
| primary: Em.I18n.t('common.proceedAnyway'), |
| primaryClass: 'btn-danger', |
| marginBottom: 200, |
| onPrimary: function () { |
| this.hide(); |
| deferred.resolve(); |
| }, |
| onSecondary: function () { |
| this.hide(); |
| deferred.reject("invalid_configs"); // message used to differentiate types of rejections. |
| }, |
| onClose: function () { |
| this.hide(); |
| deferred.reject("invalid_configs"); // message used to differentiate types of rejections. |
| }, |
| bodyClass: Em.View.extend({ |
| controller: self, |
| templateName: require('templates/common/configs/config_recommendation_popup') |
| }) |
| }); |
| } else { |
| deferred.resolve(); |
| } |
| } |
| }); |