Skip to content

Commit bd72953

Browse files
committed
[eventLog] prevent log writing when initialization fails
resolves #68309 Previously, if the initialization of the elasticsearch resources failed during initialization, the event logger would still try to write events. Which is somewhat of a catastrophic failure, as typically the logger would try writing to the alias name, but no alias exists, so a new index would be created with the name of the alias. Making it impossible to initialize successfully later until that index was deleted. The core initialization calls already returned success indicators, so this PR just responds to those and prevents the logger from writing to the index if intialization failed.
1 parent a906c73 commit bd72953

File tree

5 files changed

+57
-12
lines changed

5 files changed

+57
-12
lines changed

x-pack/plugins/event_log/server/es/context.mock.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const createContextMock = () => {
1717
logger: loggingSystemMock.createLogger(),
1818
esNames: namesMock.create(),
1919
initialize: jest.fn(),
20-
waitTillReady: jest.fn(),
20+
waitTillReady: jest.fn(async () => Promise.resolve(true)),
2121
esAdapter: clusterClientAdapterMock.create(),
2222
initialized: true,
2323
};

x-pack/plugins/event_log/server/es/context.test.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@
77
import { createEsContext } from './context';
88
import { LegacyClusterClient, Logger } from '../../../../../src/core/server';
99
import { elasticsearchServiceMock, loggingSystemMock } from '../../../../../src/core/server/mocks';
10-
jest.mock('../lib/../../../../package.json', () => ({
11-
version: '1.2.3',
12-
}));
10+
jest.mock('../lib/../../../../package.json', () => ({ version: '1.2.3' }));
11+
jest.mock('./init');
1312
type EsClusterClient = Pick<jest.Mocked<LegacyClusterClient>, 'callAsInternalUser' | 'asScoped'>;
1413

1514
let logger: Logger;
@@ -92,4 +91,16 @@ describe('createEsContext', () => {
9291
);
9392
expect(doesIndexTemplateExist).toBeTruthy();
9493
});
94+
95+
test('should handled failed initialization', async () => {
96+
jest.requireMock('./init').initializeEs.mockResolvedValue(false);
97+
const context = createEsContext({
98+
logger,
99+
clusterClientPromise: Promise.resolve(clusterClient),
100+
indexNameRoot: 'test2',
101+
});
102+
context.initialize();
103+
const success = await context.waitTillReady();
104+
expect(success).toBe(false);
105+
});
95106
});

x-pack/plugins/event_log/server/es/context.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,21 +64,23 @@ class EsContextImpl implements EsContext {
6464

6565
setImmediate(async () => {
6666
try {
67-
await this._initialize();
68-
this.logger.debug('readySignal.signal(true)');
69-
this.readySignal.signal(true);
67+
const success = await this._initialize();
68+
this.logger.debug(`readySignal.signal(${success})`);
69+
this.readySignal.signal(success);
7070
} catch (err) {
7171
this.logger.debug('readySignal.signal(false)');
7272
this.readySignal.signal(false);
7373
}
7474
});
7575
}
7676

77+
// waits till the ES initialization is done, returns true if it was successful,
78+
// false if it was not successful
7779
async waitTillReady(): Promise<boolean> {
7880
return await this.readySignal.wait();
7981
}
8082

81-
private async _initialize() {
82-
await initializeEs(this);
83+
private async _initialize(): Promise<boolean> {
84+
return await initializeEs(this);
8385
}
8486
}

x-pack/plugins/event_log/server/event_logger.test.ts

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,52 @@ import { delay } from './lib/delay';
1414
import { EVENT_LOGGED_PREFIX } from './event_logger';
1515

1616
const KIBANA_SERVER_UUID = '424-24-2424';
17+
const WRITE_LOG_WAIT_MILLIS = 3000;
1718

1819
describe('EventLogger', () => {
1920
let systemLogger: ReturnType<typeof loggingSystemMock.createLogger>;
20-
let esContext: EsContext;
21+
let esContext: jest.Mocked<EsContext>;
2122
let service: IEventLogService;
2223
let eventLogger: IEventLogger;
2324

2425
beforeEach(() => {
26+
jest.resetAllMocks();
2527
systemLogger = loggingSystemMock.createLogger();
2628
esContext = contextMock.create();
2729
service = new EventLogService({
2830
esContext,
2931
systemLogger,
30-
config: { enabled: true, logEntries: true, indexEntries: false },
32+
config: { enabled: true, logEntries: true, indexEntries: true },
3133
kibanaUUID: KIBANA_SERVER_UUID,
3234
});
3335
eventLogger = service.getLogger({});
3436
});
3537

38+
test('handles successful initialization', async () => {
39+
service.registerProviderActions('test-provider', ['test-action-1']);
40+
eventLogger = service.getLogger({
41+
event: { provider: 'test-provider', action: 'test-action-1' },
42+
});
43+
44+
eventLogger.logEvent({});
45+
await waitForLogEvent(systemLogger);
46+
delay(WRITE_LOG_WAIT_MILLIS); // sleep a bit since event logging is async
47+
expect(esContext.esAdapter.indexDocument).toHaveBeenCalled();
48+
});
49+
50+
test('handles failed initialization', async () => {
51+
service.registerProviderActions('test-provider', ['test-action-1']);
52+
eventLogger = service.getLogger({
53+
event: { provider: 'test-provider', action: 'test-action-1' },
54+
});
55+
esContext.waitTillReady.mockImplementation(async () => Promise.resolve(false));
56+
57+
eventLogger.logEvent({});
58+
await waitForLogEvent(systemLogger);
59+
delay(WRITE_LOG_WAIT_MILLIS); // sleep a bit longer since event logging is async
60+
expect(esContext.esAdapter.indexDocument).not.toHaveBeenCalled();
61+
});
62+
3663
test('method logEvent() writes expected default values', async () => {
3764
service.registerProviderActions('test-provider', ['test-action-1']);
3865
eventLogger = service.getLogger({

x-pack/plugins/event_log/server/event_logger.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,12 @@ function indexEventDoc(esContext: EsContext, doc: Doc): void {
183183
// whew, the thing that actually writes the event log document!
184184
async function indexLogEventDoc(esContext: EsContext, doc: unknown) {
185185
esContext.logger.debug(`writing to event log: ${JSON.stringify(doc)}`);
186-
await esContext.waitTillReady();
186+
const success = await esContext.waitTillReady();
187+
if (!success) {
188+
esContext.logger.debug(`event log did not initialize correctly, event not written`);
189+
return;
190+
}
191+
187192
await esContext.esAdapter.indexDocument(doc);
188193
esContext.logger.debug(`writing to event log complete`);
189194
}

0 commit comments

Comments
 (0)