mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Synthetics] Project monitors - support lightweight project monitors (#141066)
* Improve project formatter * update * update imports * adjust logic and add tests for lightweight project monitors * update test * update api test * test * update more test * more fix * update tests * [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix' * remove references to preserve monitor id * [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' * adjust errors * adjust tests * [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' * update * code reuse * update type * add tests * update * update * fix types * deepclone policies * update test * add tests * update type * Update src/plugins/interactive_setup/public/theme/kibana_theme_provider.tsx * [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix' Co-authored-by: shahzad31 <shahzad.muhammad@elastic.co> Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
e82b7ff582
commit
fa636c655b
36 changed files with 1632 additions and 551 deletions
|
@ -6,7 +6,8 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { EuiProvider, EuiProviderProps } from '@elastic/eui';
|
||||
import type { EuiProviderProps } from '@elastic/eui';
|
||||
import { EuiProvider } from '@elastic/eui';
|
||||
import createCache from '@emotion/cache';
|
||||
import type { FC } from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
|
|
|
@ -46,6 +46,7 @@ export const DEFAULT_COMMON_FIELDS: CommonFields = {
|
|||
[ConfigKey.LOCATIONS]: [],
|
||||
[ConfigKey.NAMESPACE]: DEFAULT_NAMESPACE_STRING,
|
||||
[ConfigKey.MONITOR_SOURCE_TYPE]: SourceType.UI,
|
||||
[ConfigKey.JOURNEY_ID]: '',
|
||||
};
|
||||
|
||||
export const DEFAULT_BROWSER_ADVANCED_FIELDS: BrowserAdvancedFields = {
|
||||
|
@ -63,7 +64,6 @@ export const DEFAULT_BROWSER_ADVANCED_FIELDS: BrowserAdvancedFields = {
|
|||
|
||||
export const DEFAULT_BROWSER_SIMPLE_FIELDS: BrowserSimpleFields = {
|
||||
...DEFAULT_COMMON_FIELDS,
|
||||
[ConfigKey.JOURNEY_ID]: '',
|
||||
[ConfigKey.PROJECT_ID]: '',
|
||||
[ConfigKey.PLAYWRIGHT_OPTIONS]: '',
|
||||
[ConfigKey.METADATA]: {
|
||||
|
@ -96,6 +96,7 @@ export const DEFAULT_BROWSER_SIMPLE_FIELDS: BrowserSimpleFields = {
|
|||
[ConfigKey.ZIP_URL_TLS_VERSION]: undefined,
|
||||
[ConfigKey.URLS]: '',
|
||||
[ConfigKey.FORM_MONITOR_TYPE]: FormMonitorType.MULTISTEP,
|
||||
[ConfigKey.TIMEOUT]: null,
|
||||
};
|
||||
|
||||
export const DEFAULT_HTTP_SIMPLE_FIELDS: HTTPSimpleFields = {
|
||||
|
|
|
@ -72,7 +72,6 @@ export const browserFormatters: BrowserFormatMap = {
|
|||
arrayToJsonFormatter(fields[ConfigKey.JOURNEY_FILTERS_TAGS]),
|
||||
[ConfigKey.THROTTLING_CONFIG]: throttlingFormatter,
|
||||
[ConfigKey.IGNORE_HTTPS_ERRORS]: null,
|
||||
[ConfigKey.JOURNEY_ID]: null,
|
||||
[ConfigKey.PROJECT_ID]: null,
|
||||
[ConfigKey.PLAYWRIGHT_OPTIONS]: null,
|
||||
[ConfigKey.CUSTOM_HEARTBEAT_ID]: null,
|
||||
|
|
|
@ -28,6 +28,7 @@ export const commonFormatters: CommonFormatMap = {
|
|||
[ConfigKey.REVISION]: null,
|
||||
[ConfigKey.MONITOR_SOURCE_TYPE]: null,
|
||||
[ConfigKey.FORM_MONITOR_TYPE]: null,
|
||||
[ConfigKey.JOURNEY_ID]: null,
|
||||
};
|
||||
|
||||
export const arrayToJsonFormatter = (value: string[] = []) =>
|
||||
|
|
|
@ -37,8 +37,8 @@ export const BandwidthLimitKeyCodec = tEnum<BandwidthLimitKey>(
|
|||
export type BandwidthLimitKeyType = t.TypeOf<typeof BandwidthLimitKeyCodec>;
|
||||
|
||||
export const LocationGeoCodec = t.interface({
|
||||
lat: t.number,
|
||||
lon: t.number,
|
||||
lat: t.union([t.string, t.number]),
|
||||
lon: t.union([t.string, t.number]),
|
||||
});
|
||||
|
||||
export const LocationStatusCodec = tEnum<LocationStatus>('LocationStatus', LocationStatus);
|
||||
|
@ -77,13 +77,13 @@ export const PublicLocationsCodec = t.array(PublicLocationCodec);
|
|||
export const MonitorServiceLocationCodec = t.intersection([
|
||||
t.interface({
|
||||
id: t.string,
|
||||
isServiceManaged: t.boolean,
|
||||
}),
|
||||
t.partial({
|
||||
label: t.string,
|
||||
geo: LocationGeoCodec,
|
||||
url: t.string,
|
||||
isInvalid: t.boolean,
|
||||
isServiceManaged: t.boolean,
|
||||
}),
|
||||
]);
|
||||
|
||||
|
|
|
@ -8,11 +8,7 @@
|
|||
import * as t from 'io-ts';
|
||||
import { secretKeys } from '../../constants/monitor_management';
|
||||
import { ConfigKey } from './config_key';
|
||||
import {
|
||||
MonitorServiceLocationsCodec,
|
||||
MonitorServiceLocationCodec,
|
||||
ServiceLocationErrors,
|
||||
} from './locations';
|
||||
import { MonitorServiceLocationCodec, ServiceLocationErrors } from './locations';
|
||||
import {
|
||||
DataStream,
|
||||
DataStreamCodec,
|
||||
|
@ -25,6 +21,7 @@ import {
|
|||
VerificationModeCodec,
|
||||
} from './monitor_configs';
|
||||
import { MetadataCodec } from './monitor_meta_data';
|
||||
import { PrivateLocationCodec } from './synthetics_private_locations';
|
||||
|
||||
const ScheduleCodec = t.interface({
|
||||
number: t.string,
|
||||
|
@ -77,7 +74,7 @@ export const CommonFieldsCodec = t.intersection([
|
|||
[ConfigKey.SCHEDULE]: ScheduleCodec,
|
||||
[ConfigKey.APM_SERVICE_NAME]: t.string,
|
||||
[ConfigKey.TAGS]: t.array(t.string),
|
||||
[ConfigKey.LOCATIONS]: MonitorServiceLocationsCodec,
|
||||
[ConfigKey.LOCATIONS]: t.array(t.union([MonitorServiceLocationCodec, PrivateLocationCodec])),
|
||||
}),
|
||||
t.partial({
|
||||
[ConfigKey.FORM_MONITOR_TYPE]: FormMonitorTypeCodec,
|
||||
|
@ -85,6 +82,7 @@ export const CommonFieldsCodec = t.intersection([
|
|||
[ConfigKey.REVISION]: t.number,
|
||||
[ConfigKey.MONITOR_SOURCE_TYPE]: SourceTypeCodec,
|
||||
[ConfigKey.CONFIG_ID]: t.string,
|
||||
[ConfigKey.JOURNEY_ID]: t.string,
|
||||
}),
|
||||
]);
|
||||
|
||||
|
@ -218,7 +216,6 @@ export const EncryptedBrowserSimpleFieldsCodec = t.intersection([
|
|||
}),
|
||||
t.partial({
|
||||
[ConfigKey.PLAYWRIGHT_OPTIONS]: t.string,
|
||||
[ConfigKey.JOURNEY_ID]: t.string,
|
||||
[ConfigKey.PROJECT_ID]: t.string,
|
||||
[ConfigKey.ORIGINAL_SPACE]: t.string,
|
||||
[ConfigKey.CUSTOM_HEARTBEAT_ID]: t.string,
|
||||
|
|
|
@ -14,19 +14,21 @@ export const ProjectMonitorThrottlingConfigCodec = t.interface({
|
|||
latency: t.number,
|
||||
});
|
||||
|
||||
export const ProjectBrowserMonitorCodec = t.intersection([
|
||||
export const ProjectMonitorCodec = t.intersection([
|
||||
t.interface({
|
||||
type: t.string,
|
||||
id: t.string,
|
||||
name: t.string,
|
||||
schedule: t.number,
|
||||
content: t.string,
|
||||
locations: t.array(t.string),
|
||||
}),
|
||||
t.partial({
|
||||
content: t.string,
|
||||
timeout: t.string,
|
||||
privateLocations: t.array(t.string),
|
||||
throttling: ProjectMonitorThrottlingConfigCodec,
|
||||
screenshot: ScreenshotOptionCodec,
|
||||
tags: t.array(t.string),
|
||||
tags: t.union([t.string, t.array(t.string)]),
|
||||
ignoreHTTPSErrors: t.boolean,
|
||||
apmServiceName: t.string,
|
||||
playwrightOptions: t.record(t.string, t.unknown),
|
||||
|
@ -35,17 +37,21 @@ export const ProjectBrowserMonitorCodec = t.intersection([
|
|||
}),
|
||||
params: t.record(t.string, t.unknown),
|
||||
enabled: t.boolean,
|
||||
urls: t.union([t.string, t.array(t.string)]),
|
||||
hosts: t.union([t.string, t.array(t.string)]),
|
||||
max_redirects: t.string,
|
||||
wait: t.string,
|
||||
}),
|
||||
]);
|
||||
|
||||
export const ProjectMonitorsRequestCodec = t.interface({
|
||||
project: t.string,
|
||||
keep_stale: t.boolean,
|
||||
monitors: t.array(ProjectBrowserMonitorCodec),
|
||||
monitors: t.array(ProjectMonitorCodec),
|
||||
});
|
||||
|
||||
export type ProjectMonitorThrottlingConfig = t.TypeOf<typeof ProjectMonitorThrottlingConfigCodec>;
|
||||
|
||||
export type ProjectBrowserMonitor = t.TypeOf<typeof ProjectBrowserMonitorCodec>;
|
||||
export type ProjectMonitor = t.TypeOf<typeof ProjectMonitorCodec>;
|
||||
|
||||
export type ProjectMonitorsRequest = t.TypeOf<typeof ProjectMonitorsRequestCodec>;
|
||||
|
|
|
@ -7,18 +7,23 @@
|
|||
|
||||
import * as t from 'io-ts';
|
||||
|
||||
export const PrivateLocationType = t.intersection([
|
||||
export const PrivateLocationCodec = t.intersection([
|
||||
t.interface({
|
||||
label: t.string,
|
||||
id: t.string,
|
||||
agentPolicyId: t.string,
|
||||
concurrentMonitors: t.number,
|
||||
}),
|
||||
t.partial({ geo: t.interface({ lat: t.number, lon: t.number }) }),
|
||||
t.partial({
|
||||
isServiceManaged: t.boolean,
|
||||
/* Empty Lat lon was accidentally saved as an empty string instead of undefined or null
|
||||
* Need a migration to fix */
|
||||
geo: t.interface({ lat: t.union([t.string, t.number]), lon: t.union([t.string, t.number]) }),
|
||||
}),
|
||||
]);
|
||||
|
||||
export const SyntheticsPrivateLocationsType = t.type({
|
||||
locations: t.array(PrivateLocationType),
|
||||
locations: t.array(PrivateLocationCodec),
|
||||
});
|
||||
export type PrivateLocation = t.TypeOf<typeof PrivateLocationType>;
|
||||
export type PrivateLocation = t.TypeOf<typeof PrivateLocationCodec>;
|
||||
export type SyntheticsPrivateLocations = t.TypeOf<typeof SyntheticsPrivateLocationsType>;
|
||||
|
|
|
@ -104,6 +104,7 @@ describe('format', () => {
|
|||
'check.response.status': [],
|
||||
enabled,
|
||||
form_monitor_type: 'http',
|
||||
journey_id: '',
|
||||
locations: [
|
||||
{
|
||||
id: 'us_central',
|
||||
|
@ -316,6 +317,7 @@ describe('format', () => {
|
|||
'check.response.status': [],
|
||||
enabled: true,
|
||||
form_monitor_type: 'http',
|
||||
journey_id: '',
|
||||
locations: [
|
||||
{
|
||||
id: 'us_central',
|
||||
|
|
|
@ -107,7 +107,6 @@ export const browserNormalizers: BrowserNormalizerMap = {
|
|||
ConfigKey.JOURNEY_FILTERS_TAGS
|
||||
),
|
||||
[ConfigKey.IGNORE_HTTPS_ERRORS]: getBrowserNormalizer(ConfigKey.IGNORE_HTTPS_ERRORS),
|
||||
[ConfigKey.JOURNEY_ID]: getBrowserNormalizer(ConfigKey.JOURNEY_ID),
|
||||
[ConfigKey.PROJECT_ID]: getBrowserNormalizer(ConfigKey.PROJECT_ID),
|
||||
[ConfigKey.PLAYWRIGHT_OPTIONS]: getBrowserNormalizer(ConfigKey.PLAYWRIGHT_OPTIONS),
|
||||
[ConfigKey.CUSTOM_HEARTBEAT_ID]: getBrowserNormalizer(ConfigKey.CUSTOM_HEARTBEAT_ID),
|
||||
|
|
|
@ -92,4 +92,5 @@ export const commonNormalizers: CommonNormalizerMap = {
|
|||
[ConfigKey.REVISION]: getCommonNormalizer(ConfigKey.REVISION),
|
||||
[ConfigKey.MONITOR_SOURCE_TYPE]: getCommonNormalizer(ConfigKey.MONITOR_SOURCE_TYPE),
|
||||
[ConfigKey.FORM_MONITOR_TYPE]: getCommonNormalizer(ConfigKey.FORM_MONITOR_TYPE),
|
||||
[ConfigKey.JOURNEY_ID]: getCommonNormalizer(ConfigKey.JOURNEY_ID),
|
||||
};
|
||||
|
|
|
@ -6,11 +6,12 @@
|
|||
*/
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { UMServerLibs } from '../../legacy_uptime/lib/lib';
|
||||
import { ProjectBrowserMonitor } from '../../../common/runtime_types';
|
||||
import { ProjectMonitor } from '../../../common/runtime_types';
|
||||
|
||||
import { SyntheticsStreamingRouteFactory } from '../../legacy_uptime/routes/types';
|
||||
import { API_URLS } from '../../../common/constants';
|
||||
import { getAllLocations } from '../../synthetics_service/get_all_locations';
|
||||
import { ProjectMonitorFormatter } from '../../synthetics_service/project_monitor_formatter';
|
||||
import { ProjectMonitorFormatter } from '../../synthetics_service/project_monitor/project_monitor_formatter';
|
||||
|
||||
export const addSyntheticsProjectMonitorRoute: SyntheticsStreamingRouteFactory = (
|
||||
libs: UMServerLibs
|
||||
|
@ -32,7 +33,7 @@ export const addSyntheticsProjectMonitorRoute: SyntheticsStreamingRouteFactory =
|
|||
subject,
|
||||
}): Promise<any> => {
|
||||
try {
|
||||
const monitors = (request.body?.monitors as ProjectBrowserMonitor[]) || [];
|
||||
const monitors = (request.body?.monitors as ProjectMonitor[]) || [];
|
||||
const spaceId = server.spaces.spacesService.getSpaceId(request);
|
||||
const { keep_stale: keepStale, project: projectId } = request.body || {};
|
||||
const { publicLocations, privateLocations } = await getAllLocations(
|
||||
|
|
|
@ -10,8 +10,8 @@ import { formatErrors } from '@kbn/securitysolution-io-ts-utils';
|
|||
|
||||
import {
|
||||
BrowserFieldsCodec,
|
||||
ProjectBrowserMonitorCodec,
|
||||
ProjectBrowserMonitor,
|
||||
ProjectMonitorCodec,
|
||||
ProjectMonitor,
|
||||
ConfigKey,
|
||||
DataStream,
|
||||
DataStreamCodec,
|
||||
|
@ -34,16 +34,18 @@ const monitorTypeToCodecMap: Record<DataStream, MonitorCodecType> = {
|
|||
[DataStream.BROWSER]: BrowserFieldsCodec,
|
||||
};
|
||||
|
||||
/**
|
||||
* Validates monitor fields with respect to the relevant Codec identified by object's 'type' property.
|
||||
* @param monitorFields {MonitorFields} The mixed type representing the possible monitor payload from UI.
|
||||
*/
|
||||
export function validateMonitor(monitorFields: MonitorFields): {
|
||||
export interface ValidationResult {
|
||||
valid: boolean;
|
||||
reason: string;
|
||||
details: string;
|
||||
payload: object;
|
||||
} {
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates monitor fields with respect to the relevant Codec identified by object's 'type' property.
|
||||
* @param monitorFields {MonitorFields} The mixed type representing the possible monitor payload from UI.
|
||||
*/
|
||||
export function validateMonitor(monitorFields: MonitorFields): ValidationResult {
|
||||
const { [ConfigKey.MONITOR_TYPE]: monitorType } = monitorFields;
|
||||
|
||||
const decodedType = DataStreamCodec.decode(monitorType);
|
||||
|
@ -82,15 +84,7 @@ export function validateMonitor(monitorFields: MonitorFields): {
|
|||
return { valid: true, reason: '', details: '', payload: monitorFields };
|
||||
}
|
||||
|
||||
export function validateProjectMonitor(
|
||||
monitorFields: ProjectBrowserMonitor,
|
||||
projectId: string
|
||||
): {
|
||||
valid: boolean;
|
||||
reason: string;
|
||||
details: string;
|
||||
payload: object;
|
||||
} {
|
||||
export function validateProjectMonitor(monitorFields: ProjectMonitor): ValidationResult {
|
||||
const locationsError =
|
||||
monitorFields.locations &&
|
||||
monitorFields.locations.length === 0 &&
|
||||
|
@ -98,7 +92,7 @@ export function validateProjectMonitor(
|
|||
? 'Invalid value "[]" supplied to field "locations"'
|
||||
: '';
|
||||
// Cast it to ICMPCodec to satisfy typing. During runtime, correct codec will be used to decode.
|
||||
const decodedMonitor = ProjectBrowserMonitorCodec.decode(monitorFields);
|
||||
const decodedMonitor = ProjectMonitorCodec.decode(monitorFields);
|
||||
|
||||
if (isLeft(decodedMonitor)) {
|
||||
return {
|
||||
|
|
|
@ -66,7 +66,6 @@ export const browserFormatters: BrowserFormatMap = {
|
|||
[ConfigKey.JOURNEY_FILTERS_TAGS]: (fields) =>
|
||||
arrayFormatter(fields[ConfigKey.JOURNEY_FILTERS_TAGS]),
|
||||
[ConfigKey.IGNORE_HTTPS_ERRORS]: null,
|
||||
[ConfigKey.JOURNEY_ID]: null,
|
||||
[ConfigKey.PROJECT_ID]: null,
|
||||
[ConfigKey.PLAYWRIGHT_OPTIONS]: (fields) =>
|
||||
stringToObjectFormatter(fields[ConfigKey.PLAYWRIGHT_OPTIONS] || ''),
|
||||
|
|
|
@ -30,6 +30,7 @@ export const commonFormatters: CommonFormatMap = {
|
|||
[ConfigKey.MONITOR_SOURCE_TYPE]: (fields) =>
|
||||
fields[ConfigKey.MONITOR_SOURCE_TYPE] || SourceType.UI,
|
||||
[ConfigKey.FORM_MONITOR_TYPE]: null,
|
||||
[ConfigKey.JOURNEY_ID]: null,
|
||||
};
|
||||
|
||||
export const arrayFormatter = (value: string[] = []) => (value.length ? value : null);
|
||||
|
|
|
@ -1,267 +0,0 @@
|
|||
/*
|
||||
* 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 {
|
||||
DataStream,
|
||||
ScreenshotOption,
|
||||
Locations,
|
||||
LocationStatus,
|
||||
ProjectBrowserMonitor,
|
||||
PrivateLocation,
|
||||
} from '../../../common/runtime_types';
|
||||
import { DEFAULT_FIELDS } from '../../../common/constants/monitor_defaults';
|
||||
import { normalizeProjectMonitors } from './browser';
|
||||
|
||||
describe('browser normalizers', () => {
|
||||
describe('normalize push monitors', () => {
|
||||
const playwrightOptions = {
|
||||
headless: true,
|
||||
};
|
||||
const params = {
|
||||
url: 'test-url',
|
||||
};
|
||||
const projectId = 'test-project-id';
|
||||
const locations: Locations = [
|
||||
{
|
||||
id: 'us_central',
|
||||
label: 'Test Location',
|
||||
geo: { lat: 33.333, lon: 73.333 },
|
||||
url: 'test-url',
|
||||
isServiceManaged: true,
|
||||
status: LocationStatus.GA,
|
||||
},
|
||||
{
|
||||
id: 'us_east',
|
||||
label: 'Test Location',
|
||||
geo: { lat: 33.333, lon: 73.333 },
|
||||
url: 'test-url',
|
||||
isServiceManaged: true,
|
||||
status: LocationStatus.GA,
|
||||
},
|
||||
];
|
||||
const privateLocations: PrivateLocation[] = [
|
||||
{
|
||||
id: 'germany',
|
||||
label: 'Germany',
|
||||
concurrentMonitors: 1,
|
||||
agentPolicyId: 'germany',
|
||||
},
|
||||
];
|
||||
const monitors: ProjectBrowserMonitor[] = [
|
||||
{
|
||||
id: 'test-id-1',
|
||||
screenshot: ScreenshotOption.OFF,
|
||||
name: 'test-name-1',
|
||||
content: 'test content 1',
|
||||
schedule: 3,
|
||||
throttling: {
|
||||
latency: 20,
|
||||
upload: 10,
|
||||
download: 5,
|
||||
},
|
||||
locations: ['us_central'],
|
||||
tags: ['tag1', 'tag2'],
|
||||
ignoreHTTPSErrors: true,
|
||||
apmServiceName: 'cart-service',
|
||||
},
|
||||
{
|
||||
id: 'test-id-2',
|
||||
screenshot: ScreenshotOption.ON,
|
||||
name: 'test-name-2',
|
||||
content: 'test content 2',
|
||||
schedule: 10,
|
||||
throttling: {
|
||||
latency: 18,
|
||||
upload: 15,
|
||||
download: 10,
|
||||
},
|
||||
params: {},
|
||||
playwrightOptions: {},
|
||||
locations: ['us_central', 'us_east'],
|
||||
tags: ['tag3', 'tag4'],
|
||||
ignoreHTTPSErrors: false,
|
||||
apmServiceName: 'bean-service',
|
||||
},
|
||||
{
|
||||
id: 'test-id-3',
|
||||
screenshot: ScreenshotOption.ON,
|
||||
name: 'test-name-3',
|
||||
content: 'test content 3',
|
||||
schedule: 10,
|
||||
throttling: {
|
||||
latency: 18,
|
||||
upload: 15,
|
||||
download: 10,
|
||||
},
|
||||
params,
|
||||
playwrightOptions,
|
||||
locations: ['us_central', 'us_east'],
|
||||
privateLocations: ['Germany'],
|
||||
tags: ['tag3', 'tag4'],
|
||||
ignoreHTTPSErrors: false,
|
||||
apmServiceName: 'bean-service',
|
||||
},
|
||||
];
|
||||
|
||||
it('properly normalizes browser monitor', () => {
|
||||
const actual = normalizeProjectMonitors({
|
||||
locations,
|
||||
privateLocations,
|
||||
monitors,
|
||||
projectId,
|
||||
namespace: 'test-space',
|
||||
});
|
||||
expect(actual).toEqual([
|
||||
{
|
||||
...DEFAULT_FIELDS[DataStream.BROWSER],
|
||||
journey_id: 'test-id-1',
|
||||
ignore_https_errors: true,
|
||||
origin: 'project',
|
||||
locations: [
|
||||
{
|
||||
geo: {
|
||||
lat: 33.333,
|
||||
lon: 73.333,
|
||||
},
|
||||
id: 'us_central',
|
||||
isServiceManaged: true,
|
||||
label: 'Test Location',
|
||||
url: 'test-url',
|
||||
status: 'ga',
|
||||
},
|
||||
],
|
||||
name: 'test-name-1',
|
||||
schedule: {
|
||||
number: '3',
|
||||
unit: 'm',
|
||||
},
|
||||
screenshots: 'off',
|
||||
'service.name': 'cart-service',
|
||||
'source.project.content': 'test content 1',
|
||||
tags: ['tag1', 'tag2'],
|
||||
'throttling.config': '5d/10u/20l',
|
||||
'throttling.download_speed': '5',
|
||||
'throttling.is_enabled': true,
|
||||
'throttling.latency': '20',
|
||||
'throttling.upload_speed': '10',
|
||||
params: '',
|
||||
type: 'browser',
|
||||
project_id: projectId,
|
||||
namespace: 'test_space',
|
||||
original_space: 'test-space',
|
||||
custom_heartbeat_id: 'test-id-1-test-project-id-test-space',
|
||||
timeout: null,
|
||||
},
|
||||
{
|
||||
...DEFAULT_FIELDS[DataStream.BROWSER],
|
||||
journey_id: 'test-id-2',
|
||||
ignore_https_errors: false,
|
||||
origin: 'project',
|
||||
locations: [
|
||||
{
|
||||
geo: {
|
||||
lat: 33.333,
|
||||
lon: 73.333,
|
||||
},
|
||||
id: 'us_central',
|
||||
isServiceManaged: true,
|
||||
label: 'Test Location',
|
||||
url: 'test-url',
|
||||
status: 'ga',
|
||||
},
|
||||
{
|
||||
geo: {
|
||||
lat: 33.333,
|
||||
lon: 73.333,
|
||||
},
|
||||
id: 'us_east',
|
||||
isServiceManaged: true,
|
||||
label: 'Test Location',
|
||||
url: 'test-url',
|
||||
status: 'ga',
|
||||
},
|
||||
],
|
||||
name: 'test-name-2',
|
||||
params: '',
|
||||
playwright_options: '',
|
||||
schedule: {
|
||||
number: '10',
|
||||
unit: 'm',
|
||||
},
|
||||
screenshots: 'on',
|
||||
'service.name': 'bean-service',
|
||||
'source.project.content': 'test content 2',
|
||||
tags: ['tag3', 'tag4'],
|
||||
'throttling.config': '10d/15u/18l',
|
||||
'throttling.download_speed': '10',
|
||||
'throttling.is_enabled': true,
|
||||
'throttling.latency': '18',
|
||||
'throttling.upload_speed': '15',
|
||||
type: 'browser',
|
||||
project_id: projectId,
|
||||
namespace: 'test_space',
|
||||
original_space: 'test-space',
|
||||
custom_heartbeat_id: 'test-id-2-test-project-id-test-space',
|
||||
timeout: null,
|
||||
},
|
||||
{
|
||||
...DEFAULT_FIELDS[DataStream.BROWSER],
|
||||
journey_id: 'test-id-3',
|
||||
ignore_https_errors: false,
|
||||
origin: 'project',
|
||||
locations: [
|
||||
{
|
||||
geo: {
|
||||
lat: 33.333,
|
||||
lon: 73.333,
|
||||
},
|
||||
id: 'us_central',
|
||||
isServiceManaged: true,
|
||||
label: 'Test Location',
|
||||
url: 'test-url',
|
||||
status: 'ga',
|
||||
},
|
||||
{
|
||||
geo: {
|
||||
lat: 33.333,
|
||||
lon: 73.333,
|
||||
},
|
||||
id: 'us_east',
|
||||
isServiceManaged: true,
|
||||
label: 'Test Location',
|
||||
url: 'test-url',
|
||||
status: 'ga',
|
||||
},
|
||||
privateLocations[0],
|
||||
],
|
||||
name: 'test-name-3',
|
||||
params: JSON.stringify(params),
|
||||
playwright_options: JSON.stringify(playwrightOptions),
|
||||
schedule: {
|
||||
number: '10',
|
||||
unit: 'm',
|
||||
},
|
||||
screenshots: 'on',
|
||||
'service.name': 'bean-service',
|
||||
'source.project.content': 'test content 3',
|
||||
tags: ['tag3', 'tag4'],
|
||||
'throttling.config': '10d/15u/18l',
|
||||
'throttling.download_speed': '10',
|
||||
'throttling.is_enabled': true,
|
||||
'throttling.latency': '18',
|
||||
'throttling.upload_speed': '15',
|
||||
type: 'browser',
|
||||
project_id: projectId,
|
||||
namespace: 'test_space',
|
||||
original_space: 'test-space',
|
||||
custom_heartbeat_id: 'test-id-3-test-project-id-test-space',
|
||||
timeout: null,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,157 +0,0 @@
|
|||
/*
|
||||
* 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 { PrivateLocation } from '../../../common/runtime_types';
|
||||
import { DEFAULT_FIELDS } from '../../../common/constants/monitor_defaults';
|
||||
import { formatKibanaNamespace } from '../../../common/formatters';
|
||||
import {
|
||||
BrowserFields,
|
||||
ConfigKey,
|
||||
DataStream,
|
||||
FormMonitorType,
|
||||
Locations,
|
||||
ProjectBrowserMonitor,
|
||||
ScheduleUnit,
|
||||
SourceType,
|
||||
} from '../../../common/runtime_types/monitor_management';
|
||||
|
||||
/* Represents all of the push-monitor related fields that need to be
|
||||
* normalized. Excludes fields that we do not support for push monitors
|
||||
* This type ensures that contributors remember to add normalizers for push
|
||||
* monitors where appropriate when new keys are added to browser montiors */
|
||||
type NormalizedPublicFields = Omit<
|
||||
BrowserFields,
|
||||
| ConfigKey.METADATA
|
||||
| ConfigKey.SOURCE_INLINE
|
||||
| ConfigKey.SOURCE_ZIP_URL
|
||||
| ConfigKey.SOURCE_ZIP_USERNAME
|
||||
| ConfigKey.SOURCE_ZIP_PASSWORD
|
||||
| ConfigKey.SOURCE_ZIP_FOLDER
|
||||
| ConfigKey.SOURCE_ZIP_PROXY_URL
|
||||
| ConfigKey.ZIP_URL_TLS_CERTIFICATE_AUTHORITIES
|
||||
| ConfigKey.ZIP_URL_TLS_CERTIFICATE
|
||||
| ConfigKey.ZIP_URL_TLS_KEY
|
||||
| ConfigKey.ZIP_URL_TLS_KEY_PASSPHRASE
|
||||
| ConfigKey.ZIP_URL_TLS_VERIFICATION_MODE
|
||||
| ConfigKey.ZIP_URL_TLS_VERSION
|
||||
| ConfigKey.JOURNEY_FILTERS_TAGS
|
||||
| ConfigKey.SYNTHETICS_ARGS
|
||||
| ConfigKey.PORT
|
||||
| ConfigKey.URLS
|
||||
>;
|
||||
|
||||
export const normalizeProjectMonitor = ({
|
||||
locations = [],
|
||||
privateLocations = [],
|
||||
monitor,
|
||||
projectId,
|
||||
namespace,
|
||||
}: {
|
||||
locations: Locations;
|
||||
privateLocations: PrivateLocation[];
|
||||
monitor: ProjectBrowserMonitor;
|
||||
projectId: string;
|
||||
namespace: string;
|
||||
}): BrowserFields => {
|
||||
const defaultFields = DEFAULT_FIELDS[DataStream.BROWSER];
|
||||
const normalizedFields: NormalizedPublicFields = {
|
||||
[ConfigKey.MONITOR_TYPE]: DataStream.BROWSER,
|
||||
[ConfigKey.FORM_MONITOR_TYPE]: FormMonitorType.MULTISTEP,
|
||||
[ConfigKey.MONITOR_SOURCE_TYPE]: SourceType.PROJECT,
|
||||
[ConfigKey.NAME]: monitor.name || '',
|
||||
[ConfigKey.SCHEDULE]: {
|
||||
number: `${monitor.schedule}`,
|
||||
unit: ScheduleUnit.MINUTES,
|
||||
},
|
||||
[ConfigKey.PROJECT_ID]: projectId || defaultFields[ConfigKey.PROJECT_ID],
|
||||
[ConfigKey.JOURNEY_ID]: monitor.id || defaultFields[ConfigKey.JOURNEY_ID],
|
||||
[ConfigKey.SOURCE_PROJECT_CONTENT]:
|
||||
monitor.content || defaultFields[ConfigKey.SOURCE_PROJECT_CONTENT],
|
||||
[ConfigKey.LOCATIONS]: getMonitorLocations({
|
||||
monitor,
|
||||
privateLocations,
|
||||
publicLocations: locations,
|
||||
}),
|
||||
[ConfigKey.THROTTLING_CONFIG]: monitor.throttling
|
||||
? `${monitor.throttling.download}d/${monitor.throttling.upload}u/${monitor.throttling.latency}l`
|
||||
: defaultFields[ConfigKey.THROTTLING_CONFIG],
|
||||
[ConfigKey.DOWNLOAD_SPEED]: `${
|
||||
monitor.throttling?.download || defaultFields[ConfigKey.DOWNLOAD_SPEED]
|
||||
}`,
|
||||
[ConfigKey.UPLOAD_SPEED]: `${
|
||||
monitor.throttling?.upload || defaultFields[ConfigKey.UPLOAD_SPEED]
|
||||
}`,
|
||||
[ConfigKey.IS_THROTTLING_ENABLED]:
|
||||
Boolean(monitor.throttling) || defaultFields[ConfigKey.IS_THROTTLING_ENABLED],
|
||||
[ConfigKey.LATENCY]: `${monitor.throttling?.latency || defaultFields[ConfigKey.LATENCY]}`,
|
||||
[ConfigKey.APM_SERVICE_NAME]:
|
||||
monitor.apmServiceName || defaultFields[ConfigKey.APM_SERVICE_NAME],
|
||||
[ConfigKey.IGNORE_HTTPS_ERRORS]:
|
||||
monitor.ignoreHTTPSErrors || defaultFields[ConfigKey.IGNORE_HTTPS_ERRORS],
|
||||
[ConfigKey.SCREENSHOTS]: monitor.screenshot || defaultFields[ConfigKey.SCREENSHOTS],
|
||||
[ConfigKey.TAGS]: monitor.tags || defaultFields[ConfigKey.TAGS],
|
||||
[ConfigKey.PLAYWRIGHT_OPTIONS]: Object.keys(monitor.playwrightOptions || {}).length
|
||||
? JSON.stringify(monitor.playwrightOptions)
|
||||
: defaultFields[ConfigKey.PLAYWRIGHT_OPTIONS],
|
||||
[ConfigKey.PARAMS]: Object.keys(monitor.params || {}).length
|
||||
? JSON.stringify(monitor.params)
|
||||
: defaultFields[ConfigKey.PARAMS],
|
||||
[ConfigKey.JOURNEY_FILTERS_MATCH]:
|
||||
monitor.filter?.match || defaultFields[ConfigKey.JOURNEY_FILTERS_MATCH],
|
||||
[ConfigKey.NAMESPACE]: formatKibanaNamespace(namespace) || defaultFields[ConfigKey.NAMESPACE],
|
||||
[ConfigKey.ORIGINAL_SPACE]: namespace || defaultFields[ConfigKey.ORIGINAL_SPACE],
|
||||
[ConfigKey.CUSTOM_HEARTBEAT_ID]: `${monitor.id}-${projectId}-${namespace}`,
|
||||
[ConfigKey.TIMEOUT]: null,
|
||||
[ConfigKey.ENABLED]: monitor.enabled ?? defaultFields[ConfigKey.ENABLED],
|
||||
};
|
||||
return {
|
||||
...DEFAULT_FIELDS[DataStream.BROWSER],
|
||||
...normalizedFields,
|
||||
};
|
||||
};
|
||||
|
||||
export const normalizeProjectMonitors = ({
|
||||
locations = [],
|
||||
privateLocations = [],
|
||||
monitors = [],
|
||||
projectId,
|
||||
namespace,
|
||||
}: {
|
||||
locations: Locations;
|
||||
privateLocations: PrivateLocation[];
|
||||
monitors: ProjectBrowserMonitor[];
|
||||
projectId: string;
|
||||
namespace: string;
|
||||
}) => {
|
||||
return monitors.map((monitor) => {
|
||||
return normalizeProjectMonitor({ monitor, locations, privateLocations, projectId, namespace });
|
||||
});
|
||||
};
|
||||
|
||||
export const getMonitorLocations = ({
|
||||
privateLocations,
|
||||
publicLocations,
|
||||
monitor,
|
||||
}: {
|
||||
monitor: ProjectBrowserMonitor;
|
||||
privateLocations: PrivateLocation[];
|
||||
publicLocations: Locations;
|
||||
}) => {
|
||||
const publicLocs =
|
||||
monitor.locations?.map((id) => {
|
||||
return publicLocations.find((location) => location.id === id);
|
||||
}) || [];
|
||||
const privateLocs =
|
||||
monitor.privateLocations?.map((locationName) => {
|
||||
return privateLocations.find(
|
||||
(location) => location.label.toLowerCase() === locationName.toLowerCase()
|
||||
);
|
||||
}) || [];
|
||||
return [...publicLocs, ...privateLocs].filter(
|
||||
(location) => location !== undefined
|
||||
) as BrowserFields[ConfigKey.LOCATIONS];
|
||||
};
|
|
@ -7,6 +7,7 @@
|
|||
import { KibanaRequest, SavedObjectsClientContract } from '@kbn/core/server';
|
||||
import { NewPackagePolicy } from '@kbn/fleet-plugin/common';
|
||||
import { NewPackagePolicyWithId } from '@kbn/fleet-plugin/server/services/package_policy';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { formatSyntheticsPolicy } from '../../../common/formatters/format_synthetics_policy';
|
||||
import { getSyntheticsPrivateLocations } from '../../legacy_uptime/lib/saved_objects/private_locations';
|
||||
import {
|
||||
|
@ -55,7 +56,7 @@ export class SyntheticsPrivateLocation {
|
|||
|
||||
const { label: locName } = privateLocation;
|
||||
|
||||
const newPolicy = { ...newPolicyTemplate };
|
||||
const newPolicy = cloneDeep(newPolicyTemplate);
|
||||
|
||||
try {
|
||||
newPolicy.is_managed = true;
|
||||
|
|
|
@ -0,0 +1,286 @@
|
|||
/*
|
||||
* 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 {
|
||||
DataStream,
|
||||
ScreenshotOption,
|
||||
Locations,
|
||||
LocationStatus,
|
||||
ProjectMonitor,
|
||||
PrivateLocation,
|
||||
} from '../../../../common/runtime_types';
|
||||
import { DEFAULT_FIELDS } from '../../../../common/constants/monitor_defaults';
|
||||
import { normalizeProjectMonitors } from '.';
|
||||
|
||||
describe('browser normalizers', () => {
|
||||
describe('normalize push monitors', () => {
|
||||
const playwrightOptions = {
|
||||
headless: true,
|
||||
};
|
||||
const params = {
|
||||
url: 'test-url',
|
||||
};
|
||||
const projectId = 'test-project-id';
|
||||
const locations: Locations = [
|
||||
{
|
||||
id: 'us_central',
|
||||
label: 'Test Location',
|
||||
geo: { lat: 33.333, lon: 73.333 },
|
||||
url: 'test-url',
|
||||
isServiceManaged: true,
|
||||
status: LocationStatus.GA,
|
||||
},
|
||||
{
|
||||
id: 'us_east',
|
||||
label: 'Test Location',
|
||||
geo: { lat: 33.333, lon: 73.333 },
|
||||
url: 'test-url',
|
||||
isServiceManaged: true,
|
||||
status: LocationStatus.GA,
|
||||
},
|
||||
];
|
||||
const privateLocations: PrivateLocation[] = [
|
||||
{
|
||||
id: 'germany',
|
||||
label: 'Germany',
|
||||
isServiceManaged: false,
|
||||
concurrentMonitors: 1,
|
||||
agentPolicyId: 'germany',
|
||||
},
|
||||
];
|
||||
const monitors: ProjectMonitor[] = [
|
||||
{
|
||||
id: 'test-id-1',
|
||||
screenshot: ScreenshotOption.OFF,
|
||||
name: 'test-name-1',
|
||||
content: 'test content 1',
|
||||
schedule: 3,
|
||||
throttling: {
|
||||
latency: 20,
|
||||
upload: 10,
|
||||
download: 5,
|
||||
},
|
||||
locations: ['us_central'],
|
||||
tags: ['tag1', 'tag2'],
|
||||
ignoreHTTPSErrors: true,
|
||||
apmServiceName: 'cart-service',
|
||||
type: DataStream.BROWSER,
|
||||
},
|
||||
{
|
||||
id: 'test-id-2',
|
||||
screenshot: ScreenshotOption.ON,
|
||||
name: 'test-name-2',
|
||||
content: 'test content 2',
|
||||
schedule: 10,
|
||||
throttling: {
|
||||
latency: 18,
|
||||
upload: 15,
|
||||
download: 10,
|
||||
},
|
||||
params: {},
|
||||
playwrightOptions: {},
|
||||
locations: ['us_central', 'us_east'],
|
||||
tags: ['tag3', 'tag4'],
|
||||
ignoreHTTPSErrors: false,
|
||||
apmServiceName: 'bean-service',
|
||||
type: DataStream.BROWSER,
|
||||
},
|
||||
{
|
||||
id: 'test-id-3',
|
||||
screenshot: ScreenshotOption.ON,
|
||||
name: 'test-name-3',
|
||||
content: 'test content 3',
|
||||
schedule: 10,
|
||||
throttling: {
|
||||
latency: 18,
|
||||
upload: 15,
|
||||
download: 10,
|
||||
},
|
||||
params,
|
||||
playwrightOptions,
|
||||
locations: ['us_central', 'us_east'],
|
||||
privateLocations: ['Germany'],
|
||||
tags: ['tag3', 'tag4'],
|
||||
ignoreHTTPSErrors: false,
|
||||
apmServiceName: 'bean-service',
|
||||
type: DataStream.BROWSER,
|
||||
},
|
||||
];
|
||||
|
||||
it('properly normalizes browser monitor', () => {
|
||||
const actual = normalizeProjectMonitors({
|
||||
locations,
|
||||
privateLocations,
|
||||
monitors,
|
||||
projectId,
|
||||
namespace: 'test-space',
|
||||
});
|
||||
expect(actual).toEqual([
|
||||
{
|
||||
normalizedFields: {
|
||||
...DEFAULT_FIELDS[DataStream.BROWSER],
|
||||
journey_id: 'test-id-1',
|
||||
ignore_https_errors: true,
|
||||
origin: 'project',
|
||||
locations: [
|
||||
{
|
||||
geo: {
|
||||
lat: 33.333,
|
||||
lon: 73.333,
|
||||
},
|
||||
id: 'us_central',
|
||||
isServiceManaged: true,
|
||||
label: 'Test Location',
|
||||
url: 'test-url',
|
||||
status: 'ga',
|
||||
},
|
||||
],
|
||||
name: 'test-name-1',
|
||||
schedule: {
|
||||
number: '3',
|
||||
unit: 'm',
|
||||
},
|
||||
screenshots: 'off',
|
||||
'service.name': 'cart-service',
|
||||
'source.project.content': 'test content 1',
|
||||
tags: ['tag1', 'tag2'],
|
||||
'throttling.config': '5d/10u/20l',
|
||||
'throttling.download_speed': '5',
|
||||
'throttling.is_enabled': true,
|
||||
'throttling.latency': '20',
|
||||
'throttling.upload_speed': '10',
|
||||
params: '',
|
||||
type: 'browser',
|
||||
project_id: projectId,
|
||||
namespace: 'test_space',
|
||||
original_space: 'test-space',
|
||||
custom_heartbeat_id: 'test-id-1-test-project-id-test-space',
|
||||
timeout: null,
|
||||
},
|
||||
unsupportedKeys: [],
|
||||
},
|
||||
{
|
||||
normalizedFields: {
|
||||
...DEFAULT_FIELDS[DataStream.BROWSER],
|
||||
journey_id: 'test-id-2',
|
||||
ignore_https_errors: false,
|
||||
origin: 'project',
|
||||
locations: [
|
||||
{
|
||||
geo: {
|
||||
lat: 33.333,
|
||||
lon: 73.333,
|
||||
},
|
||||
id: 'us_central',
|
||||
isServiceManaged: true,
|
||||
label: 'Test Location',
|
||||
url: 'test-url',
|
||||
status: 'ga',
|
||||
},
|
||||
{
|
||||
geo: {
|
||||
lat: 33.333,
|
||||
lon: 73.333,
|
||||
},
|
||||
id: 'us_east',
|
||||
isServiceManaged: true,
|
||||
label: 'Test Location',
|
||||
url: 'test-url',
|
||||
status: 'ga',
|
||||
},
|
||||
],
|
||||
name: 'test-name-2',
|
||||
params: '',
|
||||
playwright_options: '',
|
||||
schedule: {
|
||||
number: '10',
|
||||
unit: 'm',
|
||||
},
|
||||
screenshots: 'on',
|
||||
'service.name': 'bean-service',
|
||||
'source.project.content': 'test content 2',
|
||||
tags: ['tag3', 'tag4'],
|
||||
'throttling.config': '10d/15u/18l',
|
||||
'throttling.download_speed': '10',
|
||||
'throttling.is_enabled': true,
|
||||
'throttling.latency': '18',
|
||||
'throttling.upload_speed': '15',
|
||||
type: 'browser',
|
||||
project_id: projectId,
|
||||
namespace: 'test_space',
|
||||
original_space: 'test-space',
|
||||
custom_heartbeat_id: 'test-id-2-test-project-id-test-space',
|
||||
timeout: null,
|
||||
},
|
||||
unsupportedKeys: [],
|
||||
},
|
||||
{
|
||||
normalizedFields: {
|
||||
...DEFAULT_FIELDS[DataStream.BROWSER],
|
||||
journey_id: 'test-id-3',
|
||||
ignore_https_errors: false,
|
||||
origin: 'project',
|
||||
locations: [
|
||||
{
|
||||
geo: {
|
||||
lat: 33.333,
|
||||
lon: 73.333,
|
||||
},
|
||||
id: 'us_central',
|
||||
isServiceManaged: true,
|
||||
label: 'Test Location',
|
||||
url: 'test-url',
|
||||
status: 'ga',
|
||||
},
|
||||
{
|
||||
geo: {
|
||||
lat: 33.333,
|
||||
lon: 73.333,
|
||||
},
|
||||
id: 'us_east',
|
||||
isServiceManaged: true,
|
||||
label: 'Test Location',
|
||||
url: 'test-url',
|
||||
status: 'ga',
|
||||
},
|
||||
{
|
||||
id: 'germany',
|
||||
isServiceManaged: false,
|
||||
label: 'Germany',
|
||||
agentPolicyId: 'germany',
|
||||
concurrentMonitors: 1,
|
||||
},
|
||||
],
|
||||
name: 'test-name-3',
|
||||
params: JSON.stringify(params),
|
||||
playwright_options: JSON.stringify(playwrightOptions),
|
||||
schedule: {
|
||||
number: '10',
|
||||
unit: 'm',
|
||||
},
|
||||
screenshots: 'on',
|
||||
'service.name': 'bean-service',
|
||||
'source.project.content': 'test content 3',
|
||||
tags: ['tag3', 'tag4'],
|
||||
'throttling.config': '10d/15u/18l',
|
||||
'throttling.download_speed': '10',
|
||||
'throttling.is_enabled': true,
|
||||
'throttling.latency': '18',
|
||||
'throttling.upload_speed': '15',
|
||||
type: 'browser',
|
||||
project_id: projectId,
|
||||
namespace: 'test_space',
|
||||
original_space: 'test-space',
|
||||
custom_heartbeat_id: 'test-id-3-test-project-id-test-space',
|
||||
timeout: null,
|
||||
},
|
||||
unsupportedKeys: [],
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* 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 {
|
||||
BrowserFields,
|
||||
ConfigKey,
|
||||
DataStream,
|
||||
FormMonitorType,
|
||||
Locations,
|
||||
PrivateLocation,
|
||||
ProjectMonitor,
|
||||
} from '../../../../common/runtime_types';
|
||||
import { getNormalizeCommonFields, getValueInSeconds } from './common_fields';
|
||||
import { DEFAULT_FIELDS } from '../../../../common/constants/monitor_defaults';
|
||||
|
||||
export interface NormalizedProjectProps {
|
||||
locations: Locations;
|
||||
privateLocations: PrivateLocation[];
|
||||
monitor: ProjectMonitor;
|
||||
projectId: string;
|
||||
namespace: string;
|
||||
}
|
||||
|
||||
export const getNormalizeBrowserFields = ({
|
||||
locations = [],
|
||||
privateLocations = [],
|
||||
monitor,
|
||||
projectId,
|
||||
namespace,
|
||||
}: NormalizedProjectProps): { normalizedFields: BrowserFields; unsupportedKeys: string[] } => {
|
||||
const defaultFields = DEFAULT_FIELDS[DataStream.BROWSER];
|
||||
|
||||
const commonFields = getNormalizeCommonFields({
|
||||
locations,
|
||||
privateLocations,
|
||||
monitor,
|
||||
projectId,
|
||||
namespace,
|
||||
});
|
||||
|
||||
const normalizedFields = {
|
||||
...commonFields,
|
||||
[ConfigKey.MONITOR_TYPE]: DataStream.BROWSER,
|
||||
[ConfigKey.FORM_MONITOR_TYPE]: FormMonitorType.MULTISTEP,
|
||||
[ConfigKey.SOURCE_PROJECT_CONTENT]:
|
||||
monitor.content || defaultFields[ConfigKey.SOURCE_PROJECT_CONTENT],
|
||||
[ConfigKey.THROTTLING_CONFIG]: monitor.throttling
|
||||
? `${monitor.throttling.download}d/${monitor.throttling.upload}u/${monitor.throttling.latency}l`
|
||||
: defaultFields[ConfigKey.THROTTLING_CONFIG],
|
||||
[ConfigKey.DOWNLOAD_SPEED]: `${
|
||||
monitor.throttling?.download || defaultFields[ConfigKey.DOWNLOAD_SPEED]
|
||||
}`,
|
||||
[ConfigKey.UPLOAD_SPEED]: `${
|
||||
monitor.throttling?.upload || defaultFields[ConfigKey.UPLOAD_SPEED]
|
||||
}`,
|
||||
[ConfigKey.IS_THROTTLING_ENABLED]:
|
||||
Boolean(monitor.throttling) || defaultFields[ConfigKey.IS_THROTTLING_ENABLED],
|
||||
[ConfigKey.LATENCY]: `${monitor.throttling?.latency || defaultFields[ConfigKey.LATENCY]}`,
|
||||
[ConfigKey.IGNORE_HTTPS_ERRORS]:
|
||||
monitor.ignoreHTTPSErrors || defaultFields[ConfigKey.IGNORE_HTTPS_ERRORS],
|
||||
[ConfigKey.SCREENSHOTS]: monitor.screenshot || defaultFields[ConfigKey.SCREENSHOTS],
|
||||
[ConfigKey.PLAYWRIGHT_OPTIONS]: Object.keys(monitor.playwrightOptions || {}).length
|
||||
? JSON.stringify(monitor.playwrightOptions)
|
||||
: defaultFields[ConfigKey.PLAYWRIGHT_OPTIONS],
|
||||
[ConfigKey.PARAMS]: Object.keys(monitor.params || {}).length
|
||||
? JSON.stringify(monitor.params)
|
||||
: defaultFields[ConfigKey.PARAMS],
|
||||
[ConfigKey.JOURNEY_FILTERS_MATCH]:
|
||||
monitor.filter?.match || defaultFields[ConfigKey.JOURNEY_FILTERS_MATCH],
|
||||
[ConfigKey.TIMEOUT]: monitor.timeout
|
||||
? getValueInSeconds(monitor.timeout)
|
||||
: defaultFields[ConfigKey.TIMEOUT],
|
||||
};
|
||||
return {
|
||||
normalizedFields: {
|
||||
...defaultFields,
|
||||
...normalizedFields,
|
||||
},
|
||||
unsupportedKeys: [],
|
||||
};
|
||||
};
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* 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 { omit } from 'lodash';
|
||||
import { formatKibanaNamespace } from '../../../../common/formatters';
|
||||
import {
|
||||
BrowserFields,
|
||||
ConfigKey,
|
||||
CommonFields,
|
||||
DataStream,
|
||||
PrivateLocation,
|
||||
Locations,
|
||||
ProjectMonitor,
|
||||
ScheduleUnit,
|
||||
SourceType,
|
||||
} from '../../../../common/runtime_types';
|
||||
import { DEFAULT_FIELDS } from '../../../../common/constants/monitor_defaults';
|
||||
import { DEFAULT_COMMON_FIELDS } from '../../../../common/constants/monitor_defaults';
|
||||
import { NormalizedProjectProps } from '.';
|
||||
|
||||
export const getNormalizeCommonFields = ({
|
||||
locations = [],
|
||||
privateLocations = [],
|
||||
monitor,
|
||||
projectId,
|
||||
namespace,
|
||||
}: NormalizedProjectProps): CommonFields => {
|
||||
const defaultFields = DEFAULT_COMMON_FIELDS;
|
||||
|
||||
const normalizedFields = {
|
||||
[ConfigKey.JOURNEY_ID]: monitor.id || defaultFields[ConfigKey.JOURNEY_ID],
|
||||
[ConfigKey.MONITOR_SOURCE_TYPE]: SourceType.PROJECT,
|
||||
[ConfigKey.NAME]: monitor.name || '',
|
||||
[ConfigKey.SCHEDULE]: {
|
||||
number: `${monitor.schedule}`,
|
||||
unit: ScheduleUnit.MINUTES,
|
||||
},
|
||||
[ConfigKey.PROJECT_ID]: projectId,
|
||||
[ConfigKey.LOCATIONS]: getMonitorLocations({
|
||||
monitor,
|
||||
privateLocations,
|
||||
publicLocations: locations,
|
||||
}),
|
||||
[ConfigKey.APM_SERVICE_NAME]:
|
||||
monitor.apmServiceName || defaultFields[ConfigKey.APM_SERVICE_NAME],
|
||||
[ConfigKey.TAGS]: getOptionalListField(monitor.tags) || defaultFields[ConfigKey.TAGS],
|
||||
[ConfigKey.NAMESPACE]: formatKibanaNamespace(namespace) || defaultFields[ConfigKey.NAMESPACE],
|
||||
[ConfigKey.ORIGINAL_SPACE]: namespace || defaultFields[ConfigKey.NAMESPACE],
|
||||
[ConfigKey.CUSTOM_HEARTBEAT_ID]: getCustomHeartbeatId(monitor, projectId, namespace),
|
||||
[ConfigKey.ENABLED]: monitor.enabled ?? defaultFields[ConfigKey.ENABLED],
|
||||
};
|
||||
return {
|
||||
...defaultFields,
|
||||
...normalizedFields,
|
||||
};
|
||||
};
|
||||
|
||||
export const getCustomHeartbeatId = (
|
||||
monitor: NormalizedProjectProps['monitor'],
|
||||
projectId: string,
|
||||
namespace: string
|
||||
) => {
|
||||
return `${monitor.id}-${projectId}-${namespace}`;
|
||||
};
|
||||
|
||||
export const getMonitorLocations = ({
|
||||
privateLocations,
|
||||
publicLocations,
|
||||
monitor,
|
||||
}: {
|
||||
monitor: ProjectMonitor;
|
||||
privateLocations: PrivateLocation[];
|
||||
publicLocations: Locations;
|
||||
}) => {
|
||||
const publicLocs =
|
||||
monitor.locations?.map((id) => {
|
||||
return publicLocations.find((location) => location.id === id);
|
||||
}) || [];
|
||||
const privateLocs =
|
||||
monitor.privateLocations?.map((locationName) => {
|
||||
return privateLocations.find(
|
||||
(location) =>
|
||||
location.label.toLowerCase() === locationName.toLowerCase() ||
|
||||
location.id.toLowerCase() === locationName.toLowerCase()
|
||||
);
|
||||
}) || [];
|
||||
|
||||
return [...publicLocs, ...privateLocs].filter(
|
||||
(location) => location !== undefined
|
||||
) as BrowserFields[ConfigKey.LOCATIONS];
|
||||
};
|
||||
|
||||
export const getValueInSeconds = (value: string) => {
|
||||
const keyMap = {
|
||||
h: 60 * 60,
|
||||
m: 60,
|
||||
s: 1,
|
||||
};
|
||||
const key = value.slice(-1) as 'h' | 'm' | 's';
|
||||
const time = parseInt(value.slice(0, -1), 10);
|
||||
const valueInSeconds = time * (keyMap[key] || 1);
|
||||
return typeof valueInSeconds === 'number' ? `${valueInSeconds}` : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Accounts for array values that are optionally defined as a comma seperated list
|
||||
*
|
||||
* @param {Array | string} [value]
|
||||
* @returns {array} Returns an array
|
||||
*/
|
||||
export const getOptionalListField = (value?: string[] | string): string[] => {
|
||||
if (Array.isArray(value)) {
|
||||
return value;
|
||||
}
|
||||
return value ? value.split(',') : [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Accounts for heartbeat fields that are optionally an array or single string
|
||||
*
|
||||
* @param {Array | string} [value]
|
||||
* @returns {string} Returns first item when the value is an array, or the value itself
|
||||
*/
|
||||
export const getOptionalArrayField = (value: string[] | string = '') => {
|
||||
const array = getOptionalListField(value);
|
||||
return array[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* Flattens arbitrary yaml into a synthetics monitor compatible configuration
|
||||
*
|
||||
* @param {Object} [monitor]
|
||||
* @returns {Object} Returns an object containing synthetics-compatible configuration keys
|
||||
*/
|
||||
const flattenAndFormatObject = (obj: Record<string, unknown>, prefix = '', keys: string[]) =>
|
||||
Object.keys(obj).reduce<Record<string, unknown>>((acc, k) => {
|
||||
const pre = prefix.length ? prefix + '.' : '';
|
||||
const key = pre + k;
|
||||
|
||||
/* If the key is an array of numbers, convert to an array of strings */
|
||||
if (Array.isArray(obj[k])) {
|
||||
acc[key] = (obj[k] as unknown[]).map((value) =>
|
||||
typeof value === 'number' ? String(value) : value
|
||||
);
|
||||
return acc;
|
||||
}
|
||||
|
||||
/* if the key is a supported key stop flattening early */
|
||||
if (keys.includes(key)) {
|
||||
acc[key] = obj[k];
|
||||
return acc;
|
||||
}
|
||||
|
||||
if (typeof obj[k] === 'object') {
|
||||
Object.assign(acc, flattenAndFormatObject(obj[k] as Record<string, unknown>, pre + k, keys));
|
||||
} else {
|
||||
acc[key] = obj[k];
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
export const normalizeYamlConfig = (monitor: NormalizedProjectProps['monitor']) => {
|
||||
const defaultFields = DEFAULT_FIELDS[monitor.type as DataStream];
|
||||
const supportedKeys = Object.keys(defaultFields);
|
||||
const flattenedConfig = flattenAndFormatObject(monitor, '', supportedKeys);
|
||||
const {
|
||||
locations: _locations,
|
||||
privateLocations: _privateLocations,
|
||||
content: _content,
|
||||
id: _id,
|
||||
...yamlConfig
|
||||
} = flattenedConfig;
|
||||
const unsupportedKeys = Object.keys(yamlConfig).filter((key) => !supportedKeys.includes(key));
|
||||
const supportedYamlConfig = omit(yamlConfig, unsupportedKeys);
|
||||
|
||||
return {
|
||||
yamlConfig: supportedYamlConfig,
|
||||
unsupportedKeys,
|
||||
};
|
||||
};
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* 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 { getNormalizeCommonFields } from './common_fields';
|
||||
import { NormalizedProjectProps } from './browser_monitor';
|
||||
import { DEFAULT_FIELDS } from '../../../../common/constants/monitor_defaults';
|
||||
import {
|
||||
ConfigKey,
|
||||
DataStream,
|
||||
FormMonitorType,
|
||||
HTTPFields,
|
||||
} from '../../../../common/runtime_types/monitor_management';
|
||||
import { normalizeYamlConfig, getValueInSeconds, getOptionalArrayField } from './common_fields';
|
||||
|
||||
export const getNormalizeHTTPFields = ({
|
||||
locations = [],
|
||||
privateLocations = [],
|
||||
monitor,
|
||||
projectId,
|
||||
namespace,
|
||||
}: NormalizedProjectProps): { normalizedFields: HTTPFields; unsupportedKeys: string[] } => {
|
||||
const defaultFields = DEFAULT_FIELDS[DataStream.HTTP];
|
||||
const { yamlConfig, unsupportedKeys } = normalizeYamlConfig(monitor);
|
||||
|
||||
const commonFields = getNormalizeCommonFields({
|
||||
locations,
|
||||
privateLocations,
|
||||
monitor,
|
||||
projectId,
|
||||
namespace,
|
||||
});
|
||||
|
||||
const normalizedFields = {
|
||||
...yamlConfig,
|
||||
...commonFields,
|
||||
[ConfigKey.MONITOR_TYPE]: DataStream.HTTP,
|
||||
[ConfigKey.FORM_MONITOR_TYPE]: FormMonitorType.HTTP,
|
||||
[ConfigKey.URLS]: getOptionalArrayField(monitor.urls) || defaultFields[ConfigKey.URLS],
|
||||
[ConfigKey.MAX_REDIRECTS]:
|
||||
monitor[ConfigKey.MAX_REDIRECTS] || defaultFields[ConfigKey.MAX_REDIRECTS],
|
||||
[ConfigKey.TIMEOUT]: monitor.timeout
|
||||
? getValueInSeconds(monitor.timeout)
|
||||
: defaultFields[ConfigKey.TIMEOUT],
|
||||
};
|
||||
return {
|
||||
normalizedFields: {
|
||||
...defaultFields,
|
||||
...normalizedFields,
|
||||
},
|
||||
unsupportedKeys,
|
||||
};
|
||||
};
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* 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 { getNormalizeCommonFields } from './common_fields';
|
||||
import { NormalizedProjectProps } from './browser_monitor';
|
||||
import { DEFAULT_FIELDS } from '../../../../common/constants/monitor_defaults';
|
||||
import {
|
||||
ConfigKey,
|
||||
DataStream,
|
||||
FormMonitorType,
|
||||
ICMPFields,
|
||||
} from '../../../../common/runtime_types/monitor_management';
|
||||
import { normalizeYamlConfig, getValueInSeconds, getOptionalArrayField } from './common_fields';
|
||||
|
||||
export const getNormalizeICMPFields = ({
|
||||
locations = [],
|
||||
privateLocations = [],
|
||||
monitor,
|
||||
projectId,
|
||||
namespace,
|
||||
}: NormalizedProjectProps): { normalizedFields: ICMPFields; unsupportedKeys: string[] } => {
|
||||
const defaultFields = DEFAULT_FIELDS[DataStream.ICMP];
|
||||
const { yamlConfig, unsupportedKeys } = normalizeYamlConfig(monitor);
|
||||
|
||||
const commonFields = getNormalizeCommonFields({
|
||||
locations,
|
||||
privateLocations,
|
||||
monitor,
|
||||
projectId,
|
||||
namespace,
|
||||
});
|
||||
|
||||
const normalizedFields = {
|
||||
...yamlConfig,
|
||||
...commonFields,
|
||||
[ConfigKey.MONITOR_TYPE]: DataStream.ICMP,
|
||||
[ConfigKey.FORM_MONITOR_TYPE]: FormMonitorType.ICMP,
|
||||
[ConfigKey.HOSTS]:
|
||||
getOptionalArrayField(monitor[ConfigKey.HOSTS]) || defaultFields[ConfigKey.HOSTS],
|
||||
[ConfigKey.TIMEOUT]: monitor.timeout
|
||||
? getValueInSeconds(monitor.timeout)
|
||||
: defaultFields[ConfigKey.TIMEOUT],
|
||||
[ConfigKey.WAIT]: monitor.wait
|
||||
? getValueInSeconds(monitor.wait) || defaultFields[ConfigKey.WAIT]
|
||||
: defaultFields[ConfigKey.WAIT],
|
||||
};
|
||||
return {
|
||||
normalizedFields: {
|
||||
...defaultFields,
|
||||
...normalizedFields,
|
||||
},
|
||||
unsupportedKeys,
|
||||
};
|
||||
};
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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 {
|
||||
DataStream,
|
||||
PrivateLocation,
|
||||
Locations,
|
||||
ProjectMonitor,
|
||||
} from '../../../../common/runtime_types';
|
||||
import { getNormalizeBrowserFields } from './browser_monitor';
|
||||
import { getNormalizeICMPFields } from './icmp_monitor';
|
||||
import { getNormalizeTCPFields } from './tcp_monitor';
|
||||
import { getNormalizeHTTPFields } from './http_monitor';
|
||||
|
||||
export interface NormalizedProjectProps {
|
||||
locations: Locations;
|
||||
privateLocations: PrivateLocation[];
|
||||
monitor: ProjectMonitor;
|
||||
projectId: string;
|
||||
namespace: string;
|
||||
}
|
||||
|
||||
export const normalizeProjectMonitor = (props: NormalizedProjectProps) => {
|
||||
const { monitor } = props;
|
||||
const type = monitor.type || DataStream.BROWSER;
|
||||
|
||||
switch (type) {
|
||||
case DataStream.BROWSER:
|
||||
return getNormalizeBrowserFields(props);
|
||||
|
||||
case DataStream.HTTP:
|
||||
return getNormalizeHTTPFields(props);
|
||||
|
||||
case DataStream.TCP:
|
||||
return getNormalizeTCPFields(props);
|
||||
|
||||
case DataStream.ICMP:
|
||||
return getNormalizeICMPFields(props);
|
||||
default:
|
||||
throw new Error(`Unsupported monitor type ${monitor.type}`);
|
||||
}
|
||||
};
|
||||
|
||||
export const normalizeProjectMonitors = ({
|
||||
locations = [],
|
||||
privateLocations = [],
|
||||
monitors = [],
|
||||
projectId,
|
||||
namespace,
|
||||
}: {
|
||||
locations: Locations;
|
||||
privateLocations: PrivateLocation[];
|
||||
monitors: ProjectMonitor[];
|
||||
projectId: string;
|
||||
namespace: string;
|
||||
}) => {
|
||||
return monitors.map((monitor) => {
|
||||
return normalizeProjectMonitor({ monitor, locations, privateLocations, projectId, namespace });
|
||||
});
|
||||
};
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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 { NormalizedProjectProps } from './browser_monitor';
|
||||
import { DEFAULT_FIELDS } from '../../../../common/constants/monitor_defaults';
|
||||
import { normalizeYamlConfig, getValueInSeconds } from './common_fields';
|
||||
|
||||
import {
|
||||
ConfigKey,
|
||||
DataStream,
|
||||
FormMonitorType,
|
||||
TCPFields,
|
||||
} from '../../../../common/runtime_types/monitor_management';
|
||||
import { getNormalizeCommonFields, getOptionalArrayField } from './common_fields';
|
||||
|
||||
export const getNormalizeTCPFields = ({
|
||||
locations = [],
|
||||
privateLocations = [],
|
||||
monitor,
|
||||
projectId,
|
||||
namespace,
|
||||
}: NormalizedProjectProps): { normalizedFields: TCPFields; unsupportedKeys: string[] } => {
|
||||
const defaultFields = DEFAULT_FIELDS[DataStream.TCP];
|
||||
const { yamlConfig, unsupportedKeys } = normalizeYamlConfig(monitor);
|
||||
|
||||
const commonFields = getNormalizeCommonFields({
|
||||
locations,
|
||||
privateLocations,
|
||||
monitor,
|
||||
projectId,
|
||||
namespace,
|
||||
});
|
||||
|
||||
const normalizedFields = {
|
||||
...yamlConfig,
|
||||
...commonFields,
|
||||
[ConfigKey.MONITOR_TYPE]: DataStream.TCP,
|
||||
[ConfigKey.FORM_MONITOR_TYPE]: FormMonitorType.TCP,
|
||||
[ConfigKey.HOSTS]:
|
||||
getOptionalArrayField(monitor[ConfigKey.HOSTS]) || defaultFields[ConfigKey.HOSTS],
|
||||
[ConfigKey.TIMEOUT]: monitor.timeout
|
||||
? getValueInSeconds(monitor.timeout)
|
||||
: defaultFields[ConfigKey.TIMEOUT],
|
||||
};
|
||||
return {
|
||||
normalizedFields: {
|
||||
...defaultFields,
|
||||
...normalizedFields,
|
||||
},
|
||||
unsupportedKeys,
|
||||
};
|
||||
};
|
|
@ -10,20 +10,21 @@ import {
|
|||
INSUFFICIENT_FLEET_PERMISSIONS,
|
||||
ProjectMonitorFormatter,
|
||||
} from './project_monitor_formatter';
|
||||
import { LocationStatus } from '../../common/runtime_types';
|
||||
import { LocationStatus } from '../../../common/runtime_types';
|
||||
import { times } from 'lodash';
|
||||
import { SyntheticsService } from './synthetics_service';
|
||||
import { UptimeServerSetup } from '../legacy_uptime/lib/adapters';
|
||||
import { SyntheticsService } from '../synthetics_service';
|
||||
import { UptimeServerSetup } from '../../legacy_uptime/lib/adapters';
|
||||
import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks';
|
||||
import { SyntheticsMonitorClient } from './synthetics_monitor/synthetics_monitor_client';
|
||||
import { SyntheticsMonitorClient } from '../synthetics_monitor/synthetics_monitor_client';
|
||||
import { httpServerMock } from '@kbn/core-http-server-mocks';
|
||||
import { Subject } from 'rxjs';
|
||||
import { formatSecrets } from './utils';
|
||||
import { formatSecrets } from '../utils';
|
||||
|
||||
import * as telemetryHooks from '../routes/telemetry/monitor_upgrade_sender';
|
||||
import * as telemetryHooks from '../../routes/telemetry/monitor_upgrade_sender';
|
||||
|
||||
const testMonitors = [
|
||||
{
|
||||
type: 'browser',
|
||||
throttling: { download: 5, upload: 3, latency: 20 },
|
||||
schedule: 3,
|
||||
locations: [],
|
||||
|
@ -46,6 +47,7 @@ const testMonitors = [
|
|||
filter: { match: 'check if title is present 10 0' },
|
||||
},
|
||||
{
|
||||
type: 'browser',
|
||||
throttling: { download: 5, upload: 3, latency: 20 },
|
||||
schedule: 3,
|
||||
locations: [],
|
|
@ -13,30 +13,34 @@ import {
|
|||
SavedObjectsFindResult,
|
||||
} from '@kbn/core/server';
|
||||
import { EncryptedSavedObjectsClient } from '@kbn/encrypted-saved-objects-plugin/server';
|
||||
import { syncNewMonitorBulk } from '../routes/monitor_cruds/bulk_cruds/add_monitor_bulk';
|
||||
import { deleteMonitorBulk } from '../routes/monitor_cruds/bulk_cruds/delete_monitor_bulk';
|
||||
import { SyntheticsMonitorClient } from './synthetics_monitor/synthetics_monitor_client';
|
||||
import { syncNewMonitorBulk } from '../../routes/monitor_cruds/bulk_cruds/add_monitor_bulk';
|
||||
import { deleteMonitorBulk } from '../../routes/monitor_cruds/bulk_cruds/delete_monitor_bulk';
|
||||
import { SyntheticsMonitorClient } from '../synthetics_monitor/synthetics_monitor_client';
|
||||
import {
|
||||
BrowserFields,
|
||||
ConfigKey,
|
||||
SyntheticsMonitorWithSecrets,
|
||||
EncryptedSyntheticsMonitor,
|
||||
ServiceLocationErrors,
|
||||
ProjectBrowserMonitor,
|
||||
ProjectMonitor,
|
||||
Locations,
|
||||
SyntheticsMonitor,
|
||||
MonitorFields,
|
||||
PrivateLocation,
|
||||
} from '../../common/runtime_types';
|
||||
} from '../../../common/runtime_types';
|
||||
import {
|
||||
syntheticsMonitorType,
|
||||
syntheticsMonitor,
|
||||
} from '../legacy_uptime/lib/saved_objects/synthetics_monitor';
|
||||
import { normalizeProjectMonitor } from './normalizers/browser';
|
||||
import { formatSecrets, normalizeSecrets } from './utils/secrets';
|
||||
import { syncEditedMonitor } from '../routes/monitor_cruds/edit_monitor';
|
||||
import { validateProjectMonitor } from '../routes/monitor_cruds/monitor_validation';
|
||||
import type { UptimeServerSetup } from '../legacy_uptime/lib/adapters/framework';
|
||||
} from '../../legacy_uptime/lib/saved_objects/synthetics_monitor';
|
||||
import { UptimeServerSetup } from '../../legacy_uptime/lib/adapters';
|
||||
import { formatSecrets, normalizeSecrets } from '../utils/secrets';
|
||||
import { syncEditedMonitor } from '../../routes/monitor_cruds/edit_monitor';
|
||||
import {
|
||||
validateProjectMonitor,
|
||||
validateMonitor,
|
||||
ValidationResult,
|
||||
} from '../../routes/monitor_cruds/monitor_validation';
|
||||
import { normalizeProjectMonitor } from './normalizers';
|
||||
|
||||
interface StaleMonitor {
|
||||
stale: boolean;
|
||||
|
@ -44,7 +48,7 @@ interface StaleMonitor {
|
|||
savedObjectId: string;
|
||||
}
|
||||
type StaleMonitorMap = Record<string, StaleMonitor>;
|
||||
type FailedMonitors = Array<{ id?: string; reason: string; details: string; payload?: object }>;
|
||||
type FailedError = Array<{ id?: string; reason: string; details: string; payload?: object }>;
|
||||
|
||||
export const INSUFFICIENT_FLEET_PERMISSIONS =
|
||||
'Insufficient permissions. In order to configure private locations, you must have Fleet and Integrations write permissions. To resolve, please generate a new API key with a user who has Fleet and Integrations write permissions.';
|
||||
|
@ -58,13 +62,13 @@ export class ProjectMonitorFormatter {
|
|||
private savedObjectsClient: SavedObjectsClientContract;
|
||||
private encryptedSavedObjectsClient: EncryptedSavedObjectsClient;
|
||||
private staleMonitorsMap: StaleMonitorMap = {};
|
||||
private monitors: ProjectBrowserMonitor[] = [];
|
||||
private monitors: ProjectMonitor[] = [];
|
||||
public createdMonitors: string[] = [];
|
||||
public deletedMonitors: string[] = [];
|
||||
public updatedMonitors: string[] = [];
|
||||
public staleMonitors: string[] = [];
|
||||
public failedMonitors: FailedMonitors = [];
|
||||
public failedStaleMonitors: FailedMonitors = [];
|
||||
public failedMonitors: FailedError = [];
|
||||
public failedStaleMonitors: FailedError = [];
|
||||
private server: UptimeServerSetup;
|
||||
private projectFilter: string;
|
||||
private syntheticsMonitorClient: SyntheticsMonitorClient;
|
||||
|
@ -94,7 +98,7 @@ export class ProjectMonitorFormatter {
|
|||
encryptedSavedObjectsClient: EncryptedSavedObjectsClient;
|
||||
projectId: string;
|
||||
spaceId: string;
|
||||
monitors: ProjectBrowserMonitor[];
|
||||
monitors: ProjectMonitor[];
|
||||
server: UptimeServerSetup;
|
||||
syntheticsMonitorClient: SyntheticsMonitorClient;
|
||||
request: KibanaRequest;
|
||||
|
@ -138,9 +142,9 @@ export class ProjectMonitorFormatter {
|
|||
if (this.staleMonitorsMap[monitor.id]) {
|
||||
this.staleMonitorsMap[monitor.id].stale = false;
|
||||
}
|
||||
normalizedUpdateMonitors.push(normM);
|
||||
normalizedUpdateMonitors.push(normM as MonitorFields);
|
||||
} else {
|
||||
normalizedNewMonitors.push(normM);
|
||||
normalizedNewMonitors.push(normM as MonitorFields);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -152,7 +156,7 @@ export class ProjectMonitorFormatter {
|
|||
await this.handleStaleMonitors();
|
||||
};
|
||||
|
||||
validatePermissions = async ({ monitor }: { monitor: ProjectBrowserMonitor }) => {
|
||||
validatePermissions = async ({ monitor }: { monitor: ProjectMonitor }) => {
|
||||
if (this.writeIntegrationPoliciesPermissions || (monitor.privateLocations ?? []).length === 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -167,11 +171,11 @@ export class ProjectMonitorFormatter {
|
|||
}
|
||||
};
|
||||
|
||||
validateProjectMonitor = async ({ monitor }: { monitor: ProjectBrowserMonitor }) => {
|
||||
validateProjectMonitor = async ({ monitor }: { monitor: ProjectMonitor }) => {
|
||||
try {
|
||||
await this.validatePermissions({ monitor });
|
||||
|
||||
const normalizedMonitor = normalizeProjectMonitor({
|
||||
const { normalizedFields: normalizedMonitor, unsupportedKeys } = normalizeProjectMonitor({
|
||||
monitor,
|
||||
locations: this.locations,
|
||||
privateLocations: this.privateLocations,
|
||||
|
@ -179,19 +183,40 @@ export class ProjectMonitorFormatter {
|
|||
namespace: this.spaceId,
|
||||
});
|
||||
|
||||
const validationResult = validateProjectMonitor(monitor, this.projectId);
|
||||
|
||||
if (!validationResult.valid) {
|
||||
const { reason: message, details, payload } = validationResult;
|
||||
if (unsupportedKeys.length) {
|
||||
this.failedMonitors.push({
|
||||
id: monitor.id,
|
||||
reason: message,
|
||||
details,
|
||||
payload,
|
||||
reason: 'Unsupported Heartbeat option',
|
||||
details: `The following Heartbeat options are not supported for ${
|
||||
monitor.type
|
||||
} project monitors in ${this.server.kibanaVersion}: ${unsupportedKeys.join('|')}`,
|
||||
});
|
||||
if (this.staleMonitorsMap[monitor.id]) {
|
||||
this.staleMonitorsMap[monitor.id].stale = false;
|
||||
}
|
||||
this.handleStreamingMessage({
|
||||
message: `${monitor.id}: failed to create or update monitor`,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
/* Validates that the payload sent from the synthetics agent is valid */
|
||||
const { valid: isMonitorPayloadValid } = this.validateMonitor({
|
||||
validationResult: validateProjectMonitor({
|
||||
...monitor,
|
||||
type: normalizedMonitor[ConfigKey.MONITOR_TYPE],
|
||||
}),
|
||||
monitorId: monitor.id,
|
||||
});
|
||||
|
||||
if (!isMonitorPayloadValid) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/* Validates that the normalized monitor is a valid monitor saved object type */
|
||||
const { valid: isNormalizedMonitorValid } = this.validateMonitor({
|
||||
validationResult: validateMonitor(normalizedMonitor as MonitorFields),
|
||||
monitorId: monitor.id,
|
||||
});
|
||||
|
||||
if (!isNormalizedMonitorValid) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -310,7 +335,7 @@ export class ProjectMonitorFormatter {
|
|||
try {
|
||||
for (const monitor of monitors) {
|
||||
const previousMonitor = await this.getExistingMonitor(monitor[ConfigKey.JOURNEY_ID]!);
|
||||
await this.updateMonitor(previousMonitor, monitor);
|
||||
await this.updateMonitor(previousMonitor, monitor as MonitorFields);
|
||||
}
|
||||
|
||||
if (monitors.length > 0) {
|
||||
|
@ -335,7 +360,7 @@ export class ProjectMonitorFormatter {
|
|||
|
||||
private updateMonitor = async (
|
||||
previousMonitor: SavedObjectsFindResult<EncryptedSyntheticsMonitor>,
|
||||
normalizedMonitor: BrowserFields
|
||||
normalizedMonitor: MonitorFields
|
||||
): Promise<{
|
||||
editedMonitor: SavedObjectsUpdateResponse<EncryptedSyntheticsMonitor>;
|
||||
errors: ServiceLocationErrors;
|
||||
|
@ -478,4 +503,26 @@ export class ProjectMonitorFormatter {
|
|||
this.subject?.next(message);
|
||||
}
|
||||
};
|
||||
|
||||
private validateMonitor = ({
|
||||
validationResult,
|
||||
monitorId,
|
||||
}: {
|
||||
validationResult: ValidationResult;
|
||||
monitorId: string;
|
||||
}) => {
|
||||
const { reason: message, details, payload: validationPayload, valid } = validationResult;
|
||||
if (!valid) {
|
||||
this.failedMonitors.push({
|
||||
id: monitorId,
|
||||
reason: message,
|
||||
details,
|
||||
payload: validationPayload,
|
||||
});
|
||||
if (this.staleMonitorsMap[monitorId]) {
|
||||
this.staleMonitorsMap[monitorId].stale = false;
|
||||
}
|
||||
}
|
||||
return validationResult;
|
||||
};
|
||||
}
|
|
@ -21,7 +21,7 @@ import { FtrProviderContext } from '../../../ftr_provider_context';
|
|||
import { getFixtureJson } from './helper/get_fixture_json';
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
describe('[POST] /internal/uptime/service/monitors', function () {
|
||||
describe('AddNewMonitors', function () {
|
||||
this.tags('skipCloud');
|
||||
|
||||
const supertestAPI = getService('supertest');
|
||||
|
|
|
@ -31,6 +31,9 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
const projectMonitorEndpoint = kibanaServerUrl + API_URLS.SYNTHETICS_MONITORS_PROJECT;
|
||||
|
||||
let projectMonitors: ProjectMonitorsRequest;
|
||||
let httpProjectMonitors: ProjectMonitorsRequest;
|
||||
let tcpProjectMonitors: ProjectMonitorsRequest;
|
||||
let icmpProjectMonitors: ProjectMonitorsRequest;
|
||||
|
||||
let testPolicyId = '';
|
||||
const testPrivateLocations = new PrivateLocationTestService(getService);
|
||||
|
@ -88,6 +91,272 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
|
||||
beforeEach(() => {
|
||||
projectMonitors = setUniqueIds(getFixtureJson('project_browser_monitor'));
|
||||
httpProjectMonitors = setUniqueIds(getFixtureJson('project_http_monitor'));
|
||||
tcpProjectMonitors = setUniqueIds(getFixtureJson('project_tcp_monitor'));
|
||||
icmpProjectMonitors = setUniqueIds(getFixtureJson('project_icmp_monitor'));
|
||||
});
|
||||
|
||||
it('project monitors - handles http monitors', async () => {
|
||||
const kibanaVersion = await kibanaServer.version.get();
|
||||
const successfulMonitors = [httpProjectMonitors.monitors[1]];
|
||||
|
||||
try {
|
||||
const messages = await parseStreamApiResponse(
|
||||
projectMonitorEndpoint,
|
||||
JSON.stringify(httpProjectMonitors)
|
||||
);
|
||||
|
||||
expect(messages).to.have.length(3);
|
||||
expect(messages[2].updatedMonitors).eql([]);
|
||||
expect(messages[2].createdMonitors).eql(successfulMonitors.map((monitor) => monitor.id));
|
||||
expect(messages[2].failedMonitors).eql([
|
||||
{
|
||||
id: httpProjectMonitors.monitors[0].id,
|
||||
details: `The following Heartbeat options are not supported for ${httpProjectMonitors.monitors[0].type} project monitors in ${kibanaVersion}: check.response.body|unsupportedKey.nestedUnsupportedKey`,
|
||||
reason: 'Unsupported Heartbeat option',
|
||||
},
|
||||
]);
|
||||
|
||||
for (const monitor of successfulMonitors) {
|
||||
const journeyId = monitor.id;
|
||||
const createdMonitorsResponse = await supertest
|
||||
.get(API_URLS.SYNTHETICS_MONITORS)
|
||||
.query({ filter: `${syntheticsMonitorType}.attributes.journey_id: ${journeyId}` })
|
||||
.set('kbn-xsrf', 'true')
|
||||
.expect(200);
|
||||
|
||||
expect(createdMonitorsResponse.body.monitors[0].attributes).to.eql({
|
||||
__ui: {
|
||||
is_tls_enabled: false,
|
||||
},
|
||||
'check.request.method': 'POST',
|
||||
'check.response.status': ['200'],
|
||||
config_id: '',
|
||||
custom_heartbeat_id: `${journeyId}-test-suite-default`,
|
||||
enabled: false,
|
||||
form_monitor_type: 'http',
|
||||
journey_id: journeyId,
|
||||
locations: [
|
||||
{
|
||||
geo: {
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
},
|
||||
id: 'localhost',
|
||||
isInvalid: false,
|
||||
isServiceManaged: true,
|
||||
label: 'Local Synthetics Service',
|
||||
status: 'experimental',
|
||||
url: 'mockDevUrl',
|
||||
},
|
||||
],
|
||||
max_redirects: '0',
|
||||
name: monitor.name,
|
||||
namespace: 'default',
|
||||
origin: 'project',
|
||||
original_space: 'default',
|
||||
project_id: 'test-suite',
|
||||
proxy_url: '',
|
||||
'response.include_body': 'always',
|
||||
'response.include_headers': false,
|
||||
revision: 1,
|
||||
schedule: {
|
||||
number: '60',
|
||||
unit: 'm',
|
||||
},
|
||||
'service.name': '',
|
||||
'ssl.certificate': '',
|
||||
'ssl.certificate_authorities': '',
|
||||
'ssl.supported_protocols': ['TLSv1.1', 'TLSv1.2', 'TLSv1.3'],
|
||||
'ssl.verification_mode': 'full',
|
||||
tags: Array.isArray(monitor.tags) ? monitor.tags : monitor.tags?.split(','),
|
||||
timeout: '80',
|
||||
type: 'http',
|
||||
urls: Array.isArray(monitor.urls) ? monitor.urls?.[0] : monitor.urls,
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
await Promise.all([
|
||||
successfulMonitors.map((monitor) => {
|
||||
return deleteMonitor(monitor.id, httpProjectMonitors.project);
|
||||
}),
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
it('project monitors - handles tcp monitors', async () => {
|
||||
const successfulMonitors = [tcpProjectMonitors.monitors[0], tcpProjectMonitors.monitors[1]];
|
||||
const kibanaVersion = await kibanaServer.version.get();
|
||||
|
||||
try {
|
||||
const messages = await parseStreamApiResponse(
|
||||
projectMonitorEndpoint,
|
||||
JSON.stringify(tcpProjectMonitors)
|
||||
);
|
||||
|
||||
expect(messages).to.have.length(3);
|
||||
expect(messages[2].updatedMonitors).eql([]);
|
||||
expect(messages[2].createdMonitors).eql(successfulMonitors.map((monitor) => monitor.id));
|
||||
expect(messages[2].failedMonitors).eql([
|
||||
{
|
||||
id: tcpProjectMonitors.monitors[2].id,
|
||||
details: `The following Heartbeat options are not supported for ${tcpProjectMonitors.monitors[0].type} project monitors in ${kibanaVersion}: ports|unsupportedKey.nestedUnsupportedKey`,
|
||||
reason: 'Unsupported Heartbeat option',
|
||||
},
|
||||
]);
|
||||
|
||||
for (const monitor of successfulMonitors) {
|
||||
const journeyId = monitor.id;
|
||||
const createdMonitorsResponse = await supertest
|
||||
.get(API_URLS.SYNTHETICS_MONITORS)
|
||||
.query({ filter: `${syntheticsMonitorType}.attributes.journey_id: ${journeyId}` })
|
||||
.set('kbn-xsrf', 'true')
|
||||
.expect(200);
|
||||
|
||||
expect(createdMonitorsResponse.body.monitors[0].attributes).to.eql({
|
||||
__ui: {
|
||||
is_tls_enabled: false,
|
||||
},
|
||||
config_id: '',
|
||||
custom_heartbeat_id: `${journeyId}-test-suite-default`,
|
||||
enabled: true,
|
||||
form_monitor_type: 'tcp',
|
||||
journey_id: journeyId,
|
||||
locations: [
|
||||
{
|
||||
geo: {
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
},
|
||||
id: 'localhost',
|
||||
isInvalid: false,
|
||||
isServiceManaged: true,
|
||||
label: 'Local Synthetics Service',
|
||||
status: 'experimental',
|
||||
url: 'mockDevUrl',
|
||||
},
|
||||
],
|
||||
name: monitor.name,
|
||||
namespace: 'default',
|
||||
origin: 'project',
|
||||
original_space: 'default',
|
||||
project_id: 'test-suite',
|
||||
revision: 1,
|
||||
schedule: {
|
||||
number: '1',
|
||||
unit: 'm',
|
||||
},
|
||||
proxy_url: '',
|
||||
proxy_use_local_resolver: false,
|
||||
'service.name': '',
|
||||
'ssl.certificate': '',
|
||||
'ssl.certificate_authorities': '',
|
||||
'ssl.supported_protocols': ['TLSv1.1', 'TLSv1.2', 'TLSv1.3'],
|
||||
'ssl.verification_mode': 'full',
|
||||
tags: Array.isArray(monitor.tags) ? monitor.tags : monitor.tags?.split(','),
|
||||
timeout: '16',
|
||||
type: 'tcp',
|
||||
hosts: Array.isArray(monitor.hosts) ? monitor.hosts?.[0] : monitor.hosts,
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
await Promise.all([
|
||||
successfulMonitors.map((monitor) => {
|
||||
return deleteMonitor(monitor.id, tcpProjectMonitors.project);
|
||||
}),
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
it('project monitors - handles icmp monitors', async () => {
|
||||
const successfulMonitors = [icmpProjectMonitors.monitors[0], icmpProjectMonitors.monitors[1]];
|
||||
const kibanaVersion = await kibanaServer.version.get();
|
||||
|
||||
try {
|
||||
const messages = await parseStreamApiResponse(
|
||||
projectMonitorEndpoint,
|
||||
JSON.stringify(icmpProjectMonitors)
|
||||
);
|
||||
|
||||
expect(messages).to.have.length(3);
|
||||
expect(messages[2].updatedMonitors).eql([]);
|
||||
expect(messages[2].createdMonitors).eql(successfulMonitors.map((monitor) => monitor.id));
|
||||
expect(messages[2].failedMonitors).eql([
|
||||
{
|
||||
id: icmpProjectMonitors.monitors[2].id,
|
||||
details: `The following Heartbeat options are not supported for ${icmpProjectMonitors.monitors[0].type} project monitors in ${kibanaVersion}: unsupportedKey.nestedUnsupportedKey`,
|
||||
reason: 'Unsupported Heartbeat option',
|
||||
},
|
||||
]);
|
||||
|
||||
for (const monitor of successfulMonitors) {
|
||||
const journeyId = monitor.id;
|
||||
const createdMonitorsResponse = await supertest
|
||||
.get(API_URLS.SYNTHETICS_MONITORS)
|
||||
.query({ filter: `${syntheticsMonitorType}.attributes.journey_id: ${journeyId}` })
|
||||
.set('kbn-xsrf', 'true')
|
||||
.expect(200);
|
||||
|
||||
expect(createdMonitorsResponse.body.monitors[0].attributes).to.eql({
|
||||
config_id: '',
|
||||
custom_heartbeat_id: `${journeyId}-test-suite-default`,
|
||||
enabled: true,
|
||||
form_monitor_type: 'icmp',
|
||||
journey_id: journeyId,
|
||||
locations: [
|
||||
{
|
||||
geo: {
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
},
|
||||
id: 'localhost',
|
||||
isInvalid: false,
|
||||
isServiceManaged: true,
|
||||
label: 'Local Synthetics Service',
|
||||
status: 'experimental',
|
||||
url: 'mockDevUrl',
|
||||
},
|
||||
{
|
||||
agentPolicyId: testPolicyId,
|
||||
concurrentMonitors: 1,
|
||||
geo: {
|
||||
lat: '',
|
||||
lon: '',
|
||||
},
|
||||
id: testPolicyId,
|
||||
isInvalid: false,
|
||||
isServiceManaged: false,
|
||||
label: 'Test private location 0',
|
||||
},
|
||||
],
|
||||
name: monitor.name,
|
||||
namespace: 'default',
|
||||
origin: 'project',
|
||||
original_space: 'default',
|
||||
project_id: 'test-suite',
|
||||
revision: 1,
|
||||
schedule: {
|
||||
number: '1',
|
||||
unit: 'm',
|
||||
},
|
||||
'service.name': '',
|
||||
tags: Array.isArray(monitor.tags) ? monitor.tags : monitor.tags?.split(','),
|
||||
timeout: '16',
|
||||
type: 'icmp',
|
||||
hosts: Array.isArray(monitor.hosts) ? monitor.hosts?.[0] : monitor.hosts,
|
||||
wait:
|
||||
monitor.wait?.slice(-1) === 's'
|
||||
? monitor.wait?.slice(0, -1)
|
||||
: `${parseInt(monitor.wait?.slice(0, -1) || '1', 10) * 60}`,
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
await Promise.all([
|
||||
successfulMonitors.map((monitor) => {
|
||||
return deleteMonitor(monitor.id, icmpProjectMonitors.project);
|
||||
}),
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
it('project monitors - returns a list of successfully created monitors', async () => {
|
||||
|
@ -468,8 +737,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
expect(messages[0].updatedMonitors).eql([]);
|
||||
expect(messages[0].failedMonitors).eql([
|
||||
{
|
||||
details:
|
||||
'Invalid value "3m" supplied to "schedule" | Invalid value "" supplied to "tags"',
|
||||
details: 'Invalid value "3m" supplied to "schedule"',
|
||||
id: projectMonitors.monitors[0].id,
|
||||
payload: {
|
||||
content:
|
||||
|
@ -492,6 +760,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
latency: 20,
|
||||
upload: 3,
|
||||
},
|
||||
type: 'browser',
|
||||
},
|
||||
reason: 'Failed to save or update monitor. Configuration is not valid',
|
||||
},
|
||||
|
@ -813,9 +1082,9 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
privateLocations: ['Test private location 0'],
|
||||
};
|
||||
const testMonitors = [projectMonitors.monitors[0], secondMonitor];
|
||||
const username = 'admin';
|
||||
const username = 'test-username';
|
||||
const roleName = 'uptime read only';
|
||||
const password = `${username}-password`;
|
||||
const password = `test-password`;
|
||||
try {
|
||||
await security.role.create(roleName, {
|
||||
kibana: [
|
||||
|
@ -1006,9 +1275,9 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
const packagePolicy = apiResponsePolicy.body.items.find(
|
||||
(pkgPolicy: PackagePolicy) =>
|
||||
pkgPolicy.id ===
|
||||
monitorsResponse.body.monitors[0].attributes[ConfigKey.CUSTOM_HEARTBEAT_ID] +
|
||||
'-' +
|
||||
testPolicyId
|
||||
`${
|
||||
monitorsResponse.body.monitors[0].attributes[ConfigKey.CUSTOM_HEARTBEAT_ID]
|
||||
}-${testPolicyId}`
|
||||
);
|
||||
expect(packagePolicy.name).eql(
|
||||
`${projectMonitors.monitors[0].id}-${projectMonitors.project}-default-Test private location 0`
|
||||
|
@ -1030,10 +1299,71 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
} finally {
|
||||
await deleteMonitor(projectMonitors.monitors[0].id, projectMonitors.project);
|
||||
|
||||
const packagesResponse = await supertest.get(
|
||||
'/api/fleet/package_policies?page=1&perPage=2000&kuery=ingest-package-policies.package.name%3A%20synthetics'
|
||||
);
|
||||
expect(packagesResponse.body.items.length).eql(0);
|
||||
}
|
||||
});
|
||||
|
||||
it('deletes integration policies for project monitors when private location is removed from the monitor - lightweight', async () => {
|
||||
const monitorRequest = {
|
||||
...httpProjectMonitors,
|
||||
monitors: [
|
||||
{ ...httpProjectMonitors.monitors[1], privateLocations: ['Test private location 0'] },
|
||||
],
|
||||
};
|
||||
try {
|
||||
await supertest
|
||||
.put(API_URLS.SYNTHETICS_MONITORS_PROJECT)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send(monitorRequest);
|
||||
|
||||
const monitorsResponse = await supertest
|
||||
.get(API_URLS.SYNTHETICS_MONITORS)
|
||||
.query({
|
||||
filter: `${syntheticsMonitorType}.attributes.journey_id: ${monitorRequest.monitors[0].id}`,
|
||||
})
|
||||
.set('kbn-xsrf', 'true')
|
||||
.expect(200);
|
||||
|
||||
const apiResponsePolicy = await supertest.get(
|
||||
'/api/fleet/package_policies?page=1&perPage=2000&kuery=ingest-package-policies.package.name%3A%20synthetics'
|
||||
);
|
||||
|
||||
const packagePolicy = apiResponsePolicy.body.items.find(
|
||||
(pkgPolicy: PackagePolicy) =>
|
||||
pkgPolicy.id ===
|
||||
`${
|
||||
monitorsResponse.body.monitors[0].attributes[ConfigKey.CUSTOM_HEARTBEAT_ID]
|
||||
}-${testPolicyId}`
|
||||
);
|
||||
|
||||
expect(packagePolicy.policy_id).eql(testPolicyId);
|
||||
|
||||
await supertest
|
||||
.put(API_URLS.SYNTHETICS_MONITORS_PROJECT)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
...monitorRequest,
|
||||
monitors: [{ ...monitorRequest.monitors[0], privateLocations: [] }],
|
||||
});
|
||||
|
||||
const apiResponsePolicy2 = await supertest.get(
|
||||
'/api/fleet/package_policies?page=1&perPage=2000&kuery=ingest-package-policies.package.name%3A%20synthetics'
|
||||
);
|
||||
expect(apiResponsePolicy2.body.items.length).eql(0);
|
||||
|
||||
const packagePolicy2 = apiResponsePolicy2.body.items.find(
|
||||
(pkgPolicy: PackagePolicy) =>
|
||||
pkgPolicy.id ===
|
||||
`${
|
||||
monitorsResponse.body.monitors[0].attributes[ConfigKey.CUSTOM_HEARTBEAT_ID]
|
||||
}-${testPolicyId}`
|
||||
);
|
||||
|
||||
expect(packagePolicy2).eql(undefined);
|
||||
} finally {
|
||||
await deleteMonitor(projectMonitors.monitors[0].id, projectMonitors.project);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1064,9 +1394,9 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
const packagePolicy = apiResponsePolicy.body.items.find(
|
||||
(pkgPolicy: PackagePolicy) =>
|
||||
pkgPolicy.id ===
|
||||
monitorsResponse.body.monitors[0].attributes[ConfigKey.CUSTOM_HEARTBEAT_ID] +
|
||||
'-' +
|
||||
testPolicyId
|
||||
`${
|
||||
monitorsResponse.body.monitors[0].attributes[ConfigKey.CUSTOM_HEARTBEAT_ID]
|
||||
}-${testPolicyId}`
|
||||
);
|
||||
|
||||
expect(packagePolicy.policy_id).eql(testPolicyId);
|
||||
|
@ -1099,9 +1429,9 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
const packagePolicy2 = apiResponsePolicy2.body.items.find(
|
||||
(pkgPolicy: PackagePolicy) =>
|
||||
pkgPolicy.id ===
|
||||
monitorsResponse.body.monitors[0].attributes[ConfigKey.CUSTOM_HEARTBEAT_ID] +
|
||||
'-' +
|
||||
testPolicyId
|
||||
`${
|
||||
monitorsResponse.body.monitors[0].attributes[ConfigKey.CUSTOM_HEARTBEAT_ID]
|
||||
}-${testPolicyId}`
|
||||
);
|
||||
|
||||
expect(packagePolicy2).eql(undefined);
|
||||
|
@ -1209,6 +1539,169 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
}
|
||||
});
|
||||
|
||||
it('deletes integration policies when project monitors are deleted - lightweight', async () => {
|
||||
const monitorRequest = {
|
||||
...httpProjectMonitors,
|
||||
monitors: [
|
||||
{ ...httpProjectMonitors.monitors[1], privateLocations: ['Test private location 0'] },
|
||||
],
|
||||
};
|
||||
try {
|
||||
await supertest
|
||||
.put(API_URLS.SYNTHETICS_MONITORS_PROJECT)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send(monitorRequest);
|
||||
|
||||
const monitorsResponse = await supertest
|
||||
.get(API_URLS.SYNTHETICS_MONITORS)
|
||||
.query({
|
||||
filter: `${syntheticsMonitorType}.attributes.journey_id: ${monitorRequest.monitors[0].id}`,
|
||||
})
|
||||
.set('kbn-xsrf', 'true')
|
||||
.expect(200);
|
||||
|
||||
const apiResponsePolicy = await supertest.get(
|
||||
'/api/fleet/package_policies?page=1&perPage=2000&kuery=ingest-package-policies.package.name%3A%20synthetics'
|
||||
);
|
||||
|
||||
const packagePolicy = apiResponsePolicy.body.items.find(
|
||||
(pkgPolicy: PackagePolicy) =>
|
||||
pkgPolicy.id ===
|
||||
`${
|
||||
monitorsResponse.body.monitors[0].attributes[ConfigKey.CUSTOM_HEARTBEAT_ID]
|
||||
}-${testPolicyId}`
|
||||
);
|
||||
|
||||
expect(packagePolicy.policy_id).eql(testPolicyId);
|
||||
|
||||
const configId = monitorsResponse.body.monitors[0].id;
|
||||
const id = monitorsResponse.body.monitors[0].attributes[ConfigKey.CUSTOM_HEARTBEAT_ID];
|
||||
|
||||
const httpInput = packagePolicy.inputs.find(
|
||||
(input: any) => input.type === 'synthetics/http'
|
||||
);
|
||||
expect(httpInput).to.eql({
|
||||
type: 'synthetics/http',
|
||||
policy_template: 'synthetics',
|
||||
enabled: true,
|
||||
streams: [
|
||||
{
|
||||
enabled: true,
|
||||
data_stream: { type: 'synthetics', dataset: 'http' },
|
||||
release: 'experimental',
|
||||
vars: {
|
||||
__ui: { value: '{"is_tls_enabled":false}', type: 'yaml' },
|
||||
enabled: { value: false, type: 'bool' },
|
||||
type: { value: 'http', type: 'text' },
|
||||
name: { value: 'My Monitor 3', type: 'text' },
|
||||
schedule: { value: '"@every 60m"', type: 'text' },
|
||||
urls: { value: 'http://localhost:9200', type: 'text' },
|
||||
'service.name': { value: '', type: 'text' },
|
||||
timeout: { value: '80s', type: 'text' },
|
||||
max_redirects: { value: '0', type: 'integer' },
|
||||
proxy_url: { value: '', type: 'text' },
|
||||
tags: { value: '["tag2","tag2"]', type: 'yaml' },
|
||||
username: { value: '', type: 'text' },
|
||||
password: { value: '', type: 'password' },
|
||||
'response.include_headers': { value: false, type: 'bool' },
|
||||
'response.include_body': { value: 'always', type: 'text' },
|
||||
'check.request.method': { value: 'POST', type: 'text' },
|
||||
'check.request.headers': {
|
||||
value: '{"Content-Type":"application/x-www-form-urlencoded"}',
|
||||
type: 'yaml',
|
||||
},
|
||||
'check.request.body': { value: null, type: 'yaml' },
|
||||
'check.response.status': { value: '["200"]', type: 'yaml' },
|
||||
'check.response.headers': { value: null, type: 'yaml' },
|
||||
'check.response.body.positive': { value: '["Saved","saved"]', type: 'yaml' },
|
||||
'check.response.body.negative': { value: null, type: 'yaml' },
|
||||
'ssl.certificate_authorities': { value: null, type: 'yaml' },
|
||||
'ssl.certificate': { value: null, type: 'yaml' },
|
||||
'ssl.key': { value: null, type: 'yaml' },
|
||||
'ssl.key_passphrase': { value: null, type: 'text' },
|
||||
'ssl.verification_mode': { value: 'full', type: 'text' },
|
||||
'ssl.supported_protocols': {
|
||||
value: '["TLSv1.1","TLSv1.2","TLSv1.3"]',
|
||||
type: 'yaml',
|
||||
},
|
||||
location_name: { value: 'Test private location 0', type: 'text' },
|
||||
id: {
|
||||
value: id,
|
||||
type: 'text',
|
||||
},
|
||||
config_id: { value: configId, type: 'text' },
|
||||
run_once: { value: false, type: 'bool' },
|
||||
origin: { value: 'project', type: 'text' },
|
||||
},
|
||||
id: `synthetics/http-http-${id}-${testPolicyId}`,
|
||||
compiled_stream: {
|
||||
__ui: { is_tls_enabled: false },
|
||||
type: 'http',
|
||||
name: 'My Monitor 3',
|
||||
id,
|
||||
origin: 'project',
|
||||
enabled: false,
|
||||
urls: 'http://localhost:9200',
|
||||
schedule: '@every 60m',
|
||||
timeout: '80s',
|
||||
max_redirects: 0,
|
||||
tags: ['tag2', 'tag2'],
|
||||
'response.include_headers': false,
|
||||
'response.include_body': 'always',
|
||||
'check.request.method': 'POST',
|
||||
'check.request.headers': { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
'check.response.status': ['200'],
|
||||
'check.response.body.positive': ['Saved', 'saved'],
|
||||
'ssl.verification_mode': 'full',
|
||||
'ssl.supported_protocols': ['TLSv1.1', 'TLSv1.2', 'TLSv1.3'],
|
||||
processors: [
|
||||
{ add_observer_metadata: { geo: { name: 'Test private location 0' } } },
|
||||
{
|
||||
add_fields: {
|
||||
target: '',
|
||||
fields: {
|
||||
'monitor.fleet_managed': true,
|
||||
config_id: configId,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await supertest
|
||||
.put(API_URLS.SYNTHETICS_MONITORS_PROJECT)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
...monitorRequest,
|
||||
monitors: [],
|
||||
});
|
||||
|
||||
const apiResponsePolicy2 = await supertest.get(
|
||||
'/api/fleet/package_policies?page=1&perPage=2000&kuery=ingest-package-policies.package.name%3A%20synthetics'
|
||||
);
|
||||
|
||||
const packagePolicy2 = apiResponsePolicy2.body.items.find(
|
||||
(pkgPolicy: PackagePolicy) =>
|
||||
pkgPolicy.id ===
|
||||
`${
|
||||
monitorsResponse.body.monitors[0].attributes[ConfigKey.CUSTOM_HEARTBEAT_ID]
|
||||
} - ${testPolicyId}`
|
||||
);
|
||||
|
||||
expect(packagePolicy2).eql(undefined);
|
||||
} finally {
|
||||
await deleteMonitor(projectMonitors.monitors[0].id, projectMonitors.project);
|
||||
|
||||
const apiResponsePolicy2 = await supertest.get(
|
||||
'/api/fleet/package_policies?page=1&perPage=2000&kuery=ingest-package-policies.package.name%3A%20synthetics'
|
||||
);
|
||||
expect(apiResponsePolicy2.body.items.length).eql(0);
|
||||
}
|
||||
});
|
||||
|
||||
it('handles updating package policies when project monitors are updated', async () => {
|
||||
try {
|
||||
await supertest
|
||||
|
|
|
@ -77,5 +77,6 @@
|
|||
"namespace": "testnamespace",
|
||||
"revision": 1,
|
||||
"origin": "ui",
|
||||
"form_monitor_type": "http"
|
||||
"form_monitor_type": "http",
|
||||
"journey_id": ""
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"type": "tcp",
|
||||
"locations": [],
|
||||
"journey_id": "",
|
||||
"enabled": true,
|
||||
"schedule": {
|
||||
"number": "3",
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
{
|
||||
"keep_stale": true,
|
||||
"project": "test-suite",
|
||||
"monitors": [{
|
||||
"throttling": {
|
||||
"download": 5,
|
||||
"upload": 3,
|
||||
"latency": 20
|
||||
},
|
||||
"schedule": 10,
|
||||
"locations": [
|
||||
"localhost"
|
||||
],
|
||||
"params": {},
|
||||
"playwrightOptions": {
|
||||
"headless": true,
|
||||
"chromiumSandbox": false
|
||||
},
|
||||
"name": "check if title is present",
|
||||
"id": "check-if-title-is-present",
|
||||
"tags": [],
|
||||
"content": "UEsDBBQACAAIAON5qVQAAAAAAAAAAAAAAAAfAAAAZXhhbXBsZXMvdG9kb3MvYmFzaWMuam91cm5leS50c22Q0WrDMAxF3/sVF7MHB0LMXlc6RvcN+wDPVWNviW0sdUsp/fe5SSiD7UFCWFfHujIGlpnkybwxFTZfoY/E3hsaLEtwhs9RPNWKDU12zAOxkXRIbN4tB9d9pFOJdO6EN2HMqQguWN9asFBuQVMmJ7jiWNII9fIXrbabdUYr58l9IhwhQQZCYORCTFFUC31Btj21NRc7Mq4Nds+4bDD/pNVgT9F52Jyr2Fa+g75LAPttg8yErk+S9ELpTmVotlVwnfNCuh2lepl3+JflUmSBJ3uggt1v9INW/lHNLKze9dJe1J3QJK8pSvWkm6aTtCet5puq+x63+AFQSwcIAPQ3VfcAAACcAQAAUEsBAi0DFAAIAAgA43mpVAD0N1X3AAAAnAEAAB8AAAAAAAAAAAAgAKSBAAAAAGV4YW1wbGVzL3RvZG9zL2Jhc2ljLmpvdXJuZXkudHNQSwUGAAAAAAEAAQBNAAAARAEAAAAA",
|
||||
"filter": {
|
||||
"match": "check if title is present"
|
||||
}
|
||||
}]
|
||||
"keep_stale": true,
|
||||
"project": "test-suite",
|
||||
"monitors": [{
|
||||
"throttling": {
|
||||
"download": 5,
|
||||
"upload": 3,
|
||||
"latency": 20
|
||||
},
|
||||
"schedule": 10,
|
||||
"locations": [
|
||||
"localhost"
|
||||
],
|
||||
"params": {},
|
||||
"playwrightOptions": {
|
||||
"headless": true,
|
||||
"chromiumSandbox": false
|
||||
},
|
||||
"name": "check if title is present",
|
||||
"id": "check-if-title-is-present",
|
||||
"tags": [],
|
||||
"content": "UEsDBBQACAAIAON5qVQAAAAAAAAAAAAAAAAfAAAAZXhhbXBsZXMvdG9kb3MvYmFzaWMuam91cm5leS50c22Q0WrDMAxF3/sVF7MHB0LMXlc6RvcN+wDPVWNviW0sdUsp/fe5SSiD7UFCWFfHujIGlpnkybwxFTZfoY/E3hsaLEtwhs9RPNWKDU12zAOxkXRIbN4tB9d9pFOJdO6EN2HMqQguWN9asFBuQVMmJ7jiWNII9fIXrbabdUYr58l9IhwhQQZCYORCTFFUC31Btj21NRc7Mq4Nds+4bDD/pNVgT9F52Jyr2Fa+g75LAPttg8yErk+S9ELpTmVotlVwnfNCuh2lepl3+JflUmSBJ3uggt1v9INW/lHNLKze9dJe1J3QJK8pSvWkm6aTtCet5puq+x63+AFQSwcIAPQ3VfcAAACcAQAAUEsBAi0DFAAIAAgA43mpVAD0N1X3AAAAnAEAAB8AAAAAAAAAAAAgAKSBAAAAAGV4YW1wbGVzL3RvZG9zL2Jhc2ljLmpvdXJuZXkudHNQSwUGAAAAAAEAAQBNAAAARAEAAAAA",
|
||||
"filter": {
|
||||
"match": "check if title is present"
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
{
|
||||
"project": "test-suite",
|
||||
"keep_stale": false,
|
||||
"monitors": [
|
||||
{
|
||||
"locations": ["localhost"],
|
||||
"type": "http",
|
||||
"enabled": false,
|
||||
"id": "my-monitor-2",
|
||||
"name": "My Monitor 2",
|
||||
"urls": [
|
||||
"http://localhost:9200"
|
||||
],
|
||||
"schedule": 60,
|
||||
"timeout": "80s",
|
||||
"check.request": {
|
||||
"method": "POST",
|
||||
"headers": {
|
||||
"Content-Type": "application/x-www-form-urlencoded"
|
||||
}
|
||||
},
|
||||
"response": {
|
||||
"include_body": "always"
|
||||
},
|
||||
"response.include_headers": false,
|
||||
"check.response": {
|
||||
"status": [
|
||||
200
|
||||
],
|
||||
"body": [
|
||||
"Saved",
|
||||
"saved"
|
||||
]
|
||||
},
|
||||
"content": "",
|
||||
"unsupportedKey": {
|
||||
"nestedUnsupportedKey": "unsupportedValue"
|
||||
}
|
||||
},
|
||||
{
|
||||
"locations": ["localhost"],
|
||||
"type": "http",
|
||||
"enabled": false,
|
||||
"id": "my-monitor-3",
|
||||
"name": "My Monitor 3",
|
||||
"urls": [
|
||||
"http://localhost:9200"
|
||||
],
|
||||
"schedule": 60,
|
||||
"timeout": "80s",
|
||||
"check.request": {
|
||||
"method": "POST",
|
||||
"headers": {
|
||||
"Content-Type": "application/x-www-form-urlencoded"
|
||||
}
|
||||
},
|
||||
"response": {
|
||||
"include_body": "always"
|
||||
},
|
||||
"tags": "tag2,tag2",
|
||||
"response.include_headers": false,
|
||||
"check.response": {
|
||||
"status": [
|
||||
200
|
||||
],
|
||||
"body":{
|
||||
"positive": [
|
||||
"Saved",
|
||||
"saved"
|
||||
]
|
||||
}
|
||||
},
|
||||
"content": ""
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
|
||||
|
||||
|
||||
{
|
||||
"project": "test-suite",
|
||||
"keep_stale": true,
|
||||
"monitors": [
|
||||
{
|
||||
"locations": [ "localhost" ],
|
||||
"type": "icmp",
|
||||
"id": "Cloudflare-DNS",
|
||||
"name": "Cloudflare DNS",
|
||||
"hosts": [ "1.1.1.1" ],
|
||||
"schedule": 1,
|
||||
"tags": [ "service:smtp", "org:google" ],
|
||||
"privateLocations": [ "Test private location 0" ],
|
||||
"content": "",
|
||||
"wait": "30s"
|
||||
},
|
||||
{
|
||||
"locations": [ "localhost" ],
|
||||
"type": "icmp",
|
||||
"id": "Cloudflare-DNS-2",
|
||||
"name": "Cloudflare DNS 2",
|
||||
"hosts": "1.1.1.1",
|
||||
"schedule": 1,
|
||||
"tags": "tag1,tag2",
|
||||
"privateLocations": [ "Test private location 0" ],
|
||||
"content": "",
|
||||
"wait": "1m"
|
||||
},
|
||||
{
|
||||
"locations": [ "localhost" ],
|
||||
"type": "icmp",
|
||||
"id": "Cloudflare-DNS-3",
|
||||
"name": "Cloudflare DNS 3",
|
||||
"hosts": "1.1.1.1",
|
||||
"schedule": 1,
|
||||
"tags": "tag1,tag2",
|
||||
"privateLocations": [ "Test private location 0" ],
|
||||
"content": "",
|
||||
"unsupportedKey": {
|
||||
"nestedUnsupportedKey": "unnsuportedValue"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"project": "test-suite",
|
||||
"keep_stale": true,
|
||||
"monitors": [
|
||||
{
|
||||
"locations": [ "localhost" ],
|
||||
"type": "tcp",
|
||||
"id": "gmail-smtp",
|
||||
"name": "GMail SMTP",
|
||||
"hosts": [ "smtp.gmail.com:587" ],
|
||||
"schedule": 1,
|
||||
"tags": [ "service:smtp", "org:google" ],
|
||||
"privateLocations": [ "BEEP" ],
|
||||
"content": ""
|
||||
},
|
||||
{
|
||||
"locations": [ "localhost" ],
|
||||
"type": "tcp",
|
||||
"id": "always-down",
|
||||
"name": "Always Down",
|
||||
"hosts": "localhost:18278",
|
||||
"schedule": 1,
|
||||
"tags": "tag1,tag2",
|
||||
"privateLocations": [ "BEEP" ],
|
||||
"content": ""
|
||||
},
|
||||
{
|
||||
"locations": [ "localhost" ],
|
||||
"type": "tcp",
|
||||
"id": "always-down",
|
||||
"name": "Always Down",
|
||||
"hosts": "localhost",
|
||||
"ports": ["5698"],
|
||||
"schedule": 1,
|
||||
"tags": "tag1,tag2",
|
||||
"privateLocations": [ "BEEP" ],
|
||||
"content": "",
|
||||
"unsupportedKey": {
|
||||
"nestedUnsupportedKey": "unnsuportedValue"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -13,7 +13,7 @@ import { FtrProviderContext } from '../../../ftr_provider_context';
|
|||
import { getFixtureJson } from './helper/get_fixture_json';
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
describe('[GET] /internal/uptime/service/monitors', function () {
|
||||
describe('getSyntheticsMonitors', function () {
|
||||
this.tags('skipCloud');
|
||||
|
||||
const supertest = getService('supertest');
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue