[8.8] [RAM][8.8] Fix get active maintenance window query (#157112) (#157119)

# Backport

This will backport the following commits from `main` to `8.8`:
- [[RAM][8.8] Fix get active maintenance window query
(#157112)](https://github.com/elastic/kibana/pull/157112)

<!--- Backport version: 8.9.7 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Jiawei
Wu","email":"74562234+JiaweiWu@users.noreply.github.com"},"sourceCommit":{"committedDate":"2023-05-09T02:27:59Z","message":"[RAM][8.8]
Fix get active maintenance window query (#157112)\n\n## Summary\r\nFix
the active maintenance window query, originally the KQL query
got\r\nconverted to something like:\r\n\r\n```\r\n query: {\r\n bool:
{\r\n filter: [\r\n {\r\n range: {\r\n
'maintenance-window.attributes.events': {\r\n gte: from,\r\n },\r\n
},\r\n },\r\n {\r\n range: {\r\n 'maintenance-window.attributes.events':
{\r\n lte: to,\r\n },\r\n },\r\n },\r\n ],\r\n },\r\n},\r\n```\r\nWhen
in reality we wanted a query like:\r\n\r\n```\r\nquery: {\r\n bool:
{\r\n filter: \r\n range: {\r\n 'maintenance-window.attributes.events':
{\r\n gte: from,\r\n lte: to,\r\n },\r\n },\r\n },\r\n
},\r\n},\r\n```\r\nWhich return some upcoming maintenance windows that
we did not want.\r\n\r\n### Checklist\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios","sha":"6d4f695b759b8fe30ac7314951c39dce6f27e376","branchLabelMapping":{"^v8.9.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["bug","backport","release_note:skip","Team:ResponseOps","Feature:Alerting/RulesManagement","v8.8.0","v8.9.0"],"number":157112,"url":"https://github.com/elastic/kibana/pull/157112","mergeCommit":{"message":"[RAM][8.8]
Fix get active maintenance window query (#157112)\n\n## Summary\r\nFix
the active maintenance window query, originally the KQL query
got\r\nconverted to something like:\r\n\r\n```\r\n query: {\r\n bool:
{\r\n filter: [\r\n {\r\n range: {\r\n
'maintenance-window.attributes.events': {\r\n gte: from,\r\n },\r\n
},\r\n },\r\n {\r\n range: {\r\n 'maintenance-window.attributes.events':
{\r\n lte: to,\r\n },\r\n },\r\n },\r\n ],\r\n },\r\n},\r\n```\r\nWhen
in reality we wanted a query like:\r\n\r\n```\r\nquery: {\r\n bool:
{\r\n filter: \r\n range: {\r\n 'maintenance-window.attributes.events':
{\r\n gte: from,\r\n lte: to,\r\n },\r\n },\r\n },\r\n
},\r\n},\r\n```\r\nWhich return some upcoming maintenance windows that
we did not want.\r\n\r\n### Checklist\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios","sha":"6d4f695b759b8fe30ac7314951c39dce6f27e376"}},"sourceBranch":"main","suggestedTargetBranches":["8.8"],"targetPullRequestStates":[{"branch":"8.8","label":"v8.8.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.9.0","labelRegex":"^v8.9.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/157112","number":157112,"mergeCommit":{"message":"[RAM][8.8]
Fix get active maintenance window query (#157112)\n\n## Summary\r\nFix
the active maintenance window query, originally the KQL query
got\r\nconverted to something like:\r\n\r\n```\r\n query: {\r\n bool:
{\r\n filter: [\r\n {\r\n range: {\r\n
'maintenance-window.attributes.events': {\r\n gte: from,\r\n },\r\n
},\r\n },\r\n {\r\n range: {\r\n 'maintenance-window.attributes.events':
{\r\n lte: to,\r\n },\r\n },\r\n },\r\n ],\r\n },\r\n},\r\n```\r\nWhen
in reality we wanted a query like:\r\n\r\n```\r\nquery: {\r\n bool:
{\r\n filter: \r\n range: {\r\n 'maintenance-window.attributes.events':
{\r\n gte: from,\r\n lte: to,\r\n },\r\n },\r\n },\r\n
},\r\n},\r\n```\r\nWhich return some upcoming maintenance windows that
we did not want.\r\n\r\n### Checklist\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios","sha":"6d4f695b759b8fe30ac7314951c39dce6f27e376"}}]}]
BACKPORT-->

Co-authored-by: Jiawei Wu <74562234+JiaweiWu@users.noreply.github.com>
This commit is contained in:
Kibana Machine 2023-05-09 00:33:24 -04:00 committed by GitHub
parent 28a26dd8e7
commit f55816f117
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 79 additions and 100 deletions

View file

@ -12,10 +12,7 @@ import { update, UpdateParams } from './methods/update';
import { find, FindResult } from './methods/find';
import { deleteMaintenanceWindow, DeleteParams } from './methods/delete';
import { archive, ArchiveParams } from './methods/archive';
import {
getActiveMaintenanceWindows,
ActiveParams,
} from './methods/get_active_maintenance_windows';
import { getActiveMaintenanceWindows } from './methods/get_active_maintenance_windows';
import { finish, FinishParams } from './methods/finish';
import {
@ -71,6 +68,6 @@ export class MaintenanceWindowClient {
archive(this.context, params);
public finish = (params: FinishParams): Promise<MaintenanceWindow> =>
finish(this.context, params);
public getActiveMaintenanceWindows = (params?: ActiveParams): Promise<MaintenanceWindow[]> =>
getActiveMaintenanceWindows(this.context, params);
public getActiveMaintenanceWindows = (): Promise<MaintenanceWindow[]> =>
getActiveMaintenanceWindows(this.context);
}

View file

@ -48,12 +48,7 @@ describe('MaintenanceWindowClient - getActiveMaintenanceWindows', () => {
],
} as unknown as SavedObjectsFindResponse);
const startDate = new Date().toISOString();
const result = await getActiveMaintenanceWindows(mockContext, {
start: startDate,
interval: '1h',
});
const result = await getActiveMaintenanceWindows(mockContext);
const findCallParams = savedObjectsClient.find.mock.calls[0][0];
@ -65,33 +60,11 @@ describe('MaintenanceWindowClient - getActiveMaintenanceWindows', () => {
"filter": Array [
Object {
"bool": Object {
"filter": Array [
"minimum_should_match": 1,
"should": Array [
Object {
"bool": Object {
"minimum_should_match": 1,
"should": Array [
Object {
"range": Object {
"maintenance-window.attributes.events": Object {
"gte": "2023-02-26T00:00:00.000Z",
},
},
},
],
},
},
Object {
"bool": Object {
"minimum_should_match": 1,
"should": Array [
Object {
"range": Object {
"maintenance-window.attributes.events": Object {
"lte": "2023-02-26T01:00:00.000Z",
},
},
},
],
"match": Object {
"maintenance-window.attributes.events": "2023-02-26T00:00:00.000Z",
},
},
],
@ -131,12 +104,7 @@ describe('MaintenanceWindowClient - getActiveMaintenanceWindows', () => {
saved_objects: [],
} as unknown as SavedObjectsFindResponse);
const startDate = new Date().toISOString();
const result = await getActiveMaintenanceWindows(mockContext, {
start: startDate,
interval: '4d',
});
const result = await getActiveMaintenanceWindows(mockContext);
const findCallParams = savedObjectsClient.find.mock.calls[0][0];
@ -147,33 +115,11 @@ describe('MaintenanceWindowClient - getActiveMaintenanceWindows', () => {
"filter": Array [
Object {
"bool": Object {
"filter": Array [
"minimum_should_match": 1,
"should": Array [
Object {
"bool": Object {
"minimum_should_match": 1,
"should": Array [
Object {
"range": Object {
"maintenance-window.attributes.events": Object {
"gte": "2023-02-26T00:00:00.000Z",
},
},
},
],
},
},
Object {
"bool": Object {
"minimum_should_match": 1,
"should": Array [
Object {
"range": Object {
"maintenance-window.attributes.events": Object {
"lte": "2023-03-02T00:00:00.000Z",
},
},
},
],
"match": Object {
"maintenance-window.attributes.events": "2023-02-26T00:00:00.000Z",
},
},
],
@ -203,17 +149,12 @@ describe('MaintenanceWindowClient - getActiveMaintenanceWindows', () => {
savedObjectsClient.find.mockRejectedValueOnce('something went wrong');
const startDate = new Date().toISOString();
await expect(async () => {
await getActiveMaintenanceWindows(mockContext, {
start: startDate,
interval: '4d',
});
await getActiveMaintenanceWindows(mockContext);
}).rejects.toThrowError();
expect(mockContext.logger.error).toHaveBeenLastCalledWith(
'Failed to find active maintenance window by interval: 4d with start date: 2023-02-26T00:00:00.000Z, Error: something went wrong'
'Failed to find active maintenance window by interval, Error: something went wrong'
);
});
});

View file

@ -6,14 +6,12 @@
*/
import Boom from '@hapi/boom';
import moment from 'moment';
import { nodeBuilder, fromKueryExpression } from '@kbn/es-query';
import { nodeBuilder } from '@kbn/es-query';
import { getMaintenanceWindowFromRaw } from '../get_maintenance_window_from_raw';
import {
MaintenanceWindow,
MaintenanceWindowSOAttributes,
MAINTENANCE_WINDOW_SAVED_OBJECT_TYPE,
parseDuration,
MaintenanceWindowClientContext,
} from '../../../common';
@ -27,30 +25,16 @@ export interface MaintenanceWindowAggregationResult {
};
}
export interface ActiveParams {
start?: string;
interval?: string;
}
export async function getActiveMaintenanceWindows(
context: MaintenanceWindowClientContext,
params?: ActiveParams
context: MaintenanceWindowClientContext
): Promise<MaintenanceWindow[]> {
const { savedObjectsClient, logger } = context;
const { start, interval } = params || {};
const startDate = start ? new Date(start) : new Date();
const duration = interval ? parseDuration(interval) : 0;
const endDate = moment.utc(startDate).add(duration, 'ms').toDate();
const startDate = new Date();
const startDateISO = startDate.toISOString();
const endDateISO = endDate.toISOString();
const filter = nodeBuilder.and([
nodeBuilder.and([
fromKueryExpression(`maintenance-window.attributes.events >= "${startDateISO}"`),
fromKueryExpression(`maintenance-window.attributes.events <= "${endDateISO}"`),
]),
nodeBuilder.is('maintenance-window.attributes.events', startDateISO),
nodeBuilder.is('maintenance-window.attributes.enabled', 'true'),
]);
@ -67,7 +51,7 @@ export async function getActiveMaintenanceWindows(
})
);
} catch (e) {
const errorMessage = `Failed to find active maintenance window by interval: ${interval} with start date: ${startDate.toISOString()}, Error: ${e}`;
const errorMessage = `Failed to find active maintenance window by interval, Error: ${e}`;
logger.error(errorMessage);
throw Boom.boomify(e, { message: errorMessage });
}

View file

@ -39,7 +39,7 @@ export const activeMaintenanceWindowsRoute = (
});
}
const maintenanceWindowClient = (await context.alerting).getMaintenanceWindowClient();
const result = await maintenanceWindowClient.getActiveMaintenanceWindows({});
const result = await maintenanceWindowClient.getActiveMaintenanceWindows();
return res.ok({
body: result.map((maintenanceWindow) => rewriteMaintenanceWindowRes(maintenanceWindow)),

View file

@ -24,10 +24,11 @@ export default function activeMaintenanceWindowTests({ getService }: FtrProvider
r_rule: {
dtstart: new Date().toISOString(),
tzid: 'UTC',
count: 10,
freq: 2, // weekly
},
};
after(() => objectRemover.removeAll());
afterEach(() => objectRemover.removeAll());
for (const scenario of UserAtSpaceScenarios) {
const { user, space } = scenario;
@ -121,6 +122,62 @@ export default function activeMaintenanceWindowTests({ getService }: FtrProvider
});
}
it('should return active maintenance windows', async () => {
const { body: window1 } = await supertest
.post(`${getUrlPrefix('space1')}/internal/alerting/rules/maintenance_window`)
.set('kbn-xsrf', 'foo')
.send({
...createParams,
duration: 30 * 60 * 1000,
r_rule: {
...createParams.r_rule,
dtstart: moment().subtract(1, 'hour').toISOString(),
},
})
.expect(200);
objectRemover.add('space1', window1.id, 'rules/maintenance_window', 'alerting', true);
const { body: window2 } = await supertest
.post(`${getUrlPrefix('space1')}/internal/alerting/rules/maintenance_window`)
.set('kbn-xsrf', 'foo')
.send({
...createParams,
duration: 30 * 60 * 1000,
r_rule: {
...createParams.r_rule,
dtstart: moment().subtract(5, 'minutes').toISOString(),
},
})
.expect(200);
objectRemover.add('space1', window2.id, 'rules/maintenance_window', 'alerting', true);
const { body: window3 } = await supertest
.post(`${getUrlPrefix('space1')}/internal/alerting/rules/maintenance_window`)
.set('kbn-xsrf', 'foo')
.send({
...createParams,
duration: 30 * 60 * 1000,
r_rule: {
...createParams.r_rule,
dtstart: moment().add(1, 'hour').toISOString(),
},
})
.expect(200);
objectRemover.add('space1', window3.id, 'rules/maintenance_window', 'alerting', true);
const { body: activeWindows } = await supertest
.get(`${getUrlPrefix('space1')}/internal/alerting/rules/maintenance_window/_active`)
.set('kbn-xsrf', 'foo')
.send({})
.expect(200);
expect(activeWindows.length).eql(1);
expect(activeWindows[0].id).eql(window2.id);
});
it('should return an empty array if there are no active maintenance windows', async () => {
const { body: createdMaintenanceWindow } = await supertest
.post(`${getUrlPrefix('space1')}/internal/alerting/rules/maintenance_window`)