Add semantic version checking. Set minimum elasticsearch version to 1.2.1

This commit is contained in:
Rashid Khan 2014-06-18 13:56:43 -07:00
parent e8c9173e6f
commit b526eb2917
7 changed files with 291 additions and 38 deletions

View file

@ -110,7 +110,7 @@ define(function (require) {
.catch(function (err) {
// TODO: we should probably display a message of some kind
if (err instanceof MissingIndices) {
index.fetchFieldsError = 'Unable to fetch mapping. Do you have recent indices matching the interval?';
index.fetchFieldsError = 'Unable to fetch mapping. Do you have indices matching the pattern?';
return [];
}

View file

@ -1,47 +1,21 @@
define(function (require) {
return function CheckEsVersionFn(Private, es, configFile, Notifier) {
var _ = require('lodash');
var versionmath = require('utils/versionmath');
return function CheckEsVersionFn(Private, es, configFile, Notifier, minimumElasticsearchVersion) {
return function checkEsVersion() {
var notify = new Notifier({ location: 'Setup: Elasticsearch version check' });
var complete = notify.lifecycle('check es version');
var SetupError = Private(require('components/setup/_setup_error'));
// core expression for finding a version
var versionExp = '([\\d\\.]*\\d)(?:\\.\\w+)?';
/**
* Regular Expression to extract a version number from a string
* @type {RegExp}
*/
var versionRE = new RegExp(versionExp);
/**
* Regular Expression to extract a version range from a string
* @type {RegExp}
*/
var versionRangeRE = new RegExp(versionExp + '\\s*\\-\\s*' + versionExp);
var int = function (txt) {
var i = parseInt(txt, 10);
return (!i || isNaN(i)) ? 0 : i;
};
return es.info()
return es.nodes.info()
.then(function (info) {
var raw = info.version.number;
var sections = raw.split('-');
var someTypeOfBeta = sections.length > 1;
var all = sections.shift().split('.');
var major = int(all.shift());
var minor = int(all.shift());
var patch = int(all.shift());
var currentRelease = major === 1 && minor >= 1;
var betaPreRelease = major === 1 && minor === 0 && someTypeOfBeta;
if (currentRelease || betaPreRelease) return true;
else throw SetupError('Incompatible Elasticsearch version "' + raw + '". Expected version 1.1 or a 1.0-Beta release');
var versions = _.map(info.nodes, function (v) {
// Remove everything after the -, we don't handle beta/rc ES versions
return v.version.split('-')[0];
});
if (versionmath.is('>=' + minimumElasticsearchVersion, versions)) return true;
else throw SetupError('This version of Kibana requires at least Elasticsearch ' + minimumElasticsearchVersion);
})
.then(complete, complete.failure);
};

View file

@ -25,6 +25,8 @@ define(function (require) {
kibana
// This stores the Kibana revision number, @REV@ is replaced by grunt.
.constant('kbnVersion', '@REV@')
// The minimum Elasticsearch version required to run Kibana
.constant('minimumElasticsearchVersion', '1.2.1')
// Use this for cache busting partials
.constant('cacheBust', 'cache-bust=' + Date.now())
// attach the route manager's known routes

View file

@ -0,0 +1,149 @@
define(function (require) {
var _ = require('lodash');
function VersionMathException(message) {
this.message = message;
this.name = 'VersionMathException';
}
// Get the max version in this cluster
var max = function (versions) {
return _.last(sortVersions(versions));
};
// Return the lowest version in the cluster
var min = function (versions) {
return _.first(sortVersions(versions));
};
// Sort versions from lowest to highest
var sortVersions = function (versions) {
var _versions = _.clone(versions),
_r = [];
while (_r.length < versions.length) {
var _h = '0';
/*jshint -W083 */
_.each(_versions, function (v) {
if (compare(_h, v)) {
_h = v;
}
});
_versions = _.without(_versions, _h);
_r.push(_h);
}
return _r.reverse();
};
/*
Takes a version string with one of the following optional comparison prefixes: >,>=,<.<=
and evaluates if the cluster meets the requirement. If the prefix is omitted exact match
is assumed
*/
var is = function (equation, versions) {
var _versions = sortVersions(versions);
var _v = equation,
_cf;
if (_v.charAt(0) === '>') {
_cf = _v.charAt(1) === '=' ? gte(_v.slice(2), _versions) : gt(_v.slice(1), _versions);
} else if (_v.charAt(0) === '<') {
_cf = _v.charAt(1) === '=' ? lte(_v.slice(2), _versions) : lt(_v.slice(1), _versions);
} else {
_cf = eq(_v, _versions);
}
return _cf;
};
// check if lowest version in cluster = `version`
var eq = function (version, versions) {
var _versions = sortVersions(versions);
return version === min(_versions) ? true : false;
};
// version > lowest version in cluster?
var gt = function (version, versions) {
var _versions = sortVersions(versions);
return version === min(_versions) ? false : gte(version, _versions);
};
// version < highest version in cluster?
var lt = function (version, versions) {
var _versions = sortVersions(versions);
return version === max(_versions) ? false : lte(version, _versions);
};
// Check if the lowest version in the cluster is >= to `version`
var gte = function (version, versions) {
var _versions = sortVersions(versions);
return compare(version, min(_versions));
};
// Check if the highest version in the cluster is <= to `version`
var lte = function (version, versions) {
var _versions = sortVersions(versions);
return compare(max(_versions), version);
};
// Determine if a specific version meets the minimum requirement
var compare = function (required, installed) {
if (_.isUndefined(installed)) {
return;
}
if (!required || !installed) {
return undefined;
}
var a = installed.split('.');
var b = required.split('.');
var i;
// leave suffixes as is ("RC1 or -SNAPSHOT")
for (i = 0; i < Math.min(a.length, 3); ++i) {
a[i] = Number(a[i]);
}
for (i = 0; i < Math.min(b.length, 3); ++i) {
b[i] = Number(b[i]);
}
if (a.length === 2) {
a[2] = 0;
}
if (a[0] > b[0]) { return true; }
if (a[0] < b[0]) { return false; }
if (a[1] > b[1]) { return true; }
if (a[1] < b[1]) { return false; }
if (a[2] > b[2]) { return true; }
if (a[2] < b[2]) { return false; }
if (a.length > 3) {
// rc/beta suffix
if (b.length <= 3) {
return false;
} // no suffix on b -> a<b
return a[3] >= b[3];
}
if (b.length > 3) {
// b has a suffix but a not -> a>b
return true;
}
return true;
};
return {
min: min,
max: max,
is: is,
eq: eq,
gt: gt,
gte: gte,
lt: lt,
lte: lte
};
});

View file

@ -59,6 +59,7 @@
'specs/filters/start_from',
'specs/utils/datemath',
'specs/utils/interval',
'specs/utils/versionmath',
], function (sinon) {
var xhr = sinon.useFakeXMLHttpRequest();

View file

@ -21,7 +21,6 @@ define(function (require) {
describe('description', function () {
it('returns a readable description for an interval', function () {
expect(interval.describe('1ms')).to.be('1ms');
expect(interval.describe('1s')).to.be('1s');
expect(interval.describe('1m')).to.be('1m');
expect(interval.describe('1h')).to.be('1h');

View file

@ -0,0 +1,128 @@
define(function (require) {
var _ = require('lodash');
var versionmath = require('utils/versionmath');
var versions = [
'1.1.12',
'0.90.0',
'0.90.1',
'1.0.0',
'1.0',
'1.2.3',
'2.0.0',
'2.0.1',
'2.3.1'
];
describe('version math (0.90.0 - 2.3.1)', function () {
var methods = 'max,min,eq,is,lt,lte,gt,gte'.split(',');
describe('methods', function () {
it('should have ' + methods.join(', ') + ' methods', function () {
_.each(methods, function (method) {
expect(versionmath[method]).to.be.a(Function);
});
});
});
describe('min & max', function () {
it('has a max of 2.3.1', function () {
expect(versionmath.max(versions)).to.be('2.3.1');
});
it('has a min of 0.90.0', function () {
expect(versionmath.min(versions)).to.be('0.90.0');
});
});
describe('eq / lowest version', function () {
it('should be true for 0.90.0', function () {
expect(versionmath.eq('0.90.0', versions)).to.be(true);
});
it('should be false for 1.0', function () {
expect(versionmath.eq('1.0', versions)).to.be(false);
});
});
describe('gt / lowest version', function () {
it('is > 0.20.3', function () {
expect(versionmath.gt('0.20.3', versions)).to.be(true);
});
it('is not > 0.90.0', function () {
expect(versionmath.gt('0.90.0', versions)).to.be(false);
});
it('is not > 1.0.0', function () {
expect(versionmath.gt('1.0.0', versions)).to.be(false);
});
});
describe('gte / lowest version', function () {
it('is >= 0.20.3', function () {
expect(versionmath.gte('0.20.3', versions)).to.be(true);
});
it('is >= 0.90.0', function () {
expect(versionmath.gte('0.90.0', versions)).to.be(true);
});
it('is not >= 1.0.0', function () {
expect(versionmath.gte('1.0.0', versions)).to.be(false);
});
});
describe('lt / highest version', function () {
it('is not < 0.20.3', function () {
expect(versionmath.lt('0.20.3', versions)).to.be(false);
});
it('is not < 2.3.1', function () {
expect(versionmath.lt('2.3.1', versions)).to.be(false);
});
it('is < 2.5', function () {
expect(versionmath.lt('2.5', versions)).to.be(true);
});
});
describe('lte / highest version', function () {
it('is not =< 0.20.3', function () {
expect(versionmath.lte('0.20.3', versions)).to.be(false);
});
it('is =< 2.3.1', function () {
expect(versionmath.lte('2.3.1', versions)).to.be(true);
});
it('is =< 2.5', function () {
expect(versionmath.lte('2.5', versions)).to.be(true);
});
});
describe('is', function () {
it('exactly, <, <=, >, >=', function () {
expect(versionmath.is('0.90.0', versions)).to.be(true);
expect(versionmath.is('0.20.0', versions)).to.be(false);
expect(versionmath.is('>0.20.0', versions)).to.be(true);
expect(versionmath.is('>0.90.0', versions)).to.be(false);
expect(versionmath.is('>0.90.1', versions)).to.be(false);
expect(versionmath.is('>=0.20.0', versions)).to.be(true);
expect(versionmath.is('>=0.90.0', versions)).to.be(true);
expect(versionmath.is('>=0.90.1', versions)).to.be(false);
expect(versionmath.is('<2.5', versions)).to.be(true);
expect(versionmath.is('<2.3.1', versions)).to.be(false);
expect(versionmath.is('<0.90.1', versions)).to.be(false);
expect(versionmath.is('<=2.5', versions)).to.be(true);
expect(versionmath.is('<=2.3.1', versions)).to.be(true);
expect(versionmath.is('<=0.90.1', versions)).to.be(false);
});
});
});
});