Skip to content

Commit 9bdd23a

Browse files
authored
Do not write UUID file during optimize process (#58899)
1 parent b46a335 commit 9bdd23a

File tree

7 files changed

+278
-80
lines changed

7 files changed

+278
-80
lines changed

src/core/server/uuid/resolve_uuid.test.ts

Lines changed: 170 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
import { join } from 'path';
2121
import { readFile, writeFile } from './fs';
22-
import { resolveInstanceUuid } from './resolve_uuid';
22+
import { resolveInstanceUuid, UUID_7_6_0_BUG } from './resolve_uuid';
2323
import { configServiceMock } from '../config/config_service.mock';
2424
import { loggingServiceMock } from '../logging/logging_service.mock';
2525
import { BehaviorSubject } from 'rxjs';
@@ -97,58 +97,96 @@ describe('resolveInstanceUuid', () => {
9797
});
9898

9999
describe('when file is present and config property is set', () => {
100-
it('writes to file and returns the config uuid if they mismatch', async () => {
101-
const uuid = await resolveInstanceUuid(configService, logger);
102-
expect(uuid).toEqual(DEFAULT_CONFIG_UUID);
103-
expect(writeFile).toHaveBeenCalledWith(
104-
join('data-folder', 'uuid'),
105-
DEFAULT_CONFIG_UUID,
106-
expect.any(Object)
107-
);
108-
expect(logger.debug).toHaveBeenCalledTimes(1);
109-
expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(`
110-
Array [
111-
"Updating Kibana instance UUID to: CONFIG_UUID (was: FILE_UUID)",
112-
]
113-
`);
100+
describe('when they mismatch', () => {
101+
describe('when syncToFile is true', () => {
102+
it('writes to file and returns the config uuid', async () => {
103+
const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: true });
104+
expect(uuid).toEqual(DEFAULT_CONFIG_UUID);
105+
expect(writeFile).toHaveBeenCalledWith(
106+
join('data-folder', 'uuid'),
107+
DEFAULT_CONFIG_UUID,
108+
expect.any(Object)
109+
);
110+
expect(logger.debug).toHaveBeenCalledTimes(1);
111+
expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(`
112+
Array [
113+
"Updating Kibana instance UUID to: CONFIG_UUID (was: FILE_UUID)",
114+
]
115+
`);
116+
});
117+
});
118+
119+
describe('when syncTofile is false', () => {
120+
it('does not write to file and returns the config uuid', async () => {
121+
const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: false });
122+
expect(uuid).toEqual(DEFAULT_CONFIG_UUID);
123+
expect(writeFile).not.toHaveBeenCalled();
124+
expect(logger.debug).toHaveBeenCalledTimes(1);
125+
expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(`
126+
Array [
127+
"Updating Kibana instance UUID to: CONFIG_UUID (was: FILE_UUID)",
128+
]
129+
`);
130+
});
131+
});
114132
});
115-
it('does not write to file if they match', async () => {
116-
mockReadFile({ uuid: DEFAULT_CONFIG_UUID });
117-
const uuid = await resolveInstanceUuid(configService, logger);
118-
expect(uuid).toEqual(DEFAULT_CONFIG_UUID);
119-
expect(writeFile).not.toHaveBeenCalled();
120-
expect(logger.debug).toHaveBeenCalledTimes(1);
121-
expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(`
122-
Array [
123-
"Kibana instance UUID: CONFIG_UUID",
124-
]
125-
`);
133+
134+
describe('when they match', () => {
135+
it('does not write to file', async () => {
136+
mockReadFile({ uuid: DEFAULT_CONFIG_UUID });
137+
const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: true });
138+
expect(uuid).toEqual(DEFAULT_CONFIG_UUID);
139+
expect(writeFile).not.toHaveBeenCalled();
140+
expect(logger.debug).toHaveBeenCalledTimes(1);
141+
expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(`
142+
Array [
143+
"Kibana instance UUID: CONFIG_UUID",
144+
]
145+
`);
146+
});
126147
});
127148
});
128149

129150
describe('when file is not present and config property is set', () => {
130-
it('writes the uuid to file and returns the config uuid', async () => {
131-
mockReadFile({ error: fileNotFoundError });
132-
const uuid = await resolveInstanceUuid(configService, logger);
133-
expect(uuid).toEqual(DEFAULT_CONFIG_UUID);
134-
expect(writeFile).toHaveBeenCalledWith(
135-
join('data-folder', 'uuid'),
136-
DEFAULT_CONFIG_UUID,
137-
expect.any(Object)
138-
);
139-
expect(logger.debug).toHaveBeenCalledTimes(1);
140-
expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(`
141-
Array [
142-
"Setting new Kibana instance UUID: CONFIG_UUID",
143-
]
144-
`);
151+
describe('when syncToFile is true', () => {
152+
it('writes the uuid to file and returns the config uuid', async () => {
153+
mockReadFile({ error: fileNotFoundError });
154+
const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: true });
155+
expect(uuid).toEqual(DEFAULT_CONFIG_UUID);
156+
expect(writeFile).toHaveBeenCalledWith(
157+
join('data-folder', 'uuid'),
158+
DEFAULT_CONFIG_UUID,
159+
expect.any(Object)
160+
);
161+
expect(logger.debug).toHaveBeenCalledTimes(1);
162+
expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(`
163+
Array [
164+
"Setting new Kibana instance UUID: CONFIG_UUID",
165+
]
166+
`);
167+
});
168+
});
169+
170+
describe('when syncToFile is false', () => {
171+
it('does not write the uuid to file and returns the config uuid', async () => {
172+
mockReadFile({ error: fileNotFoundError });
173+
const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: false });
174+
expect(uuid).toEqual(DEFAULT_CONFIG_UUID);
175+
expect(writeFile).not.toHaveBeenCalled();
176+
expect(logger.debug).toHaveBeenCalledTimes(1);
177+
expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(`
178+
Array [
179+
"Setting new Kibana instance UUID: CONFIG_UUID",
180+
]
181+
`);
182+
});
145183
});
146184
});
147185

148186
describe('when file is present and config property is not set', () => {
149187
it('does not write to file and returns the file uuid', async () => {
150188
configService = getConfigService(undefined);
151-
const uuid = await resolveInstanceUuid(configService, logger);
189+
const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: true });
152190
expect(uuid).toEqual(DEFAULT_FILE_UUID);
153191
expect(writeFile).not.toHaveBeenCalled();
154192
expect(logger.debug).toHaveBeenCalledTimes(1);
@@ -160,39 +198,111 @@ describe('resolveInstanceUuid', () => {
160198
});
161199
});
162200

