This commit is contained in:
Jonathan Budzenski 2018-11-08 13:39:14 -06:00
parent 479f95e9e1
commit f8e8aaed2a
No known key found for this signature in database
GPG key ID: D28BF9418FA0F292
6 changed files with 128 additions and 120 deletions

View file

@ -44,6 +44,7 @@ export default function (kibana) {
alwaysPresentCertificate: Joi.boolean().default(false),
}).default();
const versionSchema = Joi.string().valid('major', 'minor', 'patch', 'exact', 'off');
return Joi.object({
enabled: Joi.boolean().default(true),
url: Joi.string().uri({ scheme: ['http', 'https'] }).default('http://localhost:9200'),
@ -62,6 +63,14 @@ export default function (kibana) {
healthCheck: Joi.object({
delay: Joi.number().default(2500)
}).default(),
version: Joi.object({
warn: Joi.when('$dev', {
is: true,
then: versionSchema.default('patch'),
otherwise: versionSchema.default('exact')
}),
error: versionSchema.default('major')
}).default()
}).default();
},

View file

@ -1,58 +0,0 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. 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.
*/
import expect from 'expect.js';
import isEsCompatibleWithKibana from '../is_es_compatible_with_kibana';
describe('plugins/elasticsearch', () => {
describe('lib/is_es_compatible_with_kibana', () => {
describe('returns false', () => {
it('when ES major is greater than Kibana major', () => {
expect(isEsCompatibleWithKibana('1.0.0', '0.0.0')).to.be(false);
});
it('when ES major is less than Kibana major', () => {
expect(isEsCompatibleWithKibana('0.0.0', '1.0.0')).to.be(false);
});
it('when majors are equal, but ES minor is less than Kibana minor', () => {
expect(isEsCompatibleWithKibana('1.0.0', '1.1.0')).to.be(false);
});
});
describe('returns true', () => {
it('when version numbers are the same', () => {
expect(isEsCompatibleWithKibana('1.1.1', '1.1.1')).to.be(true);
});
it('when majors are equal, and ES minor is greater than Kibana minor', () => {
expect(isEsCompatibleWithKibana('1.1.0', '1.0.0')).to.be(true);
});
it('when majors and minors are equal, and ES patch is greater than Kibana patch', () => {
expect(isEsCompatibleWithKibana('1.1.1', '1.1.0')).to.be(true);
});
it('when majors and minors are equal, but ES patch is less than Kibana patch', () => {
expect(isEsCompatibleWithKibana('1.1.0', '1.1.1')).to.be(true);
});
});
});
});

View file

@ -0,0 +1,70 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. 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.
*/
import expect from 'expect.js';
import { versionsMatch } from '../version_match';
describe('plugins/elasticsearch', () => {
describe('lib/version_match', () => {
it('off', () => {
expect(versionsMatch('abc', '1.0.0', 'off')).to.be(true);
expect(versionsMatch('2.0.0', '1.0.0', 'off')).to.be(true);
expect(versionsMatch('1.1.0', '1.0.0', 'off')).to.be(true);
expect(versionsMatch('1.0.1', '1.0.0', 'off')).to.be(true);
expect(versionsMatch('1.0.0-alpha1', '1.0.0', 'off')).to.be(true);
expect(versionsMatch('1.0.0', '1.0.0', 'off')).to.be(true);
});
it('major', () => {
expect(versionsMatch('abc', '1.0.0', 'major')).to.be(false);
expect(versionsMatch('2.0.0', '1.0.0', 'major')).to.be(false);
expect(versionsMatch('1.1.0', '1.0.0', 'major')).to.be(true);
expect(versionsMatch('1.0.1', '1.0.0', 'major')).to.be(true);
expect(versionsMatch('1.0.0-alpha1', '1.0.0', 'major')).to.be(true);
expect(versionsMatch('1.0.0', '1.0.0', 'major')).to.be(true);
});
it('minor', () => {
expect(versionsMatch('abc', '1.0.0', 'minor')).to.be(false);
expect(versionsMatch('2.0.0', '1.0.0', 'minor')).to.be(false);
expect(versionsMatch('1.1.0', '1.0.0', 'minor')).to.be(false);
expect(versionsMatch('1.0.1', '1.0.0', 'minor')).to.be(true);
expect(versionsMatch('1.0.0-alpha1', '1.0.0', 'minor')).to.be(true);
expect(versionsMatch('1.0.0', '1.0.0', 'minor')).to.be(true);
});
it('patch', () => {
expect(versionsMatch('abc', '1.0.0', 'patch')).to.be(false);
expect(versionsMatch('2.0.0', '1.0.0', 'patch')).to.be(false);
expect(versionsMatch('1.1.0', '1.0.0', 'patch')).to.be(false);
expect(versionsMatch('1.0.1', '1.0.0', 'patch')).to.be(false);
expect(versionsMatch('1.0.0-alpha1', '1.0.0', 'patch')).to.be(true);
expect(versionsMatch('1.0.0', '1.0.0', 'patch')).to.be(true);
});
it('exact', () => {
expect(versionsMatch('abc', '1.0.0', 'exact')).to.be(false);
expect(versionsMatch('2.0.0', '1.0.0', 'exact')).to.be(false);
expect(versionsMatch('1.1.0', '1.0.0', 'exact')).to.be(false);
expect(versionsMatch('1.0.1', '1.0.0', 'exact')).to.be(false);
expect(versionsMatch('1.0.0-alpha1', '1.0.0', 'exact')).to.be(false);
expect(versionsMatch('1.0.0', '1.0.0', 'exact')).to.be(true);
});
});
});

