Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
36fef75
inital effort to move to JWT and added jest based tests on libs
mattapperson Jun 27, 2018
aac4632
assign beats tests all passing
mattapperson Jun 27, 2018
9acb876
token tests now pass
mattapperson Jun 27, 2018
dd634b9
add more tests
mattapperson Jun 28, 2018
de2c4cc
all tests now green
mattapperson Jun 30, 2018
7c3c53a
move enrollment token back to a hash
mattapperson Jul 2, 2018
480fae5
remove un-needed comment
mattapperson Jul 2, 2018
03544e3
alias lodash get to avoid confusion
mattapperson Jul 2, 2018
3a7bdac
isolated hash creation
mattapperson Jul 2, 2018
5575ab5
Add initial efforts for backend framework adapter testing
mattapperson Jul 3, 2018
f17046e
move ES code to a DatabaseAdapter from BackendAdapter and add a TON o…
mattapperson Jul 6, 2018
d328dd3
re-typed
mattapperson Jul 9, 2018
d169319
renamed types to match pattern
mattapperson Jul 9, 2018
e430b44
aditional renames
mattapperson Jul 9, 2018
6334d76
adapter tests should always just use adapterSetup();
mattapperson Jul 11, 2018
95e5764
database now uses InternalRequest
mattapperson Jul 11, 2018
06568ca
corrected spelling of framework
mattapperson Jul 11, 2018
b7dc1e7
fix typings
mattapperson Jul 11, 2018
0b42c23
remove CRUFT
mattapperson Jul 11, 2018
69a2439
RequestOrInternal
mattapperson Jul 11, 2018
cfbc1a1
Dont pass around request objects everywhere, just pass the user. Also…
mattapperson Jul 11, 2018
8533c1b
fix tests, add test, removed extra comment
mattapperson Jul 12, 2018
ab88e51
fix auth
mattapperson Jul 12, 2018
ea26917
updated lock file
mattapperson Jul 12, 2018
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
31 changes: 31 additions & 0 deletions x-pack/plugins/beats/common/domain_types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* 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 { ConfigurationBlockTypes } from './constants';

export interface ConfigurationBlock {
type: ConfigurationBlockTypes;
block_yml: string;
}

export interface CMBeat {
id: string;
access_token: string;
verified_on?: string;
type: string;
version?: string;
host_ip: string;
host_name: string;
ephemeral_id?: string;
local_configuration_yml?: string;
tags?: string[];
central_configuration_yml?: string;
metadata?: {};
}

export interface BeatTag {
id: string;
configuration_blocks: ConfigurationBlock[];
}
22 changes: 12 additions & 10 deletions x-pack/plugins/beats/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,20 @@ import { initServerWithKibana } from './server/kibana.index';

const DEFAULT_ENROLLMENT_TOKENS_TTL_S = 10 * 60; // 10 minutes

export const config = Joi.object({
enabled: Joi.boolean().default(true),
encryptionKey: Joi.string(),
enrollmentTokensTtlInSeconds: Joi.number()
.integer()
.min(1)
.default(DEFAULT_ENROLLMENT_TOKENS_TTL_S),
}).default();
export const configPrefix = 'xpack.beats';

