From 3b4b34148b3610569155810722f4266ae561ea51 Mon Sep 17 00:00:00 2001 From: Brad White Date: Tue, 28 Nov 2023 17:16:47 -0700 Subject: [PATCH] fix/142865/path.data config unused (#158426) (cherry picked from commit 86d2f58c09b3bfedd12576f9fc5fe68649028f9c) --- docs/setup/settings.asciidoc | 5 +- packages/kbn-utils/src/path/index.test.ts | 98 ++++++++++++++++++++++- packages/kbn-utils/src/path/index.ts | 40 ++++++--- packages/kbn-utils/tsconfig.json | 1 + 4 files changed, 131 insertions(+), 13 deletions(-) diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc index 13e3fad93cfca..37bb26ae53a38 100644 --- a/docs/setup/settings.asciidoc +++ b/docs/setup/settings.asciidoc @@ -326,8 +326,9 @@ or `*` to select all roles. *Default: `*`* Choose the default email connector for user notifications. As of `8.6.0`, {kib} is shipping with a new notification mechanism that will send email notifications for various user actions, e.g. assigning a _Case_ to a user. To enable notifications, an email connector must be <> in the system via `kibana.yml`, and the notifications plugin must be configured to point to the ID of that connector. [[path-data]] `path.data`:: -The path where {kib} stores persistent data -not saved in {es}. *Default: `data`* +The path where {kib} stores persistent data not saved in {es}. +Can be a relative or absolute path. +Relative paths are resolved starting from the installation directory. *Default: `data`* `pid.file`:: Specifies the path where {kib} creates the process ID file. diff --git a/packages/kbn-utils/src/path/index.test.ts b/packages/kbn-utils/src/path/index.test.ts index 608f3cb2cfeb2..163dfbef598dc 100644 --- a/packages/kbn-utils/src/path/index.test.ts +++ b/packages/kbn-utils/src/path/index.test.ts @@ -6,8 +6,10 @@ * Side Public License, v 1. */ +import { join } from 'path'; import { accessSync, constants } from 'fs'; -import { getConfigPath, getDataPath, getLogsPath, getConfigDirectory } from '.'; +import { rm, mkdtemp, writeFile } from 'fs/promises'; +import { getConfigPath, getDataPath, getLogsPath, getConfigDirectory, buildDataPaths } from '.'; import { REPO_ROOT } from '@kbn/repo-info'; expect.addSnapshotSerializer( @@ -46,3 +48,97 @@ describe('Default path finder', () => { expect(() => accessSync(configPath, constants.R_OK)).not.toThrow(); }); }); + +describe('Custom data path finder', () => { + const originalArgv = process.argv; + + beforeEach(() => { + process.argv = originalArgv; + }); + + it('ignores the path.data flag when no value is provided', () => { + process.argv = ['--foo', 'bar', '--path.data', '--baz', 'xyz']; + + expect(buildDataPaths()).toMatchInlineSnapshot(` + Array [ + /data, + "/var/lib/kibana", + ] + `); + }); + + describe('overrides path.data when provided as command line argument', () => { + it('with absolute path', () => { + process.argv = ['--foo', 'bar', '--path.data', '/some/data/path', '--baz', 'xyz']; + + /* + * Test buildDataPaths since getDataPath returns the first valid directory and + * custom paths do not exist in environment. Custom directories are built during env init. + */ + expect(buildDataPaths()).toMatchInlineSnapshot(` + Array [ + "/some/data/path", + /data, + "/var/lib/kibana", + ] + `); + }); + + it('with relative path', () => { + process.argv = ['--foo', 'bar', '--path.data', 'data2', '--baz', 'xyz']; + + /* + * Test buildDataPaths since getDataPath returns the first valid directory and + * custom paths do not exist in environment. Custom directories are built during env init. + */ + expect(buildDataPaths()).toMatchInlineSnapshot(` + Array [ + /data2, + /data, + "/var/lib/kibana", + ] + `); + }); + }); + + describe('overrides path.data when provided by kibana.yml', () => { + let tempDir: string; + let tempConfigFile: string; + + beforeAll(async () => { + tempDir = await mkdtemp('config-test'); + tempConfigFile = join(tempDir, 'kibana.yml'); + }); + + afterAll(async () => { + await rm(tempDir, { recursive: true }); + delete process.env.KBN_PATH_CONF; + }); + + it('with absolute path', async () => { + process.env.KBN_PATH_CONF = tempDir; + await writeFile(tempConfigFile, `path.data: /path/from/yml`); + + expect(buildDataPaths()).toMatchInlineSnapshot(` + Array [ + "/path/from/yml", + /data, + "/var/lib/kibana", + ] + `); + }); + + it('with relative path', async () => { + process.env.KBN_PATH_CONF = tempDir; + await writeFile(tempConfigFile, `path.data: data2`); + + expect(buildDataPaths()).toMatchInlineSnapshot(` + Array [ + /data2, + /data, + "/var/lib/kibana", + ] + `); + }); + }); +}); diff --git a/packages/kbn-utils/src/path/index.ts b/packages/kbn-utils/src/path/index.ts index 63ca454dd04fd..caeaa9a493f17 100644 --- a/packages/kbn-utils/src/path/index.ts +++ b/packages/kbn-utils/src/path/index.ts @@ -6,18 +6,22 @@ * Side Public License, v 1. */ -import { join } from 'path'; +import { join, resolve } from 'path'; import { accessSync, constants } from 'fs'; import { TypeOf, schema } from '@kbn/config-schema'; import { REPO_ROOT } from '@kbn/repo-info'; +import { getConfigFromFiles } from '@kbn/config'; +import getopts from 'getopts'; const isString = (v: any): v is string => typeof v === 'string'; -const CONFIG_PATHS = [ - process.env.KBN_PATH_CONF && join(process.env.KBN_PATH_CONF, 'kibana.yml'), - join(REPO_ROOT, 'config/kibana.yml'), - '/etc/kibana/kibana.yml', -].filter(isString); +const buildConfigPaths = () => { + return [ + process.env.KBN_PATH_CONF && resolve(process.env.KBN_PATH_CONF, 'kibana.yml'), + join(REPO_ROOT, 'config/kibana.yml'), + '/etc/kibana/kibana.yml', + ].filter(isString); +}; const CONFIG_DIRECTORIES = [ process.env.KBN_PATH_CONF, @@ -25,8 +29,6 @@ const CONFIG_DIRECTORIES = [ '/etc/kibana', ].filter(isString); -const DATA_PATHS = [join(REPO_ROOT, 'data'), '/var/lib/kibana'].filter(isString); - const LOGS_PATHS = [join(REPO_ROOT, 'logs'), '/var/log/kibana'].filter(isString); function findFile(paths: string[]) { @@ -41,11 +43,29 @@ function findFile(paths: string[]) { return availablePath || paths[0]; } +export const buildDataPaths = (): string[] => { + const configDataPath = getConfigFromFiles([getConfigPath()]).path?.data; + const argv = process.argv.slice(2); + const options = getopts(argv, { + string: ['pathData'], + alias: { + pathData: 'path.data', + }, + }); + + return [ + !!options.pathData && resolve(REPO_ROOT, options.pathData), + configDataPath && resolve(REPO_ROOT, configDataPath), + join(REPO_ROOT, 'data'), + '/var/lib/kibana', + ].filter(isString); +}; + /** * Get the path of kibana.yml * @internal */ -export const getConfigPath = () => findFile(CONFIG_PATHS); +export const getConfigPath = () => findFile(buildConfigPaths()); /** * Get the directory containing configuration files @@ -57,7 +77,7 @@ export const getConfigDirectory = () => findFile(CONFIG_DIRECTORIES); * Get the directory containing runtime data * @internal */ -export const getDataPath = () => findFile(DATA_PATHS); +export const getDataPath = () => findFile(buildDataPaths()); /** * Get the directory containing logs diff --git a/packages/kbn-utils/tsconfig.json b/packages/kbn-utils/tsconfig.json index 6baa222ef8c37..f6e7fb408bfa2 100644 --- a/packages/kbn-utils/tsconfig.json +++ b/packages/kbn-utils/tsconfig.json @@ -13,6 +13,7 @@ "kbn_references": [ "@kbn/config-schema", "@kbn/repo-info", + "@kbn/config", ], "exclude": [ "target/**/*",