From 31c680a6c5857161ff1ec9074458dc732412826c Mon Sep 17 00:00:00 2001 From: Dario Gieselaar Date: Tue, 19 May 2020 14:55:45 +0200 Subject: [PATCH] [7.x] [APM] Add license guard for annotations (#65995) (#66623) --- 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 474ab1c6082a44..782f8957cf188b 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 8e2cfe980039ce..712a46f76bb747 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 58639ef084ce65..6ea9f82d11ab91 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 3f2604468e17c5..71b1a42b2000d9 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 3c29822acd6dd0..21ebfcd6205e72 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 7047f9f4c56da0..efc28404e69903 100644 --- a/x-pack/scripts/functional_tests.js +++ b/x-pack/scripts/functional_tests.js @@ -17,6 +17,8 @@ require('@kbn/test').runTestsCli([ 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'), @@ -27,6 +29,8 @@ require('@kbn/test').runTestsCli([ require.resolve('../test/token_api_integration/config'), require.resolve('../test/oidc_api_integration/config'), require.resolve('../test/oidc_api_integration/implicit_flow.config'), + 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'), require.resolve('../test/login_selector_api_integration/config'), require.resolve('../test/encrypted_saved_objects_api_integration/config'), diff --git a/x-pack/test/api_integration/apis/index.js b/x-pack/test/api_integration/apis/index.js index 75fa90bb4c3fe8..321fbce52a75a5 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 00000000000000..541fe9ec023bcf --- /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 8af648e062cf44..04974d57074a56 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 00000000000000..a939ef06273569 --- /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 8aefadd8117753..910c4797f39b76 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 5f61c963a69aa0..f3647c65106c92 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 de076e8c46729e..f3c1a3c3f63d56 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 00000000000000..9e011a98bbfcd4 --- /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 00000000000000..90600816d17114 --- /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 00000000000000..ca5b11d469c470 --- /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 4746a7713f34b3..9beea6a53dd4d4 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 00000000000000..3a4571afb3d4a7 --- /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 00000000000000..0e8bf1daaf9e61 --- /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 00000000000000..cd86c8a0f2cda7 --- /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 00000000000000..a4c04a9229fa94 --- /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 00000000000000..9e011a98bbfcd4 --- /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 00000000000000..90600816d17114 --- /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 00000000000000..c073e2e6af7fed --- /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 93bc4c44ba40a0..e742dec3dd72c7 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 00000000000000..d1acf4d98f7f97 --- /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')); + }); +}