201+
describe('when file is present with 7.6.0 UUID', () => {
202+
describe('when config property is not set', () => {
203+
it('writes new uuid to file and returns new uuid', async () => {
204+
mockReadFile({ uuid: UUID_7_6_0_BUG });
205+
configService = getConfigService(undefined);
206+
const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: true });
207+
expect(uuid).not.toEqual(UUID_7_6_0_BUG);
208+
expect(uuid).toEqual('NEW_UUID');
209+
expect(writeFile).toHaveBeenCalledWith(
210+
join('data-folder', 'uuid'),
211+
'NEW_UUID',
212+
expect.any(Object)
213+
);
214+
expect(logger.debug).toHaveBeenCalledTimes(2);
215+
expect(logger.debug.mock.calls).toMatchInlineSnapshot(`
216+
Array [
217+
Array [
218+
"UUID from 7.6.0 bug detected, ignoring file UUID",
219+
],
220+
Array [
221+
"Setting new Kibana instance UUID: NEW_UUID",
222+
],
223+
]
224+
`);
225+
});
226+
});
227+
228+
describe('when config property is set', () => {
229+
it('writes config uuid to file and returns config uuid', async () => {
230+
mockReadFile({ uuid: UUID_7_6_0_BUG });
231+
configService = getConfigService(DEFAULT_CONFIG_UUID);
232+
const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: true });
233+
expect(uuid).not.toEqual(UUID_7_6_0_BUG);
234+
expect(uuid).toEqual(DEFAULT_CONFIG_UUID);
235+
expect(writeFile).toHaveBeenCalledWith(
236+
join('data-folder', 'uuid'),
237+
DEFAULT_CONFIG_UUID,
238+
expect.any(Object)
239+
);
240+
expect(logger.debug).toHaveBeenCalledTimes(2);
241+
expect(logger.debug.mock.calls).toMatchInlineSnapshot(`
242+
Array [
243+
Array [
244+
"UUID from 7.6.0 bug detected, ignoring file UUID",
245+
],
246+
Array [
247+
"Setting new Kibana instance UUID: CONFIG_UUID",
248+
],
249+
]
250+
`);
251+
});
252+
});
253+
});
254+
163255
describe('when file is not present and config property is not set', () => {
164-
it('generates a new uuid and write it to file', async () => {
165-
configService = getConfigService(undefined);
166-
mockReadFile({ error: fileNotFoundError });
167-
const uuid = await resolveInstanceUuid(configService, logger);
168-
expect(uuid).toEqual('NEW_UUID');
169-
expect(writeFile).toHaveBeenCalledWith(
170-
join('data-folder', 'uuid'),
171-
'NEW_UUID',
172-
expect.any(Object)
173-
);
174-
expect(logger.debug).toHaveBeenCalledTimes(1);
175-
expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(`
176-
Array [
177-
"Setting new Kibana instance UUID: NEW_UUID",
178-
]
179-
`);
256+
describe('when syncToFile is true', () => {
257+
it('generates a new uuid and write it to file', async () => {
258+
configService = getConfigService(undefined);
259+
mockReadFile({ error: fileNotFoundError });
260+
const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: true });
261+
expect(uuid).toEqual('NEW_UUID');
262+
expect(writeFile).toHaveBeenCalledWith(
263+
join('data-folder', 'uuid'),
264+
'NEW_UUID',
265+
expect.any(Object)
266+
);
267+
expect(logger.debug).toHaveBeenCalledTimes(1);
268+
expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(`
269+
Array [
270+
"Setting new Kibana instance UUID: NEW_UUID",
271+
]
272+
`);
273+
});
274+
});
275+
276+
describe('when syncToFile is false', () => {
277+
it('generates a new uuid and does not write it to file', async () => {
278+
configService = getConfigService(undefined);
279+
mockReadFile({ error: fileNotFoundError });
280+
const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: false });
281+
expect(uuid).toEqual('NEW_UUID');
282+
expect(writeFile).not.toHaveBeenCalled();
283+
expect(logger.debug).toHaveBeenCalledTimes(1);
284+
expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(`
285+
Array [
286+
"Setting new Kibana instance UUID: NEW_UUID",
287+
]
288+
`);
289+
});
180290
});
181291
});
182292

183293
describe('when file access error occurs', () => {
184294
it('throws an explicit error for file read errors', async () => {
185295
mockReadFile({ error: permissionError });
186296
await expect(
187-
resolveInstanceUuid(configService, logger)
297+
resolveInstanceUuid({ configService, logger, syncToFile: true })
188298
).rejects.toThrowErrorMatchingInlineSnapshot(
189299
`"Unable to read Kibana UUID file, please check the uuid.server configuration value in kibana.yml and ensure Kibana has sufficient permissions to read / write to this file. Error was: EACCES"`
190300
);
191301
});
192302
it('throws an explicit error for file write errors', async () => {
193303
mockWriteFile(isDirectoryError);
194304
await expect(
195-
resolveInstanceUuid(configService, logger)
305+
resolveInstanceUuid({ configService, logger, syncToFile: true })
196306
).rejects.toThrowErrorMatchingInlineSnapshot(
197307
`"Unable to write Kibana UUID file, please check the uuid.server configuration value in kibana.yml and ensure Kibana has sufficient permissions to read / write to this file. Error was: EISDIR"`
198308
);

src/core/server/uuid/resolve_uuid.ts

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,21 @@ import { Logger } from '../logging';
2828

2929
const FILE_ENCODING = 'utf8';
3030
const FILE_NAME = 'uuid';
31+
/**
32+
* This UUID was inadvertantly shipped in the 7.6.0 distributable and should be deleted if found.
33+
* See https://github.com/elastic/kibana/issues/57673 for more info.
34+
*/
35+
export const UUID_7_6_0_BUG = `ce42b997-a913-4d58-be46-bb1937feedd6`;
3136

32-
export async function resolveInstanceUuid(
33-
configService: IConfigService,
34-
logger: Logger
35-
): Promise<string> {
37+
export async function resolveInstanceUuid({
38+
configService,
39+
syncToFile,
40+
logger,
41+
}: {
42+
configService: IConfigService;
43+
syncToFile: boolean;
44+
logger: Logger;
45+
}): Promise<string> {
3646
const [pathConfig, serverConfig] = await Promise.all([
3747
configService
3848
.atPath<PathConfigType>(pathConfigDef.path)
@@ -46,7 +56,7 @@ export async function resolveInstanceUuid(
4656

4757
const uuidFilePath = join(pathConfig.data, FILE_NAME);
4858

49-
const uuidFromFile = await readUuidFromFile(uuidFilePath);
59+
const uuidFromFile = await readUuidFromFile(uuidFilePath, logger);
5060
const uuidFromConfig = serverConfig.uuid;
5161

5262
if (uuidFromConfig) {
@@ -61,26 +71,33 @@ export async function resolveInstanceUuid(
6171
} else {
6272
logger.debug(`Updating Kibana instance UUID to: ${uuidFromConfig} (was: ${uuidFromFile})`);
6373
}
64-
await writeUuidToFile(uuidFilePath, uuidFromConfig);
74+
await writeUuidToFile(uuidFilePath, uuidFromConfig, syncToFile);
6575
return uuidFromConfig;
6676
}
6777
}
6878
if (uuidFromFile === undefined) {
6979
const newUuid = uuid.v4();
7080
// no uuid either in config or file, we need to generate and write it.
7181
logger.debug(`Setting new Kibana instance UUID: ${newUuid}`);
72-
await writeUuidToFile(uuidFilePath, newUuid);
82+
await writeUuidToFile(uuidFilePath, newUuid, syncToFile);
7383
return newUuid;
7484
}
7585

7686
logger.debug(`Resuming persistent Kibana instance UUID: ${uuidFromFile}`);
7787
return uuidFromFile;
7888
}
7989

80-
async function readUuidFromFile(filepath: string): Promise<string | undefined> {
90+
async function readUuidFromFile(filepath: string, logger: Logger): Promise<string | undefined> {
8191
try {
8292
const content = await readFile(filepath);
83-
return content.toString(FILE_ENCODING);
93+
const decoded = content.toString(FILE_ENCODING);
94+
95+
if (decoded === UUID_7_6_0_BUG) {
96+
logger.debug(`UUID from 7.6.0 bug detected, ignoring file UUID`);
97+
return undefined;
98+
} else {
99+
return decoded;
100+
}
84101
} catch (e) {
85102
if (e.code === 'ENOENT') {
86103
// non-existent uuid file is ok, we will create it.
@@ -94,7 +111,11 @@ async function readUuidFromFile(filepath: string): Promise<string | undefined> {
94111
}
95112
}
96113

97-
async function writeUuidToFile(filepath: string, uuidValue: string) {
114+
async function writeUuidToFile(filepath: string, uuidValue: string, syncToFile: boolean) {
115+
if (!syncToFile) {
116+
return;
117+
}
118+
98119
try {
99120
return await writeFile(filepath, uuidValue, { encoding: FILE_ENCODING });
100121
} catch (e) {

0 commit comments

Comments
 (0)