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 2016/04/28 19:19:15 UTC
ambari git commit: AMBARI-16166 Refactor config
validation.(ababiichuk)
Repository: ambari
Updated Branches:
refs/heads/trunk 1b49c6c97 -> c26e2ff61
AMBARI-16166 Refactor config validation.(ababiichuk)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/c26e2ff6
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/c26e2ff6
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/c26e2ff6
Branch: refs/heads/trunk
Commit: c26e2ff61b2fd02c2c72232de154d62401287847
Parents: 1b49c6c
Author: ababiichuk <ab...@hortonworks.com>
Authored: Thu Apr 28 19:38:41 2016 +0300
Committer: ababiichuk <ab...@hortonworks.com>
Committed: Thu Apr 28 20:18:51 2016 +0300
----------------------------------------------------------------------
.../hawq/activateStandby/step2_controller.js | 1 -
.../hawq/addStandby/step3_controller.js | 1 -
.../nameNode/step3_controller.js | 1 -
.../resourceManager/step3_controller.js | 1 -
.../app/controllers/wizard/step7_controller.js | 1 -
.../configs/stack_config_properties_mapper.js | 1 +
ambari-web/app/messages.js | 14 +-
.../configs/config_recommendation_parser.js | 2 -
.../configs/objects/service_config_property.js | 262 ++-----------------
ambari-web/app/utils/config.js | 154 ++++++++++-
ambari-web/app/utils/validator.js | 2 +-
.../notification_configs_view.js | 7 -
.../configs/widgets/list_config_widget_view.js | 7 +-
.../config_recommendation_parser_test.js | 21 +-
.../objects/service_config_property_test.js | 86 ------
ambari-web/test/models/form_test.js | 22 --
ambari-web/test/utils/config_test.js | 24 ++
.../notification_configs_view_test.js | 18 +-
18 files changed, 224 insertions(+), 401 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/c26e2ff6/ambari-web/app/controllers/main/admin/highAvailability/hawq/activateStandby/step2_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/admin/highAvailability/hawq/activateStandby/step2_controller.js b/ambari-web/app/controllers/main/admin/highAvailability/hawq/activateStandby/step2_controller.js
index a14817a..ff338de 100644
--- a/ambari-web/app/controllers/main/admin/highAvailability/hawq/activateStandby/step2_controller.js
+++ b/ambari-web/app/controllers/main/admin/highAvailability/hawq/activateStandby/step2_controller.js
@@ -90,7 +90,6 @@ App.ActivateHawqStandbyWizardStep2Controller = Em.Controller.extend({
var serviceConfigProperty = App.ServiceConfigProperty.create(_serviceConfigProperty);
componentConfig.configs.pushObject(serviceConfigProperty);
serviceConfigProperty.set('isEditable', serviceConfigProperty.get('isReconfigurable'));
- serviceConfigProperty.validate();
}, this);
},
http://git-wip-us.apache.org/repos/asf/ambari/blob/c26e2ff6/ambari-web/app/controllers/main/admin/highAvailability/hawq/addStandby/step3_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/admin/highAvailability/hawq/addStandby/step3_controller.js b/ambari-web/app/controllers/main/admin/highAvailability/hawq/addStandby/step3_controller.js
index fd28ad5..3378cd5 100644
--- a/ambari-web/app/controllers/main/admin/highAvailability/hawq/addStandby/step3_controller.js
+++ b/ambari-web/app/controllers/main/admin/highAvailability/hawq/addStandby/step3_controller.js
@@ -133,7 +133,6 @@ App.AddHawqStandbyWizardStep3Controller = Em.Controller.extend({
var serviceConfigProperty = App.ServiceConfigProperty.create(_serviceConfigProperty);
componentConfig.configs.pushObject(serviceConfigProperty);
serviceConfigProperty.set('isEditable', serviceConfigProperty.get('isReconfigurable'));
- serviceConfigProperty.validate();
}, this);
},
http://git-wip-us.apache.org/repos/asf/ambari/blob/c26e2ff6/ambari-web/app/controllers/main/admin/highAvailability/nameNode/step3_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/admin/highAvailability/nameNode/step3_controller.js b/ambari-web/app/controllers/main/admin/highAvailability/nameNode/step3_controller.js
index 7305861..1dcf2b7 100644
--- a/ambari-web/app/controllers/main/admin/highAvailability/nameNode/step3_controller.js
+++ b/ambari-web/app/controllers/main/admin/highAvailability/nameNode/step3_controller.js
@@ -228,7 +228,6 @@ App.HighAvailabilityWizardStep3Controller = Em.Controller.extend({
var serviceConfigProperty = App.ServiceConfigProperty.create(_serviceConfigProperty);
componentConfig.configs.pushObject(serviceConfigProperty);
serviceConfigProperty.set('isEditable', serviceConfigProperty.get('isReconfigurable'));
- serviceConfigProperty.validate();
}, this);
},
http://git-wip-us.apache.org/repos/asf/ambari/blob/c26e2ff6/ambari-web/app/controllers/main/admin/highAvailability/resourceManager/step3_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/admin/highAvailability/resourceManager/step3_controller.js b/ambari-web/app/controllers/main/admin/highAvailability/resourceManager/step3_controller.js
index 00ae0c3..36dcfb8 100644
--- a/ambari-web/app/controllers/main/admin/highAvailability/resourceManager/step3_controller.js
+++ b/ambari-web/app/controllers/main/admin/highAvailability/resourceManager/step3_controller.js
@@ -170,7 +170,6 @@ App.RMHighAvailabilityWizardStep3Controller = Em.Controller.extend(App.Blueprint
var serviceConfigProperty = App.ServiceConfigProperty.create(_serviceConfigProperty);
componentConfig.configs.pushObject(serviceConfigProperty);
serviceConfigProperty.set('isEditable', serviceConfigProperty.get('isReconfigurable'));
- serviceConfigProperty.validate();
}, this);
},
http://git-wip-us.apache.org/repos/asf/ambari/blob/c26e2ff6/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 8ed465d..c97de10 100644
--- a/ambari-web/app/controllers/wizard/step7_controller.js
+++ b/ambari-web/app/controllers/wizard/step7_controller.js
@@ -748,7 +748,6 @@ App.WizardStep7Controller = Em.Controller.extend(App.ServerValidatorMixin, App.E
if (!this.get('content.serviceConfigProperties.length') && !serviceConfigProperty.get('hasInitialValue')) {
App.ConfigInitializer.initialValue(serviceConfigProperty, localDB, dependencies);
}
- serviceConfigProperty.validate();
configsByService[_config.serviceName].pushObject(serviceConfigProperty);
}, this);
http://git-wip-us.apache.org/repos/asf/ambari/blob/c26e2ff6/ambari-web/app/mappers/configs/stack_config_properties_mapper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers/configs/stack_config_properties_mapper.js b/ambari-web/app/mappers/configs/stack_config_properties_mapper.js
index 59f9916..5c34f62 100644
--- a/ambari-web/app/mappers/configs/stack_config_properties_mapper.js
+++ b/ambari-web/app/mappers/configs/stack_config_properties_mapper.js
@@ -144,6 +144,7 @@ App.stackConfigPropertiesMapper = App.QuickDataMapper.create({
var v = Em.isNone(staticConfigInfo.recommendedValue) ? staticConfigInfo.recommendedValue : staticConfigInfo.value;
staticConfigInfo.value = staticConfigInfo.recommendedValue = App.config.formatPropertyValue(staticConfigInfo, v);
staticConfigInfo.isSecureConfig = App.config.getIsSecure(staticConfigInfo.name);
+ staticConfigInfo.description = App.config.getDescription(staticConfigInfo.description, staticConfigInfo.displayType);
staticConfigInfo.isUserProperty = false;
App.configsCollection.add(staticConfigInfo);
http://git-wip-us.apache.org/repos/asf/ambari/blob/c26e2ff6/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index a1ed7be..e195b7a 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -480,7 +480,6 @@ Em.I18n.translations = {
'users.userName.validationFail': 'Only lowercase letters and numbers are recommended; must start with a letter',
'host.spacesValidation': 'Cannot contain whitespace',
- 'host.trimspacesValidation': 'Cannot contain leading or trailing whitespace',
'services.hdfs.rebalance.title' : 'HDFS Rebalance',
'services.ganglia.description':'Ganglia Metrics Collection system',
@@ -994,7 +993,6 @@ Em.I18n.translations = {
'form.validator.alertGroupName':'Invalid Alert Group Name. Only alphanumerics, hyphens, spaces and underscores are allowed.',
'form.validator.alertNotificationName':'Invalid Alert Notification Name. Only alphanumerics, hyphens, spaces and underscores are allowed.',
'form.validator.configKey.specific':'"{0}" is invalid Key. Only alphanumerics, hyphens, underscores, asterisks and periods are allowed.',
- 'form.validator.error.trailingSpaces': 'Cannot contain trailing whitespace',
'alerts.add.header': 'Create Alert Definition',
'alerts.add.step1.header': 'Choose Type',
@@ -2964,6 +2962,18 @@ Em.I18n.translations = {
'config.warnMessage.outOfBoundaries.greater': 'Values greater than {0} are not recommended',
'config.warnMessage.outOfBoundaries.less': 'Values smaller than {0} are not recommended',
+ 'errorMessage.config.required': 'This is required',
+ 'errorMessage.config.number.integer': 'Must contain digits only',
+ 'errorMessage.config.number.float': 'Must be a valid number',
+ 'errorMessage.config.mail': 'Must be a valid email address',
+ 'errorMessage.config.user': 'Value is not valid',
+ 'errorMessage.config.password': 'Passwords do not match',
+ 'errorMessage.config.directory.heterogeneous': 'dir format is wrong, can be "[{storage type}]/{dir name}"',
+ 'errorMessage.config.directory.default': 'Must be a slash or drive at the start, and must not contain white spaces',
+ 'errorMessage.config.directory.allowed': 'Can\'t start with "home(s)"',
+ 'errorMessage.config.spaces.trailing': 'Cannot contain trailing whitespace',
+ 'errorMessage.config.spaces.trim': 'Cannot contain leading or trailing whitespace',
+
'utils.ajax.errorMessage': 'Error message',
'utils.ajax.defaultErrorPopupBody.message': 'received on {0} method for API: {1}',
'utils.ajax.defaultErrorPopupBody.statusCode': '{0} status code',
http://git-wip-us.apache.org/repos/asf/ambari/blob/c26e2ff6/ambari-web/app/mixins/common/configs/config_recommendation_parser.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/configs/config_recommendation_parser.js b/ambari-web/app/mixins/common/configs/config_recommendation_parser.js
index 82916aa..65cc20f 100644
--- a/ambari-web/app/mixins/common/configs/config_recommendation_parser.js
+++ b/ambari-web/app/mixins/common/configs/config_recommendation_parser.js
@@ -171,8 +171,6 @@ App.ConfigRecommendationParser = Em.Mixin.create(App.ConfigRecommendations, {
newConfig = App.config.getDefaultConfig(name, fileName, coreObject),
addedPropertyObject = App.ServiceConfigProperty.create(newConfig);
- addedPropertyObject.validate();
-
this.applyRecommendation(name, fileName, "Default",
recommendedValue, null, parentProperties);
http://git-wip-us.apache.org/repos/asf/ambari/blob/c26e2ff6/ambari-web/app/models/configs/objects/service_config_property.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/configs/objects/service_config_property.js b/ambari-web/app/models/configs/objects/service_config_property.js
index 8e6327b..a244dfd 100644
--- a/ambari-web/app/models/configs/objects/service_config_property.js
+++ b/ambari-web/app/models/configs/objects/service_config_property.js
@@ -17,7 +17,6 @@
*/
var App = require('app');
-var validator = require('utils/validator');
/**
* @class ServiceConfigProperty
@@ -143,8 +142,11 @@ App.ServiceConfigProperty = Em.Object.extend({
isComparison: false,
hasCompareDiffs: false,
showLabel: true,
- error: false,
- warn: false,
+
+ error: Em.computed.bool('errorMessage.length'),
+ warn: Em.computed.bool('warnMessage.length'),
+ isValid: Em.computed.equal('errorMessage', ''),
+
previousValue: null, // cached value before changing config <code>value</code>
/**
@@ -159,17 +161,9 @@ App.ServiceConfigProperty = Em.Object.extend({
* true if property has warning or error
* @type {boolean}
*/
- hasIssues: function () {
- var originalSCPIssued = (this.get('errorMessage') + this.get('warnMessage')) !== "";
- var overridesIssue = false;
- (this.get('overrides') || []).forEach(function(override) {
- if (override.get('errorMessage') + override.get('warnMessage') !== "") {
- overridesIssue = true;
- return;
- }
- });
- return originalSCPIssued || overridesIssue;
- }.property('errorMessage', 'warnMessage', 'overrides.@each.warnMessage', 'overrides.@each.errorMessage'),
+ hasIssues: Em.computed.or('error', 'warn', 'overridesWithIssues.length'),
+
+ overridesWithIssues: Em.computed.filterBy('overrides', 'hasIssues', true),
index: null, //sequence number in category
editDone: false, //Text field: on focusOut: true, on focusIn: false
@@ -253,6 +247,13 @@ App.ServiceConfigProperty = Em.Object.extend({
}.property('isUserProperty', 'isOriginalSCP', 'overrides.length', 'isRequiredByAgent'),
init: function () {
+ this.setInitialValues();
+ this.set('viewClass', App.config.getViewClass(this.get("displayType"), this.get('dependentConfigPattern'), this.get('unit')));
+ this.set('validator', App.config.getValidator(this.get("displayType")));
+ this.validate();
+ },
+
+ setInitialValues: function () {
if (Em.isNone(this.get('value'))) {
if (!Em.isNone(this.get('savedValue'))) {
this.set('value', this.get('savedValue'));
@@ -260,12 +261,11 @@ App.ServiceConfigProperty = Em.Object.extend({
this.set('value', this.get('recommendedValue'));
}
}
- if(this.get("displayType") === "password") {
+ if (this.get("displayType") === "password") {
this.set('retypedPassword', this.get('value'));
this.set('recommendedValue', '');
}
this.set('initialValue', this.get('value'));
- this.updateDescription();
},
/**
@@ -313,211 +313,19 @@ App.ServiceConfigProperty = Em.Object.extend({
*/
cantBeUndone: Em.computed.existsIn('displayType', ["componentHost", "componentHosts", "radio button"]),
- isValid: Em.computed.equal('errorMessage', ''),
-
- viewClass: function () {
- switch (this.get('displayType')) {
- case 'checkbox':
- case 'boolean':
- if (this.get('dependentConfigPattern')) {
- return App.ServiceConfigCheckboxWithDependencies;
- } else {
- return App.ServiceConfigCheckbox;
- }
- case 'password':
- return App.ServiceConfigPasswordField;
- case 'combobox':
- return App.ServiceConfigComboBox;
- case 'radio button':
- return App.ServiceConfigRadioButtons;
- break;
- case 'directories':
- return App.ServiceConfigTextArea;
- break;
- case 'directory':
- return App.ServiceConfigTextField;
- break;
- case 'content':
- return App.ServiceConfigTextAreaContent;
- break;
- case 'multiLine':
- return App.ServiceConfigTextArea;
- break;
- case 'custom':
- return App.ServiceConfigBigTextArea;
- case 'componentHost':
- return App.ServiceConfigMasterHostView;
- case 'label':
- return App.ServiceConfigLabelView;
- case 'componentHosts':
- return App.ServiceConfigComponentHostsView;
- case 'supportTextConnection':
- return App.checkConnectionView;
- case 'capacityScheduler':
- return App.CapacitySceduler;
- default:
- if (this.get('unit')) {
- return App.ServiceConfigTextFieldWithUnit;
- } else {
- return App.ServiceConfigTextField;
- }
- }
- }.property('displayType'),
-
validate: function () {
- var value = this.get('value');
- var supportsFinal = this.get('supportsFinal');
- var isFinal = this.get('isFinal');
- var valueRange = this.get('valueRange');
-
- var isError = false;
- var isWarn = false;
-
- if (typeof value === 'string' && value.length === 0) {
- if (this.get('isRequired') && this.get('widgetType') != 'test-db-connection') {
- this.set('errorMessage', 'This is required');
- isError = true;
- } else {
- return;
- }
- }
-
- if (!isError) {
- switch (this.get('displayType')) {
- case 'int':
- if (('' + value).trim().length === 0) {
- this.set('errorMessage', '');
- isError = false;
- return;
- }
- if (validator.isConfigValueLink(value)) {
- isError = false;
- } else if (!validator.isValidInt(value)) {
- this.set('errorMessage', 'Must contain digits only');
- isError = true;
- } else {
- if(valueRange){
- if(value < valueRange[0] || value > valueRange[1]){
- this.set('errorMessage', 'Must match the range');
- isError = true;
- }
- }
- }
- break;
- case 'float':
- if (validator.isConfigValueLink(value)) {
- isError = false;
- } else if (!validator.isValidFloat(value)) {
- this.set('errorMessage', 'Must be a valid number');
- isError = true;
- }
- break;
- case 'checkbox':
- break;
- case 'directories':
- case 'directory':
- if (this.get('configSupportHeterogeneous')) {
- if (!validator.isValidDataNodeDir(value)) {
- this.set('errorMessage', 'dir format is wrong, can be "[{storage type}]/{dir name}"');
- isError = true;
- }
- } else {
- if (!validator.isValidDir(value)) {
- this.set('errorMessage', 'Must be a slash or drive at the start, and must not contain white spaces');
- isError = true;
- }
- }
- if (!isError) {
- if (!validator.isAllowedDir(value)) {
- this.set('errorMessage', 'Can\'t start with "home(s)"');
- isError = true;
- } else {
- // Invalidate values which end with spaces.
- if (value !== ' ' && validator.isNotTrimmedRight(value)) {
- this.set('errorMessage', Em.I18n.t('form.validator.error.trailingSpaces'));
- isError = true;
- }
- }
- }
- break;
- case 'custom':
- break;
- case 'email':
- if (!validator.isValidEmail(value)) {
- this.set('errorMessage', 'Must be a valid email address');
- isError = true;
- }
- break;
- case 'supportTextConnection':
- case 'host':
- var connectionProperties = ['kdc_hosts'];
- if ((validator.isNotTrimmed(value) && connectionProperties.contains(this.get('name')) || validator.isNotTrimmed(value))) {
- this.set('errorMessage', Em.I18n.t('host.trimspacesValidation'));
- isError = true;
- }
- break;
- case 'password':
- // retypedPassword is set by the retypePasswordView child view of App.ServiceConfigPasswordField
- if (value !== this.get('retypedPassword')) {
- this.set('errorMessage', 'Passwords do not match');
- isError = true;
- }
- break;
- case 'user':
- case 'database':
- case 'db_user':
- if (!validator.isValidDbName(value)){
- this.set('errorMessage', 'Value is not valid');
- isError = true;
- }
- break;
- case 'multiLine':
- case 'content':
- default:
- if(this.get('name')=='javax.jdo.option.ConnectionURL' || this.get('name')=='oozie.service.JPAService.jdbc.url') {
- if (validator.isConfigValueLink(value)) {
- isError = false;
- } else if (validator.isNotTrimmed(value)) {
- this.set('errorMessage', Em.I18n.t('host.trimspacesValidation'));
- isError = true;
- }
- } else {
- // Avoid single space values which is work around for validate empty properties.
- // Invalidate values which end with spaces.
- if (value !== ' ' && validator.isNotTrimmedRight(value)) {
- this.set('errorMessage', Em.I18n.t('form.validator.error.trailingSpaces'));
- isError = true;
- }
- }
- break;
- }
- }
-
- if (!isWarn || isError) { // Errors get priority
- this.set('warnMessage', '');
- this.set('warn', false);
+ if (!this.get('isEditable')) {
+ this.set('errorMessage', ''); // do not perform validation for not editable configs
+ } else if ((this.get('value') + '').length === 0) {
+ this.set('errorMessage', this.get('isRequired') ? Em.I18n.t('errorMessage.config.required') : '');
} else {
- this.set('warn', true);
+ this.set('errorMessage', this.validator(this.get('value'), this.get('name'), this.get('retypedPassword')));
}
+ }.observes('value', 'retypedPassword', 'isEditable'),
- if (!isError) {
- this.set('errorMessage', '');
- this.set('error', false);
- } else {
- this.set('error', true);
- }
- }.observes('value', 'isFinal', 'retypedPassword'),
+ viewClass: App.ServiceConfigTextField,
- /**
- * defines specific directory properties that
- * allows setting drive type before dir name
- * ex: [SSD]/usr/local/my_dir
- * @param config
- * @returns {*|Boolean|boolean}
- */
- configSupportHeterogeneous: function() {
- return ['directories', 'directory'].contains(this.get('displayType')) && ['dfs.datanode.data.dir'].contains(this.get('name'));
- }.property('displayType', 'name'),
+ validator: function() { return '' },
/**
* Get override for selected group
@@ -531,28 +339,6 @@ App.ServiceConfigProperty = Em.Object.extend({
return this.get('overrides').findProperty('group.name', groupName);
}
return null;
- },
-
- /**
- * Update description for `password`-config
- * Add extra-message about their comparison
- *
- * @method updateDescription
- */
- updateDescription: function () {
- var description = this.get('description');
- var displayType = this.get('displayType');
- var additionalDescription = Em.I18n.t('services.service.config.password.additionalDescription');
- if ('password' === displayType) {
- if (description) {
- if (!description.contains(additionalDescription)) {
- description += '<br />' + additionalDescription;
- }
- } else {
- description = additionalDescription;
- }
- }
- this.set('description', description);
}
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/c26e2ff6/ambari-web/app/utils/config.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/config.js b/ambari-web/app/utils/config.js
index 8b12a50..2bc5273 100644
--- a/ambari-web/app/utils/config.js
+++ b/ambari-web/app/utils/config.js
@@ -238,9 +238,7 @@ App.config = Em.Object.create({
}
if (useEmberObject) {
- var serviceConfigProperty = App.ServiceConfigProperty.create(serviceConfigObj);
- serviceConfigProperty.validate();
- configs.push(serviceConfigProperty);
+ configs.push(App.ServiceConfigProperty.create(serviceConfigObj));
} else {
configs.push(serviceConfigObj);
}
@@ -422,13 +420,7 @@ App.config = Em.Object.create({
* @returns {string}
*/
getDefaultCategory: function(stackConfigProperty, fileName) {
- var tag = this.getConfigTagFromFileName(fileName);
- switch (tag) {
- case 'capacity-scheduler':
- return 'CapacityScheduler';
- default :
- return (stackConfigProperty ? 'Advanced ' : 'Custom ') + tag;
- }
+ return (stackConfigProperty ? 'Advanced ' : 'Custom ') + this.getConfigTagFromFileName(fileName);
},
/**
@@ -441,6 +433,146 @@ App.config = Em.Object.create({
},
/**
+ * Returns description, formatted if needed
+ *
+ * @param {String} description
+ * @param {String} displayType
+ * @returns {String}
+ */
+ getDescription: function(description, displayType) {
+ var additionalDescription = Em.I18n.t('services.service.config.password.additionalDescription');
+ if ('password' === displayType) {
+ if (description && !description.contains(additionalDescription)) {
+ return description + '<br />' + additionalDescription;
+ } else {
+ return additionalDescription;
+ }
+ }
+ return description
+ },
+
+ /**
+ * Get view class based on display type of config
+ *
+ * @param displayType
+ * @param dependentConfigPattern
+ * @param unit
+ * @returns {*}
+ */
+ getViewClass: function (displayType, dependentConfigPattern, unit) {
+ switch (displayType) {
+ case 'checkbox':
+ case 'boolean':
+ return dependentConfigPattern ? App.ServiceConfigCheckboxWithDependencies : App.ServiceConfigCheckbox;
+ case 'password':
+ return App.ServiceConfigPasswordField;
+ case 'combobox':
+ return App.ServiceConfigComboBox;
+ case 'radio button':
+ return App.ServiceConfigRadioButtons;
+ case 'directories':
+ return App.ServiceConfigTextArea;
+ case 'directory':
+ return App.ServiceConfigTextField;
+ case 'content':
+ return App.ServiceConfigTextAreaContent;
+ case 'multiLine':
+ return App.ServiceConfigTextArea;
+ case 'custom':
+ return App.ServiceConfigBigTextArea;
+ case 'componentHost':
+ return App.ServiceConfigMasterHostView;
+ case 'label':
+ return App.ServiceConfigLabelView;
+ case 'componentHosts':
+ return App.ServiceConfigComponentHostsView;
+ case 'supportTextConnection':
+ return App.checkConnectionView;
+ case 'capacityScheduler':
+ return App.CapacitySceduler;
+ default:
+ return unit ? App.ServiceConfigTextFieldWithUnit : App.ServiceConfigTextField;
+ }
+ },
+
+ /**
+ * Returns validator function based on config type
+ *
+ * @param displayType
+ * @returns {Function}
+ */
+ getValidator: function (displayType) {
+ switch (displayType) {
+ case 'checkbox':
+ case 'custom':
+ return function () {
+ return ''
+ };
+ case 'int':
+ return function (value) {
+ return !validator.isValidInt(value) && !validator.isConfigValueLink(value)
+ ? Em.I18n.t('errorMessage.config.number.integer') : '';
+ };
+ case 'float':
+ return function (value) {
+ return !validator.isValidFloat(value) && !validator.isConfigValueLink(value)
+ ? Em.I18n.t('errorMessage.config.number.float') : '';
+ };
+ case 'directories':
+ case 'directory':
+ return function (value, name) {
+ if (App.config.isDirHeterogeneous(name)) {
+ if (!validator.isValidDataNodeDir(value)) return Em.I18n.t('errorMessage.config.directory.heterogeneous');
+ } else {
+ if (!validator.isValidDir(value)) return Em.I18n.t('errorMessage.config.directory.default');
+ }
+ if (!validator.isAllowedDir(value)) {
+ return Em.I18n.t('errorMessage.config.directory.allowed');
+ }
+ return validator.isNotTrimmedRight(value) ? Em.I18n.t('errorMessage.config.spaces.trailing') : '';
+ };
+ case 'email':
+ return function (value) {
+ return !validator.isValidEmail(value) ? Em.I18n.t('errorMessage.config.mail') : '';
+ };
+ case 'supportTextConnection':
+ case 'host':
+ return function (value) {
+ return validator.isNotTrimmed(value) ? Em.I18n.t('errorMessage.config.spaces.trim') : '';
+ };
+ case 'password':
+ return function (value, name, retypedPassword) {
+ return value !== retypedPassword ? Em.I18n.t('errorMessage.config.password') : '';
+ };
+ case 'user':
+ case 'database':
+ case 'db_user':
+ return function (value) {
+ return !validator.isValidDbName(value) ? Em.I18n.t('errorMessage.config.user') : '';
+ };
+ default:
+ return function (value, name) {
+ if (['javax.jdo.option.ConnectionURL', 'oozie.service.JPAService.jdbc.url'].contains(name)
+ && !validator.isConfigValueLink(value) && validator.isConfigValueLink(value)) {
+ return Em.I18n.t('errorMessage.config.spaces.trim');
+ } else {
+ return validator.isNotTrimmedRight(value) ? Em.I18n.t('errorMessage.config.spaces.trailing') : '';
+ }
+ };
+ }
+ },
+
+ /**
+ * Defines if config support heterogeneous devices
+ *
+ * @param {string} name
+ * @returns {boolean}
+ */
+ isDirHeterogeneous: function(name) {
+ return ['dfs.datanode.data.dir'].contains(name);
+ },
+
+ /**
* format property value depending on displayType
* and one exception for 'kdc_type'
* @param serviceConfigProperty
@@ -636,6 +768,7 @@ App.config = Em.Object.create({
'isFinal': isFinal,
'savedIsFinal': savedIsFinal,
'recommendedIsFinal': recommendedIsFinal,
+ 'category': 'CapacityScheduler',
'displayName': 'Capacity Scheduler',
'description': 'Capacity Scheduler properties',
'displayType': 'capacityScheduler'
@@ -944,7 +1077,6 @@ App.config = Em.Object.create({
serviceConfigProperty.set('overrideValues', savedOverrides.mapProperty('savedValue'));
serviceConfigProperty.set('overrideIsFinalValues', savedOverrides.mapProperty('savedIsFinal'));
- newOverride.validate();
return newOverride;
},
http://git-wip-us.apache.org/repos/asf/ambari/blob/c26e2ff6/ambari-web/app/utils/validator.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/validator.js b/ambari-web/app/utils/validator.js
index 896228b..9d11746 100644
--- a/ambari-web/app/utils/validator.js
+++ b/ambari-web/app/utils/validator.js
@@ -145,7 +145,7 @@ module.exports = {
* @returns {Boolean} - <code>true</code> if ends with spaces
*/
isNotTrimmedRight: function(value) {
- return /\s+$/.test(("" + value).split(/\n/).slice(-1)[0]);
+ return value !== ' ' && /\s+$/.test(("" + value).split(/\n/).slice(-1)[0]);
},
/**
http://git-wip-us.apache.org/repos/asf/ambari/blob/c26e2ff6/ambari-web/app/views/common/configs/custom_category_views/notification_configs_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/configs/custom_category_views/notification_configs_view.js b/ambari-web/app/views/common/configs/custom_category_views/notification_configs_view.js
index 3da387a..9ad8762 100644
--- a/ambari-web/app/views/common/configs/custom_category_views/notification_configs_view.js
+++ b/ambari-web/app/views/common/configs/custom_category_views/notification_configs_view.js
@@ -122,13 +122,6 @@ App.NotificationsConfigsView = App.ServiceConfigsByCategoryView.extend({
updateConfig: function (config, flag) {
config.set('isRequired', flag);
config.set('isEditable', flag);
- if (flag) {
- config.validate();
- }
- else {
- config.set('errorMessage', '');
- config.propertyDidChange('isValid');
- }
}
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/c26e2ff6/ambari-web/app/views/common/configs/widgets/list_config_widget_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/configs/widgets/list_config_widget_view.js b/ambari-web/app/views/common/configs/widgets/list_config_widget_view.js
index 3bcd81e..92e814c 100644
--- a/ambari-web/app/views/common/configs/widgets/list_config_widget_view.js
+++ b/ambari-web/app/views/common/configs/widgets/list_config_widget_view.js
@@ -219,8 +219,11 @@ App.ListConfigWidgetView = App.ConfigWidgetView.extend({
currentlySelected = this.get('options').filterProperty('isSelected').length,
selectionDisabled = allowedToSelect <= currentlySelected;
this.get('options').filterProperty('isSelected', false).setEach('isDisabled', selectionDisabled);
- this.set('config.errorMessage', currentlySelected < neededToSelect ? 'You should select at least ' + neededToSelect + ' item(s)' : '');
- this.get('config').validate();
+ if (currentlySelected < neededToSelect) {
+ this.set('config.errorMessage', 'You should select at least ' + neededToSelect + ' item(s)');
+ } else {
+ this.get('config').validate();
+ }
},
/**
http://git-wip-us.apache.org/repos/asf/ambari/blob/c26e2ff6/ambari-web/test/mixins/common/configs/config_recommendation_parser_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/mixins/common/configs/config_recommendation_parser_test.js b/ambari-web/test/mixins/common/configs/config_recommendation_parser_test.js
index 403ab98..ae668c7 100644
--- a/ambari-web/test/mixins/common/configs/config_recommendation_parser_test.js
+++ b/ambari-web/test/mixins/common/configs/config_recommendation_parser_test.js
@@ -166,10 +166,8 @@ describe('App.ConfigRecommendationParser', function() {
it ('adds new property', function() {
expect(instanceObject._createNewProperty.calledWith('p1', 'file-name', 'serviceName1', 'v1', [])).to.be.true;
- expect(stepConfig.get('configs.0')).to.eql(App.ServiceConfigProperty.create({
- 'name': 'p1',
- 'filename': 'file-name'
- }));
+ expect(stepConfig.get('configs.0.name')).to.equal('p1');
+ expect(stepConfig.get('configs.0.filename')).to.equal('file-name');
});
} else {
@@ -276,15 +274,22 @@ describe('App.ConfigRecommendationParser', function() {
});
it('adds new config', function() {
- expect(instanceObject._createNewProperty('name', 'fileName', 'recommendedValue', null)).to.eql(App.ServiceConfigProperty.create({
+ var res = {
'value': 'recommendedValue',
'recommendedValue': 'recommendedValue',
- 'initialValue': 'initialValue',
'savedValue': null,
'name': 'name',
- 'filename': 'fileName'
- }));
+ 'filename': 'fileName',
+ 'errorMessage': ''
+ };
+
+ var test = instanceObject._createNewProperty('name', 'fileName', 'recommendedValue', null);
+ for (var k in res) {
+ if (res.hasOwnProperty(k)) {
+ expect(test.get(k)).to.eql(res[k]);
+ }
+ }
expect(instanceObject.applyRecommendation.calledOnce).to.be.true;
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/c26e2ff6/ambari-web/test/models/configs/objects/service_config_property_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/models/configs/objects/service_config_property_test.js b/ambari-web/test/models/configs/objects/service_config_property_test.js
index b8a6f4e..3a1d14c 100644
--- a/ambari-web/test/models/configs/objects/service_config_property_test.js
+++ b/ambari-web/test/models/configs/objects/service_config_property_test.js
@@ -385,96 +385,10 @@ describe('App.ServiceConfigProperty', function () {
});
});
- describe('#viewClass', function () {
- classCases.forEach(function (item) {
- it ('should be ' + item.viewClass, function () {
- Em.keys(item.initial).forEach(function (prop) {
- serviceConfigProperty.set(prop, item.initial[prop]);
- });
- expect(serviceConfigProperty.get('viewClass')).to.eql(item.viewClass);
- });
- });
- });
-
- describe('#validate', function () {
- it('not required', function () {
- serviceConfigProperty.setProperties({
- isRequired: false,
- value: ''
- });
- expect(serviceConfigProperty.get('errorMessage')).to.be.empty;
- expect(serviceConfigProperty.get('error')).to.be.false;
- });
- it('test-db-connection widget', function () {
- serviceConfigProperty.setProperties({
- isRequired: true,
- widgetType: 'test-db-connection',
- value: ''
- });
- expect(serviceConfigProperty.get('errorMessage')).to.be.empty;
- expect(serviceConfigProperty.get('error')).to.be.false;
- });
- it('should validate', function () {
- serviceConfigProperty.setProperties({
- isRequired: true,
- value: 'value'
- });
- expect(serviceConfigProperty.get('errorMessage')).to.be.empty;
- expect(serviceConfigProperty.get('error')).to.be.false;
- });
- it('should fail', function () {
- serviceConfigProperty.setProperties({
- isRequired: true,
- value: 'value'
- });
- serviceConfigProperty.set('value', '');
- expect(serviceConfigProperty.get('errorMessage')).to.equal('This is required');
- expect(serviceConfigProperty.get('error')).to.be.true;
- });
- });
-
describe('#overrideIsFinalValues', function () {
it('should be defined as empty array', function () {
expect(serviceConfigProperty.get('overrideIsFinalValues')).to.eql([]);
});
});
- describe('#updateDescription', function () {
-
- beforeEach(function () {
- serviceConfigProperty.setProperties({
- displayType: 'password',
- description: ''
- });
- });
-
- it('should add extra-message to the description for `password`-configs', function () {
-
- var extraMessage = Em.I18n.t('services.service.config.password.additionalDescription');
- serviceConfigProperty.updateDescription();
- expect(serviceConfigProperty.get('description')).to.contain(extraMessage);
-
- });
-
- it('should not add extra-message to the description if it already contains it', function () {
-
- var extraMessage = Em.I18n.t('services.service.config.password.additionalDescription');
- serviceConfigProperty.updateDescription();
- serviceConfigProperty.updateDescription();
- serviceConfigProperty.updateDescription();
- expect(serviceConfigProperty.get('description')).to.contain(extraMessage);
- var subd = serviceConfigProperty.get('description').replace(extraMessage, '');
- expect(subd).to.not.contain(extraMessage);
- });
-
- it('should add extra-message to the description if description is not defined', function () {
-
- serviceConfigProperty.set('description', undefined);
- var extraMessage = Em.I18n.t('services.service.config.password.additionalDescription');
- serviceConfigProperty.updateDescription();
- expect(serviceConfigProperty.get('description')).to.contain(extraMessage);
- });
-
- });
-
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/c26e2ff6/ambari-web/test/models/form_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/models/form_test.js b/ambari-web/test/models/form_test.js
index 2d45ada..573deae 100644
--- a/ambari-web/test/models/form_test.js
+++ b/ambari-web/test/models/form_test.js
@@ -185,28 +185,6 @@ describe('App.FormField', function () {
});
});
- describe('#viewClass', function () {
- displayTypeCases.forEach(function (item) {
- it('should be ' + item.classString, function () {
- formField.set('displayType', item.type);
- expect(formField.get('viewClass').toString()).to.contain(item.classString);
- });
- });
- });
-
- /*eslint-disable mocha-cleanup/asserts-limit */
- describe('#validate', function () {
- it('should return error message', function () {
- formField.set('isRequired', true);
- expectError('This is required');
- });
- it('should return empty error message', function () {
- formField.set('isRequired', false);
- expectError('');
- formField.set('value', 'value');
- expectError('');
- });
- });
/*eslint-enable mocha-cleanup/asserts-limit */
describe('#isHiddenField', function () {
http://git-wip-us.apache.org/repos/asf/ambari/blob/c26e2ff6/ambari-web/test/utils/config_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/utils/config_test.js b/ambari-web/test/utils/config_test.js
index fd7c188..97c3cd7 100644
--- a/ambari-web/test/utils/config_test.js
+++ b/ambari-web/test/utils/config_test.js
@@ -891,4 +891,28 @@ describe('App.config', function () {
});
});
+ describe('#getDescription', function () {
+
+ it('should add extra-message to the description for `password`-configs', function () {
+ var extraMessage = Em.I18n.t('services.service.config.password.additionalDescription');
+ expect(App.config.getDescription('', 'password')).to.contain(extraMessage);
+ });
+
+ it('should not add extra-message to the description if it already contains it', function () {
+
+ var extraMessage = Em.I18n.t('services.service.config.password.additionalDescription');
+ var res = App.config.getDescription(extraMessage, 'password');
+ expect(res).to.contain(extraMessage);
+ expect(res).to.contain(extraMessage);
+ var subd = res.replace(extraMessage, '');
+ expect(subd).to.not.contain(extraMessage);
+ });
+
+ it('should add extra-message to the description if description is not defined', function () {
+
+ var extraMessage = Em.I18n.t('services.service.config.password.additionalDescription');
+ expect(App.config.getDescription(undefined, 'password')).to.contain(extraMessage);
+ });
+
+ });
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/c26e2ff6/ambari-web/test/views/common/configs/custom_category_views/notification_configs_view_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/common/configs/custom_category_views/notification_configs_view_test.js b/ambari-web/test/views/common/configs/custom_category_views/notification_configs_view_test.js
index 3af85ac..8f03434 100644
--- a/ambari-web/test/views/common/configs/custom_category_views/notification_configs_view_test.js
+++ b/ambari-web/test/views/common/configs/custom_category_views/notification_configs_view_test.js
@@ -217,14 +217,7 @@ describe('App.NotificationsConfigsView', function () {
var config;
beforeEach(function () {
- config = Em.Object.create({
- validate: Em.K
- });
- sinon.spy(config, 'validate');
- });
-
- afterEach(function () {
- config.validate.restore();
+ config = Em.Object.create();
});
describe("flag is true", function () {
@@ -238,9 +231,6 @@ describe('App.NotificationsConfigsView', function () {
it('isEditable is true', function () {
expect(config.get('isEditable')).to.be.true;
});
- it('validate is called once', function () {
- expect(config.validate.calledOnce).to.be.true;
- });
});
describe("flag is false", function () {
@@ -253,12 +243,6 @@ describe('App.NotificationsConfigsView', function () {
it('isEditable is false', function () {
expect(config.get('isEditable')).to.be.false;
});
- it('errorMessage is empty', function () {
- expect(config.get('errorMessage')).to.be.empty;
- });
- it('validate is not called', function () {
- expect(config.validate.called).to.be.false;
- });
});
});
});