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

[8.9] [Uptime] Include synthetics-* for existing alerts (#160063) #161334

Merged
merged 4 commits into from
Jul 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion x-pack/plugins/synthetics/server/feature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
*/

import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server';
import { umDynamicSettings } from './legacy_uptime/lib/saved_objects/uptime_settings';
import { syntheticsMonitorType, syntheticsParamType } from '../common/types/saved_objects';
import { SYNTHETICS_RULE_TYPES } from '../common/constants/synthetics_alerts';
import { privateLocationsSavedObjectName } from '../common/saved_objects/private_locations';
import { PLUGIN } from '../common/constants/plugin';
import { UPTIME_RULE_TYPES } from '../common/constants/uptime_alerts';
import { umDynamicSettings } from './legacy_uptime/lib/saved_objects/uptime_settings';
import { syntheticsApiKeyObjectType } from './legacy_uptime/lib/saved_objects/service_api_key';

export const uptimeFeature = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,10 @@ export const durationAnomalyAlertFactory: UptimeAlertTypeFactory<ActionGroupIds>
}) {
const uptimeEsClient = new UptimeEsClient(
savedObjectsClient,
scopedClusterClient.asCurrentUser
scopedClusterClient.asCurrentUser,
{
isLegacyAlert: true,
}
);
const { share, basePath } = server;
const alertsLocator: LocatorPublic<AlertsLocatorParams> | undefined =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,10 @@ export const statusCheckAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (
share.url.locators.get(alertsLocatorID);
const uptimeEsClient = new UptimeEsClient(
savedObjectsClient,
scopedClusterClient.asCurrentUser
scopedClusterClient.asCurrentUser,
{
isLegacyAlert: true,
}
);

const filterString = await formatFilterString(uptimeEsClient, filters, search, libs);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ export const tlsAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (
spaceId,
startedAt,
state,
rule,
}) {
const { share, basePath } = _server;
const alertsLocator: LocatorPublic<AlertsLocatorParams> | undefined =
Expand All @@ -163,7 +164,10 @@ export const tlsAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (

const uptimeEsClient = new UptimeEsClient(
savedObjectsClient,
scopedClusterClient.asCurrentUser
scopedClusterClient.asCurrentUser,
{
isLegacyAlert: true,
}
);

const certExpirationThreshold =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,10 @@ export const tlsLegacyAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (_s

const uptimeEsClient = new UptimeEsClient(
savedObjectsClient,
scopedClusterClient.asCurrentUser
scopedClusterClient.asCurrentUser,
{
isLegacyAlert: true,
}
);
const { certs, total }: CertResult = await libs.requests.getCerts({
uptimeEsClient,
Expand Down
176 changes: 176 additions & 0 deletions x-pack/plugins/synthetics/server/legacy_uptime/lib/lib.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/*
* 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 { UptimeEsClient } from './lib';
import { savedObjectsClientMock, uiSettingsServiceMock } from '@kbn/core/server/mocks';
import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks';
import { savedObjectsAdapter } from './saved_objects';

describe('UptimeEsClient', () => {
let uptimeEsClient: UptimeEsClient;
const savedObjectsClient = savedObjectsClientMock.create();
const esClient = elasticsearchClientMock.createClusterClient().asInternalUser;

beforeEach(() => {
uptimeEsClient = new UptimeEsClient(savedObjectsClient, esClient);
});

afterEach(() => {
jest.clearAllMocks();
});

describe('search', () => {
it('should call baseESClient.search with correct parameters', async () => {
const mockSearchParams = {
body: {
query: {
match_all: {},
},
},
};

const result = await uptimeEsClient.search({
body: {
query: {
match_all: {},
},
},
});

expect(esClient.search).toHaveBeenCalledWith(
{
index: 'heartbeat-8*,heartbeat-7*',
...mockSearchParams,
},
{ meta: true }
);
expect(result).toEqual({
body: {},
headers: {
'x-elastic-product': 'Elasticsearch',
},
meta: {},
statusCode: 200,
warnings: [],
});
});

it('should throw an error if baseESClient.search throws an error', async () => {
const mockSearchParams = {
body: {
query: {
match_all: {},
},
},
};
const mockError = new Error('Search error');
esClient.search.mockRejectedValueOnce(mockError);

await expect(uptimeEsClient.search(mockSearchParams)).rejects.toThrow(mockError);
expect(esClient.search).toHaveBeenCalledWith(
{
index: 'heartbeat-8*,heartbeat-7*',
...mockSearchParams,
},
{ meta: true }
);
});
});

describe('count', () => {
it('should call baseESClient.count with correct parameters', async () => {
const mockCountParams = {
index: 'example',
};

const result = await uptimeEsClient.count(mockCountParams);

expect(esClient.count).toHaveBeenCalledWith(mockCountParams, { meta: true });
expect(result).toEqual({
indices: 'heartbeat-8*,heartbeat-7*',
result: {
body: {},
headers: {
'x-elastic-product': 'Elasticsearch',
},
meta: {},
statusCode: 200,
warnings: [],
},
});
});

it('should throw an error if baseESClient.count throws an error', async () => {
const mockCountParams = {
index: 'example',
};
const mockError = new Error('Count error');
esClient.count.mockRejectedValueOnce(mockError);

await expect(uptimeEsClient.count(mockCountParams)).rejects.toThrow(mockError);
expect(esClient.count).toHaveBeenCalledWith(mockCountParams, { meta: true });
});
});

describe('getInspectEnabled', () => {
it('should return false if uiSettings is not available', async () => {
const result = await uptimeEsClient.getInspectEnabled();

expect(result).toBe(false);
});

it('should return the value from uiSettings if available', async () => {
const mockUiSettings = uiSettingsServiceMock.createClient();
uptimeEsClient.uiSettings = {
client: mockUiSettings,
} as any;

// @ts-expect-error
mockUiSettings.get.mockReturnValue(true);

await uptimeEsClient.getInspectEnabled();

expect(uptimeEsClient.isInspectorEnabled).toBe(true);
expect(mockUiSettings.get).toHaveBeenCalledWith('observability:enableInspectEsQueries');
});
});
describe('heartbeatIndices', () => {
it('appends synthetics-* in index for legacy alerts', async () => {
savedObjectsAdapter.getUptimeDynamicSettings = jest.fn().mockResolvedValue({
heartbeatIndices: 'heartbeat-8*,heartbeat-7*',
syntheticsIndexRemoved: true,
});
uptimeEsClient = new UptimeEsClient(savedObjectsClient, esClient, { isLegacyAlert: true });

const mockSearchParams = {
body: {
query: {
match_all: {},
},
},
};

await uptimeEsClient.search({
body: {
query: {
match_all: {},
},
},
});

expect(esClient.search).toHaveBeenCalledWith(
{
index: 'heartbeat-8*,heartbeat-7*,synthetics-*',
...mockSearchParams,
},
{ meta: true }
);
});
});

// Add more tests for other methods and edge cases
});
33 changes: 22 additions & 11 deletions x-pack/plugins/synthetics/server/legacy_uptime/lib/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,8 @@ import { enableInspectEsQueries } from '@kbn/observability-plugin/common';
import { getInspectResponse } from '@kbn/observability-shared-plugin/common';
import { API_URLS } from '../../../common/constants';
import { UptimeServerSetup } from './adapters';
import { UMLicenseCheck } from './domains';
import { UptimeRequests } from './requests';
import { savedObjectsAdapter } from './saved_objects/saved_objects';

export interface UMDomainLibs {
requests: UptimeRequests;
license: UMLicenseCheck;
}

export type { UMServerLibs } from '../uptime_server';

export interface CountResponse {
Expand All @@ -55,6 +48,7 @@ export class UptimeEsClient {
inspectableEsQueries: InspectResponse = [];
uiSettings?: CoreRequestHandlerContext['uiSettings'];
savedObjectsClient: SavedObjectsClientContract;
isLegacyAlert?: boolean;

constructor(
savedObjectsClient: SavedObjectsClientContract,
Expand All @@ -64,9 +58,17 @@ export class UptimeEsClient {
uiSettings?: CoreRequestHandlerContext['uiSettings'];
request?: KibanaRequest;
heartbeatIndices?: string;
isLegacyAlert?: boolean;
}
) {
const { isDev = false, uiSettings, request, heartbeatIndices = '' } = options ?? {};
const {
isLegacyAlert,
isDev = false,
uiSettings,
request,
heartbeatIndices = '',
} = options ?? {};
this.isLegacyAlert = isLegacyAlert;
this.uiSettings = uiSettings;
this.baseESClient = esClient;
this.savedObjectsClient = savedObjectsClient;
Expand Down Expand Up @@ -197,11 +199,20 @@ export class UptimeEsClient {
}

async getIndices() {
// if isLegacyAlert appends synthetics-* if it's not already there
let indices = '';
let syntheticsIndexRemoved = false;
if (this.heartbeatIndices) {
return this.heartbeatIndices;
indices = this.heartbeatIndices;
} else {
const settings = await savedObjectsAdapter.getUptimeDynamicSettings(this.savedObjectsClient);
indices = settings?.heartbeatIndices || '';
syntheticsIndexRemoved = settings.syntheticsIndexRemoved ?? false;
}
if (this.isLegacyAlert && !indices.includes('synthetics-') && syntheticsIndexRemoved) {
indices = indices + ',synthetics-*';
}
const settings = await savedObjectsAdapter.getUptimeDynamicSettings(this.savedObjectsClient);
return settings?.heartbeatIndices || '';
return indices;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ describe('remove890Indices migration', () => {
attributes: {
...doc.attributes,
heartbeatIndices: 'heartbeat-8*,something_else',
syntheticsIndexRemoved: true,
},
});
});
Expand All @@ -129,6 +130,7 @@ describe('remove890Indices migration', () => {
attributes: {
...doc.attributes,
heartbeatIndices: 'something_else,heartbeat-8*',
syntheticsIndexRemoved: true,
},
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,14 @@ export const remove890Indices: SavedObjectMigrationFn<
indicesArr.push('heartbeat-8*');
}

const syntheticsIndexRemoved = indexToRemove > -1;

return {
...doc,
attributes: {
...doc.attributes,
heartbeatIndices: indicesArr.join(','),
...(syntheticsIndexRemoved && { syntheticsIndexRemoved }),
},
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { SavedObjectsType } from '@kbn/core/server';
import { i18n } from '@kbn/i18n';
import { add820Indices, remove890Indices } from './migrations';
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/synthetics/server/runtime_types/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const DynamicSettingsAttributesCodec = t.intersection([
}),
t.partial({
defaultEmail: DefaultEmailCodec,
syntheticsIndexRemoved: t.boolean,
}),
]);

Expand Down
1 change: 0 additions & 1 deletion x-pack/plugins/translations/translations/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -36846,7 +36846,6 @@
"xpack.synthetics.totalDuration.metrics": "Durée de l’étape",
"xpack.synthetics.totalDuration.transferSize": "Taille du transfert",
"xpack.synthetics.uptimeFeatureCatalogueTitle": "Uptime",
"xpack.synthetics.uptimeSettings.index": "Paramètres Uptime - Index",
"xpack.synthetics.wait": "Attendre",
"xpack.synthetics.waterfall.applyFilters.label": "Sélectionner un élément auquel appliquer le filtre",
"xpack.synthetics.waterfall.applyFilters.message": "Cliquer pour ajouter ou retirer le filtre",
Expand Down