-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Move current HTTP APIs to legacy folder * Rename BASE_ALERT_API_PATH to LEGACY_BASE_ALERT_API_PATH * Fix failing tests and extra files * Move current alert HTTP APIs to legacy folder (#93943) * Move current HTTP APIs to legacy folder * Rename BASE_ALERT_API_PATH to LEGACY_BASE_ALERT_API_PATH * Fix failing tests and extra files * Add necessary files * Create rule route * Get rule API * Update rule API * Delete rule route * Aggregate rules API * Disable rule API * Enable rule API * Find rules API * Fix Update API * Get rule alert summary API * Get rule state API * Health API * Rule types API * Mute all API * Mute alert API * Unmute all API * Unmute alert route * Update API key API * corrected tpye by making it much more complicated * removed unneeded cocde * Fixes * Add back health route * mutedInstanceIds -> mutedAlertIds * lastRun -> last_run * alert_type_state -> rule_type_state & alert_instances -> alerts Co-authored-by: Gidi Meir Morris <[email protected]>
- Loading branch information
Showing
48 changed files
with
3,892 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
/* | ||
* 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 { ErrorThatHandlesItsOwnResponse } from './types'; | ||
|
||
export function isErrorThatHandlesItsOwnResponse( | ||
e: ErrorThatHandlesItsOwnResponse | ||
): e is ErrorThatHandlesItsOwnResponse { | ||
return typeof (e as ErrorThatHandlesItsOwnResponse).sendResponse === 'function'; | ||
} | ||
|
||
export { ErrorThatHandlesItsOwnResponse }; | ||
export { AlertTypeDisabledError, AlertTypeDisabledReason } from './alert_type_disabled'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
150 changes: 150 additions & 0 deletions
150
x-pack/plugins/alerting/server/routes/aggregate_rules.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
/* | ||
* 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 { aggregateRulesRoute } from './aggregate_rules'; | ||
import { httpServiceMock } from 'src/core/server/mocks'; | ||
import { licenseStateMock } from '../lib/license_state.mock'; | ||
import { verifyApiAccess } from '../lib/license_api_access'; | ||
import { mockHandlerArguments } from './_mock_handler_arguments'; | ||
import { alertsClientMock } from '../alerts_client.mock'; | ||
|
||
const alertsClient = alertsClientMock.create(); | ||
|
||
jest.mock('../lib/license_api_access.ts', () => ({ | ||
verifyApiAccess: jest.fn(), | ||
})); | ||
|
||
beforeEach(() => { | ||
jest.resetAllMocks(); | ||
}); | ||
|
||
describe('aggregateRulesRoute', () => { | ||
it('aggregate rules with proper parameters', async () => { | ||
const licenseState = licenseStateMock.create(); | ||
const router = httpServiceMock.createRouter(); | ||
|
||
aggregateRulesRoute(router, licenseState); | ||
|
||
const [config, handler] = router.get.mock.calls[0]; | ||
|
||
expect(config.path).toMatchInlineSnapshot(`"/api/alerting/rules/_aggregate"`); | ||
|
||
const aggregateResult = { | ||
alertExecutionStatus: { | ||
ok: 15, | ||
error: 2, | ||
active: 23, | ||
pending: 1, | ||
unknown: 0, | ||
}, | ||
}; | ||
alertsClient.aggregate.mockResolvedValueOnce(aggregateResult); | ||
|
||
const [context, req, res] = mockHandlerArguments( | ||
{ alertsClient }, | ||
{ | ||
query: { | ||
default_search_operator: 'AND', | ||
}, | ||
}, | ||
['ok'] | ||
); | ||
|
||
expect(await handler(context, req, res)).toMatchInlineSnapshot(` | ||
Object { | ||
"body": Object { | ||
"rule_execution_status": Object { | ||
"active": 23, | ||
"error": 2, | ||
"ok": 15, | ||
"pending": 1, | ||
"unknown": 0, | ||
}, | ||
}, | ||
} | ||
`); | ||
|
||
expect(alertsClient.aggregate).toHaveBeenCalledTimes(1); | ||
expect(alertsClient.aggregate.mock.calls[0]).toMatchInlineSnapshot(` | ||
Array [ | ||
Object { | ||
"options": Object { | ||
"defaultSearchOperator": "AND", | ||
}, | ||
}, | ||
] | ||
`); | ||
|
||
expect(res.ok).toHaveBeenCalledWith({ | ||
body: { | ||
rule_execution_status: { | ||
ok: 15, | ||
error: 2, | ||
active: 23, | ||
pending: 1, | ||
unknown: 0, | ||
}, | ||
}, | ||
}); | ||
}); | ||
|
||
it('ensures the license allows aggregating rules', async () => { | ||
const licenseState = licenseStateMock.create(); | ||
const router = httpServiceMock.createRouter(); | ||
|
||
aggregateRulesRoute(router, licenseState); | ||
|
||
const [, handler] = router.get.mock.calls[0]; | ||
|
||
alertsClient.aggregate.mockResolvedValueOnce({ | ||
alertExecutionStatus: { | ||
ok: 15, | ||
error: 2, | ||
active: 23, | ||
pending: 1, | ||
unknown: 0, | ||
}, | ||
}); | ||
|
||
const [context, req, res] = mockHandlerArguments( | ||
{ alertsClient }, | ||
{ | ||
query: { | ||
default_search_operator: 'OR', | ||
}, | ||
} | ||
); | ||
|
||
await handler(context, req, res); | ||
|
||
expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); | ||
}); | ||
|
||
it('ensures the license check prevents aggregating rules', async () => { | ||
const licenseState = licenseStateMock.create(); | ||
const router = httpServiceMock.createRouter(); | ||
|
||
(verifyApiAccess as jest.Mock).mockImplementation(() => { | ||
throw new Error('OMG'); | ||
}); | ||
|
||
aggregateRulesRoute(router, licenseState); | ||
|
||
const [, handler] = router.get.mock.calls[0]; | ||
|
||
const [context, req, res] = mockHandlerArguments( | ||
{}, | ||
{ | ||
query: {}, | ||
}, | ||
['ok'] | ||
); | ||
expect(handler(context, req, res)).rejects.toMatchInlineSnapshot(`[Error: OMG]`); | ||
|
||
expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
/* | ||
* 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 { IRouter } from 'kibana/server'; | ||
import { schema } from '@kbn/config-schema'; | ||
import { ILicenseState } from '../lib'; | ||
import { AggregateResult, AggregateOptions } from '../alerts_client'; | ||
import { RewriteResponseCase, RewriteRequestCase, verifyAccessAndContext } from './lib'; | ||
import { AlertingRequestHandlerContext, BASE_ALERTING_API_PATH } from '../types'; | ||
|
||
// config definition | ||
const querySchema = schema.object({ | ||
search: schema.maybe(schema.string()), | ||
default_search_operator: schema.oneOf([schema.literal('OR'), schema.literal('AND')], { | ||
defaultValue: 'OR', | ||
}), | ||
search_fields: schema.maybe(schema.arrayOf(schema.string())), | ||
has_reference: schema.maybe( | ||
// use nullable as maybe is currently broken | ||
// in config-schema | ||
schema.nullable( | ||
schema.object({ | ||
type: schema.string(), | ||
id: schema.string(), | ||
}) | ||
) | ||
), | ||
filter: schema.maybe(schema.string()), | ||
}); | ||
|
||
const rewriteQueryReq: RewriteRequestCase<AggregateOptions> = ({ | ||
default_search_operator: defaultSearchOperator, | ||
has_reference: hasReference, | ||
search_fields: searchFields, | ||
...rest | ||
}) => ({ | ||
...rest, | ||
defaultSearchOperator, | ||
...(hasReference ? { hasReference } : {}), | ||
...(searchFields ? { searchFields } : {}), | ||
}); | ||
const rewriteBodyRes: RewriteResponseCase<AggregateResult> = ({ | ||
alertExecutionStatus, | ||
...rest | ||
}) => ({ | ||
...rest, | ||
rule_execution_status: alertExecutionStatus, | ||
}); | ||
|
||
export const aggregateRulesRoute = ( | ||
router: IRouter<AlertingRequestHandlerContext>, | ||
licenseState: ILicenseState | ||
) => { | ||
router.get( | ||
{ | ||
path: `${BASE_ALERTING_API_PATH}/rules/_aggregate`, | ||
validate: { | ||
query: querySchema, | ||
}, | ||
}, | ||
router.handleLegacyErrors( | ||
verifyAccessAndContext(licenseState, async function (context, req, res) { | ||
const alertsClient = context.alerting.getAlertsClient(); | ||
const options = rewriteQueryReq({ | ||
...req.query, | ||
has_reference: req.query.has_reference || undefined, | ||
}); | ||
const aggregateResult = await alertsClient.aggregate({ options }); | ||
return res.ok({ | ||
body: rewriteBodyRes(aggregateResult), | ||
}); | ||
}) | ||
) | ||
); | ||
}; |
Oops, something went wrong.