Skip to content

Commit 231610c

Browse files
authored
[Monitoring] Migrate data source for legacy alerts to monitoring data directly (#87377)
* License expiration * Fetch legacy alert data from the source * Add back in the one test file * Remove deprecated code * Fix up tests * Add test files * Fix i18n * Update tests * PR feedback * Fix types and tests * Fix license headers * Remove unused function * Fix faulty license expiration logic
1 parent 87212e6 commit 231610c

32 files changed

+1802
-792
lines changed

x-pack/plugins/monitoring/common/types/alerts.ts

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@
66
*/
77

88
import { Alert, AlertTypeParams, SanitizedAlert } from '../../../alerts/common';
9-
import { AlertParamType, AlertMessageTokenType, AlertSeverity } from '../enums';
9+
import {
10+
AlertParamType,
11+
AlertMessageTokenType,
12+
AlertSeverity,
13+
AlertClusterHealthType,
14+
} from '../enums';
1015

1116
export type CommonAlert = Alert<AlertTypeParams> | SanitizedAlert<AlertTypeParams>;
1217

@@ -60,6 +65,8 @@ export interface AlertInstanceState {
6065
| AlertDiskUsageState
6166
| AlertThreadPoolRejectionsState
6267
| AlertNodeState
68+
| AlertLicenseState
69+
| AlertNodesChangedState
6370
>;
6471
[x: string]: unknown;
6572
}
@@ -74,6 +81,7 @@ export interface AlertState {
7481
export interface AlertNodeState extends AlertState {
7582
nodeId: string;
7683
nodeName?: string;
84+
meta: any;
7785
[key: string]: unknown;
7886
}
7987

@@ -96,6 +104,14 @@ export interface AlertThreadPoolRejectionsState extends AlertState {
96104
nodeName?: string;
97105
}
98106

107+
export interface AlertLicenseState extends AlertState {
108+
expiryDateMS: number;
109+
}
110+
111+
export interface AlertNodesChangedState extends AlertState {
112+
node: AlertClusterStatsNode;
113+
}
114+
99115
export interface AlertUiState {
100116
isFiring: boolean;
101117
resolvedMS?: number;
@@ -228,3 +244,36 @@ export interface LegacyAlertNodesChangedList {
228244
added: { [nodeName: string]: string };
229245
restarted: { [nodeName: string]: string };
230246
}
247+
248+
export interface AlertLicense {
249+
status: string;
250+
type: string;
251+
expiryDateMS: number;
252+
clusterUuid: string;
253+
ccs?: string;
254+
}
255+
256+
export interface AlertClusterStatsNodes {
257+
clusterUuid: string;
258+
recentNodes: AlertClusterStatsNode[];
259+
priorNodes: AlertClusterStatsNode[];
260+
ccs?: string;
261+
}
262+
263+
export interface AlertClusterStatsNode {
264+
nodeUuid: string;
265+
nodeEphemeralId?: string;
266+
nodeName?: string;
267+
}
268+
269+
export interface AlertClusterHealth {
270+
health: AlertClusterHealthType;
271+
clusterUuid: string;
272+
ccs?: string;
273+
}
274+
275+
export interface AlertVersions {
276+
clusterUuid: string;
277+
ccs?: string;
278+
versions: string[];
279+
}

x-pack/plugins/monitoring/common/types/es.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,10 @@ export interface ElasticsearchLegacySource {
154154
cluster_state?: {
155155
status?: string;
156156
nodes?: {
157-
[nodeUuid: string]: {};
157+
[nodeUuid: string]: {
158+
ephemeral_id?: string;
159+
name?: string;
160+
};
158161
};
159162
master_node?: boolean;
160163
};
@@ -170,6 +173,7 @@ export interface ElasticsearchLegacySource {
170173
license?: {
171174
status?: string;
172175
type?: string;
176+
expiry_date_in_millis?: number;
173177
};
174178
logstash_state?: {
175179
pipeline?: {

x-pack/plugins/monitoring/server/alerts/base_alert.ts

Lines changed: 1 addition & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -26,26 +26,16 @@ import {
2626
AlertEnableAction,
2727
CommonAlertFilter,
2828
CommonAlertParams,
29-
LegacyAlert,
3029
} from '../../common/types/alerts';
3130
import { fetchAvailableCcs } from '../lib/alerts/fetch_available_ccs';
3231
import { fetchClusters } from '../lib/alerts/fetch_clusters';
3332
import { getCcsIndexPattern } from '../lib/alerts/get_ccs_index_pattern';
34-
import { INDEX_PATTERN_ELASTICSEARCH, INDEX_ALERTS } from '../../common/constants';
33+
import { INDEX_PATTERN_ELASTICSEARCH } from '../../common/constants';
3534
import { AlertSeverity } from '../../common/enums';
36-
import { MonitoringLicenseService } from '../types';
3735
import { mbSafeQuery } from '../lib/mb_safe_query';
3836
import { appendMetricbeatIndex } from '../lib/alerts/append_mb_index';
3937
import { parseDuration } from '../../../alerts/common/parse_duration';
4038
import { Globals } from '../static_globals';
41-
import { fetchLegacyAlerts } from '../lib/alerts/fetch_legacy_alerts';
42-
import { mapLegacySeverity } from '../lib/alerts/map_legacy_severity';
43-
44-
interface LegacyOptions {
45-
watchName: string;
46-
nodeNameLabel: string;
47-
changeDataValues?: Partial<AlertData>;
48-
}
4939

5040
type ExecutedState =
5141
| {
@@ -60,7 +50,6 @@ interface AlertOptions {
6050
name: string;
6151
throttle?: string | null;
6252
interval?: string;
63-
legacy?: LegacyOptions;
6453
defaultParams?: Partial<CommonAlertParams>;
6554
actionVariables: Array<{ name: string; description: string }>;
6655
fetchClustersRange?: number;
@@ -126,16 +115,6 @@ export class BaseAlert {
126115
};
127116
}
128117

129-
public isEnabled(licenseService: MonitoringLicenseService) {
130-
if (this.alertOptions.legacy) {
131-
const watcherFeature = licenseService.getWatcherFeature();
132-
if (!watcherFeature.isAvailable || !watcherFeature.isEnabled) {
133-
return false;
134-
}
135-
}
136-
return true;
137-
}
138-
139118
public getId() {
140119
return this.rawAlert?.id;
141120
}
@@ -271,10 +250,6 @@ export class BaseAlert {
271250
params as CommonAlertParams,
272251
availableCcs
273252
);
274-
if (this.alertOptions.legacy) {
275-
const data = await this.fetchLegacyData(callCluster, clusters, availableCcs);
276-
return await this.processLegacyData(data, clusters, services, state);
277-
}
278253
const data = await this.fetchData(params, callCluster, clusters, availableCcs);
279254
return await this.processData(data, clusters, services, state);
280255
}
@@ -312,35 +287,6 @@ export class BaseAlert {
312287
throw new Error('Child classes must implement `fetchData`');
313288
}
314289

315-
protected async fetchLegacyData(
316-
callCluster: CallCluster,
317-
clusters: AlertCluster[],
318-
availableCcs: string[]
319-
): Promise<AlertData[]> {
320-
let alertIndexPattern = INDEX_ALERTS;
321-
if (availableCcs) {
322-
alertIndexPattern = getCcsIndexPattern(alertIndexPattern, availableCcs);
323-
}
324-
const legacyAlerts = await fetchLegacyAlerts(
325-
callCluster,
326-
clusters,
327-
alertIndexPattern,
328-
this.alertOptions.legacy!.watchName,
329-
Globals.app.config.ui.max_bucket_size
330-
);
331-
332-
return legacyAlerts.map((legacyAlert) => {
333-
return {
334-
clusterUuid: legacyAlert.metadata.cluster_uuid,
335-
shouldFire: !legacyAlert.resolved_timestamp,
336-
severity: mapLegacySeverity(legacyAlert.metadata.severity),
337-
meta: legacyAlert,
338-
nodeName: this.alertOptions.legacy!.nodeNameLabel,
339-
...this.alertOptions.legacy!.changeDataValues,
340-
};
341-
});
342-
}
343-
344290
protected async processData(
345291
data: AlertData[],
346292
clusters: AlertCluster[],
@@ -395,34 +341,6 @@ export class BaseAlert {
395341
return state;
396342
}
397343

398-
protected async processLegacyData(
399-
data: AlertData[],
400-
clusters: AlertCluster[],
401-
services: AlertServices<AlertInstanceState, never, 'default'>,
402-
state: ExecutedState
403-
) {
404-
const currentUTC = +new Date();
405-
for (const item of data) {
406-
const instanceId = `${this.alertOptions.id}:${item.clusterUuid}`;
407-
const instance = services.alertInstanceFactory(instanceId);
408-
if (!item.shouldFire) {
409-
instance.replaceState({ alertStates: [] });
410-
continue;
411-
}
412-
const cluster = clusters.find((c: AlertCluster) => c.clusterUuid === item.clusterUuid);
413-
const alertState: AlertState = this.getDefaultAlertState(cluster!, item);
414-
alertState.nodeName = item.nodeName;
415-
alertState.ui.triggeredMS = currentUTC;
416-
alertState.ui.isFiring = true;
417-
alertState.ui.severity = item.severity;
418-
alertState.ui.message = this.getUiMessage(alertState, item);
419-
instance.replaceState({ alertStates: [alertState] });
420-
this.executeActions(instance, alertState, item, cluster);
421-
}
422-
state.lastChecked = currentUTC;
423-
return state;
424-
}
425-
426344
protected getDefaultAlertState(cluster: AlertCluster, item: AlertData): AlertState {
427345
return {
428346
cluster,
@@ -437,10 +355,6 @@ export class BaseAlert {
437355
};
438356
}
439357

440-
protected getVersions(legacyAlert: LegacyAlert) {
441-
return `[${legacyAlert.message.match(/(?<=Versions: \[).+?(?=\])/)}]`;
442-
}
443-
444358
protected getUiMessage(
445359
alertState: AlertState | unknown,
446360
item: AlertData | unknown

x-pack/plugins/monitoring/server/alerts/cluster_health_alert.test.ts

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77

88
import { ClusterHealthAlert } from './cluster_health_alert';
99
import { ALERT_CLUSTER_HEALTH } from '../../common/constants';
10-
import { fetchLegacyAlerts } from '../lib/alerts/fetch_legacy_alerts';
10+
import { AlertClusterHealthType, AlertSeverity } from '../../common/enums';
11+
import { fetchClusterHealth } from '../lib/alerts/fetch_cluster_health';
1112
import { fetchClusters } from '../lib/alerts/fetch_clusters';
1213

1314
const RealDate = Date;
@@ -26,8 +27,8 @@ jest.mock('../static_globals', () => ({
2627
},
2728
}));
2829

29-
jest.mock('../lib/alerts/fetch_legacy_alerts', () => ({
30-
fetchLegacyAlerts: jest.fn(),
30+
jest.mock('../lib/alerts/fetch_cluster_health', () => ({
31+
fetchClusterHealth: jest.fn(),
3132
}));
3233
jest.mock('../lib/alerts/fetch_clusters', () => ({
3334
fetchClusters: jest.fn(),
@@ -63,16 +64,16 @@ describe('ClusterHealthAlert', () => {
6364
function FakeDate() {}
6465
FakeDate.prototype.valueOf = () => 1;
6566

67+
const ccs = undefined;
6668
const clusterUuid = 'abc123';
6769
const clusterName = 'testCluster';
68-
const legacyAlert = {
69-
prefix: 'Elasticsearch cluster status is yellow.',
70-
message: 'Allocate missing replica shards.',
71-
metadata: {
72-
severity: 2000,
73-
cluster_uuid: clusterUuid,
70+
const healths = [
71+
{
72+
health: AlertClusterHealthType.Yellow,
73+
clusterUuid,
74+
ccs,
7475
},
75-
};
76+
];
7677

7778
const replaceState = jest.fn();
7879
const scheduleActions = jest.fn();
@@ -94,8 +95,8 @@ describe('ClusterHealthAlert', () => {
9495
beforeEach(() => {
9596
// @ts-ignore
9697
Date = FakeDate;
97-
(fetchLegacyAlerts as jest.Mock).mockImplementation(() => {
98-
return [legacyAlert];
98+
(fetchClusterHealth as jest.Mock).mockImplementation(() => {
99+
return healths;
99100
});
100101
(fetchClusters as jest.Mock).mockImplementation(() => {
101102
return [{ clusterUuid, clusterName }];
@@ -120,8 +121,15 @@ describe('ClusterHealthAlert', () => {
120121
alertStates: [
121122
{
122123
cluster: { clusterUuid: 'abc123', clusterName: 'testCluster' },
123-
ccs: undefined,
124-
nodeName: 'Elasticsearch cluster alert',
124+
ccs,
125+
itemLabel: undefined,
126+
nodeId: undefined,
127+
nodeName: undefined,
128+
meta: {
129+
ccs,
130+
clusterUuid,
131+
health: AlertClusterHealthType.Yellow,
132+
},
125133
ui: {
126134
isFiring: true,
127135
message: {
@@ -140,7 +148,7 @@ describe('ClusterHealthAlert', () => {
140148
},
141149
],
142150
},
143-
severity: 'danger',
151+
severity: AlertSeverity.Warning,
144152
triggeredMS: 1,
145153
lastCheckedMS: 0,
146154
},
@@ -160,9 +168,15 @@ describe('ClusterHealthAlert', () => {
160168
});
161169
});
162170

163-
it('should not fire actions if there is no legacy alert', async () => {
164-
(fetchLegacyAlerts as jest.Mock).mockImplementation(() => {
165-
return [];
171+
it('should not fire actions if the cluster health is green', async () => {
172+
(fetchClusterHealth as jest.Mock).mockImplementation(() => {
173+
return [
174+
{
175+
health: AlertClusterHealthType.Green,
176+
clusterUuid,
177+
ccs,
178+
},
179+
];
166180
});
167181
const alert = new ClusterHealthAlert();
168182
const type = alert.getAlertType();

0 commit comments

Comments
 (0)