Updated Branches: refs/heads/trunk 275096202 -> e6e7ec1f9
AMBARI-3884. Validate string-type dynamic configs in YARN and MR2. (onechiporenko) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/e6e7ec1f Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/e6e7ec1f Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/e6e7ec1f Branch: refs/heads/trunk Commit: e6e7ec1f9b740f4b6dbbd2b6db30122cb292f087 Parents: 2750962 Author: Oleg Nechiporenko <[email protected]> Authored: Tue Nov 26 13:50:35 2013 +0200 Committer: Oleg Nechiporenko <[email protected]> Committed: Tue Nov 26 13:53:42 2013 +0200 ---------------------------------------------------------------------- .../validators/mapreduce2_configs_validator.js | 6 +- .../validators/service_configs_validator.js | 81 +++++++++ .../service_configs_validator_test.js | 179 +++++++++++++++++++ 3 files changed, 263 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/e6e7ec1f/ambari-web/app/utils/configs/validators/mapreduce2_configs_validator.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/utils/configs/validators/mapreduce2_configs_validator.js b/ambari-web/app/utils/configs/validators/mapreduce2_configs_validator.js index c5803d7..a469daa 100644 --- a/ambari-web/app/utils/configs/validators/mapreduce2_configs_validator.js +++ b/ambari-web/app/utils/configs/validators/mapreduce2_configs_validator.js @@ -34,11 +34,11 @@ App.MapReduce2ConfigsValidator = App.ServiceConfigsValidator.create({ }, mapreduceMapJavaOpts: function(config) { - return null; + return this.validateXmxValue(config); }, mapreduceReduceJavaOpts: function(config) { - return null; + return this.validateXmxValue(config); }, mapreduceTaskIoSortMb: function(config) { @@ -58,7 +58,7 @@ App.MapReduce2ConfigsValidator = App.ServiceConfigsValidator.create({ }, yarnAppMapreduceAmCommandOpts: function(config) { - return null; + return this.validateXmxValue(config); } }); http://git-wip-us.apache.org/repos/asf/ambari/blob/e6e7ec1f/ambari-web/app/utils/configs/validators/service_configs_validator.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/utils/configs/validators/service_configs_validator.js b/ambari-web/app/utils/configs/validators/service_configs_validator.js index a14108c..ed8d9a6 100644 --- a/ambari-web/app/utils/configs/validators/service_configs_validator.js +++ b/ambari-web/app/utils/configs/validators/service_configs_validator.js @@ -54,6 +54,7 @@ App.ServiceConfigsValidator = Em.Object.extend({ /** * Check if provided <code>config.value</code> is less than <code>recommendedDefaults</code> * @param {object} config - configProperty name + * @return {string|null} */ validatorLessThenDefaultValue: function(config) { var defaultValue = this.get('recommendedDefaults')[config.get('name')]; @@ -66,6 +67,86 @@ App.ServiceConfigsValidator = Em.Object.extend({ return "Value is less than the recommended default of "+defaultValue; } return null; + }, + + /** + * Check if provided <code>config.value</code> is less than <code>recommendedDefaults</code> + * Value looks like "-Xmx****m" + * @param {object} config + * @return {string|null} + */ + validateXmxValue: function(config) { + var defaultValueRaw = this.get('recommendedDefaults')[config.get('name')]; + var currentValueRaw = config.get('value'); + if (!this._checkXmxValueFormat(currentValueRaw)) { + return 'Invalid value format'; + } + var currentValue = this._formatXmxSizeToBytes(this._getXmxSize(currentValueRaw)); + var defaultValue = this._formatXmxSizeToBytes(this._getXmxSize(defaultValueRaw)); + if (currentValue < defaultValue) { + return "Value is less than the recommended default of " + defaultValueRaw; + } + return null; + }, + /** + * Verify if provided value has proper format (should be like "-Xmx***(b|k|m|g|p|t|B|K|M|G|P|T)") + * @param {string} value + * @returns {boolean} + * @private + */ + _checkXmxValueFormat: function(value) { + var regex = /^\-Xmx(\d+)(b|k|m|g|p|t|B|K|M|G|P|T)?(\s+)?(\s.+)?$/; + if (!regex.test(value)) { + return false; + } + // "-Xmx" can be only one + if (value.match(/\-Xmx/ig).length != 1) { + return false; + } + return true; + }, + /** + * Parse Xmx size from raw value + * @param {string} value + * @returns {string} + * @private + */ + _getXmxSize: function(value) { + var regex = /\-Xmx(\d+)(.?)/; + var result = regex.exec(value); + if (result.length > 1) { + // result[2] - is a space or size formatter (b|k|m|g etc) + return result[1] + result[2].toLowerCase(); + } + return result[1]; + }, + /** + * Calculate bytes size from value + * @param {string} value + * @returns {int} + * @private + */ + _formatXmxSizeToBytes: function(value) { + value = value.toLowerCase(); + if (value.length == 0) { + return 0; + } + var modifier = value[value.length - 1]; + if (modifier == ' ' || "0123456789".indexOf(modifier) != -1) { + modifier = 'b'; + } + var m = 1; + switch (modifier) { + case 'b': m = 1; break; + case 'k': m = 1024; break; + case 'm': m = 1024 * 1024; break; + case 'g': m = 1024 * 1024 * 1024; break; + case 't': m = 1024 * 1024 * 1024 * 1024; break; + case 'p': m = 1024 * 1024 * 1024 * 1024 * 1024; break; + } + var result = parseInt(value.replace(modifier, '').trim()); + result *= m; + return result; } }); http://git-wip-us.apache.org/repos/asf/ambari/blob/e6e7ec1f/ambari-web/test/utils/configs/validators/service_configs_validator_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/utils/configs/validators/service_configs_validator_test.js b/ambari-web/test/utils/configs/validators/service_configs_validator_test.js index 744053f..3fbe2e5 100644 --- a/ambari-web/test/utils/configs/validators/service_configs_validator_test.js +++ b/ambari-web/test/utils/configs/validators/service_configs_validator_test.js @@ -78,4 +78,183 @@ describe('App.ServiceConfigsValidator', function() { }); }); + describe('#_checkXmxValueFormat', function() { + var tests = [ + {value: '',e: false}, + {value: '-',e: false}, + {value: '100',e: false}, + {value: '-Xmx',e: false}, + {value: '-XMX1',e: false}, + {value: '-Xmxb',e: false}, + {value: '-Xmxk',e: false}, + {value: '-Xmxm',e: false}, + {value: '-Xmxg',e: false}, + {value: '-Xmxp',e: false}, + {value: '-Xmxt',e: false}, + {value: '-XmxB',e: false}, + {value: '-XmxK',e: false}, + {value: '-XmxM',e: false}, + {value: '-XmxG',e: false}, + {value: '-XmxP',e: false}, + {value: '-XmxT',e: false}, + {value: '-Xmx1',e: true}, + {value: '-Xmx1b',e: true}, + {value: '-Xmx1k',e: true}, + {value: '-Xmx1m',e: true}, + {value: '-Xmx1g',e: true}, + {value: '-Xmx1t',e: true}, + {value: '-Xmx1p',e: true}, + {value: '-Xmx1B',e: true}, + {value: '-Xmx1K',e: true}, + {value: '-Xmx1M',e: true}, + {value: '-Xmx1G',e: true}, + {value: '-Xmx1T',e: true}, + {value: '-Xmx1P',e: true}, + {value: '-Xmx100',e: true}, + {value: '-Xmx100b',e: true}, + {value: '-Xmx100k',e: true}, + {value: '-Xmx100m',e: true}, + {value: '-Xmx100g',e: true}, + {value: '-Xmx100t',e: true}, + {value: '-Xmx100p',e: true}, + {value: '-Xmx100B',e: true}, + {value: '-Xmx100K',e: true}, + {value: '-Xmx100M',e: true}, + {value: '-Xmx100G',e: true}, + {value: '-Xmx100T',e: true}, + {value: '-Xmx100P',e: true}, + {value: '-Xmx100Psome',e: false}, + {value: '-Xmx100P-Xmx',e: false}, + {value: '-Xmx100P -Xmx',e: false}, + {value: '-Xmx100P -XMX',e: false} + ]; + tests.forEach(function(test) { + it(test.value, function() { + var v = App.ServiceConfigsValidator.create({}); + expect(v._checkXmxValueFormat(test.value)).to.equal(test.e); + }); + }); + }); + + describe('#_getXmxSize', function() { + var tests = [ + {value: '-Xmx1', e: '1'}, + {value: '-Xmx1b', e: '1b'}, + {value: '-Xmx1k', e: '1k'}, + {value: '-Xmx1m', e: '1m'}, + {value: '-Xmx1g', e: '1g'}, + {value: '-Xmx1t', e: '1t'}, + {value: '-Xmx1p', e: '1p'}, + {value: '-Xmx1B', e: '1b'}, + {value: '-Xmx1K', e: '1k'}, + {value: '-Xmx1M', e: '1m'}, + {value: '-Xmx1G', e: '1g'}, + {value: '-Xmx1T', e: '1t'}, + {value: '-Xmx1P', e: '1p'}, + {value: '-Xmx100b', e: '100b'}, + {value: '-Xmx100k', e: '100k'}, + {value: '-Xmx100m', e: '100m'}, + {value: '-Xmx100g', e: '100g'}, + {value: '-Xmx100t', e: '100t'}, + {value: '-Xmx100p', e: '100p'}, + {value: '-Xmx100B', e: '100b'}, + {value: '-Xmx100K', e: '100k'}, + {value: '-Xmx100M', e: '100m'}, + {value: '-Xmx100G', e: '100g'}, + {value: '-Xmx100T', e: '100t'}, + {value: '-Xmx100P', e: '100p'} + ]; + tests.forEach(function(test) { + it(test.value, function() { + var v = App.ServiceConfigsValidator.create({}); + expect(v._getXmxSize(test.value)).to.equal(test.e); + }); + }); + }); + + describe('#_formatXmxSizeToBytes', function() { + var tests = [ + {value: '1', e: 1}, + {value: '1 ', e: 1}, + {value: '100', e: 100}, + {value: '100 ', e: 100}, + {value: '100b', e: 100}, + {value: '100B', e: 100}, + {value: '100k', e: 100 * 1024}, + {value: '100K', e: 100 * 1024}, + {value: '100m', e: 100 * 1024 * 1024}, + {value: '100M', e: 100 * 1024 * 1024}, + {value: '100g', e: 100 * 1024 * 1024 * 1024}, + {value: '100G', e: 100 * 1024 * 1024 * 1024}, + {value: '100t', e: 100 * 1024 * 1024 * 1024 * 1024}, + {value: '100T', e: 100 * 1024 * 1024 * 1024 * 1024}, + {value: '100p', e: 100 * 1024 * 1024 * 1024 * 1024 * 1024}, + {value: '100P', e: 100 * 1024 * 1024 * 1024 * 1024 * 1024} + ]; + tests.forEach(function(test) { + it(test.value, function() { + var v = App.ServiceConfigsValidator.create({}); + expect(v._formatXmxSizeToBytes(test.value)).to.equal(test.e); + }); + }); + }); + + describe('#validateXmxValue', function() { + var tests = [ + { + recommendedDefaults: { + 'property1': '-Xmx1024m' + }, + config: Em.Object.create({ + value: '-Xmx2g', + name: 'property1' + }), + e: null + }, + { + recommendedDefaults: { + 'property1': '-Xmx12' + }, + config: Em.Object.create({ + value: '-Xmx24', + name: 'property1' + }), + e: null + }, + { + recommendedDefaults: { + 'property1': '-Xmx333k' + }, + config: Em.Object.create({ + value: '-Xmx134k', + name: 'property1' + }), + e: 'string' + }, + { + recommendedDefaults: { + 'property1': '-Xmx333k' + }, + config: Em.Object.create({ + value: '-Xmx534', + name: 'property1' + }), + e: 'string' + } + ]; + tests.forEach(function(test) { + it(test.config.get('value'), function() { + var v = App.ServiceConfigsValidator.create({}); + v.set('recommendedDefaults', test.recommendedDefaults); + var r = v.validateXmxValue(test.config); + if (test.e) { + expect(r).to.be.a(test.e); + } + else { + expect(r).to.equal(null) + } + }); + }); + }); + });
