From 265cc7624768fef99a7cad9045a79e8610308886 Mon Sep 17 00:00:00 2001 From: Pierre Gayvallet Date: Tue, 30 Mar 2021 13:39:32 +0200 Subject: [PATCH 1/4] Remove core->cli dependency (#95145) * extract http_tools to package * fix readme * start moving stuff * cleaning up `isDevCliParent` * choose bootstrap script * fix bootstrap script logic * fix watch paths logic * import REPO_ROOT from correct package * create the @kbn/crypto package * update core's `dev` config * only export bootstrap function * extract sslConfig to http-tools package * fix core types * fix optimizer tests * fix cli_dev_mode tests * fix basePath proxy tests * update generated doc * fix unit tests * create @kbn/dev-cli-mode package * remove useless comment * self-review NITS * update CODEOWNERS file * add devOnly flag * use variable for DEV_MODE_PATH * review comments * fix logger/log adapter * fix log calls in base path proxy server * address some review comments * rename @kbn/http-tools to @kbn/server-http-tools * more review comments * move test to correct file * add comment on getBootstrapScript * fix lint * lint * add cli-dev-mode to eslint dev packages * review comments * update yarn.lock * Revert "[ci] skip building ts refs when not necessary (#95739)" This reverts commit e46a74f7 --- .eslintrc.js | 1 + .github/CODEOWNERS | 3 + ...lugin-core-server.kibanaresponsefactory.md | 4 +- package.json | 3 + .../kbn-cli-dev-mode}/README.md | 10 +- packages/kbn-cli-dev-mode/jest.config.js | 13 + packages/kbn-cli-dev-mode/package.json | 26 + .../src/base_path_proxy_server.test.ts | 358 ++++++ .../src}/base_path_proxy_server.ts | 46 +- packages/kbn-cli-dev-mode/src/bootstrap.ts | 43 + .../src}/cli_dev_mode.test.ts | 139 +-- .../kbn-cli-dev-mode/src}/cli_dev_mode.ts | 84 +- .../kbn-cli-dev-mode/src/config/dev_config.ts | 28 + .../src/config/http_config.ts | 65 ++ packages/kbn-cli-dev-mode/src/config/index.ts | 13 + .../src/config/load_config.ts | 44 + .../src/config/plugins_config.ts | 37 + packages/kbn-cli-dev-mode/src/config/types.ts | 17 + .../kbn-cli-dev-mode/src}/dev_server.test.ts | 0 .../kbn-cli-dev-mode/src}/dev_server.ts | 0 .../src}/get_active_inspect_flag.ts | 0 .../src}/get_server_watch_paths.test.ts | 0 .../src}/get_server_watch_paths.ts | 10 +- .../kbn-cli-dev-mode/src}/index.ts | 3 +- .../kbn-cli-dev-mode/src}/log.ts | 0 packages/kbn-cli-dev-mode/src/log_adapter.ts | 28 + .../kbn-cli-dev-mode/src}/optimizer.test.ts | 6 + .../kbn-cli-dev-mode/src}/optimizer.ts | 2 + ...should_redirect_from_old_base_path.test.ts | 0 .../should_redirect_from_old_base_path.ts | 0 .../kbn-cli-dev-mode/src}/test_helpers.ts | 0 .../src}/using_server_process.ts | 0 .../kbn-cli-dev-mode/src}/watcher.test.ts | 0 .../kbn-cli-dev-mode/src}/watcher.ts | 0 packages/kbn-cli-dev-mode/tsconfig.json | 11 + packages/kbn-config/src/__mocks__/env.ts | 1 - .../src/__snapshots__/env.test.ts.snap | 6 - packages/kbn-config/src/env.test.ts | 1 - packages/kbn-config/src/env.ts | 8 - packages/kbn-config/src/index.ts | 7 +- packages/kbn-config/src/raw/index.ts | 2 +- .../kbn-config/src/raw/raw_config_service.ts | 2 +- packages/kbn-crypto/README.md | 3 + packages/kbn-crypto/jest.config.js | 13 + packages/kbn-crypto/package.json | 16 + .../kbn-crypto/src}/__fixtures__/README.md | 0 .../kbn-crypto/src}/__fixtures__/index.ts | 0 .../kbn-crypto/src}/__fixtures__/no_ca.p12 | Bin .../kbn-crypto/src}/__fixtures__/no_cert.p12 | Bin .../kbn-crypto/src}/__fixtures__/no_key.p12 | Bin .../kbn-crypto/src}/__fixtures__/two_cas.p12 | Bin .../kbn-crypto/src}/__fixtures__/two_keys.p12 | Bin .../kbn-crypto/src}/index.ts | 0 .../kbn-crypto/src}/pkcs12.test.ts | 2 +- .../kbn-crypto/src}/pkcs12.ts | 0 .../kbn-crypto/src}/sha256.test.ts | 0 .../kbn-crypto/src}/sha256.ts | 0 packages/kbn-crypto/tsconfig.json | 11 + packages/kbn-server-http-tools/README.md | 3 + packages/kbn-server-http-tools/jest.config.js | 13 + packages/kbn-server-http-tools/package.json | 20 + .../src/create_server.ts | 29 + .../default_validation_error_handler.test.ts | 51 + .../src/default_validation_error_handler.ts | 63 + .../src/get_listener_options.ts | 21 + .../src/get_request_id.test.ts | 85 ++ .../src/get_request_id.ts | 22 + .../src/get_server_options.test.ts | 122 ++ .../src/get_server_options.ts | 75 ++ packages/kbn-server-http-tools/src/index.ts | 15 + .../kbn-server-http-tools/src/ssl/index.ts | 2 +- .../src/ssl}/ssl_config.test.mocks.ts | 2 +- .../src/ssl}/ssl_config.test.ts | 2 +- .../src/ssl}/ssl_config.ts | 17 +- packages/kbn-server-http-tools/src/types.ts | 37 + packages/kbn-server-http-tools/tsconfig.json | 14 + packages/kbn-utils/src/repo_root.ts | 2 + src/cli/serve/serve.js | 78 +- src/core/server/bootstrap.ts | 16 +- src/core/server/dev/dev_config.ts | 23 +- src/core/server/dev/index.ts | 3 +- .../elasticsearch_config.test.mocks.ts | 2 +- .../elasticsearch_config.test.ts | 6 +- .../elasticsearch/elasticsearch_config.ts | 2 +- .../external_url/external_url_config.ts | 2 +- .../http/base_path_proxy_server.test.ts | 1021 ----------------- src/core/server/http/http_config.ts | 4 +- src/core/server/http/http_server.test.ts | 24 + src/core/server/http/http_server.ts | 7 +- src/core/server/http/http_service.test.ts | 23 - src/core/server/http/http_service.ts | 10 +- src/core/server/http/http_tools.test.ts | 274 ----- src/core/server/http/http_tools.ts | 186 --- src/core/server/http/https_redirect_server.ts | 2 +- src/core/server/http/index.ts | 1 - .../http/integration_tests/router.test.ts | 5 +- src/core/server/legacy/legacy_service.test.ts | 73 -- src/core/server/legacy/legacy_service.ts | 45 +- .../server/plugins/plugins_service.test.ts | 34 +- src/core/server/plugins/plugins_service.ts | 20 +- src/core/server/root/index.ts | 9 +- src/core/server/server.api.md | 8 +- src/core/server/server.test.ts | 16 - src/core/server/server.ts | 11 +- src/core/server/utils/index.ts | 1 - src/core/test_helpers/kbn_server.ts | 1 - yarn.lock | 12 + 107 files changed, 1611 insertions(+), 1969 deletions(-) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode}/README.md (72%) create mode 100644 packages/kbn-cli-dev-mode/jest.config.js create mode 100644 packages/kbn-cli-dev-mode/package.json create mode 100644 packages/kbn-cli-dev-mode/src/base_path_proxy_server.test.ts rename {src/core/server/http => packages/kbn-cli-dev-mode/src}/base_path_proxy_server.ts (90%) create mode 100644 packages/kbn-cli-dev-mode/src/bootstrap.ts rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/cli_dev_mode.test.ts (79%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/cli_dev_mode.ts (83%) create mode 100644 packages/kbn-cli-dev-mode/src/config/dev_config.ts create mode 100644 packages/kbn-cli-dev-mode/src/config/http_config.ts create mode 100644 packages/kbn-cli-dev-mode/src/config/index.ts create mode 100644 packages/kbn-cli-dev-mode/src/config/load_config.ts create mode 100644 packages/kbn-cli-dev-mode/src/config/plugins_config.ts create mode 100644 packages/kbn-cli-dev-mode/src/config/types.ts rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/dev_server.test.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/dev_server.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/get_active_inspect_flag.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/get_server_watch_paths.test.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/get_server_watch_paths.ts (87%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/index.ts (86%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/log.ts (100%) create mode 100644 packages/kbn-cli-dev-mode/src/log_adapter.ts rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/optimizer.test.ts (96%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/optimizer.ts (97%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/should_redirect_from_old_base_path.test.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/should_redirect_from_old_base_path.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/test_helpers.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/using_server_process.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/watcher.test.ts (100%) rename {src/dev/cli_dev_mode => packages/kbn-cli-dev-mode/src}/watcher.ts (100%) create mode 100644 packages/kbn-cli-dev-mode/tsconfig.json create mode 100644 packages/kbn-crypto/README.md create mode 100644 packages/kbn-crypto/jest.config.js create mode 100644 packages/kbn-crypto/package.json rename {src/core/server/utils/crypto => packages/kbn-crypto/src}/__fixtures__/README.md (100%) rename {src/core/server/utils/crypto => packages/kbn-crypto/src}/__fixtures__/index.ts (100%) rename {src/core/server/utils/crypto => packages/kbn-crypto/src}/__fixtures__/no_ca.p12 (100%) rename {src/core/server/utils/crypto => packages/kbn-crypto/src}/__fixtures__/no_cert.p12 (100%) rename {src/core/server/utils/crypto => packages/kbn-crypto/src}/__fixtures__/no_key.p12 (100%) rename {src/core/server/utils/crypto => packages/kbn-crypto/src}/__fixtures__/two_cas.p12 (100%) rename {src/core/server/utils/crypto => packages/kbn-crypto/src}/__fixtures__/two_keys.p12 (100%) rename {src/core/server/utils/crypto => packages/kbn-crypto/src}/index.ts (100%) rename {src/core/server/utils/crypto => packages/kbn-crypto/src}/pkcs12.test.ts (99%) rename {src/core/server/utils/crypto => packages/kbn-crypto/src}/pkcs12.ts (100%) rename {src/core/server/utils/crypto => packages/kbn-crypto/src}/sha256.test.ts (100%) rename {src/core/server/utils/crypto => packages/kbn-crypto/src}/sha256.ts (100%) create mode 100644 packages/kbn-crypto/tsconfig.json create mode 100644 packages/kbn-server-http-tools/README.md create mode 100644 packages/kbn-server-http-tools/jest.config.js create mode 100644 packages/kbn-server-http-tools/package.json create mode 100644 packages/kbn-server-http-tools/src/create_server.ts create mode 100644 packages/kbn-server-http-tools/src/default_validation_error_handler.test.ts create mode 100644 packages/kbn-server-http-tools/src/default_validation_error_handler.ts create mode 100644 packages/kbn-server-http-tools/src/get_listener_options.ts create mode 100644 packages/kbn-server-http-tools/src/get_request_id.test.ts create mode 100644 packages/kbn-server-http-tools/src/get_request_id.ts create mode 100644 packages/kbn-server-http-tools/src/get_server_options.test.ts create mode 100644 packages/kbn-server-http-tools/src/get_server_options.ts create mode 100644 packages/kbn-server-http-tools/src/index.ts rename src/core/server/legacy/cli_dev_mode.js => packages/kbn-server-http-tools/src/ssl/index.ts (86%) rename {src/core/server/http => packages/kbn-server-http-tools/src/ssl}/ssl_config.test.mocks.ts (95%) rename {src/core/server/http => packages/kbn-server-http-tools/src/ssl}/ssl_config.test.ts (99%) rename {src/core/server/http => packages/kbn-server-http-tools/src/ssl}/ssl_config.ts (93%) create mode 100644 packages/kbn-server-http-tools/src/types.ts create mode 100644 packages/kbn-server-http-tools/tsconfig.json delete mode 100644 src/core/server/http/base_path_proxy_server.test.ts delete mode 100644 src/core/server/http/http_tools.test.ts delete mode 100644 src/core/server/http/http_tools.ts diff --git a/.eslintrc.js b/.eslintrc.js index ab868c29b7bed8..a7b45534391c0a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -93,6 +93,7 @@ const SAFER_LODASH_SET_DEFINITELYTYPED_HEADER = ` const DEV_PACKAGES = [ 'kbn-babel-code-parser', 'kbn-dev-utils', + 'kbn-cli-dev-mode', 'kbn-docs-utils', 'kbn-es*', 'kbn-eslint*', diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 33b3e4a7dede62..3d44f46aca4ff7 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -158,6 +158,7 @@ /packages/kbn-ui-shared-deps/ @elastic/kibana-operations /packages/kbn-es-archiver/ @elastic/kibana-operations /packages/kbn-utils/ @elastic/kibana-operations +/packages/kbn-cli-dev-mode/ @elastic/kibana-operations /src/cli/keystore/ @elastic/kibana-operations /src/legacy/server/warnings/ @elastic/kibana-operations /.ci/es-snapshots/ @elastic/kibana-operations @@ -194,6 +195,8 @@ /packages/kbn-config/ @elastic/kibana-core /packages/kbn-logging/ @elastic/kibana-core /packages/kbn-legacy-logging/ @elastic/kibana-core +/packages/kbn-crypto/ @elastic/kibana-core +/packages/kbn-http-tools/ @elastic/kibana-core /src/legacy/server/config/ @elastic/kibana-core /src/legacy/server/http/ @elastic/kibana-core /src/legacy/server/logging/ @elastic/kibana-core diff --git a/docs/development/core/server/kibana-plugin-core-server.kibanaresponsefactory.md b/docs/development/core/server/kibana-plugin-core-server.kibanaresponsefactory.md index 551cbe3c937504..395c26a6e4bf65 100644 --- a/docs/development/core/server/kibana-plugin-core-server.kibanaresponsefactory.md +++ b/docs/development/core/server/kibana-plugin-core-server.kibanaresponsefactory.md @@ -10,10 +10,10 @@ Set of helpers used to create `KibanaResponse` to form HTTP response on an incom ```typescript kibanaResponseFactory: { - custom: | Buffer | Error | Stream | { + custom: | Error | Buffer | { message: string | Error; attributes?: Record | undefined; - } | undefined>(options: CustomHttpResponseOptions) => KibanaResponse; + } | Stream | undefined>(options: CustomHttpResponseOptions) => KibanaResponse; badRequest: (options?: ErrorHttpResponseOptions) => KibanaResponse; unauthorized: (options?: ErrorHttpResponseOptions) => KibanaResponse; forbidden: (options?: ErrorHttpResponseOptions) => KibanaResponse; diff --git a/package.json b/package.json index 99591fdc1ea405..2654c433ac5fa8 100644 --- a/package.json +++ b/package.json @@ -127,11 +127,13 @@ "@kbn/apm-utils": "link:packages/kbn-apm-utils", "@kbn/config": "link:packages/kbn-config", "@kbn/config-schema": "link:packages/kbn-config-schema", + "@kbn/crypto": "link:packages/kbn-crypto", "@kbn/i18n": "link:packages/kbn-i18n", "@kbn/interpreter": "link:packages/kbn-interpreter", "@kbn/legacy-logging": "link:packages/kbn-legacy-logging", "@kbn/logging": "link:packages/kbn-logging", "@kbn/monaco": "link:packages/kbn-monaco", + "@kbn/server-http-tools": "link:packages/kbn-server-http-tools", "@kbn/std": "link:packages/kbn-std", "@kbn/tinymath": "link:packages/kbn-tinymath", "@kbn/ui-framework": "link:packages/kbn-ui-framework", @@ -451,6 +453,7 @@ "@jest/reporters": "^26.5.2", "@kbn/babel-code-parser": "link:packages/kbn-babel-code-parser", "@kbn/babel-preset": "link:packages/kbn-babel-preset", + "@kbn/cli-dev-mode": "link:packages/kbn-cli-dev-mode", "@kbn/dev-utils": "link:packages/kbn-dev-utils", "@kbn/docs-utils": "link:packages/kbn-docs-utils", "@kbn/es": "link:packages/kbn-es", diff --git a/src/dev/cli_dev_mode/README.md b/packages/kbn-cli-dev-mode/README.md similarity index 72% rename from src/dev/cli_dev_mode/README.md rename to packages/kbn-cli-dev-mode/README.md index 397017027a52f1..6ce41249674ce2 100644 --- a/src/dev/cli_dev_mode/README.md +++ b/packages/kbn-cli-dev-mode/README.md @@ -26,8 +26,12 @@ The `DevServer` object is responsible for everything related to running and rest The `Optimizer` object manages a `@kbn/optimizer` instance, adapting its configuration and logging to the data available to the CLI. -## `BasePathProxyServer` (currently passed from core) +## `BasePathProxyServer` -The `BasePathProxyServer` is passed to the `CliDevMode` from core when the dev mode is trigged by the `--dev` flag. This proxy injects a random three character base path in the URL that Kibana is served from to help ensure that Kibana features are written to adapt to custom base path configurations from users. +This proxy injects a random three character base path in the URL that Kibana is served from to help ensure that Kibana features +are written to adapt to custom base path configurations from users. -The basePathProxy also has another important job, ensuring that requests don't fail because the server is restarting and that the browser receives front-end assets containing all saved changes. We accomplish this by observing the ready state of the `Optimizer` and `DevServer` objects and pausing all requests through the proxy until both objects report that they aren't building/restarting based on recently saved changes. \ No newline at end of file +The basePathProxy also has another important job, ensuring that requests don't fail because the server is restarting and +that the browser receives front-end assets containing all saved changes. We accomplish this by observing the ready state of +the `Optimizer` and `DevServer` objects and pausing all requests through the proxy until both objects report that +they aren't building/restarting based on recently saved changes. \ No newline at end of file diff --git a/packages/kbn-cli-dev-mode/jest.config.js b/packages/kbn-cli-dev-mode/jest.config.js new file mode 100644 index 00000000000000..d04dc571ef2a0b --- /dev/null +++ b/packages/kbn-cli-dev-mode/jest.config.js @@ -0,0 +1,13 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../..', + roots: ['/packages/kbn-cli-dev-mode'], +}; diff --git a/packages/kbn-cli-dev-mode/package.json b/packages/kbn-cli-dev-mode/package.json new file mode 100644 index 00000000000000..2ee9831e960842 --- /dev/null +++ b/packages/kbn-cli-dev-mode/package.json @@ -0,0 +1,26 @@ +{ + "name": "@kbn/cli-dev-mode", + "main": "./target/index.js", + "types": "./target/index.d.ts", + "version": "1.0.0", + "license": "SSPL-1.0 OR Elastic License 2.0", + "private": true, + "scripts": { + "build": "../../node_modules/.bin/tsc", + "kbn:bootstrap": "yarn build", + "kbn:watch": "yarn build --watch" + }, + "kibana": { + "devOnly": true + }, + "dependencies": { + "@kbn/config": "link:../kbn-config", + "@kbn/config-schema": "link:../kbn-config-schema", + "@kbn/logging": "link:../kbn-logging", + "@kbn/server-http-tools": "link:../kbn-server-http-tools", + "@kbn/optimizer": "link:../kbn-optimizer", + "@kbn/std": "link:../kbn-std", + "@kbn/dev-utils": "link:../kbn-dev-utils", + "@kbn/utils": "link:../kbn-utils" + } +} \ No newline at end of file diff --git a/packages/kbn-cli-dev-mode/src/base_path_proxy_server.test.ts b/packages/kbn-cli-dev-mode/src/base_path_proxy_server.test.ts new file mode 100644 index 00000000000000..c99485c2733645 --- /dev/null +++ b/packages/kbn-cli-dev-mode/src/base_path_proxy_server.test.ts @@ -0,0 +1,358 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Server } from '@hapi/hapi'; +import { EMPTY } from 'rxjs'; +import supertest from 'supertest'; +import { + getServerOptions, + getListenerOptions, + createServer, + IHttpConfig, +} from '@kbn/server-http-tools'; +import { ByteSizeValue } from '@kbn/config-schema'; + +import { BasePathProxyServer, BasePathProxyServerOptions } from './base_path_proxy_server'; +import { DevConfig } from './config/dev_config'; +import { TestLog } from './log'; + +describe('BasePathProxyServer', () => { + let server: Server; + let proxyServer: BasePathProxyServer; + let logger: TestLog; + let config: IHttpConfig; + let basePath: string; + let proxySupertest: supertest.SuperTest; + + beforeEach(async () => { + logger = new TestLog(); + + config = { + host: '127.0.0.1', + port: 10012, + keepaliveTimeout: 1000, + socketTimeout: 1000, + cors: { + enabled: false, + allowCredentials: false, + allowOrigin: [], + }, + ssl: { enabled: false }, + maxPayload: new ByteSizeValue(1024), + }; + + const serverOptions = getServerOptions(config); + const listenerOptions = getListenerOptions(config); + server = createServer(serverOptions, listenerOptions); + + // setup and start the proxy server + const proxyConfig: IHttpConfig = { ...config, port: 10013 }; + const devConfig = new DevConfig({ basePathProxyTarget: config.port }); + proxyServer = new BasePathProxyServer(logger, proxyConfig, devConfig); + const options: BasePathProxyServerOptions = { + shouldRedirectFromOldBasePath: () => true, + delayUntil: () => EMPTY, + }; + await proxyServer.start(options); + + // set the base path or throw if for some unknown reason it is not setup + if (proxyServer.basePath == null) { + throw new Error('Invalid null base path, all tests will fail'); + } else { + basePath = proxyServer.basePath; + } + proxySupertest = supertest(`http://127.0.0.1:${proxyConfig.port}`); + }); + + afterEach(async () => { + await server.stop(); + await proxyServer.stop(); + jest.clearAllMocks(); + }); + + test('root URL will return a 302 redirect', async () => { + await proxySupertest.get('/').expect(302); + }); + + test('root URL will return a redirect location with exactly 3 characters that are a-z', async () => { + const res = await proxySupertest.get('/'); + const location = res.header.location; + expect(location).toMatch(/[a-z]{3}/); + }); + + test('forwards request with the correct path', async () => { + server.route({ + method: 'GET', + path: `${basePath}/foo/{test}`, + handler: (request, h) => { + return h.response(request.params.test); + }, + }); + await server.start(); + + await proxySupertest + .get(`${basePath}/foo/some-string`) + .expect(200) + .then((res) => { + expect(res.text).toBe('some-string'); + }); + }); + + test('forwards request with the correct query params', async () => { + server.route({ + method: 'GET', + path: `${basePath}/foo/`, + handler: (request, h) => { + return h.response(request.query); + }, + }); + + await server.start(); + + await proxySupertest + .get(`${basePath}/foo/?bar=test&quux=123`) + .expect(200) + .then((res) => { + expect(res.body).toEqual({ bar: 'test', quux: '123' }); + }); + }); + + test('forwards the request body', async () => { + server.route({ + method: 'POST', + path: `${basePath}/foo/`, + handler: (request, h) => { + return h.response(request.payload); + }, + }); + + await server.start(); + + await proxySupertest + .post(`${basePath}/foo/`) + .send({ + bar: 'test', + baz: 123, + }) + .expect(200) + .then((res) => { + expect(res.body).toEqual({ bar: 'test', baz: 123 }); + }); + }); + + test('returns the correct status code', async () => { + server.route({ + method: 'GET', + path: `${basePath}/foo/`, + handler: (request, h) => { + return h.response({ foo: 'bar' }).code(417); + }, + }); + + await server.start(); + + await proxySupertest + .get(`${basePath}/foo/`) + .expect(417) + .then((res) => { + expect(res.body).toEqual({ foo: 'bar' }); + }); + }); + + test('returns the response headers', async () => { + server.route({ + method: 'GET', + path: `${basePath}/foo/`, + handler: (request, h) => { + return h.response({ foo: 'bar' }).header('foo', 'bar'); + }, + }); + + await server.start(); + + await proxySupertest + .get(`${basePath}/foo/`) + .expect(200) + .then((res) => { + expect(res.get('foo')).toEqual('bar'); + }); + }); + + test('handles putting', async () => { + server.route({ + method: 'PUT', + path: `${basePath}/foo/`, + handler: (request, h) => { + return h.response(request.payload); + }, + }); + + await server.start(); + + await proxySupertest + .put(`${basePath}/foo/`) + .send({ + bar: 'test', + baz: 123, + }) + .expect(200) + .then((res) => { + expect(res.body).toEqual({ bar: 'test', baz: 123 }); + }); + }); + + test('handles deleting', async () => { + server.route({ + method: 'DELETE', + path: `${basePath}/foo/{test}`, + handler: (request, h) => { + return h.response(request.params.test); + }, + }); + await server.start(); + + await proxySupertest + .delete(`${basePath}/foo/some-string`) + .expect(200) + .then((res) => { + expect(res.text).toBe('some-string'); + }); + }); + + describe('with `basepath: /bar` and `rewriteBasePath: false`', () => { + beforeEach(async () => { + const configWithBasePath: IHttpConfig = { + ...config, + basePath: '/bar', + rewriteBasePath: false, + } as IHttpConfig; + + const serverOptions = getServerOptions(configWithBasePath); + const listenerOptions = getListenerOptions(configWithBasePath); + server = createServer(serverOptions, listenerOptions); + + server.route({ + method: 'GET', + path: `${basePath}/`, + handler: (request, h) => { + return h.response('value:/'); + }, + }); + server.route({ + method: 'GET', + path: `${basePath}/foo`, + handler: (request, h) => { + return h.response('value:/foo'); + }, + }); + + await server.start(); + }); + + test('/bar => 404', async () => { + await proxySupertest.get(`${basePath}/bar`).expect(404); + }); + + test('/bar/ => 404', async () => { + await proxySupertest.get(`${basePath}/bar/`).expect(404); + }); + + test('/bar/foo => 404', async () => { + await proxySupertest.get(`${basePath}/bar/foo`).expect(404); + }); + + test('/ => /', async () => { + await proxySupertest + .get(`${basePath}/`) + .expect(200) + .then((res) => { + expect(res.text).toBe('value:/'); + }); + }); + + test('/foo => /foo', async () => { + await proxySupertest + .get(`${basePath}/foo`) + .expect(200) + .then((res) => { + expect(res.text).toBe('value:/foo'); + }); + }); + }); + + describe('shouldRedirect', () => { + let proxyServerWithoutShouldRedirect: BasePathProxyServer; + let proxyWithoutShouldRedirectSupertest: supertest.SuperTest; + + beforeEach(async () => { + // setup and start a proxy server which does not use "shouldRedirectFromOldBasePath" + const proxyConfig: IHttpConfig = { ...config, port: 10004 }; + const devConfig = new DevConfig({ basePathProxyTarget: config.port }); + proxyServerWithoutShouldRedirect = new BasePathProxyServer(logger, proxyConfig, devConfig); + const options: Readonly = { + shouldRedirectFromOldBasePath: () => false, // Return false to not redirect + delayUntil: () => EMPTY, + }; + await proxyServerWithoutShouldRedirect.start(options); + proxyWithoutShouldRedirectSupertest = supertest(`http://127.0.0.1:${proxyConfig.port}`); + }); + + afterEach(async () => { + await proxyServerWithoutShouldRedirect.stop(); + }); + + test('it will do a redirect if it detects what looks like a stale or previously used base path', async () => { + const fakeBasePath = basePath !== 'abc' ? 'abc' : 'efg'; + const res = await proxySupertest.get(`/${fakeBasePath}`).expect(302); + const location = res.header.location; + expect(location).toEqual(`${basePath}/`); + }); + + test('it will NOT do a redirect if it detects what looks like a stale or previously used base path if we intentionally turn it off', async () => { + const fakeBasePath = basePath !== 'abc' ? 'abc' : 'efg'; + await proxyWithoutShouldRedirectSupertest.get(`/${fakeBasePath}`).expect(404); + }); + + test('it will NOT redirect if it detects a larger path than 3 characters', async () => { + await proxySupertest.get('/abcde').expect(404); + }); + + test('it will NOT redirect if it is not a GET verb', async () => { + const fakeBasePath = basePath !== 'abc' ? 'abc' : 'efg'; + await proxySupertest.put(`/${fakeBasePath}`).expect(404); + }); + }); + + describe('constructor option for sending in a custom basePath', () => { + let proxyServerWithFooBasePath: BasePathProxyServer; + let proxyWithFooBasePath: supertest.SuperTest; + + beforeEach(async () => { + // setup and start a proxy server which uses a basePath of "foo" + const proxyConfig = { ...config, port: 10004, basePath: '/foo' }; // <-- "foo" here in basePath + const devConfig = new DevConfig({ basePathProxyTarget: config.port }); + proxyServerWithFooBasePath = new BasePathProxyServer(logger, proxyConfig, devConfig); + const options: Readonly = { + shouldRedirectFromOldBasePath: () => true, + delayUntil: () => EMPTY, + }; + await proxyServerWithFooBasePath.start(options); + proxyWithFooBasePath = supertest(`http://127.0.0.1:${proxyConfig.port}`); + }); + + afterEach(async () => { + await proxyServerWithFooBasePath.stop(); + }); + + test('it will do a redirect to foo which is our passed in value for the configuration', async () => { + const res = await proxyWithFooBasePath.get('/bar').expect(302); + const location = res.header.location; + expect(location).toEqual('/foo/'); + }); + }); +}); diff --git a/src/core/server/http/base_path_proxy_server.ts b/packages/kbn-cli-dev-mode/src/base_path_proxy_server.ts similarity index 90% rename from src/core/server/http/base_path_proxy_server.ts rename to packages/kbn-cli-dev-mode/src/base_path_proxy_server.ts index a5ed0271893937..40841c8327cc29 100644 --- a/src/core/server/http/base_path_proxy_server.ts +++ b/packages/kbn-cli-dev-mode/src/base_path_proxy_server.ts @@ -8,21 +8,21 @@ import Url from 'url'; import { Agent as HttpsAgent, ServerOptions as TlsOptions } from 'https'; - import apm from 'elastic-apm-node'; -import { ByteSizeValue } from '@kbn/config-schema'; import { Server, Request } from '@hapi/hapi'; import HapiProxy from '@hapi/h2o2'; import { sampleSize } from 'lodash'; import * as Rx from 'rxjs'; import { take } from 'rxjs/operators'; +import { ByteSizeValue } from '@kbn/config-schema'; +import { createServer, getListenerOptions, getServerOptions } from '@kbn/server-http-tools'; -import { DevConfig } from '../dev'; -import { Logger } from '../logging'; -import { HttpConfig } from './http_config'; -import { createServer, getListenerOptions, getServerOptions } from './http_tools'; +import { DevConfig, HttpConfig } from './config'; +import { Log } from './log'; +const ONE_GIGABYTE = 1024 * 1024 * 1024; const alphabet = 'abcdefghijklmnopqrztuvwxyz'.split(''); +const getRandomBasePath = () => sampleSize(alphabet, 3).join(''); export interface BasePathProxyServerOptions { shouldRedirectFromOldBasePath: (path: string) => boolean; @@ -30,9 +30,22 @@ export interface BasePathProxyServerOptions { } export class BasePathProxyServer { + private readonly httpConfig: HttpConfig; private server?: Server; private httpsAgent?: HttpsAgent; + constructor( + private readonly log: Log, + httpConfig: HttpConfig, + private readonly devConfig: DevConfig + ) { + this.httpConfig = { + ...httpConfig, + maxPayload: new ByteSizeValue(ONE_GIGABYTE), + basePath: httpConfig.basePath ?? `/${getRandomBasePath()}`, + }; + } + public get basePath() { return this.httpConfig.basePath; } @@ -49,21 +62,8 @@ export class BasePathProxyServer { return this.httpConfig.port; } - constructor( - private readonly log: Logger, - private readonly httpConfig: HttpConfig, - private readonly devConfig: DevConfig - ) { - const ONE_GIGABYTE = 1024 * 1024 * 1024; - httpConfig.maxPayload = new ByteSizeValue(ONE_GIGABYTE); - - if (!httpConfig.basePath) { - httpConfig.basePath = `/${sampleSize(alphabet, 3).join('')}`; - } - } - - public async start(options: Readonly) { - this.log.debug('starting basepath proxy server'); + public async start(options: BasePathProxyServerOptions) { + this.log.write('starting basepath proxy server'); const serverOptions = getServerOptions(this.httpConfig); const listenerOptions = getListenerOptions(this.httpConfig); @@ -88,7 +88,7 @@ export class BasePathProxyServer { await this.server.start(); - this.log.info( + this.log.write( `basepath proxy server running at ${Url.format({ host: this.server.info.uri, pathname: this.httpConfig.basePath, @@ -101,7 +101,7 @@ export class BasePathProxyServer { return; } - this.log.debug('stopping basepath proxy server'); + this.log.write('stopping basepath proxy server'); await this.server.stop(); this.server = undefined; diff --git a/packages/kbn-cli-dev-mode/src/bootstrap.ts b/packages/kbn-cli-dev-mode/src/bootstrap.ts new file mode 100644 index 00000000000000..86a276c64f1f55 --- /dev/null +++ b/packages/kbn-cli-dev-mode/src/bootstrap.ts @@ -0,0 +1,43 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { REPO_ROOT } from '@kbn/utils'; +import { CliArgs, Env, RawConfigAdapter } from '@kbn/config'; +import { CliDevMode } from './cli_dev_mode'; +import { CliLog } from './log'; +import { convertToLogger } from './log_adapter'; +import { loadConfig } from './config'; + +interface BootstrapArgs { + configs: string[]; + cliArgs: CliArgs; + applyConfigOverrides: RawConfigAdapter; +} + +export async function bootstrapDevMode({ configs, cliArgs, applyConfigOverrides }: BootstrapArgs) { + const log = new CliLog(!!cliArgs.quiet, !!cliArgs.silent); + + const env = Env.createDefault(REPO_ROOT, { + configs, + cliArgs, + }); + + const config = await loadConfig({ + env, + logger: convertToLogger(log), + rawConfigAdapter: applyConfigOverrides, + }); + + const cliDevMode = new CliDevMode({ + cliArgs, + config, + log, + }); + + await cliDevMode.start(); +} diff --git a/src/dev/cli_dev_mode/cli_dev_mode.test.ts b/packages/kbn-cli-dev-mode/src/cli_dev_mode.test.ts similarity index 79% rename from src/dev/cli_dev_mode/cli_dev_mode.test.ts rename to packages/kbn-cli-dev-mode/src/cli_dev_mode.test.ts index 9ace543a8929bf..d5bafe7280bd92 100644 --- a/src/dev/cli_dev_mode/cli_dev_mode.test.ts +++ b/packages/kbn-cli-dev-mode/src/cli_dev_mode.test.ts @@ -7,16 +7,16 @@ */ import Path from 'path'; - +import * as Rx from 'rxjs'; import { REPO_ROOT, createAbsolutePathSerializer, createAnyInstanceSerializer, } from '@kbn/dev-utils'; -import * as Rx from 'rxjs'; import { TestLog } from './log'; -import { CliDevMode } from './cli_dev_mode'; +import { CliDevMode, SomeCliArgs } from './cli_dev_mode'; +import type { CliDevConfig } from './config'; expect.addSnapshotSerializer(createAbsolutePathSerializer()); expect.addSnapshotSerializer(createAnyInstanceSerializer(Rx.Observable, 'Rx.Observable')); @@ -31,6 +31,9 @@ const { Optimizer } = jest.requireMock('./optimizer'); jest.mock('./dev_server'); const { DevServer } = jest.requireMock('./dev_server'); +jest.mock('./base_path_proxy_server'); +const { BasePathProxyServer } = jest.requireMock('./base_path_proxy_server'); + jest.mock('@kbn/dev-utils/target/ci_stats_reporter'); const { CiStatsReporter } = jest.requireMock('@kbn/dev-utils/target/ci_stats_reporter'); @@ -41,13 +44,6 @@ jest.mock('./get_server_watch_paths', () => ({ })), })); -beforeEach(() => { - process.argv = ['node', './script', 'foo', 'bar', 'baz']; - jest.clearAllMocks(); -}); - -const log = new TestLog(); - const mockBasePathProxy = { targetPort: 9999, basePath: '/foo/bar', @@ -55,26 +51,53 @@ const mockBasePathProxy = { stop: jest.fn(), }; -const defaultOptions = { +let log: TestLog; + +beforeEach(() => { + process.argv = ['node', './script', 'foo', 'bar', 'baz']; + log = new TestLog(); + BasePathProxyServer.mockImplementation(() => mockBasePathProxy); +}); + +afterEach(() => { + jest.clearAllMocks(); + mockBasePathProxy.start.mockReset(); + mockBasePathProxy.stop.mockReset(); +}); + +const createCliArgs = (parts: Partial = {}): SomeCliArgs => ({ + basePath: false, cache: true, disableOptimizer: false, dist: true, oss: true, - pluginPaths: [], - pluginScanDirs: [Path.resolve(REPO_ROOT, 'src/plugins')], - quiet: false, - silent: false, runExamples: false, watch: true, - log, -}; + silent: false, + quiet: false, + ...parts, +}); -afterEach(() => { - log.messages.length = 0; +const createDevConfig = (parts: Partial = {}): CliDevConfig => ({ + plugins: { + pluginSearchPaths: [Path.resolve(REPO_ROOT, 'src/plugins')], + additionalPluginPaths: [], + }, + dev: { + basePathProxyTargetPort: 9000, + }, + http: {} as any, + ...parts, +}); + +const createOptions = ({ cliArgs = {} }: { cliArgs?: Partial } = {}) => ({ + cliArgs: createCliArgs(cliArgs), + config: createDevConfig(), + log, }); it('passes correct args to sub-classes', () => { - new CliDevMode(defaultOptions); + new CliDevMode(createOptions()); expect(DevServer.mock.calls).toMatchInlineSnapshot(` Array [ @@ -105,6 +128,9 @@ it('passes correct args to sub-classes', () => { "enabled": true, "oss": true, "pluginPaths": Array [], + "pluginScanDirs": Array [ + /src/plugins, + ], "quiet": false, "repoRoot": , "runExamples": false, @@ -131,33 +157,38 @@ it('passes correct args to sub-classes', () => { ], ] `); + + expect(BasePathProxyServer).not.toHaveBeenCalled(); + expect(log.messages).toMatchInlineSnapshot(`Array []`); }); it('disables the optimizer', () => { - new CliDevMode({ - ...defaultOptions, - disableOptimizer: true, - }); + new CliDevMode(createOptions({ cliArgs: { disableOptimizer: true } })); expect(Optimizer.mock.calls[0][0]).toHaveProperty('enabled', false); }); it('disables the watcher', () => { - new CliDevMode({ - ...defaultOptions, - watch: false, - }); + new CliDevMode(createOptions({ cliArgs: { watch: false } })); expect(Optimizer.mock.calls[0][0]).toHaveProperty('watch', false); expect(Watcher.mock.calls[0][0]).toHaveProperty('enabled', false); }); -it('overrides the basePath of the server when basePathProxy is defined', () => { - new CliDevMode({ - ...defaultOptions, - basePathProxy: mockBasePathProxy as any, - }); +it('enables the basePath proxy', () => { + new CliDevMode(createOptions({ cliArgs: { basePath: true } })); + + expect(BasePathProxyServer).toHaveBeenCalledTimes(1); + expect(BasePathProxyServer.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + , + Object {}, + Object { + "basePathProxyTargetPort": 9000, + }, + ] + `); expect(DevServer.mock.calls[0][0].argv).toMatchInlineSnapshot(` Array [ @@ -229,9 +260,7 @@ describe('#start()/#stop()', () => { }); it('logs a warning if basePathProxy is not passed', () => { - new CliDevMode({ - ...defaultOptions, - }).start(); + new CliDevMode(createOptions()).start(); expect(log.messages).toMatchInlineSnapshot(` Array [ @@ -261,16 +290,9 @@ describe('#start()/#stop()', () => { }); it('calls start on BasePathProxy if enabled', () => { - const basePathProxy: any = { - start: jest.fn(), - }; + new CliDevMode(createOptions({ cliArgs: { basePath: true } })).start(); - new CliDevMode({ - ...defaultOptions, - basePathProxy, - }).start(); - - expect(basePathProxy.start.mock.calls).toMatchInlineSnapshot(` + expect(mockBasePathProxy.start.mock.calls).toMatchInlineSnapshot(` Array [ Array [ Object { @@ -283,7 +305,7 @@ describe('#start()/#stop()', () => { }); it('subscribes to Optimizer#run$, Watcher#run$, and DevServer#run$', () => { - new CliDevMode(defaultOptions).start(); + new CliDevMode(createOptions()).start(); expect(optimizerRun$.observers).toHaveLength(1); expect(watcherRun$.observers).toHaveLength(1); @@ -291,10 +313,7 @@ describe('#start()/#stop()', () => { }); it('logs an error and exits the process if Optimizer#run$ errors', () => { - new CliDevMode({ - ...defaultOptions, - basePathProxy: mockBasePathProxy as any, - }).start(); + new CliDevMode(createOptions({ cliArgs: { basePath: true } })).start(); expect(processExitMock).not.toHaveBeenCalled(); optimizerRun$.error({ stack: 'Error: foo bar' }); @@ -319,10 +338,7 @@ describe('#start()/#stop()', () => { }); it('logs an error and exits the process if Watcher#run$ errors', () => { - new CliDevMode({ - ...defaultOptions, - basePathProxy: mockBasePathProxy as any, - }).start(); + new CliDevMode(createOptions({ cliArgs: { basePath: true } })).start(); expect(processExitMock).not.toHaveBeenCalled(); watcherRun$.error({ stack: 'Error: foo bar' }); @@ -347,10 +363,7 @@ describe('#start()/#stop()', () => { }); it('logs an error and exits the process if DevServer#run$ errors', () => { - new CliDevMode({ - ...defaultOptions, - basePathProxy: mockBasePathProxy as any, - }).start(); + new CliDevMode(createOptions({ cliArgs: { basePath: true } })).start(); expect(processExitMock).not.toHaveBeenCalled(); devServerRun$.error({ stack: 'Error: foo bar' }); @@ -376,10 +389,7 @@ describe('#start()/#stop()', () => { it('throws if start() has already been called', () => { expect(() => { - const devMode = new CliDevMode({ - ...defaultOptions, - basePathProxy: mockBasePathProxy as any, - }); + const devMode = new CliDevMode(createOptions({ cliArgs: { basePath: true } })); devMode.start(); devMode.start(); @@ -387,10 +397,7 @@ describe('#start()/#stop()', () => { }); it('unsubscribes from all observables and stops basePathProxy when stopped', () => { - const devMode = new CliDevMode({ - ...defaultOptions, - basePathProxy: mockBasePathProxy as any, - }); + const devMode = new CliDevMode(createOptions({ cliArgs: { basePath: true } })); devMode.start(); devMode.stop(); diff --git a/src/dev/cli_dev_mode/cli_dev_mode.ts b/packages/kbn-cli-dev-mode/src/cli_dev_mode.ts similarity index 83% rename from src/dev/cli_dev_mode/cli_dev_mode.ts rename to packages/kbn-cli-dev-mode/src/cli_dev_mode.ts index f4f95f20daeef3..94dbcb9654e8ae 100644 --- a/src/dev/cli_dev_mode/cli_dev_mode.ts +++ b/packages/kbn-cli-dev-mode/src/cli_dev_mode.ts @@ -7,8 +7,6 @@ */ import Path from 'path'; - -import { REPO_ROOT, CiStatsReporter } from '@kbn/dev-utils'; import * as Rx from 'rxjs'; import { map, @@ -20,24 +18,32 @@ import { switchMap, concatMap, } from 'rxjs/operators'; - -import { CliArgs } from '../../core/server/config'; -import { LegacyConfig } from '../../core/server/legacy'; -import { BasePathProxyServer } from '../../core/server/http'; +import { CliArgs } from '@kbn/config'; +import { REPO_ROOT, CiStatsReporter } from '@kbn/dev-utils'; import { Log, CliLog } from './log'; import { Optimizer } from './optimizer'; import { DevServer } from './dev_server'; import { Watcher } from './watcher'; +import { BasePathProxyServer } from './base_path_proxy_server'; import { shouldRedirectFromOldBasePath } from './should_redirect_from_old_base_path'; import { getServerWatchPaths } from './get_server_watch_paths'; +import { CliDevConfig } from './config'; // timeout where the server is allowed to exit gracefully const GRACEFUL_TIMEOUT = 5000; export type SomeCliArgs = Pick< CliArgs, - 'quiet' | 'silent' | 'disableOptimizer' | 'watch' | 'oss' | 'runExamples' | 'cache' | 'dist' + | 'quiet' + | 'silent' + | 'disableOptimizer' + | 'watch' + | 'oss' + | 'runExamples' + | 'cache' + | 'dist' + | 'basePath' >; export interface CliDevModeOptions { @@ -76,49 +82,28 @@ const firstAllTrue = (...sources: Array>) => * */ export class CliDevMode { - static fromCoreServices( - cliArgs: SomeCliArgs, - config: LegacyConfig, - basePathProxy?: BasePathProxyServer - ) { - new CliDevMode({ - quiet: !!cliArgs.quiet, - silent: !!cliArgs.silent, - cache: !!cliArgs.cache, - disableOptimizer: !!cliArgs.disableOptimizer, - dist: !!cliArgs.dist, - oss: !!cliArgs.oss, - runExamples: !!cliArgs.runExamples, - pluginPaths: config.get('plugins.paths'), - pluginScanDirs: config.get('plugins.scanDirs'), - watch: !!cliArgs.watch, - basePathProxy, - }).start(); - } private readonly log: Log; private readonly basePathProxy?: BasePathProxyServer; private readonly watcher: Watcher; private readonly devServer: DevServer; private readonly optimizer: Optimizer; private startTime?: number; - private subscription?: Rx.Subscription; - constructor(options: CliDevModeOptions) { - this.basePathProxy = options.basePathProxy; - this.log = options.log || new CliLog(!!options.quiet, !!options.silent); + constructor({ cliArgs, config, log }: { cliArgs: SomeCliArgs; config: CliDevConfig; log?: Log }) { + this.log = log || new CliLog(!!cliArgs.quiet, !!cliArgs.silent); + + if (cliArgs.basePath) { + this.basePathProxy = new BasePathProxyServer(this.log, config.http, config.dev); + } const { watchPaths, ignorePaths } = getServerWatchPaths({ - pluginPaths: options.pluginPaths ?? [], - pluginScanDirs: [ - ...(options.pluginScanDirs ?? []), - Path.resolve(REPO_ROOT, 'src/plugins'), - Path.resolve(REPO_ROOT, 'x-pack/plugins'), - ], + pluginPaths: config.plugins.additionalPluginPaths, + pluginScanDirs: config.plugins.pluginSearchPaths, }); this.watcher = new Watcher({ - enabled: !!options.watch, + enabled: !!cliArgs.watch, log: this.log, cwd: REPO_ROOT, paths: watchPaths, @@ -133,10 +118,10 @@ export class CliDevMode { script: Path.resolve(REPO_ROOT, 'scripts/kibana'), argv: [ ...process.argv.slice(2).filter((v) => v !== '--no-watch'), - ...(options.basePathProxy + ...(this.basePathProxy ? [ - `--server.port=${options.basePathProxy.targetPort}`, - `--server.basePath=${options.basePathProxy.basePath}`, + `--server.port=${this.basePathProxy.targetPort}`, + `--server.basePath=${this.basePathProxy.basePath}`, '--server.rewriteBasePath=true', ] : []), @@ -153,16 +138,17 @@ export class CliDevMode { }); this.optimizer = new Optimizer({ - enabled: !options.disableOptimizer, + enabled: !cliArgs.disableOptimizer, repoRoot: REPO_ROOT, - oss: options.oss, - pluginPaths: options.pluginPaths, - runExamples: options.runExamples, - cache: options.cache, - dist: options.dist, - quiet: options.quiet, - silent: options.silent, - watch: options.watch, + oss: cliArgs.oss, + pluginPaths: config.plugins.additionalPluginPaths, + pluginScanDirs: config.plugins.pluginSearchPaths, + runExamples: cliArgs.runExamples, + cache: cliArgs.cache, + dist: cliArgs.dist, + quiet: !!cliArgs.quiet, + silent: !!cliArgs.silent, + watch: cliArgs.watch, }); } diff --git a/packages/kbn-cli-dev-mode/src/config/dev_config.ts b/packages/kbn-cli-dev-mode/src/config/dev_config.ts new file mode 100644 index 00000000000000..ddb54bb8f3f7c9 --- /dev/null +++ b/packages/kbn-cli-dev-mode/src/config/dev_config.ts @@ -0,0 +1,28 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { schema, TypeOf } from '@kbn/config-schema'; + +export const devConfigSchema = schema.object( + { + basePathProxyTarget: schema.number({ + defaultValue: 5603, + }), + }, + { unknowns: 'ignore' } +); + +export type DevConfigType = TypeOf; + +export class DevConfig { + public basePathProxyTargetPort: number; + + constructor(rawConfig: DevConfigType) { + this.basePathProxyTargetPort = rawConfig.basePathProxyTarget; + } +} diff --git a/packages/kbn-cli-dev-mode/src/config/http_config.ts b/packages/kbn-cli-dev-mode/src/config/http_config.ts new file mode 100644 index 00000000000000..34f208c28df680 --- /dev/null +++ b/packages/kbn-cli-dev-mode/src/config/http_config.ts @@ -0,0 +1,65 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ByteSizeValue, schema, TypeOf } from '@kbn/config-schema'; +import { ICorsConfig, IHttpConfig, ISslConfig, SslConfig, sslSchema } from '@kbn/server-http-tools'; + +export const httpConfigSchema = schema.object( + { + host: schema.string({ + defaultValue: 'localhost', + hostname: true, + }), + basePath: schema.maybe(schema.string()), + port: schema.number({ + defaultValue: 5601, + }), + maxPayload: schema.byteSize({ + defaultValue: '1048576b', + }), + keepaliveTimeout: schema.number({ + defaultValue: 120000, + }), + socketTimeout: schema.number({ + defaultValue: 120000, + }), + cors: schema.object({ + enabled: schema.boolean({ defaultValue: false }), + allowCredentials: schema.boolean({ defaultValue: false }), + allowOrigin: schema.arrayOf(schema.string(), { + defaultValue: ['*'], + }), + }), + ssl: sslSchema, + }, + { unknowns: 'ignore' } +); + +export type HttpConfigType = TypeOf; + +export class HttpConfig implements IHttpConfig { + basePath?: string; + host: string; + port: number; + maxPayload: ByteSizeValue; + keepaliveTimeout: number; + socketTimeout: number; + cors: ICorsConfig; + ssl: ISslConfig; + + constructor(rawConfig: HttpConfigType) { + this.basePath = rawConfig.basePath; + this.host = rawConfig.host; + this.port = rawConfig.port; + this.maxPayload = rawConfig.maxPayload; + this.keepaliveTimeout = rawConfig.keepaliveTimeout; + this.socketTimeout = rawConfig.socketTimeout; + this.cors = rawConfig.cors; + this.ssl = new SslConfig(rawConfig.ssl); + } +} diff --git a/packages/kbn-cli-dev-mode/src/config/index.ts b/packages/kbn-cli-dev-mode/src/config/index.ts new file mode 100644 index 00000000000000..89f6d647ef4f51 --- /dev/null +++ b/packages/kbn-cli-dev-mode/src/config/index.ts @@ -0,0 +1,13 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export type { DevConfig } from './dev_config'; +export type { PluginsConfig } from './plugins_config'; +export type { HttpConfig } from './http_config'; +export type { CliDevConfig } from './types'; +export { loadConfig } from './load_config'; diff --git a/packages/kbn-cli-dev-mode/src/config/load_config.ts b/packages/kbn-cli-dev-mode/src/config/load_config.ts new file mode 100644 index 00000000000000..46129834ca2d9e --- /dev/null +++ b/packages/kbn-cli-dev-mode/src/config/load_config.ts @@ -0,0 +1,44 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Env, RawConfigService, ConfigService, RawConfigAdapter } from '@kbn/config'; +import { Logger } from '@kbn/logging'; +import { devConfigSchema, DevConfig, DevConfigType } from './dev_config'; +import { httpConfigSchema, HttpConfig, HttpConfigType } from './http_config'; +import { pluginsConfigSchema, PluginsConfig, PluginsConfigType } from './plugins_config'; +import { CliDevConfig } from './types'; + +export const loadConfig = async ({ + env, + logger, + rawConfigAdapter, +}: { + env: Env; + logger: Logger; + rawConfigAdapter: RawConfigAdapter; +}): Promise => { + const rawConfigService = new RawConfigService(env.configs, rawConfigAdapter); + rawConfigService.loadConfig(); + + const configService = new ConfigService(rawConfigService, env, logger); + configService.setSchema('dev', devConfigSchema); + configService.setSchema('plugins', pluginsConfigSchema); + configService.setSchema('http', httpConfigSchema); + + await configService.validate(); + + const devConfig = configService.atPathSync('dev'); + const pluginsConfig = configService.atPathSync('plugins'); + const httpConfig = configService.atPathSync('http'); + + return { + dev: new DevConfig(devConfig), + plugins: new PluginsConfig(pluginsConfig, env), + http: new HttpConfig(httpConfig), + }; +}; diff --git a/packages/kbn-cli-dev-mode/src/config/plugins_config.ts b/packages/kbn-cli-dev-mode/src/config/plugins_config.ts new file mode 100644 index 00000000000000..7c7fa8902edb3b --- /dev/null +++ b/packages/kbn-cli-dev-mode/src/config/plugins_config.ts @@ -0,0 +1,37 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { schema, TypeOf } from '@kbn/config-schema'; +import { Env } from '@kbn/config'; + +export const pluginsConfigSchema = schema.object( + { + paths: schema.arrayOf(schema.string(), { defaultValue: [] }), + }, + { unknowns: 'ignore' } +); + +export type PluginsConfigType = TypeOf; + +/** @internal */ +export class PluginsConfig { + /** + * Defines directories that we should scan for the plugin subdirectories. + */ + public readonly pluginSearchPaths: string[]; + + /** + * Defines directories where an additional plugin exists. + */ + public readonly additionalPluginPaths: string[]; + + constructor(rawConfig: PluginsConfigType, env: Env) { + this.pluginSearchPaths = [...env.pluginSearchPaths]; + this.additionalPluginPaths = rawConfig.paths; + } +} diff --git a/packages/kbn-cli-dev-mode/src/config/types.ts b/packages/kbn-cli-dev-mode/src/config/types.ts new file mode 100644 index 00000000000000..017442e09bd0df --- /dev/null +++ b/packages/kbn-cli-dev-mode/src/config/types.ts @@ -0,0 +1,17 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { DevConfig } from './dev_config'; +import type { HttpConfig } from './http_config'; +import type { PluginsConfig } from './plugins_config'; + +export interface CliDevConfig { + dev: DevConfig; + http: HttpConfig; + plugins: PluginsConfig; +} diff --git a/src/dev/cli_dev_mode/dev_server.test.ts b/packages/kbn-cli-dev-mode/src/dev_server.test.ts similarity index 100% rename from src/dev/cli_dev_mode/dev_server.test.ts rename to packages/kbn-cli-dev-mode/src/dev_server.test.ts diff --git a/src/dev/cli_dev_mode/dev_server.ts b/packages/kbn-cli-dev-mode/src/dev_server.ts similarity index 100% rename from src/dev/cli_dev_mode/dev_server.ts rename to packages/kbn-cli-dev-mode/src/dev_server.ts diff --git a/src/dev/cli_dev_mode/get_active_inspect_flag.ts b/packages/kbn-cli-dev-mode/src/get_active_inspect_flag.ts similarity index 100% rename from src/dev/cli_dev_mode/get_active_inspect_flag.ts rename to packages/kbn-cli-dev-mode/src/get_active_inspect_flag.ts diff --git a/src/dev/cli_dev_mode/get_server_watch_paths.test.ts b/packages/kbn-cli-dev-mode/src/get_server_watch_paths.test.ts similarity index 100% rename from src/dev/cli_dev_mode/get_server_watch_paths.test.ts rename to packages/kbn-cli-dev-mode/src/get_server_watch_paths.test.ts diff --git a/src/dev/cli_dev_mode/get_server_watch_paths.ts b/packages/kbn-cli-dev-mode/src/get_server_watch_paths.ts similarity index 87% rename from src/dev/cli_dev_mode/get_server_watch_paths.ts rename to packages/kbn-cli-dev-mode/src/get_server_watch_paths.ts index 46aa15659a5139..53aa53b5aa63a5 100644 --- a/src/dev/cli_dev_mode/get_server_watch_paths.ts +++ b/packages/kbn-cli-dev-mode/src/get_server_watch_paths.ts @@ -47,15 +47,7 @@ export function getServerWatchPaths({ pluginPaths, pluginScanDirs }: Options) { ...pluginScanDirs, ].map((path) => Path.resolve(path)) ) - ); - - for (const watchPath of watchPaths) { - if (!Fs.existsSync(fromRoot(watchPath))) { - throw new Error( - `A watch directory [${watchPath}] does not exist, which will cause chokidar to fail. Either make sure the directory exists or remove it as a watch source in the ClusterManger` - ); - } - } + ).filter((path) => Fs.existsSync(fromRoot(path))); const ignorePaths = [ /[\\\/](\..*|node_modules|bower_components|target|public|__[a-z0-9_]+__|coverage)([\\\/]|$)/, diff --git a/src/dev/cli_dev_mode/index.ts b/packages/kbn-cli-dev-mode/src/index.ts similarity index 86% rename from src/dev/cli_dev_mode/index.ts rename to packages/kbn-cli-dev-mode/src/index.ts index db46957504b112..98b52087f231a3 100644 --- a/src/dev/cli_dev_mode/index.ts +++ b/packages/kbn-cli-dev-mode/src/index.ts @@ -6,5 +6,4 @@ * Side Public License, v 1. */ -export * from './cli_dev_mode'; -export * from './log'; +export { bootstrapDevMode } from './bootstrap'; diff --git a/src/dev/cli_dev_mode/log.ts b/packages/kbn-cli-dev-mode/src/log.ts similarity index 100% rename from src/dev/cli_dev_mode/log.ts rename to packages/kbn-cli-dev-mode/src/log.ts diff --git a/packages/kbn-cli-dev-mode/src/log_adapter.ts b/packages/kbn-cli-dev-mode/src/log_adapter.ts new file mode 100644 index 00000000000000..65161fcc56e0e6 --- /dev/null +++ b/packages/kbn-cli-dev-mode/src/log_adapter.ts @@ -0,0 +1,28 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Logger } from '@kbn/logging'; +import { Log } from './log'; + +export const convertToLogger = (cliLog: Log): Logger => { + const getErrorMessage = (msgOrError: string | Error): string => { + return typeof msgOrError === 'string' ? msgOrError : msgOrError.message; + }; + + const adapter: Logger = { + trace: (message) => cliLog.write(message), + debug: (message) => cliLog.write(message), + info: (message) => cliLog.write(message), + warn: (msgOrError) => cliLog.warn('warning', getErrorMessage(msgOrError)), + error: (msgOrError) => cliLog.bad('error', getErrorMessage(msgOrError)), + fatal: (msgOrError) => cliLog.bad('fatal', getErrorMessage(msgOrError)), + log: (record) => cliLog.write(record.message), + get: () => adapter, + }; + return adapter; +}; diff --git a/src/dev/cli_dev_mode/optimizer.test.ts b/packages/kbn-cli-dev-mode/src/optimizer.test.ts similarity index 96% rename from src/dev/cli_dev_mode/optimizer.test.ts rename to packages/kbn-cli-dev-mode/src/optimizer.test.ts index 409ad1a455a57b..c270a00329897a 100644 --- a/src/dev/cli_dev_mode/optimizer.test.ts +++ b/packages/kbn-cli-dev-mode/src/optimizer.test.ts @@ -43,6 +43,7 @@ const defaultOptions: Options = { dist: true, oss: true, pluginPaths: ['/some/dir'], + pluginScanDirs: ['/some-scan-path'], quiet: true, silent: true, repoRoot: '/app', @@ -83,6 +84,7 @@ it('uses options to create valid OptimizerConfig', () => { runExamples: false, oss: false, pluginPaths: [], + pluginScanDirs: [], repoRoot: '/foo/bar', watch: false, }); @@ -99,6 +101,9 @@ it('uses options to create valid OptimizerConfig', () => { "pluginPaths": Array [ "/some/dir", ], + "pluginScanDirs": Array [ + "/some-scan-path", + ], "repoRoot": "/app", "watch": true, }, @@ -111,6 +116,7 @@ it('uses options to create valid OptimizerConfig', () => { "includeCoreBundle": true, "oss": false, "pluginPaths": Array [], + "pluginScanDirs": Array [], "repoRoot": "/foo/bar", "watch": false, }, diff --git a/src/dev/cli_dev_mode/optimizer.ts b/packages/kbn-cli-dev-mode/src/optimizer.ts similarity index 97% rename from src/dev/cli_dev_mode/optimizer.ts rename to packages/kbn-cli-dev-mode/src/optimizer.ts index 771da21e6151b8..5e2f16fcf7daa8 100644 --- a/src/dev/cli_dev_mode/optimizer.ts +++ b/packages/kbn-cli-dev-mode/src/optimizer.ts @@ -31,6 +31,7 @@ export interface Options { oss: boolean; runExamples: boolean; pluginPaths: string[]; + pluginScanDirs: string[]; writeLogTo?: Writable; } @@ -56,6 +57,7 @@ export class Optimizer { oss: options.oss, examples: options.runExamples, pluginPaths: options.pluginPaths, + pluginScanDirs: options.pluginScanDirs, }); const dim = Chalk.dim('np bld'); diff --git a/src/dev/cli_dev_mode/should_redirect_from_old_base_path.test.ts b/packages/kbn-cli-dev-mode/src/should_redirect_from_old_base_path.test.ts similarity index 100% rename from src/dev/cli_dev_mode/should_redirect_from_old_base_path.test.ts rename to packages/kbn-cli-dev-mode/src/should_redirect_from_old_base_path.test.ts diff --git a/src/dev/cli_dev_mode/should_redirect_from_old_base_path.ts b/packages/kbn-cli-dev-mode/src/should_redirect_from_old_base_path.ts similarity index 100% rename from src/dev/cli_dev_mode/should_redirect_from_old_base_path.ts rename to packages/kbn-cli-dev-mode/src/should_redirect_from_old_base_path.ts diff --git a/src/dev/cli_dev_mode/test_helpers.ts b/packages/kbn-cli-dev-mode/src/test_helpers.ts similarity index 100% rename from src/dev/cli_dev_mode/test_helpers.ts rename to packages/kbn-cli-dev-mode/src/test_helpers.ts diff --git a/src/dev/cli_dev_mode/using_server_process.ts b/packages/kbn-cli-dev-mode/src/using_server_process.ts similarity index 100% rename from src/dev/cli_dev_mode/using_server_process.ts rename to packages/kbn-cli-dev-mode/src/using_server_process.ts diff --git a/src/dev/cli_dev_mode/watcher.test.ts b/packages/kbn-cli-dev-mode/src/watcher.test.ts similarity index 100% rename from src/dev/cli_dev_mode/watcher.test.ts rename to packages/kbn-cli-dev-mode/src/watcher.test.ts diff --git a/src/dev/cli_dev_mode/watcher.ts b/packages/kbn-cli-dev-mode/src/watcher.ts similarity index 100% rename from src/dev/cli_dev_mode/watcher.ts rename to packages/kbn-cli-dev-mode/src/watcher.ts diff --git a/packages/kbn-cli-dev-mode/tsconfig.json b/packages/kbn-cli-dev-mode/tsconfig.json new file mode 100644 index 00000000000000..b2bdaf8ceea36e --- /dev/null +++ b/packages/kbn-cli-dev-mode/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "declaration": true, + "outDir": "./target", + "declarationMap": true, + "types": ["jest", "node"] + }, + "include": ["./src/**/*.ts"], + "exclude": ["target"] +} diff --git a/packages/kbn-config/src/__mocks__/env.ts b/packages/kbn-config/src/__mocks__/env.ts index e3b3106933f1e9..6f05f8f1f5a45a 100644 --- a/packages/kbn-config/src/__mocks__/env.ts +++ b/packages/kbn-config/src/__mocks__/env.ts @@ -30,6 +30,5 @@ export function getEnvOptions(options: DeepPartial = {}): EnvOptions runExamples: false, ...(options.cliArgs || {}), }, - isDevCliParent: options.isDevCliParent !== undefined ? options.isDevCliParent : false, }; } diff --git a/packages/kbn-config/src/__snapshots__/env.test.ts.snap b/packages/kbn-config/src/__snapshots__/env.test.ts.snap index fae14529a4af3d..570ed948774cc1 100644 --- a/packages/kbn-config/src/__snapshots__/env.test.ts.snap +++ b/packages/kbn-config/src/__snapshots__/env.test.ts.snap @@ -21,7 +21,6 @@ Env { "/some/other/path/some-kibana.yml", ], "homeDir": "/test/kibanaRoot", - "isDevCliParent": false, "logDir": "/test/kibanaRoot/log", "mode": Object { "dev": true, @@ -65,7 +64,6 @@ Env { "/some/other/path/some-kibana.yml", ], "homeDir": "/test/kibanaRoot", - "isDevCliParent": false, "logDir": "/test/kibanaRoot/log", "mode": Object { "dev": false, @@ -108,7 +106,6 @@ Env { "/test/cwd/config/kibana.yml", ], "homeDir": "/test/kibanaRoot", - "isDevCliParent": true, "logDir": "/test/kibanaRoot/log", "mode": Object { "dev": true, @@ -151,7 +148,6 @@ Env { "/some/other/path/some-kibana.yml", ], "homeDir": "/test/kibanaRoot", - "isDevCliParent": false, "logDir": "/test/kibanaRoot/log", "mode": Object { "dev": false, @@ -194,7 +190,6 @@ Env { "/some/other/path/some-kibana.yml", ], "homeDir": "/test/kibanaRoot", - "isDevCliParent": false, "logDir": "/test/kibanaRoot/log", "mode": Object { "dev": false, @@ -237,7 +232,6 @@ Env { "/some/other/path/some-kibana.yml", ], "homeDir": "/some/home/dir", - "isDevCliParent": false, "logDir": "/some/home/dir/log", "mode": Object { "dev": false, diff --git a/packages/kbn-config/src/env.test.ts b/packages/kbn-config/src/env.test.ts index 09d44f31cf8d55..b9e97514c2dffb 100644 --- a/packages/kbn-config/src/env.test.ts +++ b/packages/kbn-config/src/env.test.ts @@ -36,7 +36,6 @@ test('correctly creates default environment in dev mode.', () => { REPO_ROOT, getEnvOptions({ configs: ['/test/cwd/config/kibana.yml'], - isDevCliParent: true, }) ); diff --git a/packages/kbn-config/src/env.ts b/packages/kbn-config/src/env.ts index b6ff5e3b5aab22..c4845ab429c573 100644 --- a/packages/kbn-config/src/env.ts +++ b/packages/kbn-config/src/env.ts @@ -15,7 +15,6 @@ import { PackageInfo, EnvironmentMode } from './types'; export interface EnvOptions { configs: string[]; cliArgs: CliArgs; - isDevCliParent: boolean; } /** @internal */ @@ -89,12 +88,6 @@ export class Env { */ public readonly configs: readonly string[]; - /** - * Indicates that this Kibana instance is running in the parent process of the dev cli. - * @internal - */ - public readonly isDevCliParent: boolean; - /** * @internal */ @@ -111,7 +104,6 @@ export class Env { this.cliArgs = Object.freeze(options.cliArgs); this.configs = Object.freeze(options.configs); - this.isDevCliParent = options.isDevCliParent; const isDevMode = this.cliArgs.dev || this.cliArgs.envName === 'development'; this.mode = Object.freeze({ diff --git a/packages/kbn-config/src/index.ts b/packages/kbn-config/src/index.ts index 24f271c979f321..8b0bdb0befbfdb 100644 --- a/packages/kbn-config/src/index.ts +++ b/packages/kbn-config/src/index.ts @@ -16,7 +16,12 @@ export { ConfigDeprecationWithContext, } from './deprecation'; -export { RawConfigurationProvider, RawConfigService, getConfigFromFiles } from './raw'; +export { + RawConfigurationProvider, + RawConfigService, + RawConfigAdapter, + getConfigFromFiles, +} from './raw'; export { ConfigService, IConfigService } from './config_service'; export { Config, ConfigPath, isConfigPath, hasConfigPathIntersection } from './config'; diff --git a/packages/kbn-config/src/raw/index.ts b/packages/kbn-config/src/raw/index.ts index 8f65e7877ba56f..01ad83728aa085 100644 --- a/packages/kbn-config/src/raw/index.ts +++ b/packages/kbn-config/src/raw/index.ts @@ -6,5 +6,5 @@ * Side Public License, v 1. */ -export { RawConfigService, RawConfigurationProvider } from './raw_config_service'; +export { RawConfigService, RawConfigurationProvider, RawConfigAdapter } from './raw_config_service'; export { getConfigFromFiles } from './read_config'; diff --git a/packages/kbn-config/src/raw/raw_config_service.ts b/packages/kbn-config/src/raw/raw_config_service.ts index af901f2b3d28e3..cce1132bebdb0e 100644 --- a/packages/kbn-config/src/raw/raw_config_service.ts +++ b/packages/kbn-config/src/raw/raw_config_service.ts @@ -13,7 +13,7 @@ import typeDetect from 'type-detect'; import { getConfigFromFiles } from './read_config'; -type RawConfigAdapter = (rawConfig: Record) => Record; +export type RawConfigAdapter = (rawConfig: Record) => Record; export type RawConfigurationProvider = Pick; diff --git a/packages/kbn-crypto/README.md b/packages/kbn-crypto/README.md new file mode 100644 index 00000000000000..4404c22eba37c5 --- /dev/null +++ b/packages/kbn-crypto/README.md @@ -0,0 +1,3 @@ +# @kbn/crypto + +Crypto tools and utilities for Kibana \ No newline at end of file diff --git a/packages/kbn-crypto/jest.config.js b/packages/kbn-crypto/jest.config.js new file mode 100644 index 00000000000000..811b87e5ed0f6e --- /dev/null +++ b/packages/kbn-crypto/jest.config.js @@ -0,0 +1,13 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../..', + roots: ['/packages/kbn-crypto'], +}; diff --git a/packages/kbn-crypto/package.json b/packages/kbn-crypto/package.json new file mode 100644 index 00000000000000..6c7b3f3b0c719b --- /dev/null +++ b/packages/kbn-crypto/package.json @@ -0,0 +1,16 @@ +{ + "name": "@kbn/crypto", + "version": "1.0.0", + "private": true, + "license": "SSPL-1.0 OR Elastic License 2.0", + "main": "./target/index.js", + "scripts": { + "build": "../../node_modules/.bin/tsc", + "kbn:bootstrap": "yarn build", + "kbn:watch": "yarn build --watch" + }, + "dependencies": {}, + "devDependencies": { + "@kbn/dev-utils": "link:../kbn-dev-utils" + } +} \ No newline at end of file diff --git a/src/core/server/utils/crypto/__fixtures__/README.md b/packages/kbn-crypto/src/__fixtures__/README.md similarity index 100% rename from src/core/server/utils/crypto/__fixtures__/README.md rename to packages/kbn-crypto/src/__fixtures__/README.md diff --git a/src/core/server/utils/crypto/__fixtures__/index.ts b/packages/kbn-crypto/src/__fixtures__/index.ts similarity index 100% rename from src/core/server/utils/crypto/__fixtures__/index.ts rename to packages/kbn-crypto/src/__fixtures__/index.ts diff --git a/src/core/server/utils/crypto/__fixtures__/no_ca.p12 b/packages/kbn-crypto/src/__fixtures__/no_ca.p12 similarity index 100% rename from src/core/server/utils/crypto/__fixtures__/no_ca.p12 rename to packages/kbn-crypto/src/__fixtures__/no_ca.p12 diff --git a/src/core/server/utils/crypto/__fixtures__/no_cert.p12 b/packages/kbn-crypto/src/__fixtures__/no_cert.p12 similarity index 100% rename from src/core/server/utils/crypto/__fixtures__/no_cert.p12 rename to packages/kbn-crypto/src/__fixtures__/no_cert.p12 diff --git a/src/core/server/utils/crypto/__fixtures__/no_key.p12 b/packages/kbn-crypto/src/__fixtures__/no_key.p12 similarity index 100% rename from src/core/server/utils/crypto/__fixtures__/no_key.p12 rename to packages/kbn-crypto/src/__fixtures__/no_key.p12 diff --git a/src/core/server/utils/crypto/__fixtures__/two_cas.p12 b/packages/kbn-crypto/src/__fixtures__/two_cas.p12 similarity index 100% rename from src/core/server/utils/crypto/__fixtures__/two_cas.p12 rename to packages/kbn-crypto/src/__fixtures__/two_cas.p12 diff --git a/src/core/server/utils/crypto/__fixtures__/two_keys.p12 b/packages/kbn-crypto/src/__fixtures__/two_keys.p12 similarity index 100% rename from src/core/server/utils/crypto/__fixtures__/two_keys.p12 rename to packages/kbn-crypto/src/__fixtures__/two_keys.p12 diff --git a/src/core/server/utils/crypto/index.ts b/packages/kbn-crypto/src/index.ts similarity index 100% rename from src/core/server/utils/crypto/index.ts rename to packages/kbn-crypto/src/index.ts diff --git a/src/core/server/utils/crypto/pkcs12.test.ts b/packages/kbn-crypto/src/pkcs12.test.ts similarity index 99% rename from src/core/server/utils/crypto/pkcs12.test.ts rename to packages/kbn-crypto/src/pkcs12.test.ts index 8c6e5bae3b9c1e..ba8eb6554f7b8b 100644 --- a/src/core/server/utils/crypto/pkcs12.test.ts +++ b/packages/kbn-crypto/src/pkcs12.test.ts @@ -18,7 +18,7 @@ import { import { NO_CA_PATH, NO_CERT_PATH, NO_KEY_PATH, TWO_CAS_PATH, TWO_KEYS_PATH } from './__fixtures__'; import { readFileSync } from 'fs'; -import { readPkcs12Keystore, Pkcs12ReadResult, readPkcs12Truststore } from './index'; +import { readPkcs12Keystore, Pkcs12ReadResult, readPkcs12Truststore } from './pkcs12'; const reformatPem = (pem: string) => { // ensure consistency in line endings when comparing two PEM files diff --git a/src/core/server/utils/crypto/pkcs12.ts b/packages/kbn-crypto/src/pkcs12.ts similarity index 100% rename from src/core/server/utils/crypto/pkcs12.ts rename to packages/kbn-crypto/src/pkcs12.ts diff --git a/src/core/server/utils/crypto/sha256.test.ts b/packages/kbn-crypto/src/sha256.test.ts similarity index 100% rename from src/core/server/utils/crypto/sha256.test.ts rename to packages/kbn-crypto/src/sha256.test.ts diff --git a/src/core/server/utils/crypto/sha256.ts b/packages/kbn-crypto/src/sha256.ts similarity index 100% rename from src/core/server/utils/crypto/sha256.ts rename to packages/kbn-crypto/src/sha256.ts diff --git a/packages/kbn-crypto/tsconfig.json b/packages/kbn-crypto/tsconfig.json new file mode 100644 index 00000000000000..e9dd6313e6f79e --- /dev/null +++ b/packages/kbn-crypto/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target", + "declaration": true, + "declarationMap": true + }, + "include": [ + "src/**/*" + ] +} diff --git a/packages/kbn-server-http-tools/README.md b/packages/kbn-server-http-tools/README.md new file mode 100644 index 00000000000000..c53b7b85354383 --- /dev/null +++ b/packages/kbn-server-http-tools/README.md @@ -0,0 +1,3 @@ +# @kbn/http-tools + +Http utilities for core and the basepath server \ No newline at end of file diff --git a/packages/kbn-server-http-tools/jest.config.js b/packages/kbn-server-http-tools/jest.config.js new file mode 100644 index 00000000000000..e409c235546227 --- /dev/null +++ b/packages/kbn-server-http-tools/jest.config.js @@ -0,0 +1,13 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../..', + roots: ['/packages/kbn-server-http-tools'], +}; diff --git a/packages/kbn-server-http-tools/package.json b/packages/kbn-server-http-tools/package.json new file mode 100644 index 00000000000000..a8f99689f33354 --- /dev/null +++ b/packages/kbn-server-http-tools/package.json @@ -0,0 +1,20 @@ +{ + "name": "@kbn/server-http-tools", + "main": "./target/index.js", + "version": "1.0.0", + "license": "SSPL-1.0 OR Elastic License 2.0", + "private": true, + "scripts": { + "build": "rm -rf target && ../../node_modules/.bin/tsc", + "kbn:bootstrap": "yarn build", + "kbn:watch": "yarn build --watch" + }, + "dependencies": { + "@kbn/config-schema": "link:../kbn-config-schema", + "@kbn/crypto": "link:../kbn-crypto", + "@kbn/std": "link:../kbn-std" + }, + "devDependencies": { + "@kbn/utility-types": "link:../kbn-utility-types" + } +} \ No newline at end of file diff --git a/packages/kbn-server-http-tools/src/create_server.ts b/packages/kbn-server-http-tools/src/create_server.ts new file mode 100644 index 00000000000000..4752e342d5d3e3 --- /dev/null +++ b/packages/kbn-server-http-tools/src/create_server.ts @@ -0,0 +1,29 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Server, ServerOptions } from '@hapi/hapi'; +import { ListenerOptions } from './get_listener_options'; + +export function createServer(serverOptions: ServerOptions, listenerOptions: ListenerOptions) { + const server = new Server(serverOptions); + + server.listener.keepAliveTimeout = listenerOptions.keepaliveTimeout; + server.listener.setTimeout(listenerOptions.socketTimeout); + server.listener.on('timeout', (socket) => { + socket.destroy(); + }); + server.listener.on('clientError', (err, socket) => { + if (socket.writable) { + socket.end(Buffer.from('HTTP/1.1 400 Bad Request\r\n\r\n', 'ascii')); + } else { + socket.destroy(err); + } + }); + + return server; +} diff --git a/packages/kbn-server-http-tools/src/default_validation_error_handler.test.ts b/packages/kbn-server-http-tools/src/default_validation_error_handler.test.ts new file mode 100644 index 00000000000000..93b09ef13e0307 --- /dev/null +++ b/packages/kbn-server-http-tools/src/default_validation_error_handler.test.ts @@ -0,0 +1,51 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import Joi from 'joi'; +import { Request, ResponseToolkit } from '@hapi/hapi'; +import { + defaultValidationErrorHandler, + HapiValidationError, +} from './default_validation_error_handler'; + +const emptyOutput = { + statusCode: 400, + headers: {}, + payload: { + statusCode: 400, + error: '', + validation: { + source: '', + keys: [], + }, + }, +}; + +describe('defaultValidationErrorHandler', () => { + it('formats value validation errors correctly', () => { + expect.assertions(1); + const schema = Joi.array().items( + Joi.object({ + type: Joi.string().required(), + }).required() + ); + + const error = schema.validate([{}], { abortEarly: false }).error as HapiValidationError; + + // Emulate what Hapi v17 does by default + error.output = { ...emptyOutput }; + error.output.payload.validation.keys = ['0.type', '']; + + try { + defaultValidationErrorHandler({} as Request, {} as ResponseToolkit, error); + } catch (err) { + // Verify the empty string gets corrected to 'value' + expect(err.output.payload.validation.keys).toEqual(['0.type', 'value']); + } + }); +}); diff --git a/packages/kbn-server-http-tools/src/default_validation_error_handler.ts b/packages/kbn-server-http-tools/src/default_validation_error_handler.ts new file mode 100644 index 00000000000000..d2f4e993f3e4b2 --- /dev/null +++ b/packages/kbn-server-http-tools/src/default_validation_error_handler.ts @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Lifecycle, Request, ResponseToolkit, Util } from '@hapi/hapi'; +import { ValidationError } from 'joi'; +import Hoek from '@hapi/hoek'; + +/** + * Hapi extends the ValidationError interface to add this output key with more data. + */ +export interface HapiValidationError extends ValidationError { + output: { + statusCode: number; + headers: Util.Dictionary; + payload: { + statusCode: number; + error: string; + message?: string; + validation: { + source: string; + keys: string[]; + }; + }; + }; +} + +/** + * Used to replicate Hapi v16 and below's validation responses. Should be used in the routes.validate.failAction key. + */ +export function defaultValidationErrorHandler( + request: Request, + h: ResponseToolkit, + err?: Error +): Lifecycle.ReturnValue { + // Newer versions of Joi don't format the key for missing params the same way. This shim + // provides backwards compatibility. Unfortunately, Joi doesn't export it's own Error class + // in JS so we have to rely on the `name` key before we can cast it. + // + // The Hapi code we're 'overwriting' can be found here: + // https://github.com/hapijs/hapi/blob/master/lib/validation.js#L102 + if (err && err.name === 'ValidationError' && err.hasOwnProperty('output')) { + const validationError: HapiValidationError = err as HapiValidationError; + const validationKeys: string[] = []; + + validationError.details.forEach((detail) => { + if (detail.path.length > 0) { + validationKeys.push(Hoek.escapeHtml(detail.path.join('.'))); + } else { + // If no path, use the value sigil to signal the entire value had an issue. + validationKeys.push('value'); + } + }); + + validationError.output.payload.validation.keys = validationKeys; + } + + throw err; +} diff --git a/packages/kbn-server-http-tools/src/get_listener_options.ts b/packages/kbn-server-http-tools/src/get_listener_options.ts new file mode 100644 index 00000000000000..00884312b599fb --- /dev/null +++ b/packages/kbn-server-http-tools/src/get_listener_options.ts @@ -0,0 +1,21 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { IHttpConfig } from './types'; + +export interface ListenerOptions { + keepaliveTimeout: number; + socketTimeout: number; +} + +export function getListenerOptions(config: IHttpConfig): ListenerOptions { + return { + keepaliveTimeout: config.keepaliveTimeout, + socketTimeout: config.socketTimeout, + }; +} diff --git a/packages/kbn-server-http-tools/src/get_request_id.test.ts b/packages/kbn-server-http-tools/src/get_request_id.test.ts new file mode 100644 index 00000000000000..1b098ed4842d30 --- /dev/null +++ b/packages/kbn-server-http-tools/src/get_request_id.test.ts @@ -0,0 +1,85 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { getRequestId } from './get_request_id'; + +jest.mock('uuid', () => ({ + v4: jest.fn().mockReturnValue('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'), +})); + +describe('getRequestId', () => { + describe('when allowFromAnyIp is true', () => { + it('generates a UUID if no x-opaque-id header is present', () => { + const request = { + headers: {}, + raw: { req: { socket: { remoteAddress: '1.1.1.1' } } }, + } as any; + expect(getRequestId(request, { allowFromAnyIp: true, ipAllowlist: [] })).toEqual( + 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' + ); + }); + + it('uses x-opaque-id header value if present', () => { + const request = { + headers: { + 'x-opaque-id': 'id from header', + }, + raw: { req: { socket: { remoteAddress: '1.1.1.1' } } }, + } as any; + expect(getRequestId(request, { allowFromAnyIp: true, ipAllowlist: [] })).toEqual( + 'id from header' + ); + }); + }); + + describe('when allowFromAnyIp is false', () => { + describe('and ipAllowlist is empty', () => { + it('generates a UUID even if x-opaque-id header is present', () => { + const request = { + headers: { 'x-opaque-id': 'id from header' }, + raw: { req: { socket: { remoteAddress: '1.1.1.1' } } }, + } as any; + expect(getRequestId(request, { allowFromAnyIp: false, ipAllowlist: [] })).toEqual( + 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' + ); + }); + }); + + describe('and ipAllowlist is not empty', () => { + it('uses x-opaque-id header if request comes from trusted IP address', () => { + const request = { + headers: { 'x-opaque-id': 'id from header' }, + raw: { req: { socket: { remoteAddress: '1.1.1.1' } } }, + } as any; + expect(getRequestId(request, { allowFromAnyIp: false, ipAllowlist: ['1.1.1.1'] })).toEqual( + 'id from header' + ); + }); + + it('generates a UUID if request comes from untrusted IP address', () => { + const request = { + headers: { 'x-opaque-id': 'id from header' }, + raw: { req: { socket: { remoteAddress: '5.5.5.5' } } }, + } as any; + expect(getRequestId(request, { allowFromAnyIp: false, ipAllowlist: ['1.1.1.1'] })).toEqual( + 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' + ); + }); + + it('generates UUID if request comes from trusted IP address but no x-opaque-id header is present', () => { + const request = { + headers: {}, + raw: { req: { socket: { remoteAddress: '1.1.1.1' } } }, + } as any; + expect(getRequestId(request, { allowFromAnyIp: false, ipAllowlist: ['1.1.1.1'] })).toEqual( + 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' + ); + }); + }); + }); +}); diff --git a/packages/kbn-server-http-tools/src/get_request_id.ts b/packages/kbn-server-http-tools/src/get_request_id.ts new file mode 100644 index 00000000000000..3af70ecc3a7a32 --- /dev/null +++ b/packages/kbn-server-http-tools/src/get_request_id.ts @@ -0,0 +1,22 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Request } from '@hapi/hapi'; +import uuid from 'uuid'; + +export function getRequestId( + request: Request, + { allowFromAnyIp, ipAllowlist }: { allowFromAnyIp: boolean; ipAllowlist: string[] } +): string { + const remoteAddress = request.raw.req.socket?.remoteAddress; + return allowFromAnyIp || + // socket may be undefined in integration tests that connect via the http listener directly + (remoteAddress && ipAllowlist.includes(remoteAddress)) + ? request.headers['x-opaque-id'] ?? uuid.v4() + : uuid.v4(); +} diff --git a/packages/kbn-server-http-tools/src/get_server_options.test.ts b/packages/kbn-server-http-tools/src/get_server_options.test.ts new file mode 100644 index 00000000000000..fdcc749f4ae9a1 --- /dev/null +++ b/packages/kbn-server-http-tools/src/get_server_options.test.ts @@ -0,0 +1,122 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ByteSizeValue } from '@kbn/config-schema'; +import { getServerOptions } from './get_server_options'; +import { IHttpConfig } from './types'; + +jest.mock('fs', () => { + const original = jest.requireActual('fs'); + return { + // Hapi Inert patches native methods + ...original, + readFileSync: jest.fn(), + }; +}); + +const createConfig = (parts: Partial): IHttpConfig => ({ + host: 'localhost', + port: 5601, + socketTimeout: 120000, + keepaliveTimeout: 120000, + maxPayload: ByteSizeValue.parse('1048576b'), + ...parts, + cors: { + enabled: false, + allowCredentials: false, + allowOrigin: ['*'], + ...parts.cors, + }, + ssl: { + enabled: false, + ...parts.ssl, + }, +}); + +describe('getServerOptions', () => { + beforeEach(() => + jest.requireMock('fs').readFileSync.mockImplementation((path: string) => `content-${path}`) + ); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('properly configures TLS with default options', () => { + const httpConfig = createConfig({ + ssl: { + enabled: true, + key: 'some-key-path', + certificate: 'some-certificate-path', + }, + }); + + expect(getServerOptions(httpConfig).tls).toMatchInlineSnapshot(` + Object { + "ca": undefined, + "cert": "some-certificate-path", + "ciphers": undefined, + "honorCipherOrder": true, + "key": "some-key-path", + "passphrase": undefined, + "rejectUnauthorized": undefined, + "requestCert": undefined, + "secureOptions": undefined, + } + `); + }); + + it('properly configures TLS with client authentication', () => { + const httpConfig = createConfig({ + ssl: { + enabled: true, + key: 'some-key-path', + certificate: 'some-certificate-path', + certificateAuthorities: ['ca-1', 'ca-2'], + cipherSuites: ['suite-a', 'suite-b'], + keyPassphrase: 'passPhrase', + rejectUnauthorized: true, + requestCert: true, + getSecureOptions: () => 42, + }, + }); + + expect(getServerOptions(httpConfig).tls).toMatchInlineSnapshot(` + Object { + "ca": Array [ + "ca-1", + "ca-2", + ], + "cert": "some-certificate-path", + "ciphers": "suite-a:suite-b", + "honorCipherOrder": true, + "key": "some-key-path", + "passphrase": "passPhrase", + "rejectUnauthorized": true, + "requestCert": true, + "secureOptions": 42, + } + `); + }); + + it('properly configures CORS when cors enabled', () => { + const httpConfig = createConfig({ + cors: { + enabled: true, + allowCredentials: false, + allowOrigin: ['*'], + }, + }); + + expect(getServerOptions(httpConfig).routes?.cors).toEqual({ + credentials: false, + origin: ['*'], + headers: ['Accept', 'Authorization', 'Content-Type', 'If-None-Match', 'kbn-xsrf'], + }); + }); +}); diff --git a/packages/kbn-server-http-tools/src/get_server_options.ts b/packages/kbn-server-http-tools/src/get_server_options.ts new file mode 100644 index 00000000000000..ade90a0e0d3f5d --- /dev/null +++ b/packages/kbn-server-http-tools/src/get_server_options.ts @@ -0,0 +1,75 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { RouteOptionsCors, ServerOptions } from '@hapi/hapi'; +import { ServerOptions as TLSOptions } from 'https'; +import { defaultValidationErrorHandler } from './default_validation_error_handler'; +import { IHttpConfig } from './types'; + +const corsAllowedHeaders = ['Accept', 'Authorization', 'Content-Type', 'If-None-Match', 'kbn-xsrf']; + +/** + * Converts Kibana `HttpConfig` into `ServerOptions` that are accepted by the Hapi server. + */ +export function getServerOptions(config: IHttpConfig, { configureTLS = true } = {}) { + const cors: RouteOptionsCors | false = config.cors.enabled + ? { + credentials: config.cors.allowCredentials, + origin: config.cors.allowOrigin, + headers: corsAllowedHeaders, + } + : false; + const options: ServerOptions = { + host: config.host, + port: config.port, + routes: { + cache: { + privacy: 'private', + otherwise: 'private, no-cache, no-store, must-revalidate', + }, + cors, + payload: { + maxBytes: config.maxPayload.getValueInBytes(), + }, + validate: { + failAction: defaultValidationErrorHandler, + options: { + abortEarly: false, + }, + }, + }, + state: { + strictHeader: false, + isHttpOnly: true, + isSameSite: false, // necessary to allow using Kibana inside an iframe + }, + }; + + if (configureTLS && config.ssl.enabled) { + const ssl = config.ssl; + + // TODO: Hapi types have a typo in `tls` property type definition: `https.RequestOptions` is used instead of + // `https.ServerOptions`, and `honorCipherOrder` isn't presented in `https.RequestOptions`. + const tlsOptions: TLSOptions = { + ca: ssl.certificateAuthorities, + cert: ssl.certificate, + ciphers: config.ssl.cipherSuites?.join(':'), + // We use the server's cipher order rather than the client's to prevent the BEAST attack. + honorCipherOrder: true, + key: ssl.key, + passphrase: ssl.keyPassphrase, + secureOptions: ssl.getSecureOptions ? ssl.getSecureOptions() : undefined, + requestCert: ssl.requestCert, + rejectUnauthorized: ssl.rejectUnauthorized, + }; + + options.tls = tlsOptions; + } + + return options; +} diff --git a/packages/kbn-server-http-tools/src/index.ts b/packages/kbn-server-http-tools/src/index.ts new file mode 100644 index 00000000000000..bd1dffa0bb0cab --- /dev/null +++ b/packages/kbn-server-http-tools/src/index.ts @@ -0,0 +1,15 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export type { IHttpConfig, ISslConfig, ICorsConfig } from './types'; +export { createServer } from './create_server'; +export { defaultValidationErrorHandler } from './default_validation_error_handler'; +export { getListenerOptions } from './get_listener_options'; +export { getServerOptions } from './get_server_options'; +export { getRequestId } from './get_request_id'; +export { sslSchema, SslConfig } from './ssl'; diff --git a/src/core/server/legacy/cli_dev_mode.js b/packages/kbn-server-http-tools/src/ssl/index.ts similarity index 86% rename from src/core/server/legacy/cli_dev_mode.js rename to packages/kbn-server-http-tools/src/ssl/index.ts index 3c4bdb4149780a..cbc3f17f915efd 100644 --- a/src/core/server/legacy/cli_dev_mode.js +++ b/packages/kbn-server-http-tools/src/ssl/index.ts @@ -6,4 +6,4 @@ * Side Public License, v 1. */ -export { CliDevMode } from '../../../dev/cli_dev_mode'; +export { SslConfig, sslSchema } from './ssl_config'; diff --git a/src/core/server/http/ssl_config.test.mocks.ts b/packages/kbn-server-http-tools/src/ssl/ssl_config.test.mocks.ts similarity index 95% rename from src/core/server/http/ssl_config.test.mocks.ts rename to packages/kbn-server-http-tools/src/ssl/ssl_config.test.mocks.ts index 81dbcf55100f87..adc4adb76f8047 100644 --- a/src/core/server/http/ssl_config.test.mocks.ts +++ b/packages/kbn-server-http-tools/src/ssl/ssl_config.test.mocks.ts @@ -13,7 +13,7 @@ jest.mock('fs', () => { export const mockReadPkcs12Keystore = jest.fn(); export const mockReadPkcs12Truststore = jest.fn(); -jest.mock('../utils', () => ({ +jest.mock('@kbn/crypto', () => ({ readPkcs12Keystore: mockReadPkcs12Keystore, readPkcs12Truststore: mockReadPkcs12Truststore, })); diff --git a/src/core/server/http/ssl_config.test.ts b/packages/kbn-server-http-tools/src/ssl/ssl_config.test.ts similarity index 99% rename from src/core/server/http/ssl_config.test.ts rename to packages/kbn-server-http-tools/src/ssl/ssl_config.test.ts index bb6b1c7ff29f3e..112fcd8a449f75 100644 --- a/src/core/server/http/ssl_config.test.ts +++ b/packages/kbn-server-http-tools/src/ssl/ssl_config.test.ts @@ -34,7 +34,7 @@ describe('#SslConfig', () => { beforeEach(() => { const realFs = jest.requireActual('fs'); mockReadFileSync.mockImplementation((path: string) => realFs.readFileSync(path)); - const utils = jest.requireActual('../utils'); + const utils = jest.requireActual('@kbn/crypto'); mockReadPkcs12Keystore.mockImplementation((path: string, password?: string) => utils.readPkcs12Keystore(path, password) ); diff --git a/src/core/server/http/ssl_config.ts b/packages/kbn-server-http-tools/src/ssl/ssl_config.ts similarity index 93% rename from src/core/server/http/ssl_config.ts rename to packages/kbn-server-http-tools/src/ssl/ssl_config.ts index 917d416a775639..53d3616a09a75e 100644 --- a/src/core/server/http/ssl_config.ts +++ b/packages/kbn-server-http-tools/src/ssl/ssl_config.ts @@ -7,9 +7,9 @@ */ import { schema, TypeOf } from '@kbn/config-schema'; +import { readPkcs12Keystore, readPkcs12Truststore } from '@kbn/crypto'; import { constants as cryptoConstants } from 'crypto'; import { readFileSync } from 'fs'; -import { readPkcs12Keystore, readPkcs12Truststore } from '../utils'; const protocolMap = new Map([ ['TLSv1', cryptoConstants.SSL_OP_NO_TLSv1], @@ -81,14 +81,13 @@ type SslConfigType = TypeOf; export class SslConfig { public enabled: boolean; - public redirectHttpFromPort: number | undefined; - public key: string | undefined; - public certificate: string | undefined; - public certificateAuthorities: string[] | undefined; - public keyPassphrase: string | undefined; + public redirectHttpFromPort?: number; + public key?: string; + public certificate?: string; + public certificateAuthorities?: string[]; + public keyPassphrase?: string; public requestCert: boolean; public rejectUnauthorized: boolean; - public cipherSuites: string[]; public supportedProtocols: string[]; @@ -164,6 +163,4 @@ export class SslConfig { } } -const readFile = (file: string) => { - return readFileSync(file, 'utf8'); -}; +const readFile = (file: string) => readFileSync(file, 'utf8'); diff --git a/packages/kbn-server-http-tools/src/types.ts b/packages/kbn-server-http-tools/src/types.ts new file mode 100644 index 00000000000000..3cc117d542eeec --- /dev/null +++ b/packages/kbn-server-http-tools/src/types.ts @@ -0,0 +1,37 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ByteSizeValue } from '@kbn/config-schema'; + +export interface IHttpConfig { + host: string; + port: number; + maxPayload: ByteSizeValue; + keepaliveTimeout: number; + socketTimeout: number; + cors: ICorsConfig; + ssl: ISslConfig; +} + +export interface ICorsConfig { + enabled: boolean; + allowCredentials: boolean; + allowOrigin: string[]; +} + +export interface ISslConfig { + enabled: boolean; + key?: string; + certificate?: string; + certificateAuthorities?: string[]; + cipherSuites?: string[]; + keyPassphrase?: string; + requestCert?: boolean; + rejectUnauthorized?: boolean; + getSecureOptions?: () => number; +} diff --git a/packages/kbn-server-http-tools/tsconfig.json b/packages/kbn-server-http-tools/tsconfig.json new file mode 100644 index 00000000000000..ec84b963aed700 --- /dev/null +++ b/packages/kbn-server-http-tools/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target", + "declaration": true, + "declarationMap": true + }, + "include": [ + "src/**/*" + ], + "dependencies": { + "@kbn/std": "link:../kbn-std" + } +} diff --git a/packages/kbn-utils/src/repo_root.ts b/packages/kbn-utils/src/repo_root.ts index 20a25023f41660..2c1617098fe20f 100644 --- a/packages/kbn-utils/src/repo_root.ts +++ b/packages/kbn-utils/src/repo_root.ts @@ -57,3 +57,5 @@ const { kibanaDir, kibanaPkgJson } = findKibanaPackageJson(); export const REPO_ROOT = kibanaDir; export const UPSTREAM_BRANCH = kibanaPkgJson.branch; + +export const fromRoot = (...paths: string[]) => Path.resolve(REPO_ROOT, ...paths); diff --git a/src/cli/serve/serve.js b/src/cli/serve/serve.js index 34b78bbd7e51e8..86b4ac53841f71 100644 --- a/src/cli/serve/serve.js +++ b/src/cli/serve/serve.js @@ -12,10 +12,8 @@ import { statSync } from 'fs'; import { resolve } from 'path'; import url from 'url'; -import { getConfigPath } from '@kbn/utils'; +import { getConfigPath, fromRoot } from '@kbn/utils'; import { IS_KIBANA_DISTRIBUTABLE } from '../../legacy/utils'; -import { fromRoot } from '../../core/server/utils'; -import { bootstrap } from '../../core/server'; import { readKeystore } from '../keystore/read_keystore'; function canRequire(path) { @@ -31,9 +29,21 @@ function canRequire(path) { } } -const DEV_MODE_PATH = resolve(__dirname, '../../dev/cli_dev_mode'); +const DEV_MODE_PATH = '@kbn/cli-dev-mode'; const DEV_MODE_SUPPORTED = canRequire(DEV_MODE_PATH); +const getBootstrapScript = (isDev) => { + if (DEV_MODE_SUPPORTED && isDev && process.env.isDevCliChild !== 'true') { + // need dynamic require to exclude it from production build + // eslint-disable-next-line import/no-dynamic-require + const { bootstrapDevMode } = require(DEV_MODE_PATH); + return bootstrapDevMode; + } else { + const { bootstrap } = require('../../core/server'); + return bootstrap; + } +}; + const pathCollector = function () { const paths = []; return function (path) { @@ -79,6 +89,7 @@ function applyConfigOverrides(rawConfig, opts, extraCliOptions) { throw new Error(`Can't use --ssl when "${path}" configuration is already defined.`); } } + ensureNotDefined('server.ssl.certificate'); ensureNotDefined('server.ssl.key'); ensureNotDefined('server.ssl.keystore.path'); @@ -210,31 +221,40 @@ export default function (program) { } const unknownOptions = this.getUnknownOptions(); - await bootstrap({ - configs: [].concat(opts.config || []), - cliArgs: { - dev: !!opts.dev, - envName: unknownOptions.env ? unknownOptions.env.name : undefined, - // no longer supported - quiet: !!opts.quiet, - silent: !!opts.silent, - watch: !!opts.watch, - runExamples: !!opts.runExamples, - // We want to run without base path when the `--run-examples` flag is given so that we can use local - // links in other documentation sources, like "View this tutorial [here](http://localhost:5601/app/tutorial/xyz)". - // We can tell users they only have to run with `yarn start --run-examples` to get those - // local links to work. Similar to what we do for "View in Console" links in our - // elastic.co links. - basePath: opts.runExamples ? false : !!opts.basePath, - optimize: !!opts.optimize, - disableOptimizer: !opts.optimizer, - oss: !!opts.oss, - cache: !!opts.cache, - dist: !!opts.dist, - }, - features: { - isCliDevModeSupported: DEV_MODE_SUPPORTED, - }, + const configs = [].concat(opts.config || []); + const cliArgs = { + dev: !!opts.dev, + envName: unknownOptions.env ? unknownOptions.env.name : undefined, + // no longer supported + quiet: !!opts.quiet, + silent: !!opts.silent, + watch: !!opts.watch, + runExamples: !!opts.runExamples, + // We want to run without base path when the `--run-examples` flag is given so that we can use local + // links in other documentation sources, like "View this tutorial [here](http://localhost:5601/app/tutorial/xyz)". + // We can tell users they only have to run with `yarn start --run-examples` to get those + // local links to work. Similar to what we do for "View in Console" links in our + // elastic.co links. + basePath: opts.runExamples ? false : !!opts.basePath, + optimize: !!opts.optimize, + disableOptimizer: !opts.optimizer, + oss: !!opts.oss, + cache: !!opts.cache, + dist: !!opts.dist, + }; + + // In development mode, the main process uses the @kbn/dev-cli-mode + // bootstrap script instead of core's. The DevCliMode instance + // is in charge of starting up the optimizer, and spawning another + // `/script/kibana` process with the `isDevCliChild` varenv set to true. + // This variable is then used to identify that we're the 'real' + // Kibana server process, and will be using core's bootstrap script + // to effectively start Kibana. + const bootstrapScript = getBootstrapScript(cliArgs.dev); + + await bootstrapScript({ + configs, + cliArgs, applyConfigOverrides: (rawConfig) => applyConfigOverrides(rawConfig, opts, unknownOptions), }); }); diff --git a/src/core/server/bootstrap.ts b/src/core/server/bootstrap.ts index 42f6d9aedf1d69..4a07e0c010685a 100644 --- a/src/core/server/bootstrap.ts +++ b/src/core/server/bootstrap.ts @@ -11,18 +11,10 @@ import { CliArgs, Env, RawConfigService } from './config'; import { Root } from './root'; import { CriticalError } from './errors'; -interface KibanaFeatures { - // Indicates whether we can run Kibana in dev mode in which Kibana is run as - // a child process together with optimizer "worker" processes that are - // orchestrated by a parent process (dev mode only feature). - isCliDevModeSupported: boolean; -} - interface BootstrapArgs { configs: string[]; cliArgs: CliArgs; applyConfigOverrides: (config: Record) => Record; - features: KibanaFeatures; } /** @@ -30,12 +22,7 @@ interface BootstrapArgs { * @internal * @param param0 - options */ -export async function bootstrap({ - configs, - cliArgs, - applyConfigOverrides, - features, -}: BootstrapArgs) { +export async function bootstrap({ configs, cliArgs, applyConfigOverrides }: BootstrapArgs) { if (cliArgs.optimize) { // --optimize is deprecated and does nothing now, avoid starting up and just shutdown return; @@ -52,7 +39,6 @@ export async function bootstrap({ const env = Env.createDefault(REPO_ROOT, { configs, cliArgs, - isDevCliParent: cliArgs.dev && features.isCliDevModeSupported && !process.env.isDevCliChild, }); const rawConfigService = new RawConfigService(env.configs, applyConfigOverrides); diff --git a/src/core/server/dev/dev_config.ts b/src/core/server/dev/dev_config.ts index 3a303a61c85637..2fec778d857137 100644 --- a/src/core/server/dev/dev_config.ts +++ b/src/core/server/dev/dev_config.ts @@ -6,26 +6,11 @@ * Side Public License, v 1. */ -import { schema, TypeOf } from '@kbn/config-schema'; +import { schema } from '@kbn/config-schema'; export const config = { path: 'dev', - schema: schema.object({ - basePathProxyTarget: schema.number({ - defaultValue: 5603, - }), - }), + // dev configuration is validated by the dev cli. + // we only need to register the `dev` schema to avoid failing core's config validation + schema: schema.object({}, { unknowns: 'ignore' }), }; - -export type DevConfigType = TypeOf; - -export class DevConfig { - public basePathProxyTargetPort: number; - - /** - * @internal - */ - constructor(rawConfig: DevConfigType) { - this.basePathProxyTargetPort = rawConfig.basePathProxyTarget; - } -} diff --git a/src/core/server/dev/index.ts b/src/core/server/dev/index.ts index 6e0fd343d2ec84..70257d2a5e6c51 100644 --- a/src/core/server/dev/index.ts +++ b/src/core/server/dev/index.ts @@ -6,5 +6,4 @@ * Side Public License, v 1. */ -export { config, DevConfig } from './dev_config'; -export type { DevConfigType } from './dev_config'; +export { config } from './dev_config'; diff --git a/src/core/server/elasticsearch/elasticsearch_config.test.mocks.ts b/src/core/server/elasticsearch/elasticsearch_config.test.mocks.ts index 32602849d2e450..63b2233b06a967 100644 --- a/src/core/server/elasticsearch/elasticsearch_config.test.mocks.ts +++ b/src/core/server/elasticsearch/elasticsearch_config.test.mocks.ts @@ -11,7 +11,7 @@ jest.mock('fs', () => ({ readFileSync: mockReadFileSync })); export const mockReadPkcs12Keystore = jest.fn(); export const mockReadPkcs12Truststore = jest.fn(); -jest.mock('../utils', () => ({ +jest.mock('@kbn/crypto', () => ({ readPkcs12Keystore: mockReadPkcs12Keystore, readPkcs12Truststore: mockReadPkcs12Truststore, })); diff --git a/src/core/server/elasticsearch/elasticsearch_config.test.ts b/src/core/server/elasticsearch/elasticsearch_config.test.ts index d3f9693bab229d..4b6cf220ccd525 100644 --- a/src/core/server/elasticsearch/elasticsearch_config.test.ts +++ b/src/core/server/elasticsearch/elasticsearch_config.test.ts @@ -244,12 +244,12 @@ describe('throws when config is invalid', () => { beforeAll(() => { const realFs = jest.requireActual('fs'); mockReadFileSync.mockImplementation((path: string) => realFs.readFileSync(path)); - const utils = jest.requireActual('../utils'); + const crypto = jest.requireActual('@kbn/crypto'); mockReadPkcs12Keystore.mockImplementation((path: string, password?: string) => - utils.readPkcs12Keystore(path, password) + crypto.readPkcs12Keystore(path, password) ); mockReadPkcs12Truststore.mockImplementation((path: string, password?: string) => - utils.readPkcs12Truststore(path, password) + crypto.readPkcs12Truststore(path, password) ); }); diff --git a/src/core/server/elasticsearch/elasticsearch_config.ts b/src/core/server/elasticsearch/elasticsearch_config.ts index 879002a6ece51e..d3432344f5a739 100644 --- a/src/core/server/elasticsearch/elasticsearch_config.ts +++ b/src/core/server/elasticsearch/elasticsearch_config.ts @@ -7,10 +7,10 @@ */ import { schema, TypeOf } from '@kbn/config-schema'; +import { readPkcs12Keystore, readPkcs12Truststore } from '@kbn/crypto'; import { Duration } from 'moment'; import { readFileSync } from 'fs'; import { ConfigDeprecationProvider } from 'src/core/server'; -import { readPkcs12Keystore, readPkcs12Truststore } from '../utils'; import { ServiceConfigDescriptor } from '../internal_types'; import { getReservedHeaders } from './default_headers'; diff --git a/src/core/server/external_url/external_url_config.ts b/src/core/server/external_url/external_url_config.ts index 7e4afbfbfea05a..da4e8199dc6230 100644 --- a/src/core/server/external_url/external_url_config.ts +++ b/src/core/server/external_url/external_url_config.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { createSHA256Hash } from '../utils'; +import { createSHA256Hash } from '@kbn/crypto'; import { config } from './config'; const DEFAULT_CONFIG = Object.freeze(config.schema.validate({})); diff --git a/src/core/server/http/base_path_proxy_server.test.ts b/src/core/server/http/base_path_proxy_server.test.ts deleted file mode 100644 index 80c03a2af9031b..00000000000000 --- a/src/core/server/http/base_path_proxy_server.test.ts +++ /dev/null @@ -1,1021 +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 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { BasePathProxyServer, BasePathProxyServerOptions } from './base_path_proxy_server'; -import { loggingSystemMock } from '../logging/logging_system.mock'; -import { DevConfig } from '../dev/dev_config'; -import { EMPTY } from 'rxjs'; -import { HttpConfig } from './http_config'; -import { ByteSizeValue, schema } from '@kbn/config-schema'; -import { - KibanaRequest, - KibanaResponseFactory, - Router, - RouteValidationFunction, - RouteValidationResultFactory, -} from './router'; -import { HttpServer } from './http_server'; -import supertest from 'supertest'; -import { RequestHandlerContext } from 'kibana/server'; -import { readFileSync } from 'fs'; -import { KBN_CERT_PATH, KBN_KEY_PATH } from '@kbn/dev-utils'; -import { omit } from 'lodash'; -import { Readable } from 'stream'; - -/** - * Most of these tests are inspired by: - * src/core/server/http/http_server.test.ts - * and copied for completeness from that file. The modifications are that these tests use the developer proxy. - */ -describe('BasePathProxyServer', () => { - let server: HttpServer; - let proxyServer: BasePathProxyServer; - let config: HttpConfig; - let configWithSSL: HttpConfig; - let basePath: string; - let certificate: string; - let key: string; - let proxySupertest: supertest.SuperTest; - const logger = loggingSystemMock.createLogger(); - const enhanceWithContext = (fn: (...args: any[]) => any) => fn.bind(null, {}); - - beforeAll(() => { - certificate = readFileSync(KBN_CERT_PATH, 'utf8'); - key = readFileSync(KBN_KEY_PATH, 'utf8'); - }); - - beforeEach(async () => { - // setup the server but don't start it until each individual test so that routes can be dynamically configured per unit test. - server = new HttpServer(logger, 'tests'); - config = ({ - name: 'kibana', - host: '127.0.0.1', - port: 10012, - compression: { enabled: true }, - requestId: { - allowFromAnyIp: true, - ipAllowlist: [], - }, - autoListen: true, - keepaliveTimeout: 1000, - socketTimeout: 1000, - cors: { - enabled: false, - allowCredentials: false, - allowOrigin: [], - }, - ssl: { enabled: false }, - customResponseHeaders: {}, - maxPayload: new ByteSizeValue(1024), - rewriteBasePath: true, - } as unknown) as HttpConfig; - - configWithSSL = { - ...config, - ssl: { - enabled: true, - certificate, - cipherSuites: ['TLS_AES_256_GCM_SHA384'], - getSecureOptions: () => 0, - key, - redirectHttpFromPort: config.port + 1, - }, - } as HttpConfig; - - // setup and start the proxy server - const proxyConfig: HttpConfig = { ...config, port: 10013 }; - const devConfig = new DevConfig({ basePathProxyTarget: config.port }); - proxyServer = new BasePathProxyServer(logger, proxyConfig, devConfig); - const options: Readonly = { - shouldRedirectFromOldBasePath: () => true, - delayUntil: () => EMPTY, - }; - await proxyServer.start(options); - - // set the base path or throw if for some unknown reason it is not setup - if (proxyServer.basePath == null) { - throw new Error('Invalid null base path, all tests will fail'); - } else { - basePath = proxyServer.basePath; - } - proxySupertest = supertest(`http://127.0.0.1:${proxyConfig.port}`); - }); - - afterEach(async () => { - await server.stop(); - await proxyServer.stop(); - jest.clearAllMocks(); - }); - - test('root URL will return a 302 redirect', async () => { - await proxySupertest.get('/').expect(302); - }); - - test('root URL will return a redirect location with exactly 3 characters that are a-z', async () => { - const res = await proxySupertest.get('/'); - const location = res.header.location; - expect(location).toMatch(/[a-z]{3}/); - }); - - test('valid params', async () => { - const router = new Router(`${basePath}/foo`, logger, enhanceWithContext); - router.get( - { - path: '/{test}', - validate: { - params: schema.object({ - test: schema.string(), - }), - }, - }, - (_, req, res) => { - return res.ok({ body: req.params.test }); - } - ); - const { registerRouter } = await server.setup(config); - registerRouter(router); - await server.start(); - - await proxySupertest - .get(`${basePath}/foo/some-string`) - .expect(200) - .then((res) => { - expect(res.text).toBe('some-string'); - }); - }); - - test('invalid params', async () => { - const router = new Router(`${basePath}/foo`, logger, enhanceWithContext); - - router.get( - { - path: '/{test}', - validate: { - params: schema.object({ - test: schema.number(), - }), - }, - }, - (_, req, res) => { - return res.ok({ body: String(req.params.test) }); - } - ); - - const { registerRouter } = await server.setup(config); - registerRouter(router); - - await server.start(); - - await proxySupertest - .get(`${basePath}/foo/some-string`) - .expect(400) - .then((res) => { - expect(res.body).toEqual({ - error: 'Bad Request', - statusCode: 400, - message: '[request params.test]: expected value of type [number] but got [string]', - }); - }); - }); - - test('valid query', async () => { - const router = new Router(`${basePath}/foo`, logger, enhanceWithContext); - - router.get( - { - path: '/', - validate: { - query: schema.object({ - bar: schema.string(), - quux: schema.number(), - }), - }, - }, - (_, req, res) => { - return res.ok({ body: req.query }); - } - ); - - const { registerRouter } = await server.setup(config); - registerRouter(router); - - await server.start(); - - await proxySupertest - .get(`${basePath}/foo/?bar=test&quux=123`) - .expect(200) - .then((res) => { - expect(res.body).toEqual({ bar: 'test', quux: 123 }); - }); - }); - - test('invalid query', async () => { - const router = new Router(`${basePath}/foo`, logger, enhanceWithContext); - - router.get( - { - path: '/', - validate: { - query: schema.object({ - bar: schema.number(), - }), - }, - }, - (_, req, res) => { - return res.ok({ body: req.query }); - } - ); - - const { registerRouter } = await server.setup(config); - registerRouter(router); - - await server.start(); - - await proxySupertest - .get(`${basePath}/foo/?bar=test`) - .expect(400) - .then((res) => { - expect(res.body).toEqual({ - error: 'Bad Request', - statusCode: 400, - message: '[request query.bar]: expected value of type [number] but got [string]', - }); - }); - }); - - test('valid body', async () => { - const router = new Router(`${basePath}/foo`, logger, enhanceWithContext); - - router.post( - { - path: '/', - validate: { - body: schema.object({ - bar: schema.string(), - baz: schema.number(), - }), - }, - }, - (_, req, res) => { - return res.ok({ body: req.body }); - } - ); - - const { registerRouter } = await server.setup(config); - registerRouter(router); - - await server.start(); - - await proxySupertest - .post(`${basePath}/foo/`) - .send({ - bar: 'test', - baz: 123, - }) - .expect(200) - .then((res) => { - expect(res.body).toEqual({ bar: 'test', baz: 123 }); - }); - }); - - test('valid body with validate function', async () => { - const router = new Router(`${basePath}/foo`, logger, enhanceWithContext); - - router.post( - { - path: '/', - validate: { - body: ({ bar, baz } = {}, { ok, badRequest }) => { - if (typeof bar === 'string' && typeof baz === 'number') { - return ok({ bar, baz }); - } else { - return badRequest('Wrong payload', ['body']); - } - }, - }, - }, - (_, req, res) => { - return res.ok({ body: req.body }); - } - ); - - const { registerRouter } = await server.setup(config); - registerRouter(router); - - await server.start(); - - await proxySupertest - .post(`${basePath}/foo/`) - .send({ - bar: 'test', - baz: 123, - }) - .expect(200) - .then((res) => { - expect(res.body).toEqual({ bar: 'test', baz: 123 }); - }); - }); - - test('not inline validation - specifying params', async () => { - const router = new Router(`${basePath}/foo`, logger, enhanceWithContext); - - const bodyValidation = ( - { bar, baz }: any = {}, - { ok, badRequest }: RouteValidationResultFactory - ) => { - if (typeof bar === 'string' && typeof baz === 'number') { - return ok({ bar, baz }); - } else { - return badRequest('Wrong payload', ['body']); - } - }; - - router.post( - { - path: '/', - validate: { - body: bodyValidation, - }, - }, - (_, req, res) => { - return res.ok({ body: req.body }); - } - ); - - const { registerRouter } = await server.setup(config); - registerRouter(router); - - await server.start(); - - await proxySupertest - .post(`${basePath}/foo/`) - .send({ - bar: 'test', - baz: 123, - }) - .expect(200) - .then((res) => { - expect(res.body).toEqual({ bar: 'test', baz: 123 }); - }); - }); - - test('not inline validation - specifying validation handler', async () => { - const router = new Router(`${basePath}/foo`, logger, enhanceWithContext); - - const bodyValidation: RouteValidationFunction<{ bar: string; baz: number }> = ( - { bar, baz } = {}, - { ok, badRequest } - ) => { - if (typeof bar === 'string' && typeof baz === 'number') { - return ok({ bar, baz }); - } else { - return badRequest('Wrong payload', ['body']); - } - }; - - router.post( - { - path: '/', - validate: { - body: bodyValidation, - }, - }, - (_, req, res) => { - return res.ok({ body: req.body }); - } - ); - - const { registerRouter } = await server.setup(config); - registerRouter(router); - - await server.start(); - - await proxySupertest - .post(`${basePath}/foo/`) - .send({ - bar: 'test', - baz: 123, - }) - .expect(200) - .then((res) => { - expect(res.body).toEqual({ bar: 'test', baz: 123 }); - }); - }); - - test('not inline handler - KibanaRequest', async () => { - const router = new Router(`${basePath}/foo`, logger, enhanceWithContext); - - const handler = ( - context: RequestHandlerContext, - req: KibanaRequest, - res: KibanaResponseFactory - ) => { - const body = { - bar: req.body.bar.toUpperCase(), - baz: req.body.baz.toString(), - }; - - return res.ok({ body }); - }; - - router.post( - { - path: '/', - validate: { - body: ({ bar, baz } = {}, { ok, badRequest }) => { - if (typeof bar === 'string' && typeof baz === 'number') { - return ok({ bar, baz }); - } else { - return badRequest('Wrong payload', ['body']); - } - }, - }, - }, - handler - ); - - const { registerRouter } = await server.setup(config); - registerRouter(router); - - await server.start(); - - await proxySupertest - .post(`${basePath}/foo/`) - .send({ - bar: 'test', - baz: 123, - }) - .expect(200) - .then((res) => { - expect(res.body).toEqual({ bar: 'TEST', baz: '123' }); - }); - }); - - test('invalid body', async () => { - const router = new Router(`${basePath}/foo`, logger, enhanceWithContext); - - router.post( - { - path: '/', - validate: { - body: schema.object({ - bar: schema.number(), - }), - }, - }, - (_, req, res) => { - return res.ok({ body: req.body }); - } - ); - - const { registerRouter } = await server.setup(config); - registerRouter(router); - - await server.start(); - - await proxySupertest - .post(`${basePath}/foo/`) - .send({ bar: 'test' }) - .expect(400) - .then((res) => { - expect(res.body).toEqual({ - error: 'Bad Request', - statusCode: 400, - message: '[request body.bar]: expected value of type [number] but got [string]', - }); - }); - }); - - test('handles putting', async () => { - const router = new Router(`${basePath}/foo`, logger, enhanceWithContext); - - router.put( - { - path: '/', - validate: { - body: schema.object({ - key: schema.string(), - }), - }, - }, - (_, req, res) => { - return res.ok({ body: req.body }); - } - ); - - const { registerRouter } = await server.setup(config); - registerRouter(router); - - await server.start(); - - await proxySupertest - .put(`${basePath}/foo/`) - .send({ key: 'new value' }) - .expect(200) - .then((res) => { - expect(res.body).toEqual({ key: 'new value' }); - }); - }); - - test('handles deleting', async () => { - const router = new Router(`${basePath}/foo`, logger, enhanceWithContext); - - router.delete( - { - path: '/{id}', - validate: { - params: schema.object({ - id: schema.number(), - }), - }, - }, - (_, req, res) => { - return res.ok({ body: { key: req.params.id } }); - } - ); - - const { registerRouter } = await server.setup(config); - registerRouter(router); - - await server.start(); - - await proxySupertest - .delete(`${basePath}/foo/3`) - .expect(200) - .then((res) => { - expect(res.body).toEqual({ key: 3 }); - }); - }); - - describe('with `basepath: /bar` and `rewriteBasePath: false`', () => { - let configWithBasePath: HttpConfig; - - beforeEach(async () => { - configWithBasePath = { - ...config, - basePath: '/bar', - rewriteBasePath: false, - } as HttpConfig; - - const router = new Router(`${basePath}/`, logger, enhanceWithContext); - router.get({ path: '/', validate: false }, (_, __, res) => res.ok({ body: 'value:/' })); - router.get({ path: '/foo', validate: false }, (_, __, res) => res.ok({ body: 'value:/foo' })); - - const { registerRouter } = await server.setup(configWithBasePath); - registerRouter(router); - - await server.start(); - }); - - test('/bar => 404', async () => { - await proxySupertest.get(`${basePath}/bar`).expect(404); - }); - - test('/bar/ => 404', async () => { - await proxySupertest.get(`${basePath}/bar/`).expect(404); - }); - - test('/bar/foo => 404', async () => { - await proxySupertest.get(`${basePath}/bar/foo`).expect(404); - }); - - test('/ => /', async () => { - await proxySupertest - .get(`${basePath}/`) - .expect(200) - .then((res) => { - expect(res.text).toBe('value:/'); - }); - }); - - test('/foo => /foo', async () => { - await proxySupertest - .get(`${basePath}/foo`) - .expect(200) - .then((res) => { - expect(res.text).toBe('value:/foo'); - }); - }); - }); - - test('with defined `redirectHttpFromPort`', async () => { - const router = new Router(`${basePath}/`, logger, enhanceWithContext); - router.get({ path: '/', validate: false }, (_, __, res) => res.ok({ body: 'value:/' })); - - const { registerRouter } = await server.setup(configWithSSL); - registerRouter(router); - - await server.start(); - }); - - test('allows attaching metadata to attach meta-data tag strings to a route', async () => { - const tags = ['my:tag']; - const { registerRouter } = await server.setup(config); - - const router = new Router(basePath, logger, enhanceWithContext); - router.get({ path: '/with-tags', validate: false, options: { tags } }, (_, req, res) => - res.ok({ body: { tags: req.route.options.tags } }) - ); - router.get({ path: '/without-tags', validate: false }, (_, req, res) => - res.ok({ body: { tags: req.route.options.tags } }) - ); - registerRouter(router); - - await server.start(); - await proxySupertest.get(`${basePath}/with-tags`).expect(200, { tags }); - - await proxySupertest.get(`${basePath}/without-tags`).expect(200, { tags: [] }); - }); - - describe('response headers', () => { - test('default headers', async () => { - const { registerRouter } = await server.setup(config); - - const router = new Router(basePath, logger, enhanceWithContext); - router.get({ path: '/', validate: false }, (_, req, res) => res.ok({ body: req.route })); - registerRouter(router); - - await server.start(); - const response = await proxySupertest.get(`${basePath}/`).expect(200); - - const restHeaders = omit(response.header, ['date', 'content-length']); - expect(restHeaders).toMatchInlineSnapshot(` - Object { - "accept-ranges": "bytes", - "cache-control": "private, no-cache, no-store, must-revalidate", - "connection": "close", - "content-type": "application/json; charset=utf-8", - } - `); - }); - }); - - test('exposes route details of incoming request to a route handler (POST + payload options)', async () => { - const { registerRouter } = await server.setup(config); - - const router = new Router(basePath, logger, enhanceWithContext); - router.post( - { - path: '/', - validate: { body: schema.object({ test: schema.number() }) }, - options: { body: { accepts: 'application/json' } }, - }, - (_, req, res) => res.ok({ body: req.route }) - ); - registerRouter(router); - - await server.start(); - await proxySupertest - .post(`${basePath}/`) - .send({ test: 1 }) - .expect(200, { - method: 'post', - path: `${basePath}/`, - options: { - authRequired: true, - xsrfRequired: true, - tags: [], - timeout: { - payload: 10000, - idleSocket: 1000, - }, - body: { - parse: true, // hapi populates the default - maxBytes: 1024, // hapi populates the default - accepts: ['application/json'], - output: 'data', - }, - }, - }); - }); - - test('should return a stream in the body', async () => { - const { registerRouter } = await server.setup(config); - - const router = new Router(basePath, logger, enhanceWithContext); - router.put( - { - path: '/', - validate: { body: schema.stream() }, - options: { body: { output: 'stream' } }, - }, - (_, req, res) => { - expect(req.body).toBeInstanceOf(Readable); - return res.ok({ body: req.route.options.body }); - } - ); - registerRouter(router); - - await server.start(); - await proxySupertest.put(`${basePath}/`).send({ test: 1 }).expect(200, { - parse: true, - maxBytes: 1024, // hapi populates the default - output: 'stream', - }); - }); - - describe('timeout options', () => { - describe('payload timeout', () => { - test('POST routes set the payload timeout', async () => { - const { registerRouter } = await server.setup(config); - - const router = new Router(basePath, logger, enhanceWithContext); - router.post( - { - path: '/', - validate: false, - options: { - timeout: { - payload: 300000, - }, - }, - }, - (_, req, res) => { - return res.ok({ - body: { - timeout: req.route.options.timeout, - }, - }); - } - ); - registerRouter(router); - await server.start(); - await proxySupertest - .post(`${basePath}/`) - .send({ test: 1 }) - .expect(200, { - timeout: { - payload: 300000, - idleSocket: 1000, // This is an extra option added by the proxy - }, - }); - }); - - test('DELETE routes set the payload timeout', async () => { - const { registerRouter } = await server.setup(config); - - const router = new Router(basePath, logger, enhanceWithContext); - router.delete( - { - path: '/', - validate: false, - options: { - timeout: { - payload: 300000, - }, - }, - }, - (context, req, res) => { - return res.ok({ - body: { - timeout: req.route.options.timeout, - }, - }); - } - ); - registerRouter(router); - await server.start(); - await proxySupertest.delete(`${basePath}/`).expect(200, { - timeout: { - payload: 300000, - idleSocket: 1000, // This is an extra option added by the proxy - }, - }); - }); - - test('PUT routes set the payload timeout and automatically adjusts the idle socket timeout', async () => { - const { registerRouter } = await server.setup(config); - - const router = new Router(basePath, logger, enhanceWithContext); - router.put( - { - path: '/', - validate: false, - options: { - timeout: { - payload: 300000, - }, - }, - }, - (_, req, res) => { - return res.ok({ - body: { - timeout: req.route.options.timeout, - }, - }); - } - ); - registerRouter(router); - await server.start(); - await proxySupertest.put(`${basePath}/`).expect(200, { - timeout: { - payload: 300000, - idleSocket: 1000, // This is an extra option added by the proxy - }, - }); - }); - - test('PATCH routes set the payload timeout and automatically adjusts the idle socket timeout', async () => { - const { registerRouter } = await server.setup(config); - - const router = new Router(basePath, logger, enhanceWithContext); - router.patch( - { - path: '/', - validate: false, - options: { - timeout: { - payload: 300000, - }, - }, - }, - (_, req, res) => { - return res.ok({ - body: { - timeout: req.route.options.timeout, - }, - }); - } - ); - registerRouter(router); - await server.start(); - await proxySupertest.patch(`${basePath}/`).expect(200, { - timeout: { - payload: 300000, - idleSocket: 1000, // This is an extra option added by the proxy - }, - }); - }); - }); - - describe('idleSocket timeout', () => { - test('uses server socket timeout when not specified in the route', async () => { - const { registerRouter } = await server.setup({ - ...config, - socketTimeout: 11000, - }); - - const router = new Router(basePath, logger, enhanceWithContext); - router.get( - { - path: '/', - validate: { body: schema.maybe(schema.any()) }, - }, - (_, req, res) => { - return res.ok({ - body: { - timeout: req.route.options.timeout, - }, - }); - } - ); - registerRouter(router); - - await server.start(); - await proxySupertest - .get(`${basePath}/`) - .send() - .expect(200, { - timeout: { - idleSocket: 11000, - }, - }); - }); - - test('sets the socket timeout when specified in the route', async () => { - const { registerRouter } = await server.setup({ - ...config, - socketTimeout: 11000, - }); - - const router = new Router(basePath, logger, enhanceWithContext); - router.get( - { - path: '/', - validate: { body: schema.maybe(schema.any()) }, - options: { timeout: { idleSocket: 12000 } }, - }, - (context, req, res) => { - return res.ok({ - body: { - timeout: req.route.options.timeout, - }, - }); - } - ); - registerRouter(router); - - await server.start(); - await proxySupertest - .get(`${basePath}/`) - .send() - .expect(200, { - timeout: { - idleSocket: 12000, - }, - }); - }); - - test('idleSocket timeout can be smaller than the payload timeout', async () => { - const { registerRouter } = await server.setup(config); - - const router = new Router(basePath, logger, enhanceWithContext); - router.post( - { - path: `${basePath}/`, - validate: { body: schema.any() }, - options: { - timeout: { - payload: 1000, - idleSocket: 10, - }, - }, - }, - (_, req, res) => { - return res.ok({ body: { timeout: req.route.options.timeout } }); - } - ); - - registerRouter(router); - - await server.start(); - }); - }); - }); - - describe('shouldRedirect', () => { - let proxyServerWithoutShouldRedirect: BasePathProxyServer; - let proxyWithoutShouldRedirectSupertest: supertest.SuperTest; - - beforeEach(async () => { - // setup and start a proxy server which does not use "shouldRedirectFromOldBasePath" - const proxyConfig: HttpConfig = { ...config, port: 10004 }; - const devConfig = new DevConfig({ basePathProxyTarget: config.port }); - proxyServerWithoutShouldRedirect = new BasePathProxyServer(logger, proxyConfig, devConfig); - const options: Readonly = { - shouldRedirectFromOldBasePath: () => false, // Return false to not redirect - delayUntil: () => EMPTY, - }; - await proxyServerWithoutShouldRedirect.start(options); - proxyWithoutShouldRedirectSupertest = supertest(`http://127.0.0.1:${proxyConfig.port}`); - }); - - afterEach(async () => { - await proxyServerWithoutShouldRedirect.stop(); - }); - - test('it will do a redirect if it detects what looks like a stale or previously used base path', async () => { - const fakeBasePath = basePath !== 'abc' ? 'abc' : 'efg'; - const res = await proxySupertest.get(`/${fakeBasePath}`).expect(302); - const location = res.header.location; - expect(location).toEqual(`${basePath}/`); - }); - - test('it will NOT do a redirect if it detects what looks like a stale or previously used base path if we intentionally turn it off', async () => { - const fakeBasePath = basePath !== 'abc' ? 'abc' : 'efg'; - await proxyWithoutShouldRedirectSupertest.get(`/${fakeBasePath}`).expect(404); - }); - - test('it will NOT redirect if it detects a larger path than 3 characters', async () => { - await proxySupertest.get('/abcde').expect(404); - }); - - test('it will NOT redirect if it is not a GET verb', async () => { - const fakeBasePath = basePath !== 'abc' ? 'abc' : 'efg'; - await proxySupertest.put(`/${fakeBasePath}`).expect(404); - }); - }); - - describe('constructor option for sending in a custom basePath', () => { - let proxyServerWithFooBasePath: BasePathProxyServer; - let proxyWithFooBasePath: supertest.SuperTest; - - beforeEach(async () => { - // setup and start a proxy server which uses a basePath of "foo" - const proxyConfig: HttpConfig = { ...config, port: 10004, basePath: '/foo' }; // <-- "foo" here in basePath - const devConfig = new DevConfig({ basePathProxyTarget: config.port }); - proxyServerWithFooBasePath = new BasePathProxyServer(logger, proxyConfig, devConfig); - const options: Readonly = { - shouldRedirectFromOldBasePath: () => true, - delayUntil: () => EMPTY, - }; - await proxyServerWithFooBasePath.start(options); - proxyWithFooBasePath = supertest(`http://127.0.0.1:${proxyConfig.port}`); - }); - - afterEach(async () => { - await proxyServerWithFooBasePath.stop(); - }); - - test('it will do a redirect to foo which is our passed in value for the configuration', async () => { - const res = await proxyWithFooBasePath.get('/bar').expect(302); - const location = res.header.location; - expect(location).toEqual('/foo/'); - }); - }); -}); diff --git a/src/core/server/http/http_config.ts b/src/core/server/http/http_config.ts index 2bbe9f3f96a559..356dad201ce95d 100644 --- a/src/core/server/http/http_config.ts +++ b/src/core/server/http/http_config.ts @@ -7,12 +7,12 @@ */ import { ByteSizeValue, schema, TypeOf } from '@kbn/config-schema'; +import { IHttpConfig, SslConfig, sslSchema } from '@kbn/server-http-tools'; import { hostname } from 'os'; import url from 'url'; import { CspConfigType, CspConfig, ICspConfig } from '../csp'; import { ExternalUrlConfig, IExternalUrlConfig } from '../external_url'; -import { SslConfig, sslSchema } from './ssl_config'; const validBasePathRegex = /^\/.*[^\/]$/; const uuidRegexp = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i; @@ -156,7 +156,7 @@ export const config = { }; export type HttpConfigType = TypeOf; -export class HttpConfig { +export class HttpConfig implements IHttpConfig { public name: string; public autoListen: boolean; public host: string; diff --git a/src/core/server/http/http_server.test.ts b/src/core/server/http/http_server.test.ts index 54be7b35f68ad4..ccd14d4b99e112 100644 --- a/src/core/server/http/http_server.test.ts +++ b/src/core/server/http/http_server.test.ts @@ -1288,6 +1288,30 @@ test('should return a stream in the body', async () => { }); }); +test('closes sockets on timeout', async () => { + const { registerRouter, server: innerServer } = await server.setup({ + ...config, + socketTimeout: 1000, + }); + const router = new Router('', logger, enhanceWithContext); + + router.get({ path: '/a', validate: false }, async (context, req, res) => { + await new Promise((resolve) => setTimeout(resolve, 2000)); + return res.ok({}); + }); + router.get({ path: '/b', validate: false }, (context, req, res) => res.ok({})); + + registerRouter(router); + + registerRouter(router); + + await server.start(); + + expect(supertest(innerServer.listener).get('/a')).rejects.toThrow('socket hang up'); + + await supertest(innerServer.listener).get('/b').expect(200); +}); + describe('setup contract', () => { describe('#createSessionStorage', () => { test('creates session storage factory', async () => { diff --git a/src/core/server/http/http_server.ts b/src/core/server/http/http_server.ts index b0510bc414bf83..cd7d7ccc5aeffa 100644 --- a/src/core/server/http/http_server.ts +++ b/src/core/server/http/http_server.ts @@ -10,10 +10,15 @@ import { Server, Request } from '@hapi/hapi'; import HapiStaticFiles from '@hapi/inert'; import url from 'url'; import uuid from 'uuid'; +import { + createServer, + getListenerOptions, + getServerOptions, + getRequestId, +} from '@kbn/server-http-tools'; import { Logger, LoggerFactory } from '../logging'; import { HttpConfig } from './http_config'; -import { createServer, getListenerOptions, getServerOptions, getRequestId } from './http_tools'; import { adoptToHapiAuthFormat, AuthenticationHandler } from './lifecycle/auth'; import { adoptToHapiOnPreAuth, OnPreAuthHandler } from './lifecycle/on_pre_auth'; import { adoptToHapiOnPostAuthFormat, OnPostAuthHandler } from './lifecycle/on_post_auth'; diff --git a/src/core/server/http/http_service.test.ts b/src/core/server/http/http_service.test.ts index 9354c89b632929..83279e99bc4761 100644 --- a/src/core/server/http/http_service.test.ts +++ b/src/core/server/http/http_service.test.ts @@ -242,29 +242,6 @@ test('returns http server contract on setup', async () => { }); }); -test('does not start http server if process is dev cluster master', async () => { - const configService = createConfigService(); - const httpServer = { - isListening: () => false, - setup: jest.fn().mockReturnValue({}), - start: jest.fn(), - stop: noop, - }; - mockHttpServer.mockImplementation(() => httpServer); - - const service = new HttpService({ - coreId, - configService, - env: Env.createDefault(REPO_ROOT, getEnvOptions({ isDevCliParent: true })), - logger, - }); - - await service.setup(setupDeps); - await service.start(); - - expect(httpServer.start).not.toHaveBeenCalled(); -}); - test('does not start http server if configured with `autoListen:false`', async () => { const configService = createConfigService({ autoListen: false, diff --git a/src/core/server/http/http_service.ts b/src/core/server/http/http_service.ts index 87143e1160c6c3..5b90440f6ad701 100644 --- a/src/core/server/http/http_service.ts +++ b/src/core/server/http/http_service.ts @@ -153,15 +153,13 @@ export class HttpService } /** - * Indicates if http server has configured to start listening on a configured port. - * We shouldn't start http service in two cases: - * 1. If `server.autoListen` is explicitly set to `false`. - * 2. When the process is run as dev cluster master in which case cluster manager - * will fork a dedicated process where http service will be set up instead. + * Indicates if http server is configured to start listening on a configured port. + * (if `server.autoListen` is not explicitly set to `false`.) + * * @internal * */ private shouldListen(config: HttpConfig) { - return !this.coreContext.env.isDevCliParent && config.autoListen; + return config.autoListen; } public async stop() { diff --git a/src/core/server/http/http_tools.test.ts b/src/core/server/http/http_tools.test.ts deleted file mode 100644 index c2fa3816324fc4..00000000000000 --- a/src/core/server/http/http_tools.test.ts +++ /dev/null @@ -1,274 +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 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -jest.mock('fs', () => { - const original = jest.requireActual('fs'); - return { - // Hapi Inert patches native methods - ...original, - readFileSync: jest.fn(), - }; -}); - -jest.mock('uuid', () => ({ - v4: jest.fn().mockReturnValue('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'), -})); - -import supertest from 'supertest'; -import { Request, ResponseToolkit } from '@hapi/hapi'; -import Joi from 'joi'; - -import { - defaultValidationErrorHandler, - HapiValidationError, - getServerOptions, - getRequestId, -} from './http_tools'; -import { HttpServer } from './http_server'; -import { HttpConfig, config } from './http_config'; -import { Router } from './router'; -import { loggingSystemMock } from '../logging/logging_system.mock'; -import { ByteSizeValue } from '@kbn/config-schema'; - -const emptyOutput = { - statusCode: 400, - headers: {}, - payload: { - statusCode: 400, - error: '', - validation: { - source: '', - keys: [], - }, - }, -}; - -afterEach(() => jest.clearAllMocks()); - -describe('defaultValidationErrorHandler', () => { - it('formats value validation errors correctly', () => { - expect.assertions(1); - const schema = Joi.array().items( - Joi.object({ - type: Joi.string().required(), - }).required() - ); - - const error = schema.validate([{}], { abortEarly: false }).error as HapiValidationError; - - // Emulate what Hapi v17 does by default - error.output = { ...emptyOutput }; - error.output.payload.validation.keys = ['0.type', '']; - - try { - defaultValidationErrorHandler({} as Request, {} as ResponseToolkit, error); - } catch (err) { - // Verify the empty string gets corrected to 'value' - expect(err.output.payload.validation.keys).toEqual(['0.type', 'value']); - } - }); -}); - -describe('timeouts', () => { - const logger = loggingSystemMock.create(); - const server = new HttpServer(logger, 'foo'); - const enhanceWithContext = (fn: (...args: any[]) => any) => fn.bind(null, {}); - - test('closes sockets on timeout', async () => { - const router = new Router('', logger.get(), enhanceWithContext); - router.get({ path: '/a', validate: false }, async (context, req, res) => { - await new Promise((resolve) => setTimeout(resolve, 2000)); - return res.ok({}); - }); - router.get({ path: '/b', validate: false }, (context, req, res) => res.ok({})); - const { registerRouter, server: innerServer } = await server.setup({ - socketTimeout: 1000, - host: '127.0.0.1', - maxPayload: new ByteSizeValue(1024), - ssl: {}, - cors: { - enabled: false, - }, - compression: { enabled: true }, - requestId: { - allowFromAnyIp: true, - ipAllowlist: [], - }, - } as any); - registerRouter(router); - - await server.start(); - - expect(supertest(innerServer.listener).get('/a')).rejects.toThrow('socket hang up'); - - await supertest(innerServer.listener).get('/b').expect(200); - }); - - afterAll(async () => { - await server.stop(); - }); -}); - -describe('getServerOptions', () => { - beforeEach(() => - jest.requireMock('fs').readFileSync.mockImplementation((path: string) => `content-${path}`) - ); - - it('properly configures TLS with default options', () => { - const httpConfig = new HttpConfig( - config.schema.validate({ - ssl: { - enabled: true, - key: 'some-key-path', - certificate: 'some-certificate-path', - }, - }), - {} as any, - {} as any - ); - - expect(getServerOptions(httpConfig).tls).toMatchInlineSnapshot(` - Object { - "ca": undefined, - "cert": "content-some-certificate-path", - "ciphers": "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA256:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA", - "honorCipherOrder": true, - "key": "content-some-key-path", - "passphrase": undefined, - "rejectUnauthorized": false, - "requestCert": false, - "secureOptions": 67108864, - } - `); - }); - - it('properly configures TLS with client authentication', () => { - const httpConfig = new HttpConfig( - config.schema.validate({ - ssl: { - enabled: true, - key: 'some-key-path', - certificate: 'some-certificate-path', - certificateAuthorities: ['ca-1', 'ca-2'], - clientAuthentication: 'required', - }, - }), - {} as any, - {} as any - ); - - expect(getServerOptions(httpConfig).tls).toMatchInlineSnapshot(` - Object { - "ca": Array [ - "content-ca-1", - "content-ca-2", - ], - "cert": "content-some-certificate-path", - "ciphers": "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA256:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA", - "honorCipherOrder": true, - "key": "content-some-key-path", - "passphrase": undefined, - "rejectUnauthorized": true, - "requestCert": true, - "secureOptions": 67108864, - } - `); - }); - - it('properly configures CORS when cors enabled', () => { - const httpConfig = new HttpConfig( - config.schema.validate({ - cors: { - enabled: true, - allowCredentials: false, - allowOrigin: ['*'], - }, - }), - {} as any, - {} as any - ); - - expect(getServerOptions(httpConfig).routes?.cors).toEqual({ - credentials: false, - origin: ['*'], - headers: ['Accept', 'Authorization', 'Content-Type', 'If-None-Match', 'kbn-xsrf'], - }); - }); -}); - -describe('getRequestId', () => { - describe('when allowFromAnyIp is true', () => { - it('generates a UUID if no x-opaque-id header is present', () => { - const request = { - headers: {}, - raw: { req: { socket: { remoteAddress: '1.1.1.1' } } }, - } as any; - expect(getRequestId(request, { allowFromAnyIp: true, ipAllowlist: [] })).toEqual( - 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' - ); - }); - - it('uses x-opaque-id header value if present', () => { - const request = { - headers: { - 'x-opaque-id': 'id from header', - raw: { req: { socket: { remoteAddress: '1.1.1.1' } } }, - }, - } as any; - expect(getRequestId(request, { allowFromAnyIp: true, ipAllowlist: [] })).toEqual( - 'id from header' - ); - }); - }); - - describe('when allowFromAnyIp is false', () => { - describe('and ipAllowlist is empty', () => { - it('generates a UUID even if x-opaque-id header is present', () => { - const request = { - headers: { 'x-opaque-id': 'id from header' }, - raw: { req: { socket: { remoteAddress: '1.1.1.1' } } }, - } as any; - expect(getRequestId(request, { allowFromAnyIp: false, ipAllowlist: [] })).toEqual( - 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' - ); - }); - }); - - describe('and ipAllowlist is not empty', () => { - it('uses x-opaque-id header if request comes from trusted IP address', () => { - const request = { - headers: { 'x-opaque-id': 'id from header' }, - raw: { req: { socket: { remoteAddress: '1.1.1.1' } } }, - } as any; - expect(getRequestId(request, { allowFromAnyIp: false, ipAllowlist: ['1.1.1.1'] })).toEqual( - 'id from header' - ); - }); - - it('generates a UUID if request comes from untrusted IP address', () => { - const request = { - headers: { 'x-opaque-id': 'id from header' }, - raw: { req: { socket: { remoteAddress: '5.5.5.5' } } }, - } as any; - expect(getRequestId(request, { allowFromAnyIp: false, ipAllowlist: ['1.1.1.1'] })).toEqual( - 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' - ); - }); - - it('generates UUID if request comes from trusted IP address but no x-opaque-id header is present', () => { - const request = { - headers: {}, - raw: { req: { socket: { remoteAddress: '1.1.1.1' } } }, - } as any; - expect(getRequestId(request, { allowFromAnyIp: false, ipAllowlist: ['1.1.1.1'] })).toEqual( - 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' - ); - }); - }); - }); -}); diff --git a/src/core/server/http/http_tools.ts b/src/core/server/http/http_tools.ts deleted file mode 100644 index e909b454feae2c..00000000000000 --- a/src/core/server/http/http_tools.ts +++ /dev/null @@ -1,186 +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 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { Server } from '@hapi/hapi'; -import type { - Lifecycle, - Request, - ResponseToolkit, - RouteOptionsCors, - ServerOptions, - Util, -} from '@hapi/hapi'; -import Hoek from '@hapi/hoek'; -import type { ServerOptions as TLSOptions } from 'https'; -import type { ValidationError } from 'joi'; -import uuid from 'uuid'; -import { ensureNoUnsafeProperties } from '@kbn/std'; -import { HttpConfig } from './http_config'; - -const corsAllowedHeaders = ['Accept', 'Authorization', 'Content-Type', 'If-None-Match', 'kbn-xsrf']; -/** - * Converts Kibana `HttpConfig` into `ServerOptions` that are accepted by the Hapi server. - */ -export function getServerOptions(config: HttpConfig, { configureTLS = true } = {}) { - const cors: RouteOptionsCors | false = config.cors.enabled - ? { - credentials: config.cors.allowCredentials, - origin: config.cors.allowOrigin, - headers: corsAllowedHeaders, - } - : false; - // Note that all connection options configured here should be exactly the same - // as in the legacy platform server (see `src/legacy/server/http/index`). Any change - // SHOULD BE applied in both places. The only exception is TLS-specific options, - // that are configured only here. - const options: ServerOptions = { - host: config.host, - port: config.port, - routes: { - cache: { - privacy: 'private', - otherwise: 'private, no-cache, no-store, must-revalidate', - }, - cors, - payload: { - maxBytes: config.maxPayload.getValueInBytes(), - }, - validate: { - failAction: defaultValidationErrorHandler, - options: { - abortEarly: false, - }, - // TODO: This payload validation can be removed once the legacy platform is completely removed. - // This is a default payload validation which applies to all LP routes which do not specify their own - // `validate.payload` handler, in order to reduce the likelyhood of prototype pollution vulnerabilities. - // (All NP routes are already required to specify their own validation in order to access the payload) - payload: (value) => Promise.resolve(ensureNoUnsafeProperties(value)), - }, - }, - state: { - strictHeader: false, - isHttpOnly: true, - isSameSite: false, // necessary to allow using Kibana inside an iframe - }, - }; - - if (configureTLS && config.ssl.enabled) { - const ssl = config.ssl; - - // TODO: Hapi types have a typo in `tls` property type definition: `https.RequestOptions` is used instead of - // `https.ServerOptions`, and `honorCipherOrder` isn't presented in `https.RequestOptions`. - const tlsOptions: TLSOptions = { - ca: ssl.certificateAuthorities, - cert: ssl.certificate, - ciphers: config.ssl.cipherSuites.join(':'), - // We use the server's cipher order rather than the client's to prevent the BEAST attack. - honorCipherOrder: true, - key: ssl.key, - passphrase: ssl.keyPassphrase, - secureOptions: ssl.getSecureOptions(), - requestCert: ssl.requestCert, - rejectUnauthorized: ssl.rejectUnauthorized, - }; - - options.tls = tlsOptions; - } - - return options; -} - -export function getListenerOptions(config: HttpConfig) { - return { - keepaliveTimeout: config.keepaliveTimeout, - socketTimeout: config.socketTimeout, - }; -} - -interface ListenerOptions { - keepaliveTimeout: number; - socketTimeout: number; -} - -export function createServer(serverOptions: ServerOptions, listenerOptions: ListenerOptions) { - const server = new Server(serverOptions); - - server.listener.keepAliveTimeout = listenerOptions.keepaliveTimeout; - server.listener.setTimeout(listenerOptions.socketTimeout); - server.listener.on('timeout', (socket) => { - socket.destroy(); - }); - server.listener.on('clientError', (err, socket) => { - if (socket.writable) { - socket.end(Buffer.from('HTTP/1.1 400 Bad Request\r\n\r\n', 'ascii')); - } else { - socket.destroy(err); - } - }); - - return server; -} - -/** - * Hapi extends the ValidationError interface to add this output key with more data. - */ -export interface HapiValidationError extends ValidationError { - output: { - statusCode: number; - headers: Util.Dictionary; - payload: { - statusCode: number; - error: string; - message?: string; - validation: { - source: string; - keys: string[]; - }; - }; - }; -} - -/** - * Used to replicate Hapi v16 and below's validation responses. Should be used in the routes.validate.failAction key. - */ -export function defaultValidationErrorHandler( - request: Request, - h: ResponseToolkit, - err?: Error -): Lifecycle.ReturnValue { - // Newer versions of Joi don't format the key for missing params the same way. This shim - // provides backwards compatibility. Unfortunately, Joi doesn't export it's own Error class - // in JS so we have to rely on the `name` key before we can cast it. - // - // The Hapi code we're 'overwriting' can be found here: - // https://github.com/hapijs/hapi/blob/master/lib/validation.js#L102 - if (err && err.name === 'ValidationError' && err.hasOwnProperty('output')) { - const validationError: HapiValidationError = err as HapiValidationError; - const validationKeys: string[] = []; - - validationError.details.forEach((detail) => { - if (detail.path.length > 0) { - validationKeys.push(Hoek.escapeHtml(detail.path.join('.'))); - } else { - // If no path, use the value sigil to signal the entire value had an issue. - validationKeys.push('value'); - } - }); - - validationError.output.payload.validation.keys = validationKeys; - } - - throw err; -} - -export function getRequestId(request: Request, options: HttpConfig['requestId']): string { - return options.allowFromAnyIp || - // socket may be undefined in integration tests that connect via the http listener directly - (request.raw.req.socket?.remoteAddress && - options.ipAllowlist.includes(request.raw.req.socket.remoteAddress)) - ? request.headers['x-opaque-id'] ?? uuid.v4() - : uuid.v4(); -} diff --git a/src/core/server/http/https_redirect_server.ts b/src/core/server/http/https_redirect_server.ts index dd29a46d728e72..28909c0308c223 100644 --- a/src/core/server/http/https_redirect_server.ts +++ b/src/core/server/http/https_redirect_server.ts @@ -8,10 +8,10 @@ import { Request, ResponseToolkit, Server } from '@hapi/hapi'; import { format as formatUrl } from 'url'; +import { createServer, getListenerOptions, getServerOptions } from '@kbn/server-http-tools'; import { Logger } from '../logging'; import { HttpConfig } from './http_config'; -import { createServer, getListenerOptions, getServerOptions } from './http_tools'; export class HttpsRedirectServer { private server?: Server; diff --git a/src/core/server/http/index.ts b/src/core/server/http/index.ts index c35b7e2fcd0429..84fe5149c89c66 100644 --- a/src/core/server/http/index.ts +++ b/src/core/server/http/index.ts @@ -56,7 +56,6 @@ export type { DestructiveRouteMethod, SafeRouteMethod, } from './router'; -export { BasePathProxyServer } from './base_path_proxy_server'; export type { OnPreRoutingHandler, OnPreRoutingToolkit } from './lifecycle/on_pre_routing'; export type { AuthenticationHandler, diff --git a/src/core/server/http/integration_tests/router.test.ts b/src/core/server/http/integration_tests/router.test.ts index 03324dc6c722ff..5b297ab44f8bbe 100644 --- a/src/core/server/http/integration_tests/router.test.ts +++ b/src/core/server/http/integration_tests/router.test.ts @@ -11,14 +11,12 @@ import Boom from '@hapi/boom'; import supertest from 'supertest'; import { schema } from '@kbn/config-schema'; -import { HttpService } from '../http_service'; - import { contextServiceMock } from '../../context/context_service.mock'; import { loggingSystemMock } from '../../logging/logging_system.mock'; import { createHttpServer } from '../test_utils'; +import { HttpService } from '../http_service'; let server: HttpService; - let logger: ReturnType; const contextSetup = contextServiceMock.createSetupContract(); @@ -28,7 +26,6 @@ const setupDeps = { beforeEach(() => { logger = loggingSystemMock.create(); - server = createHttpServer({ logger }); }); diff --git a/src/core/server/legacy/legacy_service.test.ts b/src/core/server/legacy/legacy_service.test.ts index da6b521bfde9a7..db36bd73602c47 100644 --- a/src/core/server/legacy/legacy_service.test.ts +++ b/src/core/server/legacy/legacy_service.test.ts @@ -7,16 +7,12 @@ */ jest.mock('../../../legacy/server/kbn_server'); -jest.mock('./cli_dev_mode'); import { BehaviorSubject, throwError } from 'rxjs'; import { REPO_ROOT } from '@kbn/dev-utils'; -// @ts-expect-error js file to remove TS dependency on cli -import { CliDevMode as MockCliDevMode } from './cli_dev_mode'; import KbnServer from '../../../legacy/server/kbn_server'; import { Config, Env, ObjectToConfigAdapter } from '../config'; -import { BasePathProxyServer } from '../http'; import { DiscoveredPlugin } from '../plugins'; import { getEnvOptions, configServiceMock } from '../config/mocks'; @@ -228,7 +224,6 @@ describe('once LegacyService is set up with connection info', () => { ); expect(MockKbnServer).not.toHaveBeenCalled(); - expect(MockCliDevMode).not.toHaveBeenCalled(); }); test('reconfigures logging configuration if new config is received.', async () => { @@ -335,74 +330,6 @@ describe('once LegacyService is set up without connection info', () => { }); }); -describe('once LegacyService is set up in `devClusterMaster` mode', () => { - beforeEach(() => { - configService.atPath.mockImplementation((path) => { - return new BehaviorSubject( - path === 'dev' ? { basePathProxyTargetPort: 100500 } : { basePath: '/abc' } - ); - }); - }); - - test('creates CliDevMode without base path proxy.', async () => { - const devClusterLegacyService = new LegacyService({ - coreId, - env: Env.createDefault( - REPO_ROOT, - getEnvOptions({ - cliArgs: { silent: true, basePath: false }, - isDevCliParent: true, - }) - ), - logger, - configService: configService as any, - }); - - await devClusterLegacyService.setupLegacyConfig(); - await devClusterLegacyService.setup(setupDeps); - await devClusterLegacyService.start(startDeps); - - expect(MockCliDevMode.fromCoreServices).toHaveBeenCalledTimes(1); - expect(MockCliDevMode.fromCoreServices).toHaveBeenCalledWith( - expect.objectContaining({ silent: true, basePath: false }), - expect.objectContaining({ - get: expect.any(Function), - set: expect.any(Function), - }), - undefined - ); - }); - - test('creates CliDevMode with base path proxy.', async () => { - const devClusterLegacyService = new LegacyService({ - coreId, - env: Env.createDefault( - REPO_ROOT, - getEnvOptions({ - cliArgs: { quiet: true, basePath: true }, - isDevCliParent: true, - }) - ), - logger, - configService: configService as any, - }); - - await devClusterLegacyService.setupLegacyConfig(); - await devClusterLegacyService.setup(setupDeps); - await devClusterLegacyService.start(startDeps); - - expect(MockCliDevMode.fromCoreServices).toHaveBeenCalledTimes(1); - expect(MockCliDevMode.fromCoreServices).toHaveBeenCalledWith( - expect.objectContaining({ quiet: true, basePath: true }), - expect.objectContaining({ - get: expect.any(Function), - set: expect.any(Function), - }), - expect.any(BasePathProxyServer) - ); - }); -}); - describe('start', () => { test('Cannot start without setup phase', async () => { const legacyService = new LegacyService({ diff --git a/src/core/server/legacy/legacy_service.ts b/src/core/server/legacy/legacy_service.ts index 63b84e2461e71b..f7abe942d0009d 100644 --- a/src/core/server/legacy/legacy_service.ts +++ b/src/core/server/legacy/legacy_service.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { combineLatest, ConnectableObservable, EMPTY, Observable, Subscription } from 'rxjs'; +import { combineLatest, ConnectableObservable, Observable, Subscription } from 'rxjs'; import { first, map, publishReplay, tap } from 'rxjs/operators'; import type { PublicMethodsOf } from '@kbn/utility-types'; import { PathConfigType } from '@kbn/utils'; @@ -18,9 +18,7 @@ import { CoreService } from '../../types'; import { Config } from '../config'; import { CoreContext } from '../core_context'; import { CspConfigType, config as cspConfig } from '../csp'; -import { DevConfig, DevConfigType, config as devConfig } from '../dev'; import { - BasePathProxyServer, HttpConfig, HttpConfigType, config as httpConfig, @@ -64,7 +62,6 @@ export class LegacyService implements CoreService { /** Symbol to represent the legacy platform as a fake "plugin". Used by the ContextService */ public readonly legacyId = Symbol(); private readonly log: Logger; - private readonly devConfig$: Observable; private readonly httpConfig$: Observable; private kbnServer?: LegacyKbnServer; private configSubscription?: Subscription; @@ -77,9 +74,6 @@ export class LegacyService implements CoreService { const { logger, configService } = coreContext; this.log = logger.get('legacy-service'); - this.devConfig$ = configService - .atPath(devConfig.path) - .pipe(map((rawConfig) => new DevConfig(rawConfig))); this.httpConfig$ = combineLatest( configService.atPath(httpConfig.path), configService.atPath(cspConfig.path), @@ -142,17 +136,12 @@ export class LegacyService implements CoreService { this.log.debug('starting legacy service'); - // Receive initial config and create kbnServer/ClusterManager. - if (this.coreContext.env.isDevCliParent) { - await this.setupCliDevMode(this.legacyRawConfig!); - } else { - this.kbnServer = await this.createKbnServer( - this.settings!, - this.legacyRawConfig!, - setupDeps, - startDeps - ); - } + this.kbnServer = await this.createKbnServer( + this.settings!, + this.legacyRawConfig!, + setupDeps, + startDeps + ); } public async stop() { @@ -169,26 +158,6 @@ export class LegacyService implements CoreService { } } - private async setupCliDevMode(config: LegacyConfig) { - const basePathProxy$ = this.coreContext.env.cliArgs.basePath - ? combineLatest([this.devConfig$, this.httpConfig$]).pipe( - first(), - map( - ([dev, http]) => - new BasePathProxyServer(this.coreContext.logger.get('server'), http, dev) - ) - ) - : EMPTY; - - // eslint-disable-next-line @typescript-eslint/no-var-requires - const { CliDevMode } = require('./cli_dev_mode'); - CliDevMode.fromCoreServices( - this.coreContext.env.cliArgs, - config, - await basePathProxy$.toPromise() - ); - } - private async createKbnServer( settings: LegacyVars, config: LegacyConfig, diff --git a/src/core/server/plugins/plugins_service.test.ts b/src/core/server/plugins/plugins_service.test.ts index 6a49dd963b4e8f..2d54648d229502 100644 --- a/src/core/server/plugins/plugins_service.test.ts +++ b/src/core/server/plugins/plugins_service.test.ts @@ -91,7 +91,7 @@ const createPlugin = ( }); }; -async function testSetup(options: { isDevCliParent?: boolean } = {}) { +async function testSetup() { mockPackage.raw = { branch: 'feature-v1', version: 'v1', @@ -103,10 +103,7 @@ async function testSetup(options: { isDevCliParent?: boolean } = {}) { }; coreId = Symbol('core'); - env = Env.createDefault(REPO_ROOT, { - ...getEnvOptions(), - isDevCliParent: options.isDevCliParent ?? false, - }); + env = Env.createDefault(REPO_ROOT, getEnvOptions()); config$ = new BehaviorSubject>({ plugins: { initialize: true } }); const rawConfigService = rawConfigServiceMock.create({ rawConfig$: config$ }); @@ -626,30 +623,3 @@ describe('PluginsService', () => { }); }); }); - -describe('PluginService when isDevCliParent is true', () => { - beforeEach(async () => { - await testSetup({ - isDevCliParent: true, - }); - }); - - describe('#discover()', () => { - it('does not try to run discovery', async () => { - await expect(pluginsService.discover({ environment: environmentSetup })).resolves - .toMatchInlineSnapshot(` - Object { - "pluginPaths": Array [], - "pluginTree": undefined, - "uiPlugins": Object { - "browserConfigs": Map {}, - "internal": Map {}, - "public": Map {}, - }, - } - `); - - expect(mockDiscover).not.toHaveBeenCalled(); - }); - }); -}); diff --git a/src/core/server/plugins/plugins_service.ts b/src/core/server/plugins/plugins_service.ts index 92b06d7b6a09b7..8b33e2cf4cc6be 100644 --- a/src/core/server/plugins/plugins_service.ts +++ b/src/core/server/plugins/plugins_service.ts @@ -7,7 +7,7 @@ */ import Path from 'path'; -import { Observable, EMPTY } from 'rxjs'; +import { Observable } from 'rxjs'; import { filter, first, map, mergeMap, tap, toArray } from 'rxjs/operators'; import { pick } from '@kbn/std'; @@ -75,11 +75,9 @@ export class PluginsService implements CoreService; private readonly pluginConfigDescriptors = new Map(); private readonly uiPluginInternalInfo = new Map(); - private readonly discoveryDisabled: boolean; constructor(private readonly coreContext: CoreContext) { this.log = coreContext.logger.get('plugins-service'); - this.discoveryDisabled = coreContext.env.isDevCliParent; this.pluginsSystem = new PluginsSystem(coreContext); this.configService = coreContext.configService; this.config$ = coreContext.configService @@ -90,14 +88,9 @@ export class PluginsService implements CoreService(); - const initialize = config.initialize && !this.coreContext.env.isDevCliParent; - if (initialize) { + if (config.initialize) { contracts = await this.pluginsSystem.setupPlugins(deps); this.registerPluginStaticDirs(deps); } else { @@ -131,7 +123,7 @@ export class PluginsService implements CoreService void ) { this.loggingSystem = new LoggingSystem(); @@ -87,10 +87,7 @@ export class Root { // Stream that maps config updates to logger updates, including update failures. const update$ = configService.getConfig$().pipe( // always read the logging config when the underlying config object is re-read - // except for the CLI process where we only apply the default logging config once - switchMap(() => - this.env.isDevCliParent ? of(undefined) : configService.atPath('logging') - ), + switchMap(() => configService.atPath('logging')), concatMap((config) => this.loggingSystem.upgrade(config)), // This specifically console.logs because we were not able to configure the logger. // eslint-disable-next-line no-console diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index cf1647ef5cec36..551471d3d3ba81 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -297,7 +297,7 @@ export class BasePath { // Warning: (ae-forgotten-export) The symbol "BootstrapArgs" needs to be exported by the entry point index.d.ts // // @internal (undocumented) -export function bootstrap({ configs, cliArgs, applyConfigOverrides, features, }: BootstrapArgs): Promise; +export function bootstrap({ configs, cliArgs, applyConfigOverrides }: BootstrapArgs): Promise; // @public export interface Capabilities { @@ -343,7 +343,7 @@ export const config: { pingTimeout: Type; logQueries: Type; ssl: import("@kbn/config-schema").ObjectType<{ - verificationMode: Type<"none" | "certificate" | "full">; + verificationMode: Type<"certificate" | "none" | "full">; certificateAuthorities: Type; certificate: Type; key: Type; @@ -1265,10 +1265,10 @@ export type KibanaResponseFactory = typeof kibanaResponseFactory; // @public export const kibanaResponseFactory: { - custom: | Buffer | Error | Stream | { + custom: | Error | Buffer | { message: string | Error; attributes?: Record | undefined; - } | undefined>(options: CustomHttpResponseOptions) => KibanaResponse; + } | Stream | undefined>(options: CustomHttpResponseOptions) => KibanaResponse; badRequest: (options?: ErrorHttpResponseOptions) => KibanaResponse; unauthorized: (options?: ErrorHttpResponseOptions) => KibanaResponse; forbidden: (options?: ErrorHttpResponseOptions) => KibanaResponse; diff --git a/src/core/server/server.test.ts b/src/core/server/server.test.ts index f2a2b10fdbfde5..fcf09b0295bcbd 100644 --- a/src/core/server/server.test.ts +++ b/src/core/server/server.test.ts @@ -205,19 +205,3 @@ test(`doesn't setup core services if legacy config validation fails`, async () = expect(mockLoggingService.setup).not.toHaveBeenCalled(); expect(mockI18nService.setup).not.toHaveBeenCalled(); }); - -test(`doesn't validate config if env.isDevCliParent is true`, async () => { - const devParentEnv = Env.createDefault(REPO_ROOT, { - ...getEnvOptions(), - isDevCliParent: true, - }); - - const server = new Server(rawConfigService, devParentEnv, logger); - await server.setup(); - - expect(mockEnsureValidConfiguration).not.toHaveBeenCalled(); - expect(mockContextService.setup).toHaveBeenCalled(); - expect(mockHttpService.setup).toHaveBeenCalled(); - expect(mockElasticsearchService.setup).toHaveBeenCalled(); - expect(mockSavedObjectsService.setup).toHaveBeenCalled(); -}); diff --git a/src/core/server/server.ts b/src/core/server/server.ts index ef5164a8c48e18..8905bcd28fe17c 100644 --- a/src/core/server/server.ts +++ b/src/core/server/server.ts @@ -120,13 +120,10 @@ export class Server { }); const legacyConfigSetup = await this.legacy.setupLegacyConfig(); - // rely on dev server to validate config, don't validate in the parent process - if (!this.env.isDevCliParent) { - // Immediately terminate in case of invalid configuration - // This needs to be done after plugin discovery - await this.configService.validate(); - await ensureValidConfiguration(this.configService, legacyConfigSetup); - } + // Immediately terminate in case of invalid configuration + // This needs to be done after plugin discovery + await this.configService.validate(); + await ensureValidConfiguration(this.configService, legacyConfigSetup); const contextServiceSetup = this.context.setup({ // We inject a fake "legacy plugin" with dependencies on every plugin so that legacy plugins: diff --git a/src/core/server/utils/index.ts b/src/core/server/utils/index.ts index e2dc2c7d99a93e..b0776c48f3bed2 100644 --- a/src/core/server/utils/index.ts +++ b/src/core/server/utils/index.ts @@ -6,6 +6,5 @@ * Side Public License, v 1. */ -export * from './crypto'; export * from './from_root'; export * from './package_json'; diff --git a/src/core/test_helpers/kbn_server.ts b/src/core/test_helpers/kbn_server.ts index 5e274712ad3a78..d702fed73778f1 100644 --- a/src/core/test_helpers/kbn_server.ts +++ b/src/core/test_helpers/kbn_server.ts @@ -70,7 +70,6 @@ export function createRootWithSettings( dist: false, ...cliArgs, }, - isDevCliParent: false, }); return new Root( diff --git a/yarn.lock b/yarn.lock index ce504fd9e96862..0bbfe98f5d1d86 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2618,6 +2618,10 @@ version "0.0.0" uid "" +"@kbn/cli-dev-mode@link:packages/kbn-cli-dev-mode": + version "0.0.0" + uid "" + "@kbn/config-schema@link:packages/kbn-config-schema": version "0.0.0" uid "" @@ -2626,6 +2630,10 @@ version "0.0.0" uid "" +"@kbn/crypto@link:packages/kbn-crypto": + version "0.0.0" + uid "" + "@kbn/dev-utils@link:packages/kbn-dev-utils": version "0.0.0" uid "" @@ -2690,6 +2698,10 @@ version "0.0.0" uid "" +"@kbn/server-http-tools@link:packages/kbn-server-http-tools": + version "0.0.0" + uid "" + "@kbn/std@link:packages/kbn-std": version "0.0.0" uid "" From 907b5c860d872cc3dad6f401cb67251f148b2aa6 Mon Sep 17 00:00:00 2001 From: Robert Oskamp Date: Tue, 30 Mar 2021 13:40:31 +0200 Subject: [PATCH 2/4] Update CODEOWNERS for ml-ui (#95773) --- .github/CODEOWNERS | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3d44f46aca4ff7..f27885c1e32c34 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -119,18 +119,23 @@ # Machine Learning /x-pack/plugins/ml/ @elastic/ml-ui +/x-pack/test/accessibility/apps/ml.ts @elastic/ml-ui +/x-pack/test/accessibility/apps/ml_embeddables_in_dashboard.ts @elastic/ml-ui +/x-pack/test/api_integration/apis/ml/ @elastic/ml-ui +/x-pack/test/api_integration_basic/apis/ml/ @elastic/ml-ui /x-pack/test/functional/apps/ml/ @elastic/ml-ui +/x-pack/test/functional/es_archives/ml/ @elastic/ml-ui /x-pack/test/functional/services/ml/ @elastic/ml-ui -/x-pack/test/accessibility/apps/ml.ts @elastic/ml-ui +/x-pack/test/functional_basic/apps/ml/ @elastic/ml-ui +/x-pack/test/functional_with_es_ssl/apps/ml/ @elastic/ml-ui + # ML team owns and maintains the transform plugin despite it living in the Elasticsearch management section. /x-pack/plugins/transform/ @elastic/ml-ui -/x-pack/test/functional/apps/transform/ @elastic/ml-ui -/x-pack/test/functional/services/transform/ @elastic/ml-ui /x-pack/test/accessibility/apps/transform.ts @elastic/ml-ui -/x-pack/test/api_integration_basic/apis/ml/ @elastic/ml-ui -/x-pack/test/functional_basic/apps/ml/ @elastic/ml-ui - +/x-pack/test/api_integration/apis/transform/ @elastic/ml-ui /x-pack/test/api_integration_basic/apis/transform/ @elastic/ml-ui +/x-pack/test/functional/apps/transform/ @elastic/ml-ui +/x-pack/test/functional/services/transform/ @elastic/ml-ui /x-pack/test/functional_basic/apps/transform/ @elastic/ml-ui # Maps From b58dd3efe8ba04c43665f3cd823ca19e94de2289 Mon Sep 17 00:00:00 2001 From: Liza Katz Date: Tue, 30 Mar 2021 15:24:30 +0300 Subject: [PATCH 3/4] [Sessions] Extract search abort controllers logic into a separate class (#95688) * simplify abort controller logic and extract it into a class * docs * delete unused tests * code review * code review * code review --- ...lic.searchinterceptor.handlesearcherror.md | 4 +- ...n-plugins-data-public.searchinterceptor.md | 2 +- src/plugins/data/public/public.api.md | 14 +-- .../data/public/search/search_interceptor.ts | 86 ++------------ .../kibana_utils/common/abort_utils.test.ts | 89 +-------------- .../kibana_utils/common/abort_utils.ts | 29 ----- src/plugins/kibana_utils/common/index.ts | 2 +- src/plugins/kibana_utils/public/index.ts | 1 - src/plugins/kibana_utils/server/index.ts | 1 - .../search/search_abort_controller.test.ts | 105 ++++++++++++++++++ .../public/search/search_abort_controller.ts | 78 +++++++++++++ .../public/search/search_interceptor.ts | 33 +++--- 12 files changed, 216 insertions(+), 228 deletions(-) create mode 100644 x-pack/plugins/data_enhanced/public/search/search_abort_controller.test.ts create mode 100644 x-pack/plugins/data_enhanced/public/search/search_abort_controller.ts diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.handlesearcherror.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.handlesearcherror.md index 5f8966f0227ac5..f6421d65bc551d 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.handlesearcherror.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.handlesearcherror.md @@ -7,7 +7,7 @@ Signature: ```typescript -protected handleSearchError(e: KibanaServerError | AbortError, timeoutSignal: AbortSignal, options?: ISearchOptions): Error; +protected handleSearchError(e: KibanaServerError | AbortError, options?: ISearchOptions, isTimeout?: boolean): Error; ``` ## Parameters @@ -15,8 +15,8 @@ protected handleSearchError(e: KibanaServerError | AbortError, timeoutSignal: Ab | Parameter | Type | Description | | --- | --- | --- | | e | KibanaServerError | AbortError | | -| timeoutSignal | AbortSignal | | | options | ISearchOptions | | +| isTimeout | boolean | | Returns: diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.md index 2247813562dc72..9d18309fc07be1 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.md @@ -27,7 +27,7 @@ export declare class SearchInterceptor | Method | Modifiers | Description | | --- | --- | --- | | [getTimeoutMode()](./kibana-plugin-plugins-data-public.searchinterceptor.gettimeoutmode.md) | | | -| [handleSearchError(e, timeoutSignal, options)](./kibana-plugin-plugins-data-public.searchinterceptor.handlesearcherror.md) | | | +| [handleSearchError(e, options, isTimeout)](./kibana-plugin-plugins-data-public.searchinterceptor.handlesearcherror.md) | | | | [search(request, options)](./kibana-plugin-plugins-data-public.searchinterceptor.search.md) | | Searches using the given search method. Overrides the AbortSignal with one that will abort either when the request times out, or when the original AbortSignal is aborted. Updates pendingCount$ when the request is started/finalized. | | [showError(e)](./kibana-plugin-plugins-data-public.searchinterceptor.showerror.md) | | | diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index e4085abe140501..746d035e9bfb6a 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -2322,8 +2322,6 @@ export interface SearchError { // @public (undocumented) export class SearchInterceptor { constructor(deps: SearchInterceptorDeps); - // @internal - protected abortController: AbortController; // @internal (undocumented) protected application: CoreStart['application']; // (undocumented) @@ -2334,22 +2332,12 @@ export class SearchInterceptor { // Warning: (ae-forgotten-export) The symbol "AbortError" needs to be exported by the entry point index.d.ts // // (undocumented) - protected handleSearchError(e: KibanaServerError | AbortError, timeoutSignal: AbortSignal, options?: ISearchOptions): Error; + protected handleSearchError(e: KibanaServerError | AbortError, options?: ISearchOptions, isTimeout?: boolean): Error; // @internal protected pendingCount$: BehaviorSubject; // @internal (undocumented) protected runSearch(request: IKibanaSearchRequest, options?: ISearchOptions): Promise; search(request: IKibanaSearchRequest, options?: ISearchOptions): Observable; - // @internal (undocumented) - protected setupAbortSignal({ abortSignal, timeout, }: { - abortSignal?: AbortSignal; - timeout?: number; - }): { - timeoutSignal: AbortSignal; - combinedSignal: AbortSignal; - cleanup: () => void; - abort: () => void; - }; // (undocumented) showError(e: Error): void; } diff --git a/src/plugins/data/public/search/search_interceptor.ts b/src/plugins/data/public/search/search_interceptor.ts index f5a2dc0571fdcf..3df2313f837982 100644 --- a/src/plugins/data/public/search/search_interceptor.ts +++ b/src/plugins/data/public/search/search_interceptor.ts @@ -7,7 +7,7 @@ */ import { memoize } from 'lodash'; -import { BehaviorSubject, throwError, timer, defer, from, Observable, NEVER } from 'rxjs'; +import { BehaviorSubject, throwError, defer, from, Observable } from 'rxjs'; import { catchError, finalize } from 'rxjs/operators'; import { PublicMethodsOf } from '@kbn/utility-types'; import { CoreStart, CoreSetup, ToastsSetup } from 'kibana/public'; @@ -30,11 +30,7 @@ import { getHttpError, } from './errors'; import { toMountPoint } from '../../../kibana_react/public'; -import { - AbortError, - getCombinedAbortSignal, - KibanaServerError, -} from '../../../kibana_utils/public'; +import { AbortError, KibanaServerError } from '../../../kibana_utils/public'; import { ISessionService } from './session'; export interface SearchInterceptorDeps { @@ -48,12 +44,6 @@ export interface SearchInterceptorDeps { } export class SearchInterceptor { - /** - * `abortController` used to signal all searches to abort. - * @internal - */ - protected abortController = new AbortController(); - /** * Observable that emits when the number of pending requests changes. * @internal @@ -98,10 +88,10 @@ export class SearchInterceptor { */ protected handleSearchError( e: KibanaServerError | AbortError, - timeoutSignal: AbortSignal, - options?: ISearchOptions + options?: ISearchOptions, + isTimeout?: boolean ): Error { - if (timeoutSignal.aborted || e.message === 'Request timed out') { + if (isTimeout || e.message === 'Request timed out') { // Handle a client or a server side timeout const err = new SearchTimeoutError(e, this.getTimeoutMode()); @@ -154,60 +144,6 @@ export class SearchInterceptor { ); } - /** - * @internal - */ - protected setupAbortSignal({ - abortSignal, - timeout, - }: { - abortSignal?: AbortSignal; - timeout?: number; - }) { - // Schedule this request to automatically timeout after some interval - const timeoutController = new AbortController(); - const { signal: timeoutSignal } = timeoutController; - const timeout$ = timeout ? timer(timeout) : NEVER; - const subscription = timeout$.subscribe(() => { - this.deps.usageCollector?.trackQueryTimedOut(); - timeoutController.abort(); - }); - - const selfAbortController = new AbortController(); - - // Get a combined `AbortSignal` that will be aborted whenever the first of the following occurs: - // 1. The internal abort controller aborts - // 2. The request times out - // 3. abort() is called on `selfAbortController`. This is used by session service to abort all pending searches that it tracks - // in the current session - // 4. The passed-in signal aborts (e.g. when re-fetching, or whenever the app determines) - const signals = [ - this.abortController.signal, - timeoutSignal, - selfAbortController.signal, - ...(abortSignal ? [abortSignal] : []), - ]; - - const { signal: combinedSignal, cleanup: cleanupCombinedSignal } = getCombinedAbortSignal( - signals - ); - const cleanup = () => { - subscription.unsubscribe(); - combinedSignal.removeEventListener('abort', cleanup); - cleanupCombinedSignal(); - }; - combinedSignal.addEventListener('abort', cleanup); - - return { - timeoutSignal, - combinedSignal, - cleanup, - abort: () => { - selfAbortController.abort(); - }, - }; - } - private showTimeoutErrorToast = (e: SearchTimeoutError, sessionId?: string) => { this.deps.toasts.addDanger({ title: 'Timed out', @@ -245,25 +181,21 @@ export class SearchInterceptor { */ public search( request: IKibanaSearchRequest, - options?: ISearchOptions + options: ISearchOptions = {} ): Observable { // Defer the following logic until `subscribe` is actually called return defer(() => { - if (options?.abortSignal?.aborted) { + if (options.abortSignal?.aborted) { return throwError(new AbortError()); } - const { timeoutSignal, combinedSignal, cleanup } = this.setupAbortSignal({ - abortSignal: options?.abortSignal, - }); this.pendingCount$.next(this.pendingCount$.getValue() + 1); - return from(this.runSearch(request, { ...options, abortSignal: combinedSignal })).pipe( + return from(this.runSearch(request, options)).pipe( catchError((e: Error | AbortError) => { - return throwError(this.handleSearchError(e, timeoutSignal, options)); + return throwError(this.handleSearchError(e, options)); }), finalize(() => { this.pendingCount$.next(this.pendingCount$.getValue() - 1); - cleanup(); }) ); }); diff --git a/src/plugins/kibana_utils/common/abort_utils.test.ts b/src/plugins/kibana_utils/common/abort_utils.test.ts index 1f8a1ef3d84c58..0d34a7852fb440 100644 --- a/src/plugins/kibana_utils/common/abort_utils.test.ts +++ b/src/plugins/kibana_utils/common/abort_utils.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { AbortError, abortSignalToPromise, getCombinedAbortSignal } from './abort_utils'; +import { AbortError, abortSignalToPromise } from './abort_utils'; jest.useFakeTimers(); @@ -66,91 +66,4 @@ describe('AbortUtils', () => { }); }); }); - - describe('getCombinedAbortSignal', () => { - test('should return an AbortSignal', () => { - const signal = getCombinedAbortSignal([]).signal; - expect(signal).toBeInstanceOf(AbortSignal); - }); - - test('should not abort if none of the signals abort', async () => { - const controller1 = new AbortController(); - const controller2 = new AbortController(); - setTimeout(() => controller1.abort(), 2000); - setTimeout(() => controller2.abort(), 1000); - const signal = getCombinedAbortSignal([controller1.signal, controller2.signal]).signal; - expect(signal.aborted).toBe(false); - jest.advanceTimersByTime(500); - await flushPromises(); - expect(signal.aborted).toBe(false); - }); - - test('should abort when the first signal aborts', async () => { - const controller1 = new AbortController(); - const controller2 = new AbortController(); - setTimeout(() => controller1.abort(), 2000); - setTimeout(() => controller2.abort(), 1000); - const signal = getCombinedAbortSignal([controller1.signal, controller2.signal]).signal; - expect(signal.aborted).toBe(false); - jest.advanceTimersByTime(1000); - await flushPromises(); - expect(signal.aborted).toBe(true); - }); - - test('should be aborted if any of the signals is already aborted', async () => { - const controller1 = new AbortController(); - const controller2 = new AbortController(); - controller1.abort(); - const signal = getCombinedAbortSignal([controller1.signal, controller2.signal]).signal; - expect(signal.aborted).toBe(true); - }); - - describe('cleanup listener', () => { - const createMockController = () => { - const controller = new AbortController(); - const spyAddListener = jest.spyOn(controller.signal, 'addEventListener'); - const spyRemoveListener = jest.spyOn(controller.signal, 'removeEventListener'); - return { - controller, - getTotalListeners: () => - Math.max(spyAddListener.mock.calls.length - spyRemoveListener.mock.calls.length, 0), - }; - }; - - test('cleanup should cleanup inner listeners', () => { - const controller1 = createMockController(); - const controller2 = createMockController(); - - const { cleanup } = getCombinedAbortSignal([ - controller1.controller.signal, - controller2.controller.signal, - ]); - - expect(controller1.getTotalListeners()).toBe(1); - expect(controller2.getTotalListeners()).toBe(1); - - cleanup(); - - expect(controller1.getTotalListeners()).toBe(0); - expect(controller2.getTotalListeners()).toBe(0); - }); - - test('abort should cleanup inner listeners', async () => { - const controller1 = createMockController(); - const controller2 = createMockController(); - - getCombinedAbortSignal([controller1.controller.signal, controller2.controller.signal]); - - expect(controller1.getTotalListeners()).toBe(1); - expect(controller2.getTotalListeners()).toBe(1); - - controller1.controller.abort(); - - await flushPromises(); - - expect(controller1.getTotalListeners()).toBe(0); - expect(controller2.getTotalListeners()).toBe(0); - }); - }); - }); }); diff --git a/src/plugins/kibana_utils/common/abort_utils.ts b/src/plugins/kibana_utils/common/abort_utils.ts index f4c750745a605d..051f947b68c1b6 100644 --- a/src/plugins/kibana_utils/common/abort_utils.ts +++ b/src/plugins/kibana_utils/common/abort_utils.ts @@ -45,32 +45,3 @@ export function abortSignalToPromise( return { promise, cleanup }; } - -/** - * Returns an `AbortSignal` that will be aborted when the first of the given signals aborts. - * - * @param signals - */ -export function getCombinedAbortSignal( - signals: AbortSignal[] -): { signal: AbortSignal; cleanup: () => void } { - const controller = new AbortController(); - let cleanup = () => {}; - - if (signals.some((signal) => signal.aborted)) { - controller.abort(); - } else { - const promises = signals.map((signal) => abortSignalToPromise(signal)); - cleanup = () => { - promises.forEach((p) => p.cleanup()); - controller.signal.removeEventListener('abort', cleanup); - }; - controller.signal.addEventListener('abort', cleanup); - Promise.race(promises.map((p) => p.promise)).catch(() => { - cleanup(); - controller.abort(); - }); - } - - return { signal: controller.signal, cleanup }; -} diff --git a/src/plugins/kibana_utils/common/index.ts b/src/plugins/kibana_utils/common/index.ts index 398bf1415c0050..76a7cb2855c6e0 100644 --- a/src/plugins/kibana_utils/common/index.ts +++ b/src/plugins/kibana_utils/common/index.ts @@ -13,7 +13,7 @@ export * from './ui'; export * from './state_containers'; export * from './typed_json'; export * from './errors'; -export { AbortError, abortSignalToPromise, getCombinedAbortSignal } from './abort_utils'; +export { AbortError, abortSignalToPromise } from './abort_utils'; export { createGetterSetter, Get, Set } from './create_getter_setter'; export { distinctUntilChangedWithInitialValue } from './distinct_until_changed_with_initial_value'; export { url } from './url'; diff --git a/src/plugins/kibana_utils/public/index.ts b/src/plugins/kibana_utils/public/index.ts index 9a94757cdcb7ac..75c52e1301ea57 100644 --- a/src/plugins/kibana_utils/public/index.ts +++ b/src/plugins/kibana_utils/public/index.ts @@ -15,7 +15,6 @@ export { fieldWildcardFilter, fieldWildcardMatcher, Get, - getCombinedAbortSignal, JsonArray, JsonObject, JsonValue, diff --git a/src/plugins/kibana_utils/server/index.ts b/src/plugins/kibana_utils/server/index.ts index babc5c4a201ee2..483c5aa92b45ed 100644 --- a/src/plugins/kibana_utils/server/index.ts +++ b/src/plugins/kibana_utils/server/index.ts @@ -13,7 +13,6 @@ export { fieldWildcardFilter, fieldWildcardMatcher, Get, - getCombinedAbortSignal, Set, url, } from '../common'; diff --git a/x-pack/plugins/data_enhanced/public/search/search_abort_controller.test.ts b/x-pack/plugins/data_enhanced/public/search/search_abort_controller.test.ts new file mode 100644 index 00000000000000..68282c1e947f70 --- /dev/null +++ b/x-pack/plugins/data_enhanced/public/search/search_abort_controller.test.ts @@ -0,0 +1,105 @@ +/* + * 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 { SearchAbortController } from './search_abort_controller'; + +const timeTravel = (msToRun = 0) => { + jest.advanceTimersByTime(msToRun); + return new Promise((resolve) => setImmediate(resolve)); +}; + +describe('search abort controller', () => { + test('is not aborted when empty', () => { + const sac = new SearchAbortController(); + expect(sac.getSignal().aborted).toBe(false); + }); + + test('immediately aborts when passed an aborted signal in the constructor', () => { + const controller = new AbortController(); + controller.abort(); + const sac = new SearchAbortController(controller.signal); + expect(sac.getSignal().aborted).toBe(true); + }); + + test('aborts when input signal is aborted', () => { + const controller = new AbortController(); + const sac = new SearchAbortController(controller.signal); + expect(sac.getSignal().aborted).toBe(false); + controller.abort(); + expect(sac.getSignal().aborted).toBe(true); + }); + + test('aborts when all input signals are aborted', () => { + const controller = new AbortController(); + const sac = new SearchAbortController(controller.signal); + + const controller2 = new AbortController(); + sac.addAbortSignal(controller2.signal); + expect(sac.getSignal().aborted).toBe(false); + controller.abort(); + expect(sac.getSignal().aborted).toBe(false); + controller2.abort(); + expect(sac.getSignal().aborted).toBe(true); + }); + + test('aborts explicitly even if all inputs are not aborted', () => { + const controller = new AbortController(); + const sac = new SearchAbortController(controller.signal); + + const controller2 = new AbortController(); + sac.addAbortSignal(controller2.signal); + + expect(sac.getSignal().aborted).toBe(false); + sac.abort(); + expect(sac.getSignal().aborted).toBe(true); + }); + + test('doesnt abort, if cleared', () => { + const controller = new AbortController(); + const sac = new SearchAbortController(controller.signal); + expect(sac.getSignal().aborted).toBe(false); + sac.cleanup(); + controller.abort(); + expect(sac.getSignal().aborted).toBe(false); + }); + + describe('timeout abort', () => { + beforeEach(() => { + jest.useFakeTimers(); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + + test('doesnt abort on timeout, if cleared', () => { + const sac = new SearchAbortController(undefined, 100); + expect(sac.getSignal().aborted).toBe(false); + sac.cleanup(); + timeTravel(100); + expect(sac.getSignal().aborted).toBe(false); + }); + + test('aborts on timeout, even if no signals passed in', () => { + const sac = new SearchAbortController(undefined, 100); + expect(sac.getSignal().aborted).toBe(false); + timeTravel(100); + expect(sac.getSignal().aborted).toBe(true); + expect(sac.isTimeout()).toBe(true); + }); + + test('aborts on timeout, even if there are unaborted signals', () => { + const controller = new AbortController(); + const sac = new SearchAbortController(controller.signal, 100); + + expect(sac.getSignal().aborted).toBe(false); + timeTravel(100); + expect(sac.getSignal().aborted).toBe(true); + expect(sac.isTimeout()).toBe(true); + }); + }); +}); diff --git a/x-pack/plugins/data_enhanced/public/search/search_abort_controller.ts b/x-pack/plugins/data_enhanced/public/search/search_abort_controller.ts new file mode 100644 index 00000000000000..4482a7771dc285 --- /dev/null +++ b/x-pack/plugins/data_enhanced/public/search/search_abort_controller.ts @@ -0,0 +1,78 @@ +/* + * 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 { Subscription, timer } from 'rxjs'; + +export enum AbortReason { + Timeout = 'timeout', +} + +export class SearchAbortController { + private inputAbortSignals: AbortSignal[] = new Array(); + private abortController: AbortController = new AbortController(); + private timeoutSub?: Subscription; + private destroyed = false; + private reason?: AbortReason; + + constructor(abortSignal?: AbortSignal, timeout?: number) { + if (abortSignal) { + this.addAbortSignal(abortSignal); + } + + if (timeout) { + this.timeoutSub = timer(timeout).subscribe(() => { + this.reason = AbortReason.Timeout; + this.abortController.abort(); + this.timeoutSub!.unsubscribe(); + }); + } + } + + private abortHandler = () => { + const allAborted = this.inputAbortSignals.every((signal) => signal.aborted); + if (allAborted) { + this.abortController.abort(); + this.cleanup(); + } + }; + + public cleanup() { + this.destroyed = true; + this.timeoutSub?.unsubscribe(); + this.inputAbortSignals.forEach((abortSignal) => { + abortSignal.removeEventListener('abort', this.abortHandler); + }); + } + + public addAbortSignal(inputSignal: AbortSignal) { + if (this.destroyed) { + return; + } + + this.inputAbortSignals.push(inputSignal); + + if (inputSignal.aborted) { + this.abortHandler(); + } else { + // abort our internal controller if the input signal aborts + inputSignal.addEventListener('abort', this.abortHandler); + } + } + + public getSignal() { + return this.abortController.signal; + } + + public abort() { + this.cleanup(); + this.abortController.abort(); + } + + public isTimeout() { + return this.reason === AbortReason.Timeout; + } +} diff --git a/x-pack/plugins/data_enhanced/public/search/search_interceptor.ts b/x-pack/plugins/data_enhanced/public/search/search_interceptor.ts index 0dfec1a35d9006..b9d8553d3dc5a8 100644 --- a/x-pack/plugins/data_enhanced/public/search/search_interceptor.ts +++ b/x-pack/plugins/data_enhanced/public/search/search_interceptor.ts @@ -17,6 +17,7 @@ import { SearchSessionState, } from '../../../../../src/plugins/data/public'; import { ENHANCED_ES_SEARCH_STRATEGY, IAsyncSearchOptions, pollSearch } from '../../common'; +import { SearchAbortController } from './search_abort_controller'; export class EnhancedSearchInterceptor extends SearchInterceptor { private uiSettingsSub: Subscription; @@ -47,31 +48,30 @@ export class EnhancedSearchInterceptor extends SearchInterceptor { } public search({ id, ...request }: IKibanaSearchRequest, options: IAsyncSearchOptions = {}) { - const { combinedSignal, timeoutSignal, cleanup, abort } = this.setupAbortSignal({ - abortSignal: options.abortSignal, - timeout: this.searchTimeout, - }); - const strategy = options?.strategy ?? ENHANCED_ES_SEARCH_STRATEGY; - const searchOptions = { ...options, strategy, abortSignal: combinedSignal }; + const searchOptions = { + strategy: ENHANCED_ES_SEARCH_STRATEGY, + ...options, + }; + const { sessionId, strategy, abortSignal } = searchOptions; const search = () => this.runSearch({ id, ...request }, searchOptions); + const searchAbortController = new SearchAbortController(abortSignal, this.searchTimeout); this.pendingCount$.next(this.pendingCount$.getValue() + 1); - - const untrackSearch = - this.deps.session.isCurrentSession(options.sessionId) && - this.deps.session.trackSearch({ abort }); + const untrackSearch = this.deps.session.isCurrentSession(options.sessionId) + ? this.deps.session.trackSearch({ abort: () => searchAbortController.abort() }) + : undefined; // track if this search's session will be send to background // if yes, then we don't need to cancel this search when it is aborted let isSavedToBackground = false; const savedToBackgroundSub = - this.deps.session.isCurrentSession(options.sessionId) && + this.deps.session.isCurrentSession(sessionId) && this.deps.session.state$ .pipe( skip(1), // ignore any state, we are only interested in transition x -> BackgroundLoading filter( (state) => - this.deps.session.isCurrentSession(options.sessionId) && + this.deps.session.isCurrentSession(sessionId) && state === SearchSessionState.BackgroundLoading ), take(1) @@ -84,15 +84,18 @@ export class EnhancedSearchInterceptor extends SearchInterceptor { if (id && !isSavedToBackground) this.deps.http.delete(`/internal/search/${strategy}/${id}`); }); - return pollSearch(search, cancel, { ...options, abortSignal: combinedSignal }).pipe( + return pollSearch(search, cancel, { + ...options, + abortSignal: searchAbortController.getSignal(), + }).pipe( tap((response) => (id = response.id)), catchError((e: Error) => { cancel(); - return throwError(this.handleSearchError(e, timeoutSignal, options)); + return throwError(this.handleSearchError(e, options, searchAbortController.isTimeout())); }), finalize(() => { this.pendingCount$.next(this.pendingCount$.getValue() - 1); - cleanup(); + searchAbortController.cleanup(); if (untrackSearch && this.deps.session.isCurrentSession(options.sessionId)) { // untrack if this search still belongs to current session untrackSearch(); From 3abb79a17939ae70d465a97472e341bd8ad2ec0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20C=C3=B4t=C3=A9?= Date: Tue, 30 Mar 2021 08:27:28 -0400 Subject: [PATCH 4/4] Create new alerting HTTP APIs that use the new terminology (#93977) * Move current alert HTTP APIs to legacy folder (#93943) * Move current HTTP APIs to legacy folder * Rename BASE_ALERT_API_PATH to LEGACY_BASE_ALERT_API_PATH * Fix failing tests and extra files * Create new rule HTTP APIs (#93980) * Move current HTTP APIs to legacy folder * Rename BASE_ALERT_API_PATH to LEGACY_BASE_ALERT_API_PATH * Fix failing tests and extra files * Move current alert HTTP APIs to legacy folder (#93943) * Move current HTTP APIs to legacy folder * Rename BASE_ALERT_API_PATH to LEGACY_BASE_ALERT_API_PATH * Fix failing tests and extra files * Add necessary files * Create rule route * Get rule API * Update rule API * Delete rule route * Aggregate rules API * Disable rule API * Enable rule API * Find rules API * Fix Update API * Get rule alert summary API * Get rule state API * Health API * Rule types API * Mute all API * Mute alert API * Unmute all API * Unmute alert route * Update API key API * corrected tpye by making it much more complicated * removed unneeded cocde * Fixes * Add back health route * mutedInstanceIds -> mutedAlertIds * lastRun -> last_run * alert_type_state -> rule_type_state & alert_instances -> alerts Co-authored-by: Gidi Meir Morris * Create docs for new rule HTTP APIs, deprecate old docs (#94745) * Create docs for new APIs, deprecate old docs * Remove connector_type_id * Update docs * Add link to legacy APIs from rules API docs * Remove connector_type_id references * [DOCS] Add legacy APIs to index.asciidoc * Fix camel case Co-authored-by: lcawl * Make alerting tests use new rules APIs (#95159) * Make API integration tests use new HTTP APIs * Fix end to end tests * Fix test failures * Fix more test failures * Rename some files * Add tests for legacy APIs (#95333) * Initial commit (#95457) * Move some new alerting APIs to /internal (#95461) * Initial commit * Update README.md * Use internal API * Merge deprecated warning w/ alternative solution * Update API docs Co-authored-by: Gidi Meir Morris Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: lcawl --- api_docs/alerting.json | 70 +- api_docs/apm.json | 2 +- api_docs/console.json | 2 +- api_docs/core.json | 118 +- api_docs/core_http.json | 2 +- api_docs/core_saved_objects.json | 934 ++++++--- api_docs/data.json | 67 +- api_docs/data_autocomplete.json | 2 +- api_docs/data_enhanced.json | 6 +- api_docs/data_index_patterns.json | 30 +- api_docs/data_search.json | 627 ++---- api_docs/data_search.mdx | 3 + api_docs/event_log.json | 10 +- api_docs/expressions.json | 280 +-- api_docs/fleet.json | 313 ++- api_docs/global_search.json | 2 +- api_docs/index_management.json | 8 +- api_docs/infra.json | 6 +- api_docs/lens.json | 100 +- api_docs/lists.json | 182 ++ api_docs/ml.json | 1674 +++-------------- api_docs/observability.json | 272 ++- api_docs/observability.mdx | 3 - api_docs/reporting.json | 4 +- api_docs/security.json | 2 +- api_docs/security_solution.json | 36 +- api_docs/telemetry.json | 16 +- api_docs/telemetry_collection_manager.json | 2 +- api_docs/telemetry_collection_xpack.json | 160 +- api_docs/telemetry_collection_xpack.mdx | 4 +- api_docs/vis_type_timeseries.json | 2 +- docs/api/alerting.asciidoc | 47 + docs/api/alerting/create_rule.asciidoc | 196 ++ docs/api/alerting/delete_rule.asciidoc | 41 + docs/api/alerting/disable_rule.asciidoc | 39 + docs/api/alerting/enable_rule.asciidoc | 39 + docs/api/alerting/find_rules.asciidoc | 127 ++ docs/api/alerting/get_rules.asciidoc | 75 + docs/api/alerting/health.asciidoc | 93 + .../legacy}/create.asciidoc | 6 +- .../legacy}/delete.asciidoc | 6 +- .../legacy}/disable.asciidoc | 6 +- .../legacy}/enable.asciidoc | 6 +- .../{alerts => alerting/legacy}/find.asciidoc | 6 +- .../{alerts => alerting/legacy}/get.asciidoc | 6 +- .../legacy}/health.asciidoc | 6 +- docs/api/alerting/legacy/index.asciidoc | 18 + .../{alerts => alerting/legacy}/list.asciidoc | 6 +- .../{alerts => alerting/legacy}/mute.asciidoc | 6 +- .../legacy}/mute_all.asciidoc | 6 +- .../legacy}/unmute.asciidoc | 6 +- .../legacy}/unmute_all.asciidoc | 6 +- .../legacy}/update.asciidoc | 6 +- docs/api/alerting/list_rule_types.asciidoc | 135 ++ docs/api/alerting/mute_alert.asciidoc | 42 + docs/api/alerting/mute_all_alerts.asciidoc | 39 + docs/api/alerting/unmute_alert.asciidoc | 42 + docs/api/alerting/unmute_all_alerts.asciidoc | 39 + docs/api/alerting/update_rule.asciidoc | 136 ++ docs/api/alerts.asciidoc | 42 - docs/user/api.asciidoc | 2 +- .../public/components/view_alert.tsx | 10 +- .../public/components/view_astros_alert.tsx | 10 +- x-pack/plugins/alerting/README.md | 18 +- x-pack/plugins/alerting/common/index.ts | 4 +- x-pack/plugins/alerting/public/alert_api.ts | 8 +- .../server/alerts_client/alerts_client.ts | 8 +- .../alerting/server/lib/errors/index.ts | 17 + x-pack/plugins/alerting/server/lib/index.ts | 9 +- x-pack/plugins/alerting/server/plugin.ts | 38 +- .../server/routes/aggregate_rules.test.ts | 150 ++ .../alerting/server/routes/aggregate_rules.ts | 79 + .../server/routes/create_rule.test.ts | 298 +++ .../alerting/server/routes/create_rule.ts | 141 ++ .../server/routes/delete_rule.test.ts | 109 ++ .../alerting/server/routes/delete_rule.ts | 38 + .../server/routes/disable_rule.test.ts | 81 + .../alerting/server/routes/disable_rule.ts | 45 + .../server/routes/enable_rule.test.ts | 81 + .../alerting/server/routes/enable_rule.ts | 45 + .../alerting/server/routes/find_rules.test.ts | 148 ++ .../alerting/server/routes/find_rules.ts | 143 ++ .../alerting/server/routes/get_rule.test.ts | 169 ++ .../alerting/server/routes/get_rule.ts | 84 + .../routes/get_rule_alert_summary.test.ts | 106 ++ .../server/routes/get_rule_alert_summary.ts | 77 + .../server/routes/get_rule_state.test.ts | 150 ++ .../alerting/server/routes/get_rule_state.ts | 54 + .../alerting/server/routes/health.test.ts | 74 +- .../plugins/alerting/server/routes/health.ts | 98 +- .../plugins/alerting/server/routes/index.ts | 64 +- .../routes/{ => legacy}/aggregate.test.ts | 10 +- .../server/routes/{ => legacy}/aggregate.ts | 14 +- .../server/routes/{ => legacy}/create.test.ts | 14 +- .../server/routes/{ => legacy}/create.ts | 30 +- .../server/routes/{ => legacy}/delete.test.ts | 10 +- .../server/routes/{ => legacy}/delete.ts | 10 +- .../routes/{ => legacy}/disable.test.ts | 10 +- .../server/routes/{ => legacy}/disable.ts | 12 +- .../server/routes/{ => legacy}/enable.test.ts | 10 +- .../server/routes/{ => legacy}/enable.ts | 14 +- .../server/routes/{ => legacy}/find.test.ts | 10 +- .../server/routes/{ => legacy}/find.ts | 14 +- .../server/routes/{ => legacy}/get.test.ts | 12 +- .../server/routes/{ => legacy}/get.ts | 10 +- .../get_alert_instance_summary.test.ts | 10 +- .../get_alert_instance_summary.ts | 10 +- .../{ => legacy}/get_alert_state.test.ts | 8 +- .../routes/{ => legacy}/get_alert_state.ts | 10 +- .../server/routes/legacy/health.test.ts | 336 ++++ .../alerting/server/routes/legacy/health.ts | 71 + .../alerting/server/routes/legacy/index.ts | 53 + .../{ => legacy}/list_alert_types.test.ts | 14 +- .../routes/{ => legacy}/list_alert_types.ts | 10 +- .../routes/{ => legacy}/mute_all.test.ts | 10 +- .../server/routes/{ => legacy}/mute_all.ts | 12 +- .../routes/{ => legacy}/mute_instance.test.ts | 10 +- .../routes/{ => legacy}/mute_instance.ts | 16 +- .../routes/{ => legacy}/unmute_all.test.ts | 10 +- .../server/routes/{ => legacy}/unmute_all.ts | 12 +- .../{ => legacy}/unmute_instance.test.ts | 10 +- .../routes/{ => legacy}/unmute_instance.ts | 12 +- .../server/routes/{ => legacy}/update.test.ts | 14 +- .../server/routes/{ => legacy}/update.ts | 20 +- .../{ => legacy}/update_api_key.test.ts | 10 +- .../routes/{ => legacy}/update_api_key.ts | 14 +- .../alerting/server/routes/lib/index.ts | 15 + .../server/routes/lib/rewrite_request_case.ts | 82 + .../routes/lib/verify_access_and_context.ts | 34 + .../alerting/server/routes/mute_alert.test.ts | 86 + .../alerting/server/routes/mute_alert.ts | 55 + .../server/routes/mute_all_rule.test.ts | 80 + .../alerting/server/routes/mute_all_rule.ts | 45 + .../alerting/server/routes/rule_types.test.ts | 223 +++ .../alerting/server/routes/rule_types.ts | 56 + .../server/routes/unmute_alert.test.ts | 86 + .../alerting/server/routes/unmute_alert.ts | 55 + .../server/routes/unmute_all_rule.test.ts | 80 + .../alerting/server/routes/unmute_all_rule.ts | 45 + .../server/routes/update_rule.test.ts | 215 +++ .../alerting/server/routes/update_rule.ts | 147 ++ .../server/routes/update_rule_api_key.test.ts | 82 + .../server/routes/update_rule_api_key.ts | 45 + .../public/alerts/configuration.tsx | 10 +- .../monitoring/server/alerts/base_alert.ts | 2 +- .../server/routes/api/v1/alerts/enable.ts | 4 +- .../notifications/create_notifications.ts | 4 +- .../detection_engine/rules/create_rules.ts | 4 +- .../rules/install_prepacked_rules.ts | 6 +- .../public/application/constants/index.ts | 2 +- .../public/application/lib/alert_api.ts | 34 +- .../tests/alerts/basic_noop_alert_type.ts | 2 +- .../tests/alerts/gold_noop_alert_type.ts | 4 +- .../common/lib/alert_utils.ts | 50 +- .../common/lib/get_test_alert_data.ts | 4 +- .../tests/actions/get_all.ts | 2 +- .../tests/alerting/alerts.ts | 40 +- .../tests/alerting/create.ts | 91 +- .../tests/alerting/delete.ts | 69 +- .../tests/alerting/disable.ts | 48 +- .../tests/alerting/enable.ts | 54 +- .../tests/alerting/event_log.ts | 6 +- .../tests/alerting/execution_status.ts | 14 +- .../tests/alerting/find.ts | 140 +- .../security_and_spaces/tests/alerting/get.ts | 64 +- .../alerting/get_alert_instance_summary.ts | 50 +- .../tests/alerting/get_alert_state.ts | 26 +- .../tests/alerting/index.ts | 2 +- .../tests/alerting/mustache_templates.ts | 12 +- .../tests/alerting/mute_all.ts | 42 +- .../tests/alerting/mute_instance.ts | 54 +- .../tests/alerting/rbac_legacy.ts | 2 +- .../{list_alert_types.ts => rule_types.ts} | 68 +- .../tests/alerting/unmute_all.ts | 50 +- .../tests/alerting/unmute_instance.ts | 58 +- .../tests/alerting/update.ts | 273 +-- .../tests/alerting/update_api_key.ts | 54 +- .../spaces_only/tests/alerting/aggregate.ts | 95 +- .../spaces_only/tests/alerting/alerts_base.ts | 58 +- .../builtin_alert_types/es_query/alert.ts | 13 +- .../index_threshold/alert.ts | 13 +- .../spaces_only/tests/alerting/create.ts | 152 +- .../spaces_only/tests/alerting/delete.ts | 30 +- .../spaces_only/tests/alerting/disable.ts | 39 +- .../spaces_only/tests/alerting/enable.ts | 51 +- .../spaces_only/tests/alerting/event_log.ts | 26 +- .../tests/alerting/execution_status.ts | 99 +- .../spaces_only/tests/alerting/find.ts | 95 +- .../spaces_only/tests/alerting/get.ts | 81 +- .../alerting/get_alert_instance_summary.ts | 140 +- .../tests/alerting/get_alert_state.ts | 77 +- .../spaces_only/tests/alerting/index.ts | 2 +- .../spaces_only/tests/alerting/migrations.ts | 28 +- .../tests/alerting/mustache_templates.ts | 60 +- .../spaces_only/tests/alerting/mute_all.ts | 38 +- .../tests/alerting/mute_instance.ts | 42 +- .../spaces_only/tests/alerting/notify_when.ts | 48 +- .../{list_alert_types.ts => rule_types.ts} | 64 +- .../spaces_only/tests/alerting/unmute_all.ts | 42 +- .../tests/alerting/unmute_instance.ts | 50 +- .../spaces_only/tests/alerting/update.ts | 104 +- .../tests/alerting/update_api_key.ts | 44 +- .../alert_create_flyout.ts | 9 +- .../apps/triggers_actions_ui/alerts_list.ts | 5 +- .../apps/triggers_actions_ui/details.ts | 24 +- .../apps/triggers_actions_ui/home_page.ts | 2 +- .../lib/get_test_data.ts | 4 +- 207 files changed, 9203 insertions(+), 4485 deletions(-) create mode 100644 docs/api/alerting.asciidoc create mode 100644 docs/api/alerting/create_rule.asciidoc create mode 100644 docs/api/alerting/delete_rule.asciidoc create mode 100644 docs/api/alerting/disable_rule.asciidoc create mode 100644 docs/api/alerting/enable_rule.asciidoc create mode 100644 docs/api/alerting/find_rules.asciidoc create mode 100644 docs/api/alerting/get_rules.asciidoc create mode 100644 docs/api/alerting/health.asciidoc rename docs/api/{alerts => alerting/legacy}/create.asciidoc (97%) rename docs/api/{alerts => alerting/legacy}/delete.asciidoc (86%) rename docs/api/{alerts => alerting/legacy}/disable.asciidoc (85%) rename docs/api/{alerts => alerting/legacy}/enable.asciidoc (85%) rename docs/api/{alerts => alerting/legacy}/find.asciidoc (96%) rename docs/api/{alerts => alerting/legacy}/get.asciidoc (92%) rename docs/api/{alerts => alerting/legacy}/health.asciidoc (92%) create mode 100644 docs/api/alerting/legacy/index.asciidoc rename docs/api/{alerts => alerting/legacy}/list.asciidoc (96%) rename docs/api/{alerts => alerting/legacy}/mute.asciidoc (87%) rename docs/api/{alerts => alerting/legacy}/mute_all.asciidoc (83%) rename docs/api/{alerts => alerting/legacy}/unmute.asciidoc (87%) rename docs/api/{alerts => alerting/legacy}/unmute_all.asciidoc (83%) rename docs/api/{alerts => alerting/legacy}/update.asciidoc (96%) create mode 100644 docs/api/alerting/list_rule_types.asciidoc create mode 100644 docs/api/alerting/mute_alert.asciidoc create mode 100644 docs/api/alerting/mute_all_alerts.asciidoc create mode 100644 docs/api/alerting/unmute_alert.asciidoc create mode 100644 docs/api/alerting/unmute_all_alerts.asciidoc create mode 100644 docs/api/alerting/update_rule.asciidoc delete mode 100644 docs/api/alerts.asciidoc create mode 100644 x-pack/plugins/alerting/server/lib/errors/index.ts create mode 100644 x-pack/plugins/alerting/server/routes/aggregate_rules.test.ts create mode 100644 x-pack/plugins/alerting/server/routes/aggregate_rules.ts create mode 100644 x-pack/plugins/alerting/server/routes/create_rule.test.ts create mode 100644 x-pack/plugins/alerting/server/routes/create_rule.ts create mode 100644 x-pack/plugins/alerting/server/routes/delete_rule.test.ts create mode 100644 x-pack/plugins/alerting/server/routes/delete_rule.ts create mode 100644 x-pack/plugins/alerting/server/routes/disable_rule.test.ts create mode 100644 x-pack/plugins/alerting/server/routes/disable_rule.ts create mode 100644 x-pack/plugins/alerting/server/routes/enable_rule.test.ts create mode 100644 x-pack/plugins/alerting/server/routes/enable_rule.ts create mode 100644 x-pack/plugins/alerting/server/routes/find_rules.test.ts create mode 100644 x-pack/plugins/alerting/server/routes/find_rules.ts create mode 100644 x-pack/plugins/alerting/server/routes/get_rule.test.ts create mode 100644 x-pack/plugins/alerting/server/routes/get_rule.ts create mode 100644 x-pack/plugins/alerting/server/routes/get_rule_alert_summary.test.ts create mode 100644 x-pack/plugins/alerting/server/routes/get_rule_alert_summary.ts create mode 100644 x-pack/plugins/alerting/server/routes/get_rule_state.test.ts create mode 100644 x-pack/plugins/alerting/server/routes/get_rule_state.ts rename x-pack/plugins/alerting/server/routes/{ => legacy}/aggregate.test.ts (91%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/aggregate.ts (83%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/create.test.ts (93%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/create.ts (75%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/delete.test.ts (89%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/delete.ts (76%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/disable.test.ts (86%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/disable.ts (74%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/enable.test.ts (86%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/enable.ts (72%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/find.test.ts (91%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/find.ts (86%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/get.test.ts (90%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/get.ts (76%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/get_alert_instance_summary.test.ts (89%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/get_alert_instance_summary.ts (79%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/get_alert_state.test.ts (93%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/get_alert_state.ts (77%) create mode 100644 x-pack/plugins/alerting/server/routes/legacy/health.test.ts create mode 100644 x-pack/plugins/alerting/server/routes/legacy/health.ts create mode 100644 x-pack/plugins/alerting/server/routes/legacy/index.ts rename x-pack/plugins/alerting/server/routes/{ => legacy}/list_alert_types.test.ts (92%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/list_alert_types.ts (72%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/mute_all.test.ts (86%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/mute_all.ts (74%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/mute_instance.test.ts (87%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/mute_instance.ts (72%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/unmute_all.test.ts (86%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/unmute_all.ts (74%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/unmute_instance.test.ts (87%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/unmute_instance.ts (74%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/update.test.ts (92%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/update.ts (81%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/update_api_key.test.ts (86%) rename x-pack/plugins/alerting/server/routes/{ => legacy}/update_api_key.ts (72%) create mode 100644 x-pack/plugins/alerting/server/routes/lib/index.ts create mode 100644 x-pack/plugins/alerting/server/routes/lib/rewrite_request_case.ts create mode 100644 x-pack/plugins/alerting/server/routes/lib/verify_access_and_context.ts create mode 100644 x-pack/plugins/alerting/server/routes/mute_alert.test.ts create mode 100644 x-pack/plugins/alerting/server/routes/mute_alert.ts create mode 100644 x-pack/plugins/alerting/server/routes/mute_all_rule.test.ts create mode 100644 x-pack/plugins/alerting/server/routes/mute_all_rule.ts create mode 100644 x-pack/plugins/alerting/server/routes/rule_types.test.ts create mode 100644 x-pack/plugins/alerting/server/routes/rule_types.ts create mode 100644 x-pack/plugins/alerting/server/routes/unmute_alert.test.ts create mode 100644 x-pack/plugins/alerting/server/routes/unmute_alert.ts create mode 100644 x-pack/plugins/alerting/server/routes/unmute_all_rule.test.ts create mode 100644 x-pack/plugins/alerting/server/routes/unmute_all_rule.ts create mode 100644 x-pack/plugins/alerting/server/routes/update_rule.test.ts create mode 100644 x-pack/plugins/alerting/server/routes/update_rule.ts create mode 100644 x-pack/plugins/alerting/server/routes/update_rule_api_key.test.ts create mode 100644 x-pack/plugins/alerting/server/routes/update_rule_api_key.ts rename x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/{list_alert_types.ts => rule_types.ts} (66%) rename x-pack/test/alerting_api_integration/spaces_only/tests/alerting/{list_alert_types.ts => rule_types.ts} (59%) diff --git a/api_docs/alerting.json b/api_docs/alerting.json index 5550798c4316f2..f6e37bafdedb09 100644 --- a/api_docs/alerting.json +++ b/api_docs/alerting.json @@ -810,7 +810,7 @@ "description": [], "source": { "path": "x-pack/plugins/alerting/server/alerts_client/alerts_client.ts", - "lineNumber": 132 + "lineNumber": 133 } }, { @@ -821,7 +821,7 @@ "description": [], "source": { "path": "x-pack/plugins/alerting/server/alerts_client/alerts_client.ts", - "lineNumber": 133 + "lineNumber": 134 } }, { @@ -832,7 +832,7 @@ "description": [], "source": { "path": "x-pack/plugins/alerting/server/alerts_client/alerts_client.ts", - "lineNumber": 134 + "lineNumber": 135 } }, { @@ -843,7 +843,7 @@ "description": [], "source": { "path": "x-pack/plugins/alerting/server/alerts_client/alerts_client.ts", - "lineNumber": 135 + "lineNumber": 136 }, "signature": [ "Pick<", @@ -860,7 +860,7 @@ ], "source": { "path": "x-pack/plugins/alerting/server/alerts_client/alerts_client.ts", - "lineNumber": 131 + "lineNumber": 132 }, "initialIsOpen": false }, @@ -905,7 +905,7 @@ "description": [], "source": { "path": "x-pack/plugins/alerting/server/plugin.ts", - "lineNumber": 111 + "lineNumber": 93 } } ], @@ -913,13 +913,13 @@ "returnComment": [], "source": { "path": "x-pack/plugins/alerting/server/plugin.ts", - "lineNumber": 103 + "lineNumber": 85 } } ], "source": { "path": "x-pack/plugins/alerting/server/plugin.ts", - "lineNumber": 102 + "lineNumber": 84 }, "initialIsOpen": false }, @@ -938,7 +938,7 @@ "description": [], "source": { "path": "x-pack/plugins/alerting/server/plugin.ts", - "lineNumber": 123 + "lineNumber": 105 }, "signature": [ "() => Set<", @@ -994,7 +994,7 @@ "description": [], "source": { "path": "x-pack/plugins/alerting/server/plugin.ts", - "lineNumber": 124 + "lineNumber": 106 } } ], @@ -1002,7 +1002,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/alerting/server/plugin.ts", - "lineNumber": 124 + "lineNumber": 106 } }, { @@ -1013,7 +1013,7 @@ "description": [], "source": { "path": "x-pack/plugins/alerting/server/plugin.ts", - "lineNumber": 125 + "lineNumber": 107 }, "signature": [ "() => Promise<", @@ -1030,7 +1030,7 @@ ], "source": { "path": "x-pack/plugins/alerting/server/plugin.ts", - "lineNumber": 122 + "lineNumber": 104 }, "initialIsOpen": false } @@ -1118,7 +1118,7 @@ }, ", \"enabled\" | \"id\" | \"name\" | \"params\" | \"actions\" | \"muteAll\" | \"tags\" | \"alertTypeId\" | \"consumer\" | \"schedule\" | \"scheduledTaskId\" | \"createdBy\" | \"updatedBy\" | \"createdAt\" | \"updatedAt\" | \"apiKeyOwner\" | \"throttle\" | \"notifyWhen\" | \"mutedInstanceIds\" | \"executionStatus\">>; delete: ({ id }: { id: string; }) => Promise<{}>; create: = never>({ data, options, }: ", "CreateOptions", - ") => Promise<", + ") => Promise>; find: ({ options: { fields, ...options }, }?: { options?: ", + ", \"enabled\" | \"id\" | \"name\" | \"params\" | \"actions\" | \"muteAll\" | \"tags\" | \"alertTypeId\" | \"consumer\" | \"schedule\" | \"scheduledTaskId\" | \"createdBy\" | \"updatedBy\" | \"createdAt\" | \"updatedAt\" | \"apiKeyOwner\" | \"throttle\" | \"notifyWhen\" | \"mutedInstanceIds\" | \"executionStatus\">>; find: ({ options: { fields, ...options }, }?: { options?: ", "FindOptions", " | undefined; }) => Promise<", { @@ -2922,7 +2922,7 @@ "description": [], "source": { "path": "x-pack/plugins/alerting/common/index.ts", - "lineNumber": 28 + "lineNumber": 30 }, "signature": [ "\"alerts\"" @@ -3006,16 +3006,16 @@ }, { "tags": [], - "id": "def-common.BASE_ALERT_API_PATH", + "id": "def-common.BASE_ALERTING_API_PATH", "type": "string", - "label": "BASE_ALERT_API_PATH", + "label": "BASE_ALERTING_API_PATH", "description": [], "source": { "path": "x-pack/plugins/alerting/common/index.ts", - "lineNumber": 27 + "lineNumber": 28 }, "signature": [ - "\"/api/alerts\"" + "\"/api/alerting\"" ], "initialIsOpen": false }, @@ -3034,6 +3034,36 @@ ], "initialIsOpen": false }, + { + "tags": [], + "id": "def-common.INTERNAL_BASE_ALERTING_API_PATH", + "type": "string", + "label": "INTERNAL_BASE_ALERTING_API_PATH", + "description": [], + "source": { + "path": "x-pack/plugins/alerting/common/index.ts", + "lineNumber": 29 + }, + "signature": [ + "\"/internal/alerting\"" + ], + "initialIsOpen": false + }, + { + "tags": [], + "id": "def-common.LEGACY_BASE_ALERT_API_PATH", + "type": "string", + "label": "LEGACY_BASE_ALERT_API_PATH", + "description": [], + "source": { + "path": "x-pack/plugins/alerting/common/index.ts", + "lineNumber": 27 + }, + "signature": [ + "\"/api/alerts\"" + ], + "initialIsOpen": false + }, { "id": "def-common.RawAlertInstance", "type": "Type", diff --git a/api_docs/apm.json b/api_docs/apm.json index ac26de577cf0f9..7ddf4f2548d849 100644 --- a/api_docs/apm.json +++ b/api_docs/apm.json @@ -747,7 +747,7 @@ "text": "APMEventESSearchRequest" }, ">(params: TParams, { includeLegacyData }?: { includeLegacyData?: boolean | undefined; }): Promise<", - "ESSearchResponse", + "InferSearchResponseOf", " void; }" + "{ addProcessorDefinition: (processor: unknown) => void; }" ], "lifecycle": "start", "initialIsOpen": true diff --git a/api_docs/core.json b/api_docs/core.json index e02bd33d6671b4..cb416cba80078d 100644 --- a/api_docs/core.json +++ b/api_docs/core.json @@ -1431,7 +1431,7 @@ "description": [], "source": { "path": "src/core/public/doc_links/doc_links_service.ts", - "lineNumber": 300 + "lineNumber": 302 } }, { @@ -1442,7 +1442,7 @@ "description": [], "source": { "path": "src/core/public/doc_links/doc_links_service.ts", - "lineNumber": 301 + "lineNumber": 303 } }, { @@ -1453,7 +1453,7 @@ "description": [], "source": { "path": "src/core/public/doc_links/doc_links_service.ts", - "lineNumber": 302 + "lineNumber": 304 }, "signature": [ "{ readonly dashboard: { readonly guide: string; readonly drilldowns: string; readonly drilldownsTriggerPicker: string; readonly urlDrilldownTemplateSyntax: string; readonly urlDrilldownVariables: string; }; readonly discover: Record; readonly filebeat: { readonly base: string; readonly installation: string; readonly configuration: string; readonly elasticsearchOutput: string; readonly elasticsearchModule: string; readonly startup: string; readonly exportedFields: string; }; readonly auditbeat: { readonly base: string; }; readonly metricbeat: { readonly base: string; readonly configure: string; readonly httpEndpoint: string; readonly install: string; readonly start: string; }; readonly enterpriseSearch: { readonly base: string; readonly appSearchBase: string; readonly workplaceSearchBase: string; }; readonly heartbeat: { readonly base: string; }; readonly logstash: { readonly base: string; }; readonly functionbeat: { readonly base: string; }; readonly winlogbeat: { readonly base: string; }; readonly aggs: { readonly composite: string; readonly composite_missing_bucket: string; readonly date_histogram: string; readonly date_range: string; readonly date_format_pattern: string; readonly filter: string; readonly filters: string; readonly geohash_grid: string; readonly histogram: string; readonly ip_range: string; readonly range: string; readonly significant_terms: string; readonly terms: string; readonly avg: string; readonly avg_bucket: string; readonly max_bucket: string; readonly min_bucket: string; readonly sum_bucket: string; readonly cardinality: string; readonly count: string; readonly cumulative_sum: string; readonly derivative: string; readonly geo_bounds: string; readonly geo_centroid: string; readonly max: string; readonly median: string; readonly min: string; readonly moving_avg: string; readonly percentile_ranks: string; readonly serial_diff: string; readonly std_dev: string; readonly sum: string; readonly top_hits: string; }; readonly runtimeFields: string; readonly scriptedFields: { readonly scriptFields: string; readonly scriptAggs: string; readonly painless: string; readonly painlessApi: string; readonly painlessLangSpec: string; readonly painlessSyntax: string; readonly painlessWalkthrough: string; readonly luceneExpressions: string; }; readonly indexPatterns: { readonly introduction: string; readonly fieldFormattersNumber: string; readonly fieldFormattersString: string; }; readonly addData: string; readonly kibana: string; readonly elasticsearch: Record; readonly siem: { readonly guide: string; readonly gettingStarted: string; }; readonly query: { readonly eql: string; readonly luceneQuerySyntax: string; readonly queryDsl: string; readonly kueryQuerySyntax: string; }; readonly date: { readonly dateMath: string; readonly dateMathIndexNames: string; }; readonly management: Record; readonly ml: Record; readonly transforms: Record; readonly visualize: Record; readonly apis: Readonly<{ createIndex: string; createSnapshotLifecyclePolicy: string; createRoleMapping: string; createRoleMappingTemplates: string; createApiKey: string; createPipeline: string; createTransformRequest: string; cronExpressions: string; executeWatchActionModes: string; indexExists: string; openIndex: string; putComponentTemplate: string; painlessExecute: string; painlessExecuteAPIContexts: string; putComponentTemplateMetadata: string; putSnapshotLifecyclePolicy: string; putWatch: string; updateTransform: string; }>; readonly observability: Record; readonly alerting: Record; readonly maps: Record; readonly monitoring: Record; readonly security: Readonly<{ apiKeyServiceSettings: string; clusterPrivileges: string; elasticsearchSettings: string; elasticsearchEnableSecurity: string; indicesPrivileges: string; kibanaTLS: string; kibanaPrivileges: string; mappingRoles: string; mappingRolesFieldRules: string; runAsPrivilege: string; }>; readonly watcher: Record; readonly ccs: Record; readonly plugins: Record; readonly snapshotRestore: Record; readonly ingest: Record; }" @@ -1462,7 +1462,7 @@ ], "source": { "path": "src/core/public/doc_links/doc_links_service.ts", - "lineNumber": 299 + "lineNumber": 301 }, "initialIsOpen": false }, @@ -3833,7 +3833,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 141 + "lineNumber": 142 }, "signature": [ "string | undefined" @@ -3842,7 +3842,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 139 + "lineNumber": 140 }, "initialIsOpen": false }, @@ -3865,7 +3865,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 78 + "lineNumber": 79 }, "signature": [ "string | string[]" @@ -3879,7 +3879,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 79 + "lineNumber": 80 }, "signature": [ "number | undefined" @@ -3893,7 +3893,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 80 + "lineNumber": 81 }, "signature": [ "number | undefined" @@ -3907,7 +3907,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 81 + "lineNumber": 82 }, "signature": [ "string | undefined" @@ -3916,15 +3916,15 @@ { "tags": [], "id": "def-public.SavedObjectsFindOptions.sortOrder", - "type": "string", + "type": "CompoundType", "label": "sortOrder", "description": [], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 82 + "lineNumber": 83 }, "signature": [ - "string | undefined" + "\"asc\" | \"desc\" | \"_doc\" | undefined" ] }, { @@ -3937,7 +3937,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 88 + "lineNumber": 89 }, "signature": [ "string[] | undefined" @@ -3953,7 +3953,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 90 + "lineNumber": 91 }, "signature": [ "string | undefined" @@ -3969,7 +3969,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 92 + "lineNumber": 93 }, "signature": [ "string[] | undefined" @@ -3985,10 +3985,10 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 96 + "lineNumber": 97 }, "signature": [ - "unknown[] | undefined" + "string[] | undefined" ] }, { @@ -4001,7 +4001,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 101 + "lineNumber": 102 }, "signature": [ "string[] | undefined" @@ -4017,7 +4017,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 107 + "lineNumber": 108 }, "signature": [ { @@ -4048,7 +4048,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 111 + "lineNumber": 112 }, "signature": [ "\"AND\" | \"OR\" | undefined" @@ -4064,7 +4064,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 116 + "lineNumber": 117 }, "signature": [ "\"AND\" | \"OR\" | undefined" @@ -4078,7 +4078,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 117 + "lineNumber": 118 }, "signature": [ "any" @@ -4092,7 +4092,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 118 + "lineNumber": 119 }, "signature": [ "string[] | undefined" @@ -4108,7 +4108,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 126 + "lineNumber": 127 }, "signature": [ "Map | undefined" @@ -4124,7 +4124,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 128 + "lineNumber": 129 }, "signature": [ "string | undefined" @@ -4140,7 +4140,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 132 + "lineNumber": 133 }, "signature": [ { @@ -4156,7 +4156,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 77 + "lineNumber": 78 }, "initialIsOpen": false }, @@ -4177,7 +4177,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 61 + "lineNumber": 62 } }, { @@ -4188,13 +4188,13 @@ "description": [], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 62 + "lineNumber": 63 } } ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 60 + "lineNumber": 61 }, "initialIsOpen": false }, @@ -5753,7 +5753,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 226 + "lineNumber": 227 }, "signature": [ "\"multiple\" | \"single\" | \"multiple-isolated\" | \"agnostic\"" @@ -8002,7 +8002,7 @@ ], "source": { "path": "src/core/server/index.ts", - "lineNumber": 459 + "lineNumber": 462 }, "signature": [ { @@ -8024,7 +8024,7 @@ ], "source": { "path": "src/core/server/index.ts", - "lineNumber": 461 + "lineNumber": 464 }, "signature": [ { @@ -8046,7 +8046,7 @@ ], "source": { "path": "src/core/server/index.ts", - "lineNumber": 463 + "lineNumber": 466 }, "signature": [ { @@ -8068,7 +8068,7 @@ ], "source": { "path": "src/core/server/index.ts", - "lineNumber": 465 + "lineNumber": 468 }, "signature": [ { @@ -8099,7 +8099,7 @@ ], "source": { "path": "src/core/server/index.ts", - "lineNumber": 470 + "lineNumber": 473 }, "signature": [ { @@ -8121,7 +8121,7 @@ ], "source": { "path": "src/core/server/index.ts", - "lineNumber": 472 + "lineNumber": 475 }, "signature": [ { @@ -8143,7 +8143,7 @@ ], "source": { "path": "src/core/server/index.ts", - "lineNumber": 474 + "lineNumber": 477 }, "signature": [ { @@ -8165,7 +8165,7 @@ ], "source": { "path": "src/core/server/index.ts", - "lineNumber": 476 + "lineNumber": 479 }, "signature": [ { @@ -8187,7 +8187,7 @@ ], "source": { "path": "src/core/server/index.ts", - "lineNumber": 478 + "lineNumber": 481 }, "signature": [ { @@ -8209,7 +8209,7 @@ ], "source": { "path": "src/core/server/index.ts", - "lineNumber": 480 + "lineNumber": 483 }, "signature": [ { @@ -8231,7 +8231,7 @@ ], "source": { "path": "src/core/server/index.ts", - "lineNumber": 482 + "lineNumber": 485 }, "signature": [ { @@ -8247,7 +8247,7 @@ ], "source": { "path": "src/core/server/index.ts", - "lineNumber": 457 + "lineNumber": 460 }, "initialIsOpen": false }, @@ -8272,7 +8272,7 @@ ], "source": { "path": "src/core/server/index.ts", - "lineNumber": 505 + "lineNumber": 508 }, "signature": [ { @@ -8294,7 +8294,7 @@ ], "source": { "path": "src/core/server/index.ts", - "lineNumber": 507 + "lineNumber": 510 }, "signature": [ { @@ -8316,7 +8316,7 @@ ], "source": { "path": "src/core/server/index.ts", - "lineNumber": 509 + "lineNumber": 512 }, "signature": [ { @@ -8338,7 +8338,7 @@ ], "source": { "path": "src/core/server/index.ts", - "lineNumber": 511 + "lineNumber": 514 }, "signature": [ { @@ -8360,7 +8360,7 @@ ], "source": { "path": "src/core/server/index.ts", - "lineNumber": 513 + "lineNumber": 516 }, "signature": [ { @@ -8382,7 +8382,7 @@ ], "source": { "path": "src/core/server/index.ts", - "lineNumber": 515 + "lineNumber": 518 }, "signature": [ { @@ -8397,7 +8397,7 @@ ], "source": { "path": "src/core/server/index.ts", - "lineNumber": 503 + "lineNumber": 506 }, "initialIsOpen": false }, @@ -14272,7 +14272,7 @@ "description": [], "source": { "path": "src/core/server/index.ts", - "lineNumber": 425 + "lineNumber": 428 }, "signature": [ "{ savedObjects: { client: Pick<", @@ -14283,7 +14283,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">; typeRegistry: Pick<", + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">; typeRegistry: Pick<", { "pluginId": "core", "scope": "server", @@ -14307,7 +14307,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">; getExporter: (client: Pick<", + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">; getExporter: (client: Pick<", { "pluginId": "core", "scope": "server", @@ -14320,7 +14320,7 @@ ], "source": { "path": "src/core/server/index.ts", - "lineNumber": 424 + "lineNumber": 427 }, "initialIsOpen": false }, @@ -15689,7 +15689,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">) => ", + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">) => ", { "pluginId": "core", "scope": "server", @@ -15715,7 +15715,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">" + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">" ], "description": [], "source": { @@ -15965,7 +15965,7 @@ "lineNumber": 22 }, "signature": [ - "Pick & { transport: { request(params: TransportRequestParams, options?: TransportRequestOptions | undefined): TransportRequestPromise; }; }" + "Pick & { transport: { request(params: TransportRequestParams, options?: TransportRequestOptions | undefined): TransportRequestPromise; }; }" ], "initialIsOpen": false }, @@ -16616,7 +16616,7 @@ ], "source": { "path": "src/core/server/index.ts", - "lineNumber": 493 + "lineNumber": 496 }, "signature": [ "() => Promise<[", diff --git a/api_docs/core_http.json b/api_docs/core_http.json index 8053550cc0e805..ce5ceb2840ec70 100644 --- a/api_docs/core_http.json +++ b/api_docs/core_http.json @@ -974,7 +974,7 @@ "lineNumber": 197 }, "signature": [ - "\"error\" | \"manual\" | \"follow\" | undefined" + "\"error\" | \"follow\" | \"manual\" | undefined" ] }, { diff --git a/api_docs/core_saved_objects.json b/api_docs/core_saved_objects.json index d862df7ef10bbc..54f13f3911be6b 100644 --- a/api_docs/core_saved_objects.json +++ b/api_docs/core_saved_objects.json @@ -1530,7 +1530,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 397 + "lineNumber": 402 }, "signature": [ "typeof ", @@ -1551,7 +1551,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 398 + "lineNumber": 403 }, "signature": [ "typeof ", @@ -1601,7 +1601,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 414 + "lineNumber": 419 } }, { @@ -1614,7 +1614,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 414 + "lineNumber": 419 } }, { @@ -1634,7 +1634,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 414 + "lineNumber": 419 } } ], @@ -1642,7 +1642,7 @@ "returnComment": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 414 + "lineNumber": 419 } }, { @@ -1697,7 +1697,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 425 + "lineNumber": 430 } }, { @@ -1717,7 +1717,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 426 + "lineNumber": 431 } } ], @@ -1725,7 +1725,7 @@ "returnComment": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 424 + "lineNumber": 429 } }, { @@ -1780,7 +1780,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 439 + "lineNumber": 444 } }, { @@ -1799,7 +1799,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 440 + "lineNumber": 445 } } ], @@ -1807,7 +1807,7 @@ "returnComment": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 438 + "lineNumber": 443 } }, { @@ -1839,7 +1839,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 452 + "lineNumber": 457 } }, { @@ -1852,7 +1852,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 452 + "lineNumber": 457 } }, { @@ -1871,7 +1871,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 452 + "lineNumber": 457 } } ], @@ -1879,7 +1879,7 @@ "returnComment": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 452 + "lineNumber": 457 } }, { @@ -1925,7 +1925,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 461 + "lineNumber": 466 } } ], @@ -1933,7 +1933,7 @@ "returnComment": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 461 + "lineNumber": 466 } }, { @@ -1990,7 +1990,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 477 + "lineNumber": 482 } }, { @@ -2009,7 +2009,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 478 + "lineNumber": 483 } } ], @@ -2017,7 +2017,7 @@ "returnComment": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 476 + "lineNumber": 481 } }, { @@ -2059,7 +2059,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 491 + "lineNumber": 496 } }, { @@ -2074,7 +2074,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 492 + "lineNumber": 497 } }, { @@ -2093,7 +2093,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 493 + "lineNumber": 498 } } ], @@ -2101,7 +2101,7 @@ "returnComment": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 490 + "lineNumber": 495 } }, { @@ -2143,7 +2143,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 506 + "lineNumber": 511 } }, { @@ -2158,7 +2158,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 507 + "lineNumber": 512 } }, { @@ -2177,7 +2177,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 508 + "lineNumber": 513 } } ], @@ -2185,7 +2185,7 @@ "returnComment": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 505 + "lineNumber": 510 } }, { @@ -2225,7 +2225,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 521 + "lineNumber": 526 } }, { @@ -2238,7 +2238,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 522 + "lineNumber": 527 } }, { @@ -2251,7 +2251,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 523 + "lineNumber": 528 } }, { @@ -2270,7 +2270,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 524 + "lineNumber": 529 } } ], @@ -2278,7 +2278,7 @@ "returnComment": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 520 + "lineNumber": 525 } }, { @@ -2318,7 +2318,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 538 + "lineNumber": 543 } }, { @@ -2331,7 +2331,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 539 + "lineNumber": 544 } }, { @@ -2344,7 +2344,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 540 + "lineNumber": 545 } }, { @@ -2363,7 +2363,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 541 + "lineNumber": 546 } } ], @@ -2371,7 +2371,7 @@ "returnComment": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 537 + "lineNumber": 542 } }, { @@ -2411,7 +2411,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 555 + "lineNumber": 560 } }, { @@ -2424,7 +2424,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 556 + "lineNumber": 561 } }, { @@ -2437,7 +2437,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 557 + "lineNumber": 562 } }, { @@ -2456,7 +2456,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 558 + "lineNumber": 563 } } ], @@ -2464,7 +2464,7 @@ "returnComment": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 554 + "lineNumber": 559 } }, { @@ -2519,7 +2519,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 569 + "lineNumber": 574 } }, { @@ -2539,7 +2539,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 570 + "lineNumber": 575 } } ], @@ -2547,7 +2547,7 @@ "returnComment": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 568 + "lineNumber": 573 } }, { @@ -2587,7 +2587,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 579 + "lineNumber": 584 } }, { @@ -2600,7 +2600,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 580 + "lineNumber": 585 } }, { @@ -2620,7 +2620,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 581 + "lineNumber": 586 } } ], @@ -2628,7 +2628,7 @@ "returnComment": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 578 + "lineNumber": 583 } }, { @@ -2655,7 +2655,7 @@ ">" ], "description": [ - "\nOpens a Point In Time (PIT) against the indices for the specified Saved Object types.\nThe returned `id` can then be passed to {@link SavedObjectsClient.find} to search\nagainst that PIT." + "\nOpens a Point In Time (PIT) against the indices for the specified Saved Object types.\nThe returned `id` can then be passed to {@link SavedObjectsClient.find} to search\nagainst that PIT.\n\nOnly use this API if you have an advanced use case that's not solved by the\n{@link SavedObjectsClient.createPointInTimeFinder} method." ], "children": [ { @@ -2668,7 +2668,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 592 + "lineNumber": 600 } }, { @@ -2687,7 +2687,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 593 + "lineNumber": 601 } } ], @@ -2695,7 +2695,7 @@ "returnComment": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 591 + "lineNumber": 599 } }, { @@ -2722,7 +2722,7 @@ ">" ], "description": [ - "\nCloses a Point In Time (PIT) by ID. This simply proxies the request to ES via the\nElasticsearch client, and is included in the Saved Objects Client as a convenience\nfor consumers who are using {@link SavedObjectsClient.openPointInTimeForType}." + "\nCloses a Point In Time (PIT) by ID. This simply proxies the request to ES via the\nElasticsearch client, and is included in the Saved Objects Client as a convenience\nfor consumers who are using {@link SavedObjectsClient.openPointInTimeForType}.\n\nOnly use this API if you have an advanced use case that's not solved by the\n{@link SavedObjectsClient.createPointInTimeFinder} method." ], "children": [ { @@ -2735,7 +2735,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 603 + "lineNumber": 614 } }, { @@ -2755,7 +2755,90 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 603 + "lineNumber": 614 + } + } + ], + "tags": [], + "returnComment": [], + "source": { + "path": "src/core/server/saved_objects/service/saved_objects_client.ts", + "lineNumber": 614 + } + }, + { + "id": "def-server.SavedObjectsClient.createPointInTimeFinder", + "type": "Function", + "label": "createPointInTimeFinder", + "signature": [ + "(findOptions: Pick<", + { + "pluginId": "core", + "scope": "server", + "docId": "kibCoreSavedObjectsPluginApi", + "section": "def-server.SavedObjectsFindOptions", + "text": "SavedObjectsFindOptions" + }, + ", \"type\" | \"filter\" | \"fields\" | \"search\" | \"perPage\" | \"sortField\" | \"sortOrder\" | \"searchFields\" | \"rootSearchFields\" | \"hasReference\" | \"hasReferenceOperator\" | \"defaultSearchOperator\" | \"namespaces\" | \"typeToNamespacesMap\" | \"preference\">, dependencies?: ", + { + "pluginId": "core", + "scope": "server", + "docId": "kibCoreSavedObjectsPluginApi", + "section": "def-server.SavedObjectsCreatePointInTimeFinderDependencies", + "text": "SavedObjectsCreatePointInTimeFinderDependencies" + }, + " | undefined) => ", + { + "pluginId": "core", + "scope": "server", + "docId": "kibCoreSavedObjectsPluginApi", + "section": "def-server.ISavedObjectsPointInTimeFinder", + "text": "ISavedObjectsPointInTimeFinder" + } + ], + "description": [ + "\nReturns a {@link ISavedObjectsPointInTimeFinder} to help page through\nlarge sets of saved objects. We strongly recommend using this API for\nany `find` queries that might return more than 1000 saved objects,\nhowever this API is only intended for use in server-side \"batch\"\nprocessing of objects where you are collecting all objects in memory\nor streaming them back to the client.\n\nDo NOT use this API in a route handler to facilitate paging through\nsaved objects on the client-side unless you are streaming all of the\nresults back to the client at once. Because the returned generator is\nstateful, you cannot rely on subsequent http requests retrieving new\npages from the same Kibana server in multi-instance deployments.\n\nThe generator wraps calls to {@link SavedObjectsClient.find} and iterates\nover multiple pages of results using `_pit` and `search_after`. This will\nopen a new Point-In-Time (PIT), and continue paging until a set of\nresults is received that's smaller than the designated `perPage`.\n\nOnce you have retrieved all of the results you need, it is recommended\nto call `close()` to clean up the PIT and prevent Elasticsearch from\nconsuming resources unnecessarily. This is only required if you are\ndone iterating and have not yet paged through all of the results: the\nPIT will automatically be closed for you once you reach the last page\nof results, or if the underlying call to `find` fails for any reason.\n" + ], + "children": [ + { + "type": "Object", + "label": "findOptions", + "isRequired": true, + "signature": [ + "Pick<", + { + "pluginId": "core", + "scope": "server", + "docId": "kibCoreSavedObjectsPluginApi", + "section": "def-server.SavedObjectsFindOptions", + "text": "SavedObjectsFindOptions" + }, + ", \"type\" | \"filter\" | \"fields\" | \"search\" | \"perPage\" | \"sortField\" | \"sortOrder\" | \"searchFields\" | \"rootSearchFields\" | \"hasReference\" | \"hasReferenceOperator\" | \"defaultSearchOperator\" | \"namespaces\" | \"typeToNamespacesMap\" | \"preference\">" + ], + "description": [], + "source": { + "path": "src/core/server/saved_objects/service/saved_objects_client.ts", + "lineNumber": 664 + } + }, + { + "type": "Object", + "label": "dependencies", + "isRequired": false, + "signature": [ + { + "pluginId": "core", + "scope": "server", + "docId": "kibCoreSavedObjectsPluginApi", + "section": "def-server.SavedObjectsCreatePointInTimeFinderDependencies", + "text": "SavedObjectsCreatePointInTimeFinderDependencies" + }, + " | undefined" + ], + "description": [], + "source": { + "path": "src/core/server/saved_objects/service/saved_objects_client.ts", + "lineNumber": 665 } } ], @@ -2763,13 +2846,13 @@ "returnComment": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 603 + "lineNumber": 663 } } ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 396 + "lineNumber": 401 }, "initialIsOpen": false }, @@ -4167,7 +4250,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/export/saved_objects_exporter.ts", - "lineNumber": 38 + "lineNumber": 37 }, "signature": [ "Pick<", @@ -4178,7 +4261,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">" + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">" ] }, { @@ -4189,7 +4272,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/export/saved_objects_exporter.ts", - "lineNumber": 39 + "lineNumber": 38 }, "signature": [ "Record" + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">" ] }, { @@ -4274,7 +4357,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/export/saved_objects_exporter.ts", - "lineNumber": 50 + "lineNumber": 49 }, "signature": [ "Pick<", @@ -4296,7 +4379,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/export/saved_objects_exporter.ts", - "lineNumber": 51 + "lineNumber": 50 } }, { @@ -4307,7 +4390,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/export/saved_objects_exporter.ts", - "lineNumber": 52 + "lineNumber": 51 }, "signature": [ "Logger" @@ -4316,7 +4399,7 @@ ], "source": { "path": "src/core/server/saved_objects/export/saved_objects_exporter.ts", - "lineNumber": 48 + "lineNumber": 47 } } ], @@ -4324,7 +4407,7 @@ "returnComment": [], "source": { "path": "src/core/server/saved_objects/export/saved_objects_exporter.ts", - "lineNumber": 43 + "lineNumber": 42 } }, { @@ -4364,7 +4447,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/export/saved_objects_exporter.ts", - "lineNumber": 75 + "lineNumber": 74 } } ], @@ -4374,7 +4457,7 @@ "returnComment": [], "source": { "path": "src/core/server/saved_objects/export/saved_objects_exporter.ts", - "lineNumber": 75 + "lineNumber": 74 } }, { @@ -4414,7 +4497,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/export/saved_objects_exporter.ts", - "lineNumber": 93 + "lineNumber": 92 } } ], @@ -4424,13 +4507,13 @@ "returnComment": [], "source": { "path": "src/core/server/saved_objects/export/saved_objects_exporter.ts", - "lineNumber": 93 + "lineNumber": 92 } } ], "source": { "path": "src/core/server/saved_objects/export/saved_objects_exporter.ts", - "lineNumber": 37 + "lineNumber": 36 }, "initialIsOpen": false }, @@ -4727,7 +4810,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">" + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">" ] }, { @@ -4820,7 +4903,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">" + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">" ] }, { @@ -5258,7 +5341,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 237 + "lineNumber": 257 } }, { @@ -5271,7 +5354,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 238 + "lineNumber": 258 } }, { @@ -5290,7 +5373,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 239 + "lineNumber": 259 } } ], @@ -5302,7 +5385,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 236 + "lineNumber": 256 } }, { @@ -5359,7 +5442,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 330 + "lineNumber": 350 } }, { @@ -5378,7 +5461,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 331 + "lineNumber": 351 } } ], @@ -5390,7 +5473,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 329 + "lineNumber": 349 } }, { @@ -5445,7 +5528,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 517 + "lineNumber": 541 } }, { @@ -5464,7 +5547,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 518 + "lineNumber": 542 } } ], @@ -5472,7 +5555,7 @@ "returnComment": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 516 + "lineNumber": 540 } }, { @@ -5504,7 +5587,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 602 + "lineNumber": 627 } }, { @@ -5517,7 +5600,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 602 + "lineNumber": 627 } }, { @@ -5536,7 +5619,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 602 + "lineNumber": 627 } } ], @@ -5546,7 +5629,7 @@ "returnComment": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 602 + "lineNumber": 627 } }, { @@ -5578,7 +5661,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 664 + "lineNumber": 690 } }, { @@ -5597,7 +5680,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 665 + "lineNumber": 691 } } ], @@ -5607,7 +5690,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 663 + "lineNumber": 689 } }, { @@ -5651,7 +5734,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 725 + "lineNumber": 751 } } ], @@ -5663,7 +5746,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 725 + "lineNumber": 751 } }, { @@ -5720,7 +5803,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 875 + "lineNumber": 906 } }, { @@ -5739,7 +5822,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 876 + "lineNumber": 907 } } ], @@ -5751,7 +5834,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 874 + "lineNumber": 905 } }, { @@ -5791,7 +5874,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 960 + "lineNumber": 993 } }, { @@ -5804,7 +5887,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 961 + "lineNumber": 994 } }, { @@ -5823,7 +5906,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 962 + "lineNumber": 995 } } ], @@ -5835,7 +5918,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 959 + "lineNumber": 992 } }, { @@ -5875,7 +5958,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 998 + "lineNumber": 1035 } }, { @@ -5888,7 +5971,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 999 + "lineNumber": 1036 } }, { @@ -5907,7 +5990,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1000 + "lineNumber": 1037 } } ], @@ -5919,7 +6002,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 997 + "lineNumber": 1034 } }, { @@ -5959,7 +6042,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1117 + "lineNumber": 1160 } }, { @@ -5972,7 +6055,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1118 + "lineNumber": 1161 } }, { @@ -5985,7 +6068,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1119 + "lineNumber": 1162 } }, { @@ -6004,7 +6087,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1120 + "lineNumber": 1163 } } ], @@ -6014,7 +6097,7 @@ "returnComment": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1116 + "lineNumber": 1159 } }, { @@ -6054,7 +6137,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1190 + "lineNumber": 1232 } }, { @@ -6067,7 +6150,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1191 + "lineNumber": 1233 } }, { @@ -6080,7 +6163,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1192 + "lineNumber": 1234 } }, { @@ -6099,7 +6182,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1193 + "lineNumber": 1235 } } ], @@ -6107,7 +6190,7 @@ "returnComment": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1189 + "lineNumber": 1231 } }, { @@ -6147,7 +6230,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1253 + "lineNumber": 1295 } }, { @@ -6160,7 +6243,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1254 + "lineNumber": 1296 } }, { @@ -6173,7 +6256,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1255 + "lineNumber": 1297 } }, { @@ -6192,7 +6275,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1256 + "lineNumber": 1298 } } ], @@ -6200,7 +6283,7 @@ "returnComment": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1252 + "lineNumber": 1294 } }, { @@ -6257,7 +6340,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1358 + "lineNumber": 1401 } }, { @@ -6276,7 +6359,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1359 + "lineNumber": 1402 } } ], @@ -6288,7 +6371,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1357 + "lineNumber": 1400 } }, { @@ -6328,7 +6411,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1573 + "lineNumber": 1620 } }, { @@ -6341,7 +6424,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1574 + "lineNumber": 1621 } }, { @@ -6360,7 +6443,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1575 + "lineNumber": 1622 } } ], @@ -6368,7 +6451,7 @@ "returnComment": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1572 + "lineNumber": 1619 } }, { @@ -6392,7 +6475,7 @@ "section": "def-server.SavedObjectsIncrementCounterOptions", "text": "SavedObjectsIncrementCounterOptions" }, - ") => Promise<", + ") => Promise<", { "pluginId": "core", "scope": "common", @@ -6418,7 +6501,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1670 + "lineNumber": 1731 } }, { @@ -6433,7 +6516,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1671 + "lineNumber": 1732 } }, { @@ -6456,7 +6539,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1672 + "lineNumber": 1733 } }, { @@ -6470,14 +6553,15 @@ "docId": "kibCoreSavedObjectsPluginApi", "section": "def-server.SavedObjectsIncrementCounterOptions", "text": "SavedObjectsIncrementCounterOptions" - } + }, + "" ], "description": [ "- {@link SavedObjectsIncrementCounterOptions}" ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1673 + "lineNumber": 1734 } } ], @@ -6487,7 +6571,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1669 + "lineNumber": 1730 } }, { @@ -6514,7 +6598,7 @@ ">" ], "description": [ - "\nOpens a Point In Time (PIT) against the indices for the specified Saved Object types.\nThe returned `id` can then be passed to `SavedObjects.find` to search against that PIT.\n" + "\nOpens a Point In Time (PIT) against the indices for the specified Saved Object types.\nThe returned `id` can then be passed to `SavedObjects.find` to search against that PIT.\n\nOnly use this API if you have an advanced use case that's not solved by the\n{@link SavedObjectsRepository.createPointInTimeFinder} method.\n" ], "children": [ { @@ -6527,7 +6611,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1821 + "lineNumber": 1891 } }, { @@ -6546,7 +6630,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1822 + "lineNumber": 1892 } } ], @@ -6558,7 +6642,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1820 + "lineNumber": 1890 } }, { @@ -6585,7 +6669,7 @@ ">" ], "description": [ - "\nCloses a Point In Time (PIT) by ID. This simply proxies the request to ES\nvia the Elasticsearch client, and is included in the Saved Objects Client\nas a convenience for consumers who are using `openPointInTimeForType`.\n" + "\nCloses a Point In Time (PIT) by ID. This simply proxies the request to ES\nvia the Elasticsearch client, and is included in the Saved Objects Client\nas a convenience for consumers who are using `openPointInTimeForType`.\n\nOnly use this API if you have an advanced use case that's not solved by the\n{@link SavedObjectsRepository.createPointInTimeFinder} method.\n" ], "children": [ { @@ -6598,7 +6682,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1890 + "lineNumber": 1967 } }, { @@ -6620,7 +6704,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1891 + "lineNumber": 1968 } } ], @@ -6630,13 +6714,96 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 1889 + "lineNumber": 1966 + } + }, + { + "id": "def-server.SavedObjectsRepository.createPointInTimeFinder", + "type": "Function", + "label": "createPointInTimeFinder", + "signature": [ + "(findOptions: Pick<", + { + "pluginId": "core", + "scope": "server", + "docId": "kibCoreSavedObjectsPluginApi", + "section": "def-server.SavedObjectsFindOptions", + "text": "SavedObjectsFindOptions" + }, + ", \"type\" | \"filter\" | \"fields\" | \"search\" | \"perPage\" | \"sortField\" | \"sortOrder\" | \"searchFields\" | \"rootSearchFields\" | \"hasReference\" | \"hasReferenceOperator\" | \"defaultSearchOperator\" | \"namespaces\" | \"typeToNamespacesMap\" | \"preference\">, dependencies?: ", + { + "pluginId": "core", + "scope": "server", + "docId": "kibCoreSavedObjectsPluginApi", + "section": "def-server.SavedObjectsCreatePointInTimeFinderDependencies", + "text": "SavedObjectsCreatePointInTimeFinderDependencies" + }, + " | undefined) => ", + { + "pluginId": "core", + "scope": "server", + "docId": "kibCoreSavedObjectsPluginApi", + "section": "def-server.ISavedObjectsPointInTimeFinder", + "text": "ISavedObjectsPointInTimeFinder" + } + ], + "description": [ + "\nReturns a {@link ISavedObjectsPointInTimeFinder} to help page through\nlarge sets of saved objects. We strongly recommend using this API for\nany `find` queries that might return more than 1000 saved objects,\nhowever this API is only intended for use in server-side \"batch\"\nprocessing of objects where you are collecting all objects in memory\nor streaming them back to the client.\n\nDo NOT use this API in a route handler to facilitate paging through\nsaved objects on the client-side unless you are streaming all of the\nresults back to the client at once. Because the returned generator is\nstateful, you cannot rely on subsequent http requests retrieving new\npages from the same Kibana server in multi-instance deployments.\n\nThis generator wraps calls to {@link SavedObjectsRepository.find} and\niterates over multiple pages of results using `_pit` and `search_after`.\nThis will open a new Point-In-Time (PIT), and continue paging until a\nset of results is received that's smaller than the designated `perPage`.\n\nOnce you have retrieved all of the results you need, it is recommended\nto call `close()` to clean up the PIT and prevent Elasticsearch from\nconsuming resources unnecessarily. This is only required if you are\ndone iterating and have not yet paged through all of the results: the\nPIT will automatically be closed for you once you reach the last page\nof results, or if the underlying call to `find` fails for any reason.\n" + ], + "children": [ + { + "type": "Object", + "label": "findOptions", + "isRequired": true, + "signature": [ + "Pick<", + { + "pluginId": "core", + "scope": "server", + "docId": "kibCoreSavedObjectsPluginApi", + "section": "def-server.SavedObjectsFindOptions", + "text": "SavedObjectsFindOptions" + }, + ", \"type\" | \"filter\" | \"fields\" | \"search\" | \"perPage\" | \"sortField\" | \"sortOrder\" | \"searchFields\" | \"rootSearchFields\" | \"hasReference\" | \"hasReferenceOperator\" | \"defaultSearchOperator\" | \"namespaces\" | \"typeToNamespacesMap\" | \"preference\">" + ], + "description": [], + "source": { + "path": "src/core/server/saved_objects/service/lib/repository.ts", + "lineNumber": 2023 + } + }, + { + "type": "Object", + "label": "dependencies", + "isRequired": false, + "signature": [ + { + "pluginId": "core", + "scope": "server", + "docId": "kibCoreSavedObjectsPluginApi", + "section": "def-server.SavedObjectsCreatePointInTimeFinderDependencies", + "text": "SavedObjectsCreatePointInTimeFinderDependencies" + }, + " | undefined" + ], + "description": [], + "source": { + "path": "src/core/server/saved_objects/service/lib/repository.ts", + "lineNumber": 2024 + } + } + ], + "tags": [], + "returnComment": [], + "source": { + "path": "src/core/server/saved_objects/service/lib/repository.ts", + "lineNumber": 2022 } } ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 143 + "lineNumber": 158 }, "initialIsOpen": false }, @@ -7617,6 +7784,62 @@ ], "functions": [], "interfaces": [ + { + "id": "def-server.ISavedObjectsPointInTimeFinder", + "type": "Interface", + "label": "ISavedObjectsPointInTimeFinder", + "description": [], + "tags": [ + "public" + ], + "children": [ + { + "tags": [], + "id": "def-server.ISavedObjectsPointInTimeFinder.find", + "type": "Function", + "label": "find", + "description": [ + "\nAn async generator which wraps calls to `savedObjectsClient.find` and\niterates over multiple pages of results using `_pit` and `search_after`.\nThis will open a new Point-In-Time (PIT), and continue paging until a set\nof results is received that's smaller than the designated `perPage` size." + ], + "source": { + "path": "src/core/server/saved_objects/service/lib/point_in_time_finder.ts", + "lineNumber": 49 + }, + "signature": [ + "() => AsyncGenerator<", + { + "pluginId": "core", + "scope": "server", + "docId": "kibCoreSavedObjectsPluginApi", + "section": "def-server.SavedObjectsFindResponse", + "text": "SavedObjectsFindResponse" + }, + ", any, unknown>" + ] + }, + { + "tags": [], + "id": "def-server.ISavedObjectsPointInTimeFinder.close", + "type": "Function", + "label": "close", + "description": [ + "\nCloses the Point-In-Time associated with this finder instance.\n\nOnce you have retrieved all of the results you need, it is recommended\nto call `close()` to clean up the PIT and prevent Elasticsearch from\nconsuming resources unnecessarily. This is only required if you are\ndone iterating and have not yet paged through all of the results: the\nPIT will automatically be closed for you once you reach the last page\nof results, or if the underlying call to `find` fails for any reason." + ], + "source": { + "path": "src/core/server/saved_objects/service/lib/point_in_time_finder.ts", + "lineNumber": 60 + }, + "signature": [ + "() => Promise" + ] + } + ], + "source": { + "path": "src/core/server/saved_objects/service/lib/point_in_time_finder.ts", + "lineNumber": 42 + }, + "initialIsOpen": false + }, { "id": "def-server.SavedObjectExportBaseOptions", "type": "Interface", @@ -7843,7 +8066,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 219 + "lineNumber": 224 }, "signature": [ "string | undefined" @@ -7859,7 +8082,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 221 + "lineNumber": 226 }, "signature": [ "boolean | \"wait_for\" | undefined" @@ -7868,7 +8091,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 217 + "lineNumber": 222 }, "initialIsOpen": false }, @@ -7893,7 +8116,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 230 + "lineNumber": 235 }, "signature": [ "string[]" @@ -7902,7 +8125,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 228 + "lineNumber": 233 }, "initialIsOpen": false }, @@ -7927,7 +8150,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 141 + "lineNumber": 142 }, "signature": [ "string | undefined" @@ -7936,7 +8159,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 139 + "lineNumber": 140 }, "initialIsOpen": false }, @@ -7969,7 +8192,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 66 + "lineNumber": 71 }, "signature": [ "string | undefined" @@ -7983,7 +8206,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 67 + "lineNumber": 72 } }, { @@ -7994,7 +8217,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 68 + "lineNumber": 73 }, "signature": [ "T" @@ -8008,7 +8231,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 69 + "lineNumber": 74 }, "signature": [ "string | undefined" @@ -8022,7 +8245,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 70 + "lineNumber": 75 }, "signature": [ { @@ -8045,7 +8268,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 72 + "lineNumber": 77 }, "signature": [ { @@ -8068,7 +8291,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 82 + "lineNumber": 87 }, "signature": [ "string | undefined" @@ -8084,7 +8307,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 84 + "lineNumber": 89 }, "signature": [ "string | undefined" @@ -8100,7 +8323,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 91 + "lineNumber": 96 }, "signature": [ "string[] | undefined" @@ -8109,7 +8332,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 65 + "lineNumber": 70 }, "initialIsOpen": false }, @@ -8132,7 +8355,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 294 + "lineNumber": 299 } }, { @@ -8143,7 +8366,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 295 + "lineNumber": 300 } }, { @@ -8156,7 +8379,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 297 + "lineNumber": 302 }, "signature": [ "string[] | undefined" @@ -8165,7 +8388,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 293 + "lineNumber": 298 }, "initialIsOpen": false }, @@ -8198,7 +8421,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 120 + "lineNumber": 125 }, "signature": [ { @@ -8214,7 +8437,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 119 + "lineNumber": 124 }, "initialIsOpen": false }, @@ -8247,7 +8470,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 305 + "lineNumber": 310 }, "signature": [ { @@ -8263,7 +8486,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 304 + "lineNumber": 309 }, "initialIsOpen": false }, @@ -8306,7 +8529,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 101 + "lineNumber": 106 } }, { @@ -8319,7 +8542,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 103 + "lineNumber": 108 } }, { @@ -8332,7 +8555,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 105 + "lineNumber": 110 }, "signature": [ "Partial" @@ -8348,7 +8571,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 112 + "lineNumber": 117 }, "signature": [ "string | undefined" @@ -8357,7 +8580,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 98 + "lineNumber": 103 }, "initialIsOpen": false }, @@ -8399,7 +8622,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 275 + "lineNumber": 280 }, "signature": [ "boolean | \"wait_for\" | undefined" @@ -8408,7 +8631,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 273 + "lineNumber": 278 }, "initialIsOpen": false }, @@ -8441,7 +8664,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 313 + "lineNumber": 318 }, "signature": [ { @@ -8457,7 +8680,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 312 + "lineNumber": 317 }, "initialIsOpen": false }, @@ -8480,7 +8703,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 184 + "lineNumber": 189 } }, { @@ -8491,13 +8714,13 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 185 + "lineNumber": 190 } } ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 183 + "lineNumber": 188 }, "initialIsOpen": false }, @@ -8520,7 +8743,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 193 + "lineNumber": 198 }, "signature": [ "{ id: string; type: string; error: ", @@ -8537,7 +8760,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 192 + "lineNumber": 197 }, "initialIsOpen": false }, @@ -8617,7 +8840,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">" + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">" ] }, { @@ -8689,7 +8912,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 385 + "lineNumber": 390 } }, { @@ -8702,13 +8925,13 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 389 + "lineNumber": 394 } } ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 380 + "lineNumber": 385 }, "initialIsOpen": false }, @@ -8931,7 +9154,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 27 + "lineNumber": 32 }, "signature": [ "string | undefined" @@ -8947,7 +9170,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 29 + "lineNumber": 34 }, "signature": [ "boolean | undefined" @@ -8963,7 +9186,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 34 + "lineNumber": 39 }, "signature": [ "string | undefined" @@ -8979,7 +9202,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 36 + "lineNumber": 41 }, "signature": [ { @@ -9002,7 +9225,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 46 + "lineNumber": 51 }, "signature": [ "string | undefined" @@ -9016,7 +9239,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 47 + "lineNumber": 52 }, "signature": [ { @@ -9039,7 +9262,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 49 + "lineNumber": 54 }, "signature": [ "boolean | \"wait_for\" | undefined" @@ -9055,7 +9278,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 51 + "lineNumber": 56 }, "signature": [ "string | undefined" @@ -9071,7 +9294,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 58 + "lineNumber": 63 }, "signature": [ "string[] | undefined" @@ -9080,7 +9303,45 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 25 + "lineNumber": 30 + }, + "initialIsOpen": false + }, + { + "id": "def-server.SavedObjectsCreatePointInTimeFinderDependencies", + "type": "Interface", + "label": "SavedObjectsCreatePointInTimeFinderDependencies", + "description": [], + "tags": [ + "public" + ], + "children": [ + { + "tags": [], + "id": "def-server.SavedObjectsCreatePointInTimeFinderDependencies.client", + "type": "Object", + "label": "client", + "description": [], + "source": { + "path": "src/core/server/saved_objects/service/lib/point_in_time_finder.ts", + "lineNumber": 30 + }, + "signature": [ + "Pick, \"find\" | \"openPointInTimeForType\" | \"closePointInTime\">" + ] + } + ], + "source": { + "path": "src/core/server/saved_objects/service/lib/point_in_time_finder.ts", + "lineNumber": 29 }, "initialIsOpen": false }, @@ -9122,7 +9383,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 118 + "lineNumber": 133 }, "signature": [ "boolean | undefined" @@ -9131,7 +9392,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 116 + "lineNumber": 131 }, "initialIsOpen": false }, @@ -9173,7 +9434,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 239 + "lineNumber": 244 }, "signature": [ "boolean | \"wait_for\" | undefined" @@ -9182,7 +9443,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 237 + "lineNumber": 242 }, "initialIsOpen": false }, @@ -9207,7 +9468,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 248 + "lineNumber": 253 }, "signature": [ "string[]" @@ -9216,7 +9477,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 246 + "lineNumber": 251 }, "initialIsOpen": false }, @@ -9258,7 +9519,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 284 + "lineNumber": 289 }, "signature": [ "boolean | \"wait_for\" | undefined" @@ -9274,7 +9535,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 286 + "lineNumber": 291 }, "signature": [ "boolean | undefined" @@ -9283,7 +9544,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 282 + "lineNumber": 287 }, "initialIsOpen": false }, @@ -9548,7 +9809,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 78 + "lineNumber": 79 }, "signature": [ "string | string[]" @@ -9562,7 +9823,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 79 + "lineNumber": 80 }, "signature": [ "number | undefined" @@ -9576,7 +9837,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 80 + "lineNumber": 81 }, "signature": [ "number | undefined" @@ -9590,7 +9851,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 81 + "lineNumber": 82 }, "signature": [ "string | undefined" @@ -9599,15 +9860,15 @@ { "tags": [], "id": "def-server.SavedObjectsFindOptions.sortOrder", - "type": "string", + "type": "CompoundType", "label": "sortOrder", "description": [], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 82 + "lineNumber": 83 }, "signature": [ - "string | undefined" + "\"asc\" | \"desc\" | \"_doc\" | undefined" ] }, { @@ -9620,7 +9881,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 88 + "lineNumber": 89 }, "signature": [ "string[] | undefined" @@ -9636,7 +9897,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 90 + "lineNumber": 91 }, "signature": [ "string | undefined" @@ -9652,7 +9913,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 92 + "lineNumber": 93 }, "signature": [ "string[] | undefined" @@ -9668,10 +9929,10 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 96 + "lineNumber": 97 }, "signature": [ - "unknown[] | undefined" + "string[] | undefined" ] }, { @@ -9684,7 +9945,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 101 + "lineNumber": 102 }, "signature": [ "string[] | undefined" @@ -9700,7 +9961,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 107 + "lineNumber": 108 }, "signature": [ { @@ -9731,7 +9992,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 111 + "lineNumber": 112 }, "signature": [ "\"AND\" | \"OR\" | undefined" @@ -9747,7 +10008,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 116 + "lineNumber": 117 }, "signature": [ "\"AND\" | \"OR\" | undefined" @@ -9761,7 +10022,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 117 + "lineNumber": 118 }, "signature": [ "any" @@ -9775,7 +10036,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 118 + "lineNumber": 119 }, "signature": [ "string[] | undefined" @@ -9791,7 +10052,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 126 + "lineNumber": 127 }, "signature": [ "Map | undefined" @@ -9807,7 +10068,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 128 + "lineNumber": 129 }, "signature": [ "string | undefined" @@ -9823,7 +10084,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 132 + "lineNumber": 133 }, "signature": [ { @@ -9839,7 +10100,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 77 + "lineNumber": 78 }, "initialIsOpen": false }, @@ -9860,7 +10121,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 61 + "lineNumber": 62 } }, { @@ -9871,13 +10132,13 @@ "description": [], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 62 + "lineNumber": 63 } } ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 60 + "lineNumber": 61 }, "initialIsOpen": false }, @@ -9910,7 +10171,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 172 + "lineNumber": 177 }, "signature": [ { @@ -9931,7 +10192,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 173 + "lineNumber": 178 } }, { @@ -9942,7 +10203,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 174 + "lineNumber": 179 } }, { @@ -9953,7 +10214,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 175 + "lineNumber": 180 } }, { @@ -9964,7 +10225,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 176 + "lineNumber": 181 }, "signature": [ "string | undefined" @@ -9973,7 +10234,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 171 + "lineNumber": 176 }, "initialIsOpen": false }, @@ -10010,7 +10271,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 131 + "lineNumber": 136 } }, { @@ -10023,16 +10284,16 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 160 + "lineNumber": 165 }, "signature": [ - "unknown[] | undefined" + "string[] | undefined" ] } ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 127 + "lineNumber": 132 }, "initialIsOpen": false }, @@ -10971,7 +11232,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 135 + "lineNumber": 150 } }, { @@ -10984,7 +11245,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 137 + "lineNumber": 152 }, "signature": [ "number | undefined" @@ -10993,7 +11254,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 133 + "lineNumber": 148 }, "initialIsOpen": false }, @@ -11009,7 +11270,7 @@ "section": "def-server.SavedObjectsIncrementCounterOptions", "text": "SavedObjectsIncrementCounterOptions" }, - " extends ", + " extends ", { "pluginId": "core", "scope": "server", @@ -11033,7 +11294,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 102 + "lineNumber": 113 }, "signature": [ "boolean | undefined" @@ -11049,7 +11310,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 104 + "lineNumber": 115 }, "signature": [ { @@ -11072,16 +11333,32 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 109 + "lineNumber": 120 }, "signature": [ "boolean | \"wait_for\" | undefined" ] + }, + { + "tags": [], + "id": "def-server.SavedObjectsIncrementCounterOptions.upsertAttributes", + "type": "Uncategorized", + "label": "upsertAttributes", + "description": [ + "\nAttributes to use when upserting the document if it doesn't exist." + ], + "source": { + "path": "src/core/server/saved_objects/service/lib/repository.ts", + "lineNumber": 124 + }, + "signature": [ + "Attributes | undefined" + ] } ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 97 + "lineNumber": 107 }, "initialIsOpen": false }, @@ -11243,7 +11520,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 355 + "lineNumber": 360 }, "signature": [ "string | undefined" @@ -11259,7 +11536,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 359 + "lineNumber": 364 }, "signature": [ "string | undefined" @@ -11268,7 +11545,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 351 + "lineNumber": 356 }, "initialIsOpen": false }, @@ -11291,13 +11568,13 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 369 + "lineNumber": 374 } } ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 365 + "lineNumber": 370 }, "initialIsOpen": false }, @@ -11318,7 +11595,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 69 + "lineNumber": 70 } }, { @@ -11329,7 +11606,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 70 + "lineNumber": 71 }, "signature": [ "string | undefined" @@ -11338,7 +11615,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 68 + "lineNumber": 69 }, "initialIsOpen": false }, @@ -11491,7 +11768,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 257 + "lineNumber": 262 }, "signature": [ "boolean | undefined" @@ -11500,7 +11777,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 255 + "lineNumber": 260 }, "initialIsOpen": false }, @@ -11542,13 +11819,13 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 266 + "lineNumber": 271 } } ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 264 + "lineNumber": 269 }, "initialIsOpen": false }, @@ -11592,7 +11869,7 @@ "section": "def-server.SavedObjectsRepository", "text": "SavedObjectsRepository" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"deleteByNamespace\" | \"incrementCounter\">" + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\" | \"deleteByNamespace\" | \"incrementCounter\">" ] }, { @@ -11616,7 +11893,7 @@ "section": "def-server.SavedObjectsRepository", "text": "SavedObjectsRepository" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"deleteByNamespace\" | \"incrementCounter\">" + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\" | \"deleteByNamespace\" | \"incrementCounter\">" ] } ], @@ -11741,7 +12018,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 331 + "lineNumber": 336 }, "signature": [ { @@ -11764,7 +12041,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 341 + "lineNumber": 346 }, "signature": [ "\"conflict\" | \"exactMatch\" | \"aliasMatch\"" @@ -11780,7 +12057,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 345 + "lineNumber": 350 }, "signature": [ "string | undefined" @@ -11789,7 +12066,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 330 + "lineNumber": 335 }, "initialIsOpen": false }, @@ -11931,7 +12208,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">" + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">" ] }, { @@ -11963,7 +12240,7 @@ "section": "def-server.SavedObjectsRepository", "text": "SavedObjectsRepository" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"deleteByNamespace\" | \"incrementCounter\">" + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\" | \"deleteByNamespace\" | \"incrementCounter\">" ] }, { @@ -11987,7 +12264,7 @@ "section": "def-server.SavedObjectsRepository", "text": "SavedObjectsRepository" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"deleteByNamespace\" | \"incrementCounter\">" + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\" | \"deleteByNamespace\" | \"incrementCounter\">" ] }, { @@ -12034,7 +12311,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">) => Pick<", + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">) => Pick<", { "pluginId": "core", "scope": "server", @@ -12066,7 +12343,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">) => Pick<", + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">) => Pick<", { "pluginId": "core", "scope": "server", @@ -12127,7 +12404,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 50 + "lineNumber": 51 }, "signature": [ "{ [status: string]: number; skipped: number; migrated: number; }" @@ -12136,7 +12413,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 49 + "lineNumber": 50 }, "initialIsOpen": false }, @@ -12159,7 +12436,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 237 + "lineNumber": 238 } }, { @@ -12172,7 +12449,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 244 + "lineNumber": 245 } }, { @@ -12185,7 +12462,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 248 + "lineNumber": 249 }, "signature": [ { @@ -12207,7 +12484,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 252 + "lineNumber": 253 }, "signature": [ "string | undefined" @@ -12223,7 +12500,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 256 + "lineNumber": 257 }, "signature": [ "string | undefined" @@ -12239,7 +12516,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 260 + "lineNumber": 261 }, "signature": [ { @@ -12261,7 +12538,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 264 + "lineNumber": 265 }, "signature": [ { @@ -12292,7 +12569,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 313 + "lineNumber": 314 }, "signature": [ "string | undefined" @@ -12308,7 +12585,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 317 + "lineNumber": 318 }, "signature": [ { @@ -12324,7 +12601,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 233 + "lineNumber": 234 }, "initialIsOpen": false }, @@ -12349,7 +12626,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 329 + "lineNumber": 330 }, "signature": [ "boolean | undefined" @@ -12365,7 +12642,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 333 + "lineNumber": 334 }, "signature": [ "string | undefined" @@ -12381,7 +12658,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 338 + "lineNumber": 339 }, "signature": [ "string | undefined" @@ -12397,7 +12674,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 343 + "lineNumber": 344 }, "signature": [ "((savedObject: ", @@ -12421,7 +12698,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 348 + "lineNumber": 349 }, "signature": [ "((savedObject: ", @@ -12445,7 +12722,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 357 + "lineNumber": 358 }, "signature": [ "((savedObject: ", @@ -12469,7 +12746,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 368 + "lineNumber": 369 }, "signature": [ { @@ -12492,7 +12769,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 411 + "lineNumber": 412 }, "signature": [ { @@ -12508,7 +12785,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 325 + "lineNumber": 326 }, "initialIsOpen": false }, @@ -12606,7 +12883,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 206 + "lineNumber": 211 }, "signature": [ "string | undefined" @@ -12622,7 +12899,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 208 + "lineNumber": 213 }, "signature": [ { @@ -12645,7 +12922,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 210 + "lineNumber": 215 }, "signature": [ "boolean | \"wait_for\" | undefined" @@ -12654,7 +12931,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 204 + "lineNumber": 209 }, "initialIsOpen": false }, @@ -12689,7 +12966,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 322 + "lineNumber": 327 }, "signature": [ "Partial" @@ -12703,7 +12980,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 323 + "lineNumber": 328 }, "signature": [ { @@ -12719,7 +12996,7 @@ ], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 320 + "lineNumber": 325 }, "initialIsOpen": false } @@ -12736,7 +13013,7 @@ "description": [], "source": { "path": "src/core/server/saved_objects/export/saved_objects_exporter.ts", - "lineNumber": 32 + "lineNumber": 31 }, "signature": [ "{ exportByTypes: (options: SavedObjectsExportByTypeOptions) => Promise<", @@ -12776,10 +13053,10 @@ ], "source": { "path": "src/core/server/saved_objects/service/lib/repository.ts", - "lineNumber": 128 + "lineNumber": 143 }, "signature": [ - "{ get: (type: string, id: string, options?: SavedObjectsBaseOptions) => Promise>; delete: (type: string, id: string, options?: SavedObjectsDeleteOptions) => Promise<{}>; create: (type: string, attributes: T, options?: SavedObjectsCreateOptions) => Promise>; find: (options: SavedObjectsFindOptions) => Promise>; update: (type: string, id: string, attributes: Partial, options?: SavedObjectsUpdateOptions) => Promise>; bulkCreate: (objects: SavedObjectsBulkCreateObject[], options?: SavedObjectsCreateOptions) => Promise>; bulkGet: (objects?: SavedObjectsBulkGetObject[], options?: SavedObjectsBaseOptions) => Promise>; bulkUpdate: (objects: SavedObjectsBulkUpdateObject[], options?: SavedObjectsBulkUpdateOptions) => Promise>; checkConflicts: (objects?: SavedObjectsCheckConflictsObject[], options?: SavedObjectsBaseOptions) => Promise; resolve: (type: string, id: string, options?: SavedObjectsBaseOptions) => Promise>; addToNamespaces: (type: string, id: string, namespaces: string[], options?: SavedObjectsAddToNamespacesOptions) => Promise; deleteFromNamespaces: (type: string, id: string, namespaces: string[], options?: SavedObjectsDeleteFromNamespacesOptions) => Promise; removeReferencesTo: (type: string, id: string, options?: SavedObjectsRemoveReferencesToOptions) => Promise; openPointInTimeForType: (type: string | string[], { keepAlive, preference }?: SavedObjectsOpenPointInTimeOptions) => Promise; closePointInTime: (id: string, options?: SavedObjectsBaseOptions | undefined) => Promise; deleteByNamespace: (namespace: string, options?: SavedObjectsDeleteByNamespaceOptions) => Promise; incrementCounter: (type: string, id: string, counterFields: (string | SavedObjectsIncrementCounterField)[], options?: SavedObjectsIncrementCounterOptions) => Promise>; }" + "{ get: (type: string, id: string, options?: SavedObjectsBaseOptions) => Promise>; delete: (type: string, id: string, options?: SavedObjectsDeleteOptions) => Promise<{}>; create: (type: string, attributes: T, options?: SavedObjectsCreateOptions) => Promise>; find: (options: SavedObjectsFindOptions) => Promise>; update: (type: string, id: string, attributes: Partial, options?: SavedObjectsUpdateOptions) => Promise>; bulkCreate: (objects: SavedObjectsBulkCreateObject[], options?: SavedObjectsCreateOptions) => Promise>; bulkGet: (objects?: SavedObjectsBulkGetObject[], options?: SavedObjectsBaseOptions) => Promise>; bulkUpdate: (objects: SavedObjectsBulkUpdateObject[], options?: SavedObjectsBulkUpdateOptions) => Promise>; checkConflicts: (objects?: SavedObjectsCheckConflictsObject[], options?: SavedObjectsBaseOptions) => Promise; resolve: (type: string, id: string, options?: SavedObjectsBaseOptions) => Promise>; addToNamespaces: (type: string, id: string, namespaces: string[], options?: SavedObjectsAddToNamespacesOptions) => Promise; deleteFromNamespaces: (type: string, id: string, namespaces: string[], options?: SavedObjectsDeleteFromNamespacesOptions) => Promise; removeReferencesTo: (type: string, id: string, options?: SavedObjectsRemoveReferencesToOptions) => Promise; openPointInTimeForType: (type: string | string[], { keepAlive, preference }?: SavedObjectsOpenPointInTimeOptions) => Promise; closePointInTime: (id: string, options?: SavedObjectsBaseOptions | undefined) => Promise; createPointInTimeFinder: (findOptions: Pick, dependencies?: SavedObjectsCreatePointInTimeFinderDependencies | undefined) => ISavedObjectsPointInTimeFinder; deleteByNamespace: (namespace: string, options?: SavedObjectsDeleteByNamespaceOptions) => Promise; incrementCounter: (type: string, id: string, counterFields: (string | SavedObjectsIncrementCounterField)[], options?: SavedObjectsIncrementCounterOptions) => Promise>; }" ], "initialIsOpen": false }, @@ -12814,7 +13091,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 148 + "lineNumber": 149 }, "signature": [ "false | true | \"wait_for\"" @@ -12895,7 +13172,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 212 + "lineNumber": 213 }, "signature": [ "{ get: (type: string, id: string, options?: SavedObjectsBaseOptions) => Promise>; delete: (type: string, id: string, options?: ", @@ -12972,7 +13249,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">" + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">" ], "initialIsOpen": false }, @@ -13041,7 +13318,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">" + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">" ], "initialIsOpen": false }, @@ -13055,13 +13332,46 @@ "description": [], "source": { "path": "src/core/server/saved_objects/service/saved_objects_client.ts", - "lineNumber": 375 + "lineNumber": 380 }, "signature": [ "SavedObjectsBaseOptions" ], "initialIsOpen": false }, + { + "id": "def-server.SavedObjectsCreatePointInTimeFinderOptions", + "type": "Type", + "label": "SavedObjectsCreatePointInTimeFinderOptions", + "tags": [ + "public" + ], + "description": [], + "source": { + "path": "src/core/server/saved_objects/service/lib/point_in_time_finder.ts", + "lineNumber": 21 + }, + "signature": [ + "{ type: string | string[]; filter?: any; fields?: string[] | undefined; search?: string | undefined; perPage?: number | undefined; sortField?: string | undefined; sortOrder?: \"asc\" | \"desc\" | \"_doc\" | undefined; searchFields?: string[] | undefined; rootSearchFields?: string[] | undefined; hasReference?: ", + { + "pluginId": "core", + "scope": "server", + "docId": "kibCoreSavedObjectsPluginApi", + "section": "def-server.SavedObjectsFindOptionsReference", + "text": "SavedObjectsFindOptionsReference" + }, + " | ", + { + "pluginId": "core", + "scope": "server", + "docId": "kibCoreSavedObjectsPluginApi", + "section": "def-server.SavedObjectsFindOptionsReference", + "text": "SavedObjectsFindOptionsReference" + }, + "[] | undefined; hasReferenceOperator?: \"AND\" | \"OR\" | undefined; defaultSearchOperator?: \"AND\" | \"OR\" | undefined; namespaces?: string[] | undefined; typeToNamespacesMap?: Map | undefined; preference?: string | undefined; }" + ], + "initialIsOpen": false + }, { "id": "def-server.SavedObjectsExportTransform", "type": "Type", @@ -13210,7 +13520,7 @@ ], "source": { "path": "src/core/server/saved_objects/types.ts", - "lineNumber": 226 + "lineNumber": 227 }, "signature": [ "\"multiple\" | \"single\" | \"multiple-isolated\" | \"agnostic\"" diff --git a/api_docs/data.json b/api_docs/data.json index a9ef03d881ce88..a51ad465fe9034 100644 --- a/api_docs/data.json +++ b/api_docs/data.json @@ -7022,8 +7022,7 @@ "docId": "kibDataSearchPluginApi", "section": "def-common.ISearchRequestParams", "text": "ISearchRequestParams" - }, - ">" + } ], "description": [], "children": [ @@ -8696,7 +8695,7 @@ "section": "def-common.ISearchRequestParams", "text": "ISearchRequestParams" }, - ">>" + ">" ], "description": [], "tags": [], @@ -8709,7 +8708,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/es_search/types.ts", - "lineNumber": 20 + "lineNumber": 19 }, "signature": [ "string | undefined" @@ -8718,7 +8717,7 @@ ], "source": { "path": "src/plugins/data/common/search/es_search/types.ts", - "lineNumber": 19 + "lineNumber": 18 }, "initialIsOpen": false }, @@ -10763,7 +10762,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/search_source/fetch/types.ts", - "lineNumber": 37 + "lineNumber": 40 } }, { @@ -10774,7 +10773,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/search_source/fetch/types.ts", - "lineNumber": 38 + "lineNumber": 41 } }, { @@ -10785,7 +10784,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/search_source/fetch/types.ts", - "lineNumber": 39 + "lineNumber": 42 } }, { @@ -10796,7 +10795,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/search_source/fetch/types.ts", - "lineNumber": 40 + "lineNumber": 43 } }, { @@ -10807,7 +10806,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/search_source/fetch/types.ts", - "lineNumber": 41 + "lineNumber": 44 } }, { @@ -10818,13 +10817,13 @@ "description": [], "source": { "path": "src/plugins/data/common/search/search_source/fetch/types.ts", - "lineNumber": 42 + "lineNumber": 45 } } ], "source": { "path": "src/plugins/data/common/search/search_source/fetch/types.ts", - "lineNumber": 36 + "lineNumber": 39 }, "initialIsOpen": false }, @@ -11484,7 +11483,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/es_search/types.ts", - "lineNumber": 13 + "lineNumber": 12 }, "signature": [ "\"es\"" @@ -11608,7 +11607,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 26 + "lineNumber": 34 }, "signature": [ "ExpressionFunctionDefinition<\"kibana_context\", ", @@ -11751,10 +11750,10 @@ "description": [], "source": { "path": "src/plugins/data/common/search/es_search/types.ts", - "lineNumber": 23 + "lineNumber": 22 }, "signature": [ - "IKibanaSearchResponse>" + "IKibanaSearchResponse>" ], "initialIsOpen": false }, @@ -11847,7 +11846,7 @@ "description": [], "source": { "path": "src/plugins/data/common/index_patterns/expressions/load_index_pattern.ts", - "lineNumber": 34 + "lineNumber": 35 }, "signature": [ "ExpressionFunctionDefinition<\"indexPatternLoad\", null, Arguments, Output, ", @@ -14487,15 +14486,7 @@ "lineNumber": 46 }, "signature": [ - "{ addQuerySuggestionProvider: (language: string, provider: ", - { - "pluginId": "data", - "scope": "public", - "docId": "kibDataAutocompletePluginApi", - "section": "def-public.QuerySuggestionGetFn", - "text": "QuerySuggestionGetFn" - }, - ") => void; getQuerySuggestions: ", + "{ getQuerySuggestions: ", { "pluginId": "data", "scope": "public", @@ -15163,7 +15154,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">, elasticsearchClient: ", + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">, elasticsearchClient: ", { "pluginId": "core", "scope": "server", @@ -15190,7 +15181,7 @@ "description": [], "source": { "path": "src/plugins/data/server/plugin.ts", - "lineNumber": 107 + "lineNumber": 104 } } ], @@ -15198,7 +15189,7 @@ "returnComment": [], "source": { "path": "src/plugins/data/server/plugin.ts", - "lineNumber": 107 + "lineNumber": 104 } }, { @@ -15214,7 +15205,7 @@ "returnComment": [], "source": { "path": "src/plugins/data/server/plugin.ts", - "lineNumber": 121 + "lineNumber": 118 } } ], @@ -19507,7 +19498,7 @@ "section": "def-common.ISearchRequestParams", "text": "ISearchRequestParams" }, - ">>" + ">" ], "description": [], "tags": [], @@ -19520,7 +19511,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/es_search/types.ts", - "lineNumber": 20 + "lineNumber": 19 }, "signature": [ "string | undefined" @@ -19529,7 +19520,7 @@ ], "source": { "path": "src/plugins/data/common/search/es_search/types.ts", - "lineNumber": 19 + "lineNumber": 18 }, "initialIsOpen": false }, @@ -20433,7 +20424,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/es_search/types.ts", - "lineNumber": 13 + "lineNumber": 12 }, "signature": [ "\"es\"" @@ -20527,7 +20518,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 26 + "lineNumber": 34 }, "signature": [ "ExpressionFunctionDefinition<\"kibana_context\", ", @@ -20636,10 +20627,10 @@ "description": [], "source": { "path": "src/plugins/data/common/search/es_search/types.ts", - "lineNumber": 23 + "lineNumber": 22 }, "signature": [ - "IKibanaSearchResponse>" + "IKibanaSearchResponse>" ], "initialIsOpen": false }, @@ -20717,7 +20708,7 @@ "description": [], "source": { "path": "src/plugins/data/common/index_patterns/expressions/load_index_pattern.ts", - "lineNumber": 34 + "lineNumber": 35 }, "signature": [ "ExpressionFunctionDefinition<\"indexPatternLoad\", null, Arguments, Output, ", diff --git a/api_docs/data_autocomplete.json b/api_docs/data_autocomplete.json index a66ca49d0c1819..7792a7abe5c8a1 100644 --- a/api_docs/data_autocomplete.json +++ b/api_docs/data_autocomplete.json @@ -324,7 +324,7 @@ "description": [], "source": { "path": "src/plugins/data/public/autocomplete/autocomplete_service.ts", - "lineNumber": 93 + "lineNumber": 96 }, "signature": [ "{ getQuerySuggestions: QuerySuggestionGetFn; hasQuerySuggestions: (language: string) => boolean; getValueSuggestions: ValueSuggestionsGetFn; }" diff --git a/api_docs/data_enhanced.json b/api_docs/data_enhanced.json index 5bd7a970f9b73a..80f1d1fc15a5a8 100644 --- a/api_docs/data_enhanced.json +++ b/api_docs/data_enhanced.json @@ -46,7 +46,7 @@ "description": [], "source": { "path": "x-pack/plugins/data_enhanced/public/plugin.ts", - "lineNumber": 40 + "lineNumber": 38 }, "signature": [ "void" @@ -903,9 +903,7 @@ "lineNumber": 27 }, "signature": [ - "IKibanaSearchResponse>" + "IKibanaSearchResponse>" ], "initialIsOpen": false }, diff --git a/api_docs/data_index_patterns.json b/api_docs/data_index_patterns.json index afcea7d50b3040..8058f6a72f9c34 100644 --- a/api_docs/data_index_patterns.json +++ b/api_docs/data_index_patterns.json @@ -368,7 +368,7 @@ "section": "def-server.DataPluginStart", "text": "DataPluginStart" }, - ">, { logger, expressions }: ", + ">, { expressions }: ", { "pluginId": "data", "scope": "server", @@ -413,12 +413,12 @@ "description": [], "source": { "path": "src/plugins/data/server/index_patterns/index_patterns_service.ts", - "lineNumber": 49 + "lineNumber": 47 } }, { "type": "Object", - "label": "{ logger, expressions }", + "label": "{ expressions }", "isRequired": true, "signature": [ { @@ -432,7 +432,7 @@ "description": [], "source": { "path": "src/plugins/data/server/index_patterns/index_patterns_service.ts", - "lineNumber": 50 + "lineNumber": 48 } } ], @@ -440,7 +440,7 @@ "returnComment": [], "source": { "path": "src/plugins/data/server/index_patterns/index_patterns_service.ts", - "lineNumber": 48 + "lineNumber": 46 } }, { @@ -472,7 +472,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">, elasticsearchClient: ", + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">, elasticsearchClient: ", { "pluginId": "core", "scope": "server", @@ -507,7 +507,7 @@ "description": [], "source": { "path": "src/plugins/data/server/index_patterns/index_patterns_service.ts", - "lineNumber": 76 + "lineNumber": 58 } }, { @@ -526,7 +526,7 @@ "description": [], "source": { "path": "src/plugins/data/server/index_patterns/index_patterns_service.ts", - "lineNumber": 76 + "lineNumber": 58 } } ], @@ -534,13 +534,13 @@ "returnComment": [], "source": { "path": "src/plugins/data/server/index_patterns/index_patterns_service.ts", - "lineNumber": 76 + "lineNumber": 58 } } ], "source": { "path": "src/plugins/data/server/index_patterns/index_patterns_service.ts", - "lineNumber": 47 + "lineNumber": 45 }, "initialIsOpen": false } @@ -3903,7 +3903,7 @@ "label": "getIndexPatternLoadMeta", "source": { "path": "src/plugins/data/common/index_patterns/expressions/load_index_pattern.ts", - "lineNumber": 41 + "lineNumber": 42 }, "tags": [], "returnComment": [], @@ -5937,7 +5937,7 @@ "description": [], "source": { "path": "src/plugins/data/common/index_patterns/expressions/load_index_pattern.ts", - "lineNumber": 18 + "lineNumber": 19 }, "signature": [ "\"index_pattern\"" @@ -5951,7 +5951,7 @@ "description": [], "source": { "path": "src/plugins/data/common/index_patterns/expressions/load_index_pattern.ts", - "lineNumber": 19 + "lineNumber": 20 }, "signature": [ { @@ -5966,7 +5966,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/expressions/load_index_pattern.ts", - "lineNumber": 17 + "lineNumber": 18 }, "initialIsOpen": false }, @@ -6677,7 +6677,7 @@ "description": [], "source": { "path": "src/plugins/data/common/index_patterns/expressions/load_index_pattern.ts", - "lineNumber": 34 + "lineNumber": 35 }, "signature": [ "ExpressionFunctionDefinition<\"indexPatternLoad\", null, Arguments, Output, ", diff --git a/api_docs/data_search.json b/api_docs/data_search.json index a75b669cbd288d..53b8294de02fc6 100644 --- a/api_docs/data_search.json +++ b/api_docs/data_search.json @@ -1621,7 +1621,7 @@ "description": [], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 88 + "lineNumber": 90 }, "signature": [ "(sessionId: string, attributes: Partial) => Promise<", @@ -1643,7 +1643,7 @@ "description": [], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 89 + "lineNumber": 91 }, "signature": [ "(sessionId: string) => Promise<", @@ -1665,7 +1665,7 @@ "description": [], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 90 + "lineNumber": 92 }, "signature": [ "(options: Pick<", @@ -1695,7 +1695,7 @@ "description": [], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 91 + "lineNumber": 93 }, "signature": [ "(sessionId: string, attributes: Partial) => Promise<", @@ -1717,7 +1717,7 @@ "description": [], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 92 + "lineNumber": 94 }, "signature": [ "(sessionId: string) => Promise<{}>" @@ -1731,7 +1731,7 @@ "description": [], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 93 + "lineNumber": 95 }, "signature": [ "(sessionId: string) => Promise<{}>" @@ -1745,7 +1745,7 @@ "description": [], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 94 + "lineNumber": 96 }, "signature": [ "(sessionId: string, expires: Date) => Promise<", @@ -1762,7 +1762,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 87 + "lineNumber": 89 }, "initialIsOpen": false }, @@ -1843,7 +1843,7 @@ "description": [], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 41 + "lineNumber": 43 }, "signature": [ { @@ -1865,7 +1865,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 46 + "lineNumber": 48 }, "signature": [ " ", @@ -2009,7 +2009,7 @@ "description": [], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 110 + "lineNumber": 112 }, "signature": [ "(request: ", @@ -2038,7 +2038,7 @@ "description": [], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 111 + "lineNumber": 113 }, "signature": [ "{ asScoped: (request: ", @@ -2063,7 +2063,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 97 + "lineNumber": 99 }, "initialIsOpen": false }, @@ -2094,7 +2094,7 @@ "description": [], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 73 + "lineNumber": 75 }, "signature": [ "(request: SearchStrategyRequest, options: ", @@ -2126,7 +2126,7 @@ "description": [], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 78 + "lineNumber": 80 }, "signature": [ "((id: string, options: ", @@ -2156,7 +2156,7 @@ "description": [], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 79 + "lineNumber": 81 }, "signature": [ "((id: string, keepAlive: string, options: ", @@ -2181,7 +2181,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 69 + "lineNumber": 71 }, "initialIsOpen": false }, @@ -2200,7 +2200,7 @@ "description": [], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 34 + "lineNumber": 36 }, "signature": [ "Pick<", @@ -2211,7 +2211,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">" + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">" ] }, { @@ -2222,7 +2222,7 @@ "description": [], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 35 + "lineNumber": 37 }, "signature": [ { @@ -2242,7 +2242,7 @@ "description": [], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 36 + "lineNumber": 38 }, "signature": [ { @@ -2262,7 +2262,7 @@ "description": [], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 37 + "lineNumber": 39 }, "signature": [ { @@ -2278,7 +2278,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 33 + "lineNumber": 35 }, "initialIsOpen": false }, @@ -2344,7 +2344,23 @@ } ], "enums": [], - "misc": [], + "misc": [ + { + "id": "def-server.SearchRequestHandlerContext", + "type": "Type", + "label": "SearchRequestHandlerContext", + "tags": [], + "description": [], + "source": { + "path": "src/plugins/data/server/search/types.ts", + "lineNumber": 118 + }, + "signature": [ + "IScopedSearchClient" + ], + "initialIsOpen": false + } + ], "objects": [] }, "common": { @@ -9455,6 +9471,70 @@ "returnComment": [], "initialIsOpen": false }, + { + "id": "def-common.getKibanaContextFn", + "type": "Function", + "children": [ + { + "type": "Function", + "label": "getStartDependencies", + "isRequired": true, + "signature": [ + "(getKibanaRequest: (() => ", + { + "pluginId": "core", + "scope": "server", + "docId": "kibCoreHttpPluginApi", + "section": "def-server.KibanaRequest", + "text": "KibanaRequest" + }, + ") | undefined) => Promise<", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.KibanaContextStartDependencies", + "text": "KibanaContextStartDependencies" + }, + ">" + ], + "description": [], + "source": { + "path": "src/plugins/data/common/search/expressions/kibana_context.ts", + "lineNumber": 52 + } + } + ], + "signature": [ + "(getStartDependencies: (getKibanaRequest: (() => ", + { + "pluginId": "core", + "scope": "server", + "docId": "kibCoreHttpPluginApi", + "section": "def-server.KibanaRequest", + "text": "KibanaRequest" + }, + ") | undefined) => Promise<", + "KibanaContextStartDependencies", + ">) => ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.ExpressionFunctionKibanaContext", + "text": "ExpressionFunctionKibanaContext" + } + ], + "description": [], + "label": "getKibanaContextFn", + "source": { + "path": "src/plugins/data/common/search/expressions/kibana_context.ts", + "lineNumber": 51 + }, + "tags": [], + "returnComment": [], + "initialIsOpen": false + }, { "id": "def-common.getMaxMetricAgg", "type": "Function", @@ -10015,8 +10095,7 @@ "docId": "kibDataSearchPluginApi", "section": "def-common.ISearchRequestParams", "text": "ISearchRequestParams" - }, - ">" + } ], "description": [], "children": [ @@ -15167,7 +15246,7 @@ ], "source": { "path": "src/plugins/data/common/search/search_source/fetch/types.ts", - "lineNumber": 33 + "lineNumber": 36 }, "signature": [ { @@ -15477,7 +15556,7 @@ "section": "def-common.ISearchRequestParams", "text": "ISearchRequestParams" }, - ">>" + ">" ], "description": [], "tags": [], @@ -15490,7 +15569,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/es_search/types.ts", - "lineNumber": 20 + "lineNumber": 19 }, "signature": [ "string | undefined" @@ -15499,7 +15578,7 @@ ], "source": { "path": "src/plugins/data/common/search/es_search/types.ts", - "lineNumber": 19 + "lineNumber": 18 }, "initialIsOpen": false }, @@ -16090,7 +16169,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/search_source/legacy/types.ts", - "lineNumber": 36 + "lineNumber": 35 }, "signature": [ "(params: { body: ", @@ -16120,7 +16199,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/search_source/legacy/types.ts", - "lineNumber": 40 + "lineNumber": 39 }, "signature": [ "BehaviorSubject", @@ -16130,7 +16209,7 @@ ], "source": { "path": "src/plugins/data/common/search/search_source/legacy/types.ts", - "lineNumber": 35 + "lineNumber": 34 }, "initialIsOpen": false }, @@ -16224,7 +16303,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/search_source/legacy/types.ts", - "lineNumber": 26 + "lineNumber": 25 }, "signature": [ "MsearchRequest[]" @@ -16233,7 +16312,7 @@ ], "source": { "path": "src/plugins/data/common/search/search_source/legacy/types.ts", - "lineNumber": 25 + "lineNumber": 24 }, "initialIsOpen": false }, @@ -16252,21 +16331,19 @@ "description": [], "source": { "path": "src/plugins/data/common/search/search_source/legacy/types.ts", - "lineNumber": 31 + "lineNumber": 30 }, "signature": [ "ApiResponse", "<{ responses: ", "SearchResponse", - "[]; }, ", - "Context", - ">" + "[]; }, unknown>" ] } ], "source": { "path": "src/plugins/data/common/search/search_source/legacy/types.ts", - "lineNumber": 30 + "lineNumber": 29 }, "initialIsOpen": false }, @@ -16613,7 +16690,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/search_source/fetch/types.ts", - "lineNumber": 37 + "lineNumber": 40 } }, { @@ -16624,7 +16701,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/search_source/fetch/types.ts", - "lineNumber": 38 + "lineNumber": 41 } }, { @@ -16635,7 +16712,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/search_source/fetch/types.ts", - "lineNumber": 39 + "lineNumber": 42 } }, { @@ -16646,7 +16723,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/search_source/fetch/types.ts", - "lineNumber": 40 + "lineNumber": 43 } }, { @@ -16657,7 +16734,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/search_source/fetch/types.ts", - "lineNumber": 41 + "lineNumber": 44 } }, { @@ -16668,13 +16745,13 @@ "description": [], "source": { "path": "src/plugins/data/common/search/search_source/fetch/types.ts", - "lineNumber": 42 + "lineNumber": 45 } } ], "source": { "path": "src/plugins/data/common/search/search_source/fetch/types.ts", - "lineNumber": 36 + "lineNumber": 39 }, "initialIsOpen": false }, @@ -17568,7 +17645,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/search_source/legacy/types.ts", - "lineNumber": 49 + "lineNumber": 48 } }, { @@ -17579,7 +17656,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/search_source/legacy/types.ts", - "lineNumber": 50 + "lineNumber": 49 }, "signature": [ "(params: ", @@ -17604,7 +17681,7 @@ ], "source": { "path": "src/plugins/data/common/search/search_source/legacy/types.ts", - "lineNumber": 48 + "lineNumber": 47 }, "initialIsOpen": false }, @@ -17633,7 +17710,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/search_source/legacy/types.ts", - "lineNumber": 54 + "lineNumber": 53 }, "signature": [ "Promise<", @@ -17649,7 +17726,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/search_source/legacy/types.ts", - "lineNumber": 55 + "lineNumber": 54 }, "signature": [ "() => void" @@ -17658,7 +17735,7 @@ ], "source": { "path": "src/plugins/data/common/search/search_source/legacy/types.ts", - "lineNumber": 53 + "lineNumber": 52 }, "initialIsOpen": false }, @@ -17694,7 +17771,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/search_source/legacy/types.ts", - "lineNumber": 44 + "lineNumber": 43 }, "signature": [ "Record[]" @@ -17703,7 +17780,7 @@ ], "source": { "path": "src/plugins/data/common/search/search_source/legacy/types.ts", - "lineNumber": 43 + "lineNumber": 42 }, "initialIsOpen": false }, @@ -18653,7 +18730,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/es_search/types.ts", - "lineNumber": 13 + "lineNumber": 12 }, "signature": [ "\"es\"" @@ -18877,7 +18954,7 @@ "description": [], "source": { "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 26 + "lineNumber": 34 }, "signature": [ "ExpressionFunctionDefinition<\"kibana_context\", ", @@ -19315,10 +19392,10 @@ "description": [], "source": { "path": "src/plugins/data/common/search/es_search/types.ts", - "lineNumber": 23 + "lineNumber": 22 }, "signature": [ - "IKibanaSearchResponse>" + "IKibanaSearchResponse>" ], "initialIsOpen": false }, @@ -19530,10 +19607,10 @@ "description": [], "source": { "path": "src/plugins/data/common/search/es_search/types.ts", - "lineNumber": 15 + "lineNumber": 14 }, "signature": [ - "{ trackTotalHits?: boolean | undefined; } & Search" + "{ trackTotalHits?: boolean | undefined; } & estypes.SearchRequest" ], "initialIsOpen": false }, @@ -20649,426 +20726,6 @@ }, "initialIsOpen": false }, - { - "id": "def-common.kibanaContextFunction", - "type": "Object", - "tags": [], - "children": [ - { - "tags": [], - "id": "def-common.kibanaContextFunction.name", - "type": "string", - "label": "name", - "description": [], - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 44 - }, - "signature": [ - "\"kibana_context\"" - ] - }, - { - "tags": [], - "id": "def-common.kibanaContextFunction.type", - "type": "string", - "label": "type", - "description": [], - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 45 - }, - "signature": [ - "\"kibana_context\"" - ] - }, - { - "tags": [], - "id": "def-common.kibanaContextFunction.inputTypes", - "type": "Array", - "label": "inputTypes", - "description": [], - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 46 - }, - "signature": [ - "(\"kibana_context\" | \"null\")[]" - ] - }, - { - "tags": [], - "id": "def-common.kibanaContextFunction.help", - "type": "string", - "label": "help", - "description": [], - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 47 - } - }, - { - "id": "def-common.kibanaContextFunction.args", - "type": "Object", - "tags": [], - "children": [ - { - "id": "def-common.kibanaContextFunction.args.q", - "type": "Object", - "tags": [], - "children": [ - { - "tags": [], - "id": "def-common.kibanaContextFunction.args.q.types", - "type": "Array", - "label": "types", - "description": [], - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 52 - }, - "signature": [ - "(\"null\" | \"kibana_query\")[]" - ] - }, - { - "tags": [], - "id": "def-common.kibanaContextFunction.args.q.aliases", - "type": "Array", - "label": "aliases", - "description": [], - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 53 - }, - "signature": [ - "string[]" - ] - }, - { - "tags": [], - "id": "def-common.kibanaContextFunction.args.q.default", - "type": "Uncategorized", - "label": "default", - "description": [], - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 54 - }, - "signature": [ - "null" - ] - }, - { - "tags": [], - "id": "def-common.kibanaContextFunction.args.q.help", - "type": "string", - "label": "help", - "description": [], - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 55 - } - } - ], - "description": [], - "label": "q", - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 51 - } - }, - { - "id": "def-common.kibanaContextFunction.args.filters", - "type": "Object", - "tags": [], - "children": [ - { - "tags": [], - "id": "def-common.kibanaContextFunction.args.filters.types", - "type": "Array", - "label": "types", - "description": [], - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 60 - }, - "signature": [ - "(\"null\" | \"kibana_filter\")[]" - ] - }, - { - "tags": [], - "id": "def-common.kibanaContextFunction.args.filters.multi", - "type": "boolean", - "label": "multi", - "description": [], - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 61 - }, - "signature": [ - "true" - ] - }, - { - "tags": [], - "id": "def-common.kibanaContextFunction.args.filters.help", - "type": "string", - "label": "help", - "description": [], - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 62 - } - } - ], - "description": [], - "label": "filters", - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 59 - } - }, - { - "id": "def-common.kibanaContextFunction.args.timeRange", - "type": "Object", - "tags": [], - "children": [ - { - "tags": [], - "id": "def-common.kibanaContextFunction.args.timeRange.types", - "type": "Array", - "label": "types", - "description": [], - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 67 - }, - "signature": [ - "(\"null\" | \"timerange\")[]" - ] - }, - { - "tags": [], - "id": "def-common.kibanaContextFunction.args.timeRange.default", - "type": "Uncategorized", - "label": "default", - "description": [], - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 68 - }, - "signature": [ - "null" - ] - }, - { - "tags": [], - "id": "def-common.kibanaContextFunction.args.timeRange.help", - "type": "string", - "label": "help", - "description": [], - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 69 - } - } - ], - "description": [], - "label": "timeRange", - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 66 - } - }, - { - "id": "def-common.kibanaContextFunction.args.savedSearchId", - "type": "Object", - "tags": [], - "children": [ - { - "tags": [], - "id": "def-common.kibanaContextFunction.args.savedSearchId.types", - "type": "Array", - "label": "types", - "description": [], - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 74 - }, - "signature": [ - "(\"string\" | \"null\")[]" - ] - }, - { - "tags": [], - "id": "def-common.kibanaContextFunction.args.savedSearchId.default", - "type": "Uncategorized", - "label": "default", - "description": [], - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 75 - }, - "signature": [ - "null" - ] - }, - { - "tags": [], - "id": "def-common.kibanaContextFunction.args.savedSearchId.help", - "type": "string", - "label": "help", - "description": [], - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 76 - } - } - ], - "description": [], - "label": "savedSearchId", - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 73 - } - } - ], - "description": [], - "label": "args", - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 50 - } - }, - { - "id": "def-common.kibanaContextFunction.fn", - "type": "Function", - "label": "fn", - "signature": [ - "(input: Input, args: Arguments, { getSavedObject }: ", - { - "pluginId": "expressions", - "scope": "common", - "docId": "kibExpressionsPluginApi", - "section": "def-common.ExecutionContext", - "text": "ExecutionContext" - }, - "<", - { - "pluginId": "inspector", - "scope": "common", - "docId": "kibInspectorPluginApi", - "section": "def-common.Adapters", - "text": "Adapters" - }, - ", ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.ExecutionContextSearch", - "text": "ExecutionContextSearch" - }, - ">) => Promise<{ type: \"kibana_context\"; query: ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataQueryPluginApi", - "section": "def-common.Query", - "text": "Query" - }, - "[]; filters: ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataPluginApi", - "section": "def-common.Filter", - "text": "Filter" - } - ], - "description": [], - "children": [ - { - "type": "CompoundType", - "label": "input", - "isRequired": false, - "signature": [ - "Input" - ], - "description": [], - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 82 - } - }, - { - "type": "Object", - "label": "args", - "isRequired": true, - "signature": [ - "Arguments" - ], - "description": [], - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 82 - } - }, - { - "type": "Object", - "label": "{ getSavedObject }", - "isRequired": true, - "signature": [ - { - "pluginId": "expressions", - "scope": "common", - "docId": "kibExpressionsPluginApi", - "section": "def-common.ExecutionContext", - "text": "ExecutionContext" - }, - "<", - { - "pluginId": "inspector", - "scope": "common", - "docId": "kibInspectorPluginApi", - "section": "def-common.Adapters", - "text": "Adapters" - }, - ", ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.ExecutionContextSearch", - "text": "ExecutionContextSearch" - }, - ">" - ], - "description": [], - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 82 - } - } - ], - "tags": [], - "returnComment": [], - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 82 - } - } - ], - "description": [], - "label": "kibanaContextFunction", - "source": { - "path": "src/plugins/data/common/search/expressions/kibana_context.ts", - "lineNumber": 43 - }, - "initialIsOpen": false - }, { "id": "def-common.kibanaFilterFunction", "type": "Object", diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index 70cbd231252480..370bd2ffd101e8 100644 --- a/api_docs/data_search.mdx +++ b/api_docs/data_search.mdx @@ -36,6 +36,9 @@ import dataSearchObj from './data_search.json'; ### Interfaces +### Consts, variables and types + + ## Common ### Objects diff --git a/api_docs/event_log.json b/api_docs/event_log.json index 64266b05635567..aea4d0c0019131 100644 --- a/api_docs/event_log.json +++ b/api_docs/event_log.json @@ -225,7 +225,7 @@ "description": [], "source": { "path": "x-pack/plugins/event_log/server/es/cluster_client_adapter.ts", - "lineNumber": 35 + "lineNumber": 36 } }, { @@ -236,7 +236,7 @@ "description": [], "source": { "path": "x-pack/plugins/event_log/server/es/cluster_client_adapter.ts", - "lineNumber": 36 + "lineNumber": 37 } }, { @@ -247,7 +247,7 @@ "description": [], "source": { "path": "x-pack/plugins/event_log/server/es/cluster_client_adapter.ts", - "lineNumber": 37 + "lineNumber": 38 } }, { @@ -258,7 +258,7 @@ "description": [], "source": { "path": "x-pack/plugins/event_log/server/es/cluster_client_adapter.ts", - "lineNumber": 38 + "lineNumber": 39 }, "signature": [ "(Readonly<{ '@timestamp'?: string | undefined; kibana?: Readonly<{ server_uuid?: string | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; saved_objects?: Readonly<{ type?: string | undefined; id?: string | undefined; rel?: string | undefined; namespace?: string | undefined; } & {}>[] | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; error?: Readonly<{ message?: string | undefined; } & {}> | undefined; message?: string | undefined; tags?: string[] | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; event?: Readonly<{ start?: string | undefined; end?: string | undefined; action?: string | undefined; provider?: string | undefined; duration?: number | undefined; outcome?: string | undefined; reason?: string | undefined; } & {}> | undefined; } & {}> | undefined)[]" @@ -267,7 +267,7 @@ ], "source": { "path": "x-pack/plugins/event_log/server/es/cluster_client_adapter.ts", - "lineNumber": 34 + "lineNumber": 35 }, "initialIsOpen": false } diff --git a/api_docs/expressions.json b/api_docs/expressions.json index eefffb009be2ac..06c97e497ae41f 100644 --- a/api_docs/expressions.json +++ b/api_docs/expressions.json @@ -1562,7 +1562,7 @@ "description": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 223 + "lineNumber": 230 } } ], @@ -1570,7 +1570,7 @@ "returnComment": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 223 + "lineNumber": 230 } }, { @@ -1606,7 +1606,7 @@ "description": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 233 + "lineNumber": 241 } }, { @@ -1619,7 +1619,7 @@ "description": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 233 + "lineNumber": 241 } } ], @@ -1627,7 +1627,7 @@ "returnComment": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 233 + "lineNumber": 241 } }, { @@ -1670,7 +1670,7 @@ "description": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 241 + "lineNumber": 249 } }, { @@ -1683,7 +1683,7 @@ "description": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 241 + "lineNumber": 249 } } ], @@ -1691,7 +1691,7 @@ "returnComment": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 241 + "lineNumber": 249 } }, { @@ -1715,7 +1715,7 @@ "returnComment": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 250 + "lineNumber": 258 } } ], @@ -2975,7 +2975,7 @@ "description": [], "source": { "path": "src/plugins/expressions/public/plugin.ts", - "lineNumber": 40 + "lineNumber": 35 } } ], @@ -2983,7 +2983,7 @@ "returnComment": [], "source": { "path": "src/plugins/expressions/public/plugin.ts", - "lineNumber": 40 + "lineNumber": 35 } }, { @@ -3028,7 +3028,7 @@ "description": [], "source": { "path": "src/plugins/expressions/public/plugin.ts", - "lineNumber": 56 + "lineNumber": 45 } } ], @@ -3036,7 +3036,7 @@ "returnComment": [], "source": { "path": "src/plugins/expressions/public/plugin.ts", - "lineNumber": 56 + "lineNumber": 45 } }, { @@ -3079,7 +3079,7 @@ "description": [], "source": { "path": "src/plugins/expressions/public/plugin.ts", - "lineNumber": 70 + "lineNumber": 59 } } ], @@ -3087,7 +3087,7 @@ "returnComment": [], "source": { "path": "src/plugins/expressions/public/plugin.ts", - "lineNumber": 70 + "lineNumber": 59 } }, { @@ -3103,13 +3103,13 @@ "returnComment": [], "source": { "path": "src/plugins/expressions/public/plugin.ts", - "lineNumber": 86 + "lineNumber": 75 } } ], "source": { "path": "src/plugins/expressions/public/plugin.ts", - "lineNumber": 37 + "lineNumber": 32 }, "initialIsOpen": false }, @@ -3180,7 +3180,7 @@ "description": [], "source": { "path": "src/plugins/expressions/public/plugin.ts", - "lineNumber": 40 + "lineNumber": 35 } } ], @@ -3188,7 +3188,7 @@ "returnComment": [], "source": { "path": "src/plugins/expressions/public/plugin.ts", - "lineNumber": 40 + "lineNumber": 35 } }, { @@ -3233,7 +3233,7 @@ "description": [], "source": { "path": "src/plugins/expressions/public/plugin.ts", - "lineNumber": 56 + "lineNumber": 45 } } ], @@ -3241,7 +3241,7 @@ "returnComment": [], "source": { "path": "src/plugins/expressions/public/plugin.ts", - "lineNumber": 56 + "lineNumber": 45 } }, { @@ -3284,7 +3284,7 @@ "description": [], "source": { "path": "src/plugins/expressions/public/plugin.ts", - "lineNumber": 70 + "lineNumber": 59 } } ], @@ -3292,7 +3292,7 @@ "returnComment": [], "source": { "path": "src/plugins/expressions/public/plugin.ts", - "lineNumber": 70 + "lineNumber": 59 } }, { @@ -3308,13 +3308,13 @@ "returnComment": [], "source": { "path": "src/plugins/expressions/public/plugin.ts", - "lineNumber": 86 + "lineNumber": 75 } } ], "source": { "path": "src/plugins/expressions/public/plugin.ts", - "lineNumber": 37 + "lineNumber": 32 }, "initialIsOpen": false }, @@ -5908,7 +5908,7 @@ ], "source": { "path": "src/plugins/expressions/common/execution/types.ts", - "lineNumber": 28 + "lineNumber": 27 }, "signature": [ "() => ExecutionContextSearch" @@ -5924,7 +5924,7 @@ ], "source": { "path": "src/plugins/expressions/common/execution/types.ts", - "lineNumber": 33 + "lineNumber": 32 }, "signature": [ "Record" @@ -5940,7 +5940,7 @@ ], "source": { "path": "src/plugins/expressions/common/execution/types.ts", - "lineNumber": 38 + "lineNumber": 37 }, "signature": [ "Record string | undefined" @@ -6012,7 +6012,7 @@ ], "source": { "path": "src/plugins/expressions/common/execution/types.ts", - "lineNumber": 60 + "lineNumber": 59 }, "signature": [ "(() => ", @@ -6026,46 +6026,6 @@ ") | undefined" ] }, - { - "tags": [], - "id": "def-public.ExecutionContext.getSavedObject", - "type": "Function", - "label": "getSavedObject", - "description": [ - "\nAllows to fetch saved objects from ElasticSearch. In browser `getSavedObject`\nfunction is provided automatically by the Expressions plugin. On the server\nthe caller of the expression has to provide this context function. The\nreason is because on the browser we always know the user who tries to\nfetch a saved object, thus saved object client is scoped automatically to\nthat user. However, on the server we can scope that saved object client to\nany user, or even not scope it at all and execute it as an \"internal\" user." - ], - "source": { - "path": "src/plugins/expressions/common/execution/types.ts", - "lineNumber": 71 - }, - "signature": [ - "((type: string, id: string) => Promise<", - { - "pluginId": "core", - "scope": "common", - "docId": "kibCorePluginApi", - "section": "def-common.SavedObject", - "text": "SavedObject" - }, - ">) | undefined" - ] - }, { "tags": [], "id": "def-public.ExecutionContext.isSyncColorsEnabled", @@ -6076,7 +6036,7 @@ ], "source": { "path": "src/plugins/expressions/common/execution/types.ts", - "lineNumber": 79 + "lineNumber": 64 }, "signature": [ "(() => boolean) | undefined" @@ -6085,7 +6045,7 @@ ], "source": { "path": "src/plugins/expressions/common/execution/types.ts", - "lineNumber": 21 + "lineNumber": 20 }, "initialIsOpen": false }, @@ -9481,7 +9441,7 @@ ], "source": { "path": "src/plugins/expressions/public/plugin.ts", - "lineNumber": 24 + "lineNumber": 19 }, "signature": [ "{ readonly getType: (name: string) => ", @@ -9562,7 +9522,7 @@ "description": [], "source": { "path": "src/plugins/expressions/public/plugin.ts", - "lineNumber": 30 + "lineNumber": 25 }, "signature": [ "typeof ", @@ -9583,7 +9543,7 @@ "description": [], "source": { "path": "src/plugins/expressions/public/plugin.ts", - "lineNumber": 31 + "lineNumber": 26 }, "signature": [ "typeof ", @@ -9604,7 +9564,7 @@ "description": [], "source": { "path": "src/plugins/expressions/public/plugin.ts", - "lineNumber": 32 + "lineNumber": 27 }, "signature": [ { @@ -9624,7 +9584,7 @@ "description": [], "source": { "path": "src/plugins/expressions/public/plugin.ts", - "lineNumber": 33 + "lineNumber": 28 }, "signature": [ "({ className, dataAttrs, padding, renderError, expression, onEvent, onData$, reload$, debounce, ...expressionLoaderOptions }: ", @@ -9646,7 +9606,7 @@ "description": [], "source": { "path": "src/plugins/expressions/public/plugin.ts", - "lineNumber": 34 + "lineNumber": 29 }, "signature": [ "typeof ", @@ -9662,7 +9622,7 @@ ], "source": { "path": "src/plugins/expressions/public/plugin.ts", - "lineNumber": 29 + "lineNumber": 24 }, "lifecycle": "start", "initialIsOpen": true @@ -11035,7 +10995,7 @@ "description": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 223 + "lineNumber": 230 } } ], @@ -11043,7 +11003,7 @@ "returnComment": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 223 + "lineNumber": 230 } }, { @@ -11079,7 +11039,7 @@ "description": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 233 + "lineNumber": 241 } }, { @@ -11092,7 +11052,7 @@ "description": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 233 + "lineNumber": 241 } } ], @@ -11100,7 +11060,7 @@ "returnComment": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 233 + "lineNumber": 241 } }, { @@ -11143,7 +11103,7 @@ "description": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 241 + "lineNumber": 249 } }, { @@ -11156,7 +11116,7 @@ "description": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 241 + "lineNumber": 249 } } ], @@ -11164,7 +11124,7 @@ "returnComment": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 241 + "lineNumber": 249 } }, { @@ -11188,7 +11148,7 @@ "returnComment": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 250 + "lineNumber": 258 } } ], @@ -13984,7 +13944,7 @@ ], "source": { "path": "src/plugins/expressions/common/execution/types.ts", - "lineNumber": 28 + "lineNumber": 27 }, "signature": [ "() => ExecutionContextSearch" @@ -14000,7 +13960,7 @@ ], "source": { "path": "src/plugins/expressions/common/execution/types.ts", - "lineNumber": 33 + "lineNumber": 32 }, "signature": [ "Record" @@ -14016,7 +13976,7 @@ ], "source": { "path": "src/plugins/expressions/common/execution/types.ts", - "lineNumber": 38 + "lineNumber": 37 }, "signature": [ "Record string | undefined" @@ -14088,7 +14048,7 @@ ], "source": { "path": "src/plugins/expressions/common/execution/types.ts", - "lineNumber": 60 + "lineNumber": 59 }, "signature": [ "(() => ", @@ -14102,46 +14062,6 @@ ") | undefined" ] }, - { - "tags": [], - "id": "def-server.ExecutionContext.getSavedObject", - "type": "Function", - "label": "getSavedObject", - "description": [ - "\nAllows to fetch saved objects from ElasticSearch. In browser `getSavedObject`\nfunction is provided automatically by the Expressions plugin. On the server\nthe caller of the expression has to provide this context function. The\nreason is because on the browser we always know the user who tries to\nfetch a saved object, thus saved object client is scoped automatically to\nthat user. However, on the server we can scope that saved object client to\nany user, or even not scope it at all and execute it as an \"internal\" user." - ], - "source": { - "path": "src/plugins/expressions/common/execution/types.ts", - "lineNumber": 71 - }, - "signature": [ - "((type: string, id: string) => Promise<", - { - "pluginId": "core", - "scope": "common", - "docId": "kibCorePluginApi", - "section": "def-common.SavedObject", - "text": "SavedObject" - }, - ">) | undefined" - ] - }, { "tags": [], "id": "def-server.ExecutionContext.isSyncColorsEnabled", @@ -14152,7 +14072,7 @@ ], "source": { "path": "src/plugins/expressions/common/execution/types.ts", - "lineNumber": 79 + "lineNumber": 64 }, "signature": [ "(() => boolean) | undefined" @@ -14161,7 +14081,7 @@ ], "source": { "path": "src/plugins/expressions/common/execution/types.ts", - "lineNumber": 21 + "lineNumber": 20 }, "initialIsOpen": false }, @@ -18395,7 +18315,7 @@ "description": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 223 + "lineNumber": 230 } } ], @@ -18403,7 +18323,7 @@ "returnComment": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 223 + "lineNumber": 230 } }, { @@ -18439,7 +18359,7 @@ "description": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 233 + "lineNumber": 241 } }, { @@ -18452,7 +18372,7 @@ "description": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 233 + "lineNumber": 241 } } ], @@ -18460,7 +18380,7 @@ "returnComment": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 233 + "lineNumber": 241 } }, { @@ -18503,7 +18423,7 @@ "description": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 241 + "lineNumber": 249 } }, { @@ -18516,7 +18436,7 @@ "description": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 241 + "lineNumber": 249 } } ], @@ -18524,7 +18444,7 @@ "returnComment": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 241 + "lineNumber": 249 } }, { @@ -18548,7 +18468,7 @@ "returnComment": [], "source": { "path": "src/plugins/expressions/common/executor/executor.ts", - "lineNumber": 250 + "lineNumber": 258 } } ], @@ -23230,7 +23150,7 @@ "description": [], "source": { "path": "src/plugins/expressions/common/execution/types.ts", - "lineNumber": 86 + "lineNumber": 71 }, "signature": [ { @@ -23250,7 +23170,7 @@ "description": [], "source": { "path": "src/plugins/expressions/common/execution/types.ts", - "lineNumber": 87 + "lineNumber": 72 }, "signature": [ { @@ -23265,7 +23185,7 @@ ], "source": { "path": "src/plugins/expressions/common/execution/types.ts", - "lineNumber": 85 + "lineNumber": 70 }, "initialIsOpen": false }, @@ -23362,7 +23282,7 @@ ], "source": { "path": "src/plugins/expressions/common/execution/types.ts", - "lineNumber": 28 + "lineNumber": 27 }, "signature": [ "() => ExecutionContextSearch" @@ -23378,7 +23298,7 @@ ], "source": { "path": "src/plugins/expressions/common/execution/types.ts", - "lineNumber": 33 + "lineNumber": 32 }, "signature": [ "Record" @@ -23394,7 +23314,7 @@ ], "source": { "path": "src/plugins/expressions/common/execution/types.ts", - "lineNumber": 38 + "lineNumber": 37 }, "signature": [ "Record string | undefined" @@ -23466,7 +23386,7 @@ ], "source": { "path": "src/plugins/expressions/common/execution/types.ts", - "lineNumber": 60 + "lineNumber": 59 }, "signature": [ "(() => ", @@ -23480,46 +23400,6 @@ ") | undefined" ] }, - { - "tags": [], - "id": "def-common.ExecutionContext.getSavedObject", - "type": "Function", - "label": "getSavedObject", - "description": [ - "\nAllows to fetch saved objects from ElasticSearch. In browser `getSavedObject`\nfunction is provided automatically by the Expressions plugin. On the server\nthe caller of the expression has to provide this context function. The\nreason is because on the browser we always know the user who tries to\nfetch a saved object, thus saved object client is scoped automatically to\nthat user. However, on the server we can scope that saved object client to\nany user, or even not scope it at all and execute it as an \"internal\" user." - ], - "source": { - "path": "src/plugins/expressions/common/execution/types.ts", - "lineNumber": 71 - }, - "signature": [ - "((type: string, id: string) => Promise<", - { - "pluginId": "core", - "scope": "common", - "docId": "kibCorePluginApi", - "section": "def-common.SavedObject", - "text": "SavedObject" - }, - ">) | undefined" - ] - }, { "tags": [], "id": "def-common.ExecutionContext.isSyncColorsEnabled", @@ -23530,7 +23410,7 @@ ], "source": { "path": "src/plugins/expressions/common/execution/types.ts", - "lineNumber": 79 + "lineNumber": 64 }, "signature": [ "(() => boolean) | undefined" @@ -23539,7 +23419,7 @@ ], "source": { "path": "src/plugins/expressions/common/execution/types.ts", - "lineNumber": 21 + "lineNumber": 20 }, "initialIsOpen": false }, diff --git a/api_docs/fleet.json b/api_docs/fleet.json index ed51f88ee9d5d9..60d0dca4d8a108 100644 --- a/api_docs/fleet.json +++ b/api_docs/fleet.json @@ -1789,7 +1789,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">, id: string, withPackagePolicies?: boolean) => Promise<", + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">, id: string, withPackagePolicies?: boolean) => Promise<", { "pluginId": "fleet", "scope": "common", @@ -1819,7 +1819,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">, options: Readonly<{ page?: number | undefined; perPage?: number | undefined; sortField?: string | undefined; sortOrder?: \"asc\" | \"desc\" | undefined; kuery?: any; showUpgradeable?: boolean | undefined; } & {}> & { withPackagePolicies?: boolean | undefined; }) => Promise<{ items: ", + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">, options: Readonly<{ page?: number | undefined; perPage?: number | undefined; sortField?: string | undefined; sortOrder?: \"asc\" | \"desc\" | undefined; kuery?: any; showUpgradeable?: boolean | undefined; } & {}> & { withPackagePolicies?: boolean | undefined; }) => Promise<{ items: ", { "pluginId": "fleet", "scope": "common", @@ -1849,7 +1849,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">) => Promise" + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">) => Promise" ] }, { @@ -1871,7 +1871,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">, id: string, options?: { standalone: boolean; } | undefined) => Promise<", + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">, id: string, options?: { standalone: boolean; } | undefined) => Promise<", { "pluginId": "fleet", "scope": "common", @@ -2434,7 +2434,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">, pkgName: string, datasetPath: string) => Promise" + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">, pkgName: string, datasetPath: string) => Promise" ], "description": [], "children": [ @@ -2451,7 +2451,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">" + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">" ], "description": [], "source": { @@ -2661,7 +2661,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">, pkgName: string) => Promise<", + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">, pkgName: string) => Promise<", { "pluginId": "fleet", "scope": "common", @@ -2686,7 +2686,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">" + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">" ], "description": [], "source": { @@ -3744,7 +3744,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 152 + "lineNumber": 151 } }, { @@ -3755,7 +3755,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 153 + "lineNumber": 152 }, "signature": [ { @@ -3776,7 +3776,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 154 + "lineNumber": 153 }, "signature": [ "string | undefined" @@ -3790,7 +3790,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 155 + "lineNumber": 154 }, "signature": [ "string | undefined" @@ -3804,7 +3804,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 156 + "lineNumber": 155 }, "signature": [ "string[]" @@ -3813,7 +3813,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 151 + "lineNumber": 150 }, "initialIsOpen": false }, @@ -3849,7 +3849,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 49 + "lineNumber": 48 }, "signature": [ { @@ -3869,7 +3869,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 50 + "lineNumber": 49 }, "signature": [ "any" @@ -3883,7 +3883,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 51 + "lineNumber": 50 }, "signature": [ "string | undefined" @@ -3897,7 +3897,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 52 + "lineNumber": 51 } }, { @@ -3908,7 +3908,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 53 + "lineNumber": 52 } }, { @@ -3919,7 +3919,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 54 + "lineNumber": 53 } }, { @@ -3930,7 +3930,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 55 + "lineNumber": 54 }, "signature": [ "any" @@ -3939,7 +3939,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 48 + "lineNumber": 47 }, "initialIsOpen": false }, @@ -3975,13 +3975,13 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 124 + "lineNumber": 123 } } ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 123 + "lineNumber": 122 }, "initialIsOpen": false }, @@ -4000,7 +4000,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 130 + "lineNumber": 129 }, "signature": [ "any" @@ -4009,7 +4009,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 129 + "lineNumber": 128 }, "initialIsOpen": false }, @@ -4174,7 +4174,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 59 + "lineNumber": 58 } }, { @@ -4185,7 +4185,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 60 + "lineNumber": 59 }, "signature": [ { @@ -4205,7 +4205,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 61 + "lineNumber": 60 }, "signature": [ "{ policy: ", @@ -4227,7 +4227,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 64 + "lineNumber": 63 } }, { @@ -4238,7 +4238,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 65 + "lineNumber": 64 } }, { @@ -4249,7 +4249,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 66 + "lineNumber": 65 } }, { @@ -4260,7 +4260,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 67 + "lineNumber": 66 }, "signature": [ "any" @@ -4269,7 +4269,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 58 + "lineNumber": 57 }, "initialIsOpen": false }, @@ -4298,7 +4298,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 160 + "lineNumber": 159 }, "signature": [ "string | undefined" @@ -4312,7 +4312,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 161 + "lineNumber": 160 }, "signature": [ "string[] | undefined" @@ -4321,7 +4321,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 159 + "lineNumber": 158 }, "initialIsOpen": false }, @@ -5111,7 +5111,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 193 + "lineNumber": 200 }, "signature": [ "{ agentId: string; }" @@ -5120,7 +5120,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 192 + "lineNumber": 199 }, "initialIsOpen": false }, @@ -5521,7 +5521,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 173 + "lineNumber": 172 }, "signature": [ "number | undefined" @@ -5537,7 +5537,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 177 + "lineNumber": 176 }, "signature": [ "string | undefined" @@ -5553,7 +5553,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 181 + "lineNumber": 180 }, "signature": [ { @@ -5575,7 +5575,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 185 + "lineNumber": 184 } }, { @@ -5588,7 +5588,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 189 + "lineNumber": 188 } }, { @@ -5601,7 +5601,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 193 + "lineNumber": 192 }, "signature": [ "string | undefined" @@ -5617,7 +5617,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 197 + "lineNumber": 196 }, "signature": [ "string | undefined" @@ -5633,7 +5633,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 201 + "lineNumber": 200 }, "signature": [ "string | null | undefined" @@ -5649,7 +5649,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 205 + "lineNumber": 204 }, "signature": [ "string | null | undefined" @@ -5665,7 +5665,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 209 + "lineNumber": 208 }, "signature": [ "string | undefined" @@ -5679,7 +5679,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 210 + "lineNumber": 209 }, "signature": [ { @@ -5702,7 +5702,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 214 + "lineNumber": 213 }, "signature": [ { @@ -5724,7 +5724,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 218 + "lineNumber": 217 }, "signature": [ { @@ -5746,7 +5746,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 222 + "lineNumber": 221 }, "signature": [ "string | undefined" @@ -5762,7 +5762,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 226 + "lineNumber": 225 }, "signature": [ "number | null | undefined" @@ -5778,7 +5778,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 230 + "lineNumber": 229 }, "signature": [ "number | undefined" @@ -5794,7 +5794,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 234 + "lineNumber": 233 }, "signature": [ "string | undefined" @@ -5810,7 +5810,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 238 + "lineNumber": 237 }, "signature": [ "string | undefined" @@ -5826,7 +5826,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 242 + "lineNumber": 241 }, "signature": [ "\"online\" | \"error\" | \"updating\" | \"degraded\" | undefined" @@ -5842,7 +5842,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 246 + "lineNumber": 245 }, "signature": [ "string | undefined" @@ -5858,7 +5858,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 250 + "lineNumber": 249 }, "signature": [ "string | undefined" @@ -5874,7 +5874,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 254 + "lineNumber": 253 }, "signature": [ "string | undefined" @@ -5890,7 +5890,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 258 + "lineNumber": 257 }, "signature": [ "string[] | undefined" @@ -5906,7 +5906,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 262 + "lineNumber": 261 }, "signature": [ "number | undefined" @@ -5915,7 +5915,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 169 + "lineNumber": 168 }, "initialIsOpen": false }, @@ -5938,7 +5938,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 286 + "lineNumber": 285 }, "signature": [ "string | undefined" @@ -5954,7 +5954,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 290 + "lineNumber": 289 }, "signature": [ "number | undefined" @@ -5970,7 +5970,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 294 + "lineNumber": 293 }, "signature": [ "string | undefined" @@ -5986,7 +5986,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 298 + "lineNumber": 297 }, "signature": [ "string | undefined" @@ -6002,7 +6002,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 302 + "lineNumber": 301 }, "signature": [ "string | undefined" @@ -6018,7 +6018,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 306 + "lineNumber": 305 }, "signature": [ "string | undefined" @@ -6034,7 +6034,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 310 + "lineNumber": 309 }, "signature": [ "string | undefined" @@ -6050,7 +6050,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 314 + "lineNumber": 313 }, "signature": [ "string[] | undefined" @@ -6066,7 +6066,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 318 + "lineNumber": 317 }, "signature": [ "{ [k: string]: unknown; } | undefined" @@ -6080,7 +6080,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 321 + "lineNumber": 320 }, "signature": [ "any" @@ -6089,7 +6089,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 282 + "lineNumber": 281 }, "initialIsOpen": false }, @@ -6112,7 +6112,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 271 + "lineNumber": 270 } }, { @@ -6125,7 +6125,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 275 + "lineNumber": 274 } }, { @@ -6136,7 +6136,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 276 + "lineNumber": 275 }, "signature": [ "any" @@ -6145,7 +6145,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 267 + "lineNumber": 266 }, "initialIsOpen": false }, @@ -6968,7 +6968,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 208 + "lineNumber": 215 }, "signature": [ "{ kuery?: string | undefined; policyId?: string | undefined; }" @@ -6977,7 +6977,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 207 + "lineNumber": 214 }, "initialIsOpen": false }, @@ -6996,7 +6996,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 215 + "lineNumber": 222 }, "signature": [ "{ events: number; total: number; online: number; error: number; offline: number; other: number; updating: number; }" @@ -7005,7 +7005,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 214 + "lineNumber": 221 }, "initialIsOpen": false }, @@ -7436,7 +7436,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 175 + "lineNumber": 182 }, "signature": [ "{ agentId: string; }" @@ -7450,7 +7450,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 178 + "lineNumber": 185 }, "signature": [ "{ page: number; perPage: number; kuery?: string | undefined; }" @@ -7459,7 +7459,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 174 + "lineNumber": 181 }, "initialIsOpen": false }, @@ -7478,7 +7478,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 186 + "lineNumber": 193 }, "signature": [ { @@ -7499,7 +7499,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 187 + "lineNumber": 194 } }, { @@ -7510,7 +7510,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 188 + "lineNumber": 195 } }, { @@ -7521,13 +7521,13 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 189 + "lineNumber": 196 } } ], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 185 + "lineNumber": 192 }, "initialIsOpen": false }, @@ -8883,7 +8883,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 43 + "lineNumber": 42 }, "signature": [ { @@ -8903,7 +8903,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 44 + "lineNumber": 43 }, "signature": [ "any" @@ -8917,7 +8917,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 45 + "lineNumber": 44 }, "signature": [ "string | undefined" @@ -8926,7 +8926,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 42 + "lineNumber": 41 }, "initialIsOpen": false }, @@ -8945,7 +8945,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 98 + "lineNumber": 97 }, "signature": [ "\"STATE\" | \"ERROR\" | \"ACTION_RESULT\" | \"ACTION\"" @@ -8959,7 +8959,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 99 + "lineNumber": 98 }, "signature": [ "\"RUNNING\" | \"STARTING\" | \"IN_PROGRESS\" | \"CONFIG\" | \"FAILED\" | \"STOPPING\" | \"STOPPED\" | \"DEGRADED\" | \"UPDATING\" | \"DATA_DUMP\" | \"ACKNOWLEDGED\" | \"UNKNOWN\"" @@ -8973,7 +8973,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 114 + "lineNumber": 113 } }, { @@ -8984,7 +8984,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 115 + "lineNumber": 114 } }, { @@ -8995,7 +8995,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 116 + "lineNumber": 115 }, "signature": [ "any" @@ -9009,7 +9009,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 117 + "lineNumber": 116 } }, { @@ -9020,7 +9020,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 118 + "lineNumber": 117 }, "signature": [ "string | undefined" @@ -9034,7 +9034,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 119 + "lineNumber": 118 }, "signature": [ "string | undefined" @@ -9048,7 +9048,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 120 + "lineNumber": 119 }, "signature": [ "string | undefined" @@ -9057,7 +9057,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 97 + "lineNumber": 96 }, "initialIsOpen": false }, @@ -10708,7 +10708,7 @@ "children": [], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 148 + "lineNumber": 154 }, "initialIsOpen": false }, @@ -10727,7 +10727,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 161 + "lineNumber": 167 }, "signature": [ "{ policy_id: string; agents: string | string[]; }" @@ -10736,35 +10736,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 160 - }, - "initialIsOpen": false - }, - { - "id": "def-common.PostBulkAgentReassignResponse", - "type": "Interface", - "label": "PostBulkAgentReassignResponse", - "description": [], - "tags": [], - "children": [ - { - "id": "def-common.PostBulkAgentReassignResponse.Unnamed", - "type": "Any", - "label": "Unnamed", - "tags": [], - "description": [], - "source": { - "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 168 - }, - "signature": [ - "any" - ] - } - ], - "source": { - "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 167 + "lineNumber": 166 }, "initialIsOpen": false }, @@ -10837,19 +10809,6 @@ }, "initialIsOpen": false }, - { - "id": "def-common.PostBulkAgentUpgradeResponse", - "type": "Interface", - "label": "PostBulkAgentUpgradeResponse", - "description": [], - "tags": [], - "children": [], - "source": { - "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 145 - }, - "initialIsOpen": false - }, { "id": "def-common.PostEnrollmentAPIKeyRequest", "type": "Interface", @@ -11047,7 +11006,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 151 + "lineNumber": 157 }, "signature": [ "{ agentId: string; }" @@ -11061,7 +11020,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 154 + "lineNumber": 160 }, "signature": [ "{ policy_id: string; }" @@ -11070,7 +11029,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 150 + "lineNumber": 156 }, "initialIsOpen": false }, @@ -11083,7 +11042,7 @@ "children": [], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 158 + "lineNumber": 164 }, "initialIsOpen": false }, @@ -12138,7 +12097,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 199 + "lineNumber": 206 }, "signature": [ "{ agentId: string; }" @@ -12152,7 +12111,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 202 + "lineNumber": 209 }, "signature": [ "{ user_provided_metadata: Record; }" @@ -12161,7 +12120,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", - "lineNumber": 198 + "lineNumber": 205 }, "initialIsOpen": false }, @@ -12597,7 +12556,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 88 + "lineNumber": 87 }, "signature": [ "CommonAgentActionSOAttributes & { agent_id: string; }" @@ -12615,7 +12574,7 @@ "lineNumber": 34 }, "signature": [ - "\"POLICY_CHANGE\" | \"UNENROLL\" | \"UPGRADE\" | \"SETTINGS\" | \"INTERNAL_POLICY_REASSIGN\"" + "\"POLICY_CHANGE\" | \"UNENROLL\" | \"UPGRADE\" | \"SETTINGS\" | \"POLICY_REASSIGN\"" ], "initialIsOpen": false }, @@ -12642,7 +12601,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 127 + "lineNumber": 126 }, "signature": [ "NewAgentEvent" @@ -12657,7 +12616,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 91 + "lineNumber": 90 }, "signature": [ "CommonAgentActionSOAttributes & { policy_id: string; policy_revision: number; }" @@ -12672,7 +12631,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 72 + "lineNumber": 71 }, "signature": [ "Pick & { type: 'CONFIG_CHANGE'; data: { config: FullAgentPolicy;}; }" @@ -12920,7 +12879,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent.ts", - "lineNumber": 95 + "lineNumber": 94 }, "signature": [ { @@ -13822,6 +13781,36 @@ ], "initialIsOpen": false }, + { + "id": "def-common.PostBulkAgentReassignResponse", + "type": "Type", + "label": "PostBulkAgentReassignResponse", + "tags": [], + "description": [], + "source": { + "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", + "lineNumber": 173 + }, + "signature": [ + "{ [x: string]: { success: boolean; error?: string | undefined; }; }" + ], + "initialIsOpen": false + }, + { + "id": "def-common.PostBulkAgentUpgradeResponse", + "type": "Type", + "label": "PostBulkAgentUpgradeResponse", + "tags": [], + "description": [], + "source": { + "path": "x-pack/plugins/fleet/common/types/rest_spec/agent.ts", + "lineNumber": 145 + }, + "signature": [ + "{ [x: string]: { success: boolean; error?: string | undefined; }; }" + ], + "initialIsOpen": false + }, { "id": "def-common.RegistryPackage", "type": "Type", diff --git a/api_docs/global_search.json b/api_docs/global_search.json index 985abf3417935a..0cb40be77a7aeb 100644 --- a/api_docs/global_search.json +++ b/api_docs/global_search.json @@ -704,7 +704,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">; typeRegistry: Pick<", + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">; typeRegistry: Pick<", { "pluginId": "core", "scope": "server", diff --git a/api_docs/index_management.json b/api_docs/index_management.json index 8c6ba711642ffd..6c66a94bf59f5d 100644 --- a/api_docs/index_management.json +++ b/api_docs/index_management.json @@ -1121,13 +1121,7 @@ "lineNumber": 58 }, "signature": [ - { - "pluginId": "indexManagement", - "scope": "common", - "docId": "kibIndexManagementPluginApi", - "section": "def-common.Health", - "text": "Health" - } + "ClusterStatus" ] }, { diff --git a/api_docs/infra.json b/api_docs/infra.json index a10be8ce8bf04b..9d64df881fc528 100644 --- a/api_docs/infra.json +++ b/api_docs/infra.json @@ -198,7 +198,7 @@ "description": [], "source": { "path": "x-pack/plugins/infra/server/plugin.ts", - "lineNumber": 64 + "lineNumber": 65 }, "signature": [ "{ readonly sources?: Readonly<{ default?: Readonly<{ fields?: Readonly<{ host?: string | undefined; message?: string[] | undefined; timestamp?: string | undefined; tiebreaker?: string | undefined; container?: string | undefined; pod?: string | undefined; } & {}> | undefined; logAlias?: string | undefined; metricAlias?: string | undefined; } & {}> | undefined; } & {}> | undefined; readonly enabled: boolean; readonly query: Readonly<{} & { partitionSize: number; partitionFactor: number; }>; }" @@ -222,7 +222,7 @@ "description": [], "source": { "path": "x-pack/plugins/infra/server/plugin.ts", - "lineNumber": 75 + "lineNumber": 76 }, "signature": [ "(sourceId: string, sourceProperties: ", @@ -239,7 +239,7 @@ ], "source": { "path": "x-pack/plugins/infra/server/plugin.ts", - "lineNumber": 74 + "lineNumber": 75 }, "lifecycle": "setup", "initialIsOpen": true diff --git a/api_docs/lens.json b/api_docs/lens.json index e586016c22fc3f..b5321bf24ba6b0 100644 --- a/api_docs/lens.json +++ b/api_docs/lens.json @@ -82,7 +82,7 @@ "lineNumber": 43 }, "signature": [ - "\"cardinality\"" + "\"unique_count\"" ] } ], @@ -238,7 +238,7 @@ "description": [], "source": { "path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/filters/filters.tsx", - "lineNumber": 73 + "lineNumber": 74 }, "signature": [ "\"filters\"" @@ -252,7 +252,7 @@ "description": [], "source": { "path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/filters/filters.tsx", - "lineNumber": 74 + "lineNumber": 75 }, "signature": [ "{ filters: ", @@ -269,7 +269,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/filters/filters.tsx", - "lineNumber": 72 + "lineNumber": 73 }, "initialIsOpen": false }, @@ -291,7 +291,7 @@ "lineNumber": 46 }, "signature": [ - "\"range\" | \"filters\" | \"count\" | \"max\" | \"min\" | \"date_histogram\" | \"sum\" | \"terms\" | \"avg\" | \"median\" | \"cumulative_sum\" | \"derivative\" | \"moving_average\" | \"counter_rate\" | \"cardinality\" | \"percentile\" | \"last_value\" | undefined" + "\"range\" | \"filters\" | \"count\" | \"max\" | \"min\" | \"date_histogram\" | \"sum\" | \"average\" | \"terms\" | \"median\" | \"cumulative_sum\" | \"moving_average\" | \"counter_rate\" | \"differences\" | \"unique_count\" | \"percentile\" | \"last_value\" | undefined" ] }, { @@ -538,6 +538,30 @@ "signature": [ "() => boolean" ] + }, + { + "tags": [], + "id": "def-public.LensPublicStart.getXyVisTypes", + "type": "Function", + "label": "getXyVisTypes", + "description": [ + "\nMethod which returns xy VisualizationTypes array keeping this async as to not impact page load bundle" + ], + "source": { + "path": "x-pack/plugins/lens/public/plugin.ts", + "lineNumber": 108 + }, + "signature": [ + "() => Promise<", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.VisualizationType", + "text": "VisualizationType" + }, + "[]>" + ] } ], "source": { @@ -929,7 +953,7 @@ "description": [], "source": { "path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx", - "lineNumber": 59 + "lineNumber": 57 }, "signature": [ "\"terms\"" @@ -943,7 +967,7 @@ "description": [], "source": { "path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx", - "lineNumber": 60 + "lineNumber": 58 }, "signature": [ "{ size: number; orderBy: { type: \"alphabetical\"; } | { type: \"column\"; columnId: string; }; orderDirection: \"asc\" | \"desc\"; otherBucket?: boolean | undefined; missingBucket?: boolean | undefined; format?: { id: string; params?: { decimals: number; } | undefined; } | undefined; }" @@ -952,7 +976,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx", - "lineNumber": 58 + "lineNumber": 56 }, "initialIsOpen": false }, @@ -1114,7 +1138,7 @@ "description": [], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 420 + "lineNumber": 423 }, "signature": [ { @@ -1134,7 +1158,7 @@ "description": [], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 421 + "lineNumber": 424 }, "signature": [ { @@ -1154,7 +1178,7 @@ "description": [], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 422 + "lineNumber": 425 }, "signature": [ "\"hide\" | \"inside\" | \"outside\" | undefined" @@ -1168,7 +1192,7 @@ "description": [], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 423 + "lineNumber": 426 }, "signature": [ "\"None\" | \"Zero\" | \"Linear\" | \"Carry\" | \"Lookahead\" | undefined" @@ -1182,7 +1206,7 @@ "description": [], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 424 + "lineNumber": 427 }, "signature": [ { @@ -1203,7 +1227,7 @@ "description": [], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 425 + "lineNumber": 428 }, "signature": [ "string | undefined" @@ -1217,7 +1241,7 @@ "description": [], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 426 + "lineNumber": 429 }, "signature": [ "string | undefined" @@ -1231,7 +1255,7 @@ "description": [], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 427 + "lineNumber": 430 }, "signature": [ "string | undefined" @@ -1245,7 +1269,7 @@ "description": [], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 428 + "lineNumber": 431 }, "signature": [ { @@ -1266,7 +1290,7 @@ "description": [], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 429 + "lineNumber": 432 }, "signature": [ { @@ -1287,7 +1311,7 @@ "description": [], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 430 + "lineNumber": 433 }, "signature": [ { @@ -1299,11 +1323,25 @@ }, " | undefined" ] + }, + { + "tags": [], + "id": "def-public.XYState.curveType", + "type": "CompoundType", + "label": "curveType", + "description": [], + "source": { + "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", + "lineNumber": 434 + }, + "signature": [ + "\"LINEAR\" | \"CURVE_MONOTONE_X\" | undefined" + ] } ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 419 + "lineNumber": 422 }, "initialIsOpen": false } @@ -1318,10 +1356,10 @@ "description": [], "source": { "path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx", - "lineNumber": 127 + "lineNumber": 126 }, "signature": [ - "BaseIndexPatternColumn & { params?: { format?: { id: string; params?: { decimals: number; } | undefined; } | undefined; } | undefined; } & FieldBasedIndexPatternColumn & { operationType: \"avg\"; }" + "BaseIndexPatternColumn & { params?: { format?: { id: string; params?: { decimals: number; } | undefined; } | undefined; } | undefined; } & FieldBasedIndexPatternColumn & { operationType: \"average\"; }" ], "initialIsOpen": false }, @@ -1380,12 +1418,12 @@ "tags": [], "description": [], "source": { - "path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/derivative.tsx", - "lineNumber": 35 + "path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/differences.tsx", + "lineNumber": 37 }, "signature": [ "BaseIndexPatternColumn", - " & { params?: { format?: { id: string; params?: { decimals: number; } | undefined; } | undefined; } | undefined; } & ReferenceBasedIndexPatternColumn & { operationType: 'derivative'; }" + " & { params?: { format?: { id: string; params?: { decimals: number; } | undefined; } | undefined; } | undefined; } & ReferenceBasedIndexPatternColumn & { operationType: typeof OPERATION_NAME; }" ], "initialIsOpen": false }, @@ -1456,7 +1494,7 @@ "section": "def-public.DateHistogramIndexPatternColumn", "text": "DateHistogramIndexPatternColumn" }, - " | MetricColumn<\"min\"> | MetricColumn<\"max\"> | MetricColumn<\"avg\"> | ", + " | MetricColumn<\"min\"> | MetricColumn<\"max\"> | MetricColumn<\"average\"> | ", { "pluginId": "lens", "scope": "public", @@ -1475,7 +1513,7 @@ "description": [], "source": { "path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx", - "lineNumber": 129 + "lineNumber": 128 }, "signature": [ "BaseIndexPatternColumn & { params?: { format?: { id: string; params?: { decimals: number; } | undefined; } | undefined; } | undefined; } & FieldBasedIndexPatternColumn & { operationType: \"max\"; }" @@ -1490,7 +1528,7 @@ "description": [], "source": { "path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx", - "lineNumber": 130 + "lineNumber": 129 }, "signature": [ "BaseIndexPatternColumn & { params?: { format?: { id: string; params?: { decimals: number; } | undefined; } | undefined; } | undefined; } & FieldBasedIndexPatternColumn & { operationType: \"median\"; }" @@ -1505,7 +1543,7 @@ "description": [], "source": { "path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx", - "lineNumber": 128 + "lineNumber": 127 }, "signature": [ "BaseIndexPatternColumn & { params?: { format?: { id: string; params?: { decimals: number; } | undefined; } | undefined; } | undefined; } & FieldBasedIndexPatternColumn & { operationType: \"min\"; }" @@ -1541,7 +1579,7 @@ "lineNumber": 406 }, "signature": [ - "\"range\" | \"filters\" | \"count\" | \"max\" | \"min\" | \"date_histogram\" | \"sum\" | \"terms\" | \"avg\" | \"median\" | \"cumulative_sum\" | \"derivative\" | \"moving_average\" | \"counter_rate\" | \"cardinality\" | \"percentile\" | \"last_value\"" + "\"range\" | \"filters\" | \"count\" | \"max\" | \"min\" | \"date_histogram\" | \"sum\" | \"average\" | \"terms\" | \"median\" | \"cumulative_sum\" | \"moving_average\" | \"counter_rate\" | \"differences\" | \"unique_count\" | \"percentile\" | \"last_value\"" ], "initialIsOpen": false }, @@ -1598,7 +1636,7 @@ "description": [], "source": { "path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx", - "lineNumber": 126 + "lineNumber": 125 }, "signature": [ "BaseIndexPatternColumn & { params?: { format?: { id: string; params?: { decimals: number; } | undefined; } | undefined; } | undefined; } & FieldBasedIndexPatternColumn & { operationType: \"sum\"; }" diff --git a/api_docs/lists.json b/api_docs/lists.json index fe06ebe62ce232..fc935809cd7d86 100644 --- a/api_docs/lists.json +++ b/api_docs/lists.json @@ -3698,6 +3698,188 @@ "lineNumber": 48 }, "initialIsOpen": false + }, + { + "id": "def-server.UpdateExceptionListItemOptions", + "type": "Interface", + "label": "UpdateExceptionListItemOptions", + "description": [], + "tags": [], + "children": [ + { + "tags": [], + "id": "def-server.UpdateExceptionListItemOptions._version", + "type": "string", + "label": "_version", + "description": [], + "source": { + "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts", + "lineNumber": 144 + }, + "signature": [ + "string | undefined" + ] + }, + { + "tags": [], + "id": "def-server.UpdateExceptionListItemOptions.comments", + "type": "Array", + "label": "comments", + "description": [], + "source": { + "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts", + "lineNumber": 145 + }, + "signature": [ + "({ comment: string; } & { id?: string | undefined; })[]" + ] + }, + { + "tags": [], + "id": "def-server.UpdateExceptionListItemOptions.entries", + "type": "Array", + "label": "entries", + "description": [], + "source": { + "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts", + "lineNumber": 146 + }, + "signature": [ + "({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"text\" | \"keyword\" | \"ip\" | \"long\" | \"double\" | \"date_nanos\" | \"geo_point\" | \"geo_shape\" | \"short\" | \"binary\" | \"date_range\" | \"ip_range\" | \"shape\" | \"integer\" | \"byte\" | \"float\" | \"double_range\" | \"float_range\" | \"half_float\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]" + ] + }, + { + "tags": [], + "id": "def-server.UpdateExceptionListItemOptions.id", + "type": "string", + "label": "id", + "description": [], + "source": { + "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts", + "lineNumber": 147 + }, + "signature": [ + "string | undefined" + ] + }, + { + "tags": [], + "id": "def-server.UpdateExceptionListItemOptions.itemId", + "type": "string", + "label": "itemId", + "description": [], + "source": { + "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts", + "lineNumber": 148 + }, + "signature": [ + "string | undefined" + ] + }, + { + "tags": [], + "id": "def-server.UpdateExceptionListItemOptions.namespaceType", + "type": "CompoundType", + "label": "namespaceType", + "description": [], + "source": { + "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts", + "lineNumber": 149 + }, + "signature": [ + "\"single\" | \"agnostic\"" + ] + }, + { + "tags": [], + "id": "def-server.UpdateExceptionListItemOptions.name", + "type": "string", + "label": "name", + "description": [], + "source": { + "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts", + "lineNumber": 150 + }, + "signature": [ + "string | undefined" + ] + }, + { + "tags": [], + "id": "def-server.UpdateExceptionListItemOptions.osTypes", + "type": "Array", + "label": "osTypes", + "description": [], + "source": { + "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts", + "lineNumber": 151 + }, + "signature": [ + "(\"windows\" | \"linux\" | \"macos\")[]" + ] + }, + { + "tags": [], + "id": "def-server.UpdateExceptionListItemOptions.description", + "type": "string", + "label": "description", + "description": [], + "source": { + "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts", + "lineNumber": 152 + }, + "signature": [ + "string | undefined" + ] + }, + { + "tags": [], + "id": "def-server.UpdateExceptionListItemOptions.meta", + "type": "Uncategorized", + "label": "meta", + "description": [], + "source": { + "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts", + "lineNumber": 153 + }, + "signature": [ + "object | undefined" + ] + }, + { + "tags": [], + "id": "def-server.UpdateExceptionListItemOptions.tags", + "type": "Array", + "label": "tags", + "description": [], + "source": { + "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts", + "lineNumber": 154 + }, + "signature": [ + "string[] | undefined" + ] + }, + { + "tags": [], + "id": "def-server.UpdateExceptionListItemOptions.type", + "type": "string", + "label": "type", + "description": [], + "source": { + "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts", + "lineNumber": 155 + }, + "signature": [ + "\"simple\" | undefined" + ] + } + ], + "source": { + "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts", + "lineNumber": 143 + }, + "initialIsOpen": false } ], "enums": [], diff --git a/api_docs/ml.json b/api_docs/ml.json index fa9bd613195a67..067ae4c0ea212f 100644 --- a/api_docs/ml.json +++ b/api_docs/ml.json @@ -1626,13 +1626,7 @@ "isRequired": false, "signature": [ "Record | undefined" ], "description": [], @@ -1700,210 +1694,6 @@ } ], "interfaces": [ - { - "id": "def-server.AnalysisConfig", - "type": "Interface", - "label": "AnalysisConfig", - "description": [], - "tags": [], - "children": [ - { - "tags": [], - "id": "def-server.AnalysisConfig.bucket_span", - "type": "string", - "label": "bucket_span", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 48 - } - }, - { - "tags": [], - "id": "def-server.AnalysisConfig.categorization_field_name", - "type": "string", - "label": "categorization_field_name", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 49 - }, - "signature": [ - "string | undefined" - ] - }, - { - "tags": [], - "id": "def-server.AnalysisConfig.categorization_filters", - "type": "Array", - "label": "categorization_filters", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 50 - }, - "signature": [ - "string[] | undefined" - ] - }, - { - "tags": [], - "id": "def-server.AnalysisConfig.categorization_analyzer", - "type": "CompoundType", - "label": "categorization_analyzer", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 51 - }, - "signature": [ - "string | object | undefined" - ] - }, - { - "tags": [], - "id": "def-server.AnalysisConfig.detectors", - "type": "Array", - "label": "detectors", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 52 - }, - "signature": [ - { - "pluginId": "ml", - "scope": "common", - "docId": "kibMlPluginApi", - "section": "def-common.Detector", - "text": "Detector" - }, - "[]" - ] - }, - { - "tags": [], - "id": "def-server.AnalysisConfig.influencers", - "type": "Array", - "label": "influencers", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 53 - }, - "signature": [ - "string[]" - ] - }, - { - "tags": [], - "id": "def-server.AnalysisConfig.latency", - "type": "number", - "label": "latency", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 54 - }, - "signature": [ - "number | undefined" - ] - }, - { - "tags": [], - "id": "def-server.AnalysisConfig.multivariate_by_fields", - "type": "CompoundType", - "label": "multivariate_by_fields", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 55 - }, - "signature": [ - "boolean | undefined" - ] - }, - { - "tags": [], - "id": "def-server.AnalysisConfig.summary_count_field_name", - "type": "string", - "label": "summary_count_field_name", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 56 - }, - "signature": [ - "string | undefined" - ] - }, - { - "tags": [], - "id": "def-server.AnalysisConfig.per_partition_categorization", - "type": "Object", - "label": "per_partition_categorization", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 57 - }, - "signature": [ - { - "pluginId": "ml", - "scope": "common", - "docId": "kibMlPluginApi", - "section": "def-common.PerPartitionCategorization", - "text": "PerPartitionCategorization" - }, - " | undefined" - ] - } - ], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 47 - }, - "initialIsOpen": false - }, - { - "id": "def-server.AnalysisLimits", - "type": "Interface", - "label": "AnalysisLimits", - "description": [], - "tags": [], - "children": [ - { - "tags": [], - "id": "def-server.AnalysisLimits.categorization_examples_limit", - "type": "number", - "label": "categorization_examples_limit", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 73 - }, - "signature": [ - "number | undefined" - ] - }, - { - "tags": [], - "id": "def-server.AnalysisLimits.model_memory_limit", - "type": "string", - "label": "model_memory_limit", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 74 - } - } - ], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 72 - }, - "initialIsOpen": false - }, { "id": "def-server.AnomaliesTableRecord", "type": "Interface", @@ -2692,48 +2482,6 @@ }, "initialIsOpen": false }, - { - "id": "def-server.ChunkingConfig", - "type": "Interface", - "label": "ChunkingConfig", - "description": [], - "tags": [], - "children": [ - { - "tags": [], - "id": "def-server.ChunkingConfig.mode", - "type": "CompoundType", - "label": "mode", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", - "lineNumber": 32 - }, - "signature": [ - "\"auto\" | \"off\" | \"manual\"" - ] - }, - { - "tags": [], - "id": "def-server.ChunkingConfig.time_span", - "type": "string", - "label": "time_span", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", - "lineNumber": 33 - }, - "signature": [ - "string | undefined" - ] - } - ], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", - "lineNumber": 31 - }, - "initialIsOpen": false - }, { "id": "def-server.CombinedJob", "type": "Interface", @@ -2771,13 +2519,7 @@ "lineNumber": 20 }, "signature": [ - { - "pluginId": "ml", - "scope": "common", - "docId": "kibMlPluginApi", - "section": "def-common.Datafeed", - "text": "Datafeed" - } + "Datafeed" ] } ], @@ -2841,128 +2583,72 @@ "initialIsOpen": false }, { - "id": "def-server.CustomRule", + "id": "def-server.CustomSettings", "type": "Interface", - "label": "CustomRule", + "label": "CustomSettings", "description": [], "tags": [], "children": [ { "tags": [], - "id": "def-server.CustomRule.actions", + "id": "def-server.CustomSettings.custom_urls", "type": "Array", - "label": "actions", + "label": "custom_urls", "description": [], "source": { "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 91 + "lineNumber": 16 }, "signature": [ - "string[]" + { + "pluginId": "ml", + "scope": "common", + "docId": "kibMlPluginApi", + "section": "def-common.UrlConfig", + "text": "UrlConfig" + }, + "[] | undefined" ] }, { "tags": [], - "id": "def-server.CustomRule.scope", - "type": "Uncategorized", - "label": "scope", + "id": "def-server.CustomSettings.created_by", + "type": "CompoundType", + "label": "created_by", "description": [], "source": { "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 92 + "lineNumber": 17 }, "signature": [ - "object | undefined" + { + "pluginId": "ml", + "scope": "common", + "docId": "kibMlPluginApi", + "section": "def-common.CREATED_BY_LABEL", + "text": "CREATED_BY_LABEL" + }, + " | undefined" ] }, { "tags": [], - "id": "def-server.CustomRule.conditions", - "type": "Array", - "label": "conditions", + "id": "def-server.CustomSettings.job_tags", + "type": "Object", + "label": "job_tags", "description": [], "source": { "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 93 + "lineNumber": 18 }, "signature": [ - "any[]" + "{ [tag: string]: string; } | undefined" ] } ], "source": { "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 90 - }, - "initialIsOpen": false - }, - { - "id": "def-server.CustomSettings", - "type": "Interface", - "label": "CustomSettings", - "description": [], - "tags": [], - "children": [ - { - "tags": [], - "id": "def-server.CustomSettings.custom_urls", - "type": "Array", - "label": "custom_urls", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 15 - }, - "signature": [ - { - "pluginId": "ml", - "scope": "common", - "docId": "kibMlPluginApi", - "section": "def-common.UrlConfig", - "text": "UrlConfig" - }, - "[] | undefined" - ] - }, - { - "tags": [], - "id": "def-server.CustomSettings.created_by", - "type": "CompoundType", - "label": "created_by", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 16 - }, - "signature": [ - { - "pluginId": "ml", - "scope": "common", - "docId": "kibMlPluginApi", - "section": "def-common.CREATED_BY_LABEL", - "text": "CREATED_BY_LABEL" - }, - " | undefined" - ] - }, - { - "tags": [], - "id": "def-server.CustomSettings.job_tags", - "type": "Object", - "label": "job_tags", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 17 - }, - "signature": [ - "{ [tag: string]: string; } | undefined" - ] - } - ], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 14 + "lineNumber": 15 }, "initialIsOpen": false }, @@ -3182,1065 +2868,223 @@ "initialIsOpen": false }, { - "id": "def-server.DataDescription", - "type": "Interface", - "label": "DataDescription", - "description": [], - "tags": [], - "children": [ - { - "tags": [], - "id": "def-server.DataDescription.format", - "type": "string", - "label": "format", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 78 - }, - "signature": [ - "string | undefined" - ] - }, - { - "tags": [], - "id": "def-server.DataDescription.time_field", - "type": "string", - "label": "time_field", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 79 - } - }, - { - "tags": [], - "id": "def-server.DataDescription.time_format", - "type": "string", - "label": "time_format", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 80 - }, - "signature": [ - "string | undefined" - ] - } - ], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 77 - }, - "initialIsOpen": false - }, - { - "id": "def-server.Datafeed", + "id": "def-server.DatafeedStats", "type": "Interface", - "label": "Datafeed", + "label": "DatafeedStats", "description": [], "tags": [], "children": [ { "tags": [], - "id": "def-server.Datafeed.datafeed_id", + "id": "def-server.DatafeedStats.datafeed_id", "type": "string", "label": "datafeed_id", "description": [], "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", - "lineNumber": 14 + "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed_stats.ts", + "lineNumber": 12 } }, { "tags": [], - "id": "def-server.Datafeed.aggregations", - "type": "Object", - "label": "aggregations", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", - "lineNumber": 15 - }, - "signature": [ - "Record | undefined" - ] - }, - { - "tags": [], - "id": "def-server.Datafeed.aggs", - "type": "Object", - "label": "aggs", + "id": "def-server.DatafeedStats.state", + "type": "Enum", + "label": "state", "description": [], "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", - "lineNumber": 16 + "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed_stats.ts", + "lineNumber": 13 }, "signature": [ - "Record | undefined" + { + "pluginId": "ml", + "scope": "common", + "docId": "kibMlPluginApi", + "section": "def-common.DATAFEED_STATE", + "text": "DATAFEED_STATE" + } ] }, { "tags": [], - "id": "def-server.Datafeed.chunking_config", + "id": "def-server.DatafeedStats.node", "type": "Object", - "label": "chunking_config", + "label": "node", "description": [], "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", - "lineNumber": 17 + "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed_stats.ts", + "lineNumber": 14 }, "signature": [ { "pluginId": "ml", "scope": "common", "docId": "kibMlPluginApi", - "section": "def-common.ChunkingConfig", - "text": "ChunkingConfig" - }, - " | undefined" + "section": "def-common.Node", + "text": "Node" + } ] }, { "tags": [], - "id": "def-server.Datafeed.frequency", + "id": "def-server.DatafeedStats.assignment_explanation", "type": "string", - "label": "frequency", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", - "lineNumber": 18 - }, - "signature": [ - "string | undefined" - ] - }, - { - "tags": [], - "id": "def-server.Datafeed.indices", - "type": "Array", - "label": "indices", + "label": "assignment_explanation", "description": [], "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", - "lineNumber": 19 - }, - "signature": [ - "string[]" - ] + "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed_stats.ts", + "lineNumber": 15 + } }, { "tags": [], - "id": "def-server.Datafeed.indexes", - "type": "Array", - "label": "indexes", + "id": "def-server.DatafeedStats.timing_stats", + "type": "Object", + "label": "timing_stats", "description": [], "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", - "lineNumber": 20 + "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed_stats.ts", + "lineNumber": 16 }, "signature": [ - "string[] | undefined" + "TimingStats" ] - }, + } + ], + "source": { + "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed_stats.ts", + "lineNumber": 11 + }, + "initialIsOpen": false + }, + { + "id": "def-server.ForecastsStats", + "type": "Interface", + "label": "ForecastsStats", + "description": [], + "tags": [], + "children": [ { "tags": [], - "id": "def-server.Datafeed.job_id", - "type": "string", - "label": "job_id", + "id": "def-server.ForecastsStats.total", + "type": "number", + "label": "total", "description": [], "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", - "lineNumber": 21 + "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job_stats.ts", + "lineNumber": 66 } }, { "tags": [], - "id": "def-server.Datafeed.query", - "type": "Uncategorized", - "label": "query", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", - "lineNumber": 22 - }, - "signature": [ - "object" - ] - }, - { - "tags": [], - "id": "def-server.Datafeed.query_delay", - "type": "string", - "label": "query_delay", + "id": "def-server.ForecastsStats.forecasted_jobs", + "type": "number", + "label": "forecasted_jobs", "description": [], "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", - "lineNumber": 23 - }, - "signature": [ - "string | undefined" - ] + "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job_stats.ts", + "lineNumber": 67 + } }, { "tags": [], - "id": "def-server.Datafeed.script_fields", - "type": "Object", - "label": "script_fields", + "id": "def-server.ForecastsStats.memory_bytes", + "type": "Any", + "label": "memory_bytes", "description": [], "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", - "lineNumber": 24 + "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job_stats.ts", + "lineNumber": 68 }, "signature": [ - "Record | undefined" + "any" ] }, { "tags": [], - "id": "def-server.Datafeed.runtime_mappings", - "type": "Object", - "label": "runtime_mappings", + "id": "def-server.ForecastsStats.records", + "type": "Any", + "label": "records", "description": [], "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", - "lineNumber": 25 - }, - "signature": [ - "Record | undefined" - ] - }, - { - "tags": [], - "id": "def-server.Datafeed.scroll_size", - "type": "number", - "label": "scroll_size", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", - "lineNumber": 26 - }, - "signature": [ - "number | undefined" - ] - }, - { - "tags": [], - "id": "def-server.Datafeed.delayed_data_check_config", - "type": "Uncategorized", - "label": "delayed_data_check_config", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", - "lineNumber": 27 - }, - "signature": [ - "object | undefined" - ] - }, - { - "tags": [], - "id": "def-server.Datafeed.indices_options", - "type": "Object", - "label": "indices_options", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", - "lineNumber": 28 - }, - "signature": [ - { - "pluginId": "ml", - "scope": "common", - "docId": "kibMlPluginApi", - "section": "def-common.IndicesOptions", - "text": "IndicesOptions" - }, - " | undefined" - ] - } - ], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", - "lineNumber": 13 - }, - "initialIsOpen": false - }, - { - "id": "def-server.DatafeedStats", - "type": "Interface", - "label": "DatafeedStats", - "description": [], - "tags": [], - "children": [ - { - "tags": [], - "id": "def-server.DatafeedStats.datafeed_id", - "type": "string", - "label": "datafeed_id", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed_stats.ts", - "lineNumber": 12 - } - }, - { - "tags": [], - "id": "def-server.DatafeedStats.state", - "type": "Enum", - "label": "state", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed_stats.ts", - "lineNumber": 13 - }, - "signature": [ - { - "pluginId": "ml", - "scope": "common", - "docId": "kibMlPluginApi", - "section": "def-common.DATAFEED_STATE", - "text": "DATAFEED_STATE" - } - ] - }, - { - "tags": [], - "id": "def-server.DatafeedStats.node", - "type": "Object", - "label": "node", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed_stats.ts", - "lineNumber": 14 - }, - "signature": [ - { - "pluginId": "ml", - "scope": "common", - "docId": "kibMlPluginApi", - "section": "def-common.Node", - "text": "Node" - } - ] - }, - { - "tags": [], - "id": "def-server.DatafeedStats.assignment_explanation", - "type": "string", - "label": "assignment_explanation", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed_stats.ts", - "lineNumber": 15 - } - }, - { - "tags": [], - "id": "def-server.DatafeedStats.timing_stats", - "type": "Object", - "label": "timing_stats", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed_stats.ts", - "lineNumber": 16 - }, - "signature": [ - "TimingStats" - ] - } - ], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed_stats.ts", - "lineNumber": 11 - }, - "initialIsOpen": false - }, - { - "id": "def-server.Detector", - "type": "Interface", - "label": "Detector", - "description": [], - "tags": [], - "children": [ - { - "tags": [], - "id": "def-server.Detector.by_field_name", - "type": "string", - "label": "by_field_name", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 61 - }, - "signature": [ - "string | undefined" - ] - }, - { - "tags": [], - "id": "def-server.Detector.detector_description", - "type": "string", - "label": "detector_description", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 62 - }, - "signature": [ - "string | undefined" - ] - }, - { - "tags": [], - "id": "def-server.Detector.detector_index", - "type": "number", - "label": "detector_index", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 63 - }, - "signature": [ - "number | undefined" - ] - }, - { - "tags": [], - "id": "def-server.Detector.exclude_frequent", - "type": "string", - "label": "exclude_frequent", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 64 - }, - "signature": [ - "string | undefined" - ] - }, - { - "tags": [], - "id": "def-server.Detector.field_name", - "type": "string", - "label": "field_name", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 65 - }, - "signature": [ - "string | undefined" - ] - }, - { - "tags": [], - "id": "def-server.Detector.function", - "type": "string", - "label": "function", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 66 - } - }, - { - "tags": [], - "id": "def-server.Detector.over_field_name", - "type": "string", - "label": "over_field_name", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 67 - }, - "signature": [ - "string | undefined" - ] - }, - { - "tags": [], - "id": "def-server.Detector.partition_field_name", - "type": "string", - "label": "partition_field_name", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 68 - }, - "signature": [ - "string | undefined" - ] - }, - { - "tags": [], - "id": "def-server.Detector.use_null", - "type": "CompoundType", - "label": "use_null", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 69 - }, - "signature": [ - "boolean | undefined" - ] - }, - { - "tags": [], - "id": "def-server.Detector.custom_rules", - "type": "Array", - "label": "custom_rules", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 70 - }, - "signature": [ - { - "pluginId": "ml", - "scope": "common", - "docId": "kibMlPluginApi", - "section": "def-common.CustomRule", - "text": "CustomRule" - }, - "[] | undefined" - ] - } - ], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 60 - }, - "initialIsOpen": false - }, - { - "id": "def-server.ForecastsStats", - "type": "Interface", - "label": "ForecastsStats", - "description": [], - "tags": [], - "children": [ - { - "tags": [], - "id": "def-server.ForecastsStats.total", - "type": "number", - "label": "total", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job_stats.ts", - "lineNumber": 66 - } - }, - { - "tags": [], - "id": "def-server.ForecastsStats.forecasted_jobs", - "type": "number", - "label": "forecasted_jobs", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job_stats.ts", - "lineNumber": 67 - } - }, - { - "tags": [], - "id": "def-server.ForecastsStats.memory_bytes", - "type": "Any", - "label": "memory_bytes", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job_stats.ts", - "lineNumber": 68 - }, - "signature": [ - "any" - ] - }, - { - "tags": [], - "id": "def-server.ForecastsStats.records", - "type": "Any", - "label": "records", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job_stats.ts", - "lineNumber": 69 - }, - "signature": [ - "any" - ] - }, - { - "tags": [], - "id": "def-server.ForecastsStats.processing_time_ms", - "type": "Any", - "label": "processing_time_ms", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job_stats.ts", - "lineNumber": 70 - }, - "signature": [ - "any" - ] - }, - { - "tags": [], - "id": "def-server.ForecastsStats.status", - "type": "Any", - "label": "status", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job_stats.ts", - "lineNumber": 71 - }, - "signature": [ - "any" - ] - } - ], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job_stats.ts", - "lineNumber": 65 - }, - "initialIsOpen": false - }, - { - "id": "def-server.IndicesOptions", - "type": "Interface", - "label": "IndicesOptions", - "description": [], - "tags": [], - "children": [ - { - "tags": [], - "id": "def-server.IndicesOptions.expand_wildcards", - "type": "CompoundType", - "label": "expand_wildcards", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", - "lineNumber": 49 - }, - "signature": [ - "\"all\" | \"none\" | \"hidden\" | \"open\" | \"closed\" | undefined" - ] - }, - { - "tags": [], - "id": "def-server.IndicesOptions.ignore_unavailable", - "type": "CompoundType", - "label": "ignore_unavailable", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", - "lineNumber": 50 - }, - "signature": [ - "boolean | undefined" - ] - }, - { - "tags": [], - "id": "def-server.IndicesOptions.allow_no_indices", - "type": "CompoundType", - "label": "allow_no_indices", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", - "lineNumber": 51 - }, - "signature": [ - "boolean | undefined" - ] - }, - { - "tags": [], - "id": "def-server.IndicesOptions.ignore_throttled", - "type": "CompoundType", - "label": "ignore_throttled", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", - "lineNumber": 52 - }, - "signature": [ - "boolean | undefined" - ] - } - ], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", - "lineNumber": 48 - }, - "initialIsOpen": false - }, - { - "id": "def-server.Influencer", - "type": "Interface", - "label": "Influencer", - "description": [], - "tags": [], - "children": [ - { - "tags": [], - "id": "def-server.Influencer.influencer_field_name", - "type": "string", - "label": "influencer_field_name", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomalies.ts", - "lineNumber": 11 - } - }, - { - "tags": [], - "id": "def-server.Influencer.influencer_field_values", - "type": "Array", - "label": "influencer_field_values", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomalies.ts", - "lineNumber": 12 - }, - "signature": [ - "string[]" - ] - } - ], - "source": { - "path": "x-pack/plugins/ml/common/types/anomalies.ts", - "lineNumber": 10 - }, - "initialIsOpen": false - }, - { - "id": "def-server.Job", - "type": "Interface", - "label": "Job", - "description": [], - "tags": [], - "children": [ - { - "tags": [], - "id": "def-server.Job.job_id", - "type": "string", - "label": "job_id", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 23 - } - }, - { - "tags": [], - "id": "def-server.Job.analysis_config", - "type": "Object", - "label": "analysis_config", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 24 - }, - "signature": [ - { - "pluginId": "ml", - "scope": "common", - "docId": "kibMlPluginApi", - "section": "def-common.AnalysisConfig", - "text": "AnalysisConfig" - } - ] - }, - { - "tags": [], - "id": "def-server.Job.analysis_limits", - "type": "Object", - "label": "analysis_limits", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 25 - }, - "signature": [ - { - "pluginId": "ml", - "scope": "common", - "docId": "kibMlPluginApi", - "section": "def-common.AnalysisLimits", - "text": "AnalysisLimits" - }, - " | undefined" - ] - }, - { - "tags": [], - "id": "def-server.Job.background_persist_interval", - "type": "string", - "label": "background_persist_interval", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 26 - }, - "signature": [ - "string | undefined" - ] - }, - { - "tags": [], - "id": "def-server.Job.custom_settings", - "type": "Object", - "label": "custom_settings", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 27 - }, - "signature": [ - { - "pluginId": "ml", - "scope": "common", - "docId": "kibMlPluginApi", - "section": "def-common.CustomSettings", - "text": "CustomSettings" - }, - " | undefined" - ] - }, - { - "tags": [], - "id": "def-server.Job.data_description", - "type": "Object", - "label": "data_description", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 28 - }, - "signature": [ - { - "pluginId": "ml", - "scope": "common", - "docId": "kibMlPluginApi", - "section": "def-common.DataDescription", - "text": "DataDescription" - } - ] - }, - { - "tags": [], - "id": "def-server.Job.description", - "type": "string", - "label": "description", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 29 - } - }, - { - "tags": [], - "id": "def-server.Job.groups", - "type": "Array", - "label": "groups", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 30 - }, - "signature": [ - "string[]" - ] - }, - { - "tags": [], - "id": "def-server.Job.model_plot_config", - "type": "Object", - "label": "model_plot_config", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 31 - }, - "signature": [ - { - "pluginId": "ml", - "scope": "common", - "docId": "kibMlPluginApi", - "section": "def-common.ModelPlotConfig", - "text": "ModelPlotConfig" - }, - " | undefined" - ] - }, - { - "tags": [], - "id": "def-server.Job.model_snapshot_retention_days", - "type": "number", - "label": "model_snapshot_retention_days", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 32 - }, - "signature": [ - "number | undefined" - ] - }, - { - "tags": [], - "id": "def-server.Job.daily_model_snapshot_retention_after_days", - "type": "number", - "label": "daily_model_snapshot_retention_after_days", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 33 - }, - "signature": [ - "number | undefined" - ] - }, - { - "tags": [], - "id": "def-server.Job.renormalization_window_days", - "type": "number", - "label": "renormalization_window_days", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 34 - }, - "signature": [ - "number | undefined" - ] - }, - { - "tags": [], - "id": "def-server.Job.results_index_name", - "type": "string", - "label": "results_index_name", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 35 - }, - "signature": [ - "string | undefined" - ] - }, - { - "tags": [], - "id": "def-server.Job.results_retention_days", - "type": "number", - "label": "results_retention_days", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 36 - }, - "signature": [ - "number | undefined" - ] - }, - { - "tags": [], - "id": "def-server.Job.create_time", - "type": "number", - "label": "create_time", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 39 - }, - "signature": [ - "number | undefined" - ] - }, - { - "tags": [], - "id": "def-server.Job.finished_time", - "type": "number", - "label": "finished_time", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 40 + "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job_stats.ts", + "lineNumber": 69 }, "signature": [ - "number | undefined" + "any" ] }, { "tags": [], - "id": "def-server.Job.job_type", - "type": "string", - "label": "job_type", + "id": "def-server.ForecastsStats.processing_time_ms", + "type": "Any", + "label": "processing_time_ms", "description": [], "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 41 + "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job_stats.ts", + "lineNumber": 70 }, "signature": [ - "\"anomaly_detector\" | undefined" + "any" ] }, { "tags": [], - "id": "def-server.Job.job_version", - "type": "string", - "label": "job_version", + "id": "def-server.ForecastsStats.status", + "type": "Any", + "label": "status", "description": [], "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 42 + "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job_stats.ts", + "lineNumber": 71 }, "signature": [ - "string | undefined" + "any" ] - }, + } + ], + "source": { + "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job_stats.ts", + "lineNumber": 65 + }, + "initialIsOpen": false + }, + { + "id": "def-server.Influencer", + "type": "Interface", + "label": "Influencer", + "description": [], + "tags": [], + "children": [ { "tags": [], - "id": "def-server.Job.model_snapshot_id", + "id": "def-server.Influencer.influencer_field_name", "type": "string", - "label": "model_snapshot_id", + "label": "influencer_field_name", "description": [], "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 43 - }, - "signature": [ - "string | undefined" - ] + "path": "x-pack/plugins/ml/common/types/anomalies.ts", + "lineNumber": 11 + } }, { "tags": [], - "id": "def-server.Job.deleting", - "type": "CompoundType", - "label": "deleting", + "id": "def-server.Influencer.influencer_field_values", + "type": "Array", + "label": "influencer_field_values", "description": [], "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 44 + "path": "x-pack/plugins/ml/common/types/anomalies.ts", + "lineNumber": 12 }, "signature": [ - "boolean | undefined" + "string[]" ] } ], "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 22 + "path": "x-pack/plugins/ml/common/types/anomalies.ts", + "lineNumber": 10 }, "initialIsOpen": false }, @@ -4790,62 +3634,6 @@ }, "initialIsOpen": false }, - { - "id": "def-server.ModelPlotConfig", - "type": "Interface", - "label": "ModelPlotConfig", - "description": [], - "tags": [], - "children": [ - { - "tags": [], - "id": "def-server.ModelPlotConfig.enabled", - "type": "CompoundType", - "label": "enabled", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 84 - }, - "signature": [ - "boolean | undefined" - ] - }, - { - "tags": [], - "id": "def-server.ModelPlotConfig.annotations_enabled", - "type": "CompoundType", - "label": "annotations_enabled", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 85 - }, - "signature": [ - "boolean | undefined" - ] - }, - { - "tags": [], - "id": "def-server.ModelPlotConfig.terms", - "type": "string", - "label": "terms", - "description": [], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 86 - }, - "signature": [ - "string | undefined" - ] - } - ], - "source": { - "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 83 - }, - "initialIsOpen": false - }, { "id": "def-server.ModelSizeStats", "type": "Interface", @@ -5298,7 +4086,7 @@ "description": [], "source": { "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 97 + "lineNumber": 106 }, "signature": [ "boolean | undefined" @@ -5312,7 +4100,7 @@ "description": [], "source": { "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 98 + "lineNumber": 107 }, "signature": [ "boolean | undefined" @@ -5321,7 +4109,7 @@ ], "source": { "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 96 + "lineNumber": 105 }, "initialIsOpen": false } @@ -5336,13 +4124,43 @@ "description": [], "source": { "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", - "lineNumber": 36 + "lineNumber": 44 }, "signature": [ "{ [x: string]: { date_histogram: { field: string; fixed_interval: string;}; aggregations?: { [key: string]: any; } | undefined; aggs?: { [key: string]: any; } | undefined; }; }" ], "initialIsOpen": false }, + { + "id": "def-server.AnalysisConfig", + "type": "Type", + "label": "AnalysisConfig", + "tags": [], + "description": [], + "source": { + "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", + "lineNumber": 49 + }, + "signature": [ + "estypes.AnalysisConfig" + ], + "initialIsOpen": false + }, + { + "id": "def-server.AnalysisLimits", + "type": "Type", + "label": "AnalysisLimits", + "tags": [], + "description": [], + "source": { + "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", + "lineNumber": 77 + }, + "signature": [ + "estypes.AnalysisLimits" + ], + "initialIsOpen": false + }, { "id": "def-server.AnomalyResultType", "type": "Type", @@ -5366,13 +4184,73 @@ "description": [], "source": { "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 12 + "lineNumber": 13 }, "signature": [ "string" ], "initialIsOpen": false }, + { + "id": "def-server.ChunkingConfig", + "type": "Type", + "label": "ChunkingConfig", + "tags": [], + "description": [], + "source": { + "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", + "lineNumber": 37 + }, + "signature": [ + "estypes.ChunkingConfig" + ], + "initialIsOpen": false + }, + { + "id": "def-server.CustomRule", + "type": "Type", + "label": "CustomRule", + "tags": [], + "description": [], + "source": { + "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", + "lineNumber": 97 + }, + "signature": [ + "estypes.DetectionRule" + ], + "initialIsOpen": false + }, + { + "id": "def-server.DataDescription", + "type": "Type", + "label": "DataDescription", + "tags": [], + "description": [], + "source": { + "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", + "lineNumber": 83 + }, + "signature": [ + "estypes.DataDescription" + ], + "initialIsOpen": false + }, + { + "id": "def-server.Datafeed", + "type": "Type", + "label": "Datafeed", + "tags": [], + "description": [], + "source": { + "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", + "lineNumber": 14 + }, + "signature": [ + "estypes.Datafeed" + ], + "initialIsOpen": false + }, { "id": "def-server.DatafeedId", "type": "Type", @@ -5381,7 +4259,7 @@ "description": [], "source": { "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", - "lineNumber": 11 + "lineNumber": 12 }, "signature": [ "string" @@ -5399,7 +4277,23 @@ "lineNumber": 14 }, "signature": [ - "Datafeed & DatafeedStats" + "Datafeed", + " & DatafeedStats" + ], + "initialIsOpen": false + }, + { + "id": "def-server.Detector", + "type": "Type", + "label": "Detector", + "tags": [], + "description": [], + "source": { + "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", + "lineNumber": 63 + }, + "signature": [ + "estypes.Detector" ], "initialIsOpen": false }, @@ -5418,6 +4312,36 @@ ], "initialIsOpen": false }, + { + "id": "def-server.IndicesOptions", + "type": "Type", + "label": "IndicesOptions", + "tags": [], + "description": [], + "source": { + "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/datafeed.ts", + "lineNumber": 56 + }, + "signature": [ + "estypes.IndicesOptions" + ], + "initialIsOpen": false + }, + { + "id": "def-server.Job", + "type": "Type", + "label": "Job", + "tags": [], + "description": [], + "source": { + "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", + "lineNumber": 23 + }, + "signature": [ + "estypes.Job" + ], + "initialIsOpen": false + }, { "id": "def-server.JobId", "type": "Type", @@ -5426,7 +4350,7 @@ "description": [], "source": { "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", - "lineNumber": 11 + "lineNumber": 12 }, "signature": [ "string" @@ -5444,7 +4368,8 @@ "lineNumber": 13 }, "signature": [ - "Job & JobStats" + "Job", + " & JobStats" ], "initialIsOpen": false }, @@ -5463,6 +4388,21 @@ ], "initialIsOpen": false }, + { + "id": "def-server.ModelPlotConfig", + "type": "Type", + "label": "ModelPlotConfig", + "tags": [], + "description": [], + "source": { + "path": "x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts", + "lineNumber": 90 + }, + "signature": [ + "estypes.ModelPlotConfig" + ], + "initialIsOpen": false + }, { "id": "def-server.ModuleSetupPayload", "type": "Type", diff --git a/api_docs/observability.json b/api_docs/observability.json index 439fd18db6469f..2128e27f0106f8 100644 --- a/api_docs/observability.json +++ b/api_docs/observability.json @@ -474,7 +474,7 @@ "description": [], "source": { "path": "x-pack/plugins/observability/public/hooks/use_fetcher.tsx", - "lineNumber": 30 + "lineNumber": 31 } }, { @@ -487,7 +487,7 @@ "description": [], "source": { "path": "x-pack/plugins/observability/public/hooks/use_fetcher.tsx", - "lineNumber": 31 + "lineNumber": 32 } }, { @@ -505,7 +505,7 @@ "description": [], "source": { "path": "x-pack/plugins/observability/public/hooks/use_fetcher.tsx", - "lineNumber": 33 + "lineNumber": 34 }, "signature": [ "boolean | undefined" @@ -514,7 +514,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/hooks/use_fetcher.tsx", - "lineNumber": 32 + "lineNumber": 33 } } ], @@ -522,7 +522,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/observability/public/hooks/use_fetcher.tsx", - "lineNumber": 29 + "lineNumber": 30 }, "initialIsOpen": false }, @@ -1359,6 +1359,136 @@ }, "initialIsOpen": false }, + { + "id": "def-public.ObservabilityPublicPluginsSetup", + "type": "Interface", + "label": "ObservabilityPublicPluginsSetup", + "description": [], + "tags": [], + "children": [ + { + "tags": [], + "id": "def-public.ObservabilityPublicPluginsSetup.data", + "type": "Object", + "label": "data", + "description": [], + "source": { + "path": "x-pack/plugins/observability/public/plugin.ts", + "lineNumber": 30 + }, + "signature": [ + { + "pluginId": "data", + "scope": "public", + "docId": "kibDataPluginApi", + "section": "def-public.DataPublicPluginSetup", + "text": "DataPublicPluginSetup" + } + ] + }, + { + "tags": [], + "id": "def-public.ObservabilityPublicPluginsSetup.home", + "type": "Object", + "label": "home", + "description": [], + "source": { + "path": "x-pack/plugins/observability/public/plugin.ts", + "lineNumber": 31 + }, + "signature": [ + { + "pluginId": "home", + "scope": "public", + "docId": "kibHomePluginApi", + "section": "def-public.HomePublicPluginSetup", + "text": "HomePublicPluginSetup" + }, + " | undefined" + ] + } + ], + "source": { + "path": "x-pack/plugins/observability/public/plugin.ts", + "lineNumber": 29 + }, + "initialIsOpen": false + }, + { + "id": "def-public.ObservabilityPublicPluginsStart", + "type": "Interface", + "label": "ObservabilityPublicPluginsStart", + "description": [], + "tags": [], + "children": [ + { + "tags": [], + "id": "def-public.ObservabilityPublicPluginsStart.home", + "type": "Object", + "label": "home", + "description": [], + "source": { + "path": "x-pack/plugins/observability/public/plugin.ts", + "lineNumber": 35 + }, + "signature": [ + { + "pluginId": "home", + "scope": "public", + "docId": "kibHomePluginApi", + "section": "def-public.HomePublicPluginStart", + "text": "HomePublicPluginStart" + }, + " | undefined" + ] + }, + { + "tags": [], + "id": "def-public.ObservabilityPublicPluginsStart.data", + "type": "Object", + "label": "data", + "description": [], + "source": { + "path": "x-pack/plugins/observability/public/plugin.ts", + "lineNumber": 36 + }, + "signature": [ + { + "pluginId": "data", + "scope": "public", + "docId": "kibDataPluginApi", + "section": "def-public.DataPublicPluginStart", + "text": "DataPublicPluginStart" + } + ] + }, + { + "tags": [], + "id": "def-public.ObservabilityPublicPluginsStart.lens", + "type": "Object", + "label": "lens", + "description": [], + "source": { + "path": "x-pack/plugins/observability/public/plugin.ts", + "lineNumber": 37 + }, + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.LensPublicStart", + "text": "LensPublicStart" + } + ] + } + ], + "source": { + "path": "x-pack/plugins/observability/public/plugin.ts", + "lineNumber": 34 + }, + "initialIsOpen": false + }, { "id": "def-public.Series", "type": "Interface", @@ -1951,21 +2081,21 @@ ], "objects": [], "setup": { - "id": "def-public.ObservabilityPluginSetup", + "id": "def-public.ObservabilityPublicSetup", "type": "Interface", - "label": "ObservabilityPluginSetup", + "label": "ObservabilityPublicSetup", "description": [], "tags": [], "children": [ { "tags": [], - "id": "def-public.ObservabilityPluginSetup.dashboard", + "id": "def-public.ObservabilityPublicSetup.dashboard", "type": "Object", "label": "dashboard", "description": [], "source": { "path": "x-pack/plugins/observability/public/plugin.ts", - "lineNumber": 25 + "lineNumber": 26 }, "signature": [ "{ register: typeof ", @@ -1982,20 +2112,20 @@ ], "source": { "path": "x-pack/plugins/observability/public/plugin.ts", - "lineNumber": 24 + "lineNumber": 25 }, "lifecycle": "setup", "initialIsOpen": true }, "start": { - "id": "def-public.ObservabilityPluginStart", + "id": "def-public.ObservabilityPublicStart", "type": "Type", - "label": "ObservabilityPluginStart", + "label": "ObservabilityPublicStart", "tags": [], "description": [], "source": { "path": "x-pack/plugins/observability/public/plugin.ts", - "lineNumber": 33 + "lineNumber": 40 }, "signature": [ "void" @@ -2086,8 +2216,8 @@ "pluginId": "observability", "scope": "server", "docId": "kibObservabilityPluginApi", - "section": "def-server.MappingsDefinition", - "text": "MappingsDefinition" + "section": "def-server.Mappings", + "text": "Mappings" }, "; client: ", { @@ -2118,26 +2248,26 @@ "description": [], "source": { "path": "x-pack/plugins/observability/server/utils/create_or_update_index.ts", - "lineNumber": 32 + "lineNumber": 20 } }, { "tags": [], "id": "def-server.createOrUpdateIndex.{\n- index,\n mappings,\n client,\n logger,\n}.mappings", - "type": "Object", + "type": "CompoundType", "label": "mappings", "description": [], "source": { "path": "x-pack/plugins/observability/server/utils/create_or_update_index.ts", - "lineNumber": 33 + "lineNumber": 21 }, "signature": [ { "pluginId": "observability", "scope": "server", "docId": "kibObservabilityPluginApi", - "section": "def-server.MappingsDefinition", - "text": "MappingsDefinition" + "section": "def-server.Mappings", + "text": "Mappings" } ] }, @@ -2149,7 +2279,7 @@ "description": [], "source": { "path": "x-pack/plugins/observability/server/utils/create_or_update_index.ts", - "lineNumber": 34 + "lineNumber": 22 }, "signature": [ { @@ -2169,7 +2299,7 @@ "description": [], "source": { "path": "x-pack/plugins/observability/server/utils/create_or_update_index.ts", - "lineNumber": 35 + "lineNumber": 23 }, "signature": [ "Logger" @@ -2178,7 +2308,7 @@ ], "source": { "path": "x-pack/plugins/observability/server/utils/create_or_update_index.ts", - "lineNumber": 31 + "lineNumber": 19 } } ], @@ -2186,7 +2316,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/observability/server/utils/create_or_update_index.ts", - "lineNumber": 26 + "lineNumber": 14 }, "initialIsOpen": false }, @@ -2224,82 +2354,32 @@ "initialIsOpen": false } ], - "interfaces": [ + "interfaces": [], + "enums": [], + "misc": [ { - "id": "def-server.MappingsDefinition", - "type": "Interface", - "label": "MappingsDefinition", - "description": [], + "id": "def-server.Mappings", + "type": "Type", + "label": "Mappings", "tags": [], - "children": [ - { - "tags": [], - "id": "def-server.MappingsDefinition.dynamic", - "type": "CompoundType", - "label": "dynamic", - "description": [], - "source": { - "path": "x-pack/plugins/observability/server/utils/create_or_update_index.ts", - "lineNumber": 21 - }, - "signature": [ - "boolean | \"strict\" | undefined" - ] - }, - { - "tags": [], - "id": "def-server.MappingsDefinition.properties", - "type": "Object", - "label": "properties", - "description": [], - "source": { - "path": "x-pack/plugins/observability/server/utils/create_or_update_index.ts", - "lineNumber": 22 - }, - "signature": [ - "Record" - ] - }, - { - "tags": [], - "id": "def-server.MappingsDefinition.dynamic_templates", - "type": "Array", - "label": "dynamic_templates", - "description": [], - "source": { - "path": "x-pack/plugins/observability/server/utils/create_or_update_index.ts", - "lineNumber": 23 - }, - "signature": [ - "any[] | undefined" - ] - } - ], + "description": [], "source": { "path": "x-pack/plugins/observability/server/utils/create_or_update_index.ts", - "lineNumber": 20 + "lineNumber": 11 }, + "signature": [ + "TypeMapping", + " & { all_field?: ", + "AllField", + " | undefined; date_detection?: boolean | undefined; dynamic?: boolean | \"strict\" | undefined; dynamic_date_formats?: string[] | undefined; dynamic_templates?: Record | Record[] | undefined; field_names_field?: ", + "FieldNamesField" + ], "initialIsOpen": false - } - ], - "enums": [], - "misc": [ + }, { "id": "def-server.ObservabilityConfig", "type": "Type", @@ -2330,7 +2410,9 @@ "Annotation", "; }>; getById: (getByIdParams: { id: string; }) => Promise<", "GetResponse", - ">; delete: (deleteParams: { id: string; }) => Promise>; }" + ">; delete: (deleteParams: { id: string; }) => Promise<", + "DeleteResponse", + ">; }" ], "initialIsOpen": false } diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index 353e65b0fa0808..ef0e952f5161c7 100644 --- a/api_docs/observability.mdx +++ b/api_docs/observability.mdx @@ -42,9 +42,6 @@ import observabilityObj from './observability.json'; ### Classes -### Interfaces - - ### Consts, variables and types diff --git a/api_docs/reporting.json b/api_docs/reporting.json index 29d0d485452da4..be0c9638660387 100644 --- a/api_docs/reporting.json +++ b/api_docs/reporting.json @@ -1352,7 +1352,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">) => Promise<", + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">) => Promise<", { "pluginId": "core", "scope": "server", @@ -1377,7 +1377,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">" + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">" ], "description": [], "source": { diff --git a/api_docs/security.json b/api_docs/security.json index 8e1214654a82f2..938a043a555cf2 100644 --- a/api_docs/security.json +++ b/api_docs/security.json @@ -982,7 +982,7 @@ "lineNumber": 109 }, "signature": [ - "{ type: string; reason: string; caused_by: { type: string; reason: string; }; }[] | undefined" + "{ type: string; reason: string; caused_by?: { type: string; reason: string; } | undefined; }[] | undefined" ] } ], diff --git a/api_docs/security_solution.json b/api_docs/security_solution.json index ae208eb4facc74..ae85541ba6bfd6 100644 --- a/api_docs/security_solution.json +++ b/api_docs/security_solution.json @@ -52,7 +52,7 @@ "description": [], "source": { "path": "x-pack/plugins/security_solution/public/plugin.tsx", - "lineNumber": 75 + "lineNumber": 79 } } ], @@ -60,7 +60,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/security_solution/public/plugin.tsx", - "lineNumber": 75 + "lineNumber": 79 } }, { @@ -144,7 +144,7 @@ "description": [], "source": { "path": "x-pack/plugins/security_solution/public/plugin.tsx", - "lineNumber": 98 + "lineNumber": 103 } }, { @@ -163,7 +163,7 @@ "description": [], "source": { "path": "x-pack/plugins/security_solution/public/plugin.tsx", - "lineNumber": 98 + "lineNumber": 103 } } ], @@ -171,7 +171,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/security_solution/public/plugin.tsx", - "lineNumber": 98 + "lineNumber": 103 } }, { @@ -215,7 +215,7 @@ "description": [], "source": { "path": "x-pack/plugins/security_solution/public/plugin.tsx", - "lineNumber": 348 + "lineNumber": 353 } }, { @@ -234,7 +234,7 @@ "description": [], "source": { "path": "x-pack/plugins/security_solution/public/plugin.tsx", - "lineNumber": 348 + "lineNumber": 353 } } ], @@ -242,7 +242,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/security_solution/public/plugin.tsx", - "lineNumber": 348 + "lineNumber": 353 } }, { @@ -258,13 +258,13 @@ "returnComment": [], "source": { "path": "x-pack/plugins/security_solution/public/plugin.tsx", - "lineNumber": 393 + "lineNumber": 398 } } ], "source": { "path": "x-pack/plugins/security_solution/public/plugin.tsx", - "lineNumber": 72 + "lineNumber": 75 }, "initialIsOpen": false } @@ -607,7 +607,7 @@ "description": [], "source": { "path": "x-pack/plugins/security_solution/server/plugin.ts", - "lineNumber": 338 + "lineNumber": 339 } }, { @@ -626,7 +626,7 @@ "description": [], "source": { "path": "x-pack/plugins/security_solution/server/plugin.ts", - "lineNumber": 338 + "lineNumber": 339 } } ], @@ -634,7 +634,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/security_solution/server/plugin.ts", - "lineNumber": 338 + "lineNumber": 339 } }, { @@ -650,7 +650,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/security_solution/server/plugin.ts", - "lineNumber": 404 + "lineNumber": 405 } } ], @@ -1415,9 +1415,7 @@ "signature": [ "Error & Partial<", "ResponseError", - ", ", - "Context", - ">>" + ", unknown>>" ], "description": [], "source": { @@ -1429,9 +1427,7 @@ "signature": [ "(err: Error & Partial<", "ResponseError", - ", ", - "Context", - ">>) => ", + ", unknown>>) => ", "OutputError" ], "description": [], diff --git a/api_docs/telemetry.json b/api_docs/telemetry.json index 2d0108158e7e32..043e126de36407 100644 --- a/api_docs/telemetry.json +++ b/api_docs/telemetry.json @@ -334,7 +334,7 @@ "signature": [ "({ esClient }: ", "StatsCollectionConfig", - ") => Promise<{ clusterUuid: any; }[]>" + ") => Promise<{ clusterUuid: string; }[]>" ], "description": [ "\nGet the cluster uuids from the connected cluster." @@ -369,7 +369,7 @@ "description": [], "source": { "path": "src/plugins/telemetry/server/telemetry_collection/get_local_stats.ts", - "lineNumber": 59 + "lineNumber": 60 } }, { @@ -388,7 +388,7 @@ "description": [], "source": { "path": "src/plugins/telemetry/server/telemetry_collection/get_local_stats.ts", - "lineNumber": 60 + "lineNumber": 61 } }, { @@ -407,7 +407,7 @@ "description": [], "source": { "path": "src/plugins/telemetry/server/telemetry_collection/get_local_stats.ts", - "lineNumber": 61 + "lineNumber": 62 } } ], @@ -434,7 +434,7 @@ "label": "getLocalStats", "source": { "path": "src/plugins/telemetry/server/telemetry_collection/get_local_stats.ts", - "lineNumber": 58 + "lineNumber": 59 }, "tags": [], "returnComment": [], @@ -453,7 +453,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">, uiSettingsClient: ", + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">, uiSettingsClient: ", { "pluginId": "core", "scope": "server", @@ -478,7 +478,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">" + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">" ], "description": [], "source": { @@ -694,7 +694,7 @@ "description": [], "source": { "path": "src/plugins/telemetry/server/telemetry_collection/get_local_stats.ts", - "lineNumber": 50 + "lineNumber": 51 }, "signature": [ "{ timestamp: string; cluster_uuid: string; cluster_name: string; version: string; cluster_stats: any; collection: string; stack_stats: { data: DataTelemetryPayload | undefined; kibana: { count: number; indices: number; os: {}; versions: { version: string; count: number; }[]; plugins: { [plugin: string]: any; }; } | undefined; }; }" diff --git a/api_docs/telemetry_collection_manager.json b/api_docs/telemetry_collection_manager.json index 09e4b884bf809e..30d3bb76a43b20 100644 --- a/api_docs/telemetry_collection_manager.json +++ b/api_docs/telemetry_collection_manager.json @@ -105,7 +105,7 @@ "section": "def-server.SavedObjectsClient", "text": "SavedObjectsClient" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">" + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\" | \"createPointInTimeFinder\">" ] }, { diff --git a/api_docs/telemetry_collection_xpack.json b/api_docs/telemetry_collection_xpack.json index cf1b1a5998553b..8110cd6f2d27e2 100644 --- a/api_docs/telemetry_collection_xpack.json +++ b/api_docs/telemetry_collection_xpack.json @@ -11,167 +11,25 @@ "server": { "classes": [], "functions": [], - "interfaces": [ + "interfaces": [], + "enums": [], + "misc": [ { "id": "def-server.ESLicense", - "type": "Interface", + "type": "Type", "label": "ESLicense", - "description": [], "tags": [], - "children": [ - { - "tags": [], - "id": "def-server.ESLicense.status", - "type": "string", - "label": "status", - "description": [], - "source": { - "path": "x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_license.ts", - "lineNumber": 12 - } - }, - { - "tags": [], - "id": "def-server.ESLicense.uid", - "type": "string", - "label": "uid", - "description": [], - "source": { - "path": "x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_license.ts", - "lineNumber": 13 - } - }, - { - "tags": [], - "id": "def-server.ESLicense.hkey", - "type": "string", - "label": "hkey", - "description": [], - "source": { - "path": "x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_license.ts", - "lineNumber": 14 - } - }, - { - "tags": [], - "id": "def-server.ESLicense.type", - "type": "string", - "label": "type", - "description": [], - "source": { - "path": "x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_license.ts", - "lineNumber": 15 - } - }, - { - "tags": [], - "id": "def-server.ESLicense.issue_date", - "type": "string", - "label": "issue_date", - "description": [], - "source": { - "path": "x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_license.ts", - "lineNumber": 16 - } - }, - { - "tags": [], - "id": "def-server.ESLicense.issue_date_in_millis", - "type": "number", - "label": "issue_date_in_millis", - "description": [], - "source": { - "path": "x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_license.ts", - "lineNumber": 17 - } - }, - { - "tags": [], - "id": "def-server.ESLicense.expiry_date", - "type": "string", - "label": "expiry_date", - "description": [], - "source": { - "path": "x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_license.ts", - "lineNumber": 18 - } - }, - { - "tags": [], - "id": "def-server.ESLicense.expiry_date_in_millis", - "type": "number", - "label": "expiry_date_in_millis", - "description": [], - "source": { - "path": "x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_license.ts", - "lineNumber": 19 - } - }, - { - "tags": [], - "id": "def-server.ESLicense.max_nodes", - "type": "number", - "label": "max_nodes", - "description": [], - "source": { - "path": "x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_license.ts", - "lineNumber": 20 - } - }, - { - "tags": [], - "id": "def-server.ESLicense.issued_to", - "type": "string", - "label": "issued_to", - "description": [], - "source": { - "path": "x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_license.ts", - "lineNumber": 21 - } - }, - { - "tags": [], - "id": "def-server.ESLicense.issuer", - "type": "string", - "label": "issuer", - "description": [], - "source": { - "path": "x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_license.ts", - "lineNumber": 22 - } - }, - { - "tags": [], - "id": "def-server.ESLicense.start_date_in_millis", - "type": "number", - "label": "start_date_in_millis", - "description": [], - "source": { - "path": "x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_license.ts", - "lineNumber": 23 - } - }, - { - "tags": [], - "id": "def-server.ESLicense.max_resource_units", - "type": "number", - "label": "max_resource_units", - "description": [], - "source": { - "path": "x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_license.ts", - "lineNumber": 24 - } - } - ], + "description": [], "source": { "path": "x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_license.ts", - "lineNumber": 11 + "lineNumber": 10 }, + "signature": [ + "estypes.LicenseInformation" + ], "initialIsOpen": false } ], - "enums": [], - "misc": [], "objects": [] }, "common": { diff --git a/api_docs/telemetry_collection_xpack.mdx b/api_docs/telemetry_collection_xpack.mdx index dbebc1cde59ab0..058a9d3fcb460e 100644 --- a/api_docs/telemetry_collection_xpack.mdx +++ b/api_docs/telemetry_collection_xpack.mdx @@ -13,6 +13,6 @@ import telemetryCollectionXpackObj from './telemetry_collection_xpack.json'; ## Server -### Interfaces - +### Consts, variables and types + diff --git a/api_docs/vis_type_timeseries.json b/api_docs/vis_type_timeseries.json index 6f349cb3dfb936..907ced500294ac 100644 --- a/api_docs/vis_type_timeseries.json +++ b/api_docs/vis_type_timeseries.json @@ -37,7 +37,7 @@ { "pluginId": "data", "scope": "server", - "docId": "kibDataPluginApi", + "docId": "kibDataSearchPluginApi", "section": "def-server.DataRequestHandlerContext", "text": "DataRequestHandlerContext" }, diff --git a/docs/api/alerting.asciidoc b/docs/api/alerting.asciidoc new file mode 100644 index 00000000000000..ad2d358d17ba0a --- /dev/null +++ b/docs/api/alerting.asciidoc @@ -0,0 +1,47 @@ +[[alerting-apis]] +== Alerting APIs + +The following APIs are available for {kib} alerting. + +* <> to create a rule + +* <> to update the attributes for existing rules + +* <> to retrieve a single rule by ID + +* <> to permanently remove a rule + +* <> to retrieve a paginated set of rules by condition + +* <> to retrieve a list of rule types + +* <> to enable a single rule by ID + +* <> to disable a single rule by ID + +* <> to mute alert for a single rule by ID + +* <> to unmute alert for a single rule by ID + +* <> to mute all alerts for a single rule by ID + +* <> to unmute all alerts for a single rule by ID + +* <> to retrieve the health of the Alerting framework + +For deprecated APIs, refer to <>. + +include::alerting/create_rule.asciidoc[] +include::alerting/update_rule.asciidoc[] +include::alerting/get_rules.asciidoc[] +include::alerting/delete_rule.asciidoc[] +include::alerting/find_rules.asciidoc[] +include::alerting/list_rule_types.asciidoc[] +include::alerting/enable_rule.asciidoc[] +include::alerting/disable_rule.asciidoc[] +include::alerting/mute_all_alerts.asciidoc[] +include::alerting/mute_alert.asciidoc[] +include::alerting/unmute_all_alerts.asciidoc[] +include::alerting/unmute_alert.asciidoc[] +include::alerting/health.asciidoc[] +include::alerting/legacy/index.asciidoc[] diff --git a/docs/api/alerting/create_rule.asciidoc b/docs/api/alerting/create_rule.asciidoc new file mode 100644 index 00000000000000..01b6dfc40fcf6e --- /dev/null +++ b/docs/api/alerting/create_rule.asciidoc @@ -0,0 +1,196 @@ +[[create-rule-api]] +=== Create rule API +++++ +Create rule +++++ + +Create {kib} rules. + +[[create-rule-api-request]] +==== Request + +`POST :/api/alerting/rule/` + +`POST :/s//api/alerting/rule/` + +[[create-rule-api-path-params]] +==== Path parameters + +``:: + (Optional, string) Specifies a UUID v1 or v4 to use instead of a randomly generated ID. + +`space_id`:: + (Optional, string) An identifier for the space. If `space_id` is not provided in the URL, the default space is used. + +[[create-rule-api-request-body]] +==== Request body + +`name`:: + (Required, string) A name to reference and search. + +`tags`:: + (Optional, string array) A list of keywords to reference and search. + +`rule_type_id`:: + (Required, string) The ID of the rule type that you want to call when the rule is scheduled to run. + +`schedule`:: + (Required, object) The schedule specifying when this rule should be run, using one of the available schedule formats specified under ++ +._Schedule Formats_. +[%collapsible%open] +===== +A schedule is structured such that the key specifies the format you wish to use and its value specifies the schedule. + +We currently support the _Interval format_ which specifies the interval in seconds, minutes, hours or days at which the rule should execute. +Example: `{ interval: "10s" }`, `{ interval: "5m" }`, `{ interval: "1h" }`, `{ interval: "1d" }`. + +There are plans to support multiple other schedule formats in the near future. +===== + +`throttle`:: + (Optional, string) How often this rule should fire the same actions. This will prevent the rule from sending out the same notification over and over. For example, if a rule with a `schedule` of 1 minute stays in a triggered state for 90 minutes, setting a `throttle` of `10m` or `1h` will prevent it from sending 90 notifications during this period. + +`notify_when`:: + (Required, string) The condition for throttling the notification: `onActionGroupChange`, `onActiveAlert`, or `onThrottleInterval`. + +`enabled`:: + (Optional, boolean) Indicates if you want to run the rule on an interval basis after it is created. + +`consumer`:: + (Required, string) The name of the application that owns the rule. This name has to match the Kibana Feature name, as that dictates the required RBAC privileges. + +`params`:: + (Required, object) The parameters to pass to the rule type executor `params` value. This will also validate against the rule type params validator, if defined. + +`actions`:: + (Optional, object array) An array of the following action objects. ++ +.Properties of the action objects: +[%collapsible%open] +===== + `group`::: + (Required, string) Grouping actions is recommended for escalations for different types of alerts. If you don't need this, set this value to `default`. + + `id`::: + (Required, string) The ID of the connector saved object to execute. + + `params`::: + (Required, object) The map to the `params` that the <> will receive. ` params` are handled as Mustache templates and passed a default set of context. +===== + + +[[create-rule-api-request-codes]] +==== Response code + +`200`:: + Indicates a successful call. + +[[create-rule-api-example]] +==== Example + +[source,sh] +-------------------------------------------------- +$ curl -X POST api/alerting/rule -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d ' +{ + "params":{ + "aggType":"avg", + "termSize":6, + "thresholdComparator":">", + "timeWindowSize":5, + "timeWindowUnit":"m", + "groupBy":"top", + "threshold":[ + 1000 + ], + "index":[ + ".test-index" + ], + "timeField":"@timestamp", + "aggField":"sheet.version", + "termField":"name.keyword" + }, + "consumer":"alerts", + "rule_type_id":".index-threshold", + "schedule":{ + "interval":"1m" + }, + "actions":[ + { + "id":"dceeb5d0-6b41-11eb-802b-85b0c1bc8ba2", + "group":"threshold met", + "params":{ + "level":"info", + "message":"alert '{{alertName}}' is active for group '{{context.group}}':\n\n- Value: {{context.value}}\n- Conditions Met: {{context.conditions}} over {{params.timeWindowSize}}{{params.timeWindowUnit}}\n- Timestamp: {{context.date}}" + } + } + ], + "tags":[ + "cpu" + ], + "notify_when":"onActionGroupChange", + "name":"my alert" +}' +-------------------------------------------------- +// KIBANA + +The API returns the following: + +[source,sh] +-------------------------------------------------- +{ + "id": "41893910-6bca-11eb-9e0d-85d233e3ee35", + "notify_when": "onActionGroupChange", + "params": { + "aggType": "avg", + "termSize": 6, + "thresholdComparator": ">", + "timeWindowSize": 5, + "timeWindowUnit": "m", + "groupBy": "top", + "threshold": [ + 1000 + ], + "index": [ + ".kibana" + ], + "timeField": "@timestamp", + "aggField": "sheet.version", + "termField": "name.keyword" + }, + "consumer": "alerts", + "rule_type_id": ".index-threshold", + "schedule": { + "interval": "1m" + }, + "actions": [ + { + "connector_type_id": ".server-log", + "group": "threshold met", + "params": { + "level": "info", + "message": "alert {{alertName}} is active for group {{context.group}}:\n\n- Value: {{context.value}}\n- Conditions Met: {{context.conditions}} over {{params.timeWindowSize}}{{params.timeWindowUnit}}\n- Timestamp: {{context.date}}" + }, + "id": "dceeb5d0-6b41-11eb-802b-85b0c1bc8ba2" + } + ], + "tags": [ + "cpu" + ], + "name": "my alert", + "enabled": true, + "throttle": null, + "api_key_owner": "elastic", + "created_by": "elastic", + "updated_by": "elastic", + "mute_all": false, + "muted_alert_ids": [], + "updated_at": "2021-02-10T18:03:19.961Z", + "created_at": "2021-02-10T18:03:19.961Z", + "scheduled_task_id": "425b0800-6bca-11eb-9e0d-85d233e3ee35", + "execution_status": { + "last_execution_date": "2021-02-10T18:03:19.966Z", + "status": "pending" + } +} +-------------------------------------------------- diff --git a/docs/api/alerting/delete_rule.asciidoc b/docs/api/alerting/delete_rule.asciidoc new file mode 100644 index 00000000000000..29e642e04c9e2f --- /dev/null +++ b/docs/api/alerting/delete_rule.asciidoc @@ -0,0 +1,41 @@ +[[delete-rule-api]] +=== Delete rule API +++++ +Delete rule +++++ + +Permanently remove a rule. + +WARNING: Once you delete a rule, you cannot recover it. + +[[delete-rule-api-request]] +==== Request + +`DELETE :/api/alerting/rule/` + +`DELETE :/s//api/alerting/rule/` + +[[delete-rule-api-path-params]] +==== Path parameters + +`id`:: + (Required, string) The ID of the rule that you want to remove. + +`space_id`:: + (Optional, string) An identifier for the space. If `space_id` is not provided in the URL, the default space is used. + +[[delete-rule-api-response-codes]] +==== Response code + +`200`:: + Indicates a successful call. + +==== Example + +Delete a rule with ID: + +[source,sh] +-------------------------------------------------- +$ curl -X DELETE api/alerting/rule/41893910-6bca-11eb-9e0d-85d233e3ee35 +-------------------------------------------------- +// KIBANA diff --git a/docs/api/alerting/disable_rule.asciidoc b/docs/api/alerting/disable_rule.asciidoc new file mode 100644 index 00000000000000..ce003335623efb --- /dev/null +++ b/docs/api/alerting/disable_rule.asciidoc @@ -0,0 +1,39 @@ +[[disable-rule-api]] +=== Disable rule API +++++ +Disable rule +++++ + +Disable a rule. + +[[disable-rule-api-request]] +==== Request + +`POST :/api/alerting/rule//_disable` + +`POST :/s//api/alerting/rule//_disable` + +[[disable-rule-api-path-params]] +==== Path parameters + +`id`:: + (Required, string) The ID of the rule that you want to disable. + +`space_id`:: + (Optional, string) An identifier for the space. If `space_id` is not provided in the URL, the default space is used. + +[[disable-rule-api-response-codes]] +==== Response code + +`200`:: + Indicates a successful call. + +==== Example + +Disable a rule with ID: + +[source,sh] +-------------------------------------------------- +$ curl -X POST api/alerting/rule/41893910-6bca-11eb-9e0d-85d233e3ee35/_disable +-------------------------------------------------- +// KIBANA diff --git a/docs/api/alerting/enable_rule.asciidoc b/docs/api/alerting/enable_rule.asciidoc new file mode 100644 index 00000000000000..60f18b35109043 --- /dev/null +++ b/docs/api/alerting/enable_rule.asciidoc @@ -0,0 +1,39 @@ +[[enable-rule-api]] +=== Enable rule API +++++ +Enable rule +++++ + +Enable a rule. + +[[enable-rule-api-request]] +==== Request + +`POST :/api/alerting/rule//_enable` + +`POST :/s//api/alerting/rule//_enable` + +[[enable-rule-api-path-params]] +==== Path parameters + +`id`:: + (Required, string) The ID of the rule that you want to enable. + +`space_id`:: + (Optional, string) An identifier for the space. If `space_id` is not provided in the URL, the default space is used. + +[[enable-rule-api-response-codes]] +==== Response code + +`200`:: + Indicates a successful call. + +==== Example + +Enable a rule with ID: + +[source,sh] +-------------------------------------------------- +$ curl -X POST api/alerting/rule/41893910-6bca-11eb-9e0d-85d233e3ee35/_enable +-------------------------------------------------- +// KIBANA diff --git a/docs/api/alerting/find_rules.asciidoc b/docs/api/alerting/find_rules.asciidoc new file mode 100644 index 00000000000000..2df8b3522725cd --- /dev/null +++ b/docs/api/alerting/find_rules.asciidoc @@ -0,0 +1,127 @@ +[[find-rules-api]] +=== Find rules API +++++ +Find rules +++++ + +Retrieve a paginated set of rules based on condition. + +NOTE: As rules change in {kib}, the results on each page of the response also +change. Use the find API for traditional paginated results, but avoid using it to export large amounts of data. + +[[find-rules-api-request]] +==== Request + +`GET :/api/alerting/rules/_find` + +`GET :/s//api/alerting/rules/_find` + +[[find-rules-api-path-params]] +==== Path parameters + +`space_id`:: + (Optional, string) An identifier for the space. If `space_id` is not provided in the URL, the default space is used. + +[[find-rules-api-query-params]] +==== Query Parameters + +NOTE: Rule `params` are stored as a {ref}/flattened.html[flattened field type] and analyzed as keywords. + +`per_page`:: + (Optional, number) The number of rules to return per page. + +`page`:: + (Optional, number) The page number. + +`search`:: + (Optional, string) An Elasticsearch {ref}/query-dsl-simple-query-string-query.html[simple_query_string] query that filters the rules in the response. + +`default_search_operator`:: + (Optional, string) The operator to use for the `simple_query_string`. The default is 'OR'. + +`search_fields`:: + (Optional, array|string) The fields to perform the `simple_query_string` parsed query against. + +`fields`:: + (Optional, array|string) The fields to return in the `attributes` key of the response. + +`sort_field`:: + (Optional, string) Sorts the response. Could be a rule field returned in the `attributes` key of the response. + +`sort_order`:: + (Optional, string) Sort direction, either `asc` or `desc`. + +`has_reference`:: + (Optional, object) Filters the rules that have a relation with the reference objects with the specific "type" and "ID". + +`filter`:: + (Optional, string) A <> string that you filter with an attribute from your saved object. + It should look like savedObjectType.attributes.title: "myTitle". However, If you used a direct attribute of a saved object, such as `updatedAt`, + you will have to define your filter, for example, savedObjectType.updatedAt > 2018-12-22. + +[[find-rules-api-request-codes]] +==== Response code + +`200`:: + Indicates a successful call. + +==== Examples + +Find rules with names that start with `my`: + +[source,sh] +-------------------------------------------------- +$ curl -X GET api/alerting/rules/_find?search_fields=name&search=my* +-------------------------------------------------- +// KIBANA + +The API returns the following: + +[source,sh] +-------------------------------------------------- +{ + "page": 1, + "per_page": 10, + "total": 1, + "data": [ + { + "id": "0a037d60-6b62-11eb-9e0d-85d233e3ee35", + "notify_when": "onActionGroupChange", + "params": { + "aggType": "avg", + }, + "consumer": "alerts", + "rule_type_id": "test.rule.type", + "schedule": { + "interval": "1m" + }, + "actions": [], + "tags": [], + "name": "test rule", + "enabled": true, + "throttle": null, + "api_key_owner": "elastic", + "created_by": "elastic", + "updated_by": "elastic", + "mute_all": false, + "muted_alert_ids": [], + "updated_at": "2021-02-10T05:37:19.086Z", + "created_at": "2021-02-10T05:37:19.086Z", + "scheduled_task_id": "0b092d90-6b62-11eb-9e0d-85d233e3ee35", + "execution_status": { + "last_execution_date": "2021-02-10T17:55:14.262Z", + "status": "ok" + } + }, + ] +} +-------------------------------------------------- + +For parameters that accept multiple values (e.g. `fields`), repeat the +query parameter for each value: + +[source,sh] +-------------------------------------------------- +$ curl -X GET api/alerting/rules/_find?fields=id&fields=name +-------------------------------------------------- +// KIBANA diff --git a/docs/api/alerting/get_rules.asciidoc b/docs/api/alerting/get_rules.asciidoc new file mode 100644 index 00000000000000..1594ec1fb7ae60 --- /dev/null +++ b/docs/api/alerting/get_rules.asciidoc @@ -0,0 +1,75 @@ +[[get-rule-api]] +=== Get rule API +++++ +Get rule +++++ + +Retrieve a rule by ID. + +[[get-rule-api-request]] +==== Request + +`GET :/api/alerting/rule/` + +`GET :/s//api/alerting/rule/` + +[[get-rule-api-params]] +==== Path parameters + +`id`:: + (Required, string) The ID of the rule to retrieve. + +`space_id`:: + (Optional, string) An identifier for the space. If `space_id` is not provided in the URL, the default space is used. + +[[get-rule-api-codes]] +==== Response code + +`200`:: + Indicates a successful call. + +[[get-rule-api-example]] +==== Example + +Retrieve the rule object with the ID `41893910-6bca-11eb-9e0d-85d233e3ee35`: + +[source,sh] +-------------------------------------------------- +$ curl -X GET api/alerting/rule/41893910-6bca-11eb-9e0d-85d233e3ee35 +-------------------------------------------------- +// KIBANA + +The API returns the following: + +[source,sh] +-------------------------------------------------- +{ + "id": "0a037d60-6b62-11eb-9e0d-85d233e3ee35", + "notify_when": "onActionGroupChange", + "params": { + "aggType": "avg", + }, + "consumer": "alerts", + "rule_type_id": "test.rule.type", + "schedule": { + "interval": "1m" + }, + "actions": [], + "tags": [], + "name": "test rule", + "enabled": true, + "throttle": null, + "api_key_owner": "elastic", + "created_by": "elastic", + "updated_by": "elastic", + "mute_all": false, + "muted_alert_ids": [], + "updated_at": "2021-02-10T05:37:19.086Z", + "created_at": "2021-02-10T05:37:19.086Z", + "scheduled_task_id": "0b092d90-6b62-11eb-9e0d-85d233e3ee35", + "execution_status": { + "last_execution_date": "2021-02-10T17:55:14.262Z", + "status": "ok" + } +} +-------------------------------------------------- diff --git a/docs/api/alerting/health.asciidoc b/docs/api/alerting/health.asciidoc new file mode 100644 index 00000000000000..1e6b9ce22a981d --- /dev/null +++ b/docs/api/alerting/health.asciidoc @@ -0,0 +1,93 @@ +[[get-alerting-framework-health-api]] +=== Get Alerting framework health API +++++ +Get Alerting framework health +++++ + +Retrieve the health status of the Alerting framework. + +[[get-alerting-framework-health-api-request]] +==== Request + +`GET :/api/alerting/_health` + +`GET :/s//api/alerting/_health` + +[[get-alerting-framework-health-api-params]] +==== Path parameters + +`space_id`:: + (Optional, string) An identifier for the space. If `space_id` is not provided in the URL, the default space is used. + +[[get-alerting-framework-health-api-codes]] +==== Response code + +`200`:: + Indicates a successful call. + +[[get-alerting-framework-health-api-example]] +==== Example + +Retrieve the health status of the Alerting framework: + +[source,sh] +-------------------------------------------------- +$ curl -X GET api/alerting/_health +-------------------------------------------------- +// KIBANA + +The API returns the following: + +[source,sh] +-------------------------------------------------- +{ + "is_sufficiently_secure":true, + "has_permanent_encryption_key":true, + "alerting_framework_health":{ + "decryption_health":{ + "status":"ok", + "timestamp":"2021-02-10T23:35:04.949Z" + }, + "execution_health":{ + "status":"ok", + "timestamp":"2021-02-10T23:35:04.949Z" + }, + "read_health":{ + "status":"ok", + "timestamp":"2021-02-10T23:35:04.949Z" + } + } +} +-------------------------------------------------- + +The health API response contains the following properties: + +[cols="2*<"] +|=== + +| `is_sufficiently_secure` +| Returns `false` if security is enabled, but TLS is not. + +| `has_permanent_encryption_key` +| Return the state `false` if Encrypted Saved Object plugin has not a permanent encryption Key. + +| `alerting_framework_health` +| This state property has three substates that identify the health of the alerting framework API: `decryption_health`, `execution_health`, and `read_health`. + +|=== + +`alerting_framework_health` consists of the following properties: + +[cols="2*<"] +|=== + +| `decryption_health` +| Returns the timestamp and status of the rule decryption: `ok`, `warn` or `error` . + +| `execution_health` +| Returns the timestamp and status of the rule execution: `ok`, `warn` or `error`. + +| `read_health` +| Returns the timestamp and status of the rule reading events: `ok`, `warn` or `error`. + +|=== diff --git a/docs/api/alerts/create.asciidoc b/docs/api/alerting/legacy/create.asciidoc similarity index 97% rename from docs/api/alerts/create.asciidoc rename to docs/api/alerting/legacy/create.asciidoc index c3e6d36813972b..5c594d64a3f45b 100644 --- a/docs/api/alerts/create.asciidoc +++ b/docs/api/alerting/legacy/create.asciidoc @@ -1,9 +1,11 @@ [[alerts-api-create]] -=== Create alert API +=== Legacy create alert API ++++ -Create alert +Legacy create alert ++++ +WARNING: Deprecated in 7.13.0. Use <> instead. + Create {kib} alerts. [[alerts-api-create-request]] diff --git a/docs/api/alerts/delete.asciidoc b/docs/api/alerting/legacy/delete.asciidoc similarity index 86% rename from docs/api/alerts/delete.asciidoc rename to docs/api/alerting/legacy/delete.asciidoc index 72dfd5e87336cb..68851973cab5b9 100644 --- a/docs/api/alerts/delete.asciidoc +++ b/docs/api/alerting/legacy/delete.asciidoc @@ -1,9 +1,11 @@ [[alerts-api-delete]] -=== Delete alert API +=== Legacy delete alert API ++++ -Delete alert +Legacy delete alert ++++ +WARNING: Deprecated in 7.13.0. Use <> instead. + Permanently remove an alert. WARNING: Once you delete an alert, you cannot recover it. diff --git a/docs/api/alerts/disable.asciidoc b/docs/api/alerting/legacy/disable.asciidoc similarity index 85% rename from docs/api/alerts/disable.asciidoc rename to docs/api/alerting/legacy/disable.asciidoc index 86c58c37c2ecd1..56e06371570c2a 100644 --- a/docs/api/alerts/disable.asciidoc +++ b/docs/api/alerting/legacy/disable.asciidoc @@ -1,9 +1,11 @@ [[alerts-api-disable]] -=== Disable alert API +=== Legacy disable alert API ++++ -Disable alert +Legacy disable alert ++++ +WARNING: Deprecated in 7.13.0. Use <> instead. + Disable an alert. [[alerts-api-disable-request]] diff --git a/docs/api/alerts/enable.asciidoc b/docs/api/alerting/legacy/enable.asciidoc similarity index 85% rename from docs/api/alerts/enable.asciidoc rename to docs/api/alerting/legacy/enable.asciidoc index de1a5f7985a38a..913d96a84352bd 100644 --- a/docs/api/alerts/enable.asciidoc +++ b/docs/api/alerting/legacy/enable.asciidoc @@ -1,9 +1,11 @@ [[alerts-api-enable]] -=== Enable alert API +=== Legacy enable alert API ++++ -Enable alert +Legacy enable alert ++++ +WARNING: Deprecated in 7.13.0. Use <> instead. + Enable an alert. [[alerts-api-enable-request]] diff --git a/docs/api/alerts/find.asciidoc b/docs/api/alerting/legacy/find.asciidoc similarity index 96% rename from docs/api/alerts/find.asciidoc rename to docs/api/alerting/legacy/find.asciidoc index cc66d4e0f41834..94d9bc425bd214 100644 --- a/docs/api/alerts/find.asciidoc +++ b/docs/api/alerting/legacy/find.asciidoc @@ -1,9 +1,11 @@ [[alerts-api-find]] -=== Find alerts API +=== Legacy find alerts API ++++ -Find alerts +Legacy find alerts ++++ +WARNING: Deprecated in 7.13.0. Use <> instead. + Retrieve a paginated set of alerts based on condition. NOTE: As alerts change in {kib}, the results on each page of the response also diff --git a/docs/api/alerts/get.asciidoc b/docs/api/alerting/legacy/get.asciidoc similarity index 92% rename from docs/api/alerts/get.asciidoc rename to docs/api/alerting/legacy/get.asciidoc index 433605e8573325..f1014d18e87741 100644 --- a/docs/api/alerts/get.asciidoc +++ b/docs/api/alerting/legacy/get.asciidoc @@ -1,9 +1,11 @@ [[alerts-api-get]] -=== Get alert API +=== Legacy get alert API ++++ -Get alert +Legacy get alert ++++ +WARNING: Deprecated in 7.13.0. Use <> instead. + Retrieve an alert by ID. [[alerts-api-get-request]] diff --git a/docs/api/alerts/health.asciidoc b/docs/api/alerting/legacy/health.asciidoc similarity index 92% rename from docs/api/alerts/health.asciidoc rename to docs/api/alerting/legacy/health.asciidoc index b29e5def533849..b25307fb5efd18 100644 --- a/docs/api/alerts/health.asciidoc +++ b/docs/api/alerting/legacy/health.asciidoc @@ -1,9 +1,11 @@ [[alerts-api-health]] -=== Get Alerting framework health API +=== Legacy get Alerting framework health API ++++ -Get Alerting framework health +Legacy get Alerting framework health ++++ +WARNING: Deprecated in 7.13.0. Use <> instead. + Retrieve the health status of the Alerting framework. [[alerts-api-health-request]] diff --git a/docs/api/alerting/legacy/index.asciidoc b/docs/api/alerting/legacy/index.asciidoc new file mode 100644 index 00000000000000..cce2c378bdb581 --- /dev/null +++ b/docs/api/alerting/legacy/index.asciidoc @@ -0,0 +1,18 @@ +[[alerts-api]] +=== Deprecated 7.x APIs + +These APIs are deprecated and will be removed as of 8.0. + +include::create.asciidoc[leveloffset=+1] +include::delete.asciidoc[leveloffset=+1] +include::disable.asciidoc[leveloffset=+1] +include::enable.asciidoc[leveloffset=+1] +include::find.asciidoc[leveloffset=+1] +include::get.asciidoc[leveloffset=+1] +include::health.asciidoc[leveloffset=+1] +include::list.asciidoc[leveloffset=+1] +include::mute.asciidoc[leveloffset=+1] +include::mute_all.asciidoc[leveloffset=+1] +include::unmute.asciidoc[leveloffset=+1] +include::unmute_all.asciidoc[leveloffset=+1] +include::update.asciidoc[leveloffset=+1] \ No newline at end of file diff --git a/docs/api/alerts/list.asciidoc b/docs/api/alerting/legacy/list.asciidoc similarity index 96% rename from docs/api/alerts/list.asciidoc rename to docs/api/alerting/legacy/list.asciidoc index e180945accfd3e..e9ef3bbc27cd9f 100644 --- a/docs/api/alerts/list.asciidoc +++ b/docs/api/alerting/legacy/list.asciidoc @@ -1,9 +1,11 @@ [[alerts-api-list]] -=== List alert types API +=== Legacy list alert types API ++++ -List all alert types API +Legacy list all alert types ++++ +WARNING: Deprecated in 7.13.0. Use <> instead. + Retrieve a list of all alert types. [[alerts-api-list-request]] diff --git a/docs/api/alerts/mute.asciidoc b/docs/api/alerting/legacy/mute.asciidoc similarity index 87% rename from docs/api/alerts/mute.asciidoc rename to docs/api/alerting/legacy/mute.asciidoc index 84a2996b658386..dff42f5911e53f 100644 --- a/docs/api/alerts/mute.asciidoc +++ b/docs/api/alerting/legacy/mute.asciidoc @@ -1,9 +1,11 @@ [[alerts-api-mute]] -=== Mute alert instance API +=== Legacy mute alert instance API ++++ -Mute alert instance +Legacy mute alert instance ++++ +WARNING: Deprecated in 7.13.0. Use <> instead. + Mute an alert instance. [[alerts-api-mute-request]] diff --git a/docs/api/alerts/mute_all.asciidoc b/docs/api/alerting/legacy/mute_all.asciidoc similarity index 83% rename from docs/api/alerts/mute_all.asciidoc rename to docs/api/alerting/legacy/mute_all.asciidoc index 02f41eb3b768ec..df89fa15d15902 100644 --- a/docs/api/alerts/mute_all.asciidoc +++ b/docs/api/alerting/legacy/mute_all.asciidoc @@ -1,9 +1,11 @@ [[alerts-api-mute-all]] -=== Mute all alert instances API +=== Legacy mute all alert instances API ++++ -Mute all alert instances +Legacy mute all alert instances ++++ +WARNING: Deprecated in 7.13.0. Use <> instead. + Mute all alert instances. [[alerts-api-mute-all-request]] diff --git a/docs/api/alerts/unmute.asciidoc b/docs/api/alerting/legacy/unmute.asciidoc similarity index 87% rename from docs/api/alerts/unmute.asciidoc rename to docs/api/alerting/legacy/unmute.asciidoc index eb73bb539154f8..0be7e40dc1a198 100644 --- a/docs/api/alerts/unmute.asciidoc +++ b/docs/api/alerting/legacy/unmute.asciidoc @@ -1,9 +1,11 @@ [[alerts-api-unmute]] -=== Unmute alert instance API +=== Legacy unmute alert instance API ++++ -Unmute alert instance +Legacy unmute alert instance ++++ +WARNING: Deprecated in 7.13.0. Use <> instead. + Unmute an alert instance. [[alerts-api-unmute-request]] diff --git a/docs/api/alerts/unmute_all.asciidoc b/docs/api/alerting/legacy/unmute_all.asciidoc similarity index 83% rename from docs/api/alerts/unmute_all.asciidoc rename to docs/api/alerting/legacy/unmute_all.asciidoc index a20a20fd8204a4..8687c2d2fe8bb2 100644 --- a/docs/api/alerts/unmute_all.asciidoc +++ b/docs/api/alerting/legacy/unmute_all.asciidoc @@ -1,9 +1,11 @@ [[alerts-api-unmute-all]] -=== Unmute all alert instances API +=== Legacy unmute all alert instances API ++++ -Unmute all alert instances +Legacy unmute all alert instances ++++ +WARNING: Deprecated in 7.13.0. Use <> instead. + Unmute all alert instances. [[alerts-api-unmute-all-request]] diff --git a/docs/api/alerts/update.asciidoc b/docs/api/alerting/legacy/update.asciidoc similarity index 96% rename from docs/api/alerts/update.asciidoc rename to docs/api/alerting/legacy/update.asciidoc index a0b147ed4a15d1..bffdf26c314001 100644 --- a/docs/api/alerts/update.asciidoc +++ b/docs/api/alerting/legacy/update.asciidoc @@ -1,9 +1,11 @@ [[alerts-api-update]] -=== Update alert API +=== Legacy update alert API ++++ -Update alert +Legacy update alert ++++ +WARNING: Deprecated in 7.13.0. Use <> instead. + Update the attributes for an existing alert. [[alerts-api-update-request]] diff --git a/docs/api/alerting/list_rule_types.asciidoc b/docs/api/alerting/list_rule_types.asciidoc new file mode 100644 index 00000000000000..77ca8601a6e8ba --- /dev/null +++ b/docs/api/alerting/list_rule_types.asciidoc @@ -0,0 +1,135 @@ +[[list-rule-types-api]] +=== List rule types API +++++ +List rule types +++++ + +Retrieve a list of alerting rule types. + +[[list-rule-types-api-request]] +==== Request + +`GET :/api/alerting/rule_types` + +`GET :/s//api/alerting/rule_types` + +[[list-rule-types-api-params]] +==== Path parameters + +`space_id`:: + (Optional, string) An identifier for the space. If `space_id` is not provided in the URL, the default space is used. + +[[list-rule-types-api-codes]] +==== Response code + +`200`:: + Indicates a successful call. + +[[list-rule-types-api-example]] +==== Example + +[source,sh] +-------------------------------------------------- +$ curl -X GET api/alerting/rule_types +-------------------------------------------------- +// KIBANA + +The API returns the following: + +[source,sh] +-------------------------------------------------- +[ + { + "id":".index-threshold", + "name":"Index threshold", + "action_groups":[ + { + "id":"threshold met", + "name":"Threshold met" + }, + { + "id":"recovered", + "name":"Recovered" + } + ], + "recovery_action_group":{ + "id":"recovered", + "name":"Recovered" + }, + "default_action_group_id":"threshold met", + "action_variables":{ + "context":[ + { + "name":"message", + "description":"A pre-constructed message for the alert." + }, + ], + "state":[], + "params":[ + { + "name":"threshold", + "description":"An array of values to use as the threshold; 'between' and 'notBetween' require two values, the others require one." + }, + { + "name":"index", + "description":"index" + }, + ] + }, + "producer":"stackAlerts", + "minimum_license_required":"basic", + "enabled_in_license":true, + "authorized_consumers":{ + "alerts":{ + "read":true, + "all":true + }, + "stackAlerts":{ + "read":true, + "all":true + }, + "uptime":{ + "read":true, + "all":true + } + } + } +] +-------------------------------------------------- + +Each rule type contains the following properties: + +[cols="2*<"] +|=== + +| `name` +| The descriptive name of the rule type. + +| `id` +| The unique ID of the rule type. + +| `minimum_license_required` +| The license required to use the rule type. + +| `enabled_in_license` +| Whether the rule type is enabled or disabled based on the license. + +| `action_groups` +| An explicit list of groups for which the rule type can schedule actions, each with the action group's unique ID and human readable name. Rule `actions` validation will use this configuration to ensure that groups are valid. Use `kbn-i18n` to translate the names of the action group when registering the rule type. + +| `recovery_action_group` +| An action group to use when an alert goes from an active state, to an inactive one. Do not specify this action group under the `action_groups` property. If `recovery_action_group` is not specified, the default `recovered` action group is used. + +| `default_action_group_od` +| The default ID for the rule type group. + +| `action_variables` +| An explicit list of action variables that the rule type makes available via context and state in action parameter templates, and a short human readable description. The Rule UI will use this information to prompt users for these variables in action parameter editors. Use `kbn-i18n` to translate the descriptions. + +| `producer` +| The ID of the application producing this rule type. + +| `authorized_consumers` +| The list of the plugins IDs that have access to the rule type. + +|=== diff --git a/docs/api/alerting/mute_alert.asciidoc b/docs/api/alerting/mute_alert.asciidoc new file mode 100644 index 00000000000000..4ebf12d1ce10c6 --- /dev/null +++ b/docs/api/alerting/mute_alert.asciidoc @@ -0,0 +1,42 @@ +[[mute-alert-api]] +=== Mute alert API +++++ +Mute alert +++++ + +Mute an alert. + +[[mute-alert-api-request]] +==== Request + +`POST :/api/alerting/rule//alert//_mute` + +`POST :/s//api/alerting/rule//alert//_mute` + +[[mute-alert-api-path-params]] +==== Path parameters + +`rule_id`:: + (Required, string) The ID of the rule whose alert you want to mute. + +`alert_id`:: + (Required, string) The ID of the alert that you want to mute. + +`space_id`:: + (Optional, string) An identifier for the space. If `space_id` is not provided in the URL, the default space is used. + +[[mute-alert-api-response-codes]] +==== Response code + +`200`:: + Indicates a successful call. + +==== Example + +Mute alert with ID: + +[source,sh] +-------------------------------------------------- +$ curl -X POST api/alerting/rule/41893910-6bca-11eb-9e0d-85d233e3ee35/alert/dceeb5d0-6b41-11eb-802b-85b0c1bc8ba2/_mute +-------------------------------------------------- +// KIBANA diff --git a/docs/api/alerting/mute_all_alerts.asciidoc b/docs/api/alerting/mute_all_alerts.asciidoc new file mode 100644 index 00000000000000..58b6b14f49b4f4 --- /dev/null +++ b/docs/api/alerting/mute_all_alerts.asciidoc @@ -0,0 +1,39 @@ +[[mute-all-alerts-api]] +=== Mute all alerts API +++++ +Mute all alerts +++++ + +Mute all alerts. + +[[mute-all-alerts-api-request]] +==== Request + +`POST :/api/alerting/rule//_mute_all` + +`POST :/s//api/alerting/rule//_mute_all` + +[[mute-all-alerts-api-path-params]] +==== Path parameters + +`id`:: + (Required, string) The ID of the rule whose alerts you want to mute. + +`space_id`:: + (Optional, string) An identifier for the space. If `space_id` is not provided in the URL, the default space is used. + +[[mute-all-alerts-api-response-codes]] +==== Response code + +`200`:: + Indicates a successful call. + +==== Example + +Mute all alerts with ID: + +[source,sh] +-------------------------------------------------- +$ curl -X POST api/alerting/rule/41893910-6bca-11eb-9e0d-85d233e3ee35/_mute_all +-------------------------------------------------- +// KIBANA diff --git a/docs/api/alerting/unmute_alert.asciidoc b/docs/api/alerting/unmute_alert.asciidoc new file mode 100644 index 00000000000000..6e8870bb2fdaeb --- /dev/null +++ b/docs/api/alerting/unmute_alert.asciidoc @@ -0,0 +1,42 @@ +[[unmute-alert-api]] +=== Unmute alert API +++++ +Unmute alert +++++ + +Unmute an alert. + +[[unmute-alert-api-request]] +==== Request + +`POST :/api/alerting/rule//alert//_unmute` + +`POST :/s//api/alerting/rule//alert//_unmute` + +[[unmute-alert-api-path-params]] +==== Path parameters + +`rule_id`:: + (Required, string) The ID of the rule whose alert you want to mute. + +`alert_id`:: + (Required, string) The ID of the alert that you want to unmute. + +`space_id`:: + (Optional, string) An identifier for the space. If `space_id` is not provided in the URL, the default space is used. + +[[unmute-alert-api-response-codes]] +==== Response code + +`200`:: + Indicates a successful call. + +==== Example + +Unmute alert with ID: + +[source,sh] +-------------------------------------------------- +$ curl -X POST api/alerting/rule/41893910-6bca-11eb-9e0d-85d233e3ee35/alert/dceeb5d0-6b41-11eb-802b-85b0c1bc8ba2/_unmute +-------------------------------------------------- +// KIBANA diff --git a/docs/api/alerting/unmute_all_alerts.asciidoc b/docs/api/alerting/unmute_all_alerts.asciidoc new file mode 100644 index 00000000000000..c429ca288ae79c --- /dev/null +++ b/docs/api/alerting/unmute_all_alerts.asciidoc @@ -0,0 +1,39 @@ +[[unmute-all-alerts-api]] +=== Unmute all alerts API +++++ +Unmute all alerts +++++ + +Unmute all alerts. + +[[unmute-all-alerts-api-all-request]] +==== Request + +`POST :/api/alerting/rule//_unmute_all` + +`POST :/s//api/alerting/rule//_unmute_all` + +[[unmute-all-alerts-api-path-params]] +==== Path parameters + +`id`:: + (Required, string) The ID of the rule whose alerts you want to unmute. + +`space_id`:: + (Optional, string) An identifier for the space. If `space_id` is not provided in the URL, the default space is used. + +[[unmute-all-alerts-api-response-codes]] +==== Response code + +`200`:: + Indicates a successful call. + +==== Example + +Unmute all alerts with ID: + +[source,sh] +-------------------------------------------------- +$ curl -X POST api/alerting/rule/41893910-6bca-11eb-9e0d-85d233e3ee35/_unmute_all +-------------------------------------------------- +// KIBANA diff --git a/docs/api/alerting/update_rule.asciidoc b/docs/api/alerting/update_rule.asciidoc new file mode 100644 index 00000000000000..76c88a009be011 --- /dev/null +++ b/docs/api/alerting/update_rule.asciidoc @@ -0,0 +1,136 @@ +[[update-rule-api]] +=== Update rule API +++++ +Update rule +++++ + +Update the attributes for an existing rule. + +[[update-rule-api-request]] +==== Request + +`PUT :/api/alerting/rule/` + +`PUT :/s//api/alerting/rule/` + +[[update-rule-api-path-params]] +==== Path parameters + +`id`:: + (Required, string) The ID of the rule that you want to update. + +`space_id`:: + (Optional, string) An identifier for the space. If `space_id` is not provided in the URL, the default space is used. + +[[update-rule-api-request-body]] +==== Request body + +`name`:: + (Required, string) A name to reference and search. + +`tags`:: + (Optional, string array) A list of keywords to reference and search. + +`schedule`:: + (Required, object) When to run this rule. Use one of the available schedule formats. ++ +._Schedule Formats_. +[%collapsible%open] +===== +A schedule uses a key: value format. {kib} currently supports the _Interval format_ , which specifies the interval in seconds, minutes, hours, or days at which to execute the rule. + +Example: `{ interval: "10s" }`, `{ interval: "5m" }`, `{ interval: "1h" }`, `{ interval: "1d" }`. + +===== + +`throttle`:: + (Optional, string) How often this rule should fire the same actions. This will prevent the rule from sending out the same notification over and over. For example, if a rule with a `schedule` of 1 minute stays in a triggered state for 90 minutes, setting a `throttle` of `10m` or `1h` will prevent it from sending 90 notifications during this period. + +`notify_when`:: + (Required, string) The condition for throttling the notification: `onActionGroupChange`, `onActiveAlert`, or `onThrottleInterval`. + +`params`:: + (Required, object) The parameters to pass to the rule type executor `params` value. This will also validate against the rule type params validator, if defined. + +`actions`:: + (Optional, object array) An array of the following action objects. ++ +.Properties of the action objects: +[%collapsible%open] +===== + `group`::: + (Required, string) Grouping actions is recommended for escalations for different types of alerts. If you don't need this, set the value to `default`. + + `id`::: + (Required, string) The ID of the action that saved object executes. + + `params`::: + (Required, object) The map to the `params` that the <> will receive. `params` are handled as Mustache templates and passed a default set of context. +===== + + +[[update-rule-api-response-codes]] +==== Response code + +`200`:: + Indicates a successful call. + +[[update-rule-api-example]] +==== Example + +Update a rule with ID `ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74` with a different name: + +[source,sh] +-------------------------------------------------- +$ curl -X PUT api/alerting/rule/ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 + +{ + "notify_when": "onActionGroupChange", + "params": { + "aggType": "avg", + }, + "schedule": { + "interval": "1m" + }, + "actions": [], + "tags": [], + "name": "new name", + "throttle": null, +} +-------------------------------------------------- +// KIBANA + +The API returns the following: + +[source,sh] +-------------------------------------------------- +{ + "id": "ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74", + "notify_when": "onActionGroupChange", + "params": { + "aggType": "avg", + }, + "consumer": "alerts", + "rule_type_id": "test.rule.type", + "schedule": { + "interval": "1m" + }, + "actions": [], + "tags": [], + "name": "new name", + "enabled": true, + "throttle": null, + "api_key_owner": "elastic", + "created_by": "elastic", + "updated_by": "elastic", + "mute_all": false, + "muted_alert_ids": [], + "updated_at": "2021-02-10T05:37:19.086Z", + "created_at": "2021-02-10T05:37:19.086Z", + "scheduled_task_id": "0b092d90-6b62-11eb-9e0d-85d233e3ee35", + "execution_status": { + "last_execution_date": "2021-02-10T17:55:14.262Z", + "status": "ok" + } +} +-------------------------------------------------- diff --git a/docs/api/alerts.asciidoc b/docs/api/alerts.asciidoc deleted file mode 100644 index a19c538bcb4d7b..00000000000000 --- a/docs/api/alerts.asciidoc +++ /dev/null @@ -1,42 +0,0 @@ -[[alerts-api]] -== Alerts APIs - -The following APIs are available for managing {kib} alerts. - -* <> to create an alert - -* <> to update the attributes for existing alerts - -* <> to retrieve a single alert by ID - -* <> to permanently remove an alert - -* <> to retrieve a paginated set of alerts by condition - -* <> to retrieve a list of all alert types - -* <> to enable a single alert by ID - -* <> to disable a single alert by ID - -* <> to mute alert instances for a single alert by ID - -* <> to unmute alert instances for a single alert by ID - -* <> to unmute all alert instances for a single alert by ID - -* <> to retrieve the health of the alerts framework - -include::alerts/create.asciidoc[] -include::alerts/update.asciidoc[] -include::alerts/get.asciidoc[] -include::alerts/delete.asciidoc[] -include::alerts/find.asciidoc[] -include::alerts/list.asciidoc[] -include::alerts/enable.asciidoc[] -include::alerts/disable.asciidoc[] -include::alerts/mute_all.asciidoc[] -include::alerts/mute.asciidoc[] -include::alerts/unmute_all.asciidoc[] -include::alerts/unmute.asciidoc[] -include::alerts/health.asciidoc[] diff --git a/docs/user/api.asciidoc b/docs/user/api.asciidoc index c41f3d8a829e4b..6daf252c524ddd 100644 --- a/docs/user/api.asciidoc +++ b/docs/user/api.asciidoc @@ -99,7 +99,7 @@ include::{kib-repo-dir}/api/spaces-management.asciidoc[] include::{kib-repo-dir}/api/role-management.asciidoc[] include::{kib-repo-dir}/api/session-management.asciidoc[] include::{kib-repo-dir}/api/saved-objects.asciidoc[] -include::{kib-repo-dir}/api/alerts.asciidoc[] +include::{kib-repo-dir}/api/alerting.asciidoc[] include::{kib-repo-dir}/api/actions-and-connectors.asciidoc[] include::{kib-repo-dir}/api/dashboard-api.asciidoc[] include::{kib-repo-dir}/api/logstash-configuration-management.asciidoc[] diff --git a/x-pack/examples/alerting_example/public/components/view_alert.tsx b/x-pack/examples/alerting_example/public/components/view_alert.tsx index 8c942d685af27b..40eeb9fd360dca 100644 --- a/x-pack/examples/alerting_example/public/components/view_alert.tsx +++ b/x-pack/examples/alerting_example/public/components/view_alert.tsx @@ -21,8 +21,12 @@ import { import { withRouter, RouteComponentProps } from 'react-router-dom'; import { CoreStart } from 'kibana/public'; import { isEmpty } from 'lodash'; -import { Alert, AlertTaskState, BASE_ALERT_API_PATH } from '../../../../plugins/alerting/common'; import { ALERTING_EXAMPLE_APP_ID } from '../../common/constants'; +import { + Alert, + AlertTaskState, + LEGACY_BASE_ALERT_API_PATH, +} from '../../../../plugins/alerting/common'; type Props = RouteComponentProps & { http: CoreStart['http']; @@ -34,10 +38,10 @@ export const ViewAlertPage = withRouter(({ http, id }: Props) => { useEffect(() => { if (!alert) { - http.get(`${BASE_ALERT_API_PATH}/alert/${id}`).then(setAlert); + http.get(`${LEGACY_BASE_ALERT_API_PATH}/alert/${id}`).then(setAlert); } if (!alertState) { - http.get(`${BASE_ALERT_API_PATH}/alert/${id}/state`).then(setAlertState); + http.get(`${LEGACY_BASE_ALERT_API_PATH}/alert/${id}/state`).then(setAlertState); } }, [alert, alertState, http, id]); diff --git a/x-pack/examples/alerting_example/public/components/view_astros_alert.tsx b/x-pack/examples/alerting_example/public/components/view_astros_alert.tsx index 7e8487b0179fae..8eef1882b93899 100644 --- a/x-pack/examples/alerting_example/public/components/view_astros_alert.tsx +++ b/x-pack/examples/alerting_example/public/components/view_astros_alert.tsx @@ -23,8 +23,12 @@ import { import { withRouter, RouteComponentProps } from 'react-router-dom'; import { CoreStart } from 'kibana/public'; import { isEmpty } from 'lodash'; -import { Alert, AlertTaskState, BASE_ALERT_API_PATH } from '../../../../plugins/alerting/common'; import { ALERTING_EXAMPLE_APP_ID, AlwaysFiringParams } from '../../common/constants'; +import { + Alert, + AlertTaskState, + LEGACY_BASE_ALERT_API_PATH, +} from '../../../../plugins/alerting/common'; type Props = RouteComponentProps & { http: CoreStart['http']; @@ -40,10 +44,10 @@ export const ViewPeopleInSpaceAlertPage = withRouter(({ http, id }: Props) => { useEffect(() => { if (!alert) { - http.get(`${BASE_ALERT_API_PATH}/alert/${id}`).then(setAlert); + http.get(`${LEGACY_BASE_ALERT_API_PATH}/alert/${id}`).then(setAlert); } if (!alertState) { - http.get(`${BASE_ALERT_API_PATH}/alert/${id}/state`).then(setAlertState); + http.get(`${LEGACY_BASE_ALERT_API_PATH}/alert/${id}/state`).then(setAlertState); } }, [alert, alertState, http, id]); diff --git a/x-pack/plugins/alerting/README.md b/x-pack/plugins/alerting/README.md index 19322fed7363ea..eb64d71be565ea 100644 --- a/x-pack/plugins/alerting/README.md +++ b/x-pack/plugins/alerting/README.md @@ -453,20 +453,20 @@ The only case in which this handler will not be used to evaluate the navigation You can use the `registerNavigation` api to specify as many AlertType specific handlers as you like, but you can only use it once per AlertType as we wouldn't know which handler to use if you specified two for the same AlertType. For the same reason, you can only use `registerDefaultNavigation` once per plugin, as it covers all cases for your specific plugin. -## Experimental RESTful API +## Internal HTTP APIs -Using of the alert type requires you to create an alert that will contain parameters and actions for a given alert type. API description for CRUD operations is a part of the [user documentation](https://www.elastic.co/guide/en/kibana/master/alerts-api-update.html). -API listed below is experimental and could be changed or removed in the future. +Using of the rule type requires you to create a rule that will contain parameters and actions for a given rule type. API description for CRUD operations is a part of the [user documentation](https://www.elastic.co/guide/en/kibana/master/alerting-apis.html). +API listed below are internal and should not be consumed by plugin outside the alerting plugins. -### `GET /api/alerts/alert/{id}/state`: Get alert state +### `GET /internal/alerting/rule/{id}/state`: Get rule state Params: |Property|Description|Type| |---|---|---| -|id|The id of the alert whose state you're trying to get.|string| +|id|The id of the rule whose state you're trying to get.|string| -### `GET /api/alerts/alert/{id}/_instance_summary`: Get alert instance summary +### `GET /internal/alerting/rule/{id}/_alert_summary`: Get rule alert summary Similar to the `GET state` call, but collects additional information from the event log. @@ -475,7 +475,7 @@ Params: |Property|Description|Type| |---|---|---| -|id|The id of the alert whose instance summary you're trying to get.|string| +|id|The id of the rule whose alert summary you're trying to get.|string| Query: @@ -483,11 +483,11 @@ Query: |---|---|---| |dateStart|The date to start looking for alert events in the event log. Either an ISO date string, or a duration string indicating time since now.|string| -### `POST /api/alerts/alert/{id}/_update_api_key`: Update alert API key +### `POST /internal/alerting/rule/{id}/_update_api_key`: Update rule API key |Property|Description|Type| |---|---|---| -|id|The id of the alert you're trying to update the API key for. System will use user in request context to generate an API key for.|string| +|id|The id of the rule you're trying to update the API key for. System will use user in request context to generate an API key for.|string| ## Alert instance factory diff --git a/x-pack/plugins/alerting/common/index.ts b/x-pack/plugins/alerting/common/index.ts index ff1540090a357e..3530abb7384eac 100644 --- a/x-pack/plugins/alerting/common/index.ts +++ b/x-pack/plugins/alerting/common/index.ts @@ -24,5 +24,7 @@ export interface AlertingFrameworkHealth { alertingFrameworkHeath: AlertsHealth; } -export const BASE_ALERT_API_PATH = '/api/alerts'; +export const LEGACY_BASE_ALERT_API_PATH = '/api/alerts'; +export const BASE_ALERTING_API_PATH = '/api/alerting'; +export const INTERNAL_BASE_ALERTING_API_PATH = '/internal/alerting'; export const ALERTS_FEATURE_ID = 'alerts'; diff --git a/x-pack/plugins/alerting/public/alert_api.ts b/x-pack/plugins/alerting/public/alert_api.ts index 6eb2e29a7e8e57..d1213c80b95be1 100644 --- a/x-pack/plugins/alerting/public/alert_api.ts +++ b/x-pack/plugins/alerting/public/alert_api.ts @@ -7,11 +7,11 @@ import { HttpSetup } from 'kibana/public'; import { i18n } from '@kbn/i18n'; -import { BASE_ALERT_API_PATH } from '../common'; +import { LEGACY_BASE_ALERT_API_PATH } from '../common'; import type { Alert, AlertType } from '../common'; export async function loadAlertTypes({ http }: { http: HttpSetup }): Promise { - return await http.get(`${BASE_ALERT_API_PATH}/list_alert_types`); + return await http.get(`${LEGACY_BASE_ALERT_API_PATH}/list_alert_types`); } export async function loadAlertType({ @@ -22,7 +22,7 @@ export async function loadAlertType({ id: AlertType['id']; }): Promise { const maybeAlertType = ((await http.get( - `${BASE_ALERT_API_PATH}/list_alert_types` + `${LEGACY_BASE_ALERT_API_PATH}/list_alert_types` )) as AlertType[]).find((type) => type.id === id); if (!maybeAlertType) { throw new Error( @@ -44,5 +44,5 @@ export async function loadAlert({ http: HttpSetup; alertId: string; }): Promise { - return await http.get(`${BASE_ALERT_API_PATH}/alert/${alertId}`); + return await http.get(`${LEGACY_BASE_ALERT_API_PATH}/alert/${alertId}`); } diff --git a/x-pack/plugins/alerting/server/alerts_client/alerts_client.ts b/x-pack/plugins/alerting/server/alerts_client/alerts_client.ts index 1b29191d9063e0..e316ecd3c6fec6 100644 --- a/x-pack/plugins/alerting/server/alerts_client/alerts_client.ts +++ b/x-pack/plugins/alerting/server/alerts_client/alerts_client.ts @@ -125,7 +125,7 @@ interface IndexType { [key: string]: unknown; } -interface AggregateResult { +export interface AggregateResult { alertExecutionStatus: { [status: string]: number }; } @@ -157,7 +157,7 @@ export interface CreateOptions { }; } -interface UpdateOptions { +export interface UpdateOptions { id: string; data: { name: string; @@ -170,7 +170,7 @@ interface UpdateOptions { }; } -interface GetAlertInstanceSummaryParams { +export interface GetAlertInstanceSummaryParams { id: string; dateStart?: string; } @@ -229,7 +229,7 @@ export class AlertsClient { public async create({ data, options, - }: CreateOptions): Promise> { + }: CreateOptions): Promise> { const id = options?.id || SavedObjectsUtils.generateId(); try { diff --git a/x-pack/plugins/alerting/server/lib/errors/index.ts b/x-pack/plugins/alerting/server/lib/errors/index.ts new file mode 100644 index 00000000000000..9c6d233f15d3d0 --- /dev/null +++ b/x-pack/plugins/alerting/server/lib/errors/index.ts @@ -0,0 +1,17 @@ +/* + * 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 { ErrorThatHandlesItsOwnResponse } from './types'; + +export function isErrorThatHandlesItsOwnResponse( + e: ErrorThatHandlesItsOwnResponse +): e is ErrorThatHandlesItsOwnResponse { + return typeof (e as ErrorThatHandlesItsOwnResponse).sendResponse === 'function'; +} + +export { ErrorThatHandlesItsOwnResponse }; +export { AlertTypeDisabledError, AlertTypeDisabledReason } from './alert_type_disabled'; diff --git a/x-pack/plugins/alerting/server/lib/index.ts b/x-pack/plugins/alerting/server/lib/index.ts index 3fd0ac403f8f8a..493b0041069339 100644 --- a/x-pack/plugins/alerting/server/lib/index.ts +++ b/x-pack/plugins/alerting/server/lib/index.ts @@ -6,10 +6,17 @@ */ export { parseDuration, validateDurationSchema } from '../../common/parse_duration'; -export { LicenseState } from './license_state'; +export { ILicenseState, LicenseState } from './license_state'; export { validateAlertTypeParams } from './validate_alert_type_params'; export { getAlertNotifyWhenType } from './get_alert_notify_when_type'; +export { verifyApiAccess } from './license_api_access'; export { ErrorWithReason, getReasonFromError, isErrorWithReason } from './error_with_reason'; +export { + AlertTypeDisabledError, + AlertTypeDisabledReason, + ErrorThatHandlesItsOwnResponse, + isErrorThatHandlesItsOwnResponse, +} from './errors'; export { executionStatusFromState, executionStatusFromError, diff --git a/x-pack/plugins/alerting/server/plugin.ts b/x-pack/plugins/alerting/server/plugin.ts index ff36ebcd84ba52..787d3cc548ba13 100644 --- a/x-pack/plugins/alerting/server/plugin.ts +++ b/x-pack/plugins/alerting/server/plugin.ts @@ -37,25 +37,7 @@ import { } from '../../../../src/core/server'; import type { AlertingRequestHandlerContext } from './types'; -import { - aggregateAlertRoute, - createAlertRoute, - deleteAlertRoute, - findAlertRoute, - getAlertRoute, - getAlertStateRoute, - getAlertInstanceSummaryRoute, - listAlertTypesRoute, - updateAlertRoute, - enableAlertRoute, - disableAlertRoute, - updateApiKeyRoute, - muteAllAlertRoute, - unmuteAllAlertRoute, - muteAlertInstanceRoute, - unmuteAlertInstanceRoute, - healthRoute, -} from './routes'; +import { defineRoutes } from './routes'; import { LICENSE_TYPE, LicensingPluginSetup, LicensingPluginStart } from '../../licensing/server'; import { PluginSetupContract as ActionsPluginSetupContract, @@ -266,23 +248,7 @@ export class AlertingPlugin { // Routes const router = core.http.createRouter(); // Register routes - aggregateAlertRoute(router, this.licenseState); - createAlertRoute(router, this.licenseState); - deleteAlertRoute(router, this.licenseState); - findAlertRoute(router, this.licenseState); - getAlertRoute(router, this.licenseState); - getAlertStateRoute(router, this.licenseState); - getAlertInstanceSummaryRoute(router, this.licenseState); - listAlertTypesRoute(router, this.licenseState); - updateAlertRoute(router, this.licenseState); - enableAlertRoute(router, this.licenseState); - disableAlertRoute(router, this.licenseState); - updateApiKeyRoute(router, this.licenseState); - muteAllAlertRoute(router, this.licenseState); - unmuteAllAlertRoute(router, this.licenseState); - muteAlertInstanceRoute(router, this.licenseState); - unmuteAlertInstanceRoute(router, this.licenseState); - healthRoute(router, this.licenseState, plugins.encryptedSavedObjects); + defineRoutes(router, this.licenseState, plugins.encryptedSavedObjects); return { registerType< diff --git a/x-pack/plugins/alerting/server/routes/aggregate_rules.test.ts b/x-pack/plugins/alerting/server/routes/aggregate_rules.test.ts new file mode 100644 index 00000000000000..26c06eae33d0a2 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/aggregate_rules.test.ts @@ -0,0 +1,150 @@ +/* + * 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 { aggregateRulesRoute } from './aggregate_rules'; +import { httpServiceMock } from 'src/core/server/mocks'; +import { licenseStateMock } from '../lib/license_state.mock'; +import { verifyApiAccess } from '../lib/license_api_access'; +import { mockHandlerArguments } from './_mock_handler_arguments'; +import { alertsClientMock } from '../alerts_client.mock'; + +const alertsClient = alertsClientMock.create(); + +jest.mock('../lib/license_api_access.ts', () => ({ + verifyApiAccess: jest.fn(), +})); + +beforeEach(() => { + jest.resetAllMocks(); +}); + +describe('aggregateRulesRoute', () => { + it('aggregate rules with proper parameters', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + aggregateRulesRoute(router, licenseState); + + const [config, handler] = router.get.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/internal/alerting/rules/_aggregate"`); + + const aggregateResult = { + alertExecutionStatus: { + ok: 15, + error: 2, + active: 23, + pending: 1, + unknown: 0, + }, + }; + alertsClient.aggregate.mockResolvedValueOnce(aggregateResult); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + query: { + default_search_operator: 'AND', + }, + }, + ['ok'] + ); + + expect(await handler(context, req, res)).toMatchInlineSnapshot(` + Object { + "body": Object { + "rule_execution_status": Object { + "active": 23, + "error": 2, + "ok": 15, + "pending": 1, + "unknown": 0, + }, + }, + } + `); + + expect(alertsClient.aggregate).toHaveBeenCalledTimes(1); + expect(alertsClient.aggregate.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "options": Object { + "defaultSearchOperator": "AND", + }, + }, + ] + `); + + expect(res.ok).toHaveBeenCalledWith({ + body: { + rule_execution_status: { + ok: 15, + error: 2, + active: 23, + pending: 1, + unknown: 0, + }, + }, + }); + }); + + it('ensures the license allows aggregating rules', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + aggregateRulesRoute(router, licenseState); + + const [, handler] = router.get.mock.calls[0]; + + alertsClient.aggregate.mockResolvedValueOnce({ + alertExecutionStatus: { + ok: 15, + error: 2, + active: 23, + pending: 1, + unknown: 0, + }, + }); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + query: { + default_search_operator: 'OR', + }, + } + ); + + await handler(context, req, res); + + expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); + }); + + it('ensures the license check prevents aggregating rules', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + (verifyApiAccess as jest.Mock).mockImplementation(() => { + throw new Error('OMG'); + }); + + aggregateRulesRoute(router, licenseState); + + const [, handler] = router.get.mock.calls[0]; + + const [context, req, res] = mockHandlerArguments( + {}, + { + query: {}, + }, + ['ok'] + ); + expect(handler(context, req, res)).rejects.toMatchInlineSnapshot(`[Error: OMG]`); + + expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); + }); +}); diff --git a/x-pack/plugins/alerting/server/routes/aggregate_rules.ts b/x-pack/plugins/alerting/server/routes/aggregate_rules.ts new file mode 100644 index 00000000000000..ecebd7851af6bc --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/aggregate_rules.ts @@ -0,0 +1,79 @@ +/* + * 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 { IRouter } from 'kibana/server'; +import { schema } from '@kbn/config-schema'; +import { ILicenseState } from '../lib'; +import { AggregateResult, AggregateOptions } from '../alerts_client'; +import { RewriteResponseCase, RewriteRequestCase, verifyAccessAndContext } from './lib'; +import { AlertingRequestHandlerContext, INTERNAL_BASE_ALERTING_API_PATH } from '../types'; + +// config definition +const querySchema = schema.object({ + search: schema.maybe(schema.string()), + default_search_operator: schema.oneOf([schema.literal('OR'), schema.literal('AND')], { + defaultValue: 'OR', + }), + search_fields: schema.maybe(schema.arrayOf(schema.string())), + has_reference: schema.maybe( + // use nullable as maybe is currently broken + // in config-schema + schema.nullable( + schema.object({ + type: schema.string(), + id: schema.string(), + }) + ) + ), + filter: schema.maybe(schema.string()), +}); + +const rewriteQueryReq: RewriteRequestCase = ({ + default_search_operator: defaultSearchOperator, + has_reference: hasReference, + search_fields: searchFields, + ...rest +}) => ({ + ...rest, + defaultSearchOperator, + ...(hasReference ? { hasReference } : {}), + ...(searchFields ? { searchFields } : {}), +}); +const rewriteBodyRes: RewriteResponseCase = ({ + alertExecutionStatus, + ...rest +}) => ({ + ...rest, + rule_execution_status: alertExecutionStatus, +}); + +export const aggregateRulesRoute = ( + router: IRouter, + licenseState: ILicenseState +) => { + router.get( + { + path: `${INTERNAL_BASE_ALERTING_API_PATH}/rules/_aggregate`, + validate: { + query: querySchema, + }, + }, + router.handleLegacyErrors( + verifyAccessAndContext(licenseState, async function (context, req, res) { + const alertsClient = context.alerting.getAlertsClient(); + const options = rewriteQueryReq({ + ...req.query, + has_reference: req.query.has_reference || undefined, + }); + const aggregateResult = await alertsClient.aggregate({ options }); + return res.ok({ + body: rewriteBodyRes(aggregateResult), + }); + }) + ) + ); +}; diff --git a/x-pack/plugins/alerting/server/routes/create_rule.test.ts b/x-pack/plugins/alerting/server/routes/create_rule.test.ts new file mode 100644 index 00000000000000..5dbc5014ef6ba1 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/create_rule.test.ts @@ -0,0 +1,298 @@ +/* + * 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 { pick } from 'lodash'; +import { createRuleRoute } from './create_rule'; +import { httpServiceMock } from 'src/core/server/mocks'; +import { licenseStateMock } from '../lib/license_state.mock'; +import { verifyApiAccess } from '../lib/license_api_access'; +import { mockHandlerArguments } from './_mock_handler_arguments'; +import { CreateOptions } from '../alerts_client'; +import { alertsClientMock } from '../alerts_client.mock'; +import { AlertTypeDisabledError } from '../lib'; +import { AsApiContract } from './lib'; +import { SanitizedAlert } from '../types'; + +const alertsClient = alertsClientMock.create(); + +jest.mock('../lib/license_api_access.ts', () => ({ + verifyApiAccess: jest.fn(), +})); + +beforeEach(() => { + jest.resetAllMocks(); +}); + +describe('createRuleRoute', () => { + const createdAt = new Date(); + const updatedAt = new Date(); + + const mockedAlert: SanitizedAlert<{ bar: boolean }> = { + alertTypeId: '1', + consumer: 'bar', + name: 'abc', + schedule: { interval: '10s' }, + tags: ['foo'], + params: { + bar: true, + }, + throttle: '30s', + actions: [ + { + actionTypeId: 'test', + group: 'default', + id: '2', + params: { + foo: true, + }, + }, + ], + enabled: true, + muteAll: false, + createdBy: '', + updatedBy: '', + apiKeyOwner: '', + mutedInstanceIds: [], + notifyWhen: 'onActionGroupChange', + createdAt, + updatedAt, + id: '123', + executionStatus: { + status: 'unknown', + lastExecutionDate: new Date('2020-08-20T19:23:38Z'), + }, + }; + + const ruleToCreate: AsApiContract['data']> = { + ...pick(mockedAlert, 'consumer', 'name', 'schedule', 'tags', 'params', 'throttle', 'enabled'), + rule_type_id: mockedAlert.alertTypeId, + notify_when: mockedAlert.notifyWhen, + actions: [ + { + group: mockedAlert.actions[0].group, + id: mockedAlert.actions[0].id, + params: mockedAlert.actions[0].params, + }, + ], + }; + + const createResult: AsApiContract> = { + ...ruleToCreate, + mute_all: mockedAlert.muteAll, + created_by: mockedAlert.createdBy, + updated_by: mockedAlert.updatedBy, + api_key_owner: mockedAlert.apiKeyOwner, + muted_alert_ids: mockedAlert.mutedInstanceIds, + created_at: mockedAlert.createdAt, + updated_at: mockedAlert.updatedAt, + id: mockedAlert.id, + execution_status: { + status: mockedAlert.executionStatus.status, + last_execution_date: mockedAlert.executionStatus.lastExecutionDate, + }, + actions: [ + { + ...ruleToCreate.actions[0], + connector_type_id: 'test', + }, + ], + }; + + it('creates a rule with proper parameters', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + createRuleRoute(router, licenseState); + + const [config, handler] = router.post.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/api/alerting/rule/{id?}"`); + + alertsClient.create.mockResolvedValueOnce(mockedAlert); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + body: ruleToCreate, + }, + ['ok'] + ); + + expect(await handler(context, req, res)).toEqual({ body: createResult }); + + expect(alertsClient.create).toHaveBeenCalledTimes(1); + expect(alertsClient.create.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "data": Object { + "actions": Array [ + Object { + "group": "default", + "id": "2", + "params": Object { + "foo": true, + }, + }, + ], + "alertTypeId": "1", + "consumer": "bar", + "enabled": true, + "name": "abc", + "notifyWhen": "onActionGroupChange", + "params": Object { + "bar": true, + }, + "schedule": Object { + "interval": "10s", + }, + "tags": Array [ + "foo", + ], + "throttle": "30s", + }, + "options": Object { + "id": undefined, + }, + }, + ] + `); + + expect(res.ok).toHaveBeenCalledWith({ + body: createResult, + }); + }); + + it('allows providing a custom id', async () => { + const expectedResult = { + ...createResult, + id: 'custom-id', + }; + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + createRuleRoute(router, licenseState); + + const [config, handler] = router.post.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/api/alerting/rule/{id?}"`); + + alertsClient.create.mockResolvedValueOnce({ + ...mockedAlert, + id: 'custom-id', + }); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + params: { id: 'custom-id' }, + body: ruleToCreate, + }, + ['ok'] + ); + + expect(await handler(context, req, res)).toEqual({ body: expectedResult }); + + expect(alertsClient.create).toHaveBeenCalledTimes(1); + expect(alertsClient.create.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "data": Object { + "actions": Array [ + Object { + "group": "default", + "id": "2", + "params": Object { + "foo": true, + }, + }, + ], + "alertTypeId": "1", + "consumer": "bar", + "enabled": true, + "name": "abc", + "notifyWhen": "onActionGroupChange", + "params": Object { + "bar": true, + }, + "schedule": Object { + "interval": "10s", + }, + "tags": Array [ + "foo", + ], + "throttle": "30s", + }, + "options": Object { + "id": "custom-id", + }, + }, + ] + `); + + expect(res.ok).toHaveBeenCalledWith({ + body: expectedResult, + }); + }); + + it('ensures the license allows creating rules', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + createRuleRoute(router, licenseState); + + const [, handler] = router.post.mock.calls[0]; + + alertsClient.create.mockResolvedValueOnce(mockedAlert); + + const [context, req, res] = mockHandlerArguments({ alertsClient }, { body: ruleToCreate }); + + await handler(context, req, res); + + expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); + }); + + it('ensures the license check prevents creating rules', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + (verifyApiAccess as jest.Mock).mockImplementation(() => { + throw new Error('OMG'); + }); + + createRuleRoute(router, licenseState); + + const [, handler] = router.post.mock.calls[0]; + + alertsClient.create.mockResolvedValueOnce(mockedAlert); + + const [context, req, res] = mockHandlerArguments({ alertsClient }, {}); + + expect(handler(context, req, res)).rejects.toMatchInlineSnapshot(`[Error: OMG]`); + + expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); + }); + + it('ensures the rule type gets validated for the license', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + createRuleRoute(router, licenseState); + + const [, handler] = router.post.mock.calls[0]; + + alertsClient.create.mockRejectedValue(new AlertTypeDisabledError('Fail', 'license_invalid')); + + const [context, req, res] = mockHandlerArguments({ alertsClient }, { body: ruleToCreate }, [ + 'ok', + 'forbidden', + ]); + + await handler(context, req, res); + + expect(res.forbidden).toHaveBeenCalledWith({ body: { message: 'Fail' } }); + }); +}); diff --git a/x-pack/plugins/alerting/server/routes/create_rule.ts b/x-pack/plugins/alerting/server/routes/create_rule.ts new file mode 100644 index 00000000000000..4e31db970ccc63 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/create_rule.ts @@ -0,0 +1,141 @@ +/* + * 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 { IRouter } from 'kibana/server'; +import { schema } from '@kbn/config-schema'; +import { validateDurationSchema, ILicenseState, AlertTypeDisabledError } from '../lib'; +import { CreateOptions } from '../alerts_client'; +import { + RewriteRequestCase, + RewriteResponseCase, + handleDisabledApiKeysError, + verifyAccessAndContext, +} from './lib'; +import { + SanitizedAlert, + validateNotifyWhenType, + AlertTypeParams, + AlertingRequestHandlerContext, + BASE_ALERTING_API_PATH, + AlertNotifyWhenType, +} from '../types'; + +export const bodySchema = schema.object({ + name: schema.string(), + rule_type_id: schema.string(), + enabled: schema.boolean({ defaultValue: true }), + consumer: schema.string(), + tags: schema.arrayOf(schema.string(), { defaultValue: [] }), + throttle: schema.nullable(schema.string({ validate: validateDurationSchema })), + params: schema.recordOf(schema.string(), schema.any(), { defaultValue: {} }), + schedule: schema.object({ + interval: schema.string({ validate: validateDurationSchema }), + }), + actions: schema.arrayOf( + schema.object({ + group: schema.string(), + id: schema.string(), + params: schema.recordOf(schema.string(), schema.any(), { defaultValue: {} }), + }), + { defaultValue: [] } + ), + notify_when: schema.string({ validate: validateNotifyWhenType }), +}); + +const rewriteBodyReq: RewriteRequestCase['data']> = ({ + rule_type_id: alertTypeId, + notify_when: notifyWhen, + ...rest +}) => ({ + ...rest, + alertTypeId, + notifyWhen, +}); +const rewriteBodyRes: RewriteResponseCase> = ({ + actions, + alertTypeId, + scheduledTaskId, + createdBy, + updatedBy, + createdAt, + updatedAt, + apiKeyOwner, + notifyWhen, + muteAll, + mutedInstanceIds, + executionStatus: { lastExecutionDate, ...executionStatus }, + ...rest +}) => ({ + ...rest, + rule_type_id: alertTypeId, + scheduled_task_id: scheduledTaskId, + created_by: createdBy, + updated_by: updatedBy, + created_at: createdAt, + updated_at: updatedAt, + api_key_owner: apiKeyOwner, + notify_when: notifyWhen, + mute_all: muteAll, + muted_alert_ids: mutedInstanceIds, + execution_status: { + ...executionStatus, + last_execution_date: lastExecutionDate, + }, + actions: actions.map(({ group, id, actionTypeId, params }) => ({ + group, + id, + params, + connector_type_id: actionTypeId, + })), +}); + +export const createRuleRoute = ( + router: IRouter, + licenseState: ILicenseState +) => { + router.post( + { + path: `${BASE_ALERTING_API_PATH}/rule/{id?}`, + validate: { + params: schema.maybe( + schema.object({ + id: schema.maybe(schema.string()), + }) + ), + body: bodySchema, + }, + }, + handleDisabledApiKeysError( + router.handleLegacyErrors( + verifyAccessAndContext(licenseState, async function (context, req, res) { + const alertsClient = context.alerting.getAlertsClient(); + const rule = req.body; + const params = req.params; + try { + const createdRule: SanitizedAlert = await alertsClient.create( + { + data: rewriteBodyReq({ + ...rule, + notify_when: rule.notify_when as AlertNotifyWhenType, + }), + options: { id: params?.id }, + } + ); + return res.ok({ + body: rewriteBodyRes(createdRule), + }); + } catch (e) { + if (e instanceof AlertTypeDisabledError) { + return e.sendResponse(res); + } + throw e; + } + }) + ) + ) + ); +}; diff --git a/x-pack/plugins/alerting/server/routes/delete_rule.test.ts b/x-pack/plugins/alerting/server/routes/delete_rule.test.ts new file mode 100644 index 00000000000000..16d344548fc25f --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/delete_rule.test.ts @@ -0,0 +1,109 @@ +/* + * 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 { deleteRuleRoute } from './delete_rule'; +import { httpServiceMock } from 'src/core/server/mocks'; +import { licenseStateMock } from '../lib/license_state.mock'; +import { verifyApiAccess } from '../lib/license_api_access'; +import { mockHandlerArguments } from './_mock_handler_arguments'; +import { alertsClientMock } from '../alerts_client.mock'; + +const alertsClient = alertsClientMock.create(); + +jest.mock('../lib/license_api_access.ts', () => ({ + verifyApiAccess: jest.fn(), +})); + +beforeEach(() => { + jest.resetAllMocks(); +}); + +describe('deleteRuleRoute', () => { + it('deletes an alert with proper parameters', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + deleteRuleRoute(router, licenseState); + + const [config, handler] = router.delete.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/api/alerting/rule/{id}"`); + + alertsClient.delete.mockResolvedValueOnce({}); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + params: { + id: '1', + }, + }, + ['noContent'] + ); + + expect(await handler(context, req, res)).toEqual(undefined); + + expect(alertsClient.delete).toHaveBeenCalledTimes(1); + expect(alertsClient.delete.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "id": "1", + }, + ] + `); + + expect(res.noContent).toHaveBeenCalled(); + }); + + it('ensures the license allows deleting rules', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + deleteRuleRoute(router, licenseState); + + const [, handler] = router.delete.mock.calls[0]; + + alertsClient.delete.mockResolvedValueOnce({}); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + params: { id: '1' }, + } + ); + + await handler(context, req, res); + + expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); + }); + + it('ensures the license check prevents deleting rules', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + (verifyApiAccess as jest.Mock).mockImplementation(() => { + throw new Error('OMG'); + }); + + deleteRuleRoute(router, licenseState); + + const [, handler] = router.delete.mock.calls[0]; + + alertsClient.delete.mockResolvedValueOnce({}); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + id: '1', + } + ); + + expect(handler(context, req, res)).rejects.toMatchInlineSnapshot(`[Error: OMG]`); + + expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); + }); +}); diff --git a/x-pack/plugins/alerting/server/routes/delete_rule.ts b/x-pack/plugins/alerting/server/routes/delete_rule.ts new file mode 100644 index 00000000000000..724eb5352ed238 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/delete_rule.ts @@ -0,0 +1,38 @@ +/* + * 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 { IRouter } from 'kibana/server'; +import { schema } from '@kbn/config-schema'; +import { ILicenseState } from '../lib'; +import { verifyAccessAndContext } from './lib'; +import { AlertingRequestHandlerContext, BASE_ALERTING_API_PATH } from '../types'; + +const paramSchema = schema.object({ + id: schema.string(), +}); + +export const deleteRuleRoute = ( + router: IRouter, + licenseState: ILicenseState +) => { + router.delete( + { + path: `${BASE_ALERTING_API_PATH}/rule/{id}`, + validate: { + params: paramSchema, + }, + }, + router.handleLegacyErrors( + verifyAccessAndContext(licenseState, async function (context, req, res) { + const alertsClient = context.alerting.getAlertsClient(); + const { id } = req.params; + await alertsClient.delete({ id }); + return res.noContent(); + }) + ) + ); +}; diff --git a/x-pack/plugins/alerting/server/routes/disable_rule.test.ts b/x-pack/plugins/alerting/server/routes/disable_rule.test.ts new file mode 100644 index 00000000000000..a77a8443a97fb1 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/disable_rule.test.ts @@ -0,0 +1,81 @@ +/* + * 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 { disableRuleRoute } from './disable_rule'; +import { httpServiceMock } from 'src/core/server/mocks'; +import { licenseStateMock } from '../lib/license_state.mock'; +import { mockHandlerArguments } from './_mock_handler_arguments'; +import { alertsClientMock } from '../alerts_client.mock'; +import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; + +const alertsClient = alertsClientMock.create(); + +jest.mock('../lib/license_api_access.ts', () => ({ + verifyApiAccess: jest.fn(), +})); + +beforeEach(() => { + jest.resetAllMocks(); +}); + +describe('disableRuleRoute', () => { + it('disables a rule', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + disableRuleRoute(router, licenseState); + + const [config, handler] = router.post.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/api/alerting/rule/{id}/_disable"`); + + alertsClient.disable.mockResolvedValueOnce(); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + params: { + id: '1', + }, + }, + ['noContent'] + ); + + expect(await handler(context, req, res)).toEqual(undefined); + + expect(alertsClient.disable).toHaveBeenCalledTimes(1); + expect(alertsClient.disable.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "id": "1", + }, + ] + `); + + expect(res.noContent).toHaveBeenCalled(); + }); + + it('ensures the rule type gets validated for the license', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + disableRuleRoute(router, licenseState); + + const [, handler] = router.post.mock.calls[0]; + + alertsClient.disable.mockRejectedValue(new AlertTypeDisabledError('Fail', 'license_invalid')); + + const [context, req, res] = mockHandlerArguments({ alertsClient }, { params: {}, body: {} }, [ + 'ok', + 'forbidden', + ]); + + await handler(context, req, res); + + expect(res.forbidden).toHaveBeenCalledWith({ body: { message: 'Fail' } }); + }); +}); diff --git a/x-pack/plugins/alerting/server/routes/disable_rule.ts b/x-pack/plugins/alerting/server/routes/disable_rule.ts new file mode 100644 index 00000000000000..2a2f0f4aa25fc0 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/disable_rule.ts @@ -0,0 +1,45 @@ +/* + * 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 { IRouter } from 'kibana/server'; +import { schema } from '@kbn/config-schema'; +import { ILicenseState, AlertTypeDisabledError } from '../lib'; +import { verifyAccessAndContext } from './lib'; +import { AlertingRequestHandlerContext, BASE_ALERTING_API_PATH } from '../types'; + +const paramSchema = schema.object({ + id: schema.string(), +}); + +export const disableRuleRoute = ( + router: IRouter, + licenseState: ILicenseState +) => { + router.post( + { + path: `${BASE_ALERTING_API_PATH}/rule/{id}/_disable`, + validate: { + params: paramSchema, + }, + }, + router.handleLegacyErrors( + verifyAccessAndContext(licenseState, async function (context, req, res) { + const alertsClient = context.alerting.getAlertsClient(); + const { id } = req.params; + try { + await alertsClient.disable({ id }); + return res.noContent(); + } catch (e) { + if (e instanceof AlertTypeDisabledError) { + return e.sendResponse(res); + } + throw e; + } + }) + ) + ); +}; diff --git a/x-pack/plugins/alerting/server/routes/enable_rule.test.ts b/x-pack/plugins/alerting/server/routes/enable_rule.test.ts new file mode 100644 index 00000000000000..71889d153ce5fe --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/enable_rule.test.ts @@ -0,0 +1,81 @@ +/* + * 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 { enableRuleRoute } from './enable_rule'; +import { httpServiceMock } from 'src/core/server/mocks'; +import { licenseStateMock } from '../lib/license_state.mock'; +import { mockHandlerArguments } from './_mock_handler_arguments'; +import { alertsClientMock } from '../alerts_client.mock'; +import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; + +const alertsClient = alertsClientMock.create(); + +jest.mock('../lib/license_api_access.ts', () => ({ + verifyApiAccess: jest.fn(), +})); + +beforeEach(() => { + jest.resetAllMocks(); +}); + +describe('enableRuleRoute', () => { + it('enables a rule', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + enableRuleRoute(router, licenseState); + + const [config, handler] = router.post.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/api/alerting/rule/{id}/_enable"`); + + alertsClient.enable.mockResolvedValueOnce(); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + params: { + id: '1', + }, + }, + ['noContent'] + ); + + expect(await handler(context, req, res)).toEqual(undefined); + + expect(alertsClient.enable).toHaveBeenCalledTimes(1); + expect(alertsClient.enable.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "id": "1", + }, + ] + `); + + expect(res.noContent).toHaveBeenCalled(); + }); + + it('ensures the rule type gets validated for the license', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + enableRuleRoute(router, licenseState); + + const [, handler] = router.post.mock.calls[0]; + + alertsClient.enable.mockRejectedValue(new AlertTypeDisabledError('Fail', 'license_invalid')); + + const [context, req, res] = mockHandlerArguments({ alertsClient }, { params: {}, body: {} }, [ + 'ok', + 'forbidden', + ]); + + await handler(context, req, res); + + expect(res.forbidden).toHaveBeenCalledWith({ body: { message: 'Fail' } }); + }); +}); diff --git a/x-pack/plugins/alerting/server/routes/enable_rule.ts b/x-pack/plugins/alerting/server/routes/enable_rule.ts new file mode 100644 index 00000000000000..9c7526630d0a3f --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/enable_rule.ts @@ -0,0 +1,45 @@ +/* + * 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 { IRouter } from 'kibana/server'; +import { schema } from '@kbn/config-schema'; +import { ILicenseState, AlertTypeDisabledError } from '../lib'; +import { verifyAccessAndContext } from './lib'; +import { AlertingRequestHandlerContext, BASE_ALERTING_API_PATH } from '../types'; + +const paramSchema = schema.object({ + id: schema.string(), +}); + +export const enableRuleRoute = ( + router: IRouter, + licenseState: ILicenseState +) => { + router.post( + { + path: `${BASE_ALERTING_API_PATH}/rule/{id}/_enable`, + validate: { + params: paramSchema, + }, + }, + router.handleLegacyErrors( + verifyAccessAndContext(licenseState, async function (context, req, res) { + const alertsClient = context.alerting.getAlertsClient(); + const { id } = req.params; + try { + await alertsClient.enable({ id }); + return res.noContent(); + } catch (e) { + if (e instanceof AlertTypeDisabledError) { + return e.sendResponse(res); + } + throw e; + } + }) + ) + ); +}; diff --git a/x-pack/plugins/alerting/server/routes/find_rules.test.ts b/x-pack/plugins/alerting/server/routes/find_rules.test.ts new file mode 100644 index 00000000000000..98bb3c77daecc2 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/find_rules.test.ts @@ -0,0 +1,148 @@ +/* + * 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 { findRulesRoute } from './find_rules'; +import { httpServiceMock } from 'src/core/server/mocks'; +import { licenseStateMock } from '../lib/license_state.mock'; +import { verifyApiAccess } from '../lib/license_api_access'; +import { mockHandlerArguments } from './_mock_handler_arguments'; +import { alertsClientMock } from '../alerts_client.mock'; + +const alertsClient = alertsClientMock.create(); + +jest.mock('../lib/license_api_access.ts', () => ({ + verifyApiAccess: jest.fn(), +})); + +beforeEach(() => { + jest.resetAllMocks(); +}); + +describe('findRulesRoute', () => { + it('finds rules with proper parameters', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + findRulesRoute(router, licenseState); + + const [config, handler] = router.get.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/api/alerting/rules/_find"`); + + const findResult = { + page: 1, + perPage: 1, + total: 0, + data: [], + }; + alertsClient.find.mockResolvedValueOnce(findResult); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + query: { + per_page: 1, + page: 1, + default_search_operator: 'OR', + }, + }, + ['ok'] + ); + + expect(await handler(context, req, res)).toMatchInlineSnapshot(` + Object { + "body": Object { + "data": Array [], + "page": 1, + "per_page": 1, + "total": 0, + }, + } + `); + + expect(alertsClient.find).toHaveBeenCalledTimes(1); + expect(alertsClient.find.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "options": Object { + "defaultSearchOperator": "OR", + "page": 1, + "perPage": 1, + }, + }, + ] + `); + + expect(res.ok).toHaveBeenCalledWith({ + body: { + page: 1, + per_page: 1, + total: 0, + data: [], + }, + }); + }); + + it('ensures the license allows finding rules', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + findRulesRoute(router, licenseState); + + const [, handler] = router.get.mock.calls[0]; + + alertsClient.find.mockResolvedValueOnce({ + page: 1, + perPage: 1, + total: 0, + data: [], + }); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + query: { + per_page: 1, + page: 1, + default_search_operator: 'OR', + }, + } + ); + + await handler(context, req, res); + + expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); + }); + + it('ensures the license check prevents finding rules', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + (verifyApiAccess as jest.Mock).mockImplementation(() => { + throw new Error('OMG'); + }); + + findRulesRoute(router, licenseState); + + const [, handler] = router.get.mock.calls[0]; + + const [context, req, res] = mockHandlerArguments( + {}, + { + query: { + per_page: 1, + page: 1, + default_search_operator: 'OR', + }, + }, + ['ok'] + ); + expect(handler(context, req, res)).rejects.toMatchInlineSnapshot(`[Error: OMG]`); + + expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); + }); +}); diff --git a/x-pack/plugins/alerting/server/routes/find_rules.ts b/x-pack/plugins/alerting/server/routes/find_rules.ts new file mode 100644 index 00000000000000..06b7960b67297f --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/find_rules.ts @@ -0,0 +1,143 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { omit } from 'lodash'; +import { IRouter } from 'kibana/server'; +import { schema } from '@kbn/config-schema'; +import { ILicenseState } from '../lib'; +import { FindOptions, FindResult } from '../alerts_client'; +import { RewriteRequestCase, RewriteResponseCase, verifyAccessAndContext } from './lib'; +import { AlertTypeParams, AlertingRequestHandlerContext, BASE_ALERTING_API_PATH } from '../types'; + +// query definition +const querySchema = schema.object({ + per_page: schema.number({ defaultValue: 10, min: 0 }), + page: schema.number({ defaultValue: 1, min: 1 }), + search: schema.maybe(schema.string()), + default_search_operator: schema.oneOf([schema.literal('OR'), schema.literal('AND')], { + defaultValue: 'OR', + }), + search_fields: schema.maybe(schema.oneOf([schema.arrayOf(schema.string()), schema.string()])), + sort_field: schema.maybe(schema.string()), + sort_order: schema.maybe(schema.oneOf([schema.literal('asc'), schema.literal('desc')])), + has_reference: schema.maybe( + // use nullable as maybe is currently broken + // in config-schema + schema.nullable( + schema.object({ + type: schema.string(), + id: schema.string(), + }) + ) + ), + fields: schema.maybe(schema.arrayOf(schema.string())), + filter: schema.maybe(schema.string()), +}); + +const rewriteQueryReq: RewriteRequestCase = ({ + default_search_operator: defaultSearchOperator, + has_reference: hasReference, + search_fields: searchFields, + per_page: perPage, + sort_field: sortField, + sort_order: sortOrder, + ...rest +}) => ({ + ...rest, + defaultSearchOperator, + perPage, + ...(sortField ? { sortField } : {}), + ...(sortOrder ? { sortOrder } : {}), + ...(hasReference ? { hasReference } : {}), + ...(searchFields ? { searchFields } : {}), +}); +const rewriteBodyRes: RewriteResponseCase> = ({ + perPage, + data, + ...restOfResult +}) => { + return { + ...restOfResult, + per_page: perPage, + data: data.map( + ({ + alertTypeId, + createdBy, + updatedBy, + createdAt, + updatedAt, + apiKeyOwner, + notifyWhen, + muteAll, + mutedInstanceIds, + executionStatus, + actions, + scheduledTaskId, + ...rest + }) => ({ + ...rest, + rule_type_id: alertTypeId, + created_by: createdBy, + updated_by: updatedBy, + created_at: createdAt, + updated_at: updatedAt, + api_key_owner: apiKeyOwner, + notify_when: notifyWhen, + mute_all: muteAll, + muted_alert_ids: mutedInstanceIds, + scheduled_task_id: scheduledTaskId, + execution_status: executionStatus && { + ...omit(executionStatus, 'lastExecutionDate'), + last_execution_date: executionStatus.lastExecutionDate, + }, + actions: actions.map(({ group, id, actionTypeId, params }) => ({ + group, + id, + params, + connector_type_id: actionTypeId, + })), + }) + ), + }; +}; + +export const findRulesRoute = ( + router: IRouter, + licenseState: ILicenseState +) => { + router.get( + { + path: `${BASE_ALERTING_API_PATH}/rules/_find`, + validate: { + query: querySchema, + }, + }, + router.handleLegacyErrors( + verifyAccessAndContext(licenseState, async function (context, req, res) { + const alertsClient = context.alerting.getAlertsClient(); + + const options = rewriteQueryReq({ + ...req.query, + has_reference: req.query.has_reference || undefined, + search_fields: searchFieldsAsArray(req.query.search_fields), + }); + + const findResult = await alertsClient.find({ options }); + return res.ok({ + body: rewriteBodyRes(findResult), + }); + }) + ) + ); +}; + +function searchFieldsAsArray(searchFields: string | string[] | undefined): string[] | undefined { + if (!searchFields) { + return; + } + return Array.isArray(searchFields) ? searchFields : [searchFields]; +} diff --git a/x-pack/plugins/alerting/server/routes/get_rule.test.ts b/x-pack/plugins/alerting/server/routes/get_rule.test.ts new file mode 100644 index 00000000000000..fc900797cdc89b --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/get_rule.test.ts @@ -0,0 +1,169 @@ +/* + * 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 { pick } from 'lodash'; +import { getRuleRoute } from './get_rule'; +import { httpServiceMock } from 'src/core/server/mocks'; +import { licenseStateMock } from '../lib/license_state.mock'; +import { verifyApiAccess } from '../lib/license_api_access'; +import { mockHandlerArguments } from './_mock_handler_arguments'; +import { alertsClientMock } from '../alerts_client.mock'; +import { SanitizedAlert } from '../types'; +import { AsApiContract } from './lib'; + +const alertsClient = alertsClientMock.create(); +jest.mock('../lib/license_api_access.ts', () => ({ + verifyApiAccess: jest.fn(), +})); + +beforeEach(() => { + jest.resetAllMocks(); +}); + +describe('getRuleRoute', () => { + const mockedAlert: SanitizedAlert<{ + bar: boolean; + }> = { + id: '1', + alertTypeId: '1', + schedule: { interval: '10s' }, + params: { + bar: true, + }, + createdAt: new Date(), + updatedAt: new Date(), + actions: [ + { + group: 'default', + id: '2', + actionTypeId: 'test', + params: { + foo: true, + }, + }, + ], + consumer: 'bar', + name: 'abc', + tags: ['foo'], + enabled: true, + muteAll: false, + notifyWhen: 'onActionGroupChange', + createdBy: '', + updatedBy: '', + apiKeyOwner: '', + throttle: '30s', + mutedInstanceIds: [], + executionStatus: { + status: 'unknown', + lastExecutionDate: new Date('2020-08-20T19:23:38Z'), + }, + }; + + const getResult: AsApiContract> = { + ...pick(mockedAlert, 'consumer', 'name', 'schedule', 'tags', 'params', 'throttle', 'enabled'), + rule_type_id: mockedAlert.alertTypeId, + notify_when: mockedAlert.notifyWhen, + mute_all: mockedAlert.muteAll, + created_by: mockedAlert.createdBy, + updated_by: mockedAlert.updatedBy, + api_key_owner: mockedAlert.apiKeyOwner, + muted_alert_ids: mockedAlert.mutedInstanceIds, + created_at: mockedAlert.createdAt, + updated_at: mockedAlert.updatedAt, + id: mockedAlert.id, + execution_status: { + status: mockedAlert.executionStatus.status, + last_execution_date: mockedAlert.executionStatus.lastExecutionDate, + }, + actions: [ + { + group: mockedAlert.actions[0].group, + id: mockedAlert.actions[0].id, + params: mockedAlert.actions[0].params, + connector_type_id: mockedAlert.actions[0].actionTypeId, + }, + ], + }; + + it('gets a rule with proper parameters', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + getRuleRoute(router, licenseState); + const [config, handler] = router.get.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/api/alerting/rule/{id}"`); + + alertsClient.get.mockResolvedValueOnce(mockedAlert); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + params: { id: '1' }, + }, + ['ok'] + ); + await handler(context, req, res); + + expect(alertsClient.get).toHaveBeenCalledTimes(1); + expect(alertsClient.get.mock.calls[0][0].id).toEqual('1'); + + expect(res.ok).toHaveBeenCalledWith({ + body: getResult, + }); + }); + + it('ensures the license allows getting rules', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + getRuleRoute(router, licenseState); + + const [, handler] = router.get.mock.calls[0]; + + alertsClient.get.mockResolvedValueOnce(mockedAlert); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + params: { id: '1' }, + }, + ['ok'] + ); + + await handler(context, req, res); + + expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); + }); + + it('ensures the license check prevents getting rules', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + (verifyApiAccess as jest.Mock).mockImplementation(() => { + throw new Error('OMG'); + }); + + getRuleRoute(router, licenseState); + + const [, handler] = router.get.mock.calls[0]; + + alertsClient.get.mockResolvedValueOnce(mockedAlert); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + params: { id: '1' }, + }, + ['ok'] + ); + + expect(handler(context, req, res)).rejects.toMatchInlineSnapshot(`[Error: OMG]`); + + expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); + }); +}); diff --git a/x-pack/plugins/alerting/server/routes/get_rule.ts b/x-pack/plugins/alerting/server/routes/get_rule.ts new file mode 100644 index 00000000000000..fd03f32047e749 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/get_rule.ts @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { omit } from 'lodash'; +import { schema } from '@kbn/config-schema'; +import { IRouter } from 'kibana/server'; +import { ILicenseState } from '../lib'; +import { verifyAccessAndContext, RewriteResponseCase } from './lib'; +import { + AlertTypeParams, + AlertingRequestHandlerContext, + BASE_ALERTING_API_PATH, + SanitizedAlert, +} from '../types'; + +const paramSchema = schema.object({ + id: schema.string(), +}); + +const rewriteBodyRes: RewriteResponseCase> = ({ + alertTypeId, + createdBy, + updatedBy, + createdAt, + updatedAt, + apiKeyOwner, + notifyWhen, + muteAll, + mutedInstanceIds, + executionStatus, + actions, + scheduledTaskId, + ...rest +}) => ({ + ...rest, + rule_type_id: alertTypeId, + created_by: createdBy, + updated_by: updatedBy, + created_at: createdAt, + updated_at: updatedAt, + api_key_owner: apiKeyOwner, + notify_when: notifyWhen, + mute_all: muteAll, + muted_alert_ids: mutedInstanceIds, + scheduled_task_id: scheduledTaskId, + execution_status: executionStatus && { + ...omit(executionStatus, 'lastExecutionDate'), + last_execution_date: executionStatus.lastExecutionDate, + }, + actions: actions.map(({ group, id, actionTypeId, params }) => ({ + group, + id, + params, + connector_type_id: actionTypeId, + })), +}); + +export const getRuleRoute = ( + router: IRouter, + licenseState: ILicenseState +) => { + router.get( + { + path: `${BASE_ALERTING_API_PATH}/rule/{id}`, + validate: { + params: paramSchema, + }, + }, + router.handleLegacyErrors( + verifyAccessAndContext(licenseState, async function (context, req, res) { + const alertsClient = context.alerting.getAlertsClient(); + const { id } = req.params; + const rule = await alertsClient.get({ id }); + return res.ok({ + body: rewriteBodyRes(rule), + }); + }) + ) + ); +}; diff --git a/x-pack/plugins/alerting/server/routes/get_rule_alert_summary.test.ts b/x-pack/plugins/alerting/server/routes/get_rule_alert_summary.test.ts new file mode 100644 index 00000000000000..fab6d46219a373 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/get_rule_alert_summary.test.ts @@ -0,0 +1,106 @@ +/* + * 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 { getRuleAlertSummaryRoute } from './get_rule_alert_summary'; +import { httpServiceMock } from 'src/core/server/mocks'; +import { licenseStateMock } from '../lib/license_state.mock'; +import { mockHandlerArguments } from './_mock_handler_arguments'; +import { SavedObjectsErrorHelpers } from 'src/core/server'; +import { alertsClientMock } from '../alerts_client.mock'; +import { AlertInstanceSummary } from '../types'; + +const alertsClient = alertsClientMock.create(); +jest.mock('../lib/license_api_access.ts', () => ({ + verifyApiAccess: jest.fn(), +})); + +beforeEach(() => { + jest.resetAllMocks(); +}); + +describe('getRuleAlertSummaryRoute', () => { + const dateString = new Date().toISOString(); + const mockedAlertInstanceSummary: AlertInstanceSummary = { + id: '', + name: '', + tags: [], + alertTypeId: '', + consumer: '', + muteAll: false, + throttle: null, + enabled: false, + statusStartDate: dateString, + statusEndDate: dateString, + status: 'OK', + errorMessages: [], + instances: {}, + }; + + it('gets rule alert summary', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + getRuleAlertSummaryRoute(router, licenseState); + + const [config, handler] = router.get.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/internal/alerting/rule/{id}/_alert_summary"`); + + alertsClient.getAlertInstanceSummary.mockResolvedValueOnce(mockedAlertInstanceSummary); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + params: { + id: '1', + }, + query: {}, + }, + ['ok'] + ); + + await handler(context, req, res); + + expect(alertsClient.getAlertInstanceSummary).toHaveBeenCalledTimes(1); + expect(alertsClient.getAlertInstanceSummary.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "dateStart": undefined, + "id": "1", + }, + ] + `); + + expect(res.ok).toHaveBeenCalled(); + }); + + it('returns NOT-FOUND when rule is not found', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + getRuleAlertSummaryRoute(router, licenseState); + + const [, handler] = router.get.mock.calls[0]; + + alertsClient.getAlertInstanceSummary = jest + .fn() + .mockResolvedValueOnce(SavedObjectsErrorHelpers.createGenericNotFoundError('alert', '1')); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + params: { + id: '1', + }, + query: {}, + }, + ['notFound'] + ); + + expect(await handler(context, req, res)).toEqual(undefined); + }); +}); diff --git a/x-pack/plugins/alerting/server/routes/get_rule_alert_summary.ts b/x-pack/plugins/alerting/server/routes/get_rule_alert_summary.ts new file mode 100644 index 00000000000000..7a3679851d53ff --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/get_rule_alert_summary.ts @@ -0,0 +1,77 @@ +/* + * 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 { IRouter } from 'kibana/server'; +import { schema } from '@kbn/config-schema'; +import { ILicenseState } from '../lib'; +import { GetAlertInstanceSummaryParams } from '../alerts_client'; +import { RewriteRequestCase, RewriteResponseCase, verifyAccessAndContext } from './lib'; +import { + AlertingRequestHandlerContext, + INTERNAL_BASE_ALERTING_API_PATH, + AlertInstanceSummary, +} from '../types'; + +const paramSchema = schema.object({ + id: schema.string(), +}); + +const querySchema = schema.object({ + date_start: schema.maybe(schema.string()), +}); + +const rewriteReq: RewriteRequestCase = ({ + date_start: dateStart, + ...rest +}) => ({ + ...rest, + dateStart, +}); +const rewriteBodyRes: RewriteResponseCase = ({ + alertTypeId, + muteAll, + statusStartDate, + statusEndDate, + errorMessages, + lastRun, + instances: alerts, + ...rest +}) => ({ + ...rest, + alerts, + rule_type_id: alertTypeId, + mute_all: muteAll, + status_start_date: statusStartDate, + status_end_date: statusEndDate, + error_messages: errorMessages, + last_run: lastRun, +}); + +export const getRuleAlertSummaryRoute = ( + router: IRouter, + licenseState: ILicenseState +) => { + router.get( + { + path: `${INTERNAL_BASE_ALERTING_API_PATH}/rule/{id}/_alert_summary`, + validate: { + params: paramSchema, + query: querySchema, + }, + }, + router.handleLegacyErrors( + verifyAccessAndContext(licenseState, async function (context, req, res) { + const alertsClient = context.alerting.getAlertsClient(); + const { id } = req.params; + const summary = await alertsClient.getAlertInstanceSummary( + rewriteReq({ id, ...req.query }) + ); + return res.ok({ body: rewriteBodyRes(summary) }); + }) + ) + ); +}; diff --git a/x-pack/plugins/alerting/server/routes/get_rule_state.test.ts b/x-pack/plugins/alerting/server/routes/get_rule_state.test.ts new file mode 100644 index 00000000000000..71e06b60d1026f --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/get_rule_state.test.ts @@ -0,0 +1,150 @@ +/* + * 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 { getRuleStateRoute } from './get_rule_state'; +import { httpServiceMock } from 'src/core/server/mocks'; +import { licenseStateMock } from '../lib/license_state.mock'; +import { mockHandlerArguments } from './_mock_handler_arguments'; +import { SavedObjectsErrorHelpers } from 'src/core/server'; +import { alertsClientMock } from '../alerts_client.mock'; + +const alertsClient = alertsClientMock.create(); +jest.mock('../lib/license_api_access.ts', () => ({ + verifyApiAccess: jest.fn(), +})); + +beforeEach(() => { + jest.resetAllMocks(); +}); + +describe('getRuleStateRoute', () => { + const mockedAlertState = { + alertTypeState: { + some: 'value', + }, + alertInstances: { + first_instance: { + state: {}, + meta: { + lastScheduledActions: { + group: 'first_group', + date: new Date(), + }, + }, + }, + second_instance: {}, + }, + }; + + it('gets rule state', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + getRuleStateRoute(router, licenseState); + + const [config, handler] = router.get.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/internal/alerting/rule/{id}/state"`); + + alertsClient.getAlertState.mockResolvedValueOnce(mockedAlertState); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + params: { + id: '1', + }, + }, + ['ok'] + ); + + await handler(context, req, res); + + expect(alertsClient.getAlertState).toHaveBeenCalledTimes(1); + expect(alertsClient.getAlertState.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "id": "1", + }, + ] + `); + + expect(res.ok).toHaveBeenCalled(); + }); + + it('returns NO-CONTENT when rule exists but has no task state yet', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + getRuleStateRoute(router, licenseState); + + const [config, handler] = router.get.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/internal/alerting/rule/{id}/state"`); + + alertsClient.getAlertState.mockResolvedValueOnce(undefined); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + params: { + id: '1', + }, + }, + ['noContent'] + ); + + expect(await handler(context, req, res)).toEqual(undefined); + + expect(alertsClient.getAlertState).toHaveBeenCalledTimes(1); + expect(alertsClient.getAlertState.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "id": "1", + }, + ] + `); + + expect(res.noContent).toHaveBeenCalled(); + }); + + it('returns NOT-FOUND when rule is not found', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + getRuleStateRoute(router, licenseState); + + const [config, handler] = router.get.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/internal/alerting/rule/{id}/state"`); + + alertsClient.getAlertState = jest + .fn() + .mockResolvedValueOnce(SavedObjectsErrorHelpers.createGenericNotFoundError('alert', '1')); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + params: { + id: '1', + }, + }, + ['notFound'] + ); + + expect(await handler(context, req, res)).toEqual(undefined); + + expect(alertsClient.getAlertState).toHaveBeenCalledTimes(1); + expect(alertsClient.getAlertState.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "id": "1", + }, + ] + `); + }); +}); diff --git a/x-pack/plugins/alerting/server/routes/get_rule_state.ts b/x-pack/plugins/alerting/server/routes/get_rule_state.ts new file mode 100644 index 00000000000000..08087d1ece8afa --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/get_rule_state.ts @@ -0,0 +1,54 @@ +/* + * 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 { IRouter } from 'kibana/server'; +import { schema } from '@kbn/config-schema'; +import { ILicenseState } from '../lib'; +import { RewriteResponseCase, verifyAccessAndContext } from './lib'; +import { + AlertingRequestHandlerContext, + INTERNAL_BASE_ALERTING_API_PATH, + AlertTaskState, +} from '../types'; + +const paramSchema = schema.object({ + id: schema.string(), +}); + +const rewriteBodyRes: RewriteResponseCase = ({ + alertTypeState, + alertInstances, + previousStartedAt, + ...rest +}) => ({ + ...rest, + rule_type_state: alertTypeState, + alerts: alertInstances, + previous_started_at: previousStartedAt, +}); + +export const getRuleStateRoute = ( + router: IRouter, + licenseState: ILicenseState +) => { + router.get( + { + path: `${INTERNAL_BASE_ALERTING_API_PATH}/rule/{id}/state`, + validate: { + params: paramSchema, + }, + }, + router.handleLegacyErrors( + verifyAccessAndContext(licenseState, async function (context, req, res) { + const alertsClient = context.alerting.getAlertsClient(); + const { id } = req.params; + const state = await alertsClient.getAlertState({ id }); + return state ? res.ok({ body: rewriteBodyRes(state) }) : res.noContent(); + }) + ) + ); +}; diff --git a/x-pack/plugins/alerting/server/routes/health.test.ts b/x-pack/plugins/alerting/server/routes/health.test.ts index 75c621e4a0abf3..be63e0b7054be2 100644 --- a/x-pack/plugins/alerting/server/routes/health.test.ts +++ b/x-pack/plugins/alerting/server/routes/health.test.ts @@ -54,7 +54,7 @@ describe('healthRoute', () => { const [config] = router.get.mock.calls[0]; - expect(config.path).toMatchInlineSnapshot(`"/api/alerts/_health"`); + expect(config.path).toMatchInlineSnapshot(`"/api/alerting/_health"`); }); it('queries the usage api', async () => { @@ -107,22 +107,22 @@ describe('healthRoute', () => { expect(await handler(context, req, res)).toStrictEqual({ body: { - alertingFrameworkHeath: { - decryptionHealth: { + alerting_framework_heath: { + decryption_health: { status: HealthStatus.OK, timestamp: currentDate, }, - executionHealth: { + execution_health: { status: HealthStatus.OK, timestamp: currentDate, }, - readHealth: { + read_health: { status: HealthStatus.OK, timestamp: currentDate, }, }, - hasPermanentEncryptionKey: false, - isSufficientlySecure: true, + has_permanent_encryption_key: false, + is_sufficiently_secure: true, }, }); }); @@ -148,22 +148,22 @@ describe('healthRoute', () => { expect(await handler(context, req, res)).toStrictEqual({ body: { - alertingFrameworkHeath: { - decryptionHealth: { + alerting_framework_heath: { + decryption_health: { status: HealthStatus.OK, timestamp: currentDate, }, - executionHealth: { + execution_health: { status: HealthStatus.OK, timestamp: currentDate, }, - readHealth: { + read_health: { status: HealthStatus.OK, timestamp: currentDate, }, }, - hasPermanentEncryptionKey: true, - isSufficientlySecure: true, + has_permanent_encryption_key: true, + is_sufficiently_secure: true, }, }); }); @@ -189,22 +189,22 @@ describe('healthRoute', () => { expect(await handler(context, req, res)).toStrictEqual({ body: { - alertingFrameworkHeath: { - decryptionHealth: { + alerting_framework_heath: { + decryption_health: { status: HealthStatus.OK, timestamp: currentDate, }, - executionHealth: { + execution_health: { status: HealthStatus.OK, timestamp: currentDate, }, - readHealth: { + read_health: { status: HealthStatus.OK, timestamp: currentDate, }, }, - hasPermanentEncryptionKey: true, - isSufficientlySecure: true, + has_permanent_encryption_key: true, + is_sufficiently_secure: true, }, }); }); @@ -230,22 +230,22 @@ describe('healthRoute', () => { expect(await handler(context, req, res)).toStrictEqual({ body: { - alertingFrameworkHeath: { - decryptionHealth: { + alerting_framework_heath: { + decryption_health: { status: HealthStatus.OK, timestamp: currentDate, }, - executionHealth: { + execution_health: { status: HealthStatus.OK, timestamp: currentDate, }, - readHealth: { + read_health: { status: HealthStatus.OK, timestamp: currentDate, }, }, - hasPermanentEncryptionKey: true, - isSufficientlySecure: false, + has_permanent_encryption_key: true, + is_sufficiently_secure: false, }, }); }); @@ -273,22 +273,22 @@ describe('healthRoute', () => { expect(await handler(context, req, res)).toStrictEqual({ body: { - alertingFrameworkHeath: { - decryptionHealth: { + alerting_framework_heath: { + decryption_health: { status: HealthStatus.OK, timestamp: currentDate, }, - executionHealth: { + execution_health: { status: HealthStatus.OK, timestamp: currentDate, }, - readHealth: { + read_health: { status: HealthStatus.OK, timestamp: currentDate, }, }, - hasPermanentEncryptionKey: true, - isSufficientlySecure: false, + has_permanent_encryption_key: true, + is_sufficiently_secure: false, }, }); }); @@ -316,22 +316,22 @@ describe('healthRoute', () => { expect(await handler(context, req, res)).toStrictEqual({ body: { - alertingFrameworkHeath: { - decryptionHealth: { + alerting_framework_heath: { + decryption_health: { status: HealthStatus.OK, timestamp: currentDate, }, - executionHealth: { + execution_health: { status: HealthStatus.OK, timestamp: currentDate, }, - readHealth: { + read_health: { status: HealthStatus.OK, timestamp: currentDate, }, }, - hasPermanentEncryptionKey: true, - isSufficientlySecure: true, + has_permanent_encryption_key: true, + is_sufficiently_secure: true, }, }); }); diff --git a/x-pack/plugins/alerting/server/routes/health.ts b/x-pack/plugins/alerting/server/routes/health.ts index de0b14465c5acf..c2a122a28fa490 100644 --- a/x-pack/plugins/alerting/server/routes/health.ts +++ b/x-pack/plugins/alerting/server/routes/health.ts @@ -6,11 +6,15 @@ */ import { ApiResponse } from '@elastic/elasticsearch'; -import type { AlertingRouter } from '../types'; -import { ILicenseState } from '../lib/license_state'; -import { verifyApiAccess } from '../lib/license_api_access'; -import { AlertingFrameworkHealth } from '../types'; +import { IRouter } from 'kibana/server'; +import { ILicenseState } from '../lib'; import { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objects/server'; +import { RewriteResponseCase, verifyAccessAndContext } from './lib'; +import { + AlertingRequestHandlerContext, + BASE_ALERTING_API_PATH, + AlertingFrameworkHealth, +} from '../types'; interface XPackUsageSecurity { security?: { @@ -23,49 +27,63 @@ interface XPackUsageSecurity { }; } -export function healthRoute( - router: AlertingRouter, +const rewriteBodyRes: RewriteResponseCase = ({ + isSufficientlySecure, + hasPermanentEncryptionKey, + alertingFrameworkHeath, + ...rest +}) => ({ + ...rest, + is_sufficiently_secure: isSufficientlySecure, + has_permanent_encryption_key: hasPermanentEncryptionKey, + alerting_framework_heath: { + decryption_health: alertingFrameworkHeath.decryptionHealth, + execution_health: alertingFrameworkHeath.executionHealth, + read_health: alertingFrameworkHeath.readHealth, + }, +}); + +export const healthRoute = ( + router: IRouter, licenseState: ILicenseState, encryptedSavedObjects: EncryptedSavedObjectsPluginSetup -) { +) => { router.get( { - path: '/api/alerts/_health', + path: `${BASE_ALERTING_API_PATH}/_health`, validate: false, }, - router.handleLegacyErrors(async function (context, req, res) { - verifyApiAccess(licenseState); - if (!context.alerting) { - return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); - } - try { - const { - body: { - security: { - enabled: isSecurityEnabled = false, - ssl: { http: { enabled: isTLSEnabled = false } = {} } = {}, - } = {}, - }, - }: ApiResponse = await context.core.elasticsearch.client.asInternalUser.transport // Do not augment with such input. // `transport.request` is potentially unsafe when combined with untrusted user input. - .request({ - method: 'GET', - path: '/_xpack/usage', - }); + router.handleLegacyErrors( + verifyAccessAndContext(licenseState, async function (context, req, res) { + try { + const { + body: { + security: { + enabled: isSecurityEnabled = false, + ssl: { http: { enabled: isTLSEnabled = false } = {} } = {}, + } = {}, + }, + }: ApiResponse = await context.core.elasticsearch.client.asInternalUser.transport // Do not augment with such input. // `transport.request` is potentially unsafe when combined with untrusted user input. + .request({ + method: 'GET', + path: '/_xpack/usage', + }); - const alertingFrameworkHeath = await context.alerting.getFrameworkHealth(); + const alertingFrameworkHeath = await context.alerting.getFrameworkHealth(); - const frameworkHealth: AlertingFrameworkHealth = { - isSufficientlySecure: !isSecurityEnabled || (isSecurityEnabled && isTLSEnabled), - hasPermanentEncryptionKey: encryptedSavedObjects.canEncrypt, - alertingFrameworkHeath, - }; + const frameworkHealth: AlertingFrameworkHealth = { + isSufficientlySecure: !isSecurityEnabled || (isSecurityEnabled && isTLSEnabled), + hasPermanentEncryptionKey: encryptedSavedObjects.canEncrypt, + alertingFrameworkHeath, + }; - return res.ok({ - body: frameworkHealth, - }); - } catch (error) { - return res.badRequest({ body: error }); - } - }) + return res.ok({ + body: rewriteBodyRes(frameworkHealth), + }); + } catch (error) { + return res.badRequest({ body: error }); + } + }) + ) ); -} +}; diff --git a/x-pack/plugins/alerting/server/routes/index.ts b/x-pack/plugins/alerting/server/routes/index.ts index e250d17866a2b1..c6f12ffba2f20c 100644 --- a/x-pack/plugins/alerting/server/routes/index.ts +++ b/x-pack/plugins/alerting/server/routes/index.ts @@ -5,20 +5,50 @@ * 2.0. */ -export { aggregateAlertRoute } from './aggregate'; -export { createAlertRoute } from './create'; -export { deleteAlertRoute } from './delete'; -export { findAlertRoute } from './find'; -export { getAlertRoute } from './get'; -export { getAlertStateRoute } from './get_alert_state'; -export { getAlertInstanceSummaryRoute } from './get_alert_instance_summary'; -export { listAlertTypesRoute } from './list_alert_types'; -export { updateAlertRoute } from './update'; -export { enableAlertRoute } from './enable'; -export { disableAlertRoute } from './disable'; -export { updateApiKeyRoute } from './update_api_key'; -export { muteAlertInstanceRoute } from './mute_instance'; -export { unmuteAlertInstanceRoute } from './unmute_instance'; -export { muteAllAlertRoute } from './mute_all'; -export { unmuteAllAlertRoute } from './unmute_all'; -export { healthRoute } from './health'; +import { IRouter } from 'kibana/server'; +import { ILicenseState } from '../lib'; +import { defineLegacyRoutes } from './legacy'; +import { AlertingRequestHandlerContext } from '../types'; +import { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objects/server'; +import { createRuleRoute } from './create_rule'; +import { getRuleRoute } from './get_rule'; +import { updateRuleRoute } from './update_rule'; +import { deleteRuleRoute } from './delete_rule'; +import { aggregateRulesRoute } from './aggregate_rules'; +import { disableRuleRoute } from './disable_rule'; +import { enableRuleRoute } from './enable_rule'; +import { findRulesRoute } from './find_rules'; +import { getRuleAlertSummaryRoute } from './get_rule_alert_summary'; +import { getRuleStateRoute } from './get_rule_state'; +import { healthRoute } from './health'; +import { ruleTypesRoute } from './rule_types'; +import { muteAllRuleRoute } from './mute_all_rule'; +import { muteAlertRoute } from './mute_alert'; +import { unmuteAllRuleRoute } from './unmute_all_rule'; +import { unmuteAlertRoute } from './unmute_alert'; +import { updateRuleApiKeyRoute } from './update_rule_api_key'; + +export function defineRoutes( + router: IRouter, + licenseState: ILicenseState, + encryptedSavedObjects: EncryptedSavedObjectsPluginSetup +) { + defineLegacyRoutes(router, licenseState, encryptedSavedObjects); + createRuleRoute(router, licenseState); + getRuleRoute(router, licenseState); + updateRuleRoute(router, licenseState); + deleteRuleRoute(router, licenseState); + aggregateRulesRoute(router, licenseState); + disableRuleRoute(router, licenseState); + enableRuleRoute(router, licenseState); + findRulesRoute(router, licenseState); + getRuleAlertSummaryRoute(router, licenseState); + getRuleStateRoute(router, licenseState); + healthRoute(router, licenseState, encryptedSavedObjects); + ruleTypesRoute(router, licenseState); + muteAllRuleRoute(router, licenseState); + muteAlertRoute(router, licenseState); + unmuteAllRuleRoute(router, licenseState); + unmuteAlertRoute(router, licenseState); + updateRuleApiKeyRoute(router, licenseState); +} diff --git a/x-pack/plugins/alerting/server/routes/aggregate.test.ts b/x-pack/plugins/alerting/server/routes/legacy/aggregate.test.ts similarity index 91% rename from x-pack/plugins/alerting/server/routes/aggregate.test.ts rename to x-pack/plugins/alerting/server/routes/legacy/aggregate.test.ts index 60e9a2a1bcc79c..94331902d9aceb 100644 --- a/x-pack/plugins/alerting/server/routes/aggregate.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/aggregate.test.ts @@ -7,14 +7,14 @@ import { aggregateAlertRoute } from './aggregate'; import { httpServiceMock } from 'src/core/server/mocks'; -import { licenseStateMock } from '../lib/license_state.mock'; -import { verifyApiAccess } from '../lib/license_api_access'; -import { mockHandlerArguments } from './_mock_handler_arguments'; -import { alertsClientMock } from '../alerts_client.mock'; +import { licenseStateMock } from '../../lib/license_state.mock'; +import { verifyApiAccess } from '../../lib/license_api_access'; +import { mockHandlerArguments } from './../_mock_handler_arguments'; +import { alertsClientMock } from '../../alerts_client.mock'; const alertsClient = alertsClientMock.create(); -jest.mock('../lib/license_api_access.ts', () => ({ +jest.mock('../../lib/license_api_access.ts', () => ({ verifyApiAccess: jest.fn(), })); diff --git a/x-pack/plugins/alerting/server/routes/aggregate.ts b/x-pack/plugins/alerting/server/routes/legacy/aggregate.ts similarity index 83% rename from x-pack/plugins/alerting/server/routes/aggregate.ts rename to x-pack/plugins/alerting/server/routes/legacy/aggregate.ts index 1416f60277daa0..91189fdf3d0a6c 100644 --- a/x-pack/plugins/alerting/server/routes/aggregate.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/aggregate.ts @@ -6,12 +6,12 @@ */ import { schema } from '@kbn/config-schema'; -import type { AlertingRouter } from '../types'; -import { ILicenseState } from '../lib/license_state'; -import { verifyApiAccess } from '../lib/license_api_access'; -import { BASE_ALERT_API_PATH } from '../../common'; -import { renameKeys } from './lib/rename_keys'; -import { FindOptions } from '../alerts_client'; +import type { AlertingRouter } from '../../types'; +import { ILicenseState } from '../../lib/license_state'; +import { verifyApiAccess } from '../../lib/license_api_access'; +import { LEGACY_BASE_ALERT_API_PATH } from '../../../common'; +import { renameKeys } from './../lib/rename_keys'; +import { FindOptions } from '../../alerts_client'; // config definition const querySchema = schema.object({ @@ -36,7 +36,7 @@ const querySchema = schema.object({ export const aggregateAlertRoute = (router: AlertingRouter, licenseState: ILicenseState) => { router.get( { - path: `${BASE_ALERT_API_PATH}/_aggregate`, + path: `${LEGACY_BASE_ALERT_API_PATH}/_aggregate`, validate: { query: querySchema, }, diff --git a/x-pack/plugins/alerting/server/routes/create.test.ts b/x-pack/plugins/alerting/server/routes/legacy/create.test.ts similarity index 93% rename from x-pack/plugins/alerting/server/routes/create.test.ts rename to x-pack/plugins/alerting/server/routes/legacy/create.test.ts index 1a2dfec8612e37..fd3252d2fca774 100644 --- a/x-pack/plugins/alerting/server/routes/create.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/create.test.ts @@ -7,16 +7,16 @@ import { createAlertRoute } from './create'; import { httpServiceMock } from 'src/core/server/mocks'; -import { licenseStateMock } from '../lib/license_state.mock'; -import { verifyApiAccess } from '../lib/license_api_access'; -import { mockHandlerArguments } from './_mock_handler_arguments'; -import { alertsClientMock } from '../alerts_client.mock'; -import { Alert } from '../../common/alert'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +import { licenseStateMock } from '../../lib/license_state.mock'; +import { verifyApiAccess } from '../../lib/license_api_access'; +import { mockHandlerArguments } from './../_mock_handler_arguments'; +import { alertsClientMock } from '../../alerts_client.mock'; +import { Alert } from '../../../common/alert'; +import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; const alertsClient = alertsClientMock.create(); -jest.mock('../lib/license_api_access.ts', () => ({ +jest.mock('../../lib/license_api_access.ts', () => ({ verifyApiAccess: jest.fn(), })); diff --git a/x-pack/plugins/alerting/server/routes/create.ts b/x-pack/plugins/alerting/server/routes/legacy/create.ts similarity index 75% rename from x-pack/plugins/alerting/server/routes/create.ts rename to x-pack/plugins/alerting/server/routes/legacy/create.ts index 7b1a518112ddd2..fca2b671185273 100644 --- a/x-pack/plugins/alerting/server/routes/create.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/create.ts @@ -6,19 +6,19 @@ */ import { schema } from '@kbn/config-schema'; -import type { AlertingRouter } from '../types'; -import { ILicenseState } from '../lib/license_state'; -import { verifyApiAccess } from '../lib/license_api_access'; -import { validateDurationSchema } from '../lib'; -import { handleDisabledApiKeysError } from './lib/error_handler'; +import type { AlertingRouter } from '../../types'; +import { ILicenseState } from '../../lib/license_state'; +import { verifyApiAccess } from '../../lib/license_api_access'; +import { validateDurationSchema } from '../../lib'; +import { handleDisabledApiKeysError } from './../lib/error_handler'; import { - Alert, + SanitizedAlert, AlertNotifyWhenType, AlertTypeParams, - BASE_ALERT_API_PATH, + LEGACY_BASE_ALERT_API_PATH, validateNotifyWhenType, -} from '../types'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +} from '../../types'; +import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; export const bodySchema = schema.object({ name: schema.string(), @@ -46,7 +46,7 @@ export const bodySchema = schema.object({ export const createAlertRoute = (router: AlertingRouter, licenseState: ILicenseState) => { router.post( { - path: `${BASE_ALERT_API_PATH}/alert/{id?}`, + path: `${LEGACY_BASE_ALERT_API_PATH}/alert/{id?}`, validate: { params: schema.maybe( schema.object({ @@ -68,10 +68,12 @@ export const createAlertRoute = (router: AlertingRouter, licenseState: ILicenseS const params = req.params; const notifyWhen = alert?.notifyWhen ? (alert.notifyWhen as AlertNotifyWhenType) : null; try { - const alertRes: Alert = await alertsClient.create({ - data: { ...alert, notifyWhen }, - options: { id: params?.id }, - }); + const alertRes: SanitizedAlert = await alertsClient.create( + { + data: { ...alert, notifyWhen }, + options: { id: params?.id }, + } + ); return res.ok({ body: alertRes, }); diff --git a/x-pack/plugins/alerting/server/routes/delete.test.ts b/x-pack/plugins/alerting/server/routes/legacy/delete.test.ts similarity index 89% rename from x-pack/plugins/alerting/server/routes/delete.test.ts rename to x-pack/plugins/alerting/server/routes/legacy/delete.test.ts index 47564f67d42a5a..e71b2788b98c7c 100644 --- a/x-pack/plugins/alerting/server/routes/delete.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/delete.test.ts @@ -7,14 +7,14 @@ import { deleteAlertRoute } from './delete'; import { httpServiceMock } from 'src/core/server/mocks'; -import { licenseStateMock } from '../lib/license_state.mock'; -import { verifyApiAccess } from '../lib/license_api_access'; -import { mockHandlerArguments } from './_mock_handler_arguments'; -import { alertsClientMock } from '../alerts_client.mock'; +import { licenseStateMock } from '../../lib/license_state.mock'; +import { verifyApiAccess } from '../../lib/license_api_access'; +import { mockHandlerArguments } from './../_mock_handler_arguments'; +import { alertsClientMock } from '../../alerts_client.mock'; const alertsClient = alertsClientMock.create(); -jest.mock('../lib/license_api_access.ts', () => ({ +jest.mock('../../lib/license_api_access.ts', () => ({ verifyApiAccess: jest.fn(), })); diff --git a/x-pack/plugins/alerting/server/routes/delete.ts b/x-pack/plugins/alerting/server/routes/legacy/delete.ts similarity index 76% rename from x-pack/plugins/alerting/server/routes/delete.ts rename to x-pack/plugins/alerting/server/routes/legacy/delete.ts index e217fd0533771a..650126be4499d5 100644 --- a/x-pack/plugins/alerting/server/routes/delete.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/delete.ts @@ -6,10 +6,10 @@ */ import { schema } from '@kbn/config-schema'; -import type { AlertingRouter } from '../types'; -import { ILicenseState } from '../lib/license_state'; -import { verifyApiAccess } from '../lib/license_api_access'; -import { BASE_ALERT_API_PATH } from '../../common'; +import type { AlertingRouter } from '../../types'; +import { ILicenseState } from '../../lib/license_state'; +import { verifyApiAccess } from '../../lib/license_api_access'; +import { LEGACY_BASE_ALERT_API_PATH } from '../../../common'; const paramSchema = schema.object({ id: schema.string(), @@ -18,7 +18,7 @@ const paramSchema = schema.object({ export const deleteAlertRoute = (router: AlertingRouter, licenseState: ILicenseState) => { router.delete( { - path: `${BASE_ALERT_API_PATH}/alert/{id}`, + path: `${LEGACY_BASE_ALERT_API_PATH}/alert/{id}`, validate: { params: paramSchema, }, diff --git a/x-pack/plugins/alerting/server/routes/disable.test.ts b/x-pack/plugins/alerting/server/routes/legacy/disable.test.ts similarity index 86% rename from x-pack/plugins/alerting/server/routes/disable.test.ts rename to x-pack/plugins/alerting/server/routes/legacy/disable.test.ts index 347b1641515e62..34c0af711a338b 100644 --- a/x-pack/plugins/alerting/server/routes/disable.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/disable.test.ts @@ -7,14 +7,14 @@ import { disableAlertRoute } from './disable'; import { httpServiceMock } from 'src/core/server/mocks'; -import { licenseStateMock } from '../lib/license_state.mock'; -import { mockHandlerArguments } from './_mock_handler_arguments'; -import { alertsClientMock } from '../alerts_client.mock'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +import { licenseStateMock } from '../../lib/license_state.mock'; +import { mockHandlerArguments } from './../_mock_handler_arguments'; +import { alertsClientMock } from '../../alerts_client.mock'; +import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; const alertsClient = alertsClientMock.create(); -jest.mock('../lib/license_api_access.ts', () => ({ +jest.mock('../../lib/license_api_access.ts', () => ({ verifyApiAccess: jest.fn(), })); diff --git a/x-pack/plugins/alerting/server/routes/disable.ts b/x-pack/plugins/alerting/server/routes/legacy/disable.ts similarity index 74% rename from x-pack/plugins/alerting/server/routes/disable.ts rename to x-pack/plugins/alerting/server/routes/legacy/disable.ts index 7129fbdd52698a..140e0492fbaaba 100644 --- a/x-pack/plugins/alerting/server/routes/disable.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/disable.ts @@ -6,11 +6,11 @@ */ import { schema } from '@kbn/config-schema'; -import type { AlertingRouter } from '../types'; -import { ILicenseState } from '../lib/license_state'; -import { verifyApiAccess } from '../lib/license_api_access'; -import { BASE_ALERT_API_PATH } from '../../common'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +import type { AlertingRouter } from '../../types'; +import { ILicenseState } from '../../lib/license_state'; +import { verifyApiAccess } from '../../lib/license_api_access'; +import { LEGACY_BASE_ALERT_API_PATH } from '../../../common'; +import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; const paramSchema = schema.object({ id: schema.string(), @@ -19,7 +19,7 @@ const paramSchema = schema.object({ export const disableAlertRoute = (router: AlertingRouter, licenseState: ILicenseState) => { router.post( { - path: `${BASE_ALERT_API_PATH}/alert/{id}/_disable`, + path: `${LEGACY_BASE_ALERT_API_PATH}/alert/{id}/_disable`, validate: { params: paramSchema, }, diff --git a/x-pack/plugins/alerting/server/routes/enable.test.ts b/x-pack/plugins/alerting/server/routes/legacy/enable.test.ts similarity index 86% rename from x-pack/plugins/alerting/server/routes/enable.test.ts rename to x-pack/plugins/alerting/server/routes/legacy/enable.test.ts index c12a19fc35dbeb..88229472a29364 100644 --- a/x-pack/plugins/alerting/server/routes/enable.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/enable.test.ts @@ -7,14 +7,14 @@ import { enableAlertRoute } from './enable'; import { httpServiceMock } from 'src/core/server/mocks'; -import { licenseStateMock } from '../lib/license_state.mock'; -import { mockHandlerArguments } from './_mock_handler_arguments'; -import { alertsClientMock } from '../alerts_client.mock'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +import { licenseStateMock } from '../../lib/license_state.mock'; +import { mockHandlerArguments } from './../_mock_handler_arguments'; +import { alertsClientMock } from '../../alerts_client.mock'; +import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; const alertsClient = alertsClientMock.create(); -jest.mock('../lib/license_api_access.ts', () => ({ +jest.mock('../../lib/license_api_access.ts', () => ({ verifyApiAccess: jest.fn(), })); diff --git a/x-pack/plugins/alerting/server/routes/enable.ts b/x-pack/plugins/alerting/server/routes/legacy/enable.ts similarity index 72% rename from x-pack/plugins/alerting/server/routes/enable.ts rename to x-pack/plugins/alerting/server/routes/legacy/enable.ts index d874e9b6106b9b..fcf9ceb8a058bf 100644 --- a/x-pack/plugins/alerting/server/routes/enable.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/enable.ts @@ -6,12 +6,12 @@ */ import { schema } from '@kbn/config-schema'; -import type { AlertingRouter } from '../types'; -import { ILicenseState } from '../lib/license_state'; -import { verifyApiAccess } from '../lib/license_api_access'; -import { BASE_ALERT_API_PATH } from '../../common'; -import { handleDisabledApiKeysError } from './lib/error_handler'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +import type { AlertingRouter } from '../../types'; +import { ILicenseState } from '../../lib/license_state'; +import { verifyApiAccess } from '../../lib/license_api_access'; +import { LEGACY_BASE_ALERT_API_PATH } from '../../../common'; +import { handleDisabledApiKeysError } from './../lib/error_handler'; +import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; const paramSchema = schema.object({ id: schema.string(), @@ -20,7 +20,7 @@ const paramSchema = schema.object({ export const enableAlertRoute = (router: AlertingRouter, licenseState: ILicenseState) => { router.post( { - path: `${BASE_ALERT_API_PATH}/alert/{id}/_enable`, + path: `${LEGACY_BASE_ALERT_API_PATH}/alert/{id}/_enable`, validate: { params: paramSchema, }, diff --git a/x-pack/plugins/alerting/server/routes/find.test.ts b/x-pack/plugins/alerting/server/routes/legacy/find.test.ts similarity index 91% rename from x-pack/plugins/alerting/server/routes/find.test.ts rename to x-pack/plugins/alerting/server/routes/legacy/find.test.ts index 791e2babc062e3..640451afcca972 100644 --- a/x-pack/plugins/alerting/server/routes/find.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/find.test.ts @@ -7,14 +7,14 @@ import { findAlertRoute } from './find'; import { httpServiceMock } from 'src/core/server/mocks'; -import { licenseStateMock } from '../lib/license_state.mock'; -import { verifyApiAccess } from '../lib/license_api_access'; -import { mockHandlerArguments } from './_mock_handler_arguments'; -import { alertsClientMock } from '../alerts_client.mock'; +import { licenseStateMock } from '../../lib/license_state.mock'; +import { verifyApiAccess } from '../../lib/license_api_access'; +import { mockHandlerArguments } from './../_mock_handler_arguments'; +import { alertsClientMock } from '../../alerts_client.mock'; const alertsClient = alertsClientMock.create(); -jest.mock('../lib/license_api_access.ts', () => ({ +jest.mock('../../lib/license_api_access.ts', () => ({ verifyApiAccess: jest.fn(), })); diff --git a/x-pack/plugins/alerting/server/routes/find.ts b/x-pack/plugins/alerting/server/routes/legacy/find.ts similarity index 86% rename from x-pack/plugins/alerting/server/routes/find.ts rename to x-pack/plugins/alerting/server/routes/legacy/find.ts index ad345de6852662..1d54df53d883ab 100644 --- a/x-pack/plugins/alerting/server/routes/find.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/find.ts @@ -6,13 +6,13 @@ */ import { schema } from '@kbn/config-schema'; -import type { AlertingRouter } from '../types'; +import type { AlertingRouter } from '../../types'; -import { ILicenseState } from '../lib/license_state'; -import { verifyApiAccess } from '../lib/license_api_access'; -import { BASE_ALERT_API_PATH } from '../../common'; -import { renameKeys } from './lib/rename_keys'; -import { FindOptions } from '../alerts_client'; +import { ILicenseState } from '../../lib/license_state'; +import { verifyApiAccess } from '../../lib/license_api_access'; +import { LEGACY_BASE_ALERT_API_PATH } from '../../../common'; +import { renameKeys } from './../lib/rename_keys'; +import { FindOptions } from '../../alerts_client'; // config definition const querySchema = schema.object({ @@ -42,7 +42,7 @@ const querySchema = schema.object({ export const findAlertRoute = (router: AlertingRouter, licenseState: ILicenseState) => { router.get( { - path: `${BASE_ALERT_API_PATH}/_find`, + path: `${LEGACY_BASE_ALERT_API_PATH}/_find`, validate: { query: querySchema, }, diff --git a/x-pack/plugins/alerting/server/routes/get.test.ts b/x-pack/plugins/alerting/server/routes/legacy/get.test.ts similarity index 90% rename from x-pack/plugins/alerting/server/routes/get.test.ts rename to x-pack/plugins/alerting/server/routes/legacy/get.test.ts index 79938e572dfcf1..b2704cdd234f12 100644 --- a/x-pack/plugins/alerting/server/routes/get.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/get.test.ts @@ -7,14 +7,14 @@ import { getAlertRoute } from './get'; import { httpServiceMock } from 'src/core/server/mocks'; -import { licenseStateMock } from '../lib/license_state.mock'; -import { verifyApiAccess } from '../lib/license_api_access'; -import { mockHandlerArguments } from './_mock_handler_arguments'; -import { alertsClientMock } from '../alerts_client.mock'; -import { Alert } from '../../common'; +import { licenseStateMock } from '../../lib/license_state.mock'; +import { verifyApiAccess } from '../../lib/license_api_access'; +import { mockHandlerArguments } from './../_mock_handler_arguments'; +import { alertsClientMock } from '../../alerts_client.mock'; +import { Alert } from '../../../common'; const alertsClient = alertsClientMock.create(); -jest.mock('../lib/license_api_access.ts', () => ({ +jest.mock('../../lib/license_api_access.ts', () => ({ verifyApiAccess: jest.fn(), })); diff --git a/x-pack/plugins/alerting/server/routes/get.ts b/x-pack/plugins/alerting/server/routes/legacy/get.ts similarity index 76% rename from x-pack/plugins/alerting/server/routes/get.ts rename to x-pack/plugins/alerting/server/routes/legacy/get.ts index 93d2f29f53c18d..cf63a4387a93ee 100644 --- a/x-pack/plugins/alerting/server/routes/get.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/get.ts @@ -6,10 +6,10 @@ */ import { schema } from '@kbn/config-schema'; -import { ILicenseState } from '../lib/license_state'; -import { verifyApiAccess } from '../lib/license_api_access'; -import { BASE_ALERT_API_PATH } from '../../common'; -import type { AlertingRouter } from '../types'; +import { ILicenseState } from '../../lib/license_state'; +import { verifyApiAccess } from '../../lib/license_api_access'; +import { LEGACY_BASE_ALERT_API_PATH } from '../../../common'; +import type { AlertingRouter } from '../../types'; const paramSchema = schema.object({ id: schema.string(), @@ -18,7 +18,7 @@ const paramSchema = schema.object({ export const getAlertRoute = (router: AlertingRouter, licenseState: ILicenseState) => { router.get( { - path: `${BASE_ALERT_API_PATH}/alert/{id}`, + path: `${LEGACY_BASE_ALERT_API_PATH}/alert/{id}`, validate: { params: paramSchema, }, diff --git a/x-pack/plugins/alerting/server/routes/get_alert_instance_summary.test.ts b/x-pack/plugins/alerting/server/routes/legacy/get_alert_instance_summary.test.ts similarity index 89% rename from x-pack/plugins/alerting/server/routes/get_alert_instance_summary.test.ts rename to x-pack/plugins/alerting/server/routes/legacy/get_alert_instance_summary.test.ts index 3157f18afbb95b..0162ef91f55e7e 100644 --- a/x-pack/plugins/alerting/server/routes/get_alert_instance_summary.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/get_alert_instance_summary.test.ts @@ -7,14 +7,14 @@ import { getAlertInstanceSummaryRoute } from './get_alert_instance_summary'; import { httpServiceMock } from 'src/core/server/mocks'; -import { licenseStateMock } from '../lib/license_state.mock'; -import { mockHandlerArguments } from './_mock_handler_arguments'; +import { licenseStateMock } from '../../lib/license_state.mock'; +import { mockHandlerArguments } from './../_mock_handler_arguments'; import { SavedObjectsErrorHelpers } from 'src/core/server'; -import { alertsClientMock } from '../alerts_client.mock'; -import { AlertInstanceSummary } from '../types'; +import { alertsClientMock } from '../../alerts_client.mock'; +import { AlertInstanceSummary } from '../../types'; const alertsClient = alertsClientMock.create(); -jest.mock('../lib/license_api_access.ts', () => ({ +jest.mock('../../lib/license_api_access.ts', () => ({ verifyApiAccess: jest.fn(), })); diff --git a/x-pack/plugins/alerting/server/routes/get_alert_instance_summary.ts b/x-pack/plugins/alerting/server/routes/legacy/get_alert_instance_summary.ts similarity index 79% rename from x-pack/plugins/alerting/server/routes/get_alert_instance_summary.ts rename to x-pack/plugins/alerting/server/routes/legacy/get_alert_instance_summary.ts index 71c85caa38c8d4..00c96197f6f9be 100644 --- a/x-pack/plugins/alerting/server/routes/get_alert_instance_summary.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/get_alert_instance_summary.ts @@ -6,10 +6,10 @@ */ import { schema } from '@kbn/config-schema'; -import type { AlertingRouter } from '../types'; -import { ILicenseState } from '../lib/license_state'; -import { verifyApiAccess } from '../lib/license_api_access'; -import { BASE_ALERT_API_PATH } from '../../common'; +import type { AlertingRouter } from '../../types'; +import { ILicenseState } from '../../lib/license_state'; +import { verifyApiAccess } from '../../lib/license_api_access'; +import { LEGACY_BASE_ALERT_API_PATH } from '../../../common'; const paramSchema = schema.object({ id: schema.string(), @@ -25,7 +25,7 @@ export const getAlertInstanceSummaryRoute = ( ) => { router.get( { - path: `${BASE_ALERT_API_PATH}/alert/{id}/_instance_summary`, + path: `${LEGACY_BASE_ALERT_API_PATH}/alert/{id}/_instance_summary`, validate: { params: paramSchema, query: querySchema, diff --git a/x-pack/plugins/alerting/server/routes/get_alert_state.test.ts b/x-pack/plugins/alerting/server/routes/legacy/get_alert_state.test.ts similarity index 93% rename from x-pack/plugins/alerting/server/routes/get_alert_state.test.ts rename to x-pack/plugins/alerting/server/routes/legacy/get_alert_state.test.ts index 5aa96d6c734470..f08e0992cbba04 100644 --- a/x-pack/plugins/alerting/server/routes/get_alert_state.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/get_alert_state.test.ts @@ -7,13 +7,13 @@ import { getAlertStateRoute } from './get_alert_state'; import { httpServiceMock } from 'src/core/server/mocks'; -import { licenseStateMock } from '../lib/license_state.mock'; -import { mockHandlerArguments } from './_mock_handler_arguments'; +import { licenseStateMock } from '../../lib/license_state.mock'; +import { mockHandlerArguments } from './../_mock_handler_arguments'; import { SavedObjectsErrorHelpers } from 'src/core/server'; -import { alertsClientMock } from '../alerts_client.mock'; +import { alertsClientMock } from '../../alerts_client.mock'; const alertsClient = alertsClientMock.create(); -jest.mock('../lib/license_api_access.ts', () => ({ +jest.mock('../../lib/license_api_access.ts', () => ({ verifyApiAccess: jest.fn(), })); diff --git a/x-pack/plugins/alerting/server/routes/get_alert_state.ts b/x-pack/plugins/alerting/server/routes/legacy/get_alert_state.ts similarity index 77% rename from x-pack/plugins/alerting/server/routes/get_alert_state.ts rename to x-pack/plugins/alerting/server/routes/legacy/get_alert_state.ts index 3a05946162d37e..5e7cbfbe6eb952 100644 --- a/x-pack/plugins/alerting/server/routes/get_alert_state.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/get_alert_state.ts @@ -6,10 +6,10 @@ */ import { schema } from '@kbn/config-schema'; -import type { AlertingRouter } from '../types'; -import { ILicenseState } from '../lib/license_state'; -import { verifyApiAccess } from '../lib/license_api_access'; -import { BASE_ALERT_API_PATH } from '../../common'; +import type { AlertingRouter } from '../../types'; +import { ILicenseState } from '../../lib/license_state'; +import { verifyApiAccess } from '../../lib/license_api_access'; +import { LEGACY_BASE_ALERT_API_PATH } from '../../../common'; const paramSchema = schema.object({ id: schema.string(), @@ -18,7 +18,7 @@ const paramSchema = schema.object({ export const getAlertStateRoute = (router: AlertingRouter, licenseState: ILicenseState) => { router.get( { - path: `${BASE_ALERT_API_PATH}/alert/{id}/state`, + path: `${LEGACY_BASE_ALERT_API_PATH}/alert/{id}/state`, validate: { params: paramSchema, }, diff --git a/x-pack/plugins/alerting/server/routes/legacy/health.test.ts b/x-pack/plugins/alerting/server/routes/legacy/health.test.ts new file mode 100644 index 00000000000000..74de5f70a32e77 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/legacy/health.test.ts @@ -0,0 +1,336 @@ +/* + * 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 { healthRoute } from './health'; +import { httpServiceMock } from 'src/core/server/mocks'; +import { mockHandlerArguments } from './../_mock_handler_arguments'; +import { elasticsearchServiceMock } from '../../../../../../src/core/server/mocks'; +import { verifyApiAccess } from '../../lib/license_api_access'; +import { licenseStateMock } from '../../lib/license_state.mock'; +import { encryptedSavedObjectsMock } from '../../../../encrypted_saved_objects/server/mocks'; +import { alertsClientMock } from '../../alerts_client.mock'; +import { HealthStatus } from '../../types'; +import { alertsMock } from '../../mocks'; +const alertsClient = alertsClientMock.create(); + +jest.mock('../../lib/license_api_access.ts', () => ({ + verifyApiAccess: jest.fn(), +})); + +const alerting = alertsMock.createStart(); + +const currentDate = new Date().toISOString(); +beforeEach(() => { + jest.resetAllMocks(); + alerting.getFrameworkHealth.mockResolvedValue({ + decryptionHealth: { + status: HealthStatus.OK, + timestamp: currentDate, + }, + executionHealth: { + status: HealthStatus.OK, + timestamp: currentDate, + }, + readHealth: { + status: HealthStatus.OK, + timestamp: currentDate, + }, + }); +}); + +describe('healthRoute', () => { + it('registers the route', async () => { + const router = httpServiceMock.createRouter(); + + const licenseState = licenseStateMock.create(); + const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); + healthRoute(router, licenseState, encryptedSavedObjects); + + const [config] = router.get.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/api/alerts/_health"`); + }); + + it('queries the usage api', async () => { + const router = httpServiceMock.createRouter(); + + const licenseState = licenseStateMock.create(); + const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); + healthRoute(router, licenseState, encryptedSavedObjects); + const [, handler] = router.get.mock.calls[0]; + + const esClient = elasticsearchServiceMock.createScopedClusterClient(); + esClient.asInternalUser.transport.request.mockReturnValue( + elasticsearchServiceMock.createSuccessTransportRequestPromise({}) + ); + + const [context, req, res] = mockHandlerArguments({ esClient, alertsClient }, {}, ['ok']); + + await handler(context, req, res); + + expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); + + expect(esClient.asInternalUser.transport.request.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "method": "GET", + "path": "/_xpack/usage", + }, + ] + `); + }); + + it('evaluates whether Encrypted Saved Objects is missing encryption key', async () => { + const router = httpServiceMock.createRouter(); + + const licenseState = licenseStateMock.create(); + const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: false }); + healthRoute(router, licenseState, encryptedSavedObjects); + const [, handler] = router.get.mock.calls[0]; + + const esClient = elasticsearchServiceMock.createScopedClusterClient(); + esClient.asInternalUser.transport.request.mockReturnValue( + elasticsearchServiceMock.createSuccessTransportRequestPromise({}) + ); + + const [context, req, res] = mockHandlerArguments( + { esClient, alertsClient, getFrameworkHealth: alerting.getFrameworkHealth }, + {}, + ['ok'] + ); + + expect(await handler(context, req, res)).toStrictEqual({ + body: { + alertingFrameworkHeath: { + decryptionHealth: { + status: HealthStatus.OK, + timestamp: currentDate, + }, + executionHealth: { + status: HealthStatus.OK, + timestamp: currentDate, + }, + readHealth: { + status: HealthStatus.OK, + timestamp: currentDate, + }, + }, + hasPermanentEncryptionKey: false, + isSufficientlySecure: true, + }, + }); + }); + + it('evaluates missing security info from the usage api to mean that the security plugin is disbled', async () => { + const router = httpServiceMock.createRouter(); + + const licenseState = licenseStateMock.create(); + const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); + healthRoute(router, licenseState, encryptedSavedObjects); + const [, handler] = router.get.mock.calls[0]; + + const esClient = elasticsearchServiceMock.createScopedClusterClient(); + esClient.asInternalUser.transport.request.mockReturnValue( + elasticsearchServiceMock.createSuccessTransportRequestPromise({}) + ); + + const [context, req, res] = mockHandlerArguments( + { esClient, alertsClient, getFrameworkHealth: alerting.getFrameworkHealth }, + {}, + ['ok'] + ); + + expect(await handler(context, req, res)).toStrictEqual({ + body: { + alertingFrameworkHeath: { + decryptionHealth: { + status: HealthStatus.OK, + timestamp: currentDate, + }, + executionHealth: { + status: HealthStatus.OK, + timestamp: currentDate, + }, + readHealth: { + status: HealthStatus.OK, + timestamp: currentDate, + }, + }, + hasPermanentEncryptionKey: true, + isSufficientlySecure: true, + }, + }); + }); + + it('evaluates missing security http info from the usage api to mean that the security plugin is disbled', async () => { + const router = httpServiceMock.createRouter(); + + const licenseState = licenseStateMock.create(); + const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); + healthRoute(router, licenseState, encryptedSavedObjects); + const [, handler] = router.get.mock.calls[0]; + + const esClient = elasticsearchServiceMock.createScopedClusterClient(); + esClient.asInternalUser.transport.request.mockReturnValue( + elasticsearchServiceMock.createSuccessTransportRequestPromise({}) + ); + + const [context, req, res] = mockHandlerArguments( + { esClient, alertsClient, getFrameworkHealth: alerting.getFrameworkHealth }, + {}, + ['ok'] + ); + + expect(await handler(context, req, res)).toStrictEqual({ + body: { + alertingFrameworkHeath: { + decryptionHealth: { + status: HealthStatus.OK, + timestamp: currentDate, + }, + executionHealth: { + status: HealthStatus.OK, + timestamp: currentDate, + }, + readHealth: { + status: HealthStatus.OK, + timestamp: currentDate, + }, + }, + hasPermanentEncryptionKey: true, + isSufficientlySecure: true, + }, + }); + }); + + it('evaluates security enabled, and missing ssl info from the usage api to mean that the user cannot generate keys', async () => { + const router = httpServiceMock.createRouter(); + + const licenseState = licenseStateMock.create(); + const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); + healthRoute(router, licenseState, encryptedSavedObjects); + const [, handler] = router.get.mock.calls[0]; + + const esClient = elasticsearchServiceMock.createScopedClusterClient(); + esClient.asInternalUser.transport.request.mockReturnValue( + elasticsearchServiceMock.createSuccessTransportRequestPromise({ security: { enabled: true } }) + ); + + const [context, req, res] = mockHandlerArguments( + { esClient, alertsClient, getFrameworkHealth: alerting.getFrameworkHealth }, + {}, + ['ok'] + ); + + expect(await handler(context, req, res)).toStrictEqual({ + body: { + alertingFrameworkHeath: { + decryptionHealth: { + status: HealthStatus.OK, + timestamp: currentDate, + }, + executionHealth: { + status: HealthStatus.OK, + timestamp: currentDate, + }, + readHealth: { + status: HealthStatus.OK, + timestamp: currentDate, + }, + }, + hasPermanentEncryptionKey: true, + isSufficientlySecure: false, + }, + }); + }); + + it('evaluates security enabled, SSL info present but missing http info from the usage api to mean that the user cannot generate keys', async () => { + const router = httpServiceMock.createRouter(); + + const licenseState = licenseStateMock.create(); + const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); + healthRoute(router, licenseState, encryptedSavedObjects); + const [, handler] = router.get.mock.calls[0]; + + const esClient = elasticsearchServiceMock.createScopedClusterClient(); + esClient.asInternalUser.transport.request.mockReturnValue( + elasticsearchServiceMock.createSuccessTransportRequestPromise({ + security: { enabled: true, ssl: {} }, + }) + ); + + const [context, req, res] = mockHandlerArguments( + { esClient, alertsClient, getFrameworkHealth: alerting.getFrameworkHealth }, + {}, + ['ok'] + ); + + expect(await handler(context, req, res)).toStrictEqual({ + body: { + alertingFrameworkHeath: { + decryptionHealth: { + status: HealthStatus.OK, + timestamp: currentDate, + }, + executionHealth: { + status: HealthStatus.OK, + timestamp: currentDate, + }, + readHealth: { + status: HealthStatus.OK, + timestamp: currentDate, + }, + }, + hasPermanentEncryptionKey: true, + isSufficientlySecure: false, + }, + }); + }); + + it('evaluates security and tls enabled to mean that the user can generate keys', async () => { + const router = httpServiceMock.createRouter(); + + const licenseState = licenseStateMock.create(); + const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); + healthRoute(router, licenseState, encryptedSavedObjects); + const [, handler] = router.get.mock.calls[0]; + + const esClient = elasticsearchServiceMock.createScopedClusterClient(); + esClient.asInternalUser.transport.request.mockReturnValue( + elasticsearchServiceMock.createSuccessTransportRequestPromise({ + security: { enabled: true, ssl: { http: { enabled: true } } }, + }) + ); + + const [context, req, res] = mockHandlerArguments( + { esClient, alertsClient, getFrameworkHealth: alerting.getFrameworkHealth }, + {}, + ['ok'] + ); + + expect(await handler(context, req, res)).toStrictEqual({ + body: { + alertingFrameworkHeath: { + decryptionHealth: { + status: HealthStatus.OK, + timestamp: currentDate, + }, + executionHealth: { + status: HealthStatus.OK, + timestamp: currentDate, + }, + readHealth: { + status: HealthStatus.OK, + timestamp: currentDate, + }, + }, + hasPermanentEncryptionKey: true, + isSufficientlySecure: true, + }, + }); + }); +}); diff --git a/x-pack/plugins/alerting/server/routes/legacy/health.ts b/x-pack/plugins/alerting/server/routes/legacy/health.ts new file mode 100644 index 00000000000000..b9906a56ce9724 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/legacy/health.ts @@ -0,0 +1,71 @@ +/* + * 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 { ApiResponse } from '@elastic/elasticsearch'; +import type { AlertingRouter } from '../../types'; +import { ILicenseState } from '../../lib/license_state'; +import { verifyApiAccess } from '../../lib/license_api_access'; +import { AlertingFrameworkHealth } from '../../types'; +import { EncryptedSavedObjectsPluginSetup } from '../../../../encrypted_saved_objects/server'; + +interface XPackUsageSecurity { + security?: { + enabled?: boolean; + ssl?: { + http?: { + enabled?: boolean; + }; + }; + }; +} + +export function healthRoute( + router: AlertingRouter, + licenseState: ILicenseState, + encryptedSavedObjects: EncryptedSavedObjectsPluginSetup +) { + router.get( + { + path: '/api/alerts/_health', + validate: false, + }, + router.handleLegacyErrors(async function (context, req, res) { + verifyApiAccess(licenseState); + if (!context.alerting) { + return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); + } + try { + const { + body: { + security: { + enabled: isSecurityEnabled = false, + ssl: { http: { enabled: isTLSEnabled = false } = {} } = {}, + } = {}, + }, + }: ApiResponse = await context.core.elasticsearch.client.asInternalUser.transport // Do not augment with such input. // `transport.request` is potentially unsafe when combined with untrusted user input. + .request({ + method: 'GET', + path: '/_xpack/usage', + }); + + const alertingFrameworkHeath = await context.alerting.getFrameworkHealth(); + + const frameworkHealth: AlertingFrameworkHealth = { + isSufficientlySecure: !isSecurityEnabled || (isSecurityEnabled && isTLSEnabled), + hasPermanentEncryptionKey: encryptedSavedObjects.canEncrypt, + alertingFrameworkHeath, + }; + + return res.ok({ + body: frameworkHealth, + }); + } catch (error) { + return res.badRequest({ body: error }); + } + }) + ); +} diff --git a/x-pack/plugins/alerting/server/routes/legacy/index.ts b/x-pack/plugins/alerting/server/routes/legacy/index.ts new file mode 100644 index 00000000000000..d1b2f9784f24d5 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/legacy/index.ts @@ -0,0 +1,53 @@ +/* + * 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 { IRouter } from 'kibana/server'; +import { ILicenseState } from '../../lib'; +import { AlertingRequestHandlerContext } from '../../types'; +import { EncryptedSavedObjectsPluginSetup } from '../../../../encrypted_saved_objects/server'; + +import { aggregateAlertRoute } from './aggregate'; +import { createAlertRoute } from './create'; +import { deleteAlertRoute } from './delete'; +import { findAlertRoute } from './find'; +import { getAlertRoute } from './get'; +import { getAlertStateRoute } from './get_alert_state'; +import { getAlertInstanceSummaryRoute } from './get_alert_instance_summary'; +import { listAlertTypesRoute } from './list_alert_types'; +import { updateAlertRoute } from './update'; +import { enableAlertRoute } from './enable'; +import { disableAlertRoute } from './disable'; +import { updateApiKeyRoute } from './update_api_key'; +import { muteAlertInstanceRoute } from './mute_instance'; +import { unmuteAlertInstanceRoute } from './unmute_instance'; +import { muteAllAlertRoute } from './mute_all'; +import { unmuteAllAlertRoute } from './unmute_all'; +import { healthRoute } from './health'; + +export function defineLegacyRoutes( + router: IRouter, + licenseState: ILicenseState, + encryptedSavedObjects: EncryptedSavedObjectsPluginSetup +) { + aggregateAlertRoute(router, licenseState); + createAlertRoute(router, licenseState); + deleteAlertRoute(router, licenseState); + findAlertRoute(router, licenseState); + getAlertRoute(router, licenseState); + getAlertStateRoute(router, licenseState); + getAlertInstanceSummaryRoute(router, licenseState); + listAlertTypesRoute(router, licenseState); + updateAlertRoute(router, licenseState); + enableAlertRoute(router, licenseState); + disableAlertRoute(router, licenseState); + updateApiKeyRoute(router, licenseState); + muteAllAlertRoute(router, licenseState); + unmuteAllAlertRoute(router, licenseState); + muteAlertInstanceRoute(router, licenseState); + unmuteAlertInstanceRoute(router, licenseState); + healthRoute(router, licenseState, encryptedSavedObjects); +} diff --git a/x-pack/plugins/alerting/server/routes/list_alert_types.test.ts b/x-pack/plugins/alerting/server/routes/legacy/list_alert_types.test.ts similarity index 92% rename from x-pack/plugins/alerting/server/routes/list_alert_types.test.ts rename to x-pack/plugins/alerting/server/routes/legacy/list_alert_types.test.ts index 5ef2e8cc9ec7d5..3e6f2f484a6d87 100644 --- a/x-pack/plugins/alerting/server/routes/list_alert_types.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/list_alert_types.test.ts @@ -7,16 +7,16 @@ import { listAlertTypesRoute } from './list_alert_types'; import { httpServiceMock } from 'src/core/server/mocks'; -import { licenseStateMock } from '../lib/license_state.mock'; -import { verifyApiAccess } from '../lib/license_api_access'; -import { mockHandlerArguments } from './_mock_handler_arguments'; -import { alertsClientMock } from '../alerts_client.mock'; -import { RecoveredActionGroup } from '../../common'; -import { RegistryAlertTypeWithAuth } from '../authorization'; +import { licenseStateMock } from '../../lib/license_state.mock'; +import { verifyApiAccess } from '../../lib/license_api_access'; +import { mockHandlerArguments } from './../_mock_handler_arguments'; +import { alertsClientMock } from '../../alerts_client.mock'; +import { RecoveredActionGroup } from '../../../common'; +import { RegistryAlertTypeWithAuth } from '../../authorization'; const alertsClient = alertsClientMock.create(); -jest.mock('../lib/license_api_access.ts', () => ({ +jest.mock('../../lib/license_api_access.ts', () => ({ verifyApiAccess: jest.fn(), })); diff --git a/x-pack/plugins/alerting/server/routes/list_alert_types.ts b/x-pack/plugins/alerting/server/routes/legacy/list_alert_types.ts similarity index 72% rename from x-pack/plugins/alerting/server/routes/list_alert_types.ts rename to x-pack/plugins/alerting/server/routes/legacy/list_alert_types.ts index 2040f71f8ad054..da41cc487228c8 100644 --- a/x-pack/plugins/alerting/server/routes/list_alert_types.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/list_alert_types.ts @@ -5,15 +5,15 @@ * 2.0. */ -import type { AlertingRouter } from '../types'; -import { ILicenseState } from '../lib/license_state'; -import { verifyApiAccess } from '../lib/license_api_access'; -import { BASE_ALERT_API_PATH } from '../../common'; +import type { AlertingRouter } from '../../types'; +import { ILicenseState } from '../../lib/license_state'; +import { verifyApiAccess } from '../../lib/license_api_access'; +import { LEGACY_BASE_ALERT_API_PATH } from '../../../common'; export const listAlertTypesRoute = (router: AlertingRouter, licenseState: ILicenseState) => { router.get( { - path: `${BASE_ALERT_API_PATH}/list_alert_types`, + path: `${LEGACY_BASE_ALERT_API_PATH}/list_alert_types`, validate: {}, }, router.handleLegacyErrors(async function (context, req, res) { diff --git a/x-pack/plugins/alerting/server/routes/mute_all.test.ts b/x-pack/plugins/alerting/server/routes/legacy/mute_all.test.ts similarity index 86% rename from x-pack/plugins/alerting/server/routes/mute_all.test.ts rename to x-pack/plugins/alerting/server/routes/legacy/mute_all.test.ts index 8c938d71ab06c2..ffe893fa604905 100644 --- a/x-pack/plugins/alerting/server/routes/mute_all.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/mute_all.test.ts @@ -7,13 +7,13 @@ import { muteAllAlertRoute } from './mute_all'; import { httpServiceMock } from 'src/core/server/mocks'; -import { licenseStateMock } from '../lib/license_state.mock'; -import { mockHandlerArguments } from './_mock_handler_arguments'; -import { alertsClientMock } from '../alerts_client.mock'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +import { licenseStateMock } from '../../lib/license_state.mock'; +import { mockHandlerArguments } from './../_mock_handler_arguments'; +import { alertsClientMock } from '../../alerts_client.mock'; +import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; const alertsClient = alertsClientMock.create(); -jest.mock('../lib/license_api_access.ts', () => ({ +jest.mock('../../lib/license_api_access.ts', () => ({ verifyApiAccess: jest.fn(), })); diff --git a/x-pack/plugins/alerting/server/routes/mute_all.ts b/x-pack/plugins/alerting/server/routes/legacy/mute_all.ts similarity index 74% rename from x-pack/plugins/alerting/server/routes/mute_all.ts rename to x-pack/plugins/alerting/server/routes/legacy/mute_all.ts index fee1fdfe5a4f7b..643aeb97084a81 100644 --- a/x-pack/plugins/alerting/server/routes/mute_all.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/mute_all.ts @@ -6,11 +6,11 @@ */ import { schema } from '@kbn/config-schema'; -import type { AlertingRouter } from '../types'; -import { ILicenseState } from '../lib/license_state'; -import { verifyApiAccess } from '../lib/license_api_access'; -import { BASE_ALERT_API_PATH } from '../../common'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +import type { AlertingRouter } from '../../types'; +import { ILicenseState } from '../../lib/license_state'; +import { verifyApiAccess } from '../../lib/license_api_access'; +import { LEGACY_BASE_ALERT_API_PATH } from '../../../common'; +import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; const paramSchema = schema.object({ id: schema.string(), @@ -19,7 +19,7 @@ const paramSchema = schema.object({ export const muteAllAlertRoute = (router: AlertingRouter, licenseState: ILicenseState) => { router.post( { - path: `${BASE_ALERT_API_PATH}/alert/{id}/_mute_all`, + path: `${LEGACY_BASE_ALERT_API_PATH}/alert/{id}/_mute_all`, validate: { params: paramSchema, }, diff --git a/x-pack/plugins/alerting/server/routes/mute_instance.test.ts b/x-pack/plugins/alerting/server/routes/legacy/mute_instance.test.ts similarity index 87% rename from x-pack/plugins/alerting/server/routes/mute_instance.test.ts rename to x-pack/plugins/alerting/server/routes/legacy/mute_instance.test.ts index 83bf57f5259a3f..a00c75663c5f01 100644 --- a/x-pack/plugins/alerting/server/routes/mute_instance.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/mute_instance.test.ts @@ -7,13 +7,13 @@ import { muteAlertInstanceRoute } from './mute_instance'; import { httpServiceMock } from 'src/core/server/mocks'; -import { licenseStateMock } from '../lib/license_state.mock'; -import { mockHandlerArguments } from './_mock_handler_arguments'; -import { alertsClientMock } from '../alerts_client.mock'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +import { licenseStateMock } from '../../lib/license_state.mock'; +import { mockHandlerArguments } from './../_mock_handler_arguments'; +import { alertsClientMock } from '../../alerts_client.mock'; +import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; const alertsClient = alertsClientMock.create(); -jest.mock('../lib/license_api_access.ts', () => ({ +jest.mock('../../lib/license_api_access.ts', () => ({ verifyApiAccess: jest.fn(), })); diff --git a/x-pack/plugins/alerting/server/routes/mute_instance.ts b/x-pack/plugins/alerting/server/routes/legacy/mute_instance.ts similarity index 72% rename from x-pack/plugins/alerting/server/routes/mute_instance.ts rename to x-pack/plugins/alerting/server/routes/legacy/mute_instance.ts index ab7749178f6cf0..2b35f59c7fce16 100644 --- a/x-pack/plugins/alerting/server/routes/mute_instance.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/mute_instance.ts @@ -6,13 +6,13 @@ */ import { schema } from '@kbn/config-schema'; -import type { AlertingRouter } from '../types'; -import { ILicenseState } from '../lib/license_state'; -import { verifyApiAccess } from '../lib/license_api_access'; -import { BASE_ALERT_API_PATH } from '../../common'; -import { renameKeys } from './lib/rename_keys'; -import { MuteOptions } from '../alerts_client'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +import type { AlertingRouter } from '../../types'; +import { ILicenseState } from '../../lib/license_state'; +import { verifyApiAccess } from '../../lib/license_api_access'; +import { LEGACY_BASE_ALERT_API_PATH } from '../../../common'; +import { renameKeys } from './../lib/rename_keys'; +import { MuteOptions } from '../../alerts_client'; +import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; const paramSchema = schema.object({ alert_id: schema.string(), @@ -22,7 +22,7 @@ const paramSchema = schema.object({ export const muteAlertInstanceRoute = (router: AlertingRouter, licenseState: ILicenseState) => { router.post( { - path: `${BASE_ALERT_API_PATH}/alert/{alert_id}/alert_instance/{alert_instance_id}/_mute`, + path: `${LEGACY_BASE_ALERT_API_PATH}/alert/{alert_id}/alert_instance/{alert_instance_id}/_mute`, validate: { params: paramSchema, }, diff --git a/x-pack/plugins/alerting/server/routes/unmute_all.test.ts b/x-pack/plugins/alerting/server/routes/legacy/unmute_all.test.ts similarity index 86% rename from x-pack/plugins/alerting/server/routes/unmute_all.test.ts rename to x-pack/plugins/alerting/server/routes/legacy/unmute_all.test.ts index 0c2d3105e581cc..8511a8b68a4476 100644 --- a/x-pack/plugins/alerting/server/routes/unmute_all.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/unmute_all.test.ts @@ -7,13 +7,13 @@ import { unmuteAllAlertRoute } from './unmute_all'; import { httpServiceMock } from 'src/core/server/mocks'; -import { licenseStateMock } from '../lib/license_state.mock'; -import { mockHandlerArguments } from './_mock_handler_arguments'; -import { alertsClientMock } from '../alerts_client.mock'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +import { licenseStateMock } from '../../lib/license_state.mock'; +import { mockHandlerArguments } from './../_mock_handler_arguments'; +import { alertsClientMock } from '../../alerts_client.mock'; +import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; const alertsClient = alertsClientMock.create(); -jest.mock('../lib/license_api_access.ts', () => ({ +jest.mock('../../lib/license_api_access.ts', () => ({ verifyApiAccess: jest.fn(), })); diff --git a/x-pack/plugins/alerting/server/routes/unmute_all.ts b/x-pack/plugins/alerting/server/routes/legacy/unmute_all.ts similarity index 74% rename from x-pack/plugins/alerting/server/routes/unmute_all.ts rename to x-pack/plugins/alerting/server/routes/legacy/unmute_all.ts index 2e67884f8a9449..1259428be3329f 100644 --- a/x-pack/plugins/alerting/server/routes/unmute_all.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/unmute_all.ts @@ -6,11 +6,11 @@ */ import { schema } from '@kbn/config-schema'; -import type { AlertingRouter } from '../types'; -import { ILicenseState } from '../lib/license_state'; -import { verifyApiAccess } from '../lib/license_api_access'; -import { BASE_ALERT_API_PATH } from '../../common'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +import type { AlertingRouter } from '../../types'; +import { ILicenseState } from '../../lib/license_state'; +import { verifyApiAccess } from '../../lib/license_api_access'; +import { LEGACY_BASE_ALERT_API_PATH } from '../../../common'; +import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; const paramSchema = schema.object({ id: schema.string(), @@ -19,7 +19,7 @@ const paramSchema = schema.object({ export const unmuteAllAlertRoute = (router: AlertingRouter, licenseState: ILicenseState) => { router.post( { - path: `${BASE_ALERT_API_PATH}/alert/{id}/_unmute_all`, + path: `${LEGACY_BASE_ALERT_API_PATH}/alert/{id}/_unmute_all`, validate: { params: paramSchema, }, diff --git a/x-pack/plugins/alerting/server/routes/unmute_instance.test.ts b/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.test.ts similarity index 87% rename from x-pack/plugins/alerting/server/routes/unmute_instance.test.ts rename to x-pack/plugins/alerting/server/routes/legacy/unmute_instance.test.ts index eddd00390a7f33..d28868a3c92301 100644 --- a/x-pack/plugins/alerting/server/routes/unmute_instance.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.test.ts @@ -7,13 +7,13 @@ import { unmuteAlertInstanceRoute } from './unmute_instance'; import { httpServiceMock } from 'src/core/server/mocks'; -import { licenseStateMock } from '../lib/license_state.mock'; -import { mockHandlerArguments } from './_mock_handler_arguments'; -import { alertsClientMock } from '../alerts_client.mock'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +import { licenseStateMock } from '../../lib/license_state.mock'; +import { mockHandlerArguments } from './../_mock_handler_arguments'; +import { alertsClientMock } from '../../alerts_client.mock'; +import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; const alertsClient = alertsClientMock.create(); -jest.mock('../lib/license_api_access.ts', () => ({ +jest.mock('../../lib/license_api_access.ts', () => ({ verifyApiAccess: jest.fn(), })); diff --git a/x-pack/plugins/alerting/server/routes/unmute_instance.ts b/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.ts similarity index 74% rename from x-pack/plugins/alerting/server/routes/unmute_instance.ts rename to x-pack/plugins/alerting/server/routes/legacy/unmute_instance.ts index d39fc696eef082..25f5aa654bde14 100644 --- a/x-pack/plugins/alerting/server/routes/unmute_instance.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.ts @@ -6,11 +6,11 @@ */ import { schema } from '@kbn/config-schema'; -import type { AlertingRouter } from '../types'; -import { ILicenseState } from '../lib/license_state'; -import { verifyApiAccess } from '../lib/license_api_access'; -import { BASE_ALERT_API_PATH } from '../../common'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +import type { AlertingRouter } from '../../types'; +import { ILicenseState } from '../../lib/license_state'; +import { verifyApiAccess } from '../../lib/license_api_access'; +import { LEGACY_BASE_ALERT_API_PATH } from '../../../common'; +import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; const paramSchema = schema.object({ alertId: schema.string(), @@ -20,7 +20,7 @@ const paramSchema = schema.object({ export const unmuteAlertInstanceRoute = (router: AlertingRouter, licenseState: ILicenseState) => { router.post( { - path: `${BASE_ALERT_API_PATH}/alert/{alertId}/alert_instance/{alertInstanceId}/_unmute`, + path: `${LEGACY_BASE_ALERT_API_PATH}/alert/{alertId}/alert_instance/{alertInstanceId}/_unmute`, validate: { params: paramSchema, }, diff --git a/x-pack/plugins/alerting/server/routes/update.test.ts b/x-pack/plugins/alerting/server/routes/legacy/update.test.ts similarity index 92% rename from x-pack/plugins/alerting/server/routes/update.test.ts rename to x-pack/plugins/alerting/server/routes/legacy/update.test.ts index 892f1a25844c4d..da58d0dc41522e 100644 --- a/x-pack/plugins/alerting/server/routes/update.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/update.test.ts @@ -7,15 +7,15 @@ import { updateAlertRoute } from './update'; import { httpServiceMock } from 'src/core/server/mocks'; -import { licenseStateMock } from '../lib/license_state.mock'; -import { verifyApiAccess } from '../lib/license_api_access'; -import { mockHandlerArguments } from './_mock_handler_arguments'; -import { alertsClientMock } from '../alerts_client.mock'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; -import { AlertNotifyWhenType } from '../../common'; +import { licenseStateMock } from '../../lib/license_state.mock'; +import { verifyApiAccess } from '../../lib/license_api_access'; +import { mockHandlerArguments } from './../_mock_handler_arguments'; +import { alertsClientMock } from '../../alerts_client.mock'; +import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; +import { AlertNotifyWhenType } from '../../../common'; const alertsClient = alertsClientMock.create(); -jest.mock('../lib/license_api_access.ts', () => ({ +jest.mock('../../lib/license_api_access.ts', () => ({ verifyApiAccess: jest.fn(), })); diff --git a/x-pack/plugins/alerting/server/routes/update.ts b/x-pack/plugins/alerting/server/routes/legacy/update.ts similarity index 81% rename from x-pack/plugins/alerting/server/routes/update.ts rename to x-pack/plugins/alerting/server/routes/legacy/update.ts index 11373e71d14be2..23a0719319e00f 100644 --- a/x-pack/plugins/alerting/server/routes/update.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/update.ts @@ -6,13 +6,17 @@ */ import { schema } from '@kbn/config-schema'; -import type { AlertingRouter } from '../types'; -import { ILicenseState } from '../lib/license_state'; -import { verifyApiAccess } from '../lib/license_api_access'; -import { validateDurationSchema } from '../lib'; -import { handleDisabledApiKeysError } from './lib/error_handler'; -import { AlertNotifyWhenType, BASE_ALERT_API_PATH, validateNotifyWhenType } from '../../common'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +import type { AlertingRouter } from '../../types'; +import { ILicenseState } from '../../lib/license_state'; +import { verifyApiAccess } from '../../lib/license_api_access'; +import { validateDurationSchema } from '../../lib'; +import { handleDisabledApiKeysError } from './../lib/error_handler'; +import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; +import { + AlertNotifyWhenType, + LEGACY_BASE_ALERT_API_PATH, + validateNotifyWhenType, +} from '../../../common'; const paramSchema = schema.object({ id: schema.string(), @@ -41,7 +45,7 @@ const bodySchema = schema.object({ export const updateAlertRoute = (router: AlertingRouter, licenseState: ILicenseState) => { router.put( { - path: `${BASE_ALERT_API_PATH}/alert/{id}`, + path: `${LEGACY_BASE_ALERT_API_PATH}/alert/{id}`, validate: { body: bodySchema, params: paramSchema, diff --git a/x-pack/plugins/alerting/server/routes/update_api_key.test.ts b/x-pack/plugins/alerting/server/routes/legacy/update_api_key.test.ts similarity index 86% rename from x-pack/plugins/alerting/server/routes/update_api_key.test.ts rename to x-pack/plugins/alerting/server/routes/legacy/update_api_key.test.ts index 0added369fd618..3f556f480f69c6 100644 --- a/x-pack/plugins/alerting/server/routes/update_api_key.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/update_api_key.test.ts @@ -7,13 +7,13 @@ import { updateApiKeyRoute } from './update_api_key'; import { httpServiceMock } from 'src/core/server/mocks'; -import { licenseStateMock } from '../lib/license_state.mock'; -import { mockHandlerArguments } from './_mock_handler_arguments'; -import { alertsClientMock } from '../alerts_client.mock'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +import { licenseStateMock } from '../../lib/license_state.mock'; +import { mockHandlerArguments } from './../_mock_handler_arguments'; +import { alertsClientMock } from '../../alerts_client.mock'; +import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; const alertsClient = alertsClientMock.create(); -jest.mock('../lib/license_api_access.ts', () => ({ +jest.mock('../../lib/license_api_access.ts', () => ({ verifyApiAccess: jest.fn(), })); diff --git a/x-pack/plugins/alerting/server/routes/update_api_key.ts b/x-pack/plugins/alerting/server/routes/legacy/update_api_key.ts similarity index 72% rename from x-pack/plugins/alerting/server/routes/update_api_key.ts rename to x-pack/plugins/alerting/server/routes/legacy/update_api_key.ts index a615ee8a5bbd2a..a4da2538b0bf97 100644 --- a/x-pack/plugins/alerting/server/routes/update_api_key.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/update_api_key.ts @@ -6,12 +6,12 @@ */ import { schema } from '@kbn/config-schema'; -import type { AlertingRouter } from '../types'; -import { ILicenseState } from '../lib/license_state'; -import { verifyApiAccess } from '../lib/license_api_access'; -import { BASE_ALERT_API_PATH } from '../../common'; -import { handleDisabledApiKeysError } from './lib/error_handler'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +import type { AlertingRouter } from '../../types'; +import { ILicenseState } from '../../lib/license_state'; +import { verifyApiAccess } from '../../lib/license_api_access'; +import { LEGACY_BASE_ALERT_API_PATH } from '../../../common'; +import { handleDisabledApiKeysError } from './../lib/error_handler'; +import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; const paramSchema = schema.object({ id: schema.string(), @@ -20,7 +20,7 @@ const paramSchema = schema.object({ export const updateApiKeyRoute = (router: AlertingRouter, licenseState: ILicenseState) => { router.post( { - path: `${BASE_ALERT_API_PATH}/alert/{id}/_update_api_key`, + path: `${LEGACY_BASE_ALERT_API_PATH}/alert/{id}/_update_api_key`, validate: { params: paramSchema, }, diff --git a/x-pack/plugins/alerting/server/routes/lib/index.ts b/x-pack/plugins/alerting/server/routes/lib/index.ts new file mode 100644 index 00000000000000..142513e23e5e7f --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/lib/index.ts @@ -0,0 +1,15 @@ +/* + * 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. + */ + +export { + handleDisabledApiKeysError, + isApiKeyDisabledError, + isSecurityPluginDisabledError, +} from './error_handler'; +export { renameKeys } from './rename_keys'; +export { AsApiContract, RewriteRequestCase, RewriteResponseCase } from './rewrite_request_case'; +export { verifyAccessAndContext } from './verify_access_and_context'; diff --git a/x-pack/plugins/alerting/server/routes/lib/rewrite_request_case.ts b/x-pack/plugins/alerting/server/routes/lib/rewrite_request_case.ts new file mode 100644 index 00000000000000..361ba5ff5e55de --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/lib/rewrite_request_case.ts @@ -0,0 +1,82 @@ +/* + * 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 { JsonValue } from '../../../../../../src/plugins/kibana_utils/common'; + +type RenameAlertToRule = K extends `alertTypeId` + ? `ruleTypeId` + : K extends `alertId` + ? `ruleId` + : K extends `alertExecutionStatus` + ? `ruleExecutionStatus` + : K extends `actionTypeId` + ? `connectorTypeId` + : K extends `alertInstanceId` + ? `alertId` + : K extends `mutedInstanceIds` + ? `mutedAlertIds` + : K extends `instances` + ? `alerts` + : K; + +export type AsApiContract< + T, + ComplexPropertyKeys = `actions` | `executionStatus`, + OpaquePropertyKeys = `params` +> = T extends Array + ? Array> + : { + [K in keyof T as CamelToSnake< + RenameAlertToRule> + >]: K extends OpaquePropertyKeys + ? // don't convert explciitly opaque types which we treat as a black box + T[K] + : T[K] extends undefined + ? AsApiContract> | undefined + : // don't convert built in types + T[K] extends Date | JsonValue + ? T[K] + : T[K] extends Array + ? Array> + : K extends ComplexPropertyKeys + ? AsApiContract + : T[K] extends object + ? AsApiContract + : // don't convert anything else + T[K]; + }; + +export type RewriteRequestCase = (requested: AsApiContract) => T; +export type RewriteResponseCase = ( + responded: T +) => T extends Array ? Array> : AsApiContract; + +/** + * This type maps Camel Case strings into their Snake Case version. + * This is achieved by checking each character and, if it is an uppercase character, it is mapped to an + * underscore followed by a lowercase one. + * + * The reason there are two ternaries is that, for perfformance reasons, TS limits its + * character parsing to ~15 characters. + * To get around this we use the second turnery to parse 2 characters at a time, which allows us to support + * strings that are 30 characters long. + * + * If you get the TS #2589 error ("Type instantiation is excessively deep and possibly infinite") then most + * likely you have a string that's longer than 30 characters. + * Address this by reducing the length if possible, otherwise, you'll need to add a 3rd ternary which + * parses 3 chars at a time :grimace: + * + * For more details see this PR comment: https://github.com/microsoft/TypeScript/pull/40336#issuecomment-686723087 + */ +type CamelToSnake = string extends T + ? string + : T extends `${infer C0}${infer C1}${infer R}` + ? `${C0 extends Uppercase ? '_' : ''}${Lowercase}${C1 extends Uppercase + ? '_' + : ''}${Lowercase}${CamelToSnake}` + : T extends `${infer C0}${infer R}` + ? `${C0 extends Uppercase ? '_' : ''}${Lowercase}${CamelToSnake}` + : ''; diff --git a/x-pack/plugins/alerting/server/routes/lib/verify_access_and_context.ts b/x-pack/plugins/alerting/server/routes/lib/verify_access_and_context.ts new file mode 100644 index 00000000000000..f0177f04bf9b27 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/lib/verify_access_and_context.ts @@ -0,0 +1,34 @@ +/* + * 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 { RequestHandler } from 'kibana/server'; +import { ILicenseState, isErrorThatHandlesItsOwnResponse, verifyApiAccess } from '../../lib'; +import { AlertingRequestHandlerContext } from '../../types'; + +type AlertingRequestHandlerWrapper = ( + licenseState: ILicenseState, + handler: RequestHandler +) => RequestHandler; + +export const verifyAccessAndContext: AlertingRequestHandlerWrapper = (licenseState, handler) => { + return async (context, request, response) => { + verifyApiAccess(licenseState); + + if (!context.alerting) { + return response.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); + } + + try { + return await handler(context, request, response); + } catch (e) { + if (isErrorThatHandlesItsOwnResponse(e)) { + return e.sendResponse(response); + } + throw e; + } + }; +}; diff --git a/x-pack/plugins/alerting/server/routes/mute_alert.test.ts b/x-pack/plugins/alerting/server/routes/mute_alert.test.ts new file mode 100644 index 00000000000000..64ba22f2980ecb --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/mute_alert.test.ts @@ -0,0 +1,86 @@ +/* + * 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 { muteAlertRoute } from './mute_alert'; +import { httpServiceMock } from 'src/core/server/mocks'; +import { licenseStateMock } from '../lib/license_state.mock'; +import { mockHandlerArguments } from './_mock_handler_arguments'; +import { alertsClientMock } from '../alerts_client.mock'; +import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; + +const alertsClient = alertsClientMock.create(); +jest.mock('../lib/license_api_access.ts', () => ({ + verifyApiAccess: jest.fn(), +})); + +beforeEach(() => { + jest.resetAllMocks(); +}); + +describe('muteAlertRoute', () => { + it('mutes an alert', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + muteAlertRoute(router, licenseState); + + const [config, handler] = router.post.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot( + `"/api/alerting/rule/{rule_id}/alert/{alert_id}/_mute"` + ); + + alertsClient.muteInstance.mockResolvedValueOnce(); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + params: { + rule_id: '1', + alert_id: '2', + }, + }, + ['noContent'] + ); + + expect(await handler(context, req, res)).toEqual(undefined); + + expect(alertsClient.muteInstance).toHaveBeenCalledTimes(1); + expect(alertsClient.muteInstance.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "alertId": "1", + "alertInstanceId": "2", + }, + ] + `); + + expect(res.noContent).toHaveBeenCalled(); + }); + + it('ensures the rule type gets validated for the license', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + muteAlertRoute(router, licenseState); + + const [, handler] = router.post.mock.calls[0]; + + alertsClient.muteInstance.mockRejectedValue( + new AlertTypeDisabledError('Fail', 'license_invalid') + ); + + const [context, req, res] = mockHandlerArguments({ alertsClient }, { params: {}, body: {} }, [ + 'ok', + 'forbidden', + ]); + + await handler(context, req, res); + + expect(res.forbidden).toHaveBeenCalledWith({ body: { message: 'Fail' } }); + }); +}); diff --git a/x-pack/plugins/alerting/server/routes/mute_alert.ts b/x-pack/plugins/alerting/server/routes/mute_alert.ts new file mode 100644 index 00000000000000..f1b928cf8c543b --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/mute_alert.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { IRouter } from 'kibana/server'; +import { schema } from '@kbn/config-schema'; +import { ILicenseState, AlertTypeDisabledError } from '../lib'; +import { MuteOptions } from '../alerts_client'; +import { RewriteRequestCase, verifyAccessAndContext } from './lib'; +import { AlertingRequestHandlerContext, BASE_ALERTING_API_PATH } from '../types'; + +const paramSchema = schema.object({ + rule_id: schema.string(), + alert_id: schema.string(), +}); + +const rewriteParamsReq: RewriteRequestCase = ({ + rule_id: alertId, + alert_id: alertInstanceId, +}) => ({ + alertId, + alertInstanceId, +}); + +export const muteAlertRoute = ( + router: IRouter, + licenseState: ILicenseState +) => { + router.post( + { + path: `${BASE_ALERTING_API_PATH}/rule/{rule_id}/alert/{alert_id}/_mute`, + validate: { + params: paramSchema, + }, + }, + router.handleLegacyErrors( + verifyAccessAndContext(licenseState, async function (context, req, res) { + const alertsClient = context.alerting.getAlertsClient(); + const params = rewriteParamsReq(req.params); + try { + await alertsClient.muteInstance(params); + return res.noContent(); + } catch (e) { + if (e instanceof AlertTypeDisabledError) { + return e.sendResponse(res); + } + throw e; + } + }) + ) + ); +}; diff --git a/x-pack/plugins/alerting/server/routes/mute_all_rule.test.ts b/x-pack/plugins/alerting/server/routes/mute_all_rule.test.ts new file mode 100644 index 00000000000000..0d53708db2567d --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/mute_all_rule.test.ts @@ -0,0 +1,80 @@ +/* + * 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 { muteAllRuleRoute } from './mute_all_rule'; +import { httpServiceMock } from 'src/core/server/mocks'; +import { licenseStateMock } from '../lib/license_state.mock'; +import { mockHandlerArguments } from './_mock_handler_arguments'; +import { alertsClientMock } from '../alerts_client.mock'; +import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; + +const alertsClient = alertsClientMock.create(); +jest.mock('../lib/license_api_access.ts', () => ({ + verifyApiAccess: jest.fn(), +})); + +beforeEach(() => { + jest.resetAllMocks(); +}); + +describe('muteAllRuleRoute', () => { + it('mute a rule', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + muteAllRuleRoute(router, licenseState); + + const [config, handler] = router.post.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/api/alerting/rule/{id}/_mute_all"`); + + alertsClient.muteAll.mockResolvedValueOnce(); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + params: { + id: '1', + }, + }, + ['noContent'] + ); + + expect(await handler(context, req, res)).toEqual(undefined); + + expect(alertsClient.muteAll).toHaveBeenCalledTimes(1); + expect(alertsClient.muteAll.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "id": "1", + }, + ] + `); + + expect(res.noContent).toHaveBeenCalled(); + }); + + it('ensures the rule type gets validated for the license', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + muteAllRuleRoute(router, licenseState); + + const [, handler] = router.post.mock.calls[0]; + + alertsClient.muteAll.mockRejectedValue(new AlertTypeDisabledError('Fail', 'license_invalid')); + + const [context, req, res] = mockHandlerArguments({ alertsClient }, { params: {}, body: {} }, [ + 'ok', + 'forbidden', + ]); + + await handler(context, req, res); + + expect(res.forbidden).toHaveBeenCalledWith({ body: { message: 'Fail' } }); + }); +}); diff --git a/x-pack/plugins/alerting/server/routes/mute_all_rule.ts b/x-pack/plugins/alerting/server/routes/mute_all_rule.ts new file mode 100644 index 00000000000000..29d40249ef0797 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/mute_all_rule.ts @@ -0,0 +1,45 @@ +/* + * 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 { IRouter } from 'kibana/server'; +import { schema } from '@kbn/config-schema'; +import { ILicenseState, AlertTypeDisabledError } from '../lib'; +import { verifyAccessAndContext } from './lib'; +import { AlertingRequestHandlerContext, BASE_ALERTING_API_PATH } from '../types'; + +const paramSchema = schema.object({ + id: schema.string(), +}); + +export const muteAllRuleRoute = ( + router: IRouter, + licenseState: ILicenseState +) => { + router.post( + { + path: `${BASE_ALERTING_API_PATH}/rule/{id}/_mute_all`, + validate: { + params: paramSchema, + }, + }, + router.handleLegacyErrors( + verifyAccessAndContext(licenseState, async function (context, req, res) { + const alertsClient = context.alerting.getAlertsClient(); + const { id } = req.params; + try { + await alertsClient.muteAll({ id }); + return res.noContent(); + } catch (e) { + if (e instanceof AlertTypeDisabledError) { + return e.sendResponse(res); + } + throw e; + } + }) + ) + ); +}; diff --git a/x-pack/plugins/alerting/server/routes/rule_types.test.ts b/x-pack/plugins/alerting/server/routes/rule_types.test.ts new file mode 100644 index 00000000000000..58c9a4b4c46fd0 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/rule_types.test.ts @@ -0,0 +1,223 @@ +/* + * 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 { ruleTypesRoute } from './rule_types'; +import { httpServiceMock } from 'src/core/server/mocks'; +import { licenseStateMock } from '../lib/license_state.mock'; +import { verifyApiAccess } from '../lib/license_api_access'; +import { mockHandlerArguments } from './_mock_handler_arguments'; +import { alertsClientMock } from '../alerts_client.mock'; +import { RecoveredActionGroup } from '../../common'; +import { RegistryAlertTypeWithAuth } from '../authorization'; +import { AsApiContract } from './lib'; + +const alertsClient = alertsClientMock.create(); + +jest.mock('../lib/license_api_access.ts', () => ({ + verifyApiAccess: jest.fn(), +})); + +beforeEach(() => { + jest.resetAllMocks(); +}); + +describe('ruleTypesRoute', () => { + it('lists rule types with proper parameters', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + ruleTypesRoute(router, licenseState); + + const [config, handler] = router.get.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/api/alerting/rule_types"`); + + const listTypes = [ + { + id: '1', + name: 'name', + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + recoveryActionGroup: RecoveredActionGroup, + authorizedConsumers: {}, + actionVariables: { + context: [], + state: [], + }, + producer: 'test', + enabledInLicense: true, + } as RegistryAlertTypeWithAuth, + ]; + const expectedResult: Array> = [ + { + id: '1', + name: 'name', + action_groups: [ + { + id: 'default', + name: 'Default', + }, + ], + default_action_group_id: 'default', + minimum_license_required: 'basic', + recovery_action_group: RecoveredActionGroup, + authorized_consumers: {}, + action_variables: { + context: [], + state: [], + }, + producer: 'test', + enabled_in_license: true, + }, + ]; + alertsClient.listAlertTypes.mockResolvedValueOnce(new Set(listTypes)); + + const [context, req, res] = mockHandlerArguments({ alertsClient }, {}, ['ok']); + + expect(await handler(context, req, res)).toMatchInlineSnapshot(` + Object { + "body": Array [ + Object { + "action_groups": Array [ + Object { + "id": "default", + "name": "Default", + }, + ], + "action_variables": Object { + "context": Array [], + "state": Array [], + }, + "authorized_consumers": Object {}, + "default_action_group_id": "default", + "enabled_in_license": true, + "id": "1", + "minimum_license_required": "basic", + "name": "name", + "producer": "test", + "recovery_action_group": Object { + "id": "recovered", + "name": "Recovered", + }, + }, + ], + } + `); + + expect(alertsClient.listAlertTypes).toHaveBeenCalledTimes(1); + + expect(res.ok).toHaveBeenCalledWith({ + body: expectedResult, + }); + }); + + it('ensures the license allows listing rule types', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + ruleTypesRoute(router, licenseState); + + const [config, handler] = router.get.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/api/alerting/rule_types"`); + + const listTypes = [ + { + id: '1', + name: 'name', + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + recoveryActionGroup: RecoveredActionGroup, + authorizedConsumers: {}, + actionVariables: { + context: [], + state: [], + }, + producer: 'alerts', + enabledInLicense: true, + } as RegistryAlertTypeWithAuth, + ]; + + alertsClient.listAlertTypes.mockResolvedValueOnce(new Set(listTypes)); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + params: { id: '1' }, + }, + ['ok'] + ); + + await handler(context, req, res); + + expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); + }); + + it('ensures the license check prevents listing rule types', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + (verifyApiAccess as jest.Mock).mockImplementation(() => { + throw new Error('OMG'); + }); + + ruleTypesRoute(router, licenseState); + + const [config, handler] = router.get.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/api/alerting/rule_types"`); + + const listTypes = [ + { + id: '1', + name: 'name', + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + recoveryActionGroup: RecoveredActionGroup, + authorizedConsumers: {}, + actionVariables: { + context: [], + state: [], + }, + producer: 'alerts', + enabledInLicense: true, + } as RegistryAlertTypeWithAuth, + ]; + + alertsClient.listAlertTypes.mockResolvedValueOnce(new Set(listTypes)); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + params: { id: '1' }, + }, + ['ok'] + ); + + expect(handler(context, req, res)).rejects.toMatchInlineSnapshot(`[Error: OMG]`); + + expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); + }); +}); diff --git a/x-pack/plugins/alerting/server/routes/rule_types.ts b/x-pack/plugins/alerting/server/routes/rule_types.ts new file mode 100644 index 00000000000000..a3a44f9b013cd8 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/rule_types.ts @@ -0,0 +1,56 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { IRouter } from 'kibana/server'; +import { ILicenseState } from '../lib'; +import { RegistryAlertTypeWithAuth } from '../authorization'; +import { RewriteResponseCase, verifyAccessAndContext } from './lib'; +import { AlertingRequestHandlerContext, BASE_ALERTING_API_PATH } from '../types'; + +const rewriteBodyRes: RewriteResponseCase = (results) => { + return results.map( + ({ + enabledInLicense, + recoveryActionGroup, + actionGroups, + defaultActionGroupId, + minimumLicenseRequired, + actionVariables, + authorizedConsumers, + ...rest + }) => ({ + ...rest, + enabled_in_license: enabledInLicense, + recovery_action_group: recoveryActionGroup, + action_groups: actionGroups, + default_action_group_id: defaultActionGroupId, + minimum_license_required: minimumLicenseRequired, + action_variables: actionVariables, + authorized_consumers: authorizedConsumers, + }) + ); +}; + +export const ruleTypesRoute = ( + router: IRouter, + licenseState: ILicenseState +) => { + router.get( + { + path: `${BASE_ALERTING_API_PATH}/rule_types`, + validate: {}, + }, + router.handleLegacyErrors( + verifyAccessAndContext(licenseState, async function (context, req, res) { + const ruleTypes = Array.from(await context.alerting.getAlertsClient().listAlertTypes()); + return res.ok({ + body: rewriteBodyRes(ruleTypes), + }); + }) + ) + ); +}; diff --git a/x-pack/plugins/alerting/server/routes/unmute_alert.test.ts b/x-pack/plugins/alerting/server/routes/unmute_alert.test.ts new file mode 100644 index 00000000000000..a491ba394f8397 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/unmute_alert.test.ts @@ -0,0 +1,86 @@ +/* + * 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 { unmuteAlertRoute } from './unmute_alert'; +import { httpServiceMock } from 'src/core/server/mocks'; +import { licenseStateMock } from '../lib/license_state.mock'; +import { mockHandlerArguments } from './_mock_handler_arguments'; +import { alertsClientMock } from '../alerts_client.mock'; +import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; + +const alertsClient = alertsClientMock.create(); +jest.mock('../lib/license_api_access.ts', () => ({ + verifyApiAccess: jest.fn(), +})); + +beforeEach(() => { + jest.resetAllMocks(); +}); + +describe('unmuteAlertRoute', () => { + it('unmutes an alert', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + unmuteAlertRoute(router, licenseState); + + const [config, handler] = router.post.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot( + `"/api/alerting/rule/{rule_id}/alert/{alert_id}/_unmute"` + ); + + alertsClient.unmuteInstance.mockResolvedValueOnce(); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + params: { + rule_id: '1', + alert_id: '2', + }, + }, + ['noContent'] + ); + + expect(await handler(context, req, res)).toEqual(undefined); + + expect(alertsClient.unmuteInstance).toHaveBeenCalledTimes(1); + expect(alertsClient.unmuteInstance.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "alertId": "1", + "alertInstanceId": "2", + }, + ] + `); + + expect(res.noContent).toHaveBeenCalled(); + }); + + it('ensures the rule type gets validated for the license', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + unmuteAlertRoute(router, licenseState); + + const [, handler] = router.post.mock.calls[0]; + + alertsClient.unmuteInstance.mockRejectedValue( + new AlertTypeDisabledError('Fail', 'license_invalid') + ); + + const [context, req, res] = mockHandlerArguments({ alertsClient }, { params: {}, body: {} }, [ + 'ok', + 'forbidden', + ]); + + await handler(context, req, res); + + expect(res.forbidden).toHaveBeenCalledWith({ body: { message: 'Fail' } }); + }); +}); diff --git a/x-pack/plugins/alerting/server/routes/unmute_alert.ts b/x-pack/plugins/alerting/server/routes/unmute_alert.ts new file mode 100644 index 00000000000000..94bd6cd9af75f3 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/unmute_alert.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { IRouter } from 'kibana/server'; +import { schema } from '@kbn/config-schema'; +import { ILicenseState, AlertTypeDisabledError } from '../lib'; +import { MuteOptions } from '../alerts_client'; +import { RewriteRequestCase, verifyAccessAndContext } from './lib'; +import { AlertingRequestHandlerContext, BASE_ALERTING_API_PATH } from '../types'; + +const paramSchema = schema.object({ + rule_id: schema.string(), + alert_id: schema.string(), +}); + +const rewriteParamsReq: RewriteRequestCase = ({ + rule_id: alertId, + alert_id: alertInstanceId, +}) => ({ + alertId, + alertInstanceId, +}); + +export const unmuteAlertRoute = ( + router: IRouter, + licenseState: ILicenseState +) => { + router.post( + { + path: `${BASE_ALERTING_API_PATH}/rule/{rule_id}/alert/{alert_id}/_unmute`, + validate: { + params: paramSchema, + }, + }, + router.handleLegacyErrors( + verifyAccessAndContext(licenseState, async function (context, req, res) { + const alertsClient = context.alerting.getAlertsClient(); + const params = rewriteParamsReq(req.params); + try { + await alertsClient.unmuteInstance(params); + return res.noContent(); + } catch (e) { + if (e instanceof AlertTypeDisabledError) { + return e.sendResponse(res); + } + throw e; + } + }) + ) + ); +}; diff --git a/x-pack/plugins/alerting/server/routes/unmute_all_rule.test.ts b/x-pack/plugins/alerting/server/routes/unmute_all_rule.test.ts new file mode 100644 index 00000000000000..f873863bcb9022 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/unmute_all_rule.test.ts @@ -0,0 +1,80 @@ +/* + * 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 { unmuteAllRuleRoute } from './unmute_all_rule'; +import { httpServiceMock } from 'src/core/server/mocks'; +import { licenseStateMock } from '../lib/license_state.mock'; +import { mockHandlerArguments } from './_mock_handler_arguments'; +import { alertsClientMock } from '../alerts_client.mock'; +import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; + +const alertsClient = alertsClientMock.create(); +jest.mock('../lib/license_api_access.ts', () => ({ + verifyApiAccess: jest.fn(), +})); + +beforeEach(() => { + jest.resetAllMocks(); +}); + +describe('unmuteAllRuleRoute', () => { + it('unmutes a rule', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + unmuteAllRuleRoute(router, licenseState); + + const [config, handler] = router.post.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/api/alerting/rule/{id}/_unmute_all"`); + + alertsClient.unmuteAll.mockResolvedValueOnce(); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + params: { + id: '1', + }, + }, + ['noContent'] + ); + + expect(await handler(context, req, res)).toEqual(undefined); + + expect(alertsClient.unmuteAll).toHaveBeenCalledTimes(1); + expect(alertsClient.unmuteAll.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "id": "1", + }, + ] + `); + + expect(res.noContent).toHaveBeenCalled(); + }); + + it('ensures the rule type gets validated for the license', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + unmuteAllRuleRoute(router, licenseState); + + const [, handler] = router.post.mock.calls[0]; + + alertsClient.unmuteAll.mockRejectedValue(new AlertTypeDisabledError('Fail', 'license_invalid')); + + const [context, req, res] = mockHandlerArguments({ alertsClient }, { params: {}, body: {} }, [ + 'ok', + 'forbidden', + ]); + + await handler(context, req, res); + + expect(res.forbidden).toHaveBeenCalledWith({ body: { message: 'Fail' } }); + }); +}); diff --git a/x-pack/plugins/alerting/server/routes/unmute_all_rule.ts b/x-pack/plugins/alerting/server/routes/unmute_all_rule.ts new file mode 100644 index 00000000000000..96176e916cd7c8 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/unmute_all_rule.ts @@ -0,0 +1,45 @@ +/* + * 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 { IRouter } from 'kibana/server'; +import { schema } from '@kbn/config-schema'; +import { ILicenseState, AlertTypeDisabledError } from '../lib'; +import { verifyAccessAndContext } from './lib'; +import { AlertingRequestHandlerContext, BASE_ALERTING_API_PATH } from '../types'; + +const paramSchema = schema.object({ + id: schema.string(), +}); + +export const unmuteAllRuleRoute = ( + router: IRouter, + licenseState: ILicenseState +) => { + router.post( + { + path: `${BASE_ALERTING_API_PATH}/rule/{id}/_unmute_all`, + validate: { + params: paramSchema, + }, + }, + router.handleLegacyErrors( + verifyAccessAndContext(licenseState, async function (context, req, res) { + const alertsClient = context.alerting.getAlertsClient(); + const { id } = req.params; + try { + await alertsClient.unmuteAll({ id }); + return res.noContent(); + } catch (e) { + if (e instanceof AlertTypeDisabledError) { + return e.sendResponse(res); + } + throw e; + } + }) + ) + ); +}; diff --git a/x-pack/plugins/alerting/server/routes/update_rule.test.ts b/x-pack/plugins/alerting/server/routes/update_rule.test.ts new file mode 100644 index 00000000000000..a7121214cd3d34 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/update_rule.test.ts @@ -0,0 +1,215 @@ +/* + * 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 { pick } from 'lodash'; +import { updateRuleRoute } from './update_rule'; +import { httpServiceMock } from 'src/core/server/mocks'; +import { licenseStateMock } from '../lib/license_state.mock'; +import { verifyApiAccess } from '../lib/license_api_access'; +import { mockHandlerArguments } from './_mock_handler_arguments'; +import { UpdateOptions } from '../alerts_client'; +import { alertsClientMock } from '../alerts_client.mock'; +import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +import { AlertNotifyWhenType } from '../../common'; +import { AsApiContract } from './lib'; +import { PartialAlert } from '../types'; + +const alertsClient = alertsClientMock.create(); +jest.mock('../lib/license_api_access.ts', () => ({ + verifyApiAccess: jest.fn(), +})); + +beforeEach(() => { + jest.resetAllMocks(); +}); + +describe('updateRuleRoute', () => { + const mockedAlert = { + id: '1', + name: 'abc', + alertTypeId: '1', + tags: ['foo'], + throttle: '10m', + schedule: { interval: '12s' }, + params: { + otherField: false, + }, + createdAt: new Date(), + updatedAt: new Date(), + actions: [ + { + group: 'default', + id: '2', + actionTypeId: 'test', + params: { + baz: true, + }, + }, + ], + notifyWhen: 'onActionGroupChange' as AlertNotifyWhenType, + }; + + const updateRequest: AsApiContract['data']> = { + ...pick(mockedAlert, 'name', 'tags', 'schedule', 'params', 'throttle'), + notify_when: mockedAlert.notifyWhen, + actions: [ + { + group: mockedAlert.actions[0].group, + id: mockedAlert.actions[0].id, + params: mockedAlert.actions[0].params, + }, + ], + }; + + const updateResult: AsApiContract> = { + ...updateRequest, + id: mockedAlert.id, + updated_at: mockedAlert.updatedAt, + created_at: mockedAlert.createdAt, + rule_type_id: mockedAlert.alertTypeId, + actions: mockedAlert.actions.map(({ actionTypeId, ...rest }) => ({ + ...rest, + connector_type_id: actionTypeId, + })), + }; + + it('updates a rule with proper parameters', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + updateRuleRoute(router, licenseState); + + const [config, handler] = router.put.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/api/alerting/rule/{id}"`); + + alertsClient.update.mockResolvedValueOnce(mockedAlert); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + params: { + id: '1', + }, + body: updateRequest, + }, + ['ok'] + ); + + expect(await handler(context, req, res)).toEqual({ body: updateResult }); + + expect(alertsClient.update).toHaveBeenCalledTimes(1); + expect(alertsClient.update.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "data": Object { + "actions": Array [ + Object { + "group": "default", + "id": "2", + "params": Object { + "baz": true, + }, + }, + ], + "name": "abc", + "notifyWhen": "onActionGroupChange", + "params": Object { + "otherField": false, + }, + "schedule": Object { + "interval": "12s", + }, + "tags": Array [ + "foo", + ], + "throttle": "10m", + }, + "id": "1", + }, + ] + `); + + expect(res.ok).toHaveBeenCalled(); + }); + + it('ensures the license allows updating rules', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + updateRuleRoute(router, licenseState); + + const [, handler] = router.put.mock.calls[0]; + + alertsClient.update.mockResolvedValueOnce(mockedAlert); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + params: { + id: '1', + }, + body: updateRequest, + }, + ['ok'] + ); + + await handler(context, req, res); + + expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); + }); + + it('ensures the license check prevents updating rules', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + (verifyApiAccess as jest.Mock).mockImplementation(() => { + throw new Error('OMG'); + }); + + updateRuleRoute(router, licenseState); + + const [, handler] = router.put.mock.calls[0]; + + alertsClient.update.mockResolvedValueOnce(mockedAlert); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + params: { + id: '1', + }, + body: updateRequest, + }, + ['ok'] + ); + + expect(handler(context, req, res)).rejects.toMatchInlineSnapshot(`[Error: OMG]`); + + expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); + }); + + it('ensures the rule type gets validated for the license', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + updateRuleRoute(router, licenseState); + + const [, handler] = router.put.mock.calls[0]; + + alertsClient.update.mockRejectedValue(new AlertTypeDisabledError('Fail', 'license_invalid')); + + const [context, req, res] = mockHandlerArguments({ alertsClient }, { params: {}, body: {} }, [ + 'ok', + 'forbidden', + ]); + + await handler(context, req, res); + + expect(res.forbidden).toHaveBeenCalledWith({ body: { message: 'Fail' } }); + }); +}); diff --git a/x-pack/plugins/alerting/server/routes/update_rule.ts b/x-pack/plugins/alerting/server/routes/update_rule.ts new file mode 100644 index 00000000000000..ef5bd005587529 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/update_rule.ts @@ -0,0 +1,147 @@ +/* + * 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 { IRouter } from 'kibana/server'; +import { ILicenseState, AlertTypeDisabledError, validateDurationSchema } from '../lib'; +import { AlertNotifyWhenType } from '../../common'; +import { UpdateOptions } from '../alerts_client'; +import { + verifyAccessAndContext, + RewriteResponseCase, + RewriteRequestCase, + handleDisabledApiKeysError, +} from './lib'; +import { + AlertTypeParams, + AlertingRequestHandlerContext, + BASE_ALERTING_API_PATH, + validateNotifyWhenType, + PartialAlert, +} from '../types'; + +const paramSchema = schema.object({ + id: schema.string(), +}); + +const bodySchema = schema.object({ + name: schema.string(), + tags: schema.arrayOf(schema.string(), { defaultValue: [] }), + schedule: schema.object({ + interval: schema.string({ validate: validateDurationSchema }), + }), + throttle: schema.nullable(schema.string({ validate: validateDurationSchema })), + params: schema.recordOf(schema.string(), schema.any(), { defaultValue: {} }), + actions: schema.arrayOf( + schema.object({ + group: schema.string(), + id: schema.string(), + params: schema.recordOf(schema.string(), schema.any(), { defaultValue: {} }), + }), + { defaultValue: [] } + ), + notify_when: schema.string({ validate: validateNotifyWhenType }), +}); + +const rewriteBodyReq: RewriteRequestCase> = (result) => { + const { notify_when: notifyWhen, ...rest } = result.data; + return { + ...result, + data: { + ...rest, + notifyWhen, + }, + }; +}; +const rewriteBodyRes: RewriteResponseCase> = ({ + actions, + alertTypeId, + scheduledTaskId, + createdBy, + updatedBy, + createdAt, + updatedAt, + apiKeyOwner, + notifyWhen, + muteAll, + mutedInstanceIds, + executionStatus, + ...rest +}) => ({ + ...rest, + api_key_owner: apiKeyOwner, + created_by: createdBy, + updated_by: updatedBy, + ...(alertTypeId ? { rule_type_id: alertTypeId } : {}), + ...(scheduledTaskId ? { scheduled_task_id: scheduledTaskId } : {}), + ...(createdAt ? { created_at: createdAt } : {}), + ...(updatedAt ? { updated_at: updatedAt } : {}), + ...(notifyWhen ? { notify_when: notifyWhen } : {}), + ...(muteAll !== undefined ? { mute_all: muteAll } : {}), + ...(mutedInstanceIds ? { muted_alert_ids: mutedInstanceIds } : {}), + ...(executionStatus + ? { + execution_status: { + status: executionStatus.status, + last_execution_date: executionStatus.lastExecutionDate, + }, + } + : {}), + ...(actions + ? { + actions: actions.map(({ group, id, actionTypeId, params }) => ({ + group, + id, + params, + connector_type_id: actionTypeId, + })), + } + : {}), +}); + +export const updateRuleRoute = ( + router: IRouter, + licenseState: ILicenseState +) => { + router.put( + { + path: `${BASE_ALERTING_API_PATH}/rule/{id}`, + validate: { + body: bodySchema, + params: paramSchema, + }, + }, + handleDisabledApiKeysError( + router.handleLegacyErrors( + verifyAccessAndContext(licenseState, async function (context, req, res) { + const alertsClient = context.alerting.getAlertsClient(); + const { id } = req.params; + const rule = req.body; + try { + const alertRes = await alertsClient.update( + rewriteBodyReq({ + id, + data: { + ...rule, + notify_when: rule.notify_when as AlertNotifyWhenType, + }, + }) + ); + return res.ok({ + body: rewriteBodyRes(alertRes), + }); + } catch (e) { + if (e instanceof AlertTypeDisabledError) { + return e.sendResponse(res); + } + throw e; + } + }) + ) + ) + ); +}; diff --git a/x-pack/plugins/alerting/server/routes/update_rule_api_key.test.ts b/x-pack/plugins/alerting/server/routes/update_rule_api_key.test.ts new file mode 100644 index 00000000000000..ced335136adb15 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/update_rule_api_key.test.ts @@ -0,0 +1,82 @@ +/* + * 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 { updateRuleApiKeyRoute } from './update_rule_api_key'; +import { httpServiceMock } from 'src/core/server/mocks'; +import { licenseStateMock } from '../lib/license_state.mock'; +import { mockHandlerArguments } from './_mock_handler_arguments'; +import { alertsClientMock } from '../alerts_client.mock'; +import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; + +const alertsClient = alertsClientMock.create(); +jest.mock('../lib/license_api_access.ts', () => ({ + verifyApiAccess: jest.fn(), +})); + +beforeEach(() => { + jest.resetAllMocks(); +}); + +describe('updateRuleApiKeyRoute', () => { + it('updates api key for a rule', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + updateRuleApiKeyRoute(router, licenseState); + + const [config, handler] = router.post.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/internal/alerting/rule/{id}/_update_api_key"`); + + alertsClient.updateApiKey.mockResolvedValueOnce(); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + params: { + id: '1', + }, + }, + ['noContent'] + ); + + expect(await handler(context, req, res)).toEqual(undefined); + + expect(alertsClient.updateApiKey).toHaveBeenCalledTimes(1); + expect(alertsClient.updateApiKey.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "id": "1", + }, + ] + `); + + expect(res.noContent).toHaveBeenCalled(); + }); + + it('ensures the rule type gets validated for the license', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + updateRuleApiKeyRoute(router, licenseState); + + const [, handler] = router.post.mock.calls[0]; + + alertsClient.updateApiKey.mockRejectedValue( + new AlertTypeDisabledError('Fail', 'license_invalid') + ); + + const [context, req, res] = mockHandlerArguments({ alertsClient }, { params: {}, body: {} }, [ + 'ok', + 'forbidden', + ]); + + await handler(context, req, res); + + expect(res.forbidden).toHaveBeenCalledWith({ body: { message: 'Fail' } }); + }); +}); diff --git a/x-pack/plugins/alerting/server/routes/update_rule_api_key.ts b/x-pack/plugins/alerting/server/routes/update_rule_api_key.ts new file mode 100644 index 00000000000000..57206c68d448d1 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/update_rule_api_key.ts @@ -0,0 +1,45 @@ +/* + * 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 { IRouter } from 'kibana/server'; +import { schema } from '@kbn/config-schema'; +import { ILicenseState, AlertTypeDisabledError } from '../lib'; +import { verifyAccessAndContext } from './lib'; +import { AlertingRequestHandlerContext, INTERNAL_BASE_ALERTING_API_PATH } from '../types'; + +const paramSchema = schema.object({ + id: schema.string(), +}); + +export const updateRuleApiKeyRoute = ( + router: IRouter, + licenseState: ILicenseState +) => { + router.post( + { + path: `${INTERNAL_BASE_ALERTING_API_PATH}/rule/{id}/_update_api_key`, + validate: { + params: paramSchema, + }, + }, + router.handleLegacyErrors( + verifyAccessAndContext(licenseState, async function (context, req, res) { + const alertsClient = context.alerting.getAlertsClient(); + const { id } = req.params; + try { + await alertsClient.updateApiKey({ id }); + return res.noContent(); + } catch (e) { + if (e instanceof AlertTypeDisabledError) { + return e.sendResponse(res); + } + throw e; + } + }) + ) + ); +}; diff --git a/x-pack/plugins/monitoring/public/alerts/configuration.tsx b/x-pack/plugins/monitoring/public/alerts/configuration.tsx index 59411d431d83aa..5416095671d718 100644 --- a/x-pack/plugins/monitoring/public/alerts/configuration.tsx +++ b/x-pack/plugins/monitoring/public/alerts/configuration.tsx @@ -12,7 +12,7 @@ import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiSwitch } from '@elastic/eui'; import { CommonAlert } from '../../common/types/alerts'; import { Legacy } from '../legacy_shims'; import { hideBottomBar, showBottomBar } from '../lib/setup_mode'; -import { BASE_ALERT_API_PATH } from '../../../alerting/common'; +import { LEGACY_BASE_ALERT_API_PATH } from '../../../alerting/common'; interface Props { alert: CommonAlert; @@ -28,7 +28,7 @@ export const AlertConfiguration: React.FC = (props: Props) => { async function disableAlert() { setIsSaving(true); try { - await Legacy.shims.http.post(`${BASE_ALERT_API_PATH}/alert/${alert.id}/_disable`); + await Legacy.shims.http.post(`${LEGACY_BASE_ALERT_API_PATH}/alert/${alert.id}/_disable`); } catch (err) { Legacy.shims.toastNotifications.addDanger({ title: i18n.translate('xpack.monitoring.alerts.panel.disableAlert.errorTitle', { @@ -42,7 +42,7 @@ export const AlertConfiguration: React.FC = (props: Props) => { async function enableAlert() { setIsSaving(true); try { - await Legacy.shims.http.post(`${BASE_ALERT_API_PATH}/alert/${alert.id}/_enable`); + await Legacy.shims.http.post(`${LEGACY_BASE_ALERT_API_PATH}/alert/${alert.id}/_enable`); } catch (err) { Legacy.shims.toastNotifications.addDanger({ title: i18n.translate('xpack.monitoring.alerts.panel.enableAlert.errorTitle', { @@ -56,7 +56,7 @@ export const AlertConfiguration: React.FC = (props: Props) => { async function muteAlert() { setIsSaving(true); try { - await Legacy.shims.http.post(`${BASE_ALERT_API_PATH}/alert/${alert.id}/_mute_all`); + await Legacy.shims.http.post(`${LEGACY_BASE_ALERT_API_PATH}/alert/${alert.id}/_mute_all`); } catch (err) { Legacy.shims.toastNotifications.addDanger({ title: i18n.translate('xpack.monitoring.alerts.panel.muteAlert.errorTitle', { @@ -70,7 +70,7 @@ export const AlertConfiguration: React.FC = (props: Props) => { async function unmuteAlert() { setIsSaving(true); try { - await Legacy.shims.http.post(`${BASE_ALERT_API_PATH}/alert/${alert.id}/_unmute_all`); + await Legacy.shims.http.post(`${LEGACY_BASE_ALERT_API_PATH}/alert/${alert.id}/_unmute_all`); } catch (err) { Legacy.shims.toastNotifications.addDanger({ title: i18n.translate('xpack.monitoring.alerts.panel.ummuteAlert.errorTitle', { diff --git a/x-pack/plugins/monitoring/server/alerts/base_alert.ts b/x-pack/plugins/monitoring/server/alerts/base_alert.ts index fbe487f240699e..bb80d84210a481 100644 --- a/x-pack/plugins/monitoring/server/alerts/base_alert.ts +++ b/x-pack/plugins/monitoring/server/alerts/base_alert.ts @@ -116,7 +116,7 @@ export class BaseAlert { alertsClient: AlertsClient, actionsClient: ActionsClient, actions: AlertEnableAction[] - ): Promise> { + ): Promise> { const existingAlertData = await alertsClient.find({ options: { search: this.alertOptions.id, diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts b/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts index b452d22506a1c1..01ab392e0563c0 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts @@ -13,7 +13,7 @@ import { ALERT_ACTION_TYPE_LOG } from '../../../../../common/constants'; import { ActionResult } from '../../../../../../actions/common'; import { AlertingSecurity } from '../../../../lib/elasticsearch/verify_alerting_security'; import { disableWatcherClusterAlerts } from '../../../../lib/alerts/disable_watcher_cluster_alerts'; -import { Alert, AlertTypeParams } from '../../../../../../alerting/common'; +import { AlertTypeParams, SanitizedAlert } from '../../../../../../alerting/common'; const DEFAULT_SERVER_LOG_NAME = 'Monitoring: Write to Kibana log'; @@ -77,7 +77,7 @@ export function enableAlertsRoute(_server: unknown, npRoute: RouteDependencies) }, ]; - let createdAlerts: Array> = []; + let createdAlerts: Array> = []; const disabledWatcherClusterAlerts = await disableWatcherClusterAlerts( npRoute.cluster.asScoped(request).callAsCurrentUser, npRoute.logger diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/create_notifications.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/create_notifications.ts index b82e3052c39356..c445c335662895 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/create_notifications.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/create_notifications.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Alert } from '../../../../../alerting/common'; +import { SanitizedAlert } from '../../../../../alerting/common'; import { SERVER_APP_ID, NOTIFICATIONS_ID } from '../../../../common/constants'; import { CreateNotificationParams, RuleNotificationAlertTypeParams } from './types'; import { addTags } from './add_tags'; @@ -18,7 +18,7 @@ export const createNotifications = async ({ ruleAlertId, interval, name, -}: CreateNotificationParams): Promise> => +}: CreateNotificationParams): Promise> => alertsClient.create({ data: { name, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules.ts index e020810b6d03a9..a654dd6a10e329 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules.ts @@ -6,7 +6,7 @@ */ import { transformRuleToAlertAction } from '../../../../common/detection_engine/transform_actions'; -import { Alert } from '../../../../../alerting/common'; +import { SanitizedAlert } from '../../../../../alerting/common'; import { SERVER_APP_ID, SIGNALS_ID } from '../../../../common/constants'; import { CreateRulesOptions } from './types'; import { addTags } from './add_tags'; @@ -62,7 +62,7 @@ export const createRules = async ({ version, exceptionsList, actions, -}: CreateRulesOptions): Promise> => { +}: CreateRulesOptions): Promise> => { return alertsClient.create({ data: { name, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/install_prepacked_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/install_prepacked_rules.ts index 31df1dd4193a4b..7efd63cc677222 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/install_prepacked_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/install_prepacked_rules.ts @@ -6,7 +6,7 @@ */ import { AddPrepackagedRulesSchemaDecoded } from '../../../../common/detection_engine/schemas/request/add_prepackaged_rules_schema'; -import { Alert, AlertTypeParams } from '../../../../../alerting/common'; +import { SanitizedAlert, AlertTypeParams } from '../../../../../alerting/common'; import { AlertsClient } from '../../../../../alerting/server'; import { createRules } from './create_rules'; import { PartialFilter } from '../types'; @@ -15,8 +15,8 @@ export const installPrepackagedRules = ( alertsClient: AlertsClient, rules: AddPrepackagedRulesSchemaDecoded[], outputIndex: string -): Array>> => - rules.reduce>>>((acc, rule) => { +): Array>> => + rules.reduce>>>((acc, rule) => { const { anomaly_threshold: anomalyThreshold, author, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/constants/index.ts b/x-pack/plugins/triggers_actions_ui/public/application/constants/index.ts index 2d0b2e99c10a69..8ac1fbaec403be 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/constants/index.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/constants/index.ts @@ -7,7 +7,7 @@ import { i18n } from '@kbn/i18n'; -export { BASE_ALERT_API_PATH } from '../../../../alerting/common'; +export { LEGACY_BASE_ALERT_API_PATH } from '../../../../alerting/common'; export { BASE_ACTION_API_PATH } from '../../../../actions/common'; export type Section = 'connectors' | 'rules'; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts index 744e6472a9194c..80ff4155821914 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts @@ -11,7 +11,7 @@ import { pipe } from 'fp-ts/lib/pipeable'; import { fold } from 'fp-ts/lib/Either'; import { pick } from 'lodash'; import { alertStateSchema, AlertingFrameworkHealth } from '../../../../alerting/common'; -import { BASE_ALERT_API_PATH } from '../constants'; +import { LEGACY_BASE_ALERT_API_PATH } from '../constants'; import { Alert, AlertAggregations, @@ -24,7 +24,7 @@ import { } from '../../types'; export async function loadAlertTypes({ http }: { http: HttpSetup }): Promise { - return await http.get(`${BASE_ALERT_API_PATH}/list_alert_types`); + return await http.get(`${LEGACY_BASE_ALERT_API_PATH}/list_alert_types`); } export async function loadAlert({ @@ -34,7 +34,7 @@ export async function loadAlert({ http: HttpSetup; alertId: string; }): Promise { - return await http.get(`${BASE_ALERT_API_PATH}/alert/${alertId}`); + return await http.get(`${LEGACY_BASE_ALERT_API_PATH}/alert/${alertId}`); } type EmptyHttpResponse = ''; @@ -46,7 +46,7 @@ export async function loadAlertState({ alertId: string; }): Promise { return await http - .get(`${BASE_ALERT_API_PATH}/alert/${alertId}/state`) + .get(`${LEGACY_BASE_ALERT_API_PATH}/alert/${alertId}/state`) .then((state: AlertTaskState | EmptyHttpResponse) => (state ? state : {})) .then((state: AlertTaskState) => { return pipe( @@ -65,7 +65,7 @@ export async function loadAlertInstanceSummary({ http: HttpSetup; alertId: string; }): Promise { - return await http.get(`${BASE_ALERT_API_PATH}/alert/${alertId}/_instance_summary`); + return await http.get(`${LEGACY_BASE_ALERT_API_PATH}/alert/${alertId}/_instance_summary`); } export const mapFiltersToKql = ({ @@ -121,7 +121,7 @@ export async function loadAlerts({ data: Alert[]; }> { const filters = mapFiltersToKql({ typesFilter, actionTypesFilter, alertStatusesFilter }); - return await http.get(`${BASE_ALERT_API_PATH}/_find`, { + return await http.get(`${LEGACY_BASE_ALERT_API_PATH}/_find`, { query: { page: page.index + 1, per_page: page.size, @@ -149,7 +149,7 @@ export async function loadAlertAggregations({ alertStatusesFilter?: string[]; }): Promise { const filters = mapFiltersToKql({ typesFilter, actionTypesFilter, alertStatusesFilter }); - return await http.get(`${BASE_ALERT_API_PATH}/_aggregate`, { + return await http.get(`${LEGACY_BASE_ALERT_API_PATH}/_aggregate`, { query: { search_fields: searchText ? JSON.stringify(['name', 'tags']) : undefined, search: searchText, @@ -168,7 +168,7 @@ export async function deleteAlerts({ }): Promise<{ successes: string[]; errors: string[] }> { const successes: string[] = []; const errors: string[] = []; - await Promise.all(ids.map((id) => http.delete(`${BASE_ALERT_API_PATH}/alert/${id}`))).then( + await Promise.all(ids.map((id) => http.delete(`${LEGACY_BASE_ALERT_API_PATH}/alert/${id}`))).then( function (fulfilled) { successes.push(...fulfilled); }, @@ -189,7 +189,7 @@ export async function createAlert({ 'createdBy' | 'updatedBy' | 'muteAll' | 'mutedInstanceIds' | 'executionStatus' >; }): Promise { - return await http.post(`${BASE_ALERT_API_PATH}/alert`, { + return await http.post(`${LEGACY_BASE_ALERT_API_PATH}/alert`, { body: JSON.stringify(alert), }); } @@ -206,7 +206,7 @@ export async function updateAlert({ >; id: string; }): Promise { - return await http.put(`${BASE_ALERT_API_PATH}/alert/${id}`, { + return await http.put(`${LEGACY_BASE_ALERT_API_PATH}/alert/${id}`, { body: JSON.stringify( pick(alert, ['throttle', 'name', 'tags', 'schedule', 'params', 'actions', 'notifyWhen']) ), @@ -214,7 +214,7 @@ export async function updateAlert({ } export async function enableAlert({ id, http }: { id: string; http: HttpSetup }): Promise { - await http.post(`${BASE_ALERT_API_PATH}/alert/${id}/_enable`); + await http.post(`${LEGACY_BASE_ALERT_API_PATH}/alert/${id}/_enable`); } export async function enableAlerts({ @@ -228,7 +228,7 @@ export async function enableAlerts({ } export async function disableAlert({ id, http }: { id: string; http: HttpSetup }): Promise { - await http.post(`${BASE_ALERT_API_PATH}/alert/${id}/_disable`); + await http.post(`${LEGACY_BASE_ALERT_API_PATH}/alert/${id}/_disable`); } export async function disableAlerts({ @@ -250,7 +250,7 @@ export async function muteAlertInstance({ instanceId: string; http: HttpSetup; }): Promise { - await http.post(`${BASE_ALERT_API_PATH}/alert/${id}/alert_instance/${instanceId}/_mute`); + await http.post(`${LEGACY_BASE_ALERT_API_PATH}/alert/${id}/alert_instance/${instanceId}/_mute`); } export async function unmuteAlertInstance({ @@ -262,11 +262,11 @@ export async function unmuteAlertInstance({ instanceId: string; http: HttpSetup; }): Promise { - await http.post(`${BASE_ALERT_API_PATH}/alert/${id}/alert_instance/${instanceId}/_unmute`); + await http.post(`${LEGACY_BASE_ALERT_API_PATH}/alert/${id}/alert_instance/${instanceId}/_unmute`); } export async function muteAlert({ id, http }: { id: string; http: HttpSetup }): Promise { - await http.post(`${BASE_ALERT_API_PATH}/alert/${id}/_mute_all`); + await http.post(`${LEGACY_BASE_ALERT_API_PATH}/alert/${id}/_mute_all`); } export async function muteAlerts({ ids, http }: { ids: string[]; http: HttpSetup }): Promise { @@ -274,7 +274,7 @@ export async function muteAlerts({ ids, http }: { ids: string[]; http: HttpSetup } export async function unmuteAlert({ id, http }: { id: string; http: HttpSetup }): Promise { - await http.post(`${BASE_ALERT_API_PATH}/alert/${id}/_unmute_all`); + await http.post(`${LEGACY_BASE_ALERT_API_PATH}/alert/${id}/_unmute_all`); } export async function unmuteAlerts({ @@ -292,5 +292,5 @@ export async function alertingFrameworkHealth({ }: { http: HttpSetup; }): Promise { - return await http.get(`${BASE_ALERT_API_PATH}/_health`); + return await http.get(`${LEGACY_BASE_ALERT_API_PATH}/_health`); } diff --git a/x-pack/test/alerting_api_integration/basic/tests/alerts/basic_noop_alert_type.ts b/x-pack/test/alerting_api_integration/basic/tests/alerts/basic_noop_alert_type.ts index 617e430df13e70..805f4440909ec2 100644 --- a/x-pack/test/alerting_api_integration/basic/tests/alerts/basic_noop_alert_type.ts +++ b/x-pack/test/alerting_api_integration/basic/tests/alerts/basic_noop_alert_type.ts @@ -15,7 +15,7 @@ export default function basicAlertTest({ getService }: FtrProviderContext) { describe('basic alert', () => { it('should return 200 when creating a basic license alert', async () => { await supertest - .post(`/api/alerts/alert`) + .post(`/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); diff --git a/x-pack/test/alerting_api_integration/basic/tests/alerts/gold_noop_alert_type.ts b/x-pack/test/alerting_api_integration/basic/tests/alerts/gold_noop_alert_type.ts index 211d1acb2a0054..50e8760f2d8f51 100644 --- a/x-pack/test/alerting_api_integration/basic/tests/alerts/gold_noop_alert_type.ts +++ b/x-pack/test/alerting_api_integration/basic/tests/alerts/gold_noop_alert_type.ts @@ -15,9 +15,9 @@ export default function emailTest({ getService }: FtrProviderContext) { describe('create gold noop alert', () => { it('should return 403 when creating an gold alert', async () => { await supertest - .post(`/api/alerts/alert`) + .post(`/api/alerting/rule`) .set('kbn-xsrf', 'foo') - .send(getTestAlertData({ alertTypeId: 'test.gold.noop' })) + .send(getTestAlertData({ rule_type_id: 'test.gold.noop' })) .expect(403, { statusCode: 403, error: 'Forbidden', diff --git a/x-pack/test/alerting_api_integration/common/lib/alert_utils.ts b/x-pack/test/alerting_api_integration/common/lib/alert_utils.ts index fab4518b99b22b..540f8f4d1cad92 100644 --- a/x-pack/test/alerting_api_integration/common/lib/alert_utils.ts +++ b/x-pack/test/alerting_api_integration/common/lib/alert_utils.ts @@ -68,7 +68,7 @@ export class AlertUtils { public getEnableRequest(alertId: string) { const request = this.supertestWithoutAuth - .post(`${getUrlPrefix(this.space.id)}/api/alerts/alert/${alertId}/_enable`) + .post(`${getUrlPrefix(this.space.id)}/api/alerting/rule/${alertId}/_enable`) .set('kbn-xsrf', 'foo'); if (this.user) { return request.auth(this.user.username, this.user.password); @@ -78,7 +78,7 @@ export class AlertUtils { public getDisableRequest(alertId: string) { const request = this.supertestWithoutAuth - .post(`${getUrlPrefix(this.space.id)}/api/alerts/alert/${alertId}/_disable`) + .post(`${getUrlPrefix(this.space.id)}/api/alerting/rule/${alertId}/_disable`) .set('kbn-xsrf', 'foo'); if (this.user) { return request.auth(this.user.username, this.user.password); @@ -88,7 +88,7 @@ export class AlertUtils { public getMuteAllRequest(alertId: string) { const request = this.supertestWithoutAuth - .post(`${getUrlPrefix(this.space.id)}/api/alerts/alert/${alertId}/_mute_all`) + .post(`${getUrlPrefix(this.space.id)}/api/alerting/rule/${alertId}/_mute_all`) .set('kbn-xsrf', 'foo'); if (this.user) { return request.auth(this.user.username, this.user.password); @@ -98,7 +98,7 @@ export class AlertUtils { public getUnmuteAllRequest(alertId: string) { const request = this.supertestWithoutAuth - .post(`${getUrlPrefix(this.space.id)}/api/alerts/alert/${alertId}/_unmute_all`) + .post(`${getUrlPrefix(this.space.id)}/api/alerting/rule/${alertId}/_unmute_all`) .set('kbn-xsrf', 'foo'); if (this.user) { return request.auth(this.user.username, this.user.password); @@ -108,11 +108,7 @@ export class AlertUtils { public getMuteInstanceRequest(alertId: string, instanceId: string) { const request = this.supertestWithoutAuth - .post( - `${getUrlPrefix( - this.space.id - )}/api/alerts/alert/${alertId}/alert_instance/${instanceId}/_mute` - ) + .post(`${getUrlPrefix(this.space.id)}/api/alerting/rule/${alertId}/alert/${instanceId}/_mute`) .set('kbn-xsrf', 'foo'); if (this.user) { return request.auth(this.user.username, this.user.password); @@ -123,9 +119,7 @@ export class AlertUtils { public getUnmuteInstanceRequest(alertId: string, instanceId: string) { const request = this.supertestWithoutAuth .post( - `${getUrlPrefix( - this.space.id - )}/api/alerts/alert/${alertId}/alert_instance/${instanceId}/_unmute` + `${getUrlPrefix(this.space.id)}/api/alerting/rule/${alertId}/alert/${instanceId}/_unmute` ) .set('kbn-xsrf', 'foo'); if (this.user) { @@ -136,7 +130,7 @@ export class AlertUtils { public getUpdateApiKeyRequest(alertId: string) { const request = this.supertestWithoutAuth - .post(`${getUrlPrefix(this.space.id)}/api/alerts/alert/${alertId}/_update_api_key`) + .post(`${getUrlPrefix(this.space.id)}/internal/alerting/rule/${alertId}/_update_api_key`) .set('kbn-xsrf', 'foo'); if (this.user) { return request.auth(this.user.username, this.user.password); @@ -189,7 +183,7 @@ export class AlertUtils { } let request = this.supertestWithoutAuth - .post(`${getUrlPrefix(this.space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(this.space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo'); if (this.user) { request = request.auth(this.user.username, this.user.password); @@ -197,7 +191,7 @@ export class AlertUtils { const alertBody = getDefaultAlwaysFiringAlertData(reference, actionId); const response = await request.send({ ...alertBody, ...overwrites }); if (response.statusCode === 200) { - objRemover.add(this.space.id, response.body.id, 'alert', 'alerts'); + objRemover.add(this.space.id, response.body.id, 'rule', 'alerting'); } return response; } @@ -216,14 +210,16 @@ export class AlertUtils { } const request = this.supertestWithoutAuth - .put(`${getUrlPrefix(this.space.id)}/api/alerts/alert/${alertId}`) + .put(`${getUrlPrefix(this.space.id)}/api/alerting/rule/${alertId}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password); - const { alertTypeId, enabled, consumer, ...alertBody } = getDefaultAlwaysFiringAlertData( - reference, - actionId - ); + const { + rule_type_id: alertTypeId, + enabled, + consumer, + ...alertBody + } = getDefaultAlwaysFiringAlertData(reference, actionId); const response = await request.send({ ...alertBody, ...overwrites }); return response; @@ -246,7 +242,7 @@ export class AlertUtils { } let request = this.supertestWithoutAuth - .post(`${getUrlPrefix(this.space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(this.space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo'); if (this.user) { request = request.auth(this.user.username, this.user.password); @@ -257,17 +253,18 @@ export class AlertUtils { schedule: { interval: '30s' }, throttle: '30s', tags: [], - alertTypeId: 'test.failing', + rule_type_id: 'test.failing', consumer: 'alertsFixture', params: { index: ES_TEST_INDEX_NAME, reference, }, + notify_when: 'onActiveAlert', actions: [], ...overwrites, }); if (response.statusCode === 200) { - objRemover.add(this.space.id, response.body.id, 'alert', 'alerts'); + objRemover.add(this.space.id, response.body.id, 'rule', 'alerting'); } return response; } @@ -290,7 +287,7 @@ export class AlertUtils { } let request = this.supertestWithoutAuth - .post(`${getUrlPrefix(this.space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(this.space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo'); if (this.user) { request = request.auth(this.user.username, this.user.password); @@ -300,7 +297,7 @@ export class AlertUtils { ...overwrites, }); if (response.statusCode === 200) { - objRemover.add(this.space.id, response.body.id, 'alert', 'alerts'); + objRemover.add(this.space.id, response.body.id, 'rule', 'alerting'); } return response; } @@ -339,12 +336,13 @@ instanceStateValue: {{state.instanceStateValue}} schedule: { interval: '1m' }, throttle: '1m', tags: ['tag-A', 'tag-B'], - alertTypeId: 'test.always-firing', + rule_type_id: 'test.always-firing', consumer: 'alertsFixture', params: { index: ES_TEST_INDEX_NAME, reference, }, + notify_when: 'onActiveAlert', actions: [ { group: 'default', diff --git a/x-pack/test/alerting_api_integration/common/lib/get_test_alert_data.ts b/x-pack/test/alerting_api_integration/common/lib/get_test_alert_data.ts index 46624fcf86d372..22dc93b110a074 100644 --- a/x-pack/test/alerting_api_integration/common/lib/get_test_alert_data.ts +++ b/x-pack/test/alerting_api_integration/common/lib/get_test_alert_data.ts @@ -10,11 +10,11 @@ export function getTestAlertData(overwrites = {}) { enabled: true, name: 'abc', tags: ['foo'], - alertTypeId: 'test.noop', + rule_type_id: 'test.noop', consumer: 'alertsFixture', schedule: { interval: '1m' }, throttle: '1m', - notifyWhen: 'onThrottleInterval', + notify_when: 'onThrottleInterval', actions: [], params: {}, ...overwrites, diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/get_all.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/get_all.ts index 2142520894669b..1c227bc87d93f0 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/get_all.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/get_all.ts @@ -124,7 +124,7 @@ export default function getAllActionTests({ getService }: FtrProviderContext) { objectRemover.add(space.id, createdAction.id, 'action', 'actions'); const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts index 536c4cbbd710f1..24e641cb06407d 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts @@ -56,11 +56,11 @@ export default function alertTests({ getService }: FtrProviderContext) { before(async () => { const { body: createdAction } = await supertest - .post(`${getUrlPrefix(space.id)}/api/actions/action`) + .post(`${getUrlPrefix(space.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'My action', - actionTypeId: 'test.index-record', + connector_type_id: 'test.index-record', config: { unencrypted: `This value shouldn't get encrypted`, }, @@ -78,7 +78,7 @@ export default function alertTests({ getService }: FtrProviderContext) { objectRemover, }); }); - after(() => objectRemover.add(space.id, indexRecordActionId, 'action', 'actions')); + after(() => objectRemover.add(space.id, indexRecordActionId, 'connector', 'actions')); it('should schedule task, run alert and schedule actions when appropriate', async () => { const testStart = new Date(); @@ -365,24 +365,24 @@ instanceStateValue: true const retryDate = new Date(Date.now() + 60000); const { body: createdAction } = await supertest - .post(`${getUrlPrefix(space.id)}/api/actions/action`) + .post(`${getUrlPrefix(space.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'Test rate limit', - actionTypeId: 'test.rate-limit', + connector_type_id: 'test.rate-limit', config: {}, }) .expect(200); - objectRemover.add(space.id, createdAction.id, 'action', 'actions'); + objectRemover.add(space.id, createdAction.id, 'connector', 'actions'); const reference = alertUtils.generateReference(); const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send( getTestAlertData({ - alertTypeId: 'test.always-firing', + rule_type_id: 'test.always-firing', params: { index: ES_TEST_INDEX_NAME, reference: 'create-test-2', @@ -428,7 +428,7 @@ instanceStateValue: true case 'space_1_all at space1': case 'space_1_all_with_restricted_fixture at space1': expect(response.statusCode).to.eql(200); - objectRemover.add(space.id, response.body.id, 'alert', 'alerts'); + objectRemover.add(space.id, response.body.id, 'rule', 'alerting'); // Wait for the task to be attempted once and idle const scheduledActionTask = await retry.try(async () => { @@ -482,12 +482,12 @@ instanceStateValue: true const testStart = new Date(); const reference = alertUtils.generateReference(); const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send( getTestAlertData({ - alertTypeId: 'test.authorization', + rule_type_id: 'test.authorization', params: { callClusterAuthorizationIndex: authorizationIndex, savedObjectsClientType: 'dashboard', @@ -517,7 +517,7 @@ instanceStateValue: true case 'space_1_all_alerts_none_actions at space1': case 'space_1_all_with_restricted_fixture at space1': expect(response.statusCode).to.eql(200); - objectRemover.add(space.id, response.body.id, 'alert', 'alerts'); + objectRemover.add(space.id, response.body.id, 'rule', 'alerting'); // Wait for test.authorization to index a document before disabling the alert and waiting for tasks to finish await esTestIndexTool.waitForDocs('alert:test.authorization', reference); @@ -548,7 +548,7 @@ instanceStateValue: true break; case 'superuser at space1': expect(response.statusCode).to.eql(200); - objectRemover.add(space.id, response.body.id, 'alert', 'alerts'); + objectRemover.add(space.id, response.body.id, 'rule', 'alerting'); // Wait for test.authorization to index a document before disabling the alert and waiting for tasks to finish await esTestIndexTool.waitForDocs('alert:test.authorization', reference); @@ -581,21 +581,21 @@ instanceStateValue: true const testStart = new Date(); const reference = alertUtils.generateReference(); const { body: createdAction } = await supertest - .post(`${getUrlPrefix(space.id)}/api/actions/action`) + .post(`${getUrlPrefix(space.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'My action', - actionTypeId: 'test.authorization', + connector_type_id: 'test.authorization', }) .expect(200); - objectRemover.add(space.id, createdAction.id, 'action', 'actions'); + objectRemover.add(space.id, createdAction.id, 'connector', 'actions'); const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send( getTestAlertData({ - alertTypeId: 'test.always-firing', + rule_type_id: 'test.always-firing', params: { index: ES_TEST_INDEX_NAME, reference, @@ -634,7 +634,7 @@ instanceStateValue: true case 'space_1_all at space1': case 'space_1_all_with_restricted_fixture at space1': expect(response.statusCode).to.eql(200); - objectRemover.add(space.id, response.body.id, 'alert', 'alerts'); + objectRemover.add(space.id, response.body.id, 'rule', 'alerting'); // Ensure test.authorization indexed 1 document before disabling the alert and waiting for tasks to finish await esTestIndexTool.waitForDocs('action:test.authorization', reference); @@ -673,7 +673,7 @@ instanceStateValue: true break; case 'superuser at space1': expect(response.statusCode).to.eql(200); - objectRemover.add(space.id, response.body.id, 'alert', 'alerts'); + objectRemover.add(space.id, response.body.id, 'rule', 'alerting'); // Ensure test.authorization indexed 1 document before disabling the alert and waiting for tasks to finish await esTestIndexTool.waitForDocs('action:test.authorization', reference); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/create.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/create.ts index 842a3cc11c72c3..70cafe407de296 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/create.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/create.ts @@ -40,18 +40,18 @@ export default function createAlertTests({ getService }: FtrProviderContext) { describe(scenario.id, () => { it('should handle create alert request appropriately', async () => { const { body: createdAction } = await supertest - .post(`${getUrlPrefix(space.id)}/api/actions/action`) + .post(`${getUrlPrefix(space.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'MY action', - actionTypeId: 'test.noop', + connector_type_id: 'test.noop', config: {}, secrets: {}, }) .expect(200); const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send( @@ -93,7 +93,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { case 'space_1_all at space1': case 'space_1_all_with_restricted_fixture at space1': expect(response.statusCode).to.eql(200); - objectRemover.add(space.id, response.body.id, 'alert', 'alerts'); + objectRemover.add(space.id, response.body.id, 'rule', 'alerting'); expect(response.body).to.eql({ id: response.body.id, name: 'abc', @@ -101,33 +101,35 @@ export default function createAlertTests({ getService }: FtrProviderContext) { actions: [ { id: createdAction.id, - actionTypeId: createdAction.actionTypeId, + connector_type_id: createdAction.connector_type_id, group: 'default', params: {}, }, ], enabled: true, - alertTypeId: 'test.noop', + rule_type_id: 'test.noop', consumer: 'alertsFixture', params: {}, - createdBy: user.username, + created_by: user.username, schedule: { interval: '1m' }, - scheduledTaskId: response.body.scheduledTaskId, - createdAt: response.body.createdAt, - updatedAt: response.body.updatedAt, + scheduled_task_id: response.body.scheduled_task_id, + created_at: response.body.created_at, + updated_at: response.body.updated_at, throttle: '1m', - notifyWhen: 'onThrottleInterval', - updatedBy: user.username, - apiKeyOwner: user.username, - muteAll: false, - mutedInstanceIds: [], - executionStatus: response.body.executionStatus, + notify_when: 'onThrottleInterval', + updated_by: user.username, + api_key_owner: user.username, + mute_all: false, + muted_alert_ids: [], + execution_status: response.body.execution_status, }); - expect(typeof response.body.scheduledTaskId).to.be('string'); - expect(Date.parse(response.body.createdAt)).to.be.greaterThan(0); - expect(Date.parse(response.body.updatedAt)).to.be.greaterThan(0); + expect(typeof response.body.scheduled_task_id).to.be('string'); + expect(Date.parse(response.body.created_at)).to.be.greaterThan(0); + expect(Date.parse(response.body.updated_at)).to.be.greaterThan(0); - const { _source: taskRecord } = await getScheduledTask(response.body.scheduledTaskId); + const { _source: taskRecord } = await getScheduledTask( + response.body.scheduled_task_id + ); expect(taskRecord.type).to.eql('task'); expect(taskRecord.task.taskType).to.eql('alerting:test.noop'); expect(JSON.parse(taskRecord.task.params)).to.eql({ @@ -149,12 +151,12 @@ export default function createAlertTests({ getService }: FtrProviderContext) { it('should handle create alert request appropriately when consumer is the same as producer', async () => { const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send( getTestAlertData({ - alertTypeId: 'test.restricted-noop', + rule_type_id: 'test.restricted-noop', consumer: 'alertsRestrictedFixture', }) ); @@ -179,7 +181,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { case 'superuser at space1': case 'space_1_all_with_restricted_fixture at space1': expect(response.statusCode).to.eql(200); - objectRemover.add(space.id, response.body.id, 'alert', 'alerts'); + objectRemover.add(space.id, response.body.id, 'rule', 'alerting'); break; default: throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); @@ -188,11 +190,14 @@ export default function createAlertTests({ getService }: FtrProviderContext) { it('should handle create alert request appropriately when consumer is not the producer', async () => { const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send( - getTestAlertData({ alertTypeId: 'test.unrestricted-noop', consumer: 'alertsFixture' }) + getTestAlertData({ + rule_type_id: 'test.unrestricted-noop', + consumer: 'alertsFixture', + }) ); switch (scenario.id) { @@ -226,7 +231,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { case 'superuser at space1': case 'space_1_all_with_restricted_fixture at space1': expect(response.statusCode).to.eql(200); - objectRemover.add(space.id, response.body.id, 'alert', 'alerts'); + objectRemover.add(space.id, response.body.id, 'rule', 'alerting'); break; default: throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); @@ -235,12 +240,12 @@ export default function createAlertTests({ getService }: FtrProviderContext) { it('should handle create alert request appropriately when consumer is "alerts"', async () => { const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send( getTestAlertData({ - alertTypeId: 'test.noop', + rule_type_id: 'test.noop', consumer: 'alerts', }) ); @@ -272,7 +277,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { case 'superuser at space1': case 'space_1_all_with_restricted_fixture at space1': expect(response.statusCode).to.eql(200); - objectRemover.add(space.id, response.body.id, 'alert', 'alerts'); + objectRemover.add(space.id, response.body.id, 'rule', 'alerting'); break; default: throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); @@ -281,12 +286,12 @@ export default function createAlertTests({ getService }: FtrProviderContext) { it('should handle create alert request appropriately when consumer is unknown', async () => { const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send( getTestAlertData({ - alertTypeId: 'test.noop', + rule_type_id: 'test.noop', consumer: 'some consumer patrick invented', }) ); @@ -317,7 +322,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { it('should handle create alert request appropriately when an alert is disabled ', async () => { const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send(getTestAlertData({ enabled: false })); @@ -342,8 +347,8 @@ export default function createAlertTests({ getService }: FtrProviderContext) { case 'space_1_all_alerts_none_actions at space1': case 'space_1_all_with_restricted_fixture at space1': expect(response.statusCode).to.eql(200); - objectRemover.add(space.id, response.body.id, 'alert', 'alerts'); - expect(response.body.scheduledTaskId).to.eql(undefined); + objectRemover.add(space.id, response.body.id, 'rule', 'alerting'); + expect(response.body.scheduled_task_id).to.eql(undefined); break; default: throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); @@ -352,7 +357,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { it('should handle create alert request appropriately when alert name has leading and trailing whitespaces', async () => { const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send( @@ -382,7 +387,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { case 'space_1_all_with_restricted_fixture at space1': expect(response.statusCode).to.eql(200); expect(response.body.name).to.eql(' leading and trailing whitespace '); - objectRemover.add(space.id, response.body.id, 'alert', 'alerts'); + objectRemover.add(space.id, response.body.id, 'rule', 'alerting'); break; default: throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); @@ -391,12 +396,12 @@ export default function createAlertTests({ getService }: FtrProviderContext) { it('should handle create alert request appropriately when alert type is unregistered', async () => { const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send( getTestAlertData({ - alertTypeId: 'test.unregistered-alert-type', + rule_type_id: 'test.unregistered-alert-type', }) ); @@ -422,7 +427,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { it('should handle create alert request appropriately when payload is empty and invalid', async () => { const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send({}); @@ -449,12 +454,12 @@ export default function createAlertTests({ getService }: FtrProviderContext) { it(`should handle create alert request appropriately when params isn't valid`, async () => { const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send( getTestAlertData({ - alertTypeId: 'test.validation', + rule_type_id: 'test.validation', }) ); @@ -492,7 +497,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { it('should handle create alert request appropriately when interval schedule is wrong syntax', async () => { const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send(getTestAlertData(getTestAlertData({ schedule: { interval: '10x' } }))); @@ -519,7 +524,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { it('should handle create alert request appropriately when interval schedule is 0', async () => { const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send(getTestAlertData(getTestAlertData({ schedule: { interval: '0s' } }))); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/delete.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/delete.ts index 3734e4ebe7c8af..2cbb16ababd10b 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/delete.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/delete.ts @@ -40,13 +40,13 @@ export default function createDeleteTests({ getService }: FtrProviderContext) { describe(scenario.id, () => { it('should handle delete alert request appropriately', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); const response = await supertestWithoutAuth - .delete(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .delete(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password); @@ -64,9 +64,9 @@ export default function createDeleteTests({ getService }: FtrProviderContext) { ), statusCode: 403, }); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); // Ensure task still exists - await getScheduledTask(createdAlert.scheduledTaskId); + await getScheduledTask(createdAlert.scheduled_task_id); break; case 'superuser at space1': case 'space_1_all at space1': @@ -75,7 +75,7 @@ export default function createDeleteTests({ getService }: FtrProviderContext) { expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); try { - await getScheduledTask(createdAlert.scheduledTaskId); + await getScheduledTask(createdAlert.scheduled_task_id); throw new Error('Should have removed scheduled task'); } catch (e) { expect(e.status).to.eql(404); @@ -88,18 +88,18 @@ export default function createDeleteTests({ getService }: FtrProviderContext) { it('should handle delete alert request appropriately when consumer is the same as producer', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.restricted-noop', + rule_type_id: 'test.restricted-noop', consumer: 'alertsRestrictedFixture', }) ) .expect(200); const response = await supertestWithoutAuth - .delete(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .delete(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password); @@ -119,16 +119,16 @@ export default function createDeleteTests({ getService }: FtrProviderContext) { ), statusCode: 403, }); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); // Ensure task still exists - await getScheduledTask(createdAlert.scheduledTaskId); + await getScheduledTask(createdAlert.scheduled_task_id); break; case 'superuser at space1': case 'space_1_all_with_restricted_fixture at space1': expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); try { - await getScheduledTask(createdAlert.scheduledTaskId); + await getScheduledTask(createdAlert.scheduled_task_id); throw new Error('Should have removed scheduled task'); } catch (e) { expect(e.status).to.eql(404); @@ -141,15 +141,18 @@ export default function createDeleteTests({ getService }: FtrProviderContext) { it('should handle delete alert request appropriately when consumer is not the producer', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( - getTestAlertData({ alertTypeId: 'test.unrestricted-noop', consumer: 'alertsFixture' }) + getTestAlertData({ + rule_type_id: 'test.unrestricted-noop', + consumer: 'alertsFixture', + }) ) .expect(200); const response = await supertestWithoutAuth - .delete(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .delete(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password); @@ -167,9 +170,9 @@ export default function createDeleteTests({ getService }: FtrProviderContext) { ), statusCode: 403, }); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); // Ensure task still exists - await getScheduledTask(createdAlert.scheduledTaskId); + await getScheduledTask(createdAlert.scheduled_task_id); break; case 'space_1_all at space1': case 'space_1_all_alerts_none_actions at space1': @@ -183,16 +186,16 @@ export default function createDeleteTests({ getService }: FtrProviderContext) { ), statusCode: 403, }); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); // Ensure task still exists - await getScheduledTask(createdAlert.scheduledTaskId); + await getScheduledTask(createdAlert.scheduled_task_id); break; case 'superuser at space1': case 'space_1_all_with_restricted_fixture at space1': expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); try { - await getScheduledTask(createdAlert.scheduledTaskId); + await getScheduledTask(createdAlert.scheduled_task_id); throw new Error('Should have removed scheduled task'); } catch (e) { expect(e.status).to.eql(404); @@ -205,18 +208,18 @@ export default function createDeleteTests({ getService }: FtrProviderContext) { it('should handle delete alert request appropriately when consumer is "alerts"', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.noop', + rule_type_id: 'test.noop', consumer: 'alerts', }) ) .expect(200); const response = await supertestWithoutAuth - .delete(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .delete(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password); @@ -241,9 +244,9 @@ export default function createDeleteTests({ getService }: FtrProviderContext) { ), statusCode: 403, }); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); // Ensure task still exists - await getScheduledTask(createdAlert.scheduledTaskId); + await getScheduledTask(createdAlert.scheduled_task_id); break; case 'superuser at space1': case 'space_1_all at space1': @@ -252,7 +255,7 @@ export default function createDeleteTests({ getService }: FtrProviderContext) { expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); try { - await getScheduledTask(createdAlert.scheduledTaskId); + await getScheduledTask(createdAlert.scheduled_task_id); throw new Error('Should have removed scheduled task'); } catch (e) { expect(e.status).to.eql(404); @@ -265,14 +268,14 @@ export default function createDeleteTests({ getService }: FtrProviderContext) { it(`shouldn't delete alert from another space`, async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await supertestWithoutAuth - .delete(`${getUrlPrefix('other')}/api/alerts/alert/${createdAlert.id}`) + .delete(`${getUrlPrefix('other')}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password); @@ -298,7 +301,7 @@ export default function createDeleteTests({ getService }: FtrProviderContext) { it('should still be able to delete alert when AAD is broken', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); @@ -318,7 +321,7 @@ export default function createDeleteTests({ getService }: FtrProviderContext) { }); const response = await supertestWithoutAuth - .delete(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .delete(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password); @@ -336,9 +339,9 @@ export default function createDeleteTests({ getService }: FtrProviderContext) { ), statusCode: 403, }); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); // Ensure task still exists - await getScheduledTask(createdAlert.scheduledTaskId); + await getScheduledTask(createdAlert.scheduled_task_id); break; case 'superuser at space1': case 'space_1_all at space1': @@ -347,7 +350,7 @@ export default function createDeleteTests({ getService }: FtrProviderContext) { expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); try { - await getScheduledTask(createdAlert.scheduledTaskId); + await getScheduledTask(createdAlert.scheduled_task_id); throw new Error('Should have removed scheduled task'); } catch (e) { expect(e.status).to.eql(404); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/disable.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/disable.ts index 17f4bdf61b2209..b265451bbd632b 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/disable.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/disable.ts @@ -44,18 +44,18 @@ export default function createDisableAlertTests({ getService }: FtrProviderConte describe(scenario.id, () => { it('should handle disable alert request appropriately', async () => { const { body: createdAction } = await supertest - .post(`${getUrlPrefix(space.id)}/api/actions/action`) + .post(`${getUrlPrefix(space.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'MY action', - actionTypeId: 'test.noop', + connector_type_id: 'test.noop', config: {}, secrets: {}, }) .expect(200); const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ @@ -70,7 +70,7 @@ export default function createDisableAlertTests({ getService }: FtrProviderConte }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await alertUtils.getDisableRequest(createdAlert.id); @@ -89,7 +89,7 @@ export default function createDisableAlertTests({ getService }: FtrProviderConte statusCode: 403, }); // Ensure task still exists - await getScheduledTask(createdAlert.scheduledTaskId); + await getScheduledTask(createdAlert.scheduled_task_id); break; case 'space_1_all_alerts_none_actions at space1': case 'superuser at space1': @@ -98,7 +98,7 @@ export default function createDisableAlertTests({ getService }: FtrProviderConte expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); try { - await getScheduledTask(createdAlert.scheduledTaskId); + await getScheduledTask(createdAlert.scheduled_task_id); throw new Error('Should have removed scheduled task'); } catch (e) { expect(e.status).to.eql(404); @@ -118,17 +118,17 @@ export default function createDisableAlertTests({ getService }: FtrProviderConte it('should handle disable alert request appropriately when consumer is the same as producer', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.restricted-noop', + rule_type_id: 'test.restricted-noop', consumer: 'alertsRestrictedFixture', enabled: true, }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await alertUtils.getDisableRequest(createdAlert.id); @@ -154,7 +154,7 @@ export default function createDisableAlertTests({ getService }: FtrProviderConte expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); try { - await getScheduledTask(createdAlert.scheduledTaskId); + await getScheduledTask(createdAlert.scheduled_task_id); throw new Error('Should have removed scheduled task'); } catch (e) { expect(e.status).to.eql(404); @@ -167,17 +167,17 @@ export default function createDisableAlertTests({ getService }: FtrProviderConte it('should handle disable alert request appropriately when consumer is not the producer', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.unrestricted-noop', + rule_type_id: 'test.unrestricted-noop', consumer: 'alertsFixture', enabled: true, }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await alertUtils.getDisableRequest(createdAlert.id); @@ -214,7 +214,7 @@ export default function createDisableAlertTests({ getService }: FtrProviderConte expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); try { - await getScheduledTask(createdAlert.scheduledTaskId); + await getScheduledTask(createdAlert.scheduled_task_id); throw new Error('Should have removed scheduled task'); } catch (e) { expect(e.status).to.eql(404); @@ -227,17 +227,17 @@ export default function createDisableAlertTests({ getService }: FtrProviderConte it('should handle disable alert request appropriately when consumer is "alerts"', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.noop', + rule_type_id: 'test.noop', consumer: 'alerts', enabled: true, }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await alertUtils.getDisableRequest(createdAlert.id); @@ -270,7 +270,7 @@ export default function createDisableAlertTests({ getService }: FtrProviderConte expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); try { - await getScheduledTask(createdAlert.scheduledTaskId); + await getScheduledTask(createdAlert.scheduled_task_id); throw new Error('Should have removed scheduled task'); } catch (e) { expect(e.status).to.eql(404); @@ -283,11 +283,11 @@ export default function createDisableAlertTests({ getService }: FtrProviderConte it('should still be able to disable alert when AAD is broken', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData({ enabled: true })) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); await retry.try(async () => { await supertest @@ -320,7 +320,7 @@ export default function createDisableAlertTests({ getService }: FtrProviderConte statusCode: 403, }); // Ensure task still exists - await getScheduledTask(createdAlert.scheduledTaskId); + await getScheduledTask(createdAlert.scheduled_task_id); break; case 'superuser at space1': case 'space_1_all at space1': @@ -329,7 +329,7 @@ export default function createDisableAlertTests({ getService }: FtrProviderConte expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); try { - await getScheduledTask(createdAlert.scheduledTaskId); + await getScheduledTask(createdAlert.scheduled_task_id); throw new Error('Should have removed scheduled task'); } catch (e) { expect(e.status).to.eql(404); @@ -349,11 +349,11 @@ export default function createDisableAlertTests({ getService }: FtrProviderConte it(`shouldn't disable alert from another space`, async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix('other')}/api/alerts/alert`) + .post(`${getUrlPrefix('other')}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData({ enabled: true })) .expect(200); - objectRemover.add('other', createdAlert.id, 'alert', 'alerts'); + objectRemover.add('other', createdAlert.id, 'rule', 'alerting'); const response = await alertUtils.getDisableRequest(createdAlert.id); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/enable.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/enable.ts index 262a1a791a99cd..70e286b7957206 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/enable.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/enable.ts @@ -44,18 +44,18 @@ export default function createEnableAlertTests({ getService }: FtrProviderContex describe(scenario.id, () => { it('should handle enable alert request appropriately', async () => { const { body: createdAction } = await supertest - .post(`${getUrlPrefix(space.id)}/api/actions/action`) + .post(`${getUrlPrefix(space.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'MY action', - actionTypeId: 'test.noop', + connector_type_id: 'test.noop', config: {}, secrets: {}, }) .expect(200); const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ @@ -70,7 +70,7 @@ export default function createEnableAlertTests({ getService }: FtrProviderContex }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await alertUtils.getEnableRequest(createdAlert.id); @@ -114,12 +114,14 @@ export default function createEnableAlertTests({ getService }: FtrProviderContex expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(200); - expect(typeof updatedAlert.scheduledTaskId).to.eql('string'); - const { _source: taskRecord } = await getScheduledTask(updatedAlert.scheduledTaskId); + expect(typeof updatedAlert.scheduled_task_id).to.eql('string'); + const { _source: taskRecord } = await getScheduledTask( + updatedAlert.scheduled_task_id + ); expect(taskRecord.type).to.eql('task'); expect(taskRecord.task.taskType).to.eql('alerting:test.noop'); expect(JSON.parse(taskRecord.task.params)).to.eql({ @@ -141,17 +143,17 @@ export default function createEnableAlertTests({ getService }: FtrProviderContex it('should handle enable alert request appropriately when consumer is the same as producer', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.restricted-noop', + rule_type_id: 'test.restricted-noop', consumer: 'alertsRestrictedFixture', enabled: false, }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await alertUtils.getEnableRequest(createdAlert.id); @@ -177,7 +179,7 @@ export default function createEnableAlertTests({ getService }: FtrProviderContex expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); try { - await getScheduledTask(createdAlert.scheduledTaskId); + await getScheduledTask(createdAlert.scheduled_task_id); throw new Error('Should have removed scheduled task'); } catch (e) { expect(e.status).to.eql(404); @@ -190,17 +192,17 @@ export default function createEnableAlertTests({ getService }: FtrProviderContex it('should handle enable alert request appropriately when consumer is not the producer', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.unrestricted-noop', + rule_type_id: 'test.unrestricted-noop', consumer: 'alertsFixture', enabled: false, }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await alertUtils.getEnableRequest(createdAlert.id); @@ -244,17 +246,17 @@ export default function createEnableAlertTests({ getService }: FtrProviderContex it('should handle enable alert request appropriately when consumer is "alerts"', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.noop', + rule_type_id: 'test.noop', consumer: 'alerts', enabled: false, }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await alertUtils.getEnableRequest(createdAlert.id); @@ -287,7 +289,7 @@ export default function createEnableAlertTests({ getService }: FtrProviderContex expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); try { - await getScheduledTask(createdAlert.scheduledTaskId); + await getScheduledTask(createdAlert.scheduled_task_id); throw new Error('Should have removed scheduled task'); } catch (e) { expect(e.status).to.eql(404); @@ -300,11 +302,11 @@ export default function createEnableAlertTests({ getService }: FtrProviderContex it('should still be able to enable alert when AAD is broken', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData({ enabled: false })) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); await retry.try(async () => { await supertest @@ -344,12 +346,14 @@ export default function createEnableAlertTests({ getService }: FtrProviderContex expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(200); - expect(typeof updatedAlert.scheduledTaskId).to.eql('string'); - const { _source: taskRecord } = await getScheduledTask(updatedAlert.scheduledTaskId); + expect(typeof updatedAlert.scheduled_task_id).to.eql('string'); + const { _source: taskRecord } = await getScheduledTask( + updatedAlert.scheduled_task_id + ); expect(taskRecord.type).to.eql('task'); expect(taskRecord.task.taskType).to.eql('alerting:test.noop'); expect(JSON.parse(taskRecord.task.params)).to.eql({ @@ -371,11 +375,11 @@ export default function createEnableAlertTests({ getService }: FtrProviderContex it(`shouldn't enable alert from another space`, async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix('other')}/api/alerts/alert`) + .post(`${getUrlPrefix('other')}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData({ enabled: false })) .expect(200); - objectRemover.add('other', createdAlert.id, 'alert', 'alerts'); + objectRemover.add('other', createdAlert.id, 'rule', 'alerting'); const response = await alertUtils.getEnableRequest(createdAlert.id); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/event_log.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/event_log.ts index 2561a8f3a7d488..825ade55cb4b05 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/event_log.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/event_log.ts @@ -24,11 +24,11 @@ export default function eventLogTests({ getService }: FtrProviderContext) { it('should generate events for alert decrypt errors', async () => { const spaceId = Spaces[0].id; const response = await supertest - .post(`${getUrlPrefix(spaceId)}/api/alerts/alert`) + .post(`${getUrlPrefix(spaceId)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.noop', + rule_type_id: 'test.noop', schedule: { interval: '1s' }, throttle: null, }) @@ -36,7 +36,7 @@ export default function eventLogTests({ getService }: FtrProviderContext) { expect(response.status).to.eql(200); const alertId = response.body.id; - objectRemover.add(spaceId, alertId, 'alert', 'alerts'); + objectRemover.add(spaceId, alertId, 'rule', 'alerting'); await retry.try(async () => { // break AAD diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/execution_status.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/execution_status.ts index 18f0be353b7da2..2bae1c541bc485 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/execution_status.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/execution_status.ts @@ -25,17 +25,17 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon it('should eventually have error reason "decrypt" when appropriate', async () => { const response = await supertest - .post(`${getUrlPrefix(spaceId)}/api/alerts/alert`) + .post(`${getUrlPrefix(spaceId)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.noop', + rule_type_id: 'test.noop', schedule: { interval: '1s' }, }) ); expect(response.status).to.eql(200); const alertId = response.body.id; - objectRemover.add(spaceId, alertId, 'alert', 'alerts'); + objectRemover.add(spaceId, alertId, 'rule', 'alerting'); let executionStatus = await waitForStatus(alertId, new Set(['ok']), 10000); @@ -70,15 +70,15 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon expect().fail(`waiting for alert ${id} statuses ${Array.from(statuses)} timed out`); } - const response = await supertest.get(`${getUrlPrefix(spaceId)}/api/alerts/alert/${id}`); + const response = await supertest.get(`${getUrlPrefix(spaceId)}/api/alerting/rule/${id}`); expect(response.status).to.eql(200); - const { status } = response.body.executionStatus; - if (statuses.has(status)) return response.body.executionStatus; + const { status } = response.body.execution_status; + if (statuses.has(status)) return response.body.execution_status; // eslint-disable-next-line no-console console.log( `waitForStatus(${Array.from(statuses)}): got ${JSON.stringify( - response.body.executionStatus + response.body.execution_status )}, retrying` ); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/find.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/find.ts index 29a5ef6fdf1860..dda5970904f8d8 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/find.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/find.ts @@ -27,17 +27,17 @@ export default function createFindTests({ getService }: FtrProviderContext) { describe(scenario.id, () => { it('should handle find alert request appropriately', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await supertestWithoutAuth .get( `${getUrlPrefix( space.id - )}/api/alerts/_find?search=test.noop&search_fields=alertTypeId` + )}/api/alerting/rules/_find?search=test.noop&search_fields=alertTypeId` ) .auth(user.username, user.password); @@ -58,33 +58,33 @@ export default function createFindTests({ getService }: FtrProviderContext) { case 'space_1_all_with_restricted_fixture at space1': expect(response.statusCode).to.eql(200); expect(response.body.page).to.equal(1); - expect(response.body.perPage).to.be.greaterThan(0); + expect(response.body.per_page).to.be.greaterThan(0); expect(response.body.total).to.be.greaterThan(0); const match = response.body.data.find((obj: any) => obj.id === createdAlert.id); expect(match).to.eql({ id: createdAlert.id, name: 'abc', tags: ['foo'], - alertTypeId: 'test.noop', + rule_type_id: 'test.noop', consumer: 'alertsFixture', schedule: { interval: '1m' }, enabled: true, actions: [], params: {}, - createdBy: 'elastic', - scheduledTaskId: match.scheduledTaskId, - createdAt: match.createdAt, - updatedAt: match.updatedAt, + created_by: 'elastic', + scheduled_task_id: match.scheduled_task_id, + created_at: match.created_at, + updated_at: match.updated_at, throttle: '1m', - notifyWhen: 'onThrottleInterval', - updatedBy: 'elastic', - apiKeyOwner: 'elastic', - muteAll: false, - mutedInstanceIds: [], - executionStatus: match.executionStatus, + notify_when: 'onThrottleInterval', + updated_by: 'elastic', + api_key_owner: 'elastic', + mute_all: false, + muted_alert_ids: [], + execution_status: match.execution_status, }); - expect(Date.parse(match.createdAt)).to.be.greaterThan(0); - expect(Date.parse(match.updatedAt)).to.be.greaterThan(0); + expect(Date.parse(match.created_at)).to.be.greaterThan(0); + expect(Date.parse(match.updated_at)).to.be.greaterThan(0); break; default: throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); @@ -95,25 +95,25 @@ export default function createFindTests({ getService }: FtrProviderContext) { async function createNoOpAlert(overrides = {}) { const alert = getTestAlertData(overrides); const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(alert) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); return { id: createdAlert.id, - alertTypeId: alert.alertTypeId, + rule_type_id: alert.rule_type_id, }; } function createRestrictedNoOpAlert() { return createNoOpAlert({ - alertTypeId: 'test.restricted-noop', + rule_type_id: 'test.restricted-noop', consumer: 'alertsRestrictedFixture', }); } function createUnrestrictedNoOpAlert() { return createNoOpAlert({ - alertTypeId: 'test.unrestricted-noop', + rule_type_id: 'test.unrestricted-noop', consumer: 'alertsFixture', }); } @@ -131,7 +131,9 @@ export default function createFindTests({ getService }: FtrProviderContext) { const response = await supertestWithoutAuth .get( - `${getUrlPrefix(space.id)}/api/alerts/_find?per_page=${perPage}&sort_field=createdAt` + `${getUrlPrefix( + space.id + )}/api/alerting/rules/_find?per_page=${perPage}&sort_field=createdAt` ) .auth(user.username, user.password); @@ -149,12 +151,12 @@ export default function createFindTests({ getService }: FtrProviderContext) { case 'space_1_all_alerts_none_actions at space1': expect(response.statusCode).to.eql(200); expect(response.body.page).to.equal(1); - expect(response.body.perPage).to.be.equal(perPage); + expect(response.body.per_page).to.be.equal(perPage); expect(response.body.total).to.be.equal(6); { const [firstPage] = chunk( allAlerts - .filter((alert) => alert.alertTypeId !== 'test.restricted-noop') + .filter((alert) => alert.rule_type_id !== 'test.restricted-noop') .map((alert) => alert.id), perPage ); @@ -166,7 +168,7 @@ export default function createFindTests({ getService }: FtrProviderContext) { case 'space_1_all_with_restricted_fixture at space1': expect(response.statusCode).to.eql(200); expect(response.body.page).to.equal(1); - expect(response.body.perPage).to.be.equal(perPage); + expect(response.body.per_page).to.be.equal(perPage); expect(response.body.total).to.be.equal(8); { @@ -180,7 +182,7 @@ export default function createFindTests({ getService }: FtrProviderContext) { .get( `${getUrlPrefix( space.id - )}/api/alerts/_find?per_page=${perPage}&sort_field=createdAt&page=2` + )}/api/alerting/rules/_find?per_page=${perPage}&sort_field=createdAt&page=2` ) .auth(user.username, user.password); @@ -195,18 +197,18 @@ export default function createFindTests({ getService }: FtrProviderContext) { it('should handle find alert request with filter appropriately', async () => { const { body: createdAction } = await supertest - .post(`${getUrlPrefix(space.id)}/api/actions/action`) + .post(`${getUrlPrefix(space.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'My action', - actionTypeId: 'test.noop', + connector_type_id: 'test.noop', config: {}, secrets: {}, }) .expect(200); const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ @@ -221,13 +223,13 @@ export default function createFindTests({ getService }: FtrProviderContext) { }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await supertestWithoutAuth .get( `${getUrlPrefix( space.id - )}/api/alerts/_find?filter=alert.attributes.actions:{ actionTypeId: test.noop }` + )}/api/alerting/rules/_find?filter=alert.attributes.actions:{ actionTypeId: test.noop }` ) .auth(user.username, user.password); @@ -248,14 +250,14 @@ export default function createFindTests({ getService }: FtrProviderContext) { case 'space_1_all_with_restricted_fixture at space1': expect(response.statusCode).to.eql(200); expect(response.body.page).to.equal(1); - expect(response.body.perPage).to.be.greaterThan(0); + expect(response.body.per_page).to.be.greaterThan(0); expect(response.body.total).to.be.greaterThan(0); const match = response.body.data.find((obj: any) => obj.id === createdAlert.id); expect(match).to.eql({ id: createdAlert.id, name: 'abc', tags: ['foo'], - alertTypeId: 'test.noop', + rule_type_id: 'test.noop', consumer: 'alertsFixture', schedule: { interval: '1m' }, enabled: false, @@ -263,24 +265,24 @@ export default function createFindTests({ getService }: FtrProviderContext) { { id: createdAction.id, group: 'default', - actionTypeId: 'test.noop', + connector_type_id: 'test.noop', params: {}, }, ], params: {}, - createdBy: 'elastic', + created_by: 'elastic', throttle: '1m', - updatedBy: 'elastic', - apiKeyOwner: null, - muteAll: false, - mutedInstanceIds: [], - notifyWhen: 'onThrottleInterval', - createdAt: match.createdAt, - updatedAt: match.updatedAt, - executionStatus: match.executionStatus, + updated_by: 'elastic', + api_key_owner: null, + mute_all: false, + muted_alert_ids: [], + notify_when: 'onThrottleInterval', + created_at: match.created_at, + updated_at: match.updated_at, + execution_status: match.execution_status, }); - expect(Date.parse(match.createdAt)).to.be.greaterThan(0); - expect(Date.parse(match.updatedAt)).to.be.greaterThan(0); + expect(Date.parse(match.created_at)).to.be.greaterThan(0); + expect(Date.parse(match.updated_at)).to.be.greaterThan(0); break; default: throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); @@ -290,38 +292,38 @@ export default function createFindTests({ getService }: FtrProviderContext) { it('should handle find alert request with fields appropriately', async () => { const myTag = uuid.v4(); const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ enabled: false, tags: [myTag], - alertTypeId: 'test.restricted-noop', + rule_type_id: 'test.restricted-noop', consumer: 'alertsRestrictedFixture', }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); // create another type with same tag const { body: createdSecondAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ tags: [myTag], - alertTypeId: 'test.restricted-noop', + rule_type_id: 'test.restricted-noop', consumer: 'alertsRestrictedFixture', }) ) .expect(200); - objectRemover.add(space.id, createdSecondAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdSecondAlert.id, 'rule', 'alerting'); const response = await supertestWithoutAuth .get( `${getUrlPrefix( space.id - )}/api/alerts/_find?filter=alert.attributes.alertTypeId:test.restricted-noop&fields=["tags"]&sort_field=createdAt` + )}/api/alerting/rules/_find?filter=alert.attributes.alertTypeId:test.restricted-noop&fields=["tags"]&sort_field=createdAt` ) .auth(user.username, user.password); @@ -345,7 +347,7 @@ export default function createFindTests({ getService }: FtrProviderContext) { case 'space_1_all_with_restricted_fixture at space1': expect(response.statusCode).to.eql(200); expect(response.body.page).to.equal(1); - expect(response.body.perPage).to.be.greaterThan(0); + expect(response.body.per_page).to.be.greaterThan(0); expect(response.body.total).to.be.greaterThan(0); const [matchFirst, matchSecond] = response.body.data; expect(omit(matchFirst, 'updatedAt')).to.eql({ @@ -367,38 +369,38 @@ export default function createFindTests({ getService }: FtrProviderContext) { it('should handle find alert request with executionStatus field appropriately', async () => { const myTag = uuid.v4(); const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ enabled: false, tags: [myTag], - alertTypeId: 'test.restricted-noop', + rule_type_id: 'test.restricted-noop', consumer: 'alertsRestrictedFixture', }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); // create another type with same tag const { body: createdSecondAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ tags: [myTag], - alertTypeId: 'test.restricted-noop', + rule_type_id: 'test.restricted-noop', consumer: 'alertsRestrictedFixture', }) ) .expect(200); - objectRemover.add(space.id, createdSecondAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdSecondAlert.id, 'rule', 'alerting'); const response = await supertestWithoutAuth .get( `${getUrlPrefix( space.id - )}/api/alerts/_find?filter=alert.attributes.alertTypeId:test.restricted-noop&fields=["tags","executionStatus"]&sort_field=createdAt` + )}/api/alerting/rules/_find?filter=alert.attributes.alertTypeId:test.restricted-noop&fields=["tags","executionStatus"]&sort_field=createdAt` ) .auth(user.username, user.password); @@ -422,20 +424,20 @@ export default function createFindTests({ getService }: FtrProviderContext) { case 'space_1_all_with_restricted_fixture at space1': expect(response.statusCode).to.eql(200); expect(response.body.page).to.equal(1); - expect(response.body.perPage).to.be.greaterThan(0); + expect(response.body.per_page).to.be.greaterThan(0); expect(response.body.total).to.be.greaterThan(0); const [matchFirst, matchSecond] = response.body.data; expect(omit(matchFirst, 'updatedAt')).to.eql({ id: createdAlert.id, actions: [], tags: [myTag], - executionStatus: matchFirst.executionStatus, + execution_status: matchFirst.execution_status, }); expect(omit(matchSecond, 'updatedAt')).to.eql({ id: createdSecondAlert.id, actions: [], tags: [myTag], - executionStatus: matchSecond.executionStatus, + execution_status: matchSecond.execution_status, }); break; default: @@ -445,15 +447,17 @@ export default function createFindTests({ getService }: FtrProviderContext) { it(`shouldn't find alert from another space`, async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await supertestWithoutAuth .get( - `${getUrlPrefix('other')}/api/alerts/_find?search=test.noop&search_fields=alertTypeId` + `${getUrlPrefix( + 'other' + )}/api/alerting/rules/_find?search=test.noop&search_fields=alertTypeId` ) .auth(user.username, user.password); @@ -475,7 +479,7 @@ export default function createFindTests({ getService }: FtrProviderContext) { expect(response.statusCode).to.eql(200); expect(response.body).to.eql({ page: 1, - perPage: 10, + per_page: 10, total: 0, data: [], }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get.ts index 1277084b9eb0db..0400557209348c 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get.ts @@ -31,14 +31,14 @@ export default function createGetTests({ getService }: FtrProviderContext) { describe(scenario.id, () => { it('should handle get alert request appropriately', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .auth(user.username, user.password); switch (scenario.id) { @@ -61,26 +61,26 @@ export default function createGetTests({ getService }: FtrProviderContext) { id: createdAlert.id, name: 'abc', tags: ['foo'], - alertTypeId: 'test.noop', + rule_type_id: 'test.noop', consumer: 'alertsFixture', schedule: { interval: '1m' }, enabled: true, actions: [], params: {}, - createdBy: 'elastic', - scheduledTaskId: response.body.scheduledTaskId, - updatedAt: response.body.updatedAt, - createdAt: response.body.createdAt, + created_by: 'elastic', + scheduled_task_id: response.body.scheduled_task_id, + updated_at: response.body.updated_at, + created_at: response.body.created_at, throttle: '1m', - notifyWhen: 'onThrottleInterval', - updatedBy: 'elastic', - apiKeyOwner: 'elastic', - muteAll: false, - mutedInstanceIds: [], - executionStatus: response.body.executionStatus, + notify_when: 'onThrottleInterval', + updated_by: 'elastic', + api_key_owner: 'elastic', + mute_all: false, + muted_alert_ids: [], + execution_status: response.body.execution_status, }); - expect(Date.parse(response.body.createdAt)).to.be.greaterThan(0); - expect(Date.parse(response.body.updatedAt)).to.be.greaterThan(0); + expect(Date.parse(response.body.created_at)).to.be.greaterThan(0); + expect(Date.parse(response.body.updated_at)).to.be.greaterThan(0); break; default: throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); @@ -89,19 +89,19 @@ export default function createGetTests({ getService }: FtrProviderContext) { it('should handle get alert request appropriately when consumer is the same as producer', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.restricted-noop', + rule_type_id: 'test.restricted-noop', consumer: 'alertsRestrictedFixture', }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .auth(user.username, user.password); switch (scenario.id) { @@ -132,19 +132,19 @@ export default function createGetTests({ getService }: FtrProviderContext) { it('should handle get alert request appropriately when consumer is not the producer', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.unrestricted-noop', + rule_type_id: 'test.unrestricted-noop', consumer: 'alertsFixture', }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .auth(user.username, user.password); switch (scenario.id) { @@ -186,19 +186,19 @@ export default function createGetTests({ getService }: FtrProviderContext) { it('should handle get alert request appropriately when consumer is "alerts"', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.restricted-noop', + rule_type_id: 'test.restricted-noop', consumer: 'alerts', }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .auth(user.username, user.password); switch (scenario.id) { @@ -240,14 +240,14 @@ export default function createGetTests({ getService }: FtrProviderContext) { it(`shouldn't get alert from another space`, async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await supertestWithoutAuth - .get(`${getUrlPrefix('other')}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix('other')}/api/alerting/rule/${createdAlert.id}`) .auth(user.username, user.password); expect(response.statusCode).to.eql(404); @@ -272,7 +272,7 @@ export default function createGetTests({ getService }: FtrProviderContext) { it(`should handle get alert request appropriately when alert doesn't exist`, async () => { const response = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/1`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/1`) .auth(user.username, user.password); switch (scenario.id) { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get_alert_instance_summary.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get_alert_instance_summary.ts index 11514a8cf630c3..d4ca6c2aa9cd89 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get_alert_instance_summary.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get_alert_instance_summary.ts @@ -32,14 +32,16 @@ export default function createGetAlertInstanceSummaryTests({ getService }: FtrPr describe(scenario.id, () => { it('should handle getAlertInstanceSummary alert request appropriately', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}/_instance_summary`) + .get( + `${getUrlPrefix(space.id)}/internal/alerting/rule/${createdAlert.id}/_alert_summary` + ) .auth(user.username, user.password); switch (scenario.id) { @@ -58,27 +60,31 @@ export default function createGetAlertInstanceSummaryTests({ getService }: FtrPr case 'space_1_all_alerts_none_actions at space1': case 'space_1_all_with_restricted_fixture at space1': expect(response.statusCode).to.eql(200); - const { id, statusStartDate, statusEndDate } = response.body; + const { + id, + status_start_date: statusStartDate, + status_end_date: statusEndDate, + } = response.body; expect(id).to.equal(createdAlert.id); expect(Date.parse(statusStartDate)).to.be.lessThan(Date.parse(statusEndDate)); const stableBody = omit(response.body, [ 'id', - 'statusStartDate', - 'statusEndDate', - 'lastRun', + 'status_start_date', + 'status_end_date', + 'last_run', ]); expect(stableBody).to.eql({ name: 'abc', tags: ['foo'], - alertTypeId: 'test.noop', + rule_type_id: 'test.noop', consumer: 'alertsFixture', status: 'OK', - muteAll: false, + mute_all: false, throttle: '1m', enabled: true, - errorMessages: [], - instances: {}, + error_messages: [], + alerts: {}, }); break; default: @@ -88,19 +94,21 @@ export default function createGetAlertInstanceSummaryTests({ getService }: FtrPr it('should handle getAlertInstanceSummary alert request appropriately when unauthorized', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.unrestricted-noop', + rule_type_id: 'test.unrestricted-noop', consumer: 'alertsFixture', }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}/_instance_summary`) + .get( + `${getUrlPrefix(space.id)}/internal/alerting/rule/${createdAlert.id}/_alert_summary` + ) .auth(user.username, user.password); switch (scenario.id) { @@ -134,7 +142,7 @@ export default function createGetAlertInstanceSummaryTests({ getService }: FtrPr case 'superuser at space1': case 'space_1_all_with_restricted_fixture at space1': expect(response.statusCode).to.eql(200); - expect(response.body).to.key('id', 'instances', 'errorMessages'); + expect(response.body).to.key('id', 'alerts', 'error_messages'); break; default: throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); @@ -143,14 +151,16 @@ export default function createGetAlertInstanceSummaryTests({ getService }: FtrPr it(`shouldn't getAlertInstanceSummary for an alert from another space`, async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await supertestWithoutAuth - .get(`${getUrlPrefix('other')}/api/alerts/alert/${createdAlert.id}/_instance_summary`) + .get( + `${getUrlPrefix('other')}/internal/alerting/rule/${createdAlert.id}/_alert_summary` + ) .auth(user.username, user.password); expect(response.statusCode).to.eql(404); @@ -175,7 +185,7 @@ export default function createGetAlertInstanceSummaryTests({ getService }: FtrPr it(`should handle getAlertInstanceSummary request appropriately when alert doesn't exist`, async () => { const response = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/1/_instance_summary`) + .get(`${getUrlPrefix(space.id)}/internal/alerting/rule/1/_alert_summary`) .auth(user.username, user.password); switch (scenario.id) { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get_alert_state.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get_alert_state.ts index 5dcecd3f1b05f1..e00d8e53e438eb 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get_alert_state.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get_alert_state.ts @@ -31,14 +31,14 @@ export default function createGetAlertStateTests({ getService }: FtrProviderCont describe(scenario.id, () => { it('should handle getAlertState alert request appropriately', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}/state`) + .get(`${getUrlPrefix(space.id)}/internal/alerting/rule/${createdAlert.id}/state`) .auth(user.username, user.password); switch (scenario.id) { @@ -57,7 +57,7 @@ export default function createGetAlertStateTests({ getService }: FtrProviderCont case 'space_1_all_alerts_none_actions at space1': case 'space_1_all_with_restricted_fixture at space1': expect(response.statusCode).to.eql(200); - expect(response.body).to.key('alertInstances', 'previousStartedAt'); + expect(response.body).to.key('alerts', 'previous_started_at'); break; default: throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); @@ -66,19 +66,19 @@ export default function createGetAlertStateTests({ getService }: FtrProviderCont it('should handle getAlertState alert request appropriately when unauthorized', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.unrestricted-noop', + rule_type_id: 'test.unrestricted-noop', consumer: 'alertsFixture', }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}/state`) + .get(`${getUrlPrefix(space.id)}/internal/alerting/rule/${createdAlert.id}/state`) .auth(user.username, user.password); switch (scenario.id) { @@ -112,7 +112,7 @@ export default function createGetAlertStateTests({ getService }: FtrProviderCont case 'superuser at space1': case 'space_1_all_with_restricted_fixture at space1': expect(response.statusCode).to.eql(200); - expect(response.body).to.key('alertInstances', 'previousStartedAt'); + expect(response.body).to.key('alerts', 'previous_started_at'); break; default: throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); @@ -121,14 +121,14 @@ export default function createGetAlertStateTests({ getService }: FtrProviderCont it(`shouldn't getAlertState for an alert from another space`, async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await supertestWithoutAuth - .get(`${getUrlPrefix('other')}/api/alerts/alert/${createdAlert.id}/state`) + .get(`${getUrlPrefix('other')}/internal/alerting/rule/${createdAlert.id}/state`) .auth(user.username, user.password); expect(response.statusCode).to.eql(404); @@ -153,7 +153,7 @@ export default function createGetAlertStateTests({ getService }: FtrProviderCont it(`should handle getAlertState request appropriately when alert doesn't exist`, async () => { const response = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/1/state`) + .get(`${getUrlPrefix(space.id)}/internal/alerting/rule/1/state`) .auth(user.username, user.password); switch (scenario.id) { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts index e8cc8ea699e17f..b1b52d89997cd3 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts @@ -41,7 +41,7 @@ export default function alertingTests({ loadTestFile, getService }: FtrProviderC loadTestFile(require.resolve('./get')); loadTestFile(require.resolve('./get_alert_state')); loadTestFile(require.resolve('./get_alert_instance_summary')); - loadTestFile(require.resolve('./list_alert_types')); + loadTestFile(require.resolve('./rule_types')); loadTestFile(require.resolve('./mute_all')); loadTestFile(require.resolve('./mute_instance')); loadTestFile(require.resolve('./unmute_all')); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mustache_templates.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mustache_templates.ts index 6ac50d84857281..8344d4a281ba1f 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mustache_templates.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mustache_templates.ts @@ -62,28 +62,28 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon it('should render kibanaBaseUrl as non-empty string since configured', async () => { const actionResponse = await supertest - .post(`${getUrlPrefix(Spaces[0].id)}/api/actions/action`) + .post(`${getUrlPrefix(Spaces[0].id)}/api/actions/connector`) .set('kbn-xsrf', 'test') .send({ name: 'testing context variable expansion', - actionTypeId: '.slack', + connector_type_id: '.slack', secrets: { webhookUrl: slackSimulatorURL, }, }); expect(actionResponse.status).to.eql(200); const createdAction = actionResponse.body; - objectRemover.add(Spaces[0].id, createdAction.id, 'action', 'actions'); + objectRemover.add(Spaces[0].id, createdAction.id, 'connector', 'actions'); const varsTemplate = 'kibanaBaseUrl: "{{kibanaBaseUrl}}"'; const alertResponse = await supertest - .post(`${getUrlPrefix(Spaces[0].id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces[0].id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ name: 'testing context variable kibanaBaseUrl', - alertTypeId: 'test.patternFiring', + rule_type_id: 'test.patternFiring', params: { pattern: { instance: [true, true] }, }, @@ -100,7 +100,7 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon ); expect(alertResponse.status).to.eql(200); const createdAlert = alertResponse.body; - objectRemover.add(Spaces[0].id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces[0].id, createdAlert.id, 'rule', 'alerting'); const body = await retry.try(async () => waitForActionBody(slackSimulatorURL, createdAlert.id) diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute_all.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute_all.ts index f226537e462f11..993b66353756f6 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute_all.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute_all.ts @@ -35,18 +35,18 @@ export default function createMuteAlertTests({ getService }: FtrProviderContext) describe(scenario.id, () => { it('should handle mute alert request appropriately', async () => { const { body: createdAction } = await supertest - .post(`${getUrlPrefix(space.id)}/api/actions/action`) + .post(`${getUrlPrefix(space.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'MY action', - actionTypeId: 'test.noop', + connector_type_id: 'test.noop', config: {}, secrets: {}, }) .expect(200); const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ @@ -61,7 +61,7 @@ export default function createMuteAlertTests({ getService }: FtrProviderContext) }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await alertUtils.getMuteAllRequest(createdAlert.id); @@ -94,11 +94,11 @@ export default function createMuteAlertTests({ getService }: FtrProviderContext) expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(200); - expect(updatedAlert.muteAll).to.eql(true); + expect(updatedAlert.mute_all).to.eql(true); // Ensure AAD isn't broken await checkAAD({ supertest, @@ -114,17 +114,17 @@ export default function createMuteAlertTests({ getService }: FtrProviderContext) it('should handle mute alert request appropriately when consumer is the same as producer', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ enabled: false, - alertTypeId: 'test.restricted-noop', + rule_type_id: 'test.restricted-noop', consumer: 'alertsRestrictedFixture', }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await alertUtils.getMuteAllRequest(createdAlert.id); @@ -150,11 +150,11 @@ export default function createMuteAlertTests({ getService }: FtrProviderContext) expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(200); - expect(updatedAlert.muteAll).to.eql(true); + expect(updatedAlert.mute_all).to.eql(true); // Ensure AAD isn't broken await checkAAD({ supertest, @@ -170,17 +170,17 @@ export default function createMuteAlertTests({ getService }: FtrProviderContext) it('should handle mute alert request appropriately when consumer is not the producer', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ enabled: false, - alertTypeId: 'test.unrestricted-noop', + rule_type_id: 'test.unrestricted-noop', consumer: 'alertsFixture', }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await alertUtils.getMuteAllRequest(createdAlert.id); @@ -217,11 +217,11 @@ export default function createMuteAlertTests({ getService }: FtrProviderContext) expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(200); - expect(updatedAlert.muteAll).to.eql(true); + expect(updatedAlert.mute_all).to.eql(true); // Ensure AAD isn't broken await checkAAD({ supertest, @@ -237,17 +237,17 @@ export default function createMuteAlertTests({ getService }: FtrProviderContext) it('should handle mute alert request appropriately when consumer is "alerts"', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ enabled: false, - alertTypeId: 'test.restricted-noop', + rule_type_id: 'test.restricted-noop', consumer: 'alerts', }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await alertUtils.getMuteAllRequest(createdAlert.id); @@ -284,11 +284,11 @@ export default function createMuteAlertTests({ getService }: FtrProviderContext) expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(200); - expect(updatedAlert.muteAll).to.eql(true); + expect(updatedAlert.mute_all).to.eql(true); // Ensure AAD isn't broken await checkAAD({ supertest, diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute_instance.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute_instance.ts index f70a2a1af5429b..858e61154cef59 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute_instance.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/mute_instance.ts @@ -35,18 +35,18 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider describe(scenario.id, () => { it('should handle mute alert instance request appropriately', async () => { const { body: createdAction } = await supertest - .post(`${getUrlPrefix(space.id)}/api/actions/action`) + .post(`${getUrlPrefix(space.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'MY action', - actionTypeId: 'test.noop', + connector_type_id: 'test.noop', config: {}, secrets: {}, }) .expect(200); const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ @@ -61,7 +61,7 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await alertUtils.getMuteInstanceRequest(createdAlert.id, '1'); @@ -94,11 +94,11 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(200); - expect(updatedAlert.mutedInstanceIds).to.eql(['1']); + expect(updatedAlert.muted_alert_ids).to.eql(['1']); // Ensure AAD isn't broken await checkAAD({ supertest, @@ -114,17 +114,17 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider it('should handle mute alert instance request appropriately when consumer is the same as producer', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ enabled: false, - alertTypeId: 'test.restricted-noop', + rule_type_id: 'test.restricted-noop', consumer: 'alertsRestrictedFixture', }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await alertUtils.getMuteInstanceRequest(createdAlert.id, '1'); @@ -150,11 +150,11 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(200); - expect(updatedAlert.mutedInstanceIds).to.eql(['1']); + expect(updatedAlert.muted_alert_ids).to.eql(['1']); // Ensure AAD isn't broken await checkAAD({ supertest, @@ -170,17 +170,17 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider it('should handle mute alert instance request appropriately when consumer is not the producer', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ enabled: false, - alertTypeId: 'test.unrestricted-noop', + rule_type_id: 'test.unrestricted-noop', consumer: 'alertsFixture', }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await alertUtils.getMuteInstanceRequest(createdAlert.id, '1'); @@ -217,11 +217,11 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(200); - expect(updatedAlert.mutedInstanceIds).to.eql(['1']); + expect(updatedAlert.muted_alert_ids).to.eql(['1']); // Ensure AAD isn't broken await checkAAD({ supertest, @@ -237,17 +237,17 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider it('should handle mute alert instance request appropriately when consumer is "alerts"', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ enabled: false, - alertTypeId: 'test.restricted-noop', + rule_type_id: 'test.restricted-noop', consumer: 'alerts', }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await alertUtils.getMuteInstanceRequest(createdAlert.id, '1'); @@ -284,11 +284,11 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(200); - expect(updatedAlert.mutedInstanceIds).to.eql(['1']); + expect(updatedAlert.muted_alert_ids).to.eql(['1']); // Ensure AAD isn't broken await checkAAD({ supertest, @@ -304,16 +304,14 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider it('should handle mute alert instance request appropriately and not duplicate mutedInstanceIds when muting an instance already muted', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData({ enabled: false })) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); await supertest - .post( - `${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}/alert_instance/1/_mute` - ) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}/alert/1/_mute`) .set('kbn-xsrf', 'foo') .expect(204, ''); @@ -341,11 +339,11 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(200); - expect(updatedAlert.mutedInstanceIds).to.eql(['1']); + expect(updatedAlert.muted_alert_ids).to.eql(['1']); break; default: throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/rbac_legacy.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/rbac_legacy.ts index 3db35653747400..fb32be12500cad 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/rbac_legacy.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/rbac_legacy.ts @@ -160,7 +160,7 @@ export default function alertTests({ getService }: FtrProviderContext) { async function ensureLegacyAlertHasBeenMigrated(alertId: string) { const getResponse = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${alertId}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${alertId}`) .auth(user.username, user.password); expect(getResponse.status).to.eql(200); } diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/list_alert_types.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/rule_types.ts similarity index 66% rename from x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/list_alert_types.ts rename to x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/rule_types.ts index 1da93e2d850a3b..c851aaf2bbc88d 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/list_alert_types.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/rule_types.ts @@ -16,56 +16,56 @@ export default function listAlertTypes({ getService }: FtrProviderContext) { const supertestWithoutAuth = getService('supertestWithoutAuth'); const expectedNoOpType = { - actionGroups: [ + action_groups: [ { id: 'default', name: 'Default' }, { id: 'recovered', name: 'Recovered' }, ], - defaultActionGroupId: 'default', + default_action_group_id: 'default', id: 'test.noop', name: 'Test: Noop', - actionVariables: { + action_variables: { state: [], context: [], params: [], }, producer: 'alertsFixture', - minimumLicenseRequired: 'basic', - recoveryActionGroup: { + minimum_license_required: 'basic', + recovery_action_group: { id: 'recovered', name: 'Recovered', }, - enabledInLicense: true, + enabled_in_license: true, }; const expectedRestrictedNoOpType = { - actionGroups: [ + action_groups: [ { id: 'default', name: 'Default' }, { id: 'restrictedRecovered', name: 'Restricted Recovery' }, ], - recoveryActionGroup: { + recovery_action_group: { id: 'restrictedRecovered', name: 'Restricted Recovery', }, - defaultActionGroupId: 'default', + default_action_group_id: 'default', id: 'test.restricted-noop', name: 'Test: Restricted Noop', - actionVariables: { + action_variables: { state: [], context: [], params: [], }, producer: 'alertsRestrictedFixture', - minimumLicenseRequired: 'basic', - enabledInLicense: true, + minimum_license_required: 'basic', + enabled_in_license: true, }; - describe('list_alert_types', () => { + describe('rule_types', () => { for (const scenario of UserAtSpaceScenarios) { const { user, space } = scenario; describe(scenario.id, () => { it('should return 200 with list of globally available alert types', async () => { const response = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/list_alert_types`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule_types`) .auth(user.username, user.password); expect(response.statusCode).to.eql(200); @@ -82,76 +82,76 @@ export default function listAlertTypes({ getService }: FtrProviderContext) { break; case 'space_1_all at space1': case 'space_1_all_alerts_none_actions at space1': - expect(omit(noOpAlertType, 'authorizedConsumers')).to.eql(expectedNoOpType); + expect(omit(noOpAlertType, 'authorized_consumers')).to.eql(expectedNoOpType); expect(restrictedNoOpAlertType).to.eql(undefined); - expect(noOpAlertType.authorizedConsumers).to.eql({ + expect(noOpAlertType.authorized_consumers).to.eql({ alerts: { read: true, all: true }, alertsFixture: { read: true, all: true }, }); break; case 'global_read at space1': - expect(omit(noOpAlertType, 'authorizedConsumers')).to.eql(expectedNoOpType); - expect(noOpAlertType.authorizedConsumers.alertsFixture).to.eql({ + expect(omit(noOpAlertType, 'authorized_consumers')).to.eql(expectedNoOpType); + expect(noOpAlertType.authorized_consumers.alertsFixture).to.eql({ read: true, all: false, }); - expect(noOpAlertType.authorizedConsumers.alertsRestrictedFixture).to.eql({ + expect(noOpAlertType.authorized_consumers.alertsRestrictedFixture).to.eql({ read: true, all: false, }); - expect(omit(restrictedNoOpAlertType, 'authorizedConsumers')).to.eql( + expect(omit(restrictedNoOpAlertType, 'authorized_consumers')).to.eql( expectedRestrictedNoOpType ); - expect(Object.keys(restrictedNoOpAlertType.authorizedConsumers)).not.to.contain( + expect(Object.keys(restrictedNoOpAlertType.authorized_consumers)).not.to.contain( 'alertsFixture' ); - expect(restrictedNoOpAlertType.authorizedConsumers.alertsRestrictedFixture).to.eql({ + expect(restrictedNoOpAlertType.authorized_consumers.alertsRestrictedFixture).to.eql({ read: true, all: false, }); break; case 'space_1_all_with_restricted_fixture at space1': - expect(omit(noOpAlertType, 'authorizedConsumers')).to.eql(expectedNoOpType); - expect(noOpAlertType.authorizedConsumers.alertsFixture).to.eql({ + expect(omit(noOpAlertType, 'authorized_consumers')).to.eql(expectedNoOpType); + expect(noOpAlertType.authorized_consumers.alertsFixture).to.eql({ read: true, all: true, }); - expect(noOpAlertType.authorizedConsumers.alertsRestrictedFixture).to.eql({ + expect(noOpAlertType.authorized_consumers.alertsRestrictedFixture).to.eql({ read: true, all: true, }); - expect(omit(restrictedNoOpAlertType, 'authorizedConsumers')).to.eql( + expect(omit(restrictedNoOpAlertType, 'authorized_consumers')).to.eql( expectedRestrictedNoOpType ); - expect(Object.keys(restrictedNoOpAlertType.authorizedConsumers)).not.to.contain( + expect(Object.keys(restrictedNoOpAlertType.authorized_consumers)).not.to.contain( 'alertsFixture' ); - expect(restrictedNoOpAlertType.authorizedConsumers.alertsRestrictedFixture).to.eql({ + expect(restrictedNoOpAlertType.authorized_consumers.alertsRestrictedFixture).to.eql({ read: true, all: true, }); break; case 'superuser at space1': - expect(omit(noOpAlertType, 'authorizedConsumers')).to.eql(expectedNoOpType); - expect(noOpAlertType.authorizedConsumers.alertsFixture).to.eql({ + expect(omit(noOpAlertType, 'authorized_consumers')).to.eql(expectedNoOpType); + expect(noOpAlertType.authorized_consumers.alertsFixture).to.eql({ read: true, all: true, }); - expect(noOpAlertType.authorizedConsumers.alertsRestrictedFixture).to.eql({ + expect(noOpAlertType.authorized_consumers.alertsRestrictedFixture).to.eql({ read: true, all: true, }); - expect(omit(restrictedNoOpAlertType, 'authorizedConsumers')).to.eql( + expect(omit(restrictedNoOpAlertType, 'authorized_consumers')).to.eql( expectedRestrictedNoOpType ); - expect(noOpAlertType.authorizedConsumers.alertsFixture).to.eql({ + expect(noOpAlertType.authorized_consumers.alertsFixture).to.eql({ read: true, all: true, }); - expect(noOpAlertType.authorizedConsumers.alertsRestrictedFixture).to.eql({ + expect(noOpAlertType.authorized_consumers.alertsRestrictedFixture).to.eql({ read: true, all: true, }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute_all.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute_all.ts index 885759359f2292..526f809033646c 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute_all.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute_all.ts @@ -35,18 +35,18 @@ export default function createUnmuteAlertTests({ getService }: FtrProviderContex describe(scenario.id, () => { it('should handle unmute alert request appropriately', async () => { const { body: createdAction } = await supertest - .post(`${getUrlPrefix(space.id)}/api/actions/action`) + .post(`${getUrlPrefix(space.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'MY action', - actionTypeId: 'test.noop', + connector_type_id: 'test.noop', config: {}, secrets: {}, }) .expect(200); const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ @@ -61,10 +61,10 @@ export default function createUnmuteAlertTests({ getService }: FtrProviderContex }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}/_mute_all`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}/_mute_all`) .set('kbn-xsrf', 'foo') .expect(204, ''); @@ -99,11 +99,11 @@ export default function createUnmuteAlertTests({ getService }: FtrProviderContex expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(200); - expect(updatedAlert.muteAll).to.eql(false); + expect(updatedAlert.mute_all).to.eql(false); // Ensure AAD isn't broken await checkAAD({ supertest, @@ -119,20 +119,20 @@ export default function createUnmuteAlertTests({ getService }: FtrProviderContex it('should handle unmute alert request appropriately when consumer is the same as producer', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ enabled: false, - alertTypeId: 'test.restricted-noop', + rule_type_id: 'test.restricted-noop', consumer: 'alertsRestrictedFixture', }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}/_mute_all`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}/_mute_all`) .set('kbn-xsrf', 'foo') .expect(204, ''); @@ -160,11 +160,11 @@ export default function createUnmuteAlertTests({ getService }: FtrProviderContex expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(200); - expect(updatedAlert.muteAll).to.eql(false); + expect(updatedAlert.mute_all).to.eql(false); // Ensure AAD isn't broken await checkAAD({ supertest, @@ -180,20 +180,20 @@ export default function createUnmuteAlertTests({ getService }: FtrProviderContex it('should handle unmute alert request appropriately when consumer is not the producer', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ enabled: false, - alertTypeId: 'test.unrestricted-noop', + rule_type_id: 'test.unrestricted-noop', consumer: 'alertsFixture', }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}/_mute_all`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}/_mute_all`) .set('kbn-xsrf', 'foo') .expect(204, ''); @@ -232,11 +232,11 @@ export default function createUnmuteAlertTests({ getService }: FtrProviderContex expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(200); - expect(updatedAlert.muteAll).to.eql(false); + expect(updatedAlert.mute_all).to.eql(false); // Ensure AAD isn't broken await checkAAD({ supertest, @@ -252,20 +252,20 @@ export default function createUnmuteAlertTests({ getService }: FtrProviderContex it('should handle unmute alert request appropriately when consumer is "alerts"', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ enabled: false, - alertTypeId: 'test.restricted-noop', + rule_type_id: 'test.restricted-noop', consumer: 'alerts', }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}/_mute_all`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}/_mute_all`) .set('kbn-xsrf', 'foo') .expect(204, ''); @@ -304,11 +304,11 @@ export default function createUnmuteAlertTests({ getService }: FtrProviderContex expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(200); - expect(updatedAlert.muteAll).to.eql(false); + expect(updatedAlert.mute_all).to.eql(false); // Ensure AAD isn't broken await checkAAD({ supertest, diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute_instance.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute_instance.ts index fed008468e735a..c19da8ba2008c5 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute_instance.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/unmute_instance.ts @@ -35,18 +35,18 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider describe(scenario.id, () => { it('should handle unmute alert instance request appropriately', async () => { const { body: createdAction } = await supertest - .post(`${getUrlPrefix(space.id)}/api/actions/action`) + .post(`${getUrlPrefix(space.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'MY action', - actionTypeId: 'test.noop', + connector_type_id: 'test.noop', config: {}, secrets: {}, }) .expect(200); const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ @@ -61,12 +61,10 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); await supertest - .post( - `${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}/alert_instance/1/_mute` - ) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}/alert/1/_mute`) .set('kbn-xsrf', 'foo') .expect(204, ''); @@ -101,11 +99,11 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(200); - expect(updatedAlert.mutedInstanceIds).to.eql([]); + expect(updatedAlert.muted_alert_ids).to.eql([]); // Ensure AAD isn't broken await checkAAD({ supertest, @@ -121,22 +119,20 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider it('should handle unmute alert instance request appropriately when consumer is the same as producer', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ enabled: false, - alertTypeId: 'test.restricted-noop', + rule_type_id: 'test.restricted-noop', consumer: 'alertsRestrictedFixture', }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); await supertest - .post( - `${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}/alert_instance/1/_mute` - ) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}/alert/1/_mute`) .set('kbn-xsrf', 'foo') .expect(204, ''); @@ -164,11 +160,11 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(200); - expect(updatedAlert.mutedInstanceIds).to.eql([]); + expect(updatedAlert.muted_alert_ids).to.eql([]); // Ensure AAD isn't broken await checkAAD({ supertest, @@ -184,22 +180,20 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider it('should handle unmute alert instance request appropriately when consumer is not the producer', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ enabled: false, - alertTypeId: 'test.unrestricted-noop', + rule_type_id: 'test.unrestricted-noop', consumer: 'alertsFixture', }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); await supertest - .post( - `${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}/alert_instance/1/_mute` - ) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}/alert/1/_mute`) .set('kbn-xsrf', 'foo') .expect(204, ''); @@ -238,11 +232,11 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(200); - expect(updatedAlert.mutedInstanceIds).to.eql([]); + expect(updatedAlert.muted_alert_ids).to.eql([]); // Ensure AAD isn't broken await checkAAD({ supertest, @@ -258,22 +252,20 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider it('should handle unmute alert instance request appropriately when consumer is "alerts"', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ enabled: false, - alertTypeId: 'test.restricted-noop', + rule_type_id: 'test.restricted-noop', consumer: 'alerts', }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); await supertest - .post( - `${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}/alert_instance/1/_mute` - ) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}/alert/1/_mute`) .set('kbn-xsrf', 'foo') .expect(204, ''); @@ -312,11 +304,11 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(200); - expect(updatedAlert.mutedInstanceIds).to.eql([]); + expect(updatedAlert.muted_alert_ids).to.eql([]); // Ensure AAD isn't broken await checkAAD({ supertest, diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts index 300a884d5a006a..e628f0b3d950e2 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts @@ -42,22 +42,22 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { describe(scenario.id, () => { it('should handle update alert request appropriately', async () => { const { body: createdAction } = await supertest - .post(`${getUrlPrefix(space.id)}/api/actions/action`) + .post(`${getUrlPrefix(space.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'MY action', - actionTypeId: 'test.noop', + connector_type_id: 'test.noop', config: {}, secrets: {}, }) .expect(200); const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const updatedData = { name: 'bcd', @@ -74,10 +74,10 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { }, ], throttle: '1m', - notifyWhen: 'onThrottleInterval', + notify_when: 'onThrottleInterval', }; const response = await supertestWithoutAuth - .put(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .put(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send(updatedData); @@ -112,31 +112,31 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { expect(response.body).to.eql({ ...updatedData, id: createdAlert.id, - alertTypeId: 'test.noop', + rule_type_id: 'test.noop', consumer: 'alertsFixture', - createdBy: 'elastic', + created_by: 'elastic', enabled: true, - updatedBy: user.username, - apiKeyOwner: user.username, - muteAll: false, - mutedInstanceIds: [], + updated_by: user.username, + api_key_owner: user.username, + mute_all: false, + muted_alert_ids: [], actions: [ { id: createdAction.id, - actionTypeId: 'test.noop', + connector_type_id: 'test.noop', group: 'default', params: {}, }, ], - scheduledTaskId: createdAlert.scheduledTaskId, - createdAt: response.body.createdAt, - updatedAt: response.body.updatedAt, - executionStatus: response.body.executionStatus, + scheduled_task_id: createdAlert.scheduled_task_id, + created_at: response.body.created_at, + updated_at: response.body.updated_at, + execution_status: response.body.execution_status, }); - expect(Date.parse(response.body.createdAt)).to.be.greaterThan(0); - expect(Date.parse(response.body.updatedAt)).to.be.greaterThan(0); - expect(Date.parse(response.body.updatedAt)).to.be.greaterThan( - Date.parse(response.body.createdAt) + expect(Date.parse(response.body.created_at)).to.be.greaterThan(0); + expect(Date.parse(response.body.updated_at)).to.be.greaterThan(0); + expect(Date.parse(response.body.updated_at)).to.be.greaterThan( + Date.parse(response.body.created_at) ); // Ensure AAD isn't broken await checkAAD({ @@ -153,16 +153,16 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { it('should handle update alert request appropriately when consumer is the same as producer', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.restricted-noop', + rule_type_id: 'test.restricted-noop', consumer: 'alertsRestrictedFixture', }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const updatedData = { name: 'bcd', @@ -173,10 +173,10 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { schedule: { interval: '12s' }, actions: [], throttle: '1m', - notifyWhen: 'onThrottleInterval', + notify_when: 'onThrottleInterval', }; const response = await supertestWithoutAuth - .put(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .put(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send(updatedData); @@ -204,23 +204,23 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { expect(response.body).to.eql({ ...updatedData, id: createdAlert.id, - alertTypeId: 'test.restricted-noop', + rule_type_id: 'test.restricted-noop', consumer: 'alertsRestrictedFixture', - createdBy: 'elastic', + created_by: 'elastic', enabled: true, - updatedBy: user.username, - apiKeyOwner: user.username, - muteAll: false, - mutedInstanceIds: [], - scheduledTaskId: createdAlert.scheduledTaskId, - createdAt: response.body.createdAt, - updatedAt: response.body.updatedAt, - executionStatus: response.body.executionStatus, + updated_by: user.username, + api_key_owner: user.username, + mute_all: false, + muted_alert_ids: [], + scheduled_task_id: createdAlert.scheduled_task_id, + created_at: response.body.created_at, + updated_at: response.body.updated_at, + execution_status: response.body.execution_status, }); - expect(Date.parse(response.body.createdAt)).to.be.greaterThan(0); - expect(Date.parse(response.body.updatedAt)).to.be.greaterThan(0); - expect(Date.parse(response.body.updatedAt)).to.be.greaterThan( - Date.parse(response.body.createdAt) + expect(Date.parse(response.body.created_at)).to.be.greaterThan(0); + expect(Date.parse(response.body.updated_at)).to.be.greaterThan(0); + expect(Date.parse(response.body.updated_at)).to.be.greaterThan( + Date.parse(response.body.created_at) ); // Ensure AAD isn't broken await checkAAD({ @@ -237,16 +237,16 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { it('should handle update alert request appropriately when consumer is not the producer', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.unrestricted-noop', + rule_type_id: 'test.unrestricted-noop', consumer: 'alertsFixture', }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const updatedData = { name: 'bcd', @@ -257,10 +257,10 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { schedule: { interval: '12s' }, actions: [], throttle: '1m', - notifyWhen: 'onThrottleInterval', + notify_when: 'onThrottleInterval', }; const response = await supertestWithoutAuth - .put(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .put(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send(updatedData); @@ -299,23 +299,23 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { expect(response.body).to.eql({ ...updatedData, id: createdAlert.id, - alertTypeId: 'test.unrestricted-noop', + rule_type_id: 'test.unrestricted-noop', consumer: 'alertsFixture', - createdBy: 'elastic', + created_by: 'elastic', enabled: true, - updatedBy: user.username, - apiKeyOwner: user.username, - muteAll: false, - mutedInstanceIds: [], - scheduledTaskId: createdAlert.scheduledTaskId, - createdAt: response.body.createdAt, - updatedAt: response.body.updatedAt, - executionStatus: response.body.executionStatus, + updated_by: user.username, + api_key_owner: user.username, + mute_all: false, + muted_alert_ids: [], + scheduled_task_id: createdAlert.scheduled_task_id, + created_at: response.body.created_at, + updated_at: response.body.updated_at, + execution_status: response.body.execution_status, }); - expect(Date.parse(response.body.createdAt)).to.be.greaterThan(0); - expect(Date.parse(response.body.updatedAt)).to.be.greaterThan(0); - expect(Date.parse(response.body.updatedAt)).to.be.greaterThan( - Date.parse(response.body.createdAt) + expect(Date.parse(response.body.created_at)).to.be.greaterThan(0); + expect(Date.parse(response.body.updated_at)).to.be.greaterThan(0); + expect(Date.parse(response.body.updated_at)).to.be.greaterThan( + Date.parse(response.body.created_at) ); // Ensure AAD isn't broken await checkAAD({ @@ -332,16 +332,16 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { it('should handle update alert request appropriately when consumer is "alerts"', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.restricted-noop', + rule_type_id: 'test.restricted-noop', consumer: 'alerts', }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const updatedData = { name: 'bcd', @@ -352,10 +352,10 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { schedule: { interval: '12s' }, actions: [], throttle: '1m', - notifyWhen: 'onThrottleInterval', + notify_when: 'onThrottleInterval', }; const response = await supertestWithoutAuth - .put(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .put(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send(updatedData); @@ -394,23 +394,23 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { expect(response.body).to.eql({ ...updatedData, id: createdAlert.id, - alertTypeId: 'test.restricted-noop', + rule_type_id: 'test.restricted-noop', consumer: 'alerts', - createdBy: 'elastic', + created_by: 'elastic', enabled: true, - updatedBy: user.username, - apiKeyOwner: user.username, - muteAll: false, - mutedInstanceIds: [], - scheduledTaskId: createdAlert.scheduledTaskId, - createdAt: response.body.createdAt, - updatedAt: response.body.updatedAt, - executionStatus: response.body.executionStatus, + updated_by: user.username, + api_key_owner: user.username, + mute_all: false, + muted_alert_ids: [], + scheduled_task_id: createdAlert.scheduled_task_id, + created_at: response.body.created_at, + updated_at: response.body.updated_at, + execution_status: response.body.execution_status, }); - expect(Date.parse(response.body.createdAt)).to.be.greaterThan(0); - expect(Date.parse(response.body.updatedAt)).to.be.greaterThan(0); - expect(Date.parse(response.body.updatedAt)).to.be.greaterThan( - Date.parse(response.body.createdAt) + expect(Date.parse(response.body.created_at)).to.be.greaterThan(0); + expect(Date.parse(response.body.updated_at)).to.be.greaterThan(0); + expect(Date.parse(response.body.updated_at)).to.be.greaterThan( + Date.parse(response.body.created_at) ); // Ensure AAD isn't broken await checkAAD({ @@ -427,11 +427,11 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { it('should still be able to update when AAD is broken', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); await retry.try(async () => { await supertest @@ -456,10 +456,10 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { schedule: { interval: '12s' }, actions: [], throttle: '1m', - notifyWhen: 'onThrottleInterval', + notify_when: 'onThrottleInterval', }; const response = await supertestWithoutAuth - .put(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .put(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send(updatedData); @@ -487,23 +487,23 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { expect(response.body).to.eql({ ...updatedData, id: createdAlert.id, - alertTypeId: 'test.noop', + rule_type_id: 'test.noop', consumer: 'alertsFixture', - createdBy: 'elastic', + created_by: 'elastic', enabled: true, - updatedBy: user.username, - apiKeyOwner: user.username, - muteAll: false, - mutedInstanceIds: [], - scheduledTaskId: createdAlert.scheduledTaskId, - createdAt: response.body.createdAt, - updatedAt: response.body.updatedAt, - executionStatus: response.body.executionStatus, + updated_by: user.username, + api_key_owner: user.username, + mute_all: false, + muted_alert_ids: [], + scheduled_task_id: createdAlert.scheduled_task_id, + created_at: response.body.created_at, + updated_at: response.body.updated_at, + execution_status: response.body.execution_status, }); - expect(Date.parse(response.body.createdAt)).to.be.greaterThan(0); - expect(Date.parse(response.body.updatedAt)).to.be.greaterThan(0); - expect(Date.parse(response.body.updatedAt)).to.be.greaterThan( - Date.parse(response.body.createdAt) + expect(Date.parse(response.body.created_at)).to.be.greaterThan(0); + expect(Date.parse(response.body.updated_at)).to.be.greaterThan(0); + expect(Date.parse(response.body.updated_at)).to.be.greaterThan( + Date.parse(response.body.created_at) ); // Ensure AAD isn't broken await checkAAD({ @@ -520,11 +520,11 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { it('should handle update alert request appropriately when alert name has leading and trailing whitespaces', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const updatedData = { name: ' leading and trailing whitespace ', @@ -535,10 +535,10 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { schedule: { interval: '12s' }, actions: [], throttle: '1m', - notifyWhen: 'onThrottleInterval', + notify_when: 'onActiveAlert', }; const response = await supertestWithoutAuth - .put(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .put(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send(updatedData); @@ -572,14 +572,14 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { it(`shouldn't update alert from another space`, async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await supertestWithoutAuth - .put(`${getUrlPrefix('other')}/api/alerts/alert/${createdAlert.id}`) + .put(`${getUrlPrefix('other')}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send({ @@ -591,6 +591,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { schedule: { interval: '12s' }, throttle: '1m', actions: [], + notify_when: 'onActiveAlert', }); expect(response.statusCode).to.eql(404); @@ -615,26 +616,27 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { it('should handle update alert request appropriately when attempting to change alert type', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await supertestWithoutAuth - .put(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .put(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send({ name: 'bcd', tags: ['bar'], throttle: '1m', - alertTypeId: '1', + rule_type_id: '1', params: { foo: true, }, schedule: { interval: '12s' }, actions: [], + notify_when: 'onActiveAlert', }); switch (scenario.id) { @@ -649,7 +651,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { expect(response.body).to.eql({ statusCode: 400, error: 'Bad Request', - message: '[request body.alertTypeId]: definition for this key is missing', + message: '[request body.rule_type_id]: definition for this key is missing', }); break; default: @@ -659,7 +661,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { it('should handle update alert request appropriately when payload is empty and invalid', async () => { const response = await supertestWithoutAuth - .put(`${getUrlPrefix(space.id)}/api/alerts/alert/1`) + .put(`${getUrlPrefix(space.id)}/api/alerting/rule/1`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send({}); @@ -686,21 +688,21 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { it(`should handle update alert request appropriately when alertTypeConfig isn't valid`, async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.validation', + rule_type_id: 'test.validation', params: { param1: 'test', }, }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await supertestWithoutAuth - .put(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .put(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send({ @@ -710,6 +712,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { throttle: '1m', params: {}, actions: [], + notify_when: 'onActiveAlert', }); switch (scenario.id) { @@ -746,7 +749,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { it('should handle update alert request appropriately when interval schedule is wrong syntax', async () => { const response = await supertestWithoutAuth - .put(`${getUrlPrefix(space.id)}/api/alerts/alert/1`) + .put(`${getUrlPrefix(space.id)}/api/alerting/rule/1`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send( @@ -779,7 +782,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { it('should handle updates to an alert schedule by rescheduling the underlying task', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ @@ -787,10 +790,10 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); await retry.try(async () => { - const alertTask = (await getAlertingTaskById(createdAlert.scheduledTaskId)).docs[0]; + const alertTask = (await getAlertingTaskById(createdAlert.scheduled_task_id)).docs[0]; expect(alertTask.status).to.eql('idle'); // ensure the alert inital run has completed and it's been rescheduled to half an hour from now ensureDatetimeIsWithinRange(Date.parse(alertTask.runAt), 30 * 60 * 1000); @@ -805,10 +808,10 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { schedule: { interval: '1m' }, actions: [], throttle: '1m', - notifyWhen: 'onThrottleInterval', + notify_when: 'onThrottleInterval', }; const response = await supertestWithoutAuth - .put(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .put(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send(updatedData); @@ -834,7 +837,8 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { case 'space_1_all_with_restricted_fixture at space1': expect(response.statusCode).to.eql(200); await retry.try(async () => { - const alertTask = (await getAlertingTaskById(createdAlert.scheduledTaskId)).docs[0]; + const alertTask = (await getAlertingTaskById(createdAlert.scheduled_task_id)) + .docs[0]; expect(alertTask.status).to.eql('idle'); // ensure the alert is rescheduled to a minute from now ensureDatetimeIsWithinRange(Date.parse(alertTask.runAt), 60 * 1000); @@ -847,21 +851,22 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { it('should handle updates for a long running alert type without failing the underlying tasks due to invalidated ApiKey', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send({ enabled: true, name: 'abc', tags: ['foo'], - alertTypeId: 'test.longRunning', + rule_type_id: 'test.longRunning', consumer: 'alertsFixture', schedule: { interval: '1s' }, throttle: '1m', actions: [], params: {}, + notify_when: 'onThrottleInterval', }) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const updatedData = { name: 'bcd', tags: ['bar'], @@ -871,17 +876,17 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { schedule: { interval: '1m' }, actions: [], throttle: '1m', - notifyWhen: 'onThrottleInterval', + notify_when: 'onThrottleInterval', }; const response = await supertestWithoutAuth - .put(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .put(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send(updatedData); const statusUpdates: string[] = []; await retry.try(async () => { - const alertTask = (await getAlertingTaskById(createdAlert.scheduledTaskId)).docs[0]; + const alertTask = (await getAlertingTaskById(createdAlert.scheduled_task_id)).docs[0]; statusUpdates.push(alertTask.status); expect(alertTask.status).to.eql('idle'); }); @@ -909,7 +914,8 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { case 'space_1_all_with_restricted_fixture at space1': expect(response.statusCode).to.eql(200); await retry.try(async () => { - const alertTask = (await getAlertingTaskById(createdAlert.scheduledTaskId)).docs[0]; + const alertTask = (await getAlertingTaskById(createdAlert.scheduled_task_id)) + .docs[0]; expect(alertTask.status).to.eql('idle'); // ensure the alert is rescheduled to a minute from now ensureDatetimeIsWithinRange(Date.parse(alertTask.runAt), 60 * 1000); @@ -922,7 +928,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { it('should handle updates to an alert schedule by setting the new schedule for the underlying task', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ @@ -930,10 +936,10 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); await retry.try(async () => { - const alertTask = (await getAlertingTaskById(createdAlert.scheduledTaskId)).docs[0]; + const alertTask = (await getAlertingTaskById(createdAlert.scheduled_task_id)).docs[0]; expect(alertTask.status).to.eql('idle'); expect(alertTask.schedule).to.eql({ interval: '1m' }); }); @@ -947,10 +953,10 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { schedule: { interval: '1s' }, actions: [], throttle: '1m', - notifyWhen: 'onThrottleInterval', + notify_when: 'onThrottleInterval', }; const response = await supertestWithoutAuth - .put(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .put(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send(updatedData); @@ -976,7 +982,8 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { case 'space_1_all_with_restricted_fixture at space1': expect(response.statusCode).to.eql(200); await retry.try(async () => { - const alertTask = (await getAlertingTaskById(createdAlert.scheduledTaskId)).docs[0]; + const alertTask = (await getAlertingTaskById(createdAlert.scheduled_task_id)) + .docs[0]; expect(alertTask.status).to.eql('idle'); expect(alertTask.schedule).to.eql({ interval: '1s' }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update_api_key.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update_api_key.ts index d8e07812286a90..a434109a18933a 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update_api_key.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update_api_key.ts @@ -36,18 +36,18 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte describe(scenario.id, () => { it('should handle update alert api key request appropriately', async () => { const { body: createdAction } = await supertest - .post(`${getUrlPrefix(space.id)}/api/actions/action`) + .post(`${getUrlPrefix(space.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'MY action', - actionTypeId: 'test.noop', + connector_type_id: 'test.noop', config: {}, secrets: {}, }) .expect(200); const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ @@ -61,7 +61,7 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await alertUtils.getUpdateApiKeyRequest(createdAlert.id); switch (scenario.id) { @@ -93,11 +93,11 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(200); - expect(updatedAlert.apiKeyOwner).to.eql(user.username); + expect(updatedAlert.api_key_owner).to.eql(user.username); // Ensure AAD isn't broken await checkAAD({ supertest, @@ -113,16 +113,16 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte it('should handle update alert api key request appropriately when consumer is the same as producer', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.restricted-noop', + rule_type_id: 'test.restricted-noop', consumer: 'alertsRestrictedFixture', }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await alertUtils.getUpdateApiKeyRequest(createdAlert.id); switch (scenario.id) { @@ -147,11 +147,11 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(200); - expect(updatedAlert.apiKeyOwner).to.eql(user.username); + expect(updatedAlert.api_key_owner).to.eql(user.username); // Ensure AAD isn't broken await checkAAD({ supertest, @@ -167,16 +167,16 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte it('should handle update alert api key request appropriately when consumer is not the producer', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.unrestricted-noop', + rule_type_id: 'test.unrestricted-noop', consumer: 'alertsFixture', }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await alertUtils.getUpdateApiKeyRequest(createdAlert.id); switch (scenario.id) { @@ -212,11 +212,11 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(200); - expect(updatedAlert.apiKeyOwner).to.eql(user.username); + expect(updatedAlert.api_key_owner).to.eql(user.username); // Ensure AAD isn't broken await checkAAD({ supertest, @@ -232,16 +232,16 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte it('should handle update alert api key request appropriately when consumer is "alerts"', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.restricted-noop', + rule_type_id: 'test.restricted-noop', consumer: 'alerts', }) ) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); const response = await alertUtils.getUpdateApiKeyRequest(createdAlert.id); switch (scenario.id) { @@ -277,11 +277,11 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(200); - expect(updatedAlert.apiKeyOwner).to.eql(user.username); + expect(updatedAlert.api_key_owner).to.eql(user.username); // Ensure AAD isn't broken await checkAAD({ supertest, @@ -297,11 +297,11 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte it('should still be able to update API key when AAD is broken', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); await retry.try(async () => { await supertest @@ -341,11 +341,11 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte expect(response.statusCode).to.eql(204); expect(response.body).to.eql(''); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .expect(200); - expect(updatedAlert.apiKeyOwner).to.eql(user.username); + expect(updatedAlert.api_key_owner).to.eql(user.username); // Ensure AAD isn't broken await checkAAD({ supertest, @@ -361,11 +361,11 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte it(`shouldn't update alert api key from another space`, async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix('other')}/api/alerts/alert`) + .post(`${getUrlPrefix('other')}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add('other', createdAlert.id, 'alert', 'alerts'); + objectRemover.add('other', createdAlert.id, 'rule', 'alerting'); const response = await alertUtils.getUpdateApiKeyRequest(createdAlert.id); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/aggregate.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/aggregate.ts index 140812bf2032a7..65aa38cb23c24f 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/aggregate.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/aggregate.ts @@ -21,12 +21,12 @@ export default function createAggregateTests({ getService }: FtrProviderContext) it('should aggregate when there are no alerts', async () => { const response = await supertest.get( - `${getUrlPrefix(Spaces.space1.id)}/api/alerts/_aggregate` + `${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rules/_aggregate` ); expect(response.status).to.eql(200); expect(response.body).to.eql({ - alertExecutionStatus: { + rule_execution_status: { ok: 0, active: 0, error: 0, @@ -45,12 +45,12 @@ export default function createAggregateTests({ getService }: FtrProviderContext) [...Array(NumOkAlerts)].map(async () => { const okAlertId = await createTestAlert( { - alertTypeId: 'test.noop', + rule_type_id: 'test.noop', schedule: { interval: '1s' }, }, 'ok' ); - objectRemover.add(Spaces.space1.id, okAlertId, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, okAlertId, 'rule', 'alerting'); }) ); @@ -58,7 +58,7 @@ export default function createAggregateTests({ getService }: FtrProviderContext) [...Array(NumActiveAlerts)].map(async () => { const activeAlertId = await createTestAlert( { - alertTypeId: 'test.patternFiring', + rule_type_id: 'test.patternFiring', schedule: { interval: '1s' }, params: { pattern: { instance: new Array(100).fill(true) }, @@ -66,7 +66,7 @@ export default function createAggregateTests({ getService }: FtrProviderContext) }, 'active' ); - objectRemover.add(Spaces.space1.id, activeAlertId, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, activeAlertId, 'rule', 'alerting'); }) ); @@ -74,12 +74,12 @@ export default function createAggregateTests({ getService }: FtrProviderContext) [...Array(NumErrorAlerts)].map(async () => { const activeAlertId = await createTestAlert( { - alertTypeId: 'test.throw', + rule_type_id: 'test.throw', schedule: { interval: '1s' }, }, 'error' ); - objectRemover.add(Spaces.space1.id, activeAlertId, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, activeAlertId, 'rule', 'alerting'); }) ); @@ -88,12 +88,12 @@ export default function createAggregateTests({ getService }: FtrProviderContext) // too early. await delay(1000); const reponse = await supertest.get( - `${getUrlPrefix(Spaces.space1.id)}/api/alerts/_aggregate` + `${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rules/_aggregate` ); expect(reponse.status).to.eql(200); expect(reponse.body).to.eql({ - alertExecutionStatus: { + rule_execution_status: { ok: NumOkAlerts, active: NumActiveAlerts, error: NumErrorAlerts, @@ -102,6 +102,75 @@ export default function createAggregateTests({ getService }: FtrProviderContext) }, }); }); + + describe('legacy', () => { + it('should aggregate alert status totals', async () => { + const NumOkAlerts = 4; + const NumActiveAlerts = 1; + const NumErrorAlerts = 2; + + await Promise.all( + [...Array(NumOkAlerts)].map(async () => { + const okAlertId = await createTestAlert( + { + rule_type_id: 'test.noop', + schedule: { interval: '1s' }, + }, + 'ok' + ); + objectRemover.add(Spaces.space1.id, okAlertId, 'rule', 'alerting'); + }) + ); + + await Promise.all( + [...Array(NumActiveAlerts)].map(async () => { + const activeAlertId = await createTestAlert( + { + rule_type_id: 'test.patternFiring', + schedule: { interval: '1s' }, + params: { + pattern: { instance: new Array(100).fill(true) }, + }, + }, + 'active' + ); + objectRemover.add(Spaces.space1.id, activeAlertId, 'rule', 'alerting'); + }) + ); + + await Promise.all( + [...Array(NumErrorAlerts)].map(async () => { + const activeAlertId = await createTestAlert( + { + rule_type_id: 'test.throw', + schedule: { interval: '1s' }, + }, + 'error' + ); + objectRemover.add(Spaces.space1.id, activeAlertId, 'rule', 'alerting'); + }) + ); + + // Adding delay to allow ES refresh cycle to run. Even when the waitForStatus + // calls are successful, the call to aggregate may return stale totals if called + // too early. + await delay(1000); + const reponse = await supertest.get( + `${getUrlPrefix(Spaces.space1.id)}/api/alerts/_aggregate` + ); + + expect(reponse.status).to.eql(200); + expect(reponse.body).to.eql({ + alertExecutionStatus: { + ok: NumOkAlerts, + active: NumActiveAlerts, + error: NumErrorAlerts, + pending: 0, + unknown: 0, + }, + }); + }); + }); }); const WaitForStatusIncrement = 500; @@ -116,11 +185,11 @@ export default function createAggregateTests({ getService }: FtrProviderContext) } const response = await supertest.get( - `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${id}` + `${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${id}` ); expect(response.status).to.eql(200); - const { executionStatus } = response.body || {}; + const { execution_status: executionStatus } = response.body || {}; const { status } = executionStatus || {}; const message = `waitForStatus(${Array.from(statuses)}): got ${JSON.stringify( @@ -144,7 +213,7 @@ export default function createAggregateTests({ getService }: FtrProviderContext) async function createTestAlert(testAlertOverrides = {}, status: string) { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData(testAlertOverrides)) .expect(200); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/alerts_base.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/alerts_base.ts index 49b4d7770962a8..89f6f7f54f4c37 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/alerts_base.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/alerts_base.ts @@ -46,11 +46,11 @@ export function alertTests({ getService }: FtrProviderContext, space: Space) { await esTestIndexTool.setup(); await es.indices.create({ index: authorizationIndex }); const { body: createdAction } = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/actions/action`) + .post(`${getUrlPrefix(space.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'My action', - actionTypeId: 'test.index-record', + connector_type_id: 'test.index-record', config: { unencrypted: `This value shouldn't get encrypted`, }, @@ -71,7 +71,7 @@ export function alertTests({ getService }: FtrProviderContext, space: Space) { after(async () => { await esTestIndexTool.destroy(); await es.indices.delete({ index: authorizationIndex }); - objectRemover.add(space.id, indexRecordActionId, 'action', 'actions'); + objectRemover.add(space.id, indexRecordActionId, 'connector', 'actions'); await objectRemover.removeAll(); }); @@ -142,11 +142,11 @@ instanceStateValue: true const reference = alertUtils.generateReference(); const { body: createdAction } = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/actions/action`) + .post(`${getUrlPrefix(space.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'MY action', - actionTypeId: 'test.noop', + connector_type_id: 'test.noop', config: {}, secrets: {}, }) @@ -158,11 +158,11 @@ instanceStateValue: true }; const createdAlert = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.patternFiring', + rule_type_id: 'test.patternFiring', schedule: { interval: '1s' }, throttle: null, params: { @@ -189,7 +189,7 @@ instanceStateValue: true expect(createdAlert.status).to.eql(200); const alertId = createdAlert.body.id; - objectRemover.add(space.id, alertId, 'alert', 'alerts'); + objectRemover.add(space.id, alertId, 'rule', 'alerting'); const actionTestRecord = ( await esTestIndexTool.waitForDocs('action:test.index-record', reference) @@ -203,11 +203,11 @@ instanceStateValue: true const reference = alertUtils.generateReference(); const { body: createdAction } = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/actions/action`) + .post(`${getUrlPrefix(space.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'MY action', - actionTypeId: 'test.noop', + connector_type_id: 'test.noop', config: {}, secrets: {}, }) @@ -219,11 +219,11 @@ instanceStateValue: true }; // created disabled alert const createdAlert = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.patternFiring', + rule_type_id: 'test.patternFiring', schedule: { interval: '1s' }, enabled: false, throttle: null, @@ -262,7 +262,7 @@ instanceStateValue: true const actionTestRecord = await esTestIndexTool.search('action:test.index-record', reference); expect(actionTestRecord.hits.total.value).to.eql(0); - objectRemover.add(space.id, alertId, 'alert', 'alerts'); + objectRemover.add(space.id, alertId, 'rule', 'alerting'); }); it('should reschedule failing alerts using the Task Manager retry logic with alert schedule interval', async () => { @@ -282,7 +282,7 @@ instanceStateValue: true await esTestIndexTool.waitForDocs('alert:test.failing', reference); await retry.try(async () => { - const alertTask = (await getAlertingTaskById(response.body.scheduledTaskId)).docs[0]; + const alertTask = (await getAlertingTaskById(response.body.scheduled_task_id)).docs[0]; expect(alertTask.status).to.eql('idle'); expect(alertTask.schedule.interval).to.eql('10s'); // ensure the alert is rescheduled correctly @@ -301,24 +301,24 @@ instanceStateValue: true const retryDate = new Date(Date.now() + 60000); const { body: createdAction } = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/actions/action`) + .post(`${getUrlPrefix(space.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'Test rate limit', - actionTypeId: 'test.rate-limit', + connector_type_id: 'test.rate-limit', config: {}, }) .expect(200); - objectRemover.add(space.id, createdAction.id, 'action', 'actions'); + objectRemover.add(space.id, createdAction.id, 'connector', 'actions'); const reference = alertUtils.generateReference(); const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ schedule: { interval: '1m' }, - alertTypeId: 'test.always-firing', + rule_type_id: 'test.always-firing', params: { index: ES_TEST_INDEX_NAME, reference: 'create-test-2', @@ -338,7 +338,7 @@ instanceStateValue: true ); expect(response.statusCode).to.eql(200); - objectRemover.add(space.id, response.body.id, 'alert', 'alerts'); + objectRemover.add(space.id, response.body.id, 'rule', 'alerting'); const scheduledActionTask = await retry.try(async () => { const searchResult = await es.search({ index: '.kibana_task_manager', @@ -382,11 +382,11 @@ instanceStateValue: true it('should have proper callCluster and savedObjectsClient authorization for alert type executor', async () => { const reference = alertUtils.generateReference(); const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.authorization', + rule_type_id: 'test.authorization', params: { callClusterAuthorizationIndex: authorizationIndex, savedObjectsClientType: 'dashboard', @@ -398,7 +398,7 @@ instanceStateValue: true ); expect(response.statusCode).to.eql(200); - objectRemover.add(space.id, response.body.id, 'alert', 'alerts'); + objectRemover.add(space.id, response.body.id, 'rule', 'alerting'); const alertTestRecord = ( await esTestIndexTool.waitForDocs('alert:test.authorization', reference) )[0]; @@ -419,20 +419,20 @@ instanceStateValue: true it('should have proper callCluster and savedObjectsClient authorization for action type executor', async () => { const reference = alertUtils.generateReference(); const { body: createdAction } = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/actions/action`) + .post(`${getUrlPrefix(space.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'My action', - actionTypeId: 'test.authorization', + connector_type_id: 'test.authorization', }) .expect(200); - objectRemover.add(space.id, createdAction.id, 'action', 'actions'); + objectRemover.add(space.id, createdAction.id, 'connector', 'actions'); const response = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.always-firing', + rule_type_id: 'test.always-firing', params: { index: ES_TEST_INDEX_NAME, reference, @@ -454,7 +454,7 @@ instanceStateValue: true ); expect(response.statusCode).to.eql(200); - objectRemover.add(space.id, response.body.id, 'alert', 'alerts'); + objectRemover.add(space.id, response.body.id, 'rule', 'alerting'); const actionTestRecord = ( await esTestIndexTool.waitForDocs('action:test.authorization', reference) )[0]; diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/es_query/alert.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/es_query/alert.ts index 777caacd465d8f..8511bcdf89d3bf 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/es_query/alert.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/es_query/alert.ts @@ -207,15 +207,16 @@ export default function alertTests({ getService }: FtrProviderContext) { }; const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send({ name: params.name, consumer: 'alerts', enabled: true, - alertTypeId: ALERT_TYPE_ID, + rule_type_id: ALERT_TYPE_ID, schedule: { interval: `${ALERT_INTERVAL_SECONDS}s` }, actions: [action], + notify_when: 'onActiveAlert', params: { index: [ES_TEST_INDEX_NAME], timeField: params.timeField || 'date', @@ -230,7 +231,7 @@ export default function alertTests({ getService }: FtrProviderContext) { .expect(200); const alertId = createdAlert.id; - objectRemover.add(Spaces.space1.id, alertId, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, alertId, 'rule', 'alerting'); return alertId; } @@ -239,11 +240,11 @@ export default function alertTests({ getService }: FtrProviderContext) { async function createAction(supertest: any, objectRemover: ObjectRemover): Promise { const { body: createdAction } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/action`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'index action for es query FT', - actionTypeId: ACTION_TYPE_ID, + connector_type_id: ACTION_TYPE_ID, config: { index: ES_TEST_OUTPUT_INDEX_NAME, }, @@ -252,7 +253,7 @@ async function createAction(supertest: any, objectRemover: ObjectRemover): Promi .expect(200); const actionId = createdAction.id; - objectRemover.add(Spaces.space1.id, actionId, 'action', 'actions'); + objectRemover.add(Spaces.space1.id, actionId, 'connector', 'actions'); return actionId; } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/alert.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/alert.ts index e0275f3ead37aa..3d7e391d7530fa 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/alert.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/alert.ts @@ -357,15 +357,16 @@ export default function alertTests({ getService }: FtrProviderContext) { }; const { status, body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send({ name: params.name, consumer: 'alerts', enabled: true, - alertTypeId: ALERT_TYPE_ID, + rule_type_id: ALERT_TYPE_ID, schedule: { interval: `${ALERT_INTERVAL_SECONDS}s` }, actions: [action], + notify_when: 'onActiveAlert', params: { index: ES_TEST_INDEX_NAME, timeField: params.timeField || 'date', @@ -387,7 +388,7 @@ export default function alertTests({ getService }: FtrProviderContext) { expect(status).to.be(200); const alertId = createdAlert.id; - objectRemover.add(Spaces.space1.id, alertId, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, alertId, 'rule', 'alerting'); return alertId; } @@ -396,11 +397,11 @@ export default function alertTests({ getService }: FtrProviderContext) { async function createAction(supertest: any, objectRemover: ObjectRemover): Promise { const { statusCode, body: createdAction } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/action`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'index action for index threshold FT', - actionTypeId: ACTION_TYPE_ID, + connector_type_id: ACTION_TYPE_ID, config: { index: ES_TEST_OUTPUT_INDEX_NAME, }, @@ -413,7 +414,7 @@ async function createAction(supertest: any, objectRemover: ObjectRemover): Promi expect(statusCode).to.be(200); const actionId = createdAction.id; - objectRemover.add(Spaces.space1.id, actionId, 'action', 'actions'); + objectRemover.add(Spaces.space1.id, actionId, 'connector', 'actions'); return actionId; } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/create.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/create.ts index 6e0bf867c95877..9033b1f303943b 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/create.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/create.ts @@ -35,18 +35,18 @@ export default function createAlertTests({ getService }: FtrProviderContext) { it('should handle create alert request appropriately', async () => { const { body: createdAction } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/action`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'MY action', - actionTypeId: 'test.noop', + connector_type_id: 'test.noop', config: {}, secrets: {}, }) .expect(200); const response = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ @@ -61,7 +61,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { ); expect(response.status).to.eql(200); - objectRemover.add(Spaces.space1.id, response.body.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, response.body.id, 'rule', 'alerting'); expect(response.body).to.eql({ id: response.body.id, name: 'abc', @@ -69,34 +69,34 @@ export default function createAlertTests({ getService }: FtrProviderContext) { actions: [ { id: createdAction.id, - actionTypeId: createdAction.actionTypeId, + connector_type_id: createdAction.connector_type_id, group: 'default', params: {}, }, ], enabled: true, - alertTypeId: 'test.noop', + rule_type_id: 'test.noop', consumer: 'alertsFixture', params: {}, - createdBy: null, + created_by: null, schedule: { interval: '1m' }, - scheduledTaskId: response.body.scheduledTaskId, - updatedBy: null, - apiKeyOwner: null, + scheduled_task_id: response.body.scheduled_task_id, + updated_by: null, + api_key_owner: null, throttle: '1m', - notifyWhen: 'onThrottleInterval', - muteAll: false, - mutedInstanceIds: [], - createdAt: response.body.createdAt, - updatedAt: response.body.updatedAt, - executionStatus: response.body.executionStatus, + notify_when: 'onThrottleInterval', + mute_all: false, + muted_alert_ids: [], + created_at: response.body.created_at, + updated_at: response.body.updated_at, + execution_status: response.body.execution_status, }); - expect(Date.parse(response.body.createdAt)).to.be.greaterThan(0); - expect(Date.parse(response.body.updatedAt)).to.be.greaterThan(0); - expect(Date.parse(response.body.updatedAt)).to.eql(Date.parse(response.body.createdAt)); + expect(Date.parse(response.body.created_at)).to.be.greaterThan(0); + expect(Date.parse(response.body.updated_at)).to.be.greaterThan(0); + expect(Date.parse(response.body.updated_at)).to.eql(Date.parse(response.body.created_at)); - expect(typeof response.body.scheduledTaskId).to.be('string'); - const { _source: taskRecord } = await getScheduledTask(response.body.scheduledTaskId); + expect(typeof response.body.scheduled_task_id).to.be('string'); + const { _source: taskRecord } = await getScheduledTask(response.body.scheduled_task_id); expect(taskRecord.type).to.eql('task'); expect(taskRecord.task.taskType).to.eql('alerting:test.noop'); expect(JSON.parse(taskRecord.task.params)).to.eql({ @@ -115,12 +115,12 @@ export default function createAlertTests({ getService }: FtrProviderContext) { it('should allow providing custom saved object ids (uuid v1)', async () => { const customId = '09570bb0-6299-11eb-8fde-9fe5ce6ea450'; const response = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${customId}`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${customId}`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()); expect(response.status).to.eql(200); - objectRemover.add(Spaces.space1.id, response.body.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, response.body.id, 'rule', 'alerting'); expect(response.body.id).to.eql(customId); // Ensure AAD isn't broken await checkAAD({ @@ -134,12 +134,12 @@ export default function createAlertTests({ getService }: FtrProviderContext) { it('should allow providing custom saved object ids (uuid v4)', async () => { const customId = 'b3bc6d83-3192-4ffd-9702-ad4fb88617ba'; const response = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${customId}`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${customId}`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()); expect(response.status).to.eql(200); - objectRemover.add(Spaces.space1.id, response.body.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, response.body.id, 'rule', 'alerting'); expect(response.body.id).to.eql(customId); // Ensure AAD isn't broken await checkAAD({ @@ -153,7 +153,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { it('should not allow providing simple custom ids (non uuid)', async () => { const customId = '1'; const response = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${customId}`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${customId}`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()); @@ -169,13 +169,13 @@ export default function createAlertTests({ getService }: FtrProviderContext) { it('should return 409 when document with id already exists', async () => { const customId = '5031f8f0-629a-11eb-b500-d1931a8e5df7'; const createdAlertResponse = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${customId}`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${customId}`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlertResponse.body.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlertResponse.body.id, 'rule', 'alerting'); await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${customId}`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${customId}`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(409); @@ -183,7 +183,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { it('should handle create alert request appropriately when consumer is unknown', async () => { const response = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData({ consumer: 'some consumer patrick invented' })); @@ -201,13 +201,101 @@ export default function createAlertTests({ getService }: FtrProviderContext) { it('should handle create alert request appropriately when an alert is disabled ', async () => { const response = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData({ enabled: false })); expect(response.status).to.eql(200); - objectRemover.add(Spaces.space1.id, response.body.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, response.body.id, 'rule', 'alerting'); expect(response.body.scheduledTaskId).to.eql(undefined); }); + + describe('legacy', () => { + it('should handle create alert request appropriately', async () => { + const { body: createdAction } = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/connector`) + .set('kbn-xsrf', 'foo') + .send({ + name: 'MY action', + connector_type_id: 'test.noop', + config: {}, + secrets: {}, + }) + .expect(200); + + const { + rule_type_id: alertTypeId, + notify_when: notifyWhen, + ...testAlert + } = getTestAlertData({ + actions: [ + { + id: createdAction.id, + group: 'default', + params: {}, + }, + ], + }); + const response = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .set('kbn-xsrf', 'foo') + .send({ + ...testAlert, + alertTypeId, + notifyWhen, + }); + + expect(response.status).to.eql(200); + objectRemover.add(Spaces.space1.id, response.body.id, 'rule', 'alerting'); + expect(response.body).to.eql({ + id: response.body.id, + name: 'abc', + tags: ['foo'], + actions: [ + { + id: createdAction.id, + actionTypeId: createdAction.connector_type_id, + group: 'default', + params: {}, + }, + ], + enabled: true, + alertTypeId: 'test.noop', + consumer: 'alertsFixture', + params: {}, + createdBy: null, + schedule: { interval: '1m' }, + scheduledTaskId: response.body.scheduledTaskId, + updatedBy: null, + apiKeyOwner: null, + throttle: '1m', + notifyWhen: 'onThrottleInterval', + muteAll: false, + mutedInstanceIds: [], + createdAt: response.body.createdAt, + updatedAt: response.body.updatedAt, + executionStatus: response.body.executionStatus, + }); + expect(Date.parse(response.body.createdAt)).to.be.greaterThan(0); + expect(Date.parse(response.body.updatedAt)).to.be.greaterThan(0); + expect(Date.parse(response.body.updatedAt)).to.eql(Date.parse(response.body.createdAt)); + + expect(typeof response.body.scheduledTaskId).to.be('string'); + const { _source: taskRecord } = await getScheduledTask(response.body.scheduledTaskId); + expect(taskRecord.type).to.eql('task'); + expect(taskRecord.task.taskType).to.eql('alerting:test.noop'); + expect(JSON.parse(taskRecord.task.params)).to.eql({ + alertId: response.body.id, + spaceId: Spaces.space1.id, + }); + // Ensure AAD isn't broken + await checkAAD({ + supertest, + spaceId: Spaces.space1.id, + type: 'alert', + id: response.body.id, + }); + }); + }); }); } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/delete.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/delete.ts index 4e033eabc2ac2f..04ae217d477606 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/delete.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/delete.ts @@ -29,13 +29,13 @@ export default function createDeleteTests({ getService }: FtrProviderContext) { it('should handle delete alert request appropriately', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); await supertest - .delete(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}`) + .delete(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .expect(204, ''); @@ -49,13 +49,13 @@ export default function createDeleteTests({ getService }: FtrProviderContext) { it(`shouldn't delete alert from another space`, async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); await supertest - .delete(`${getUrlPrefix(Spaces.other.id)}/api/alerts/alert/${createdAlert.id}`) + .delete(`${getUrlPrefix(Spaces.other.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .expect(404, { statusCode: 404, @@ -63,5 +63,27 @@ export default function createDeleteTests({ getService }: FtrProviderContext) { message: `Saved object [alert/${createdAlert.id}] not found`, }); }); + + describe('legacy', () => { + it('should handle delete alert request appropriately', async () => { + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData()) + .expect(200); + + await supertest + .delete(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}`) + .set('kbn-xsrf', 'foo') + .expect(204, ''); + + try { + await getScheduledTask(createdAlert.scheduledTaskId); + throw new Error('Should have removed scheduled task'); + } catch (e) { + expect(e.status).to.eql(404); + } + }); + }); }); } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/disable.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/disable.ts index b2bb24aec902d6..60749343cf269d 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/disable.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/disable.ts @@ -36,11 +36,11 @@ export default function createDisableAlertTests({ getService }: FtrProviderConte it('should handle disable alert request appropriately', async () => { const { body: createdAlert } = await supertestWithoutAuth - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData({ enabled: true })) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); await alertUtils.disable(createdAlert.id); @@ -62,11 +62,11 @@ export default function createDisableAlertTests({ getService }: FtrProviderConte it(`shouldn't disable alert from another space`, async () => { const { body: createdAlert } = await supertestWithoutAuth - .post(`${getUrlPrefix(Spaces.other.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.other.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData({ enabled: true })) .expect(200); - objectRemover.add(Spaces.other.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.other.id, createdAlert.id, 'rule', 'alerting'); await alertUtils.getDisableRequest(createdAlert.id).expect(404, { statusCode: 404, @@ -74,5 +74,36 @@ export default function createDisableAlertTests({ getService }: FtrProviderConte message: `Saved object [alert/${createdAlert.id}] not found`, }); }); + + describe('legacy', () => { + it('should handle disable alert request appropriately', async () => { + const { body: createdAlert } = await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData({ enabled: true })) + .expect(200); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); + + await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/_disable`) + .set('kbn-xsrf', 'foo') + .expect(204); + + try { + await getScheduledTask(createdAlert.scheduledTaskId); + throw new Error('Should have removed scheduled task'); + } catch (e) { + expect(e.status).to.eql(404); + } + + // Ensure AAD isn't broken + await checkAAD({ + supertest: supertestWithoutAuth, + spaceId: Spaces.space1.id, + type: 'alert', + id: createdAlert.id, + }); + }); + }); }); } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/enable.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/enable.ts index 29347a2d1d3980..f0b0d1f34a2770 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/enable.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/enable.ts @@ -36,20 +36,20 @@ export default function createEnableAlertTests({ getService }: FtrProviderContex it('should handle enable alert request appropriately', async () => { const { body: createdAlert } = await supertestWithoutAuth - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData({ enabled: false })) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); await alertUtils.enable(createdAlert.id); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .expect(200); - expect(typeof updatedAlert.scheduledTaskId).to.eql('string'); - const { _source: taskRecord } = await getScheduledTask(updatedAlert.scheduledTaskId); + expect(typeof updatedAlert.scheduled_task_id).to.eql('string'); + const { _source: taskRecord } = await getScheduledTask(updatedAlert.scheduled_task_id); expect(taskRecord.type).to.eql('task'); expect(taskRecord.task.taskType).to.eql('alerting:test.noop'); expect(JSON.parse(taskRecord.task.params)).to.eql({ @@ -68,11 +68,11 @@ export default function createEnableAlertTests({ getService }: FtrProviderContex it(`shouldn't enable alert from another space`, async () => { const { body: createdAlert } = await supertestWithoutAuth - .post(`${getUrlPrefix(Spaces.other.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.other.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData({ enabled: false })) .expect(200); - objectRemover.add(Spaces.other.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.other.id, createdAlert.id, 'rule', 'alerting'); await alertUtils.getEnableRequest(createdAlert.id).expect(404, { statusCode: 404, @@ -80,5 +80,42 @@ export default function createEnableAlertTests({ getService }: FtrProviderContex message: `Saved object [alert/${createdAlert.id}] not found`, }); }); + + describe('legacy', () => { + it('should handle enable alert request appropriately', async () => { + const { body: createdAlert } = await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData({ enabled: false })) + .expect(200); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); + + await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/_enable`) + .set('kbn-xsrf', 'foo') + .expect(204); + + const { body: updatedAlert } = await supertestWithoutAuth + .get(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${createdAlert.id}`) + .set('kbn-xsrf', 'foo') + .expect(200); + expect(typeof updatedAlert.scheduled_task_id).to.eql('string'); + const { _source: taskRecord } = await getScheduledTask(updatedAlert.scheduled_task_id); + expect(taskRecord.type).to.eql('task'); + expect(taskRecord.task.taskType).to.eql('alerting:test.noop'); + expect(JSON.parse(taskRecord.task.params)).to.eql({ + alertId: createdAlert.id, + spaceId: Spaces.space1.id, + }); + + // Ensure AAD isn't broken + await checkAAD({ + supertest: supertestWithoutAuth, + spaceId: Spaces.space1.id, + type: 'alert', + id: createdAlert.id, + }); + }); + }); }); } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/event_log.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/event_log.ts index 2e97711cdef2c0..5d54fe3d2b1f78 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/event_log.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/event_log.ts @@ -26,11 +26,11 @@ export default function eventLogTests({ getService }: FtrProviderContext) { it('should generate expected events for normal operation', async () => { const { body: createdAction } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/action`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'MY action', - actionTypeId: 'test.noop', + connector_type_id: 'test.noop', config: {}, secrets: {}, }) @@ -42,11 +42,11 @@ export default function eventLogTests({ getService }: FtrProviderContext) { }; const response = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.patternFiring', + rule_type_id: 'test.patternFiring', schedule: { interval: '1s' }, throttle: null, params: { @@ -64,7 +64,7 @@ export default function eventLogTests({ getService }: FtrProviderContext) { expect(response.status).to.eql(200); const alertId = response.body.id; - objectRemover.add(Spaces.space1.id, alertId, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, alertId, 'rule', 'alerting'); // get the events we're expecting const events = await retry.try(async () => { @@ -174,11 +174,11 @@ export default function eventLogTests({ getService }: FtrProviderContext) { it('should generate expected events for normal operation with subgroups', async () => { const { body: createdAction } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/action`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'MY action', - actionTypeId: 'test.noop', + connector_type_id: 'test.noop', config: {}, secrets: {}, }) @@ -191,11 +191,11 @@ export default function eventLogTests({ getService }: FtrProviderContext) { }; const response = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.patternFiring', + rule_type_id: 'test.patternFiring', schedule: { interval: '1s' }, throttle: null, params: { @@ -213,7 +213,7 @@ export default function eventLogTests({ getService }: FtrProviderContext) { expect(response.status).to.eql(200); const alertId = response.body.id; - objectRemover.add(Spaces.space1.id, alertId, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, alertId, 'rule', 'alerting'); // get the events we're expecting const events = await retry.try(async () => { @@ -315,11 +315,11 @@ export default function eventLogTests({ getService }: FtrProviderContext) { it('should generate events for execution errors', async () => { const response = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.throw', + rule_type_id: 'test.throw', schedule: { interval: '1s' }, throttle: null, }) @@ -327,7 +327,7 @@ export default function eventLogTests({ getService }: FtrProviderContext) { expect(response.status).to.eql(200); const alertId = response.body.id; - objectRemover.add(Spaces.space1.id, alertId, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, alertId, 'rule', 'alerting'); const events = await retry.try(async () => { return await getEventLog({ diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/execution_status.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/execution_status.ts index f2a79b72dc7317..0f7ed80cfd38df 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/execution_status.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/execution_status.ts @@ -28,15 +28,19 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon it('should be "pending" for newly created alert', async () => { const dateStart = Date.now(); const response = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()); const dateEnd = Date.now(); expect(response.status).to.eql(200); - objectRemover.add(Spaces.space1.id, response.body.id, 'alert', 'alerts'); - - expect(response.body.executionStatus).to.be.ok(); - const { status, lastExecutionDate, error } = response.body.executionStatus; + objectRemover.add(Spaces.space1.id, response.body.id, 'rule', 'alerting'); + + expect(response.body.execution_status).to.be.ok(); + const { + error, + status, + last_execution_date: lastExecutionDate, + } = response.body.execution_status; expect(status).to.be('pending'); ensureDatetimesAreOrdered([dateStart, lastExecutionDate, dateEnd]); expect(error).not.to.be.ok(); @@ -54,25 +58,25 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon const dates = []; dates.push(Date.now()); const response = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.noop', + rule_type_id: 'test.noop', schedule: { interval: '1s' }, }) ); expect(response.status).to.eql(200); const alertId = response.body.id; - const alertUpdatedAt = response.body.updatedAt; - dates.push(response.body.executionStatus.lastExecutionDate); - objectRemover.add(Spaces.space1.id, alertId, 'alert', 'alerts'); + const alertUpdatedAt = response.body.updated_at; + dates.push(response.body.execution_status.last_execution_date); + objectRemover.add(Spaces.space1.id, alertId, 'rule', 'alerting'); const executionStatus = await waitForStatus(alertId, new Set(['ok'])); - dates.push(executionStatus.lastExecutionDate); + dates.push(executionStatus.last_execution_date); dates.push(Date.now()); ensureDatetimesAreOrdered(dates); - ensureAlertUpdatedAtHasNotChanged(alertId, alertUpdatedAt); + await ensureAlertUpdatedAtHasNotChanged(alertId, alertUpdatedAt); // Ensure AAD isn't broken await checkAAD({ @@ -87,11 +91,11 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon const dates = []; dates.push(Date.now()); const response = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.patternFiring', + rule_type_id: 'test.patternFiring', schedule: { interval: '1s' }, params: { pattern: { instance: trues(100) }, @@ -100,15 +104,15 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon ); expect(response.status).to.eql(200); const alertId = response.body.id; - const alertUpdatedAt = response.body.updatedAt; - dates.push(response.body.executionStatus.lastExecutionDate); - objectRemover.add(Spaces.space1.id, alertId, 'alert', 'alerts'); + const alertUpdatedAt = response.body.updated_at; + dates.push(response.body.execution_status.last_execution_date); + objectRemover.add(Spaces.space1.id, alertId, 'rule', 'alerting'); const executionStatus = await waitForStatus(alertId, new Set(['active'])); - dates.push(executionStatus.lastExecutionDate); + dates.push(executionStatus.last_execution_date); dates.push(Date.now()); ensureDatetimesAreOrdered(dates); - ensureAlertUpdatedAtHasNotChanged(alertId, alertUpdatedAt); + await ensureAlertUpdatedAtHasNotChanged(alertId, alertUpdatedAt); // Ensure AAD isn't broken await checkAAD({ @@ -123,25 +127,25 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon const dates = []; dates.push(Date.now()); const response = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.throw', + rule_type_id: 'test.throw', schedule: { interval: '1s' }, }) ); expect(response.status).to.eql(200); const alertId = response.body.id; - const alertUpdatedAt = response.body.updatedAt; - dates.push(response.body.executionStatus.lastExecutionDate); - objectRemover.add(Spaces.space1.id, alertId, 'alert', 'alerts'); + const alertUpdatedAt = response.body.updated_at; + dates.push(response.body.execution_status.last_execution_date); + objectRemover.add(Spaces.space1.id, alertId, 'rule', 'alerting'); const executionStatus = await waitForStatus(alertId, new Set(['error'])); - dates.push(executionStatus.lastExecutionDate); + dates.push(executionStatus.last_execution_date); dates.push(Date.now()); ensureDatetimesAreOrdered(dates); - ensureAlertUpdatedAtHasNotChanged(alertId, alertUpdatedAt); + await ensureAlertUpdatedAtHasNotChanged(alertId, alertUpdatedAt); // Ensure AAD isn't broken await checkAAD({ @@ -159,41 +163,41 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon it('should eventually have error reason "execute" when appropriate', async () => { const response = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.throw', + rule_type_id: 'test.throw', schedule: { interval: '1s' }, }) ); expect(response.status).to.eql(200); const alertId = response.body.id; - const alertUpdatedAt = response.body.updatedAt; - objectRemover.add(Spaces.space1.id, alertId, 'alert', 'alerts'); + const alertUpdatedAt = response.body.updated_at; + objectRemover.add(Spaces.space1.id, alertId, 'rule', 'alerting'); const executionStatus = await waitForStatus(alertId, new Set(['error'])); expect(executionStatus.error).to.be.ok(); expect(executionStatus.error.reason).to.be('execute'); expect(executionStatus.error.message).to.be('this alert is intended to fail'); - ensureAlertUpdatedAtHasNotChanged(alertId, alertUpdatedAt); + await ensureAlertUpdatedAtHasNotChanged(alertId, alertUpdatedAt); }); it('should eventually have error reason "unknown" when appropriate', async () => { const response = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.validation', + rule_type_id: 'test.validation', schedule: { interval: '1s' }, params: { param1: 'valid now, but will change to a number soon!' }, }) ); expect(response.status).to.eql(200); const alertId = response.body.id; - const alertUpdatedAt = response.body.updatedAt; - objectRemover.add(Spaces.space1.id, alertId, 'alert', 'alerts'); + const alertUpdatedAt = response.body.updated_at; + objectRemover.add(Spaces.space1.id, alertId, 'rule', 'alerting'); let executionStatus = await waitForStatus(alertId, new Set(['ok'])); @@ -211,7 +215,7 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon executionStatus = await waitForStatus(alertId, new Set(['error'])); expect(executionStatus.error).to.be.ok(); expect(executionStatus.error.reason).to.be('unknown'); - ensureAlertUpdatedAtHasNotChanged(alertId, alertUpdatedAt); + await ensureAlertUpdatedAtHasNotChanged(alertId, alertUpdatedAt); const message = 'params invalid: [param1]: expected value of type [string] but got [number]'; expect(executionStatus.error.message).to.be(message); @@ -220,17 +224,17 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon it('should be able to find over all the fields', async () => { const startDate = Date.now(); const createResponse = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.throw', + rule_type_id: 'test.throw', schedule: { interval: '1s' }, }) ); expect(createResponse.status).to.eql(200); const alertId = createResponse.body.id; - objectRemover.add(Spaces.space1.id, alertId, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, alertId, 'rule', 'alerting'); await waitForStatus(alertId, new Set(['error'])); @@ -264,11 +268,11 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon } const response = await supertest.get( - `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${id}` + `${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${id}` ); expect(response.status).to.eql(200); - const { executionStatus } = response.body || {}; + const { execution_status: executionStatus } = response.body || {}; const { status } = executionStatus || {}; const message = `waitForStatus(${Array.from(statuses)}): got ${JSON.stringify( @@ -300,7 +304,8 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon const response = await supertest.get(`${getUrlPrefix(Spaces.space1.id)}/${findUri}`); expect(response.status).to.eql(200); - const { executionStatus } = response.body.data.find((obj: any) => obj.id === id) || {}; + const { execution_status: executionStatus } = + response.body.data.find((obj: any) => obj.id === id) || {}; const { status } = executionStatus || {}; const message = `waitForFindStatus(${Array.from(statuses)}): got ${JSON.stringify( @@ -320,12 +325,12 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon async function ensureAlertUpdatedAtHasNotChanged(alertId: string, originalUpdatedAt: string) { const response = await supertest.get( - `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${alertId}` + `${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${alertId}` ); - const { updatedAt, executionStatus } = response.body; + const { updated_at: updatedAt, execution_status: executionStatus } = response.body; expect(Date.parse(updatedAt)).to.be.greaterThan(0); expect(Date.parse(updatedAt)).to.eql(Date.parse(originalUpdatedAt)); - expect(Date.parse(executionStatus.lastExecutionDate)).to.be.greaterThan( + expect(Date.parse(executionStatus.last_execution_date)).to.be.greaterThan( Date.parse(originalUpdatedAt) ); } @@ -335,7 +340,7 @@ function expectErrorExecutionStatus(executionStatus: Record, startD expect(executionStatus).to.be.ok(); expect(executionStatus.status).to.equal('error'); - const statusDate = Date.parse(executionStatus.lastExecutionDate); + const statusDate = Date.parse(executionStatus.last_execution_date); const stopDate = Date.now(); expect(startDate).to.be.lessThan(statusDate); expect(stopDate).to.be.greaterThan(statusDate); @@ -345,7 +350,7 @@ function expectErrorExecutionStatus(executionStatus: Record, startD } function getFindUri(filter: string) { - return `api/alerts/_find?filter=alert.attributes.executionStatus.${filter}`; + return `api/alerting/rules/_find?filter=alert.attributes.executionStatus.${filter}`; } function trues(length: number): boolean[] { diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts index 1493c99162bf5c..191bcb1bb52f0c 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts @@ -21,76 +21,76 @@ export default function createFindTests({ getService }: FtrProviderContext) { async function createAlert(overwrites = {}) { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData(overwrites)) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); return createdAlert; } it('should handle find alert request appropriately', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); const response = await supertest.get( `${getUrlPrefix( Spaces.space1.id - )}/api/alerts/_find?search=test.noop&search_fields=alertTypeId` + )}/api/alerting/rules/_find?search=test.noop&search_fields=alertTypeId` ); expect(response.status).to.eql(200); expect(response.body.page).to.equal(1); - expect(response.body.perPage).to.be.greaterThan(0); + expect(response.body.per_page).to.be.greaterThan(0); expect(response.body.total).to.be.greaterThan(0); const match = response.body.data.find((obj: any) => obj.id === createdAlert.id); expect(match).to.eql({ id: createdAlert.id, name: 'abc', tags: ['foo'], - alertTypeId: 'test.noop', + rule_type_id: 'test.noop', consumer: 'alertsFixture', schedule: { interval: '1m' }, enabled: true, actions: [], params: {}, - createdBy: null, - apiKeyOwner: null, - scheduledTaskId: match.scheduledTaskId, - updatedBy: null, + created_by: null, + api_key_owner: null, + scheduled_task_id: match.scheduled_task_id, + updated_by: null, throttle: '1m', - notifyWhen: 'onThrottleInterval', - muteAll: false, - mutedInstanceIds: [], - createdAt: match.createdAt, - updatedAt: match.updatedAt, - executionStatus: match.executionStatus, + notify_when: 'onThrottleInterval', + mute_all: false, + muted_alert_ids: [], + created_at: match.created_at, + updated_at: match.updated_at, + execution_status: match.execution_status, }); - expect(Date.parse(match.createdAt)).to.be.greaterThan(0); - expect(Date.parse(match.updatedAt)).to.be.greaterThan(0); + expect(Date.parse(match.created_at)).to.be.greaterThan(0); + expect(Date.parse(match.updated_at)).to.be.greaterThan(0); }); it(`shouldn't find alert from another space`, async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); await supertest .get( `${getUrlPrefix( Spaces.other.id - )}/api/alerts/_find?search=test.noop&search_fields=alertTypeId` + )}/api/alerting/rules/_find?search=test.noop&search_fields=alertTypeId` ) .expect(200, { page: 1, - perPage: 10, + per_page: 10, total: 0, data: [], }); @@ -106,12 +106,59 @@ export default function createFindTests({ getService }: FtrProviderContext) { const response = await supertest.get( `${getUrlPrefix( Spaces.space1.id - )}/api/alerts/_find?filter=alert.attributes.params.strValue:"my b"` + )}/api/alerting/rules/_find?filter=alert.attributes.params.strValue:"my b"` ); expect(response.status).to.eql(200); expect(response.body.total).to.equal(1); expect(response.body.data[0].params.strValue).to.eql('my b'); }); + + describe('legacy', () => { + it('should handle find alert request appropriately', async () => { + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData()) + .expect(200); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); + + const response = await supertest.get( + `${getUrlPrefix( + Spaces.space1.id + )}/api/alerts/_find?search=test.noop&search_fields=alertTypeId` + ); + + expect(response.status).to.eql(200); + expect(response.body.page).to.equal(1); + expect(response.body.perPage).to.be.greaterThan(0); + expect(response.body.total).to.be.greaterThan(0); + const match = response.body.data.find((obj: any) => obj.id === createdAlert.id); + expect(match).to.eql({ + id: createdAlert.id, + name: 'abc', + tags: ['foo'], + alertTypeId: 'test.noop', + consumer: 'alertsFixture', + schedule: { interval: '1m' }, + enabled: true, + actions: [], + params: {}, + createdBy: null, + apiKeyOwner: null, + scheduledTaskId: match.scheduledTaskId, + updatedBy: null, + throttle: '1m', + notifyWhen: 'onThrottleInterval', + muteAll: false, + mutedInstanceIds: [], + createdAt: match.createdAt, + updatedAt: match.updatedAt, + executionStatus: match.executionStatus, + }); + expect(Date.parse(match.createdAt)).to.be.greaterThan(0); + expect(Date.parse(match.updatedAt)).to.be.greaterThan(0); + }); + }); }); } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts index 3846e35f34fb1c..5245488dcb7b43 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts @@ -21,14 +21,14 @@ export default function createGetTests({ getService }: FtrProviderContext) { it('should handle get alert request appropriately', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); const response = await supertest.get( - `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}` + `${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${createdAlert.id}` ); expect(response.status).to.eql(200); @@ -36,38 +36,38 @@ export default function createGetTests({ getService }: FtrProviderContext) { id: createdAlert.id, name: 'abc', tags: ['foo'], - alertTypeId: 'test.noop', + rule_type_id: 'test.noop', consumer: 'alertsFixture', schedule: { interval: '1m' }, enabled: true, actions: [], params: {}, - createdBy: null, - scheduledTaskId: response.body.scheduledTaskId, - updatedBy: null, - apiKeyOwner: null, + created_by: null, + scheduled_task_id: response.body.scheduled_task_id, + updated_by: null, + api_key_owner: null, throttle: '1m', - notifyWhen: 'onThrottleInterval', - muteAll: false, - mutedInstanceIds: [], - createdAt: response.body.createdAt, - updatedAt: response.body.updatedAt, - executionStatus: response.body.executionStatus, + notify_when: 'onThrottleInterval', + mute_all: false, + muted_alert_ids: [], + created_at: response.body.created_at, + updated_at: response.body.updated_at, + execution_status: response.body.execution_status, }); - expect(Date.parse(response.body.createdAt)).to.be.greaterThan(0); - expect(Date.parse(response.body.updatedAt)).to.be.greaterThan(0); + expect(Date.parse(response.body.created_at)).to.be.greaterThan(0); + expect(Date.parse(response.body.updated_at)).to.be.greaterThan(0); }); it(`shouldn't find alert from another space`, async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); await supertest - .get(`${getUrlPrefix(Spaces.other.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(Spaces.other.id)}/api/alerting/rule/${createdAlert.id}`) .expect(404, { statusCode: 404, error: 'Not Found', @@ -76,11 +76,52 @@ export default function createGetTests({ getService }: FtrProviderContext) { }); it(`should handle get alert request appropriately when alert doesn't exist`, async () => { - await supertest.get(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/1`).expect(404, { + await supertest.get(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/1`).expect(404, { statusCode: 404, error: 'Not Found', message: 'Saved object [alert/1] not found', }); }); + + describe('legacy', () => { + it('should handle get alert request appropriately', async () => { + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData()) + .expect(200); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); + + const response = await supertest.get( + `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}` + ); + + expect(response.status).to.eql(200); + expect(response.body).to.eql({ + id: createdAlert.id, + name: 'abc', + tags: ['foo'], + alertTypeId: 'test.noop', + consumer: 'alertsFixture', + schedule: { interval: '1m' }, + enabled: true, + actions: [], + params: {}, + createdBy: null, + scheduledTaskId: response.body.scheduledTaskId, + updatedBy: null, + apiKeyOwner: null, + throttle: '1m', + notifyWhen: 'onThrottleInterval', + muteAll: false, + mutedInstanceIds: [], + createdAt: response.body.createdAt, + updatedAt: response.body.updatedAt, + executionStatus: response.body.executionStatus, + }); + expect(Date.parse(response.body.createdAt)).to.be.greaterThan(0); + expect(Date.parse(response.body.updatedAt)).to.be.greaterThan(0); + }); + }); }); } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get_alert_instance_summary.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get_alert_instance_summary.ts index 25d9efdebdfb0c..099502e375faa1 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get_alert_instance_summary.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get_alert_instance_summary.ts @@ -32,7 +32,7 @@ export default function createGetAlertInstanceSummaryTests({ getService }: FtrPr it(`handles non-existant alert`, async () => { await supertest - .get(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/1/_instance_summary`) + .get(`${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rule/1/_alert_summary`) .expect(404, { statusCode: 404, error: 'Not Found', @@ -42,106 +42,106 @@ export default function createGetAlertInstanceSummaryTests({ getService }: FtrPr it('handles no-op alert', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); await waitForEvents(createdAlert.id, ['execute']); const response = await supertest.get( - `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/_instance_summary` + `${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rule/${createdAlert.id}/_alert_summary` ); expect(response.status).to.eql(200); - const { statusStartDate, statusEndDate } = response.body; + const { status_start_date: statusStartDate, status_end_date: statusEndDate } = response.body; expect(Date.parse(statusStartDate)).to.be.lessThan(Date.parse(statusEndDate)); - const stableBody = omit(response.body, ['statusStartDate', 'statusEndDate', 'lastRun']); + const stableBody = omit(response.body, ['status_start_date', 'status_end_date', 'last_run']); expect(stableBody).to.eql({ id: createdAlert.id, name: 'abc', tags: ['foo'], - alertTypeId: 'test.noop', + rule_type_id: 'test.noop', consumer: 'alertsFixture', status: 'OK', - muteAll: false, + mute_all: false, throttle: '1m', enabled: true, - errorMessages: [], - instances: {}, + error_messages: [], + alerts: {}, }); }); it('handles no-op alert without waiting for execution event', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); const response = await supertest.get( - `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/_instance_summary` + `${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rule/${createdAlert.id}/_alert_summary` ); expect(response.status).to.eql(200); - const { statusStartDate, statusEndDate } = response.body; + const { status_start_date: statusStartDate, status_end_date: statusEndDate } = response.body; expect(Date.parse(statusStartDate)).to.be.lessThan(Date.parse(statusEndDate)); - const stableBody = omit(response.body, ['statusStartDate', 'statusEndDate', 'lastRun']); + const stableBody = omit(response.body, ['status_start_date', 'status_end_date', 'last_run']); expect(stableBody).to.eql({ id: createdAlert.id, name: 'abc', tags: ['foo'], - alertTypeId: 'test.noop', + rule_type_id: 'test.noop', consumer: 'alertsFixture', status: 'OK', - muteAll: false, + mute_all: false, throttle: '1m', enabled: true, - errorMessages: [], - instances: {}, + error_messages: [], + alerts: {}, }); }); it('handles dateStart parameter', async () => { const dateStart = '2020-08-08T08:08:08.008Z'; const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); await waitForEvents(createdAlert.id, ['execute']); const response = await supertest.get( - `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${ + `${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rule/${ createdAlert.id - }/_instance_summary?dateStart=${dateStart}` + }/_alert_summary?date_start=${dateStart}` ); expect(response.status).to.eql(200); - const { statusStartDate, statusEndDate } = response.body; + const { status_start_date: statusStartDate, status_end_date: statusEndDate } = response.body; expect(Date.parse(statusStartDate)).to.be.lessThan(Date.parse(statusEndDate)); expect(statusStartDate).to.be(dateStart); }); it('handles invalid dateStart parameter', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); await waitForEvents(createdAlert.id, ['execute']); const dateStart = 'X0X0-08-08T08:08:08.008Z'; const response = await supertest.get( - `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${ + `${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rule/${ createdAlert.id - }/_instance_summary?dateStart=${dateStart}` + }/_alert_summary?date_start=${dateStart}` ); expect(response.status).to.eql(400); expect(response.body).to.eql({ @@ -153,20 +153,20 @@ export default function createGetAlertInstanceSummaryTests({ getService }: FtrPr it('handles muted instances', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); await alertUtils.muteInstance(createdAlert.id, '1'); await waitForEvents(createdAlert.id, ['execute']); const response = await supertest.get( - `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/_instance_summary` + `${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rule/${createdAlert.id}/_alert_summary` ); expect(response.status).to.eql(200); - expect(response.body.instances).to.eql({ + expect(response.body.alerts).to.eql({ '1': { status: 'OK', muted: true, @@ -177,17 +177,17 @@ export default function createGetAlertInstanceSummaryTests({ getService }: FtrPr it('handles alert errors', async () => { const dateNow = Date.now(); const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') - .send(getTestAlertData({ alertTypeId: 'test.throw' })) + .send(getTestAlertData({ rule_type_id: 'test.throw' })) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); await waitForEvents(createdAlert.id, ['execute']); const response = await supertest.get( - `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/_instance_summary` + `${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rule/${createdAlert.id}/_alert_summary` ); - const { errorMessages } = response.body; + const { error_messages: errorMessages } = response.body; expect(errorMessages.length).to.be.greaterThan(0); const errorMessage = errorMessages[0]; expect(Date.parse(errorMessage.date)).to.be.greaterThan(dateNow); @@ -203,26 +203,26 @@ export default function createGetAlertInstanceSummaryTests({ getService }: FtrPr }; const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.patternFiring', + rule_type_id: 'test.patternFiring', params: { pattern }, schedule: { interval: '1s' }, }) ) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); await alertUtils.muteInstance(createdAlert.id, 'instanceC'); await alertUtils.muteInstance(createdAlert.id, 'instanceD'); await waitForEvents(createdAlert.id, ['new-instance', 'recovered-instance']); const response = await supertest.get( - `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/_instance_summary` + `${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rule/${createdAlert.id}/_alert_summary` ); - const actualInstances = response.body.instances; + const actualInstances = response.body.alerts; const expectedInstances = { instanceA: { status: 'Active', @@ -247,6 +247,62 @@ export default function createGetAlertInstanceSummaryTests({ getService }: FtrPr }; expect(actualInstances).to.eql(expectedInstances); }); + + describe('legacy', () => { + it('handles multi-instance status', async () => { + // pattern of when the alert should fire + const pattern = { + instanceA: [true, true, true, true], + instanceB: [true, true, false, false], + instanceC: [true, true, true, true], + }; + + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send( + getTestAlertData({ + rule_type_id: 'test.patternFiring', + params: { pattern }, + schedule: { interval: '1s' }, + }) + ) + .expect(200); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); + + await alertUtils.muteInstance(createdAlert.id, 'instanceC'); + await alertUtils.muteInstance(createdAlert.id, 'instanceD'); + await waitForEvents(createdAlert.id, ['new-instance', 'recovered-instance']); + const response = await supertest.get( + `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/_instance_summary` + ); + + const actualInstances = response.body.instances; + const expectedInstances = { + instanceA: { + status: 'Active', + muted: false, + actionGroupId: 'default', + activeStartDate: actualInstances.instanceA.activeStartDate, + }, + instanceB: { + status: 'OK', + muted: false, + }, + instanceC: { + status: 'Active', + muted: true, + actionGroupId: 'default', + activeStartDate: actualInstances.instanceC.activeStartDate, + }, + instanceD: { + status: 'OK', + muted: true, + }, + }; + expect(actualInstances).to.eql(expectedInstances); + }); + }); }); async function waitForEvents(id: string, actions: string[]) { diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get_alert_state.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get_alert_state.ts index e3a23e499149bf..9154c85af1bc7a 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get_alert_state.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get_alert_state.ts @@ -22,57 +22,58 @@ export default function createGetAlertStateTests({ getService }: FtrProviderCont it('should handle getAlertState request appropriately', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); const response = await supertest.get( - `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/state` + `${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rule/${createdAlert.id}/state` ); expect(response.status).to.eql(200); - expect(response.body).to.key('alertInstances', 'previousStartedAt'); + expect(response.body).to.key('alerts', 'previous_started_at'); }); it('should fetch updated state', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send({ enabled: true, name: 'abc', tags: ['foo'], - alertTypeId: 'test.cumulative-firing', + rule_type_id: 'test.cumulative-firing', consumer: 'alertsFixture', schedule: { interval: '5s' }, throttle: '5s', actions: [], params: {}, + notify_when: 'onThrottleInterval', }) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); // wait for alert to actually execute await retry.try(async () => { const response = await supertest.get( - `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/state` + `${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rule/${createdAlert.id}/state` ); expect(response.status).to.eql(200); - expect(response.body).to.key('alertInstances', 'alertTypeState', 'previousStartedAt'); - expect(response.body.alertTypeState.runCount).to.greaterThan(1); + expect(response.body).to.key('alerts', 'rule_type_state', 'previous_started_at'); + expect(response.body.rule_type_state.runCount).to.greaterThan(1); }); const response = await supertest.get( - `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/state` + `${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rule/${createdAlert.id}/state` ); - expect(response.body.alertTypeState.runCount).to.greaterThan(0); + expect(response.body.rule_type_state.runCount).to.greaterThan(0); - const alertInstances = Object.entries>(response.body.alertInstances); - expect(alertInstances.length).to.eql(response.body.alertTypeState.runCount); + const alertInstances = Object.entries>(response.body.alerts); + expect(alertInstances.length).to.eql(response.body.rule_type_state.runCount); alertInstances.forEach(([key, value], index) => { expect(key).to.eql(`instance-${index}`); expect(value.state).to.eql({ instanceStateValue: true }); @@ -81,12 +82,58 @@ export default function createGetAlertStateTests({ getService }: FtrProviderCont it(`should handle getAlertState request appropriately when alert doesn't exist`, async () => { await supertest - .get(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/1/state`) + .get(`${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rule/1/state`) .expect(404, { statusCode: 404, error: 'Not Found', message: 'Saved object [alert/1] not found', }); }); + + describe('legacy', () => { + it('should fetch updated state', async () => { + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send({ + enabled: true, + name: 'abc', + tags: ['foo'], + rule_type_id: 'test.cumulative-firing', + consumer: 'alertsFixture', + schedule: { interval: '5s' }, + throttle: '5s', + actions: [], + params: {}, + notify_when: 'onThrottleInterval', + }) + .expect(200); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); + + // wait for alert to actually execute + await retry.try(async () => { + const response = await supertest.get( + `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/state` + ); + + expect(response.status).to.eql(200); + expect(response.body).to.key('alertInstances', 'alertTypeState', 'previousStartedAt'); + expect(response.body.alertTypeState.runCount).to.greaterThan(1); + }); + + const response = await supertest.get( + `${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rule/${createdAlert.id}/state` + ); + + expect(response.body.rule_type_state.runCount).to.greaterThan(0); + + const alertInstances = Object.entries>(response.body.alerts); + expect(alertInstances.length).to.eql(response.body.rule_type_state.runCount); + alertInstances.forEach(([key, value], index) => { + expect(key).to.eql(`instance-${index}`); + expect(value.state).to.eql({ instanceStateValue: true }); + }); + }); + }); }); } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts index c1050d26e083ba..e9aeec1717c968 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts @@ -23,7 +23,7 @@ export default function alertingTests({ loadTestFile, getService }: FtrProviderC loadTestFile(require.resolve('./get')); loadTestFile(require.resolve('./get_alert_state')); loadTestFile(require.resolve('./get_alert_instance_summary')); - loadTestFile(require.resolve('./list_alert_types')); + loadTestFile(require.resolve('./rule_types')); loadTestFile(require.resolve('./event_log')); loadTestFile(require.resolve('./execution_status')); loadTestFile(require.resolve('./mute_all')); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/migrations.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/migrations.ts index 3954dbdb337a36..30e69d62933e03 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/migrations.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/migrations.ts @@ -25,7 +25,7 @@ export default function createGetTests({ getService }: FtrProviderContext) { it('7.10.0 migrates the `alerting` consumer to be the `alerts`', async () => { const response = await supertest.get( - `${getUrlPrefix(``)}/api/alerts/alert/74f3e6d7-b7bb-477d-ac28-92ee22728e6e` + `${getUrlPrefix(``)}/api/alerting/rule/74f3e6d7-b7bb-477d-ac28-92ee22728e6e` ); expect(response.status).to.eql(200); @@ -34,7 +34,7 @@ export default function createGetTests({ getService }: FtrProviderContext) { it('7.10.0 migrates the `metrics` consumer to be the `infrastructure`', async () => { const response = await supertest.get( - `${getUrlPrefix(``)}/api/alerts/alert/74f3e6d7-b7bb-477d-ac28-fdf248d5f2a4` + `${getUrlPrefix(``)}/api/alerting/rule/74f3e6d7-b7bb-477d-ac28-fdf248d5f2a4` ); expect(response.status).to.eql(200); @@ -43,14 +43,14 @@ export default function createGetTests({ getService }: FtrProviderContext) { it('7.10.0 migrates PagerDuty actions to have a default dedupKey', async () => { const response = await supertest.get( - `${getUrlPrefix(``)}/api/alerts/alert/b6087f72-994f-46fb-8120-c6e5c50d0f8f` + `${getUrlPrefix(``)}/api/alerting/rule/b6087f72-994f-46fb-8120-c6e5c50d0f8f` ); expect(response.status).to.eql(200); expect(response.body.actions).to.eql([ { - actionTypeId: '.pagerduty', + connector_type_id: '.pagerduty', id: 'a6a8ab7a-35cf-445e-ade3-215a029c2ee3', group: 'default', params: { @@ -60,7 +60,7 @@ export default function createGetTests({ getService }: FtrProviderContext) { }, }, { - actionTypeId: '.pagerduty', + connector_type_id: '.pagerduty', id: 'a6a8ab7a-35cf-445e-ade3-215a029c2ee3', group: 'default', params: { @@ -71,7 +71,7 @@ export default function createGetTests({ getService }: FtrProviderContext) { }, }, { - actionTypeId: '.pagerduty', + connector_type_id: '.pagerduty', id: 'a6a8ab7a-35cf-445e-ade3-215a029c2ee3', group: 'default', params: { @@ -86,32 +86,32 @@ export default function createGetTests({ getService }: FtrProviderContext) { it('7.11.0 migrates alerts to contain `updatedAt` field', async () => { const response = await supertest.get( - `${getUrlPrefix(``)}/api/alerts/alert/74f3e6d7-b7bb-477d-ac28-92ee22728e6e` + `${getUrlPrefix(``)}/api/alerting/rule/74f3e6d7-b7bb-477d-ac28-92ee22728e6e` ); expect(response.status).to.eql(200); - expect(response.body.updatedAt).to.eql('2020-06-17T15:35:39.839Z'); + expect(response.body.updated_at).to.eql('2020-06-17T15:35:39.839Z'); }); it('7.11.0 migrates alerts to contain `notifyWhen` field', async () => { const response = await supertest.get( - `${getUrlPrefix(``)}/api/alerts/alert/74f3e6d7-b7bb-477d-ac28-92ee22728e6e` + `${getUrlPrefix(``)}/api/alerting/rule/74f3e6d7-b7bb-477d-ac28-92ee22728e6e` ); expect(response.status).to.eql(200); - expect(response.body.notifyWhen).to.eql('onActiveAlert'); + expect(response.body.notify_when).to.eql('onActiveAlert'); }); it('7.11.2 migrates alerts with case actions, case fields are nested in an incident object', async () => { const response = await supertest.get( - `${getUrlPrefix(``)}/api/alerts/alert/99f3e6d7-b7bb-477d-ac28-92ee22726969` + `${getUrlPrefix(``)}/api/alerting/rule/99f3e6d7-b7bb-477d-ac28-92ee22726969` ); expect(response.status).to.eql(200); expect(response.body.actions).to.eql([ { id: '66a8ab7a-35cf-445e-ade3-215a029c6969', - actionTypeId: '.servicenow', + connector_type_id: '.servicenow', group: 'threshold met', params: { subAction: 'pushToService', @@ -129,7 +129,7 @@ export default function createGetTests({ getService }: FtrProviderContext) { }, { id: '66a8ab7a-35cf-445e-ade3-215a029c6969', - actionTypeId: '.jira', + connector_type_id: '.jira', group: 'threshold met', params: { subAction: 'pushToService', @@ -153,7 +153,7 @@ export default function createGetTests({ getService }: FtrProviderContext) { }, { id: '66a8ab7a-35cf-445e-ade3-215a029c6969', - actionTypeId: '.resilient', + connector_type_id: '.resilient', group: 'threshold met', params: { subAction: 'pushToService', diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mustache_templates.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mustache_templates.ts index ae24994588348c..8d300733bafc37 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mustache_templates.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mustache_templates.ts @@ -63,11 +63,11 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon it('should handle escapes in webhook', async () => { const url = formatUrl(new URL(webhookSimulatorURL), { auth: false }); const actionResponse = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/action`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/connector`) .set('kbn-xsrf', 'test') .send({ name: 'testing mustache escapes for webhook', - actionTypeId: '.webhook', + connector_type_id: '.webhook', secrets: {}, config: { headers: { @@ -78,19 +78,19 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon }); expect(actionResponse.status).to.eql(200); const createdAction = actionResponse.body; - objectRemover.add(Spaces.space1.id, createdAction.id, 'action', 'actions'); + objectRemover.add(Spaces.space1.id, createdAction.id, 'connector', 'actions'); // from x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts, // const EscapableStrings const varsTemplate = '{{context.escapableDoubleQuote}} -- {{context.escapableLineFeed}}'; const alertResponse = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ name: 'testing variable escapes for webhook', - alertTypeId: 'test.patternFiring', + rule_type_id: 'test.patternFiring', params: { pattern: { instance: [true] }, }, @@ -107,7 +107,7 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon ); expect(alertResponse.status).to.eql(200); const createdAlert = alertResponse.body; - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); const body = await retry.try(async () => waitForActionBody(webhookSimulatorURL, createdAlert.id) @@ -117,18 +117,18 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon it('should handle escapes in slack', async () => { const actionResponse = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/action`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/connector`) .set('kbn-xsrf', 'test') .send({ name: "testing backtic'd mustache escapes for slack", - actionTypeId: '.slack', + connector_type_id: '.slack', secrets: { webhookUrl: slackSimulatorURL, }, }); expect(actionResponse.status).to.eql(200); const createdAction = actionResponse.body; - objectRemover.add(Spaces.space1.id, createdAction.id, 'action', 'actions'); + objectRemover.add(Spaces.space1.id, createdAction.id, 'connector', 'actions'); // from x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts, // const EscapableStrings @@ -136,12 +136,12 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon '{{context.escapableBacktic}} -- {{context.escapableBold}} -- {{context.escapableBackticBold}} -- {{context.escapableHtml}}'; const alertResponse = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ name: 'testing variable escapes for slack', - alertTypeId: 'test.patternFiring', + rule_type_id: 'test.patternFiring', params: { pattern: { instance: [true] }, }, @@ -158,7 +158,7 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon ); expect(alertResponse.status).to.eql(200); const createdAlert = alertResponse.body; - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); const body = await retry.try(async () => waitForActionBody(slackSimulatorURL, createdAlert.id) @@ -168,30 +168,30 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon it('should handle context variable object expansion', async () => { const actionResponse = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/action`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/connector`) .set('kbn-xsrf', 'test') .send({ name: 'testing context variable expansion', - actionTypeId: '.slack', + connector_type_id: '.slack', secrets: { webhookUrl: slackSimulatorURL, }, }); expect(actionResponse.status).to.eql(200); const createdAction = actionResponse.body; - objectRemover.add(Spaces.space1.id, createdAction.id, 'action', 'actions'); + objectRemover.add(Spaces.space1.id, createdAction.id, 'connector', 'actions'); // from x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts, // const DeepContextVariables const varsTemplate = '{{context.deep}}'; const alertResponse = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ name: 'testing context variable expansion', - alertTypeId: 'test.patternFiring', + rule_type_id: 'test.patternFiring', params: { pattern: { instance: [true, true] }, }, @@ -208,7 +208,7 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon ); expect(alertResponse.status).to.eql(200); const createdAlert = alertResponse.body; - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); const body = await retry.try(async () => waitForActionBody(slackSimulatorURL, createdAlert.id) @@ -220,28 +220,28 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon it('should render kibanaBaseUrl as empty string since not configured', async () => { const actionResponse = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/action`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/connector`) .set('kbn-xsrf', 'test') .send({ name: 'testing context variable expansion', - actionTypeId: '.slack', + connector_type_id: '.slack', secrets: { webhookUrl: slackSimulatorURL, }, }); expect(actionResponse.status).to.eql(200); const createdAction = actionResponse.body; - objectRemover.add(Spaces.space1.id, createdAction.id, 'action', 'actions'); + objectRemover.add(Spaces.space1.id, createdAction.id, 'connector', 'actions'); const varsTemplate = 'kibanaBaseUrl: "{{kibanaBaseUrl}}"'; const alertResponse = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ name: 'testing context variable kibanaBaseUrl', - alertTypeId: 'test.patternFiring', + rule_type_id: 'test.patternFiring', params: { pattern: { instance: [true, true] }, }, @@ -258,7 +258,7 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon ); expect(alertResponse.status).to.eql(200); const createdAlert = alertResponse.body; - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); const body = await retry.try(async () => waitForActionBody(slackSimulatorURL, createdAlert.id) @@ -269,11 +269,11 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon it('should render action variables in rule action', async () => { const url = formatUrl(new URL(webhookSimulatorURL), { auth: false }); const actionResponse = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/action`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/connector`) .set('kbn-xsrf', 'test') .send({ name: 'testing action variable rendering', - actionTypeId: '.webhook', + connector_type_id: '.webhook', secrets: {}, config: { headers: { @@ -284,15 +284,15 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon }); expect(actionResponse.status).to.eql(200); const createdAction = actionResponse.body; - objectRemover.add(Spaces.space1.id, createdAction.id, 'action', 'actions'); + objectRemover.add(Spaces.space1.id, createdAction.id, 'connector', 'actions'); const alertResponse = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ name: 'testing variable escapes for webhook', - alertTypeId: 'test.patternFiring', + rule_type_id: 'test.patternFiring', params: { pattern: { instance: [true] }, }, @@ -309,7 +309,7 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon ); expect(alertResponse.status).to.eql(200); const createdAlert = alertResponse.body; - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); const body = await retry.try(async () => waitForActionBody(webhookSimulatorURL, createdAlert.id) diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute_all.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute_all.ts index feac0849a28646..c21a13edbf2cb3 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute_all.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute_all.ts @@ -28,19 +28,19 @@ export default function createMuteTests({ getService }: FtrProviderContext) { it('should handle mute alert request appropriately', async () => { const { body: createdAlert } = await supertestWithoutAuth - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData({ enabled: false })) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); await alertUtils.muteAll(createdAlert.id); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .expect(200); - expect(updatedAlert.muteAll).to.eql(true); + expect(updatedAlert.mute_all).to.eql(true); // Ensure AAD isn't broken await checkAAD({ @@ -50,5 +50,35 @@ export default function createMuteTests({ getService }: FtrProviderContext) { id: createdAlert.id, }); }); + + describe('legacy', () => { + it('should handle mute alert request appropriately', async () => { + const { body: createdAlert } = await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData({ enabled: false })) + .expect(200); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); + + await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/_mute_all`) + .set('kbn-xsrf', 'foo') + .expect(204); + + const { body: updatedAlert } = await supertestWithoutAuth + .get(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${createdAlert.id}`) + .set('kbn-xsrf', 'foo') + .expect(200); + expect(updatedAlert.mute_all).to.eql(true); + + // Ensure AAD isn't broken + await checkAAD({ + supertest: supertestWithoutAuth, + spaceId: Spaces.space1.id, + type: 'alert', + id: createdAlert.id, + }); + }); + }); }); } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute_instance.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute_instance.ts index 0205485e322eaa..afe29280748a5a 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute_instance.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/mute_instance.ts @@ -28,19 +28,19 @@ export default function createMuteInstanceTests({ getService }: FtrProviderConte it('should handle mute alert instance request appropriately', async () => { const { body: createdAlert } = await supertestWithoutAuth - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData({ enabled: false })) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); await alertUtils.muteInstance(createdAlert.id, '1'); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .expect(200); - expect(updatedAlert.mutedInstanceIds).to.eql(['1']); + expect(updatedAlert.muted_alert_ids).to.eql(['1']); // Ensure AAD isn't broken await checkAAD({ @@ -50,5 +50,39 @@ export default function createMuteInstanceTests({ getService }: FtrProviderConte id: createdAlert.id, }); }); + + describe('legacy', () => { + it('should handle mute alert instance request appropriately', async () => { + const { body: createdAlert } = await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData({ enabled: false })) + .expect(200); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); + + await supertestWithoutAuth + .post( + `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${ + createdAlert.id + }/alert_instance/1/_mute` + ) + .set('kbn-xsrf', 'foo') + .expect(204); + + const { body: updatedAlert } = await supertestWithoutAuth + .get(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${createdAlert.id}`) + .set('kbn-xsrf', 'foo') + .expect(200); + expect(updatedAlert.muted_alert_ids).to.eql(['1']); + + // Ensure AAD isn't broken + await checkAAD({ + supertest: supertestWithoutAuth, + spaceId: Spaces.space1.id, + type: 'alert', + id: createdAlert.id, + }); + }); + }); }); } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/notify_when.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/notify_when.ts index 29720f8d60ff52..7f1b82614a1000 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/notify_when.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/notify_when.ts @@ -24,22 +24,22 @@ export default function createNotifyWhenTests({ getService }: FtrProviderContext it(`alert with notifyWhen=onActiveAlert should always execute actions `, async () => { const { body: defaultAction } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/action`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'My Default Action', - actionTypeId: 'test.noop', + connector_type_id: 'test.noop', config: {}, secrets: {}, }) .expect(200); const { body: recoveredAction } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/action`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'My Recovered Action', - actionTypeId: 'test.noop', + connector_type_id: 'test.noop', config: {}, secrets: {}, }) @@ -52,15 +52,15 @@ export default function createNotifyWhenTests({ getService }: FtrProviderContext active ? 'default' : 'recovered' ); const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.patternFiring', + rule_type_id: 'test.patternFiring', params: { pattern }, schedule: { interval: '1s' }, throttle: null, - notifyWhen: 'onActiveAlert', + notify_when: 'onActiveAlert', actions: [ { id: defaultAction.id, @@ -76,7 +76,7 @@ export default function createNotifyWhenTests({ getService }: FtrProviderContext }) ) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); const events = await retry.try(async () => { return await getEventLog({ @@ -101,22 +101,22 @@ export default function createNotifyWhenTests({ getService }: FtrProviderContext it(`alert with notifyWhen=onActionGroupChange should execute actions when action group changes`, async () => { const { body: defaultAction } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/action`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'My Default Action', - actionTypeId: 'test.noop', + connector_type_id: 'test.noop', config: {}, secrets: {}, }) .expect(200); const { body: recoveredAction } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/action`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'My Recovered Action', - actionTypeId: 'test.noop', + connector_type_id: 'test.noop', config: {}, secrets: {}, }) @@ -128,15 +128,15 @@ export default function createNotifyWhenTests({ getService }: FtrProviderContext const expectedActionGroupBasedOnPattern = ['default', 'recovered', 'default', 'recovered']; const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.patternFiring', + rule_type_id: 'test.patternFiring', params: { pattern }, schedule: { interval: '1s' }, throttle: null, - notifyWhen: 'onActionGroupChange', + notify_when: 'onActionGroupChange', actions: [ { id: defaultAction.id, @@ -152,7 +152,7 @@ export default function createNotifyWhenTests({ getService }: FtrProviderContext }) ) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); const events = await retry.try(async () => { return await getEventLog({ @@ -177,22 +177,22 @@ export default function createNotifyWhenTests({ getService }: FtrProviderContext it(`alert with notifyWhen=onActionGroupChange should only execute actions when action subgroup changes`, async () => { const { body: defaultAction } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/action`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'My Default Action', - actionTypeId: 'test.noop', + connector_type_id: 'test.noop', config: {}, secrets: {}, }) .expect(200); const { body: recoveredAction } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/action`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/connector`) .set('kbn-xsrf', 'foo') .send({ name: 'My Recovered Action', - actionTypeId: 'test.noop', + connector_type_id: 'test.noop', config: {}, secrets: {}, }) @@ -219,15 +219,15 @@ export default function createNotifyWhenTests({ getService }: FtrProviderContext ]; const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.patternFiring', + rule_type_id: 'test.patternFiring', params: { pattern }, schedule: { interval: '1s' }, throttle: null, - notifyWhen: 'onActionGroupChange', + notify_when: 'onActionGroupChange', actions: [ { id: defaultAction.id, @@ -243,7 +243,7 @@ export default function createNotifyWhenTests({ getService }: FtrProviderContext }) ) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); const events = await retry.try(async () => { return await getEventLog({ diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/list_alert_types.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/rule_types.ts similarity index 59% rename from x-pack/test/alerting_api_integration/spaces_only/tests/alerting/list_alert_types.ts rename to x-pack/test/alerting_api_integration/spaces_only/tests/alerting/rule_types.ts index 38e38824ca9d7b..3d3cec4c30252f 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/list_alert_types.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/rule_types.ts @@ -14,42 +14,42 @@ import { FtrProviderContext } from '../../../common/ftr_provider_context'; export default function listAlertTypes({ getService }: FtrProviderContext) { const supertest = getService('supertest'); - describe('list_alert_types', () => { + describe('rule_types', () => { it('should return 200 with list of alert types', async () => { const response = await supertest.get( - `${getUrlPrefix(Spaces.space1.id)}/api/alerts/list_alert_types` + `${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule_types` ); expect(response.status).to.eql(200); - const { authorizedConsumers, ...fixtureAlertType } = response.body.find( + const { authorized_consumers: authorizedConsumers, ...fixtureAlertType } = response.body.find( (alertType: any) => alertType.id === 'test.noop' ); expect(fixtureAlertType).to.eql({ - actionGroups: [ + action_groups: [ { id: 'default', name: 'Default' }, { id: 'recovered', name: 'Recovered' }, ], - defaultActionGroupId: 'default', + default_action_group_id: 'default', id: 'test.noop', name: 'Test: Noop', - actionVariables: { + action_variables: { state: [], params: [], context: [], }, - recoveryActionGroup: { + recovery_action_group: { id: 'recovered', name: 'Recovered', }, producer: 'alertsFixture', - minimumLicenseRequired: 'basic', - enabledInLicense: true, + minimum_license_required: 'basic', + enabled_in_license: true, }); expect(Object.keys(authorizedConsumers)).to.contain('alertsFixture'); }); it('should return actionVariables with both context and state', async () => { const response = await supertest.get( - `${getUrlPrefix(Spaces.space1.id)}/api/alerts/list_alert_types` + `${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule_types` ); expect(response.status).to.eql(200); @@ -57,7 +57,7 @@ export default function listAlertTypes({ getService }: FtrProviderContext) { (alertType: any) => alertType.id === 'test.always-firing' ); - expect(fixtureAlertType.actionVariables).to.eql({ + expect(fixtureAlertType.action_variables).to.eql({ state: [{ name: 'instanceStateValue', description: 'the instance state value' }], params: [{ name: 'instanceParamsValue', description: 'the instance params value' }], context: [{ name: 'instanceContextValue', description: 'the instance context value' }], @@ -66,7 +66,7 @@ export default function listAlertTypes({ getService }: FtrProviderContext) { it('should return actionVariables with just context', async () => { const response = await supertest.get( - `${getUrlPrefix(Spaces.space1.id)}/api/alerts/list_alert_types` + `${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule_types` ); expect(response.status).to.eql(200); @@ -74,7 +74,7 @@ export default function listAlertTypes({ getService }: FtrProviderContext) { (alertType: any) => alertType.id === 'test.onlyContextVariables' ); - expect(fixtureAlertType.actionVariables).to.eql({ + expect(fixtureAlertType.action_variables).to.eql({ state: [], params: [], context: [{ name: 'aContextVariable', description: 'this is a context variable' }], @@ -83,7 +83,7 @@ export default function listAlertTypes({ getService }: FtrProviderContext) { it('should return actionVariables with just state', async () => { const response = await supertest.get( - `${getUrlPrefix(Spaces.space1.id)}/api/alerts/list_alert_types` + `${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule_types` ); expect(response.status).to.eql(200); @@ -91,11 +91,45 @@ export default function listAlertTypes({ getService }: FtrProviderContext) { (alertType: any) => alertType.id === 'test.onlyStateVariables' ); - expect(fixtureAlertType.actionVariables).to.eql({ + expect(fixtureAlertType.action_variables).to.eql({ state: [{ name: 'aStateVariable', description: 'this is a state variable' }], context: [], params: [], }); }); + + describe('legacy', () => { + it('should return 200 with list of alert types', async () => { + const response = await supertest.get( + `${getUrlPrefix(Spaces.space1.id)}/api/alerts/list_alert_types` + ); + expect(response.status).to.eql(200); + const { authorizedConsumers, ...fixtureAlertType } = response.body.find( + (alertType: any) => alertType.id === 'test.noop' + ); + expect(fixtureAlertType).to.eql({ + actionGroups: [ + { id: 'default', name: 'Default' }, + { id: 'recovered', name: 'Recovered' }, + ], + defaultActionGroupId: 'default', + id: 'test.noop', + name: 'Test: Noop', + actionVariables: { + state: [], + params: [], + context: [], + }, + recoveryActionGroup: { + id: 'recovered', + name: 'Recovered', + }, + producer: 'alertsFixture', + minimumLicenseRequired: 'basic', + enabledInLicense: true, + }); + expect(Object.keys(authorizedConsumers)).to.contain('alertsFixture'); + }); + }); }); } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute_all.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute_all.ts index 13b021474e01eb..2fffa9189e0ad7 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute_all.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute_all.ts @@ -28,20 +28,20 @@ export default function createUnmuteTests({ getService }: FtrProviderContext) { it('should handle unmute alert request appropriately', async () => { const { body: createdAlert } = await supertestWithoutAuth - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData({ enabled: false })) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); await alertUtils.muteAll(createdAlert.id); await alertUtils.unmuteAll(createdAlert.id); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .expect(200); - expect(updatedAlert.muteAll).to.eql(false); + expect(updatedAlert.mute_all).to.eql(false); // Ensure AAD isn't broken await checkAAD({ @@ -51,5 +51,39 @@ export default function createUnmuteTests({ getService }: FtrProviderContext) { id: createdAlert.id, }); }); + + describe('legacy', () => { + it('should handle unmute alert request appropriately', async () => { + const { body: createdAlert } = await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData({ enabled: false })) + .expect(200); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); + + await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/_mute_all`) + .set('kbn-xsrf', 'foo') + .expect(204); + await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/_unmute_all`) + .set('kbn-xsrf', 'foo') + .expect(204); + + const { body: updatedAlert } = await supertestWithoutAuth + .get(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${createdAlert.id}`) + .set('kbn-xsrf', 'foo') + .expect(200); + expect(updatedAlert.mute_all).to.eql(false); + + // Ensure AAD isn't broken + await checkAAD({ + supertest: supertestWithoutAuth, + spaceId: Spaces.space1.id, + type: 'alert', + id: createdAlert.id, + }); + }); + }); }); } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute_instance.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute_instance.ts index 5cba2ab2305dec..e0c42136628d3d 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute_instance.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/unmute_instance.ts @@ -28,20 +28,20 @@ export default function createUnmuteInstanceTests({ getService }: FtrProviderCon it('should handle unmute alert instance request appropriately', async () => { const { body: createdAlert } = await supertestWithoutAuth - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData({ enabled: false })) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); await alertUtils.muteInstance(createdAlert.id, '1'); await alertUtils.unmuteInstance(createdAlert.id, '1'); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .expect(200); - expect(updatedAlert.mutedInstanceIds).to.eql([]); + expect(updatedAlert.muted_alert_ids).to.eql([]); // Ensure AAD isn't broken await checkAAD({ @@ -51,5 +51,47 @@ export default function createUnmuteInstanceTests({ getService }: FtrProviderCon id: createdAlert.id, }); }); + + describe('legacy', () => { + it('should handle unmute alert instance request appropriately', async () => { + const { body: createdAlert } = await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData({ enabled: false })) + .expect(200); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); + + await supertestWithoutAuth + .post( + `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${ + createdAlert.id + }/alert_instance/1/_mute` + ) + .set('kbn-xsrf', 'foo') + .expect(204); + await supertestWithoutAuth + .post( + `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${ + createdAlert.id + }/alert_instance/1/_unmute` + ) + .set('kbn-xsrf', 'foo') + .expect(204); + + const { body: updatedAlert } = await supertestWithoutAuth + .get(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${createdAlert.id}`) + .set('kbn-xsrf', 'foo') + .expect(200); + expect(updatedAlert.muted_alert_ids).to.eql([]); + + // Ensure AAD isn't broken + await checkAAD({ + supertest: supertestWithoutAuth, + spaceId: Spaces.space1.id, + type: 'alert', + id: createdAlert.id, + }); + }); + }); }); } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update.ts index d97352966504ad..318da3e1140979 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update.ts @@ -21,11 +21,11 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { it('should handle update alert request appropriately', async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); const updatedData = { name: 'bcd', @@ -36,9 +36,10 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { schedule: { interval: '12s' }, actions: [], throttle: '1m', + notify_when: 'onThrottleInterval', }; const response = await supertest - .put(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}`) + .put(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .send(updatedData) .expect(200); @@ -47,24 +48,24 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { ...updatedData, id: createdAlert.id, tags: ['bar'], - alertTypeId: 'test.noop', + rule_type_id: 'test.noop', consumer: 'alertsFixture', - createdBy: null, + created_by: null, enabled: true, - updatedBy: null, - apiKeyOwner: null, - muteAll: false, - mutedInstanceIds: [], - notifyWhen: 'onThrottleInterval', - scheduledTaskId: createdAlert.scheduledTaskId, - createdAt: response.body.createdAt, - updatedAt: response.body.updatedAt, - executionStatus: response.body.executionStatus, + updated_by: null, + api_key_owner: null, + mute_all: false, + muted_alert_ids: [], + notify_when: 'onThrottleInterval', + scheduled_task_id: createdAlert.scheduled_task_id, + created_at: response.body.created_at, + updated_at: response.body.updated_at, + execution_status: response.body.execution_status, }); - expect(Date.parse(response.body.createdAt)).to.be.greaterThan(0); - expect(Date.parse(response.body.updatedAt)).to.be.greaterThan(0); - expect(Date.parse(response.body.updatedAt)).to.be.greaterThan( - Date.parse(response.body.createdAt) + expect(Date.parse(response.body.created_at)).to.be.greaterThan(0); + expect(Date.parse(response.body.updated_at)).to.be.greaterThan(0); + expect(Date.parse(response.body.updated_at)).to.be.greaterThan( + Date.parse(response.body.created_at) ); // Ensure AAD isn't broken @@ -78,14 +79,14 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { it(`shouldn't update alert from another space`, async () => { const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); await supertest - .put(`${getUrlPrefix(Spaces.other.id)}/api/alerts/alert/${createdAlert.id}`) + .put(`${getUrlPrefix(Spaces.other.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .send({ name: 'bcd', @@ -96,6 +97,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { schedule: { interval: '12s' }, actions: [], throttle: '1m', + notify_when: 'onThrottleInterval', }) .expect(404, { statusCode: 404, @@ -103,5 +105,65 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { message: `Saved object [alert/${createdAlert.id}] not found`, }); }); + + describe('legacy', () => { + it('should handle update alert request appropriately', async () => { + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData()) + .expect(200); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); + + const updatedData = { + name: 'bcd', + tags: ['bar'], + params: { + foo: true, + }, + schedule: { interval: '12s' }, + actions: [], + throttle: '1m', + notifyWhen: 'onThrottleInterval', + }; + const response = await supertest + .put(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}`) + .set('kbn-xsrf', 'foo') + .send(updatedData) + .expect(200); + + expect(response.body).to.eql({ + ...updatedData, + id: createdAlert.id, + tags: ['bar'], + alertTypeId: 'test.noop', + consumer: 'alertsFixture', + createdBy: null, + enabled: true, + updatedBy: null, + apiKeyOwner: null, + muteAll: false, + mutedInstanceIds: [], + notifyWhen: 'onThrottleInterval', + scheduledTaskId: createdAlert.scheduled_task_id, + createdAt: response.body.createdAt, + updatedAt: response.body.updatedAt, + executionStatus: response.body.executionStatus, + }); + expect(Date.parse(response.body.createdAt)).to.be.greaterThan(0); + expect(Date.parse(response.body.updatedAt)).to.be.greaterThan(0); + expect(Date.parse(response.body.updatedAt)).to.be.greaterThan( + Date.parse(response.body.createdAt) + ); + + // Ensure AAD isn't broken + await checkAAD({ + supertest, + spaceId: Spaces.space1.id, + type: 'alert', + id: createdAlert.id, + }); + }); + }); }); } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update_api_key.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update_api_key.ts index 32ce38d1417724..78ceadec44a9ae 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update_api_key.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update_api_key.ts @@ -32,19 +32,19 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte it('should handle update alert api key appropriately', async () => { const { body: createdAlert } = await supertestWithoutAuth - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); await alertUtils.updateApiKey(createdAlert.id); const { body: updatedAlert } = await supertestWithoutAuth - .get(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}`) + .get(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${createdAlert.id}`) .set('kbn-xsrf', 'foo') .expect(200); - expect(updatedAlert.apiKeyOwner).to.eql(null); + expect(updatedAlert.api_key_owner).to.eql(null); // Ensure AAD isn't broken await checkAAD({ @@ -57,11 +57,11 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte it(`shouldn't update alert api key from another space`, async () => { const { body: createdAlert } = await supertestWithoutAuth - .post(`${getUrlPrefix(Spaces.other.id)}/api/alerts/alert`) + .post(`${getUrlPrefix(Spaces.other.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); - objectRemover.add(Spaces.other.id, createdAlert.id, 'alert', 'alerts'); + objectRemover.add(Spaces.other.id, createdAlert.id, 'rule', 'alerting'); await alertUtils.getUpdateApiKeyRequest(createdAlert.id).expect(404, { statusCode: 404, @@ -69,5 +69,37 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte message: `Saved object [alert/${createdAlert.id}] not found`, }); }); + + describe('legacy', () => { + it('should handle update alert api key appropriately', async () => { + const { body: createdAlert } = await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData()) + .expect(200); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); + + await supertestWithoutAuth + .post( + `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/_update_api_key` + ) + .set('kbn-xsrf', 'foo') + .expect(204); + + const { body: updatedAlert } = await supertestWithoutAuth + .get(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${createdAlert.id}`) + .set('kbn-xsrf', 'foo') + .expect(200); + expect(updatedAlert.api_key_owner).to.eql(null); + + // Ensure AAD isn't broken + await checkAAD({ + supertest: supertestWithoutAuth, + spaceId: Spaces.space1.id, + type: 'alert', + id: createdAlert.id, + }); + }); + }); }); } diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alert_create_flyout.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alert_create_flyout.ts index d73488fab23730..661b452855a869 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alert_create_flyout.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alert_create_flyout.ts @@ -20,14 +20,19 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { async function getAlertsByName(name: string) { const { body: { data: alerts }, - } = await supertest.get(`/api/alerts/_find?search=${name}&search_fields=name`).expect(200); + } = await supertest + .get(`/api/alerting/rules/_find?search=${name}&search_fields=name`) + .expect(200); return alerts; } async function deleteAlerts(alertIds: string[]) { alertIds.forEach(async (alertId: string) => { - await supertest.delete(`/api/alerts/alert/${alertId}`).set('kbn-xsrf', 'foo').expect(204, ''); + await supertest + .delete(`/api/alerting/rule/${alertId}`) + .set('kbn-xsrf', 'foo') + .expect(204, ''); }); } diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts_list.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts_list.ts index e73e1fd8c37134..550e6ca455b225 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts_list.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts_list.ts @@ -20,7 +20,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { async function createAlertManualCleanup(overwrites: Record = {}) { const { body: createdAlert } = await supertest - .post(`/api/alerts/alert`) + .post(`/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData(overwrites)) .expect(200); @@ -29,7 +29,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { async function createFailingAlert() { return await createAlert({ - alertTypeId: 'test.failing', + rule_type_id: 'test.failing', schedule: { interval: '30s' }, }); } @@ -445,7 +445,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { actions: [ { id: action.id, - actionTypeId: '.slack', group: 'default', params: { level: 'info', message: 'gfghfhg' }, }, diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts index 5c4566121d4788..97f8b3f61dc892 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts @@ -42,7 +42,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { async function createAlert(overwrites: Record = {}) { const { body: createdAlert } = await supertest - .post(`/api/alerts/alert`) + .post(`/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData(overwrites)) .expect(200); @@ -52,11 +52,11 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { async function createAlwaysFiringAlert(overwrites: Record = {}) { const { body: createdAlert } = await supertest - .post(`/api/alerts/alert`) + .post(`/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - alertTypeId: 'test.always-firing', + rule_type_id: 'test.always-firing', ...overwrites, }) ) @@ -93,14 +93,14 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { async function getAlertInstanceSummary(alertId: string) { const { body: summary } = await supertest - .get(`/api/alerts/alert/${alertId}/_instance_summary`) + .get(`/internal/alerting/rule/${alertId}/_alert_summary`) .expect(200); return summary; } async function muteAlertInstance(alertId: string, alertInstanceId: string) { const { body: response } = await supertest - .post(`/api/alerts/alert/${alertId}/alert_instance/${alertInstanceId}/_mute`) + .post(`/api/alerting/rule/${alertId}/alert/${alertInstanceId}/_mute`) .set('kbn-xsrf', 'foo') .expect(204); @@ -221,7 +221,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { before(async () => { await createAlwaysFiringAlert({ name: alertName, - alertTypeId: '.index-threshold', + rule_type_id: '.index-threshold', params: { aggType: 'count', termSize: 5, @@ -526,7 +526,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // await first run to complete so we have an initial state await retry.try(async () => { - const { instances: alertInstances } = await getAlertInstanceSummary(alert.id); + const { alerts: alertInstances } = await getAlertInstanceSummary(alert.id); expect(Object.keys(alertInstances).length).to.eql(instances.length); }); }); @@ -552,12 +552,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const summary = await getAlertInstanceSummary(alert.id); const dateOnAllInstancesFromApiResponse: Record = mapValues( - summary.instances, + summary.alerts, (instance) => instance.activeStartDate ); const actionGroupNameOnAllInstancesFromApiResponse = mapValues( - summary.instances, + summary.alerts, (instance) => { const name = actionGroupNameFromId(instance.actionGroupId); return name ? ` (${name})` : ''; @@ -724,7 +724,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // await first run to complete so we have an initial state await retry.try(async () => { - const { instances: alertInstances } = await getAlertInstanceSummary(alert.id); + const { alerts: alertInstances } = await getAlertInstanceSummary(alert.id); expect(Object.keys(alertInstances).length).to.eql(instances.length); }); @@ -749,7 +749,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // Verify content await testSubjects.existOrFail('alertInstancesList'); - const { instances: alertInstances } = await getAlertInstanceSummary(alert.id); + const { alerts: alertInstances } = await getAlertInstanceSummary(alert.id); const items = await pageObjects.alertDetailsUI.getAlertInstancesList(); expect(items.length).to.eql(PAGE_SIZE); @@ -762,7 +762,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // Verify content await testSubjects.existOrFail('alertInstancesList'); - const { instances: alertInstances } = await getAlertInstanceSummary(alert.id); + const { alerts: alertInstances } = await getAlertInstanceSummary(alert.id); await pageObjects.alertDetailsUI.clickPaginationNextPage(); diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts index 4aeadf5f1ae8a3..8ebb720930364b 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts @@ -91,7 +91,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { objectRemover.add(createdAction.id, 'action', 'actions'); const { body: createdAlert } = await supertest - .post(`/api/alerts/alert`) + .post(`/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestAlertData()) .expect(200); diff --git a/x-pack/test/functional_with_es_ssl/lib/get_test_data.ts b/x-pack/test/functional_with_es_ssl/lib/get_test_data.ts index 11ccd15571259a..8dc8a5e06645c5 100644 --- a/x-pack/test/functional_with_es_ssl/lib/get_test_data.ts +++ b/x-pack/test/functional_with_es_ssl/lib/get_test_data.ts @@ -16,11 +16,11 @@ export function getTestAlertData(overwrites = {}) { enabled: true, name: generateUniqueKey(), tags: ['foo', 'bar'], - alertTypeId: 'test.noop', + rule_type_id: 'test.noop', consumer: 'alerts', schedule: { interval: '1m' }, throttle: '1m', - notifyWhen: 'onThrottleInterval', + notify_when: 'onThrottleInterval', actions: [], params: {}, ...overwrites,