"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.update = update; var _boom = _interopRequireDefault(require("@hapi/boom")); var _lodash = require("lodash"); var _lib = require("../../lib"); var _authorization = require("../../authorization"); var _parse_duration = require("../../../common/parse_duration"); var _retry_if_conflicts = require("../../lib/retry_if_conflicts"); var _bulk_mark_api_keys_for_invalidation = require("../../invalidate_pending_api_keys/bulk_mark_api_keys_for_invalidation"); var _audit_events = require("../common/audit_events"); var _mapped_params_utils = require("../common/mapped_params_utils"); var _lib2 = require("../lib"); /* * 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. */ async function update(context, { id, data, allowMissingConnectorSecrets, shouldIncrementRevision }) { return await (0, _retry_if_conflicts.retryIfConflicts)(context.logger, `rulesClient.update('${id}')`, async () => await updateWithOCC(context, { id, data, allowMissingConnectorSecrets, shouldIncrementRevision })); } async function updateWithOCC(context, { id, data, allowMissingConnectorSecrets, shouldIncrementRevision }) { var _context$auditLogger2; let alertSavedObject; try { alertSavedObject = await context.encryptedSavedObjectsClient.getDecryptedAsInternalUser('alert', id, { namespace: context.namespace }); } catch (e) { // We'll skip invalidating the API key since we failed to load the decrypted saved object context.logger.error(`update(): Failed to load API key to invalidate on alert ${id}: ${e.message}`); // Still attempt to load the object using SOC alertSavedObject = await context.unsecuredSavedObjectsClient.get('alert', id); } try { await context.authorization.ensureAuthorized({ ruleTypeId: alertSavedObject.attributes.alertTypeId, consumer: alertSavedObject.attributes.consumer, operation: _authorization.WriteOperations.Update, entity: _authorization.AlertingAuthorizationEntity.Rule }); } catch (error) { var _context$auditLogger; (_context$auditLogger = context.auditLogger) === null || _context$auditLogger === void 0 ? void 0 : _context$auditLogger.log((0, _audit_events.ruleAuditEvent)({ action: _audit_events.RuleAuditAction.UPDATE, savedObject: { type: 'alert', id }, error })); throw error; } (_context$auditLogger2 = context.auditLogger) === null || _context$auditLogger2 === void 0 ? void 0 : _context$auditLogger2.log((0, _audit_events.ruleAuditEvent)({ action: _audit_events.RuleAuditAction.UPDATE, outcome: 'unknown', savedObject: { type: 'alert', id } })); context.ruleTypeRegistry.ensureRuleTypeEnabled(alertSavedObject.attributes.alertTypeId); const migratedActions = await (0, _lib2.migrateLegacyActions)(context, { ruleId: id, attributes: alertSavedObject.attributes }); const updateResult = await updateAlert(context, { id, data, allowMissingConnectorSecrets, shouldIncrementRevision }, migratedActions.hasLegacyActions ? { ...alertSavedObject, attributes: { ...alertSavedObject.attributes, notifyWhen: undefined, throttle: undefined } } : alertSavedObject); await Promise.all([alertSavedObject.attributes.apiKey && !alertSavedObject.attributes.apiKeyCreatedByUser ? (0, _bulk_mark_api_keys_for_invalidation.bulkMarkApiKeysForInvalidation)({ apiKeys: [alertSavedObject.attributes.apiKey] }, context.logger, context.unsecuredSavedObjectsClient) : null, (async () => { if (updateResult.scheduledTaskId && updateResult.schedule && !(0, _lodash.isEqual)(alertSavedObject.attributes.schedule, updateResult.schedule)) { try { var _tasks$; const { tasks } = await context.taskManager.bulkUpdateSchedules([updateResult.scheduledTaskId], updateResult.schedule); context.logger.debug(`Rule update has rescheduled the underlying task: ${updateResult.scheduledTaskId} to run at: ${tasks === null || tasks === void 0 ? void 0 : (_tasks$ = tasks[0]) === null || _tasks$ === void 0 ? void 0 : _tasks$.runAt}`); } catch (err) { context.logger.error(`Rule update failed to run its underlying task. TaskManager bulkUpdateSchedules failed with Error: ${err.message}`); } } })()]); return updateResult; } async function updateAlert(context, { id, data: initialData, allowMissingConnectorSecrets, shouldIncrementRevision = () => true }, currentRule) { var _data$notifyWhen, _data$throttle; const { attributes, version } = currentRule; const data = { ...initialData, actions: (0, _lib2.addGeneratedActionValues)(initialData.actions) }; const ruleType = context.ruleTypeRegistry.get(attributes.alertTypeId); // Validate const validatedAlertTypeParams = (0, _lib.validateRuleTypeParams)(data.params, ruleType.validate.params); await (0, _lib2.validateActions)(context, ruleType, data, allowMissingConnectorSecrets); // Throw error if schedule interval is less than the minimum and we are enforcing it const intervalInMs = (0, _parse_duration.parseDuration)(data.schedule.interval); if (intervalInMs < context.minimumScheduleIntervalInMs && context.minimumScheduleInterval.enforce) { throw _boom.default.badRequest(`Error updating rule: the interval is less than the allowed minimum interval of ${context.minimumScheduleInterval.value}`); } // Extract saved object references for this rule const { references, params: updatedParams, actions } = await (0, _lib2.extractReferences)(context, ruleType, data.actions, validatedAlertTypeParams); const username = await context.getUserName(); const apiKeyAttributes = await (0, _lib2.createNewAPIKeySet)(context, { id: ruleType.id, ruleName: data.name, username, shouldUpdateApiKey: attributes.enabled, errorMessage: 'Error updating rule: could not create API key' }); const notifyWhen = (0, _lib.getRuleNotifyWhenType)((_data$notifyWhen = data.notifyWhen) !== null && _data$notifyWhen !== void 0 ? _data$notifyWhen : null, (_data$throttle = data.throttle) !== null && _data$throttle !== void 0 ? _data$throttle : null); // Increment revision if applicable field has changed const revision = shouldIncrementRevision(updatedParams) ? (0, _lib2.incrementRevision)(currentRule, { id, data, allowMissingConnectorSecrets }, updatedParams) : currentRule.attributes.revision; let updatedObject; const createAttributes = (0, _lib2.updateMeta)(context, { ...attributes, ...data, ...apiKeyAttributes, params: updatedParams, actions, notifyWhen, revision, updatedBy: username, updatedAt: new Date().toISOString() }); const mappedParams = (0, _mapped_params_utils.getMappedParams)(updatedParams); if (Object.keys(mappedParams).length) { createAttributes.mapped_params = mappedParams; } try { updatedObject = await context.unsecuredSavedObjectsClient.create('alert', createAttributes, { id, overwrite: true, version, references }); } catch (e) { // Avoid unused API key await (0, _bulk_mark_api_keys_for_invalidation.bulkMarkApiKeysForInvalidation)({ apiKeys: createAttributes.apiKey && !createAttributes.apiKeyCreatedByUser ? [createAttributes.apiKey] : [] }, context.logger, context.unsecuredSavedObjectsClient); throw e; } // Log warning if schedule interval is less than the minimum but we're not enforcing it if (intervalInMs < context.minimumScheduleIntervalInMs && !context.minimumScheduleInterval.enforce) { context.logger.warn(`Rule schedule interval (${data.schedule.interval}) for "${ruleType.id}" rule type with ID "${id}" is less than the minimum value (${context.minimumScheduleInterval.value}). Running rules at this interval may impact alerting performance. Set "xpack.alerting.rules.minimumScheduleInterval.enforce" to true to prevent such changes.`); } return (0, _lib2.getPartialRuleFromRaw)(context, id, ruleType, updatedObject.attributes, updatedObject.references, false, true); }