mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[RAM][HTTP Versioning] Version GET Rule Route (#181304)
## Summary Parent Issue: https://github.com/elastic/kibana/issues/157883 Issue: https://github.com/elastic/kibana/issues/181263 Versions the GET rule endpoint with added input and output validation. ``` GET /internal/alerting/rule/{id} GET /api/alerting/rule/{id} ``` ### Checklist Delete any items that are not applicable to this PR. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
This commit is contained in:
parent
5814f2e0ce
commit
a1ada76026
39 changed files with 707 additions and 299 deletions
15
x-pack/plugins/alerting/common/routes/rule/apis/get/index.ts
Normal file
15
x-pack/plugins/alerting/common/routes/rule/apis/get/index.ts
Normal 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 { getRuleRequestParamsSchema } from './schemas/latest';
|
||||
export type { GetRuleRequestParams, GetRuleResponse } from './types/latest';
|
||||
|
||||
export { getRuleRequestParamsSchema as getRuleRequestParamsSchemaV1 } from './schemas/v1';
|
||||
export type {
|
||||
GetRuleRequestParams as GetRuleRequestParamsV1,
|
||||
GetRuleResponse as GetRuleResponseV1,
|
||||
} from './types/v1';
|
|
@ -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 './v1';
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* 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';
|
||||
|
||||
export const getRuleRequestParamsSchema = schema.object({
|
||||
id: schema.string(),
|
||||
});
|
|
@ -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 './v1';
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* 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 { TypeOf } from '@kbn/config-schema';
|
||||
import { RuleParamsV1, RuleResponseV1 } from '../../../response';
|
||||
import { getRuleRequestParamsSchemaV1 } from '..';
|
||||
|
||||
export type GetRuleRequestParams = TypeOf<typeof getRuleRequestParamsSchemaV1>;
|
||||
|
||||
export interface GetRuleResponse<Params extends RuleParamsV1 = never> {
|
||||
body: RuleResponseV1<Params>;
|
||||
}
|
|
@ -43,7 +43,7 @@ export interface RuleResponse<Params extends RuleParams = never> {
|
|||
mute_all: RuleResponseSchemaType['mute_all'];
|
||||
notify_when?: RuleResponseSchemaType['notify_when'];
|
||||
muted_alert_ids: RuleResponseSchemaType['muted_alert_ids'];
|
||||
execution_status: RuleResponseSchemaType['execution_status'];
|
||||
execution_status?: RuleResponseSchemaType['execution_status'];
|
||||
monitoring?: RuleResponseSchemaType['monitoring'];
|
||||
snooze_schedule?: RuleResponseSchemaType['snooze_schedule'];
|
||||
active_snoozes?: RuleResponseSchemaType['active_snoozes'];
|
||||
|
|
|
@ -400,6 +400,7 @@ describe('scheduleBackfill()', () => {
|
|||
rules: [
|
||||
{
|
||||
id: existingDecryptedRule1.id,
|
||||
legacyId: null,
|
||||
actions: existingDecryptedRule1.attributes.actions,
|
||||
alertTypeId: existingDecryptedRule1.attributes.alertTypeId,
|
||||
apiKey: existingDecryptedRule1.attributes.apiKey,
|
||||
|
@ -430,6 +431,7 @@ describe('scheduleBackfill()', () => {
|
|||
},
|
||||
{
|
||||
id: existingDecryptedRule2.id,
|
||||
legacyId: null,
|
||||
actions: existingDecryptedRule2.attributes.actions,
|
||||
alertTypeId: existingDecryptedRule2.attributes.alertTypeId,
|
||||
apiKey: existingDecryptedRule2.attributes.apiKey,
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
import { AlertConsumers } from '@kbn/rule-data-utils';
|
||||
|
||||
import { RulesClient, ConstructorOptions } from '../rules_client';
|
||||
import { RulesClient, ConstructorOptions } from '../../../../rules_client/rules_client';
|
||||
import {
|
||||
savedObjectsClientMock,
|
||||
loggingSystemMock,
|
||||
|
@ -14,21 +14,21 @@ import {
|
|||
uiSettingsServiceMock,
|
||||
} from '@kbn/core/server/mocks';
|
||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
||||
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
||||
import { ruleTypeRegistryMock } from '../../../../rule_type_registry.mock';
|
||||
import { alertingAuthorizationMock } from '../../../../authorization/alerting_authorization.mock';
|
||||
import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks';
|
||||
import { actionsAuthorizationMock } from '@kbn/actions-plugin/server/mocks';
|
||||
import { AlertingAuthorization } from '../../authorization/alerting_authorization';
|
||||
import { AlertingAuthorization } from '../../../../authorization/alerting_authorization';
|
||||
import { ActionsAuthorization } from '@kbn/actions-plugin/server';
|
||||
import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks';
|
||||
import { getBeforeSetup, setGlobalDate } from './lib';
|
||||
import { RecoveredActionGroup } from '../../../common';
|
||||
import { formatLegacyActions } from '../lib';
|
||||
import { ConnectorAdapterRegistry } from '../../connector_adapters/connector_adapter_registry';
|
||||
import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects';
|
||||
import { backfillClientMock } from '../../backfill_client/backfill_client.mock';
|
||||
import { getBeforeSetup, setGlobalDate } from '../../../../rules_client/tests/lib';
|
||||
import { RecoveredActionGroup } from '../../../../../common';
|
||||
import { formatLegacyActions } from '../../../../rules_client/lib';
|
||||
import { ConnectorAdapterRegistry } from '../../../../connector_adapters/connector_adapter_registry';
|
||||
import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects';
|
||||
import { backfillClientMock } from '../../../../backfill_client/backfill_client.mock';
|
||||
|
||||
jest.mock('../lib/siem_legacy_actions/format_legacy_actions', () => {
|
||||
jest.mock('../../../../rules_client/lib/siem_legacy_actions/format_legacy_actions', () => {
|
||||
return {
|
||||
formatLegacyActions: jest.fn(),
|
||||
};
|
||||
|
@ -91,6 +91,10 @@ describe('get()', () => {
|
|||
params: {
|
||||
bar: true,
|
||||
},
|
||||
executionStatus: {
|
||||
status: 'unknown',
|
||||
lastExecutionDate: new Date('2020-08-20T19:23:38Z'),
|
||||
},
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
actions: [
|
||||
|
@ -128,6 +132,10 @@ describe('get()', () => {
|
|||
],
|
||||
"alertTypeId": "123",
|
||||
"createdAt": 2019-02-12T21:01:22.479Z,
|
||||
"executionStatus": Object {
|
||||
"lastExecutionDate": 2020-08-20T19:23:38.000Z,
|
||||
"status": "unknown",
|
||||
},
|
||||
"id": "1",
|
||||
"notifyWhen": "onActiveAlert",
|
||||
"params": Object {
|
||||
|
@ -143,11 +151,12 @@ describe('get()', () => {
|
|||
`);
|
||||
expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledTimes(1);
|
||||
expect(unsecuredSavedObjectsClient.get.mock.calls[0]).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"alert",
|
||||
"1",
|
||||
]
|
||||
`);
|
||||
Array [
|
||||
"alert",
|
||||
"1",
|
||||
undefined,
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test('gets rule with actions using preconfigured connectors', async () => {
|
||||
|
@ -161,6 +170,10 @@ describe('get()', () => {
|
|||
params: {
|
||||
bar: true,
|
||||
},
|
||||
executionStatus: {
|
||||
status: 'unknown',
|
||||
lastExecutionDate: new Date('2020-08-20T19:23:38Z'),
|
||||
},
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
actions: [
|
||||
|
@ -214,6 +227,10 @@ describe('get()', () => {
|
|||
],
|
||||
"alertTypeId": "123",
|
||||
"createdAt": 2019-02-12T21:01:22.479Z,
|
||||
"executionStatus": Object {
|
||||
"lastExecutionDate": 2020-08-20T19:23:38.000Z,
|
||||
"status": "unknown",
|
||||
},
|
||||
"id": "1",
|
||||
"notifyWhen": "onActiveAlert",
|
||||
"params": Object {
|
||||
|
@ -229,11 +246,12 @@ describe('get()', () => {
|
|||
`);
|
||||
expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledTimes(1);
|
||||
expect(unsecuredSavedObjectsClient.get.mock.calls[0]).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"alert",
|
||||
"1",
|
||||
]
|
||||
`);
|
||||
Array [
|
||||
"alert",
|
||||
"1",
|
||||
undefined,
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test('gets rule with actions using system connectors', async () => {
|
||||
|
@ -247,6 +265,10 @@ describe('get()', () => {
|
|||
params: {
|
||||
bar: true,
|
||||
},
|
||||
executionStatus: {
|
||||
status: 'unknown',
|
||||
lastExecutionDate: new Date('2020-08-20T19:23:38Z'),
|
||||
},
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
actions: [
|
||||
|
@ -289,6 +311,10 @@ describe('get()', () => {
|
|||
],
|
||||
"alertTypeId": "123",
|
||||
"createdAt": 2019-02-12T21:01:22.479Z,
|
||||
"executionStatus": Object {
|
||||
"lastExecutionDate": 2020-08-20T19:23:38.000Z,
|
||||
"status": "unknown",
|
||||
},
|
||||
"id": "1",
|
||||
"notifyWhen": "onActiveAlert",
|
||||
"params": Object {
|
||||
|
@ -311,11 +337,12 @@ describe('get()', () => {
|
|||
`);
|
||||
expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledTimes(1);
|
||||
expect(unsecuredSavedObjectsClient.get.mock.calls[0]).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"alert",
|
||||
"1",
|
||||
]
|
||||
`);
|
||||
Array [
|
||||
"alert",
|
||||
"1",
|
||||
undefined,
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test('should call useSavedObjectReferences.injectReferences if defined for rule type', async () => {
|
||||
|
@ -356,6 +383,10 @@ describe('get()', () => {
|
|||
bar: true,
|
||||
parameterThatIsSavedObjectRef: 'soRef_0',
|
||||
},
|
||||
executionStatus: {
|
||||
status: 'unknown',
|
||||
lastExecutionDate: new Date('2020-08-20T19:23:38Z'),
|
||||
},
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
actions: [
|
||||
|
@ -406,6 +437,10 @@ describe('get()', () => {
|
|||
],
|
||||
"alertTypeId": "123",
|
||||
"createdAt": 2019-02-12T21:01:22.479Z,
|
||||
"executionStatus": Object {
|
||||
"lastExecutionDate": 2020-08-20T19:23:38.000Z,
|
||||
"status": "unknown",
|
||||
},
|
||||
"id": "1",
|
||||
"notifyWhen": "onActiveAlert",
|
||||
"params": Object {
|
||||
|
@ -487,6 +522,10 @@ describe('get()', () => {
|
|||
bar: true,
|
||||
parameterThatIsSavedObjectRef: 'soRef_0',
|
||||
},
|
||||
executionStatus: {
|
||||
status: 'unknown',
|
||||
lastExecutionDate: new Date('2020-08-20T19:23:38Z'),
|
||||
},
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
actions: [
|
||||
|
@ -530,6 +569,10 @@ describe('get()', () => {
|
|||
params: {
|
||||
bar: true,
|
||||
},
|
||||
executionStatus: {
|
||||
status: 'unknown',
|
||||
lastExecutionDate: new Date('2020-08-20T19:23:38Z'),
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
group: 'default',
|
||||
|
@ -592,6 +635,10 @@ describe('get()', () => {
|
|||
params: {
|
||||
bar: true,
|
||||
},
|
||||
executionStatus: {
|
||||
status: 'unknown',
|
||||
lastExecutionDate: new Date('2020-08-20T19:23:38Z'),
|
||||
},
|
||||
actions: [],
|
||||
},
|
||||
references: [],
|
||||
|
@ -648,6 +695,10 @@ describe('get()', () => {
|
|||
params: {
|
||||
bar: true,
|
||||
},
|
||||
executionStatus: {
|
||||
status: 'unknown',
|
||||
lastExecutionDate: new Date('2020-08-20T19:23:38Z'),
|
||||
},
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
actions: [
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* 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 Boom from '@hapi/boom';
|
||||
import { AlertConsumers } from '@kbn/rule-data-utils';
|
||||
import {
|
||||
SanitizedRule,
|
||||
SanitizedRuleWithLegacyId,
|
||||
Rule as DeprecatedRule,
|
||||
} from '../../../../types';
|
||||
import { ReadOperations, AlertingAuthorizationEntity } from '../../../../authorization';
|
||||
import { ruleAuditEvent, RuleAuditAction } from '../../../../rules_client/common/audit_events';
|
||||
import { RulesClientContext } from '../../../../rules_client/types';
|
||||
import { formatLegacyActions } from '../../../../rules_client/lib';
|
||||
import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects';
|
||||
import { GetRuleParams } from './types';
|
||||
import { getRuleParamsSchema } from './schemas';
|
||||
import { getRuleSo } from '../../../../data/rule';
|
||||
import { transformRuleAttributesToRuleDomain, transformRuleDomainToRule } from '../../transforms';
|
||||
import { RuleParams } from '../../types';
|
||||
import { ruleDomainSchema } from '../../schemas';
|
||||
|
||||
export async function getRule<Params extends RuleParams = never>(
|
||||
context: RulesClientContext,
|
||||
params: GetRuleParams
|
||||
): Promise<SanitizedRule<Params> | SanitizedRuleWithLegacyId<Params>> {
|
||||
const {
|
||||
id,
|
||||
includeLegacyId = false,
|
||||
includeSnoozeData = false,
|
||||
excludeFromPublicApi = false,
|
||||
} = params;
|
||||
|
||||
try {
|
||||
getRuleParamsSchema.validate(params);
|
||||
} catch (error) {
|
||||
throw Boom.badRequest(`Error validating get data - ${error.message}`);
|
||||
}
|
||||
|
||||
const result = await getRuleSo({
|
||||
savedObjectsClient: context.unsecuredSavedObjectsClient,
|
||||
id,
|
||||
});
|
||||
|
||||
try {
|
||||
await context.authorization.ensureAuthorized({
|
||||
ruleTypeId: result.attributes.alertTypeId,
|
||||
consumer: result.attributes.consumer,
|
||||
operation: ReadOperations.Get,
|
||||
entity: AlertingAuthorizationEntity.Rule,
|
||||
});
|
||||
} catch (error) {
|
||||
context.auditLogger?.log(
|
||||
ruleAuditEvent({
|
||||
action: RuleAuditAction.GET,
|
||||
savedObject: { type: RULE_SAVED_OBJECT_TYPE, id },
|
||||
error,
|
||||
})
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
context.auditLogger?.log(
|
||||
ruleAuditEvent({
|
||||
action: RuleAuditAction.GET,
|
||||
savedObject: { type: RULE_SAVED_OBJECT_TYPE, id },
|
||||
})
|
||||
);
|
||||
|
||||
const ruleType = context.ruleTypeRegistry.get(result.attributes.alertTypeId);
|
||||
|
||||
const ruleDomain = transformRuleAttributesToRuleDomain<Params>(
|
||||
result.attributes,
|
||||
{
|
||||
id: result.id,
|
||||
logger: context.logger,
|
||||
ruleType,
|
||||
references: result.references,
|
||||
includeSnoozeData,
|
||||
},
|
||||
context.isSystemAction
|
||||
);
|
||||
|
||||
// Try to validate created rule, but don't throw.
|
||||
try {
|
||||
ruleDomainSchema.validate(ruleDomain);
|
||||
} catch (e) {
|
||||
context.logger.warn(`Error validating get rule domain object for id: ${id}, ${e}`);
|
||||
}
|
||||
|
||||
// Convert domain rule to rule (Remove certain properties)
|
||||
const rule = transformRuleDomainToRule<Params>(ruleDomain, {
|
||||
isPublic: excludeFromPublicApi,
|
||||
includeLegacyId,
|
||||
});
|
||||
|
||||
// format legacy actions for SIEM rules
|
||||
if (result.attributes.consumer === AlertConsumers.SIEM) {
|
||||
const [migratedRule] = await formatLegacyActions([rule as DeprecatedRule], {
|
||||
savedObjectsClient: context.unsecuredSavedObjectsClient,
|
||||
logger: context.logger,
|
||||
});
|
||||
|
||||
return migratedRule;
|
||||
}
|
||||
|
||||
// TODO (http-versioning): Remove this cast, this enables us to move forward
|
||||
// without fixing all of other solution types
|
||||
return rule as SanitizedRule<Params>;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* 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 type { GetRuleParams } from './types';
|
||||
export { getRule } from './get_rule';
|
|
@ -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.
|
||||
*/
|
||||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
|
||||
export const getRuleParamsSchema = schema.object({
|
||||
id: schema.string(),
|
||||
includeLegacyId: schema.maybe(schema.boolean()),
|
||||
includeSnoozeData: schema.maybe(schema.boolean()),
|
||||
excludeFromPublicApi: schema.maybe(schema.boolean()),
|
||||
});
|
|
@ -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 './get_rule_params_schema';
|
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* 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 { TypeOf } from '@kbn/config-schema';
|
||||
import { getRuleParamsSchema } from '../schemas';
|
||||
|
||||
export type GetRuleParams = TypeOf<typeof getRuleParamsSchema>;
|
|
@ -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 './get_rule_params';
|
|
@ -174,6 +174,7 @@ export const ruleDomainSchema = schema.object({
|
|||
running: schema.maybe(schema.nullable(schema.boolean())),
|
||||
viewInAppRelativeUrl: schema.maybe(schema.nullable(schema.string())),
|
||||
alertDelay: schema.maybe(alertDelaySchema),
|
||||
legacyId: schema.maybe(schema.nullable(schema.string())),
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -213,4 +214,5 @@ export const ruleSchema = schema.object({
|
|||
running: schema.maybe(schema.nullable(schema.boolean())),
|
||||
viewInAppRelativeUrl: schema.maybe(schema.nullable(schema.string())),
|
||||
alertDelay: schema.maybe(alertDelaySchema),
|
||||
legacyId: schema.maybe(schema.nullable(schema.string())),
|
||||
});
|
||||
|
|
|
@ -10,7 +10,7 @@ import { SavedObjectReference } from '@kbn/core/server';
|
|||
import { ruleExecutionStatusValues } from '../constants';
|
||||
import { getRuleSnoozeEndTime } from '../../../lib';
|
||||
import { RuleDomain, Monitoring, RuleParams } from '../types';
|
||||
import { RuleAttributes } from '../../../data/rule/types';
|
||||
import { RuleAttributes, RuleExecutionStatusAttributes } from '../../../data/rule/types';
|
||||
import { PartialRule } from '../../../types';
|
||||
import { UntypedNormalizedRuleType } from '../../../rule_type_registry';
|
||||
import { injectReferencesIntoParams } from '../../../rules_client/common';
|
||||
|
@ -32,7 +32,7 @@ const INITIAL_LAST_RUN_METRICS = {
|
|||
const transformEsExecutionStatus = (
|
||||
logger: Logger,
|
||||
ruleId: string,
|
||||
esRuleExecutionStatus: RuleAttributes['executionStatus']
|
||||
esRuleExecutionStatus: RuleExecutionStatusAttributes
|
||||
): RuleDomain['executionStatus'] => {
|
||||
const {
|
||||
lastExecutionDate,
|
||||
|
@ -204,7 +204,9 @@ export const transformRuleAttributesToRuleDomain = <Params extends RuleParams =
|
|||
muteAll: esRule.muteAll,
|
||||
notifyWhen: esRule.notifyWhen,
|
||||
mutedInstanceIds: esRule.mutedInstanceIds,
|
||||
executionStatus: transformEsExecutionStatus(logger, id, executionStatus),
|
||||
...(executionStatus
|
||||
? { executionStatus: transformEsExecutionStatus(logger, id, executionStatus) }
|
||||
: {}),
|
||||
...(monitoring ? { monitoring: transformEsMonitoring(logger, id, monitoring) } : {}),
|
||||
snoozeSchedule: snoozeScheduleDates ?? [],
|
||||
...(includeSnoozeData
|
||||
|
@ -229,6 +231,7 @@ export const transformRuleAttributesToRuleDomain = <Params extends RuleParams =
|
|||
revision: esRule.revision,
|
||||
running: esRule.running,
|
||||
...(esRule.alertDelay ? { alertDelay: esRule.alertDelay } : {}),
|
||||
...(esRule.legacyId !== undefined ? { legacyId: esRule.legacyId } : {}),
|
||||
};
|
||||
|
||||
// Bad casts, but will fix once we fix all rule types
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* 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 { transformRuleDomainToRule } from './transform_rule_domain_to_rule';
|
||||
import { RuleDomain } from '../types';
|
||||
|
||||
describe('transformRuleDomainToRule', () => {
|
||||
const MOCK_API_KEY = Buffer.from('123:abc').toString('base64');
|
||||
const defaultAction = {
|
||||
uuid: '1',
|
||||
group: 'default',
|
||||
id: '1',
|
||||
actionTypeId: '.test',
|
||||
params: {},
|
||||
frequency: {
|
||||
summary: false,
|
||||
notifyWhen: 'onThrottleInterval' as const,
|
||||
throttle: '1m',
|
||||
},
|
||||
alertsFilter: {
|
||||
query: {
|
||||
kql: 'test:1',
|
||||
dsl: '{}',
|
||||
filters: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const systemAction = {
|
||||
id: '2',
|
||||
uuid: '123',
|
||||
actionTypeId: '.test-system-action',
|
||||
params: {},
|
||||
};
|
||||
|
||||
const rule: RuleDomain<{}> = {
|
||||
id: 'test',
|
||||
enabled: false,
|
||||
name: 'my rule name',
|
||||
tags: ['foo'],
|
||||
alertTypeId: 'myType',
|
||||
consumer: 'myApp',
|
||||
schedule: { interval: '1m' },
|
||||
actions: [defaultAction],
|
||||
systemActions: [systemAction],
|
||||
params: {},
|
||||
mapped_params: {},
|
||||
createdBy: 'user',
|
||||
createdAt: new Date('2019-02-12T21:01:22.479Z'),
|
||||
updatedAt: new Date('2019-02-12T21:01:22.479Z'),
|
||||
legacyId: 'legacyId',
|
||||
muteAll: false,
|
||||
mutedInstanceIds: [],
|
||||
snoozeSchedule: [],
|
||||
scheduledTaskId: 'task-123',
|
||||
executionStatus: {
|
||||
lastExecutionDate: new Date('2019-02-12T21:01:22.479Z'),
|
||||
status: 'pending' as const,
|
||||
},
|
||||
throttle: null,
|
||||
notifyWhen: null,
|
||||
revision: 0,
|
||||
updatedBy: 'user',
|
||||
apiKey: MOCK_API_KEY,
|
||||
apiKeyOwner: 'user',
|
||||
};
|
||||
|
||||
it('should transform rule domain to rule', () => {
|
||||
const result = transformRuleDomainToRule(rule);
|
||||
|
||||
expect(result).toEqual({
|
||||
id: 'test',
|
||||
enabled: false,
|
||||
name: 'my rule name',
|
||||
tags: ['foo'],
|
||||
alertTypeId: 'myType',
|
||||
consumer: 'myApp',
|
||||
schedule: { interval: '1m' },
|
||||
actions: [defaultAction],
|
||||
systemActions: [systemAction],
|
||||
params: {},
|
||||
mapped_params: {},
|
||||
createdBy: 'user',
|
||||
createdAt: new Date('2019-02-12T21:01:22.479Z'),
|
||||
updatedAt: new Date('2019-02-12T21:01:22.479Z'),
|
||||
muteAll: false,
|
||||
mutedInstanceIds: [],
|
||||
snoozeSchedule: [],
|
||||
scheduledTaskId: 'task-123',
|
||||
executionStatus: {
|
||||
lastExecutionDate: new Date('2019-02-12T21:01:22.479Z'),
|
||||
status: 'pending' as const,
|
||||
},
|
||||
throttle: null,
|
||||
notifyWhen: null,
|
||||
revision: 0,
|
||||
updatedBy: 'user',
|
||||
apiKeyOwner: 'user',
|
||||
});
|
||||
});
|
||||
|
||||
it('should remove public fields if isPublic is true', () => {
|
||||
const result = transformRuleDomainToRule(rule, {
|
||||
isPublic: true,
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
id: 'test',
|
||||
enabled: false,
|
||||
name: 'my rule name',
|
||||
tags: ['foo'],
|
||||
alertTypeId: 'myType',
|
||||
consumer: 'myApp',
|
||||
schedule: { interval: '1m' },
|
||||
actions: [defaultAction],
|
||||
systemActions: [systemAction],
|
||||
params: {},
|
||||
mapped_params: {},
|
||||
createdBy: 'user',
|
||||
createdAt: new Date('2019-02-12T21:01:22.479Z'),
|
||||
updatedAt: new Date('2019-02-12T21:01:22.479Z'),
|
||||
muteAll: false,
|
||||
mutedInstanceIds: [],
|
||||
scheduledTaskId: 'task-123',
|
||||
executionStatus: {
|
||||
lastExecutionDate: new Date('2019-02-12T21:01:22.479Z'),
|
||||
status: 'pending' as const,
|
||||
},
|
||||
throttle: null,
|
||||
notifyWhen: null,
|
||||
revision: 0,
|
||||
updatedBy: 'user',
|
||||
apiKeyOwner: 'user',
|
||||
});
|
||||
});
|
||||
|
||||
it('should include legacy id if includeLegacyId is true', () => {
|
||||
const result = transformRuleDomainToRule(rule, {
|
||||
includeLegacyId: true,
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
id: 'test',
|
||||
enabled: false,
|
||||
name: 'my rule name',
|
||||
tags: ['foo'],
|
||||
alertTypeId: 'myType',
|
||||
consumer: 'myApp',
|
||||
schedule: { interval: '1m' },
|
||||
legacyId: 'legacyId',
|
||||
actions: [defaultAction],
|
||||
systemActions: [systemAction],
|
||||
params: {},
|
||||
mapped_params: {},
|
||||
createdBy: 'user',
|
||||
createdAt: new Date('2019-02-12T21:01:22.479Z'),
|
||||
updatedAt: new Date('2019-02-12T21:01:22.479Z'),
|
||||
muteAll: false,
|
||||
mutedInstanceIds: [],
|
||||
snoozeSchedule: [],
|
||||
scheduledTaskId: 'task-123',
|
||||
executionStatus: {
|
||||
lastExecutionDate: new Date('2019-02-12T21:01:22.479Z'),
|
||||
status: 'pending' as const,
|
||||
},
|
||||
throttle: null,
|
||||
notifyWhen: null,
|
||||
revision: 0,
|
||||
updatedBy: 'user',
|
||||
apiKeyOwner: 'user',
|
||||
});
|
||||
});
|
||||
});
|
|
@ -9,13 +9,14 @@ import { RuleDomain, Rule, RuleParams } from '../types';
|
|||
|
||||
interface TransformRuleDomainToRuleOptions {
|
||||
isPublic?: boolean;
|
||||
includeLegacyId?: boolean;
|
||||
}
|
||||
|
||||
export const transformRuleDomainToRule = <Params extends RuleParams = never>(
|
||||
ruleDomain: RuleDomain<Params>,
|
||||
options?: TransformRuleDomainToRuleOptions
|
||||
): Rule<Params> => {
|
||||
const { isPublic = false } = options || {};
|
||||
const { isPublic = false, includeLegacyId = false } = options || {};
|
||||
|
||||
const rule: Rule<Params> = {
|
||||
id: ruleDomain.id,
|
||||
|
@ -51,6 +52,7 @@ export const transformRuleDomainToRule = <Params extends RuleParams = never>(
|
|||
running: ruleDomain.running,
|
||||
viewInAppRelativeUrl: ruleDomain.viewInAppRelativeUrl,
|
||||
alertDelay: ruleDomain.alertDelay,
|
||||
legacyId: ruleDomain.legacyId,
|
||||
};
|
||||
|
||||
if (isPublic) {
|
||||
|
@ -61,6 +63,10 @@ export const transformRuleDomainToRule = <Params extends RuleParams = never>(
|
|||
delete rule.viewInAppRelativeUrl;
|
||||
}
|
||||
|
||||
if (!includeLegacyId) {
|
||||
delete rule.legacyId;
|
||||
}
|
||||
|
||||
// Remove all undefined keys to clean up the object
|
||||
type RuleKeys = keyof Rule;
|
||||
for (const key in rule) {
|
||||
|
|
|
@ -53,17 +53,23 @@ export const transformRuleDomainToRuleAttributes = ({
|
|||
muteAll: rule.muteAll,
|
||||
mutedInstanceIds: rule.mutedInstanceIds,
|
||||
...(meta ? { meta } : {}),
|
||||
executionStatus: {
|
||||
status: rule.executionStatus.status,
|
||||
lastExecutionDate: rule.executionStatus.lastExecutionDate.toISOString(),
|
||||
...(rule.executionStatus.lastDuration
|
||||
? { lastDuration: rule.executionStatus.lastDuration }
|
||||
: {}),
|
||||
...(rule.executionStatus.error !== undefined ? { error: rule.executionStatus.error } : {}),
|
||||
...(rule.executionStatus.warning !== undefined
|
||||
? { warning: rule.executionStatus.warning }
|
||||
: {}),
|
||||
},
|
||||
...(rule.executionStatus
|
||||
? {
|
||||
executionStatus: {
|
||||
status: rule.executionStatus.status,
|
||||
lastExecutionDate: rule.executionStatus.lastExecutionDate.toISOString(),
|
||||
...(rule.executionStatus.lastDuration
|
||||
? { lastDuration: rule.executionStatus.lastDuration }
|
||||
: {}),
|
||||
...(rule.executionStatus.error !== undefined
|
||||
? { error: rule.executionStatus.error }
|
||||
: {}),
|
||||
...(rule.executionStatus.warning !== undefined
|
||||
? { warning: rule.executionStatus.warning }
|
||||
: {}),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
...(rule.monitoring ? { monitoring: rule.monitoring } : {}),
|
||||
...(rule.snoozeSchedule ? { snoozeSchedule: rule.snoozeSchedule } : {}),
|
||||
...(rule.isSnoozedUntil !== undefined
|
||||
|
|
|
@ -72,7 +72,7 @@ export interface Rule<Params extends RuleParams = never> {
|
|||
muteAll: RuleSchemaType['muteAll'];
|
||||
notifyWhen?: RuleSchemaType['notifyWhen'];
|
||||
mutedInstanceIds: RuleSchemaType['mutedInstanceIds'];
|
||||
executionStatus: RuleExecutionStatus;
|
||||
executionStatus?: RuleExecutionStatus;
|
||||
monitoring?: RuleSchemaType['monitoring'];
|
||||
snoozeSchedule?: RuleSchemaType['snoozeSchedule'];
|
||||
activeSnoozes?: RuleSchemaType['activeSnoozes'];
|
||||
|
@ -83,6 +83,7 @@ export interface Rule<Params extends RuleParams = never> {
|
|||
running?: RuleSchemaType['running'];
|
||||
viewInAppRelativeUrl?: RuleSchemaType['viewInAppRelativeUrl'];
|
||||
alertDelay?: RuleSchemaType['alertDelay'];
|
||||
legacyId?: RuleSchemaType['legacyId'];
|
||||
}
|
||||
|
||||
export interface RuleDomain<Params extends RuleParams = never> {
|
||||
|
@ -109,7 +110,7 @@ export interface RuleDomain<Params extends RuleParams = never> {
|
|||
muteAll: RuleDomainSchemaType['muteAll'];
|
||||
notifyWhen?: RuleDomainSchemaType['notifyWhen'];
|
||||
mutedInstanceIds: RuleDomainSchemaType['mutedInstanceIds'];
|
||||
executionStatus: RuleExecutionStatus;
|
||||
executionStatus?: RuleExecutionStatus;
|
||||
monitoring?: RuleDomainSchemaType['monitoring'];
|
||||
snoozeSchedule?: RuleDomainSchemaType['snoozeSchedule'];
|
||||
activeSnoozes?: RuleDomainSchemaType['activeSnoozes'];
|
||||
|
@ -120,4 +121,5 @@ export interface RuleDomain<Params extends RuleParams = never> {
|
|||
running?: RuleDomainSchemaType['running'];
|
||||
viewInAppRelativeUrl?: RuleDomainSchemaType['viewInAppRelativeUrl'];
|
||||
alertDelay?: RuleSchemaType['alertDelay'];
|
||||
legacyId?: RuleSchemaType['legacyId'];
|
||||
}
|
||||
|
|
|
@ -171,7 +171,7 @@ export interface RuleAttributes {
|
|||
muteAll: boolean;
|
||||
mutedInstanceIds: string[];
|
||||
meta?: RuleMetaAttributes;
|
||||
executionStatus: RuleExecutionStatusAttributes;
|
||||
executionStatus?: RuleExecutionStatusAttributes;
|
||||
monitoring?: RuleMonitoringAttributes;
|
||||
snoozeSchedule?: RuleSnoozeScheduleAttributes[];
|
||||
isSnoozedUntil?: string | null;
|
||||
|
|
|
@ -1,129 +0,0 @@
|
|||
/*
|
||||
* 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 { omit } from 'lodash';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { IRouter } from '@kbn/core/server';
|
||||
import { ILicenseState } from '../lib';
|
||||
import { verifyAccessAndContext, rewriteRuleLastRun } from './lib';
|
||||
import {
|
||||
RuleTypeParams,
|
||||
AlertingRequestHandlerContext,
|
||||
BASE_ALERTING_API_PATH,
|
||||
INTERNAL_BASE_ALERTING_API_PATH,
|
||||
SanitizedRule,
|
||||
} from '../types';
|
||||
import { transformRuleActions } from './rule/transforms';
|
||||
|
||||
const paramSchema = schema.object({
|
||||
id: schema.string(),
|
||||
});
|
||||
|
||||
const rewriteBodyRes = ({
|
||||
alertTypeId,
|
||||
createdBy,
|
||||
updatedBy,
|
||||
createdAt,
|
||||
updatedAt,
|
||||
apiKeyOwner,
|
||||
apiKeyCreatedByUser,
|
||||
notifyWhen,
|
||||
muteAll,
|
||||
mutedInstanceIds,
|
||||
executionStatus,
|
||||
actions,
|
||||
systemActions,
|
||||
scheduledTaskId,
|
||||
snoozeSchedule,
|
||||
isSnoozedUntil,
|
||||
lastRun,
|
||||
nextRun,
|
||||
viewInAppRelativeUrl,
|
||||
...rest
|
||||
}: SanitizedRule<RuleTypeParams>) => ({
|
||||
...rest,
|
||||
rule_type_id: alertTypeId,
|
||||
created_by: createdBy,
|
||||
updated_by: updatedBy,
|
||||
created_at: createdAt,
|
||||
updated_at: updatedAt,
|
||||
api_key_owner: apiKeyOwner,
|
||||
notify_when: notifyWhen,
|
||||
muted_alert_ids: mutedInstanceIds,
|
||||
mute_all: muteAll,
|
||||
...(isSnoozedUntil !== undefined ? { is_snoozed_until: isSnoozedUntil } : {}),
|
||||
snooze_schedule: snoozeSchedule,
|
||||
scheduled_task_id: scheduledTaskId,
|
||||
execution_status: executionStatus && {
|
||||
...omit(executionStatus, 'lastExecutionDate', 'lastDuration'),
|
||||
last_execution_date: executionStatus.lastExecutionDate,
|
||||
last_duration: executionStatus.lastDuration,
|
||||
},
|
||||
actions: transformRuleActions(actions, systemActions),
|
||||
...(lastRun ? { last_run: rewriteRuleLastRun(lastRun) } : {}),
|
||||
...(nextRun ? { next_run: nextRun } : {}),
|
||||
...(viewInAppRelativeUrl ? { view_in_app_relative_url: viewInAppRelativeUrl } : {}),
|
||||
...(apiKeyCreatedByUser !== undefined ? { api_key_created_by_user: apiKeyCreatedByUser } : {}),
|
||||
});
|
||||
|
||||
interface BuildGetRulesRouteParams {
|
||||
licenseState: ILicenseState;
|
||||
path: string;
|
||||
router: IRouter<AlertingRequestHandlerContext>;
|
||||
excludeFromPublicApi?: boolean;
|
||||
}
|
||||
const buildGetRuleRoute = ({
|
||||
licenseState,
|
||||
path,
|
||||
router,
|
||||
excludeFromPublicApi = false,
|
||||
}: BuildGetRulesRouteParams) => {
|
||||
router.get(
|
||||
{
|
||||
path,
|
||||
validate: {
|
||||
params: paramSchema,
|
||||
},
|
||||
},
|
||||
router.handleLegacyErrors(
|
||||
verifyAccessAndContext(licenseState, async function (context, req, res) {
|
||||
const rulesClient = (await context.alerting).getRulesClient();
|
||||
const { id } = req.params;
|
||||
const rule = await rulesClient.get({
|
||||
id,
|
||||
excludeFromPublicApi,
|
||||
includeSnoozeData: true,
|
||||
});
|
||||
return res.ok({
|
||||
body: rewriteBodyRes(rule),
|
||||
});
|
||||
})
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export const getRuleRoute = (
|
||||
router: IRouter<AlertingRequestHandlerContext>,
|
||||
licenseState: ILicenseState
|
||||
) =>
|
||||
buildGetRuleRoute({
|
||||
excludeFromPublicApi: true,
|
||||
licenseState,
|
||||
path: `${BASE_ALERTING_API_PATH}/rule/{id}`,
|
||||
router,
|
||||
});
|
||||
|
||||
export const getInternalRuleRoute = (
|
||||
router: IRouter<AlertingRequestHandlerContext>,
|
||||
licenseState: ILicenseState
|
||||
) =>
|
||||
buildGetRuleRoute({
|
||||
excludeFromPublicApi: false,
|
||||
licenseState,
|
||||
path: `${INTERNAL_BASE_ALERTING_API_PATH}/rule/{id}`,
|
||||
router,
|
||||
});
|
|
@ -14,7 +14,7 @@ import { GetAlertIndicesAlias, ILicenseState } from '../lib';
|
|||
import { defineLegacyRoutes } from './legacy';
|
||||
import { AlertingRequestHandlerContext } from '../types';
|
||||
import { createRuleRoute } from './rule/apis/create';
|
||||
import { getRuleRoute, getInternalRuleRoute } from './get_rule';
|
||||
import { getRuleRoute, getInternalRuleRoute } from './rule/apis/get/get_rule_route';
|
||||
import { updateRuleRoute } from './rule/apis/update/update_rule_route';
|
||||
import { deleteRuleRoute } from './delete_rule';
|
||||
import { aggregateRulesRoute } from './rule/apis/aggregate/aggregate_rules_route';
|
||||
|
|
|
@ -6,16 +6,16 @@
|
|||
*/
|
||||
|
||||
import { pick } from 'lodash';
|
||||
import { getRuleRoute } from './get_rule';
|
||||
import { getRuleRoute } from './get_rule_route';
|
||||
import { httpServiceMock } from '@kbn/core/server/mocks';
|
||||
import { licenseStateMock } from '../lib/license_state.mock';
|
||||
import { verifyApiAccess } from '../lib/license_api_access';
|
||||
import { mockHandlerArguments } from './_mock_handler_arguments';
|
||||
import { rulesClientMock } from '../rules_client.mock';
|
||||
import { RuleAction, RuleSystemAction, SanitizedRule } from '../types';
|
||||
import { licenseStateMock } from '../../../../lib/license_state.mock';
|
||||
import { verifyApiAccess } from '../../../../lib/license_api_access';
|
||||
import { mockHandlerArguments } from '../../../_mock_handler_arguments';
|
||||
import { rulesClientMock } from '../../../../rules_client.mock';
|
||||
import { RuleAction, RuleSystemAction, SanitizedRule } from '../../../../types';
|
||||
|
||||
const rulesClient = rulesClientMock.create();
|
||||
jest.mock('../lib/license_api_access', () => ({
|
||||
jest.mock('../../../../lib/license_api_access', () => ({
|
||||
verifyApiAccess: jest.fn(),
|
||||
}));
|
||||
|
||||
|
@ -64,8 +64,8 @@ describe('getRuleRoute', () => {
|
|||
params: {
|
||||
bar: true,
|
||||
},
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
createdAt: new Date('2020-08-20T19:23:38Z'),
|
||||
updatedAt: new Date('2020-08-20T19:23:38Z'),
|
||||
actions: [action],
|
||||
consumer: 'bar',
|
||||
name: 'abc',
|
||||
|
@ -95,13 +95,13 @@ describe('getRuleRoute', () => {
|
|||
updated_by: mockedAlert.updatedBy,
|
||||
api_key_owner: mockedAlert.apiKeyOwner,
|
||||
muted_alert_ids: mockedAlert.mutedInstanceIds,
|
||||
created_at: mockedAlert.createdAt,
|
||||
updated_at: mockedAlert.updatedAt,
|
||||
created_at: mockedAlert.createdAt.toISOString(),
|
||||
updated_at: mockedAlert.updatedAt.toISOString(),
|
||||
id: mockedAlert.id,
|
||||
revision: mockedAlert.revision,
|
||||
execution_status: {
|
||||
status: mockedAlert.executionStatus.status,
|
||||
last_execution_date: mockedAlert.executionStatus.lastExecutionDate,
|
||||
last_execution_date: mockedAlert.executionStatus.lastExecutionDate.toISOString(),
|
||||
},
|
||||
actions: [
|
||||
{
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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 '@kbn/core/server';
|
||||
import { ILicenseState } from '../../../../lib';
|
||||
import { verifyAccessAndContext } from '../../../lib';
|
||||
import type { RuleParamsV1 } from '../../../../../common/routes/rule/response';
|
||||
import { Rule } from '../../../../application/rule/types';
|
||||
import {
|
||||
AlertingRequestHandlerContext,
|
||||
BASE_ALERTING_API_PATH,
|
||||
INTERNAL_BASE_ALERTING_API_PATH,
|
||||
} from '../../../../types';
|
||||
import { transformRuleToRuleResponseV1 } from '../../transforms';
|
||||
|
||||
import type {
|
||||
GetRuleRequestParamsV1,
|
||||
GetRuleResponseV1,
|
||||
} from '../../../../../common/routes/rule/apis/get';
|
||||
import { getRuleRequestParamsSchemaV1 } from '../../../../../common/routes/rule/apis/get';
|
||||
|
||||
interface BuildGetRulesRouteParams {
|
||||
licenseState: ILicenseState;
|
||||
path: string;
|
||||
router: IRouter<AlertingRequestHandlerContext>;
|
||||
excludeFromPublicApi?: boolean;
|
||||
}
|
||||
const buildGetRuleRoute = ({
|
||||
licenseState,
|
||||
path,
|
||||
router,
|
||||
excludeFromPublicApi = false,
|
||||
}: BuildGetRulesRouteParams) => {
|
||||
router.get(
|
||||
{
|
||||
path,
|
||||
validate: {
|
||||
params: getRuleRequestParamsSchemaV1,
|
||||
},
|
||||
},
|
||||
router.handleLegacyErrors(
|
||||
verifyAccessAndContext(licenseState, async function (context, req, res) {
|
||||
const rulesClient = (await context.alerting).getRulesClient();
|
||||
const params: GetRuleRequestParamsV1 = req.params;
|
||||
|
||||
// TODO (http-versioning): Remove this cast, this enables us to move forward
|
||||
// without fixing all of other solution types
|
||||
const rule: Rule<RuleParamsV1> = (await rulesClient.get({
|
||||
id: params.id,
|
||||
excludeFromPublicApi,
|
||||
includeSnoozeData: true,
|
||||
})) as Rule<RuleParamsV1>;
|
||||
|
||||
const response: GetRuleResponseV1<RuleParamsV1> = {
|
||||
body: transformRuleToRuleResponseV1<RuleParamsV1>(rule),
|
||||
};
|
||||
return res.ok(response);
|
||||
})
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export const getRuleRoute = (
|
||||
router: IRouter<AlertingRequestHandlerContext>,
|
||||
licenseState: ILicenseState
|
||||
) =>
|
||||
buildGetRuleRoute({
|
||||
excludeFromPublicApi: true,
|
||||
licenseState,
|
||||
path: `${BASE_ALERTING_API_PATH}/rule/{id}`,
|
||||
router,
|
||||
});
|
||||
|
||||
export const getInternalRuleRoute = (
|
||||
router: IRouter<AlertingRequestHandlerContext>,
|
||||
licenseState: ILicenseState
|
||||
) =>
|
||||
buildGetRuleRoute({
|
||||
excludeFromPublicApi: false,
|
||||
licenseState,
|
||||
path: `${INTERNAL_BASE_ALERTING_API_PATH}/rule/{id}`,
|
||||
router,
|
||||
});
|
|
@ -102,8 +102,8 @@ describe('resolveRuleRoute', () => {
|
|||
id: mockedRule.id,
|
||||
revision: mockedRule.revision,
|
||||
execution_status: {
|
||||
status: mockedRule.executionStatus.status,
|
||||
last_execution_date: mockedRule.executionStatus.lastExecutionDate.toISOString(),
|
||||
status: mockedRule.executionStatus!.status,
|
||||
last_execution_date: mockedRule.executionStatus!.lastExecutionDate.toISOString(),
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
|
|
|
@ -115,15 +115,19 @@ export const transformRuleToRuleResponse = <Params extends RuleParams = never>(
|
|||
...(rule.notifyWhen !== undefined ? { notify_when: rule.notifyWhen } : {}),
|
||||
muted_alert_ids: rule.mutedInstanceIds,
|
||||
...(rule.scheduledTaskId !== undefined ? { scheduled_task_id: rule.scheduledTaskId } : {}),
|
||||
execution_status: {
|
||||
status: rule.executionStatus.status,
|
||||
...(rule.executionStatus.error ? { error: rule.executionStatus.error } : {}),
|
||||
...(rule.executionStatus.warning ? { warning: rule.executionStatus.warning } : {}),
|
||||
last_execution_date: rule.executionStatus.lastExecutionDate?.toISOString(),
|
||||
...(rule.executionStatus.lastDuration !== undefined
|
||||
? { last_duration: rule.executionStatus.lastDuration }
|
||||
: {}),
|
||||
},
|
||||
...(rule.executionStatus
|
||||
? {
|
||||
execution_status: {
|
||||
status: rule.executionStatus.status,
|
||||
...(rule.executionStatus.error ? { error: rule.executionStatus.error } : {}),
|
||||
...(rule.executionStatus.warning ? { warning: rule.executionStatus.warning } : {}),
|
||||
last_execution_date: rule.executionStatus.lastExecutionDate?.toISOString(),
|
||||
...(rule.executionStatus.lastDuration !== undefined
|
||||
? { last_duration: rule.executionStatus.lastDuration }
|
||||
: {}),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
...(rule.monitoring ? { monitoring: transformMonitoring(rule.monitoring) } : {}),
|
||||
...(rule.snoozeSchedule ? { snooze_schedule: rule.snoozeSchedule } : {}),
|
||||
...(rule.activeSnoozes ? { active_snoozes: rule.activeSnoozes } : {}),
|
||||
|
|
|
@ -1,79 +0,0 @@
|
|||
/*
|
||||
* 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 { AlertConsumers } from '@kbn/rule-data-utils';
|
||||
|
||||
import { RawRule, SanitizedRule, RuleTypeParams, SanitizedRuleWithLegacyId } from '../../types';
|
||||
import { ReadOperations, AlertingAuthorizationEntity } from '../../authorization';
|
||||
import { ruleAuditEvent, RuleAuditAction } from '../common/audit_events';
|
||||
import { getAlertFromRaw } from '../lib/get_alert_from_raw';
|
||||
import { RulesClientContext } from '../types';
|
||||
import { formatLegacyActions } from '../lib';
|
||||
import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects';
|
||||
|
||||
export interface GetParams {
|
||||
id: string;
|
||||
includeLegacyId?: boolean;
|
||||
includeSnoozeData?: boolean;
|
||||
excludeFromPublicApi?: boolean;
|
||||
}
|
||||
|
||||
export async function get<Params extends RuleTypeParams = never>(
|
||||
context: RulesClientContext,
|
||||
{
|
||||
id,
|
||||
includeLegacyId = false,
|
||||
includeSnoozeData = false,
|
||||
excludeFromPublicApi = false,
|
||||
}: GetParams
|
||||
): Promise<SanitizedRule<Params> | SanitizedRuleWithLegacyId<Params>> {
|
||||
const result = await context.unsecuredSavedObjectsClient.get<RawRule>(RULE_SAVED_OBJECT_TYPE, id);
|
||||
try {
|
||||
await context.authorization.ensureAuthorized({
|
||||
ruleTypeId: result.attributes.alertTypeId,
|
||||
consumer: result.attributes.consumer,
|
||||
operation: ReadOperations.Get,
|
||||
entity: AlertingAuthorizationEntity.Rule,
|
||||
});
|
||||
} catch (error) {
|
||||
context.auditLogger?.log(
|
||||
ruleAuditEvent({
|
||||
action: RuleAuditAction.GET,
|
||||
savedObject: { type: RULE_SAVED_OBJECT_TYPE, id },
|
||||
error,
|
||||
})
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
context.auditLogger?.log(
|
||||
ruleAuditEvent({
|
||||
action: RuleAuditAction.GET,
|
||||
savedObject: { type: RULE_SAVED_OBJECT_TYPE, id },
|
||||
})
|
||||
);
|
||||
const rule = getAlertFromRaw<Params>(
|
||||
context,
|
||||
result.id,
|
||||
result.attributes.alertTypeId,
|
||||
result.attributes,
|
||||
result.references,
|
||||
includeLegacyId,
|
||||
excludeFromPublicApi,
|
||||
includeSnoozeData
|
||||
);
|
||||
|
||||
// format legacy actions for SIEM rules
|
||||
if (result.attributes.consumer === AlertConsumers.SIEM) {
|
||||
const [migratedRule] = await formatLegacyActions([rule], {
|
||||
savedObjectsClient: context.unsecuredSavedObjectsClient,
|
||||
logger: context.logger,
|
||||
});
|
||||
|
||||
return migratedRule;
|
||||
}
|
||||
|
||||
return rule;
|
||||
}
|
|
@ -19,7 +19,7 @@ import { IExecutionErrorsResult } from '../../../common';
|
|||
import { formatExecutionErrorsResult } from '../../lib/format_execution_log_errors';
|
||||
import { parseDate } from '../common';
|
||||
import { RulesClientContext } from '../types';
|
||||
import { get } from './get';
|
||||
import { getRule } from '../../application/rule/methods/get/get_rule';
|
||||
import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects';
|
||||
|
||||
const actionErrorLogDefaultFilter =
|
||||
|
@ -41,7 +41,7 @@ export async function getActionErrorLog(
|
|||
{ id, dateStart, dateEnd, filter, page, perPage, sort }: GetActionErrorLogByIdParams
|
||||
): Promise<IExecutionErrorsResult> {
|
||||
context.logger.debug(`getActionErrorLog(): getting action error logs for rule ${id}`);
|
||||
const rule = (await get(context, { id, includeLegacyId: true })) as SanitizedRuleWithLegacyId;
|
||||
const rule = (await getRule(context, { id, includeLegacyId: true })) as SanitizedRuleWithLegacyId;
|
||||
|
||||
try {
|
||||
await context.authorization.ensureAuthorized({
|
||||
|
|
|
@ -10,7 +10,7 @@ import { RuleTaskState } from '../../types';
|
|||
import { taskInstanceToAlertTaskInstance } from '../../task_runner/alert_task_instance';
|
||||
import { ReadOperations, AlertingAuthorizationEntity } from '../../authorization';
|
||||
import { RulesClientContext } from '../types';
|
||||
import { get } from './get';
|
||||
import { getRule } from '../../application/rule/methods/get/get_rule';
|
||||
|
||||
export interface GetAlertStateParams {
|
||||
id: string;
|
||||
|
@ -19,7 +19,7 @@ export async function getAlertState(
|
|||
context: RulesClientContext,
|
||||
{ id }: GetAlertStateParams
|
||||
): Promise<RuleTaskState | void> {
|
||||
const rule = await get(context, { id });
|
||||
const rule = await getRule(context, { id });
|
||||
await context.authorization.ensureAuthorized({
|
||||
ruleTypeId: rule.alertTypeId,
|
||||
consumer: rule.consumer,
|
||||
|
|
|
@ -12,7 +12,7 @@ import { alertSummaryFromEventLog } from '../../lib/alert_summary_from_event_log
|
|||
import { parseDuration } from '../../../common/parse_duration';
|
||||
import { parseDate } from '../common';
|
||||
import { RulesClientContext } from '../types';
|
||||
import { get } from './get';
|
||||
import { getRule } from '../../application/rule/methods/get/get_rule';
|
||||
import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects';
|
||||
|
||||
export interface GetAlertSummaryParams {
|
||||
|
@ -26,7 +26,7 @@ export async function getAlertSummary(
|
|||
{ id, dateStart, numberOfExecutions }: GetAlertSummaryParams
|
||||
): Promise<AlertSummary> {
|
||||
context.logger.debug(`getAlertSummary(): getting alert ${id}`);
|
||||
const rule = (await get(context, { id, includeLegacyId: true })) as SanitizedRuleWithLegacyId;
|
||||
const rule = (await getRule(context, { id, includeLegacyId: true })) as SanitizedRuleWithLegacyId;
|
||||
|
||||
await context.authorization.ensureAuthorized({
|
||||
ruleTypeId: rule.alertTypeId,
|
||||
|
|
|
@ -19,7 +19,7 @@ import {
|
|||
} from '../../lib/get_execution_log_aggregation';
|
||||
import { RulesClientContext } from '../types';
|
||||
import { parseDate } from '../common';
|
||||
import { get } from './get';
|
||||
import { getRule } from '../../application/rule/methods/get/get_rule';
|
||||
import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects';
|
||||
|
||||
export interface GetRuleExecutionKPIParams {
|
||||
|
@ -41,7 +41,7 @@ export async function getRuleExecutionKPI(
|
|||
{ id, dateStart, dateEnd, filter }: GetRuleExecutionKPIParams
|
||||
) {
|
||||
context.logger.debug(`getRuleExecutionKPI(): getting execution KPI for rule ${id}`);
|
||||
const rule = (await get(context, { id, includeLegacyId: true })) as SanitizedRuleWithLegacyId;
|
||||
const rule = (await getRule(context, { id, includeLegacyId: true })) as SanitizedRuleWithLegacyId;
|
||||
|
||||
try {
|
||||
// Make sure user has access to this rule
|
||||
|
|
|
@ -21,7 +21,7 @@ import {
|
|||
import { IExecutionLogResult } from '../../../common';
|
||||
import { parseDate } from '../common';
|
||||
import { RulesClientContext } from '../types';
|
||||
import { get } from './get';
|
||||
import { getRule } from '../../application/rule/methods/get/get_rule';
|
||||
import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects';
|
||||
|
||||
export interface GetExecutionLogByIdParams {
|
||||
|
@ -49,7 +49,7 @@ export async function getExecutionLogForRule(
|
|||
{ id, dateStart, dateEnd, filter, page, perPage, sort }: GetExecutionLogByIdParams
|
||||
): Promise<IExecutionLogResult> {
|
||||
context.logger.debug(`getExecutionLogForRule(): getting execution log for rule ${id}`);
|
||||
const rule = (await get(context, { id, includeLegacyId: true })) as SanitizedRuleWithLegacyId;
|
||||
const rule = (await getRule(context, { id, includeLegacyId: true })) as SanitizedRuleWithLegacyId;
|
||||
|
||||
try {
|
||||
// Make sure user has access to this rule
|
||||
|
|
|
@ -15,7 +15,7 @@ import { createRule, CreateRuleParams } from '../application/rule/methods/create
|
|||
import { updateRule, UpdateRuleParams } from '../application/rule/methods/update';
|
||||
import { snoozeRule, SnoozeRuleOptions } from '../application/rule/methods/snooze';
|
||||
import { unsnoozeRule, UnsnoozeParams } from '../application/rule/methods/unsnooze';
|
||||
import { get, GetParams } from './methods/get';
|
||||
import { getRule, GetRuleParams } from '../application/rule/methods/get';
|
||||
import { resolveRule, ResolveParams } from '../application/rule/methods/resolve';
|
||||
import { getAlertState, GetAlertStateParams } from './methods/get_alert_state';
|
||||
import { getAlertSummary, GetAlertSummaryParams } from './methods/get_alert_summary';
|
||||
|
@ -134,8 +134,8 @@ export class RulesClient {
|
|||
public delete = (params: { id: string }) => deleteRule(this.context, params);
|
||||
public find = <Params extends RuleTypeParams = never>(params?: FindParams) =>
|
||||
find<Params>(this.context, params);
|
||||
public get = <Params extends RuleTypeParams = never>(params: GetParams) =>
|
||||
get<Params>(this.context, params);
|
||||
public get = <Params extends RuleTypeParams = never>(params: GetRuleParams) =>
|
||||
getRule<Params>(this.context, params);
|
||||
public resolve = <Params extends RuleTypeParams = never>(params: ResolveParams) =>
|
||||
resolveRule<Params>(this.context, params);
|
||||
public update = <Params extends RuleTypeParams = never>(params: UpdateRuleParams<Params>) =>
|
||||
|
|
|
@ -80,6 +80,10 @@ describe('getAlertState()', () => {
|
|||
params: {
|
||||
bar: true,
|
||||
},
|
||||
executionStatus: {
|
||||
status: 'unknown',
|
||||
lastExecutionDate: new Date('2020-08-20T19:23:38Z'),
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
group: 'default',
|
||||
|
@ -116,11 +120,12 @@ describe('getAlertState()', () => {
|
|||
await rulesClient.getAlertState({ id: '1' });
|
||||
expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledTimes(1);
|
||||
expect(unsecuredSavedObjectsClient.get.mock.calls[0]).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"alert",
|
||||
"1",
|
||||
]
|
||||
`);
|
||||
Array [
|
||||
"alert",
|
||||
"1",
|
||||
undefined,
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test('gets the underlying task from TaskManager', async () => {
|
||||
|
@ -137,6 +142,10 @@ describe('getAlertState()', () => {
|
|||
params: {
|
||||
bar: true,
|
||||
},
|
||||
executionStatus: {
|
||||
status: 'unknown',
|
||||
lastExecutionDate: new Date('2020-08-20T19:23:38Z'),
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
group: 'default',
|
||||
|
@ -195,6 +204,10 @@ describe('getAlertState()', () => {
|
|||
params: {
|
||||
bar: true,
|
||||
},
|
||||
executionStatus: {
|
||||
status: 'unknown',
|
||||
lastExecutionDate: new Date('2020-08-20T19:23:38Z'),
|
||||
},
|
||||
actions: [],
|
||||
enabled: true,
|
||||
scheduledTaskId,
|
||||
|
@ -208,8 +221,7 @@ describe('getAlertState()', () => {
|
|||
|
||||
await rulesClient.getAlertState({ id: '1' });
|
||||
|
||||
expect(rulesClientParams.logger.warn).toHaveBeenCalledTimes(1);
|
||||
expect(rulesClientParams.logger.warn).toHaveBeenCalledWith('Task (task-123) not found');
|
||||
expect(rulesClientParams.logger.warn).toHaveBeenNthCalledWith(2, 'Task (task-123) not found');
|
||||
});
|
||||
|
||||
test('logs a warning if the taskManager throws an error', async () => {
|
||||
|
@ -226,6 +238,10 @@ describe('getAlertState()', () => {
|
|||
params: {
|
||||
bar: true,
|
||||
},
|
||||
executionStatus: {
|
||||
status: 'unknown',
|
||||
lastExecutionDate: new Date('2020-08-20T19:23:38Z'),
|
||||
},
|
||||
actions: [],
|
||||
enabled: true,
|
||||
scheduledTaskId,
|
||||
|
@ -239,8 +255,8 @@ describe('getAlertState()', () => {
|
|||
|
||||
await rulesClient.getAlertState({ id: '1' });
|
||||
|
||||
expect(rulesClientParams.logger.warn).toHaveBeenCalledTimes(1);
|
||||
expect(rulesClientParams.logger.warn).toHaveBeenCalledWith(
|
||||
expect(rulesClientParams.logger.warn).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
'An error occurred when getting the task state for (task-123): Bad Request'
|
||||
);
|
||||
});
|
||||
|
@ -257,6 +273,11 @@ describe('getAlertState()', () => {
|
|||
params: {
|
||||
bar: true,
|
||||
},
|
||||
enabled: true,
|
||||
executionStatus: {
|
||||
status: 'unknown',
|
||||
lastExecutionDate: new Date('2020-08-20T19:23:38Z'),
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
group: 'default',
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
"tags": [
|
||||
],
|
||||
"throttle": null,
|
||||
"updatedAt": "2020-06-17T15:35:38.497Z",
|
||||
"updatedBy": "elastic"
|
||||
},
|
||||
"migrationVersion": {
|
||||
|
@ -133,6 +134,7 @@
|
|||
"tags": [
|
||||
],
|
||||
"throttle": null,
|
||||
"updatedAt": "2020-09-22T15:16:07.451Z",
|
||||
"updatedBy": "elastic"
|
||||
},
|
||||
"migrationVersion": {
|
||||
|
@ -210,6 +212,7 @@
|
|||
"tags": [
|
||||
],
|
||||
"throttle": null,
|
||||
"updatedAt": "2020-06-17T15:35:38.497Z",
|
||||
"updatedBy": "elastic"
|
||||
},
|
||||
"migrationVersion": {
|
||||
|
@ -306,6 +309,7 @@
|
|||
"foo"
|
||||
],
|
||||
"throttle": "1m",
|
||||
"updatedAt": "2020-09-22T15:16:07.451Z",
|
||||
"updatedBy": null
|
||||
},
|
||||
"migrationVersion": {
|
||||
|
@ -372,6 +376,7 @@
|
|||
"apiKey" : null,
|
||||
"createdBy" : "elastic",
|
||||
"updatedBy" : "elastic",
|
||||
"updatedAt" : "2021-07-27T20:42:55.896Z",
|
||||
"createdAt" : "2021-07-27T20:42:55.896Z",
|
||||
"muteAll" : false,
|
||||
"mutedInstanceIds" : [ ],
|
||||
|
@ -431,6 +436,7 @@
|
|||
"tags": [
|
||||
],
|
||||
"throttle": null,
|
||||
"updatedAt": "2020-09-22T15:16:07.451Z",
|
||||
"updatedBy": "elastic"
|
||||
},
|
||||
"migrationVersion": {
|
||||
|
@ -478,6 +484,7 @@
|
|||
"createdBy" : "elastic",
|
||||
"updatedBy" : "elastic",
|
||||
"createdAt" : "2021-07-27T20:42:55.896Z",
|
||||
"updatedAt" : "2021-07-27T20:42:55.896Z",
|
||||
"muteAll" : false,
|
||||
"mutedInstanceIds" : [ ],
|
||||
"scheduledTaskId" : null,
|
||||
|
@ -518,6 +525,7 @@
|
|||
"createdBy" : "elastic",
|
||||
"updatedBy" : "elastic",
|
||||
"createdAt" : "2021-07-27T20:42:55.896Z",
|
||||
"updatedAt" : "2021-07-27T20:42:55.896Z",
|
||||
"muteAll" : false,
|
||||
"mutedInstanceIds" : [ ],
|
||||
"scheduledTaskId" : null,
|
||||
|
@ -558,6 +566,7 @@
|
|||
"apiKey" : null,
|
||||
"createdBy" : "elastic",
|
||||
"updatedBy" : "elastic",
|
||||
"updatedAt" : "2021-07-27T20:42:55.896Z",
|
||||
"createdAt" : "2021-07-27T20:42:55.896Z",
|
||||
"muteAll" : false,
|
||||
"mutedInstanceIds" : [ ],
|
||||
|
@ -598,6 +607,7 @@
|
|||
"apiKey" : null,
|
||||
"createdBy" : "elastic",
|
||||
"updatedBy" : "elastic",
|
||||
"updatedAt" : "2021-07-27T20:42:55.896Z",
|
||||
"createdAt" : "2021-07-27T20:42:55.896Z",
|
||||
"muteAll" : false,
|
||||
"mutedInstanceIds" : [ ],
|
||||
|
@ -647,6 +657,7 @@
|
|||
"createdBy" : "elastic",
|
||||
"updatedBy" : "elastic",
|
||||
"createdAt" : "2021-07-27T20:42:55.896Z",
|
||||
"updatedAt" : "2021-07-27T20:42:55.896Z",
|
||||
"muteAll" : false,
|
||||
"mutedInstanceIds" : [ ],
|
||||
"scheduledTaskId" : null,
|
||||
|
@ -740,6 +751,7 @@
|
|||
"createdBy":"3270256467",
|
||||
"updatedBy":"3270256467",
|
||||
"createdAt":"2022-02-16T01:24:02.121Z",
|
||||
"updatedAt":"2021-07-27T20:42:55.896Z",
|
||||
"muteAll":true,
|
||||
"mutedInstanceIds":[
|
||||
|
||||
|
@ -833,6 +845,7 @@
|
|||
"createdBy":"3270256467",
|
||||
"updatedBy":"3270256467",
|
||||
"createdAt":"2022-02-16T01:25:02.121Z",
|
||||
"updatedAt":"2022-02-16T01:25:02.121Z",
|
||||
"muteAll":true,
|
||||
"mutedInstanceIds":[
|
||||
|
||||
|
@ -875,6 +888,7 @@
|
|||
"createdBy" : "elastic",
|
||||
"updatedBy" : "elastic",
|
||||
"createdAt" : "2021-07-27T20:42:55.896Z",
|
||||
"updatedAt": "2021-07-27T20:42:55.896Z",
|
||||
"muteAll" : false,
|
||||
"mutedInstanceIds" : [ ],
|
||||
"scheduledTaskId" : null,
|
||||
|
@ -926,6 +940,7 @@
|
|||
"createdBy" : "elastic",
|
||||
"updatedBy" : "elastic",
|
||||
"createdAt": "2022-03-26T16:04:50.698Z",
|
||||
"updatedAt": "2022-03-26T16:04:50.698Z",
|
||||
"muteAll": false,
|
||||
"mutedInstanceIds": [],
|
||||
"scheduledTaskId": "776cb5c0-ad1e-11ec-ab9e-5f5932f4fad8",
|
||||
|
@ -1023,6 +1038,7 @@
|
|||
"createdBy":"elastic",
|
||||
"updatedBy":"elastic",
|
||||
"createdAt":"2021-07-27T20:42:55.896Z",
|
||||
"updatedAt":"2021-07-27T20:42:55.896Z",
|
||||
"muteAll":true,
|
||||
"mutedInstanceIds":[
|
||||
|
||||
|
@ -1082,6 +1098,7 @@
|
|||
"createdBy" : "elastic",
|
||||
"updatedBy" : "elastic",
|
||||
"createdAt": "2022-03-26T16:04:50.698Z",
|
||||
"updatedAt":"2022-03-26T16:04:50.698Z",
|
||||
"muteAll": false,
|
||||
"mutedInstanceIds": [],
|
||||
"scheduledTaskId": "c8b39c29-d860-43b6-8817-b8058d80ddbc",
|
||||
|
@ -1133,6 +1150,7 @@
|
|||
"createdBy" : "elastic",
|
||||
"updatedBy" : "elastic",
|
||||
"createdAt": "2022-03-26T16:04:50.698Z",
|
||||
"updatedAt": "2022-03-26T16:04:50.698Z",
|
||||
"muteAll": false,
|
||||
"mutedInstanceIds": [],
|
||||
"scheduledTaskId": "62c62b7f-8bf3-4104-a064-6247b7bda44f",
|
||||
|
@ -1184,6 +1202,7 @@
|
|||
"createdBy" : "elastic",
|
||||
"updatedBy" : "elastic",
|
||||
"createdAt": "2022-03-26T16:04:50.698Z",
|
||||
"updatedAt": "2022-03-26T16:04:50.698Z",
|
||||
"muteAll": false,
|
||||
"mutedInstanceIds": [],
|
||||
"scheduledTaskId": "f0d13f4d-35ae-4554-897a-6392e97bb84c",
|
||||
|
@ -1225,6 +1244,7 @@
|
|||
"tags": [],
|
||||
"throttle": null,
|
||||
"updatedBy": "elastic",
|
||||
"updatedAt": "2022-08-24T19:02:30.889Z",
|
||||
"isSnoozedUntil": "2022-08-24T19:05:49.817Z"
|
||||
},
|
||||
"migrationVersion": {
|
||||
|
@ -1263,6 +1283,7 @@
|
|||
"tags": [],
|
||||
"throttle": null,
|
||||
"updatedBy": "elastic",
|
||||
"updatedAt": "2022-08-24T19:02:30.889Z",
|
||||
"isSnoozedUntil": "2022-08-24T19:05:49.817Z",
|
||||
"executionStatus": {
|
||||
"status": "ok",
|
||||
|
@ -1321,6 +1342,7 @@
|
|||
"tags": [],
|
||||
"throttle": null,
|
||||
"updatedBy": "elastic",
|
||||
"updatedAt": "2022-08-24T19:02:30.889Z",
|
||||
"isSnoozedUntil": "2022-08-24T19:05:49.817Z",
|
||||
"executionStatus": {
|
||||
"status": "warning",
|
||||
|
@ -1394,6 +1416,7 @@
|
|||
"createdBy" : "elastic",
|
||||
"updatedBy" : "elastic",
|
||||
"createdAt": "2023-01-26T14:20:13.449Z",
|
||||
"updatedAt": "2023-01-26T14:20:13.449Z",
|
||||
"muteAll": false,
|
||||
"mutedInstanceIds": [],
|
||||
"scheduledTaskId": "8bd01ff0-9d84-11ed-994d-f1971f849da5",
|
||||
|
@ -1457,6 +1480,7 @@
|
|||
"createdBy":"elastic",
|
||||
"updatedBy":"elastic",
|
||||
"createdAt":"2023-03-27T20:42:55.896Z",
|
||||
"updatedAt":"2023-03-27T20:42:55.896Z",
|
||||
"muteAll":true,
|
||||
"mutedInstanceIds":[],
|
||||
"scheduledTaskId":null,
|
||||
|
|
|
@ -173,6 +173,9 @@
|
|||
"updatedBy": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"updatedAt": {
|
||||
"type": "date"
|
||||
},
|
||||
"isSnoozedUntil": {
|
||||
"type": "date"
|
||||
},
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
"tags": [
|
||||
],
|
||||
"throttle": null,
|
||||
"updatedAt": "2020-06-17T15:35:38.497Z",
|
||||
"updatedBy": "elastic"
|
||||
},
|
||||
"migrationVersion": {
|
||||
|
@ -69,6 +70,7 @@
|
|||
"tags": [
|
||||
],
|
||||
"throttle": null,
|
||||
"updatedAt": "2020-06-17T15:35:38.497Z",
|
||||
"updatedBy": "elastic"
|
||||
},
|
||||
"migrationVersion": {
|
||||
|
|
|
@ -172,6 +172,9 @@
|
|||
},
|
||||
"updatedBy": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"updatedAt": {
|
||||
"type": "date"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue