diff --git a/docs/releasenotes.asciidoc b/docs/releasenotes.asciidoc index 69a78d1af27d7..70c7e9ff14db9 100644 --- a/docs/releasenotes.asciidoc +++ b/docs/releasenotes.asciidoc @@ -16,6 +16,7 @@ The {version} release of Kibana requires Elasticsearch {esversion} or later. * {k4issue}6531[Issue 6531]: Improved warning for URL lengths that approach browser limits. * {k4issue}6602[Issue 6602]: Improves dark theme support. * {k4issue}6791[Issue 6791]: Enables composition of custom user toast notifications in Advanced Settings. +* {k4pull}8014[Pull Request 8014]: Changes the UUID config setting from `uuid` to `server.uuid`, and puts UUID storage into data file instead of Elasticsearch. [float] [[bugfixes]] diff --git a/src/core_plugins/elasticsearch/lib/health_check.js b/src/core_plugins/elasticsearch/lib/health_check.js index 6920b4eb593f9..cca77e2f2398a 100644 --- a/src/core_plugins/elasticsearch/lib/health_check.js +++ b/src/core_plugins/elasticsearch/lib/health_check.js @@ -5,7 +5,6 @@ import exposeClient from './expose_client'; import migrateConfig from './migrate_config'; import createKibanaIndex from './create_kibana_index'; import checkEsVersion from './check_es_version'; -import manageUuid from './manage_uuid'; const NoConnections = elasticsearch.errors.NoConnections; import util from 'util'; const format = util.format; @@ -19,7 +18,6 @@ const REQUEST_DELAY = 2500; module.exports = function (plugin, server) { const config = server.config(); const client = server.plugins.elasticsearch.client; - const uuidManagement = manageUuid(server); plugin.status.yellow('Waiting for Elasticsearch'); @@ -89,7 +87,6 @@ module.exports = function (plugin, server) { return waitForPong() .then(_.partial(checkEsVersion, server)) .then(waitForShards) - .then(uuidManagement) .then(setGreenStatus) .then(_.partial(migrateConfig, server)) .catch(err => plugin.status.red(err)); diff --git a/src/core_plugins/elasticsearch/lib/manage_uuid.js b/src/core_plugins/elasticsearch/lib/manage_uuid.js deleted file mode 100644 index 43be6c9654268..0000000000000 --- a/src/core_plugins/elasticsearch/lib/manage_uuid.js +++ /dev/null @@ -1,81 +0,0 @@ -import uuid from 'node-uuid'; -import { hostname } from 'os'; -const serverHostname = hostname(); - -/* Handle different scenarios: - * - config uuid exists, data uuid exists and matches - * - nothing to do - * - config uuid missing, data uuid exists - * - set uuid from data as config uuid - * - config uuid exists, data uuid exists but mismatches - * - update data uuid with config uuid - * - config uuid missing, data uuid missing - * - generate new uuid, set in config and insert in data - * ("config uuid" = uuid in server.config, - * "data uuid" = uuid in .kibana index) - */ -export default function manageUuid(server) { - const TYPE = 'server'; - const config = server.config(); - const serverPort = server.info.port; - const client = server.plugins.elasticsearch.client; - - return function uuidManagement() { - const fieldId = `${serverHostname}-${serverPort}`; - const kibanaIndex = config.get('kibana.index'); - let kibanaUuid = config.get('uuid'); - - function logToServer(msg) { - server.log(['server', 'uuid', fieldId], msg); - } - - return client.get({ - index: kibanaIndex, - ignore: [404], - type: TYPE, - id: fieldId - }).then(result => { - if (result.found) { - if (kibanaUuid === result._source.uuid) { - // config uuid exists, data uuid exists and matches - logToServer(`Kibana instance UUID: ${kibanaUuid}`); - return; - } - - if (!kibanaUuid) { - // config uuid missing, data uuid exists - kibanaUuid = result._source.uuid; - logToServer(`Resuming persistent Kibana instance UUID: ${kibanaUuid}`); - config.set('uuid', kibanaUuid); - return; - } - - if (kibanaUuid !== result._source.uuid) { - // config uuid exists, data uuid exists but mismatches - logToServer(`Updating Kibana instance UUID to: ${kibanaUuid} (was: ${result._source.uuid})`); - return client.update({ - index: kibanaIndex, - type: TYPE, - id: fieldId, - body: { doc: { uuid: kibanaUuid } } - }); - } - } - - // data uuid missing - if (!kibanaUuid) { - // config uuid missing - kibanaUuid = uuid.v4(); - config.set('uuid', kibanaUuid); - } - - logToServer(`Setting new Kibana instance UUID: ${kibanaUuid}`); - return client.index({ - index: kibanaIndex, - type: TYPE, - id: fieldId, - body: { uuid: kibanaUuid } - }); - }); - }; -} diff --git a/src/core_plugins/kibana/index.js b/src/core_plugins/kibana/index.js index 35ee2915f0bf0..ac337892136a9 100644 --- a/src/core_plugins/kibana/index.js +++ b/src/core_plugins/kibana/index.js @@ -1,3 +1,4 @@ +import manageUuid from './server/lib/manage_uuid'; import ingest from './server/routes/api/ingest'; import search from './server/routes/api/search'; import settings from './server/routes/api/settings'; @@ -84,6 +85,9 @@ module.exports = function (kibana) { }, init: function (server, options) { + // uuid + manageUuid(server); + // routes ingest(server); search(server); settings(server); diff --git a/src/core_plugins/elasticsearch/lib/__tests__/manage_uuid.js b/src/core_plugins/kibana/server/lib/__tests__/manage_uuid.js similarity index 66% rename from src/core_plugins/elasticsearch/lib/__tests__/manage_uuid.js rename to src/core_plugins/kibana/server/lib/__tests__/manage_uuid.js index 80a0687f9ab0d..9b0d16faafe4e 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/manage_uuid.js +++ b/src/core_plugins/kibana/server/lib/__tests__/manage_uuid.js @@ -1,11 +1,11 @@ import expect from 'expect.js'; import sinon from 'sinon'; import Joi from 'joi'; -import * as kbnTestServer from '../../../../../test/utils/kbn_server.js'; -import fromRoot from '../../../../utils/from_root'; +import * as kbnTestServer from '../../../../../../test/utils/kbn_server.js'; +import fromRoot from '../../../../../utils/from_root'; import manageUuid from '../manage_uuid'; -describe('plugins/elasticsearch', function () { +describe('core_plugins/kibana/server/lib', function () { describe('manage_uuid', function () { const testUuid = 'c4add484-0cba-4e05-86fe-4baa112d9e53'; let kbnServer; @@ -23,7 +23,6 @@ describe('plugins/elasticsearch', function () { }); await kbnServer.ready(); - await kbnServer.server.plugins.elasticsearch.waitUntilReady(); }); // clear uuid stuff from previous test runs @@ -38,53 +37,48 @@ describe('plugins/elasticsearch', function () { }); it('ensure config uuid is validated as a guid', async function () { - config.set('uuid', testUuid); - expect(config.get('uuid')).to.be(testUuid); + config.set('server.uuid', testUuid); + expect(config.get('server.uuid')).to.be(testUuid); expect(() => { - config.set('uuid', 'foouid'); + config.set('server.uuid', 'foouid'); }).to.throwException((e) => { expect(e.name).to.be('ValidationError'); }); }); it('finds the previously set uuid with config match', async function () { - const uuidManagement = manageUuid(kbnServer.server); const msg = `Kibana instance UUID: ${testUuid}`; - config.set('uuid', testUuid); + config.set('server.uuid', testUuid); - await uuidManagement(); - await uuidManagement(); + await manageUuid(kbnServer.server); + await manageUuid(kbnServer.server); expect(kbnServer.server.log.lastCall.args[1]).to.be.eql(msg); }); it('updates the previously set uuid with config value', async function () { - const uuidManagement = manageUuid(kbnServer.server); - config.set('uuid', testUuid); + config.set('server.uuid', testUuid); - await uuidManagement(); + await manageUuid(kbnServer.server); const newUuid = '5b2de169-2785-441b-ae8c-186a1936b17d'; const msg = `Updating Kibana instance UUID to: ${newUuid} (was: ${testUuid})`; - config.set('uuid', newUuid); - await uuidManagement(); + config.set('server.uuid', newUuid); + await manageUuid(kbnServer.server); expect(kbnServer.server.log.lastCall.args[1]).to.be(msg); }); it('resumes the uuid stored in data and sets it to the config', async function () { - const uuidManagement = manageUuid(kbnServer.server); const partialMsg = 'Resuming persistent Kibana instance UUID'; - config.set('uuid'); // set to undefined + config.set('server.uuid'); // set to undefined - await uuidManagement(); + await manageUuid(kbnServer.server); - expect(config.get('uuid')).to.be.ok(); // not undefined any more + expect(config.get('server.uuid')).to.be.ok(); // not undefined any more expect(kbnServer.server.log.lastCall.args[1]).to.match(new RegExp(`^${partialMsg}`)); }); - - }); }); diff --git a/src/core_plugins/kibana/server/lib/manage_uuid.js b/src/core_plugins/kibana/server/lib/manage_uuid.js new file mode 100644 index 0000000000000..b6c13550f92f5 --- /dev/null +++ b/src/core_plugins/kibana/server/lib/manage_uuid.js @@ -0,0 +1,72 @@ +import uuid from 'node-uuid'; +import Promise from 'bluebird'; +import { join as pathJoin } from 'path'; +import { readFile as readFileCallback, writeFile as writeFileCallback } from 'fs'; + +const FILE_ENCODING = 'utf8'; + +export default async function manageUuid(server) { + const config = server.config(); + const serverPort = server.info.port; + const serverHostname = config.get('server.host'); + const fileName = `${serverHostname}:${serverPort}`; + const uuidFile = pathJoin(config.get('path.data'), fileName); + + async function detectUuid() { + const readFile = Promise.promisify(readFileCallback); + try { + const result = await readFile(uuidFile); + return result.toString(FILE_ENCODING); + } catch (e) { + return false; + } + } + + async function writeUuid(uuid) { + const writeFile = Promise.promisify(writeFileCallback); + try { + return await writeFile(uuidFile, uuid, { encoding: FILE_ENCODING }); + } catch (e) { + return false; + } + } + + // detect if uuid exists already from before a restart + const logToServer = (msg) => server.log(['server', 'uuid', fileName], msg); + const dataFileUuid = await detectUuid(); + let serverConfigUuid = config.get('server.uuid'); // check if already set in config + + if (dataFileUuid) { + // data uuid found + if (serverConfigUuid === dataFileUuid) { + // config uuid exists, data uuid exists and matches + logToServer(`Kibana instance UUID: ${dataFileUuid}`); + return; + } + + if (!serverConfigUuid) { + // config uuid missing, data uuid exists + serverConfigUuid = dataFileUuid; + logToServer(`Resuming persistent Kibana instance UUID: ${serverConfigUuid}`); + config.set('server.uuid', serverConfigUuid); + return; + } + + if (serverConfigUuid !== dataFileUuid) { + // config uuid exists, data uuid exists but mismatches + logToServer(`Updating Kibana instance UUID to: ${serverConfigUuid} (was: ${dataFileUuid})`); + return writeUuid(serverConfigUuid); + } + } + + // data uuid missing + + if (!serverConfigUuid) { + // config uuid missing + serverConfigUuid = uuid.v4(); + config.set('server.uuid', serverConfigUuid); + } + + logToServer(`Setting new Kibana instance UUID: ${serverConfigUuid}`); + return writeUuid(serverConfigUuid); +} diff --git a/src/server/config/schema.js b/src/server/config/schema.js index 074ccec05b579..dbabdeae2d91e 100644 --- a/src/server/config/schema.js +++ b/src/server/config/schema.js @@ -30,9 +30,9 @@ module.exports = () => Joi.object({ exclusive: Joi.boolean().default(false) }).default(), - uuid: Joi.string().guid().default(), server: Joi.object({ + uuid: Joi.string().guid().default(), name: Joi.string().default(os.hostname()), host: Joi.string().hostname().default('localhost'), port: Joi.number().default(5601), diff --git a/src/server/status/index.js b/src/server/status/index.js index 597401df7e478..487621ba6a768 100644 --- a/src/server/status/index.js +++ b/src/server/status/index.js @@ -18,7 +18,7 @@ export default function (kbnServer, server, config) { handler: function (request, reply) { return reply({ name: config.get('server.name'), - uuid: config.get('uuid'), + uuid: config.get('server.uuid'), status: kbnServer.status.toJSON(), metrics: kbnServer.metrics });