View file

@ -23,7 +23,7 @@
*/
import { forEach, get } from 'lodash';
import isEsCompatibleWithKibana from './is_es_compatible_with_kibana';
import { versionsMatch } from './version_match';
/**
* tracks the node descriptions that get logged in warnings so
@ -37,6 +37,9 @@ const lastWarnedNodesForServer = new WeakMap();
export function ensureEsVersion(server, kibanaVersion) {
const { callWithInternalUser } = server.plugins.elasticsearch.getCluster('admin');
const config = server.config();
const warnPrecision = config.get('elasticsearch.version.warn');
const errorPrecision = config.get('elasticsearch.version.error');
server.log(['plugin', 'debug'], 'Checking Elasticsearch version');
return callWithInternalUser('nodes.info', {
@ -54,18 +57,11 @@ export function ensureEsVersion(server, kibanaVersion) {
const warningNodes = [];
forEach(info.nodes, esNode => {
if (!isEsCompatibleWithKibana(esNode.version, kibanaVersion)) {
if (!versionsMatch(esNode.version, kibanaVersion, errorPrecision)) {
// Exit early to avoid collecting ES nodes with newer major versions in the `warningNodes`.
return incompatibleNodes.push(esNode);
}
// It's acceptable if ES and Kibana versions are not the same so long as
// they are not incompatible, but we should warn about it
// In development we ignore, this can be expected when testing against snapshots
// or across version qualifiers
const isProd = server.config().get('env.prod');
const versionMismatch = esNode.version !== kibanaVersion;
if (isProd && versionMismatch) {
if (!versionsMatch(esNode.version, kibanaVersion, warnPrecision)) {
warningNodes.push(esNode);
}
});

View file

@ -1,52 +0,0 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. 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.
*/
/**
* Let's weed out the ES versions that won't work with a given Kibana version.
* 1. Major version differences will never work together.
* 2. Older versions of ES won't work with newer versions of Kibana.
*/
import semver from 'semver';
export default function isEsCompatibleWithKibana(esVersion, kibanaVersion) {
const esVersionNumbers = {
major: semver.major(esVersion),
minor: semver.minor(esVersion),
patch: semver.patch(esVersion),
};
const kibanaVersionNumbers = {
major: semver.major(kibanaVersion),
minor: semver.minor(kibanaVersion),
patch: semver.patch(kibanaVersion),
};
// Reject mismatching major version numbers.
if (esVersionNumbers.major !== kibanaVersionNumbers.major) {
return false;
}
// Reject older minor versions of ES.
if (esVersionNumbers.minor < kibanaVersionNumbers.minor) {
return false;
}
return true;
}

View file

@ -0,0 +1,43 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. 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.
*/
import { intersects, coerce } from 'semver';
import { get } from 'lodash';
export function versionsMatch(a, b, precision) {
if (precision === 'off') return true;
const parsedA = get(coerce(a), 'version', null);
const parsedB = get(coerce(b), 'version', null);
if (!(parsedA && parsedB)) return false;
switch (precision) {
case 'major':
return intersects(`^${parsedA}`, `^${parsedB}`);
case 'minor':
return intersects(`~${parsedA}`, `~${parsedB}`);
case 'patch':
return intersects(parsedA, parsedB);
case 'exact':
return a === b;
default:
throw new Error('unexpected precision');
}
}