[Synthetics] Adds additional heartbeat configuration options to the Synthetics app (#154390)

## Summary

Closes https://github.com/elastic/kibana/issues/140864
Relates to https://github.com/elastic/synthetics-dev/issues/159
Relates to https://github.com/elastic/synthetics/issues/655

Adds missing heartbeat configs to the Synthetics app. The additional
configs are specified below:

HTTP (proxy_headers, mode, ipv4, ipv6, response.include_body_max_bytes,
check.response.json)

![image](https://user-images.githubusercontent.com/11356435/231040397-4f80d3af-ff08-4ef1-bbd9-c49f63d29bd0.png)

![image](https://user-images.githubusercontent.com/11356435/231040371-b7baa693-d573-46e1-b0f1-6d21c32522b8.png)


TCP (mode, ipv4, ivp6)

![image](https://user-images.githubusercontent.com/11356435/231040065-ad865160-7f6c-4450-ab1c-98c17aedd3f0.png)

ICMP (mode, ipv4, ipv6)

![image](https://user-images.githubusercontent.com/11356435/231039925-d2a2e9ab-69aa-4d74-8c3e-91223dd963d1.png)


### Testing

1. Create a private location
2. Create an http monitor selecting both a public and private location,
adjusting the settings for mode, ipv4, ipv6,
response.include_body_max_bytes, check.response.json and proxy headers.
3. Navigate to the edit page for that monitor, ensure the configuration
above was saved to the monitor settings
4. Create an icmp monitor selecting both a public and private location,
adjusting the settings for mode, ipv6, and ipv4.
5. Navigate to the dit page for that monitor, ensure the configuration
above was saved to the monitor settings
6. Create an tcp monitor selecting both a public and private location,
adjusting the settings for mode, ipv6, and ipv4.
7. Navigate to the dit page for that monitor, ensure the configuration
above was saved to the monitor settings
8. Navigate to the agent policy for the private location selected.
Ensure that the configuration options are represented on the the
individual integration policies

---------

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: florent-leborgne <florent.leborgne@elastic.co>
Co-authored-by: Shahzad <shahzad31comp@gmail.com>
This commit is contained in:
Dominique Clarke 2023-04-25 08:03:10 -04:00 committed by GitHub
parent f1c18d940d
commit c3ccede36e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 613 additions and 151 deletions

View file

@ -6,6 +6,7 @@
*/
import { i18n } from '@kbn/i18n';
import {
CodeEditorMode,
BrowserAdvancedFields,
BrowserSimpleFields,
CommonFields,
@ -198,19 +199,25 @@ export const DEFAULT_HTTP_SIMPLE_FIELDS: HTTPSimpleFields = {
export const DEFAULT_HTTP_ADVANCED_FIELDS: HTTPAdvancedFields = {
[ConfigKey.PASSWORD]: '',
[ConfigKey.PROXY_URL]: '',
[ConfigKey.PROXY_HEADERS]: {},
[ConfigKey.RESPONSE_BODY_CHECK_NEGATIVE]: [],
[ConfigKey.RESPONSE_BODY_CHECK_POSITIVE]: [],
[ConfigKey.RESPONSE_JSON_CHECK]: [],
[ConfigKey.RESPONSE_BODY_INDEX]: ResponseBodyIndexPolicy.ON_ERROR,
[ConfigKey.RESPONSE_HEADERS_CHECK]: {},
[ConfigKey.RESPONSE_HEADERS_INDEX]: true,
[ConfigKey.RESPONSE_STATUS_CHECK]: [],
[ConfigKey.REQUEST_BODY_CHECK]: {
value: '',
type: Mode.PLAINTEXT,
type: CodeEditorMode.PLAINTEXT,
},
[ConfigKey.REQUEST_HEADERS_CHECK]: {},
[ConfigKey.REQUEST_METHOD_CHECK]: HTTPMethod.GET,
[ConfigKey.USERNAME]: '',
[ConfigKey.MODE]: Mode.ANY,
[ConfigKey.RESPONSE_BODY_MAX_BYTES]: '1024',
[ConfigKey.IPV4]: true,
[ConfigKey.IPV6]: true,
};
export const DEFAULT_ICMP_SIMPLE_FIELDS: ICMPSimpleFields = {
@ -238,6 +245,15 @@ export const DEFAULT_TCP_ADVANCED_FIELDS: TCPAdvancedFields = {
[ConfigKey.PROXY_USE_LOCAL_RESOLVER]: false,
[ConfigKey.RESPONSE_RECEIVE_CHECK]: '',
[ConfigKey.REQUEST_SEND_CHECK]: '',
[ConfigKey.MODE]: Mode.ANY,
[ConfigKey.IPV4]: true,
[ConfigKey.IPV6]: true,
};
export const DEFAULT_ICMP_ADVANCED_FIELDS = {
[ConfigKey.MODE]: Mode.ANY,
[ConfigKey.IPV4]: true,
[ConfigKey.IPV6]: true,
};
export const DEFAULT_TLS_FIELDS: TLSFields = {
@ -262,6 +278,7 @@ export const DEFAULT_FIELDS: MonitorDefaults = {
},
[DataStream.ICMP]: {
...DEFAULT_ICMP_SIMPLE_FIELDS,
...DEFAULT_ICMP_ADVANCED_FIELDS,
},
[DataStream.BROWSER]: {
...DEFAULT_BROWSER_SIMPLE_FIELDS,

View file

@ -27,6 +27,7 @@ export enum ConfigKey {
JOURNEY_ID = 'journey_id',
MAX_REDIRECTS = 'max_redirects',
METADATA = '__ui',
MODE = 'mode',
MONITOR_TYPE = 'type',
NAME = 'name',
NAMESPACE = 'namespace',
@ -37,12 +38,15 @@ export enum ConfigKey {
ORIGINAL_SPACE = 'original_space', // the original space the montior was saved in. Used by push monitors to ensure uniqueness of monitor id sent to heartbeat and prevent data collisions
PORT = 'url.port',
PROXY_URL = 'proxy_url',
PROXY_HEADERS = 'proxy_headers',
PROXY_USE_LOCAL_RESOLVER = 'proxy_use_local_resolver',
RESPONSE_BODY_CHECK_NEGATIVE = 'check.response.body.negative',
RESPONSE_BODY_CHECK_POSITIVE = 'check.response.body.positive',
RESPONSE_JSON_CHECK = 'check.response.json',
RESPONSE_BODY_INDEX = 'response.include_body',
RESPONSE_HEADERS_CHECK = 'check.response.headers',
RESPONSE_HEADERS_INDEX = 'response.include_headers',
RESPONSE_BODY_MAX_BYTES = 'response.include_body_max_bytes',
RESPONSE_RECEIVE_CHECK = 'check.receive',
RESPONSE_STATUS_CHECK = 'check.response.status',
REQUEST_BODY_CHECK = 'check.request.body',
@ -54,6 +58,8 @@ export enum ConfigKey {
SCREENSHOTS = 'screenshots',
SOURCE_PROJECT_CONTENT = 'source.project.content',
SOURCE_INLINE = 'source.inline.script',
IPV4 = 'ipv4',
IPV6 = 'ipv6',
PROJECT_ID = 'project_id',
SYNTHETICS_ARGS = 'synthetics_args',
TEXT_ASSERTION = 'playwright_text_assertion',
@ -73,6 +79,7 @@ export enum ConfigKey {
}
export const secretKeys = [
ConfigKey.PROXY_HEADERS,
ConfigKey.PARAMS,
ConfigKey.PASSWORD,
ConfigKey.REQUEST_BODY_CHECK,
@ -80,6 +87,7 @@ export const secretKeys = [
ConfigKey.REQUEST_SEND_CHECK,
ConfigKey.RESPONSE_BODY_CHECK_NEGATIVE,
ConfigKey.RESPONSE_BODY_CHECK_POSITIVE,
ConfigKey.RESPONSE_JSON_CHECK,
ConfigKey.RESPONSE_HEADERS_CHECK,
ConfigKey.RESPONSE_RECEIVE_CHECK,
ConfigKey.SOURCE_INLINE,

View file

@ -23,9 +23,11 @@ export const httpFormatters: HTTPFormatMap = {
[ConfigKey.USERNAME]: null,
[ConfigKey.PASSWORD]: null,
[ConfigKey.PROXY_URL]: null,
[ConfigKey.PROXY_HEADERS]: objectToJsonFormatter,
[ConfigKey.PORT]: null,
[ConfigKey.RESPONSE_BODY_CHECK_NEGATIVE]: arrayToJsonFormatter,
[ConfigKey.RESPONSE_BODY_CHECK_POSITIVE]: arrayToJsonFormatter,
[ConfigKey.RESPONSE_JSON_CHECK]: arrayToJsonFormatter,
[ConfigKey.RESPONSE_HEADERS_CHECK]: objectToJsonFormatter,
[ConfigKey.RESPONSE_STATUS_CHECK]: arrayToJsonFormatter,
[ConfigKey.REQUEST_HEADERS_CHECK]: objectToJsonFormatter,
@ -33,6 +35,10 @@ export const httpFormatters: HTTPFormatMap = {
fields[ConfigKey.REQUEST_BODY_CHECK]?.value
? JSON.stringify(fields[ConfigKey.REQUEST_BODY_CHECK]?.value)
: null,
[ConfigKey.RESPONSE_BODY_MAX_BYTES]: null,
[ConfigKey.MODE]: null,
[ConfigKey.IPV4]: null,
[ConfigKey.IPV6]: null,
...tlsFormatters,
...commonFormatters,
};

View file

@ -15,5 +15,8 @@ export type ICMPFormatMap = Record<keyof ICMPFields, Formatter>;
export const icmpFormatters: ICMPFormatMap = {
[ConfigKey.HOSTS]: null,
[ConfigKey.WAIT]: secondsToCronFormatter,
[ConfigKey.MODE]: null,
[ConfigKey.IPV4]: null,
[ConfigKey.IPV6]: null,
...commonFormatters,
};

View file

@ -23,6 +23,9 @@ export const tcpFormatters: TCPFormatMap = {
[ConfigKey.PROXY_URL]: null,
[ConfigKey.PORT]: null,
[ConfigKey.URLS]: null,
[ConfigKey.MODE]: null,
[ConfigKey.IPV4]: null,
[ConfigKey.IPV6]: null,
...tlsFormatters,
...commonFormatters,
};

View file

@ -54,15 +54,15 @@ export const MonacoEditorLangIdCodec = tEnum<MonacoEditorLangId>(
);
export type MonacoEditorLangIdType = t.TypeOf<typeof MonacoEditorLangIdCodec>;
export enum Mode {
export enum CodeEditorMode {
FORM = 'form',
JSON = 'json',
PLAINTEXT = 'text',
XML = 'xml',
}
export const ModeCodec = tEnum<Mode>('Mode', Mode);
export type ModeType = t.TypeOf<typeof ModeCodec>;
export const CodeEditorModeCodec = tEnum<CodeEditorMode>('CodeEditorMode', CodeEditorMode);
export type CodeEditorModeType = t.TypeOf<typeof CodeEditorModeCodec>;
export enum ContentType {
JSON = 'application/json',
@ -127,3 +127,16 @@ export enum FormMonitorType {
}
export const FormMonitorTypeCodec = tEnum<FormMonitorType>('FormMonitorType', FormMonitorType);
export enum Mode {
ANY = 'any',
ALL = 'all',
}
export const ModeCodec = tEnum<Mode>('Mode', Mode);
export type ModeType = t.TypeOf<typeof ModeCodec>;
export const ResponseCheckJSONCodec = t.interface({
description: t.string,
expression: t.string,
});
export type ResponseCheckJSON = t.TypeOf<typeof ResponseCheckJSONCodec>;

View file

@ -11,11 +11,13 @@ import { secretKeys } from '../../constants/monitor_management';
import { ConfigKey } from './config_key';
import { MonitorServiceLocationCodec, ServiceLocationErrors } from './locations';
import {
CodeEditorModeCodec,
DataStream,
DataStreamCodec,
FormMonitorTypeCodec,
ModeCodec,
ResponseBodyIndexPolicyCodec,
ResponseCheckJSONCodec,
ScheduleUnitCodec,
SourceTypeCodec,
TLSVersionCodec,
@ -94,10 +96,17 @@ export const TCPSimpleFieldsCodec = t.intersection([
export type TCPSimpleFields = t.TypeOf<typeof TCPSimpleFieldsCodec>;
// TCPAdvancedFields
export const TCPAdvancedFieldsCodec = t.interface({
[ConfigKey.PROXY_URL]: t.string,
[ConfigKey.PROXY_USE_LOCAL_RESOLVER]: t.boolean,
});
export const TCPAdvancedFieldsCodec = t.intersection([
t.interface({
[ConfigKey.PROXY_URL]: t.string,
[ConfigKey.PROXY_USE_LOCAL_RESOLVER]: t.boolean,
}),
t.partial({
[ConfigKey.MODE]: ModeCodec,
[ConfigKey.IPV4]: t.boolean,
[ConfigKey.IPV6]: t.boolean,
}),
]);
export const TCPSensitiveAdvancedFieldsCodec = t.interface({
[ConfigKey.RESPONSE_RECEIVE_CHECK]: t.string,
@ -136,7 +145,18 @@ export const ICMPSimpleFieldsCodec = t.intersection([
]);
export type ICMPSimpleFields = t.TypeOf<typeof ICMPSimpleFieldsCodec>;
export type ICMPFields = t.TypeOf<typeof ICMPSimpleFieldsCodec>;
// ICMPAdvancedFields
export const ICMPAdvancedFieldsCodec = t.partial({
[ConfigKey.MODE]: ModeCodec,
[ConfigKey.IPV4]: t.boolean,
[ConfigKey.IPV6]: t.boolean,
});
// ICMPFields
export const ICMPFieldsCodec = t.intersection([ICMPSimpleFieldsCodec, ICMPAdvancedFieldsCodec]);
export type ICMPFields = t.TypeOf<typeof ICMPFieldsCodec>;
// HTTPSimpleFields
export const HTTPSimpleFieldsCodec = t.intersection([
@ -152,23 +172,37 @@ export const HTTPSimpleFieldsCodec = t.intersection([
export type HTTPSimpleFields = t.TypeOf<typeof HTTPSimpleFieldsCodec>;
// HTTPAdvancedFields
export const HTTPAdvancedFieldsCodec = t.interface({
[ConfigKey.PROXY_URL]: t.string,
[ConfigKey.RESPONSE_BODY_INDEX]: ResponseBodyIndexPolicyCodec,
[ConfigKey.RESPONSE_HEADERS_INDEX]: t.boolean,
[ConfigKey.RESPONSE_STATUS_CHECK]: t.array(t.string),
[ConfigKey.REQUEST_METHOD_CHECK]: t.string,
});
export const HTTPAdvancedFieldsCodec = t.intersection([
t.interface({
[ConfigKey.PROXY_URL]: t.string,
[ConfigKey.RESPONSE_BODY_INDEX]: ResponseBodyIndexPolicyCodec,
[ConfigKey.RESPONSE_HEADERS_INDEX]: t.boolean,
[ConfigKey.RESPONSE_STATUS_CHECK]: t.array(t.string),
[ConfigKey.REQUEST_METHOD_CHECK]: t.string,
}),
t.partial({
[ConfigKey.MODE]: ModeCodec,
[ConfigKey.RESPONSE_BODY_MAX_BYTES]: t.string,
[ConfigKey.IPV4]: t.boolean,
[ConfigKey.IPV6]: t.boolean,
}),
]);
export const HTTPSensitiveAdvancedFieldsCodec = t.interface({
[ConfigKey.PASSWORD]: t.string,
[ConfigKey.RESPONSE_BODY_CHECK_NEGATIVE]: t.array(t.string),
[ConfigKey.RESPONSE_BODY_CHECK_POSITIVE]: t.array(t.string),
[ConfigKey.RESPONSE_HEADERS_CHECK]: t.record(t.string, t.string),
[ConfigKey.REQUEST_BODY_CHECK]: t.interface({ value: t.string, type: ModeCodec }),
[ConfigKey.REQUEST_HEADERS_CHECK]: t.record(t.string, t.string),
[ConfigKey.USERNAME]: t.string,
});
export const HTTPSensitiveAdvancedFieldsCodec = t.intersection([
t.interface({
[ConfigKey.PASSWORD]: t.string,
[ConfigKey.RESPONSE_BODY_CHECK_NEGATIVE]: t.array(t.string),
[ConfigKey.RESPONSE_BODY_CHECK_POSITIVE]: t.array(t.string),
[ConfigKey.RESPONSE_HEADERS_CHECK]: t.record(t.string, t.string),
[ConfigKey.REQUEST_BODY_CHECK]: t.interface({ value: t.string, type: CodeEditorModeCodec }),
[ConfigKey.REQUEST_HEADERS_CHECK]: t.record(t.string, t.string),
[ConfigKey.USERNAME]: t.string,
}),
t.partial({
[ConfigKey.PROXY_HEADERS]: t.record(t.string, t.string),
[ConfigKey.RESPONSE_JSON_CHECK]: t.array(ResponseCheckJSONCodec),
}),
]);
export const HTTPAdvancedCodec = t.intersection([
HTTPAdvancedFieldsCodec,

View file

@ -9,7 +9,7 @@ import React from 'react';
import { fireEvent, waitFor } from '@testing-library/react';
import { render } from '../../../utils/testing/rtl_helpers';
import { HeaderField, contentTypes } from './header_field';
import { Mode } from '../types';
import { CodeEditorMode } from '../types';
describe('<HeaderField />', () => {
const onChange = jest.fn();
@ -95,14 +95,14 @@ describe('<HeaderField />', () => {
});
it('handles content mode', async () => {
const contentMode: Mode = Mode.PLAINTEXT;
const contentMode: CodeEditorMode = CodeEditorMode.PLAINTEXT;
render(
<HeaderField defaultValue={defaultValue} onChange={onChange} contentMode={contentMode} />
);
await waitFor(() => {
expect(onChange).toBeCalledWith({
'Content-Type': contentTypes[Mode.PLAINTEXT],
'Content-Type': contentTypes[CodeEditorMode.PLAINTEXT],
});
});
});

View file

@ -7,12 +7,12 @@
import React, { useEffect, useState } from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import { ContentType, Mode } from '../types';
import { ContentType, CodeEditorMode } from '../types';
import { KeyValuePairsField, Pair } from './key_value_field';
export interface HeaderFieldProps {
contentMode?: Mode;
contentMode?: CodeEditorMode;
defaultValue: Record<string, string>;
onChange: (value: Record<string, string>) => void;
onBlur?: () => void;
@ -72,9 +72,9 @@ export const HeaderField = ({
);
};
export const contentTypes: Record<Mode, ContentType> = {
[Mode.JSON]: ContentType.JSON,
[Mode.PLAINTEXT]: ContentType.TEXT,
[Mode.XML]: ContentType.XML,
[Mode.FORM]: ContentType.FORM,
export const contentTypes: Record<CodeEditorMode, ContentType> = {
[CodeEditorMode.JSON]: ContentType.JSON,
[CodeEditorMode.PLAINTEXT]: ContentType.TEXT,
[CodeEditorMode.XML]: ContentType.XML,
[CodeEditorMode.FORM]: ContentType.FORM,
};

View file

@ -46,13 +46,15 @@ export type Pair = [
string // value
];
interface Props {
export interface KeyValuePairsFieldProps {
addPairControlLabel: string | React.ReactElement;
defaultPairs: Pair[];
onChange: (pairs: Pair[]) => void;
onBlur?: () => void;
'data-test-subj'?: string;
readOnly?: boolean;
keyLabel?: string | React.ReactElement;
valueLabel?: string | React.ReactElement;
}
export const KeyValuePairsField = ({
@ -62,7 +64,9 @@ export const KeyValuePairsField = ({
onBlur,
'data-test-subj': dataTestSubj,
readOnly,
}: Props) => {
keyLabel,
valueLabel,
}: KeyValuePairsFieldProps) => {
const [pairs, setPairs] = useState<Pair[]>(defaultPairs);
const handleOnChange = useCallback(
@ -121,20 +125,20 @@ export const KeyValuePairsField = ({
children: (
<EuiFlexGroup responsive={false}>
<EuiFlexItem>
{
{keyLabel || (
<FormattedMessage
id="xpack.synthetics.keyValuePairsField.key.label"
defaultMessage="Key"
/>
}
)}
</EuiFlexItem>
<EuiFlexItem>
{
{valueLabel || (
<FormattedMessage
id="xpack.synthetics.keyValuePairsField.value.label"
defaultMessage="Value"
/>
}
)}
</EuiFlexItem>
</EuiFlexGroup>
),

View file

@ -13,7 +13,7 @@ import { fireEvent, waitFor } from '@testing-library/react';
import { mockGlobals } from '../../../utils/testing';
import { render } from '../../../utils/testing/rtl_helpers';
import { RequestBodyField } from './request_body_field';
import { Mode } from '../types';
import { CodeEditorMode } from '../types';
mockGlobals();
@ -40,7 +40,7 @@ jest.mock('@kbn/kibana-react-plugin/public', () => {
});
describe('<RequestBodyField />', () => {
const defaultMode = Mode.PLAINTEXT;
const defaultMode = CodeEditorMode.PLAINTEXT;
const defaultValue = 'sample value';
const WrappedComponent = ({ readOnly }: { readOnly?: boolean }) => {
const [config, setConfig] = useState({
@ -55,7 +55,7 @@ describe('<RequestBodyField />', () => {
type: config.type,
}}
onChange={useCallback(
(code) => setConfig({ type: code.type as Mode, value: code.value }),
(code) => setConfig({ type: code.type as CodeEditorMode, value: code.value }),
[setConfig]
)}
readOnly={readOnly}

View file

@ -9,15 +9,15 @@ import { stringify, parse } from 'query-string';
import { FormattedMessage } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';
import { EuiTabbedContent } from '@elastic/eui';
import { Mode, MonacoEditorLangId } from '../types';
import { CodeEditorMode, MonacoEditorLangId } from '../types';
import { KeyValuePairsField, Pair } from './key_value_field';
import { CodeEditor } from './code_editor';
export interface RequestBodyFieldProps {
onChange: (requestBody: { type: Mode; value: string }) => void;
onChange: (requestBody: { type: CodeEditorMode; value: string }) => void;
onBlur?: () => void;
value: {
type: Mode;
type: CodeEditorMode;
value: string;
};
readOnly?: boolean;
@ -36,22 +36,27 @@ export const RequestBodyField = ({
readOnly,
}: RequestBodyFieldProps) => {
const [values, setValues] = useState<Record<ResponseBodyType, string>>({
[ResponseBodyType.FORM]: type === Mode.FORM ? value : '',
[ResponseBodyType.CODE]: type !== Mode.FORM ? value : '',
[ResponseBodyType.FORM]: type === CodeEditorMode.FORM ? value : '',
[ResponseBodyType.CODE]: type !== CodeEditorMode.FORM ? value : '',
});
useEffect(() => {
onChange({
type,
value: type === Mode.FORM ? values[ResponseBodyType.FORM] : values[ResponseBodyType.CODE],
value:
type === CodeEditorMode.FORM
? values[ResponseBodyType.FORM]
: values[ResponseBodyType.CODE],
});
}, [onChange, type, values]);
const handleSetMode = useCallback(
(currentMode: Mode) => {
(currentMode: CodeEditorMode) => {
onChange({
type: currentMode,
value:
currentMode === Mode.FORM ? values[ResponseBodyType.FORM] : values[ResponseBodyType.CODE],
currentMode === CodeEditorMode.FORM
? values[ResponseBodyType.FORM]
: values[ResponseBodyType.CODE],
});
},
[onChange, values]
@ -71,14 +76,14 @@ export const RequestBodyField = ({
}, {});
return setValues((prevValues) => ({
...prevValues,
[Mode.FORM]: stringify(formattedPairs),
[CodeEditorMode.FORM]: stringify(formattedPairs),
}));
},
[setValues]
);
const defaultFormPairs: Pair[] = useMemo(() => {
const pairs = parse(values[Mode.FORM]);
const pairs = parse(values[CodeEditorMode.FORM]);
const keys = Object.keys(pairs);
const formattedPairs: Pair[] = keys.map((key: string) => {
// key, value, checked;
@ -89,9 +94,9 @@ export const RequestBodyField = ({
const tabs = [
{
id: Mode.PLAINTEXT,
name: modeLabels[Mode.PLAINTEXT],
'data-test-subj': `syntheticsRequestBodyTab__${Mode.PLAINTEXT}`,
id: CodeEditorMode.PLAINTEXT,
name: modeLabels[CodeEditorMode.PLAINTEXT],
'data-test-subj': `syntheticsRequestBodyTab__${CodeEditorMode.PLAINTEXT}`,
content: (
<CodeEditor
ariaLabel={i18n.translate(
@ -100,7 +105,7 @@ export const RequestBodyField = ({
defaultMessage: 'Text code editor',
}
)}
id={Mode.PLAINTEXT}
id={CodeEditorMode.PLAINTEXT}
languageId={MonacoEditorLangId.PLAINTEXT}
onChange={(code) => {
setValues((prevValues) => ({ ...prevValues, [ResponseBodyType.CODE]: code }));
@ -112,9 +117,9 @@ export const RequestBodyField = ({
),
},
{
id: Mode.JSON,
name: modeLabels[Mode.JSON],
'data-test-subj': `syntheticsRequestBodyTab__${Mode.JSON}`,
id: CodeEditorMode.JSON,
name: modeLabels[CodeEditorMode.JSON],
'data-test-subj': `syntheticsRequestBodyTab__${CodeEditorMode.JSON}`,
content: (
<CodeEditor
ariaLabel={i18n.translate(
@ -123,7 +128,7 @@ export const RequestBodyField = ({
defaultMessage: 'JSON code editor',
}
)}
id={Mode.JSON}
id={CodeEditorMode.JSON}
languageId={MonacoEditorLangId.JSON}
onChange={(code) => {
setValues((prevValues) => ({ ...prevValues, [ResponseBodyType.CODE]: code }));
@ -135,9 +140,9 @@ export const RequestBodyField = ({
),
},
{
id: Mode.XML,
name: modeLabels[Mode.XML],
'data-test-subj': `syntheticsRequestBodyTab__${Mode.XML}`,
id: CodeEditorMode.XML,
name: modeLabels[CodeEditorMode.XML],
'data-test-subj': `syntheticsRequestBodyTab__${CodeEditorMode.XML}`,
content: (
<CodeEditor
ariaLabel={i18n.translate(
@ -146,7 +151,7 @@ export const RequestBodyField = ({
defaultMessage: 'XML code editor',
}
)}
id={Mode.XML}
id={CodeEditorMode.XML}
languageId={MonacoEditorLangId.XML}
onChange={(code) => {
setValues((prevValues) => ({ ...prevValues, [ResponseBodyType.CODE]: code }));
@ -158,9 +163,9 @@ export const RequestBodyField = ({
),
},
{
id: Mode.FORM,
name: modeLabels[Mode.FORM],
'data-test-subj': `syntheticsRequestBodyTab__${Mode.FORM}`,
id: CodeEditorMode.FORM,
name: modeLabels[CodeEditorMode.FORM],
'data-test-subj': `syntheticsRequestBodyTab__${CodeEditorMode.FORM}`,
content: (
<KeyValuePairsField
addPairControlLabel={
@ -187,7 +192,7 @@ export const RequestBodyField = ({
initialSelectedTab={tabs.find((tab) => tab.id === type)}
autoFocus="selected"
onTabClick={(tab) => {
handleSetMode(tab.id as Mode);
handleSetMode(tab.id as CodeEditorMode);
}}
/>
</div>
@ -195,25 +200,25 @@ export const RequestBodyField = ({
};
const modeLabels = {
[Mode.FORM]: i18n.translate(
[CodeEditorMode.FORM]: i18n.translate(
'xpack.synthetics.createPackagePolicy.stepConfigure.requestBodyType.form',
{
defaultMessage: 'Form',
}
),
[Mode.PLAINTEXT]: i18n.translate(
[CodeEditorMode.PLAINTEXT]: i18n.translate(
'xpack.synthetics.createPackagePolicy.stepConfigure.requestBodyType.text',
{
defaultMessage: 'Text',
}
),
[Mode.JSON]: i18n.translate(
[CodeEditorMode.JSON]: i18n.translate(
'xpack.synthetics.createPackagePolicy.stepConfigure.requestBodyType.JSON',
{
defaultMessage: 'JSON',
}
),
[Mode.XML]: i18n.translate(
[CodeEditorMode.XML]: i18n.translate(
'xpack.synthetics.createPackagePolicy.stepConfigure.requestBodyType.XML',
{
defaultMessage: 'XML',

View file

@ -24,7 +24,6 @@ export const Field = memo<Props>(
props,
fieldKey,
controlled,
showWhen,
shouldUseSetValue,
required,
validation,
@ -32,6 +31,7 @@ export const Field = memo<Props>(
fieldError,
dependencies,
customHook,
hidden,
}: Props) => {
const { register, watch, control, setValue, reset, getFieldState, formState } =
useFormContext<FormConfig>();
@ -41,13 +41,7 @@ export const Field = memo<Props>(
const [dependenciesFieldMeta, setDependenciesFieldMeta] = useState<
Record<string, ControllerFieldState>
>({});
let show = true;
let dependenciesValues: unknown[] = [];
if (showWhen) {
const [showKey, expectedValue] = showWhen;
const [actualValue] = watch([showKey]);
show = actualValue === expectedValue;
}
if (dependencies) {
dependenciesValues = watch(dependencies);
}
@ -64,7 +58,7 @@ export const Field = memo<Props>(
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [JSON.stringify(dependenciesValues || []), dependencies, getFieldState]);
if (!show) {
if (hidden && hidden(dependenciesValues)) {
return null;
}

View file

@ -6,6 +6,7 @@
*/
import React from 'react';
import { isEqual } from 'lodash';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { isValidNamespace } from '@kbn/fleet-plugin/common';
@ -15,7 +16,6 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiLink,
EuiTextArea,
EuiSelectProps,
EuiFieldTextProps,
EuiSwitchProps,
@ -54,6 +54,8 @@ import {
ResponseBodyIndexField,
ResponseBodyIndexFieldProps,
ControlledFieldProp,
KeyValuePairsField,
TextArea,
ThrottlingWrapper,
} from './field_wrappers';
import { getDocLinks } from '../../../../../kibana_services';
@ -64,16 +66,20 @@ import {
FormMonitorType,
HTTPMethod,
ScreenshotOption,
Mode,
MonitorFields,
TLSVersion,
VerificationMode,
FieldMap,
FormLocation,
ResponseBodyIndexPolicy,
ResponseCheckJSON,
ThrottlingConfig,
} from '../types';
import { AlertConfigKey, ALLOWED_SCHEDULES_IN_MINUTES } from '../constants';
import { getDefaultFormFields } from './defaults';
import { validate, validateHeaders, WHOLE_NUMBERS_ONLY, FLOATS_ONLY } from './validation';
import { KeyValuePairsFieldProps } from '../fields/key_value_field';
const getScheduleContent = (value: number) => {
if (value > 60) {
@ -765,7 +771,7 @@ export const FIELD = (readOnly?: boolean): FieldMap => ({
fieldKey: ConfigKey.RESPONSE_STATUS_CHECK,
component: FormattedComboBox,
label: i18n.translate('xpack.synthetics.monitorConfig.responseStatusCheck.label', {
defaultMessage: 'Check response status equals',
defaultMessage: 'Response status equals',
}),
helpText: i18n.translate('xpack.synthetics.monitorConfig.responseStatusCheck.helpText', {
defaultMessage:
@ -794,7 +800,7 @@ export const FIELD = (readOnly?: boolean): FieldMap => ({
fieldKey: ConfigKey.RESPONSE_HEADERS_CHECK,
component: HeaderField,
label: i18n.translate('xpack.synthetics.monitorConfig.responseHeadersCheck.label', {
defaultMessage: 'Check response headers contain',
defaultMessage: 'Response headers contain',
}),
helpText: i18n.translate('xpack.synthetics.monitorConfig.responseHeadersCheck.helpText', {
defaultMessage: 'A list of expected response headers.',
@ -814,7 +820,7 @@ export const FIELD = (readOnly?: boolean): FieldMap => ({
fieldKey: ConfigKey.RESPONSE_BODY_CHECK_POSITIVE,
component: FormattedComboBox,
label: i18n.translate('xpack.synthetics.monitorConfig.responseBodyCheck.label', {
defaultMessage: 'Check response body contains',
defaultMessage: 'Response body contains',
}),
helpText: i18n.translate('xpack.synthetics.monitorConfig.responseBodyCheck.helpText', {
defaultMessage:
@ -830,7 +836,7 @@ export const FIELD = (readOnly?: boolean): FieldMap => ({
fieldKey: ConfigKey.RESPONSE_BODY_CHECK_NEGATIVE,
component: FormattedComboBox,
label: i18n.translate('xpack.synthetics.monitorConfig.responseBodyCheckNegative.label', {
defaultMessage: 'Check response body does not contain',
defaultMessage: 'Response body does not contain',
}),
helpText: i18n.translate('xpack.synthetics.monitorConfig.responseBodyCheckNegative.helpText', {
defaultMessage:
@ -846,7 +852,7 @@ export const FIELD = (readOnly?: boolean): FieldMap => ({
fieldKey: ConfigKey.RESPONSE_RECEIVE_CHECK,
component: FieldText,
label: i18n.translate('xpack.synthetics.monitorConfig.responseReceiveCheck.label', {
defaultMessage: 'Check response contains',
defaultMessage: 'Response contains',
}),
helpText: i18n.translate('xpack.synthetics.monitorConfig.responseReceiveCheck.helpText', {
defaultMessage: 'The expected remote host response.',
@ -986,7 +992,11 @@ export const FIELD = (readOnly?: boolean): FieldMap => ({
defaultMessage:
'Verifies that the provided certificate is signed by a trusted authority (CA) and also verifies that the servers hostname (or IP address) matches the names identified within the certificate. If the Subject Alternative Name is empty, it returns an error.',
}),
showWhen: ['isTLSEnabled', true],
hidden: (dependencies) => {
const [isTLSEnabled] = dependencies;
return !Boolean(isTLSEnabled);
},
dependencies: ['isTLSEnabled'],
props: (): EuiSelectProps => ({
options: Object.values(VerificationMode).map((method) => ({
value: method,
@ -1002,7 +1012,11 @@ export const FIELD = (readOnly?: boolean): FieldMap => ({
defaultMessage: 'Supported TLS protocols',
}),
controlled: true,
showWhen: ['isTLSEnabled', true],
hidden: (dependencies) => {
const [isTLSEnabled] = dependencies;
return !Boolean(isTLSEnabled);
},
dependencies: ['isTLSEnabled'],
props: ({ field, setValue }): EuiComboBoxProps<TLSVersion> => {
return {
options: Object.values(TLSVersion).map((version) => ({
@ -1023,42 +1037,54 @@ export const FIELD = (readOnly?: boolean): FieldMap => ({
},
[ConfigKey.TLS_CERTIFICATE_AUTHORITIES]: {
fieldKey: ConfigKey.TLS_CERTIFICATE_AUTHORITIES,
component: EuiTextArea,
component: TextArea,
label: i18n.translate('xpack.synthetics.monitorConfig.certificateAuthorities.label', {
defaultMessage: 'Certificate authorities',
}),
helpText: i18n.translate('xpack.synthetics.monitorConfig.certificateAuthorities.helpText', {
defaultMessage: 'PEM-formatted custom certificate authorities.',
}),
showWhen: ['isTLSEnabled', true],
hidden: (dependencies) => {
const [isTLSEnabled] = dependencies;
return !Boolean(isTLSEnabled);
},
dependencies: ['isTLSEnabled'],
props: (): EuiTextAreaProps => ({
readOnly,
}),
},
[ConfigKey.TLS_CERTIFICATE]: {
fieldKey: ConfigKey.TLS_CERTIFICATE,
component: EuiTextArea,
component: TextArea,
label: i18n.translate('xpack.synthetics.monitorConfig.clientCertificate.label', {
defaultMessage: 'Client certificate',
}),
helpText: i18n.translate('xpack.synthetics.monitorConfig.clientCertificate.helpText', {
defaultMessage: 'PEM-formatted certificate for TLS client authentication.',
}),
showWhen: ['isTLSEnabled', true],
hidden: (dependencies) => {
const [isTLSEnabled] = dependencies;
return !Boolean(isTLSEnabled);
},
dependencies: ['isTLSEnabled'],
props: (): EuiTextAreaProps => ({
readOnly,
}),
},
[ConfigKey.TLS_KEY]: {
fieldKey: ConfigKey.TLS_KEY,
component: EuiTextArea,
component: TextArea,
label: i18n.translate('xpack.synthetics.monitorConfig.clientKey.label', {
defaultMessage: 'Client key',
}),
helpText: i18n.translate('xpack.synthetics.monitorConfig.clientKey.helpText', {
defaultMessage: 'PEM-formatted certificate key for TLS client authentication.',
}),
showWhen: ['isTLSEnabled', true],
hidden: (dependencies) => {
const [isTLSEnabled] = dependencies;
return !Boolean(isTLSEnabled);
},
dependencies: ['isTLSEnabled'],
props: (): EuiTextAreaProps => ({
readOnly,
}),
@ -1072,7 +1098,11 @@ export const FIELD = (readOnly?: boolean): FieldMap => ({
helpText: i18n.translate('xpack.synthetics.monitorConfig.clientKeyPassphrase.helpText', {
defaultMessage: 'Certificate key passphrase for TLS client authentication.',
}),
showWhen: ['isTLSEnabled', true],
hidden: (dependencies) => {
const [isTLSEnabled] = dependencies;
return !Boolean(isTLSEnabled);
},
dependencies: ['isTLSEnabled'],
props: (): EuiFieldPasswordProps => ({
readOnly,
}),
@ -1252,4 +1282,165 @@ export const FIELD = (readOnly?: boolean): FieldMap => ({
isDisabled: readOnly,
}),
},
[ConfigKey.MODE]: {
fieldKey: ConfigKey.MODE,
component: Select,
label: i18n.translate('xpack.synthetics.monitorConfig.mode.label', {
defaultMessage: 'Mode',
}),
helpText: (
<FormattedMessage
id="xpack.synthetics.monitorConfig.syntheticsArgs.mode.helpText"
defaultMessage="If {any}, the monitor pings only one IP address for a hostname. If {all}, the monitor pings all resolvable IPs for a hostname. {all} is useful if you are using a DNS-load balancer and want to ping every IP address for the specified hostname."
values={{
all: <EuiCode>all</EuiCode>,
any: <EuiCode>any</EuiCode>,
}}
/>
),
props: (): EuiSelectProps => ({
options: Object.values(Mode).map((value) => ({
value,
text: value,
})),
disabled: readOnly,
}),
},
[ConfigKey.RESPONSE_BODY_MAX_BYTES]: {
fieldKey: ConfigKey.RESPONSE_BODY_MAX_BYTES,
component: FieldNumber,
label: i18n.translate('xpack.synthetics.monitorConfig.responseBodyMaxBytes.label', {
defaultMessage: 'Response body max bytes',
}),
helpText: i18n.translate('xpack.synthetics.monitorConfig.responseBodyMaxBytes.helpText', {
defaultMessage: 'Controls the maximum size of the stored body contents.',
}),
hidden: (dependencies) => {
const [responseBodyIndex] = dependencies || [];
return responseBodyIndex === ResponseBodyIndexPolicy.NEVER;
},
props: (): EuiFieldNumberProps => ({ min: 1, step: 'any', readOnly }),
dependencies: [ConfigKey.RESPONSE_BODY_INDEX],
},
[ConfigKey.IPV4]: {
fieldKey: ConfigKey.IPV4, // also controls ipv6
component: ComboBox,
label: i18n.translate('xpack.synthetics.monitorConfig.ipv4.label', {
defaultMessage: 'IP protocols',
}),
helpText: i18n.translate('xpack.synthetics.monitorConfig.ipv4.helpText', {
defaultMessage: 'IP protocols to use when pinging the remote host.',
}),
controlled: true,
dependencies: [ConfigKey.IPV6],
props: ({ field, setValue, dependencies }): EuiComboBoxProps<string> => {
const [ipv6] = dependencies;
const ipv4 = field?.value;
const values: string[] = [];
if (ipv4) {
values.push('IPv4');
}
if (ipv6) {
values.push('IPv6');
}
return {
options: [
{
label: 'IPv4',
},
{
label: 'IPv6',
},
],
selectedOptions: values.map((version) => ({
label: version,
})),
onChange: (updatedValues: Array<EuiComboBoxOptionOption<string>>) => {
setValue(
ConfigKey.IPV4,
updatedValues.some((value) => value.label === 'IPv4')
);
setValue(
ConfigKey.IPV6,
updatedValues.some((value) => value.label === 'IPv6')
);
},
isDisabled: readOnly,
};
},
},
[ConfigKey.PROXY_HEADERS]: {
fieldKey: ConfigKey.PROXY_HEADERS,
component: HeaderField,
label: i18n.translate('xpack.synthetics.monitorConfig.proxyHeaders.label', {
defaultMessage: 'Proxy headers',
}),
helpText: i18n.translate('xpack.synthetics.monitorConfig.proxyHeaders.helpText', {
defaultMessage: 'Additional headers to send to proxies for CONNECT requests.',
}),
controlled: true,
validation: () => ({
validate: (headers) => !validateHeaders(headers),
}),
error: i18n.translate('xpack.synthetics.monitorConfig.proxyHeaders.error', {
defaultMessage: 'The header key must be a valid HTTP token.',
}),
props: (): HeaderFieldProps => ({
readOnly,
}),
},
['check.response.json']: {
fieldKey: ConfigKey.RESPONSE_JSON_CHECK,
component: KeyValuePairsField,
label: i18n.translate('xpack.synthetics.monitorConfig.responseJSON.label', {
defaultMessage: 'Response body contains JSON',
}),
helpText: i18n.translate('xpack.synthetics.monitorConfig.responseJSON.helpText', {
defaultMessage:
'A list of expressions executed against the body when parsed as JSON. The body size must be less than or equal to 100 MiB.',
}),
controlled: true,
props: ({ field, setValue }): KeyValuePairsFieldProps => ({
readOnly,
keyLabel: i18n.translate('xpack.synthetics.monitorConfig.responseJSON.key.label', {
defaultMessage: 'Description',
}),
valueLabel: i18n.translate('xpack.synthetics.monitorConfig.responseJSON.value.label', {
defaultMessage: 'Expression',
}),
addPairControlLabel: i18n.translate(
'xpack.synthetics.monitorConfig.responseJSON.addPair.label',
{
defaultMessage: 'Add expression',
}
),
onChange: (pairs) => {
const value: ResponseCheckJSON[] = pairs
.map((pair) => {
const [description, expression] = pair;
return {
description,
expression,
};
})
.filter((pair) => pair.description || pair.expression);
if (!isEqual(value, field?.value)) {
setValue(ConfigKey.RESPONSE_JSON_CHECK, value);
}
},
defaultPairs: field?.value.map((check) => [check.description, check.expression]) || [],
}),
validation: () => {
return {
validate: (value: ResponseCheckJSON[]) => {
if (value.some((check) => !check.expression || !check.description)) {
return i18n.translate('xpack.synthetics.monitorConfig.responseJSON.error', {
defaultMessage:
"This JSON expression isn't valid. Make sure that both the label and expression are defined.",
});
}
},
};
},
},
});

View file

@ -25,6 +25,8 @@ import {
EuiButtonGroupProps,
EuiComboBox,
EuiComboBoxProps,
EuiTextArea,
EuiTextAreaProps,
} from '@elastic/eui';
import {
ThrottlingConfigField,
@ -47,6 +49,10 @@ import {
HeaderField as DefaultHeaderField,
HeaderFieldProps as DefaultHeaderFieldProps,
} from '../fields/header_field';
import {
KeyValuePairsField as DefaultKeyValuePairsField,
KeyValuePairsFieldProps as DefaultKeyValuePairsFieldProps,
} from '../fields/key_value_field';
import {
RequestBodyField as DefaultRequestBodyField,
RequestBodyFieldProps as DefaultRequestBodyFieldProps,
@ -81,6 +87,10 @@ export const FieldText = React.forwardRef<HTMLInputElement, EuiFieldTextProps>(
)
);
export const TextArea = React.forwardRef<HTMLTextAreaElement, EuiTextAreaProps>((props, ref) => (
<EuiTextArea data-test-subj="syntheticsTextAreaTextArea" {...props} inputRef={ref} />
));
export const FieldNumber = React.forwardRef<HTMLInputElement, EuiFieldNumberProps>((props, ref) => (
<EuiFieldNumber data-test-subj="syntheticsFieldNumberFieldNumber" {...props} inputRef={ref} />
));
@ -129,6 +139,10 @@ export const HeaderField = React.forwardRef<unknown, DefaultHeaderFieldProps>((p
<DefaultHeaderField {...props} />
));
export const KeyValuePairsField = React.forwardRef<unknown, DefaultKeyValuePairsFieldProps>(
(props, _ref) => <DefaultKeyValuePairsField {...props} />
);
export const RequestBodyField = React.forwardRef<unknown, DefaultRequestBodyFieldProps>(
(props, _ref) => <DefaultRequestBodyField {...props} />
);

View file

@ -39,10 +39,13 @@ const HTTP_ADVANCED = (readOnly: boolean) => ({
components: [
FIELD(readOnly)[ConfigKey.USERNAME],
FIELD(readOnly)[ConfigKey.PASSWORD],
FIELD(readOnly)[ConfigKey.PROXY_URL],
FIELD(readOnly)[ConfigKey.REQUEST_METHOD_CHECK],
FIELD(readOnly)[ConfigKey.REQUEST_HEADERS_CHECK],
FIELD(readOnly)[ConfigKey.REQUEST_BODY_CHECK],
FIELD(readOnly)[ConfigKey.PROXY_URL],
FIELD(readOnly)[ConfigKey.PROXY_HEADERS],
FIELD(readOnly)[ConfigKey.MODE],
FIELD(readOnly)[ConfigKey.IPV4],
],
},
responseConfig: {
@ -58,6 +61,7 @@ const HTTP_ADVANCED = (readOnly: boolean) => ({
components: [
FIELD(readOnly)[ConfigKey.RESPONSE_HEADERS_INDEX],
FIELD(readOnly)[ConfigKey.RESPONSE_BODY_INDEX],
FIELD(readOnly)[ConfigKey.RESPONSE_BODY_MAX_BYTES],
],
},
responseChecks: {
@ -75,6 +79,7 @@ const HTTP_ADVANCED = (readOnly: boolean) => ({
FIELD(readOnly)[ConfigKey.RESPONSE_HEADERS_CHECK],
FIELD(readOnly)[ConfigKey.RESPONSE_BODY_CHECK_POSITIVE],
FIELD(readOnly)[ConfigKey.RESPONSE_BODY_CHECK_NEGATIVE],
FIELD(readOnly)[ConfigKey.RESPONSE_JSON_CHECK],
],
},
});
@ -93,6 +98,8 @@ export const TCP_ADVANCED = (readOnly: boolean) => ({
components: [
FIELD(readOnly)[`${ConfigKey.PROXY_URL}__tcp`],
FIELD(readOnly)[ConfigKey.REQUEST_SEND_CHECK],
FIELD(readOnly)[ConfigKey.MODE],
FIELD(readOnly)[ConfigKey.IPV4],
],
},
responseChecks: {
@ -109,6 +116,21 @@ export const TCP_ADVANCED = (readOnly: boolean) => ({
},
});
export const ICMP_ADVANCED = (readOnly: boolean) => ({
requestConfig: {
title: i18n.translate('xpack.synthetics.monitorConfig.section.requestConfigICMP.title', {
defaultMessage: 'Request configuration',
}),
description: i18n.translate(
'xpack.synthetics.monitorConfig.section.requestConfigICMP.description',
{
defaultMessage: 'Configure the payload sent to the remote host.',
}
),
components: [FIELD(readOnly)[ConfigKey.MODE], FIELD(readOnly)[ConfigKey.IPV4]],
},
});
export const BROWSER_ADVANCED = (readOnly: boolean) => [
{
title: i18n.translate('xpack.synthetics.monitorConfig.section.syntAgentOptions.title', {
@ -264,6 +286,6 @@ export const FORM_CONFIG = (readOnly: boolean): FieldConfig => ({
FIELD(readOnly)[ConfigKey.ENABLED],
FIELD(readOnly)[AlertConfigKey.STATUS_ENABLED],
],
advanced: [DEFAULT_DATA_OPTIONS(readOnly)],
advanced: [DEFAULT_DATA_OPTIONS(readOnly), ICMP_ADVANCED(readOnly).requestConfig],
},
});

View file

@ -17,6 +17,7 @@ import {
ServiceLocation,
FormMonitorType,
MonitorFields,
ResponseCheckJSON,
} from '../../../../../common/runtime_types/monitor_management';
import { AlertConfigKey } from './constants';
@ -55,6 +56,11 @@ export type FormConfig = MonitorFields & {
ssl: {
supported_protocols: MonitorFields[ConfigKey.TLS_VERSION];
};
check: {
response: {
json: ResponseCheckJSON[];
};
};
};
export interface FieldMeta<TFieldKey extends keyof FormConfig> {
@ -63,6 +69,7 @@ export interface FieldMeta<TFieldKey extends keyof FormConfig> {
label?: string;
ariaLabel?: string;
helpText?: string | React.ReactNode;
hidden?: (depenencies: unknown[]) => boolean;
props?: (params: {
field?: ControllerRenderProps<FormConfig, TFieldKey>;
formState: FormState<FormConfig>;
@ -88,7 +95,6 @@ export interface FieldMeta<TFieldKey extends keyof FormConfig> {
event: React.ChangeEvent<HTMLInputElement>,
formOnChange: (event: React.ChangeEvent<HTMLInputElement>) => void
) => void;
showWhen?: [keyof FormConfig, any]; // show field when another field equals an arbitrary value
validation?: (dependencies: unknown[]) => Parameters<UseFormReturn['register']>[1];
error?: React.ReactNode;
dependencies?: Array<keyof FormConfig>; // fields that another field may depend for or validation. Values are passed to the validation function
@ -123,16 +129,19 @@ export interface FieldMap {
[ConfigKey.USERNAME]: FieldMeta<ConfigKey.USERNAME>;
[ConfigKey.PASSWORD]: FieldMeta<ConfigKey.PASSWORD>;
[ConfigKey.PROXY_URL]: FieldMeta<ConfigKey.PROXY_URL>;
[ConfigKey.PROXY_HEADERS]: FieldMeta<ConfigKey.PROXY_HEADERS>;
['proxy_url__tcp']: FieldMeta<ConfigKey.PROXY_URL>;
[ConfigKey.REQUEST_METHOD_CHECK]: FieldMeta<ConfigKey.REQUEST_METHOD_CHECK>;
[ConfigKey.REQUEST_HEADERS_CHECK]: FieldMeta<ConfigKey.REQUEST_HEADERS_CHECK>;
[ConfigKey.REQUEST_BODY_CHECK]: FieldMeta<ConfigKey.REQUEST_BODY_CHECK>;
[ConfigKey.RESPONSE_HEADERS_INDEX]: FieldMeta<ConfigKey.RESPONSE_HEADERS_INDEX>;
[ConfigKey.RESPONSE_BODY_INDEX]: FieldMeta<ConfigKey.RESPONSE_BODY_INDEX>;
[ConfigKey.RESPONSE_BODY_MAX_BYTES]: FieldMeta<ConfigKey.RESPONSE_BODY_MAX_BYTES>;
[ConfigKey.RESPONSE_STATUS_CHECK]: FieldMeta<ConfigKey.RESPONSE_STATUS_CHECK>;
[ConfigKey.RESPONSE_HEADERS_CHECK]: FieldMeta<ConfigKey.RESPONSE_HEADERS_CHECK>;
[ConfigKey.RESPONSE_BODY_CHECK_POSITIVE]: FieldMeta<ConfigKey.RESPONSE_BODY_CHECK_POSITIVE>;
[ConfigKey.RESPONSE_BODY_CHECK_NEGATIVE]: FieldMeta<ConfigKey.RESPONSE_BODY_CHECK_NEGATIVE>;
[ConfigKey.RESPONSE_JSON_CHECK]: FieldMeta<ConfigKey.RESPONSE_JSON_CHECK>;
[ConfigKey.RESPONSE_RECEIVE_CHECK]: FieldMeta<ConfigKey.RESPONSE_RECEIVE_CHECK>;
[ConfigKey.REQUEST_SEND_CHECK]: FieldMeta<ConfigKey.REQUEST_SEND_CHECK>;
['source.inline']: FieldMeta<ConfigKey.SOURCE_INLINE>;
@ -142,4 +151,6 @@ export interface FieldMap {
[ConfigKey.PLAYWRIGHT_OPTIONS]: FieldMeta<ConfigKey.PLAYWRIGHT_OPTIONS>;
[ConfigKey.SYNTHETICS_ARGS]: FieldMeta<ConfigKey.SYNTHETICS_ARGS>;
[ConfigKey.IGNORE_HTTPS_ERRORS]: FieldMeta<ConfigKey.IGNORE_HTTPS_ERRORS>;
[ConfigKey.MODE]: FieldMeta<ConfigKey.MODE>;
[ConfigKey.IPV4]: FieldMeta<ConfigKey.IPV4>;
}

View file

@ -105,7 +105,7 @@ const getNearestSupportedSchedule = (currentSchedule: string): string => {
return closest;
} catch {
return ALLOWED_SCHEDULES_IN_MINUTES[0];
return '10';
}
};

View file

@ -9,6 +9,7 @@ import {
BrowserAdvancedFields,
BrowserFields,
BrowserSimpleFields,
CodeEditorMode,
CommonFields,
ConfigKey,
DataStream,
@ -18,7 +19,6 @@ import {
HTTPSimpleFields,
ICMPSimpleFields,
Metadata,
Mode,
MonitorFields,
ResponseBodyIndexPolicy,
ScheduleUnit,
@ -142,7 +142,7 @@ describe('validateMonitor', () => {
[ConfigKey.RESPONSE_HEADERS_CHECK]: {},
[ConfigKey.RESPONSE_HEADERS_INDEX]: true,
[ConfigKey.RESPONSE_STATUS_CHECK]: ['200', '201'],
[ConfigKey.REQUEST_BODY_CHECK]: { value: 'testValue', type: Mode.JSON },
[ConfigKey.REQUEST_BODY_CHECK]: { value: 'testValue', type: CodeEditorMode.JSON },
[ConfigKey.REQUEST_HEADERS_CHECK]: {},
[ConfigKey.REQUEST_METHOD_CHECK]: '',
[ConfigKey.USERNAME]: 'test-username',

View file

@ -14,7 +14,7 @@ import {
import {
ConfigKey,
DataStream,
Mode,
CodeEditorMode,
MonitorFields,
ResponseBodyIndexPolicy,
ScheduleUnit,
@ -39,11 +39,19 @@ const testHTTPConfig: Partial<MonitorFields> = {
proxy_url: '${proxyUrl}',
'check.response.body.negative': [],
'check.response.body.positive': [],
'check.response.json': [
{
description: 'test description',
expression: 'foo.bar == "myValue"',
},
],
'response.include_body': 'on_error' as ResponseBodyIndexPolicy,
'check.response.headers': {},
'check.response.headers': {
'test-header': 'test-value',
},
'response.include_headers': true,
'check.response.status': [],
'check.request.body': { type: 'text' as Mode, value: '' },
'check.request.body': { type: 'text' as CodeEditorMode, value: '' },
'check.request.headers': {},
'check.request.method': 'GET',
'ssl.verification_mode': VerificationMode.NONE,
@ -99,6 +107,15 @@ describe('formatMonitorConfig', () => {
expect(yamlConfig).toEqual({
'check.request.method': 'GET',
'check.response.headers': {
'test-header': 'test-value',
},
'check.response.json': [
{
description: 'test description',
expression: 'foo.bar == "myValue"',
},
],
enabled: true,
locations: [],
max_redirects: '0',
@ -129,6 +146,15 @@ describe('formatMonitorConfig', () => {
expect(yamlConfig).toEqual({
'check.request.method': 'GET',
'check.response.headers': {
'test-header': 'test-value',
},
'check.response.json': [
{
description: 'test description',
expression: 'foo.bar == "myValue"',
},
],
enabled: true,
locations: [],
max_redirects: '0',

View file

@ -17,10 +17,12 @@ export const httpFormatters: HTTPFormatMap = {
[ConfigKey.METADATA]: objectFormatter,
[ConfigKey.RESPONSE_BODY_CHECK_NEGATIVE]: arrayFormatter,
[ConfigKey.RESPONSE_BODY_CHECK_POSITIVE]: arrayFormatter,
[ConfigKey.RESPONSE_JSON_CHECK]: arrayFormatter,
[ConfigKey.RESPONSE_HEADERS_CHECK]: objectFormatter,
[ConfigKey.RESPONSE_STATUS_CHECK]: arrayFormatter,
[ConfigKey.REQUEST_HEADERS_CHECK]: objectFormatter,
[ConfigKey.REQUEST_BODY_CHECK]: (fields) => fields[ConfigKey.REQUEST_BODY_CHECK]?.value || null,
[ConfigKey.PROXY_HEADERS]: objectFormatter,
...tlsFormatters,
...commonFormatters,
};

View file

@ -7,11 +7,11 @@
import { get } from 'lodash';
import { DEFAULT_FIELDS } from '../../../../common/constants/monitor_defaults';
import {
CodeEditorMode,
ConfigKey,
DataStream,
FormMonitorType,
HTTPFields,
Mode,
TLSVersion,
} from '../../../../common/runtime_types/monitor_management';
import {
@ -70,6 +70,11 @@ export const getNormalizeHTTPFields = ({
(yamlConfig as Record<keyof HTTPFields, unknown>)[ConfigKey.REQUEST_BODY_CHECK] as string,
defaultFields[ConfigKey.REQUEST_BODY_CHECK]
),
[ConfigKey.RESPONSE_BODY_MAX_BYTES]: `${get(
yamlConfig,
ConfigKey.RESPONSE_BODY_MAX_BYTES,
defaultFields[ConfigKey.RESPONSE_BODY_MAX_BYTES]
)}`,
[ConfigKey.TLS_VERSION]: get(monitor, ConfigKey.TLS_VERSION)
? (getOptionalListField(get(monitor, ConfigKey.TLS_VERSION)) as TLSVersion[])
: defaultFields[ConfigKey.TLS_VERSION],
@ -94,14 +99,14 @@ export const getRequestBodyField = (
defaultValue: HTTPFields[ConfigKey.REQUEST_BODY_CHECK]
): HTTPFields[ConfigKey.REQUEST_BODY_CHECK] => {
let parsedValue: string;
let type: Mode;
let type: CodeEditorMode;
if (typeof value === 'object') {
parsedValue = JSON.stringify(value);
type = Mode.JSON;
type = CodeEditorMode.JSON;
} else {
parsedValue = value;
type = Mode.PLAINTEXT;
type = CodeEditorMode.PLAINTEXT;
}
return {
type,

View file

@ -36,7 +36,7 @@ export default function ({ getService }: FtrProviderContext) {
before(async () => {
await supertestAPI.post('/api/fleet/setup').set('kbn-xsrf', 'true').send().expect(200);
await supertestAPI
.post('/api/fleet/epm/packages/synthetics/0.11.4')
.post('/api/fleet/epm/packages/synthetics/0.12.0')
.set('kbn-xsrf', 'true')
.send({ force: true })
.expect(200);
@ -455,7 +455,7 @@ export default function ({ getService }: FtrProviderContext) {
pkgPolicy.id === monitorId + '-' + testFleetPolicyID + `-default`
);
expect(packagePolicy.package.version).eql('0.11.4');
expect(packagePolicy.package.version).eql('0.12.0');
await supertestAPI.post('/api/fleet/setup').set('kbn-xsrf', 'true').send().expect(200);
const policyResponseAfterUpgrade = await supertestAPI.get(
@ -465,7 +465,7 @@ export default function ({ getService }: FtrProviderContext) {
(pkgPolicy: PackagePolicy) =>
pkgPolicy.id === monitorId + '-' + testFleetPolicyID + `-default`
);
expect(semver.gte(packagePolicyAfterUpgrade.package.version, '0.11.4')).eql(true);
expect(semver.gte(packagePolicyAfterUpgrade.package.version, '0.12.0')).eql(true);
} finally {
await supertestAPI
.delete(API_URLS.SYNTHETICS_MONITORS + '/' + monitorId)

View file

@ -77,7 +77,7 @@ export default function ({ getService }: FtrProviderContext) {
await supertest.put(API_URLS.SYNTHETICS_ENABLEMENT).set('kbn-xsrf', 'true').expect(200);
await supertest.post('/api/fleet/setup').set('kbn-xsrf', 'true').send().expect(200);
await supertest
.post('/api/fleet/epm/packages/synthetics/0.11.4')
.post('/api/fleet/epm/packages/synthetics/0.12.0')
.set('kbn-xsrf', 'true')
.send({ force: true })
.expect(200);
@ -321,6 +321,9 @@ export default function ({ getService }: FtrProviderContext) {
custom_heartbeat_id: `${journeyId}-${project}-default`,
'check.response.body.negative': [],
'check.response.body.positive': ['Saved', 'saved'],
'check.response.json': [
{ description: 'check status', expression: 'foo.bar == "myValue"' },
],
'check.response.headers': {},
'check.request.body': {
type: 'text',
@ -357,8 +360,10 @@ export default function ({ getService }: FtrProviderContext) {
username: '',
password: '',
proxy_url: '',
proxy_headers: {},
'response.include_body': 'always',
'response.include_headers': false,
'response.include_body_max_bytes': '900',
revision: 1,
schedule: {
number: '60',
@ -378,6 +383,9 @@ export default function ({ getService }: FtrProviderContext) {
'url.port': null,
id: `${journeyId}-${project}-default`,
hash: 'ekrjelkjrelkjre',
mode: 'any',
ipv6: true,
ipv4: true,
});
}
} finally {
@ -486,6 +494,9 @@ export default function ({ getService }: FtrProviderContext) {
urls: '',
id: `${journeyId}-${project}-default`,
hash: 'ekrjelkjrelkjre',
mode: 'any',
ipv6: true,
ipv4: true,
});
}
} finally {
@ -590,6 +601,9 @@ export default function ({ getService }: FtrProviderContext) {
: `${parseInt(monitor.wait?.slice(0, -1) || '1', 10) * 60}`,
id: `${journeyId}-${project}-default`,
hash: 'ekrjelkjrelkjre',
mode: 'any',
ipv4: true,
ipv6: true,
});
}
} finally {
@ -1784,6 +1798,7 @@ export default function ({ getService }: FtrProviderContext) {
positive: ['Saved', 'saved'],
},
status: [200],
json: [{ description: 'check status', expression: 'foo.bar == "myValue"' }],
},
enabled: false,
hash: 'ekrjelkjrelkjre',
@ -1792,6 +1807,7 @@ export default function ({ getService }: FtrProviderContext) {
name: 'My Monitor 3',
response: {
include_body: 'always',
include_body_max_bytes: 900,
},
'response.include_headers': false,
schedule: 60,
@ -1885,6 +1901,12 @@ export default function ({ getService }: FtrProviderContext) {
positive: ['Saved', 'saved'],
},
status: [200],
json: [
{
description: 'check status',
expression: 'foo.bar == "myValue"',
},
],
},
enabled: false,
hash: 'ekrjelkjrelkjre',
@ -1893,6 +1915,7 @@ export default function ({ getService }: FtrProviderContext) {
name: 'My Monitor 3',
response: {
include_body: 'always',
include_body_max_bytes: 900,
},
'response.include_headers': false,
schedule: 60,
@ -1946,6 +1969,12 @@ export default function ({ getService }: FtrProviderContext) {
positive: ['Saved', 'saved'],
},
status: [200],
json: [
{
description: 'check status',
expression: 'foo.bar == "myValue"',
},
],
},
enabled: false,
hash: 'ekrjelkjrelkjre',
@ -1954,6 +1983,7 @@ export default function ({ getService }: FtrProviderContext) {
name: 'My Monitor 3',
response: {
include_body: 'always',
include_body_max_bytes: 900,
},
'response.include_headers': false,
schedule: 60,
@ -2008,6 +2038,12 @@ export default function ({ getService }: FtrProviderContext) {
positive: ['Saved', 'saved'],
},
status: [200],
json: [
{
description: 'check status',
expression: 'foo.bar == "myValue"',
},
],
},
enabled: false,
hash: 'ekrjelkjrelkjre',
@ -2016,6 +2052,7 @@ export default function ({ getService }: FtrProviderContext) {
name: 'My Monitor 3',
response: {
include_body: 'always',
include_body_max_bytes: 900,
},
'response.include_headers': false,
schedule: 60,

View file

@ -86,7 +86,7 @@ export default function ({ getService }: FtrProviderContext) {
before(async () => {
await supertest.post('/api/fleet/setup').set('kbn-xsrf', 'true').send().expect(200);
await supertest
.post('/api/fleet/epm/packages/synthetics/0.11.4')
.post('/api/fleet/epm/packages/synthetics/0.12.0')
.set('kbn-xsrf', 'true')
.send({ force: true })
.expect(200);
@ -256,6 +256,9 @@ export default function ({ getService }: FtrProviderContext) {
custom_heartbeat_id: `${journeyId}-test-suite-default`,
'check.response.body.negative': [],
'check.response.body.positive': ['Saved', 'saved'],
'check.response.json': [
{ description: 'check status', expression: 'foo.bar == "myValue"' },
],
'check.response.headers': {},
'check.request.body': {
type: 'text',
@ -292,8 +295,10 @@ export default function ({ getService }: FtrProviderContext) {
username: '',
password: '',
proxy_url: '',
proxy_headers: {},
'response.include_body': 'always',
'response.include_headers': false,
'response.include_body_max_bytes': '900',
revision: 1,
schedule: {
number: '60',
@ -313,6 +318,9 @@ export default function ({ getService }: FtrProviderContext) {
'url.port': null,
id: `${journeyId}-test-suite-default`,
hash: 'ekrjelkjrelkjre',
ipv6: true,
ipv4: true,
mode: 'any',
});
}
} finally {
@ -418,6 +426,9 @@ export default function ({ getService }: FtrProviderContext) {
urls: '',
id: `${journeyId}-test-suite-default`,
hash: 'ekrjelkjrelkjre',
ipv6: true,
ipv4: true,
mode: 'any',
});
}
} finally {
@ -520,6 +531,9 @@ export default function ({ getService }: FtrProviderContext) {
: `${parseInt(monitor.wait?.slice(0, -1) || '1', 10) * 60}`,
id: `${journeyId}-test-suite-default`,
hash: 'ekrjelkjrelkjre',
ipv6: true,
ipv4: true,
mode: 'any',
});
}
} finally {
@ -1802,11 +1816,13 @@ export default function ({ getService }: FtrProviderContext) {
timeout: { value: '80s', type: 'text' },
max_redirects: { value: '0', type: 'integer' },
proxy_url: { value: '', type: 'text' },
proxy_headers: { value: null, type: 'yaml' },
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' },
'response.include_body_max_bytes': { value: '900', type: 'text' },
'check.request.method': { value: 'POST', type: 'text' },
'check.request.headers': {
value: '{"Content-Type":"application/x-www-form-urlencoded"}',
@ -1817,6 +1833,10 @@ export default function ({ getService }: FtrProviderContext) {
'check.response.headers': { value: null, type: 'yaml' },
'check.response.body.positive': { value: '["Saved","saved"]', type: 'yaml' },
'check.response.body.negative': { value: null, type: 'yaml' },
'check.response.json': {
value: '[{"description":"check status","expression":"foo.bar == \\"myValue\\""}]',
type: 'yaml',
},
'ssl.certificate_authorities': { value: null, type: 'yaml' },
'ssl.certificate': { value: null, type: 'yaml' },
'ssl.key': { value: null, type: 'yaml' },
@ -1842,6 +1862,9 @@ export default function ({ getService }: FtrProviderContext) {
type: 'text',
value: 'test-suite',
},
ipv4: { type: 'bool', value: true },
ipv6: { type: 'bool', value: true },
mode: { type: 'text', value: 'any' },
},
id: `synthetics/http-http-${id}-${testPolicyId}`,
compiled_stream: {
@ -1866,6 +1889,15 @@ export default function ({ getService }: FtrProviderContext) {
'ssl.supported_protocols': ['TLSv1.1', 'TLSv1.2', 'TLSv1.3'],
'run_from.geo.name': 'Test private location 0',
'run_from.id': 'Test private location 0',
'check.response.json': [
{
description: 'check status',
expression: 'foo.bar == "myValue"',
},
],
ipv4: true,
ipv6: true,
mode: 'any',
processors: [
{
add_fields: {

View file

@ -41,7 +41,7 @@ export default function ({ getService }: FtrProviderContext) {
_httpMonitorJson = getFixtureJson('http_monitor');
await supertest.post('/api/fleet/setup').set('kbn-xsrf', 'true').send().expect(200);
await supertest
.post('/api/fleet/epm/packages/synthetics/0.11.4')
.post('/api/fleet/epm/packages/synthetics/0.12.0')
.set('kbn-xsrf', 'true')
.send({ force: true })
.expect(200);

View file

@ -45,7 +45,7 @@ export default function ({ getService }: FtrProviderContext) {
before(async () => {
await supertest.post('/api/fleet/setup').set('kbn-xsrf', 'true').send().expect(200);
await supertest
.post('/api/fleet/epm/packages/synthetics/0.11.4')
.post('/api/fleet/epm/packages/synthetics/0.12.0')
.set('kbn-xsrf', 'true')
.send({ force: true })
.expect(200);

View file

@ -46,7 +46,7 @@ export default function ({ getService }: FtrProviderContext) {
before(async () => {
await supertest.post('/api/fleet/setup').set('kbn-xsrf', 'true').send().expect(200);
await supertest
.post('/api/fleet/epm/packages/synthetics/0.11.4')
.post('/api/fleet/epm/packages/synthetics/0.12.0')
.set('kbn-xsrf', 'true')
.send({ force: true })
.expect(200);

View file

@ -21,7 +21,7 @@ export const getTestBrowserSyntheticsPolicy = ({
version: 'WzEzNzYsMV0=',
name: 'Test HTTP Monitor 03-Test private location 0-default',
namespace: 'testnamespace',
package: { name: 'synthetics', title: 'Elastic Synthetics', version: '0.11.4' },
package: { name: 'synthetics', title: 'Elastic Synthetics', version: '0.12.0' },
enabled: true,
policy_id: 'fe621d20-7b01-11ed-803f-475d82e1f9ca',
inputs: [
@ -44,11 +44,13 @@ export const getTestBrowserSyntheticsPolicy = ({
timeout: { type: 'text' },
max_redirects: { type: 'integer' },
proxy_url: { type: 'text' },
proxy_headers: { type: 'yaml' },
tags: { type: 'yaml' },
username: { type: 'text' },
password: { type: 'password' },
'response.include_headers': { type: 'bool' },
'response.include_body': { type: 'text' },
'response.include_body_max_bytes': { type: 'text' },
'check.request.method': { type: 'text' },
'check.request.headers': { type: 'yaml' },
'check.request.body': { type: 'yaml' },
@ -56,6 +58,7 @@ export const getTestBrowserSyntheticsPolicy = ({
'check.response.headers': { type: 'yaml' },
'check.response.body.positive': { type: 'yaml' },
'check.response.body.negative': { type: 'yaml' },
'check.response.json': { type: 'yaml' },
'ssl.certificate_authorities': { type: 'yaml' },
'ssl.certificate': { type: 'yaml' },
'ssl.key': { type: 'yaml' },
@ -69,6 +72,9 @@ export const getTestBrowserSyntheticsPolicy = ({
origin: { type: 'text' },
'monitor.project.id': { type: 'text' },
'monitor.project.name': { type: 'text' },
ipv4: { type: 'bool', value: true },
ipv6: { type: 'bool', value: true },
mode: { type: 'text' },
},
id: 'synthetics/http-http-abf904a4-cb9a-4b29-8c11-4d183cca289b-fe621d20-7b01-11ed-803f-475d82e1f9ca-default',
},
@ -109,6 +115,9 @@ export const getTestBrowserSyntheticsPolicy = ({
origin: { type: 'text' },
'monitor.project.id': { type: 'text' },
'monitor.project.name': { type: 'text' },
ipv4: { type: 'bool', value: true },
ipv6: { type: 'bool', value: true },
mode: { type: 'text' },
},
id: 'synthetics/tcp-tcp-abf904a4-cb9a-4b29-8c11-4d183cca289b-fe621d20-7b01-11ed-803f-475d82e1f9ca-default',
},
@ -140,6 +149,9 @@ export const getTestBrowserSyntheticsPolicy = ({
origin: { type: 'text' },
'monitor.project.id': { type: 'text' },
'monitor.project.name': { type: 'text' },
ipv4: { type: 'bool', value: true },
ipv6: { type: 'bool', value: true },
mode: { type: 'text' },
},
id: 'synthetics/icmp-icmp-abf904a4-cb9a-4b29-8c11-4d183cca289b-fe621d20-7b01-11ed-803f-475d82e1f9ca-default',
},
@ -249,10 +261,7 @@ export const getTestBrowserSyntheticsPolicy = ({
},
id: 'synthetics/browser-browser.network-abf904a4-cb9a-4b29-8c11-4d183cca289b-fe621d20-7b01-11ed-803f-475d82e1f9ca-default',
compiled_stream: {
processors: [
{ add_observer_metadata: { geo: { name: 'Fleet managed' } } },
{ add_fields: { target: '', fields: { 'monitor.fleet_managed': true } } },
],
processors: [{ add_fields: { target: '', fields: { 'monitor.fleet_managed': true } } }],
},
},
{
@ -264,10 +273,7 @@ export const getTestBrowserSyntheticsPolicy = ({
},
id: 'synthetics/browser-browser.screenshot-abf904a4-cb9a-4b29-8c11-4d183cca289b-fe621d20-7b01-11ed-803f-475d82e1f9ca-default',
compiled_stream: {
processors: [
{ add_observer_metadata: { geo: { name: 'Fleet managed' } } },
{ add_fields: { target: '', fields: { 'monitor.fleet_managed': true } } },
],
processors: [{ add_fields: { target: '', fields: { 'monitor.fleet_managed': true } } }],
},
},
],

View file

@ -21,7 +21,7 @@ export const getTestSyntheticsPolicy = (
version: 'WzE2MjYsMV0=',
name: 'test-monitor-name-Test private location 0-default',
namespace: namespace || 'testnamespace',
package: { name: 'synthetics', title: 'Elastic Synthetics', version: '0.11.4' },
package: { name: 'synthetics', title: 'Elastic Synthetics', version: '0.12.0' },
enabled: true,
policy_id: '5347cd10-0368-11ed-8df7-a7424c6f5167',
inputs: [
@ -55,11 +55,13 @@ export const getTestSyntheticsPolicy = (
timeout: { value: '3ms', type: 'text' },
max_redirects: { value: '3', type: 'integer' },
proxy_url: { value: proxyUrl ?? 'http://proxy.com', type: 'text' },
proxy_headers: { value: null, type: 'yaml' },
tags: { value: '["tag1","tag2"]', type: 'yaml' },
username: { value: 'test-username', type: 'text' },
password: { value: 'test', type: 'password' },
'response.include_headers': { value: true, type: 'bool' },
'response.include_body': { value: 'never', type: 'text' },
'response.include_body_max_bytes': { value: '1024', type: 'text' },
'check.request.method': { value: '', type: 'text' },
'check.request.headers': {
value: '{"sampleHeader":"sampleHeaderValue"}',
@ -70,6 +72,7 @@ export const getTestSyntheticsPolicy = (
'check.response.headers': { value: null, type: 'yaml' },
'check.response.body.positive': { value: null, type: 'yaml' },
'check.response.body.negative': { value: null, type: 'yaml' },
'check.response.json': { value: null, type: 'yaml' },
'ssl.certificate_authorities': {
value: isTLSEnabled ? '"t.string"' : null,
type: 'yaml',
@ -89,6 +92,9 @@ export const getTestSyntheticsPolicy = (
origin: { value: 'ui', type: 'text' },
'monitor.project.id': { type: 'text', value: null },
'monitor.project.name': { type: 'text', value: null },
ipv4: { type: 'bool', value: true },
ipv6: { type: 'bool', value: true },
mode: { type: 'text', value: 'any' },
},
id: 'synthetics/http-http-2bfd7da0-22ed-11ed-8c6b-09a2d21dfbc3-27337270-22ed-11ed-8c6b-09a2d21dfbc3-default',
compiled_stream: {
@ -116,6 +122,9 @@ export const getTestSyntheticsPolicy = (
'check.request.headers': { sampleHeader: 'sampleHeaderValue' },
'check.request.body': 'testValue',
'check.response.status': ['200', '201'],
ipv4: true,
ipv6: true,
mode: 'any',
...(isTLSEnabled
? {
'ssl.certificate': 't.string',
@ -179,6 +188,9 @@ export const getTestSyntheticsPolicy = (
origin: { type: 'text' },
'monitor.project.id': { type: 'text' },
'monitor.project.name': { type: 'text' },
ipv4: { type: 'bool', value: true },
ipv6: { type: 'bool', value: true },
mode: { type: 'text' },
},
id: 'synthetics/tcp-tcp-2bfd7da0-22ed-11ed-8c6b-09a2d21dfbc3-27337270-22ed-11ed-8c6b-09a2d21dfbc3-default',
},
@ -213,6 +225,9 @@ export const getTestSyntheticsPolicy = (
origin: { type: 'text' },
'monitor.project.id': { type: 'text' },
'monitor.project.name': { type: 'text' },
ipv4: { type: 'bool', value: true },
ipv6: { type: 'bool', value: true },
mode: { type: 'text' },
},
id: 'synthetics/icmp-icmp-2bfd7da0-22ed-11ed-8c6b-09a2d21dfbc3-27337270-22ed-11ed-8c6b-09a2d21dfbc3-default',
},
@ -299,10 +314,7 @@ export const getTestSyntheticsPolicy = (
},
id: 'synthetics/browser-browser.network-2bfd7da0-22ed-11ed-8c6b-09a2d21dfbc3-27337270-22ed-11ed-8c6b-09a2d21dfbc3-default',
compiled_stream: {
processors: [
{ add_observer_metadata: { geo: { name: 'Fleet managed' } } },
{ add_fields: { target: '', fields: { 'monitor.fleet_managed': true } } },
],
processors: [{ add_fields: { target: '', fields: { 'monitor.fleet_managed': true } } }],
},
},
{
@ -318,10 +330,7 @@ export const getTestSyntheticsPolicy = (
},
id: 'synthetics/browser-browser.screenshot-2bfd7da0-22ed-11ed-8c6b-09a2d21dfbc3-27337270-22ed-11ed-8c6b-09a2d21dfbc3-default',
compiled_stream: {
processors: [
{ add_observer_metadata: { geo: { name: 'Fleet managed' } } },
{ add_fields: { target: '', fields: { 'monitor.fleet_managed': true } } },
],
processors: [{ add_fields: { target: '', fields: { 'monitor.fleet_managed': true } } }],
},
},
],

View file

@ -34,7 +34,7 @@ export const getTestProjectSyntheticsPolicy = (
version: 'WzEzMDksMV0=',
name: `4b6abc6c-118b-4d93-a489-1135500d09f1-${projectId}-default-Test private location 0`,
namespace: 'default',
package: { name: 'synthetics', title: 'Elastic Synthetics', version: '0.11.4' },
package: { name: 'synthetics', title: 'Elastic Synthetics', version: '0.12.0' },
enabled: true,
policy_id: '46034710-0ba6-11ed-ba04-5f123b9faa8b',
inputs: [
@ -60,11 +60,13 @@ export const getTestProjectSyntheticsPolicy = (
timeout: { type: 'text' },
max_redirects: { type: 'integer' },
proxy_url: { type: 'text' },
proxy_headers: { type: 'yaml' },
tags: { type: 'yaml' },
username: { type: 'text' },
password: { type: 'password' },
'response.include_headers': { type: 'bool' },
'response.include_body': { type: 'text' },
'response.include_body_max_bytes': { type: 'text' },
'check.request.method': { type: 'text' },
'check.request.headers': { type: 'yaml' },
'check.request.body': { type: 'yaml' },
@ -72,6 +74,7 @@ export const getTestProjectSyntheticsPolicy = (
'check.response.headers': { type: 'yaml' },
'check.response.body.positive': { type: 'yaml' },
'check.response.body.negative': { type: 'yaml' },
'check.response.json': { type: 'yaml' },
'ssl.certificate_authorities': { type: 'yaml' },
'ssl.certificate': { type: 'yaml' },
'ssl.key': { type: 'yaml' },
@ -85,6 +88,9 @@ export const getTestProjectSyntheticsPolicy = (
origin: { type: 'text' },
'monitor.project.id': { type: 'text' },
'monitor.project.name': { type: 'text' },
ipv4: { type: 'bool', value: true },
ipv6: { type: 'bool', value: true },
mode: { type: 'text' },
},
id: `synthetics/http-http-4b6abc6c-118b-4d93-a489-1135500d09f1-${projectId}-default-d70a46e0-22ea-11ed-8c6b-09a2d21dfbc3`,
},
@ -128,6 +134,9 @@ export const getTestProjectSyntheticsPolicy = (
origin: { type: 'text' },
'monitor.project.id': { type: 'text' },
'monitor.project.name': { type: 'text' },
ipv4: { type: 'bool', value: true },
ipv6: { type: 'bool', value: true },
mode: { type: 'text' },
},
id: `synthetics/tcp-tcp-4b6abc6c-118b-4d93-a489-1135500d09f1-${projectId}-default-d70a46e0-22ea-11ed-8c6b-09a2d21dfbc3`,
},
@ -162,6 +171,9 @@ export const getTestProjectSyntheticsPolicy = (
origin: { type: 'text' },
'monitor.project.id': { type: 'text' },
'monitor.project.name': { type: 'text' },
ipv4: { type: 'bool', value: true },
ipv6: { type: 'bool', value: true },
mode: { type: 'text' },
},
id: `synthetics/icmp-icmp-4b6abc6c-118b-4d93-a489-1135500d09f1-${projectId}-default-d70a46e0-22ea-11ed-8c6b-09a2d21dfbc3`,
},
@ -287,10 +299,7 @@ export const getTestProjectSyntheticsPolicy = (
},
id: `synthetics/browser-browser.network-4b6abc6c-118b-4d93-a489-1135500d09f1-${projectId}-default-d70a46e0-22ea-11ed-8c6b-09a2d21dfbc3`,
compiled_stream: {
processors: [
{ add_observer_metadata: { geo: { name: 'Fleet managed' } } },
{ add_fields: { target: '', fields: { 'monitor.fleet_managed': true } } },
],
processors: [{ add_fields: { target: '', fields: { 'monitor.fleet_managed': true } } }],
},
},
{
@ -306,10 +315,7 @@ export const getTestProjectSyntheticsPolicy = (
},
id: `synthetics/browser-browser.screenshot-4b6abc6c-118b-4d93-a489-1135500d09f1-${projectId}-default-d70a46e0-22ea-11ed-8c6b-09a2d21dfbc3`,
compiled_stream: {
processors: [
{ add_observer_metadata: { geo: { name: 'Fleet managed' } } },
{ add_fields: { target: '', fields: { 'monitor.fleet_managed': true } } },
],
processors: [{ add_fields: { target: '', fields: { 'monitor.fleet_managed': true } } }],
},
},
],

View file

@ -44,7 +44,7 @@ export default function ({ getService }: FtrProviderContext) {
before(async () => {
await supertestAPI.post('/api/fleet/setup').set('kbn-xsrf', 'true').send().expect(200);
await supertestAPI
.post('/api/fleet/epm/packages/synthetics/0.11.4')
.post('/api/fleet/epm/packages/synthetics/0.12.0')
.set('kbn-xsrf', 'true')
.send({ force: true })
.expect(200);

View file

@ -25,9 +25,12 @@
"urls": "https://nextjs-test-synthetics.vercel.app/api/users",
"url.port": null,
"proxy_url": "http://proxy.com",
"proxy_headers": {},
"check.response.body.negative": [],
"check.response.body.positive": [],
"check.response.json": [],
"response.include_body": "never",
"response.include_body_max_bytes": "1024",
"check.request.headers": {
"sampleHeader": "sampleHeaderValue"
},
@ -81,5 +84,8 @@
"form_monitor_type": "http",
"journey_id": "",
"id": "",
"hash": ""
"hash": "",
"mode": "any",
"ipv4": true,
"ipv6": true
}

View file

@ -26,5 +26,8 @@
"origin": "ui",
"form_monitor_type": "icmp",
"id": "",
"hash": ""
"hash": "",
"mode": "any",
"ipv4": true,
"ipv6": true
}

View file

@ -56,7 +56,8 @@
}
},
"response": {
"include_body": "always"
"include_body": "always",
"include_body_max_bytes": 900
},
"tags": "tag2,tag2",
"response.include_headers": false,
@ -69,7 +70,8 @@
"Saved",
"saved"
]
}
},
"json": [{"description":"check status","expression":"foo.bar == \"myValue\""}]
},
"hash": "ekrjelkjrelkjre",
"ssl.verification_mode": "strict"

View file

@ -34,5 +34,8 @@
"origin": "ui",
"form_monitor_type": "tcp",
"id": "",
"hash": ""
"hash": "",
"mode": "any",
"ipv4": true,
"ipv6": true
}