diff --git a/src/cli/serve/__tests__/deprecated_config.js b/src/cli/serve/__tests__/deprecated_config.js index 1e55e5e62da6b..c132e814dcd12 100644 --- a/src/cli/serve/__tests__/deprecated_config.js +++ b/src/cli/serve/__tests__/deprecated_config.js @@ -1,81 +1,48 @@ import expect from 'expect.js'; -import { rewriteDeprecatedConfig } from '../deprecated_config'; +import { set } from 'lodash'; +import { checkForDeprecatedConfig } from '../deprecated_config'; import sinon from 'auto-release-sinon'; describe('cli/serve/deprecated_config', function () { - it('returns a clone of the input', function () { - const file = {}; - const output = rewriteDeprecatedConfig(file); - expect(output).to.not.be(file); + it('passes original config through', function () { + const config = {}; + set(config, 'server.xsrf.token', 'xxtokenxx'); + const output = checkForDeprecatedConfig(config); + expect(output).to.be(config); + expect(output.server).to.be(config.server); + expect(output.server.xsrf).to.be(config.server.xsrf); + expect(output.server.xsrf.token).to.be(config.server.xsrf.token); }); - describe('legacy config values', function () { - it('rewrites legacy config values with literal path replacement', function () { - const file = { port: 4000, host: 'kibana.com' }; - const output = rewriteDeprecatedConfig(file); - expect(output).to.not.be(file); - expect(output).to.eql({ - 'server.port': 4000, - 'server.host': 'kibana.com', - }); - }); - - it('logs warnings when legacy config properties are encountered', function () { - const log = sinon.stub(); - rewriteDeprecatedConfig({ port: 5555 }, log); - sinon.assert.calledOnce(log); - expect(log.firstCall.args[0]).to.match(/port.+deprecated.+server\.port/); - }); + it('logs warnings about deprecated config values', function () { + const log = sinon.stub(); + const config = {}; + set(config, 'server.xsrf.token', 'xxtokenxx'); + checkForDeprecatedConfig(config, log); + sinon.assert.calledOnce(log); + expect(log.firstCall.args[0]).to.match(/server\.xsrf\.token.+deprecated/); }); - describe('deprecated config values', function () { - it('logs warnings about deprecated config values', function () { + describe('does not support compound.keys', function () { + it('ignores fully compound keys', function () { const log = sinon.stub(); - rewriteDeprecatedConfig({ 'server.xsrf.token': 'xxtokenxx' }, log); - sinon.assert.calledOnce(log); - expect(log.firstCall.args[0]).to.match(/server\.xsrf\.token.+deprecated/); + const config = { 'server.xsrf.token': 'xxtokenxx' }; + checkForDeprecatedConfig(config, log); + sinon.assert.notCalled(log); }); - it('passes deprecated values through', function () { - const prop = 'server.xsrf.token'; - const file = { [prop]: 'xxtokenxx' }; - const output = rewriteDeprecatedConfig(file); - expect(output).to.not.be(file); - expect(output).to.have.property(prop, file[prop]); + it('ignores partially compound keys', function () { + const log = sinon.stub(); + const config = { server: { 'xsrf.token': 'xxtokenxx' } }; + checkForDeprecatedConfig(config, log); + sinon.assert.notCalled(log); }); - context('defined in a mixture of path keys and objects', function () { - it('detects nested propertie', function () { - const log = sinon.stub(); - rewriteDeprecatedConfig({ - server: { - xsrf: { - token: 'x' - } - } - }, log); - sinon.assert.calledOnce(log); - }); - - it('detects compound properties inside an object', function () { - const log = sinon.stub(); - rewriteDeprecatedConfig({ - server: { - 'xsrf.token': 'x' - } - }, log); - sinon.assert.calledOnce(log); - }); - - it('detects a property under a compound property', function () { - const log = sinon.stub(); - rewriteDeprecatedConfig({ - 'server.xsrf': { - token: 'x' - } - }, log); - sinon.assert.calledOnce(log); - }); + it('ignores partially compound keys', function () { + const log = sinon.stub(); + const config = { 'server.xsrf': { token: 'xxtokenxx' } }; + checkForDeprecatedConfig(config, log); + sinon.assert.notCalled(log); }); }); }); diff --git a/src/cli/serve/__tests__/legacy_config.js b/src/cli/serve/__tests__/legacy_config.js new file mode 100644 index 0000000000000..a380ae9e485c9 --- /dev/null +++ b/src/cli/serve/__tests__/legacy_config.js @@ -0,0 +1,28 @@ +import expect from 'expect.js'; +import { rewriteLegacyConfig } from '../legacy_config'; +import sinon from 'auto-release-sinon'; + +describe('cli/serve/legacy_config', function () { + it('returns a clone of the input', function () { + const file = {}; + const output = rewriteLegacyConfig(file); + expect(output).to.not.be(file); + }); + + it('rewrites legacy config values with literal path replacement', function () { + const file = { port: 4000, host: 'kibana.com' }; + const output = rewriteLegacyConfig(file); + expect(output).to.not.be(file); + expect(output).to.eql({ + 'server.port': 4000, + 'server.host': 'kibana.com', + }); + }); + + it('logs warnings when legacy config properties are encountered', function () { + const log = sinon.stub(); + rewriteLegacyConfig({ port: 5555 }, log); + sinon.assert.calledOnce(log); + expect(log.firstCall.args[0]).to.match(/port.+deprecated.+server\.port/); + }); +}); diff --git a/src/cli/serve/deprecated_config.js b/src/cli/serve/deprecated_config.js index b657ca93ac6ce..d0ec271a8cee8 100644 --- a/src/cli/serve/deprecated_config.js +++ b/src/cli/serve/deprecated_config.js @@ -1,65 +1,16 @@ -import { forOwn, has, noop, transform } from 'lodash'; - -const legacySettings = { - // server - port: 'server.port', - host: 'server.host', - pid_file: 'pid.file', - ssl_cert_file: 'server.ssl.cert', - ssl_key_file: 'server.ssl.key', - - // logging - log_file: 'logging.dest', - - // kibana - kibana_index: 'kibana.index', - default_app_id: 'kibana.defaultAppId', - - // es - ca: 'elasticsearch.ssl.ca', - elasticsearch_preserve_host: 'elasticsearch.preserveHost', - elasticsearch_url: 'elasticsearch.url', - kibana_elasticsearch_client_crt: 'elasticsearch.ssl.cert', - kibana_elasticsearch_client_key: 'elasticsearch.ssl.key', - kibana_elasticsearch_password: 'elasticsearch.password', - kibana_elasticsearch_username: 'elasticsearch.username', - ping_timeout: 'elasticsearch.pingTimeout', - request_timeout: 'elasticsearch.requestTimeout', - shard_timeout: 'elasticsearch.shardTimeout', - startup_timeout: 'elasticsearch.startupTimeout', - verify_ssl: 'elasticsearch.ssl.verify', -}; - -const deprecatedSettings = { - 'server.xsrf.token': 'server.xsrf.token is deprecated. It is no longer used when providing xsrf protection.' -}; - -// transform legacy options into new namespaced versions -export function rewriteDeprecatedConfig(object, log = noop) { - const rewritten = transform(object, (clone, val, key) => { - if (legacySettings.hasOwnProperty(key)) { - const replacement = legacySettings[key]; - log(`Config key "${key}" is deprecated. It has been replaced with "${replacement}"`); - clone[replacement] = val; - } else { - clone[key] = val; - } - }, {}); - - // walk through the object to find all nested keys, - // join them with simple string concatenation so that - // compound keys don't get considered a single path segment - (function recurse(obj, parent = []) { - forOwn(obj, (val, leaf) => { - const path = parent.concat(leaf); - const key = path.join('.'); - if (deprecatedSettings.hasOwnProperty(key)) { - log(deprecatedSettings[key]); - } else if (typeof val === 'object') { - recurse(val, path); - } - }); - }(rewritten)); - - return rewritten; +import { forOwn, has, noop } from 'lodash'; + +// deprecated settings are still allowed, but will be removed at a later time. They +// are checked for after the config object is prepared and known, so legacySettings +// will have already been transformed. +export const deprecatedSettings = new Map([ + [['server', 'xsrf', 'token'], 'server.xsrf.token is deprecated. It is no longer used when providing xsrf protection.'] +]); + +// check for and warn about deprecated settings +export function checkForDeprecatedConfig(object, log = noop) { + for (const [key, msg] of deprecatedSettings.entries()) { + if (has(object, key)) log(msg); + } + return object; } diff --git a/src/cli/serve/legacy_config.js b/src/cli/serve/legacy_config.js new file mode 100644 index 0000000000000..75fbb4e407eac --- /dev/null +++ b/src/cli/serve/legacy_config.js @@ -0,0 +1,47 @@ +import { noop, transform } from 'lodash'; + +// legacySettings allow kibana 4.2+ to accept the same config file that people +// used for kibana 4.0 and 4.1. These settings are transformed to their modern +// equivalents at the very begining of the process +export const legacySettings = { + // server + port: 'server.port', + host: 'server.host', + pid_file: 'pid.file', + ssl_cert_file: 'server.ssl.cert', + ssl_key_file: 'server.ssl.key', + + // logging + log_file: 'logging.dest', + + // kibana + kibana_index: 'kibana.index', + default_app_id: 'kibana.defaultAppId', + + // es + ca: 'elasticsearch.ssl.ca', + elasticsearch_preserve_host: 'elasticsearch.preserveHost', + elasticsearch_url: 'elasticsearch.url', + kibana_elasticsearch_client_crt: 'elasticsearch.ssl.cert', + kibana_elasticsearch_client_key: 'elasticsearch.ssl.key', + kibana_elasticsearch_password: 'elasticsearch.password', + kibana_elasticsearch_username: 'elasticsearch.username', + ping_timeout: 'elasticsearch.pingTimeout', + request_timeout: 'elasticsearch.requestTimeout', + shard_timeout: 'elasticsearch.shardTimeout', + startup_timeout: 'elasticsearch.startupTimeout', + verify_ssl: 'elasticsearch.ssl.verify', +}; + +// transform legacy options into new namespaced versions +export function rewriteLegacyConfig(object, log = noop) { + return transform(object, (clone, val, key) => { + if (legacySettings.hasOwnProperty(key)) { + const replacement = legacySettings[key]; + log(`Config key "${key}" is deprecated. It has been replaced with "${replacement}"`); + clone[replacement] = val; + } else { + clone[key] = val; + } + }, {}); +} diff --git a/src/cli/serve/read_yaml_config.js b/src/cli/serve/read_yaml_config.js index e7733417162fb..18e3a4520e875 100644 --- a/src/cli/serve/read_yaml_config.js +++ b/src/cli/serve/read_yaml_config.js @@ -4,7 +4,8 @@ import { safeLoad } from 'js-yaml'; import { red } from 'ansicolors'; import { fromRoot } from '../../utils'; -import { rewriteDeprecatedConfig } from './deprecated_config'; +import { rewriteLegacyConfig } from './legacy_config'; +import { checkForDeprecatedConfig } from './deprecated_config'; const log = memoize(function (message) { console.log(red('WARNING:'), message); @@ -32,9 +33,8 @@ export function merge(sources) { } export default function (paths) { - const files = [].concat(paths || []) - .map(path => safeLoad(read(path, 'utf8'))) - .map(file => rewriteDeprecatedConfig(file, log)); - - return merge(files); + const files = [].concat(paths || []); + const yamls = files.map(path => safeLoad(read(path, 'utf8'))); + const config = merge(yamls.map(file => rewriteLegacyConfig(file, log))); + return checkForDeprecatedConfig(config, log); }