Skip to content

Commit

Permalink
[Response Ops][Alerting] Using alertsClient for transform health an…
Browse files Browse the repository at this point in the history
…d anomaly detection jobs health rule types to write default alerts-as-data docs (elastic#174537)

Towards elastic/response-ops-team#164
Resolves elastic#171792

## Summary

* Switches these rule types to use `alertsClient` from alerting
framework in favor of the deprecated `alertFactory`
* Defines the `default` alert config for these rule types so framework
level fields will be written out into the
`.alerts-default.alerts-default` index with no rule type specific
fields.

Example alert doc for transform health rule:

```
{
    "kibana.alert.reason": "Transform test_transform_01 is not started.",
    "kibana.alert.rule.category": "Transform health",
    "kibana.alert.rule.consumer": "alerts",
    "kibana.alert.rule.execution.uuid": "1dd66818-962e-4fef-8ce2-5a1eab2813a2",
    "kibana.alert.rule.name": "Test all transforms",
    "kibana.alert.rule.parameters": {
        "includeTransforms": [
            "*"
        ],
        "excludeTransforms": null,
        "testsConfig": null
    },
    "kibana.alert.rule.producer": "stackAlerts",
    "kibana.alert.rule.revision": 0,
    "kibana.alert.rule.rule_type_id": "transform_health",
    "kibana.alert.rule.tags": [],
    "kibana.alert.rule.uuid": "7fb57af0-56b5-4c63-9457-add79e9c3e37",
    "kibana.space_ids": [
        "space1"
    ],
    "@timestamp": "2024-01-10T14:43:00.974Z",
    "event.action": "open",
    "event.kind": "signal",
    "kibana.alert.action_group": "transform_issue",
    "kibana.alert.flapping": false,
    "kibana.alert.flapping_history": [
        true
    ],
    "kibana.alert.instance.id": "Transform is not started",
    "kibana.alert.maintenance_window_ids": [],
    "kibana.alert.status": "active",
    "kibana.alert.uuid": "25f7b99d-e4ab-4b97-89e4-1a537692ffa5",
    "kibana.alert.workflow_status": "open",
    "kibana.alert.duration.us": 0,
    "kibana.alert.start": "2024-01-10T14:43:00.974Z",
    "kibana.alert.time_range": {
        "gte": "2024-01-10T14:43:00.974Z"
    },
    "kibana.version": "8.13.0",
    "tags": []
}
```

---------

Co-authored-by: kibanamachine <[email protected]>
  • Loading branch information
2 people authored and delanni committed Jan 11, 2024
1 parent 040f729 commit c725a75
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 47 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@ import type {
ActionGroup,
AlertInstanceContext,
AlertInstanceState,
RecoveredActionGroupId,
RuleTypeState,
} from '@kbn/alerting-plugin/common';
import { AlertsClientError, DEFAULT_AAD_CONFIG } from '@kbn/alerting-plugin/server';
import type { RuleExecutorOptions } from '@kbn/alerting-plugin/server';
import type { DefaultAlert } from '@kbn/alerts-as-data-utils';
import { ALERT_REASON } from '@kbn/rule-data-utils';
import { ML_ALERT_TYPES } from '../../../common/constants/alerts';
import { PLUGIN_ID } from '../../../common/constants/app';
import { MINIMUM_FULL_LICENSE } from '../../../common/license';
Expand Down Expand Up @@ -90,7 +94,8 @@ export type JobsHealthExecutorOptions = RuleExecutorOptions<
Record<string, unknown>,
Record<string, unknown>,
AnomalyDetectionJobsHealthAlertContext,
AnomalyDetectionJobRealtimeIssue
AnomalyDetectionJobRealtimeIssue,
DefaultAlert
>;

export function registerJobsMonitoringRuleType({
Expand All @@ -104,7 +109,9 @@ export function registerJobsMonitoringRuleType({
RuleTypeState,
AlertInstanceState,
AnomalyDetectionJobsHealthAlertContext,
AnomalyDetectionJobRealtimeIssue
AnomalyDetectionJobRealtimeIssue,
RecoveredActionGroupId,
DefaultAlert
>({
id: ML_ALERT_TYPES.AD_JOBS_HEALTH,
name: i18n.translate('xpack.ml.jobsHealthAlertingRule.name', {
Expand Down Expand Up @@ -142,12 +149,19 @@ export function registerJobsMonitoringRuleType({
minimumLicenseRequired: MINIMUM_FULL_LICENSE,
isExportable: true,
doesSetRecoveryContext: true,
alerts: DEFAULT_AAD_CONFIG,
async executor(options) {
const {
services,
rule: { name },
} = options;

const { alertsClient } = services;

if (!alertsClient) {
throw new AlertsClientError();
}

const fakeRequest = {} as KibanaRequest;
const { getTestsResults } = mlServicesProviders.jobsHealthServiceProvider(
services.savedObjectsClient,
Expand All @@ -165,19 +179,30 @@ export function registerJobsMonitoringRuleType({
.join(', ')}`
);

unhealthyTests.forEach(({ name: alertInstanceName, context }) => {
const alertInstance = services.alertFactory.create(alertInstanceName);
alertInstance.scheduleActions(ANOMALY_DETECTION_JOB_REALTIME_ISSUE, context);
unhealthyTests.forEach(({ name: alertName, context }) => {
alertsClient.report({
id: alertName,
actionGroup: ANOMALY_DETECTION_JOB_REALTIME_ISSUE,
context,
payload: {
[ALERT_REASON]: context.message,
},
});
});
}

// Set context for recovered alerts
const { getRecoveredAlerts } = services.alertFactory.done();
for (const recoveredAlert of getRecoveredAlerts()) {
const recoveredAlertId = recoveredAlert.getId();
for (const recoveredAlert of alertsClient.getRecoveredAlerts()) {
const recoveredAlertId = recoveredAlert.alert.getId();
const testResult = executionResult.find((v) => v.name === recoveredAlertId);
if (testResult) {
recoveredAlert.setContext(testResult.context);
alertsClient.setAlertData({
id: recoveredAlertId,
context: testResult.context,
payload: {
[ALERT_REASON]: testResult.context.message,
},
});
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@ import type {
ActionGroup,
AlertInstanceContext,
AlertInstanceState,
RecoveredActionGroupId,
RuleTypeState,
} from '@kbn/alerting-plugin/common';
import type { RuleType } from '@kbn/alerting-plugin/server';
import { AlertsClientError, DEFAULT_AAD_CONFIG, RuleType } from '@kbn/alerting-plugin/server';
import type { PluginSetupContract as AlertingSetup } from '@kbn/alerting-plugin/server';
import type { FieldFormatsStart } from '@kbn/field-formats-plugin/server';
import type { DefaultAlert } from '@kbn/alerts-as-data-utils';
import { ALERT_REASON } from '@kbn/rule-data-utils';
import { PLUGIN, type TransformHealth, TRANSFORM_RULE_TYPE } from '../../../../common/constants';
import { transformHealthRuleParams, TransformHealthRuleParams } from './schema';
import { transformHealthServiceProvider } from './transform_health_service';
Expand Down Expand Up @@ -73,7 +76,9 @@ export function getTransformHealthRuleType(
RuleTypeState,
AlertInstanceState,
TransformHealthAlertContext,
TransformIssue
TransformIssue,
RecoveredActionGroupId,
DefaultAlert
> {
return {
id: TRANSFORM_RULE_TYPE.TRANSFORM_HEALTH,
Expand Down Expand Up @@ -110,12 +115,17 @@ export function getTransformHealthRuleType(
minimumLicenseRequired: PLUGIN.MINIMUM_LICENSE_REQUIRED,
isExportable: true,
doesSetRecoveryContext: true,
alerts: DEFAULT_AAD_CONFIG,
async executor(options) {
const {
services: { scopedClusterClient, alertFactory, uiSettingsClient },
services: { scopedClusterClient, alertsClient, uiSettingsClient },
params,
} = options;

if (!alertsClient) {
throw new AlertsClientError();
}

const fieldFormatsRegistry = await getFieldFormatsStart().fieldFormatServiceFactory(
uiSettingsClient
);
Expand All @@ -131,18 +141,29 @@ export function getTransformHealthRuleType(

if (unhealthyTests.length > 0) {
unhealthyTests.forEach(({ name: alertInstanceName, context }) => {
const alertInstance = alertFactory.create(alertInstanceName);
alertInstance.scheduleActions(TRANSFORM_ISSUE, context);
alertsClient.report({
id: alertInstanceName,
actionGroup: TRANSFORM_ISSUE,
context,
payload: {
[ALERT_REASON]: context.message,
},
});
});
}

// Set context for recovered alerts
const { getRecoveredAlerts } = alertFactory.done();
for (const recoveredAlert of getRecoveredAlerts()) {
const recoveredAlertId = recoveredAlert.getId();
for (const recoveredAlert of alertsClient.getRecoveredAlerts()) {
const recoveredAlertId = recoveredAlert.alert.getId();
const testResult = executionResult.find((v) => v.name === recoveredAlertId);
if (testResult) {
recoveredAlert.setContext(testResult.context);
alertsClient.setAlertData({
id: recoveredAlertId,
context: testResult.context,
payload: {
[ALERT_REASON]: testResult.context.message,
},
});
}
}

Expand Down
4 changes: 3 additions & 1 deletion x-pack/plugins/transform/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@
"@kbn/data-view-editor-plugin",
"@kbn/ml-data-view-utils",
"@kbn/ml-creation-wizard-utils",
"@kbn/code-editor"
"@kbn/alerts-as-data-utils",
"@kbn/code-editor",
"@kbn/rule-data-utils"
],
"exclude": [
"target/**/*",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ import { FtrProviderContext } from '../../../../../../common/ftr_provider_contex
// eslint-disable-next-line import/no-default-export
export default function alertingTests({ loadTestFile }: FtrProviderContext) {
describe('transform_health', function () {
loadTestFile(require.resolve('./alert'));
loadTestFile(require.resolve('./rule'));
});
}
Loading

0 comments on commit c725a75

Please sign in to comment.