Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[APM] Run API tests as restricted user #70050

Merged
merged 6 commits into from
Jun 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions x-pack/plugins/apm/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,38 @@ For debugging access Elasticsearch on http://localhost:9220` (elastic/changeme)

### API integration tests

Our tests are separated in two suites: one suite runs with a basic license, and the other
with a trial license (the equivalent of gold+). This requires separate test servers and test runs.

**Start server**

Basic:

```
node scripts/functional_tests_server --config x-pack/test/apm_api_integration/basic/config.ts
```

Trial:

```
node scripts/functional_tests_server --config x-pack/test/api_integration/config.ts
node scripts/functional_tests_server --config x-pack/test/apm_api_integration/trial/config.ts
```

**Run tests**

Basic:

```
node scripts/functional_test_runner --config x-pack/test/apm_api_integration/basic/config.ts
```

Trial:

```
node scripts/functional_test_runner --config x-pack/test/api_integration/config.ts --grep='APM specs'
node scripts/functional_test_runner --config x-pack/test/apm_api_integration/trial/config.ts
```

APM tests are located in `x-pack/test/api_integration/apis/apm`.
APM tests are located in `x-pack/test/apm_api_integration`.
For debugging access Elasticsearch on http://localhost:9220` (elastic/changeme)

### Linting
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,20 @@ 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 supertestRead = getService('supertestAsApmReadUser');
const supertestWrite = getService('supertestAsApmWriteUser');
const log = getService('log');

function searchConfigurations(configuration: any) {
return supertest
return supertestRead
.post(`/api/apm/settings/agent-configuration/search`)
.send(configuration)
.set('kbn-xsrf', 'foo');
}

