"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.CpuUsageRule = void 0; var _i18n = require("@kbn/i18n"); var _numeral = _interopRequireDefault(require("@elastic/numeral")); var _parse_duration = require("@kbn/alerting-plugin/common/parse_duration"); var _base_rule = require("./base_rule"); var _constants = require("../../common/constants"); var _formatting = require("../../common/formatting"); var _fetch_cpu_usage_node_stats = require("../lib/alerts/fetch_cpu_usage_node_stats"); var _enums = require("../../common/enums"); var _alert_helpers = require("./alert_helpers"); var _static_globals = require("../static_globals"); /* * 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. */ class CpuUsageRule extends _base_rule.BaseRule { constructor(sanitizedRule) { super(sanitizedRule, { id: _constants.RULE_CPU_USAGE, name: _constants.RULE_DETAILS[_constants.RULE_CPU_USAGE].label, accessorKey: 'cpuUsage', defaultParams: { threshold: 85, duration: '5m' }, actionVariables: [{ name: 'node', description: _i18n.i18n.translate('xpack.monitoring.alerts.cpuUsage.actionVariables.node', { defaultMessage: 'The node reporting high CPU usage.' }) }, ...Object.values(_alert_helpers.AlertingDefaults.ALERT_TYPE.context)] }); this.sanitizedRule = sanitizedRule; } async fetchData(params, esClient, clusters) { const duration = (0, _parse_duration.parseDuration)(params.duration); const endMs = +new Date(); const startMs = endMs - duration; let filterQuery; if (params.filterQuery) { try { filterQuery = JSON.parse(params.filterQuery); } catch (error) { throw new Error(`Failed to parse filter query in CPU usage rule ${error}`); } } const stats = await (0, _fetch_cpu_usage_node_stats.fetchCpuUsageNodeStats)({ esClient, clusterUuids: clusters.map(cluster => cluster.clusterUuid), startMs, endMs, filterQuery, logger: this.scopedLogger }, _static_globals.Globals.app.config); return stats.map(stat => ({ clusterUuid: stat.clusterUuid, ...this.outcomeAndSeverity(stat, params.threshold), meta: { ...stat, threshold: params.threshold }, ccs: stat.ccs })); } outcomeAndSeverity(stat, threshold) { if (stat.missingLimits || stat.limitsChanged || stat.unexpectedLimits || stat.cpuUsage === undefined) { let severity = _enums.AlertSeverity.Warning; if (stat.cpuUsage && stat.cpuUsage > threshold) { severity = _enums.AlertSeverity.Danger; } return { shouldFire: true, severity }; } return { shouldFire: stat.cpuUsage > threshold, severity: _enums.AlertSeverity.Danger }; } filterAlertInstance(alertInstance, filters) { return super.filterAlertInstance(alertInstance, filters, true); } getDefaultAlertState(cluster, item) { const base = super.getDefaultAlertState(cluster, item); return { ...base, ui: { ...base.ui, severity: _enums.AlertSeverity.Danger } }; } getUiMessage(alertState, item) { const stat = item.meta; const tokens = [{ startToken: '#start_link', endToken: '#end_link', type: _enums.AlertMessageTokenType.Link, url: `elasticsearch/nodes/${stat.nodeId}` }, { startToken: '#absolute', type: _enums.AlertMessageTokenType.Time, isAbsolute: true, isRelative: false, timestamp: alertState.ui.triggeredMS }]; if (stat.missingLimits) { return { text: _i18n.i18n.translate('xpack.monitoring.alerts.cpuUsage.ui.missingLimits', { defaultMessage: `Kibana is configured for containerized workloads but node #start_link{nodeName}#end_link does not have resource limits configured. Fallback metric reports usage of {cpuUsage}%. Last checked at #absolute`, values: { nodeName: stat.nodeName, cpuUsage: (0, _numeral.default)(stat.cpuUsage).format(_formatting.ROUNDED_FLOAT) } }), tokens }; } if (stat.unexpectedLimits) { return { text: _i18n.i18n.translate('xpack.monitoring.alerts.cpuUsage.ui.unexpectedLimits', { defaultMessage: `Kibana is configured for non-containerized workloads but node #start_link{nodeName}#end_link has resource limits configured. Node reports usage of {cpuUsage}%. Last checked at #absolute`, values: { nodeName: stat.nodeName, cpuUsage: (0, _numeral.default)(stat.cpuUsage).format(_formatting.ROUNDED_FLOAT) } }), tokens }; } if (stat.limitsChanged) { return { text: _i18n.i18n.translate('xpack.monitoring.alerts.cpuUsage.ui.limitsChanged', { defaultMessage: `Resource limits for node #start_link{nodeName}#end_link has changed within the look back window, unable to confidently calculate CPU usage for alerting. Please monitor the usage until the window has moved. Last checked at #absolute`, values: { nodeName: stat.nodeName } }), tokens }; } if (stat.cpuUsage === undefined) { return { text: _i18n.i18n.translate('xpack.monitoring.alerts.cpuUsage.ui.failedToComputeUsage', { defaultMessage: `Failed to compute CPU usage for node #start_link{nodeName}#end_link. Please check the Kibana logs for more details. Last checked at #absolute`, values: { nodeName: stat.nodeName } }), tokens }; } return { text: _i18n.i18n.translate('xpack.monitoring.alerts.cpuUsage.ui.firingMessage', { defaultMessage: `Node #start_link{nodeName}#end_link is reporting CPU usage of {cpuUsage}% which is above the configured threshold of {threshold}%. Last checked at #absolute`, values: { nodeName: stat.nodeName, cpuUsage: (0, _numeral.default)(stat.cpuUsage).format(_formatting.ROUNDED_FLOAT), threshold: stat.threshold } }), nextSteps: [(0, _alert_helpers.createLink)(_i18n.i18n.translate('xpack.monitoring.alerts.cpuUsage.ui.nextSteps.hotThreads', { defaultMessage: '#start_linkCheck hot threads#end_link' }), `{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/cluster-nodes-hot-threads.html`), (0, _alert_helpers.createLink)(_i18n.i18n.translate('xpack.monitoring.alerts.cpuUsage.ui.nextSteps.runningTasks', { defaultMessage: '#start_linkCheck long running tasks#end_link' }), `{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/tasks.html`)], tokens }; } executeActions(instance, { alertStates }, item, cluster) { if (alertStates.length === 0) { return; } const firingNode = alertStates[0]; if (!firingNode || !firingNode.ui.isFiring) { return; } const shortActionText = _i18n.i18n.translate('xpack.monitoring.alerts.cpuUsage.shortAction', { defaultMessage: 'Verify CPU usage of node.' }); const fullActionText = _i18n.i18n.translate('xpack.monitoring.alerts.cpuUsage.fullAction', { defaultMessage: 'View node' }); const ccs = firingNode.ccs; const globalStateLink = this.createGlobalStateLink(`elasticsearch/nodes/${firingNode.nodeId}`, cluster.clusterUuid, ccs); const action = `[${fullActionText}](${globalStateLink})`; const internalShortMessage = this.getMessage(firingNode, cluster.clusterName, shortActionText); const internalFullMessage = this.getMessage(firingNode, cluster.clusterName, action); instance.scheduleActions('default', { internalShortMessage, internalFullMessage: _static_globals.Globals.app.isCloud ? internalShortMessage : internalFullMessage, state: _alert_helpers.AlertingDefaults.ALERT_STATE.firing, /* continue to send "nodes" and "count" values for users before https://github.com/elastic/kibana/pull/102544 see https://github.com/elastic/kibana/issues/100136#issuecomment-865229431 */ nodes: `${firingNode.nodeName}:${firingNode.cpuUsage}`, count: 1, node: `${firingNode.nodeName}:${firingNode.cpuUsage}`, clusterName: cluster.clusterName, action, actionPlain: shortActionText }); } getMessage(state, clusterName, action) { const stat = state.meta; if (stat.missingLimits || stat.limitsChanged || stat.unexpectedLimits || stat.cpuUsage === undefined) { return _i18n.i18n.translate('xpack.monitoring.alerts.cpuUsage.firing.internalMessageForFailure', { defaultMessage: `CPU usage alert for node {nodeName} in cluster {clusterName} faced issues while evaluating the usage. {action}`, values: { clusterName, nodeName: state.nodeName, action } }); } return _i18n.i18n.translate('xpack.monitoring.alerts.cpuUsage.firing.internalMessage', { defaultMessage: `CPU usage alert is firing for node {nodeName} in cluster {clusterName}. {action}`, values: { clusterName, nodeName: state.nodeName, action } }); } } exports.CpuUsageRule = CpuUsageRule;