diff --git a/x-pack/plugins/security_solution_serverless/server/task_manager/task_state.ts b/x-pack/plugins/security_solution_serverless/server/task_manager/task_state.ts new file mode 100644 index 0000000000000..dca03e31c5593 --- /dev/null +++ b/x-pack/plugins/security_solution_serverless/server/task_manager/task_state.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema, type TypeOf } from '@kbn/config-schema'; + +/** + * WARNING: Do not modify the existing versioned schema(s) below, instead define a new version (ex: 2, 3, 4). + * This is required to support zero-downtime upgrades and rollbacks. See https://github.com/elastic/kibana/issues/155764. + * + * As you add a new schema version, don't forget to change latestTaskStateSchema variable to reference the latest schema. + * For example, changing stateSchemaByVersion[1].schema to stateSchemaByVersion[2].schema. + */ +export const stateSchemaByVersion = { + 1: { + // A task that was created < 8.10 will go through this "up" migration + // to ensure it matches the v1 schema. + up: (state: Record) => ({ + lastSuccessfulReport: state.lastSuccessfulReport || null, + }), + schema: schema.object({ + lastSuccessfulReport: schema.nullable(schema.string()), + }), + }, +}; + +const latestTaskStateSchema = stateSchemaByVersion[1].schema; +export type LatestTaskStateSchema = TypeOf; + +export const emptyState: LatestTaskStateSchema = { + lastSuccessfulReport: null, +}; diff --git a/x-pack/plugins/security_solution_serverless/server/task_manager/usage_reporting_task.ts b/x-pack/plugins/security_solution_serverless/server/task_manager/usage_reporting_task.ts index a292d7646791d..2fa2f50f4b9d9 100644 --- a/x-pack/plugins/security_solution_serverless/server/task_manager/usage_reporting_task.ts +++ b/x-pack/plugins/security_solution_serverless/server/task_manager/usage_reporting_task.ts @@ -10,6 +10,7 @@ import type { CoreSetup, Logger } from '@kbn/core/server'; import type { ConcreteTaskInstance } from '@kbn/task-manager-plugin/server'; import type { CloudSetup } from '@kbn/cloud-plugin/server'; import { throwUnrecoverableError } from '@kbn/task-manager-plugin/server'; + import { usageReportingService } from '../common/services'; import type { MeteringCallback, @@ -19,6 +20,8 @@ import type { } from '../types'; import type { ServerlessSecurityConfig } from '../config'; +import { stateSchemaByVersion, emptyState } from './task_state'; + const SCOPE = ['serverlessSecurity']; const TIMEOUT = '1m'; @@ -58,6 +61,7 @@ export class SecurityUsageReportingTask { [taskType]: { title: taskTitle, timeout: TIMEOUT, + stateSchemaByVersion, createTaskRunner: ({ taskInstance }: { taskInstance: ConcreteTaskInstance }) => { return { run: async () => { @@ -94,9 +98,7 @@ export class SecurityUsageReportingTask { schedule: { interval, }, - state: { - lastSuccessfulReport: null, - }, + state: emptyState, params: { version: this.version }, }); } catch (e) {