async function createConfiguration(config: AgentConfigurationIntake) {
log.debug('creating configuration', config.service);
const res = await supertest
const res = await supertestWrite
.put(`/api/apm/settings/agent-configuration`)
.send(config)
.set('kbn-xsrf', 'foo');
Expand All @@ -34,7 +35,7 @@ export default function agentConfigurationTests({ getService }: FtrProviderConte

async function updateConfiguration(config: AgentConfigurationIntake) {
log.debug('updating configuration', config.service);
const res = await supertest
const res = await supertestWrite
.put(`/api/apm/settings/agent-configuration?overwrite=true`)
.send(config)
.set('kbn-xsrf', 'foo');
Expand All @@ -46,7 +47,7 @@ export default function agentConfigurationTests({ getService }: FtrProviderConte

async function deleteConfiguration({ service }: AgentConfigurationIntake) {
log.debug('deleting configuration', service);
const res = await supertest
const res = await supertestWrite
.delete(`/api/apm/settings/agent-configuration`)
.send({ service })
.set('kbn-xsrf', 'foo');
Expand Down
6 changes: 3 additions & 3 deletions x-pack/test/apm_api_integration/basic/tests/annotations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ 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');
const supertestWrite = getService('supertestAsApmAnnotationsWriteUser');

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');
return supertestWrite.post(url).send(data).set('kbn-xsrf', 'foo');

default:
throw new Error(`Unsupported methoed ${method}`);
throw new Error(`Unsupported method ${method}`);
}
}

Expand Down
11 changes: 6 additions & 5 deletions x-pack/test/apm_api_integration/basic/tests/custom_link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,21 @@ 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 supertestRead = getService('supertestAsApmReadUser');
const supertestWrite = getService('supertestAsApmWriteUser');
const log = getService('log');

function searchCustomLinks(filters?: any) {
const path = URL.format({
pathname: `/api/apm/settings/custom_links`,
query: filters,
});
return supertest.get(path).set('kbn-xsrf', 'foo');
return supertestRead.get(path).set('kbn-xsrf', 'foo');
}

async function createCustomLink(customLink: CustomLink) {
log.debug('creating configuration', customLink);
const res = await supertest
const res = await supertestWrite
.post(`/api/apm/settings/custom_links`)
.send(customLink)
.set('kbn-xsrf', 'foo');
Expand All @@ -35,7 +36,7 @@ export default function customLinksTests({ getService }: FtrProviderContext) {

async function updateCustomLink(id: string, customLink: CustomLink) {
log.debug('updating configuration', id, customLink);
const res = await supertest
const res = await supertestWrite
.put(`/api/apm/settings/custom_links/${id}`)
.send(customLink)
.set('kbn-xsrf', 'foo');
Expand All @@ -47,7 +48,7 @@ export default function customLinksTests({ getService }: FtrProviderContext) {

async function deleteCustomLink(id: string) {
log.debug('deleting configuration', id);
const res = await supertest
const res = await supertestWrite
.delete(`/api/apm/settings/custom_links/${id}`)
.set('kbn-xsrf', 'foo');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ 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 supertest = getService('supertestAsApmWriteUser');
const supertestWithoutAuth = getService('supertestWithoutAuth');
const security = getService('security');
const spaces = getService('spaces');
Expand Down
102 changes: 102 additions & 0 deletions x-pack/test/apm_api_integration/common/authentication.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { PromiseReturnType } from '../../../plugins/apm/typings/common';
import { SecurityServiceProvider } from '../../../../test/common/services/security';

type SecurityService = PromiseReturnType<typeof SecurityServiceProvider>;

export enum ApmUser {
apmReadUser = 'apm_read_user',
apmWriteUser = 'apm_write_user',
apmAnnotationsWriteUser = 'apm_annotations_write_user',
}

const roles = {
[ApmUser.apmReadUser]: {
elasticsearch: {
cluster: [],
indices: [
{ names: ['observability-annotations'], privileges: ['read', 'view_index_metadata'] },
],
},
kibana: [
{
base: [],
feature: {
apm: ['read'],
},
spaces: ['*'],
},
],
},
[ApmUser.apmWriteUser]: {
elasticsearch: {
cluster: [],
indices: [
{ names: ['observability-annotations'], privileges: ['read', 'view_index_metadata'] },
],
},
kibana: [
{
base: [],
feature: {
apm: ['all'],
},
spaces: ['*'],
},
],
},
[ApmUser.apmAnnotationsWriteUser]: {
elasticsearch: {
cluster: [],
indices: [
{
names: ['observability-annotations'],
privileges: [
'read',
'view_index_metadata',
'index',
'manage',
'create_index',
'create_doc',
],
},
],
},
},
};

const users = {
[ApmUser.apmReadUser]: {
roles: ['apm_user', ApmUser.apmReadUser],
},
[ApmUser.apmWriteUser]: {
roles: ['apm_user', ApmUser.apmWriteUser],
},
[ApmUser.apmAnnotationsWriteUser]: {
roles: ['apm_user', ApmUser.apmWriteUser, ApmUser.apmAnnotationsWriteUser],
},
};

export async function createApmUser(security: SecurityService, apmUser: ApmUser) {
const role = roles[apmUser];
const user = users[apmUser];

if (!role || !user) {
throw new Error(`No configuration found for ${apmUser}`);
}

await security.role.create(apmUser, role);

await security.user.create(apmUser, {
full_name: apmUser,
password: APM_TEST_PASSWORD,
roles: user.roles,
});
}

export const APM_TEST_PASSWORD = 'changeme';
42 changes: 39 additions & 3 deletions x-pack/test/apm_api_integration/common/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,34 @@
*/

import { FtrConfigProviderContext } from '@kbn/test/types/ftr';
import supertestAsPromised from 'supertest-as-promised';
import { format, UrlObject } from 'url';
import { InheritedFtrProviderContext, InheritedServices } from './ftr_provider_context';
import { PromiseReturnType } from '../../../plugins/apm/typings/common';
import { createApmUser, APM_TEST_PASSWORD, ApmUser } from './authentication';

interface Settings {
license: 'basic' | 'trial';
testFiles: string[];
name: string;
}

const supertestAsApmUser = (kibanaServer: UrlObject, apmUser: ApmUser) => async (
context: InheritedFtrProviderContext
) => {
const security = context.getService('security');
await security.init();

await createApmUser(security, apmUser);

const url = format({
...kibanaServer,
auth: `${apmUser}:${APM_TEST_PASSWORD}`,
});

return supertestAsPromised(url);
};

export function createTestConfig(settings: Settings) {
const { testFiles, license, name } = settings;

Expand All @@ -20,14 +41,27 @@ export function createTestConfig(settings: Settings) {
require.resolve('../../api_integration/config.ts')
);

const services = xPackAPITestsConfig.get('services') as InheritedServices;
const servers = xPackAPITestsConfig.get('servers');

const supertestAsApmReadUser = supertestAsApmUser(servers.kibana, ApmUser.apmReadUser);

return {
testFiles,
servers: xPackAPITestsConfig.get('servers'),
services: xPackAPITestsConfig.get('services'),
servers,
services: {
...services,
supertest: supertestAsApmReadUser,
supertestAsApmReadUser,
supertestAsApmWriteUser: supertestAsApmUser(servers.kibana, ApmUser.apmWriteUser),
supertestAsApmAnnotationsWriteUser: supertestAsApmUser(
servers.kibana,
ApmUser.apmAnnotationsWriteUser
),
},
junit: {
reportName: name,
},

esTestCluster: {
...xPackAPITestsConfig.get('esTestCluster'),
license,
Expand All @@ -36,3 +70,5 @@ export function createTestConfig(settings: Settings) {
};
};
}

export type ApmServices = PromiseReturnType<ReturnType<typeof createTestConfig>>['services'];
14 changes: 13 additions & 1 deletion x-pack/test/apm_api_integration/common/ftr_provider_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,16 @@
* you may not use this file except in compliance with the Elastic License.
*/

export { FtrProviderContext } from '../../api_integration/ftr_provider_context';
import { GenericFtrProviderContext } from '@kbn/test/types/ftr';
import { FtrProviderContext as InheritedFtrProviderContext } from '../../api_integration/ftr_provider_context';
import { ApmServices } from './config';

export type InheritedServices = InheritedFtrProviderContext extends GenericFtrProviderContext<
infer TServices,
{}
>
? TServices
: {};

export { InheritedFtrProviderContext };
export type FtrProviderContext = GenericFtrProviderContext<ApmServices, {}>;
9 changes: 5 additions & 4 deletions x-pack/test/apm_api_integration/trial/tests/annotations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ 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 supertestRead = getService('supertestAsApmReadUser');
const supertestWrite = getService('supertestAsApmAnnotationsWriteUser');
const es = getService('es');

function expectContainsObj(source: JsonObject, expected: JsonObject) {
Expand All @@ -30,13 +31,13 @@ export default function annotationApiTests({ getService }: FtrProviderContext) {
function request({ method, url, data }: { method: string; url: string; data?: JsonObject }) {
switch (method.toLowerCase()) {
case 'get':
return supertest.get(url).set('kbn-xsrf', 'foo');
return supertestRead.get(url).set('kbn-xsrf', 'foo');

case 'post':
return supertest.post(url).send(data).set('kbn-xsrf', 'foo');
return supertestWrite.post(url).send(data).set('kbn-xsrf', 'foo');

default:
throw new Error(`Unsupported methoed ${method}`);
throw new Error(`Unsupported method ${method}`);
}
}

Expand Down