Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[Response Ops][Rules] Version Unmute All Rule API #196070

Merged
merged 11 commits into from
Oct 14, 2024
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