diff --git a/docs/api/synthetics/params/add-param.asciidoc b/docs/api/synthetics/params/add-param.asciidoc new file mode 100644 index 000000000000000..fa21b5a33738ee4 --- /dev/null +++ b/docs/api/synthetics/params/add-param.asciidoc @@ -0,0 +1,123 @@ +[[add-parameters-api]] +== Add Parameters API +++++ +Add Parameters +++++ + +Adds one or more parameters to the synthetics app. + +=== {api-request-title} + +`POST :/api/synthetics/params` + +`POST :/s//api/synthetics/params` + +=== {api-prereq-title} + +You must have `all` privileges for the *Synthetics* feature in the *{observability}* section of the +<>. + + +[[parameters-add-request-body]] +==== Request body + +The request body can contain either a single parameter object or an array of parameter objects. The parameter object schema includes the following attributes: + +`key`:: +(Required, string) The key of the parameter. + +`value`:: +(Required, string) The value associated with the parameter. + +`description`:: +(Optional, string) A description of the parameter. + +`tags`:: +(Optional, array of strings) An array of tags to categorize the parameter. + +`share_across_spaces`:: +(Optional, boolean) Whether the parameter should be shared across spaces. + +When adding a single parameter, provide a single object. When adding multiple parameters, provide an array of parameter objects. + +[[parameters-add-example]] +==== Example + +Here are examples of POST requests to add parameters, either as a single parameter or as an array of parameters: + +To add a single parameter: + +[source,sh] +-------------------------------------------------- +POST /api/synthetics/params +{ + "key": "your-key-name", + "value": "your-parameter-value", + "description": "Param to use in browser monitor", + "tags": ["authentication", "security"], + "share_across_spaces": true +} +-------------------------------------------------- + +To add multiple parameters: + +[source,sh] +-------------------------------------------------- +POST /api/synthetics/params +[ + { + "key": "param1", + "value": "value1" + }, + { + "key": "param2", + "value": "value2" + } +] +-------------------------------------------------- + +The API returns a response based on the request. If you added a single parameter, it will return a single parameter object. If you added multiple parameters, it will return an array of parameter objects. + +[[parameters-add-response-example]] +==== Response Example + +The API response includes the created parameter(s) as JSON objects, where each parameter object has the following attributes: + +- `id` (string): The unique identifier of the parameter. +- `key` (string): The key of the parameter. +- `value` (string): The value associated with the parameter. +- `description` (string, optional): The description of the parameter. +- `tags` (array of strings, optional): An array of tags associated with the parameter. +- `share_across_spaces` (boolean, optional): Indicates whether the parameter is shared across spaces. + +Here's an example response for a single added parameter: + +[source,json] +-------------------------------------------------- +{ + "id": "unique-parameter-id", + "key": "your-key-name", + "value": "your-param-value", + "description": "Param to use in browser monitor", + "tags": ["authentication", "security"], + "share_across_spaces": true +} +-------------------------------------------------- + +And here's an example response for adding multiple parameters: + +[source,json] +-------------------------------------------------- +[ + { + "id": "param1-id", + "key": "param1", + "value": "value1" + }, + { + "id": "param2-id", + "key": "param2", + "value": "value2" + } +] +-------------------------------------------------- \ No newline at end of file diff --git a/docs/api/synthetics/params/delete-param.asciidoc b/docs/api/synthetics/params/delete-param.asciidoc new file mode 100644 index 000000000000000..4c7d7911ec180af --- /dev/null +++ b/docs/api/synthetics/params/delete-param.asciidoc @@ -0,0 +1,67 @@ +[[delete-parameters-api]] +== Delete Parameters API +++++ +Delete Parameters +++++ + +Deletes one or more parameters from the Synthetics app. + +=== {api-request-title} + +`DELETE :/api/synthetics/params` + +`DELETE :/s//api/synthetics/params` + +=== {api-prereq-title} + +You must have `all` privileges for the *Synthetics* feature in the *{observability}* section of the +<>. + +You must have `all` privileges for the *Synthetics* feature in the *{observability}* section of the +<>. + +[[parameters-delete-request-body]] +==== Request Body + +The request body should contain an array of parameter IDs that you want to delete. + +`ids`:: +(Required, array of strings) An array of parameter IDs to delete. + + +Here is an example of a DELETE request to delete a list of parameters by ID: + +[source,sh] +-------------------------------------------------- +DELETE /api/synthetics/params +{ + "ids": [ + "param1-id", + "param2-id" + ] +} +-------------------------------------------------- + +[[parameters-delete-response-example]] +==== Response Example + +The API response includes information about the deleted parameters, where each entry in the response array contains the following attributes: + +- `id` (string): The unique identifier of the deleted parameter. +- `deleted` (boolean): Indicates whether the parameter was successfully deleted (`true` if deleted, `false` if not). + +Here's an example response for deleting multiple parameters: + +[source,sh] +-------------------------------------------------- +[ + { + "id": "param1-id", + "deleted": true + }, + { + "id": "param2-id", + "deleted": true + } +] +-------------------------------------------------- \ No newline at end of file diff --git a/docs/api/synthetics/params/edit-param.asciidoc b/docs/api/synthetics/params/edit-param.asciidoc new file mode 100644 index 000000000000000..e615dd0c0bd1f9a --- /dev/null +++ b/docs/api/synthetics/params/edit-param.asciidoc @@ -0,0 +1,70 @@ +[[edit-parameter-by-id-api]] +== Edit Parameter by ID API +++++ +Edit Parameter +++++ + +Edits a parameter with the specified ID. + +=== {api-request-title} + +`PUT :/api/synthetics/params` + +`PUT :/s//api/synthetics/params` + +=== {api-prereq-title} + +You must have `all` privileges for the *Synthetics* feature in the *{observability}* section of the +<>. + +[[parameter-edit-path-params]] +==== Path Parameters + +`id`:: +(Required, string) The unique identifier of the parameter to be edited. + +[[parameter-edit-request-body]] +==== Request body + +The request body should contain the following attributes: + +`key`:: +(Required, string) The key of the parameter. + +`value`:: +(Required, string) The updated value associated with the parameter. + +`description`:: +(Optional, string) The updated description of the parameter. + +`tags`:: +(Optional, array of strings) An array of updated tags to categorize the parameter. + +[[parameter-edit-example]] +==== Example + +Here is an example of a PUT request to edit a parameter by its ID: + +[source,sh] +-------------------------------------------------- +PUT /api/synthetics/params/param_id1 +{ + "key": "updated_param_key", + "value": "updated-param-value", + "description": "Updated Param to be used in browser monitor", + "tags": ["authentication", "security", "updated"] +} +-------------------------------------------------- + +The API returns the updated parameter as follows: + +[source,json] +-------------------------------------------------- +{ + "id": "param_id1", + "key": "updated_param_key", + "value": "updated-param-value", + "description": "Updated Param to be used in browser monitor", + "tags": ["authentication", "security", "updated"] +} +-------------------------------------------------- diff --git a/docs/api/synthetics/params/get-params.asciidoc b/docs/api/synthetics/params/get-params.asciidoc new file mode 100644 index 000000000000000..76356b28f76190a --- /dev/null +++ b/docs/api/synthetics/params/get-params.asciidoc @@ -0,0 +1,128 @@ +[[get-parameters-api]] +== Get Parameters API +++++ +Get Parameters +++++ + +Retrieves parameters based on the provided criteria. + +=== {api-request-title} + +`GET :/api/synthetics/params/{id?}` + +`GET :/s//api/synthetics/params/{id?}` + +=== {api-prereq-title} + +You must have `read` privileges for the *Synthetics* feature in the *{observability}* section of the +<>. + +[[parameters-get-query-params]] +==== Query Parameters + +`id`:: +(Optional, string) The unique identifier of the parameter. If provided, this API will retrieve a specific parameter by its ID. If not provided, it will retrieve a list of all parameters. + +[[parameters-get-response-example]] +==== Response Example + +The API response includes parameter(s) as JSON objects, where each parameter object has the following attributes: + +- `id` (string): The unique identifier of the parameter. +- `key` (string): The key of the parameter. + +If the user has read-only permissions to the Synthetics app, the following additional attributes will be included: + +- `description` (string, optional): The description of the parameter. +- `tags` (array of strings, optional): An array of tags associated with the parameter. +- `namespaces` (array of strings): Namespaces associated with the parameter. + +If the user has write permissions, the following additional attribute will be included: + +- `value` (string): The value associated with the parameter. + + +Here's an example request for retrieving a single parameter by its ID: + +[source,sh] +-------------------------------------------------- +GET /api/synthetics/params/unique-parameter-id +-------------------------------------------------- + + +Here's an example response for retrieving a single parameter by its ID: + +For users with read-only permissions: + +[source,json] +-------------------------------------------------- +{ + "id": "unique-parameter-id", + "key": "your-api-key", + "description": "Param to use in browser monitor", + "tags": ["authentication", "security"], + "namespaces": ["namespace1", "namespace2"] +} +-------------------------------------------------- + +For users with write permissions: + +[source,json] +-------------------------------------------------- +{ + "id": "unique-parameter-id", + "key": "your-param-key", + "description": "Param to use in browser monitor", + "tags": ["authentication", "security"], + "namespaces": ["namespace1", "namespace2"], + "value": "your-param-value" +} +-------------------------------------------------- + +And here's an example response for retrieving a list of parameters: + +For users with read-only permissions: + +[source,json] +-------------------------------------------------- +[ + { + "id": "param1-id", + "key": "param1", + "description": "Description for param1", + "tags": ["tag1", "tag2"], + "namespaces": ["namespace1"] + }, + { + "id": "param2-id", + "key": "param2", + "description": "Description for param2", + "tags": ["tag3"], + "namespaces": ["namespace2"] + } +] +-------------------------------------------------- + +For users with write permissions: + +[source,json] +-------------------------------------------------- +[ + { + "id": "param1-id", + "key": "param1", + "description": "Description for param1", + "tags": ["tag1", "tag2"], + "namespaces": ["namespace1"], + "value": "value1" + }, + { + "id": "param2-id", + "key": "param2", + "description": "Description for param2", + "tags": ["tag3"], + "namespaces": ["namespace2"], + "value": "value2" + } +] +-------------------------------------------------- \ No newline at end of file diff --git a/docs/api/synthetics/synthetics-api.asciidoc b/docs/api/synthetics/synthetics-api.asciidoc new file mode 100644 index 000000000000000..88a757670736a72 --- /dev/null +++ b/docs/api/synthetics/synthetics-api.asciidoc @@ -0,0 +1,18 @@ +[[synthetics-apis]] +== Synthetics APIs + +The following APIs are available for Synthetics. + +* <> to get a parameter(s). + +* <> to create a parameter. + +* <> to edit a parameter. + +* <> to delete a parameter. + + +include::params/add-param.asciidoc[leveloffset=+1] +include::params/get-params.asciidoc[leveloffset=+1] +include::params/edit-param.asciidoc[leveloffset=+1] +include::params/delete-param.asciidoc[leveloffset=+1] diff --git a/docs/user/api.asciidoc b/docs/user/api.asciidoc index 4358c448f3634aa..7731a65baaac7d9 100644 --- a/docs/user/api.asciidoc +++ b/docs/user/api.asciidoc @@ -109,4 +109,5 @@ include::{kib-repo-dir}/api/osquery-manager.asciidoc[] include::{kib-repo-dir}/api/short-urls.asciidoc[] include::{kib-repo-dir}/api/task-manager/health.asciidoc[] include::{kib-repo-dir}/api/upgrade-assistant.asciidoc[] +include::{kib-repo-dir}/api/synthetics/synthetics-api.asciidoc[] include::{kib-repo-dir}/api/uptime-api.asciidoc[] diff --git a/x-pack/plugins/synthetics/common/constants/synthetics/rest_api.ts b/x-pack/plugins/synthetics/common/constants/synthetics/rest_api.ts index 40ae2656e2b26c7..6f7a1855ac4025c 100644 --- a/x-pack/plugins/synthetics/common/constants/synthetics/rest_api.ts +++ b/x-pack/plugins/synthetics/common/constants/synthetics/rest_api.ts @@ -6,6 +6,9 @@ */ export enum SYNTHETICS_API_URLS { + // public apis + PARAMS = `/api/synthetics/params`, + // Service end points INDEX_TEMPLATES = '/internal/synthetics/service/index_templates', SERVICE_LOCATIONS = '/internal/uptime/service/locations', @@ -24,7 +27,6 @@ export enum SYNTHETICS_API_URLS { PING_STATUSES = '/internal/synthetics/ping_statuses', OVERVIEW_STATUS = `/internal/synthetics/overview_status`, INDEX_SIZE = `/internal/synthetics/index_size`, - PARAMS = `/internal/synthetics/params`, AGENT_POLICIES = `/internal/synthetics/agent_policies`, PRIVATE_LOCATIONS = `/internal/synthetics/private_locations`, PRIVATE_LOCATIONS_MONITORS = `/internal/synthetics/private_locations/monitors`, diff --git a/x-pack/plugins/synthetics/common/constants/ui.ts b/x-pack/plugins/synthetics/common/constants/ui.ts index 64259a676189c65..8f3ee8f3b903b26 100644 --- a/x-pack/plugins/synthetics/common/constants/ui.ts +++ b/x-pack/plugins/synthetics/common/constants/ui.ts @@ -73,3 +73,5 @@ export const SYNTHETICS_INDEX_PATTERN = 'synthetics-*'; export const LICENSE_NOT_ACTIVE_ERROR = 'License not active'; export const LICENSE_MISSING_ERROR = 'Missing license information'; export const LICENSE_NOT_SUPPORTED_ERROR = 'License not supported'; + +export const INITIAL_REST_VERSION = '2023-10-31'; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/global_params/add_param_flyout.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/global_params/add_param_flyout.tsx index c79e5aec2177a1b..3fd17335d2ea5f9 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/global_params/add_param_flyout.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/global_params/add_param_flyout.tsx @@ -108,8 +108,9 @@ export const AddParamFlyout = ({ useEffect(() => { if (isEditingItem) { + const { id: _id, ...dataToEdit } = isEditingItem; setIsFlyoutVisible(true); - form.reset(isEditingItem); + form.reset(dataToEdit); } // no need to add form value, it keeps changing on reset // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/global_params/delete_param.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/global_params/delete_param.tsx index aa89829380044c7..942afb91cfe48cb 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/global_params/delete_param.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/global_params/delete_param.tsx @@ -55,7 +55,7 @@ export const DeleteParam = ({

{' '} {i18n.translate('xpack.synthetics.paramManagement.paramDeleteFailuresMessage.name', { - defaultMessage: 'Param {name} deleted successfully.', + defaultMessage: 'Param {name} failed to delete.', values: { name }, })}

diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/state/global_params/api.ts b/x-pack/plugins/synthetics/public/apps/synthetics/state/global_params/api.ts index 528921f1d5bf4cc..1499734639a33e2 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/state/global_params/api.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/state/global_params/api.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { SYNTHETICS_API_URLS } from '../../../../../common/constants'; +import { INITIAL_REST_VERSION, SYNTHETICS_API_URLS } from '../../../../../common/constants'; import { DeleteParamsResponse, SyntheticsParamRequest, @@ -18,7 +18,7 @@ import { apiService } from '../../../../utils/api_service/api_service'; export const getGlobalParams = async (): Promise => { return apiService.get( SYNTHETICS_API_URLS.PARAMS, - undefined, + { version: INITIAL_REST_VERSION }, SyntheticsParamsReadonlyCodec ); }; @@ -26,7 +26,9 @@ export const getGlobalParams = async (): Promise => { export const addGlobalParam = async ( paramRequest: SyntheticsParamRequest ): Promise => - apiService.post(SYNTHETICS_API_URLS.PARAMS, paramRequest, SyntheticsParamsCodec); + apiService.post(SYNTHETICS_API_URLS.PARAMS, paramRequest, SyntheticsParamsCodec, { + version: INITIAL_REST_VERSION, + }); export const editGlobalParam = async ({ paramRequest, @@ -36,15 +38,15 @@ export const editGlobalParam = async ({ paramRequest: SyntheticsParamRequest; }): Promise => apiService.put( - SYNTHETICS_API_URLS.PARAMS, + SYNTHETICS_API_URLS.PARAMS + `/${id}`, + paramRequest, + SyntheticsParamsCodec, { - id, - ...paramRequest, - }, - SyntheticsParamsCodec + version: INITIAL_REST_VERSION, + } ); export const deleteGlobalParams = async (ids: string[]): Promise => - apiService.delete(SYNTHETICS_API_URLS.PARAMS, { - ids: JSON.stringify(ids), + apiService.delete(SYNTHETICS_API_URLS.PARAMS, undefined, { + ids, }); diff --git a/x-pack/plugins/synthetics/public/utils/api_service/api_service.ts b/x-pack/plugins/synthetics/public/utils/api_service/api_service.ts index f1eb2607dd25b98..e077e37d0983557 100644 --- a/x-pack/plugins/synthetics/public/utils/api_service/api_service.ts +++ b/x-pack/plugins/synthetics/public/utils/api_service/api_service.ts @@ -101,8 +101,15 @@ class ApiService { return this.parseResponse(response, apiUrl, decodeType); } - public async delete(apiUrl: string, params?: HttpFetchQuery) { - const response = await this._http!.delete({ path: apiUrl, query: params }); + public async delete(apiUrl: string, params: Params = {}, data?: any) { + const { version, ...queryParams } = params; + + const response = await this._http!.delete({ + path: apiUrl, + query: queryParams, + body: JSON.stringify(data), + version, + }); if (response instanceof Error) { throw response; diff --git a/x-pack/plugins/synthetics/server/routes/index.ts b/x-pack/plugins/synthetics/server/routes/index.ts index accad22a12817cb..1c02627eddcd77c 100644 --- a/x-pack/plugins/synthetics/server/routes/index.ts +++ b/x-pack/plugins/synthetics/server/routes/index.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { getSyntheticsParamsRoute } from './settings/params/params'; +import { editSyntheticsParamsRoute } from './settings/params/edit_param'; import { getConnectorTypesRoute } from './default_alerts/get_connector_types'; import { getActionConnectorsRoute } from './default_alerts/get_action_connectors'; import { SyntheticsRestApiRouteFactory } from './types'; @@ -18,8 +20,6 @@ import { createLastSuccessfulCheckRoute } from './pings/last_successful_check'; import { createJourneyFailedStepsRoute, createJourneyRoute } from './pings/journeys'; import { updateDefaultAlertingRoute } from './default_alerts/update_default_alert'; import { syncParamsSyntheticsParamsRoute } from './settings/sync_global_params'; -import { editSyntheticsParamsRoute } from './settings/edit_param'; -import { getSyntheticsParamsRoute } from './settings/params'; import { getIndexSizesRoute } from './settings/settings'; import { getAPIKeySyntheticsRoute } from './monitor_cruds/get_api_key'; import { getServiceLocationsRoute } from './synthetics_service/get_service_locations'; @@ -44,8 +44,6 @@ import { addSyntheticsProjectMonitorRoute } from './monitor_cruds/add_monitor_pr import { syntheticsGetPingsRoute, syntheticsGetPingStatusesRoute } from './pings'; import { createGetCurrentStatusRoute } from './overview_status/overview_status'; import { getHasIntegrationMonitorsRoute } from './fleet/get_has_integration_monitors'; -import { addSyntheticsParamsRoute } from './settings/add_param'; -import { deleteSyntheticsParamsRoute } from './settings/delete_param'; import { enableDefaultAlertingRoute } from './default_alerts/enable_default_alert'; import { getDefaultAlertingRoute } from './default_alerts/get_default_alert'; import { createNetworkEventsRoute } from './network_events'; @@ -55,6 +53,8 @@ import { getPrivateLocationsRoute } from './settings/private_locations/get_priva import { getSyntheticsFilters } from './filters/filters'; import { getAllSyntheticsMonitorRoute } from './monitor_cruds/get_monitors_list'; import { getLocationMonitors } from './settings/private_locations/get_location_monitors'; +import { addSyntheticsParamsRoute } from './settings/params/add_param'; +import { deleteSyntheticsParamsRoute } from './settings/params/delete_param'; export const syntheticsAppRestApiRoutes: SyntheticsRestApiRouteFactory[] = [ addSyntheticsMonitorRoute, @@ -79,10 +79,6 @@ export const syntheticsAppRestApiRoutes: SyntheticsRestApiRouteFactory[] = [ getHasIntegrationMonitorsRoute, createGetCurrentStatusRoute, getIndexSizesRoute, - getSyntheticsParamsRoute, - editSyntheticsParamsRoute, - addSyntheticsParamsRoute, - deleteSyntheticsParamsRoute, syncParamsSyntheticsParamsRoute, enableDefaultAlertingRoute, getDefaultAlertingRoute, @@ -105,3 +101,10 @@ export const syntheticsAppRestApiRoutes: SyntheticsRestApiRouteFactory[] = [ getActionConnectorsRoute, getConnectorTypesRoute, ]; + +export const syntheticsAppPublicRestApiRoutes: SyntheticsRestApiRouteFactory[] = [ + getSyntheticsParamsRoute, + editSyntheticsParamsRoute, + addSyntheticsParamsRoute, + deleteSyntheticsParamsRoute, +]; diff --git a/x-pack/plugins/synthetics/server/routes/settings/add_param.ts b/x-pack/plugins/synthetics/server/routes/settings/add_param.ts deleted file mode 100644 index 875e4da8694e13d..000000000000000 --- a/x-pack/plugins/synthetics/server/routes/settings/add_param.ts +++ /dev/null @@ -1,79 +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 { schema } from '@kbn/config-schema'; -import { ALL_SPACES_ID } from '@kbn/security-plugin/common/constants'; -import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; -import { IKibanaResponse } from '@kbn/core/server'; -import { SyntheticsRestApiRouteFactory } from '../types'; -import { - SyntheticsParamRequest, - SyntheticsParams, - SyntheticsParamSOAttributes, -} from '../../../common/runtime_types'; -import { syntheticsParamType } from '../../../common/types/saved_objects'; -import { SYNTHETICS_API_URLS } from '../../../common/constants'; - -export const addSyntheticsParamsRoute: SyntheticsRestApiRouteFactory = () => ({ - method: 'POST', - path: SYNTHETICS_API_URLS.PARAMS, - validate: { - body: schema.object({ - key: schema.string(), - value: schema.string(), - description: schema.maybe(schema.string()), - tags: schema.maybe(schema.arrayOf(schema.string())), - share_across_spaces: schema.maybe(schema.boolean()), - }), - }, - writeAccess: true, - handler: async ({ - request, - response, - server, - savedObjectsClient, - }): Promise> => { - try { - const { id: spaceId } = (await server.spaces?.spacesService.getActiveSpace(request)) ?? { - id: DEFAULT_SPACE_ID, - }; - const { share_across_spaces: shareAcrossSpaces, ...data } = - request.body as SyntheticsParamRequest; - - const { - attributes: { key, tags, description }, - id, - namespaces, - } = await savedObjectsClient.create>( - syntheticsParamType, - data, - { - initialNamespaces: shareAcrossSpaces ? [ALL_SPACES_ID] : [spaceId], - } - ); - return response.ok({ - body: { - id, - description, - key, - namespaces, - tags, - value: data.value, - }, - }); - } catch (error) { - if (error.output?.statusCode === 404) { - const spaceId = server.spaces?.spacesService.getSpaceId(request) ?? DEFAULT_SPACE_ID; - return response.notFound({ - body: { message: `Kibana space '${spaceId}' does not exist` }, - }); - } - - throw error; - } - }, -}); diff --git a/x-pack/plugins/synthetics/server/routes/settings/delete_param.ts b/x-pack/plugins/synthetics/server/routes/settings/delete_param.ts deleted file mode 100644 index dc529902b730f66..000000000000000 --- a/x-pack/plugins/synthetics/server/routes/settings/delete_param.ts +++ /dev/null @@ -1,40 +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 { IKibanaResponse } from '@kbn/core/server'; -import { schema } from '@kbn/config-schema'; -import { SyntheticsRestApiRouteFactory } from '../types'; -import { syntheticsParamType } from '../../../common/types/saved_objects'; -import { SYNTHETICS_API_URLS } from '../../../common/constants'; -import { DeleteParamsResponse } from '../../../common/runtime_types'; - -export const deleteSyntheticsParamsRoute: SyntheticsRestApiRouteFactory = () => ({ - method: 'DELETE', - path: SYNTHETICS_API_URLS.PARAMS, - validate: { - query: schema.object({ - ids: schema.string(), - }), - }, - writeAccess: true, - handler: async ({ - savedObjectsClient, - request, - response, - }): Promise> => { - const { ids } = request.query as { ids: string }; - const parsedIds = JSON.parse(ids) as string[]; - - const result = await savedObjectsClient.bulkDelete( - parsedIds.map((id) => ({ type: syntheticsParamType, id })), - { force: true } - ); - return response.ok({ - body: result.statuses.map(({ id, success }) => ({ id, deleted: success })), - }); - }, -}); diff --git a/x-pack/plugins/synthetics/server/routes/settings/edit_param.ts b/x-pack/plugins/synthetics/server/routes/settings/edit_param.ts deleted file mode 100644 index b235d0b323c8b65..000000000000000 --- a/x-pack/plugins/synthetics/server/routes/settings/edit_param.ts +++ /dev/null @@ -1,69 +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 { schema } from '@kbn/config-schema'; -import { IKibanaResponse, SavedObject } from '@kbn/core/server'; -import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; -import { SyntheticsRestApiRouteFactory } from '../types'; -import { SyntheticsParamRequest, SyntheticsParams } from '../../../common/runtime_types'; -import { syntheticsParamType } from '../../../common/types/saved_objects'; -import { SYNTHETICS_API_URLS } from '../../../common/constants'; - -export const editSyntheticsParamsRoute: SyntheticsRestApiRouteFactory = () => ({ - method: 'PUT', - path: SYNTHETICS_API_URLS.PARAMS, - validate: { - body: schema.object({ - id: schema.string(), - key: schema.string(), - value: schema.string(), - description: schema.maybe(schema.string()), - tags: schema.maybe(schema.arrayOf(schema.string())), - share_across_spaces: schema.maybe(schema.boolean()), - }), - }, - writeAccess: true, - handler: async ({ - savedObjectsClient, - request, - response, - server, - }): Promise> => { - try { - const { id: _spaceId } = (await server.spaces?.spacesService.getActiveSpace(request)) ?? { - id: DEFAULT_SPACE_ID, - }; - const { - share_across_spaces: shareAcrossSpaces, - id, - ...data - } = request.body as SyntheticsParamRequest & { - id: string; - }; - - const { value } = data; - const { - id: responseId, - attributes: { key, tags, description }, - namespaces, - } = (await savedObjectsClient.update( - syntheticsParamType, - id, - data - )) as SavedObject; - - return response.ok({ body: { id: responseId, key, tags, description, namespaces, value } }); - } catch (error) { - if (error.output?.statusCode === 404) { - const spaceId = server.spaces?.spacesService.getSpaceId(request) ?? DEFAULT_SPACE_ID; - return response.notFound({ body: { message: `Kibana space '${spaceId}' does not exist` } }); - } - - throw error; - } - }, -}); diff --git a/x-pack/plugins/synthetics/server/routes/settings/params.ts b/x-pack/plugins/synthetics/server/routes/settings/params.ts deleted file mode 100644 index 789761c529e846b..000000000000000 --- a/x-pack/plugins/synthetics/server/routes/settings/params.ts +++ /dev/null @@ -1,74 +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 { IKibanaResponse } from '@kbn/core/server'; -import { SavedObjectsFindResult } from '@kbn/core-saved-objects-api-server'; -import { SyntheticsRestApiRouteFactory } from '../types'; -import { syntheticsParamType } from '../../../common/types/saved_objects'; -import { SYNTHETICS_API_URLS } from '../../../common/constants'; -import { SyntheticsParams, SyntheticsParamsReadonly } from '../../../common/runtime_types'; - -type SyntheticsParamsResponse = - | IKibanaResponse - | IKibanaResponse; -export const getSyntheticsParamsRoute: SyntheticsRestApiRouteFactory< - SyntheticsParamsResponse -> = () => ({ - method: 'GET', - path: SYNTHETICS_API_URLS.PARAMS, - validate: {}, - handler: async ({ savedObjectsClient, request, response, server, spaceId }) => { - try { - const encryptedSavedObjectsClient = server.encryptedSavedObjects.getClient(); - - const canSave = - (await server.coreStart?.capabilities.resolveCapabilities(request)).uptime.save ?? false; - - if (canSave) { - const finder = - await encryptedSavedObjectsClient.createPointInTimeFinderDecryptedAsInternalUser( - { - type: syntheticsParamType, - perPage: 1000, - namespaces: [spaceId], - } - ); - - const hits: Array> = []; - for await (const result of finder.find()) { - hits.push(...result.saved_objects); - } - - return response.ok({ - body: hits.map(({ id, attributes, namespaces }) => ({ - ...attributes, - id, - namespaces, - })), - }); - } else { - const data = await savedObjectsClient.find({ - type: syntheticsParamType, - perPage: 10000, - }); - return response.ok({ - body: data.saved_objects.map(({ id, attributes, namespaces }) => ({ - ...attributes, - namespaces, - id, - })), - }); - } - } catch (error) { - if (error.output?.statusCode === 404) { - return response.notFound({ body: { message: `Kibana space '${spaceId}' does not exist` } }); - } - - throw error; - } - }, -}); diff --git a/x-pack/plugins/synthetics/server/routes/settings/params/add_param.ts b/x-pack/plugins/synthetics/server/routes/settings/params/add_param.ts new file mode 100644 index 000000000000000..9e26666ed30d900 --- /dev/null +++ b/x-pack/plugins/synthetics/server/routes/settings/params/add_param.ts @@ -0,0 +1,113 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { ALL_SPACES_ID } from '@kbn/security-plugin/common/constants'; +import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; +import { SavedObject, SavedObjectsBulkCreateObject } from '@kbn/core-saved-objects-api-server'; +import { SyntheticsRestApiRouteFactory } from '../../types'; +import { + SyntheticsParamRequest, + SyntheticsParams, + SyntheticsParamSOAttributes, +} from '../../../../common/runtime_types'; +import { syntheticsParamType } from '../../../../common/types/saved_objects'; +import { SYNTHETICS_API_URLS } from '../../../../common/constants'; + +const ParamsObjectSchema = schema.object({ + key: schema.string(), + value: schema.string(), + description: schema.maybe(schema.string()), + tags: schema.maybe(schema.arrayOf(schema.string())), + share_across_spaces: schema.maybe(schema.boolean()), +}); + +export const addSyntheticsParamsRoute: SyntheticsRestApiRouteFactory< + SyntheticsParams | SyntheticsParams[] +> = () => ({ + method: 'POST', + path: SYNTHETICS_API_URLS.PARAMS, + validate: {}, + validation: { + request: { + body: schema.oneOf([ParamsObjectSchema, schema.arrayOf(ParamsObjectSchema)]), + }, + }, + writeAccess: true, + handler: async ({ request, response, server, savedObjectsClient }) => { + try { + const { id: spaceId } = (await server.spaces?.spacesService.getActiveSpace(request)) ?? { + id: DEFAULT_SPACE_ID, + }; + + const savedObjectsData = parseParamBody( + spaceId, + request.body as SyntheticsParamRequest[] | SyntheticsParamRequest + ); + + const result = await savedObjectsClient.bulkCreate>( + savedObjectsData + ); + + if (savedObjectsData.length > 1) { + return result.saved_objects.map((savedObject) => { + return toClientResponse(savedObject); + }); + } else { + return toClientResponse(result.saved_objects[0]); + } + } catch (error) { + if (error.output?.statusCode === 404) { + const spaceId = server.spaces?.spacesService.getSpaceId(request) ?? DEFAULT_SPACE_ID; + return response.notFound({ + body: { message: `Kibana space '${spaceId}' does not exist` }, + }); + } + + throw error; + } + }, +}); + +const toClientResponse = (savedObject: SavedObject>) => { + const { id, attributes: data, namespaces } = savedObject; + const { description, key, tags } = data; + return { + id, + description, + key, + namespaces, + tags, + value: data.value, + }; +}; + +const parseParamBody = ( + spaceId: string, + body: SyntheticsParamRequest[] | SyntheticsParamRequest +): Array>> => { + if (Array.isArray(body)) { + const params = body as SyntheticsParamRequest[]; + return params.map((param) => { + const { share_across_spaces: shareAcrossSpaces, ...data } = param; + return { + type: syntheticsParamType, + attributes: data, + initialNamespaces: shareAcrossSpaces ? [ALL_SPACES_ID] : [spaceId], + }; + }); + } + + const { share_across_spaces: shareAcrossSpaces, ...data } = body; + return [ + { + type: syntheticsParamType, + attributes: data, + initialNamespaces: shareAcrossSpaces ? [ALL_SPACES_ID] : [spaceId], + }, + ]; +}; diff --git a/x-pack/plugins/synthetics/server/routes/settings/params/delete_param.ts b/x-pack/plugins/synthetics/server/routes/settings/params/delete_param.ts new file mode 100644 index 000000000000000..f0f377ce82d9e55 --- /dev/null +++ b/x-pack/plugins/synthetics/server/routes/settings/params/delete_param.ts @@ -0,0 +1,40 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { SyntheticsRestApiRouteFactory } from '../../types'; +import { syntheticsParamType } from '../../../../common/types/saved_objects'; +import { SYNTHETICS_API_URLS } from '../../../../common/constants'; +import { DeleteParamsResponse } from '../../../../common/runtime_types'; + +export const deleteSyntheticsParamsRoute: SyntheticsRestApiRouteFactory< + DeleteParamsResponse[], + unknown, + unknown, + { ids: string[] } +> = () => ({ + method: 'DELETE', + path: SYNTHETICS_API_URLS.PARAMS, + validate: {}, + validation: { + request: { + body: schema.object({ + ids: schema.arrayOf(schema.string()), + }), + }, + }, + writeAccess: true, + handler: async ({ savedObjectsClient, request }) => { + const { ids } = request.body; + + const result = await savedObjectsClient.bulkDelete( + ids.map((id) => ({ type: syntheticsParamType, id })), + { force: true } + ); + return result.statuses.map(({ id, success }) => ({ id, deleted: success })); + }, +}); diff --git a/x-pack/plugins/synthetics/server/routes/settings/params/edit_param.ts b/x-pack/plugins/synthetics/server/routes/settings/params/edit_param.ts new file mode 100644 index 000000000000000..cd1b0731eedb0d1 --- /dev/null +++ b/x-pack/plugins/synthetics/server/routes/settings/params/edit_param.ts @@ -0,0 +1,76 @@ +/* + * 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 { schema, TypeOf } from '@kbn/config-schema'; +import { SavedObject } from '@kbn/core/server'; +import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; +import { SyntheticsRestApiRouteFactory } from '../../types'; +import { SyntheticsParamRequest, SyntheticsParams } from '../../../../common/runtime_types'; +import { syntheticsParamType } from '../../../../common/types/saved_objects'; +import { SYNTHETICS_API_URLS } from '../../../../common/constants'; + +const RequestParamsSchema = schema.object({ + id: schema.string(), +}); + +type RequestParams = TypeOf; + +export const editSyntheticsParamsRoute: SyntheticsRestApiRouteFactory< + SyntheticsParams, + RequestParams +> = () => ({ + method: 'PUT', + path: SYNTHETICS_API_URLS.PARAMS + '/{id}', + validate: {}, + validation: { + request: { + params: RequestParamsSchema, + body: schema.object({ + key: schema.string(), + value: schema.string(), + description: schema.maybe(schema.string()), + tags: schema.maybe(schema.arrayOf(schema.string())), + share_across_spaces: schema.maybe(schema.boolean()), + }), + }, + }, + writeAccess: true, + handler: async ({ savedObjectsClient, request, server, response }) => { + try { + const { id: _spaceId } = (await server.spaces?.spacesService.getActiveSpace(request)) ?? { + id: DEFAULT_SPACE_ID, + }; + const { id } = request.params; + const { share_across_spaces: _shareAcrossSpaces, ...data } = + request.body as SyntheticsParamRequest & { + id: string; + }; + + const { value } = data; + const { + id: responseId, + attributes: { key, tags, description }, + namespaces, + } = (await savedObjectsClient.update( + syntheticsParamType, + id, + data + )) as SavedObject; + + return { id: responseId, key, tags, description, namespaces, value }; + } catch (error) { + if (error.output?.statusCode === 404) { + const spaceId = server.spaces?.spacesService.getSpaceId(request) ?? DEFAULT_SPACE_ID; + return response.notFound({ + body: { message: `Kibana space '${spaceId}' does not exist` }, + }); + } + + throw error; + } + }, +}); diff --git a/x-pack/plugins/synthetics/server/routes/settings/params/params.ts b/x-pack/plugins/synthetics/server/routes/settings/params/params.ts new file mode 100644 index 000000000000000..8f9f4f76efd8975 --- /dev/null +++ b/x-pack/plugins/synthetics/server/routes/settings/params/params.ts @@ -0,0 +1,102 @@ +/* + * 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 { SavedObject, SavedObjectsFindResult } from '@kbn/core-saved-objects-api-server'; +import { schema, TypeOf } from '@kbn/config-schema'; +import { SyntheticsRestApiRouteFactory } from '../../types'; +import { syntheticsParamType } from '../../../../common/types/saved_objects'; +import { SYNTHETICS_API_URLS } from '../../../../common/constants'; +import { SyntheticsParams, SyntheticsParamsReadonly } from '../../../../common/runtime_types'; + +const RequestParamsSchema = schema.object({ + id: schema.maybe(schema.string()), +}); + +type RequestParams = TypeOf; + +export const getSyntheticsParamsRoute: SyntheticsRestApiRouteFactory< + SyntheticsParams[] | SyntheticsParamsReadonly[] | SyntheticsParams | SyntheticsParamsReadonly, + RequestParams +> = () => ({ + method: 'GET', + path: SYNTHETICS_API_URLS.PARAMS + '/{id?}', + validate: {}, + validation: { + request: { + params: RequestParamsSchema, + }, + }, + handler: async ({ savedObjectsClient, request, response, server, spaceId }) => { + try { + const { id: paramId } = request.params; + + const encryptedSavedObjectsClient = server.encryptedSavedObjects.getClient(); + + const canSave = + (await server.coreStart?.capabilities.resolveCapabilities(request)).uptime.save ?? false; + + if (canSave) { + if (paramId) { + const savedObject = + await encryptedSavedObjectsClient.getDecryptedAsInternalUser( + syntheticsParamType, + paramId, + { namespace: spaceId } + ); + return toClientResponse(savedObject); + } + + const finder = + await encryptedSavedObjectsClient.createPointInTimeFinderDecryptedAsInternalUser( + { + type: syntheticsParamType, + perPage: 1000, + namespaces: [spaceId], + } + ); + + const hits: Array> = []; + for await (const result of finder.find()) { + hits.push(...result.saved_objects); + } + + return hits.map((savedObject) => toClientResponse(savedObject)); + } else { + if (paramId) { + const savedObject = await savedObjectsClient.get( + syntheticsParamType, + paramId + ); + return toClientResponse(savedObject); + } + + const data = await savedObjectsClient.find({ + type: syntheticsParamType, + perPage: 10000, + }); + return data.saved_objects.map((savedObject) => toClientResponse(savedObject)); + } + } catch (error) { + if (error.output?.statusCode === 404) { + return response.notFound({ body: { message: `Kibana space '${spaceId}' does not exist` } }); + } + + throw error; + } + }, +}); + +const toClientResponse = ( + savedObject: SavedObject +) => { + const { id, attributes, namespaces } = savedObject; + return { + ...attributes, + id, + namespaces, + }; +}; diff --git a/x-pack/plugins/synthetics/server/routes/types.ts b/x-pack/plugins/synthetics/server/routes/types.ts index b372c6fd11a7f64..7224a6a9e7f5af1 100644 --- a/x-pack/plugins/synthetics/server/routes/types.ts +++ b/x-pack/plugins/synthetics/server/routes/types.ts @@ -16,6 +16,7 @@ import { KibanaResponseFactory, IKibanaResponse, } from '@kbn/core/server'; +import { FullValidationConfig } from '@kbn/core-http-server'; import { UptimeEsClient } from '../lib'; import { SyntheticsServerSetup, UptimeRequestHandlerContext } from '../types'; import { SyntheticsMonitorClient } from '../synthetics_service/synthetics_monitor/synthetics_monitor_client'; @@ -32,6 +33,7 @@ export interface UMServerRoute { method: 'GET' | 'PUT' | 'POST' | 'DELETE'; writeAccess?: boolean; handler: T; + validation?: FullValidationConfig; streamHandler?: ( context: UptimeRequestHandlerContext, request: SyntheticsRequest, @@ -57,13 +59,17 @@ export type UMKibanaRoute = UMRouteDefinition< export type SyntheticsRestApiRouteFactory< ClientContract = any, - QueryParams = Record -> = () => SyntheticsRoute; + Params = any, + Query = Record, + Body = any +> = () => SyntheticsRoute; export type SyntheticsRoute< ClientContract = unknown, - QueryParams = Record -> = UMRouteDefinition>; + Params = Record, + Query = Record, + Body = any +> = UMRouteDefinition>; export type SyntheticsRouteWrapper = ( uptimeRoute: SyntheticsRoute>, @@ -81,10 +87,14 @@ export interface UptimeRouteContext { subject?: Subject; } -export interface RouteContext> { +export interface RouteContext< + Params = Record, + Query = Record, + Body = any +> { uptimeEsClient: UptimeEsClient; context: UptimeRequestHandlerContext; - request: KibanaRequest, Query, Record>; + request: KibanaRequest; response: KibanaResponseFactory; savedObjectsClient: SavedObjectsClientContract; server: SyntheticsServerSetup; @@ -93,7 +103,12 @@ export interface RouteContext> { spaceId: string; } -export type SyntheticsRouteHandler> = ({ +export type SyntheticsRouteHandler< + ClientContract, + Params = Record, + Query = Record, + Body = any +> = ({ uptimeEsClient, context, request, @@ -101,4 +116,4 @@ export type SyntheticsRouteHandler) => Promise | ClientContract>; +}: RouteContext) => Promise | ClientContract>; diff --git a/x-pack/plugins/synthetics/server/server.ts b/x-pack/plugins/synthetics/server/server.ts index 9e829045013d4a1..69a1aa79d2410e1 100644 --- a/x-pack/plugins/synthetics/server/server.ts +++ b/x-pack/plugins/synthetics/server/server.ts @@ -11,7 +11,7 @@ import { SyntheticsPluginsSetupDependencies, SyntheticsServerSetup } from './typ import { createSyntheticsRouteWithAuth } from './routes/create_route_with_auth'; import { SyntheticsMonitorClient } from './synthetics_service/synthetics_monitor/synthetics_monitor_client'; import { syntheticsRouteWrapper } from './synthetics_route_wrapper'; -import { syntheticsAppRestApiRoutes } from './routes'; +import { syntheticsAppPublicRestApiRoutes, syntheticsAppRestApiRoutes } from './routes'; export const initSyntheticsServer = ( server: SyntheticsServerSetup, @@ -19,6 +19,7 @@ export const initSyntheticsServer = ( plugins: SyntheticsPluginsSetupDependencies, ruleDataClient: IRuleDataClient ) => { + const { router } = server; syntheticsAppRestApiRoutes.forEach((route) => { const { method, options, handler, validate, path } = syntheticsRouteWrapper( createSyntheticsRouteWithAuth(route), @@ -34,16 +35,103 @@ export const initSyntheticsServer = ( switch (method) { case 'GET': - server.router.get(routeDefinition, handler); + router.get(routeDefinition, handler); break; case 'POST': - server.router.post(routeDefinition, handler); + router.post(routeDefinition, handler); break; case 'PUT': - server.router.put(routeDefinition, handler); + router.put(routeDefinition, handler); break; case 'DELETE': - server.router.delete(routeDefinition, handler); + router.delete(routeDefinition, handler); + break; + default: + throw new Error(`Handler for method ${method} is not defined`); + } + }); + + syntheticsAppPublicRestApiRoutes.forEach((route) => { + const { method, options, handler, validate, path, validation } = syntheticsRouteWrapper( + createSyntheticsRouteWithAuth(route), + server, + syntheticsMonitorClient + ); + + const routeDefinition = { + path, + validate, + options, + }; + + switch (method) { + case 'GET': + router.versioned + .get({ + access: 'public', + path: routeDefinition.path, + options: { + tags: options?.tags, + }, + }) + .addVersion( + { + version: '2023-10-31', + validate: validation ?? false, + }, + handler + ); + break; + case 'PUT': + router.versioned + .put({ + access: 'public', + path: routeDefinition.path, + options: { + tags: options?.tags, + }, + }) + .addVersion( + { + version: '2023-10-31', + validate: validation ?? false, + }, + handler + ); + break; + case 'POST': + router.versioned + .post({ + access: 'public', + path: routeDefinition.path, + options: { + tags: options?.tags, + }, + }) + .addVersion( + { + version: '2023-10-31', + validate: validation ?? false, + }, + handler + ); + break; + case 'DELETE': + router.versioned + .delete({ + access: 'public', + path: routeDefinition.path, + options: { + tags: options?.tags, + }, + }) + .addVersion( + { + version: '2023-10-31', + validate: validation ?? false, + }, + handler + ); break; default: throw new Error(`Handler for method ${method} is not defined`); diff --git a/x-pack/test/api_integration/apis/synthetics/add_edit_params.ts b/x-pack/test/api_integration/apis/synthetics/add_edit_params.ts index f5d9256a13b4d63..4de02eb80b30c8c 100644 --- a/x-pack/test/api_integration/apis/synthetics/add_edit_params.ts +++ b/x-pack/test/api_integration/apis/synthetics/add_edit_params.ts @@ -94,9 +94,9 @@ export default function ({ getService }: FtrProviderContext) { assertHas(param, testParam); await supertestAPI - .put(SYNTHETICS_API_URLS.PARAMS) + .put(SYNTHETICS_API_URLS.PARAMS + '/' + param.id) .set('kbn-xsrf', 'true') - .send({ ...expectedUpdatedParam, id: param.id }) + .send(expectedUpdatedParam) .expect(200); const updatedGetResponse = await supertestAPI @@ -155,9 +155,9 @@ export default function ({ getService }: FtrProviderContext) { assertHas(param, testParam); await supertestAPI - .put(`/s/${SPACE_ID}${SYNTHETICS_API_URLS.PARAMS}`) + .put(`/s/${SPACE_ID}${SYNTHETICS_API_URLS.PARAMS}/${param.id}`) .set('kbn-xsrf', 'true') - .send({ ...expectedUpdatedParam, id: param.id }) + .send(expectedUpdatedParam) .expect(200); const updatedGetResponse = await supertestAPI @@ -204,9 +204,9 @@ export default function ({ getService }: FtrProviderContext) { .expect(200); await supertestAPI - .put(`/s/${SPACE_ID_TWO}${SYNTHETICS_API_URLS.PARAMS}`) + .put(`/s/${SPACE_ID_TWO}${SYNTHETICS_API_URLS.PARAMS}/${param.id}}`) .set('kbn-xsrf', 'true') - .send({ ...updatedParam, id: param.id }) + .send(updatedParam) .expect(404); const updatedGetResponse = await supertestAPI @@ -251,9 +251,9 @@ export default function ({ getService }: FtrProviderContext) { assertHas(param, testParam); await supertestAPI - .put(`/s/doesnotexist${SYNTHETICS_API_URLS.PARAMS}`) + .put(`/s/doesnotexist${SYNTHETICS_API_URLS.PARAMS}/${param.id}}`) .set('kbn-xsrf', 'true') - .send({ ...updatedParam, id: param.id }) + .send(updatedParam) .expect(404); }); diff --git a/x-pack/test/api_integration/apis/synthetics/sync_global_params.ts b/x-pack/test/api_integration/apis/synthetics/sync_global_params.ts index 742463495595113..d6ae4e8f78228b2 100644 --- a/x-pack/test/api_integration/apis/synthetics/sync_global_params.ts +++ b/x-pack/test/api_integration/apis/synthetics/sync_global_params.ts @@ -22,8 +22,6 @@ import { PrivateLocationTestService } from './services/private_location_test_ser import { comparePolicies, getTestSyntheticsPolicy } from './sample_data/test_policy'; export default function ({ getService }: FtrProviderContext) { - // FLAKY: https://github.com/elastic/kibana/issues/162594 - // Failing: See https://github.com/elastic/kibana/issues/162594 describe('SyncGlobalParams', function () { this.tags('skipCloud'); const supertestAPI = getService('supertest'); @@ -278,8 +276,8 @@ export default function ({ getService }: FtrProviderContext) { const deleteResponse = await supertestAPI .delete(SYNTHETICS_API_URLS.PARAMS) - .query({ ids: JSON.stringify(ids) }) .set('kbn-xsrf', 'true') + .send({ ids }) .expect(200); expect(deleteResponse.body).to.have.length(2);