From 5638da9c7ddbd3e952cfa65baf24f947a3613c4e Mon Sep 17 00:00:00 2001 From: Pete Hampton Date: Wed, 9 Dec 2020 11:57:52 +0000 Subject: [PATCH] record last run. --- .../server/lib/telemetry/sender.ts | 8 ++-- .../server/lib/telemetry/task.test.ts | 45 +++++++++++++++++++ .../server/lib/telemetry/task.ts | 32 +++++++++++-- 3 files changed, 78 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts b/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts index 5f43d05858e0d..42f00536464a3 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts @@ -101,7 +101,7 @@ export class TelemetryEventsSender { } } - public async fetchDiagnosticAlerts() { + public async fetchDiagnosticAlerts(executeFrom: string, executeTo: string) { const query = { expand_wildcards: 'open,hidden', index: 'logs-endpoint.diagnostic.collection-default*', @@ -111,15 +111,15 @@ export class TelemetryEventsSender { query: { range: { 'event.ingested': { - gte: 'now-5m', - lt: 'now', + gte: executeFrom, + lt: executeTo, }, }, }, sort: [ { 'event.ingested': { - order: 'asc', + order: 'desc', }, }, ], diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/task.test.ts b/x-pack/plugins/security_solution/server/lib/telemetry/task.test.ts index e499f15af2b3c..4411ad1538c7d 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/task.test.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/task.test.ts @@ -3,6 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import { moment } from 'moment'; import { loggingSystemMock } from 'src/core/server/mocks'; import { taskManagerMock } from '../../../../task_manager/server/mocks'; @@ -101,4 +102,48 @@ describe('test', () => { await taskRunner.run(); expect(mockSender.fetchDiagnosticAlerts).not.toHaveBeenCalled(); }); + + test('test -5 mins is returned when there is no previous task run', async () => { + const telemetryDiagTask = new TelemetryDiagTask( + logger, + taskManagerMock.createSetup(), + createMockTelemetryEventsSender(true) + ); + + const executeTo = moment().utc().toISOString(); + const executeFrom = undefined; + const newExecuteFrom = telemetryDiagTask.getLastExecutionTimestamp(executeTo, executeFrom); + + expect(newExecuteFrom).toEqual(moment(executeTo).subtract(5, 'minutes')); + }); + + test('test -6 mins is returned when there was a previous task run', async () => { + const telemetryDiagTask = new TelemetryDiagTask( + logger, + taskManagerMock.createSetup(), + createMockTelemetryEventsSender(true) + ); + + const executeTo = moment().utc().toISOString(); + const executeFrom = moment(executeTo).subtract(6, 'minutes'); + const newExecuteFrom = telemetryDiagTask.getLastExecutionTimestamp(executeTo, executeFrom); + + expect(newExecuteFrom).toEqual(executeFrom); + }); + + // it's possible if Kibana is down for a prolonged period the stored lastRun would have drifted + // if that is the case we will just roll it back to a 10 min search window + test('test 10 mins is returned when previous task run took longer than 10 minutes', async () => { + const telemetryDiagTask = new TelemetryDiagTask( + logger, + taskManagerMock.createSetup(), + createMockTelemetryEventsSender(true) + ); + + const executeTo = moment().utc().toISOString(); + const executeFrom = moment(executeTo).subtract(142, 'minutes'); + const newExecuteFrom = telemetryDiagTask.getLastExecutionTimestamp(executeTo, executeFrom); + + expect(newExecuteFrom).toEqual(moment(executeTo).subtract(10, 'minutes')); + }); }); diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/task.ts b/x-pack/plugins/security_solution/server/lib/telemetry/task.ts index 6b79c3d792ba9..37fdaebf61c77 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/task.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/task.ts @@ -3,6 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import moment from 'moment'; import { Logger } from 'src/core/server'; import { ConcreteTaskInstance, @@ -37,7 +38,18 @@ export class TelemetryDiagTask { createTaskRunner: ({ taskInstance }: { taskInstance: ConcreteTaskInstance }) => { return { run: async () => { - await this.runTask(taskInstance.id); + const executeTo = moment().utc().toISOString(); + const executeFrom = this.getLastExecutionTimestamp( + executeTo, + taskInstance.state?.lastExecutionTimestamp + ); + await this.runTask(taskInstance.id, executeFrom, executeTo); + + return { + state: { + lastExecutionTimestamp: executeTo, + }, + }; }, cancel: async () => {}, }; @@ -46,6 +58,20 @@ export class TelemetryDiagTask { }); } + public getLastExecutionTimestamp(executeTo: string, lastExecutionTimestamp?: string) { + if (lastExecutionTimestamp === undefined) { + this.logger.debug(`No last execution timestamp defined`); + return moment(executeTo).subtract(5, 'minutes').toISOString(); + } + + if (moment(lastExecutionTimestamp).diff(executeTo) >= 10) { + this.logger.debug(`last execution timestamp was greater than 10 minutes`); + return moment(executeTo).subtract(10, 'minutes').toISOString(); + } + + return lastExecutionTimestamp; + } + public start = async (taskManager: TaskManagerStartContract) => { try { await taskManager.ensureScheduled({ @@ -67,7 +93,7 @@ export class TelemetryDiagTask { return `${TelemetryDiagTaskConstants.TYPE}:${TelemetryDiagTaskConstants.VERSION}`; }; - public runTask = async (taskId: string) => { + public runTask = async (taskId: string, searchFrom: string, searchTo: string) => { this.logger.debug(`Running task ${taskId}`); if (taskId !== this.getTaskId()) { this.logger.debug(`Outdated task running: ${taskId}`); @@ -80,7 +106,7 @@ export class TelemetryDiagTask { return; } - const response = await this.sender.fetchDiagnosticAlerts(); + const response = await this.sender.fetchDiagnosticAlerts(searchFrom, searchTo); const hits = response.hits?.hits || []; if (!Array.isArray(hits) || !hits.length) {