Skip to content

Commit

Permalink
[Response Ops][Rules] Version Unmute All Rule API (#196070)
Browse files Browse the repository at this point in the history
## Summary

`POST /api/alerting/rule/{id}/_unmute_all` in
#195181
  • Loading branch information
jcger authored Oct 14, 2024
1 parent 1489396 commit c901fec
Show file tree
Hide file tree
Showing 17 changed files with 224 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -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.
*/

export { unmuteAllRuleRequestParamsSchema } from './schemas/latest';
export type { UnmuteAllRuleRequestParams } from './types/latest';

export { unmuteAllRuleRequestParamsSchema as unmuteAllRuleRequestParamsSchemaV1 } from './schemas/v1';
export type { UnmuteAllRuleRequestParams as UnmuteAllRuleRequestParamsV1 } from './types/v1';
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 './v1';
Original file line number Diff line number Diff line change
@@ -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 { schema } from '@kbn/config-schema';

export const unmuteAllRuleRequestParamsSchema = schema.object({
id: schema.string({
meta: {
description: 'The identifier for the rule.',
},
}),
});
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 './v1';
Original file line number Diff line number Diff line change
@@ -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 type { TypeOf } from '@kbn/config-schema';
import { unmuteAllRuleRequestParamsSchemaV1 } from '..';

export type UnmuteAllRuleRequestParams = TypeOf<typeof unmuteAllRuleRequestParamsSchemaV1>;
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 { unmuteAll } from './unmute_all';
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 './unmute_all_rule_schemas';
Original file line number Diff line number Diff line change
@@ -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 unmuteAllRuleParamsSchema = schema.object({
id: schema.string(),
});
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 './unmute_all_rule_types';
Original file line number Diff line number Diff line change
@@ -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 type { TypeOf } from '@kbn/config-schema';
import { unmuteAllRuleParamsSchema } from '../schemas';

export type UnmuteAllRuleParams = TypeOf<typeof unmuteAllRuleParamsSchema>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* 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 { RulesClientContext } from '../../../../rules_client';
import { unmuteAll } from './unmute_all';
import { savedObjectsRepositoryMock } from '@kbn/core-saved-objects-api-server-mocks';

jest.mock('../../../../lib/retry_if_conflicts', () => ({
retryIfConflicts: (_: unknown, id: unknown, asyncFn: () => Promise<unknown>) => {
return asyncFn();
},
}));

jest.mock('../../../../rules_client/lib', () => ({
updateMetaAttributes: () => {},
}));

jest.mock('../../../../saved_objects', () => ({
partiallyUpdateRule: async () => {},
}));

const loggerErrorMock = jest.fn();
const getBulkMock = jest.fn();

const savedObjectsMock = savedObjectsRepositoryMock.create();
savedObjectsMock.get = jest.fn().mockReturnValue({
attributes: {
actions: [],
},
version: '9.0.0',
});

const context = {
logger: { error: loggerErrorMock },
getActionsClient: () => {
return {
getBulk: getBulkMock,
};
},
unsecuredSavedObjectsClient: savedObjectsMock,
authorization: { ensureAuthorized: async () => {} },
ruleTypeRegistry: {
ensureRuleTypeEnabled: () => {},
},
getUserName: async () => {},
} as unknown as RulesClientContext;

describe('validate unmuteAll parameters', () => {
afterEach(() => {
jest.clearAllMocks();
});

it('should not throw an error for valid params', () => {
const validParams = {
id: 'ble',
};

expect(() => unmuteAll(context, validParams)).not.toThrow();
expect(savedObjectsMock.get).toHaveBeenCalled();
});

it('should throw Boom.badRequest for invalid params', async () => {
const invalidParams = {
id: 22,
};

// @ts-expect-error wrong type for testing purposes
await expect(unmuteAll(context, invalidParams)).rejects.toThrowErrorMatchingInlineSnapshot(
`"Error validating unmute all parameters - [id]: expected value of type [string] but got [number]"`
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,22 @@
* 2.0.
*/

import { RawRule } from '../../types';
import { WriteOperations, AlertingAuthorizationEntity } from '../../authorization';
import { retryIfConflicts } from '../../lib/retry_if_conflicts';
import { partiallyUpdateRule, RULE_SAVED_OBJECT_TYPE } from '../../saved_objects';
import { ruleAuditEvent, RuleAuditAction } from '../common/audit_events';
import { RulesClientContext } from '../types';
import { updateMetaAttributes } from '../lib';
import { clearUnscheduledSnoozeAttributes } from '../common';
import { RuleAttributes } from '../../data/rule/types';
import Boom from '@hapi/boom';
import { RawRule } from '../../../../types';
import { WriteOperations, AlertingAuthorizationEntity } from '../../../../authorization';
import { retryIfConflicts } from '../../../../lib/retry_if_conflicts';
import { partiallyUpdateRule, RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects';
import { ruleAuditEvent, RuleAuditAction } from '../../../../rules_client/common/audit_events';
import { RulesClientContext } from '../../../../rules_client/types';
import { updateMetaAttributes } from '../../../../rules_client/lib';
import { clearUnscheduledSnoozeAttributes } from '../../../../rules_client/common';
import { RuleAttributes } from '../../../../data/rule/types';
import { UnmuteAllRuleParams } from './types';
import { unmuteAllRuleParamsSchema } from './schemas';

export async function unmuteAll(
context: RulesClientContext,
{ id }: { id: string }
{ id }: UnmuteAllRuleParams
): Promise<void> {
return await retryIfConflicts(
context.logger,
Expand All @@ -26,7 +29,14 @@ export async function unmuteAll(
);
}

async function unmuteAllWithOCC(context: RulesClientContext, { id }: { id: string }) {
async function unmuteAllWithOCC(context: RulesClientContext, params: UnmuteAllRuleParams) {
try {
unmuteAllRuleParamsSchema.validate(params);
} catch (error) {
throw Boom.badRequest(`Error validating unmute all parameters - ${error.message}`);
}

const { id } = params;
const { attributes, version } = await context.unsecuredSavedObjectsClient.get<RawRule>(
RULE_SAVED_OBJECT_TYPE,
id
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/alerting/server/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import { resolveRuleRoute } from './rule/apis/resolve';
import { ruleTypesRoute } from './rule_types';
import { muteAllRuleRoute } from './rule/apis/mute_all/mute_all_rule';
import { muteAlertRoute } from './rule/apis/mute_alert/mute_alert';
import { unmuteAllRuleRoute } from './unmute_all_rule';
import { unmuteAllRuleRoute } from './rule/apis/unmute_all';
import { unmuteAlertRoute } from './rule/apis/unmute_alert/unmute_alert_route';
import { updateRuleApiKeyRoute } from './rule/apis/update_api_key/update_rule_api_key_route';
import { bulkEditInternalRulesRoute } from './rule/apis/bulk_edit/bulk_edit_rules_route';
Expand Down
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 { unmuteAllRuleRoute } from './unmute_all_rule';
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@

import { unmuteAllRuleRoute } from './unmute_all_rule';
import { httpServiceMock } from '@kbn/core/server/mocks';
import { licenseStateMock } from '../lib/license_state.mock';
import { mockHandlerArguments } from './_mock_handler_arguments';
import { rulesClientMock } from '../rules_client.mock';
import { RuleTypeDisabledError } from '../lib/errors/rule_type_disabled';
import { licenseStateMock } from '../../../../lib/license_state.mock';
import { mockHandlerArguments } from '../../../_mock_handler_arguments';
import { rulesClientMock } from '../../../../rules_client.mock';
import { RuleTypeDisabledError } from '../../../../lib/errors/rule_type_disabled';

const rulesClient = rulesClientMock.create();
jest.mock('../lib/license_api_access', () => ({
jest.mock('../../../../lib/license_api_access', () => ({
verifyApiAccess: jest.fn(),
}));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,13 @@
*/

import { IRouter } from '@kbn/core/server';
import { schema } from '@kbn/config-schema';
import { ILicenseState, RuleTypeDisabledError } from '../lib';
import { verifyAccessAndContext } from './lib';
import { AlertingRequestHandlerContext, BASE_ALERTING_API_PATH } from '../types';

const paramSchema = schema.object({
id: schema.string({
meta: {
description: 'The identifier for the rule.',
},
}),
});
import { ILicenseState, RuleTypeDisabledError } from '../../../../lib';
import { verifyAccessAndContext } from '../../../lib';
import { AlertingRequestHandlerContext, BASE_ALERTING_API_PATH } from '../../../../types';
import {
unmuteAllRuleRequestParamsSchemaV1,
UnmuteAllRuleRequestParamsV1,
} from '../../../../../common/routes/rule/apis/unmute_all';

export const unmuteAllRuleRoute = (
router: IRouter<AlertingRequestHandlerContext>,
Expand All @@ -33,7 +28,7 @@ export const unmuteAllRuleRoute = (
},
validate: {
request: {
params: paramSchema,
params: unmuteAllRuleRequestParamsSchemaV1,
},
response: {
204: {
Expand All @@ -45,9 +40,9 @@ export const unmuteAllRuleRoute = (
router.handleLegacyErrors(
verifyAccessAndContext(licenseState, async function (context, req, res) {
const rulesClient = (await context.alerting).getRulesClient();
const { id } = req.params;
const params: UnmuteAllRuleRequestParamsV1 = req.params;
try {
await rulesClient.unmuteAll({ id });
await rulesClient.unmuteAll(params);
return res.noContent();
} catch (e) {
if (e instanceof RuleTypeDisabledError) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ import { enableRule } from '../application/rule/methods/enable_rule/enable_rule'
import { updateRuleApiKey } from '../application/rule/methods/update_api_key/update_rule_api_key';
import { disableRule } from '../application/rule/methods/disable/disable_rule';
import { muteInstance } from '../application/rule/methods/mute_alert/mute_instance';
import { unmuteAll } from '../application/rule/methods/unmute_all';
import { muteAll } from '../application/rule/methods/mute_all';
import { unmuteAll } from './methods/unmute_all';
import { unmuteInstance } from '../application/rule/methods/unmute_alert/unmute_instance';
import { runSoon } from './methods/run_soon';
import { listRuleTypes } from './methods/list_rule_types';
Expand Down

0 comments on commit c901fec

Please sign in to comment.