export function beats(kibana: any) {
return new kibana.Plugin({
config: () =>
Joi.object({
enabled: Joi.boolean().default(true),
encryptionKey: Joi.string(),
enrollmentTokensTtlInSeconds: Joi.number()
.integer()
.min(1)
.default(DEFAULT_ENROLLMENT_TOKENS_TTL_S),
}).default(),
configPrefix: 'xpack.beats',
config: () => config,
configPrefix,
id: PLUGIN.ID,
require: ['kibana', 'elasticsearch', 'xpack_main'],
init(server: any) {
Expand Down
10 changes: 9 additions & 1 deletion x-pack/plugins/beats/readme.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
# Documentation for Beats CM in x-pack kibana

### Run tests
### Run tests (from x-pack dir)

Functional tests

```
node scripts/jest.js plugins/beats --watch
```

Functional API tests

```
node scripts/functional_tests --config test/api_integration/config
```
45 changes: 45 additions & 0 deletions x-pack/plugins/beats/server/lib/adapters/beats/adapter_types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { CMBeat } from '../../../../common/domain_types';
import { FrameworkRequest } from '../famework/adapter_types';

// FIXME: fix getBeatsWithIds return type
export interface CMBeatsAdapter {
insert(beat: CMBeat): Promise<void>;
update(beat: CMBeat): Promise<void>;
get(id: string): any;
getAll(req: FrameworkRequest): any;
getWithIds(req: FrameworkRequest, beatIds: string[]): any;
verifyBeats(req: FrameworkRequest, beatIds: string[]): any;
removeTagsFromBeats(
req: FrameworkRequest,
removals: BeatsTagAssignment[]
): Promise<BeatsTagAssignment[]>;
assignTagsToBeats(
req: FrameworkRequest,
assignments: BeatsTagAssignment[]
): Promise<BeatsTagAssignment[]>;
}

export interface BeatsTagAssignment {
beatId: string;
tag: string;
idxInRequest?: number;
}

interface BeatsReturnedTagAssignment {
status: number | null;
result?: string;
}

export interface CMAssignmentReturn {
assignments: BeatsReturnedTagAssignment[];
}

export interface BeatsRemovalReturn {
removals: BeatsReturnedTagAssignment[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,16 @@
import { flatten, get as _get, omit } from 'lodash';
import moment from 'moment';
import { INDEX_NAMES } from '../../../../common/constants';
import {
BackendFrameworkAdapter,
CMBeat,
CMBeatsAdapter,
CMTagAssignment,
FrameworkRequest,
} from '../../lib';
import { CMBeat } from '../../../../common/domain_types';
import { DatabaseAdapter } from '../database/adapter_types';
import { FrameworkRequest } from '../famework/adapter_types';
import { BeatsTagAssignment, CMBeatsAdapter } from './adapter_types';

export class ElasticsearchBeatsAdapter implements CMBeatsAdapter {
private framework: BackendFrameworkAdapter;
private database: DatabaseAdapter;

constructor(framework: BackendFrameworkAdapter) {
this.framework = framework;
constructor(database: DatabaseAdapter) {
this.database = database;
}

public async get(id: string) {
Expand All @@ -30,7 +27,7 @@ export class ElasticsearchBeatsAdapter implements CMBeatsAdapter {
type: '_doc',
};

const response = await this.framework.callWithInternalUser('get', params);
const response = await this.database.get(null, params);
if (!response.found) {
return null;
}
Expand All @@ -44,14 +41,13 @@ export class ElasticsearchBeatsAdapter implements CMBeatsAdapter {
type: 'beat',
};

const params = {
await this.database.create(null, {
body,
id: `beat:${beat.id}`,
index: INDEX_NAMES.BEATS,
refresh: 'wait_for',
type: '_doc',
};
await this.framework.callWithInternalUser('create', params);
});
}

public async update(beat: CMBeat) {
Expand All @@ -67,7 +63,7 @@ export class ElasticsearchBeatsAdapter implements CMBeatsAdapter {
refresh: 'wait_for',
type: '_doc',
};
return await this.framework.callWithInternalUser('index', params);
await this.database.index(null, params);
}

public async getWithIds(req: FrameworkRequest, beatIds: string[]) {
Expand All @@ -81,9 +77,9 @@ export class ElasticsearchBeatsAdapter implements CMBeatsAdapter {
index: INDEX_NAMES.BEATS,
type: '_doc',
};
const response = await this.framework.callWithRequest(req, 'mget', params);
const response = await this.database.mget(req, params);

return get(response, 'docs', [])
return _get(response, 'docs', [])
.filter((b: any) => b.found)
.map((b: any) => b._source.beat);
}
Expand All @@ -101,15 +97,13 @@ export class ElasticsearchBeatsAdapter implements CMBeatsAdapter {
])
);

const params = {
const response = await this.database.bulk(req, {
_sourceInclude: ['beat.id', 'beat.verified_on'],
body,
index: INDEX_NAMES.BEATS,
refresh: 'wait_for',
type: '_doc',
};

const response = await this.framework.callWithRequest(req, 'bulk', params);
});

return _get(response, 'items', []).map(b => ({
..._get(b, 'update.get._source.beat', {}),
Expand All @@ -123,20 +117,16 @@ export class ElasticsearchBeatsAdapter implements CMBeatsAdapter {
q: 'type:beat',
type: '_doc',
};
const response = await this.framework.callWithRequest(
req,
'search',
params
);
const response = await this.database.search(req, params);

const beats = get<any>(response, 'hits.hits', []);
const beats = _get<any>(response, 'hits.hits', []);
return beats.map((beat: any) => omit(beat._source.beat, ['access_token']));
}

public async removeTagsFromBeats(
req: FrameworkRequest,
removals: CMTagAssignment[]
): Promise<CMTagAssignment[]> {
removals: BeatsTagAssignment[]
): Promise<BeatsTagAssignment[]> {
const body = flatten(
removals.map(({ beatId, tag }) => {
const script =
Expand All @@ -153,15 +143,13 @@ export class ElasticsearchBeatsAdapter implements CMBeatsAdapter {
})
);

const params = {
const response = await this.database.bulk(req, {
body,
index: INDEX_NAMES.BEATS,
refresh: 'wait_for',
type: '_doc',
};

const response = await this.framework.callWithRequest(req, 'bulk', params);
return get<any>(response, 'items', []).map(
});
return _get<any>(response, 'items', []).map(
(item: any, resultIdx: number) => ({
idxInRequest: removals[resultIdx].idxInRequest,
result: item.update.result,
Expand All @@ -172,8 +160,8 @@ export class ElasticsearchBeatsAdapter implements CMBeatsAdapter {

public async assignTagsToBeats(
req: FrameworkRequest,
assignments: CMTagAssignment[]
): Promise<CMTagAssignment[]> {
assignments: BeatsTagAssignment[]
): Promise<BeatsTagAssignment[]> {
const body = flatten(
assignments.map(({ beatId, tag }) => {
const script =
Expand All @@ -193,18 +181,18 @@ export class ElasticsearchBeatsAdapter implements CMBeatsAdapter {
})
);

const params = {
const response = await this.database.bulk(req, {
body,
index: INDEX_NAMES.BEATS,
refresh: 'wait_for',
type: '_doc',
};

const response = await this.framework.callWithRequest(req, 'bulk', params);
return get<any>(response, 'items', []).map((item: any, resultIdx: any) => ({
idxInRequest: assignments[resultIdx].idxInRequest,
result: item.update.result,
status: item.update.status,
}));
});
return _get<any>(response, 'items', []).map(
(item: any, resultIdx: any) => ({
idxInRequest: assignments[resultIdx].idxInRequest,
result: item.update.result,
status: item.update.status,
})
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,9 @@
import { omit } from 'lodash';
import moment from 'moment';

import {
CMBeat,
CMBeatsAdapter,
CMTagAssignment,
FrameworkRequest,
} from '../../lib';
import { CMBeat } from '../../../../common/domain_types';
import { FrameworkRequest } from '../famework/adapter_types';
import { BeatsTagAssignment, CMBeatsAdapter } from './adapter_types';

export class MemoryBeatsAdapter implements CMBeatsAdapter {
private beatsDB: CMBeat[];
Expand Down Expand Up @@ -64,8 +61,8 @@ export class MemoryBeatsAdapter implements CMBeatsAdapter {

public async removeTagsFromBeats(
req: FrameworkRequest,
removals: CMTagAssignment[]
): Promise<CMTagAssignment[]> {
removals: BeatsTagAssignment[]
): Promise<BeatsTagAssignment[]> {
const beatIds = removals.map(r => r.beatId);

const response = this.beatsDB
Expand All @@ -89,15 +86,15 @@ export class MemoryBeatsAdapter implements CMBeatsAdapter {

public async assignTagsToBeats(
req: FrameworkRequest,
assignments: CMTagAssignment[]
): Promise<CMTagAssignment[]> {
assignments: BeatsTagAssignment[]
): Promise<BeatsTagAssignment[]> {
const beatIds = assignments.map(r => r.beatId);

this.beatsDB.filter(beat => beatIds.includes(beat.id)).map(beat => {
// get tags that need to be assigned to this beat
const tags = assignments
.filter(a => a.beatId === beat.id)
.map((t: CMTagAssignment) => t.tag);
.map((t: BeatsTagAssignment) => t.tag);

if (tags.length > 0) {
if (!beat.tags) {
Expand All @@ -114,10 +111,12 @@ export class MemoryBeatsAdapter implements CMBeatsAdapter {
return beat;
});

return assignments.map<any>((item: CMTagAssignment, resultIdx: number) => ({
idxInRequest: assignments[resultIdx].idxInRequest,
result: 'updated',
status: 200,
}));
return assignments.map<any>(
(item: BeatsTagAssignment, resultIdx: number) => ({
idxInRequest: assignments[resultIdx].idxInRequest,
result: 'updated',
status: 200,
})
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
// file.skip

// @ts-ignore
import { createEsTestCluster } from '@kbn/test';
// @ts-ignore
import * as kbnTestServer from '../../../../../../../../src/test_utils/kbn_server';
import { DatabaseKbnESPlugin } from '../adapter_types';
import { KibanaDatabaseAdapter } from '../kibana_database_adapter';
import { contractTests } from './test_contract';

const kbnServer = kbnTestServer.createServerWithCorePlugins();
const es = createEsTestCluster({});

contractTests('Kibana Database Adapter', {
before: async () => {
await es.start();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be problematic to use this api here, because it might not honor the user's selection of the source to obtain Elasticsearch from (snapshot, source, etc) as our test runner usually do. That will probably lead to problems on our CI systems as well. I would recommend to talk to the @elastic/kibana-platform team to integrate it properly into the test runner.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per kibana-platform, this should be fine as-is as it uses process.env.TEST_ES_FROM internally.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interesting, thanks for clarifying that

await kbnServer.ready();

return await kbnServer.server.plugins.elasticsearch.waitUntilReady();
},
after: async () => {
await kbnServer.close();
return await es.cleanup();
},
adapterSetup: () => {
return new KibanaDatabaseAdapter(kbnServer.server.plugins
.elasticsearch as DatabaseKbnESPlugin);
},
});
Loading