Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RAM] Window Maintenance Client/Saved Object and Mapping/REST APIs #153411

Merged
merged 26 commits into from
Apr 13, 2023
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
df480b9
WIP
JiaweiWu Mar 20, 2023
8964c59
Fix merge conflict
JiaweiWu Mar 20, 2023
5e38793
Implement SO, mappings, and API methods
JiaweiWu Mar 21, 2023
6530f9c
Integration tests
JiaweiWu Mar 27, 2023
55d1a1e
[CI] Auto-commit changed files from 'node scripts/precommit_hook.js -…
kibanamachine Mar 27, 2023
ef9d175
Don't index metadata
JiaweiWu Mar 27, 2023
6cdc4a9
Merge branch 'main' into issue-152270-window-maintenance-SO
kibanamachine Mar 27, 2023
83c2e85
Improve unit testing
JiaweiWu Mar 28, 2023
0fa810a
Fix tz differences in unit tests
JiaweiWu Mar 29, 2023
7658df8
Add new finish route, make tests involving timezone more consistent
JiaweiWu Mar 30, 2023
3ec6503
Route unit tests
JiaweiWu Mar 30, 2023
4c02533
Make update APIs idempotent and commutative, fix rest of the tests
JiaweiWu Apr 3, 2023
9e5bc4f
Merge branch 'main' into issue-152270-window-maintenance-SO
kibanamachine Apr 3, 2023
3ee27f4
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine Apr 3, 2023
fba8c7e
Add total property to find response, change start/end date names
JiaweiWu Apr 4, 2023
29f1da7
Fix merge conflict
JiaweiWu Apr 6, 2023
f5751bc
Change maintenance window SO namespaceType
JiaweiWu Apr 6, 2023
0433225
Update test snapshot
JiaweiWu Apr 6, 2023
a54fbe0
Remove aggregate to active function
JiaweiWu Apr 11, 2023
fd48776
Undo changes to bucket_aggs.ts
JiaweiWu Apr 11, 2023
5c94aa6
Merge branch 'main' into issue-152270-window-maintenance-SO
kibanamachine Apr 12, 2023
1bb7216
Merge branch 'main' into issue-152270-window-maintenance-SO
kibanamachine Apr 12, 2023
6381964
Fix getActiveMaintenanceWindow filter
JiaweiWu Apr 12, 2023
d65b6a9
Addressed comments
JiaweiWu Apr 13, 2023
1525d5e
Revert changes to merge event
JiaweiWu Apr 13, 2023
6e0d36f
Merge branch 'main' into issue-152270-window-maintenance-SO
kibanamachine Apr 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ describe('checking migration metadata changes on all registered SO types', () =>
"legacy-url-alias": "9b8cca3fbb2da46fd12823d3cd38fdf1c9f24bc8",
"lens": "2f6a8231591e3d62a83506b19e165774d74588ea",
"lens-ui-telemetry": "d6c4e330d170eefc6214dbf77a53de913fa3eebc",
"maintenance-window": "2cb13a3c4b7a58e9557f962286b9afd9156bf0f8",
"map": "7902b2e2a550e0b73fd5aa6c4e2ba3a4e6558877",
"metrics-explorer-view": "713dbf1ab5e067791d19170f715eb82cf07ebbcc",
"ml-job": "12e21f1b1adfcc1052dc0b10c7459de875653b94",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ const previouslyRegisteredTypes = [
'legacy-url-alias',
'lens',
'lens-ui-telemetry',
'maintenance-window',
'map',
'maps-telemetry',
'metrics-explorer-view',
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/alerting/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ export * from './rule_notify_when_type';
export * from './parse_duration';
export * from './execution_log_types';
export * from './rule_snooze_type';
export * from './rrule_type';
export * from './maintenance_window';
export * from './default_rule_aggregation';
export * from './rule_tags_aggregation';

Expand Down
60 changes: 60 additions & 0 deletions x-pack/plugins/alerting/common/maintenance_window.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* 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 { Logger, SavedObjectsClientContract } from '@kbn/core/server';
import { RRuleParams } from './rrule_type';

export enum MaintenanceWindowStatus {
Running = 'running',
Upcoming = 'upcoming',
Finished = 'finished',
Archived = 'archived',
}

export interface MaintenanceWindowModificationMetadata {
createdBy: string | null;
updatedBy: string | null;
createdAt: string;
updatedAt: string;
}

export interface DateRange {
gte: string;
lte: string;
}

export interface MaintenanceWindowSOProperties {
title: string;
enabled: boolean;
duration: number;
expirationDate: string;
events: DateRange[];
rRule: RRuleParams;
}

export type MaintenanceWindowSOAttributes = MaintenanceWindowSOProperties &
MaintenanceWindowModificationMetadata;

export type MaintenanceWindow = MaintenanceWindowSOAttributes & {
status: MaintenanceWindowStatus;
eventStartTime: string | null;
eventEndTime: string | null;
id: string;
};

export interface MaintenanceWindowClientContext {
getModificationMetadata: () => Promise<MaintenanceWindowModificationMetadata>;
savedObjectsClient: SavedObjectsClientContract;
logger: Logger;
}

export const MAINTENANCE_WINDOW_SAVED_OBJECT_TYPE = 'maintenance-window';
export const MAINTENANCE_WINDOW_FEATURE_ID = 'maintenanceWindow';
export const MAINTENANCE_WINDOW_API_PRIVILEGES = {
READ_MAINTENANCE_WINDOW: 'read-maintenance-window',
WRITE_MAINTENANCE_WINDOW: 'write-maintenance-window',
};
30 changes: 30 additions & 0 deletions x-pack/plugins/alerting/common/rrule_type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* 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 type { WeekdayStr } from 'rrule';

export type RRuleParams = Partial<RRuleRecord> & Pick<RRuleRecord, 'dtstart' | 'tzid'>;

// An iCal RRULE to define a recurrence schedule, see https://github.com/jakubroztocil/rrule for the spec
export interface RRuleRecord {
dtstart: string;
tzid: string;
freq?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
until?: string;
count?: number;
interval?: number;
wkst?: WeekdayStr;
byweekday?: Array<string | number>;
bymonth?: number[];
bysetpos?: number[];
bymonthday: number[];
byyearday: number[];
byweekno: number[];
byhour: number[];
byminute: number[];
bysecond: number[];
}
28 changes: 3 additions & 25 deletions x-pack/plugins/alerting/common/rule_snooze_type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@
* 2.0.
*/

import type { WeekdayStr } from 'rrule';

type SnoozeRRule = Partial<RRuleRecord> & Pick<RRuleRecord, 'dtstart' | 'tzid'>;
import { RRuleParams } from './rrule_type';

export interface RuleSnoozeSchedule {
duration: number;
rRule: SnoozeRRule;
rRule: RRuleParams;
// For scheduled/recurring snoozes, `id` uniquely identifies them so that they can be displayed, modified, and deleted individually
id?: string;
skipRecurrences?: string[];
Expand All @@ -21,27 +19,7 @@ export interface RuleSnoozeSchedule {
// RuleSnooze = RuleSnoozeSchedule[] throws typescript errors across the whole lib
export type RuleSnooze = Array<{
duration: number;
rRule: SnoozeRRule;
rRule: RRuleParams;
id?: string;
skipRecurrences?: string[];
}>;

// An iCal RRULE to define a recurrence schedule, see https://github.com/jakubroztocil/rrule for the spec
export interface RRuleRecord {
dtstart: string;
tzid: string;
freq?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
until?: string;
count?: number;
interval?: number;
wkst?: WeekdayStr;
byweekday?: Array<string | number>;
bymonth?: number[];
bysetpos?: number[];
bymonthday: number[];
byyearday: number[];
byweekno: number[];
byhour: number[];
byminute: number[];
bysecond: number[];
}
8 changes: 8 additions & 0 deletions x-pack/plugins/alerting/server/lib/rrule/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* 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 * from './parse_by_weekday';
13 changes: 13 additions & 0 deletions x-pack/plugins/alerting/server/lib/rrule/parse_by_weekday.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* 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 { ByWeekday, rrulestr } from 'rrule';

export function parseByWeekday(byweekday: Array<string | number>): ByWeekday[] {
const rRuleString = `RRULE:BYDAY=${byweekday.join(',')}`;
const parsedRRule = rrulestr(rRuleString);
return parsedRRule.origOptions.byweekday as ByWeekday[];
}
9 changes: 2 additions & 7 deletions x-pack/plugins/alerting/server/lib/snooze/is_snooze_active.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
* 2.0.
*/

import { RRule, ByWeekday, Weekday, rrulestr } from 'rrule';
import { RRule, Weekday } from 'rrule';
import { RuleSnoozeSchedule } from '../../types';
import { parseByWeekday } from '../rrule';
import { utcToLocalUtc, localUtcToUtc } from './timezone_helpers';

const MAX_TIMESTAMP = 8640000000000000;
Expand Down Expand Up @@ -63,9 +64,3 @@ export function isSnoozeActive(snooze: RuleSnoozeSchedule) {

return null;
}

export function parseByWeekday(byweekday: Array<string | number>): ByWeekday[] {
const rRuleString = `RRULE:BYDAY=${byweekday.join(',')}`;
const parsedRRule = rrulestr(rRuleString);
return parsedRRule.origOptions.byweekday as ByWeekday[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@

import { RRule, Weekday } from 'rrule';
import { RuleSnoozeSchedule } from '../../types';
import { isSnoozeActive, parseByWeekday } from './is_snooze_active';
import { isSnoozeActive } from './is_snooze_active';
import { parseByWeekday } from '../rrule';

export function isSnoozeExpired(snooze: RuleSnoozeSchedule) {
if (isSnoozeActive(snooze)) {
Expand Down
31 changes: 31 additions & 0 deletions x-pack/plugins/alerting/server/maintenance_window_client.mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* 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 { MaintenanceWindowClientApi } from './types';

type Schema = MaintenanceWindowClientApi;
export type MaintenanceWindowClientMock = jest.Mocked<Schema>;

const createMaintenanceWindowClientMock = () => {
const mocked: MaintenanceWindowClientMock = {
create: jest.fn(),
update: jest.fn(),
find: jest.fn(),
get: jest.fn(),
archive: jest.fn(),
getActiveMaintenanceWindows: jest.fn(),
finish: jest.fn(),
delete: jest.fn(),
};
return mocked;
};

export const maintenanceWindowClientMock: {
create: () => MaintenanceWindowClientMock;
} = {
create: createMaintenanceWindowClientMock,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*
* 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 moment from 'moment-timezone';
import { RRule } from 'rrule';
import { generateMaintenanceWindowEvents } from './generate_maintenance_window_events';

describe('generateMaintenanceWindowEvents', () => {
beforeAll(() => {
jest.useFakeTimers().setSystemTime(new Date('2023-02-26T00:00:00.000Z'));
});

it('should generate events for rrule repeating daily', () => {
// Create rrule with expiration date at: 2023-03-13T00:00:00.000Z
const result = generateMaintenanceWindowEvents({
duration: 1 * 60 * 60 * 1000,
expirationDate: moment(new Date('2023-02-27T00:00:00.000Z'))
.tz('UTC')
.add(2, 'weeks')
.toISOString(),
rRule: {
tzid: 'UTC',
freq: RRule.DAILY,
interval: 1,
dtstart: '2023-02-27T00:00:00.000Z',
},
});

expect(result.length).toEqual(15);

// Ensure start date is correct
expect(result[0].gte).toEqual('2023-02-27T00:00:00.000Z');
expect(result[0].lte).toEqual('2023-02-27T01:00:00.000Z');

// Ensure it is incrementing by the correct frequency (daily)
expect(result[1].gte).toEqual('2023-02-28T00:00:00.000Z');
expect(result[1].lte).toEqual('2023-02-28T01:00:00.000Z');

// Ensure end date is correct
expect(result[result.length - 1].gte).toEqual('2023-03-13T00:00:00.000Z');
expect(result[result.length - 1].lte).toEqual('2023-03-13T01:00:00.000Z');
});

it('should generate events for rrule repeating weekly', () => {
// Create rrule with expiration date at: 2023-04-03T00:00:00.000Z
const result = generateMaintenanceWindowEvents({
duration: 1 * 60 * 60 * 1000,
expirationDate: moment(new Date('2023-02-27T00:00:00.000Z'))
.tz('UTC')
.add(5, 'weeks')
.toISOString(),
rRule: {
tzid: 'UTC',
freq: RRule.WEEKLY,
interval: 1,
dtstart: '2023-02-27T00:00:00.000Z',
},
});

expect(result.length).toEqual(6);

// Ensure start date is correct
expect(result[0].gte).toEqual('2023-02-27T00:00:00.000Z');
expect(result[0].lte).toEqual('2023-02-27T01:00:00.000Z');

// Ensure it is incrementing by the correct frequency (weekly)
expect(result[1].gte).toEqual('2023-03-06T00:00:00.000Z');
expect(result[1].lte).toEqual('2023-03-06T01:00:00.000Z');

// Ensure end date is correct
expect(result[result.length - 1].gte).toEqual('2023-04-03T00:00:00.000Z');
expect(result[result.length - 1].lte).toEqual('2023-04-03T01:00:00.000Z');
});

it('should generate events for rrule repeating monthly', () => {
// Create rrule with expiration date at: 2023-10-27T00:00:00.000Z
const result = generateMaintenanceWindowEvents({
duration: 1 * 60 * 60 * 1000,
expirationDate: moment(new Date('2023-02-27T00:00:00.000Z'))
.tz('UTC')
.add(8, 'months')
.toISOString(),
rRule: {
tzid: 'UTC',
freq: RRule.MONTHLY,
interval: 1,
dtstart: '2023-02-27T00:00:00.000Z',
},
});

expect(result.length).toEqual(9);

// Ensure start date is correct
expect(result[0].gte).toEqual('2023-02-27T00:00:00.000Z');
expect(result[0].lte).toEqual('2023-02-27T01:00:00.000Z');

// Ensure it is incrementing by the correct frequency (monthly)
expect(result[1].gte).toEqual('2023-03-27T00:00:00.000Z');
expect(result[1].lte).toEqual('2023-03-27T01:00:00.000Z');

// Ensure end date is correct
expect(result[result.length - 1].gte).toEqual('2023-10-27T00:00:00.000Z');
expect(result[result.length - 1].lte).toEqual('2023-10-27T01:00:00.000Z');
});

it('should generate events for rrule repeating by specific days', () => {
const result = generateMaintenanceWindowEvents({
duration: 1 * 60 * 60 * 1000,
expirationDate: moment(new Date('2023-02-27T00:00:00.000Z'))
.tz('UTC')
.add(5, 'weeks')
.toISOString(),
rRule: {
tzid: 'UTC',
freq: RRule.WEEKLY,
interval: 1,
byweekday: ['TU', 'TH'],
dtstart: '2023-02-27T00:00:00.000Z',
},
});

expect(result.length).toEqual(10); // 5 weeks x 2 times a week = 10

// Ensure start date is correct (Tuesday)
expect(result[0].gte).toEqual('2023-02-28T00:00:00.000Z');
expect(result[0].lte).toEqual('2023-02-28T01:00:00.000Z');

// Ensure it is incrementing by the correct frequency (Thursday)
expect(result[1].gte).toEqual('2023-03-02T00:00:00.000Z');
expect(result[1].lte).toEqual('2023-03-02T01:00:00.000Z');

// Ensure end date is correct (Thursday)
expect(result[result.length - 1].gte).toEqual('2023-03-30T00:00:00.000Z');
expect(result[result.length - 1].lte).toEqual('2023-03-30T01:00:00.000Z');
});
});
Loading