[Response Ops][Reporting][Task Manager] Allow setting dtstart in rrule schedule - schema changes only for intermediate release (#224979)

## Summary

This PR contains the schema changes needed to support using `dtstart` in
task manager rrule schedules. This is meant for intermediate release and
then the changes will be used in this PR:
https://github.com/elastic/kibana/pull/224948

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
Ying Mao 2025-06-27 10:05:28 -04:00 committed by GitHub
parent 3ef270c167
commit f43138c059
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 124 additions and 21 deletions

View file

@ -182,7 +182,7 @@ describe('checking migration metadata changes on all registered SO types', () =>
"synthetics-private-location": "27aaa44f792f70b734905e44e3e9b56bbeac7b86",
"synthetics-privates-locations": "36036b881524108c7327fe14bd224c6e4d972cb5",
"tag": "87f21f07df9cc37001b15a26e413c18f50d1fbfe",
"task": "4bd8e19960b83c88f3cdf766ace268c081a1c619",
"task": "689edead32ea09558ceb54f64fd9aa4d324d94d0",
"telemetry": "3b3b89cf411a2a2e60487cef6ccdbc5df691aeb9",
"threshold-explorer-view": "5e2388a6835cec3c68c98b450cd267d66cce925f",
"ui-metric": "410a8ad28e0f44b161c960ff0ce950c712b17c52",

View file

@ -9,7 +9,7 @@ import moment from 'moment';
import { schema } from '@kbn/config-schema';
import { isEmpty, omit } from 'lodash';
import { RruleSchedule, scheduleRruleSchema } from '@kbn/task-manager-plugin/server';
import { RruleSchedule, scheduleRruleSchemaV1 } from '@kbn/task-manager-plugin/server';
import { SavedObjectsUtils } from '@kbn/core/server';
import { IKibanaResponse } from '@kbn/core/server';
import { RawNotification } from '../../../saved_objects/scheduled_report/schemas/latest';
@ -34,7 +34,7 @@ const MAX_ALLOWED_EMAILS = 30;
const validation = {
params: schema.object({ exportType: schema.string({ minLength: 2 }) }),
body: schema.object({
schedule: scheduleRruleSchema,
schedule: scheduleRruleSchemaV1,
notification: schema.maybe(rawNotificationSchema),
jobParams: schema.string(),
}),

View file

@ -6,7 +6,7 @@
*/
import type { SavedObjectsModelVersionMap } from '@kbn/core-saved-objects-server';
import { rawScheduledReportSchemaV1 } from './schemas';
import { rawScheduledReportSchemaV1, rawScheduledReportSchemaV2 } from './schemas';
export const scheduledReportModelVersions: SavedObjectsModelVersionMap = {
'1': {
@ -16,4 +16,11 @@ export const scheduledReportModelVersions: SavedObjectsModelVersionMap = {
create: rawScheduledReportSchemaV1,
},
},
'2': {
changes: [],
schemas: {
forwardCompatibility: rawScheduledReportSchemaV2.extends({}, { unknowns: 'ignore' }),
create: rawScheduledReportSchemaV2,
},
},
};

View file

@ -6,3 +6,4 @@
*/
export { rawScheduledReportSchema as rawScheduledReportSchemaV1 } from './v1';
export { rawScheduledReportSchema as rawScheduledReportSchemaV2 } from './v2';

View file

@ -6,7 +6,7 @@
*/
import type { TypeOf } from '@kbn/config-schema';
import type { rawNotificationSchema, rawScheduledReportSchema } from './v1';
import type { rawNotificationSchema, rawScheduledReportSchema } from './v2';
export type RawNotification = TypeOf<typeof rawNotificationSchema>;
export type RawScheduledReport = TypeOf<typeof rawScheduledReportSchema>;

View file

@ -6,7 +6,7 @@
*/
import { schema } from '@kbn/config-schema';
import { scheduleRruleSchema } from '@kbn/task-manager-plugin/server';
import { scheduleRruleSchemaV1 } from '@kbn/task-manager-plugin/server';
const rawLayoutIdSchema = schema.oneOf([
schema.literal('preserve_layout'),
@ -52,6 +52,6 @@ export const rawScheduledReportSchema = schema.object({
migrationVersion: schema.maybe(schema.string()),
notification: schema.maybe(rawNotificationSchema),
payload: schema.string(),
schedule: scheduleRruleSchema,
schedule: scheduleRruleSchemaV1,
title: schema.string(),
});

View file

@ -0,0 +1,14 @@
/*
* 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 { scheduleRruleSchemaV2 } from '@kbn/task-manager-plugin/server';
import { rawScheduledReportSchema as rawScheduledReportSchemaV1 } from './v1';
export * from './v1';
export const rawScheduledReportSchema = rawScheduledReportSchemaV1.extends({
schedule: scheduleRruleSchemaV2,
});

View file

@ -24,7 +24,7 @@ export type {
} from './task';
export { Frequency, Weekday } from '@kbn/rrule';
export { scheduleRruleSchema } from './saved_objects';
export { scheduleRruleSchemaV1, scheduleRruleSchemaV2 } from './saved_objects';
export type { RruleSchedule } from './task';
export { TaskStatus, TaskPriority, TaskCost } from './task';

View file

@ -14,7 +14,7 @@ import { getOldestIdleActionTask } from '../queries/oldest_idle_action_task';
import { TASK_MANAGER_INDEX } from '../constants';
import { backgroundTaskNodeModelVersions, taskModelVersions } from './model_versions';
export { scheduleRruleSchema } from './schemas/task';
export { scheduleRruleSchemaV1, scheduleRruleSchemaV2 } from './schemas/rrule';
export const TASK_SO_NAME = 'task';
export const BACKGROUND_TASK_NODE_SO_NAME = 'background-task-node';

View file

@ -12,6 +12,7 @@ import {
taskSchemaV3,
taskSchemaV4,
taskSchemaV5,
taskSchemaV6,
} from '../schemas/task';
// IMPORTANT!!!
@ -84,4 +85,11 @@ export const taskModelVersions: SavedObjectsModelVersionMap = {
create: taskSchemaV5,
},
},
'6': {
changes: [],
schemas: {
forwardCompatibility: taskSchemaV6.extends({}, { unknowns: 'ignore' }),
create: taskSchemaV6,
},
},
};

View file

@ -0,0 +1,15 @@
/*
* 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.
*/
export {
rruleSchedule as rruleScheduleV1,
scheduleRruleSchema as scheduleRruleSchemaV1,
} from './v1';
export {
rruleSchedule as rruleScheduleV2,
scheduleRruleSchema as scheduleRruleSchemaV2,
} from './v2';

View file

@ -9,7 +9,7 @@ import { schema } from '@kbn/config-schema';
import { Frequency } from '@kbn/rrule';
import moment from 'moment-timezone';
function validateTimezone(timezone: string) {
export function validateTimezone(timezone: string) {
if (moment.tz.zone(timezone) != null) {
return;
}
@ -36,7 +36,7 @@ const validateRecurrenceByWeekday = (array: string[]) => {
}
};
const rruleCommon = schema.object({
export const rruleCommon = schema.object({
freq: schema.oneOf([
schema.literal(0),
schema.literal(1),
@ -57,15 +57,21 @@ const rruleCommon = schema.object({
tzid: schema.string({ validate: validateTimezone, defaultValue: 'UTC' }),
});
const byminute = schema.maybe(schema.arrayOf(schema.number({ min: 0, max: 59 }), { minSize: 1 }));
const byhour = schema.maybe(schema.arrayOf(schema.number({ min: 0, max: 23 }), { minSize: 1 }));
const byweekday = schema.maybe(
export const byminute = schema.maybe(
schema.arrayOf(schema.number({ min: 0, max: 59 }), { minSize: 1 })
);
export const byhour = schema.maybe(
schema.arrayOf(schema.number({ min: 0, max: 23 }), { minSize: 1 })
);
export const byweekday = schema.maybe(
schema.arrayOf(schema.string(), {
minSize: 1,
validate: validateRecurrenceByWeekday,
})
);
const bymonthday = schema.maybe(schema.arrayOf(schema.number({ min: 1, max: 31 }), { minSize: 1 }));
export const bymonthday = schema.maybe(
schema.arrayOf(schema.number({ min: 1, max: 31 }), { minSize: 1 })
);
const rruleMonthly = rruleCommon.extends({
freq: schema.literal(Frequency.MONTHLY),
@ -92,3 +98,6 @@ const rruleDaily = rruleCommon.extends({
});
export const rruleSchedule = schema.oneOf([rruleMonthly, rruleWeekly, rruleDaily]);
export const scheduleRruleSchema = schema.object({
rrule: rruleSchedule,
});

View file

@ -0,0 +1,49 @@
/*
* 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 } from '@kbn/config-schema';
import { Frequency } from '@kbn/rrule';
import { byhour, byminute, byweekday, bymonthday, rruleCommon as rruleCommonV1 } from './v1';
const validateStartDate = (date: string) => {
const parsedValue = Date.parse(date);
if (isNaN(parsedValue)) return `Invalid date: ${date}`;
return;
};
const rruleCommon = rruleCommonV1.extends({
dtstart: schema.maybe(schema.string({ validate: validateStartDate })),
});
const rruleMonthly = rruleCommon.extends({
freq: schema.literal(Frequency.MONTHLY),
byhour,
byminute,
byweekday,
bymonthday,
});
const rruleWeekly = rruleCommon.extends({
freq: schema.literal(Frequency.WEEKLY),
byhour,
byminute,
byweekday,
bymonthday: schema.never(),
});
const rruleDaily = rruleCommon.extends({
freq: schema.literal(Frequency.DAILY),
byhour,
byminute,
byweekday,
bymonthday: schema.never(),
});
export const rruleSchedule = schema.oneOf([rruleMonthly, rruleWeekly, rruleDaily]);
export const scheduleRruleSchema = schema.object({
rrule: rruleSchedule,
});

View file

@ -7,7 +7,7 @@
import { schema } from '@kbn/config-schema';
import { isInterval } from '../../lib/intervals';
import { rruleSchedule } from './rrule';
import { scheduleRruleSchemaV1, scheduleRruleSchemaV2 } from './rrule';
export function validateDuration(duration: string) {
if (!isInterval(duration)) {
@ -59,10 +59,6 @@ export const scheduleIntervalSchema = schema.object({
interval: schema.string({ validate: validateDuration }),
});
export const scheduleRruleSchema = schema.object({
rrule: rruleSchedule,
});
export const taskSchemaV4 = taskSchemaV3.extends({
apiKey: schema.maybe(schema.string()),
userScope: schema.maybe(
@ -75,5 +71,9 @@ export const taskSchemaV4 = taskSchemaV3.extends({
});
export const taskSchemaV5 = taskSchemaV4.extends({
schedule: schema.maybe(schema.oneOf([scheduleIntervalSchema, scheduleRruleSchema])),
schedule: schema.maybe(schema.oneOf([scheduleIntervalSchema, scheduleRruleSchemaV1])),
});
export const taskSchemaV6 = taskSchemaV5.extends({
schedule: schema.maybe(schema.oneOf([scheduleIntervalSchema, scheduleRruleSchemaV2])),
});