From 0d78b6cba6eea47548748c93ce0936aef6331094 Mon Sep 17 00:00:00 2001 From: Nicolas Ruflin Date: Thu, 14 May 2020 13:41:25 +0200 Subject: [PATCH 1/9] [Ingest Manager] Add support for datastream to each template (#66367) All templates loaded by the Ingest Manager are now based on data streams. To test this, start the agent and ingest data and check with `GET _data_streams` that datstreams and not normal indices were created. Closes https://github.com/elastic/kibana/issues/66364 --- x-pack/plugins/ingest_manager/common/types/models/epm.ts | 3 +++ .../template/__snapshots__/template.test.ts.snap | 9 +++++++++ .../services/epm/elasticsearch/template/template.ts | 3 +++ 3 files changed, 15 insertions(+) diff --git a/x-pack/plugins/ingest_manager/common/types/models/epm.ts b/x-pack/plugins/ingest_manager/common/types/models/epm.ts index 82de90e4735f260..cc9e23dc9388f6f 100644 --- a/x-pack/plugins/ingest_manager/common/types/models/epm.ts +++ b/x-pack/plugins/ingest_manager/common/types/models/epm.ts @@ -276,6 +276,9 @@ export interface IndexTemplate { mappings: object; aliases: object; }; + data_stream: { + timestamp_field: string; + }; } export interface TemplateRef { diff --git a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/template/__snapshots__/template.test.ts.snap b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/template/__snapshots__/template.test.ts.snap index 440060aff961693..b1212cf3a6535bf 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/template/__snapshots__/template.test.ts.snap +++ b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/template/__snapshots__/template.test.ts.snap @@ -90,6 +90,9 @@ exports[`tests loading base.yml: base.yml 1`] = ` } }, "aliases": {} + }, + "data_stream": { + "timestamp_field": "@timestamp" } } `; @@ -184,6 +187,9 @@ exports[`tests loading coredns.logs.yml: coredns.logs.yml 1`] = ` } }, "aliases": {} + }, + "data_stream": { + "timestamp_field": "@timestamp" } } `; @@ -1662,6 +1668,9 @@ exports[`tests loading system.yml: system.yml 1`] = ` } }, "aliases": {} + }, + "data_stream": { + "timestamp_field": "@timestamp" } } `; diff --git a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/template/template.ts b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/template/template.ts index c45c7e706be588d..65b5ae636612cff 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/template/template.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/template/template.ts @@ -294,6 +294,9 @@ function getBaseTemplate( // To be filled with the aliases that we need aliases: {}, }, + data_stream: { + timestamp_field: '@timestamp', + }, }; } From ee22fd710d616713c0e35493c831d95898cf1efd Mon Sep 17 00:00:00 2001 From: Dario Gieselaar Date: Thu, 14 May 2020 13:54:35 +0200 Subject: [PATCH 2/9] [APM] Reset hash history when app is mounted (#66175) --- x-pack/plugins/apm/public/application/index.tsx | 7 +++++-- x-pack/plugins/apm/public/utils/history.ts | 6 +++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/apm/public/application/index.tsx b/x-pack/plugins/apm/public/application/index.tsx index 314bd722274debb..6c1c3d3262a0ef7 100644 --- a/x-pack/plugins/apm/public/application/index.tsx +++ b/x-pack/plugins/apm/public/application/index.tsx @@ -24,7 +24,7 @@ import { UpdateBreadcrumbs } from '../components/app/Main/UpdateBreadcrumbs'; import { APMIndicesPermission } from '../components/app/APMIndicesPermission'; import { ScrollToTopOnPathChange } from '../components/app/Main/ScrollToTopOnPathChange'; import { routes } from '../components/app/Main/route_config'; -import { history } from '../utils/history'; +import { history, resetHistory } from '../utils/history'; import { ConfigSchema } from '..'; import 'react-vis/dist/style.css'; @@ -111,6 +111,7 @@ export const renderApp = ( { element }: AppMountParameters, config: ConfigSchema ) => { + resetHistory(); ReactDOM.render( , element ); - return () => ReactDOM.unmountComponentAtNode(element); + return () => { + ReactDOM.unmountComponentAtNode(element); + }; }; diff --git a/x-pack/plugins/apm/public/utils/history.ts b/x-pack/plugins/apm/public/utils/history.ts index 1fd62341393c970..bd2203fe9206687 100644 --- a/x-pack/plugins/apm/public/utils/history.ts +++ b/x-pack/plugins/apm/public/utils/history.ts @@ -8,6 +8,10 @@ import { createHashHistory } from 'history'; // Make history singleton available across APM project // TODO: Explore using React context or hook instead? -const history = createHashHistory(); +let history = createHashHistory(); + +export const resetHistory = () => { + history = createHashHistory(); +}; export { history }; From 9981ef6f0725c178adf4e9c686abe36ecaed44af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Thu, 14 May 2020 14:19:51 +0200 Subject: [PATCH 3/9] [APM] Show `trace.id` in metadata table (#66376) Co-authored-by: Elastic Machine --- .../shared/MetadataTable/ErrorMetadata/sections.ts | 6 +++++- .../shared/MetadataTable/SpanMetadata/sections.ts | 4 ++-- .../shared/MetadataTable/TransactionMetadata/sections.ts | 4 +++- .../apm/public/components/shared/MetadataTable/sections.ts | 3 ++- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/sections.ts b/x-pack/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/sections.ts index 1eeebc8543d72f5..2c0d73f68760ded 100644 --- a/x-pack/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/sections.ts +++ b/x-pack/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/sections.ts @@ -16,11 +16,15 @@ import { AGENT, URL, USER, - CUSTOM_ERROR + CUSTOM_ERROR, + TRACE, + TRANSACTION } from '../sections'; export const ERROR_METADATA_SECTIONS: Section[] = [ { ...LABELS, required: true }, + TRACE, + TRANSACTION, ERROR, HTTP, HOST, diff --git a/x-pack/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/sections.ts b/x-pack/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/sections.ts index 5a83a9bf4ef9e14..f8d14707f164dfc 100644 --- a/x-pack/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/sections.ts +++ b/x-pack/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/sections.ts @@ -17,9 +17,9 @@ import { export const SPAN_METADATA_SECTIONS: Section[] = [ LABELS, - SPAN, - TRANSACTION, TRACE, + TRANSACTION, + SPAN, SERVICE, MESSAGE_SPAN, AGENT diff --git a/x-pack/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/sections.ts b/x-pack/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/sections.ts index 3a9a21356ba35a0..69d934e588e9d47 100644 --- a/x-pack/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/sections.ts +++ b/x-pack/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/sections.ts @@ -20,11 +20,13 @@ import { USER, USER_AGENT, CUSTOM_TRANSACTION, - MESSAGE_TRANSACTION + MESSAGE_TRANSACTION, + TRACE } from '../sections'; export const TRANSACTION_METADATA_SECTIONS: Section[] = [ { ...LABELS, required: true }, + TRACE, TRANSACTION, HTTP, HOST, diff --git a/x-pack/plugins/apm/public/components/shared/MetadataTable/sections.ts b/x-pack/plugins/apm/public/components/shared/MetadataTable/sections.ts index d6c0a72b8bb0846..a41651a454b3504 100644 --- a/x-pack/plugins/apm/public/components/shared/MetadataTable/sections.ts +++ b/x-pack/plugins/apm/public/components/shared/MetadataTable/sections.ts @@ -118,7 +118,8 @@ export const TRACE: Section = { key: 'trace', label: i18n.translate('xpack.apm.metadataTable.section.traceLabel', { defaultMessage: 'Trace' - }) + }), + properties: ['id'] }; export const ERROR: Section = { From e2c471b9e501db9d15b9c739a0f3fe3095619ee1 Mon Sep 17 00:00:00 2001 From: Lee Drengenberg Date: Thu, 14 May 2020 08:22:59 -0500 Subject: [PATCH 4/9] Await forceLogout before deleting user and role (#66492) --- .../feature_controls/advanced_settings_security.ts | 2 +- .../apps/canvas/feature_controls/canvas_security.ts | 2 +- .../feature_controls/index_patterns_security.ts | 2 +- .../apps/infra/feature_controls/infrastructure_security.ts | 4 ++-- .../functional/apps/infra/feature_controls/logs_security.ts | 6 +++--- .../functional/apps/maps/feature_controls/maps_security.ts | 2 +- .../feature_controls/saved_objects_management_security.ts | 6 +++--- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/x-pack/test/functional/apps/advanced_settings/feature_controls/advanced_settings_security.ts b/x-pack/test/functional/apps/advanced_settings/feature_controls/advanced_settings_security.ts index b5946dcf22610b7..f36f26f61512517 100644 --- a/x-pack/test/functional/apps/advanced_settings/feature_controls/advanced_settings_security.ts +++ b/x-pack/test/functional/apps/advanced_settings/feature_controls/advanced_settings_security.ts @@ -60,10 +60,10 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { }); after(async () => { + await PageObjects.security.forceLogout(); await Promise.all([ security.role.delete('global_advanced_settings_all_role'), security.user.delete('global_advanced_settings_all_user'), - PageObjects.security.forceLogout(), ]); }); diff --git a/x-pack/test/functional/apps/canvas/feature_controls/canvas_security.ts b/x-pack/test/functional/apps/canvas/feature_controls/canvas_security.ts index 71c10bd8248be8e..57f198d204764a1 100644 --- a/x-pack/test/functional/apps/canvas/feature_controls/canvas_security.ts +++ b/x-pack/test/functional/apps/canvas/feature_controls/canvas_security.ts @@ -57,10 +57,10 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { }); after(async () => { + await PageObjects.security.forceLogout(); await Promise.all([ security.role.delete('global_canvas_all_role'), security.user.delete('global_canvas_all_user'), - PageObjects.security.forceLogout(), ]); }); diff --git a/x-pack/test/functional/apps/index_patterns/feature_controls/index_patterns_security.ts b/x-pack/test/functional/apps/index_patterns/feature_controls/index_patterns_security.ts index 25ef24f6bfd3932..008590c9c8dc1f0 100644 --- a/x-pack/test/functional/apps/index_patterns/feature_controls/index_patterns_security.ts +++ b/x-pack/test/functional/apps/index_patterns/feature_controls/index_patterns_security.ts @@ -62,10 +62,10 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { }); after(async () => { + await PageObjects.security.forceLogout(); await Promise.all([ security.role.delete('global_index_patterns_all_role'), security.user.delete('global_index_patterns_all_user'), - PageObjects.security.forceLogout(), ]); }); diff --git a/x-pack/test/functional/apps/infra/feature_controls/infrastructure_security.ts b/x-pack/test/functional/apps/infra/feature_controls/infrastructure_security.ts index ede77b7d9afa7f2..1520621312b08fb 100644 --- a/x-pack/test/functional/apps/infra/feature_controls/infrastructure_security.ts +++ b/x-pack/test/functional/apps/infra/feature_controls/infrastructure_security.ts @@ -52,10 +52,10 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { }); after(async () => { + await PageObjects.security.forceLogout(); await Promise.all([ security.role.delete('global_infrastructure_all_role'), security.user.delete('global_infrastructure_all_user'), - PageObjects.security.forceLogout(), ]); }); @@ -168,10 +168,10 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { }); after(async () => { + await PageObjects.security.forceLogout(); await Promise.all([ security.role.delete('global_infrastructure_read_role'), security.user.delete('global_infrastructure_read_user'), - PageObjects.security.forceLogout(), ]); }); diff --git a/x-pack/test/functional/apps/infra/feature_controls/logs_security.ts b/x-pack/test/functional/apps/infra/feature_controls/logs_security.ts index 48ad4e90fd413f7..f53f60e5c7ea7af 100644 --- a/x-pack/test/functional/apps/infra/feature_controls/logs_security.ts +++ b/x-pack/test/functional/apps/infra/feature_controls/logs_security.ts @@ -49,10 +49,10 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { }); after(async () => { + await PageObjects.security.forceLogout(); await Promise.all([ security.role.delete('global_logs_all_role'), security.user.delete('global_logs_all_user'), - PageObjects.security.forceLogout(), ]); }); @@ -112,10 +112,10 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { }); after(async () => { + await PageObjects.security.forceLogout(); await Promise.all([ security.role.delete('global_logs_read_role'), security.user.delete('global_logs_read_user'), - PageObjects.security.forceLogout(), ]); }); @@ -175,10 +175,10 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { }); after(async () => { + await PageObjects.security.forceLogout(); await Promise.all([ security.role.delete('global_logs_no_privileges_role'), security.user.delete('global_logs_no_privileges_user'), - PageObjects.security.forceLogout(), ]); }); diff --git a/x-pack/test/functional/apps/maps/feature_controls/maps_security.ts b/x-pack/test/functional/apps/maps/feature_controls/maps_security.ts index ece162cbd96cc79..1651b118ea88ce3 100644 --- a/x-pack/test/functional/apps/maps/feature_controls/maps_security.ts +++ b/x-pack/test/functional/apps/maps/feature_controls/maps_security.ts @@ -57,10 +57,10 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { }); after(async () => { + await PageObjects.security.forceLogout(); await Promise.all([ security.role.delete('global_maps_all_role'), security.user.delete('global_maps_all_user'), - PageObjects.security.forceLogout(), ]); }); diff --git a/x-pack/test/functional/apps/saved_objects_management/feature_controls/saved_objects_management_security.ts b/x-pack/test/functional/apps/saved_objects_management/feature_controls/saved_objects_management_security.ts index d75540ae0b4a987..9fafaa6aae16b95 100644 --- a/x-pack/test/functional/apps/saved_objects_management/feature_controls/saved_objects_management_security.ts +++ b/x-pack/test/functional/apps/saved_objects_management/feature_controls/saved_objects_management_security.ts @@ -52,10 +52,10 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { }); after(async () => { + await PageObjects.security.forceLogout(); await Promise.all([ security.role.delete('global_all_role'), security.user.delete('global_all_user'), - PageObjects.security.forceLogout(), ]); }); @@ -170,10 +170,10 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { }); after(async () => { + await PageObjects.security.forceLogout(); await Promise.all([ security.role.delete('global_som_read_role'), security.user.delete('global_som_read_user'), - PageObjects.security.forceLogout(), ]); }); @@ -293,10 +293,10 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { }); after(async () => { + await PageObjects.security.forceLogout(); await Promise.all([ security.role.delete('global_visualize_all_role'), security.user.delete('global_visualize_all_user'), - PageObjects.security.forceLogout(), ]); }); From 9e6ebc50a00fd7b66d4c11d2e98cd550a543b72d Mon Sep 17 00:00:00 2001 From: Dario Gieselaar Date: Thu, 14 May 2020 16:23:38 +0200 Subject: [PATCH 5/9] [APM] Add license guard for annotations (#65995) --- x-pack/plugins/apm/server/routes/services.ts | 13 ++-- x-pack/plugins/observability/kibana.json | 3 + .../lib/annotations/bootstrap_annotations.ts | 10 ++- .../annotations/create_annotations_client.ts | 74 +++++++++++-------- .../annotations/register_annotation_apis.ts | 26 +++++-- x-pack/scripts/functional_tests.js | 4 + x-pack/test/api_integration/apis/index.js | 2 - .../test/apm_api_integration/basic/config.ts | 14 ++++ .../basic/tests}/agent_configuration.ts | 3 +- .../basic/tests/annotations.ts | 52 +++++++++++++ .../basic/tests}/custom_link.ts | 5 +- .../basic/tests}/feature_controls.ts | 3 +- .../basic/tests}/index.ts | 8 +- .../test/apm_api_integration/common/config.ts | 38 ++++++++++ .../common/ftr_provider_context.ts | 7 ++ .../test/apm_api_integration/trial/config.ts | 14 ++++ .../trial/tests}/annotations.ts | 5 +- .../apm_api_integration/trial/tests/index.ts | 15 ++++ .../basic/config.ts | 14 ++++ .../basic/tests/annotations.ts | 51 +++++++++++++ .../basic/tests/index.ts | 15 ++++ .../common/config.ts | 38 ++++++++++ .../common/ftr_provider_context.ts | 7 ++ .../trial/config.ts | 14 ++++ .../trial/tests}/annotations.ts | 3 +- .../trial/tests/index.ts | 15 ++++ 26 files changed, 392 insertions(+), 61 deletions(-) create mode 100644 x-pack/test/apm_api_integration/basic/config.ts rename x-pack/test/{api_integration/apis/apm => apm_api_integration/basic/tests}/agent_configuration.ts (98%) create mode 100644 x-pack/test/apm_api_integration/basic/tests/annotations.ts rename x-pack/test/{api_integration/apis/apm => apm_api_integration/basic/tests}/custom_link.ts (96%) rename x-pack/test/{api_integration/apis/apm => apm_api_integration/basic/tests}/feature_controls.ts (98%) rename x-pack/test/{api_integration/apis/apm => apm_api_integration/basic/tests}/index.ts (73%) create mode 100644 x-pack/test/apm_api_integration/common/config.ts create mode 100644 x-pack/test/apm_api_integration/common/ftr_provider_context.ts create mode 100644 x-pack/test/apm_api_integration/trial/config.ts rename x-pack/test/{api_integration/apis/apm => apm_api_integration/trial/tests}/annotations.ts (98%) create mode 100644 x-pack/test/apm_api_integration/trial/tests/index.ts create mode 100644 x-pack/test/observability_api_integration/basic/config.ts create mode 100644 x-pack/test/observability_api_integration/basic/tests/annotations.ts create mode 100644 x-pack/test/observability_api_integration/basic/tests/index.ts create mode 100644 x-pack/test/observability_api_integration/common/config.ts create mode 100644 x-pack/test/observability_api_integration/common/ftr_provider_context.ts create mode 100644 x-pack/test/observability_api_integration/trial/config.ts rename x-pack/test/{api_integration/apis/observability => observability_api_integration/trial/tests}/annotations.ts (98%) create mode 100644 x-pack/test/observability_api_integration/trial/tests/index.ts diff --git a/x-pack/plugins/apm/server/routes/services.ts b/x-pack/plugins/apm/server/routes/services.ts index 474ab1c6082a44c..782f8957cf188b8 100644 --- a/x-pack/plugins/apm/server/routes/services.ts +++ b/x-pack/plugins/apm/server/routes/services.ts @@ -7,7 +7,6 @@ import * as t from 'io-ts'; import Boom from 'boom'; import { unique } from 'lodash'; -import { ScopedAnnotationsClient } from '../../../observability/server'; import { setupRequest } from '../lib/helpers/setup_request'; import { getServiceAgentName } from '../lib/services/get_service_agent_name'; import { getServices } from '../lib/services/get_services'; @@ -95,13 +94,10 @@ export const serviceAnnotationsRoute = createRoute(() => ({ const { serviceName } = context.params.path; const { environment } = context.params.query; - let annotationsClient: ScopedAnnotationsClient | undefined; - - if (context.plugins.observability) { - annotationsClient = await context.plugins.observability.getScopedAnnotationsClient( - request - ); - } + const annotationsClient = await context.plugins.observability?.getScopedAnnotationsClient( + context, + request + ); return getServiceAnnotations({ setup, @@ -143,6 +139,7 @@ export const serviceAnnotationsCreateRoute = createRoute(() => ({ }, handler: async ({ request, context }) => { const annotationsClient = await context.plugins.observability?.getScopedAnnotationsClient( + context, request ); diff --git a/x-pack/plugins/observability/kibana.json b/x-pack/plugins/observability/kibana.json index 8e2cfe980039ce3..712a46f76bb7473 100644 --- a/x-pack/plugins/observability/kibana.json +++ b/x-pack/plugins/observability/kibana.json @@ -6,6 +6,9 @@ "xpack", "observability" ], + "optionalPlugins": [ + "licensing" + ], "ui": true, "server": true } diff --git a/x-pack/plugins/observability/server/lib/annotations/bootstrap_annotations.ts b/x-pack/plugins/observability/server/lib/annotations/bootstrap_annotations.ts index 58639ef084ce650..6ea9f82d11ab919 100644 --- a/x-pack/plugins/observability/server/lib/annotations/bootstrap_annotations.ts +++ b/x-pack/plugins/observability/server/lib/annotations/bootstrap_annotations.ts @@ -3,7 +3,12 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { CoreSetup, PluginInitializerContext, KibanaRequest } from 'kibana/server'; +import { + CoreSetup, + PluginInitializerContext, + KibanaRequest, + RequestHandlerContext, +} from 'kibana/server'; import { PromiseReturnType } from '../../../typings/common'; import { createAnnotationsClient } from './create_annotations_client'; import { registerAnnotationAPIs } from './register_annotation_apis'; @@ -31,11 +36,12 @@ export async function bootstrapAnnotations({ index, core, context }: Params) { }); return { - getScopedAnnotationsClient: (request: KibanaRequest) => { + getScopedAnnotationsClient: (requestContext: RequestHandlerContext, request: KibanaRequest) => { return createAnnotationsClient({ index, apiCaller: core.elasticsearch.dataClient.asScoped(request).callAsCurrentUser, logger, + license: requestContext.licensing?.license, }); }, }; diff --git a/x-pack/plugins/observability/server/lib/annotations/create_annotations_client.ts b/x-pack/plugins/observability/server/lib/annotations/create_annotations_client.ts index 3f2604468e17c5b..71b1a42b2000d98 100644 --- a/x-pack/plugins/observability/server/lib/annotations/create_annotations_client.ts +++ b/x-pack/plugins/observability/server/lib/annotations/create_annotations_client.ts @@ -7,6 +7,8 @@ import { APICaller, Logger } from 'kibana/server'; import * as t from 'io-ts'; import { Client } from 'elasticsearch'; +import Boom from 'boom'; +import { ILicense } from '../../../../licensing/server'; import { createAnnotationRt, deleteAnnotationRt, @@ -40,8 +42,9 @@ export function createAnnotationsClient(params: { index: string; apiCaller: APICaller; logger: Logger; + license?: ILicense; }) { - const { index, apiCaller, logger } = params; + const { index, apiCaller, logger, license } = params; const initIndex = () => createOrUpdateIndex({ @@ -51,48 +54,59 @@ export function createAnnotationsClient(params: { logger, }); + function ensureGoldLicense any>(fn: T): T { + return ((...args) => { + if (!license?.hasAtLeast('gold')) { + throw Boom.forbidden('Annotations require at least a gold license or a trial license.'); + } + return fn(...args); + }) as T; + } + return { get index() { return index; }, - create: async ( - createParams: CreateParams - ): Promise<{ _id: string; _index: string; _source: Annotation }> => { - const indexExists = await apiCaller('indices.exists', { - index, - }); + create: ensureGoldLicense( + async ( + createParams: CreateParams + ): Promise<{ _id: string; _index: string; _source: Annotation }> => { + const indexExists = await apiCaller('indices.exists', { + index, + }); - if (!indexExists) { - await initIndex(); - } + if (!indexExists) { + await initIndex(); + } - const annotation = { - ...createParams, - event: { - created: new Date().toISOString(), - }, - }; + const annotation = { + ...createParams, + event: { + created: new Date().toISOString(), + }, + }; - const response = (await apiCaller('index', { - index, - body: annotation, - refresh: 'wait_for', - })) as IndexDocumentResponse; + const response = (await apiCaller('index', { + index, + body: annotation, + refresh: 'wait_for', + })) as IndexDocumentResponse; - return apiCaller('get', { - index, - id: response._id, - }); - }, - getById: async (getByIdParams: GetByIdParams) => { + return apiCaller('get', { + index, + id: response._id, + }); + } + ), + getById: ensureGoldLicense(async (getByIdParams: GetByIdParams) => { const { id } = getByIdParams; return apiCaller('get', { id, index, }); - }, - delete: async (deleteParams: DeleteParams) => { + }), + delete: ensureGoldLicense(async (deleteParams: DeleteParams) => { const { id } = deleteParams; const response = (await apiCaller('delete', { @@ -101,6 +115,6 @@ export function createAnnotationsClient(params: { refresh: 'wait_for', })) as PromiseReturnType; return response; - }, + }), }; } diff --git a/x-pack/plugins/observability/server/lib/annotations/register_annotation_apis.ts b/x-pack/plugins/observability/server/lib/annotations/register_annotation_apis.ts index 3c29822acd6dd0f..21ebfcd6205e724 100644 --- a/x-pack/plugins/observability/server/lib/annotations/register_annotation_apis.ts +++ b/x-pack/plugins/observability/server/lib/annotations/register_annotation_apis.ts @@ -32,7 +32,7 @@ export function registerAnnotationAPIs({ handler: (params: { data: t.TypeOf; client: ScopedAnnotationsClient }) => Promise ): RequestHandler { return async (...args: Parameters) => { - const [, request, response] = args; + const [context, request, response] = args; const rt = types; @@ -56,16 +56,26 @@ export function registerAnnotationAPIs({ index, apiCaller, logger, + license: context.licensing?.license, }); - const res = await handler({ - data: validation.right, - client, - }); + try { + const res = await handler({ + data: validation.right, + client, + }); - return response.ok({ - body: res, - }); + return response.ok({ + body: res, + }); + } catch (err) { + return response.custom({ + statusCode: err.output?.statusCode ?? 500, + body: { + message: err.output?.payload?.message ?? 'An internal server error occured', + }, + }); + } }; } diff --git a/x-pack/scripts/functional_tests.js b/x-pack/scripts/functional_tests.js index 3ec7776f848afd9..8ea554c42d6e0da 100644 --- a/x-pack/scripts/functional_tests.js +++ b/x-pack/scripts/functional_tests.js @@ -20,6 +20,8 @@ const onlyNotInCoverageTests = [ require.resolve('../test/alerting_api_integration/basic/config.ts'), require.resolve('../test/alerting_api_integration/spaces_only/config.ts'), require.resolve('../test/alerting_api_integration/security_and_spaces/config.ts'), + require.resolve('../test/apm_api_integration/basic/config.ts'), + require.resolve('../test/apm_api_integration/trial/config.ts'), require.resolve('../test/detection_engine_api_integration/security_and_spaces/config.ts'), require.resolve('../test/detection_engine_api_integration/basic/config.ts'), require.resolve('../test/plugin_api_integration/config.ts'), @@ -29,6 +31,8 @@ const onlyNotInCoverageTests = [ require.resolve('../test/token_api_integration/config.js'), require.resolve('../test/oidc_api_integration/config.ts'), require.resolve('../test/oidc_api_integration/implicit_flow.config.ts'), + require.resolve('../test/observability_api_integration/basic/config.ts'), + require.resolve('../test/observability_api_integration/trial/config.ts'), require.resolve('../test/pki_api_integration/config.ts'), require.resolve('../test/login_selector_api_integration/config.ts'), require.resolve('../test/encrypted_saved_objects_api_integration/config.ts'), diff --git a/x-pack/test/api_integration/apis/index.js b/x-pack/test/api_integration/apis/index.js index 75fa90bb4c3fe84..321fbce52a75a5d 100644 --- a/x-pack/test/api_integration/apis/index.js +++ b/x-pack/test/api_integration/apis/index.js @@ -23,7 +23,6 @@ export default function({ loadTestFile }) { loadTestFile(require.resolve('./management')); loadTestFile(require.resolve('./uptime')); loadTestFile(require.resolve('./maps')); - loadTestFile(require.resolve('./apm')); loadTestFile(require.resolve('./siem')); loadTestFile(require.resolve('./short_urls')); loadTestFile(require.resolve('./lens')); @@ -31,6 +30,5 @@ export default function({ loadTestFile }) { loadTestFile(require.resolve('./ingest')); loadTestFile(require.resolve('./endpoint')); loadTestFile(require.resolve('./ml')); - loadTestFile(require.resolve('./observability')); }); } diff --git a/x-pack/test/apm_api_integration/basic/config.ts b/x-pack/test/apm_api_integration/basic/config.ts new file mode 100644 index 000000000000000..541fe9ec023bcfa --- /dev/null +++ b/x-pack/test/apm_api_integration/basic/config.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { createTestConfig } from '../common/config'; + +// eslint-disable-next-line import/no-default-export +export default createTestConfig({ + license: 'basic', + name: 'X-Pack APM API integration tests (basic)', + testFiles: [require.resolve('./tests')], +}); diff --git a/x-pack/test/api_integration/apis/apm/agent_configuration.ts b/x-pack/test/apm_api_integration/basic/tests/agent_configuration.ts similarity index 98% rename from x-pack/test/api_integration/apis/apm/agent_configuration.ts rename to x-pack/test/apm_api_integration/basic/tests/agent_configuration.ts index 8af648e062cf440..04974d57074a56d 100644 --- a/x-pack/test/api_integration/apis/apm/agent_configuration.ts +++ b/x-pack/test/apm_api_integration/basic/tests/agent_configuration.ts @@ -6,8 +6,9 @@ import expect from '@kbn/expect'; import { AgentConfigurationIntake } from '../../../../plugins/apm/common/agent_configuration/configuration_types'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +// eslint-disable-next-line import/no-default-export export default function agentConfigurationTests({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const log = getService('log'); diff --git a/x-pack/test/apm_api_integration/basic/tests/annotations.ts b/x-pack/test/apm_api_integration/basic/tests/annotations.ts new file mode 100644 index 000000000000000..a939ef06273569c --- /dev/null +++ b/x-pack/test/apm_api_integration/basic/tests/annotations.ts @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import { JsonObject } from 'src/plugins/kibana_utils/common'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function annotationApiTests({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + + function request({ method, url, data }: { method: string; url: string; data?: JsonObject }) { + switch (method.toLowerCase()) { + case 'post': + return supertest + .post(url) + .send(data) + .set('kbn-xsrf', 'foo'); + + default: + throw new Error(`Unsupported methoed ${method}`); + } + } + + describe('APM annotations with a basic license', () => { + describe('when creating an annotation', () => { + it('fails with a 403 forbidden', async () => { + const response = await request({ + url: '/api/apm/services/opbeans-java/annotation', + method: 'POST', + data: { + '@timestamp': new Date().toISOString(), + message: 'New deployment', + tags: ['foo'], + service: { + version: '1.1', + environment: 'production', + }, + }, + }); + + expect(response.status).to.be(403); + expect(response.body.message).to.be( + 'Annotations require at least a gold license or a trial license.' + ); + }); + }); + }); +} diff --git a/x-pack/test/api_integration/apis/apm/custom_link.ts b/x-pack/test/apm_api_integration/basic/tests/custom_link.ts similarity index 96% rename from x-pack/test/api_integration/apis/apm/custom_link.ts rename to x-pack/test/apm_api_integration/basic/tests/custom_link.ts index 8aefadd81177535..910c4797f39b76f 100644 --- a/x-pack/test/api_integration/apis/apm/custom_link.ts +++ b/x-pack/test/apm_api_integration/basic/tests/custom_link.ts @@ -3,13 +3,12 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -// import querystring from 'querystring'; -// import {isEmpty} from 'lodash' import URL from 'url'; import expect from '@kbn/expect'; import { CustomLink } from '../../../../plugins/apm/common/custom_link/custom_link_types'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +// eslint-disable-next-line import/no-default-export export default function customLinksTests({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const log = getService('log'); diff --git a/x-pack/test/api_integration/apis/apm/feature_controls.ts b/x-pack/test/apm_api_integration/basic/tests/feature_controls.ts similarity index 98% rename from x-pack/test/api_integration/apis/apm/feature_controls.ts rename to x-pack/test/apm_api_integration/basic/tests/feature_controls.ts index 5f61c963a69aa0c..f3647c65106c926 100644 --- a/x-pack/test/api_integration/apis/apm/feature_controls.ts +++ b/x-pack/test/apm_api_integration/basic/tests/feature_controls.ts @@ -5,8 +5,9 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +// eslint-disable-next-line import/no-default-export export default function featureControlsTests({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const supertestWithoutAuth = getService('supertestWithoutAuth'); diff --git a/x-pack/test/api_integration/apis/apm/index.ts b/x-pack/test/apm_api_integration/basic/tests/index.ts similarity index 73% rename from x-pack/test/api_integration/apis/apm/index.ts rename to x-pack/test/apm_api_integration/basic/tests/index.ts index de076e8c46729ea..f3c1a3c3f63d56d 100644 --- a/x-pack/test/api_integration/apis/apm/index.ts +++ b/x-pack/test/apm_api_integration/basic/tests/index.ts @@ -3,11 +3,13 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { FtrProviderContext } from '../../ftr_provider_context'; - +// eslint-disable-next-line import/no-default-export export default function apmApiIntegrationTests({ loadTestFile }: FtrProviderContext) { - describe('APM specs', () => { + describe('APM specs (basic)', function() { + this.tags('ciGroup1'); + loadTestFile(require.resolve('./annotations')); loadTestFile(require.resolve('./feature_controls')); loadTestFile(require.resolve('./agent_configuration')); diff --git a/x-pack/test/apm_api_integration/common/config.ts b/x-pack/test/apm_api_integration/common/config.ts new file mode 100644 index 000000000000000..9e011a98bbfcd48 --- /dev/null +++ b/x-pack/test/apm_api_integration/common/config.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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { FtrConfigProviderContext } from '@kbn/test/types/ftr'; + +interface Settings { + license: 'basic' | 'trial'; + testFiles: string[]; + name: string; +} + +export function createTestConfig(settings: Settings) { + const { testFiles, license, name } = settings; + + return async ({ readConfigFile }: FtrConfigProviderContext) => { + const xPackAPITestsConfig = await readConfigFile( + require.resolve('../../api_integration/config.js') + ); + + return { + testFiles, + servers: xPackAPITestsConfig.get('servers'), + services: xPackAPITestsConfig.get('services'), + junit: { + reportName: name, + }, + + esTestCluster: { + ...xPackAPITestsConfig.get('esTestCluster'), + license, + }, + kbnTestServer: xPackAPITestsConfig.get('kbnTestServer'), + }; + }; +} diff --git a/x-pack/test/apm_api_integration/common/ftr_provider_context.ts b/x-pack/test/apm_api_integration/common/ftr_provider_context.ts new file mode 100644 index 000000000000000..90600816d171149 --- /dev/null +++ b/x-pack/test/apm_api_integration/common/ftr_provider_context.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { FtrProviderContext } from '../../api_integration/ftr_provider_context'; diff --git a/x-pack/test/apm_api_integration/trial/config.ts b/x-pack/test/apm_api_integration/trial/config.ts new file mode 100644 index 000000000000000..ca5b11d469c470c --- /dev/null +++ b/x-pack/test/apm_api_integration/trial/config.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { createTestConfig } from '../common/config'; + +// eslint-disable-next-line import/no-default-export +export default createTestConfig({ + license: 'trial', + name: 'X-Pack APM API integration tests (trial)', + testFiles: [require.resolve('./tests')], +}); diff --git a/x-pack/test/api_integration/apis/apm/annotations.ts b/x-pack/test/apm_api_integration/trial/tests/annotations.ts similarity index 98% rename from x-pack/test/api_integration/apis/apm/annotations.ts rename to x-pack/test/apm_api_integration/trial/tests/annotations.ts index 4746a7713f34b39..9beea6a53dd4d40 100644 --- a/x-pack/test/api_integration/apis/apm/annotations.ts +++ b/x-pack/test/apm_api_integration/trial/tests/annotations.ts @@ -7,10 +7,11 @@ import expect from '@kbn/expect'; import { merge, cloneDeep, isPlainObject } from 'lodash'; import { JsonObject } from 'src/plugins/kibana_utils/common'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; const DEFAULT_INDEX_NAME = 'observability-annotations'; +// eslint-disable-next-line import/no-default-export export default function annotationApiTests({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const es = getService('es'); @@ -42,7 +43,7 @@ export default function annotationApiTests({ getService }: FtrProviderContext) { } } - describe('APM annotations', () => { + describe('APM annotations with a trial license', () => { describe('when creating an annotation', () => { afterEach(async () => { const indexExists = (await es.indices.exists({ index: DEFAULT_INDEX_NAME })).body; diff --git a/x-pack/test/apm_api_integration/trial/tests/index.ts b/x-pack/test/apm_api_integration/trial/tests/index.ts new file mode 100644 index 000000000000000..3a4571afb3d4a79 --- /dev/null +++ b/x-pack/test/apm_api_integration/trial/tests/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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { FtrProviderContext } from '../../../api_integration/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function observabilityApiIntegrationTests({ loadTestFile }: FtrProviderContext) { + describe('APM specs (trial)', function() { + this.tags('ciGroup1'); + loadTestFile(require.resolve('./annotations')); + }); +} diff --git a/x-pack/test/observability_api_integration/basic/config.ts b/x-pack/test/observability_api_integration/basic/config.ts new file mode 100644 index 000000000000000..0e8bf1daaf9e613 --- /dev/null +++ b/x-pack/test/observability_api_integration/basic/config.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { createTestConfig } from '../common/config'; + +// eslint-disable-next-line import/no-default-export +export default createTestConfig({ + license: 'basic', + name: 'X-Pack Observability API integration tests (basic)', + testFiles: [require.resolve('./tests')], +}); diff --git a/x-pack/test/observability_api_integration/basic/tests/annotations.ts b/x-pack/test/observability_api_integration/basic/tests/annotations.ts new file mode 100644 index 000000000000000..cd86c8a0f2cda73 --- /dev/null +++ b/x-pack/test/observability_api_integration/basic/tests/annotations.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; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import { JsonObject } from 'src/plugins/kibana_utils/common'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function annotationApiTests({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + + function request({ method, url, data }: { method: string; url: string; data?: JsonObject }) { + switch (method.toLowerCase()) { + case 'post': + return supertest + .post(url) + .send(data) + .set('kbn-xsrf', 'foo'); + + default: + throw new Error(`Unsupported methoed ${method}`); + } + } + + describe('Observability annotations with a basic license', () => { + describe('when creating an annotation', () => { + it('fails with a 403 forbidden', async () => { + const response = await request({ + url: '/api/observability/annotation', + method: 'POST', + data: { + annotation: { + type: 'deployment', + }, + '@timestamp': new Date().toISOString(), + message: 'test message', + tags: ['apm'], + }, + }); + + expect(response.status).to.be(403); + expect(response.body.message).to.be( + 'Annotations require at least a gold license or a trial license.' + ); + }); + }); + }); +} diff --git a/x-pack/test/observability_api_integration/basic/tests/index.ts b/x-pack/test/observability_api_integration/basic/tests/index.ts new file mode 100644 index 000000000000000..a4c04a9229fa949 --- /dev/null +++ b/x-pack/test/observability_api_integration/basic/tests/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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { FtrProviderContext } from '../../common/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function observabilityApiIntegrationTests({ loadTestFile }: FtrProviderContext) { + describe('Observability specs (basic)', function() { + this.tags('ciGroup1'); + loadTestFile(require.resolve('./annotations')); + }); +} diff --git a/x-pack/test/observability_api_integration/common/config.ts b/x-pack/test/observability_api_integration/common/config.ts new file mode 100644 index 000000000000000..9e011a98bbfcd48 --- /dev/null +++ b/x-pack/test/observability_api_integration/common/config.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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { FtrConfigProviderContext } from '@kbn/test/types/ftr'; + +interface Settings { + license: 'basic' | 'trial'; + testFiles: string[]; + name: string; +} + +export function createTestConfig(settings: Settings) { + const { testFiles, license, name } = settings; + + return async ({ readConfigFile }: FtrConfigProviderContext) => { + const xPackAPITestsConfig = await readConfigFile( + require.resolve('../../api_integration/config.js') + ); + + return { + testFiles, + servers: xPackAPITestsConfig.get('servers'), + services: xPackAPITestsConfig.get('services'), + junit: { + reportName: name, + }, + + esTestCluster: { + ...xPackAPITestsConfig.get('esTestCluster'), + license, + }, + kbnTestServer: xPackAPITestsConfig.get('kbnTestServer'), + }; + }; +} diff --git a/x-pack/test/observability_api_integration/common/ftr_provider_context.ts b/x-pack/test/observability_api_integration/common/ftr_provider_context.ts new file mode 100644 index 000000000000000..90600816d171149 --- /dev/null +++ b/x-pack/test/observability_api_integration/common/ftr_provider_context.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { FtrProviderContext } from '../../api_integration/ftr_provider_context'; diff --git a/x-pack/test/observability_api_integration/trial/config.ts b/x-pack/test/observability_api_integration/trial/config.ts new file mode 100644 index 000000000000000..c073e2e6af7fed4 --- /dev/null +++ b/x-pack/test/observability_api_integration/trial/config.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { createTestConfig } from '../common/config'; + +// eslint-disable-next-line import/no-default-export +export default createTestConfig({ + license: 'trial', + name: 'X-Pack Observability API integration tests (trial)', + testFiles: [require.resolve('./tests')], +}); diff --git a/x-pack/test/api_integration/apis/observability/annotations.ts b/x-pack/test/observability_api_integration/trial/tests/annotations.ts similarity index 98% rename from x-pack/test/api_integration/apis/observability/annotations.ts rename to x-pack/test/observability_api_integration/trial/tests/annotations.ts index 6d32162bfcc6581..ad3bcdbfabd8b3f 100644 --- a/x-pack/test/api_integration/apis/observability/annotations.ts +++ b/x-pack/test/observability_api_integration/trial/tests/annotations.ts @@ -8,10 +8,11 @@ import expect from '@kbn/expect'; import { JsonObject } from 'src/plugins/kibana_utils/common'; import { Annotation } from '../../../../plugins/observability/common/annotations'; import { ESSearchHit } from '../../../../plugins/apm/typings/elasticsearch'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; const DEFAULT_INDEX_NAME = 'observability-annotations'; +// eslint-disable-next-line import/no-default-export export default function annotationApiTests({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const es = getService('es'); diff --git a/x-pack/test/observability_api_integration/trial/tests/index.ts b/x-pack/test/observability_api_integration/trial/tests/index.ts new file mode 100644 index 000000000000000..d1acf4d98f7f977 --- /dev/null +++ b/x-pack/test/observability_api_integration/trial/tests/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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { FtrProviderContext } from '../../common/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function apmApiIntegrationTests({ loadTestFile }: FtrProviderContext) { + describe('Observability specs (trial)', function() { + this.tags('ciGroup1'); + loadTestFile(require.resolve('./annotations')); + }); +} From d2381eb8d29c7ce8a3a8c18271b83f22da58cf6d Mon Sep 17 00:00:00 2001 From: Andrew Cholakian Date: Thu, 14 May 2020 10:17:38 -0500 Subject: [PATCH 6/9] [Uptime] Only show ~latest checks on certs page/alert (#66349) * [Uptime] Only show ~latest checks on certs page/alert Fixes https://github.com/elastic/uptime/issues/199 Also fixes some duplicate constants used in the queries here. For default index we just use a literal `0` now since there's no way that'd ever change. * Change window to 5m * Fix dependency issues in FTR suite for certs page. * Ensures tests can run independently, and always navigate to the certs page * Ensures that the not_after field is consistent * Ensures that timespan field is always present in checked documents --- .../plugins/uptime/server/lib/alerts/tls.ts | 6 +- .../lib/requests/__tests__/get_certs.test.ts | 2 +- .../uptime/server/lib/requests/get_certs.ts | 2 +- .../uptime/server/rest_api/certs/certs.ts | 8 +-- .../apis/uptime/rest/helper/make_ping.ts | 7 ++- .../apis/uptime/rest/helper/make_tls.ts | 2 +- .../functional/apps/uptime/certificates.ts | 58 ++++++++++--------- 7 files changed, 45 insertions(+), 40 deletions(-) diff --git a/x-pack/plugins/uptime/server/lib/alerts/tls.ts b/x-pack/plugins/uptime/server/lib/alerts/tls.ts index c4464ff57521805..6aa9d1aa3c6457a 100644 --- a/x-pack/plugins/uptime/server/lib/alerts/tls.ts +++ b/x-pack/plugins/uptime/server/lib/alerts/tls.ts @@ -12,12 +12,10 @@ import { updateState } from './common'; import { ACTION_GROUP_DEFINITIONS, DYNAMIC_SETTINGS_DEFAULTS } from '../../../common/constants'; import { Cert, CertResult } from '../../../common/runtime_types'; import { commonStateTranslations, tlsTranslations } from './translations'; +import { DEFAULT_FROM, DEFAULT_TO } from '../../rest_api/certs/certs'; const { TLS } = ACTION_GROUP_DEFINITIONS; -const DEFAULT_FROM = 'now-1d'; -const DEFAULT_TO = 'now'; -const DEFAULT_INDEX = 0; const DEFAULT_SIZE = 20; interface TlsAlertState { @@ -113,7 +111,7 @@ export const tlsAlertFactory: UptimeAlertTypeFactory = (_server, libs) => ({ dynamicSettings, from: DEFAULT_FROM, to: DEFAULT_TO, - index: DEFAULT_INDEX, + index: 0, size: DEFAULT_SIZE, notValidAfter: `now+${dynamicSettings?.certExpirationThreshold ?? DYNAMIC_SETTINGS_DEFAULTS.certExpirationThreshold}d`, diff --git a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_certs.test.ts b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_certs.test.ts index 689dce98859e152..5fa5c331d398e8c 100644 --- a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_certs.test.ts +++ b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_certs.test.ts @@ -180,7 +180,7 @@ describe('getCerts', () => { }, Object { "range": Object { - "@timestamp": Object { + "monitor.timespan": Object { "gte": "now-2d", "lte": "now+1h", }, diff --git a/x-pack/plugins/uptime/server/lib/requests/get_certs.ts b/x-pack/plugins/uptime/server/lib/requests/get_certs.ts index 57a59936ddf7c6b..4793d420cbfd838 100644 --- a/x-pack/plugins/uptime/server/lib/requests/get_certs.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_certs.ts @@ -51,7 +51,7 @@ export const getCerts: UMElasticsearchQueryFn = asyn }, { range: { - '@timestamp': { + 'monitor.timespan': { gte: from, lte: to, }, diff --git a/x-pack/plugins/uptime/server/rest_api/certs/certs.ts b/x-pack/plugins/uptime/server/rest_api/certs/certs.ts index a5ca6e264d299f8..fb22d603a2d56e0 100644 --- a/x-pack/plugins/uptime/server/rest_api/certs/certs.ts +++ b/x-pack/plugins/uptime/server/rest_api/certs/certs.ts @@ -9,10 +9,10 @@ import { API_URLS } from '../../../common/constants'; import { UMServerLibs } from '../../lib/lib'; import { UMRestApiRouteFactory } from '../types'; -const DEFAULT_INDEX = 0; +export const DEFAULT_FROM = 'now-5m'; +export const DEFAULT_TO = 'now'; + const DEFAULT_SIZE = 25; -const DEFAULT_FROM = 'now-1d'; -const DEFAULT_TO = 'now'; const DEFAULT_SORT = 'not_after'; const DEFAULT_DIRECTION = 'asc'; @@ -31,7 +31,7 @@ export const createGetCertsRoute: UMRestApiRouteFactory = (libs: UMServerLibs) = }), }, handler: async ({ callES, dynamicSettings }, _context, request, response): Promise => { - const index = request.query?.index ?? DEFAULT_INDEX; + const index = request.query?.index ?? 0; const size = request.query?.size ?? DEFAULT_SIZE; const from = request.query?.from ?? DEFAULT_FROM; const to = request.query?.to ?? DEFAULT_TO; diff --git a/x-pack/test/api_integration/apis/uptime/rest/helper/make_ping.ts b/x-pack/test/api_integration/apis/uptime/rest/helper/make_ping.ts index 908c571e07e0671..f9bea050293fc3b 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/helper/make_ping.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/helper/make_ping.ts @@ -18,6 +18,7 @@ export const makePing = async ( refresh: boolean = true, tls: boolean | TlsProps = false ) => { + const timestamp = new Date(); const baseDoc: any = { tcp: { rtt: { @@ -40,7 +41,7 @@ export const makePing = async ( ephemeral_id: '0d9a8dc6-f604-49e3-86a0-d8f9d6f2cbad', version: '8.0.0', }, - '@timestamp': new Date().toISOString(), + '@timestamp': timestamp.toISOString(), resolve: { rtt: { us: 350, @@ -88,6 +89,10 @@ export const makePing = async ( check_group: uuid.v4(), type: 'http', status: 'up', + timespan: { + gte: timestamp.toISOString(), + lt: new Date(timestamp.getTime() + 5000).toISOString, + }, }, event: { dataset: 'uptime', diff --git a/x-pack/test/api_integration/apis/uptime/rest/helper/make_tls.ts b/x-pack/test/api_integration/apis/uptime/rest/helper/make_tls.ts index 360646252202451..477c9857ca36375 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/helper/make_tls.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/helper/make_tls.ts @@ -39,7 +39,7 @@ export const makeTls = ({ valid = true, commonName = '*.elastic.co', expiry, sha server: { x509: { not_before: '2020-03-01T00:00:00.000Z', - not_after: '2020-05-30T12:00:00.000Z', + not_after: expiryDate, issuer: { distinguished_name: 'CN=DigiCert SHA2 High Assurance Server CA,OU=www.digicert.com,O=DigiCert Inc,C=US', diff --git a/x-pack/test/functional/apps/uptime/certificates.ts b/x-pack/test/functional/apps/uptime/certificates.ts index 93a8a852294b23a..4a10955637844ac 100644 --- a/x-pack/test/functional/apps/uptime/certificates.ts +++ b/x-pack/test/functional/apps/uptime/certificates.ts @@ -14,13 +14,9 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const es = getService('es'); - // FLAKY: https://github.com/elastic/kibana/issues/65010 - describe.skip('certificate page', function() { - before(async () => { - await uptime.goToRoot(true); - }); - + describe('certificates', function() { beforeEach(async () => { + await uptime.goToRoot(true); await makeCheck({ es, tls: true }); await uptimeService.navigation.refreshApp(); }); @@ -30,33 +26,39 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await uptimeService.navigation.goToCertificates(); }); - it('displays certificates', async () => { - await uptimeService.cert.hasCertificates(); - }); + describe('page', () => { + beforeEach(async () => { + await uptimeService.navigation.goToCertificates(); + }); - it('displays specific certificates', async () => { - const certId = getSha256(); - const { monitorId } = await makeCheck({ - es, - tls: { - sha256: certId, - }, + it('displays certificates', async () => { + await uptimeService.cert.hasCertificates(); }); - await uptimeService.navigation.refreshApp(); - await uptimeService.cert.certificateExists({ certId, monitorId }); - }); + it('displays specific certificates', async () => { + const certId = getSha256(); + const { monitorId } = await makeCheck({ + es, + tls: { + sha256: certId, + }, + }); - it('performs search against monitor id', async () => { - const certId = getSha256(); - const { monitorId } = await makeCheck({ - es, - tls: { - sha256: certId, - }, + await uptimeService.navigation.refreshApp(); + await uptimeService.cert.certificateExists({ certId, monitorId }); + }); + + it('performs search against monitor id', async () => { + const certId = getSha256(); + const { monitorId } = await makeCheck({ + es, + tls: { + sha256: certId, + }, + }); + await uptimeService.navigation.refreshApp(); + await uptimeService.cert.searchIsWorking(monitorId); }); - await uptimeService.navigation.refreshApp(); - await uptimeService.cert.searchIsWorking(monitorId); }); }); }; From 02a2d075afce96e5ee0b3ddfba3fb0bca3cdff36 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Thu, 14 May 2020 17:46:33 +0200 Subject: [PATCH 7/9] [Discover] Catch error when popularizeField fails (#62402) * Refactor index_patterns popularize function, so no message is displayed to the user --- .../index_patterns/index_pattern.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/plugins/data/public/index_patterns/index_patterns/index_pattern.ts b/src/plugins/data/public/index_patterns/index_patterns/index_pattern.ts index 98ec4495cef29ac..f3297f21c572a5a 100644 --- a/src/plugins/data/public/index_patterns/index_patterns/index_pattern.ts +++ b/src/plugins/data/public/index_patterns/index_patterns/index_pattern.ts @@ -299,6 +299,13 @@ export class IndexPattern implements IIndexPattern { } async popularizeField(fieldName: string, unit = 1) { + /** + * This function is just used by Discover and it's high likely to be removed in the near future + * It doesn't use the save function to skip the error message that's displayed when + * a user adds several columns in a higher frequency that the changes can be persisted to ES + * resulting in 409 errors + */ + if (!this.id) return; const field = this.fields.getByName(fieldName); if (!field) { return; @@ -308,7 +315,15 @@ export class IndexPattern implements IIndexPattern { return; } field.count = count; - await this.save(); + + try { + const res = await this.savedObjectsClient.update(type, this.id, this.prepBody(), { + version: this.version, + }); + this.version = res._version; + } catch (e) { + // no need for an error message here + } } getNonScriptedFields() { From 28623ad33a1749f71a8e6f9a65c156513a2e2d4f Mon Sep 17 00:00:00 2001 From: Devon Thomson Date: Thu, 14 May 2020 12:29:03 -0400 Subject: [PATCH 8/9] [Lens] fix redirect after reload (#66328) Changed the way the lens app tracks originatingApp. It is now removed from the url when the app starts and is tracked as part of the state --- .../lens/public/app_plugin/app.test.tsx | 43 +++++++++++++++---- x-pack/plugins/lens/public/app_plugin/app.tsx | 23 ++++++---- .../lens/public/app_plugin/mounter.tsx | 17 ++++---- 3 files changed, 58 insertions(+), 25 deletions(-) diff --git a/x-pack/plugins/lens/public/app_plugin/app.test.tsx b/x-pack/plugins/lens/public/app_plugin/app.test.tsx index 7dc39225f780f6c..0608c978ad0dc2d 100644 --- a/x-pack/plugins/lens/public/app_plugin/app.test.tsx +++ b/x-pack/plugins/lens/public/app_plugin/app.test.tsx @@ -104,7 +104,12 @@ describe('Lens App', () => { storage: Storage; docId?: string; docStorage: SavedObjectStore; - redirectTo: (id?: string, returnToOrigin?: boolean, newlyCreated?: boolean) => void; + redirectTo: ( + id?: string, + returnToOrigin?: boolean, + originatingApp?: string | undefined, + newlyCreated?: boolean + ) => void; originatingApp: string | undefined; }> { return ({ @@ -140,7 +145,14 @@ describe('Lens App', () => { load: jest.fn(), save: jest.fn(), }, - redirectTo: jest.fn((id?: string, returnToOrigin?: boolean, newlyCreated?: boolean) => {}), + redirectTo: jest.fn( + ( + id?: string, + returnToOrigin?: boolean, + originatingApp?: string | undefined, + newlyCreated?: boolean + ) => {} + ), } as unknown) as jest.Mocked<{ navigation: typeof navigationStartMock; editorFrame: EditorFrameInstance; @@ -149,7 +161,12 @@ describe('Lens App', () => { storage: Storage; docId?: string; docStorage: SavedObjectStore; - redirectTo: (id?: string, returnToOrigin?: boolean, newlyCreated?: boolean) => void; + redirectTo: ( + id?: string, + returnToOrigin?: boolean, + originatingApp?: string | undefined, + newlyCreated?: boolean + ) => void; originatingApp: string | undefined; }>; } @@ -348,7 +365,12 @@ describe('Lens App', () => { storage: Storage; docId?: string; docStorage: SavedObjectStore; - redirectTo: (id?: string, returnToOrigin?: boolean, newlyCreated?: boolean) => void; + redirectTo: ( + id?: string, + returnToOrigin?: boolean, + originatingApp?: string | undefined, + newlyCreated?: boolean + ) => void; originatingApp: string | undefined; }>; @@ -521,7 +543,7 @@ describe('Lens App', () => { expression: 'kibana 3', }); - expect(args.redirectTo).toHaveBeenCalledWith('aaa', undefined, true); + expect(args.redirectTo).toHaveBeenCalledWith('aaa', undefined, undefined, true); inst.setProps({ docId: 'aaa' }); @@ -541,7 +563,7 @@ describe('Lens App', () => { expression: 'kibana 3', }); - expect(args.redirectTo).toHaveBeenCalledWith('aaa', undefined, true); + expect(args.redirectTo).toHaveBeenCalledWith('aaa', undefined, undefined, true); inst.setProps({ docId: 'aaa' }); @@ -609,7 +631,7 @@ describe('Lens App', () => { title: 'hello there', }); - expect(args.redirectTo).toHaveBeenCalledWith('aaa', true, true); + expect(args.redirectTo).toHaveBeenCalledWith('aaa', true, undefined, true); }); it('saves app filters and does not save pinned filters', async () => { @@ -677,7 +699,12 @@ describe('Lens App', () => { storage: Storage; docId?: string; docStorage: SavedObjectStore; - redirectTo: (id?: string, returnToOrigin?: boolean, newlyCreated?: boolean) => void; + redirectTo: ( + id?: string, + returnToOrigin?: boolean, + originatingApp?: string | undefined, + newlyCreated?: boolean + ) => void; }>; beforeEach(() => { diff --git a/x-pack/plugins/lens/public/app_plugin/app.tsx b/x-pack/plugins/lens/public/app_plugin/app.tsx index 9d0df16c68555d3..718f49413a0821b 100644 --- a/x-pack/plugins/lens/public/app_plugin/app.tsx +++ b/x-pack/plugins/lens/public/app_plugin/app.tsx @@ -33,6 +33,7 @@ interface State { isLoading: boolean; isSaveModalVisible: boolean; indexPatternsForTopNav: IndexPatternInstance[]; + originatingApp: string | undefined; persistedDoc?: Document; lastKnownDoc?: Document; @@ -54,7 +55,7 @@ export function App({ docId, docStorage, redirectTo, - originatingApp, + originatingAppFromUrl, navigation, }: { editorFrame: EditorFrameInstance; @@ -64,8 +65,13 @@ export function App({ storage: IStorageWrapper; docId?: string; docStorage: SavedObjectStore; - redirectTo: (id?: string, returnToOrigin?: boolean, newlyCreated?: boolean) => void; - originatingApp?: string | undefined; + redirectTo: ( + id?: string, + returnToOrigin?: boolean, + originatingApp?: string | undefined, + newlyCreated?: boolean + ) => void; + originatingAppFromUrl?: string | undefined; }) { const language = storage.get('kibana.userQueryLanguage') || core.uiSettings.get('search:queryLanguage'); @@ -77,6 +83,7 @@ export function App({ isSaveModalVisible: false, indexPatternsForTopNav: [], query: { query: '', language }, + originatingApp: originatingAppFromUrl, dateRange: { fromDate: currentRange.from, toDate: currentRange.to, @@ -229,7 +236,7 @@ export function App({ lastKnownDoc: newDoc, })); if (docId !== id || saveProps.returnToOrigin) { - redirectTo(id, saveProps.returnToOrigin, newlyCreated); + redirectTo(id, saveProps.returnToOrigin, state.originatingApp, newlyCreated); } }) .catch(e => { @@ -269,7 +276,7 @@ export function App({
{ if (isSaveable && lastKnownDoc) { setState(s => ({ ...s, isSaveModalVisible: true })); @@ -422,7 +429,7 @@ export function App({
{lastKnownDoc && state.isSaveModalVisible && ( runSave(props)} onClose={() => setState(s => ({ ...s, isSaveModalVisible: false }))} documentInfo={{ diff --git a/x-pack/plugins/lens/public/app_plugin/mounter.tsx b/x-pack/plugins/lens/public/app_plugin/mounter.tsx index b49e6cf5ba7b98d..7c875935f6320e3 100644 --- a/x-pack/plugins/lens/public/app_plugin/mounter.tsx +++ b/x-pack/plugins/lens/public/app_plugin/mounter.tsx @@ -47,15 +47,11 @@ export async function mountApp( ); const redirectTo = ( routeProps: RouteComponentProps<{ id?: string }>, - originatingApp: string, id?: string, returnToOrigin?: boolean, + originatingApp?: string, newlyCreated?: boolean ) => { - if (!!originatingApp && !returnToOrigin) { - removeQueryParam(routeProps.history, 'embeddableOriginatingApp'); - } - if (!id) { routeProps.history.push('/'); } else if (!originatingApp) { @@ -78,7 +74,10 @@ export async function mountApp( const renderEditor = (routeProps: RouteComponentProps<{ id?: string }>) => { trackUiEvent('loaded'); const urlParams = parse(routeProps.location.search) as Record; - const originatingApp = urlParams.embeddableOriginatingApp; + const originatingAppFromUrl = urlParams.embeddableOriginatingApp; + if (urlParams.embeddableOriginatingApp) { + removeQueryParam(routeProps.history, 'embeddableOriginatingApp'); + } return ( - redirectTo(routeProps, originatingApp, id, returnToOrigin, newlyCreated) + redirectTo={(id, returnToOrigin, originatingApp, newlyCreated) => + redirectTo(routeProps, id, returnToOrigin, originatingApp, newlyCreated) } - originatingApp={originatingApp} + originatingAppFromUrl={originatingAppFromUrl} /> ); }; From bf796b295b45ee6bbba6104c4962d1b6be25866a Mon Sep 17 00:00:00 2001 From: spalger Date: Thu, 14 May 2020 11:22:53 -0700 Subject: [PATCH 9/9] skip flaky suite (#43150) --- test/functional/apps/visualize/_tsvb_chart.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/functional/apps/visualize/_tsvb_chart.ts b/test/functional/apps/visualize/_tsvb_chart.ts index 333aa93b7776daa..e9cf8235ff3f4cf 100644 --- a/test/functional/apps/visualize/_tsvb_chart.ts +++ b/test/functional/apps/visualize/_tsvb_chart.ts @@ -28,7 +28,8 @@ export default function({ getService, getPageObjects }: FtrProviderContext) { const security = getService('security'); const PageObjects = getPageObjects(['visualize', 'visualBuilder', 'timePicker', 'visChart']); - describe('visual builder', function describeIndexTests() { + // FLAKY: https://github.com/elastic/kibana/issues/43150 + describe.skip('visual builder', function describeIndexTests() { this.tags('includeFirefox'); beforeEach(async () => { await security.testUser.setRoles(['kibana_admin', 'test_logstash_reader']);